This commit is contained in:
Violet Caulfield
2025-12-21 19:30:56 -06:00
parent e4a331e900
commit ff23bf171d
50 changed files with 413 additions and 229 deletions

View File

@@ -23,7 +23,7 @@ import { requestStoragePermission } from './src/utils/permisson-helpers'
import ErrorBoundary from './src/components/ErrorBoundary'
import OTAUpdateScreen from './src/components/OtaUpdates'
import { usePerformanceMonitor } from './src/hooks/use-performance-monitor'
import navigationRef from './navigation'
import navigationRef from './src/navigation/ref'
import { BUFFERS, PROGRESS_UPDATE_EVENT_INTERVAL } from './src/player/config'
import { useThemeSetting } from './src/stores/settings/app'

View File

@@ -1,7 +1,7 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<style name="AppTheme" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
</style>

View File

@@ -5,16 +5,19 @@
"": {
"name": "jellify",
"dependencies": {
"@bottom-tabs/react-navigation": "^1.1.0",
"@callstack/liquid-glass": "^0.7.0",
"@jellyfin/sdk": "0.13.0",
"@react-native-async-storage/async-storage": "^2.2.0",
"@react-native-community/cli": "20.0.0",
"@react-native-community/netinfo": "^11.4.1",
"@react-native-masked-view/masked-view": "^0.3.2",
"@react-native-vector-icons/get-image": "^12.3.0",
"@react-native-vector-icons/material-design-icons": "12.4.0",
"@react-navigation/bottom-tabs": "7.9.0",
"@react-navigation/material-top-tabs": "7.4.11",
"@react-navigation/native": "7.1.26",
"@react-navigation/native-stack": "7.9.0",
"@react-navigation/bottom-tabs": "8.0.0-alpha.0",
"@react-navigation/material-top-tabs": "8.0.0-alpha.0",
"@react-navigation/native": "8.0.0-alpha.0",
"@react-navigation/native-stack": "8.0.0-alpha.0",
"@sentry/react-native": "7.8.0",
"@shopify/flash-list": "2.2.0",
"@tamagui/config": "1.141.4",
@@ -34,6 +37,7 @@
"react-native-background-actions": "^4.0.1",
"react-native-blob-util": "^0.22.2",
"react-native-blurhash": "^2.1.3",
"react-native-bottom-tabs": "^1.1.0",
"react-native-carplay": "^2.4.1-beta.0",
"react-native-config": "1.5.6",
"react-native-device-info": "15.0.1",
@@ -356,6 +360,10 @@
"@bcoe/v8-coverage": ["@bcoe/v8-coverage@0.2.3", "", {}, "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="],
"@bottom-tabs/react-navigation": ["@bottom-tabs/react-navigation@1.1.0", "", { "dependencies": { "color": "^5.0.0" }, "peerDependencies": { "@react-navigation/native": ">=7", "react": "*", "react-native": "*", "react-native-bottom-tabs": "*" } }, "sha512-+4YppCodABcSNIgJiq95QUQ+3ClVBG+rLG3WmYI0+/nbxqKbCz6luFBep4KFOj98Iplj1JY2Ki6ix8CcOZVQ/Q=="],
"@callstack/liquid-glass": ["@callstack/liquid-glass@0.7.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-ztPuQnXG3z9kPWT0srf+yIbVZih/aifbynzormDzsFMWR6IQk3e0h8DEYic3sgW7PUa7A/GyaBBCpq10ZZvboA=="],
"@egjs/hammerjs": ["@egjs/hammerjs@2.0.17", "", { "dependencies": { "@types/hammerjs": "^2.0.36" } }, "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A=="],
"@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="],
@@ -528,6 +536,8 @@
"@react-native-vector-icons/common": ["@react-native-vector-icons/common@12.4.0", "", { "dependencies": { "find-up": "^7.0.0", "picocolors": "^1.1.1", "plist": "^3.1.0" }, "peerDependencies": { "@react-native-vector-icons/get-image": "^12.3.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@react-native-vector-icons/get-image"], "bin": { "rnvi-update-plist": "lib/commonjs/scripts/updatePlist.js" } }, "sha512-t9W0q+AW7WH1Oj5aEg7wGNXDLZJb5sIVkAWo5qtad3PcbBADqoCdikRK/ToLK+xlB0TxjcuL0T74ogudMkYGeA=="],
"@react-native-vector-icons/get-image": ["@react-native-vector-icons/get-image@12.3.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-ch9mwFWePde7AR0DfhcuNDeMH7N/vLPvoiJbqm28oeJPnCS6XA98F5GPwpMO9IE/omTv2RYwBTmhMA+8Wlwv/A=="],
"@react-native-vector-icons/material-design-icons": ["@react-native-vector-icons/material-design-icons@12.4.0", "", { "dependencies": { "@react-native-vector-icons/common": "^12.4.0" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-4ewAiHdOCujqprUJYFnBcUJduNddAc+w3Plnl1NhJksAyOaHzCNBg01JgVtkysxPho6++OOMge3FhwyBT8Wtcg=="],
"@react-native/assets-registry": ["@react-native/assets-registry@0.83.0", "", {}, "sha512-EmGSKDvmnEnBrTK75T+0Syt6gy/HACOTfziw5+392Kr1Bb28Rv26GyOIkvptnT+bb2VDHU0hx9G0vSy5/S3rmQ=="],
@@ -566,19 +576,19 @@
"@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.83.0", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.2.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-AVnDppwPidQrPrzA4ETr4o9W+40yuijg3EVgFt2hnMldMZkqwPRrgJL2GSreQjCYe1NfM5Yn4Egyy4Kd0yp4Lw=="],
"@react-navigation/bottom-tabs": ["@react-navigation/bottom-tabs@7.9.0", "", { "dependencies": { "@react-navigation/elements": "^2.9.3", "color": "^4.2.3", "sf-symbols-typescript": "^2.1.0" }, "peerDependencies": { "@react-navigation/native": "^7.1.26", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-024FWdHp3ZsE5rP8tmGI4vh+1z3wg8u8E9Frep8eeGoYo1h9rQhvgofQDGxknmrKsb7t8o8Dim+IZSvl57cPFQ=="],
"@react-navigation/bottom-tabs": ["@react-navigation/bottom-tabs@8.0.0-alpha.0", "", { "dependencies": { "@react-navigation/elements": "^3.0.0-alpha.0", "color": "^4.2.3", "sf-symbols-typescript": "^2.1.0" }, "peerDependencies": { "@react-navigation/native": "^8.0.0-alpha.0", "react": ">= 19.0.0", "react-native": "*", "react-native-safe-area-context": ">= 5.5.0", "react-native-screens": ">= 4.19.0" } }, "sha512-3RN9XkCIaB+YsLU+YBhqdhWs3Q1yV++YBLQJPWNku5tfxI3gszHrMNS0IK3EMjK2VQPmyEhFnnJFynjtkdCAYQ=="],
"@react-navigation/core": ["@react-navigation/core@7.13.7", "", { "dependencies": { "@react-navigation/routers": "^7.5.3", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "query-string": "^7.1.3", "react-is": "^19.1.0", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": ">= 18.2.0" } }, "sha512-k2ABo3250vq1ovOh/iVwXS6Hwr5PVRGXoPh/ewVFOOuEKTvOx9i//OBzt8EF+HokBxS2HBRlR2b+aCOmscRqBw=="],
"@react-navigation/core": ["@react-navigation/core@8.0.0-alpha.0", "", { "dependencies": { "@react-navigation/routers": "^8.0.0-alpha.0", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "query-string": "^7.1.3", "react-is": "^19.1.0", "use-latest-callback": "^0.3.2", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": ">= 19.0.0" } }, "sha512-xhFfK8H/x6mR/VRWtytGVwipNS8yvwpsV3EJ7pN1x1kHydm8cc4BN3e4UIHxFGYJpgHL6336KCTdpX18/GkfEQ=="],
"@react-navigation/elements": ["@react-navigation/elements@2.9.3", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@react-native-masked-view/masked-view": ">= 0.2.0", "@react-navigation/native": "^7.1.26", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" }, "optionalPeers": ["@react-native-masked-view/masked-view"] }, "sha512-3+eyvWiVPIEf6tN9UdduhOEHcTuNe3R5WovgiVkfH9+jApHMTZDc2loePTpY/i2HDJhObhhChpJzO6BVjrpdYQ=="],
"@react-navigation/elements": ["@react-navigation/elements@3.0.0-alpha.0", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.3.2", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@callstack/liquid-glass": ">= 0.6.0", "@react-navigation/native": "^8.0.0-alpha.0", "react": ">= 19.0.0", "react-native": "*", "react-native-safe-area-context": ">= 5.5.0", "react-native-screens": ">= 4.19.0" } }, "sha512-lKaWPec0rG3xYf8pmsv6AwZDtupJl/6gfxzHsRHE1/Jb++/gFDUhYNYYderCOzxuQqtgCwo8ubDnrwO0y72s4Q=="],
"@react-navigation/material-top-tabs": ["@react-navigation/material-top-tabs@7.4.11", "", { "dependencies": { "@react-navigation/elements": "^2.9.3", "color": "^4.2.3", "react-native-tab-view": "^4.2.2" }, "peerDependencies": { "@react-navigation/native": "^7.1.26", "react": ">= 18.2.0", "react-native": "*", "react-native-pager-view": ">= 6.0.0", "react-native-safe-area-context": ">= 4.0.0" } }, "sha512-RSC/f1bSpodnx1oSXw7jNrwe83JddRhb12ehCY8oZZDtrNhm3atSHzlfvHN37i3E8cln7Tmc1ieLxjWrU65n/Q=="],
"@react-navigation/material-top-tabs": ["@react-navigation/material-top-tabs@8.0.0-alpha.0", "", { "dependencies": { "@react-navigation/elements": "^3.0.0-alpha.0", "color": "^4.2.3", "react-native-tab-view": "^5.0.0-alpha.0" }, "peerDependencies": { "@react-navigation/native": "^8.0.0-alpha.0", "react": ">= 19.0.0", "react-native": "*", "react-native-pager-view": ">= 7.0.0", "react-native-safe-area-context": ">= 5.5.0" } }, "sha512-xZ1tuJ++3FS1EFW7zyOiBSoT1wWIqu/Bb/qhryDptO4Yo++tssbREKo+A+pI4N+vhhnoBu9RTvEPy3NA0blBtg=="],
"@react-navigation/native": ["@react-navigation/native@7.1.26", "", { "dependencies": { "@react-navigation/core": "^7.13.7", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "use-latest-callback": "^0.2.4" }, "peerDependencies": { "react": ">= 18.2.0", "react-native": "*" } }, "sha512-RhKmeD0E2ejzKS6z8elAfdfwShpcdkYY8zJzvHYLq+wv183BBcElTeyMLcIX6wIn7QutXeI92Yi21t7aUWfqNQ=="],
"@react-navigation/native": ["@react-navigation/native@8.0.0-alpha.0", "", { "dependencies": { "@react-navigation/core": "^8.0.0-alpha.0", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "use-latest-callback": "^0.3.2" }, "peerDependencies": { "react": ">= 19.0.0", "react-native": "*" } }, "sha512-TWnlArpOfm8FsNnV9ca9ZQAdIEOUqEiMzj5CNk6UHVaBhUVY+KZtmBVmKZaT7Xhpm4BQRlzE9OQUA8rt/0/Kzg=="],
"@react-navigation/native-stack": ["@react-navigation/native-stack@7.9.0", "", { "dependencies": { "@react-navigation/elements": "^2.9.3", "color": "^4.2.3", "sf-symbols-typescript": "^2.1.0", "warn-once": "^0.1.1" }, "peerDependencies": { "@react-navigation/native": "^7.1.26", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-C/mNPhI0Pnerl7C2cB+6fAkdgSmfKECMERrbyfjx3P6JmEuTC54o+GV1c62FUmlRaRUassVHbtw4EeaY2uLh0g=="],
"@react-navigation/native-stack": ["@react-navigation/native-stack@8.0.0-alpha.0", "", { "dependencies": { "@react-navigation/elements": "^3.0.0-alpha.0", "sf-symbols-typescript": "^2.1.0", "warn-once": "^0.1.1" }, "peerDependencies": { "@react-navigation/native": "^8.0.0-alpha.0", "react": ">= 19.0.0", "react-native": "*", "react-native-safe-area-context": ">= 5.5.0", "react-native-screens": ">= 4.19.0" } }, "sha512-QIzCYNYYWLARMrrkFwM2Ld/f/rpiDfHCUXs2K8Rh5WhC1Zlm9Dzwb4VCM5+yO06xl7zfDriRnqPKQIxwXwY2Cw=="],
"@react-navigation/routers": ["@react-navigation/routers@7.5.3", "", { "dependencies": { "nanoid": "^3.3.11" } }, "sha512-1tJHg4KKRJuQ1/EvJxatrMef3NZXEPzwUIUZ3n1yJ2t7Q97siwRtbynRpQG9/69ebbtiZ8W3ScOZF/OmhvM4Rg=="],
"@react-navigation/routers": ["@react-navigation/routers@8.0.0-alpha.0", "", { "dependencies": { "nanoid": "^3.3.11" } }, "sha512-jMhHdY9Zrg6zmYrjOhO5f8yMVSmHh8m0YRjg+rH7xuKroJLeDaJS9/hFkSy9CAtaiY05vjis1Sy0G5+YcpdRLw=="],
"@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="],
@@ -1112,13 +1122,13 @@
"collect-v8-coverage": ["collect-v8-coverage@1.0.3", "", {}, "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw=="],
"color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
"color": ["color@5.0.3", "", { "dependencies": { "color-convert": "^3.1.3", "color-string": "^2.1.3" } }, "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-convert": ["color-convert@3.1.3", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"color-name": ["color-name@2.1.0", "", {}, "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg=="],
"color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
"color-string": ["color-string@2.1.4", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg=="],
"color2k": ["color2k@2.0.3", "", {}, "sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog=="],
@@ -1904,6 +1914,8 @@
"react-native-blurhash": ["react-native-blurhash@2.1.3", "", { "peerDependencies": { "react": ">=16.8.1", "react-native": ">=0.60.0-rc.0 <1.0.x" } }, "sha512-tYyFketZkrrEIABJ5Z1Pt6N2dqPqtSp7w4Lce17sx1bvspdppgVu/ehtZoPRZu02fYyX92RkyCeGXtCbtUNntg=="],
"react-native-bottom-tabs": ["react-native-bottom-tabs@1.1.0", "", { "dependencies": { "react-freeze": "^1.0.0", "sf-symbols-typescript": "^2.0.0", "use-latest-callback": "^0.2.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-Uu1gvM3i1Hb4DjVvR/38J1QVQEs0RkPc7K6yon99HgvRWWOyLs7kjPDhUswtb8ije4pKW712skIXWJ0lgKzbyQ=="],
"react-native-carplay": ["react-native-carplay@2.4.1-beta.0", "", { "peerDependencies": { "react": "^17.0.2 || ^18.0.0", "react-native": "^0.60.0" }, "optionalPeers": ["react", "react-native"] }, "sha512-tYJymLgJi+0516niv4ApGVC+VgENX/uCYqCX81tewSILWnS6KR7M0A9+bHyNk8xoheFyYGruX7onYxU2U8ykPA=="],
"react-native-cli-bump-version": ["react-native-cli-bump-version@1.5.1", "", {}, "sha512-C7Vss+BBD4iNMnn2YR00cU+GDDPZ+LDmIqWoh3FPwI/LBsJ/Vp5qanwtyVYRPcIe7Cg1PPB8WdeZ8XcnqF5Klw=="],
@@ -1944,7 +1956,7 @@
"react-native-sortables": ["react-native-sortables@1.9.4", "", { "optionalDependencies": { "react-native-haptic-feedback": ">=2.0.0" }, "peerDependencies": { "react": "*", "react-native": "*", "react-native-gesture-handler": ">=2.0.0", "react-native-reanimated": ">=3.0.0" } }, "sha512-a6hxT+gl14HA5Sm8UiLXJqF8KMEQVa+mUJd75OnzoVsmrxUDtjAatlMdV0kI9qTQDT/ZSFLPRmdUhOR762IA4g=="],
"react-native-tab-view": ["react-native-tab-view@4.2.2", "", { "dependencies": { "use-latest-callback": "^0.2.4" }, "peerDependencies": { "react": ">= 18.2.0", "react-native": "*", "react-native-pager-view": ">= 6.0.0" } }, "sha512-NXtrG6OchvbGjsvbySJGVocXxo4Y2vA17ph4rAaWtA2jh+AasD8OyikKBRg2SmllEfeQ+GEhcKe8kulHv8BhTg=="],
"react-native-tab-view": ["react-native-tab-view@5.0.0-alpha.0", "", { "dependencies": { "use-latest-callback": "^0.3.2" }, "peerDependencies": { "react": ">= 19.0.0", "react-native": "*", "react-native-pager-view": ">= 7.0.0" } }, "sha512-IQQbhs5x0Hbb0gnMMt6YaZ/JQqGEW/0DwvvEZL3v0b4pA3KVq62wOCoaJVn+YDsU8KYXg4/ovToGlZuGiDfEZg=="],
"react-native-text-ticker": ["react-native-text-ticker@1.15.0", "", {}, "sha512-d/uK+PIOhsYMy1r8h825iq/nADiHsabz3WMbRJSnkpQYn+K9aykUAXRRhu8ZbTAzk4CgnUWajJEFxS5ZDygsdg=="],
@@ -2206,7 +2218,7 @@
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
"use-latest-callback": ["use-latest-callback@0.2.6", "", { "peerDependencies": { "react": ">=16.8" } }, "sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg=="],
"use-latest-callback": ["use-latest-callback@0.3.3", "", { "peerDependencies": { "react": ">=16.8" } }, "sha512-G9A/EL7okx4wzBfATt8bdGg0v1K0Gp0IClTzljffM63gtPisgDKCaLCLUb4g2M4CoXDg5yyHjOU+g3SUPbXwrA=="],
"use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
@@ -2364,6 +2376,12 @@
"@react-native/eslint-config/eslint-plugin-react-native": ["eslint-plugin-react-native@4.1.0", "", { "dependencies": { "eslint-plugin-react-native-globals": "^0.1.1" }, "peerDependencies": { "eslint": "^3.17.0 || ^4 || ^5 || ^6 || ^7 || ^8" } }, "sha512-QLo7rzTBOl43FvVqDdq5Ql9IoElIuTdjrz9SKAXCvULvBoRZ44JGSkx9z4999ZusCsb4rK3gjS8gOGyeYqZv2Q=="],
"@react-navigation/bottom-tabs/color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
"@react-navigation/elements/color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
"@react-navigation/material-top-tabs/color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
"@tanstack/react-query/@tanstack/query-core": ["@tanstack/query-core@5.90.12", "", {}, "sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg=="],
"@types/react-native/@types/react": ["@types/react@19.2.6", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w=="],
@@ -2386,6 +2404,8 @@
"ansi-fragments/strip-ansi": ["strip-ansi@5.2.0", "", { "dependencies": { "ansi-regex": "^4.1.0" } }, "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA=="],
"ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"babel-jest/@jest/transform": ["@jest/transform@29.7.0", "", { "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", "@jridgewell/trace-mapping": "^0.3.18", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", "jest-haste-map": "^29.7.0", "jest-regex-util": "^29.6.3", "jest-util": "^29.7.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", "write-file-atomic": "^4.0.2" } }, "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw=="],
"babel-jest/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
@@ -2570,6 +2590,8 @@
"react-native-blob-util/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
"react-native-bottom-tabs/use-latest-callback": ["use-latest-callback@0.2.6", "", { "peerDependencies": { "react": ">=16.8" } }, "sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg=="],
"react-native-reanimated/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
"react-native-worklets/@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg=="],
@@ -2662,10 +2684,24 @@
"@react-native-vector-icons/common/find-up/path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="],
"@react-navigation/bottom-tabs/color/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"@react-navigation/bottom-tabs/color/color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
"@react-navigation/elements/color/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"@react-navigation/elements/color/color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
"@react-navigation/material-top-tabs/color/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"@react-navigation/material-top-tabs/color/color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"ansi-fragments/strip-ansi/ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="],
"ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"babel-jest/@jest/transform/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="],
"babel-jest/@jest/transform/jest-haste-map": ["jest-haste-map@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.9", "jest-regex-util": "^29.6.3", "jest-util": "^29.7.0", "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.2" } }, "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA=="],
@@ -2806,6 +2842,18 @@
"@react-native-vector-icons/common/find-up/locate-path/p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="],
"@react-navigation/bottom-tabs/color/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"@react-navigation/bottom-tabs/color/color-string/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"@react-navigation/elements/color/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"@react-navigation/elements/color/color-string/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"@react-navigation/material-top-tabs/color/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"@react-navigation/material-top-tabs/color/color-string/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"babel-jest/@jest/transform/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
"cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],

View File

@@ -12,6 +12,34 @@ PODS:
- hermes-engine (0.14.0):
- hermes-engine/Pre-built (= 0.14.0)
- hermes-engine/Pre-built (0.14.0)
- LiquidGlass (0.7.0):
- boost
- DoubleConversion
- fast_float
- fmt
- glog
- hermes-engine
- RCT-Folly
- RCT-Folly/Fabric
- RCTRequired
- RCTTypeSafety
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- MMKVCore (2.2.4)
- NitroFetch (0.1.6):
- boost
@@ -2106,6 +2134,65 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-bottom-tabs (1.1.0):
- boost
- DoubleConversion
- fast_float
- fmt
- glog
- hermes-engine
- RCT-Folly
- RCT-Folly/Fabric
- RCTRequired
- RCTTypeSafety
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- react-native-bottom-tabs/common (= 1.1.0)
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- SocketRocket
- SwiftUIIntrospect (~> 1.0)
- Yoga
- react-native-bottom-tabs/common (1.1.0):
- boost
- DoubleConversion
- fast_float
- fmt
- glog
- hermes-engine
- RCT-Folly
- RCT-Folly/Fabric
- RCTRequired
- RCTTypeSafety
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- SocketRocket
- SwiftUIIntrospect (~> 1.0)
- Yoga
- react-native-carplay (2.4.1-beta.0):
- React
- react-native-config (1.5.6):
@@ -2262,6 +2349,34 @@ PODS:
- SocketRocket
- SwiftAudioEx (= 1.1.0)
- Yoga
- react-native-vector-icons (12.3.0):
- boost
- DoubleConversion
- fast_float
- fmt
- glog
- hermes-engine
- RCT-Folly
- RCT-Folly/Fabric
- RCTRequired
- RCTTypeSafety
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-vector-icons-material-design-icons (12.4.0)
- react-native-worklets-core (1.6.2):
- boost
@@ -3243,6 +3358,7 @@ PODS:
- SocketRocket (0.7.1)
- SSZipArchive (2.4.3)
- SwiftAudioEx (1.1.0)
- SwiftUIIntrospect (1.3.0)
- Yoga (0.0.0)
DEPENDENCIES:
@@ -3254,6 +3370,7 @@ DEPENDENCIES:
- fmt (from `../node_modules/react-native/third-party-podspecs/fmt.podspec`)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
- "LiquidGlass (from `../node_modules/@callstack/liquid-glass`)"
- NitroFetch (from `../node_modules/react-native-nitro-fetch`)
- NitroMmkv (from `../node_modules/react-native-mmkv`)
- NitroModules (from `../node_modules/react-native-nitro-modules`)
@@ -3299,6 +3416,7 @@ DEPENDENCIES:
- react-native-background-actions (from `../node_modules/react-native-background-actions`)
- react-native-blob-util (from `../node_modules/react-native-blob-util`)
- react-native-blurhash (from `../node_modules/react-native-blurhash`)
- react-native-bottom-tabs (from `../node_modules/react-native-bottom-tabs`)
- react-native-carplay (from `../node_modules/react-native-carplay`)
- react-native-config (from `../node_modules/react-native-config`)
- react-native-google-cast (from `../node_modules/react-native-google-cast`)
@@ -3306,6 +3424,7 @@ DEPENDENCIES:
- react-native-pager-view (from `../node_modules/react-native-pager-view`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- react-native-track-player (from `../node_modules/react-native-track-player`)
- "react-native-vector-icons (from `../node_modules/@react-native-vector-icons/get-image`)"
- "react-native-vector-icons-material-design-icons (from `../node_modules/@react-native-vector-icons/material-design-icons`)"
- react-native-worklets-core (from `../node_modules/react-native-worklets-core`)
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
@@ -3367,6 +3486,7 @@ SPEC REPOS:
- SocketRocket
- SSZipArchive
- SwiftAudioEx
- SwiftUIIntrospect
EXTERNAL SOURCES:
boost:
@@ -3386,6 +3506,8 @@ EXTERNAL SOURCES:
hermes-engine:
:podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec"
:tag: hermes-v0.14.0
LiquidGlass:
:path: "../node_modules/@callstack/liquid-glass"
NitroFetch:
:path: "../node_modules/react-native-nitro-fetch"
NitroMmkv:
@@ -3474,6 +3596,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-blob-util"
react-native-blurhash:
:path: "../node_modules/react-native-blurhash"
react-native-bottom-tabs:
:path: "../node_modules/react-native-bottom-tabs"
react-native-carplay:
:path: "../node_modules/react-native-carplay"
react-native-config:
@@ -3488,6 +3612,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-safe-area-context"
react-native-track-player:
:path: "../node_modules/react-native-track-player"
react-native-vector-icons:
:path: "../node_modules/@react-native-vector-icons/get-image"
react-native-vector-icons-material-design-icons:
:path: "../node_modules/@react-native-vector-icons/material-design-icons"
react-native-worklets-core:
@@ -3593,6 +3719,7 @@ SPEC CHECKSUMS:
glog: 5683914934d5b6e4240e497e0f4a3b42d1854183
google-cast-sdk: 1fb6724e94cc5ff23b359176e0cf6360586bb97a
hermes-engine: 83ac7cadb2a3a158ae6d9e4192417c5232065e99
LiquidGlass: a2ea1e5036efd0964d666b4b63b5bcb3509e1651
MMKVCore: f2dd4c9befea04277a55e84e7812f930537993df
NitroFetch: 660adfb47f84b28db664f97b50e5dc28506ab6c1
NitroMmkv: ce1df9b9f0e06dfbde2455d863047e0411fceb6e
@@ -3640,6 +3767,7 @@ SPEC CHECKSUMS:
react-native-background-actions: 48e6bad9e2a47e3b04858634c5a05ea11062f680
react-native-blob-util: e2162ce4757849682559754bca954b65dc7eeb2f
react-native-blurhash: 93b024ff78f7912d22b1cdba262f3c91d3e2002e
react-native-bottom-tabs: e33312fc663d163f0be73d3474dfb448ba38dad8
react-native-carplay: 8f388f6f73e5e0f73ed154ad8794371343ee20c0
react-native-config: f1dde39f8468ad922fc7e8bd4308c8e6223d5ee8
react-native-google-cast: 7be68a5d0b7eeb95a5924c3ecef8d319ef6c0a44
@@ -3647,6 +3775,7 @@ SPEC CHECKSUMS:
react-native-pager-view: 5c3098839820aa73d75873e7b1a7eb9f119602b7
react-native-safe-area-context: c00143b4823773bba23f2f19f85663ae89ceb460
react-native-track-player: 89d8e641c83a89bea5dee43c381be743282553e9
react-native-vector-icons: 6ba2060e1b82ce0663f14375579fe1d48e9b668a
react-native-vector-icons-material-design-icons: 76cd460b3540b80527b4a80fb7f867f7deedb498
react-native-worklets-core: 28a6e2121dcf62543b703e81bc4860e9a0150cee
React-NativeModulesApple: 1a378198515f8e825c5931a7613e98da69320cee
@@ -3698,6 +3827,7 @@ SPEC CHECKSUMS:
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
SwiftAudioEx: f6aa653770f3a0d3851edaf8d834a30aee4a7646
SwiftUIIntrospect: fee9aa07293ee280373a591e1824e8ddc869ba5d
Yoga: 6ca93c8c13f56baeec55eb608577619b17a4d64e
PODFILE CHECKSUM: 05d07b9cff134e4c27345bc2b588e090e4d3431c

View File

@@ -37,16 +37,19 @@
"postinstall": "patch-package"
},
"dependencies": {
"@bottom-tabs/react-navigation": "^1.1.0",
"@callstack/liquid-glass": "^0.7.0",
"@jellyfin/sdk": "0.13.0",
"@react-native-async-storage/async-storage": "^2.2.0",
"@react-native-community/cli": "20.0.0",
"@react-native-community/netinfo": "^11.4.1",
"@react-native-masked-view/masked-view": "^0.3.2",
"@react-native-vector-icons/get-image": "^12.3.0",
"@react-native-vector-icons/material-design-icons": "12.4.0",
"@react-navigation/bottom-tabs": "7.9.0",
"@react-navigation/material-top-tabs": "7.4.11",
"@react-navigation/native": "7.1.26",
"@react-navigation/native-stack": "7.9.0",
"@react-navigation/bottom-tabs": "8.0.0-alpha.0",
"@react-navigation/material-top-tabs": "8.0.0-alpha.0",
"@react-navigation/native": "8.0.0-alpha.0",
"@react-navigation/native-stack": "8.0.0-alpha.0",
"@sentry/react-native": "7.8.0",
"@shopify/flash-list": "2.2.0",
"@tamagui/config": "1.141.4",
@@ -66,6 +69,7 @@
"react-native-background-actions": "^4.0.1",
"react-native-blob-util": "^0.22.2",
"react-native-blurhash": "^2.1.3",
"react-native-bottom-tabs": "^1.1.0",
"react-native-carplay": "^2.4.1-beta.0",
"react-native-config": "1.5.6",
"react-native-device-info": "15.0.1",

View File

@@ -1,20 +1,11 @@
import DiscoverStackParamList from '../../screens/Discover/types'
import HomeStackParamList from '../../screens/Home/types'
import LibraryStackParamList from '../../screens/Library/types'
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'
import { useNavigation } from '@react-navigation/native'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { FlashList } from '@shopify/flash-list'
import { YStack, H5 } from 'tamagui'
import { ItemCard } from '../Global/components/item-card'
export default function AlbumTrackListFooter({ album }: { album: BaseItemDto }): React.JSX.Element {
const navigation =
useNavigation<
NativeStackNavigationProp<
HomeStackParamList | LibraryStackParamList | DiscoverStackParamList
>
>()
const navigation = useNavigation('Album')
return (
<YStack marginLeft={'$2'}>

View File

@@ -39,7 +39,7 @@ export default function AlbumTrackListHeader({ album }: { album: BaseItemDto }):
queryFn: () => fetchAlbumDiscs(api, album),
})
const navigation = useNavigation<NativeStackNavigationProp<BaseStackParamList>>()
const navigation = useNavigation('Album')
const playAlbum = (shuffled: boolean = false) => {
if (!discs || discs.length === 0) return

View File

@@ -30,7 +30,7 @@ import { useStorageContext } from '../../providers/Storage'
* @returns A React component
*/
export function Album({ album }: { album: BaseItemDto }): React.JSX.Element {
const navigation = useNavigation<NativeStackNavigationProp<BaseStackParamList>>()
const navigation = useNavigation('Album')
const api = useApi()

View File

@@ -5,9 +5,7 @@ import { FlashList, FlashListRef } from '@shopify/flash-list'
import { UseInfiniteQueryResult } from '@tanstack/react-query'
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
import ItemRow from '../Global/components/item-row'
import { useNavigation } from '@react-navigation/native'
import LibraryStackParamList from '../../screens/Library/types'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { LibraryNavigator, useNavigation } from '@react-navigation/native'
import AZScroller, { useAlphabetSelector } from '../Global/components/alphabetical-selector'
import { isString } from 'lodash'
import FlashListStickyHeader from '../Global/helpers/flashlist-sticky-header'
@@ -32,7 +30,7 @@ export default function Albums({
const isFavorites = useLibraryStore((state) => state.isFavorites)
const navigation = useNavigation<NativeStackNavigationProp<LibraryStackParamList>>()
const navigation = useNavigation<LibraryNavigator>()
const sectionListRef = useRef<FlashListRef<string | number | BaseItemDto>>(null)

View File

@@ -7,8 +7,6 @@ import { useArtistContext } from '../../providers/Artist'
import FavoriteButton from '../Global/components/favorite-button'
import { InstantMixIconButton } from '../Global/components/instant-mix-button'
import { useNavigation } from '@react-navigation/native'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { BaseStackParamList } from '@/src/screens/types'
import IconButton from '../Global/helpers/icon-button'
import { fetchAlbumDiscs } from '../../api/queries/item'
import { useLoadNewQueue } from '../../providers/Player/hooks/mutations'
@@ -30,7 +28,7 @@ export default function ArtistHeader(): React.JSX.Element {
const loadNewQueue = useLoadNewQueue()
const navigation = useNavigation<NativeStackNavigationProp<BaseStackParamList>>()
const navigation = useNavigation('Artist')
const playArtist = async (shuffled: boolean = false) => {
if (!albums || albums.length === 0) return

View File

@@ -1,5 +1,3 @@
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { BaseStackParamList } from '../../screens/types'
import { useNavigation } from '@react-navigation/native'
import { Text } from '../Global/helpers/text'
import { useArtistContext } from '../../providers/Artist'
@@ -9,7 +7,7 @@ import { FlashList } from '@shopify/flash-list'
import ItemRow from '../Global/components/item-row'
export default function SimilarArtists(): React.JSX.Element {
const navigation = useNavigation<NativeStackNavigationProp<BaseStackParamList>>()
const navigation = useNavigation('Artist')
const { artist, similarArtists, fetchingSimilarArtists } = useArtistContext()
return (
@@ -26,7 +24,7 @@ export default function SimilarArtists(): React.JSX.Element {
<ItemRow
item={artist}
onPress={() => {
navigation.push('Artist', {
navigation.navigate('Artist', {
artist,
})
}}

View File

@@ -7,9 +7,7 @@ import { FlashList, FlashListRef } from '@shopify/flash-list'
import AZScroller, { useAlphabetSelector } from '../Global/components/alphabetical-selector'
import { UseInfiniteQueryResult } from '@tanstack/react-query'
import { isString } from 'lodash'
import { useNavigation } from '@react-navigation/native'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import LibraryStackParamList from '../../screens/Library/types'
import { LibraryNavigator, useNavigation } from '@react-navigation/native'
import FlashListStickyHeader from '../Global/helpers/flashlist-sticky-header'
import { closeAllSwipeableRows } from '../Global/components/swipeable-row-registry'
import useLibraryStore from '../../stores/library'
@@ -40,7 +38,7 @@ export default function Artists({
const isFavorites = useLibraryStore((state) => state.isFavorites)
const navigation = useNavigation<NativeStackNavigationProp<LibraryStackParamList>>()
const navigation = useNavigation<LibraryNavigator>()
const artists = artistsInfiniteQuery.data ?? []
const sectionListRef = useRef<FlashListRef<string | number | BaseItemDto>>(null)

View File

@@ -1,4 +1,4 @@
import navigationRef from '../../../../navigation'
import navigationRef from '../../../navigation/ref'
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'
import { StackActions, TabActions, useNavigation } from '@react-navigation/native'
import { ListItem } from 'tamagui'

View File

@@ -2,8 +2,7 @@ import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import ItemRow from '../../Global/components/item-row'
import { FlashList } from '@shopify/flash-list'
import { PlayerParamList } from '../../../screens/Player/types'
import { RouteProp, useNavigation } from '@react-navigation/native'
import { RootStackParamList } from '../../../screens/types'
import { RootNavigator, RouteProp, useNavigation } from '@react-navigation/native'
import { getTokenValue } from 'tamagui'
interface MultipleArtistsProps {
@@ -14,7 +13,7 @@ export default function MultipleArtists({
navigation,
route,
}: MultipleArtistsProps): React.JSX.Element {
const rootNavigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>()
const rootNavigation = useNavigation<RootNavigator>()
return (
<FlashList
contentContainerStyle={{

View File

@@ -16,7 +16,7 @@ import { getItemsApi } from '@jellyfin/sdk/lib/utils/api'
import { AddToQueueMutation } from '../../providers/Player/interfaces'
import { QueuingType } from '../../enums/queuing-type'
import { useEffect } from 'react'
import navigationRef from '../../../navigation'
import navigationRef from '../../navigation/ref'
import { goToAlbumFromContextSheet, goToArtistFromContextSheet } from './utils/navigation'
import { getItemName } from '../../utils/text'
import ItemImage from '../Global/components/image'

View File

@@ -1,5 +1,5 @@
import { CommonActions, StackActions, TabActions } from '@react-navigation/native'
import navigationRef from '../../../../navigation'
import navigationRef from '../../../navigation/ref'
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
export function goToAlbumFromContextSheet(album: BaseItemDto | undefined) {

View File

@@ -1,18 +1,17 @@
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import HorizontalCardList from '../../../components/Global/components/horizontal-list'
import { ItemCard } from '../../../components/Global/components/item-card'
import { H5, View, XStack } from 'tamagui'
import { H5, XStack } from 'tamagui'
import Icon from '../../Global/components/icon'
import { useNavigation } from '@react-navigation/native'
import DiscoverStackParamList from '../../../screens/Discover/types'
import navigationRef from '../../../../navigation'
import { DiscoverNavigator, useNavigation } from '@react-navigation/native'
import navigationRef from '../../../navigation/ref'
import { useRecentlyAddedAlbums } from '../../../api/queries/album'
import Animated, { FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
export default function RecentlyAdded(): React.JSX.Element | null {
const recentlyAddedAlbumsInfinityQuery = useRecentlyAddedAlbums()
const navigation = useNavigation<NativeStackNavigationProp<DiscoverStackParamList>>()
const navigation = useNavigation<DiscoverNavigator>()
const recentlyAddedExists =
recentlyAddedAlbumsInfinityQuery.data && recentlyAddedAlbumsInfinityQuery.data.length > 0

View File

@@ -1,12 +1,10 @@
import { H5, XStack } from 'tamagui'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import Icon from '../../Global/components/icon'
import HorizontalCardList from '../../Global/components/horizontal-list'
import { ItemCard } from '../../Global/components/item-card'
import { useSafeAreaFrame } from 'react-native-safe-area-context'
import { useNavigation } from '@react-navigation/native'
import DiscoverStackParamList from '../../../screens/Discover/types'
import navigationRef from '../../../../navigation'
import { DiscoverNavigator, useNavigation } from '@react-navigation/native'
import navigationRef from '../../../navigation/ref'
import { useJellifyServer } from '../../../stores'
import { usePublicPlaylists } from '../../../api/queries/playlist'
import Animated, { FadeIn, LinearTransition } from 'react-native-reanimated'
@@ -21,7 +19,7 @@ export default function PublicPlaylists(): React.JSX.Element | null {
refetch,
} = usePublicPlaylists()
const navigation = useNavigation<NativeStackNavigationProp<DiscoverStackParamList>>()
const navigation = useNavigation<DiscoverNavigator>()
const [server] = useJellifyServer()
const { width } = useSafeAreaFrame()

View File

@@ -1,11 +1,10 @@
import { H5, View, XStack } from 'tamagui'
import { H5, XStack } from 'tamagui'
import Icon from '../../Global/components/icon'
import HorizontalCardList from '../../Global/components/horizontal-list'
import { ItemCard } from '../../Global/components/item-card'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { useNavigation } from '@react-navigation/native'
import DiscoverStackParamList from '../../../screens/Discover/types'
import navigationRef from '../../../../navigation'
import { DiscoverNavigator, useNavigation } from '@react-navigation/native'
import navigationRef from '../../../navigation/ref'
import { pickFirstGenre } from '../../../utils/genre-formatting'
import Animated, { FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
import { useDiscoverArtists } from '../../../api/queries/suggestions'
@@ -13,7 +12,7 @@ import { useDiscoverArtists } from '../../../api/queries/suggestions'
export default function SuggestedArtists(): React.JSX.Element | null {
const suggestedArtistsInfiniteQuery = useDiscoverArtists()
const navigation = useNavigation<NativeStackNavigationProp<DiscoverStackParamList>>()
const navigation = useNavigation<DiscoverNavigator>()
const suggestedArtistsExist =
suggestedArtistsInfiniteQuery.data && suggestedArtistsInfiniteQuery.data.length > 0

View File

@@ -6,7 +6,7 @@ import { QueuingType } from '../../../enums/queuing-type'
import { RunTimeTicks } from '../helpers/time-codes'
import ItemImage from './image'
import FavoriteIcon from './favorite-icon'
import navigationRef from '../../../../navigation'
import navigationRef from '../../../navigation/ref'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { BaseStackParamList } from '../../../screens/types'
import { useAddToQueue, useLoadNewQueue } from '../../../providers/Player/hooks/mutations'

View File

@@ -10,7 +10,7 @@ import FavoriteIcon from './favorite-icon'
import { networkStatusTypes } from '../../../components/Network/internetConnectionWatcher'
import { useNetworkStatus } from '../../../stores/network'
import DownloadedIcon from './downloaded-icon'
import navigationRef from '../../../../navigation'
import navigationRef from '../../../navigation/ref'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { BaseStackParamList } from '../../../screens/types'
import ItemImage from './image'

View File

@@ -1,21 +1,18 @@
import HorizontalCardList from '../../../components/Global/components/horizontal-list'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import React, { useCallback } from 'react'
import { ItemCard } from '../../../components/Global/components/item-card'
import { H5, XStack } from 'tamagui'
import Icon from '../../Global/components/icon'
import { useDisplayContext } from '../../../providers/Display/display-provider'
import { useNavigation } from '@react-navigation/native'
import HomeStackParamList from '../../../screens/Home/types'
import { RootStackParamList } from '../../../screens/types'
import { HomeNavigator, RootNavigator, useNavigation } from '@react-navigation/native'
import { useFrequentlyPlayedArtists } from '../../../api/queries/frequents'
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'
import { pickFirstGenre } from '../../../utils/genre-formatting'
import Animated, { FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
export default function FrequentArtists(): React.JSX.Element {
const navigation = useNavigation<NativeStackNavigationProp<HomeStackParamList>>()
const rootNavigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>()
const navigation = useNavigation<HomeNavigator>()
const rootNavigation = useNavigation<RootNavigator>()
const frequentArtistsInfiniteQuery = useFrequentlyPlayedArtists()
const { horizontalItems } = useDisplayContext()

View File

@@ -1,4 +1,3 @@
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { H5, XStack } from 'tamagui'
import HorizontalCardList from '../../../components/Global/components/horizontal-list'
import { ItemCard } from '../../../components/Global/components/item-card'
@@ -6,9 +5,7 @@ import { QueuingType } from '../../../enums/queuing-type'
import Icon from '../../Global/components/icon'
import { useLoadNewQueue } from '../../../providers/Player/hooks/mutations'
import { useDisplayContext } from '../../../providers/Display/display-provider'
import HomeStackParamList from '../../../screens/Home/types'
import { useNavigation } from '@react-navigation/native'
import { RootStackParamList } from '../../../screens/types'
import { RootNavigator, HomeNavigator, useNavigation } from '@react-navigation/native'
import { useNetworkStatus } from '../../../stores/network'
import useStreamingDeviceProfile from '../../../stores/device-profile'
import { useFrequentlyPlayedTracks } from '../../../api/queries/frequents'
@@ -24,9 +21,9 @@ export default function FrequentlyPlayedTracks(): React.JSX.Element {
const tracksInfiniteQuery = useFrequentlyPlayedTracks()
const navigation = useNavigation<NativeStackNavigationProp<HomeStackParamList>>()
const navigation = useNavigation<HomeNavigator>()
const rootNavigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>()
const rootNavigation = useNavigation<RootNavigator>()
const loadNewQueue = useLoadNewQueue()
const { horizontalItems } = useDisplayContext()

View File

@@ -1,13 +1,10 @@
import React, { useCallback } from 'react'
import { H5, View, XStack } from 'tamagui'
import { RootStackParamList } from '../../../screens/types'
import { H5, XStack } from 'tamagui'
import { ItemCard } from '../../Global/components/item-card'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import HorizontalCardList from '../../../components/Global/components/horizontal-list'
import Icon from '../../Global/components/icon'
import { useDisplayContext } from '../../../providers/Display/display-provider'
import { useNavigation } from '@react-navigation/native'
import HomeStackParamList from '../../../screens/Home/types'
import { HomeNavigator, RootNavigator, useNavigation } from '@react-navigation/native'
import { useRecentArtists } from '../../../api/queries/recents'
import { pickFirstGenre } from '../../../utils/genre-formatting'
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'
@@ -16,9 +13,9 @@ import Animated, { FadeIn, FadeOut, LinearTransition } from 'react-native-reanim
export default function RecentArtists(): React.JSX.Element {
const recentArtistsInfiniteQuery = useRecentArtists()
const navigation = useNavigation<NativeStackNavigationProp<HomeStackParamList>>()
const navigation = useNavigation<HomeNavigator>()
const rootNavigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>()
const rootNavigation = useNavigation<RootNavigator>()
const { horizontalItems } = useDisplayContext()

View File

@@ -1,15 +1,12 @@
import React from 'react'
import { H5, XStack } from 'tamagui'
import { ItemCard } from '../../Global/components/item-card'
import { RootStackParamList } from '../../../screens/types'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { QueuingType } from '../../../enums/queuing-type'
import HorizontalCardList from '../../../components/Global/components/horizontal-list'
import Icon from '../../Global/components/icon'
import { useLoadNewQueue } from '../../../providers/Player/hooks/mutations'
import { useDisplayContext } from '../../../providers/Display/display-provider'
import { useNavigation } from '@react-navigation/native'
import HomeStackParamList from '../../../screens/Home/types'
import { HomeNavigator, RootNavigator, useNavigation } from '@react-navigation/native'
import { useNetworkStatus } from '../../../stores/network'
import useStreamingDeviceProfile from '../../../stores/device-profile'
import { useRecentlyPlayedTracks } from '../../../api/queries/recents'
@@ -23,8 +20,8 @@ export default function RecentlyPlayed(): React.JSX.Element {
const deviceProfile = useStreamingDeviceProfile()
const navigation = useNavigation<NativeStackNavigationProp<HomeStackParamList>>()
const rootNavigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>()
const navigation = useNavigation<HomeNavigator>()
const rootNavigation = useNavigation<RootNavigator>()
const loadNewQueue = useLoadNewQueue()

View File

@@ -1,7 +1,7 @@
import React from 'react'
import Tracks from '../../Tracks/component'
import { useNavigation } from '@react-navigation/native'
import { LibraryNavigator, useNavigation } from '@react-navigation/native'
import LibraryStackParamList from '@/src/screens/Library/types'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import useTracks from '../../../api/queries/track'
@@ -12,7 +12,7 @@ function TracksTab(): React.JSX.Element {
const { isFavorites, isDownloaded } = useLibraryStore()
const navigation = useNavigation<NativeStackNavigationProp<LibraryStackParamList>>()
const navigation = useNavigation<LibraryNavigator>()
return (
<Tracks

View File

@@ -3,7 +3,7 @@ import { Spacer, useTheme, XStack } from 'tamagui'
import Icon from '../../Global/components/icon'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { useNavigation } from '@react-navigation/native'
import { PlayerNavigator, useNavigation } from '@react-navigation/native'
import { PlayerParamList } from '../../../screens/Player/types'
import { CastButton, MediaHlsSegmentFormat, useRemoteMediaClient } from 'react-native-google-cast'
import { useEffect } from 'react'
@@ -13,7 +13,7 @@ import Animated, { FadeIn, FadeOut } from 'react-native-reanimated'
import { useCurrentTrack } from '../../../stores/player/queue'
export default function Footer(): React.JSX.Element {
const navigation = useNavigation<NativeStackNavigationProp<PlayerParamList>>()
const navigation = useNavigation<PlayerNavigator>()
const playerEngineData = usePlayerEngineStore((state) => state.playerEngineData)
const theme = useTheme()

View File

@@ -10,7 +10,7 @@ import Animated, {
} from 'react-native-reanimated'
import { LayoutChangeEvent } from 'react-native'
import MaterialDesignIcons from '@react-native-vector-icons/material-design-icons'
import navigationRef from '../../../../navigation'
import navigationRef from '../../../navigation/ref'
import { useCurrentTrack, useQueueRef } from '../../../stores/player/queue'
import TextTicker from 'react-native-text-ticker'
import { TextTickerConfig } from '../component.config'

View File

@@ -1,6 +1,6 @@
import { Spacer, Square } from 'tamagui'
import { Text } from '../../Global/helpers/text'
import navigationRef from '../../../../navigation'
import navigationRef from '../../../navigation/ref'
import { parseBitrateFromTranscodingUrl } from '../../../utils/url-parsers'
import { BaseItemDto, MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client'
import { SourceType } from '../../../types/JellifyTrack'

View File

@@ -7,7 +7,7 @@ import { useQuery } from '@tanstack/react-query'
import { fetchItem } from '../../../api/queries/item'
import FavoriteButton from '../../Global/components/favorite-button'
import { QueryKeys } from '../../../enums/query-keys'
import navigationRef from '../../../../navigation'
import navigationRef from '../../../navigation/ref'
import Icon from '../../Global/components/icon'
import { getItemName } from '../../../utils/text'
import { CommonActions } from '@react-navigation/native'

View File

@@ -1,6 +1,6 @@
import React from 'react'
import { Progress, XStack, YStack } from 'tamagui'
import { useNavigation } from '@react-navigation/native'
import { RootNavigator, useNavigation } from '@react-navigation/native'
import { Text } from '../Global/helpers/text'
import TextTicker from 'react-native-text-ticker'
import { PlayPauseIcon } from './components/buttons'
@@ -19,8 +19,6 @@ import Animated, {
withSpring,
} from 'react-native-reanimated'
import { runOnJS } from 'react-native-worklets'
import { RootStackParamList } from '../../screens/types'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import ItemImage from '../Global/components/image'
import { usePrevious, useSkip } from '../../providers/Player/hooks/mutations'
import { useCurrentTrack } from '../../stores/player/queue'
@@ -30,7 +28,7 @@ export default function Miniplayer(): React.JSX.Element {
const skip = useSkip()
const previous = usePrevious()
const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>()
const navigation = useNavigation<RootNavigator>()
const translateX = useSharedValue(0)
const translateY = useSharedValue(0)

View File

@@ -1,12 +1,10 @@
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { H5, Spacer, XStack, YStack } from 'tamagui'
import { InstantMixButton } from '../../Global/components/instant-mix-button'
import Icon from '../../Global/components/icon'
import { useNetworkStatus } from '../../../stores/network'
import { QueuingType } from '../../../enums/queuing-type'
import { useNavigation } from '@react-navigation/native'
import LibraryStackParamList from '@/src/screens/Library/types'
import { useNavigation, LibraryNavigator } from '@react-navigation/native'
import { useLoadNewQueue } from '../../../providers/Player/hooks/mutations'
import useStreamingDeviceProfile from '../../../stores/device-profile'
import ItemImage from '../../Global/components/image'
@@ -100,7 +98,7 @@ function PlaylistHeaderControls({
const [networkStatus] = useNetworkStatus()
const navigation = useNavigation<NativeStackNavigationProp<LibraryStackParamList>>()
const navigation = useNavigation<LibraryNavigator>()
const playPlaylist = (shuffled: boolean = false) => {
if (!playlistTracks || playlistTracks.length === 0) return

View File

@@ -2,21 +2,19 @@ import { ScrollView, Separator, Spinner, useTheme, XStack, YStack } from 'tamagu
import Track from '../Global/components/track'
import Icon from '../Global/components/icon'
import { PlaylistProps } from './interfaces'
import { StackActions, useNavigation } from '@react-navigation/native'
import { RootStackParamList } from '../../screens/types'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { RootNavigator, StackActions, useNavigation } from '@react-navigation/native'
import Sortable from 'react-native-sortables'
import { useReducedHapticsSetting } from '../../stores/settings/app'
import { RenderItemInfo } from 'react-native-sortables/dist/typescript/types'
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'
import PlaylistTracklistHeader from './components/header'
import navigationRef from '../../../navigation'
import navigationRef from '../../navigation/ref'
import { useLoadNewQueue } from '../../providers/Player/hooks/mutations'
import { useNetworkStatus } from '../../stores/network'
import { QueuingType } from '../../enums/queuing-type'
import { useApi } from '../../stores'
import useStreamingDeviceProfile from '../../stores/device-profile'
import { useCallback, useEffect, useLayoutEffect, useState } from 'react'
import { useEffect, useLayoutEffect, useState } from 'react'
import { updatePlaylist } from '../../../src/api/mutations/playlists'
import { usePlaylistTracks } from '../../../src/api/queries/playlist'
import useHapticFeedback from '../../hooks/use-haptic-feedback'
@@ -110,7 +108,7 @@ export default function Playlist({
* Fetches all remaining pages before entering edit mode.
* This prevents data loss when saving a playlist that has unloaded tracks.
*/
const handleEnterEditMode = useCallback(async () => {
const handleEnterEditMode = async () => {
if (hasNextPage) {
setIsPreparingEditMode(true)
try {
@@ -125,7 +123,7 @@ export default function Playlist({
}
}
setEditing(true)
}, [hasNextPage, fetchNextPage])
}
useEffect(() => {
if (!isPending && isSuccess) setPlaylistTracks(tracks)
@@ -257,7 +255,7 @@ export default function Playlist({
const streamingDeviceProfile = useStreamingDeviceProfile()
const rootNavigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>()
const rootNavigation = useNavigation<RootNavigator>()
// Render item for Sortable.Grid (edit mode only)
const renderSortableItem = ({ item: track, index }: RenderItemInfo<BaseItemDto>) => {

View File

@@ -4,7 +4,7 @@ import { FlashList } from '@shopify/flash-list'
import ItemRow from '../Global/components/item-row'
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
import { FetchNextPageOptions } from '@tanstack/react-query'
import { useNavigation } from '@react-navigation/native'
import { LibraryNavigator, useNavigation } from '@react-navigation/native'
import { BaseStackParamList } from '@/src/screens/types'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { closeAllSwipeableRows } from '../Global/components/swipeable-row-registry'
@@ -37,7 +37,7 @@ export default function Playlists({
}: PlaylistsProps): React.JSX.Element {
const theme = useTheme()
const navigation = useNavigation<NativeStackNavigationProp<BaseStackParamList>>()
const navigation = useNavigation<LibraryNavigator>()
// Memoized key extractor to prevent recreation on each render
const keyExtractor = useCallback((item: BaseItemDto) => item.Id!, [])

View File

@@ -4,10 +4,8 @@ import { H5, Separator, Spinner, YStack } from 'tamagui'
import { ItemCard } from '../Global/components/item-card'
import HorizontalCardList from '../Global/components/horizontal-list'
import { FlashList } from '@shopify/flash-list'
import SearchParamList from '../../screens/Search/types'
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
import { useNavigation } from '@react-navigation/native'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { SearchNavigator, useNavigation } from '@react-navigation/native'
import { closeAllSwipeableRows } from '../Global/components/swipeable-row-registry'
export default function Suggestions({
@@ -15,7 +13,7 @@ export default function Suggestions({
}: {
suggestions: BaseItemDto[] | undefined
}): React.JSX.Element {
const navigation = useNavigation<NativeStackNavigationProp<SearchParamList>>()
const navigation = useNavigation<SearchNavigator>()
const handleScrollBeginDrag = () => {
closeAllSwipeableRows()
}

View File

@@ -1,8 +1,6 @@
import React, { useState } from 'react'
import SignOut from './sign-out-button'
import { SettingsStackParamList } from '../../../screens/Settings/types'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { useNavigation } from '@react-navigation/native'
import { SettingsNavigator, useNavigation } from '@react-navigation/native'
import { Text } from '../../Global/helpers/text'
import SettingsListGroup from './settings-list-group'
import HTTPS from '../../../constants/protocols'
@@ -25,7 +23,7 @@ export default function AccountTab(): React.JSX.Element {
const [prId, setPrId] = usePrId()
const [localPrId, setLocalPrId] = useState(prId)
const navigation = useNavigation<NativeStackNavigationProp<SettingsStackParamList>>()
const navigation = useNavigation<SettingsNavigator>()
const handleSubmitPr = () => {
if (localPrId.trim()) {

View File

@@ -8,16 +8,13 @@ import {
useAutoDownload,
useDownloadQuality,
} from '../../../stores/settings/usage'
import { useNavigation } from '@react-navigation/native'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { SettingsStackParamList } from '../../../screens/Settings/types'
import { SettingsNavigator, useNavigation } from '@react-navigation/native'
export default function StorageTab(): React.JSX.Element {
const [autoDownload, setAutoDownload] = useAutoDownload()
const [downloadQuality, setDownloadQuality] = useDownloadQuality()
const { data: downloadedTracks } = useAllDownloadedTracks()
const navigation =
useNavigation<NativeStackNavigationProp<SettingsStackParamList, 'Settings'>>()
const navigation = useNavigation<SettingsNavigator>()
return (
<SettingsListGroup

View File

@@ -1,5 +1,5 @@
import { DarkTheme, DefaultTheme } from '@react-navigation/native'
import { getToken, getTokens } from 'tamagui'
import { DarkTheme, DefaultTheme, Theme } from '@react-navigation/native'
import { getTokens } from 'tamagui'
interface Fonts {
regular: FontStyle
@@ -43,7 +43,7 @@ const JellifyFonts: Fonts = {
},
}
export const JellifyDarkTheme: ReactNavigation.Theme = {
export const JellifyDarkTheme: Theme = {
dark: true,
colors: {
...DarkTheme.colors,
@@ -67,7 +67,7 @@ export const JellifyLightTheme = {
fonts: JellifyFonts,
}
export const JellifyOLEDTheme: ReactNavigation.Theme = {
export const JellifyOLEDTheme: Theme = {
dark: true,
colors: {
...DarkTheme.colors,

View File

@@ -1,5 +1,5 @@
import { createNavigationContainerRef } from '@react-navigation/native'
import { RootStackParamList } from './src/screens/types'
import { RootStackParamList } from '../screens/types'
const navigationRef = createNavigationContainerRef<RootStackParamList>()

View File

@@ -1,7 +1,6 @@
import { useMutation } from '@tanstack/react-query'
import TrackPlayer, { RepeatMode, State } from 'react-native-track-player'
import { loadQueue, playLaterInQueue, playNextInQueue } from '../functions/queue'
import { isUndefined } from 'lodash'
import { previous, skip } from '../functions/controls'
import { AddToQueueMutation, QueueMutation, QueueOrderMutation } from '../interfaces'
import { QueuingType } from '../../../enums/queuing-type'
@@ -11,12 +10,10 @@ import JellifyTrack from '@/src/types/JellifyTrack'
import calculateTrackVolume from '../utils/normalization'
import usePlayerEngineStore, { PlayerEngine } from '../../../stores/player/engine'
import { useRemoteMediaClient } from 'react-native-google-cast'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { RootStackParamList } from '../../../screens/types'
import { useNavigation } from '@react-navigation/native'
import useHapticFeedback from '../../../hooks/use-haptic-feedback'
import { usePlayerQueueStore } from '../../../stores/player/queue'
import { useCallback } from 'react'
import navigationRef from '../../../navigation/ref'
/**
* A mutation to handle starting playback
@@ -186,34 +183,30 @@ export const useLoadNewQueue = () => {
const isCasting =
usePlayerEngineStore((state) => state.playerEngineData) === PlayerEngine.GOOGLE_CAST
const remoteClient = useRemoteMediaClient()
const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>()
const trigger = useHapticFeedback()
return useCallback(
async (variables: QueueMutation) => {
trigger('impactLight')
await TrackPlayer.pause()
const { finalStartIndex, tracks } = await loadQueue({ ...variables })
return async (variables: QueueMutation) => {
trigger('impactLight')
await TrackPlayer.pause()
const { finalStartIndex, tracks } = await loadQueue({ ...variables })
usePlayerQueueStore.getState().setCurrentIndex(finalStartIndex)
if (isCasting && remoteClient) {
await TrackPlayer.skip(finalStartIndex)
navigation.navigate('PlayerRoot', { screen: 'PlayerScreen' })
return
}
usePlayerQueueStore.getState().setCurrentIndex(finalStartIndex)
if (isCasting && remoteClient) {
await TrackPlayer.skip(finalStartIndex)
navigationRef.navigate('PlayerRoot', { screen: 'PlayerScreen' })
return
}
if (variables.startPlayback) await TrackPlayer.play()
await TrackPlayer.skip(finalStartIndex)
usePlayerQueueStore.getState().setQueueRef(variables.queue)
usePlayerQueueStore.getState().setQueue(tracks)
usePlayerQueueStore.getState().setCurrentTrack(tracks[finalStartIndex])
},
[isCasting, remoteClient, navigation, trigger, usePlayerQueueStore],
)
if (variables.startPlayback) await TrackPlayer.play()
usePlayerQueueStore.getState().setQueueRef(variables.queue)
usePlayerQueueStore.getState().setQueue(tracks)
usePlayerQueueStore.getState().setCurrentTrack(tracks[finalStartIndex])
}
}
export const usePrevious = () => {

View File

@@ -104,3 +104,9 @@ export function Discover(): React.JSX.Element {
</DiscoverStack.Navigator>
)
}
type DiscoverStackType = typeof DiscoverStack
declare module '@react-navigation/core' {
interface DiscoverNavigator extends DiscoverStackType {}
}

View File

@@ -103,3 +103,9 @@ export default function Home(): React.JSX.Element {
</HomeStack.Navigator>
)
}
type HomeStackType = typeof HomeStack
declare module '@react-navigation/core' {
interface HomeNavigator extends HomeStackType {}
}

View File

@@ -84,3 +84,9 @@ export default function LibraryScreen(): React.JSX.Element {
</LibraryStack.Navigator>
)
}
type LibraryStackType = typeof LibraryStack
declare module '@react-navigation/core' {
interface LibraryNavigator extends LibraryStackType {}
}

View File

@@ -1,11 +1,10 @@
import React from 'react'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { RootStackParamList } from '../types'
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
import LibrarySelector from '../../components/Global/components/library-selector'
import LoginStackParamList from './types'
import { useNavigation } from '@react-navigation/native'
import { useJellifyLibrary } from '../../stores'
import navigationRef from '../../navigation/ref'
export default function ServerLibrary({
navigation,
@@ -14,8 +13,6 @@ export default function ServerLibrary({
}): React.JSX.Element {
const [, setLibrary] = useJellifyLibrary()
const rootNavigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>()
const handleLibrarySelected = (
libraryId: string,
selectedLibrary: BaseItemDto,
@@ -28,7 +25,7 @@ export default function ServerLibrary({
playlistLibraryId: playlistLibrary?.Id,
playlistLibraryPrimaryImageId: playlistLibrary?.ImageTags?.Primary,
})
rootNavigation.navigate('Tabs', { screen: 'HomeTab' })
navigationRef.navigate('Tabs', { screen: 'HomeTab' })
}
const handleCancel = () => {

View File

@@ -50,3 +50,9 @@ export default function Player(): React.JSX.Element {
</PlayerStack.Navigator>
)
}
type PlayerStackType = typeof PlayerStack
declare module '@react-navigation/core' {
interface PlayerNavigator extends PlayerStackType {}
}

View File

@@ -71,3 +71,9 @@ export default function SearchStack(): React.JSX.Element {
</Stack.Navigator>
)
}
type SearchStackType = typeof Stack
declare module '@react-navigation/core' {
interface SearchNavigator extends SearchStackType {}
}

View File

@@ -63,3 +63,9 @@ export default function SettingsScreen(): React.JSX.Element {
</SettingsStack.Navigator>
)
}
type SettingsStackType = typeof SettingsStack
declare module '@react-navigation/core' {
interface SettingsNavigator extends SettingsStackType {}
}

View File

@@ -6,15 +6,11 @@ import Icon from '../../components/Global/components/icon'
import { useResetQueue } from '../../providers/Player/hooks/mutations'
import { useClearAllDownloads } from '../../api/mutations/download'
import { useJellifyServer } from '../../stores'
import { useNavigation } from '@react-navigation/native'
import { RootStackParamList } from '../types'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import navigationRef from '../../navigation/ref'
export default function SignOutModal({ navigation }: SignOutModalProps): React.JSX.Element {
const [server] = useJellifyServer()
const rootNavigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>()
const { mutate: resetQueue } = useResetQueue()
const clearDownloads = useClearAllDownloads()
@@ -43,7 +39,7 @@ export default function SignOutModal({ navigation }: SignOutModalProps): React.J
borderColor={'$danger'}
onPress={() => {
navigation.goBack()
rootNavigation.navigate('Login', { screen: 'ServerAddress' })
navigationRef.navigate('Login', { screen: 'ServerAddress' })
clearDownloads()
resetQueue()

View File

@@ -1,5 +1,5 @@
import React from 'react'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import { createNativeBottomTabNavigator } from '@bottom-tabs/react-navigation'
import Home from '../Home'
import MaterialDesignIcons from '@react-native-vector-icons/material-design-icons'
import SettingsScreen from '../Settings'
@@ -10,41 +10,81 @@ import LibraryScreen from '../Library'
import TabParamList from './types'
import { TabProps } from '../types'
import TabBar from './tab-bar'
import { Platform } from 'react-native'
const Tab = createBottomTabNavigator<TabParamList>()
const Tab = createNativeBottomTabNavigator<TabParamList>()
export default function Tabs({ route, navigation }: TabProps): React.JSX.Element {
const theme = useTheme()
const jellyfishIconUnfocused = MaterialDesignIcons.getImageSourceSync(
'jellyfish-outline',
24,
theme.borderColor.val,
)
const jellyfishIconFocused = MaterialDesignIcons.getImageSourceSync(
'jellyfish',
24,
theme.primary.val,
)
const libraryIconUnfocused = MaterialDesignIcons.getImageSourceSync(
'music-box-multiple-outline',
24,
theme.borderColor.val,
)
const libraryIconFocused = MaterialDesignIcons.getImageSourceSync(
'music-box-multiple',
24,
theme.primary.val,
)
const searchIconUnfocused = MaterialDesignIcons.getImageSourceSync(
'magnify',
24,
theme.borderColor.val,
)
const searchIconFocused = MaterialDesignIcons.getImageSourceSync(
'magnify',
24,
theme.primary.val,
)
const discoverIconUnfocused = MaterialDesignIcons.getImageSourceSync(
'compass-outline',
24,
theme.borderColor.val,
)
const discoverIconFocused = MaterialDesignIcons.getImageSourceSync(
'compass',
24,
theme.primary.val,
)
const settingsIconUnfocused = MaterialDesignIcons.getImageSourceSync(
'cogs',
24,
theme.borderColor.val,
)
const settingsIconFocused = MaterialDesignIcons.getImageSourceSync(
'cogs',
24,
theme.primary.val,
)
return (
<Tab.Navigator
/*
* https://github.com/react-navigation/react-navigation/issues/12755
*/
detachInactiveScreens={Platform.OS !== 'ios'}
initialRouteName={route.params?.screen ?? 'HomeTab'}
screenOptions={{
animation: 'shift',
tabBarActiveTintColor: theme.primary.val,
tabBarInactiveTintColor: theme.borderColor.val,
lazy: true,
}}
tabBar={(props) => <TabBar {...props} />}
>
<Tab.Navigator initialRouteName={route.params?.screen ?? 'HomeTab'} render>
<Tab.Screen
name='HomeTab'
component={Home}
options={{
title: 'Home',
headerShown: false,
tabBarIcon: ({ color, size, focused }) => (
<MaterialDesignIcons
name={`jellyfish${!focused ? '-outline' : ''}`}
color={color}
size={size}
/>
),
tabBarIcon: ({ focused }) =>
focused ? jellyfishIconFocused! : jellyfishIconUnfocused!,
tabBarButtonTestID: 'home-tab-button',
}}
/>
@@ -54,14 +94,8 @@ export default function Tabs({ route, navigation }: TabProps): React.JSX.Element
component={LibraryScreen}
options={{
title: 'Library',
headerShown: false,
tabBarIcon: ({ color, size, focused }) => (
<MaterialDesignIcons
name={`music-box-multiple${!focused ? '-outline' : ''}`}
color={color}
size={size}
/>
),
tabBarIcon: ({ focused }) =>
focused ? libraryIconFocused! : libraryIconUnfocused!,
tabBarButtonTestID: 'library-tab-button',
}}
/>
@@ -71,10 +105,8 @@ export default function Tabs({ route, navigation }: TabProps): React.JSX.Element
component={SearchStack}
options={{
title: 'Search',
headerShown: false,
tabBarIcon: ({ color, size }) => (
<MaterialDesignIcons name='magnify' color={color} size={size} />
),
tabBarIcon: ({ focused }) =>
focused ? searchIconFocused! : searchIconUnfocused!,
tabBarButtonTestID: 'search-tab-button',
}}
/>
@@ -84,14 +116,8 @@ export default function Tabs({ route, navigation }: TabProps): React.JSX.Element
component={Discover}
options={{
title: 'Discover',
headerShown: false,
tabBarIcon: ({ color, size, focused }) => (
<MaterialDesignIcons
name={`compass${!focused ? '-outline' : ''}`}
color={color}
size={size}
/>
),
tabBarIcon: ({ focused }) =>
focused ? discoverIconFocused! : discoverIconUnfocused!,
tabBarButtonTestID: 'discover-tab-button',
}}
/>
@@ -101,10 +127,8 @@ export default function Tabs({ route, navigation }: TabProps): React.JSX.Element
component={SettingsScreen}
options={{
title: 'Settings',
headerShown: false,
tabBarIcon: ({ color, size }) => (
<MaterialDesignIcons name='cogs' color={color} size={size} />
),
tabBarIcon: ({ focused }) =>
focused ? settingsIconFocused! : settingsIconUnfocused!,
tabBarButtonTestID: 'settings-tab-button',
}}
/>

View File

@@ -1,7 +1,7 @@
import Player from './Player'
import Tabs from './Tabs'
import { RootStackParamList } from './types'
import { useTheme, YStack } from 'tamagui'
import { YStack } from 'tamagui'
import Login from './Login'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import Context from './Context'
@@ -19,8 +19,6 @@ import { Platform } from 'react-native'
const RootStack = createNativeStackNavigator<RootStackParamList>()
export default function Root(): React.JSX.Element {
const theme = useTheme()
const api = useApi()
const [library] = useJellifyLibrary()
@@ -31,7 +29,6 @@ export default function Root(): React.JSX.Element {
component={Tabs}
options={{
headerShown: false,
navigationBarColor: theme.background.val,
gestureEnabled: false,
}}
/>
@@ -101,6 +98,12 @@ export default function Root(): React.JSX.Element {
)
}
type RootStackType = typeof RootStack
declare module '@react-navigation/core' {
interface RootNavigator extends RootStackType {}
}
function ContextSheetHeader(item: BaseItemDto): React.JSX.Element {
return (
<YStack gap={'$1'} marginTop={'$4'} alignItems='center'>