mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 12:00:33 +00:00
Made metadascreen as modal for better user experience in ios
This commit is contained in:
parent
975f0eb9ef
commit
8de78b435a
34 changed files with 1947 additions and 265 deletions
7
app.json
7
app.json
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"expo": {
|
||||
"name": "Nuvio",
|
||||
"slug": "nuvio",
|
||||
"name": "Stremio Expo",
|
||||
"slug": "stremio-expo",
|
||||
"version": "1.0.0",
|
||||
"orientation": "default",
|
||||
"icon": "./assets/icon.png",
|
||||
|
|
@ -18,7 +18,8 @@
|
|||
"NSAppTransportSecurity": {
|
||||
"NSAllowsArbitraryLoads": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"bundleIdentifier": "com.nuvio.app"
|
||||
},
|
||||
"android": {
|
||||
"adaptiveIcon": {
|
||||
|
|
|
|||
466
build/config.gypi
Normal file
466
build/config.gypi
Normal file
|
|
@ -0,0 +1,466 @@
|
|||
# Do not edit. File was generated by node-gyp's "configure" step
|
||||
{
|
||||
"target_defaults": {
|
||||
"cflags": [],
|
||||
"configurations": {
|
||||
"Debug": {
|
||||
"v8_enable_v8_checks": 0,
|
||||
"variables": {}
|
||||
},
|
||||
"Release": {
|
||||
"v8_enable_v8_checks": 1,
|
||||
"variables": {}
|
||||
}
|
||||
},
|
||||
"default_configuration": "Release",
|
||||
"defines": [],
|
||||
"include_dirs": [],
|
||||
"libraries": [],
|
||||
"msbuild_toolset": "v143",
|
||||
"msvs_windows_target_platform_version": "10.0.22621.0"
|
||||
},
|
||||
"variables": {
|
||||
"asan": 0,
|
||||
"clang": 0,
|
||||
"coverage": "false",
|
||||
"dcheck_always_on": 0,
|
||||
"debug_nghttp2": "false",
|
||||
"debug_node": "false",
|
||||
"enable_lto": "false",
|
||||
"enable_pgo_generate": "false",
|
||||
"enable_pgo_use": "false",
|
||||
"error_on_warn": "false",
|
||||
"force_dynamic_crt": 0,
|
||||
"host_arch": "x64",
|
||||
"icu_data_in": "..\\..\\deps\\icu-tmp\\icudt76l.dat",
|
||||
"icu_endianness": "l",
|
||||
"icu_gyp_path": "tools/icu/icu-generic.gyp",
|
||||
"icu_path": "deps/icu-small",
|
||||
"icu_small": "false",
|
||||
"icu_ver_major": "76",
|
||||
"libdir": "lib",
|
||||
"llvm_version": "0.0",
|
||||
"napi_build_version": "9",
|
||||
"nasm_version": "2.16",
|
||||
"node_builtin_shareable_builtins": [
|
||||
"deps/cjs-module-lexer/lexer.js",
|
||||
"deps/cjs-module-lexer/dist/lexer.js",
|
||||
"deps/undici/undici.js",
|
||||
"deps/amaro/dist/index.js"
|
||||
],
|
||||
"node_byteorder": "little",
|
||||
"node_debug_lib": "false",
|
||||
"node_enable_d8": "false",
|
||||
"node_enable_v8_vtunejit": "false",
|
||||
"node_fipsinstall": "false",
|
||||
"node_install_corepack": "true",
|
||||
"node_install_npm": "true",
|
||||
"node_library_files": [
|
||||
"lib/_http_agent.js",
|
||||
"lib/_http_client.js",
|
||||
"lib/_http_common.js",
|
||||
"lib/_http_incoming.js",
|
||||
"lib/_http_outgoing.js",
|
||||
"lib/_http_server.js",
|
||||
"lib/_stream_duplex.js",
|
||||
"lib/_stream_passthrough.js",
|
||||
"lib/_stream_readable.js",
|
||||
"lib/_stream_transform.js",
|
||||
"lib/_stream_wrap.js",
|
||||
"lib/_stream_writable.js",
|
||||
"lib/_tls_common.js",
|
||||
"lib/_tls_wrap.js",
|
||||
"lib/assert.js",
|
||||
"lib/assert/strict.js",
|
||||
"lib/async_hooks.js",
|
||||
"lib/buffer.js",
|
||||
"lib/child_process.js",
|
||||
"lib/cluster.js",
|
||||
"lib/console.js",
|
||||
"lib/constants.js",
|
||||
"lib/crypto.js",
|
||||
"lib/dgram.js",
|
||||
"lib/diagnostics_channel.js",
|
||||
"lib/dns.js",
|
||||
"lib/dns/promises.js",
|
||||
"lib/domain.js",
|
||||
"lib/events.js",
|
||||
"lib/fs.js",
|
||||
"lib/fs/promises.js",
|
||||
"lib/http.js",
|
||||
"lib/http2.js",
|
||||
"lib/https.js",
|
||||
"lib/inspector.js",
|
||||
"lib/inspector/promises.js",
|
||||
"lib/internal/abort_controller.js",
|
||||
"lib/internal/assert.js",
|
||||
"lib/internal/assert/assertion_error.js",
|
||||
"lib/internal/assert/calltracker.js",
|
||||
"lib/internal/assert/myers_diff.js",
|
||||
"lib/internal/assert/utils.js",
|
||||
"lib/internal/async_context_frame.js",
|
||||
"lib/internal/async_hooks.js",
|
||||
"lib/internal/async_local_storage/async_context_frame.js",
|
||||
"lib/internal/async_local_storage/async_hooks.js",
|
||||
"lib/internal/blob.js",
|
||||
"lib/internal/blocklist.js",
|
||||
"lib/internal/bootstrap/node.js",
|
||||
"lib/internal/bootstrap/realm.js",
|
||||
"lib/internal/bootstrap/shadow_realm.js",
|
||||
"lib/internal/bootstrap/switches/does_not_own_process_state.js",
|
||||
"lib/internal/bootstrap/switches/does_own_process_state.js",
|
||||
"lib/internal/bootstrap/switches/is_main_thread.js",
|
||||
"lib/internal/bootstrap/switches/is_not_main_thread.js",
|
||||
"lib/internal/bootstrap/web/exposed-wildcard.js",
|
||||
"lib/internal/bootstrap/web/exposed-window-or-worker.js",
|
||||
"lib/internal/buffer.js",
|
||||
"lib/internal/child_process.js",
|
||||
"lib/internal/child_process/serialization.js",
|
||||
"lib/internal/cli_table.js",
|
||||
"lib/internal/cluster/child.js",
|
||||
"lib/internal/cluster/primary.js",
|
||||
"lib/internal/cluster/round_robin_handle.js",
|
||||
"lib/internal/cluster/shared_handle.js",
|
||||
"lib/internal/cluster/utils.js",
|
||||
"lib/internal/cluster/worker.js",
|
||||
"lib/internal/console/constructor.js",
|
||||
"lib/internal/console/global.js",
|
||||
"lib/internal/constants.js",
|
||||
"lib/internal/crypto/aes.js",
|
||||
"lib/internal/crypto/certificate.js",
|
||||
"lib/internal/crypto/cfrg.js",
|
||||
"lib/internal/crypto/cipher.js",
|
||||
"lib/internal/crypto/diffiehellman.js",
|
||||
"lib/internal/crypto/ec.js",
|
||||
"lib/internal/crypto/hash.js",
|
||||
"lib/internal/crypto/hashnames.js",
|
||||
"lib/internal/crypto/hkdf.js",
|
||||
"lib/internal/crypto/keygen.js",
|
||||
"lib/internal/crypto/keys.js",
|
||||
"lib/internal/crypto/mac.js",
|
||||
"lib/internal/crypto/pbkdf2.js",
|
||||
"lib/internal/crypto/random.js",
|
||||
"lib/internal/crypto/rsa.js",
|
||||
"lib/internal/crypto/scrypt.js",
|
||||
"lib/internal/crypto/sig.js",
|
||||
"lib/internal/crypto/util.js",
|
||||
"lib/internal/crypto/webcrypto.js",
|
||||
"lib/internal/crypto/webidl.js",
|
||||
"lib/internal/crypto/x509.js",
|
||||
"lib/internal/data_url.js",
|
||||
"lib/internal/debugger/inspect.js",
|
||||
"lib/internal/debugger/inspect_client.js",
|
||||
"lib/internal/debugger/inspect_repl.js",
|
||||
"lib/internal/dgram.js",
|
||||
"lib/internal/dns/callback_resolver.js",
|
||||
"lib/internal/dns/promises.js",
|
||||
"lib/internal/dns/utils.js",
|
||||
"lib/internal/encoding.js",
|
||||
"lib/internal/error_serdes.js",
|
||||
"lib/internal/errors.js",
|
||||
"lib/internal/event_target.js",
|
||||
"lib/internal/events/abort_listener.js",
|
||||
"lib/internal/events/symbols.js",
|
||||
"lib/internal/file.js",
|
||||
"lib/internal/fixed_queue.js",
|
||||
"lib/internal/freelist.js",
|
||||
"lib/internal/freeze_intrinsics.js",
|
||||
"lib/internal/fs/cp/cp-sync.js",
|
||||
"lib/internal/fs/cp/cp.js",
|
||||
"lib/internal/fs/dir.js",
|
||||
"lib/internal/fs/glob.js",
|
||||
"lib/internal/fs/promises.js",
|
||||
"lib/internal/fs/read/context.js",
|
||||
"lib/internal/fs/recursive_watch.js",
|
||||
"lib/internal/fs/rimraf.js",
|
||||
"lib/internal/fs/streams.js",
|
||||
"lib/internal/fs/sync_write_stream.js",
|
||||
"lib/internal/fs/utils.js",
|
||||
"lib/internal/fs/watchers.js",
|
||||
"lib/internal/heap_utils.js",
|
||||
"lib/internal/histogram.js",
|
||||
"lib/internal/http.js",
|
||||
"lib/internal/http2/compat.js",
|
||||
"lib/internal/http2/core.js",
|
||||
"lib/internal/http2/util.js",
|
||||
"lib/internal/inspector_async_hook.js",
|
||||
"lib/internal/inspector_network_tracking.js",
|
||||
"lib/internal/js_stream_socket.js",
|
||||
"lib/internal/legacy/processbinding.js",
|
||||
"lib/internal/linkedlist.js",
|
||||
"lib/internal/main/check_syntax.js",
|
||||
"lib/internal/main/embedding.js",
|
||||
"lib/internal/main/eval_stdin.js",
|
||||
"lib/internal/main/eval_string.js",
|
||||
"lib/internal/main/inspect.js",
|
||||
"lib/internal/main/mksnapshot.js",
|
||||
"lib/internal/main/print_help.js",
|
||||
"lib/internal/main/prof_process.js",
|
||||
"lib/internal/main/repl.js",
|
||||
"lib/internal/main/run_main_module.js",
|
||||
"lib/internal/main/test_runner.js",
|
||||
"lib/internal/main/watch_mode.js",
|
||||
"lib/internal/main/worker_thread.js",
|
||||
"lib/internal/mime.js",
|
||||
"lib/internal/modules/cjs/loader.js",
|
||||
"lib/internal/modules/esm/assert.js",
|
||||
"lib/internal/modules/esm/create_dynamic_module.js",
|
||||
"lib/internal/modules/esm/fetch_module.js",
|
||||
"lib/internal/modules/esm/formats.js",
|
||||
"lib/internal/modules/esm/get_format.js",
|
||||
"lib/internal/modules/esm/hooks.js",
|
||||
"lib/internal/modules/esm/initialize_import_meta.js",
|
||||
"lib/internal/modules/esm/load.js",
|
||||
"lib/internal/modules/esm/loader.js",
|
||||
"lib/internal/modules/esm/module_job.js",
|
||||
"lib/internal/modules/esm/module_map.js",
|
||||
"lib/internal/modules/esm/resolve.js",
|
||||
"lib/internal/modules/esm/shared_constants.js",
|
||||
"lib/internal/modules/esm/translators.js",
|
||||
"lib/internal/modules/esm/utils.js",
|
||||
"lib/internal/modules/esm/worker.js",
|
||||
"lib/internal/modules/helpers.js",
|
||||
"lib/internal/modules/package_json_reader.js",
|
||||
"lib/internal/modules/run_main.js",
|
||||
"lib/internal/modules/typescript.js",
|
||||
"lib/internal/navigator.js",
|
||||
"lib/internal/net.js",
|
||||
"lib/internal/options.js",
|
||||
"lib/internal/per_context/domexception.js",
|
||||
"lib/internal/per_context/messageport.js",
|
||||
"lib/internal/per_context/primordials.js",
|
||||
"lib/internal/perf/event_loop_delay.js",
|
||||
"lib/internal/perf/event_loop_utilization.js",
|
||||
"lib/internal/perf/nodetiming.js",
|
||||
"lib/internal/perf/observe.js",
|
||||
"lib/internal/perf/performance.js",
|
||||
"lib/internal/perf/performance_entry.js",
|
||||
"lib/internal/perf/resource_timing.js",
|
||||
"lib/internal/perf/timerify.js",
|
||||
"lib/internal/perf/usertiming.js",
|
||||
"lib/internal/perf/utils.js",
|
||||
"lib/internal/priority_queue.js",
|
||||
"lib/internal/process/execution.js",
|
||||
"lib/internal/process/finalization.js",
|
||||
"lib/internal/process/per_thread.js",
|
||||
"lib/internal/process/permission.js",
|
||||
"lib/internal/process/pre_execution.js",
|
||||
"lib/internal/process/promises.js",
|
||||
"lib/internal/process/report.js",
|
||||
"lib/internal/process/signal.js",
|
||||
"lib/internal/process/task_queues.js",
|
||||
"lib/internal/process/warning.js",
|
||||
"lib/internal/process/worker_thread_only.js",
|
||||
"lib/internal/promise_hooks.js",
|
||||
"lib/internal/querystring.js",
|
||||
"lib/internal/quic/quic.js",
|
||||
"lib/internal/quic/state.js",
|
||||
"lib/internal/quic/stats.js",
|
||||
"lib/internal/quic/symbols.js",
|
||||
"lib/internal/readline/callbacks.js",
|
||||
"lib/internal/readline/emitKeypressEvents.js",
|
||||
"lib/internal/readline/interface.js",
|
||||
"lib/internal/readline/promises.js",
|
||||
"lib/internal/readline/utils.js",
|
||||
"lib/internal/repl.js",
|
||||
"lib/internal/repl/await.js",
|
||||
"lib/internal/repl/history.js",
|
||||
"lib/internal/repl/utils.js",
|
||||
"lib/internal/socket_list.js",
|
||||
"lib/internal/socketaddress.js",
|
||||
"lib/internal/source_map/prepare_stack_trace.js",
|
||||
"lib/internal/source_map/source_map.js",
|
||||
"lib/internal/source_map/source_map_cache.js",
|
||||
"lib/internal/source_map/source_map_cache_map.js",
|
||||
"lib/internal/stream_base_commons.js",
|
||||
"lib/internal/streams/add-abort-signal.js",
|
||||
"lib/internal/streams/compose.js",
|
||||
"lib/internal/streams/destroy.js",
|
||||
"lib/internal/streams/duplex.js",
|
||||
"lib/internal/streams/duplexify.js",
|
||||
"lib/internal/streams/duplexpair.js",
|
||||
"lib/internal/streams/end-of-stream.js",
|
||||
"lib/internal/streams/from.js",
|
||||
"lib/internal/streams/lazy_transform.js",
|
||||
"lib/internal/streams/legacy.js",
|
||||
"lib/internal/streams/operators.js",
|
||||
"lib/internal/streams/passthrough.js",
|
||||
"lib/internal/streams/pipeline.js",
|
||||
"lib/internal/streams/readable.js",
|
||||
"lib/internal/streams/state.js",
|
||||
"lib/internal/streams/transform.js",
|
||||
"lib/internal/streams/utils.js",
|
||||
"lib/internal/streams/writable.js",
|
||||
"lib/internal/test/binding.js",
|
||||
"lib/internal/test/transfer.js",
|
||||
"lib/internal/test_runner/coverage.js",
|
||||
"lib/internal/test_runner/harness.js",
|
||||
"lib/internal/test_runner/mock/loader.js",
|
||||
"lib/internal/test_runner/mock/mock.js",
|
||||
"lib/internal/test_runner/mock/mock_timers.js",
|
||||
"lib/internal/test_runner/reporter/dot.js",
|
||||
"lib/internal/test_runner/reporter/junit.js",
|
||||
"lib/internal/test_runner/reporter/lcov.js",
|
||||
"lib/internal/test_runner/reporter/spec.js",
|
||||
"lib/internal/test_runner/reporter/tap.js",
|
||||
"lib/internal/test_runner/reporter/utils.js",
|
||||
"lib/internal/test_runner/reporter/v8-serializer.js",
|
||||
"lib/internal/test_runner/runner.js",
|
||||
"lib/internal/test_runner/snapshot.js",
|
||||
"lib/internal/test_runner/test.js",
|
||||
"lib/internal/test_runner/tests_stream.js",
|
||||
"lib/internal/test_runner/utils.js",
|
||||
"lib/internal/timers.js",
|
||||
"lib/internal/tls/secure-context.js",
|
||||
"lib/internal/tls/secure-pair.js",
|
||||
"lib/internal/trace_events_async_hooks.js",
|
||||
"lib/internal/tty.js",
|
||||
"lib/internal/url.js",
|
||||
"lib/internal/util.js",
|
||||
"lib/internal/util/colors.js",
|
||||
"lib/internal/util/comparisons.js",
|
||||
"lib/internal/util/debuglog.js",
|
||||
"lib/internal/util/inspect.js",
|
||||
"lib/internal/util/inspector.js",
|
||||
"lib/internal/util/parse_args/parse_args.js",
|
||||
"lib/internal/util/parse_args/utils.js",
|
||||
"lib/internal/util/types.js",
|
||||
"lib/internal/v8/startup_snapshot.js",
|
||||
"lib/internal/v8_prof_polyfill.js",
|
||||
"lib/internal/v8_prof_processor.js",
|
||||
"lib/internal/validators.js",
|
||||
"lib/internal/vm.js",
|
||||
"lib/internal/vm/module.js",
|
||||
"lib/internal/wasm_web_api.js",
|
||||
"lib/internal/watch_mode/files_watcher.js",
|
||||
"lib/internal/watchdog.js",
|
||||
"lib/internal/webidl.js",
|
||||
"lib/internal/webstorage.js",
|
||||
"lib/internal/webstreams/adapters.js",
|
||||
"lib/internal/webstreams/compression.js",
|
||||
"lib/internal/webstreams/encoding.js",
|
||||
"lib/internal/webstreams/queuingstrategies.js",
|
||||
"lib/internal/webstreams/readablestream.js",
|
||||
"lib/internal/webstreams/transfer.js",
|
||||
"lib/internal/webstreams/transformstream.js",
|
||||
"lib/internal/webstreams/util.js",
|
||||
"lib/internal/webstreams/writablestream.js",
|
||||
"lib/internal/worker.js",
|
||||
"lib/internal/worker/io.js",
|
||||
"lib/internal/worker/js_transferable.js",
|
||||
"lib/internal/worker/messaging.js",
|
||||
"lib/module.js",
|
||||
"lib/net.js",
|
||||
"lib/os.js",
|
||||
"lib/path.js",
|
||||
"lib/path/posix.js",
|
||||
"lib/path/win32.js",
|
||||
"lib/perf_hooks.js",
|
||||
"lib/process.js",
|
||||
"lib/punycode.js",
|
||||
"lib/querystring.js",
|
||||
"lib/readline.js",
|
||||
"lib/readline/promises.js",
|
||||
"lib/repl.js",
|
||||
"lib/sea.js",
|
||||
"lib/sqlite.js",
|
||||
"lib/stream.js",
|
||||
"lib/stream/consumers.js",
|
||||
"lib/stream/promises.js",
|
||||
"lib/stream/web.js",
|
||||
"lib/string_decoder.js",
|
||||
"lib/sys.js",
|
||||
"lib/test.js",
|
||||
"lib/test/reporters.js",
|
||||
"lib/timers.js",
|
||||
"lib/timers/promises.js",
|
||||
"lib/tls.js",
|
||||
"lib/trace_events.js",
|
||||
"lib/tty.js",
|
||||
"lib/url.js",
|
||||
"lib/util.js",
|
||||
"lib/util/types.js",
|
||||
"lib/v8.js",
|
||||
"lib/vm.js",
|
||||
"lib/wasi.js",
|
||||
"lib/worker_threads.js",
|
||||
"lib/zlib.js"
|
||||
],
|
||||
"node_module_version": 127,
|
||||
"node_no_browser_globals": "false",
|
||||
"node_prefix": "\\usr\\local",
|
||||
"node_release_urlbase": "https://nodejs.org/download/release/",
|
||||
"node_shared": "false",
|
||||
"node_shared_ada": "false",
|
||||
"node_shared_brotli": "false",
|
||||
"node_shared_cares": "false",
|
||||
"node_shared_http_parser": "false",
|
||||
"node_shared_libuv": "false",
|
||||
"node_shared_nghttp2": "false",
|
||||
"node_shared_nghttp3": "false",
|
||||
"node_shared_ngtcp2": "false",
|
||||
"node_shared_openssl": "false",
|
||||
"node_shared_simdjson": "false",
|
||||
"node_shared_simdutf": "false",
|
||||
"node_shared_sqlite": "false",
|
||||
"node_shared_uvwasi": "false",
|
||||
"node_shared_zlib": "false",
|
||||
"node_tag": "",
|
||||
"node_target_type": "executable",
|
||||
"node_use_amaro": "true",
|
||||
"node_use_bundled_v8": "true",
|
||||
"node_use_node_code_cache": "true",
|
||||
"node_use_node_snapshot": "true",
|
||||
"node_use_openssl": "true",
|
||||
"node_use_v8_platform": "true",
|
||||
"node_with_ltcg": "true",
|
||||
"node_without_node_options": "false",
|
||||
"node_write_snapshot_as_array_literals": "true",
|
||||
"openssl_is_fips": "false",
|
||||
"openssl_quic": "true",
|
||||
"ossfuzz": "false",
|
||||
"shlib_suffix": "so.127",
|
||||
"single_executable_application": "true",
|
||||
"target_arch": "x64",
|
||||
"ubsan": 0,
|
||||
"use_prefix_to_find_headers": "false",
|
||||
"v8_enable_31bit_smis_on_64bit_arch": 0,
|
||||
"v8_enable_extensible_ro_snapshot": 0,
|
||||
"v8_enable_gdbjit": 0,
|
||||
"v8_enable_hugepage": 0,
|
||||
"v8_enable_i18n_support": 1,
|
||||
"v8_enable_inspector": 1,
|
||||
"v8_enable_javascript_promise_hooks": 1,
|
||||
"v8_enable_lite_mode": 0,
|
||||
"v8_enable_maglev": 0,
|
||||
"v8_enable_object_print": 1,
|
||||
"v8_enable_pointer_compression": 0,
|
||||
"v8_enable_sandbox": 0,
|
||||
"v8_enable_shared_ro_heap": 1,
|
||||
"v8_enable_short_builtin_calls": 1,
|
||||
"v8_enable_wasm_simd256_revec": 1,
|
||||
"v8_enable_webassembly": 1,
|
||||
"v8_optimized_debug": 1,
|
||||
"v8_promise_internal_field_count": 1,
|
||||
"v8_random_seed": 0,
|
||||
"v8_trace_maps": 0,
|
||||
"v8_use_siphash": 1,
|
||||
"want_separate_host_toolset": 0,
|
||||
"nodedir": "C:\\Users\\NAYIF\\AppData\\Local\\Temp\\prebuild\\node\\22.13.0",
|
||||
"python": "C:\\Users\\NAYIF\\AppData\\Local\\Programs\\Python\\Python313\\python.exe",
|
||||
"standalone_static_library": 1,
|
||||
"msbuild_path": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe",
|
||||
"target": "22.13.0",
|
||||
"build_v8_with_gn": "false",
|
||||
"cache": "C:\\Users\\NAYIF\\AppData\\Local\\npm-cache",
|
||||
"globalconfig": "C:\\nvm4w\\nodejs\\etc\\npmrc",
|
||||
"global_prefix": "C:\\nvm4w\\nodejs",
|
||||
"init_module": "C:\\Users\\NAYIF\\.npm-init.js",
|
||||
"local_prefix": "F:\\stremio-expo",
|
||||
"node_gyp": "C:\\Users\\NAYIF\\AppData\\Local\\nvm\\v22.13.0\\node_modules\\npm\\node_modules\\node-gyp\\bin\\node-gyp.js",
|
||||
"npm_version": "11.0.0",
|
||||
"prefix": "C:\\nvm4w\\nodejs",
|
||||
"userconfig": "C:\\Users\\NAYIF\\.npmrc",
|
||||
"user_agent": "npm/11.0.0 node/v22.13.0 win32 x64 workspaces/false"
|
||||
}
|
||||
}
|
||||
30
ios/.gitignore
vendored
Normal file
30
ios/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# OSX
|
||||
#
|
||||
.DS_Store
|
||||
|
||||
# Xcode
|
||||
#
|
||||
build/
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
*.xccheckout
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
project.xcworkspace
|
||||
.xcode.env.local
|
||||
|
||||
# Bundle artifacts
|
||||
*.jsbundle
|
||||
|
||||
# CocoaPods
|
||||
/Pods/
|
||||
11
ios/.xcode.env
Normal file
11
ios/.xcode.env
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# This `.xcode.env` file is versioned and is used to source the environment
|
||||
# used when running script phases inside Xcode.
|
||||
# To customize your local environment, you can create an `.xcode.env.local`
|
||||
# file that is not versioned.
|
||||
|
||||
# NODE_BINARY variable contains the PATH to the node executable.
|
||||
#
|
||||
# Customize the NODE_BINARY variable here.
|
||||
# For example, to use nvm with brew, add the following line
|
||||
# . "$(brew --prefix nvm)/nvm.sh" --no-use
|
||||
export NODE_BINARY=$(command -v node)
|
||||
471
ios/Nuvio.xcodeproj/project.pbxproj
Normal file
471
ios/Nuvio.xcodeproj/project.pbxproj
Normal file
|
|
@ -0,0 +1,471 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; };
|
||||
96905EF65AED1B983A6B3ABC /* libPods-Nuvio.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-Nuvio.a */; };
|
||||
B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */; };
|
||||
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; };
|
||||
53F59A3E794F4B87B221D4C3 /* noop-file.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC1EB3A22DCB47A0A12A0CAF /* noop-file.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
13B07F961A680F5B00A75B9A /* Nuvio.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Nuvio.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Nuvio/AppDelegate.h; sourceTree = "<group>"; };
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = Nuvio/AppDelegate.mm; sourceTree = "<group>"; };
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Nuvio/Images.xcassets; sourceTree = "<group>"; };
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Nuvio/Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Nuvio/main.m; sourceTree = "<group>"; };
|
||||
58EEBF8E8E6FB1BC6CAF49B5 /* libPods-Nuvio.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Nuvio.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
6C2E3173556A471DD304B334 /* Pods-Nuvio.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Nuvio.debug.xcconfig"; path = "Target Support Files/Pods-Nuvio/Pods-Nuvio.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
7A4D352CD337FB3A3BF06240 /* Pods-Nuvio.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Nuvio.release.xcconfig"; path = "Target Support Files/Pods-Nuvio/Pods-Nuvio.release.xcconfig"; sourceTree = "<group>"; };
|
||||
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = Nuvio/SplashScreen.storyboard; sourceTree = "<group>"; };
|
||||
BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = "<group>"; };
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||
FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-Nuvio/ExpoModulesProvider.swift"; sourceTree = "<group>"; };
|
||||
DC1EB3A22DCB47A0A12A0CAF /* noop-file.swift */ = {isa = PBXFileReference; name = "noop-file.swift"; path = "Nuvio/noop-file.swift"; sourceTree = "<group>"; fileEncoding = 4; lastKnownFileType = sourcecode.swift; explicitFileType = undefined; includeInIndex = 0; };
|
||||
DD9A8A1855A34F10923D3C37 /* Nuvio-Bridging-Header.h */ = {isa = PBXFileReference; name = "Nuvio-Bridging-Header.h"; path = "Nuvio/Nuvio-Bridging-Header.h"; sourceTree = "<group>"; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; explicitFileType = undefined; includeInIndex = 0; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
96905EF65AED1B983A6B3ABC /* libPods-Nuvio.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
13B07FAE1A68108700A75B9A /* Nuvio */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BB2F792B24A3F905000567C9 /* Supporting */,
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.mm */,
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */,
|
||||
13B07FB61A68108700A75B9A /* Info.plist */,
|
||||
13B07FB71A68108700A75B9A /* main.m */,
|
||||
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */,
|
||||
DC1EB3A22DCB47A0A12A0CAF /* noop-file.swift */,
|
||||
DD9A8A1855A34F10923D3C37 /* Nuvio-Bridging-Header.h */,
|
||||
);
|
||||
name = Nuvio;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
|
||||
58EEBF8E8E6FB1BC6CAF49B5 /* libPods-Nuvio.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = Libraries;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
83CBB9F61A601CBA00E9B192 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13B07FAE1A68108700A75B9A /* Nuvio */,
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */,
|
||||
83CBBA001A601CBA00E9B192 /* Products */,
|
||||
2D16E6871FA4F8E400B85C8A /* Frameworks */,
|
||||
D65327D7A22EEC0BE12398D9 /* Pods */,
|
||||
D7E4C46ADA2E9064B798F356 /* ExpoModulesProviders */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
tabWidth = 2;
|
||||
usesTabs = 0;
|
||||
};
|
||||
83CBBA001A601CBA00E9B192 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13B07F961A680F5B00A75B9A /* Nuvio.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
92DBD88DE9BF7D494EA9DA96 /* Nuvio */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */,
|
||||
);
|
||||
name = Nuvio;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BB2F792B24A3F905000567C9 /* Supporting */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BB2F792C24A3F905000567C9 /* Expo.plist */,
|
||||
);
|
||||
name = Supporting;
|
||||
path = Nuvio/Supporting;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D65327D7A22EEC0BE12398D9 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6C2E3173556A471DD304B334 /* Pods-Nuvio.debug.xcconfig */,
|
||||
7A4D352CD337FB3A3BF06240 /* Pods-Nuvio.release.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D7E4C46ADA2E9064B798F356 /* ExpoModulesProviders */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
92DBD88DE9BF7D494EA9DA96 /* Nuvio */,
|
||||
);
|
||||
name = ExpoModulesProviders;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
13B07F861A680F5B00A75B9A /* Nuvio */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Nuvio" */;
|
||||
buildPhases = (
|
||||
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */,
|
||||
13B07F871A680F5B00A75B9A /* Sources */,
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */,
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
||||
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Nuvio;
|
||||
productName = Nuvio;
|
||||
productReference = 13B07F961A680F5B00A75B9A /* Nuvio.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
83CBB9F71A601CBA00E9B192 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1130;
|
||||
TargetAttributes = {
|
||||
13B07F861A680F5B00A75B9A = {
|
||||
LastSwiftMigration = 1250;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Nuvio" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 83CBB9F61A601CBA00E9B192;
|
||||
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
13B07F861A680F5B00A75B9A /* Nuvio */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */,
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
|
||||
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */,
|
||||
8A293A5AD8A6486B86EDC6E7 /* Nuvio-Bridging-Header.h in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Bundle React Native code and images";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios absolute | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n# Source .xcode.env.updates if it exists to allow\n# SKIP_BUNDLING to be unset if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.updates\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.updates\"\nfi\n# Source local changes to allow overrides\n# if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n\n";
|
||||
};
|
||||
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Nuvio-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Nuvio/Pods-Nuvio-resources.sh",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/EXUpdates/EXUpdates.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXUpdates.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Nuvio/Pods-Nuvio-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
13B07F871A680F5B00A75B9A /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */,
|
||||
B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */,
|
||||
53F59A3E794F4B87B221D4C3 /* noop-file.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
13B07F941A680F5B00A75B9A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 6C2E3173556A471DD304B334 /* Pods-Nuvio.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"FB_SONARKIT_ENABLED=1",
|
||||
);
|
||||
INFOPLIST_FILE = Nuvio/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 1.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.nuvio.app";
|
||||
PRODUCT_NAME = "Nuvio";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = Nuvio/Nuvio-Bridging-Header.h;
|
||||
CODE_SIGN_ENTITLEMENTS = Nuvio/Nuvio.entitlements;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
13B07F951A680F5B00A75B9A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7A4D352CD337FB3A3BF06240 /* Pods-Nuvio.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
INFOPLIST_FILE = Nuvio/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 1.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.nuvio.app";
|
||||
PRODUCT_NAME = "Nuvio";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = Nuvio/Nuvio-Bridging-Header.h;
|
||||
CODE_SIGN_ENTITLEMENTS = Nuvio/Nuvio.entitlements;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
83CBBA201A601CBA00E9B192 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
|
||||
LIBRARY_SEARCH_PATHS = "\"$(inherited)\"";
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
83CBBA211A601CBA00E9B192 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
|
||||
LIBRARY_SEARCH_PATHS = "\"$(inherited)\"";
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Nuvio" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
13B07F941A680F5B00A75B9A /* Debug */,
|
||||
13B07F951A680F5B00A75B9A /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Nuvio" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
83CBBA201A601CBA00E9B192 /* Debug */,
|
||||
83CBBA211A601CBA00E9B192 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
}
|
||||
88
ios/Nuvio.xcodeproj/xcshareddata/xcschemes/Nuvio.xcscheme
Normal file
88
ios/Nuvio.xcodeproj/xcshareddata/xcschemes/Nuvio.xcscheme
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1130"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "Nuvio.app"
|
||||
BlueprintName = "Nuvio"
|
||||
ReferencedContainer = "container:Nuvio.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
|
||||
BuildableName = "NuvioTests.xctest"
|
||||
BlueprintName = "NuvioTests"
|
||||
ReferencedContainer = "container:Nuvio.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "Nuvio.app"
|
||||
BlueprintName = "Nuvio"
|
||||
ReferencedContainer = "container:Nuvio.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "Nuvio.app"
|
||||
BlueprintName = "Nuvio"
|
||||
ReferencedContainer = "container:Nuvio.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
7
ios/Nuvio/AppDelegate.h
Normal file
7
ios/Nuvio/AppDelegate.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#import <RCTAppDelegate.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <Expo/Expo.h>
|
||||
|
||||
@interface AppDelegate : EXAppDelegateWrapper
|
||||
|
||||
@end
|
||||
62
ios/Nuvio/AppDelegate.mm
Normal file
62
ios/Nuvio/AppDelegate.mm
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#import "AppDelegate.h"
|
||||
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import <React/RCTLinkingManager.h>
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
self.moduleName = @"main";
|
||||
|
||||
// You can add your custom initial props in the dictionary below.
|
||||
// They will be passed down to the ViewController used by React Native.
|
||||
self.initialProps = @{};
|
||||
|
||||
return [super application:application didFinishLaunchingWithOptions:launchOptions];
|
||||
}
|
||||
|
||||
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
||||
{
|
||||
return [self bundleURL];
|
||||
}
|
||||
|
||||
- (NSURL *)bundleURL
|
||||
{
|
||||
#if DEBUG
|
||||
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@".expo/.virtual-metro-entry"];
|
||||
#else
|
||||
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||
#endif
|
||||
}
|
||||
|
||||
// Linking API
|
||||
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
|
||||
return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
|
||||
}
|
||||
|
||||
// Universal Links
|
||||
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
|
||||
BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
|
||||
return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result;
|
||||
}
|
||||
|
||||
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
|
||||
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
|
||||
{
|
||||
return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
|
||||
}
|
||||
|
||||
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
|
||||
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
|
||||
{
|
||||
return [super application:application didFailToRegisterForRemoteNotificationsWithError:error];
|
||||
}
|
||||
|
||||
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
|
||||
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
|
||||
{
|
||||
return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
|
||||
}
|
||||
|
||||
@end
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 907 KiB |
14
ios/Nuvio/Images.xcassets/AppIcon.appiconset/Contents.json
Normal file
14
ios/Nuvio/Images.xcassets/AppIcon.appiconset/Contents.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"images": [
|
||||
{
|
||||
"filename": "App-Icon-1024x1024@1x.png",
|
||||
"idiom": "universal",
|
||||
"platform": "ios",
|
||||
"size": "1024x1024"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "expo"
|
||||
}
|
||||
}
|
||||
6
ios/Nuvio/Images.xcassets/Contents.json
Normal file
6
ios/Nuvio/Images.xcassets/Contents.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "expo"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"colors": [
|
||||
{
|
||||
"color": {
|
||||
"components": {
|
||||
"alpha": "1.000",
|
||||
"blue": "1.00000000000000",
|
||||
"green": "1.00000000000000",
|
||||
"red": "1.00000000000000"
|
||||
},
|
||||
"color-space": "srgb"
|
||||
},
|
||||
"idiom": "universal"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "expo"
|
||||
}
|
||||
}
|
||||
23
ios/Nuvio/Images.xcassets/SplashScreenLogo.imageset/Contents.json
vendored
Normal file
23
ios/Nuvio/Images.xcassets/SplashScreenLogo.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"images": [
|
||||
{
|
||||
"idiom": "universal",
|
||||
"filename": "image.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"idiom": "universal",
|
||||
"filename": "image@2x.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom": "universal",
|
||||
"filename": "image@3x.png",
|
||||
"scale": "3x"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "expo"
|
||||
}
|
||||
}
|
||||
BIN
ios/Nuvio/Images.xcassets/SplashScreenLogo.imageset/image.png
vendored
Normal file
BIN
ios/Nuvio/Images.xcassets/SplashScreenLogo.imageset/image.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
BIN
ios/Nuvio/Images.xcassets/SplashScreenLogo.imageset/image@2x.png
vendored
Normal file
BIN
ios/Nuvio/Images.xcassets/SplashScreenLogo.imageset/image@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
BIN
ios/Nuvio/Images.xcassets/SplashScreenLogo.imageset/image@3x.png
vendored
Normal file
BIN
ios/Nuvio/Images.xcassets/SplashScreenLogo.imageset/image@3x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
74
ios/Nuvio/Info.plist
Normal file
74
ios/Nuvio/Info.plist
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Nuvio</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>com.nuvio.app</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>12.0</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>SplashScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>UIRequiresFullScreen</key>
|
||||
<false/>
|
||||
<key>UIStatusBarStyle</key>
|
||||
<string>UIStatusBarStyleDefault</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIUserInterfaceStyle</key>
|
||||
<string>Light</string>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
3
ios/Nuvio/Nuvio-Bridging-Header.h
Normal file
3
ios/Nuvio/Nuvio-Bridging-Header.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
//
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
8
ios/Nuvio/Nuvio.entitlements
Normal file
8
ios/Nuvio/Nuvio.entitlements
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
</dict>
|
||||
</plist>
|
||||
44
ios/Nuvio/SplashScreen.storyboard
Normal file
44
ios/Nuvio/SplashScreen.storyboard
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EXPO-VIEWCONTROLLER-1">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<scene sceneID="EXPO-SCENE-1">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="SplashScreenViewController" id="EXPO-VIEWCONTROLLER-1" sceneMemberID="viewController">
|
||||
<view key="view" userInteractionEnabled="NO" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="EXPO-ContainerView" userLabel="ContainerView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView id="EXPO-SplashScreen" userLabel="SplashScreenLogo" image="SplashScreenLogo" contentMode="scaleAspectFit" clipsSubviews="true" userInteractionEnabled="false" translatesAutoresizingMaskIntoConstraints="false">
|
||||
<rect key="frame" x="0" y="0" width="414" height="736"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="Rmq-lb-GrQ"/>
|
||||
<constraints>
|
||||
<constraint firstItem="EXPO-SplashScreen" firstAttribute="top" secondItem="EXPO-ContainerView" secondAttribute="top" id="83fcb9b545b870ba44c24f0feeb116490c499c52"/>
|
||||
<constraint firstItem="EXPO-SplashScreen" firstAttribute="leading" secondItem="EXPO-ContainerView" secondAttribute="leading" id="61d16215e44b98e39d0a2c74fdbfaaa22601b12c"/>
|
||||
<constraint firstItem="EXPO-SplashScreen" firstAttribute="trailing" secondItem="EXPO-ContainerView" secondAttribute="trailing" id="f934da460e9ab5acae3ad9987d5b676a108796c1"/>
|
||||
<constraint firstItem="EXPO-SplashScreen" firstAttribute="bottom" secondItem="EXPO-ContainerView" secondAttribute="bottom" id="d6a0be88096b36fb132659aa90203d39139deda9"/>
|
||||
</constraints>
|
||||
<color key="backgroundColor" name="SplashScreenBackground"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="EXPO-PLACEHOLDER-1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="0.0" y="0.0"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="SplashScreenLogo" width="414" height="736"/>
|
||||
<namedColor name="SplashScreenBackground">
|
||||
<color alpha="1.000" blue="1.00000000000000" green="1.00000000000000" red="1.00000000000000" customColorSpace="sRGB" colorSpace="custom"/>
|
||||
</namedColor>
|
||||
</resources>
|
||||
</document>
|
||||
12
ios/Nuvio/Supporting/Expo.plist
Normal file
12
ios/Nuvio/Supporting/Expo.plist
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>EXUpdatesCheckOnLaunch</key>
|
||||
<string>ALWAYS</string>
|
||||
<key>EXUpdatesEnabled</key>
|
||||
<false/>
|
||||
<key>EXUpdatesLaunchWaitMs</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
10
ios/Nuvio/main.m
Normal file
10
ios/Nuvio/main.m
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
}
|
||||
|
||||
4
ios/Nuvio/noop-file.swift
Normal file
4
ios/Nuvio/noop-file.swift
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
//
|
||||
// @generated
|
||||
// A blank Swift file must be created for native modules with Swift files to work correctly.
|
||||
//
|
||||
66
ios/Podfile
Normal file
66
ios/Podfile
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
|
||||
require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
|
||||
|
||||
require 'json'
|
||||
podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
|
||||
|
||||
ENV['RCT_NEW_ARCH_ENABLED'] = podfile_properties['newArchEnabled'] == 'true' ? '1' : '0'
|
||||
ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] = podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
|
||||
|
||||
platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1'
|
||||
install! 'cocoapods',
|
||||
:deterministic_uuids => false
|
||||
|
||||
prepare_react_native_project!
|
||||
|
||||
target 'Nuvio' do
|
||||
use_expo_modules!
|
||||
|
||||
if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'
|
||||
config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
|
||||
else
|
||||
config_command = [
|
||||
'node',
|
||||
'--no-warnings',
|
||||
'--eval',
|
||||
'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
|
||||
'react-native-config',
|
||||
'--json',
|
||||
'--platform',
|
||||
'ios'
|
||||
]
|
||||
end
|
||||
|
||||
config = use_native_modules!(config_command)
|
||||
|
||||
use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
|
||||
use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
|
||||
|
||||
use_react_native!(
|
||||
:path => config[:reactNativePath],
|
||||
:hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes',
|
||||
# An absolute path to your application root.
|
||||
:app_path => "#{Pod::Config.instance.installation_root}/..",
|
||||
:privacy_file_aggregation_enabled => podfile_properties['apple.privacyManifestAggregationEnabled'] != 'false',
|
||||
)
|
||||
|
||||
post_install do |installer|
|
||||
react_native_post_install(
|
||||
installer,
|
||||
config[:reactNativePath],
|
||||
:mac_catalyst_enabled => false,
|
||||
:ccache_enabled => podfile_properties['apple.ccacheEnabled'] == 'true',
|
||||
)
|
||||
|
||||
# This is necessary for Xcode 14, because it signs resource bundles by default
|
||||
# when building for devices.
|
||||
installer.target_installation_results.pod_target_installation_results
|
||||
.each do |pod_name, target_installation_result|
|
||||
target_installation_result.resource_bundle_targets.each do |resource_bundle_target|
|
||||
resource_bundle_target.build_configurations.each do |config|
|
||||
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
5
ios/Podfile.properties.json
Normal file
5
ios/Podfile.properties.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"expo.jsEngine": "hermes",
|
||||
"EX_DEV_CLIENT_NETWORK_INSPECTOR": "true",
|
||||
"newArchEnabled": "true"
|
||||
}
|
||||
59
package-lock.json
generated
59
package-lock.json
generated
|
|
@ -11,6 +11,7 @@
|
|||
"@expo/metro-runtime": "~4.0.1",
|
||||
"@expo/vector-icons": "^14.1.0",
|
||||
"@react-native-async-storage/async-storage": "1.23.1",
|
||||
"@react-native-community/blur": "^4.4.1",
|
||||
"@react-native-community/slider": "^4.5.6",
|
||||
"@react-navigation/bottom-tabs": "^7.3.10",
|
||||
"@react-navigation/native": "^7.1.6",
|
||||
|
|
@ -22,6 +23,8 @@
|
|||
"axios": "^1.8.4",
|
||||
"date-fns": "^4.1.0",
|
||||
"expo": "~52.0.43",
|
||||
"expo-blur": "^14.0.3",
|
||||
"expo-file-system": "^18.0.12",
|
||||
"expo-haptics": "~14.0.1",
|
||||
"expo-image": "~2.0.7",
|
||||
"expo-intent-launcher": "~12.0.2",
|
||||
|
|
@ -35,13 +38,15 @@
|
|||
"react-native": "0.76.9",
|
||||
"react-native-gesture-handler": "~2.20.2",
|
||||
"react-native-immersive-mode": "^2.0.2",
|
||||
"react-native-modal": "^14.0.0-rc.1",
|
||||
"react-native-paper": "^5.13.1",
|
||||
"react-native-reanimated": "~3.16.1",
|
||||
"react-native-safe-area-context": "4.12.0",
|
||||
"react-native-screens": "~4.4.0",
|
||||
"react-native-svg": "^15.8.0",
|
||||
"react-native-video": "^6.12.0",
|
||||
"react-native-web": "~0.19.13"
|
||||
"react-native-web": "~0.19.13",
|
||||
"subsrt": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
|
|
@ -3269,6 +3274,16 @@
|
|||
"react-native": "^0.0.0-0 || >=0.60 <1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native-community/blur": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/blur/-/blur-4.4.1.tgz",
|
||||
"integrity": "sha512-XBSsRiYxE/MOEln2ayunShfJtWztHwUxLFcSL20o+HNNRnuUDv+GXkF6FmM2zE8ZUfrnhQ/zeTqvnuDPGw6O8A==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native-community/slider": {
|
||||
"version": "4.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/slider/-/slider-4.5.6.tgz",
|
||||
|
|
@ -6572,6 +6587,17 @@
|
|||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-blur": {
|
||||
"version": "14.0.3",
|
||||
"resolved": "https://registry.npmjs.org/expo-blur/-/expo-blur-14.0.3.tgz",
|
||||
"integrity": "sha512-BL3xnqBJbYm3Hg9t/HjNjdeY7N/q8eK5tsLYxswWG1yElISWZmMvrXYekl7XaVCPfyFyz8vQeaxd7q74ZY3Wrw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"expo": "*",
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-constants": {
|
||||
"version": "17.0.8",
|
||||
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-17.0.8.tgz",
|
||||
|
|
@ -10522,6 +10548,15 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-animatable": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-animatable/-/react-native-animatable-1.4.0.tgz",
|
||||
"integrity": "sha512-DZwaDVWm2NBvBxf7I0wXKXLKb/TxDnkV53sWhCvei1pRyTX3MVFpkvdYBknNBqPrxYuAIlPxEp7gJOidIauUkw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-gesture-handler": {
|
||||
"version": "2.20.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.20.2.tgz",
|
||||
|
|
@ -10547,6 +10582,19 @@
|
|||
"react-native": ">=0.60.5"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-modal": {
|
||||
"version": "14.0.0-rc.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-modal/-/react-native-modal-14.0.0-rc.1.tgz",
|
||||
"integrity": "sha512-v5pvGyx1FlmBzdHyPqBsYQyS2mIJhVmuXyNo5EarIzxicKhuoul6XasXMviGcXboEUT0dTYWs88/VendojPiVw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-native-animatable": "1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": ">=0.70.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-paper": {
|
||||
"version": "5.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.13.1.tgz",
|
||||
|
|
@ -11885,6 +11933,15 @@
|
|||
"integrity": "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/subsrt": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/subsrt/-/subsrt-1.1.1.tgz",
|
||||
"integrity": "sha512-F15pSRRrPYnLjDKohcwkUUGhgHH+0IqpCoznMHMibZI9a2qN3ya/p3Xp/7zFOPvwez9b/qFjwtOnyS7f7d/MNw==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"subsrt": "bin/subsrt.js"
|
||||
}
|
||||
},
|
||||
"node_modules/sucrase": {
|
||||
"version": "3.35.0",
|
||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
|
||||
|
|
|
|||
|
|
@ -9,8 +9,10 @@
|
|||
"web": "expo start --web"
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/metro-runtime": "~4.0.1",
|
||||
"@expo/vector-icons": "^14.1.0",
|
||||
"@react-native-async-storage/async-storage": "1.23.1",
|
||||
"@react-native-community/blur": "^4.4.1",
|
||||
"@react-native-community/slider": "^4.5.6",
|
||||
"@react-navigation/bottom-tabs": "^7.3.10",
|
||||
"@react-navigation/native": "^7.1.6",
|
||||
|
|
@ -22,8 +24,11 @@
|
|||
"axios": "^1.8.4",
|
||||
"date-fns": "^4.1.0",
|
||||
"expo": "~52.0.43",
|
||||
"expo-blur": "^14.0.3",
|
||||
"expo-file-system": "^18.0.12",
|
||||
"expo-haptics": "~14.0.1",
|
||||
"expo-image": "~2.0.7",
|
||||
"expo-intent-launcher": "~12.0.2",
|
||||
"expo-linear-gradient": "~14.0.2",
|
||||
"expo-notifications": "~0.29.14",
|
||||
"expo-screen-orientation": "~8.0.4",
|
||||
|
|
@ -34,15 +39,15 @@
|
|||
"react-native": "0.76.9",
|
||||
"react-native-gesture-handler": "~2.20.2",
|
||||
"react-native-immersive-mode": "^2.0.2",
|
||||
"react-native-modal": "^14.0.0-rc.1",
|
||||
"react-native-paper": "^5.13.1",
|
||||
"react-native-reanimated": "~3.16.1",
|
||||
"react-native-safe-area-context": "4.12.0",
|
||||
"react-native-screens": "~4.4.0",
|
||||
"react-native-svg": "^15.8.0",
|
||||
"react-native-video": "^6.12.0",
|
||||
"expo-intent-launcher": "~12.0.2",
|
||||
"react-native-web": "~0.19.13",
|
||||
"@expo/metro-runtime": "~4.0.1"
|
||||
"subsrt": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
|
|
|
|||
|
|
@ -5,40 +5,49 @@ import { colors } from '../styles/colors';
|
|||
import { useNavigation } from '@react-navigation/native';
|
||||
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import type { RootStackParamList } from '../navigation/AppNavigator';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { BlurView as ExpoBlurView } from 'expo-blur';
|
||||
import { BlurView as CommunityBlurView } from '@react-native-community/blur';
|
||||
|
||||
type NavigationProp = NativeStackNavigationProp<RootStackParamList>;
|
||||
|
||||
export const NuvioHeader = () => {
|
||||
const navigation = useNavigation<NavigationProp>();
|
||||
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<LinearGradient
|
||||
colors={[
|
||||
'#000000',
|
||||
'rgba(0, 0, 0, 0.95)',
|
||||
'rgba(0, 0, 0, 0.8)',
|
||||
'rgba(0, 0, 0, 0.2)',
|
||||
'transparent'
|
||||
]}
|
||||
locations={[0, 0.3, 0.6, 0.8, 1]}
|
||||
style={styles.gradient}
|
||||
>
|
||||
<View style={styles.headerContainer}>
|
||||
{Platform.OS === 'ios' ? (
|
||||
<ExpoBlurView intensity={60} style={styles.blurOverlay} tint="dark" />
|
||||
) : (
|
||||
<View style={styles.androidBlurContainer}>
|
||||
<CommunityBlurView
|
||||
style={styles.androidBlur}
|
||||
blurType="dark"
|
||||
blurAmount={8}
|
||||
overlayColor="rgba(0,0,0,0.4)"
|
||||
reducedTransparencyFallbackColor="black"
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.contentContainer}>
|
||||
<Text style={styles.title}>NUVIO</Text>
|
||||
<View style={styles.titleContainer}>
|
||||
<Text style={styles.title}>NUVIO</Text>
|
||||
<View style={styles.titleAccent} />
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={styles.searchButton}
|
||||
onPress={() => navigation.navigate('Search')}
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
name="magnify"
|
||||
size={28}
|
||||
color={colors.white}
|
||||
/>
|
||||
<View style={styles.iconWrapper}>
|
||||
<MaterialCommunityIcons
|
||||
name="magnify"
|
||||
size={24}
|
||||
color={colors.white}
|
||||
/>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
@ -50,28 +59,71 @@ const styles = StyleSheet.create({
|
|||
left: 0,
|
||||
right: 0,
|
||||
zIndex: 10,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
gradient: {
|
||||
height: Platform.OS === 'ios' ? 100 : 90,
|
||||
paddingTop: Platform.OS === 'ios' ? 40 : 24,
|
||||
headerContainer: {
|
||||
height: Platform.OS === 'ios' ? 85 : 75,
|
||||
paddingTop: Platform.OS === 'ios' ? 35 : 20,
|
||||
backgroundColor: 'rgba(0,0,0,0.3)',
|
||||
},
|
||||
blurOverlay: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
zIndex: -1,
|
||||
},
|
||||
androidBlurContainer: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
zIndex: -1,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
androidBlur: {
|
||||
flex: 1,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
contentContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 24,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
titleContainer: {
|
||||
position: 'relative',
|
||||
},
|
||||
title: {
|
||||
fontSize: 32,
|
||||
fontWeight: '900',
|
||||
color: colors.white,
|
||||
letterSpacing: 1,
|
||||
letterSpacing: 2,
|
||||
fontFamily: Platform.OS === 'ios' ? 'System' : 'sans-serif-black',
|
||||
textTransform: 'uppercase',
|
||||
marginLeft: Platform.OS === 'ios' ? -4 : -8,
|
||||
textShadowColor: 'rgba(255, 255, 255, 0.2)',
|
||||
textShadowOffset: { width: 0, height: 1 },
|
||||
textShadowRadius: 4,
|
||||
},
|
||||
titleAccent: {
|
||||
position: 'absolute',
|
||||
bottom: -3,
|
||||
left: Platform.OS === 'ios' ? -2 : -6,
|
||||
width: 24,
|
||||
height: 2,
|
||||
backgroundColor: colors.primary || '#3D85C6',
|
||||
borderRadius: 1,
|
||||
},
|
||||
searchButton: {
|
||||
position: 'absolute',
|
||||
right: 16,
|
||||
padding: 8,
|
||||
},
|
||||
iconWrapper: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.08)',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgba(255, 255, 255, 0.1)',
|
||||
},
|
||||
});
|
||||
|
|
@ -557,6 +557,11 @@ const AppNavigator = () => {
|
|||
<Stack.Screen
|
||||
name="Streams"
|
||||
component={StreamsScreen as any}
|
||||
options={{
|
||||
headerShown: false,
|
||||
animation: Platform.OS === 'ios' ? 'slide_from_bottom' : 'fade_from_bottom',
|
||||
...(Platform.OS === 'ios' && { presentation: 'modal' }),
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Player"
|
||||
|
|
|
|||
|
|
@ -904,6 +904,7 @@ const styles = StyleSheet.create<any>({
|
|||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
position: 'relative',
|
||||
paddingTop: 56,
|
||||
},
|
||||
featuredBanner: {
|
||||
width: '100%',
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@ import { CastSection } from '../components/metadata/CastSection';
|
|||
import { SeriesContent } from '../components/metadata/SeriesContent';
|
||||
import { MovieContent } from '../components/metadata/MovieContent';
|
||||
import { MoreLikeThisSection } from '../components/metadata/MoreLikeThisSection';
|
||||
import AgeBadge from '../components/metadata/AgeBadge';
|
||||
import { StreamingContent } from '../services/catalogService';
|
||||
import { GroupedStreams } from '../types/streams';
|
||||
import { TMDBEpisode } from '../services/tmdbService';
|
||||
import { Cast } from '../types/cast';
|
||||
import { RouteParams, Episode } from '../types/metadata';
|
||||
import Animated, {
|
||||
useAnimatedStyle,
|
||||
|
|
@ -81,14 +84,10 @@ const MetadataScreen = () => {
|
|||
setMetadata,
|
||||
} = useMetadata({ id, type });
|
||||
|
||||
const [showFullDescription, setShowFullDescription] = useState(false);
|
||||
const contentRef = useRef<ScrollView>(null);
|
||||
const [lastScrollTop, setLastScrollTop] = useState(0);
|
||||
const [isFullDescriptionOpen, setIsFullDescriptionOpen] = useState(false);
|
||||
const fullDescriptionAnimation = useSharedValue(0);
|
||||
const [textTruncated, setTextTruncated] = useState(false);
|
||||
const descriptionHeight = useSharedValue(0);
|
||||
const fullTextHeight = useSharedValue(0);
|
||||
|
||||
// Animation values
|
||||
const screenScale = useSharedValue(0.8);
|
||||
|
|
@ -112,7 +111,7 @@ const MetadataScreen = () => {
|
|||
const watchProgressOpacity = useSharedValue(0);
|
||||
|
||||
// Debug log for route params
|
||||
logger.log('[MetadataScreen] Component mounted with route params:', { id, type, episodeId });
|
||||
// logger.log('[MetadataScreen] Component mounted with route params:', { id, type, episodeId });
|
||||
|
||||
// Function to get episode details from episodeId
|
||||
const getEpisodeDetails = useCallback((episodeId: string) => {
|
||||
|
|
@ -491,45 +490,6 @@ const MetadataScreen = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const handleOpenFullDescription = useCallback(() => {
|
||||
setIsFullDescriptionOpen(true);
|
||||
fullDescriptionAnimation.value = withTiming(1, {
|
||||
duration: 300,
|
||||
easing: Easing.bezier(0.33, 0.01, 0, 1),
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleCloseFullDescription = useCallback(() => {
|
||||
fullDescriptionAnimation.value = withTiming(0, {
|
||||
duration: 250,
|
||||
easing: Easing.bezier(0.33, 0.01, 0, 1),
|
||||
}, () => {
|
||||
runOnJS(setIsFullDescriptionOpen)(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const fullDescriptionStyle = useAnimatedStyle(() => {
|
||||
return {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: colors.darkBackground,
|
||||
opacity: fullDescriptionAnimation.value,
|
||||
transform: [
|
||||
{
|
||||
translateY: interpolate(
|
||||
fullDescriptionAnimation.value,
|
||||
[0, 1],
|
||||
[height, 0],
|
||||
Extrapolate.CLAMP
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
// Animated styles
|
||||
const containerAnimatedStyle = useAnimatedStyle(() => ({
|
||||
flex: 1,
|
||||
|
|
@ -603,7 +563,7 @@ const MetadataScreen = () => {
|
|||
|
||||
if (tmdbId) {
|
||||
const credits = await tmdb.getCredits(tmdbId, type);
|
||||
logger.log("Credits data structure:", JSON.stringify(credits).substring(0, 300));
|
||||
// logger.log("Credits data structure:", JSON.stringify(credits).substring(0, 300));
|
||||
|
||||
// Extract directors for movies
|
||||
if (type === 'movie' && credits.crew) {
|
||||
|
|
@ -617,7 +577,7 @@ const MetadataScreen = () => {
|
|||
...metadata,
|
||||
directors
|
||||
});
|
||||
logger.log("Updated directors:", directors);
|
||||
// logger.log("Updated directors:", directors);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -638,7 +598,7 @@ const MetadataScreen = () => {
|
|||
...metadata,
|
||||
creators: creators.slice(0, 3) // Limit to first 3 creators
|
||||
});
|
||||
logger.log("Updated creators:", creators.slice(0, 3));
|
||||
// logger.log("Updated creators:", creators.slice(0, 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -667,40 +627,6 @@ const MetadataScreen = () => {
|
|||
navigation.goBack();
|
||||
}, [navigation]);
|
||||
|
||||
const descriptionAnimatedStyle = useAnimatedStyle(() => ({
|
||||
height: descriptionHeight.value,
|
||||
opacity: interpolate(
|
||||
descriptionHeight.value,
|
||||
[0, fullTextHeight.value],
|
||||
[0, 1],
|
||||
Extrapolate.CLAMP
|
||||
)
|
||||
}));
|
||||
|
||||
// Function to handle text layout and store full height
|
||||
const handleTextLayout = ({ nativeEvent: { lines } }: { nativeEvent: { lines: any[] } }) => {
|
||||
if (!showFullDescription) {
|
||||
setTextTruncated(lines.length > 3);
|
||||
// Calculate height for 3 lines (24 is the lineHeight)
|
||||
descriptionHeight.value = 3 * 24;
|
||||
}
|
||||
// Store full text height
|
||||
fullTextHeight.value = lines.length * 24;
|
||||
};
|
||||
|
||||
// Function to toggle description expansion with animation
|
||||
const toggleDescription = () => {
|
||||
setShowFullDescription(!showFullDescription);
|
||||
descriptionHeight.value = withSpring(
|
||||
!showFullDescription ? fullTextHeight.value : 3 * 24,
|
||||
{
|
||||
damping: 15,
|
||||
stiffness: 100,
|
||||
mass: 0.8
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<SafeAreaView
|
||||
|
|
@ -861,7 +787,7 @@ const MetadataScreen = () => {
|
|||
<Text style={styles.metaText}>{metadata.runtime}</Text>
|
||||
)}
|
||||
{metadata.certification && (
|
||||
<AgeBadge rating={metadata.certification} />
|
||||
<Text style={styles.metaText}>{metadata.certification}</Text>
|
||||
)}
|
||||
{metadata.imdbRating && (
|
||||
<View style={styles.ratingContainer}>
|
||||
|
|
@ -900,29 +826,9 @@ const MetadataScreen = () => {
|
|||
{/* Description */}
|
||||
{metadata.description && (
|
||||
<View style={styles.descriptionContainer}>
|
||||
<Animated.View style={descriptionAnimatedStyle}>
|
||||
<Text
|
||||
style={styles.description}
|
||||
onTextLayout={handleTextLayout}
|
||||
>
|
||||
<Text style={styles.description}>
|
||||
{`${metadata.description}`}
|
||||
</Text>
|
||||
</Animated.View>
|
||||
{textTruncated && (
|
||||
<TouchableOpacity
|
||||
onPress={toggleDescription}
|
||||
style={styles.showMoreButton}
|
||||
>
|
||||
<Text style={styles.showMoreText}>
|
||||
{showFullDescription ? 'See less' : 'See more'}
|
||||
</Text>
|
||||
<MaterialIcons
|
||||
name={showFullDescription ? 'keyboard-arrow-up' : 'keyboard-arrow-down'}
|
||||
size={20}
|
||||
color={colors.textMuted}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
|
||||
|
|
@ -957,31 +863,6 @@ const MetadataScreen = () => {
|
|||
)}
|
||||
</Animated.View>
|
||||
</ScrollView>
|
||||
|
||||
{/* Full Description Modal */}
|
||||
{isFullDescriptionOpen && (
|
||||
<Animated.View style={fullDescriptionStyle}>
|
||||
<SafeAreaView style={styles.fullDescriptionContainer}>
|
||||
<View style={styles.fullDescriptionHeader}>
|
||||
<TouchableOpacity
|
||||
onPress={handleCloseFullDescription}
|
||||
style={styles.fullDescriptionCloseButton}
|
||||
>
|
||||
<MaterialIcons name="close" size={24} color={colors.text} />
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.fullDescriptionTitle}>About</Text>
|
||||
</View>
|
||||
<ScrollView
|
||||
style={styles.fullDescriptionContent}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
<Text style={styles.fullDescriptionText}>
|
||||
{metadata?.description}
|
||||
</Text>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
</Animated.View>
|
||||
)}
|
||||
</Animated.View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -14,12 +14,16 @@ import * as ScreenOrientation from 'expo-screen-orientation';
|
|||
import { useRoute, useNavigation, RouteProp } from '@react-navigation/native';
|
||||
import { RootStackParamList } from '../navigation/AppNavigator';
|
||||
import { storageService } from '../services/storageService';
|
||||
// Import stremioService for subtitles
|
||||
import { stremioService, Subtitle } from '../services/stremioService';
|
||||
// Add throttle/debounce imports
|
||||
import { debounce } from 'lodash';
|
||||
import { logger } from '../utils/logger';
|
||||
// Import FileSystem
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
|
||||
// Define the TrackPreferenceType for audio/text tracks
|
||||
type TrackPreferenceType = 'system' | 'disabled' | 'title' | 'language' | 'index';
|
||||
type TrackPreferenceType = 'system' | 'disabled' | 'title' | 'language' | 'index' | 'uri';
|
||||
|
||||
// Define the SelectedTrack type for audio/text tracks
|
||||
interface SelectedTrack {
|
||||
|
|
@ -87,20 +91,22 @@ const VideoPlayer = () => {
|
|||
const developmentTestUrl = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";
|
||||
const uri = __DEV__ && (!routeUri || routeUri.trim() === '') ? developmentTestUrl : routeUri;
|
||||
|
||||
// Log received props for debugging
|
||||
logger.log("VideoPlayer received route params:", {
|
||||
uri,
|
||||
title,
|
||||
season,
|
||||
episode,
|
||||
episodeTitle,
|
||||
quality,
|
||||
year,
|
||||
streamProvider,
|
||||
id,
|
||||
type,
|
||||
episodeId
|
||||
});
|
||||
// Log received props for debugging (only once)
|
||||
useEffect(() => {
|
||||
logger.log("VideoPlayer received route params:", {
|
||||
uri,
|
||||
title,
|
||||
season,
|
||||
episode,
|
||||
episodeTitle,
|
||||
quality,
|
||||
year,
|
||||
streamProvider,
|
||||
id,
|
||||
type,
|
||||
episodeId
|
||||
});
|
||||
}, []);
|
||||
|
||||
// Validate URI
|
||||
useEffect(() => {
|
||||
|
|
@ -141,9 +147,6 @@ const VideoPlayer = () => {
|
|||
// Add timer ref for auto-hiding controls
|
||||
const hideControlsTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
// Add a new state variable to track buffering progress
|
||||
const [bufferedProgress, setBufferedProgress] = useState(0);
|
||||
|
||||
// Add state for tracking if initial seek is done
|
||||
const [initialSeekDone, setInitialSeekDone] = useState(false);
|
||||
const lastProgressUpdate = useRef<number>(0);
|
||||
|
|
@ -154,6 +157,12 @@ const VideoPlayer = () => {
|
|||
// Add last onProgress update time to throttle updates
|
||||
const lastProgressUpdateTime = useRef(0);
|
||||
|
||||
// Add state for OpenSubtitles
|
||||
const [subtitles, setSubtitles] = useState<Subtitle[]>([]);
|
||||
const [isLoadingSubtitles, setIsLoadingSubtitles] = useState(false);
|
||||
// Add state to track the index of the active URI subtitle
|
||||
const [selectedUriTrackIndex, setSelectedUriTrackIndex] = useState<number | null>(null);
|
||||
|
||||
// Load initial progress when component mounts
|
||||
useEffect(() => {
|
||||
const loadProgress = async () => {
|
||||
|
|
@ -230,6 +239,11 @@ const VideoPlayer = () => {
|
|||
const initialTimer = setTimeout(() => {
|
||||
startHideControlsTimer();
|
||||
}, 1500);
|
||||
|
||||
// Load subtitles if id and type are available
|
||||
if (id && type) {
|
||||
loadSubtitles();
|
||||
}
|
||||
|
||||
// Disable immersive mode when component unmounts
|
||||
return () => {
|
||||
|
|
@ -290,12 +304,6 @@ const VideoPlayer = () => {
|
|||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (duration > 0 && currentTime > 0) {
|
||||
setSliderValue(currentTime);
|
||||
}
|
||||
}, [duration, currentTime]);
|
||||
|
||||
const formatTime = (seconds: number) => {
|
||||
if (isNaN(seconds)) return '0:00';
|
||||
|
||||
|
|
@ -390,8 +398,8 @@ const VideoPlayer = () => {
|
|||
|
||||
// Modify slider value change handler for community slider
|
||||
const onSliderValueChange = (value: number) => {
|
||||
// Only update the slider value, don't update currentTime here
|
||||
setSliderValue(value);
|
||||
setCurrentTime(value);
|
||||
};
|
||||
|
||||
const onSlidingComplete = (value: number) => {
|
||||
|
|
@ -401,17 +409,10 @@ const VideoPlayer = () => {
|
|||
|
||||
// Update UI immediately for responsive feel
|
||||
setCurrentTime(newTime);
|
||||
setSliderValue(newTime);
|
||||
|
||||
// Seek to the new position
|
||||
videoRef.current.seek(newTime);
|
||||
|
||||
// Reset buffered progress indicator if seeking forward
|
||||
const isFastForward = newTime > currentTime;
|
||||
if (isFastForward) {
|
||||
setBufferedProgress(newTime);
|
||||
}
|
||||
|
||||
// Reset timer for auto-hiding controls
|
||||
startHideControlsTimer();
|
||||
|
||||
|
|
@ -459,12 +460,6 @@ const VideoPlayer = () => {
|
|||
setCurrentTime(newTime);
|
||||
setSliderValue(newTime);
|
||||
}
|
||||
|
||||
// Update buffered progress more efficiently
|
||||
if (data.playableDuration) {
|
||||
// Use a functional update to ensure we're working with the latest state
|
||||
setBufferedProgress(prev => Math.max(prev, data.playableDuration || 0));
|
||||
}
|
||||
};
|
||||
|
||||
const onLoad = (data: { duration: number }) => {
|
||||
|
|
@ -480,7 +475,13 @@ const VideoPlayer = () => {
|
|||
|
||||
const onTextTracks = (e: Readonly<{ textTracks: TextTrack[] }>) => {
|
||||
logger.log("Detected Text Tracks:", e.textTracks);
|
||||
setTextTracks(e.textTracks || []);
|
||||
// Only set built-in tracks, preserve OpenSubtitles tracks
|
||||
const builtInTracks = e.textTracks || [];
|
||||
setTextTracks(prevTracks => {
|
||||
// Filter out existing built-in tracks (those with index < 100)
|
||||
const openSubtitlesTracks = prevTracks.filter(t => t.index >= 100);
|
||||
return [...builtInTracks, ...openSubtitlesTracks];
|
||||
});
|
||||
};
|
||||
|
||||
// Toggle through aspect ratio modes
|
||||
|
|
@ -626,8 +627,67 @@ const VideoPlayer = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const selectSubtitleTrack = (track: SelectedTrack | null) => {
|
||||
setSelectedTextTrack(track);
|
||||
const selectSubtitleTrack = async (track: SelectedTrack | null) => {
|
||||
// Reset previously selected external subtitle URI if any
|
||||
// Also reset the tracked index
|
||||
if (selectedTextTrack?.type === 'uri') {
|
||||
setSelectedTextTrack(null); // Clear previous selection
|
||||
setSelectedUriTrackIndex(null);
|
||||
}
|
||||
|
||||
// If selecting "Off"
|
||||
if (!track || track.type === 'disabled') {
|
||||
setSelectedTextTrack({ type: 'disabled' });
|
||||
setSelectedUriTrackIndex(null);
|
||||
}
|
||||
// If selecting a built-in track
|
||||
else if (track.type === 'index' && typeof track.value === 'number' && track.value < 100) {
|
||||
setSelectedTextTrack(track);
|
||||
setSelectedUriTrackIndex(null);
|
||||
}
|
||||
// If selecting an OpenSubtitles track (index >= 100)
|
||||
else if (track.type === 'index' && typeof track.value === 'number' && track.value >= 100) {
|
||||
const subtitleIndex = track.value - 100;
|
||||
const subtitle = subtitles[subtitleIndex];
|
||||
const originalTrackIndex = track.value; // Store the original index (>= 100)
|
||||
|
||||
if (subtitle && subtitle.url) {
|
||||
try {
|
||||
logger.log(`Attempting to download subtitle from ${subtitle.url}`);
|
||||
const localUri = `${FileSystem.cacheDirectory}${subtitle.id || Date.now()}.srt`;
|
||||
|
||||
// Download the subtitle file
|
||||
const downloadResult = await FileSystem.downloadAsync(subtitle.url, localUri);
|
||||
|
||||
if (downloadResult.status === 200) {
|
||||
logger.log(`Subtitle downloaded successfully to ${downloadResult.uri}`);
|
||||
// Set the selected track to the local file URI
|
||||
setSelectedTextTrack({ type: 'uri', value: downloadResult.uri });
|
||||
// Set the index of the active URI track
|
||||
setSelectedUriTrackIndex(originalTrackIndex);
|
||||
} else {
|
||||
logger.error(`Failed to download subtitle: Status ${downloadResult.status}`);
|
||||
setSelectedTextTrack({ type: 'disabled' }); // Fallback to disabled
|
||||
setSelectedUriTrackIndex(null);
|
||||
alert('Failed to download subtitle.');
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error downloading subtitle:', error);
|
||||
setSelectedTextTrack({ type: 'disabled' }); // Fallback to disabled
|
||||
setSelectedUriTrackIndex(null);
|
||||
alert('Error downloading subtitle.');
|
||||
}
|
||||
} else {
|
||||
logger.warn('Selected OpenSubtitle track has no URL');
|
||||
setSelectedTextTrack({ type: 'disabled' });
|
||||
setSelectedUriTrackIndex(null);
|
||||
}
|
||||
} else {
|
||||
// Handle any other cases or default
|
||||
setSelectedTextTrack(track);
|
||||
setSelectedUriTrackIndex(null); // Ensure reset for non-handled types
|
||||
}
|
||||
|
||||
// Hide the subtitle menu with animation
|
||||
Animated.timing(subtitleSlideAnim, {
|
||||
toValue: 400,
|
||||
|
|
@ -638,6 +698,40 @@ const VideoPlayer = () => {
|
|||
});
|
||||
};
|
||||
|
||||
// Function to load subtitles from OpenSubtitles v3 addon
|
||||
const loadSubtitles = async () => {
|
||||
if (!id || !type) return;
|
||||
|
||||
try {
|
||||
setIsLoadingSubtitles(true);
|
||||
logger.log(`Loading subtitles for ${type} with id ${id}${episodeId ? ` and episodeId ${episodeId}` : ''}`);
|
||||
|
||||
const subtitlesList = await stremioService.getSubtitles(type, id, episodeId);
|
||||
|
||||
if (subtitlesList && subtitlesList.length > 0) {
|
||||
logger.log(`Loaded ${subtitlesList.length} subtitles`);
|
||||
setSubtitles(subtitlesList);
|
||||
|
||||
// Convert OpenSubtitles subtitles to the format expected by react-native-video
|
||||
const convertedTracks: TextTrack[] = subtitlesList.map((sub, index) => ({
|
||||
index: 100 + index, // Use high index values to avoid conflicts
|
||||
title: sub.id,
|
||||
language: sub.lang,
|
||||
type: 'text'
|
||||
}));
|
||||
|
||||
// Combine with existing text tracks
|
||||
setTextTracks(prevTracks => [...prevTracks, ...convertedTracks]);
|
||||
} else {
|
||||
logger.log('No subtitles found');
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error loading subtitles:', error);
|
||||
} finally {
|
||||
setIsLoadingSubtitles(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<TouchableOpacity
|
||||
|
|
@ -755,17 +849,6 @@ const VideoPlayer = () => {
|
|||
<View style={styles.bottomControls}>
|
||||
{/* Slider - replaced with community slider */}
|
||||
<View style={styles.sliderContainer}>
|
||||
{/* Buffer indicator - only render if needed */}
|
||||
{bufferedProgress > 0 && (
|
||||
<View style={[
|
||||
styles.bufferIndicator,
|
||||
{
|
||||
width: `${Math.min((bufferedProgress / (duration || 1)) * 100, 100)}%`
|
||||
}
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
|
||||
<View style={styles.sliderRow}>
|
||||
<Text style={styles.currentTime}>
|
||||
{formatTime(currentTime)}
|
||||
|
|
@ -831,7 +914,9 @@ const VideoPlayer = () => {
|
|||
<Text style={[styles.bottomButtonText, textTracks.length === 0 && {color: 'grey'}]}>
|
||||
{selectedTextTrack?.type === 'disabled'
|
||||
? 'Subtitles (Off)'
|
||||
: `Subtitles (${textTracks.find(t => t.index === selectedTextTrack?.value)?.language?.toUpperCase() || 'On'})`}
|
||||
: `Subtitles (${(selectedTextTrack?.type === 'uri' && selectedUriTrackIndex !== null)
|
||||
? textTracks.find(t => t.index === selectedUriTrackIndex)?.language?.toUpperCase() || 'On'
|
||||
: textTracks.find(t => t.index === selectedTextTrack?.value)?.language?.toUpperCase() || 'On'})`}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
|
@ -928,21 +1013,38 @@ const VideoPlayer = () => {
|
|||
key={track.index}
|
||||
style={[
|
||||
styles.optionItem,
|
||||
selectedTextTrack?.type === 'index' && selectedTextTrack?.value === track.index && styles.selectedOption
|
||||
// Updated highlighting logic:
|
||||
(selectedTextTrack?.type === 'index' && selectedTextTrack?.value === track.index) ||
|
||||
(selectedUriTrackIndex === track.index) // Highlight if this URI track is active
|
||||
? styles.selectedOption
|
||||
: null
|
||||
]}
|
||||
onPress={() => selectSubtitleTrack({ type: 'index', value: track.index })}
|
||||
>
|
||||
<Ionicons
|
||||
name={selectedTextTrack?.type === 'index' && selectedTextTrack?.value === track.index ? "radio-button-on" : "radio-button-off"}
|
||||
// Updated icon logic:
|
||||
name={((selectedTextTrack?.type === 'index' && selectedTextTrack?.value === track.index) ||
|
||||
(selectedUriTrackIndex === track.index))
|
||||
? "radio-button-on"
|
||||
: "radio-button-off"}
|
||||
size={18}
|
||||
color={selectedTextTrack?.type === 'index' && selectedTextTrack?.value === track.index ? "#E50914" : "white"}
|
||||
// Updated color logic:
|
||||
color={((selectedTextTrack?.type === 'index' && selectedTextTrack?.value === track.index) ||
|
||||
(selectedUriTrackIndex === track.index))
|
||||
? "#E50914"
|
||||
: "white"}
|
||||
style={{ marginRight: 10 }}
|
||||
/>
|
||||
<Text style={[
|
||||
styles.optionItemText,
|
||||
selectedTextTrack?.type === 'index' && selectedTextTrack?.value === track.index && styles.selectedOptionText
|
||||
// Updated text style logic:
|
||||
((selectedTextTrack?.type === 'index' && selectedTextTrack?.value === track.index) ||
|
||||
(selectedUriTrackIndex === track.index))
|
||||
? styles.selectedOptionText
|
||||
: null
|
||||
]}>
|
||||
{track.language ? track.language.toUpperCase() : (track.title || `Track ${track.index + 1}`)}
|
||||
{track.index >= 100 && ' (OpenSubtitles)'}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
|
|
@ -1071,16 +1173,6 @@ const styles = StyleSheet.create({
|
|||
alignItems: 'center',
|
||||
width: '100%',
|
||||
},
|
||||
bufferIndicator: {
|
||||
position: 'absolute',
|
||||
height: 4,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.25)',
|
||||
top: 14, // Position to align with the slider track
|
||||
left: 24, // Account for the currentTime text
|
||||
right: 24, // Account for the duration text
|
||||
zIndex: 1,
|
||||
borderRadius: 2,
|
||||
},
|
||||
slider: {
|
||||
flex: 1,
|
||||
height: 40,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ class CacheService {
|
|||
private cache: Map<string, CachedContent> = new Map();
|
||||
private metadataScreenCache: Map<string, any> = new Map();
|
||||
private readonly MAX_METADATA_SCREENS = 5;
|
||||
private readonly MAX_CACHE_SIZE = 100; // Max size for the main cache
|
||||
private readonly CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours TTL for main cache items
|
||||
|
||||
private constructor() {
|
||||
// Initialize any other necessary properties
|
||||
|
|
@ -33,128 +35,227 @@ class CacheService {
|
|||
return `${type}:${id}`;
|
||||
}
|
||||
|
||||
// Helper to ensure the main cache does not exceed its size limit
|
||||
private ensureCacheLimit(): void {
|
||||
if (this.cache.size >= this.MAX_CACHE_SIZE) {
|
||||
// Remove the least recently used item (first key in Map iteration order)
|
||||
const oldestKey = this.cache.keys().next().value;
|
||||
if (oldestKey) {
|
||||
this.cache.delete(oldestKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to mark an item as recently used (by deleting and re-inserting)
|
||||
// Also ensures the timestamp is updated.
|
||||
private touch(key: string, existingData: CachedContent): void {
|
||||
this.cache.delete(key);
|
||||
this.cache.set(key, { ...existingData, timestamp: Date.now() });
|
||||
}
|
||||
|
||||
public setMetadata(id: string, type: string, metadata: StreamingContent): void {
|
||||
const key = this.getCacheKey(id, type);
|
||||
const existing = this.cache.get(key);
|
||||
this.cache.set(key, {
|
||||
...(existing || {}),
|
||||
metadata,
|
||||
timestamp: Date.now()
|
||||
} as CachedContent);
|
||||
let existing = this.cache.get(key);
|
||||
|
||||
if (existing) {
|
||||
// Update existing entry and mark as recent
|
||||
existing = { ...existing, metadata, timestamp: Date.now() };
|
||||
this.touch(key, existing);
|
||||
} else {
|
||||
// Adding a new entry, first check limit
|
||||
this.ensureCacheLimit();
|
||||
// Add the new entry
|
||||
this.cache.set(key, {
|
||||
metadata,
|
||||
timestamp: Date.now()
|
||||
} as CachedContent);
|
||||
}
|
||||
}
|
||||
|
||||
public setStreams(id: string, type: string, streams: GroupedStreams): void {
|
||||
const key = this.getCacheKey(id, type);
|
||||
const existing = this.cache.get(key);
|
||||
if (!existing?.metadata) return;
|
||||
|
||||
this.cache.set(key, {
|
||||
// Can only set streams if metadata already exists in cache
|
||||
if (!existing?.metadata) return;
|
||||
|
||||
const updatedData = {
|
||||
...existing,
|
||||
streams,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
timestamp: Date.now() // Update timestamp on modification
|
||||
};
|
||||
this.touch(key, updatedData); // Mark as recently used
|
||||
}
|
||||
|
||||
public setEpisodes(id: string, type: string, episodes: TMDBEpisode[]): void {
|
||||
const key = this.getCacheKey(id, type);
|
||||
const existing = this.cache.get(key);
|
||||
if (!existing?.metadata) return;
|
||||
|
||||
this.cache.set(key, {
|
||||
|
||||
const updatedData = {
|
||||
...existing,
|
||||
episodes,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
};
|
||||
this.touch(key, updatedData);
|
||||
}
|
||||
|
||||
public setCast(id: string, type: string, cast: Cast[]): void {
|
||||
const key = this.getCacheKey(id, type);
|
||||
const existing = this.cache.get(key);
|
||||
if (!existing?.metadata) return;
|
||||
|
||||
this.cache.set(key, {
|
||||
|
||||
const updatedData = {
|
||||
...existing,
|
||||
cast,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
};
|
||||
this.touch(key, updatedData);
|
||||
}
|
||||
|
||||
public setEpisodeStreams(id: string, type: string, episodeId: string, streams: GroupedStreams): void {
|
||||
const key = this.getCacheKey(id, type);
|
||||
const existing = this.cache.get(key);
|
||||
if (!existing?.metadata) return;
|
||||
|
||||
this.cache.set(key, {
|
||||
|
||||
const updatedData = {
|
||||
...existing,
|
||||
episodeStreams: {
|
||||
...(existing.episodeStreams || {}),
|
||||
[episodeId]: streams
|
||||
},
|
||||
timestamp: Date.now()
|
||||
});
|
||||
};
|
||||
this.touch(key, updatedData);
|
||||
}
|
||||
|
||||
// --- Getters for the main cache ---
|
||||
|
||||
public getMetadata(id: string, type: string): StreamingContent | null {
|
||||
const key = this.getCacheKey(id, type);
|
||||
return this.cache.get(key)?.metadata || null;
|
||||
const data = this.cache.get(key);
|
||||
if (data) {
|
||||
// Check for expiration first
|
||||
if (Date.now() - data.timestamp > this.CACHE_TTL_MS) {
|
||||
this.cache.delete(key); // Remove expired item
|
||||
return null;
|
||||
}
|
||||
// Not expired, proceed with LRU update
|
||||
this.touch(key, data); // Mark as recently used on access
|
||||
return data.metadata;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public getStreams(id: string, type: string): GroupedStreams | null {
|
||||
const key = this.getCacheKey(id, type);
|
||||
return this.cache.get(key)?.streams || null;
|
||||
const data = this.cache.get(key);
|
||||
if (data) {
|
||||
// Check for expiration first
|
||||
if (Date.now() - data.timestamp > this.CACHE_TTL_MS) {
|
||||
this.cache.delete(key); // Remove expired item
|
||||
return null;
|
||||
}
|
||||
// Not expired, proceed with LRU update
|
||||
this.touch(key, data); // Mark as recently used on access
|
||||
return data.streams || null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public getEpisodes(id: string, type: string): TMDBEpisode[] | null {
|
||||
const key = this.getCacheKey(id, type);
|
||||
return this.cache.get(key)?.episodes || null;
|
||||
const data = this.cache.get(key);
|
||||
if (data) {
|
||||
// Check for expiration first
|
||||
if (Date.now() - data.timestamp > this.CACHE_TTL_MS) {
|
||||
this.cache.delete(key); // Remove expired item
|
||||
return null;
|
||||
}
|
||||
// Not expired, proceed with LRU update
|
||||
this.touch(key, data); // Mark as recently used on access
|
||||
return data.episodes || null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public getCast(id: string, type: string): Cast[] | null {
|
||||
const key = this.getCacheKey(id, type);
|
||||
return this.cache.get(key)?.cast || null;
|
||||
const data = this.cache.get(key);
|
||||
if (data) {
|
||||
// Check for expiration first
|
||||
if (Date.now() - data.timestamp > this.CACHE_TTL_MS) {
|
||||
this.cache.delete(key); // Remove expired item
|
||||
return null;
|
||||
}
|
||||
// Not expired, proceed with LRU update
|
||||
this.touch(key, data); // Mark as recently used on access
|
||||
return data.cast || null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public getEpisodeStreams(id: string, type: string, episodeId: string): GroupedStreams | null {
|
||||
const key = this.getCacheKey(id, type);
|
||||
return this.cache.get(key)?.episodeStreams?.[episodeId] || null;
|
||||
const data = this.cache.get(key);
|
||||
if (data) {
|
||||
// Check for expiration first
|
||||
if (Date.now() - data.timestamp > this.CACHE_TTL_MS) {
|
||||
this.cache.delete(key); // Remove expired item
|
||||
return null;
|
||||
}
|
||||
// Not expired, check if episode stream exists and proceed with LRU update
|
||||
if (data.episodeStreams?.[episodeId]) {
|
||||
this.touch(key, data); // Mark as recently used on access
|
||||
return data.episodeStreams[episodeId];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// --- Cache utility methods ---
|
||||
|
||||
public clearCache(): void {
|
||||
this.cache.clear();
|
||||
}
|
||||
|
||||
// Checks existence without affecting LRU order
|
||||
public isCached(id: string, type: string): boolean {
|
||||
const key = this.getCacheKey(id, type);
|
||||
return this.cache.has(key);
|
||||
}
|
||||
|
||||
// --- Metadata Screen Cache (Separate LRU logic) ---
|
||||
|
||||
public cacheMetadataScreen(id: string, type: string, data: any) {
|
||||
if (!id || !type) return;
|
||||
|
||||
|
||||
const key = `${type}:${id}`;
|
||||
|
||||
// If this item is already in cache, just update it
|
||||
|
||||
// If this item is already in cache, delete to re-insert at the end (most recent)
|
||||
if (this.metadataScreenCache.has(key)) {
|
||||
this.metadataScreenCache.delete(key);
|
||||
this.metadataScreenCache.set(key, data);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we've reached the limit, remove the oldest item
|
||||
if (this.metadataScreenCache.size >= this.MAX_METADATA_SCREENS) {
|
||||
// If we've reached the limit, remove the oldest item (first key)
|
||||
else if (this.metadataScreenCache.size >= this.MAX_METADATA_SCREENS) {
|
||||
const firstKey = this.metadataScreenCache.keys().next().value;
|
||||
if (firstKey) {
|
||||
this.metadataScreenCache.delete(firstKey);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new item
|
||||
// Add the new/updated item (makes it the most recent)
|
||||
this.metadataScreenCache.set(key, data);
|
||||
}
|
||||
|
||||
public getMetadataScreen(id: string, type: string) {
|
||||
const key = `${type}:${id}`;
|
||||
return this.metadataScreenCache.get(key);
|
||||
const data = this.metadataScreenCache.get(key);
|
||||
// If found, mark as recently used by re-inserting
|
||||
if (data) {
|
||||
this.metadataScreenCache.delete(key);
|
||||
this.metadataScreenCache.set(key, data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public clearMetadataScreenCache() {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,15 @@ export interface Meta {
|
|||
certification?: string;
|
||||
}
|
||||
|
||||
export interface Subtitle {
|
||||
id: string;
|
||||
url: string;
|
||||
lang: string;
|
||||
fps?: number;
|
||||
addon?: string;
|
||||
addonName?: string;
|
||||
}
|
||||
|
||||
export interface Stream {
|
||||
name?: string;
|
||||
title?: string;
|
||||
|
|
@ -48,6 +57,12 @@ export interface StreamResponse {
|
|||
addonName: string;
|
||||
}
|
||||
|
||||
export interface SubtitleResponse {
|
||||
subtitles: Subtitle[];
|
||||
addon: string;
|
||||
addonName: string;
|
||||
}
|
||||
|
||||
// Modify the callback signature to include addon ID
|
||||
interface StreamCallback {
|
||||
(streams: Stream[] | null, addonId: string | null, addonName: string | null, error: Error | null): void;
|
||||
|
|
@ -124,8 +139,8 @@ class StremioService {
|
|||
private installedAddons: Map<string, Manifest> = new Map();
|
||||
private readonly STORAGE_KEY = 'stremio-addons';
|
||||
private readonly DEFAULT_ADDONS = [
|
||||
'https://v3-cinemeta.strem.io/manifest.json'
|
||||
|
||||
'https://v3-cinemeta.strem.io/manifest.json',
|
||||
'https://opensubtitles-v3.strem.io/manifest.json'
|
||||
];
|
||||
private readonly MAX_CONCURRENT_REQUESTS = 3;
|
||||
private readonly DEFAULT_PAGE_SIZE = 50;
|
||||
|
|
@ -720,6 +735,54 @@ class StremioService {
|
|||
items: items.slice(0, limit)
|
||||
};
|
||||
}
|
||||
|
||||
async getSubtitles(type: string, id: string, videoId?: string): Promise<Subtitle[]> {
|
||||
await this.ensureInitialized();
|
||||
|
||||
// Find the OpenSubtitles v3 addon
|
||||
const openSubtitlesAddon = this.getInstalledAddons().find(
|
||||
addon => addon.id === 'org.stremio.opensubtitlesv3'
|
||||
);
|
||||
|
||||
if (!openSubtitlesAddon) {
|
||||
logger.warn('OpenSubtitles v3 addon not found');
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const baseUrl = this.getAddonBaseURL(openSubtitlesAddon.url || '');
|
||||
|
||||
// Construct the query URL with the correct format
|
||||
// For series episodes, use the videoId directly which includes series ID + episode info
|
||||
let url = '';
|
||||
if (type === 'series' && videoId) {
|
||||
// For series, the format should be /subtitles/series/tt12345:1:2.json
|
||||
url = `${baseUrl}/subtitles/${type}/${videoId}.json`;
|
||||
} else {
|
||||
// For movies, the format is /subtitles/movie/tt12345.json
|
||||
url = `${baseUrl}/subtitles/${type}/${id}.json`;
|
||||
}
|
||||
|
||||
logger.log(`Fetching subtitles from: ${url}`);
|
||||
|
||||
const response = await this.retryRequest(async () => {
|
||||
return await axios.get(url, { timeout: 10000 });
|
||||
});
|
||||
|
||||
if (response.data && response.data.subtitles) {
|
||||
// Process and return the subtitles
|
||||
return response.data.subtitles.map((sub: any) => ({
|
||||
...sub,
|
||||
addon: openSubtitlesAddon.id,
|
||||
addonName: openSubtitlesAddon.name
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to fetch subtitles:', error);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export const stremioService = StremioService.getInstance();
|
||||
|
|
|
|||
Loading…
Reference in a new issue