Merge branch 'main' into fixing-the-artist-player-link
6
.github/workflows/build-android.yml
vendored
@@ -16,12 +16,12 @@ jobs:
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- name: 🛒 Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: 🖥 Setup Bun 1.3.2
|
||||
- name: 🖥 Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.2
|
||||
bun-version: 1.3.4
|
||||
|
||||
- name: 💎 Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
|
||||
6
.github/workflows/build-bundle.yml
vendored
@@ -14,12 +14,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 🧾 Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: 🖥 Setup Bun 1.3.2
|
||||
- name: 🖥 Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.2
|
||||
bun-version: 1.3.4
|
||||
|
||||
- name: 📦 Install dependencies
|
||||
run: bun i
|
||||
|
||||
6
.github/workflows/build-ios.yml
vendored
@@ -17,12 +17,12 @@ jobs:
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- name: 🛒 Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: 🖥 Setup Bun 1.3.2
|
||||
- name: 🖥 Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.2
|
||||
bun-version: 1.3.4
|
||||
|
||||
- name: 💬 Echo package.json version to Github ENV
|
||||
run: echo VERSION_NUMBER=$(bun -p "require('./package.json').version") >> $GITHUB_ENV
|
||||
|
||||
82
.github/workflows/maestro-test.yml
vendored
@@ -11,36 +11,36 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
build-android:
|
||||
runs-on: macos-15
|
||||
if: github.repository == 'Jellify-Music/App'
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.setver.outputs.version }}
|
||||
steps:
|
||||
- name: 🛒 Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: 🖥 Setup Bun 1.3.2
|
||||
- name: 🖥 Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.2
|
||||
bun-version: 1.3.4
|
||||
|
||||
- name: 💎 Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: '3.0'
|
||||
bundler-cache: true
|
||||
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
node_modules
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
~/.cache/turbo
|
||||
android/.gradle
|
||||
android/app/build
|
||||
key: ${{ runner.os }}-gradle-turbo-${{ hashFiles('**/bun.lock', '**/build.gradle') }}
|
||||
key: ${{ runner.os }}-bun-turbo-${{ hashFiles('**/bun.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-turbo-
|
||||
${{ runner.os }}-bun-turbo-
|
||||
|
||||
- name: ☕ Setup JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: '17'
|
||||
|
||||
- name: 🐘 Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
|
||||
- name: 🍎 Run bun init-android
|
||||
run: bun i
|
||||
@@ -65,18 +65,39 @@ jobs:
|
||||
|
||||
|
||||
run-maestro-tests:
|
||||
if: github.repository == 'Jellify-Music/App'
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-android
|
||||
|
||||
|
||||
steps:
|
||||
- name: 🛒 Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
with:
|
||||
tool-cache: true
|
||||
android: false
|
||||
dotnet: true
|
||||
haskell: true
|
||||
large-packages: true
|
||||
docker-images: true
|
||||
swap-storage: true
|
||||
|
||||
- name: 🖥 Setup Bun 1.3.2
|
||||
- name: 🛒 Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: 🖥 Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.2
|
||||
bun-version: 1.3.4
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
node_modules
|
||||
~/.cache/turbo
|
||||
key: ${{ runner.os }}-bun-turbo-${{ hashFiles('**/bun.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-bun-turbo-
|
||||
|
||||
- name: Installing Maestro
|
||||
shell: bash
|
||||
@@ -93,10 +114,6 @@ jobs:
|
||||
with:
|
||||
name: android-artifacts
|
||||
path: artifacts/
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: '3.4' # Not needed with a .ruby-version, .tool-versions or mise.toml
|
||||
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
||||
|
||||
- name: Enable KVM group perms
|
||||
shell: bash
|
||||
@@ -113,28 +130,29 @@ jobs:
|
||||
target: google_apis
|
||||
arch: x86_64
|
||||
profile: Nexus 6
|
||||
ram-size: '8192M'
|
||||
heap-size: '4096M'
|
||||
disk-size: '10G'
|
||||
cores: '4'
|
||||
disable-animations: false
|
||||
ram-size: '3072M'
|
||||
heap-size: '1024M'
|
||||
disk-size: '4G'
|
||||
cores: '3'
|
||||
disable-animations: true
|
||||
avd-name: e2e_emulator
|
||||
script: bash scripts/maestro-android-retry.sh "https://jellyfin.jellify.app" "jerry"
|
||||
|
||||
|
||||
- name: 🗣️ Notify Success on Discord
|
||||
if: success()
|
||||
if: success() && github.repository == 'Jellify-Music/App'
|
||||
run: |
|
||||
bun scripts/sendDiscordMessage.js "__**## ✅ Maestro Test Passed**__All checks completed successfully!"
|
||||
env:
|
||||
DISCORD_WEBHOOK_URL: ${{ secrets.MAESTRO_WEBHOOK_RESULTS }}
|
||||
|
||||
- name: 🗣️ Notify Failure on Discord
|
||||
if: failure()
|
||||
if: failure() && github.repository == 'Jellify-Music/App'
|
||||
run: |
|
||||
bun scripts/sendDiscordMessage.js "__**## ❌ Maestro Test Failed**__Some tests did not pass."
|
||||
env:
|
||||
DISCORD_WEBHOOK_URL: ${{ secrets.MAESTRO_WEBHOOK_RESULTS }}
|
||||
|
||||
- name: Store tests result
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
if: always()
|
||||
|
||||
22
.github/workflows/publish-beta.yml
vendored
@@ -30,15 +30,15 @@ jobs:
|
||||
release_notes: ${{ steps.set-output.outputs.release_notes }}
|
||||
steps:
|
||||
- name: 📦 Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.SIGNING_REPO_PAT }}
|
||||
|
||||
- name: 🖥 Setup Bun 1.3.2
|
||||
- name: 🖥 Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.2
|
||||
bun-version: 1.3.4
|
||||
- name: 🧠 Collect commit messages
|
||||
id: commits
|
||||
run: |
|
||||
@@ -80,14 +80,14 @@ jobs:
|
||||
version: ${{ steps.setver.outputs.version }}
|
||||
steps:
|
||||
- name: 🛒 Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
token: ${{ secrets.SIGNING_REPO_PAT }}
|
||||
|
||||
- name: 🖥 Setup Bun 1.3.2
|
||||
- name: 🖥 Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.2
|
||||
bun-version: 1.3.4
|
||||
|
||||
- name: 💎 Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
@@ -178,14 +178,14 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: 🛒 Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
token: ${{ secrets.SIGNING_REPO_PAT }}
|
||||
|
||||
- name: 🖥 Setup Bun 1.3.2
|
||||
- name: 🖥 Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.2
|
||||
bun-version: 1.3.4
|
||||
|
||||
- name: 🍎 Setup Xcode
|
||||
uses: ./.github/actions/setup-xcode
|
||||
@@ -280,10 +280,10 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 🖥 Setup Bun 1.3.2
|
||||
- name: 🖥 Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.2
|
||||
bun-version: 1.3.4
|
||||
|
||||
- name: 📦 Install dependencies
|
||||
run: bun i
|
||||
|
||||
12
.github/workflows/publish-ota-update-pr.yml
vendored
@@ -12,14 +12,12 @@ jobs:
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- name: 🛒 Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.SIGNING_REPO_PAT }}
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: 🖥 Setup Bun 1.3.2
|
||||
- name: 🖥 Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.2
|
||||
bun-version: 1.3.4
|
||||
|
||||
- name: 🥟 Run bun
|
||||
run: bun i
|
||||
@@ -29,7 +27,5 @@ jobs:
|
||||
git config --global user.email "violet@cosmonautical.cloud"
|
||||
git config --global user.name "anultravioletaurora"
|
||||
|
||||
- name: 🤖 Publish Android Update
|
||||
- name: 🤖 Publish Update
|
||||
run: bun run sendOTA:PR ${{ github.event.pull_request.number }}
|
||||
env:
|
||||
SIGNING_REPO_PAT: ${{ secrets.SIGNING_REPO_PAT }}
|
||||
|
||||
6
.github/workflows/publish-ota-update.yml
vendored
@@ -7,14 +7,14 @@ jobs:
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- name: 🛒 Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
token: ${{ secrets.SIGNING_REPO_PAT }}
|
||||
|
||||
- name: 🖥 Setup Bun 1.3.2
|
||||
- name: 🖥 Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.2
|
||||
bun-version: 1.3.4
|
||||
|
||||
- name: 🥟 Run bun install
|
||||
run: bun i
|
||||
|
||||
6
.github/workflows/run-jest-test-suite.yml
vendored
@@ -14,12 +14,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 🛒 Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: 🖥 Setup Bun 1.3.2
|
||||
- name: 🖥 Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.2
|
||||
bun-version: 1.3.4
|
||||
|
||||
- name: 📦 Cache dependencies
|
||||
uses: actions/cache@v4
|
||||
|
||||
21
README.md
@@ -4,15 +4,10 @@
|
||||
|
||||
[](https://github.com/anultravioletaurora/Jellify/releases) [](https://apps.apple.com/us/app/jellify/id6736884612) [](https://play.google.com/store/apps/details?id=com.cosmonautical.jellify)
|
||||
|
||||
|
||||
[](https://github.com/sponsors/anultravioletaurora) [](https://patreon.com/anultravioletaurora?utm_medium=unknown&utm_source=join_link&utm_campaign=creatorshare_creator&utm_content=copyLink)
|
||||
[](https://github.com/sponsors/anultravioletaurora) [](https://patreon.com/anultravioletaurora) [?logo=ko-fi&logoColor=white&color=rgb(243%2C110%2C60))](https://ko-fi.com/jellify)
|
||||
|
||||
|
||||
## Quick Links
|
||||
|
||||
[TestFlight](https://testflight.apple.com/join/etVSc7ZQ)
|
||||
|
||||
[](https://discord.gg/yf8fBatktn)
|
||||
[&color=rgb(89%2C100%2C238))](https://discord.gg/jellify)
|
||||
|
||||
## Contents
|
||||
|
||||
@@ -138,7 +133,7 @@ Install via [Altstore](https://altstore.io) or your favorite sideloading utility
|
||||
|
||||
<p align="center">
|
||||
<img src="screenshots/track_options.png" alt="Track Options" width="275" height="600">
|
||||
<img src="screenshots/playlist.png" alt="Playlist" width="275" height="600">
|
||||
<img src="screenshots/add_to_playlist.png" alt="Playlist" width="275" height="600">
|
||||
</p>
|
||||
|
||||
---
|
||||
@@ -173,7 +168,7 @@ Install via [Altstore](https://altstore.io) or your favorite sideloading utility
|
||||
|
||||
### Current
|
||||
|
||||
- Available via [Play Store](https://play.google.com/store/apps/details?id=com.cosmonautical.jellify&pcampaignid=web_share), [App Store](https://apps.apple.com/us/app/jellify/id6736884612), [Testflight](https://testflight.apple.com/join/etVSc7ZQ), and Android APKs
|
||||
- Available via [Play Store](https://play.google.com/store/apps/details?id=com.cosmonautical.jellify), [App Store](https://apps.apple.com/us/app/jellify/id6736884612), [Testflight](https://testflight.apple.com/join/etVSc7ZQ), and Android APKs
|
||||
- APKs are associated with each [release](https://github.com/anultravioletaurora/Jellify/releases)
|
||||
- Light and Dark modes
|
||||
- Home screen access to previously played tracks, artists, and your playlists
|
||||
@@ -235,8 +230,8 @@ Install via [Altstore](https://altstore.io) or your favorite sideloading utility
|
||||
[React Navigation](https://reactnavigation.org/)\
|
||||
[React Native Blurhash](https://github.com/mrousavy/react-native-blurhash)\
|
||||
[React Native CarPlay](https://github.com/birkir/react-native-carplay)\
|
||||
[React Native Draggable Flatlist](https://github.com/computerjazz/react-native-draggable-flatlist)\
|
||||
[React Native Nitro Image](https://github.com/mrousavy/react-native-nitro-image)\
|
||||
[React Native Sortables](https://github.com/MatiPl01/react-native-sortables)\
|
||||
[React Native Nitro Modules](https://github.com/mrousavy/react-native-nitro-modules)\
|
||||
[React Native Reanimated](https://docs.swmansion.com/react-native-reanimated/)\
|
||||
[React Native Toast Message](https://github.com/calintamas/react-native-toast-message)\
|
||||
[React Native Vector Icons](https://github.com/oblador/react-native-vector-icons)
|
||||
@@ -274,7 +269,7 @@ This is undoubtedly a passion project of [mine](https://github.com/anultraviolet
|
||||
|
||||
## Support the Project
|
||||
|
||||
You can support _Jellify_ development via [Patreon](https://patreon.com/anultravioletaurora?utm_medium=unknown&utm_source=join_link&utm_campaign=creatorshare_creator&utm_content=copyLink) or [GitHub Sponsors](https://github.com/sponsors/anultravioletaurora) starting at $1.
|
||||
You can support _Jellify_ development via [Patreon](https://patreon.com/anultravioletaurora) or [GitHub Sponsors](https://github.com/sponsors/anultravioletaurora) starting at $1.
|
||||
|
||||
Paid supporters will be recognized by having their name displayed within the Settings.
|
||||
|
||||
@@ -308,7 +303,7 @@ Paid supporters will be recognized by having their name displayed within the Set
|
||||
- Trevor (Android)
|
||||
- [Laine](https://github.com/lainie-ftw) (Android)
|
||||
- [Jordan](https://github.com/jordanbleu) (iOS)
|
||||
- My best(est) friend [Alyssa](https://www.instagram.com/uhh.lyssarae?igsh=MTRmczExempnbjBwZw==), for your design knowledge and for making various artwork for _Jellify_.
|
||||
- My best(est) friend [Alyssa](https://www.instagram.com/uhh.lyssarae), for your design knowledge and for making various artwork for _Jellify_.
|
||||
- You’ve been instrumental in shaping it’s user experience, my rock during development, and an overall inspiration in my life
|
||||
|
||||
|
||||
|
||||
@@ -91,8 +91,8 @@ android {
|
||||
applicationId "com.cosmonautical.jellify"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 158
|
||||
versionName "1.0.0"
|
||||
versionCode 165
|
||||
versionName "1.0.6"
|
||||
resValue "string", "build_config_package", "com.jellify"
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.facebook.react.defaults.DefaultReactActivityDelegate
|
||||
import com.reactnative.googlecast.api.RNGCCastContext
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.Nullable
|
||||
import com.swmansion.rnscreens.fragment.restoration.RNScreensFragmentFactory
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +28,9 @@ class MainActivity : ReactActivity() {
|
||||
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
|
||||
|
||||
|
||||
override fun onCreate(@Nullable savedInstanceState: Bundle?) {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// react-native-screens fragment factory for proper fragment restoration
|
||||
supportFragmentManager.fragmentFactory = RNScreensFragmentFactory()
|
||||
super.onCreate(savedInstanceState)
|
||||
// lazy load Google Cast context (if supported on this device)
|
||||
RNGCCastContext.getSharedInstance(this)
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.app.Application
|
||||
import com.facebook.react.PackageList
|
||||
import com.facebook.react.ReactApplication
|
||||
import com.facebook.react.ReactHost
|
||||
import com.facebook.react.ReactNativeHost
|
||||
import com.facebook.react.ReactPackage
|
||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
|
||||
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
|
||||
|
||||
434
bun.lock
@@ -11,29 +11,29 @@
|
||||
"@react-native-community/netinfo": "^11.4.1",
|
||||
"@react-native-masked-view/masked-view": "^0.3.2",
|
||||
"@react-native-vector-icons/material-design-icons": "12.4.0",
|
||||
"@react-navigation/bottom-tabs": "7.8.10",
|
||||
"@react-navigation/material-top-tabs": "7.4.7",
|
||||
"@react-navigation/native": "7.1.23",
|
||||
"@react-navigation/native-stack": "7.8.4",
|
||||
"@sentry/react-native": "7.6.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",
|
||||
"@sentry/react-native": "7.8.0",
|
||||
"@shopify/flash-list": "2.2.0",
|
||||
"@tamagui/config": "1.139.1",
|
||||
"@tanstack/query-async-storage-persister": "5.89.0",
|
||||
"@tanstack/react-query": "5.89.0",
|
||||
"@tanstack/react-query-persist-client": "5.89.0",
|
||||
"@tamagui/config": "1.141.4",
|
||||
"@tanstack/query-async-storage-persister": "5.90.12",
|
||||
"@tanstack/react-query": "5.90.12",
|
||||
"@tanstack/react-query-persist-client": "5.90.12",
|
||||
"@testing-library/react-native": "13.3.3",
|
||||
"@typedigital/telemetrydeck-react": "^0.4.1",
|
||||
"@typedigital/telemetrydeck-react": "0.4.1",
|
||||
"axios": "1.13.2",
|
||||
"bundle": "^2.1.0",
|
||||
"dlx": "^0.2.1",
|
||||
"invert-color": "^2.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"openai": "5.21.0",
|
||||
"react": "19.1.1",
|
||||
"react-native": "0.82.1",
|
||||
"react": "19.2.0",
|
||||
"react-native": "0.83.0",
|
||||
"react-native-background-actions": "^4.0.1",
|
||||
"react-native-blob-util": "^0.22.2",
|
||||
"react-native-blurhash": "2.1.1",
|
||||
"react-native-blurhash": "^2.1.3",
|
||||
"react-native-carplay": "^2.4.1-beta.0",
|
||||
"react-native-config": "1.5.6",
|
||||
"react-native-device-info": "15.0.1",
|
||||
@@ -43,48 +43,48 @@
|
||||
"react-native-google-cast": "^4.9.1",
|
||||
"react-native-haptic-feedback": "^2.3.3",
|
||||
"react-native-linear-gradient": "^2.8.3",
|
||||
"react-native-mmkv": "3.3.3",
|
||||
"react-native-mmkv": "^4.1.0",
|
||||
"react-native-nitro-fetch": "^0.1.6",
|
||||
"react-native-nitro-modules": "0.31.10",
|
||||
"react-native-nitro-ota": "0.7.2",
|
||||
"react-native-nitro-ota": "0.8.2",
|
||||
"react-native-pager-view": "^7.0.2",
|
||||
"react-native-reanimated": "4.1.5",
|
||||
"react-native-reanimated": "4.1.6",
|
||||
"react-native-safe-area-context": "5.6.2",
|
||||
"react-native-screens": "4.18.0",
|
||||
"react-native-screens": "4.19.0",
|
||||
"react-native-sortables": "1.9.4",
|
||||
"react-native-text-ticker": "^1.15.0",
|
||||
"react-native-toast-message": "^2.3.3",
|
||||
"react-native-track-player": "5.0.0-alpha0",
|
||||
"react-native-url-polyfill": "^2.0.0",
|
||||
"react-native-uuid": "^2.0.3",
|
||||
"react-native-worklets": "0.6.1",
|
||||
"react-native-worklets": "^0.7.1",
|
||||
"react-native-worklets-core": "^1.6.2",
|
||||
"ruby": "^0.6.1",
|
||||
"scheduler": "^0.26.0",
|
||||
"tamagui": "1.139.1",
|
||||
"zustand": "^5.0.8",
|
||||
"tamagui": "1.141.4",
|
||||
"zustand": "5.0.9",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.28.0",
|
||||
"@babel/preset-env": "^7.28.0",
|
||||
"@babel/runtime": "^7.28.0",
|
||||
"@babel/core": "7.28.5",
|
||||
"@babel/preset-env": "7.28.5",
|
||||
"@babel/runtime": "7.28.4",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "^9.32.0",
|
||||
"@eslint/js": "9.39.2",
|
||||
"@react-native-community/cli-platform-android": "20.0.0",
|
||||
"@react-native-community/cli-platform-ios": "20.0.0",
|
||||
"@react-native/babel-preset": "0.82.1",
|
||||
"@react-native/eslint-config": "0.82.1",
|
||||
"@react-native/metro-config": "0.82.1",
|
||||
"@react-native/typescript-config": "0.82.1",
|
||||
"@react-native/babel-preset": "0.83.0",
|
||||
"@react-native/eslint-config": "0.83.0",
|
||||
"@react-native/metro-config": "0.83.0",
|
||||
"@react-native/typescript-config": "0.83.0",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/lodash": "^4.17.20",
|
||||
"@types/lodash": "^4.17.21",
|
||||
"@types/node": "^24.2.1",
|
||||
"@types/react": "^19.1.1",
|
||||
"@types/react": "19.2.0",
|
||||
"@types/react-native-vector-icons": "^6.4.18",
|
||||
"@types/react-test-renderer": "19.1.0",
|
||||
"babel-plugin-module-resolver": "^5.0.2",
|
||||
"babel-plugin-react-compiler": "^1.0.0",
|
||||
"eslint": "^9.33.0",
|
||||
"eslint": "9.39.2",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-prettier": "^5.5.4",
|
||||
@@ -92,15 +92,15 @@
|
||||
"eslint-plugin-react-native": "^5.0.0",
|
||||
"globals": "^16.3.0",
|
||||
"husky": "^9.1.7",
|
||||
"jest": "^30.0.5",
|
||||
"jest": "30.2.0",
|
||||
"jscodeshift": "^17.3.0",
|
||||
"lint-staged": "^16.1.5",
|
||||
"patch-package": "8.0.0",
|
||||
"prettier": "^3.6.2",
|
||||
"react-dom": "^19.1.0",
|
||||
"prettier": "3.7.4",
|
||||
"react-dom": "19.2.0",
|
||||
"react-native-cli-bump-version": "^1.5.1",
|
||||
"react-test-renderer": "19.1.1",
|
||||
"typescript": "5.9.2",
|
||||
"react-test-renderer": "19.2.0",
|
||||
"typescript": "5.9.3",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -380,7 +380,7 @@
|
||||
|
||||
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
|
||||
|
||||
"@eslint/js": ["@eslint/js@9.39.1", "", {}, "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw=="],
|
||||
"@eslint/js": ["@eslint/js@9.39.2", "", {}, "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA=="],
|
||||
|
||||
"@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="],
|
||||
|
||||
@@ -530,95 +530,95 @@
|
||||
|
||||
"@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.82.1", "", {}, "sha512-B1SRwpntaAcckiatxbjzylvNK562Ayza05gdJCjDQHTiDafa1OABmyB5LHt7qWDOpNkaluD+w11vHF7pBmTpzQ=="],
|
||||
"@react-native/assets-registry": ["@react-native/assets-registry@0.83.0", "", {}, "sha512-EmGSKDvmnEnBrTK75T+0Syt6gy/HACOTfziw5+392Kr1Bb28Rv26GyOIkvptnT+bb2VDHU0hx9G0vSy5/S3rmQ=="],
|
||||
|
||||
"@react-native/babel-plugin-codegen": ["@react-native/babel-plugin-codegen@0.82.1", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@react-native/codegen": "0.82.1" } }, "sha512-wzmEz/RlR4SekqmaqeQjdMVh4LsnL9e62mrOikOOkHDQ3QN0nrKLuUDzXyYptVbxQ0IRua4pTm3efJLymDBoEg=="],
|
||||
"@react-native/babel-plugin-codegen": ["@react-native/babel-plugin-codegen@0.83.0", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@react-native/codegen": "0.83.0" } }, "sha512-H5K0hnv9EhcenojZb9nUMIKPvHZ7ba9vpCyQIeGJmUTDYwZqjmXXyH73+uZo+GHjCIq1n0eF/soC5HJQzalh/Q=="],
|
||||
|
||||
"@react-native/babel-preset": ["@react-native/babel-preset@0.82.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-transform-arrow-functions": "^7.24.7", "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-classes": "^7.25.4", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-for-of": "^7.24.7", "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-react-display-name": "^7.24.7", "@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/plugin-transform-react-jsx-self": "^7.24.7", "@babel/plugin-transform-react-jsx-source": "^7.24.7", "@babel/plugin-transform-regenerator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/plugin-transform-shorthand-properties": "^7.24.7", "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", "@react-native/babel-plugin-codegen": "0.82.1", "babel-plugin-syntax-hermes-parser": "0.32.0", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" } }, "sha512-Olj7p4XIsUWLKjlW46CqijaXt45PZT9Lbvv/Hz698FXTenPKk4k7sy6RGRGZPWO2TCBBfcb73dus1iNHRFSq7g=="],
|
||||
"@react-native/babel-preset": ["@react-native/babel-preset@0.83.0", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-transform-arrow-functions": "^7.24.7", "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-classes": "^7.25.4", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-for-of": "^7.24.7", "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-react-display-name": "^7.24.7", "@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/plugin-transform-react-jsx-self": "^7.24.7", "@babel/plugin-transform-react-jsx-source": "^7.24.7", "@babel/plugin-transform-regenerator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/plugin-transform-shorthand-properties": "^7.24.7", "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", "@react-native/babel-plugin-codegen": "0.83.0", "babel-plugin-syntax-hermes-parser": "0.32.0", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" } }, "sha512-v20aTae9+aergUgRQSiy3CLqRSJu5VrHLpPpyYcAkTJ2JWTbtTlKfYuEw0V/WMFpeYZnZ7IVtu/6gTISVV74UQ=="],
|
||||
|
||||
"@react-native/codegen": ["@react-native/codegen@0.82.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.32.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-ezXTN70ygVm9l2m0i+pAlct0RntoV4afftWMGUIeAWLgaca9qItQ54uOt32I/9dBJvzBibT33luIR/pBG0dQvg=="],
|
||||
"@react-native/codegen": ["@react-native/codegen@0.83.0", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.32.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-3fvMi/pSJHhikjwMZQplU4Ar9ANoR2GSBxotbkKIMI6iNduh+ln1FTvB2me69FA68aHtVZOO+cO+QpGCcvgaMA=="],
|
||||
|
||||
"@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.82.1", "", { "dependencies": { "@react-native/dev-middleware": "0.82.1", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.1", "metro-config": "^0.83.1", "metro-core": "^0.83.1", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "*" }, "optionalPeers": ["@react-native-community/cli", "@react-native/metro-config"] }, "sha512-H/eMdtOy9nEeX7YVeEG1N2vyCoifw3dr9OV8++xfUElNYV7LtSmJ6AqxZUUfxGJRDFPQvaU/8enmJlM/l11VxQ=="],
|
||||
"@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.83.0", "", { "dependencies": { "@react-native/dev-middleware": "0.83.0", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.3", "metro-config": "^0.83.3", "metro-core": "^0.83.3", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "*" }, "optionalPeers": ["@react-native-community/cli", "@react-native/metro-config"] }, "sha512-bJD5pLURgKY2YK0R6gUsFWHiblSAFt1Xyc2fsyCL8XBnB7kJfVhLAKGItk6j1QZbwm1Io41ekZxBmZdyQqIDrg=="],
|
||||
|
||||
"@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.82.1", "", {}, "sha512-a2O6M7/OZ2V9rdavOHyCQ+10z54JX8+B+apYKCQ6a9zoEChGTxUMG2YzzJ8zZJVvYf1ByWSNxv9Se0dca1hO9A=="],
|
||||
"@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.83.0", "", {}, "sha512-7XVbkH8nCjLKLe8z5DS37LNP62/QNNya/YuLlVoLfsiB54nR/kNZij5UU7rS0npAZ3WN7LR0anqLlYnzDd0JHA=="],
|
||||
|
||||
"@react-native/debugger-shell": ["@react-native/debugger-shell@0.82.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "fb-dotslash": "0.5.8" } }, "sha512-fdRHAeqqPT93bSrxfX+JHPpCXHApfDUdrXMXhoxlPgSzgXQXJDykIViKhtpu0M6slX6xU/+duq+AtP/qWJRpBw=="],
|
||||
"@react-native/debugger-shell": ["@react-native/debugger-shell@0.83.0", "", { "dependencies": { "cross-spawn": "^7.0.6", "fb-dotslash": "0.5.8" } }, "sha512-rJJxRRLLsKW+cqd0ALSBoqwL5SQTmwpd5SGl6rq9sY+fInCUKfkLEIc5HWQ0ppqoPyDteQVWbQ3a5VN84aJaNg=="],
|
||||
|
||||
"@react-native/dev-middleware": ["@react-native/dev-middleware@0.82.1", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.82.1", "@react-native/debugger-shell": "0.82.1", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^6.2.3" } }, "sha512-wuOIzms/Qg5raBV6Ctf2LmgzEOCqdP3p1AYN4zdhMT110c39TVMbunpBaJxm0Kbt2HQ762MQViF9naxk7SBo4w=="],
|
||||
"@react-native/dev-middleware": ["@react-native/dev-middleware@0.83.0", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.83.0", "@react-native/debugger-shell": "0.83.0", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^7.5.10" } }, "sha512-HWn42tbp0h8RWttua6d6PjseaSr3IdwkaoqVxhiM9kVDY7Ro00eO7tdlVgSzZzhIibdVS2b2C3x+sFoWhag1fA=="],
|
||||
|
||||
"@react-native/eslint-config": ["@react-native/eslint-config@0.82.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/eslint-parser": "^7.25.1", "@react-native/eslint-plugin": "0.82.1", "@typescript-eslint/eslint-plugin": "^8.36.0", "@typescript-eslint/parser": "^8.36.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-ft-flow": "^2.0.1", "eslint-plugin-jest": "^29.0.1", "eslint-plugin-react": "^7.30.1", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-native": "^4.0.0" }, "peerDependencies": { "eslint": ">=8", "prettier": ">=2" } }, "sha512-K3xCTEAg8WDd7WpDhQ1hsKbuY3OXaQtqpokeOdgyJag100ZvUX84YIaqDqsVaAZqjA53zCA5PbxerWs6mPA+PQ=="],
|
||||
"@react-native/eslint-config": ["@react-native/eslint-config@0.83.0", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/eslint-parser": "^7.25.1", "@react-native/eslint-plugin": "0.83.0", "@typescript-eslint/eslint-plugin": "^8.36.0", "@typescript-eslint/parser": "^8.36.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-ft-flow": "^2.0.1", "eslint-plugin-jest": "^29.0.1", "eslint-plugin-react": "^7.30.1", "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-native": "^4.0.0" }, "peerDependencies": { "eslint": ">=8", "prettier": ">=2" } }, "sha512-HTJg5XGQSGkVqeTvO7kOm1a1fNZ0VyZqhaLKAdWNwry+cWLkSnk9uohztnEIIP33FbP0Aybc7JuZIQon9OI3+w=="],
|
||||
|
||||
"@react-native/eslint-plugin": ["@react-native/eslint-plugin@0.82.1", "", {}, "sha512-PU0ho8pNp24pdegIpYRAwppfO8z7werpoTts2CJ/wXYQ+ryZKa2M31DHW+kl+K3wwwqVqFKAzLh4t3sP/mOqMQ=="],
|
||||
"@react-native/eslint-plugin": ["@react-native/eslint-plugin@0.83.0", "", {}, "sha512-a0lObGV1/1P6mrekSF+1KpRkdH2fefQ/8fm1kLTUNvR5mae8xXz+U+f+1lsgqqEHtoGHey5Ve5MUkjgj4WnqTQ=="],
|
||||
|
||||
"@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.82.1", "", {}, "sha512-KkF/2T1NSn6EJ5ALNT/gx0MHlrntFHv8YdooH9OOGl9HQn5NM0ZmQSr86o5utJsGc7ME3R6p3SaQuzlsFDrn8Q=="],
|
||||
"@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.83.0", "", {}, "sha512-BXZRmfsbgPhEPkrRPjk2njA2AzhSelBqhuoklnv3DdLTdxaRjKYW+LW0zpKo1k3qPKj7kG1YGI3miol6l1GB5g=="],
|
||||
|
||||
"@react-native/js-polyfills": ["@react-native/js-polyfills@0.82.1", "", {}, "sha512-tf70X7pUodslOBdLN37J57JmDPB/yiZcNDzS2m+4bbQzo8fhx3eG9QEBv5n4fmzqfGAgSB4BWRHgDMXmmlDSVA=="],
|
||||
"@react-native/js-polyfills": ["@react-native/js-polyfills@0.83.0", "", {}, "sha512-cVB9BMqlfbQR0v4Wxi5M2yDhZoKiNqWgiEXpp7ChdZIXI0SEnj8WwLwE3bDkyOfF8tCHdytpInXyg/al2O+dLQ=="],
|
||||
|
||||
"@react-native/metro-babel-transformer": ["@react-native/metro-babel-transformer@0.82.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@react-native/babel-preset": "0.82.1", "hermes-parser": "0.32.0", "nullthrows": "^1.1.1" } }, "sha512-kVQyYxYe1Da7cr7uGK9c44O6vTzM8YY3KW9CSLhhV1CGw7jmohU1HfLaUxDEmYfFZMc4Kj3JsIEbdUlaHMtprQ=="],
|
||||
"@react-native/metro-babel-transformer": ["@react-native/metro-babel-transformer@0.83.0", "", { "dependencies": { "@babel/core": "^7.25.2", "@react-native/babel-preset": "0.83.0", "hermes-parser": "0.32.0", "nullthrows": "^1.1.1" } }, "sha512-hB5kpR5Ho9l9xKuh5uHZEIFqnuaW8T7rDYwqf1j0xvTZu88KwaHAXya2IpDZsjlWzVMCl50cAwPkVZOlEOfJvw=="],
|
||||
|
||||
"@react-native/metro-config": ["@react-native/metro-config@0.82.1", "", { "dependencies": { "@react-native/js-polyfills": "0.82.1", "@react-native/metro-babel-transformer": "0.82.1", "metro-config": "^0.83.1", "metro-runtime": "^0.83.1" } }, "sha512-mAY6R3xnDMlmDOrUCAtLTjIkli26DZt4LNVuAjDEdnlv5sHANOr5x4qpMn7ea1p9Q/tpfHLalPQUQeJ8CZH4gA=="],
|
||||
"@react-native/metro-config": ["@react-native/metro-config@0.83.0", "", { "dependencies": { "@react-native/js-polyfills": "0.83.0", "@react-native/metro-babel-transformer": "0.83.0", "metro-config": "^0.83.3", "metro-runtime": "^0.83.3" } }, "sha512-7mWZNZOJJLMJ8adBrAgAXcwtyn8PtPjAGavK8k3/mtsWYm79ncf5PD8D9puh6wBHCYwPu2ff/l23nNV8JsqLyg=="],
|
||||
|
||||
"@react-native/normalize-color": ["@react-native/normalize-color@2.1.0", "", {}, "sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA=="],
|
||||
|
||||
"@react-native/normalize-colors": ["@react-native/normalize-colors@0.82.1", "", {}, "sha512-CCfTR1uX+Z7zJTdt3DNX9LUXr2zWXsNOyLbwupW2wmRzrxlHRYfmLgTABzRL/cKhh0Ubuwn15o72MQChvCRaHw=="],
|
||||
"@react-native/normalize-colors": ["@react-native/normalize-colors@0.83.0", "", {}, "sha512-DG1ELOqQ6RS82R1zEUGTWa/pfSPOf+vwAnQB7Ao1vRuhW/xdd2OPQJyqx5a5QWMYpGrlkCb7ERxEVX6p2QODCA=="],
|
||||
|
||||
"@react-native/typescript-config": ["@react-native/typescript-config@0.82.1", "", {}, "sha512-kCTjmBg44p0kqU4xEMg7l6SNJyHWTHuTqiT9MpHasEYcnVpBWyEQsSQAiVKONHwcUWcAktrGVLE1dYGfBmPJ3Q=="],
|
||||
"@react-native/typescript-config": ["@react-native/typescript-config@0.83.0", "", {}, "sha512-8IcgamT0qoBDL3D8Ho6YHkQrxUMf3fKHkRd6MYDjVKNamz0XtfXNLY/FNnUOolx1HbgMkkwKFcbP3AbIKFxirQ=="],
|
||||
|
||||
"@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.82.1", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.1.1", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-f5zpJg9gzh7JtCbsIwV+4kP3eI0QBuA93JGmwFRd4onQ3DnCjV2J5pYqdWtM95sjSKK1dyik59Gj01lLeKqs1Q=="],
|
||||
"@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.8.10", "", { "dependencies": { "@react-navigation/elements": "^2.9.0", "color": "^4.2.3", "sf-symbols-typescript": "^2.1.0" }, "peerDependencies": { "@react-navigation/native": "^7.1.23", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-NxKjtlRwkGU3O3hPxpS+Aq7mVNfgtLzBe4xpGjQNphLzklRbxa6Me//m2eKzogpitZhLR2xZb1A49HrLuWe2ww=="],
|
||||
"@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/core": ["@react-navigation/core@7.13.4", "", { "dependencies": { "@react-navigation/routers": "^7.5.2", "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-JM9bkb7fr4P5YUOVEwoAZq3xPeSL9V6Nd1KKTyAwCgGUVhESbSRSy3Ri/PGu6ZcLb/t7/tM1NqP5tV1e1bAwUg=="],
|
||||
"@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/elements": ["@react-navigation/elements@2.9.0", "", { "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.23", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" }, "optionalPeers": ["@react-native-masked-view/masked-view"] }, "sha512-423uE+q/esaiMbXVLckFOd9MbWG06/vCYOP2hwzEUj9ZwzUgSpsIPovcu78qa8UMuvKD8wkyouM01Wvav1y/KQ=="],
|
||||
"@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/material-top-tabs": ["@react-navigation/material-top-tabs@7.4.7", "", { "dependencies": { "@react-navigation/elements": "^2.9.0", "color": "^4.2.3", "react-native-tab-view": "^4.2.0" }, "peerDependencies": { "@react-navigation/native": "^7.1.23", "react": ">= 18.2.0", "react-native": "*", "react-native-pager-view": ">= 6.0.0", "react-native-safe-area-context": ">= 4.0.0" } }, "sha512-0fv+Ym9kOO7DLf8GRmkt9zNKPTbnYU62ATacv0zirNA+vBDT/fhlE67orUXsQa/nORXlUMvllCaKPf/oyD7UcQ=="],
|
||||
"@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/native": ["@react-navigation/native@7.1.23", "", { "dependencies": { "@react-navigation/core": "^7.13.4", "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-V+drzVkoVA8VO83cJ59UYe7dfdnMFpGDAybp7d5O1ufxt321Z5tOtNDOzhMGzHUENqo9QWc4P/HuCUmz7KMy+A=="],
|
||||
"@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-stack": ["@react-navigation/native-stack@7.8.4", "", { "dependencies": { "@react-navigation/elements": "^2.9.0", "color": "^4.2.3", "sf-symbols-typescript": "^2.1.0", "warn-once": "^0.1.1" }, "peerDependencies": { "@react-navigation/native": "^7.1.23", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-7kpYHoZZ81SPtDDG9ttZtI4nXR8GbVsLL1KnT/7RiLkFdqHXlriGpVhG5BKJRS1CYXrGEn40NogYW2+OBplglg=="],
|
||||
"@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/routers": ["@react-navigation/routers@7.5.2", "", { "dependencies": { "nanoid": "^3.3.11" } }, "sha512-kymreY5aeTz843E+iPAukrsOtc7nabAH6novtAPREmmGu77dQpfxPB2ZWpKb5nRErIRowp1kYRoN2Ckl+S6JYw=="],
|
||||
"@react-navigation/routers": ["@react-navigation/routers@7.5.3", "", { "dependencies": { "nanoid": "^3.3.11" } }, "sha512-1tJHg4KKRJuQ1/EvJxatrMef3NZXEPzwUIUZ3n1yJ2t7Q97siwRtbynRpQG9/69ebbtiZ8W3ScOZF/OmhvM4Rg=="],
|
||||
|
||||
"@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="],
|
||||
|
||||
"@sentry-internal/browser-utils": ["@sentry-internal/browser-utils@10.24.0", "", { "dependencies": { "@sentry/core": "10.24.0" } }, "sha512-2nLj5TgPc/KkGy7LCW9sBGJT0CT+9U+Vlqa8yl7APd5agzxrpRyTcm4hPBBOw5tw7D4NWWUMulFxtZKZzT/Rcw=="],
|
||||
"@sentry-internal/browser-utils": ["@sentry-internal/browser-utils@10.30.0", "", { "dependencies": { "@sentry/core": "10.30.0" } }, "sha512-dVsHTUbvgaLNetWAQC6yJFnmgD0xUbVgCkmzNB7S28wIP570GcZ4cxFGPOkXbPx6dEBUfoOREeXzLqjJLtJPfg=="],
|
||||
|
||||
"@sentry-internal/feedback": ["@sentry-internal/feedback@10.24.0", "", { "dependencies": { "@sentry/core": "10.24.0" } }, "sha512-leYFQfgax50sYTEgkcEzPP8lTvtE12nryJSsdtPNym6gmQgA2SN20oSRNlxo1AitNpwNnTkj+ow/Y9ytrJlXUQ=="],
|
||||
"@sentry-internal/feedback": ["@sentry-internal/feedback@10.30.0", "", { "dependencies": { "@sentry/core": "10.30.0" } }, "sha512-+bnQZ6SNF265nTXrRlXTmq5Ila1fRfraDOAahlOT/VM4j6zqCvNZzmeDD9J6IbxiAdhlp/YOkrG3zbr5vgYo0A=="],
|
||||
|
||||
"@sentry-internal/replay": ["@sentry-internal/replay@10.24.0", "", { "dependencies": { "@sentry-internal/browser-utils": "10.24.0", "@sentry/core": "10.24.0" } }, "sha512-xqSw3sCu5yxDQFpo/42t1zzxe+6kn542DRwHNBqIBd0CWN7un/j5YIW1Sq/+TdHYGbeG8LzD5UOuvZsT4zF2nQ=="],
|
||||
"@sentry-internal/replay": ["@sentry-internal/replay@10.30.0", "", { "dependencies": { "@sentry-internal/browser-utils": "10.30.0", "@sentry/core": "10.30.0" } }, "sha512-Pj/fMIZQkXzIw6YWpxKWUE5+GXffKq6CgXwHszVB39al1wYz1gTIrTqJqt31IBLIihfCy8XxYddglR2EW0BVIQ=="],
|
||||
|
||||
"@sentry-internal/replay-canvas": ["@sentry-internal/replay-canvas@10.24.0", "", { "dependencies": { "@sentry-internal/replay": "10.24.0", "@sentry/core": "10.24.0" } }, "sha512-pjNZ+/L/ct0huutkTQrcR+V/v3ICf5wKE8OOB2Dt3DcjNsbLKtUsy9Um6bCbSz/fRI8K/ZFlVLjiIQkMW+WX0Q=="],
|
||||
"@sentry-internal/replay-canvas": ["@sentry-internal/replay-canvas@10.30.0", "", { "dependencies": { "@sentry-internal/replay": "10.30.0", "@sentry/core": "10.30.0" } }, "sha512-RIlIz+XQ4DUWaN60CjfmicJq2O2JRtDKM5lw0wB++M5ha0TBh6rv+Ojf6BDgiV3LOQ7lZvCM57xhmNUtrGmelg=="],
|
||||
|
||||
"@sentry/babel-plugin-component-annotate": ["@sentry/babel-plugin-component-annotate@4.6.0", "", {}, "sha512-3soTX50JPQQ51FSbb4qvNBf4z/yP7jTdn43vMTp9E4IxvJ9HKJR7OEuKkCMszrZmWsVABXl02msqO7QisePdiQ=="],
|
||||
"@sentry/babel-plugin-component-annotate": ["@sentry/babel-plugin-component-annotate@4.6.1", "", {}, "sha512-aSIk0vgBqv7PhX6/Eov+vlI4puCE0bRXzUG5HdCsHBpAfeMkI8Hva6kSOusnzKqs8bf04hU7s3Sf0XxGTj/1AA=="],
|
||||
|
||||
"@sentry/browser": ["@sentry/browser@10.24.0", "", { "dependencies": { "@sentry-internal/browser-utils": "10.24.0", "@sentry-internal/feedback": "10.24.0", "@sentry-internal/replay": "10.24.0", "@sentry-internal/replay-canvas": "10.24.0", "@sentry/core": "10.24.0" } }, "sha512-kKSNYupPIIk02+4OVR13qpJ8/uzsf6SrCzgxr6EvdK8qEuGYLJyM6lLJze/C5BZTSsam6UGAfahrSI1K5il8oQ=="],
|
||||
"@sentry/browser": ["@sentry/browser@10.30.0", "", { "dependencies": { "@sentry-internal/browser-utils": "10.30.0", "@sentry-internal/feedback": "10.30.0", "@sentry-internal/replay": "10.30.0", "@sentry-internal/replay-canvas": "10.30.0", "@sentry/core": "10.30.0" } }, "sha512-7M/IJUMLo0iCMLNxDV/OHTPI0WKyluxhCcxXJn7nrCcolu8A1aq9R8XjKxm0oTCO8ht5pz8bhGXUnYJj4eoEBA=="],
|
||||
|
||||
"@sentry/cli": ["@sentry/cli@2.58.0", "", { "dependencies": { "https-proxy-agent": "^5.0.0", "node-fetch": "^2.6.7", "progress": "^2.0.3", "proxy-from-env": "^1.1.0", "which": "^2.0.2" }, "optionalDependencies": { "@sentry/cli-darwin": "2.58.0", "@sentry/cli-linux-arm": "2.58.0", "@sentry/cli-linux-arm64": "2.58.0", "@sentry/cli-linux-i686": "2.58.0", "@sentry/cli-linux-x64": "2.58.0", "@sentry/cli-win32-arm64": "2.58.0", "@sentry/cli-win32-i686": "2.58.0", "@sentry/cli-win32-x64": "2.58.0" }, "bin": { "sentry-cli": "bin/sentry-cli" } }, "sha512-ywfV2uYkNaW5BGFBgIEX+urkxWtY03GYKN08OLYJpfJeOWl5tzxAKKg+AkMZqnqsDqjCf8gLjZh7sF4jY+ZE1Q=="],
|
||||
"@sentry/cli": ["@sentry/cli@2.58.4", "", { "dependencies": { "https-proxy-agent": "^5.0.0", "node-fetch": "^2.6.7", "progress": "^2.0.3", "proxy-from-env": "^1.1.0", "which": "^2.0.2" }, "optionalDependencies": { "@sentry/cli-darwin": "2.58.4", "@sentry/cli-linux-arm": "2.58.4", "@sentry/cli-linux-arm64": "2.58.4", "@sentry/cli-linux-i686": "2.58.4", "@sentry/cli-linux-x64": "2.58.4", "@sentry/cli-win32-arm64": "2.58.4", "@sentry/cli-win32-i686": "2.58.4", "@sentry/cli-win32-x64": "2.58.4" }, "bin": { "sentry-cli": "bin/sentry-cli" } }, "sha512-ArDrpuS8JtDYEvwGleVE+FgR+qHaOp77IgdGSacz6SZy6Lv90uX0Nu4UrHCQJz8/xwIcNxSqnN22lq0dH4IqTg=="],
|
||||
|
||||
"@sentry/cli-darwin": ["@sentry/cli-darwin@2.58.0", "", { "os": "darwin" }, "sha512-dI8+85N2xNsQeJZBbfGkjFScYH0xP/8+TDgoA5YiWWxsD/qSlWv1pf2VCR83smMyfcjIkDiPYIxBDticD67skQ=="],
|
||||
"@sentry/cli-darwin": ["@sentry/cli-darwin@2.58.4", "", { "os": "darwin" }, "sha512-kbTD+P4X8O+nsNwPxCywtj3q22ecyRHWff98rdcmtRrvwz8CKi/T4Jxn/fnn2i4VEchy08OWBuZAqaA5Kh2hRQ=="],
|
||||
|
||||
"@sentry/cli-linux-arm": ["@sentry/cli-linux-arm@2.58.0", "", { "os": [ "linux", "android", "freebsd", ], "cpu": "arm" }, "sha512-QxBWSQkm2OL8d0XXTUOcX5RYZzZGkMw48ubU4g/c4rlT06PuJV56Z03jsMQdJWUDzKmVYoJdvFV/whxYIkwmWw=="],
|
||||
"@sentry/cli-linux-arm": ["@sentry/cli-linux-arm@2.58.4", "", { "os": [ "linux", "android", "freebsd", ], "cpu": "arm" }, "sha512-rdQ8beTwnN48hv7iV7e7ZKucPec5NJkRdrrycMJMZlzGBPi56LqnclgsHySJ6Kfq506A2MNuQnKGaf/sBC9REA=="],
|
||||
|
||||
"@sentry/cli-linux-arm64": ["@sentry/cli-linux-arm64@2.58.0", "", { "os": [ "linux", "android", "freebsd", ], "cpu": "arm64" }, "sha512-Fso5GImxQOigZqLHAHhz85w71zxS1bvL52PI/tcjadmKrIaJdD3ANukC0UcKyKuj9xhr/k1ufNR7V+2BD16kmg=="],
|
||||
"@sentry/cli-linux-arm64": ["@sentry/cli-linux-arm64@2.58.4", "", { "os": [ "linux", "android", "freebsd", ], "cpu": "arm64" }, "sha512-0g0KwsOozkLtzN8/0+oMZoOuQ0o7W6O+hx+ydVU1bktaMGKEJLMAWxOQNjsh1TcBbNIXVOKM/I8l0ROhaAb8Ig=="],
|
||||
|
||||
"@sentry/cli-linux-i686": ["@sentry/cli-linux-i686@2.58.0", "", { "os": [ "linux", "android", "freebsd", ], "cpu": "ia32" }, "sha512-Av+T5YwuTtbOpe/Fyr/lsbl5XIZTFspHCiAt4Kgtllme6T1ASIDhQDXDh/OVJ8So4pHkToTn3iH8mm8vLqBqOA=="],
|
||||
"@sentry/cli-linux-i686": ["@sentry/cli-linux-i686@2.58.4", "", { "os": [ "linux", "android", "freebsd", ], "cpu": "ia32" }, "sha512-NseoIQAFtkziHyjZNPTu1Gm1opeQHt7Wm1LbLrGWVIRvUOzlslO9/8i6wETUZ6TjlQxBVRgd3Q0lRBG2A8rFYA=="],
|
||||
|
||||
"@sentry/cli-linux-x64": ["@sentry/cli-linux-x64@2.58.0", "", { "os": [ "linux", "android", "freebsd", ], "cpu": "x64" }, "sha512-AxK0eqZbHn0NGWsAE8bzt/iRMMUlqsx77kru/TIBQy9cMMJaq+rLb63W7HWXln4ER32nPZYx+JuhHD9UNiAFHA=="],
|
||||
"@sentry/cli-linux-x64": ["@sentry/cli-linux-x64@2.58.4", "", { "os": [ "linux", "android", "freebsd", ], "cpu": "x64" }, "sha512-d3Arz+OO/wJYTqCYlSN3Ktm+W8rynQ/IMtSZLK8nu0ryh5mJOh+9XlXY6oDXw4YlsM8qCRrNquR8iEI1Y/IH+Q=="],
|
||||
|
||||
"@sentry/cli-win32-arm64": ["@sentry/cli-win32-arm64@2.58.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-lIRTfGjD1TQIOuFh4rJGWt3zXyeXAlfoYYQbzG/rP6gXstiGENQtfEXZyKT+wlIGSqtbBGVfL8xp65ryjbXSgQ=="],
|
||||
"@sentry/cli-win32-arm64": ["@sentry/cli-win32-arm64@2.58.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-bqYrF43+jXdDBh0f8HIJU3tbvlOFtGyRjHB8AoRuMQv9TEDUfENZyCelhdjA+KwDKYl48R1Yasb4EHNzsoO83w=="],
|
||||
|
||||
"@sentry/cli-win32-i686": ["@sentry/cli-win32-i686@2.58.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-7VdB3QZ/3t2FABgIwRP2SoJcDmZaPPPZofVmJem+FgeONeLOUvHQw9WSLG4y5Dfc9yi5wO31H1ClW4uxv8EtuA=="],
|
||||
"@sentry/cli-win32-i686": ["@sentry/cli-win32-i686@2.58.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-3triFD6jyvhVcXOmGyttf+deKZcC1tURdhnmDUIBkiDPJKGT/N5xa4qAtHJlAB/h8L9jgYih9bvJnvvFVM7yug=="],
|
||||
|
||||
"@sentry/cli-win32-x64": ["@sentry/cli-win32-x64@2.58.0", "", { "os": "win32", "cpu": "x64" }, "sha512-uItx4P4v9cKbgVbOpuShvIV8g42qLmZorPHwg3pYUu78c85xAWrmiXL+0JKNUf5JVBEHeHB+rIu08AZfDMhxig=="],
|
||||
"@sentry/cli-win32-x64": ["@sentry/cli-win32-x64@2.58.4", "", { "os": "win32", "cpu": "x64" }, "sha512-cSzN4PjM1RsCZ4pxMjI0VI7yNCkxiJ5jmWncyiwHXGiXrV1eXYdQ3n1LhUYLZ91CafyprR0OhDcE+RVZ26Qb5w=="],
|
||||
|
||||
"@sentry/core": ["@sentry/core@10.24.0", "", {}, "sha512-apJ1NtCK/Kt5uTytee+4rhhcTm4u3+z0bESH8GNMXMcuJ/A3Rvy3HUh+gqCx4BTOR0Sa44dbMvJcm/ewO+mzVg=="],
|
||||
"@sentry/core": ["@sentry/core@10.30.0", "", {}, "sha512-IfNuqIoGVO9pwphwbOptAEJJI1SCAfewS5LBU1iL7hjPBHYAnE8tCVzyZN+pooEkQQ47Q4rGanaG1xY8mjTT1A=="],
|
||||
|
||||
"@sentry/react": ["@sentry/react@10.24.0", "", { "dependencies": { "@sentry/browser": "10.24.0", "@sentry/core": "10.24.0", "hoist-non-react-statics": "^3.3.2" }, "peerDependencies": { "react": "^16.14.0 || 17.x || 18.x || 19.x" } }, "sha512-HW83v7LC5E06H/cYtU4fnlOV5fykNl5QkrOoZzKrYfAUCh4T11gjd4RvlvI+WaXb6nhD+gW2YLu95iIRHid/TA=="],
|
||||
"@sentry/react": ["@sentry/react@10.30.0", "", { "dependencies": { "@sentry/browser": "10.30.0", "@sentry/core": "10.30.0", "hoist-non-react-statics": "^3.3.2" }, "peerDependencies": { "react": "^16.14.0 || 17.x || 18.x || 19.x" } }, "sha512-3co0QwAU9VrCVBWgpRf/4G19MwzR+DM0sDe9tgN7P3pv/tMlEHhnPFv88nPfuSa2W8uVCpHehvV+GnUPF4V7Ag=="],
|
||||
|
||||
"@sentry/react-native": ["@sentry/react-native@7.6.0", "", { "dependencies": { "@sentry/babel-plugin-component-annotate": "4.6.0", "@sentry/browser": "10.24.0", "@sentry/cli": "2.58.0", "@sentry/core": "10.24.0", "@sentry/react": "10.24.0", "@sentry/types": "10.24.0" }, "peerDependencies": { "expo": ">=49.0.0", "react": ">=17.0.0", "react-native": ">=0.65.0" }, "optionalPeers": ["expo"], "bin": { "sentry-expo-upload-sourcemaps": "scripts/expo-upload-sourcemaps.js" } }, "sha512-oL6Tl6B+vHP/OtHt9LkhZMg+mntjn2mFTzqnPCggXDIPxn5cqZ41154wA7d33i6JLKiXiK02EHJlnImdb4s06w=="],
|
||||
"@sentry/react-native": ["@sentry/react-native@7.8.0", "", { "dependencies": { "@sentry/babel-plugin-component-annotate": "4.6.1", "@sentry/browser": "10.30.0", "@sentry/cli": "2.58.4", "@sentry/core": "10.30.0", "@sentry/react": "10.30.0", "@sentry/types": "10.30.0" }, "peerDependencies": { "expo": ">=49.0.0", "react": ">=17.0.0", "react-native": ">=0.65.0" }, "optionalPeers": ["expo"], "bin": { "sentry-expo-upload-sourcemaps": "scripts/expo-upload-sourcemaps.js" } }, "sha512-0YMD0ObuGPbJVfHCBaYTfmRtS7tUd64W2GMNPA3b6rGlVlMQlL7bfdkCUouVBZzFDJYLV8ik1PzJKPWunKHCvw=="],
|
||||
|
||||
"@sentry/types": ["@sentry/types@10.24.0", "", { "dependencies": { "@sentry/core": "10.24.0" } }, "sha512-hLcLS9mFVqZGbkVgkvnkFvwbqkxSv2vKI6zYNJ+3ZW6PWyS82KBEHgedwxtg2F6lCGWQHQxINKjp0GZYKxtRjg=="],
|
||||
"@sentry/types": ["@sentry/types@10.30.0", "", { "dependencies": { "@sentry/core": "10.30.0" } }, "sha512-tSyzG/JunWjbuQDDwP3DKgt8KP23ZSuNUEudMSv2jCF/956o8ksamPeidCTSVMXoEyTt5tvimWNeNvUFIFq3EA=="],
|
||||
|
||||
"@shopify/flash-list": ["@shopify/flash-list@2.2.0", "", { "peerDependencies": { "@babel/runtime": "*", "react": "*", "react-native": "*" } }, "sha512-mL61IofcfBNRZ/qazIf+pghGULkcZUQ7EZNldH1JBbIjtDb25ADSiQrt62ZTnRz0H5+bPFEZUmN9+WChHzX8pw=="],
|
||||
|
||||
@@ -634,211 +634,211 @@
|
||||
|
||||
"@sinonjs/fake-timers": ["@sinonjs/fake-timers@10.3.0", "", { "dependencies": { "@sinonjs/commons": "^3.0.0" } }, "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA=="],
|
||||
|
||||
"@tamagui/accordion": ["@tamagui/accordion@1.139.1", "", { "dependencies": { "@tamagui/collapsible": "1.139.1", "@tamagui/collection": "1.139.1", "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/polyfill-dev": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/text": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/use-direction": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-hH3/ZZwDhY6sPIhSzG3PjmH9B2rkV8GPDDOwwSBSCck2B2J/Z3fT8XLH99OtPIq+VeexQrAHiL/yaZz17lUFsQ=="],
|
||||
"@tamagui/accordion": ["@tamagui/accordion@1.141.4", "", { "dependencies": { "@tamagui/collapsible": "1.141.4", "@tamagui/collection": "1.141.4", "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/polyfill-dev": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/text": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/use-direction": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-cVoU6y/XZJzEXYQ7Jc0ROLU4ehhxRZWq6Qrm3uq1rBavY+WGDGzaCGDl69i+uzSJK3aotpt4KxkNyhsxXtfEog=="],
|
||||
|
||||
"@tamagui/adapt": ["@tamagui/adapt@1.139.1", "", { "dependencies": { "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/portal": "1.139.1", "@tamagui/z-index-stack": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-w8od60YREZ1kKbLZ5sncN2/7AonnBS4VU2yW9XAFxipV2jPtihpCETjA1fKi6IYe/m6SbLLe8XQuchMyxX9/Lw=="],
|
||||
"@tamagui/adapt": ["@tamagui/adapt@1.141.4", "", { "dependencies": { "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/portal": "1.141.4", "@tamagui/z-index-stack": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-kQQYMFNyrca7Zj+D24rhr4aWmvbruDh5hqdmzIBT5e71RSzQuH5wCO3wmCzAuTnYw3RDZSFO57sO3B6OOdOeiw=="],
|
||||
|
||||
"@tamagui/alert-dialog": ["@tamagui/alert-dialog@1.139.1", "", { "dependencies": { "@tamagui/animate-presence": "1.139.1", "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/dialog": "1.139.1", "@tamagui/dismissable": "1.139.1", "@tamagui/focus-scope": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/polyfill-dev": "1.139.1", "@tamagui/popper": "1.139.1", "@tamagui/portal": "1.139.1", "@tamagui/remove-scroll": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/text": "1.139.1", "@tamagui/use-controllable-state": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-oWepuzhaSYHWH1yofaByyWk4+znAwIc1cAQY25+gBEEvy1lGfiz6utkGvh6eOzX7DlC8IXJYVnVGq2Jv+TRiGw=="],
|
||||
"@tamagui/alert-dialog": ["@tamagui/alert-dialog@1.141.4", "", { "dependencies": { "@tamagui/animate-presence": "1.141.4", "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/dialog": "1.141.4", "@tamagui/dismissable": "1.141.4", "@tamagui/focus-scope": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/polyfill-dev": "1.141.4", "@tamagui/popper": "1.141.4", "@tamagui/portal": "1.141.4", "@tamagui/remove-scroll": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/text": "1.141.4", "@tamagui/use-controllable-state": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-+K0O99L/GAxnfSJDuExEd4IOA9EoZZk7HBwBCoxarZnCZ4/XKQFH33VoltMDuk3/D0qgCujnNHM6111Aowh6DQ=="],
|
||||
|
||||
"@tamagui/animate": ["@tamagui/animate@1.139.1", "", { "dependencies": { "@tamagui/animate-presence": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-r+XQVbQWQUIs4FmubIsxECvfE7tShrZK5Hs2d03HzA4+8LNiEJcmhAFf6nB+0ILKmT0qBXm61+0Ozrrhfqx/DQ=="],
|
||||
"@tamagui/animate": ["@tamagui/animate@1.141.4", "", { "dependencies": { "@tamagui/animate-presence": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-ysfxPYHAXSVsmktGkIkvUoNQ4xRoo4Z7LyP3sZIrR/8X1o13hl6m7rBXip7Cq/l6YY63f/F7UdbCRDXWwIUpiQ=="],
|
||||
|
||||
"@tamagui/animate-presence": ["@tamagui/animate-presence@1.139.1", "", { "dependencies": { "@tamagui/constants": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/use-constant": "1.139.1", "@tamagui/use-force-update": "1.139.1", "@tamagui/use-presence": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-PmBPQ2x1eKhHsjXJ7CbNbprN4KZjEFpvXKrlnRtQoykEtc0Ya2fZV0icVSgAitlGMUJWROLXKbiFPbiV6IUxUg=="],
|
||||
"@tamagui/animate-presence": ["@tamagui/animate-presence@1.141.4", "", { "dependencies": { "@tamagui/constants": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/use-constant": "1.141.4", "@tamagui/use-force-update": "1.141.4", "@tamagui/use-presence": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-lNeIeIB9lugp43SMZvTlKjdjKtnb1N8XF4aShaI2FKP125CgiSSZ0vf12jyKBBrPpvmr/hbnxSApH38FxPHIOA=="],
|
||||
|
||||
"@tamagui/animations-css": ["@tamagui/animations-css@1.139.1", "", { "dependencies": { "@tamagui/constants": "1.139.1", "@tamagui/cubic-bezier-animator": "1.139.1", "@tamagui/use-presence": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-Dr7E7gwZSVkhXQcn2PTY7jAHLBly8VfPRFfBRBda2nohA/VlQIYCODlxhbVCJvNKqG3UzmSF29wxGM2S2MlKeA=="],
|
||||
"@tamagui/animations-css": ["@tamagui/animations-css@1.141.4", "", { "dependencies": { "@tamagui/constants": "1.141.4", "@tamagui/cubic-bezier-animator": "1.141.4", "@tamagui/use-presence": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-fTasO+QAOLsi/fBvuyUdunat8QKxEpOVcEpI2caIzf1/PfAzPkToub8GC8jUDxCOxp1PTMFO61xDgV7ryhLD8g=="],
|
||||
|
||||
"@tamagui/animations-moti": ["@tamagui/animations-moti@1.139.1", "", { "dependencies": { "@tamagui/core": "1.139.1", "@tamagui/use-presence": "1.139.1", "moti": "^0.30.0" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-k0jEKnzZQjyZU64wDPzKSXoA+j7vArGTtlKUO4SsU3p6mB5urNbFdLkNolOzI1uZH8QFhoOLE2fgRPauf6ToXQ=="],
|
||||
"@tamagui/animations-moti": ["@tamagui/animations-moti@1.141.4", "", { "dependencies": { "@tamagui/core": "1.141.4", "@tamagui/use-presence": "1.141.4", "moti": "^0.30.0" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-K2TSnqbhK1Qg6ktnMlQwxvzB639AEgiyEHMI9uMQf+f/Vto5qeLTvD1XscBrQRFTa1qagMXL0rzLX3ijRySEfQ=="],
|
||||
|
||||
"@tamagui/animations-react-native": ["@tamagui/animations-react-native@1.139.1", "", { "dependencies": { "@tamagui/constants": "1.139.1", "@tamagui/use-presence": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-SX2I1wiAhFxpp2oRPaQjEhu/lF/JTwsmaDU2k6HerzL/mB6VaLj16HXFy+ywMSTwgqIDPYTWTD4Mvl2HX/Wegw=="],
|
||||
"@tamagui/animations-react-native": ["@tamagui/animations-react-native@1.141.4", "", { "dependencies": { "@tamagui/constants": "1.141.4", "@tamagui/use-presence": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-OV6ZCeeyKrGRlQaoDvYH+K4KuR7hRyG5/HD/yBecYxstD8jpT/w35R6u3jaeO3RhVD5UtRoGR7yOxObFr0KiOQ=="],
|
||||
|
||||
"@tamagui/avatar": ["@tamagui/avatar@1.139.1", "", { "dependencies": { "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/image": "1.139.1", "@tamagui/shapes": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/text": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-Kvgm4f8XVrnFwuAd3t1FDZ69nhJb2JC8Ty2ACHAGrIpWRp2eO4U24dATEdGftifMpK+8ukBdYQDBK0iMSsfHuw=="],
|
||||
"@tamagui/avatar": ["@tamagui/avatar@1.141.4", "", { "dependencies": { "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/image": "1.141.4", "@tamagui/shapes": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/text": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-K7cvgUbtriVVa6wSCPwZ58JqePvg0BqsiSUF1qZxNeLC3VozPFu56Y+NebPf5xdkK4lmLwhUOuA1599S1JIfpg=="],
|
||||
|
||||
"@tamagui/button": ["@tamagui/button@1.139.1", "", { "dependencies": { "@tamagui/config-default": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/font-size": "1.139.1", "@tamagui/get-button-sized": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/helpers-tamagui": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/text": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-gOlRoxKuLvpPotEIkAyHbncYx6hdPYYhAt/tqgJuWFEm2MQje8FJjhvnVGVwAXehDTx+6wc5LkxgNGpR7VSr4g=="],
|
||||
"@tamagui/button": ["@tamagui/button@1.141.4", "", { "dependencies": { "@tamagui/config-default": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/font-size": "1.141.4", "@tamagui/get-button-sized": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/helpers-tamagui": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/text": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-xqlMFabe+Xgobbwe12LH8BhJpYECuihZsWz/RX9/sctfNc/UurmC7n9Avn40DypqR0YMBOXjz1mLRJQpm2WwVw=="],
|
||||
|
||||
"@tamagui/card": ["@tamagui/card@1.139.1", "", { "dependencies": { "@tamagui/create-context": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-7w6dVESuD5FKGxYlOxAu1ednNBD0LQKvFHMRKYL/C1FdfJrCGGrMoGAWyjTO1sS4IelhCmftg+QhHDZsZAvdqA=="],
|
||||
"@tamagui/card": ["@tamagui/card@1.141.4", "", { "dependencies": { "@tamagui/create-context": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-/c/Aehx/mkKPLJWyHINJd02DQLpBWfSUQXR34Dd12bDbmfSmkK/v0GZ+YtggBOZthoR6KFAkG7erINRErAEgHQ=="],
|
||||
|
||||
"@tamagui/checkbox": ["@tamagui/checkbox@1.139.1", "", { "dependencies": { "@tamagui/checkbox-headless": "1.139.1", "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/focusable": "1.139.1", "@tamagui/font-size": "1.139.1", "@tamagui/get-token": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/helpers-tamagui": "1.139.1", "@tamagui/label": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/use-previous": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-z6BL5Kpn3T1QfSKXFsQevSt1AR8mRfh9A/dzdPmL8d0RzhMCtpJ/rgWAt+xRXbr9UNzzeHT/EF2/sC+hfM11Cw=="],
|
||||
"@tamagui/checkbox": ["@tamagui/checkbox@1.141.4", "", { "dependencies": { "@tamagui/checkbox-headless": "1.141.4", "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/focusable": "1.141.4", "@tamagui/font-size": "1.141.4", "@tamagui/get-token": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/helpers-tamagui": "1.141.4", "@tamagui/label": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/use-previous": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-7mbQs/Umj+0Jeom7coBJ4CKfwldluNy1bVJuCod/vFWS5MIvv0vActb0oLBhCyeoTLgPIT+HY8dElpr7P5WRaw=="],
|
||||
|
||||
"@tamagui/checkbox-headless": ["@tamagui/checkbox-headless@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/focusable": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/label": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/use-previous": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-qU6hDYWN0Axiq1kZ4A+y237UhPGc9WJtrRKunhRvII2MCUeFJZ/IHcsId2hqvLZvbmS9bo/2P/yOCePt/IA/Vg=="],
|
||||
"@tamagui/checkbox-headless": ["@tamagui/checkbox-headless@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/focusable": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/label": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/use-previous": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-mOZlDshobYTi2T3BIRpr024AIYxC/iQso3zEGAd2vHNKBPpeQ/vKTrdCHx/NLRKIUy0WJNzdg64rWP23wUcCUA=="],
|
||||
|
||||
"@tamagui/collapsible": ["@tamagui/collapsible@1.139.1", "", { "dependencies": { "@tamagui/animate-presence": "1.139.1", "@tamagui/compose-refs": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/polyfill-dev": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-1HNsDBsEzEoefHNzQJXwtOjoojzDZi3aKredu5DxWRCx6W/GiOYH8EqT2SVgXhXrYwh0EjYnrELlw6D1UNTDJg=="],
|
||||
"@tamagui/collapsible": ["@tamagui/collapsible@1.141.4", "", { "dependencies": { "@tamagui/animate-presence": "1.141.4", "@tamagui/compose-refs": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/polyfill-dev": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-yeaY+nRjpjX0m28bq87oBgD9fTUOveQtvmLvU+CTInMub5tXvrxVXPzx5J7g+QrbknJvGtEtedfX3I3uhzZNEQ=="],
|
||||
|
||||
"@tamagui/collection": ["@tamagui/collection@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/polyfill-dev": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/use-controllable-state": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-5S4Hgh2vKcd+YXw7A8zGwipqDdOi6wfiz61Picy+KOcn48YNLcCMFjGUCUFN5i27yflNgev0TC1iUuc+wPCBVA=="],
|
||||
"@tamagui/collection": ["@tamagui/collection@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/polyfill-dev": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/use-controllable-state": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-ZmDAlK4FSJQnNxAjIN0ovmyixg8M8jgwuk5EVDtvAqV6jzvTUA40DRh0HYBlPV2IKGzF2DFLg5SC243NrlBAJA=="],
|
||||
|
||||
"@tamagui/colors": ["@tamagui/colors@1.139.1", "", {}, "sha512-uRflr8TkunrVNdnBgEJ6Zlk/4kWYy1dlxYgT0bkG5MLfDlu4OlA4rVGwirCxfwIwrXov/E2/2qjAIUbBnxr1Zg=="],
|
||||
"@tamagui/colors": ["@tamagui/colors@1.141.4", "", {}, "sha512-iFDE1DjvU0YmhBYKrjvxQn02mstnwfsEZoJF5MppGhYLp3jfferQVpO+JuWre6heSLiy1R1bM7mO7uHsNdh3QA=="],
|
||||
|
||||
"@tamagui/compose-refs": ["@tamagui/compose-refs@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-mapsTVe30yl8+iHRxK05L5A762W8oQQjXnnLvan3EEV684YoGNGBO09aZOXp/ELGvbyjRsFHkMrbB8YbjSPdLQ=="],
|
||||
"@tamagui/compose-refs": ["@tamagui/compose-refs@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-Yx15Kp0SxtT0YxT/jLLaKlz518fIM7C18ryJzFzm5kYwe9TzIJBPUzIjlgYyCQhJJ8WwqQbkjN0FEg2J6mmgAw=="],
|
||||
|
||||
"@tamagui/config": ["@tamagui/config@1.139.1", "", { "dependencies": { "@tamagui/animations-css": "1.139.1", "@tamagui/animations-moti": "1.139.1", "@tamagui/animations-react-native": "1.139.1", "@tamagui/colors": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/font-inter": "1.139.1", "@tamagui/font-silkscreen": "1.139.1", "@tamagui/react-native-media-driver": "1.139.1", "@tamagui/shorthands": "1.139.1", "@tamagui/theme-builder": "1.139.1", "@tamagui/themes": "1.139.1", "@tamagui/web": "1.139.1" } }, "sha512-XH3SbBYVXkrnM9Q6LYQPJBTEQ6WvKNqECJILM0GmxUKUaNaF3S3o+bhvja7IIINEbyyYIJQfwjvj/H4kAPsRvg=="],
|
||||
"@tamagui/config": ["@tamagui/config@1.141.4", "", { "dependencies": { "@tamagui/animations-css": "1.141.4", "@tamagui/animations-moti": "1.141.4", "@tamagui/animations-react-native": "1.141.4", "@tamagui/colors": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/font-inter": "1.141.4", "@tamagui/font-silkscreen": "1.141.4", "@tamagui/react-native-media-driver": "1.141.4", "@tamagui/shorthands": "1.141.4", "@tamagui/theme-builder": "1.141.4", "@tamagui/themes": "1.141.4", "@tamagui/web": "1.141.4" } }, "sha512-mgVtZImkAtPm3DtiqBir71lKnvbEK4bJz/tjbc9VetTPd+68uLd+uVA3+SkR3IgUEcyjXWgeAl07Li8lWDo/fA=="],
|
||||
|
||||
"@tamagui/config-default": ["@tamagui/config-default@1.139.1", "", { "dependencies": { "@tamagui/animations-css": "1.139.1", "@tamagui/animations-react-native": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/shorthands": "1.139.1", "@tamagui/web": "1.139.1" } }, "sha512-4D0oYWFY0DMUaaTvaAtHXj+/3NTm0CFLwcOW5MtcIFN8HvR28Q/gyOpfzNe000z9OUArK5r5nH5jB1mnCMgXOw=="],
|
||||
"@tamagui/config-default": ["@tamagui/config-default@1.141.4", "", { "dependencies": { "@tamagui/animations-css": "1.141.4", "@tamagui/animations-react-native": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/shorthands": "1.141.4", "@tamagui/web": "1.141.4" } }, "sha512-v64eTMEhnnsyhcEwgcLsf4/Ab4t5bWp6Xeb0gXCJsuf3sRWk5NGBHh/wq9hK/gKjTxOLUkc20Dtn/C7e4i2Nmg=="],
|
||||
|
||||
"@tamagui/constants": ["@tamagui/constants@1.139.1", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-jwhbmR6R2gA1zcPxWvHjL0+gQdMuVmEs5XI5fgNb6kAqJ5VVfCwqq7mDtjDNDF8bW3QmZpVCZRpudyDkAFqmjA=="],
|
||||
"@tamagui/constants": ["@tamagui/constants@1.141.4", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-vh45Cv3NBOzUtIKriAr4lR1Eg947FJZjyBqto1wn/ClHg0tW1AlpZZsP3e5FGVDyBWFqIxbspoMuw2GT6eAY3w=="],
|
||||
|
||||
"@tamagui/core": ["@tamagui/core@1.139.1", "", { "dependencies": { "@tamagui/helpers": "1.139.1", "@tamagui/react-native-media-driver": "1.139.1", "@tamagui/react-native-use-pressable": "1.139.1", "@tamagui/react-native-use-responder-events": "1.139.1", "@tamagui/use-element-layout": "1.139.1", "@tamagui/use-event": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-kfRKsT6MIEtoWHywMvV+zYurLsZZVplDgpaXl7UwfXJlmFqT3enqGpMqv0TsEzTeuQpboPYBhbNgGJgO0Eihgg=="],
|
||||
"@tamagui/core": ["@tamagui/core@1.141.4", "", { "dependencies": { "@tamagui/helpers": "1.141.4", "@tamagui/react-native-media-driver": "1.141.4", "@tamagui/react-native-use-pressable": "1.141.4", "@tamagui/react-native-use-responder-events": "1.141.4", "@tamagui/use-element-layout": "1.141.4", "@tamagui/use-event": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-NIKfAjwEqnXTPkeX7ryKYvWFBrUNL5Qno27RoCFyNM++qV3Jc5IOrtOtAysGUYT+umYZqSgSLuc5SXyXcBSx7w=="],
|
||||
|
||||
"@tamagui/create-context": ["@tamagui/create-context@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-6Vfg8Ix8aypIWd2ocRMbUtoSw70sv9uDDlSU/LNxHfSNabKNg9D1LZwamQA57h6/DUYQSSp2Ucl7venk47wQJQ=="],
|
||||
"@tamagui/create-context": ["@tamagui/create-context@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-s/zBH54N09F5RuFTD6/mZTD3DyUO9safRSW205xxPYfLoCYDTnNZTMB2V8LxHR2rjBgg6YlPP1fUr1y7aowErg=="],
|
||||
|
||||
"@tamagui/create-theme": ["@tamagui/create-theme@1.139.1", "", { "dependencies": { "@tamagui/web": "1.139.1" } }, "sha512-cZIFA8WCFa5L43WJY0NbKrxh+TwgG6jdZG6id0p1lXGBjqk9Xqp3pwnjlY7GOBsvm4uwvNWK07ZSzVh3VEy+fA=="],
|
||||
"@tamagui/create-theme": ["@tamagui/create-theme@1.141.4", "", { "dependencies": { "@tamagui/web": "1.141.4" } }, "sha512-HrkoOTwbDB8VS/+8aPUVi08yF0lmcJyqjopthRmxH0KXsbANy8+33tynDW9N+CATM8fd6TW9wqLIU+mavVd07A=="],
|
||||
|
||||
"@tamagui/cubic-bezier-animator": ["@tamagui/cubic-bezier-animator@1.139.1", "", {}, "sha512-x4z+LirjGmqgwWlpwHczHIMA6jyui8ShL5Q+agqumSePG1kHf2a/TcMuCa1n/vXaHSMX5lDljfxGt2S+C8BXfA=="],
|
||||
"@tamagui/cubic-bezier-animator": ["@tamagui/cubic-bezier-animator@1.141.4", "", {}, "sha512-Wj4Cg7XjPtSE6o8Ss7AmtFeZFYzRkNtbcF2arcktgnSVsgxAjwXn9PvRuXGUy4Z+Pnvh1NLhS2J2iKG23waP0g=="],
|
||||
|
||||
"@tamagui/dialog": ["@tamagui/dialog@1.139.1", "", { "dependencies": { "@tamagui/adapt": "1.139.1", "@tamagui/animate-presence": "1.139.1", "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/dismissable": "1.139.1", "@tamagui/focus-scope": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/polyfill-dev": "1.139.1", "@tamagui/popper": "1.139.1", "@tamagui/portal": "1.139.1", "@tamagui/remove-scroll": "1.139.1", "@tamagui/sheet": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/text": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/z-index-stack": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-XOC1eUlBAFUhhHS/XtdfUVAhDb2i7EQofOmoBp8geDxHmmWXfUca+r1i7V3th270KEei7dFhbHxwW4Uwi7AphQ=="],
|
||||
"@tamagui/dialog": ["@tamagui/dialog@1.141.4", "", { "dependencies": { "@tamagui/adapt": "1.141.4", "@tamagui/animate-presence": "1.141.4", "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/dismissable": "1.141.4", "@tamagui/focus-scope": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/polyfill-dev": "1.141.4", "@tamagui/popper": "1.141.4", "@tamagui/portal": "1.141.4", "@tamagui/remove-scroll": "1.141.4", "@tamagui/sheet": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/text": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/z-index-stack": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-Vy51uOB23wl8B+B/ilrzhfFveEa7eWDHkg/CseU++qw3iVw9s+u0fhrOPqsIlOSSEwH2+CrXHBkQZsIDjivfrQ=="],
|
||||
|
||||
"@tamagui/dismissable": ["@tamagui/dismissable@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/use-escape-keydown": "1.139.1", "@tamagui/use-event": "1.139.1" }, "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-MeG90z3rP9bCDOAEQUiPoaJhpa0q+NC7MpC4TRQ7goE36tI5DSKpufpr73wSzNxu6JLv5eevKuiLgGpZT8XaFg=="],
|
||||
"@tamagui/dismissable": ["@tamagui/dismissable@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/use-escape-keydown": "1.141.4", "@tamagui/use-event": "1.141.4" }, "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-J4pwz0t8LWbvrpng+FcQU4SpG9ZfMuEipD/giyHBSZ9uNKNau+vDXGPPghxK59Tw0THOmTmpBTl+Oxos/eKXyA=="],
|
||||
|
||||
"@tamagui/elements": ["@tamagui/elements@1.139.1", "", { "dependencies": { "@tamagui/core": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-v8eCmqRygD9jr/D6ZOnid/3r0IvdBzszTTKRSo5uG2OJAwFT4RC8VUqW/7nNb0p9rtjpeb6/upDdWUc1vSEXTQ=="],
|
||||
"@tamagui/elements": ["@tamagui/elements@1.141.4", "", { "dependencies": { "@tamagui/core": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-X77AKo/ZCEDOAvT7UphwiDAqEQjmKYYI7RUZxJEBQvWk2tmAkf25WlSl4DU2zop4sVb1uctISfBLFHevOPSQdw=="],
|
||||
|
||||
"@tamagui/fake-react-native": ["@tamagui/fake-react-native@1.139.1", "", {}, "sha512-Fufym6jy4VVWEDVPWbynL+CD9J+T+7HzpVpbkukhaNVCLUrlAsj3bZ8uUSq6pPkJXRg3AEW50Tu06/npReFkoA=="],
|
||||
"@tamagui/fake-react-native": ["@tamagui/fake-react-native@1.141.4", "", {}, "sha512-0BPBA3Df9mwuSejgz+z66tyUJ0sfe/1vEjSqXTh7LMv/1g30CQ6uI8Z+s1oXeC9dDtuHajeOjxD3O2F+kC7PzQ=="],
|
||||
|
||||
"@tamagui/floating": ["@tamagui/floating@1.139.1", "", { "dependencies": { "@floating-ui/react-dom": "^2.1.6", "@floating-ui/react-native": "^0.10.7" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-8A4zSv2VjNTEB0zWeSpkoDvZU+GMoCDK/Pk4CQ9s72OCZLAtZSRVYOZuhT7RavFVmhFkgRFmnrTu2uDFaYAvJA=="],
|
||||
"@tamagui/floating": ["@tamagui/floating@1.141.4", "", { "dependencies": { "@floating-ui/react-dom": "^2.1.6", "@floating-ui/react-native": "^0.10.7" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-7RJQ+lR3dE1sO2bstXLGwFkLbBt+cRtRm3UHLzLQ8jKr3lWhbepr2mQM/hkNieC9HZS7x7XA2C8pFXAGyigRwA=="],
|
||||
|
||||
"@tamagui/focus-scope": ["@tamagui/focus-scope@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/start-transition": "1.139.1", "@tamagui/use-async": "1.139.1", "@tamagui/use-event": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-RwGQuph3IoPNiQWAvQ5RaaBUw/J2FCKiT4RfoeEfS9ZStGcqYE0jVeiN7KRZ7rTb4WMQf6ybutvyfecelAwCQw=="],
|
||||
"@tamagui/focus-scope": ["@tamagui/focus-scope@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/start-transition": "1.141.4", "@tamagui/use-async": "1.141.4", "@tamagui/use-event": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-XQhixzXWItlmisNtRg8uNce93X78wijbBd7rRsgIQjmQPnRXPmVpdTGdQCLBsu1h1OBKLlt/qqyMkt/HvtUt8w=="],
|
||||
|
||||
"@tamagui/focusable": ["@tamagui/focusable@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-914lwTz0WFuRqmxq51myR+Lni28QxqHcEoS9oF7j8HZR+TunNho09wLsbdK8G8Ar7cBrXbl03DEnIbpL/QKGgw=="],
|
||||
"@tamagui/focusable": ["@tamagui/focusable@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-JA8GmtwavvGZeer7yVYQfmWG6F5NVfQGeyhOQkCof4xydkzNpsPUevIXmVNou/1c3CPFnKWBQUvD/Zy5HiVB4g=="],
|
||||
|
||||
"@tamagui/font-inter": ["@tamagui/font-inter@1.139.1", "", { "dependencies": { "@tamagui/core": "1.139.1" } }, "sha512-UY4bb7VxFkd3FMi8dbgoh98+BppgI1CsO9h/9z/avgFAuKUDzIQhsAeUJal+GY19mvETYYyJR3EghoVzv2FmxQ=="],
|
||||
"@tamagui/font-inter": ["@tamagui/font-inter@1.141.4", "", { "dependencies": { "@tamagui/core": "1.141.4" } }, "sha512-jlPErhPX7DTy+XNhnHtpDBLPeH7tB1hvapoLnanOdyg+cBxGZQIE2uOtTISS3A8M9IPq9eH73OoWobyQ302Zsw=="],
|
||||
|
||||
"@tamagui/font-silkscreen": ["@tamagui/font-silkscreen@1.139.1", "", { "dependencies": { "@tamagui/core": "1.139.1" } }, "sha512-W4j718sNhAN2Fwaw+OK8ApqR6pBOlzkziFEMWTABFpL1seP4+w5wvZnRP9Vposy9wOlJzuzuJ+XnI8Ny2ywfIQ=="],
|
||||
"@tamagui/font-silkscreen": ["@tamagui/font-silkscreen@1.141.4", "", { "dependencies": { "@tamagui/core": "1.141.4" } }, "sha512-uRRzdFgtrZ/WJp1vDhCc5oXg4lAbw+Ib1HFTBKn1/BhlqgrwCDrAkTNDNnKzUChqpdmDLGeFSQQknmK7xG352w=="],
|
||||
|
||||
"@tamagui/font-size": ["@tamagui/font-size@1.139.1", "", { "dependencies": { "@tamagui/core": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-4H/AQwCW32+Cupxi3vYueHQUiMJ5hlKQL4VogsfTIXNkMS8vvrwYKUKz0DD0H8x3nUd0LWwzhUas5gwdB6WTjA=="],
|
||||
"@tamagui/font-size": ["@tamagui/font-size@1.141.4", "", { "dependencies": { "@tamagui/core": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-N8bS0Pqcj8UJd3rmuMGjSVOfVY7DW/1zONaE09QvzOStcB9Klfzs6UU0P4zwMkdf9vqJOfXmS7LD7aQaKK2fzQ=="],
|
||||
|
||||
"@tamagui/form": ["@tamagui/form@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/focusable": "1.139.1", "@tamagui/get-button-sized": "1.139.1", "@tamagui/get-font-sized": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/text": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-R7j57ld4dXLosnyCYxOyX8Yfs14elt8mMYBL5nNEwrIB2huRfMdWDfop+ruc711OIp/fy4fOaL5rp8v/dUb9EA=="],
|
||||
"@tamagui/form": ["@tamagui/form@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/focusable": "1.141.4", "@tamagui/get-button-sized": "1.141.4", "@tamagui/get-font-sized": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/text": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-wZbMcNuP/O9qb5L17C1jBzbzagLafFhgyfWkY7VjG94fZ+LtFGtVpl/OgV8nZWNPGl8Fdv7ccAm1Z8j/2NN8Cg=="],
|
||||
|
||||
"@tamagui/get-button-sized": ["@tamagui/get-button-sized@1.139.1", "", { "dependencies": { "@tamagui/get-token": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-ven6PhEey1NhBi5KJgCD52+dnIJ78r3w9KWjDYdndIjSkWcGu6vvI36OfDokgTTKXnYlny38PmCtVNh7XM2VMA=="],
|
||||
"@tamagui/get-button-sized": ["@tamagui/get-button-sized@1.141.4", "", { "dependencies": { "@tamagui/get-token": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-2nT2Jnly6pk1v4GUSmOOhzz3XDj0lULhjDjvMAyfm4xpo3vE3ukbdScB78dHE1NazAlJXl5zluT3LBeyBGgCug=="],
|
||||
|
||||
"@tamagui/get-font-sized": ["@tamagui/get-font-sized@1.139.1", "", { "dependencies": { "@tamagui/constants": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-eHdBGcPX1bVdEiZIDc+ChAUps3mAr5ki8nivFJHmNCWH8jpT984zPF+zR0BdQoWywswwcU1eeAuwsdScxadHEA=="],
|
||||
"@tamagui/get-font-sized": ["@tamagui/get-font-sized@1.141.4", "", { "dependencies": { "@tamagui/constants": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-Ck5mQhUeSQAMpd0ja40Ccpl3hGRIUTxohhI8OabfDhqqEODIGj7E/GYezeYNuw9xCaB0JcYTgnX1sruGmO4aRA=="],
|
||||
|
||||
"@tamagui/get-token": ["@tamagui/get-token@1.139.1", "", { "dependencies": { "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-bZijQVpQLbYGs5OnL16JkRybwYMuULgKfiuTPUAFpzOlJIgAo9m5b+6hSN5CDRquTH6poxWaNHj75V2efh3saw=="],
|
||||
"@tamagui/get-token": ["@tamagui/get-token@1.141.4", "", { "dependencies": { "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-wAcdJVLUXbbKqYF3QOip9sAeLJk19CDJjck5W7MpCma3WoXw58Kmb6VYFA7TV5hUVicv2FCRw4DkU3v/vNoDyA=="],
|
||||
|
||||
"@tamagui/group": ["@tamagui/group@1.139.1", "", { "dependencies": { "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/use-controllable-state": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-NhFnDabL4B0rDmjuEyS3J0Wf2Dq4KUoi4ph9Z6qLwHqQm9gvgssNmOp8aAgo5HAsTTB9bTOvD+2Zoqd06s68VA=="],
|
||||
"@tamagui/group": ["@tamagui/group@1.141.4", "", { "dependencies": { "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/use-controllable-state": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-8QGhqcds3RBsP/ZTKrNIxOn57jJntQqgclobNayfvoHBR3pN7kR09gTXB0taCzTY+sAPuXiW5KNEbjSozICACQ=="],
|
||||
|
||||
"@tamagui/helpers": ["@tamagui/helpers@1.139.1", "", { "dependencies": { "@tamagui/constants": "1.139.1", "@tamagui/simple-hash": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-E6QSJJxxUoLHDOD8nHlIZo0dU9MX0H5eJHnQH7EI5aKoyVVLxRaBVU3Ca6/BHziXefxCZuv+RJjPur3D2nk3Yg=="],
|
||||
"@tamagui/helpers": ["@tamagui/helpers@1.141.4", "", { "dependencies": { "@tamagui/constants": "1.141.4", "@tamagui/simple-hash": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-kO91N9WZxehm7wAvbdZ92QavOh7jSTdDJ1BzM23MAkSUN3PnnyV9b/3n2vTogNamo6a4aG/htPJKwNXEy4ZEEA=="],
|
||||
|
||||
"@tamagui/helpers-tamagui": ["@tamagui/helpers-tamagui@1.139.1", "", { "dependencies": { "@tamagui/helpers": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-N5/t+ZKOpS95dUR5mVEcfjyEVUeSLFFVedzDNIQLAazW7Bn2MD9vrSU5Sik5SgWqxoFIa600t5pPpt3abI1j3w=="],
|
||||
"@tamagui/helpers-tamagui": ["@tamagui/helpers-tamagui@1.141.4", "", { "dependencies": { "@tamagui/helpers": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-QSFG/nWeEj8az2zWejp/p1uvCHuCIkv4XW7o6PuU3j3oq/amh31c9qN2DR+PhWN0Xwxooz/SuqUrBuevk//5fw=="],
|
||||
|
||||
"@tamagui/image": ["@tamagui/image@1.139.1", "", { "dependencies": { "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-NuvdhO5AJwKIJ8EOtWlBDBkqApz3cvb3fgYdunJVcNQi7dW0+sVlX7sunbG0JbnSbie5L2p0wlaP/GaYii5D8A=="],
|
||||
"@tamagui/image": ["@tamagui/image@1.141.4", "", { "dependencies": { "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-w/nN/uu39LjQZDPuTbPZbEwhgF/HPyZ2Ug5+n7l8KHaRcFAW32OJUak8aHDDOPqPx/pvHx+Wn2hS3/EnrV0REg=="],
|
||||
|
||||
"@tamagui/is-equal-shallow": ["@tamagui/is-equal-shallow@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-ZAGI7BwXEQomWd6KI5yMngxLHmNpSchHQN+iki++Zx8Bl+m894ZwCG3WBK23CgmBiLk3WTzHgUWmNhVCm0I0ng=="],
|
||||
"@tamagui/is-equal-shallow": ["@tamagui/is-equal-shallow@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-YuzzoST+SGlAJys837RXVX3LOw1ajL76imoAytMXZhBxoJN9rHuLIzRayXGfFy+NLrVLThTlUsswSojKYIsVVQ=="],
|
||||
|
||||
"@tamagui/label": ["@tamagui/label@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/focusable": "1.139.1", "@tamagui/get-button-sized": "1.139.1", "@tamagui/get-font-sized": "1.139.1", "@tamagui/text": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-zIapwcPAIVExn//2Ftt0P7PLCDfAki4YpVd0aVqiUNGfI5bXRbMyv1M/G3grIfm29XENg7UCNeEuf0j3SnC6uw=="],
|
||||
"@tamagui/label": ["@tamagui/label@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/focusable": "1.141.4", "@tamagui/get-button-sized": "1.141.4", "@tamagui/get-font-sized": "1.141.4", "@tamagui/text": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-efoi95hQCGK1/bS7QJpbn3fOQdXLdAjOs8oyJAgJY1nOkgzZ7TQiccCZb/k4YlDdhBX/LuNzKsllywlHZmw5cQ=="],
|
||||
|
||||
"@tamagui/linear-gradient": ["@tamagui/linear-gradient@1.139.1", "", { "dependencies": { "@tamagui/core": "1.139.1", "@tamagui/stacks": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-tfJuuTxJpBWTSx7X5Z7h1R4HyXg2VcwhmWyyzRJa90zPMUzsJWArssH/OBcRQeqzXlSD1A39C5kq6bdIg2tXIQ=="],
|
||||
"@tamagui/linear-gradient": ["@tamagui/linear-gradient@1.141.4", "", { "dependencies": { "@tamagui/core": "1.141.4", "@tamagui/stacks": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-uhIrH1MHWa8JZ8Wi3O6uuyAeZwOvHwEjlI2SNR0yg6QiSnOmXxlQeMBf9CQuPoJH3dqTGUsK1fQ75/OMSBbMjg=="],
|
||||
|
||||
"@tamagui/list-item": ["@tamagui/list-item@1.139.1", "", { "dependencies": { "@tamagui/font-size": "1.139.1", "@tamagui/get-font-sized": "1.139.1", "@tamagui/get-token": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/helpers-tamagui": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/text": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-czFsX7qGmtdA303fRzAsAW7GKq52B4tMky5IbNDKB9hdXtstwHVxN5nfz7m9WHM4uUbmKVuCK+SnbfTuB4QmEA=="],
|
||||
"@tamagui/list-item": ["@tamagui/list-item@1.141.4", "", { "dependencies": { "@tamagui/font-size": "1.141.4", "@tamagui/get-font-sized": "1.141.4", "@tamagui/get-token": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/helpers-tamagui": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/text": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-5U/sfi68tZE2ill6PzD/LjZ2JO4kBPQQbPRdyOfwzTvHKJdpAnktk2C/SXQ6KzIbcW1gkU9Q97IwZnKMLbBCtg=="],
|
||||
|
||||
"@tamagui/normalize-css-color": ["@tamagui/normalize-css-color@1.139.1", "", { "dependencies": { "@react-native/normalize-color": "^2.1.0" } }, "sha512-mrQuU3tpDlx856vwunuav6JY93knNHZTEEBIH0E1AmeM68PjMbKF5rcgdc4BrP7/ZTVdjSqqoNUzRdA6uexLbA=="],
|
||||
"@tamagui/normalize-css-color": ["@tamagui/normalize-css-color@1.141.4", "", { "dependencies": { "@react-native/normalize-color": "^2.1.0" } }, "sha512-RaNFRxeDX8o0lpBU/PHo4F+dC2eOujs83j087wr1Ik6YFfxrHcay1sA8xLq3QqPbzJ/PX8r0/WGHusEz60xPyg=="],
|
||||
|
||||
"@tamagui/polyfill-dev": ["@tamagui/polyfill-dev@1.139.1", "", {}, "sha512-aP6LGaaD15jqOsV5qn29lriIG0PM8XDeQJXkp5pcjfRC5nf1Apj2C/UtqFquFQ4CWnYgKPJi+WMouV0C7y07Mw=="],
|
||||
"@tamagui/polyfill-dev": ["@tamagui/polyfill-dev@1.141.4", "", {}, "sha512-oaxMP+YoDArZ527RyfWjVH23lr1mlsX6MyRRbJhAqRqATdqUXLzYuBCpEdhwFqwUxWB4ZcH/oe8B5ESbFIW4WA=="],
|
||||
|
||||
"@tamagui/popover": ["@tamagui/popover@1.139.1", "", { "dependencies": { "@floating-ui/react": "^0.27.16", "@tamagui/adapt": "1.139.1", "@tamagui/animate": "1.139.1", "@tamagui/animate-presence": "1.139.1", "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/dismissable": "1.139.1", "@tamagui/floating": "1.139.1", "@tamagui/focus-scope": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/polyfill-dev": "1.139.1", "@tamagui/popper": "1.139.1", "@tamagui/portal": "1.139.1", "@tamagui/remove-scroll": "1.139.1", "@tamagui/scroll-view": "1.139.1", "@tamagui/sheet": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/z-index-stack": "1.139.1", "react-freeze": "^1.0.3" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-GIk76O6NkbNTFVYwEark5hhByzve8ZLRT4DPwqo9GB8gvazbkHWYW7kLOO4R8scoWS84L3nhvSizxCtxJqj61w=="],
|
||||
"@tamagui/popover": ["@tamagui/popover@1.141.4", "", { "dependencies": { "@floating-ui/react": "^0.27.16", "@tamagui/adapt": "1.141.4", "@tamagui/animate": "1.141.4", "@tamagui/animate-presence": "1.141.4", "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/dismissable": "1.141.4", "@tamagui/floating": "1.141.4", "@tamagui/focus-scope": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/polyfill-dev": "1.141.4", "@tamagui/popper": "1.141.4", "@tamagui/portal": "1.141.4", "@tamagui/remove-scroll": "1.141.4", "@tamagui/scroll-view": "1.141.4", "@tamagui/sheet": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/z-index-stack": "1.141.4", "react-freeze": "^1.0.3" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-7YRBnvNURibuUbdpmziVSMQMoxEnRd8b230P3auzCFuk4I+BrEP+7XByfPVvy3NRRQIWXl18e01vH+7wpw6Ftw=="],
|
||||
|
||||
"@tamagui/popper": ["@tamagui/popper@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/floating": "1.139.1", "@tamagui/get-token": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/start-transition": "1.139.1", "@tamagui/use-controllable-state": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-Iq/hYBkCmzF2/iJcle5Ydqr6H0tblcQp4SY6ONmnRcjkrfT8SPfbZv5nhAYAFFgCr+ftHhLa6Sh26uHJuqdOWQ=="],
|
||||
"@tamagui/popper": ["@tamagui/popper@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/floating": "1.141.4", "@tamagui/get-token": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/start-transition": "1.141.4", "@tamagui/use-controllable-state": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-NPFeu3+W0Kjy8Tm+bJJWiZFAXUlb8SlUbsvKe34vAaQ6c2xkisdqsXbBg+P9vNbH/sAAN3KDdkJlNM2/6AIXRg=="],
|
||||
|
||||
"@tamagui/portal": ["@tamagui/portal@1.139.1", "", { "dependencies": { "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/start-transition": "1.139.1", "@tamagui/use-event": "1.139.1", "@tamagui/web": "1.139.1", "@tamagui/z-index-stack": "1.139.1" }, "peerDependencies": { "react": "*", "react-dom": "*", "react-native": "*" } }, "sha512-fR98C1PhMjb2xyHxXSh2tXaAIwrd8wyvjs8xzjYn+xCWs9mkU5kKiOxSLkX76u3lFO+yySk83BnVyXkUR/884g=="],
|
||||
"@tamagui/portal": ["@tamagui/portal@1.141.4", "", { "dependencies": { "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/start-transition": "1.141.4", "@tamagui/use-event": "1.141.4", "@tamagui/web": "1.141.4", "@tamagui/z-index-stack": "1.141.4" }, "peerDependencies": { "react": "*", "react-dom": "*", "react-native": "*" } }, "sha512-UfdB98aW/PGvNmUAmw7Uvsy39dXMvC7BBlnP5OMe/5GE5fQavp7Dqi/jlv2ueF7oqhxSdqRyOTmGv6xHsqnNkA=="],
|
||||
|
||||
"@tamagui/progress": ["@tamagui/progress@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/get-token": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/stacks": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-r0Y6qCh8PVyWvaWqXrRj5zeYfD8FxPzrD75oWUFENY6inkgUKAV+qe2qcdwJ/hMXRlsAy4e4I2GVnMrAdLNKHw=="],
|
||||
"@tamagui/progress": ["@tamagui/progress@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/get-token": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/stacks": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-XzPyDquotznAqSI81TX6hCAgk23m/hUcnrvNOyb/cFAqFRalZnD2iUO08nFyb8m7Ox78b883+FHDm/xg7xxkdQ=="],
|
||||
|
||||
"@tamagui/radio-group": ["@tamagui/radio-group@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/focusable": "1.139.1", "@tamagui/get-token": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/label": "1.139.1", "@tamagui/radio-headless": "1.139.1", "@tamagui/roving-focus": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/use-previous": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-okAa0kc4zpZ3YKxgp7bZjTBLike/0Kk1ixJzZpTdshVzhDSyT+Rn0Ok59b+3chW9+ZP5/00DF5+Ke+OkW3U2IA=="],
|
||||
"@tamagui/radio-group": ["@tamagui/radio-group@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/focusable": "1.141.4", "@tamagui/get-token": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/label": "1.141.4", "@tamagui/radio-headless": "1.141.4", "@tamagui/roving-focus": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/use-previous": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-ceN+B7av88vJz6rh9rLCTLmQ3y6ig9/I0ep5tbuO+g6+AVi60h/ZQXA8ykcC4wjDRMkpt8q9Y/2DXHLsEnlKbQ=="],
|
||||
|
||||
"@tamagui/radio-headless": ["@tamagui/radio-headless@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/focusable": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/label": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/use-previous": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-o4avZwfdsLrCnLhmqYsuW/H4TBtozHYvA+3323VxDk7D61mDwuPX/X73KUZcGz2CnAqjVS4D8LBmpo/kcYYQow=="],
|
||||
"@tamagui/radio-headless": ["@tamagui/radio-headless@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/focusable": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/label": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/use-previous": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-zERVNWoiezti46MQYDne/3vmoCHBC1MjBuz197BWyuYWeVd7GFka+Qye8/DlwWw6IwiOZ3E03D2HGd8gPKdhVQ=="],
|
||||
|
||||
"@tamagui/react-native-media-driver": ["@tamagui/react-native-media-driver@1.139.1", "", { "dependencies": { "@tamagui/web": "1.139.1" }, "peerDependencies": { "react-native": "*" } }, "sha512-rzVK0//YAddUU8KYPyvmD66x3Fbmklxnxkm4Fjz6uwM4L0M2vkpF7AwCwpub36e3DaCJc7dQeIb/5uQ+vuObqw=="],
|
||||
"@tamagui/react-native-media-driver": ["@tamagui/react-native-media-driver@1.141.4", "", { "dependencies": { "@tamagui/web": "1.141.4" }, "peerDependencies": { "react-native": "*" } }, "sha512-fQttUVWKhks34g9LqPBZGRNUhKWXhDNgplhJ7mKRShVjeA7r1DkQoPWxW6bXBN9hfTW/Z3aW9pSy03cLGp6dUw=="],
|
||||
|
||||
"@tamagui/react-native-use-pressable": ["@tamagui/react-native-use-pressable@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-dRDD6GIjkb8Fq0DAjnK2DvU5VPkeX4elIFWeAyGJLG9vRFVgKBznYDzawYnyJEiNQ/gqWOTm0ylgxNYbjGMt8Q=="],
|
||||
"@tamagui/react-native-use-pressable": ["@tamagui/react-native-use-pressable@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-oZ268oyRlvZeNyqXCKJR3bLqEKYAnGy5D44KSjNr/kAZfCPE4qVf1UWdFDpNUpFLRfJKd7LRJbEt4MF1WhbX7A=="],
|
||||
|
||||
"@tamagui/react-native-use-responder-events": ["@tamagui/react-native-use-responder-events@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-y2uq6CVhymYte6PSPopWBNzxbOwaSMp/PMJ5Pg0b1Fh9yC3qT9Edk1D3gDCVRF+kQtuYBws7uLDfo053VjeD5w=="],
|
||||
"@tamagui/react-native-use-responder-events": ["@tamagui/react-native-use-responder-events@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-eqSVS/ZHEs+g+4BwnNRdXI7Ef2XZsi3NflSSU/Lovdww64N2efcvqP9xAUpbyK7ES4a2b4U1PTYBQMMCh7qHpg=="],
|
||||
|
||||
"@tamagui/remove-scroll": ["@tamagui/remove-scroll@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-ZSjwDjSKxe7Ow3Ua2fqXFrQCqPJRs0GTeX3FCgtfzydaG8TnQSpECnobf0sdgWttQHEpolAdX8jd1STfw1MEIw=="],
|
||||
"@tamagui/remove-scroll": ["@tamagui/remove-scroll@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-vbQEhST81IvlaEEQd75UMIIi8FbDoKpyUrvGdeMKjsuM40IlW6gC2Dgtvvw69mGtLf8XCLJXWAY8IxYyNP/7kw=="],
|
||||
|
||||
"@tamagui/roving-focus": ["@tamagui/roving-focus@1.139.1", "", { "dependencies": { "@tamagui/collection": "1.139.1", "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/use-direction": "1.139.1", "@tamagui/use-event": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-v2TmKEfJqaKu6SXSNC32MjEEifCc64ZsmyuT29hJpf0cGxNZBJ8qSB8a866Cp5ZIg10w5ibIWCHs9rIyEGGpyg=="],
|
||||
"@tamagui/roving-focus": ["@tamagui/roving-focus@1.141.4", "", { "dependencies": { "@tamagui/collection": "1.141.4", "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/use-direction": "1.141.4", "@tamagui/use-event": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-ZUpWXvAnjCp95R/iksXErYTttAohW3a30+SOT6+4BFbqAhZBxwrINXkwoTgJUvdMHzooSu1kfulF6dRszWY4OA=="],
|
||||
|
||||
"@tamagui/scroll-view": ["@tamagui/scroll-view@1.139.1", "", { "dependencies": { "@tamagui/stacks": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-vgzmf5E74qZwF17uabKvAjX8PWBPQW6RHemKslsc8Zt9ZZzal2BH54voQCIs9yJreydpOTNv3q8jf58Gf5O3qQ=="],
|
||||
"@tamagui/scroll-view": ["@tamagui/scroll-view@1.141.4", "", { "dependencies": { "@tamagui/stacks": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-/MXrJYIgmqysdFNmAgkyruKjZOWtIZ/OiSLMQW1ofmvOTjgFo8h42Prza8fr2SJCRF7JXE/PVlbFhExqY/0qPw=="],
|
||||
|
||||
"@tamagui/select": ["@tamagui/select@1.139.1", "", { "dependencies": { "@floating-ui/react": "^0.27.16", "@floating-ui/react-dom": "^2.1.6", "@floating-ui/react-native": "^0.10.7", "@tamagui/adapt": "1.139.1", "@tamagui/animate-presence": "1.139.1", "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/dismissable": "1.139.1", "@tamagui/focus-scope": "1.139.1", "@tamagui/focusable": "1.139.1", "@tamagui/get-token": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/list-item": "1.139.1", "@tamagui/portal": "1.139.1", "@tamagui/remove-scroll": "1.139.1", "@tamagui/separator": "1.139.1", "@tamagui/sheet": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/text": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/use-debounce": "1.139.1", "@tamagui/use-event": "1.139.1", "@tamagui/use-previous": "1.139.1" }, "peerDependencies": { "react": "*", "react-dom": "*", "react-native": "*" } }, "sha512-5lwJIcf9ofFedpjkVJlblWQ5beHJd3F6Wg9YU/seCyGv4JetSaroCDJp4l9x78F60du6DP54AB5PTGFesvWMZA=="],
|
||||
"@tamagui/select": ["@tamagui/select@1.141.4", "", { "dependencies": { "@floating-ui/react": "^0.27.16", "@floating-ui/react-dom": "^2.1.6", "@floating-ui/react-native": "^0.10.7", "@tamagui/adapt": "1.141.4", "@tamagui/animate-presence": "1.141.4", "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/dismissable": "1.141.4", "@tamagui/focus-scope": "1.141.4", "@tamagui/focusable": "1.141.4", "@tamagui/get-token": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/list-item": "1.141.4", "@tamagui/portal": "1.141.4", "@tamagui/remove-scroll": "1.141.4", "@tamagui/separator": "1.141.4", "@tamagui/sheet": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/text": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/use-debounce": "1.141.4", "@tamagui/use-event": "1.141.4", "@tamagui/use-previous": "1.141.4" }, "peerDependencies": { "react": "*", "react-dom": "*", "react-native": "*" } }, "sha512-GHYD7Rk0jTxwXPxAUUfDidG3dC2gTa7akvrfQ2JK1XeYa+t8H3GPN6k5xE7jahHHJesPK2F9wna5sjqbjnFXwA=="],
|
||||
|
||||
"@tamagui/separator": ["@tamagui/separator@1.139.1", "", { "dependencies": { "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-p8BjZEtVoxSA8T5kwwj6VMFeLNcbpUYG4DEzRi2bS8LYZG3CN6FAnGB8XBbvqQnkVfmw2KpYfjBfZaYUjh4tQg=="],
|
||||
"@tamagui/separator": ["@tamagui/separator@1.141.4", "", { "dependencies": { "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-0jdocDIJDSx2HKU924G/yai635KVSopBVLOJdSnkPIIPIbZ9tx9eXflxf+tPcEHIZtVdU2v9t0ITfTkjE21oUA=="],
|
||||
|
||||
"@tamagui/shapes": ["@tamagui/shapes@1.139.1", "", { "dependencies": { "@tamagui/stacks": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-wEx0v28q0deXPVv9tKCiQMPh50dAHWsRBUsjPts16hnKkSl8H68/6/vvUEDH5Ir/F0dLi21d36X0m4k+Kh1owQ=="],
|
||||
"@tamagui/shapes": ["@tamagui/shapes@1.141.4", "", { "dependencies": { "@tamagui/stacks": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-t+u0XQn8opOaVfbdi6cYw6aYWVRM3kKT16HQ7zlZ9uwComLlJcwCAgrq1wOUS4/uC8p0thHj/9s55CCMTr7z6w=="],
|
||||
|
||||
"@tamagui/sheet": ["@tamagui/sheet@1.139.1", "", { "dependencies": { "@tamagui/adapt": "1.139.1", "@tamagui/animate-presence": "1.139.1", "@tamagui/animations-react-native": "1.139.1", "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/portal": "1.139.1", "@tamagui/remove-scroll": "1.139.1", "@tamagui/scroll-view": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/use-constant": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/use-did-finish-ssr": "1.139.1", "@tamagui/use-keyboard-visible": "1.139.1", "@tamagui/z-index-stack": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-1P6yg1DMHqCHmI21mOR3LsG9xbGCBmdYt9/h0GgPGooE0DNXsmsThdoQJHULjckkvtfoROICmGx+ColsxqI4MA=="],
|
||||
"@tamagui/sheet": ["@tamagui/sheet@1.141.4", "", { "dependencies": { "@tamagui/adapt": "1.141.4", "@tamagui/animate-presence": "1.141.4", "@tamagui/animations-react-native": "1.141.4", "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/portal": "1.141.4", "@tamagui/remove-scroll": "1.141.4", "@tamagui/scroll-view": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/use-constant": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/use-did-finish-ssr": "1.141.4", "@tamagui/use-keyboard-visible": "1.141.4", "@tamagui/z-index-stack": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-9goKaS98Di5LD/rN9fJaaxswHlUPRA7Y73QqlnY6iPYKzAEeW3J6zMFVo6Bv9a8QScrzvee8kBxX6XXp6CgKGw=="],
|
||||
|
||||
"@tamagui/shorthands": ["@tamagui/shorthands@1.139.1", "", { "dependencies": { "@tamagui/web": "1.139.1" } }, "sha512-lpevqf1ERAZNUKysTmNddHi5bFJmpXioRqBiPBdiktUkRgHUaCTRkSYORaOpVopzH0xQ+LuZvRmonARM3XFLFg=="],
|
||||
"@tamagui/shorthands": ["@tamagui/shorthands@1.141.4", "", { "dependencies": { "@tamagui/web": "1.141.4" } }, "sha512-sfFFtgRkF32wnFq9cRdXeyP8qCPCWXspUw3TIEU0VVTawZav0OjtpKrthC+ujX5wdm9+oF5EGkKu0m2Xyc4ODQ=="],
|
||||
|
||||
"@tamagui/simple-hash": ["@tamagui/simple-hash@1.139.1", "", {}, "sha512-nnaFGje6PmIT35pXL6Yv/r0dbjzsJl4n5pJg9wniW9UXGNtW12fqr8m0wgI0IK1Ej4ehEoY/pd97owhg1uEHOw=="],
|
||||
"@tamagui/simple-hash": ["@tamagui/simple-hash@1.141.4", "", {}, "sha512-ZBJ43UVk2jgoSVfUkSXJ1ziQsxXRoGEloQCUJ1+Mf8E8qo2dAXYDRE+maFZ2oO7HatA58z8T2KIxSYRQROeG7w=="],
|
||||
|
||||
"@tamagui/slider": ["@tamagui/slider@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/get-token": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/use-debounce": "1.139.1", "@tamagui/use-direction": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-zBtfq6toMA65+CbSfqQUEOZlZwoeMdYJnoC8/KA5cE4tgi4XUcD+JYNtvujFwBXL/2skcLURuAZaZs1slOfOAw=="],
|
||||
"@tamagui/slider": ["@tamagui/slider@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/get-token": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/use-debounce": "1.141.4", "@tamagui/use-direction": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-NHXnOUy8UD8wJ1qDj2wuwZUiP3TCiBgC9yey3aOV8BmBdCiO/iCZFOz1UJtusAgSkHJ49RIuv1GRWbRJqyclbw=="],
|
||||
|
||||
"@tamagui/stacks": ["@tamagui/stacks@1.139.1", "", { "dependencies": { "@tamagui/core": "1.139.1", "@tamagui/get-button-sized": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-4tNPtkuLIlKbpMk8Z+W7vVfoIvz16hO/haRtAf/PVx3I4Zqjldiz7QwNX34ADu/0J3Pfnfg/R55W5k9UPdbp+A=="],
|
||||
"@tamagui/stacks": ["@tamagui/stacks@1.141.4", "", { "dependencies": { "@tamagui/core": "1.141.4", "@tamagui/get-button-sized": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-C0R7J9kPz5QECQ2EsYsp5WpMTm+B6GOrxI3AFxj5lC0DTnFoimuhkJnnFOMGE12ynu3vN6DZg8YKBBkIbTW74g=="],
|
||||
|
||||
"@tamagui/start-transition": ["@tamagui/start-transition@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-BgG+XT/30p3BIjYWxLU7Tfge/ZNXEQhyhzfFy6buJLwUWKfgAZyKVRdPcp7fgXoY+Ox633bZJI7tXUjXDEy+og=="],
|
||||
"@tamagui/start-transition": ["@tamagui/start-transition@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-XsJqp8k2Ejp8MWdWBonYqqoq7314wpP32mtyO5M5k8rYpM9siMxqSB1MzDECOf2rJ9dvL8/9aGQflHyt/TJSEg=="],
|
||||
|
||||
"@tamagui/switch": ["@tamagui/switch@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/focusable": "1.139.1", "@tamagui/get-token": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/label": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/switch-headless": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/use-previous": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-Zba9BK5DMJnq7/yUNVadtPqK2gKBo3JpWVgQMAz0wXv2sXa7dR117FoQ9lBTUzJa+sNljlZ5e4yhlucAdFmvFA=="],
|
||||
"@tamagui/switch": ["@tamagui/switch@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/focusable": "1.141.4", "@tamagui/get-token": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/label": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/switch-headless": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/use-previous": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-ilxMA8YSjmgNKXg7W35RqUfg/lJaOnpabY6RFXhXSovz5BtCLPMQ2MrnWXKznSXC3dI+8AblX64gl/k3IOMWMg=="],
|
||||
|
||||
"@tamagui/switch-headless": ["@tamagui/switch-headless@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/label": "1.139.1", "@tamagui/use-previous": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-pDT4f6N5t9k5aDU0eHMgP1HBaUdcfij76qvJHMfsZLC9uWt8u0mtNJuQUVPVdMetXNS+oscM34Q4/VXg5mlGwA=="],
|
||||
"@tamagui/switch-headless": ["@tamagui/switch-headless@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/label": "1.141.4", "@tamagui/use-previous": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-lG/vLMJhhDw15Xkn/rCA96uPpCXHxPV7pXifhk62la0sVozq6R8PYuvB70QGu2uVj2fLDMltkDiMNhFsKiP5HQ=="],
|
||||
|
||||
"@tamagui/tabs": ["@tamagui/tabs@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/get-button-sized": "1.139.1", "@tamagui/group": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/roving-focus": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/use-direction": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-Mbl2WYL+E4iwSNvVWKfFNPRx/CzWTWYWDiSd4Nh3aAx2vyp23F/ATOinr9gfJryDOx8V6BEyYOIZ3mbs00jMdg=="],
|
||||
"@tamagui/tabs": ["@tamagui/tabs@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/get-button-sized": "1.141.4", "@tamagui/group": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/roving-focus": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/use-direction": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-2w6hx3rHXx3CDusCGKQqINkAqTMS3BgewvSa3M/XiKPKrR/bzBVdWInD5KLKOOOSJRkUplAPUhfA6/j3BTpaag=="],
|
||||
|
||||
"@tamagui/text": ["@tamagui/text@1.139.1", "", { "dependencies": { "@tamagui/get-font-sized": "1.139.1", "@tamagui/helpers-tamagui": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-YegV383opV6dt7h5mIuAT/LKsshm5WypPV/6znDNDkrjGvodMDbFv3h9SiSTlpAa/1jqLIpdXwGhCMwRbDHvUw=="],
|
||||
"@tamagui/text": ["@tamagui/text@1.141.4", "", { "dependencies": { "@tamagui/get-font-sized": "1.141.4", "@tamagui/helpers-tamagui": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-dij/G+SSZ9rAs93YktN18VLmyl5rS3e+XcUSd4lcawzNL5WKY7iyInDvOZzEJrTnIv5nBwtwU9oaods4Wr9URw=="],
|
||||
|
||||
"@tamagui/theme": ["@tamagui/theme@1.139.1", "", { "dependencies": { "@tamagui/constants": "1.139.1", "@tamagui/start-transition": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-HIlHoZBje1YrhStYSleduVNmdPjgVJGB5Q2uOx8uutXEWaO9d814xL6+uBKoY7DZmrvd9FR/PqvgAAv/WF/PZg=="],
|
||||
"@tamagui/theme": ["@tamagui/theme@1.141.4", "", { "dependencies": { "@tamagui/constants": "1.141.4", "@tamagui/start-transition": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-wLN6BescUJEyd037M9ABnzjSRRnuZUQR9RVLtv2Mnl2qHzaG8xRDGQXBlLhm4HvHhkI1J2P0Ef2xNvQVaNuJ+w=="],
|
||||
|
||||
"@tamagui/theme-builder": ["@tamagui/theme-builder@1.139.1", "", { "dependencies": { "@tamagui/create-theme": "1.139.1", "@tamagui/web": "1.139.1", "color2k": "^2.0.2" } }, "sha512-vNnV59SD0FvZrTunKp39JC8Vf6gUBpjUuYV+JSxI93hO+mnGg/oGCRR6j1QwsxpOV6R06irWmdUMl+O/GWhHag=="],
|
||||
"@tamagui/theme-builder": ["@tamagui/theme-builder@1.141.4", "", { "dependencies": { "@tamagui/create-theme": "1.141.4", "@tamagui/web": "1.141.4", "color2k": "^2.0.2" } }, "sha512-mPvPUeJIGRVEBGvu9BG1NuAnUUEqclGqq9Q74UUoHCTPP8lIxedtfKhvf6gtoFQOhVuPeB0HArMIrZNmwzwkbg=="],
|
||||
|
||||
"@tamagui/themes": ["@tamagui/themes@1.139.1", "", { "dependencies": { "@tamagui/colors": "1.139.1", "@tamagui/create-theme": "1.139.1", "@tamagui/theme-builder": "1.139.1", "@tamagui/web": "1.139.1", "color2k": "^2.0.2" } }, "sha512-p4Hvwtigf7dUjoMXDHX1pfNV4+GVzBdE2H57d+R6L6mLTBuXjvqRyHqqTLjUrhMf3rtL5UJleWtqCRteXKytMw=="],
|
||||
"@tamagui/themes": ["@tamagui/themes@1.141.4", "", { "dependencies": { "@tamagui/colors": "1.141.4", "@tamagui/create-theme": "1.141.4", "@tamagui/theme-builder": "1.141.4", "@tamagui/web": "1.141.4", "color2k": "^2.0.2" } }, "sha512-PBU5LCRH3XKSDBHGxLuKiahNCSLCrOZo617RaBRCrQEBzWpx9cZtLQcM35H5ytO9VIVjj/g063UP0Du3y/h7WQ=="],
|
||||
|
||||
"@tamagui/timer": ["@tamagui/timer@1.139.1", "", {}, "sha512-YKahedLQEUWSNkUw/oQWHFD2AWRMONfsU3BlPe3cV1hGTICL0duqMk6XaPX9HzMVwP0kKo7IhipTZ1Q2wpGMtA=="],
|
||||
"@tamagui/timer": ["@tamagui/timer@1.141.4", "", {}, "sha512-uK81OKhy6u7c0kSf0+028XzwuuTLWN+kAAUSEtpQy/HdM4MU0oGtf1+2mnn3X8wwTBKDP9iP33uN8XHV161uEw=="],
|
||||
|
||||
"@tamagui/toggle-group": ["@tamagui/toggle-group@1.139.1", "", { "dependencies": { "@tamagui/constants": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/focusable": "1.139.1", "@tamagui/font-size": "1.139.1", "@tamagui/get-token": "1.139.1", "@tamagui/group": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/helpers-tamagui": "1.139.1", "@tamagui/roving-focus": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/use-direction": "1.139.1", "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-Jgq+tLzHEhBk5L0bOED8qL1xfcYTbOzVV9uDRdU+GAM6nzPidU0/iqNfjZAsS3JDHJIy0YvLVOgJThnMeFeu8g=="],
|
||||
"@tamagui/toggle-group": ["@tamagui/toggle-group@1.141.4", "", { "dependencies": { "@tamagui/constants": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/focusable": "1.141.4", "@tamagui/font-size": "1.141.4", "@tamagui/get-token": "1.141.4", "@tamagui/group": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/helpers-tamagui": "1.141.4", "@tamagui/roving-focus": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/use-direction": "1.141.4", "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-Stgvm+XvfbrCDFgo/fsomsrDLaO/ysA1v/TDcCVtbAbJLGjlAJxVe3B7DgagAEHRYFql62KGDOYn4MhgHjaQsw=="],
|
||||
|
||||
"@tamagui/tooltip": ["@tamagui/tooltip@1.139.1", "", { "dependencies": { "@floating-ui/react": "^0.27.16", "@tamagui/compose-refs": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/floating": "1.139.1", "@tamagui/get-token": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/polyfill-dev": "1.139.1", "@tamagui/popover": "1.139.1", "@tamagui/popper": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/text": "1.139.1", "@tamagui/use-controllable-state": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-RSNitKeIGvql7IyBkjIYklUUYMUUqewB+1jnZMz4mWDkA/dcM0uTYJRGYHt6d5s0M3UcazIGeRf+qweXjGMDuA=="],
|
||||
"@tamagui/tooltip": ["@tamagui/tooltip@1.141.4", "", { "dependencies": { "@floating-ui/react": "^0.27.16", "@tamagui/compose-refs": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/floating": "1.141.4", "@tamagui/get-token": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/polyfill-dev": "1.141.4", "@tamagui/popover": "1.141.4", "@tamagui/popper": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/text": "1.141.4", "@tamagui/use-controllable-state": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-InGdJrGeND6Ig4hEWdiIVdfj0hZKSUaLV7bSHvnCci1ba5pxr9t/Y4Z+USy01h4onumSOt7CNJZbJZW/EOMG3w=="],
|
||||
|
||||
"@tamagui/types": ["@tamagui/types@1.139.1", "", {}, "sha512-BWzJkC35l6Ue09k/fUCjJ1u5CNhIsOidTba6oYHT/2GpS48RQD2PwQxNuZn6kgWjJ5yESUHpsojAhf2mhUcXZg=="],
|
||||
"@tamagui/types": ["@tamagui/types@1.141.4", "", {}, "sha512-PO2YoO+wmIusYNL54I6A02XIoqm3ELnVGwpB5XuQfsoEy16gWU+HDsGKjlBqovSD+XHHdEJf57tMoNdG6VGezQ=="],
|
||||
|
||||
"@tamagui/use-async": ["@tamagui/use-async@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-sUssjjaUXORaKpSMFYpKdqTKILrLTJE4G5bkyNQdOnzB4vGCSRZsT99slrOxscP8mFG3XPVV3BupJ1FFGPLDCw=="],
|
||||
"@tamagui/use-async": ["@tamagui/use-async@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-X/sjWLTXVP4TEAIbC2a6c+SAnoYYrq1HzVXdeh9kN///XIj1koNwFJ1AKQ+e6dsS5d28ox8sRTyPKLryNz/r2w=="],
|
||||
|
||||
"@tamagui/use-callback-ref": ["@tamagui/use-callback-ref@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-/mL8kkfIJ9murERiTBsI6qwlOZxikjYeHqTRZvnSJaHZgyCMNo+qrJtn7nzkDuo1lzYVPYi8j1U9mcgWI6KUrQ=="],
|
||||
"@tamagui/use-callback-ref": ["@tamagui/use-callback-ref@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-mI/Jt1teDppdAhLh3DcnX/pmg9wasqXMIzRFqO6Wmgov9/jLVb8+ve/cE7jN8T8YnJHMAHFsfqRalfnUMURpDw=="],
|
||||
|
||||
"@tamagui/use-constant": ["@tamagui/use-constant@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-8ayHg6nsGaSNnICzGh31tNiThRGEq18U+KWKa71Hx7EUAfF+dVDyZ3Iy9Oy2A6NTy4rrBmE2eVJz1UYA9chthA=="],
|
||||
"@tamagui/use-constant": ["@tamagui/use-constant@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-iE5rWsl6fjBobd0jH1fMd57yekvwPD3U25DqJ0Wze5C00kvqHiWdiPeXgoZwl6i/mVT4sPmVNkfjueL0mz58Tw=="],
|
||||
|
||||
"@tamagui/use-controllable-state": ["@tamagui/use-controllable-state@1.139.1", "", { "dependencies": { "@tamagui/start-transition": "1.139.1", "@tamagui/use-event": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-Py7oFPL4P5tpSQdUJixW/ahi3ZwyAxoCf7kR8y/esCcOtjZnRyFjbDGM4rXwYqN+Y6Eat3T6gxoKJ0t1+x+LNg=="],
|
||||
"@tamagui/use-controllable-state": ["@tamagui/use-controllable-state@1.141.4", "", { "dependencies": { "@tamagui/start-transition": "1.141.4", "@tamagui/use-event": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-YK/DRJ/YU27ZFlVvPegP/YidkkZ8Kt0+EqFkpLWmNiCN8Nbf2Y6DBEafIs003DPsF0wwYTsN8ANu/SgCBJ9TCA=="],
|
||||
|
||||
"@tamagui/use-debounce": ["@tamagui/use-debounce@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-V61EGTGk4om+L+ahQD62qjKwHPfP+9Y60w1wgyxpdh1VJ925sPU080A8gamo/DlKZIGyf/hw+tOtPsYApdKdRw=="],
|
||||
"@tamagui/use-debounce": ["@tamagui/use-debounce@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-Dtk/ee5yTQJ+VD/wsDIrz86gyWBffGEkv2zKVu1OIIjUvJ2+u7GFrwwV5/kQWAdmkvne080AUGtVwHmj+v9uGA=="],
|
||||
|
||||
"@tamagui/use-did-finish-ssr": ["@tamagui/use-did-finish-ssr@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-b0nmisx8yMxRu2YzZ/Gyys6cDsiOrVNHo1cJYV7BB/UuQ5MVTFx3t5Nwa1qeU7y36Et/jUCA4x91ipiXoulqhw=="],
|
||||
"@tamagui/use-did-finish-ssr": ["@tamagui/use-did-finish-ssr@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-QnYEfmdTzkckb8mQaPWrF3c4p64T73rvKGKr9abibWVGRMjRY0cSbxv8FBcnpjgwxnfNDl63veii7RLdxGyU1w=="],
|
||||
|
||||
"@tamagui/use-direction": ["@tamagui/use-direction@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-bunQLUlB7tORvu04FB/ffxmdRt1jf+rlE6iUrVzTbXqa1gslQIjpjdY8IJyjGZVYognX3M6nOI3C8E75iDOBIg=="],
|
||||
"@tamagui/use-direction": ["@tamagui/use-direction@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-Fn13pVu+5583gDFcmFvDJSFovsjrXioiQxAJ+2y/7wjZb3uK/fBv1GgVVWJashiF9SRkr7dZhYkWRz+C8k/raQ=="],
|
||||
|
||||
"@tamagui/use-element-layout": ["@tamagui/use-element-layout@1.139.1", "", { "dependencies": { "@tamagui/constants": "1.139.1", "@tamagui/is-equal-shallow": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-z2dTvuYYFyzVzIalfgBg78rqKzBQSvBWS5RFy5WT0QSWZoyANeWmePVLesV0BRliLObVxAIGKvWHa+LPox9Anw=="],
|
||||
"@tamagui/use-element-layout": ["@tamagui/use-element-layout@1.141.4", "", { "dependencies": { "@tamagui/constants": "1.141.4", "@tamagui/is-equal-shallow": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-h+G9pg2ZiGAJX2TaEslIcPKQ7Lygml9XlnkVHAk7fvXwLyE+iHuXAl9FxYnEOFOy3xqw3Ej6Y42BAYoG48FgeA=="],
|
||||
|
||||
"@tamagui/use-escape-keydown": ["@tamagui/use-escape-keydown@1.139.1", "", { "dependencies": { "@tamagui/use-callback-ref": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-19gc6iwDMbY0Q/UOyplTHhbaCC5FDfYyzXDXmrjhT9UbIPbI/j0Z+upenHAbAITfVfLCFqjO4SZ3kgA0Mha7OA=="],
|
||||
"@tamagui/use-escape-keydown": ["@tamagui/use-escape-keydown@1.141.4", "", { "dependencies": { "@tamagui/use-callback-ref": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-fFscuu+Mx7V1Xk3VIcjBLMsmH3wS2PbqMBqaTBeT1lg/hI5tYDppoMLhweXbvi3mqrx135T2uLC7MA7P521bZQ=="],
|
||||
|
||||
"@tamagui/use-event": ["@tamagui/use-event@1.139.1", "", { "dependencies": { "@tamagui/constants": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-xlRYNfEt8URIs2h5m4XZ/7RPEjMjQbLPgaxCuUcCjvS2vmWURBhZsiYU0eLtfPivvtAuBoQI2hclAkVyqaubPg=="],
|
||||
"@tamagui/use-event": ["@tamagui/use-event@1.141.4", "", { "dependencies": { "@tamagui/constants": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-9AD3gMRA3UQwtA/lFhJyKwAeU8Q4Lcd/TodRF/GQc9tez4sJwcxPOnecNFaMF5R7y1vNrjghbaSw9W5+unVDhQ=="],
|
||||
|
||||
"@tamagui/use-force-update": ["@tamagui/use-force-update@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-fgU7dFFZ0Fr6d+yRzrgZHI9noBTUiTkx95sgIS/g6ogmVMBvuwHgLURhMloFdYzEgB6c5nA8+N2MZ9r4dQWnjQ=="],
|
||||
"@tamagui/use-force-update": ["@tamagui/use-force-update@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-+FHa8J24sLb3BWpJrah1cizvBJjhjbtxtZcvTuo3Qovt3b47ktx1o+SeEdoiGwc6OYezeuFdAYiTPVHgXqHrvQ=="],
|
||||
|
||||
"@tamagui/use-keyboard-visible": ["@tamagui/use-keyboard-visible@1.139.1", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-bAlQzv4JEHFSQZcjTLqIIuJwM7GdBxOz6PVggvzjX34Ng2U2VZEShu2Vo5InOxoX3UBZoE8zsVYumgsIwNjdVQ=="],
|
||||
"@tamagui/use-keyboard-visible": ["@tamagui/use-keyboard-visible@1.141.4", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-+f3B3TIAfUW1dPkUxtJ8WlGXhakGsvmESkbOfs0Mbk6zVONUaIXfTUB9eWOsVi/hAYL//XSOaEi54bFQD9Ug9Q=="],
|
||||
|
||||
"@tamagui/use-presence": ["@tamagui/use-presence@1.139.1", "", { "dependencies": { "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-78rVxmYbFuzCRAgkXrOwfKoC5lkZHdB5ozVEpri3qD/imlwtE8uAetlMHXMmrikr7ugYiREcpEpnRkfk5LqFVQ=="],
|
||||
"@tamagui/use-presence": ["@tamagui/use-presence@1.141.4", "", { "dependencies": { "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-KKL7kx3Wkvxhx82E1y/l4DHNC0zxhFa6FQ/76lhA5YLMy04dNXFzWzCNl2YBjH8UhypfWwJsu6teW8ku7+1NkQ=="],
|
||||
|
||||
"@tamagui/use-previous": ["@tamagui/use-previous@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-XhaflDHoddeuYvGlZF7CVSau+MYWBdYb8o2xSb3a8Uvr9wIxUymvBcE0HCGwQa7pxn5CBiRS+YlYT5hs9qwY0Q=="],
|
||||
"@tamagui/use-previous": ["@tamagui/use-previous@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-jfD+x9GpaMjEFcsTpj1ko9HrrXP/quZuwlJ3O8VHCSWCm9zEPCaHV/WLZMpeumKGeLVqUnCowqqmfWITV95cfQ=="],
|
||||
|
||||
"@tamagui/use-window-dimensions": ["@tamagui/use-window-dimensions@1.139.1", "", { "dependencies": { "@tamagui/constants": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-bT6mn3fCDbIs5p+3zAQeEQxCRSkkf60Q+jvo+qg6iULxSA7sMt6m96mVRq6atUmokvRKZorwuyys98jIERmYSA=="],
|
||||
"@tamagui/use-window-dimensions": ["@tamagui/use-window-dimensions@1.141.4", "", { "dependencies": { "@tamagui/constants": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-y2BzfajhEfbWsRIx3ATLI4uu0vEe4Vm/YKyjTCMwJTB+ZfZYoQPTiWOnmCzpsjDOTNlvP2/e1qsSoVePD5woJg=="],
|
||||
|
||||
"@tamagui/visually-hidden": ["@tamagui/visually-hidden@1.139.1", "", { "dependencies": { "@tamagui/web": "1.139.1" }, "peerDependencies": { "react": "*" } }, "sha512-MYIwr8m/vh4ClYQbVb8V+935XYq/34FOLk1+nHbmny1G5eqR4wdjuJ9k/iKGH7fUDMcARszKDU4Uz5aextAlIA=="],
|
||||
"@tamagui/visually-hidden": ["@tamagui/visually-hidden@1.141.4", "", { "dependencies": { "@tamagui/web": "1.141.4" }, "peerDependencies": { "react": "*" } }, "sha512-B0eTSm8XGNSjUG5xtceAruNh/KHw3Cik5R7LDqg/DhXdVhDSOWPXcMj35C6tGeIes8bz8BAyp9VKKyXeUCkU+w=="],
|
||||
|
||||
"@tamagui/web": ["@tamagui/web@1.139.1", "", { "dependencies": { "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/helpers": "1.139.1", "@tamagui/is-equal-shallow": "1.139.1", "@tamagui/normalize-css-color": "1.139.1", "@tamagui/timer": "1.139.1", "@tamagui/types": "1.139.1", "@tamagui/use-did-finish-ssr": "1.139.1", "@tamagui/use-event": "1.139.1", "@tamagui/use-force-update": "1.139.1" }, "peerDependencies": { "react": "*", "react-dom": "*", "react-native": "*" } }, "sha512-9eUOAHvNBndr7byhl80WT57wPDrfmU8Z8P561J9V9Bt47v2FLAGMdF3f656oSsePFOrWoRYg0QCebMldB2HE/A=="],
|
||||
"@tamagui/web": ["@tamagui/web@1.141.4", "", { "dependencies": { "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/helpers": "1.141.4", "@tamagui/is-equal-shallow": "1.141.4", "@tamagui/normalize-css-color": "1.141.4", "@tamagui/timer": "1.141.4", "@tamagui/types": "1.141.4", "@tamagui/use-did-finish-ssr": "1.141.4", "@tamagui/use-event": "1.141.4", "@tamagui/use-force-update": "1.141.4" }, "peerDependencies": { "react": "*", "react-dom": "*", "react-native": "*" } }, "sha512-hAqH75IMPcoN/PstAblJF+DbUgjk0cIuzwQiswnpn+60cIn45GkmWlwHzgIwADVrohrIKUEJXPTCu2A3cn3MWQ=="],
|
||||
|
||||
"@tamagui/z-index-stack": ["@tamagui/z-index-stack@1.139.1", "", { "peerDependencies": { "react": "*" } }, "sha512-tKp6m0wcAOq7Ydt57k/+AiKdGKdZh9BzOic0tU7Viao/TrPA2qA+IC42Hluq+Gxiazl+qLKvKG7xgQ0q8FICjw=="],
|
||||
"@tamagui/z-index-stack": ["@tamagui/z-index-stack@1.141.4", "", { "peerDependencies": { "react": "*" } }, "sha512-q/rooqEqfKxiY7lgba+7Tiyg8BF2QZ9BRUcBl4EdG4FU5fYTD5fMy7CBDszVkzTcD/Z337VEAggJVyeHxCL+Qw=="],
|
||||
|
||||
"@tanstack/query-async-storage-persister": ["@tanstack/query-async-storage-persister@5.89.0", "", { "dependencies": { "@tanstack/query-core": "5.89.0", "@tanstack/query-persist-client-core": "5.89.0" } }, "sha512-/l7JVKvQ6/oad0+ncvBcJOqRL4lIJ5E3UjfB+xgTfVeqga8wMnH1cgOlJEpvBFEDCw88hA/jpGb6Cp9my9Vc+w=="],
|
||||
"@tanstack/query-async-storage-persister": ["@tanstack/query-async-storage-persister@5.90.12", "", { "dependencies": { "@tanstack/query-core": "5.90.10", "@tanstack/query-persist-client-core": "5.91.9" } }, "sha512-bLOs6ZLTki88if8oDQDdnxk7wgMaKMAVTRxn+WiSI0An7rj3C/7/yDTjOLhwPaoipbTiFLF0/PnbpVXIbWqQYQ=="],
|
||||
|
||||
"@tanstack/query-core": ["@tanstack/query-core@5.89.0", "", {}, "sha512-joFV1MuPhSLsKfTzwjmPDrp8ENfZ9N23ymFu07nLfn3JCkSHy0CFgsyhHTJOmWaumC/WiNIKM0EJyduCF/Ih/Q=="],
|
||||
"@tanstack/query-core": ["@tanstack/query-core@5.90.10", "", {}, "sha512-EhZVFu9rl7GfRNuJLJ3Y7wtbTnENsvzp+YpcAV7kCYiXni1v8qZh++lpw4ch4rrwC0u/EZRnBHIehzCGzwXDSQ=="],
|
||||
|
||||
"@tanstack/query-persist-client-core": ["@tanstack/query-persist-client-core@5.89.0", "", { "dependencies": { "@tanstack/query-core": "5.89.0" } }, "sha512-kxZgQGgD7VqSFTDA/JyajywixHGGhzjMTtkENeVcS6BoTW6CGOkvoZH3L4/ROsaCZ4ibDfrmPzfUCpghID5ENg=="],
|
||||
"@tanstack/query-persist-client-core": ["@tanstack/query-persist-client-core@5.91.9", "", { "dependencies": { "@tanstack/query-core": "5.90.10" } }, "sha512-LliMZl/pkO/6vRf5//fO8nl4UCfM1LQsnT+N0aRYkK7bqoM3QdqHxD65EApmJRypKkqaWmiyulPG3Mi1NYuyIA=="],
|
||||
|
||||
"@tanstack/react-query": ["@tanstack/react-query@5.89.0", "", { "dependencies": { "@tanstack/query-core": "5.89.0" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-SXbtWSTSRXyBOe80mszPxpEbaN4XPRUp/i0EfQK1uyj3KCk/c8FuPJNIRwzOVe/OU3rzxrYtiNabsAmk1l714A=="],
|
||||
"@tanstack/react-query": ["@tanstack/react-query@5.90.12", "", { "dependencies": { "@tanstack/query-core": "5.90.12" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg=="],
|
||||
|
||||
"@tanstack/react-query-persist-client": ["@tanstack/react-query-persist-client@5.89.0", "", { "dependencies": { "@tanstack/query-persist-client-core": "5.89.0" }, "peerDependencies": { "@tanstack/react-query": "^5.89.0", "react": "^18 || ^19" } }, "sha512-c1RaSID8DPzr7HnO2kfah5ON/lEtN/g0gN4nRsxWPi8gjWQRMfOh9av/KJWxxqWnBMPZ+tMV5Lb1OS38GAIRrw=="],
|
||||
"@tanstack/react-query-persist-client": ["@tanstack/react-query-persist-client@5.90.12", "", { "dependencies": { "@tanstack/query-persist-client-core": "5.91.9" }, "peerDependencies": { "@tanstack/react-query": "^5.90.10", "react": "^18 || ^19" } }, "sha512-o51hwImpKgb85FnFljtCXcUzuLXpKONF9N6bhKfifPL3SNSj8neh1a2aHQd7sN9mbeIeNfGMGJuDpSt/Fc3GwQ=="],
|
||||
|
||||
"@telemetrydeck/sdk": ["@telemetrydeck/sdk@2.0.4", "", {}, "sha512-x4S83AqSo6wvLJ6nRYdyJEqd9qmblUdBgsTRrjH5z++b9pnf2NMc8NpVAa48KIB1pRuP/GTGzXxVYdNoie/DVg=="],
|
||||
|
||||
@@ -874,11 +874,11 @@
|
||||
|
||||
"@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="],
|
||||
|
||||
"@types/lodash": ["@types/lodash@4.17.20", "", {}, "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA=="],
|
||||
"@types/lodash": ["@types/lodash@4.17.21", "", {}, "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ=="],
|
||||
|
||||
"@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="],
|
||||
|
||||
"@types/react": ["@types/react@19.2.6", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w=="],
|
||||
"@types/react": ["@types/react@19.2.0", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-1LOH8xovvsKsCBq1wnT4ntDUdCJKmnEakhsuoUSy6ExlHCkGP2hqnatagYTgFk6oeL0VU31u7SNjunPN+GchtA=="],
|
||||
|
||||
"@types/react-native": ["@types/react-native@0.70.19", "", { "dependencies": { "@types/react": "*" } }, "sha512-c6WbyCgWTBgKKMESj/8b4w+zWcZSsCforson7UdXtXMecG3MxCinYi6ihhrHVPyUrVzORsvEzK8zg32z4pK6Sg=="],
|
||||
|
||||
@@ -1238,7 +1238,7 @@
|
||||
|
||||
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
||||
|
||||
"eslint": ["eslint@9.39.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.1", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g=="],
|
||||
"eslint": ["eslint@9.39.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw=="],
|
||||
|
||||
"eslint-config-prettier": ["eslint-config-prettier@10.1.8", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w=="],
|
||||
|
||||
@@ -1258,7 +1258,7 @@
|
||||
|
||||
"eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="],
|
||||
|
||||
"eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.2.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg=="],
|
||||
"eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@7.0.1", "", { "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", "hermes-parser": "^0.25.1", "zod": "^3.25.0 || ^4.0.0", "zod-validation-error": "^3.5.0 || ^4.0.0" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA=="],
|
||||
|
||||
"eslint-plugin-react-native": ["eslint-plugin-react-native@5.0.0", "", { "dependencies": { "eslint-plugin-react-native-globals": "^0.1.1" }, "peerDependencies": { "eslint": "^3.17.0 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, "sha512-VyWlyCC/7FC/aONibOwLkzmyKg4j9oI8fzrk9WYNs4I8/m436JuOTAFwLvEn1CVvc7La4cPfbCyspP4OYpP52Q=="],
|
||||
|
||||
@@ -1408,7 +1408,7 @@
|
||||
|
||||
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||
|
||||
"hermes-compiler": ["hermes-compiler@0.0.0", "", {}, "sha512-boVFutx6ME/Km2mB6vvsQcdnazEYYI/jV1pomx1wcFUG/EVqTkr5CU0CW9bKipOA/8Hyu3NYwW3THg2Q1kNCfA=="],
|
||||
"hermes-compiler": ["hermes-compiler@0.14.0", "", {}, "sha512-clxa193o+GYYwykWVFfpHduCATz8fR5jvU7ngXpfKHj+E9hr9vjLNtdLSEe8MUbObvVexV3wcyxQ00xTPIrB1Q=="],
|
||||
|
||||
"hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="],
|
||||
|
||||
@@ -1854,7 +1854,7 @@
|
||||
|
||||
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
||||
|
||||
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
|
||||
"prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="],
|
||||
|
||||
"prettier-linter-helpers": ["prettier-linter-helpers@1.0.0", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w=="],
|
||||
|
||||
@@ -1886,7 +1886,7 @@
|
||||
|
||||
"raw-body": ["raw-body@2.5.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA=="],
|
||||
|
||||
"react": ["react@19.1.1", "", {}, "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ=="],
|
||||
"react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="],
|
||||
|
||||
"react-devtools-core": ["react-devtools-core@6.1.5", "", { "dependencies": { "shell-quote": "^1.6.1", "ws": "^7" } }, "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA=="],
|
||||
|
||||
@@ -1896,13 +1896,13 @@
|
||||
|
||||
"react-is": ["react-is@19.2.0", "", {}, "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA=="],
|
||||
|
||||
"react-native": ["react-native@0.82.1", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.82.1", "@react-native/codegen": "0.82.1", "@react-native/community-cli-plugin": "0.82.1", "@react-native/gradle-plugin": "0.82.1", "@react-native/js-polyfills": "0.82.1", "@react-native/normalize-colors": "0.82.1", "@react-native/virtualized-lists": "0.82.1", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.32.0", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", "hermes-compiler": "0.0.0", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.83.1", "metro-source-map": "^0.83.1", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.26.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^6.2.3", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.1.1", "react": "^19.1.1" }, "optionalPeers": ["@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-tFAqcU7Z4g49xf/KnyCEzI4nRTu1Opcx05Ov2helr8ZTg1z7AJR/3sr2rZ+AAVlAs2IXk+B0WOxXGmdD3+4czA=="],
|
||||
"react-native": ["react-native@0.83.0", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.83.0", "@react-native/codegen": "0.83.0", "@react-native/community-cli-plugin": "0.83.0", "@react-native/gradle-plugin": "0.83.0", "@react-native/js-polyfills": "0.83.0", "@react-native/normalize-colors": "0.83.0", "@react-native/virtualized-lists": "0.83.0", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.32.0", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", "hermes-compiler": "0.14.0", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.83.3", "metro-source-map": "^0.83.3", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.27.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.1.1", "react": "^19.2.0" }, "optionalPeers": ["@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-a8wPjGfkktb1+Mjvzkky3d0u6j6zdWAzftZ2LdQtgRgqkMMfgQxD9S+ri3RNlfAFQpuCAOYUIyrNHiVkUQChxA=="],
|
||||
|
||||
"react-native-background-actions": ["react-native-background-actions@4.0.1", "", { "dependencies": { "eventemitter3": "^4.0.7" }, "peerDependencies": { "react-native": ">=0.47.0" } }, "sha512-LADhnb4ag1oH5Lotq0j8K9e2cFmrafFyg2PCME88VkTjqDUgNcJonkNdMCTHN0N3fh+hwAA7nDR4Cxkj9Q8eCw=="],
|
||||
|
||||
"react-native-blob-util": ["react-native-blob-util@0.22.2", "", { "dependencies": { "base-64": "0.1.0", "glob": "^10.3.10" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-Czx01QMg7aLsm/4F/7+eqoRAi1q/qjLY2Kao16g+n2SRnTH1+qkD8Qhx2q9okB+VNQvZKB1LbiXhktzYQV52xQ=="],
|
||||
|
||||
"react-native-blurhash": ["react-native-blurhash@2.1.1", "", { "peerDependencies": { "react": ">=16.8.1", "react-native": ">=0.60.0-rc.0 <1.0.x" } }, "sha512-b1aA5Tn31pPbqmaWnhJv7zSuN6o9M1t4yHciPunfP89LDkH2dvDIynvkE00Hen4Vmt6SnyXViSYH34MyvTvRiA=="],
|
||||
"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-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=="],
|
||||
|
||||
@@ -1926,25 +1926,25 @@
|
||||
|
||||
"react-native-linear-gradient": ["react-native-linear-gradient@2.8.3", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-KflAXZcEg54PXkLyflaSZQ3PJp4uC4whM7nT/Uot9m0e/qxFV3p6uor1983D1YOBJbJN7rrWdqIjq0T42jOJyA=="],
|
||||
|
||||
"react-native-mmkv": ["react-native-mmkv@3.3.3", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-GMsfOmNzx0p5+CtrCFRVtpOOMYNJXuksBVARSQrCFaZwjUyHJdQzcN900GGaFFNTxw2fs8s5Xje//RDKj9+PZA=="],
|
||||
"react-native-mmkv": ["react-native-mmkv@4.1.0", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "*" } }, "sha512-ia76WnU6dkLZxFkSSflxqFgHT2pIaML763aucEu7nMglF41oEWTdTtBu0o8a1cxbhZOaONk6KF8RQp5fLvPitA=="],
|
||||
|
||||
"react-native-nitro-fetch": ["react-native-nitro-fetch@0.1.6", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "^0.29.2", "react-native-worklets-core": "^1.6.0" }, "optionalPeers": ["react-native-worklets-core"] }, "sha512-DbE/vN5B67SJM8Q0myHOwSSc7ASqJPaKYXVsWdNGIPS+csr9gygCKILT4RQ+xZ92iJGKn4bfyq+rRsacRWBV9A=="],
|
||||
|
||||
"react-native-nitro-modules": ["react-native-nitro-modules@0.31.10", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-hcvjTu9YJE9fMmnAUvhG8CxvYLpOuMQ/2eyi/S6GyrecezF6Rmk/uRQEL6v09BRFWA/xRVZNQVulQPS+2HS3mQ=="],
|
||||
|
||||
"react-native-nitro-ota": ["react-native-nitro-ota@0.7.2", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "^0.29.8" } }, "sha512-DUa2/QhFJBhSbzrTHGrc+qm1pSuJctccUcHlHZXjPV4fCEpi+4Y17QqI9U4D9MUnnP77afKEZJKFy+0NQeSAdA=="],
|
||||
"react-native-nitro-ota": ["react-native-nitro-ota@0.8.2", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "^0.29.8" } }, "sha512-UhL+62PAj5yXQnpTqkMUBN1NX6oerAdA5lifg3XncLT3Nipswy3aZa7rDATYsXPBrWp4w8VvxfEKy4PWk7Ifxw=="],
|
||||
|
||||
"react-native-pager-view": ["react-native-pager-view@7.0.2", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-yj/v6BN/WGuV1VBVWaCjYOjQlhTaqJs4Ocismw0XRSsHGqO2wuQdWF8it5iFnfibQVBBED0/GC7qKOlQ4FBzNg=="],
|
||||
|
||||
"react-native-reanimated": ["react-native-reanimated@4.1.5", "", { "dependencies": { "react-native-is-edge-to-edge": "^1.2.1", "semver": "7.7.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0", "react": "*", "react-native": "*", "react-native-worklets": ">=0.5.0" } }, "sha512-UA6VUbxwhRjEw2gSNrvhkusUq3upfD3Cv+AnB07V+kC8kpvwRVI+ivwY95ePbWNFkFpP+Y2Sdw1WHpHWEV+P2Q=="],
|
||||
"react-native-reanimated": ["react-native-reanimated@4.1.6", "", { "dependencies": { "react-native-is-edge-to-edge": "^1.2.1", "semver": "7.7.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0", "react": "*", "react-native": "*", "react-native-worklets": ">=0.5.0" } }, "sha512-F+ZJBYiok/6Jzp1re75F/9aLzkgoQCOh4yxrnwATa8392RvM3kx+fiXXFvwcgE59v48lMwd9q0nzF1oJLXpfxQ=="],
|
||||
|
||||
"react-native-safe-area-context": ["react-native-safe-area-context@5.6.2", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg=="],
|
||||
|
||||
"react-native-screens": ["react-native-screens@4.18.0", "", { "dependencies": { "react-freeze": "^1.0.0", "warn-once": "^0.1.0" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-mRTLWL7Uc1p/RFNveEIIrhP22oxHduC2ZnLr/2iHwBeYpGXR0rJZ7Bgc0ktxQSHRjWTPT70qc/7yd4r9960PBQ=="],
|
||||
"react-native-screens": ["react-native-screens@4.19.0", "", { "dependencies": { "react-freeze": "^1.0.0", "warn-once": "^0.1.0" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-qSDAO3AL5bti0Ri7KZRSVmWlhDr8MV86N5GruiKVQfEL7Zx2nUi3Dl62lqHUAD/LnDvOPuDDsMHCfIpYSv3hPQ=="],
|
||||
|
||||
"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.0", "", { "dependencies": { "use-latest-callback": "^0.2.4" }, "peerDependencies": { "react": ">= 18.2.0", "react-native": "*", "react-native-pager-view": ">= 6.0.0" } }, "sha512-TUbh7Yr0tE/99t1pJQLbQ+4/Px67xkT7/r3AhfV+93Q3WoUira0Lx7yuKUP2C118doqxub8NCLERwcqsHr29nQ=="],
|
||||
"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-text-ticker": ["react-native-text-ticker@1.15.0", "", {}, "sha512-d/uK+PIOhsYMy1r8h825iq/nADiHsabz3WMbRJSnkpQYn+K9aykUAXRRhu8ZbTAzk4CgnUWajJEFxS5ZDygsdg=="],
|
||||
|
||||
@@ -1956,13 +1956,13 @@
|
||||
|
||||
"react-native-uuid": ["react-native-uuid@2.0.3", "", {}, "sha512-f/YfIS2f5UB+gut7t/9BKGSCYbRA9/74A5R1MDp+FLYsuS+OSWoiM/D8Jko6OJB6Jcu3v6ONuddvZKHdIGpeiw=="],
|
||||
|
||||
"react-native-worklets": ["react-native-worklets@0.6.1", "", { "dependencies": { "@babel/plugin-transform-arrow-functions": "^7.0.0-0", "@babel/plugin-transform-class-properties": "^7.0.0-0", "@babel/plugin-transform-classes": "^7.0.0-0", "@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0", "@babel/plugin-transform-optional-chaining": "^7.0.0-0", "@babel/plugin-transform-shorthand-properties": "^7.0.0-0", "@babel/plugin-transform-template-literals": "^7.0.0-0", "@babel/plugin-transform-unicode-regex": "^7.0.0-0", "@babel/preset-typescript": "^7.16.7", "convert-source-map": "^2.0.0", "semver": "7.7.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0", "react": "*", "react-native": "*" } }, "sha512-URca8l7c7Uog7gv4mcg9KILdJlnbvwdS5yfXQYf5TDkD2W1VY1sduEKrD+sA3lUPXH/TG1vmXAvNxCNwPMYgGg=="],
|
||||
"react-native-worklets": ["react-native-worklets@0.7.1", "", { "dependencies": { "@babel/plugin-transform-arrow-functions": "7.27.1", "@babel/plugin-transform-class-properties": "7.27.1", "@babel/plugin-transform-classes": "7.28.4", "@babel/plugin-transform-nullish-coalescing-operator": "7.27.1", "@babel/plugin-transform-optional-chaining": "7.27.1", "@babel/plugin-transform-shorthand-properties": "7.27.1", "@babel/plugin-transform-template-literals": "7.27.1", "@babel/plugin-transform-unicode-regex": "7.27.1", "@babel/preset-typescript": "7.27.1", "convert-source-map": "2.0.0", "semver": "7.7.3" }, "peerDependencies": { "@babel/core": "*", "react": "*", "react-native": "*" } }, "sha512-KNsvR48ULg73QhTlmwPbdJLPsWcyBotrGPsrDRDswb5FYpQaJEThUKc2ncXE4UM5dn/ewLoQHjSjLaKUVPxPhA=="],
|
||||
|
||||
"react-native-worklets-core": ["react-native-worklets-core@1.6.2", "", { "dependencies": { "string-hash-64": "^1.0.3" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-zw73JfL40ZL/OD2TOil1El4D9ZwS3l6AFPeFfUWXh+V2/dHN8i28jHX8QXlz5DYtAkR+Ju3U1h4yiaODi/igZw=="],
|
||||
|
||||
"react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="],
|
||||
|
||||
"react-test-renderer": ["react-test-renderer@19.1.1", "", { "dependencies": { "react-is": "^19.1.1", "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.1" } }, "sha512-aGRXI+zcBTtg0diHofc7+Vy97nomBs9WHHFY1Csl3iV0x6xucjNYZZAkiVKGiNYUv23ecOex5jE67t8ZzqYObA=="],
|
||||
"react-test-renderer": ["react-test-renderer@19.2.0", "", { "dependencies": { "react-is": "^19.2.0", "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-zLCFMHFE9vy/w3AxO0zNxy6aAupnCuLSVOJYDe/Tp+ayGI1f2PLQsFVPANSD42gdSbmYx5oN+1VWDhcXtq7hAQ=="],
|
||||
|
||||
"readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
|
||||
|
||||
@@ -2136,7 +2136,7 @@
|
||||
|
||||
"tabbable": ["tabbable@6.3.0", "", {}, "sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ=="],
|
||||
|
||||
"tamagui": ["tamagui@1.139.1", "", { "dependencies": { "@tamagui/accordion": "1.139.1", "@tamagui/adapt": "1.139.1", "@tamagui/alert-dialog": "1.139.1", "@tamagui/animate-presence": "1.139.1", "@tamagui/avatar": "1.139.1", "@tamagui/button": "1.139.1", "@tamagui/card": "1.139.1", "@tamagui/checkbox": "1.139.1", "@tamagui/compose-refs": "1.139.1", "@tamagui/constants": "1.139.1", "@tamagui/core": "1.139.1", "@tamagui/create-context": "1.139.1", "@tamagui/dialog": "1.139.1", "@tamagui/elements": "1.139.1", "@tamagui/fake-react-native": "1.139.1", "@tamagui/focusable": "1.139.1", "@tamagui/font-size": "1.139.1", "@tamagui/form": "1.139.1", "@tamagui/get-button-sized": "1.139.1", "@tamagui/get-font-sized": "1.139.1", "@tamagui/get-token": "1.139.1", "@tamagui/group": "1.139.1", "@tamagui/helpers-tamagui": "1.139.1", "@tamagui/image": "1.139.1", "@tamagui/label": "1.139.1", "@tamagui/linear-gradient": "1.139.1", "@tamagui/list-item": "1.139.1", "@tamagui/polyfill-dev": "1.139.1", "@tamagui/popover": "1.139.1", "@tamagui/popper": "1.139.1", "@tamagui/portal": "1.139.1", "@tamagui/progress": "1.139.1", "@tamagui/radio-group": "1.139.1", "@tamagui/react-native-media-driver": "1.139.1", "@tamagui/scroll-view": "1.139.1", "@tamagui/select": "1.139.1", "@tamagui/separator": "1.139.1", "@tamagui/shapes": "1.139.1", "@tamagui/sheet": "1.139.1", "@tamagui/slider": "1.139.1", "@tamagui/stacks": "1.139.1", "@tamagui/switch": "1.139.1", "@tamagui/tabs": "1.139.1", "@tamagui/text": "1.139.1", "@tamagui/theme": "1.139.1", "@tamagui/toggle-group": "1.139.1", "@tamagui/tooltip": "1.139.1", "@tamagui/use-controllable-state": "1.139.1", "@tamagui/use-debounce": "1.139.1", "@tamagui/use-force-update": "1.139.1", "@tamagui/use-window-dimensions": "1.139.1", "@tamagui/visually-hidden": "1.139.1", "@tamagui/z-index-stack": "1.139.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-z0eT+uC+hI5JT0AIv1JwxN2s9wZDGeUJc1fJ2vLrkIYgPME0f/OYTbjuO+idhcXllL/RvSeFC5MA/ZxPM4ZfxQ=="],
|
||||
"tamagui": ["tamagui@1.141.4", "", { "dependencies": { "@tamagui/accordion": "1.141.4", "@tamagui/adapt": "1.141.4", "@tamagui/alert-dialog": "1.141.4", "@tamagui/animate-presence": "1.141.4", "@tamagui/avatar": "1.141.4", "@tamagui/button": "1.141.4", "@tamagui/card": "1.141.4", "@tamagui/checkbox": "1.141.4", "@tamagui/compose-refs": "1.141.4", "@tamagui/constants": "1.141.4", "@tamagui/core": "1.141.4", "@tamagui/create-context": "1.141.4", "@tamagui/dialog": "1.141.4", "@tamagui/elements": "1.141.4", "@tamagui/fake-react-native": "1.141.4", "@tamagui/focusable": "1.141.4", "@tamagui/font-size": "1.141.4", "@tamagui/form": "1.141.4", "@tamagui/get-button-sized": "1.141.4", "@tamagui/get-font-sized": "1.141.4", "@tamagui/get-token": "1.141.4", "@tamagui/group": "1.141.4", "@tamagui/helpers-tamagui": "1.141.4", "@tamagui/image": "1.141.4", "@tamagui/label": "1.141.4", "@tamagui/linear-gradient": "1.141.4", "@tamagui/list-item": "1.141.4", "@tamagui/polyfill-dev": "1.141.4", "@tamagui/popover": "1.141.4", "@tamagui/popper": "1.141.4", "@tamagui/portal": "1.141.4", "@tamagui/progress": "1.141.4", "@tamagui/radio-group": "1.141.4", "@tamagui/react-native-media-driver": "1.141.4", "@tamagui/scroll-view": "1.141.4", "@tamagui/select": "1.141.4", "@tamagui/separator": "1.141.4", "@tamagui/shapes": "1.141.4", "@tamagui/sheet": "1.141.4", "@tamagui/slider": "1.141.4", "@tamagui/stacks": "1.141.4", "@tamagui/switch": "1.141.4", "@tamagui/tabs": "1.141.4", "@tamagui/text": "1.141.4", "@tamagui/theme": "1.141.4", "@tamagui/toggle-group": "1.141.4", "@tamagui/tooltip": "1.141.4", "@tamagui/use-controllable-state": "1.141.4", "@tamagui/use-debounce": "1.141.4", "@tamagui/use-force-update": "1.141.4", "@tamagui/use-window-dimensions": "1.141.4", "@tamagui/visually-hidden": "1.141.4", "@tamagui/z-index-stack": "1.141.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-lsApekHfFDymY7kqIRVWLRPIiY7lMtkSepuWLcTb0tAGUFKTopWRYZrLRonhKmkyWKNEZY2m7lNHCCqZGg9z0A=="],
|
||||
|
||||
"terser": ["terser@5.44.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw=="],
|
||||
|
||||
@@ -2178,7 +2178,7 @@
|
||||
|
||||
"typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", "is-typed-array": "^1.1.13", "possible-typed-array-names": "^1.0.0", "reflect.getprototypeof": "^1.0.6" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="],
|
||||
|
||||
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
|
||||
|
||||
@@ -2274,7 +2274,11 @@
|
||||
|
||||
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
|
||||
|
||||
"zustand": ["zustand@5.0.8", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw=="],
|
||||
"zod": ["zod@4.1.13", "", {}, "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig=="],
|
||||
|
||||
"zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="],
|
||||
|
||||
"zustand": ["zustand@5.0.9", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg=="],
|
||||
|
||||
"@babel/eslint-parser/eslint-visitor-keys": ["eslint-visitor-keys@2.1.0", "", {}, "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw=="],
|
||||
|
||||
@@ -2354,10 +2358,20 @@
|
||||
|
||||
"@react-native/community-cli-plugin/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
|
||||
|
||||
"@react-native/dev-middleware/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="],
|
||||
|
||||
"@react-native/eslint-config/eslint-config-prettier": ["eslint-config-prettier@8.10.2", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-/IGJ6+Dka158JnP5n5YFMOszjDWrXggGz1LaK/guZq9vZTmniaKlHcsscvkAhn9y4U+BU3JuUdYvtAMcv30y4A=="],
|
||||
|
||||
"@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=="],
|
||||
|
||||
"@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=="],
|
||||
|
||||
"@types/react-native-vector-icons/@types/react": ["@types/react@19.2.6", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w=="],
|
||||
|
||||
"@types/react-test-renderer/@types/react": ["@types/react@19.2.6", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w=="],
|
||||
|
||||
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
|
||||
|
||||
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||
@@ -2404,6 +2418,8 @@
|
||||
|
||||
"eslint-plugin-react/resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="],
|
||||
|
||||
"eslint-plugin-react-hooks/hermes-parser": ["hermes-parser@0.25.1", "", { "dependencies": { "hermes-estree": "0.25.1" } }, "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA=="],
|
||||
|
||||
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
||||
"finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||
@@ -2546,13 +2562,23 @@
|
||||
|
||||
"react-native/pretty-format": ["pretty-format@29.7.0", "", { "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } }, "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ=="],
|
||||
|
||||
"react-native/scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||
|
||||
"react-native/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
|
||||
|
||||
"react-native/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="],
|
||||
|
||||
"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-reanimated/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||
|
||||
"react-native-worklets/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=="],
|
||||
|
||||
"react-native-worklets/@babel/preset-typescript": ["@babel/preset-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ=="],
|
||||
|
||||
"react-native-worklets/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
|
||||
|
||||
"react-test-renderer/scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||
|
||||
"resolve-cwd/resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
|
||||
|
||||
@@ -2664,6 +2690,8 @@
|
||||
|
||||
"connect/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
|
||||
|
||||
"eslint-plugin-react-hooks/hermes-parser/hermes-estree": ["hermes-estree@0.25.1", "", {}, "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw=="],
|
||||
|
||||
"finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
|
||||
|
||||
"find-cache-dir/pkg-dir/find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="],
|
||||
|
||||
@@ -543,7 +543,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 267;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WAH9CZ8BPG;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -554,7 +554,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
MARKETING_VERSION = 1.0.6;
|
||||
NEW_SETTING = "";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -585,7 +585,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 267;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
DEVELOPMENT_TEAM = WAH9CZ8BPG;
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WAH9CZ8BPG;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
@@ -595,7 +595,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
MARKETING_VERSION = 1.0.6;
|
||||
NEW_SETTING = "";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -698,6 +698,7 @@
|
||||
);
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_CPLUSPLUSFLAGS = (
|
||||
"$(OTHER_CFLAGS)",
|
||||
"-DFOLLY_NO_CONFIG",
|
||||
@@ -788,6 +789,7 @@
|
||||
"\"$(inherited)\"",
|
||||
);
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_CPLUSPLUSFLAGS = (
|
||||
"$(OTHER_CFLAGS)",
|
||||
"-DFOLLY_NO_CONFIG",
|
||||
@@ -821,7 +823,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 267;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
DEVELOPMENT_TEAM = WAH9CZ8BPG;
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WAH9CZ8BPG;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
@@ -832,7 +834,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
MARKETING_VERSION = 1.0.6;
|
||||
NEW_SETTING = "";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -920,6 +922,7 @@
|
||||
"\"$(inherited)\"",
|
||||
);
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_CPLUSPLUSFLAGS = (
|
||||
"$(OTHER_CFLAGS)",
|
||||
"-DFOLLY_NO_CONFIG",
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>12</string>
|
||||
<string>13</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
@@ -32,40 +32,6 @@
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
<key>NSAllowsArbitraryLoadsForMedia</key>
|
||||
<true/>
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
<true/>
|
||||
<key>NSAllowsLocalNetworkingUsageDescription</key>
|
||||
<dict>
|
||||
<key>NSATSExceptionThirdPartyServiceConnectionUsage</key>
|
||||
<dict>
|
||||
<key>NSATSExceptionThirdPartyServiceConnectionPurpose</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>NSThirdPartyMediaStreaming</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>nip.io</key>
|
||||
<dict>
|
||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
<key>NSIncludesSubdomains</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>100.64.0.0/10</key>
|
||||
<dict>
|
||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
<key>NSIncludesSubdomains</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
@@ -73,7 +39,7 @@
|
||||
<string>_CC1AD845._googlecast._tcp</string>
|
||||
</array>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>${PRODUCT_NAME} uses the local network to connect to one's Jellyfin server for streaming music</string>
|
||||
<string>${PRODUCT_NAME} uses the local network to connect to one's Jellyfin server for streaming music</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<key>RCTNewArchEnabled</key>
|
||||
|
||||
922
ios/Podfile.lock
@@ -23,6 +23,7 @@ module.exports = {
|
||||
'./jest/setup/nitro-ota.ts',
|
||||
'./tamagui.config.ts',
|
||||
'./jest/setup/native-modules.ts',
|
||||
'./jest/setup/worklets.ts',
|
||||
],
|
||||
extensionsToTreatAsEsm: ['.ts', '.tsx'],
|
||||
transformIgnorePatterns: [
|
||||
|
||||
1
jest/setup/worklets.ts
Normal file
@@ -0,0 +1 @@
|
||||
jest.mock('react-native-worklets', () => require('react-native-worklets/src/mock'))
|
||||
@@ -36,7 +36,7 @@ appId: com.cosmonautical.jellify
|
||||
- assertVisible:
|
||||
text: "Downloaded Tracks"
|
||||
- assertVisible:
|
||||
text: "Automatically Cache Tracks"
|
||||
text: "Auto-Download Tracks"
|
||||
- assertVisible:
|
||||
text: "Download Quality"
|
||||
|
||||
|
||||
74
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jellify",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.6",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"init-android": "bun i",
|
||||
@@ -43,29 +43,29 @@
|
||||
"@react-native-community/netinfo": "^11.4.1",
|
||||
"@react-native-masked-view/masked-view": "^0.3.2",
|
||||
"@react-native-vector-icons/material-design-icons": "12.4.0",
|
||||
"@react-navigation/bottom-tabs": "7.8.10",
|
||||
"@react-navigation/material-top-tabs": "7.4.7",
|
||||
"@react-navigation/native": "7.1.23",
|
||||
"@react-navigation/native-stack": "7.8.4",
|
||||
"@sentry/react-native": "7.6.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",
|
||||
"@sentry/react-native": "7.8.0",
|
||||
"@shopify/flash-list": "2.2.0",
|
||||
"@tamagui/config": "1.139.1",
|
||||
"@tanstack/query-async-storage-persister": "5.89.0",
|
||||
"@tanstack/react-query": "5.89.0",
|
||||
"@tanstack/react-query-persist-client": "5.89.0",
|
||||
"@tamagui/config": "1.141.4",
|
||||
"@tanstack/query-async-storage-persister": "5.90.12",
|
||||
"@tanstack/react-query": "5.90.12",
|
||||
"@tanstack/react-query-persist-client": "5.90.12",
|
||||
"@testing-library/react-native": "13.3.3",
|
||||
"@typedigital/telemetrydeck-react": "^0.4.1",
|
||||
"@typedigital/telemetrydeck-react": "0.4.1",
|
||||
"axios": "1.13.2",
|
||||
"bundle": "^2.1.0",
|
||||
"dlx": "^0.2.1",
|
||||
"invert-color": "^2.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"openai": "5.21.0",
|
||||
"react": "19.1.1",
|
||||
"react-native": "0.82.1",
|
||||
"react": "19.2.0",
|
||||
"react-native": "0.83.0",
|
||||
"react-native-background-actions": "^4.0.1",
|
||||
"react-native-blob-util": "^0.22.2",
|
||||
"react-native-blurhash": "2.1.1",
|
||||
"react-native-blurhash": "^2.1.3",
|
||||
"react-native-carplay": "^2.4.1-beta.0",
|
||||
"react-native-config": "1.5.6",
|
||||
"react-native-device-info": "15.0.1",
|
||||
@@ -75,48 +75,48 @@
|
||||
"react-native-google-cast": "^4.9.1",
|
||||
"react-native-haptic-feedback": "^2.3.3",
|
||||
"react-native-linear-gradient": "^2.8.3",
|
||||
"react-native-mmkv": "3.3.3",
|
||||
"react-native-mmkv": "^4.1.0",
|
||||
"react-native-nitro-fetch": "^0.1.6",
|
||||
"react-native-nitro-modules": "0.31.10",
|
||||
"react-native-nitro-ota": "0.7.2",
|
||||
"react-native-nitro-ota": "0.8.2",
|
||||
"react-native-pager-view": "^7.0.2",
|
||||
"react-native-reanimated": "4.1.5",
|
||||
"react-native-reanimated": "4.1.6",
|
||||
"react-native-safe-area-context": "5.6.2",
|
||||
"react-native-screens": "4.18.0",
|
||||
"react-native-screens": "4.19.0",
|
||||
"react-native-sortables": "1.9.4",
|
||||
"react-native-text-ticker": "^1.15.0",
|
||||
"react-native-toast-message": "^2.3.3",
|
||||
"react-native-track-player": "5.0.0-alpha0",
|
||||
"react-native-url-polyfill": "^2.0.0",
|
||||
"react-native-uuid": "^2.0.3",
|
||||
"react-native-worklets": "0.6.1",
|
||||
"react-native-worklets": "^0.7.1",
|
||||
"react-native-worklets-core": "^1.6.2",
|
||||
"ruby": "^0.6.1",
|
||||
"scheduler": "^0.26.0",
|
||||
"tamagui": "1.139.1",
|
||||
"zustand": "^5.0.8"
|
||||
"tamagui": "1.141.4",
|
||||
"zustand": "5.0.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.28.0",
|
||||
"@babel/preset-env": "^7.28.0",
|
||||
"@babel/runtime": "^7.28.0",
|
||||
"@babel/core": "7.28.5",
|
||||
"@babel/preset-env": "7.28.5",
|
||||
"@babel/runtime": "7.28.4",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "^9.32.0",
|
||||
"@eslint/js": "9.39.2",
|
||||
"@react-native-community/cli-platform-android": "20.0.0",
|
||||
"@react-native-community/cli-platform-ios": "20.0.0",
|
||||
"@react-native/babel-preset": "0.82.1",
|
||||
"@react-native/eslint-config": "0.82.1",
|
||||
"@react-native/metro-config": "0.82.1",
|
||||
"@react-native/typescript-config": "0.82.1",
|
||||
"@react-native/babel-preset": "0.83.0",
|
||||
"@react-native/eslint-config": "0.83.0",
|
||||
"@react-native/metro-config": "0.83.0",
|
||||
"@react-native/typescript-config": "0.83.0",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/lodash": "^4.17.20",
|
||||
"@types/lodash": "^4.17.21",
|
||||
"@types/node": "^24.2.1",
|
||||
"@types/react": "^19.1.1",
|
||||
"@types/react": "19.2.0",
|
||||
"@types/react-native-vector-icons": "^6.4.18",
|
||||
"@types/react-test-renderer": "19.1.0",
|
||||
"babel-plugin-module-resolver": "^5.0.2",
|
||||
"babel-plugin-react-compiler": "^1.0.0",
|
||||
"eslint": "^9.33.0",
|
||||
"eslint": "9.39.2",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-prettier": "^5.5.4",
|
||||
@@ -124,15 +124,15 @@
|
||||
"eslint-plugin-react-native": "^5.0.0",
|
||||
"globals": "^16.3.0",
|
||||
"husky": "^9.1.7",
|
||||
"jest": "^30.0.5",
|
||||
"jest": "30.2.0",
|
||||
"jscodeshift": "^17.3.0",
|
||||
"lint-staged": "^16.1.5",
|
||||
"patch-package": "8.0.0",
|
||||
"prettier": "^3.6.2",
|
||||
"react-dom": "^19.1.0",
|
||||
"prettier": "3.7.4",
|
||||
"react-dom": "19.2.0",
|
||||
"react-native-cli-bump-version": "^1.5.1",
|
||||
"react-test-renderer": "19.1.1",
|
||||
"typescript": "5.9.2"
|
||||
"react-test-renderer": "19.2.0",
|
||||
"typescript": "5.9.3"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,ts,tsx}": [
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
diff --git a/node_modules/react-native-blurhash/android/src/main/java/com/mrousavy/blurhash/BlurhashViewManager.kt b/node_modules/react-native-blurhash/android/src/main/java/com/mrousavy/blurhash/BlurhashViewManager.kt
|
||||
index 9224e9a..193540b 100644
|
||||
--- a/node_modules/react-native-blurhash/android/src/main/java/com/mrousavy/blurhash/BlurhashViewManager.kt
|
||||
+++ b/node_modules/react-native-blurhash/android/src/main/java/com/mrousavy/blurhash/BlurhashViewManager.kt
|
||||
@@ -108,7 +108,7 @@ class BlurhashViewManager :
|
||||
return image
|
||||
}
|
||||
|
||||
- override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any>? {
|
||||
+ override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any>? {
|
||||
return MapBuilder.builder<String, Any>()
|
||||
.put(LoadErrorEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadError"))
|
||||
.put(LoadStartEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadStart"))
|
||||
diff --git a/node_modules/react-native-blurhash/ios/BlurhashViewManager.swift b/node_modules/react-native-blurhash/ios/BlurhashViewManager.swift
|
||||
index a22972f..8415cdc 100644
|
||||
--- a/node_modules/react-native-blurhash/ios/BlurhashViewManager.swift
|
||||
+++ b/node_modules/react-native-blurhash/ios/BlurhashViewManager.swift
|
||||
@@ -88,6 +88,11 @@ final class BlurhashViewWrapper: UIView, BlurhashViewDelegate {
|
||||
blurhashView.frame = frame
|
||||
}
|
||||
|
||||
+ override func layoutSubviews() {
|
||||
+ super.layoutSubviews()
|
||||
+ blurhashView.frame = bounds
|
||||
+ }
|
||||
+
|
||||
override func didSetProps(_: [String]!) {
|
||||
blurhashView.finalizeUpdates()
|
||||
}
|
||||
13
patches/react-native-reanimated+4.1.6.patch
Normal file
@@ -0,0 +1,13 @@
|
||||
diff --git a/node_modules/react-native-reanimated/compatibility.json b/node_modules/react-native-reanimated/compatibility.json
|
||||
index f1ba9cb..234363b 100644
|
||||
--- a/node_modules/react-native-reanimated/compatibility.json
|
||||
+++ b/node_modules/react-native-reanimated/compatibility.json
|
||||
@@ -4,7 +4,7 @@
|
||||
"react-native-worklets": ["nightly"]
|
||||
},
|
||||
"4.1.x": {
|
||||
- "react-native": ["0.78", "0.79", "0.80", "0.81", "0.82"],
|
||||
+ "react-native": ["0.78", "0.79", "0.80", "0.81", "0.82", "0.83"],
|
||||
"react-native-worklets": ["0.5.x", "0.6.x", "0.7.x"]
|
||||
},
|
||||
"4.0.x": {
|
||||
@@ -1,17 +0,0 @@
|
||||
diff --git a/node_modules/react-native-screens/ios/RNSScreen.mm b/node_modules/react-native-screens/ios/RNSScreen.mm
|
||||
index 65c18f1..e11b806 100644
|
||||
--- a/node_modules/react-native-screens/ios/RNSScreen.mm
|
||||
+++ b/node_modules/react-native-screens/ios/RNSScreen.mm
|
||||
@@ -928,7 +928,11 @@ - (BOOL)isTransparentModal
|
||||
- (void)invalidate
|
||||
{
|
||||
_controller = nil;
|
||||
- [_sheetsScrollView removeObserver:self forKeyPath:@"bounds" context:nil];
|
||||
+ @try {
|
||||
+ [_sheetsScrollView removeObserver:self forKeyPath:@"bounds" context:nil];
|
||||
+ } @catch (NSException *exception) {
|
||||
+ RCTLogWarn(@"[RNScreens] Tried to remove observer in invalidate, but it was not registered: %@.", exception);
|
||||
+ }
|
||||
}
|
||||
|
||||
#if !TARGET_OS_TV && !TARGET_OS_VISION
|
||||
BIN
screenshots/add_to_playlist.png
Normal file
|
After Width: | Height: | Size: 488 KiB |
|
Before Width: | Height: | Size: 1005 KiB After Width: | Height: | Size: 755 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 2.2 MiB After Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 2.7 MiB After Width: | Height: | Size: 875 KiB |
|
Before Width: | Height: | Size: 999 KiB After Width: | Height: | Size: 696 KiB |
|
Before Width: | Height: | Size: 488 KiB After Width: | Height: | Size: 772 KiB |
|
Before Width: | Height: | Size: 622 KiB After Width: | Height: | Size: 600 KiB |
@@ -17,6 +17,7 @@ const useDiscoverQueries = () => {
|
||||
refetchPublicPlaylists(),
|
||||
refetchArtistSuggestions(),
|
||||
]),
|
||||
networkMode: 'online',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MMKV } from 'react-native-mmkv'
|
||||
import { createMMKV } from 'react-native-mmkv'
|
||||
|
||||
import RNFS from 'react-native-fs'
|
||||
import JellifyTrack from '../../../types/JellifyTrack'
|
||||
@@ -27,8 +27,16 @@ const getExtensionFromUrl = (url: string): string | null => {
|
||||
|
||||
const normalizeExtension = (ext: string | undefined | null) => {
|
||||
if (!ext) return null
|
||||
|
||||
let extension
|
||||
|
||||
const clean = ext.toLowerCase()
|
||||
return clean === 'mpeg' ? 'mp3' : clean
|
||||
|
||||
if (clean.includes('mpeg')) extension = 'mp3'
|
||||
else if (clean.includes('m4a')) extension = 'm4a'
|
||||
else extension = clean
|
||||
|
||||
return extension
|
||||
}
|
||||
|
||||
const extensionFromContentType = (contentType: string | undefined): string | null => {
|
||||
@@ -52,6 +60,11 @@ export async function downloadJellyfinFile(
|
||||
setDownloadProgress: JellifyDownloadProgressState,
|
||||
preferredExtension?: string | null,
|
||||
): Promise<DownloadedFileInfo> {
|
||||
// Validate URL before attempting download to prevent NPE in native code
|
||||
if (!url || url.trim() === '') {
|
||||
throw new Error('Invalid download URL: URL is empty or undefined')
|
||||
}
|
||||
|
||||
try {
|
||||
const urlExtension = normalizeExtension(getExtensionFromUrl(url))
|
||||
const hintedExtension = normalizeExtension(preferredExtension)
|
||||
@@ -117,7 +130,7 @@ export async function downloadJellyfinFile(
|
||||
}
|
||||
}
|
||||
|
||||
const mmkv = new MMKV({
|
||||
const mmkv = createMMKV({
|
||||
id: 'offlineMode',
|
||||
encryptionKey: 'offlineMode',
|
||||
})
|
||||
@@ -160,6 +173,12 @@ export const saveAudio = async (
|
||||
//Ignore
|
||||
}
|
||||
|
||||
// Validate track URL before attempting download
|
||||
if (!track.url || track.url.trim() === '') {
|
||||
console.error('Cannot download track: URL is missing', track.item.Id)
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
const downloadedTrackFile = await downloadJellyfinFile(
|
||||
track.url,
|
||||
@@ -169,10 +188,11 @@ export const saveAudio = async (
|
||||
track.mediaSourceInfo?.Container,
|
||||
)
|
||||
let downloadedArtworkFile: DownloadedFileInfo | undefined
|
||||
if (track.artwork) {
|
||||
// Check for non-empty artwork URL (empty string passes truthy check but fails download)
|
||||
if (track.artwork && typeof track.artwork === 'string' && track.artwork.trim() !== '') {
|
||||
downloadedArtworkFile = await downloadJellyfinFile(
|
||||
track.artwork as string,
|
||||
track.item.Id as string,
|
||||
track.artwork,
|
||||
`${track.item.Id}-artwork`,
|
||||
track.title as string,
|
||||
setDownloadProgress,
|
||||
undefined,
|
||||
@@ -309,7 +329,7 @@ export const deleteDownloadsByIds = async (
|
||||
export const deleteAudioCache = async (): Promise<DeleteDownloadsResult> => {
|
||||
const downloads = getAudioCache()
|
||||
const result = await deleteDownloadsByIds(downloads.map((download) => download.item.Id))
|
||||
mmkv.delete(MMKV_OFFLINE_MODE_KEYS.AUDIO_CACHE)
|
||||
mmkv.remove(MMKV_OFFLINE_MODE_KEYS.AUDIO_CACHE)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ const useHomeQueries = () => {
|
||||
await Promise.allSettled([refetchFrequentArtists(), refetchRecentArtists()])
|
||||
return true
|
||||
},
|
||||
networkMode: 'online',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -20,4 +20,4 @@ export const useDownloadedTrack = (itemId: string | null | undefined) =>
|
||||
useDownloadedTracks([itemId])?.at(0)
|
||||
|
||||
export const useIsDownloaded = (itemIds: (string | null | undefined)[]) =>
|
||||
useDownloadedTracks(itemIds)?.length === itemIds.length
|
||||
useDownloadedTracks(itemIds)?.length === itemIds.length && itemIds.length > 0
|
||||
|
||||
18
src/api/queries/instant-mix/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { useApi, useJellifyUser } from '../../../../src/stores'
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'
|
||||
import InstantMixQueryKey from './keys'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { fetchInstantMixFromItem } from './utils'
|
||||
|
||||
const useInstantMix = (item: BaseItemDto) => {
|
||||
const api = useApi()
|
||||
|
||||
const [user] = useJellifyUser()
|
||||
|
||||
return useQuery({
|
||||
queryKey: InstantMixQueryKey(item),
|
||||
queryFn: () => fetchInstantMixFromItem(api, user, item),
|
||||
})
|
||||
}
|
||||
|
||||
export default useInstantMix
|
||||
9
src/api/queries/instant-mix/keys.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'
|
||||
|
||||
enum InstantMixQueryKeys {
|
||||
InstantMix = 'INSTANT_MIX',
|
||||
}
|
||||
|
||||
const InstantMixQueryKey = ({ Id }: BaseItemDto) => [InstantMixQueryKeys.InstantMix, Id]
|
||||
|
||||
export default InstantMixQueryKey
|
||||
@@ -1,9 +1,9 @@
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
|
||||
import { getInstantMixApi } from '@jellyfin/sdk/lib/utils/api'
|
||||
import { isUndefined } from 'lodash'
|
||||
import QueryConfig from '../../configs/query.config'
|
||||
import QueryConfig from '../../../../configs/query.config'
|
||||
import { Api } from '@jellyfin/sdk'
|
||||
import { JellifyUser } from '../../types/JellifyUser'
|
||||
import { JellifyUser } from '../../../../types/JellifyUser'
|
||||
/**
|
||||
* Fetches an instant mix for a given item
|
||||
* @param api The Jellyfin {@link Api} instance
|
||||
45
src/components/Album/footer.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
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
|
||||
>
|
||||
>()
|
||||
|
||||
return (
|
||||
<YStack marginLeft={'$2'}>
|
||||
{album.ArtistItems && album.ArtistItems.length > 1 && (
|
||||
<>
|
||||
<H5>Featuring</H5>
|
||||
|
||||
<FlashList
|
||||
data={album.ArtistItems}
|
||||
horizontal
|
||||
renderItem={({ item: artist }) => (
|
||||
<ItemCard
|
||||
size={'$8'}
|
||||
item={artist}
|
||||
caption={artist.Name ?? 'Unknown Artist'}
|
||||
onPress={() => {
|
||||
navigation.navigate('Artist', {
|
||||
artist,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</YStack>
|
||||
)
|
||||
}
|
||||
170
src/components/Album/header.tsx
Normal file
@@ -0,0 +1,170 @@
|
||||
import { fetchAlbumDiscs } from '../../api/queries/item'
|
||||
import { QueryKeys } from '../../enums/query-keys'
|
||||
import { QueuingType } from '../../enums/queuing-type'
|
||||
import { useLoadNewQueue } from '../../providers/Player/hooks/mutations'
|
||||
import { BaseStackParamList } from '../../screens/types'
|
||||
import { useApi } from '../../stores'
|
||||
import useStreamingDeviceProfile from '../../stores/device-profile'
|
||||
import { useNetworkStatus } from '../../stores/network'
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import Animated, { FadeInUp, FadeOutDown, LinearTransition } from 'react-native-reanimated'
|
||||
import { YStack, H5, XStack, Separator } from 'tamagui'
|
||||
import Icon from '../Global/components/icon'
|
||||
import ItemImage from '../Global/components/image'
|
||||
import { RunTimeTicks } from '../Global/helpers/time-codes'
|
||||
import Button from '../Global/helpers/button'
|
||||
import { Text } from '../Global/helpers/text'
|
||||
import { InstantMixButton } from '../Global/components/instant-mix-button'
|
||||
|
||||
/**
|
||||
* Renders a header for an Album's track list
|
||||
* @param album The {@link BaseItemDto} of the album to render the header for
|
||||
* @param navigation The navigation object from the parent {@link Album}
|
||||
* @param playAlbum The function to call to play the album
|
||||
* @returns A React component
|
||||
*/
|
||||
export default function AlbumTrackListHeader({ album }: { album: BaseItemDto }): React.JSX.Element {
|
||||
const api = useApi()
|
||||
|
||||
const [networkStatus] = useNetworkStatus()
|
||||
const streamingDeviceProfile = useStreamingDeviceProfile()
|
||||
|
||||
const loadNewQueue = useLoadNewQueue()
|
||||
|
||||
const { data: discs, isPending } = useQuery({
|
||||
queryKey: [QueryKeys.ItemTracks, album.Id],
|
||||
queryFn: () => fetchAlbumDiscs(api, album),
|
||||
})
|
||||
|
||||
const navigation = useNavigation<NativeStackNavigationProp<BaseStackParamList>>()
|
||||
|
||||
const playAlbum = (shuffled: boolean = false) => {
|
||||
if (!discs || discs.length === 0) return
|
||||
|
||||
const allTracks = discs.flatMap((disc) => disc.data) ?? []
|
||||
if (allTracks.length === 0) return
|
||||
|
||||
loadNewQueue({
|
||||
api,
|
||||
networkStatus,
|
||||
deviceProfile: streamingDeviceProfile,
|
||||
track: allTracks[0],
|
||||
index: 0,
|
||||
tracklist: allTracks,
|
||||
queue: album,
|
||||
queuingType: QueuingType.FromSelection,
|
||||
shuffled,
|
||||
startPlayback: true,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<YStack alignContent='center' flex={1} marginTop={'$4'}>
|
||||
<ItemImage
|
||||
item={album}
|
||||
width={200}
|
||||
height={200}
|
||||
imageOptions={{
|
||||
maxHeight: 750,
|
||||
maxWidth: 750,
|
||||
}}
|
||||
/>
|
||||
|
||||
<YStack marginTop={'$2'} alignContent='center' justifyContent='center' gap={'$2'}>
|
||||
<H5 lineBreakStrategyIOS='standard' textAlign='center' numberOfLines={5}>
|
||||
{album.Name ?? 'Untitled Album'}
|
||||
</H5>
|
||||
|
||||
{album.AlbumArtists && (
|
||||
<Text
|
||||
bold
|
||||
color={'$primary'}
|
||||
onPress={() =>
|
||||
navigation.navigate('Artist', {
|
||||
artist: album.AlbumArtists![0],
|
||||
})
|
||||
}
|
||||
textAlign='center'
|
||||
fontSize={'$5'}
|
||||
paddingBottom={'$2'}
|
||||
>
|
||||
{album.AlbumArtists![0].Name ?? 'Untitled Artist'}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<XStack justify='center' gap={'$3'} marginBottom={'$2'}>
|
||||
<YStack flex={1}>
|
||||
{album.ProductionYear ? (
|
||||
<Text fontVariant={['tabular-nums']} textAlign='right'>
|
||||
{album.ProductionYear?.toString() ?? 'Unknown Year'}
|
||||
</Text>
|
||||
) : null}
|
||||
</YStack>
|
||||
|
||||
<Separator vertical />
|
||||
|
||||
<RunTimeTicks props={{ flex: 1, textAlign: 'left' }}>
|
||||
{album.RunTimeTicks}
|
||||
</RunTimeTicks>
|
||||
</XStack>
|
||||
|
||||
{discs && (
|
||||
<XStack alignContent='center' gap={'$2'} marginHorizontal={'$2'}>
|
||||
<Animated.View
|
||||
style={{
|
||||
flex: 2,
|
||||
}}
|
||||
entering={FadeInUp.springify()}
|
||||
exiting={FadeOutDown.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
>
|
||||
<Button
|
||||
icon={() => <Icon small name='play' color='$primary' />}
|
||||
borderWidth={'$1'}
|
||||
borderColor={'$primary'}
|
||||
flex={1}
|
||||
onPress={() => playAlbum(false)}
|
||||
pressStyle={{ scale: 0.875 }}
|
||||
hoverStyle={{ scale: 0.925 }}
|
||||
animation={'bouncy'}
|
||||
>
|
||||
<Text bold color={'$primary'}>
|
||||
Play
|
||||
</Text>
|
||||
</Button>
|
||||
</Animated.View>
|
||||
|
||||
<InstantMixButton item={album} navigation={navigation} />
|
||||
|
||||
<Animated.View
|
||||
style={{
|
||||
flex: 2,
|
||||
}}
|
||||
entering={FadeInUp.springify()}
|
||||
exiting={FadeOutDown.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
>
|
||||
<Button
|
||||
icon={() => <Icon small name='shuffle' color='$primary' />}
|
||||
borderWidth={'$1'}
|
||||
borderColor={'$primary'}
|
||||
flex={1}
|
||||
onPress={() => playAlbum(true)}
|
||||
pressStyle={{ scale: 0.875 }}
|
||||
hoverStyle={{ scale: 0.925 }}
|
||||
animation={'bouncy'}
|
||||
>
|
||||
<Text bold color={'$primary'}>
|
||||
Shuffle
|
||||
</Text>
|
||||
</Button>
|
||||
</Animated.View>
|
||||
</XStack>
|
||||
)}
|
||||
</YStack>
|
||||
</YStack>
|
||||
)
|
||||
}
|
||||
@@ -1,32 +1,25 @@
|
||||
import { YStack, XStack, Separator, getToken, Spacer, Spinner } from 'tamagui'
|
||||
import { H5, Text } from '../Global/helpers/text'
|
||||
import { FlatList, SectionList } from 'react-native'
|
||||
import { RunTimeTicks } from '../Global/helpers/time-codes'
|
||||
import { YStack, XStack, Separator, Spinner } from 'tamagui'
|
||||
import { Text } from '../Global/helpers/text'
|
||||
import { SectionList } from 'react-native'
|
||||
import Track from '../Global/components/track'
|
||||
import FavoriteButton from '../Global/components/favorite-button'
|
||||
import { ItemCard } from '../Global/components/item-card'
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import InstantMixButton from '../Global/components/instant-mix-button'
|
||||
import ItemImage from '../Global/components/image'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useSafeAreaFrame } from 'react-native-safe-area-context'
|
||||
import React, { useLayoutEffect } from 'react'
|
||||
import Icon from '../Global/components/icon'
|
||||
import { useNetworkStatus } from '../../stores/network'
|
||||
import { useLoadNewQueue } from '../../providers/Player/hooks/mutations'
|
||||
import { QueuingType } from '../../enums/queuing-type'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import HomeStackParamList from '../../screens/Home/types'
|
||||
import LibraryStackParamList from '../../screens/Library/types'
|
||||
import DiscoverStackParamList from '../../screens/Discover/types'
|
||||
import { BaseStackParamList } from '../../screens/types'
|
||||
import useStreamingDeviceProfile from '../../stores/device-profile'
|
||||
import { closeAllSwipeableRows } from '../Global/components/swipeable-row-registry'
|
||||
import { useApi } from '../../stores'
|
||||
import { QueryKeys } from '../../enums/query-keys'
|
||||
import { fetchAlbumDiscs } from '../../api/queries/item'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import useAddToPendingDownloads, { usePendingDownloads } from '../../stores/network/downloads'
|
||||
import useAddToPendingDownloads, { useIsDownloading } from '../../stores/network/downloads'
|
||||
import { useIsDownloaded } from '../../api/queries/download'
|
||||
import AlbumTrackListFooter from './footer'
|
||||
import AlbumTrackListHeader from './header'
|
||||
import Animated, { FadeInUp, FadeOutDown, LinearTransition } from 'react-native-reanimated'
|
||||
import { useStorageContext } from '../../providers/Storage'
|
||||
|
||||
/**
|
||||
* The screen for an Album's track list
|
||||
@@ -46,12 +39,12 @@ export function Album({ album }: { album: BaseItemDto }): React.JSX.Element {
|
||||
queryFn: () => fetchAlbumDiscs(api, album),
|
||||
})
|
||||
|
||||
const isDownloaded = useIsDownloaded(
|
||||
discs?.flatMap(({ data }) => data).map(({ Id }) => Id) ?? [],
|
||||
)
|
||||
|
||||
const addToDownloadQueue = useAddToPendingDownloads()
|
||||
|
||||
const pendingDownloads = usePendingDownloads()
|
||||
|
||||
const downloadAlbum = (item: BaseItemDto[]) => addToDownloadQueue(item)
|
||||
|
||||
const sections = (Array.isArray(discs) ? discs : []).map(({ title, data }) => ({
|
||||
title,
|
||||
data: Array.isArray(data) ? data : [],
|
||||
@@ -61,6 +54,59 @@ export function Album({ album }: { album: BaseItemDto }): React.JSX.Element {
|
||||
|
||||
const albumTrackList = discs?.flatMap((disc) => disc.data)
|
||||
|
||||
const albumDownloadPending = useIsDownloading(albumTrackList ?? [])
|
||||
|
||||
const { deleteDownloads } = useStorageContext()
|
||||
|
||||
const handleDeleteDownload = () => deleteDownloads(albumTrackList?.map(({ Id }) => Id!) ?? [])
|
||||
|
||||
const handleDownload = () => addToDownloadQueue(albumTrackList ?? [])
|
||||
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerRight: () => (
|
||||
<XStack gap={'$2'} justifyContent='center' alignContent='center'>
|
||||
{albumTrackList &&
|
||||
(isDownloaded ? (
|
||||
<Animated.View
|
||||
entering={FadeInUp.springify()}
|
||||
exiting={FadeOutDown.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
>
|
||||
<Icon
|
||||
color='$warning'
|
||||
name='broom'
|
||||
onPress={handleDeleteDownload}
|
||||
/>
|
||||
</Animated.View>
|
||||
) : albumDownloadPending ? (
|
||||
<Spinner justifyContent='center' color={'$neutral'} />
|
||||
) : (
|
||||
<Animated.View
|
||||
entering={FadeInUp.springify()}
|
||||
exiting={FadeOutDown.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
>
|
||||
<Icon
|
||||
color='$success'
|
||||
name='download-circle-outline'
|
||||
onPress={handleDownload}
|
||||
/>
|
||||
</Animated.View>
|
||||
))}
|
||||
<FavoriteButton item={album} />
|
||||
</XStack>
|
||||
),
|
||||
})
|
||||
}, [
|
||||
album,
|
||||
navigation,
|
||||
isDownloaded,
|
||||
handleDeleteDownload,
|
||||
handleDownload,
|
||||
albumDownloadPending,
|
||||
])
|
||||
|
||||
return (
|
||||
<SectionList
|
||||
contentInsetAdjustmentBehavior='automatic'
|
||||
@@ -77,16 +123,6 @@ export function Album({ album }: { album: BaseItemDto }): React.JSX.Element {
|
||||
paddingHorizontal={'$2'}
|
||||
>
|
||||
<Text padding={'$2'} bold>{`Disc ${section.title}`}</Text>
|
||||
<Icon
|
||||
name={pendingDownloads.length ? 'progress-download' : 'download'}
|
||||
small
|
||||
onPress={() => {
|
||||
if (pendingDownloads.length) {
|
||||
return
|
||||
}
|
||||
downloadAlbum(section.data)
|
||||
}}
|
||||
/>
|
||||
</XStack>
|
||||
) : null
|
||||
}}
|
||||
@@ -102,172 +138,15 @@ export function Album({ album }: { album: BaseItemDto }): React.JSX.Element {
|
||||
)}
|
||||
ListFooterComponent={() => <AlbumTrackListFooter album={album} />}
|
||||
ListEmptyComponent={() => (
|
||||
<YStack flex={1} alignContent='center'>
|
||||
{isPending ? <Spinner color={'$primary'} /> : <Text>No tracks found</Text>}
|
||||
<YStack flex={1} alignContent='center' margin={'$4'}>
|
||||
{isPending ? (
|
||||
<Spinner color={'$primary'} />
|
||||
) : (
|
||||
<Text color={'$borderColor'}>No album tracks</Text>
|
||||
)}
|
||||
</YStack>
|
||||
)}
|
||||
onScrollBeginDrag={closeAllSwipeableRows}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a header for an Album's track list
|
||||
* @param album The {@link BaseItemDto} of the album to render the header for
|
||||
* @param navigation The navigation object from the parent {@link Album}
|
||||
* @param playAlbum The function to call to play the album
|
||||
* @returns A React component
|
||||
*/
|
||||
function AlbumTrackListHeader({ album }: { album: BaseItemDto }): React.JSX.Element {
|
||||
const api = useApi()
|
||||
|
||||
const { width } = useSafeAreaFrame()
|
||||
|
||||
const [networkStatus] = useNetworkStatus()
|
||||
const streamingDeviceProfile = useStreamingDeviceProfile()
|
||||
|
||||
const loadNewQueue = useLoadNewQueue()
|
||||
|
||||
const { data: discs, isPending } = useQuery({
|
||||
queryKey: [QueryKeys.ItemTracks, album.Id],
|
||||
queryFn: () => fetchAlbumDiscs(api, album),
|
||||
})
|
||||
|
||||
const navigation = useNavigation<NativeStackNavigationProp<BaseStackParamList>>()
|
||||
|
||||
const playAlbum = useCallback(
|
||||
(shuffled: boolean = false) => {
|
||||
if (!discs || discs.length === 0) return
|
||||
|
||||
const allTracks = discs.flatMap((disc) => disc.data) ?? []
|
||||
if (allTracks.length === 0) return
|
||||
|
||||
loadNewQueue({
|
||||
api,
|
||||
networkStatus,
|
||||
deviceProfile: streamingDeviceProfile,
|
||||
track: allTracks[0],
|
||||
index: 0,
|
||||
tracklist: allTracks,
|
||||
queue: album,
|
||||
queuingType: QueuingType.FromSelection,
|
||||
shuffled,
|
||||
startPlayback: true,
|
||||
})
|
||||
},
|
||||
[discs, loadNewQueue],
|
||||
)
|
||||
|
||||
return (
|
||||
<YStack marginTop={'$4'} alignItems='center'>
|
||||
<XStack justifyContent='center'>
|
||||
<ItemImage item={album} width={'$20'} height={'$20'} />
|
||||
|
||||
<Spacer />
|
||||
|
||||
<YStack alignContent='center' justifyContent='center'>
|
||||
<H5
|
||||
lineBreakStrategyIOS='standard'
|
||||
textAlign='center'
|
||||
numberOfLines={5}
|
||||
minWidth={width / 2.25}
|
||||
maxWidth={width / 2.15}
|
||||
>
|
||||
{album.Name ?? 'Untitled Album'}
|
||||
</H5>
|
||||
|
||||
<XStack justify='center' marginVertical={'$2'}>
|
||||
<YStack flex={1}>
|
||||
{album.ProductionYear ? (
|
||||
<Text textAlign='right'>
|
||||
{album.ProductionYear?.toString() ?? 'Unknown Year'}
|
||||
</Text>
|
||||
) : null}
|
||||
</YStack>
|
||||
|
||||
<Separator vertical marginHorizontal={'$3'} />
|
||||
|
||||
<YStack flex={1}>
|
||||
<RunTimeTicks>{album.RunTimeTicks}</RunTimeTicks>
|
||||
</YStack>
|
||||
</XStack>
|
||||
|
||||
<XStack
|
||||
justifyContent='center'
|
||||
marginVertical={'$2'}
|
||||
gap={'$4'}
|
||||
flexWrap='wrap'
|
||||
>
|
||||
<FavoriteButton item={album} />
|
||||
|
||||
<InstantMixButton item={album} navigation={navigation} />
|
||||
|
||||
<Icon name='play' onPress={() => playAlbum(false)} small />
|
||||
|
||||
<Icon name='shuffle' onPress={() => playAlbum(true)} small />
|
||||
</XStack>
|
||||
</YStack>
|
||||
</XStack>
|
||||
|
||||
<FlatList
|
||||
contentContainerStyle={{
|
||||
marginTop: getToken('$4'),
|
||||
}}
|
||||
style={{
|
||||
alignSelf: 'center',
|
||||
}}
|
||||
horizontal
|
||||
keyExtractor={(item) => item.Id!}
|
||||
data={album.AlbumArtists}
|
||||
renderItem={({ item: artist }) => (
|
||||
<ItemCard
|
||||
size={'$10'}
|
||||
item={artist}
|
||||
caption={artist.Name ?? 'Unknown Artist'}
|
||||
onPress={() => {
|
||||
navigation.navigate('Artist', {
|
||||
artist,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</YStack>
|
||||
)
|
||||
}
|
||||
|
||||
function AlbumTrackListFooter({ album }: { album: BaseItemDto }): React.JSX.Element {
|
||||
const navigation =
|
||||
useNavigation<
|
||||
NativeStackNavigationProp<
|
||||
HomeStackParamList | LibraryStackParamList | DiscoverStackParamList
|
||||
>
|
||||
>()
|
||||
|
||||
return (
|
||||
<YStack marginLeft={'$2'}>
|
||||
{album.ArtistItems && album.ArtistItems.length > 1 && (
|
||||
<>
|
||||
<H5>Featuring</H5>
|
||||
|
||||
<FlatList
|
||||
data={album.ArtistItems}
|
||||
horizontal
|
||||
renderItem={({ item: artist }) => (
|
||||
<ItemCard
|
||||
size={'$8'}
|
||||
item={artist}
|
||||
caption={artist.Name ?? 'Unknown Artist'}
|
||||
onPress={() => {
|
||||
navigation.navigate('Artist', {
|
||||
artist,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</YStack>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { RefreshControl } from 'react-native'
|
||||
import { Separator, useTheme, XStack, YStack } from 'tamagui'
|
||||
import React, { RefObject, useEffect, useRef } from 'react'
|
||||
import { Text } from '../Global/helpers/text'
|
||||
@@ -14,6 +13,7 @@ import { isString } from 'lodash'
|
||||
import FlashListStickyHeader from '../Global/helpers/flashlist-sticky-header'
|
||||
import { closeAllSwipeableRows } from '../Global/components/swipeable-row-registry'
|
||||
import useLibraryStore from '../../stores/library'
|
||||
import { RefreshControl } from 'react-native'
|
||||
|
||||
interface AlbumsProps {
|
||||
albumsInfiniteQuery: UseInfiniteQueryResult<(string | number | BaseItemDto)[], Error>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { ImageType } from '@jellyfin/sdk/lib/generated-client'
|
||||
import LinearGradient from 'react-native-linear-gradient'
|
||||
import { getTokenValue, useTheme, XStack, YStack, ZStack } from 'tamagui'
|
||||
import { XStack, YStack } from 'tamagui'
|
||||
import ItemImage from '../Global/components/image'
|
||||
import { useSafeAreaFrame } from 'react-native-safe-area-context'
|
||||
import { H5 } from '../Global/helpers/text'
|
||||
import { useArtistContext } from '../../providers/Artist'
|
||||
import FavoriteButton from '../Global/components/favorite-button'
|
||||
import InstantMixButton from '../Global/components/instant-mix-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'
|
||||
@@ -17,7 +16,6 @@ import { QueuingType } from '../../enums/queuing-type'
|
||||
import { useNetworkStatus } from '../../stores/network'
|
||||
import useStreamingDeviceProfile from '../../stores/device-profile'
|
||||
import { useApi } from '../../stores'
|
||||
import useIsLightMode from '../../hooks/use-is-light-mode'
|
||||
|
||||
export default function ArtistHeader(): React.JSX.Element {
|
||||
const { width } = useSafeAreaFrame()
|
||||
@@ -32,10 +30,6 @@ export default function ArtistHeader(): React.JSX.Element {
|
||||
|
||||
const loadNewQueue = useLoadNewQueue()
|
||||
|
||||
const theme = useTheme()
|
||||
|
||||
const isLightMode = useIsLightMode()
|
||||
|
||||
const navigation = useNavigation<NativeStackNavigationProp<BaseStackParamList>>()
|
||||
|
||||
const playArtist = async (shuffled: boolean = false) => {
|
||||
@@ -92,7 +86,7 @@ export default function ArtistHeader(): React.JSX.Element {
|
||||
<XStack alignItems='center' gap={'$3'} flex={1}>
|
||||
<FavoriteButton item={artist} />
|
||||
|
||||
<InstantMixButton item={artist} navigation={navigation} />
|
||||
<InstantMixIconButton item={artist} navigation={navigation} />
|
||||
</XStack>
|
||||
|
||||
<XStack alignItems='center' justifyContent='flex-end' gap={'$3'} flex={1}>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { RefObject, useEffect, useRef } from 'react'
|
||||
import { Separator, useTheme, XStack, YStack } from 'tamagui'
|
||||
import { Text } from '../Global/helpers/text'
|
||||
import { RefreshControl } from 'react-native'
|
||||
import ItemRow from '../Global/components/item-row'
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'
|
||||
import { FlashList, FlashListRef } from '@shopify/flash-list'
|
||||
@@ -14,6 +13,7 @@ import LibraryStackParamList from '../../screens/Library/types'
|
||||
import FlashListStickyHeader from '../Global/helpers/flashlist-sticky-header'
|
||||
import { closeAllSwipeableRows } from '../Global/components/swipeable-row-registry'
|
||||
import useLibraryStore from '../../stores/library'
|
||||
import { RefreshControl } from 'react-native'
|
||||
|
||||
export interface ArtistsProps {
|
||||
artistsInfiniteQuery: UseInfiniteQueryResult<
|
||||
@@ -142,7 +142,7 @@ export default function Artists({
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={artistsInfiniteQuery.isPending && !isAlphabetSelectorPending}
|
||||
onRefresh={() => artistsInfiniteQuery.refetch()}
|
||||
onRefresh={artistsInfiniteQuery.refetch}
|
||||
tintColor={theme.primary.val}
|
||||
/>
|
||||
}
|
||||
|
||||
35
src/components/Context/components/delete-playlist-row.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import navigationRef from '../../../../navigation'
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'
|
||||
import { StackActions, TabActions, useNavigation } from '@react-navigation/native'
|
||||
import { ListItem } from 'tamagui'
|
||||
import Icon from '../../Global/components/icon'
|
||||
import { Text } from '../../Global/helpers/text'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import LibraryStackParamList from '@/src/screens/Library/types'
|
||||
|
||||
export default function DeletePlaylistRow({
|
||||
playlist,
|
||||
}: {
|
||||
playlist: BaseItemDto
|
||||
}): React.JSX.Element {
|
||||
return (
|
||||
<ListItem
|
||||
backgroundColor={'transparent'}
|
||||
gap={'$2.5'}
|
||||
justifyContent='flex-start'
|
||||
onPress={() => {
|
||||
navigationRef.dispatch(
|
||||
StackActions.push('DeletePlaylist', {
|
||||
playlist,
|
||||
onDelete: navigationRef.goBack,
|
||||
}),
|
||||
)
|
||||
}}
|
||||
pressStyle={{ opacity: 0.5 }}
|
||||
>
|
||||
<Icon small name='delete' color='$warning' />
|
||||
|
||||
<Text bold>Delete Playlist</Text>
|
||||
</ListItem>
|
||||
)
|
||||
}
|
||||
@@ -31,11 +31,8 @@ import { useDeleteDownloads } from '../../api/mutations/download'
|
||||
import useHapticFeedback from '../../hooks/use-haptic-feedback'
|
||||
import { Platform } from 'react-native'
|
||||
import { useApi } from '../../stores'
|
||||
import useAddToPendingDownloads, {
|
||||
useIsDownloading,
|
||||
usePendingDownloads,
|
||||
} from '../../stores/network/downloads'
|
||||
import { networkStatusTypes } from '../Network/internetConnectionWatcher'
|
||||
import useAddToPendingDownloads, { useIsDownloading } from '../../stores/network/downloads'
|
||||
import DeletePlaylistRow from './components/delete-playlist-row'
|
||||
|
||||
type StackNavigation = Pick<NativeStackNavigationProp<BaseStackParamList>, 'navigate' | 'dispatch'>
|
||||
|
||||
@@ -58,8 +55,6 @@ export default function ItemContext({
|
||||
|
||||
const trigger = useHapticFeedback()
|
||||
|
||||
const [networkStatus] = useNetworkStatus()
|
||||
|
||||
const isArtist = item.Type === BaseItemKind.MusicArtist
|
||||
const isAlbum = item.Type === BaseItemKind.MusicAlbum
|
||||
const isTrack = item.Type === BaseItemKind.Audio
|
||||
@@ -95,6 +90,8 @@ export default function ItemContext({
|
||||
|
||||
const renderViewAlbumRow = isAlbum || (isTrack && album)
|
||||
|
||||
const renderDeletePlaylistRow = isPlaylist && item.CanDelete
|
||||
|
||||
const artistIds = !isPlaylist
|
||||
? isArtist
|
||||
? [item.Id]
|
||||
@@ -116,6 +113,8 @@ export default function ItemContext({
|
||||
<YGroup scrollable={Platform.OS === 'android'} marginBottom={'$8'}>
|
||||
<FavoriteContextMenuRow item={item} />
|
||||
|
||||
{renderDeletePlaylistRow && <DeletePlaylistRow playlist={item} />}
|
||||
|
||||
{renderAddToQueueRow && <AddToQueueMenuRow tracks={itemTracks} />}
|
||||
|
||||
{renderAddToQueueRow && <DownloadMenuRow items={itemTracks} />}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import React from 'react'
|
||||
import { getToken, ScrollView, useTheme, YStack } from 'tamagui'
|
||||
import RecentlyAdded from './helpers/just-added'
|
||||
import { RefreshControl } from 'react-native'
|
||||
import PublicPlaylists from './helpers/public-playlists'
|
||||
import SuggestedArtists from './helpers/suggested-artists'
|
||||
import useDiscoverQueries from '../../api/mutations/discover'
|
||||
import { useIsRestoring } from '@tanstack/react-query'
|
||||
import { useRecentlyAddedAlbums } from '../../api/queries/album'
|
||||
import { RefreshControl } from 'react-native'
|
||||
|
||||
export default function Index(): React.JSX.Element {
|
||||
const theme = useTheme()
|
||||
|
||||
const { mutateAsync: refreshAsync, isPending: refreshing } = useDiscoverQueries()
|
||||
|
||||
const isRestoring = useIsRestoring()
|
||||
|
||||
const { isPending: loadingInitialData } = useRecentlyAddedAlbums()
|
||||
|
||||
const theme = useTheme()
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
contentContainerStyle={{
|
||||
@@ -28,8 +28,8 @@ export default function Index(): React.JSX.Element {
|
||||
removeClippedSubviews
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing || isRestoring || loadingInitialData}
|
||||
onRefresh={refreshAsync}
|
||||
refreshing={refreshing || isRestoring || loadingInitialData}
|
||||
tintColor={theme.primary.val}
|
||||
/>
|
||||
}
|
||||
|
||||
@@ -9,57 +9,61 @@ import navigationRef from '../../../../navigation'
|
||||
import { useRecentlyAddedAlbums } from '../../../api/queries/album'
|
||||
import Animated, { FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
|
||||
|
||||
export default function RecentlyAdded(): React.JSX.Element | undefined {
|
||||
export default function RecentlyAdded(): React.JSX.Element | null {
|
||||
const recentlyAddedAlbumsInfinityQuery = useRecentlyAddedAlbums()
|
||||
|
||||
const navigation = useNavigation<NativeStackNavigationProp<DiscoverStackParamList>>()
|
||||
|
||||
return (
|
||||
recentlyAddedAlbumsInfinityQuery.data && (
|
||||
<Animated.View
|
||||
entering={FadeIn.springify()}
|
||||
exiting={FadeOut.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
testID='discover-recently-added'
|
||||
>
|
||||
<XStack
|
||||
alignItems='center'
|
||||
onPress={() => {
|
||||
navigation.navigate('RecentlyAdded', {
|
||||
albumsInfiniteQuery: recentlyAddedAlbumsInfinityQuery,
|
||||
})
|
||||
}}
|
||||
>
|
||||
<H5 marginLeft={'$2'}>Recently Added</H5>
|
||||
<Icon name='arrow-right' />
|
||||
</XStack>
|
||||
const recentlyAddedExists =
|
||||
recentlyAddedAlbumsInfinityQuery.data && recentlyAddedAlbumsInfinityQuery.data.length > 0
|
||||
|
||||
<HorizontalCardList
|
||||
data={recentlyAddedAlbumsInfinityQuery.data?.slice(0, 10) ?? []}
|
||||
renderItem={({ item }) => (
|
||||
<ItemCard
|
||||
caption={item.Name}
|
||||
subCaption={`${item.Artists?.join(', ')}`}
|
||||
squared
|
||||
size={'$11'}
|
||||
item={item}
|
||||
onPress={() => {
|
||||
navigation.navigate('Album', {
|
||||
album: item,
|
||||
})
|
||||
}}
|
||||
onLongPress={() => {
|
||||
navigationRef.navigate('Context', {
|
||||
item,
|
||||
navigation,
|
||||
})
|
||||
}}
|
||||
gap={'$1'}
|
||||
captionAlign='left'
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Animated.View>
|
||||
)
|
||||
)
|
||||
return recentlyAddedExists ? (
|
||||
<Animated.View
|
||||
entering={FadeIn.springify()}
|
||||
exiting={FadeOut.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
testID='discover-recently-added'
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<XStack
|
||||
alignItems='center'
|
||||
onPress={() => {
|
||||
navigation.navigate('RecentlyAdded', {
|
||||
albumsInfiniteQuery: recentlyAddedAlbumsInfinityQuery,
|
||||
})
|
||||
}}
|
||||
>
|
||||
<H5 marginLeft={'$2'}>Recently Added</H5>
|
||||
<Icon name='arrow-right' />
|
||||
</XStack>
|
||||
|
||||
<HorizontalCardList
|
||||
data={recentlyAddedAlbumsInfinityQuery.data?.slice(0, 10) ?? []}
|
||||
renderItem={({ item }) => (
|
||||
<ItemCard
|
||||
caption={item.Name}
|
||||
subCaption={`${item.Artists?.join(', ')}`}
|
||||
squared
|
||||
size={'$11'}
|
||||
item={item}
|
||||
onPress={() => {
|
||||
navigation.navigate('Album', {
|
||||
album: item,
|
||||
})
|
||||
}}
|
||||
onLongPress={() => {
|
||||
navigationRef.navigate('Context', {
|
||||
item,
|
||||
navigation,
|
||||
})
|
||||
}}
|
||||
gap={'$1'}
|
||||
captionAlign='left'
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Animated.View>
|
||||
) : null
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useJellifyServer } from '../../../stores'
|
||||
import { usePublicPlaylists } from '../../../api/queries/playlist'
|
||||
import Animated, { FadeIn, LinearTransition } from 'react-native-reanimated'
|
||||
|
||||
export default function PublicPlaylists() {
|
||||
export default function PublicPlaylists(): React.JSX.Element | null {
|
||||
const {
|
||||
data: playlists,
|
||||
fetchNextPage,
|
||||
@@ -25,57 +25,61 @@ export default function PublicPlaylists() {
|
||||
|
||||
const [server] = useJellifyServer()
|
||||
const { width } = useSafeAreaFrame()
|
||||
return (
|
||||
playlists && (
|
||||
<Animated.View
|
||||
entering={FadeIn.springify()}
|
||||
exiting={FadeIn.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
testID='discover-public-playlists'
|
||||
|
||||
const publicPlaylistsExist = playlists && playlists.length > 0
|
||||
|
||||
return publicPlaylistsExist ? (
|
||||
<Animated.View
|
||||
entering={FadeIn.springify()}
|
||||
exiting={FadeIn.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
testID='discover-public-playlists'
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<XStack
|
||||
alignItems='center'
|
||||
onPress={() => {
|
||||
navigation.navigate('PublicPlaylists', {
|
||||
playlists,
|
||||
navigation: navigation,
|
||||
fetchNextPage,
|
||||
hasNextPage,
|
||||
isPending,
|
||||
isFetchingNextPage,
|
||||
refetch,
|
||||
})
|
||||
}}
|
||||
>
|
||||
<XStack
|
||||
alignItems='center'
|
||||
onPress={() => {
|
||||
navigation.navigate('PublicPlaylists', {
|
||||
playlists,
|
||||
navigation: navigation,
|
||||
fetchNextPage,
|
||||
hasNextPage,
|
||||
isPending,
|
||||
isFetchingNextPage,
|
||||
refetch,
|
||||
})
|
||||
}}
|
||||
>
|
||||
<H5 marginLeft={'$2'} lineBreakStrategyIOS='standard' maxWidth={width * 0.8}>
|
||||
Playlists on {server?.name ?? 'Jellyfin'}
|
||||
</H5>
|
||||
<Icon name='arrow-right' />
|
||||
</XStack>
|
||||
<HorizontalCardList
|
||||
data={playlists?.slice(0, 10) ?? []}
|
||||
renderItem={({ item }) => (
|
||||
<ItemCard
|
||||
caption={item.Name}
|
||||
subCaption={`${item.Genres?.join(', ')}`}
|
||||
squared
|
||||
size={'$10'}
|
||||
item={item}
|
||||
onPress={() => {
|
||||
navigation.navigate('Playlist', { playlist: item, canEdit: false })
|
||||
}}
|
||||
onLongPress={() =>
|
||||
navigationRef.navigate('Context', {
|
||||
item,
|
||||
navigation,
|
||||
})
|
||||
}
|
||||
marginHorizontal={'$1'}
|
||||
captionAlign='left'
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Animated.View>
|
||||
)
|
||||
)
|
||||
<H5 marginLeft={'$2'} lineBreakStrategyIOS='standard' maxWidth={width * 0.8}>
|
||||
Playlists on {server?.name ?? 'Jellyfin'}
|
||||
</H5>
|
||||
<Icon name='arrow-right' />
|
||||
</XStack>
|
||||
<HorizontalCardList
|
||||
data={playlists?.slice(0, 10) ?? []}
|
||||
renderItem={({ item }) => (
|
||||
<ItemCard
|
||||
caption={item.Name}
|
||||
subCaption={`${item.Genres?.join(', ')}`}
|
||||
squared
|
||||
size={'$10'}
|
||||
item={item}
|
||||
onPress={() => {
|
||||
navigation.navigate('Playlist', { playlist: item, canEdit: false })
|
||||
}}
|
||||
onLongPress={() =>
|
||||
navigationRef.navigate('Context', {
|
||||
item,
|
||||
navigation,
|
||||
})
|
||||
}
|
||||
marginHorizontal={'$1'}
|
||||
captionAlign='left'
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Animated.View>
|
||||
) : null
|
||||
}
|
||||
|
||||
@@ -10,55 +10,59 @@ import { pickFirstGenre } from '../../../utils/genre-formatting'
|
||||
import Animated, { FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
|
||||
import { useDiscoverArtists } from '../../../api/queries/suggestions'
|
||||
|
||||
export default function SuggestedArtists(): React.JSX.Element | undefined {
|
||||
export default function SuggestedArtists(): React.JSX.Element | null {
|
||||
const suggestedArtistsInfiniteQuery = useDiscoverArtists()
|
||||
|
||||
const navigation = useNavigation<NativeStackNavigationProp<DiscoverStackParamList>>()
|
||||
|
||||
return (
|
||||
suggestedArtistsInfiniteQuery.data && (
|
||||
<Animated.View
|
||||
entering={FadeIn.springify()}
|
||||
exiting={FadeOut.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
testID='discover-suggested-artists'
|
||||
const suggestedArtistsExist =
|
||||
suggestedArtistsInfiniteQuery.data && suggestedArtistsInfiniteQuery.data.length > 0
|
||||
|
||||
return suggestedArtistsExist ? (
|
||||
<Animated.View
|
||||
entering={FadeIn.springify()}
|
||||
exiting={FadeOut.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
testID='discover-suggested-artists'
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<XStack
|
||||
alignItems='center'
|
||||
onPress={() => {
|
||||
navigation.navigate('SuggestedArtists', {
|
||||
artistsInfiniteQuery: suggestedArtistsInfiniteQuery,
|
||||
navigation: navigation,
|
||||
})
|
||||
}}
|
||||
marginLeft={'$2'}
|
||||
>
|
||||
<XStack
|
||||
alignItems='center'
|
||||
onPress={() => {
|
||||
navigation.navigate('SuggestedArtists', {
|
||||
artistsInfiniteQuery: suggestedArtistsInfiniteQuery,
|
||||
navigation: navigation,
|
||||
})
|
||||
}}
|
||||
marginLeft={'$2'}
|
||||
>
|
||||
<H5>Suggested Artists</H5>
|
||||
<Icon name='arrow-right' />
|
||||
</XStack>
|
||||
<HorizontalCardList
|
||||
data={suggestedArtistsInfiniteQuery.data?.slice(0, 10) ?? []}
|
||||
renderItem={({ item }) => (
|
||||
<ItemCard
|
||||
caption={item.Name}
|
||||
subCaption={pickFirstGenre(item.Genres)}
|
||||
size={'$10'}
|
||||
item={item}
|
||||
onPress={() => {
|
||||
navigation.navigate('Artist', {
|
||||
artist: item,
|
||||
})
|
||||
}}
|
||||
onLongPress={() =>
|
||||
navigationRef.navigate('Context', {
|
||||
item,
|
||||
navigation,
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Animated.View>
|
||||
)
|
||||
)
|
||||
<H5>Suggested Artists</H5>
|
||||
<Icon name='arrow-right' />
|
||||
</XStack>
|
||||
<HorizontalCardList
|
||||
data={suggestedArtistsInfiniteQuery.data?.slice(0, 10) ?? []}
|
||||
renderItem={({ item }) => (
|
||||
<ItemCard
|
||||
caption={item.Name}
|
||||
subCaption={pickFirstGenre(item.Genres)}
|
||||
size={'$10'}
|
||||
item={item}
|
||||
onPress={() => {
|
||||
navigation.navigate('Artist', {
|
||||
artist: item,
|
||||
})
|
||||
}}
|
||||
onLongPress={() =>
|
||||
navigationRef.navigate('Context', {
|
||||
item,
|
||||
navigation,
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Animated.View>
|
||||
) : null
|
||||
}
|
||||
|
||||
@@ -457,8 +457,8 @@ export default function SwipeableRow({
|
||||
backgroundColor={action.color}
|
||||
borderRadius={0}
|
||||
pressStyle={{ opacity: 0.8 }}
|
||||
accessibilityRole='button'
|
||||
accessibilityLabel={`Left quick action ${action.icon}`}
|
||||
role='button'
|
||||
aria-label={`Left quick action ${action.icon}`}
|
||||
onPress={() => {
|
||||
action.onPress()
|
||||
close()
|
||||
@@ -540,8 +540,8 @@ export default function SwipeableRow({
|
||||
backgroundColor={action.color}
|
||||
borderRadius={0}
|
||||
pressStyle={{ opacity: 0.8 }}
|
||||
accessibilityRole='button'
|
||||
accessibilityLabel={`Right quick action ${action.icon}`}
|
||||
role='button'
|
||||
aria-label={`Right quick action ${action.icon}`}
|
||||
onPress={() => {
|
||||
action.onPress()
|
||||
close()
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Blurhash } from 'react-native-blurhash'
|
||||
import { getBlurhashFromDto } from '../../../utils/blurhash'
|
||||
import Animated, { FadeIn, FadeOut } from 'react-native-reanimated'
|
||||
import { getItemImageUrl, ImageUrlOptions } from '../../../api/queries/image/utils'
|
||||
import { memo, useCallback, useMemo, useState } from 'react'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useApi } from '../../../stores'
|
||||
|
||||
interface ItemImageProps {
|
||||
@@ -22,51 +22,35 @@ interface ItemImageProps {
|
||||
imageOptions?: ImageUrlOptions
|
||||
}
|
||||
|
||||
const ItemImage = memo(
|
||||
function ItemImage({
|
||||
item,
|
||||
type = ImageType.Primary,
|
||||
cornered,
|
||||
circular,
|
||||
width,
|
||||
height,
|
||||
testID,
|
||||
imageOptions,
|
||||
}: ItemImageProps): React.JSX.Element {
|
||||
const api = useApi()
|
||||
function ItemImage({
|
||||
item,
|
||||
type = ImageType.Primary,
|
||||
cornered,
|
||||
circular,
|
||||
width,
|
||||
height,
|
||||
testID,
|
||||
imageOptions,
|
||||
}: ItemImageProps): React.JSX.Element {
|
||||
const api = useApi()
|
||||
|
||||
const imageUrl = useMemo(
|
||||
() => getItemImageUrl(api, item, type, imageOptions),
|
||||
[api, item.Id, type, imageOptions],
|
||||
)
|
||||
const imageUrl = getItemImageUrl(api, item, type, imageOptions)
|
||||
|
||||
return imageUrl ? (
|
||||
<Image
|
||||
item={item}
|
||||
type={type}
|
||||
imageUrl={imageUrl!}
|
||||
testID={testID}
|
||||
height={height}
|
||||
width={width}
|
||||
circular={circular}
|
||||
cornered={cornered}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
},
|
||||
(prevProps, nextProps) =>
|
||||
prevProps.item.Id === nextProps.item.Id &&
|
||||
prevProps.type === nextProps.type &&
|
||||
prevProps.cornered === nextProps.cornered &&
|
||||
prevProps.circular === nextProps.circular &&
|
||||
prevProps.width === nextProps.width &&
|
||||
prevProps.height === nextProps.height &&
|
||||
prevProps.testID === nextProps.testID &&
|
||||
prevProps.imageOptions?.maxWidth === nextProps.imageOptions?.maxWidth &&
|
||||
prevProps.imageOptions?.maxHeight === nextProps.imageOptions?.maxHeight &&
|
||||
prevProps.imageOptions?.quality === nextProps.imageOptions?.quality,
|
||||
)
|
||||
return imageUrl ? (
|
||||
<Image
|
||||
item={item}
|
||||
type={type}
|
||||
imageUrl={imageUrl!}
|
||||
testID={testID}
|
||||
height={height}
|
||||
width={width}
|
||||
circular={circular}
|
||||
cornered={cornered}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
|
||||
interface ItemBlurhashProps {
|
||||
item: BaseItemDto
|
||||
@@ -88,19 +72,20 @@ const Styles = StyleSheet.create({
|
||||
},
|
||||
})
|
||||
|
||||
const ItemBlurhash = memo(
|
||||
function ItemBlurhash({ item, type }: ItemBlurhashProps): React.JSX.Element {
|
||||
const blurhash = getBlurhashFromDto(item, type)
|
||||
function ItemBlurhash({ item, type, testID }: ItemBlurhashProps): React.JSX.Element {
|
||||
const blurhash = getBlurhashFromDto(item, type)
|
||||
|
||||
return (
|
||||
<Animated.View style={Styles.blurhash} entering={FadeIn} exiting={FadeOut}>
|
||||
<Blurhash resizeMode={'cover'} style={Styles.blurhashInner} blurhash={blurhash} />
|
||||
</Animated.View>
|
||||
)
|
||||
},
|
||||
(prevProps: ItemBlurhashProps, nextProps: ItemBlurhashProps) =>
|
||||
prevProps.item.Id === nextProps.item.Id && prevProps.type === nextProps.type,
|
||||
)
|
||||
return (
|
||||
<Animated.View style={Styles.blurhash} entering={FadeIn} exiting={FadeOut}>
|
||||
<Blurhash
|
||||
resizeMode={'cover'}
|
||||
style={Styles.blurhashInner}
|
||||
blurhash={blurhash}
|
||||
testID={testID}
|
||||
/>
|
||||
</Animated.View>
|
||||
)
|
||||
}
|
||||
|
||||
interface ImageProps {
|
||||
imageUrl: string
|
||||
@@ -113,60 +98,40 @@ interface ImageProps {
|
||||
testID?: string | undefined
|
||||
}
|
||||
|
||||
const Image = memo(
|
||||
function Image({
|
||||
item,
|
||||
type = ImageType.Primary,
|
||||
imageUrl,
|
||||
width,
|
||||
height,
|
||||
circular,
|
||||
cornered,
|
||||
testID,
|
||||
}: ImageProps): React.JSX.Element {
|
||||
const [isLoaded, setIsLoaded] = useState<boolean>(false)
|
||||
function Image({
|
||||
item,
|
||||
type = ImageType.Primary,
|
||||
imageUrl,
|
||||
width,
|
||||
height,
|
||||
circular,
|
||||
cornered,
|
||||
testID,
|
||||
}: ImageProps): React.JSX.Element {
|
||||
const [isLoaded, setIsLoaded] = useState<boolean>(false)
|
||||
|
||||
const handleImageLoad = useCallback(() => setIsLoaded(true), [setIsLoaded])
|
||||
const handleImageLoad = useCallback(() => setIsLoaded(true), [setIsLoaded])
|
||||
|
||||
const imageViewStyle = useMemo(
|
||||
() => getImageStyleSheet(width, height, cornered, circular),
|
||||
[cornered, circular, width, height],
|
||||
)
|
||||
const imageViewStyle = getImageStyleSheet(width, height, cornered, circular)
|
||||
|
||||
const imageSource = useMemo(() => ({ uri: imageUrl }), [imageUrl])
|
||||
const imageSource = { uri: imageUrl }
|
||||
|
||||
const blurhash = useMemo(
|
||||
() => (!isLoaded ? <ItemBlurhash item={item} type={type} /> : null),
|
||||
[isLoaded],
|
||||
)
|
||||
const blurhash = !isLoaded ? <ItemBlurhash item={item} type={type} testID={testID} /> : null
|
||||
|
||||
return (
|
||||
<ZStack style={imageViewStyle.view} justifyContent='center' alignContent='center'>
|
||||
<TamaguiImage
|
||||
objectFit='cover'
|
||||
source={imageSource}
|
||||
testID={testID}
|
||||
onLoad={handleImageLoad}
|
||||
style={Styles.blurhash}
|
||||
animation={'quick'}
|
||||
/>
|
||||
{blurhash}
|
||||
</ZStack>
|
||||
)
|
||||
},
|
||||
(prevProps, nextProps) => {
|
||||
return (
|
||||
prevProps.imageUrl === nextProps.imageUrl &&
|
||||
prevProps.type === nextProps.type &&
|
||||
prevProps.item.Id === nextProps.item.Id &&
|
||||
prevProps.cornered === nextProps.cornered &&
|
||||
prevProps.circular === nextProps.circular &&
|
||||
prevProps.width === nextProps.width &&
|
||||
prevProps.height === nextProps.height &&
|
||||
prevProps.testID === nextProps.testID
|
||||
)
|
||||
},
|
||||
)
|
||||
return (
|
||||
<ZStack style={imageViewStyle.view} justifyContent='center' alignContent='center'>
|
||||
<TamaguiImage
|
||||
objectFit='cover'
|
||||
source={imageSource}
|
||||
testID={testID}
|
||||
onLoad={handleImageLoad}
|
||||
style={Styles.blurhash}
|
||||
animation={'quick'}
|
||||
/>
|
||||
{blurhash}
|
||||
</ZStack>
|
||||
)
|
||||
}
|
||||
|
||||
function getImageStyleSheet(
|
||||
width: Token | string | number | string | undefined,
|
||||
|
||||
@@ -1,43 +1,68 @@
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
|
||||
import React from 'react'
|
||||
import { QueryKeys } from '../../../enums/query-keys'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { fetchInstantMixFromItem } from '../../../api/queries/instant-mixes'
|
||||
import Icon from './icon'
|
||||
import { Spacer, Spinner } from 'tamagui'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import { BaseStackParamList } from '../../../screens/types'
|
||||
import { useApi, useJellifyUser } from '../../../stores'
|
||||
import Button from '../helpers/button'
|
||||
import { CommonActions } from '@react-navigation/native'
|
||||
import { Text } from '../helpers/text'
|
||||
import Animated, { FadeInUp, FadeOutDown, LinearTransition } from 'react-native-reanimated'
|
||||
|
||||
export default function InstantMixButton({
|
||||
export function InstantMixIconButton({
|
||||
item,
|
||||
navigation,
|
||||
}: {
|
||||
item: BaseItemDto
|
||||
navigation: Pick<NativeStackNavigationProp<BaseStackParamList>, 'navigate' | 'dispatch'>
|
||||
}): React.JSX.Element {
|
||||
const api = useApi()
|
||||
const [user] = useJellifyUser()
|
||||
|
||||
const { data, isFetching, refetch } = useQuery({
|
||||
queryKey: [QueryKeys.InstantMix, item.Id!],
|
||||
queryFn: () => fetchInstantMixFromItem(api, user, item),
|
||||
})
|
||||
|
||||
return data ? (
|
||||
return (
|
||||
<Icon
|
||||
name='radio'
|
||||
color={'$success'}
|
||||
onPress={() =>
|
||||
navigation.navigate('InstantMix', {
|
||||
item,
|
||||
mix: data,
|
||||
})
|
||||
}
|
||||
/>
|
||||
) : isFetching ? (
|
||||
<Spinner alignSelf='center' />
|
||||
) : (
|
||||
<Spacer />
|
||||
)
|
||||
}
|
||||
|
||||
export function InstantMixButton({
|
||||
item,
|
||||
navigation,
|
||||
}: {
|
||||
item: BaseItemDto
|
||||
navigation: Pick<NativeStackNavigationProp<BaseStackParamList>, 'navigate' | 'dispatch'>
|
||||
}): React.JSX.Element {
|
||||
return (
|
||||
<Animated.View
|
||||
entering={FadeInUp.springify()}
|
||||
exiting={FadeOutDown.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
style={{
|
||||
flex: 2,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
borderColor={'$success'}
|
||||
borderWidth={'$1'}
|
||||
icon={<Icon name='radio' color='$success' small />}
|
||||
onPress={() =>
|
||||
navigation.dispatch(
|
||||
CommonActions.navigate('InstantMix', {
|
||||
item,
|
||||
}),
|
||||
)
|
||||
}
|
||||
pressStyle={{ scale: 0.875 }}
|
||||
hoverStyle={{ scale: 0.925 }}
|
||||
animation={'bouncy'}
|
||||
>
|
||||
<Text bold color={'$success'}>
|
||||
Mix
|
||||
</Text>
|
||||
</Button>
|
||||
</Animated.View>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useNetworkStatus } from '../../../stores/network'
|
||||
import useStreamingDeviceProfile from '../../../stores/device-profile'
|
||||
import useItemContext from '../../../hooks/use-item-context'
|
||||
import { RouteProp, useRoute } from '@react-navigation/native'
|
||||
import React from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import { LayoutChangeEvent } from 'react-native'
|
||||
import Animated, {
|
||||
SharedValue,
|
||||
@@ -211,9 +211,9 @@ function ItemRowDetails({ item }: { item: BaseItemDto }): React.JSX.Element {
|
||||
const route = useRoute<RouteProp<BaseStackParamList>>()
|
||||
|
||||
const shouldRenderArtistName =
|
||||
item.Type === 'Audio' || (item.Type === 'MusicAlbum' && route.name !== 'Artist')
|
||||
item.Type === 'Audio' || (item.Type === 'MusicAlbum' && !route.name.includes('Overview'))
|
||||
|
||||
const shouldRenderProductionYear = item.Type === 'MusicAlbum' && route.name === 'Artist'
|
||||
const shouldRenderProductionYear = item.Type === 'MusicAlbum' && route.name.includes('Overview')
|
||||
|
||||
const shouldRenderGenres = item.Type === 'Playlist' || item.Type === BaseItemKind.MusicArtist
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { Spinner, ToggleGroup, XStack, YStack } from 'tamagui'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { H3, Spinner, ToggleGroup, XStack, YStack } from 'tamagui'
|
||||
import { H2, Text } from '../helpers/text'
|
||||
import Button from '../helpers/button'
|
||||
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||
@@ -9,6 +9,13 @@ import { fetchUserViews } from '../../../api/queries/libraries'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import Icon from './icon'
|
||||
import { useApi, useJellifyLibrary, useJellifyUser } from '../../../stores'
|
||||
import Animated, {
|
||||
FadeIn,
|
||||
FadeInUp,
|
||||
FadeOut,
|
||||
FadeOutUp,
|
||||
LinearTransition,
|
||||
} from 'react-native-reanimated'
|
||||
|
||||
interface LibrarySelectorProps {
|
||||
onLibrarySelected: (
|
||||
@@ -73,9 +80,15 @@ export default function LibrarySelector({
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPending && isSuccess && libraries) {
|
||||
setMusicLibraries(
|
||||
libraries.filter((library) => library.CollectionType === CollectionType.Music),
|
||||
const filteredMusicLibraries = libraries.filter(
|
||||
(library) => library.CollectionType === CollectionType.Music,
|
||||
)
|
||||
setMusicLibraries(filteredMusicLibraries)
|
||||
|
||||
// Auto-select if there's only one music library
|
||||
if (filteredMusicLibraries.length === 1 && !selectedLibraryId) {
|
||||
setSelectedLibraryId(filteredMusicLibraries[0].Id)
|
||||
}
|
||||
|
||||
// Find the playlist library
|
||||
const foundPlaylistLibrary = libraries.find(
|
||||
@@ -86,100 +99,135 @@ export default function LibrarySelector({
|
||||
}
|
||||
}, [isPending, isSuccess, libraries])
|
||||
|
||||
const libraryToggleItems = useMemo(
|
||||
() =>
|
||||
musicLibraries.map((library) => {
|
||||
const isSelected: boolean = selectedLibraryId === library.Id!
|
||||
const libraryToggleItems = musicLibraries.map((library) => {
|
||||
const isSelected: boolean = selectedLibraryId === library.Id!
|
||||
|
||||
return (
|
||||
<ToggleGroup.Item
|
||||
key={library.Id}
|
||||
value={library.Id!}
|
||||
aria-label={library.Name!}
|
||||
pressStyle={{
|
||||
scale: 0.9,
|
||||
}}
|
||||
backgroundColor={isSelected ? '$primary' : '$background'}
|
||||
>
|
||||
<Text
|
||||
fontWeight={isSelected ? 'bold' : '600'}
|
||||
color={isSelected ? '$background' : '$neutral'}
|
||||
>
|
||||
{library.Name ?? 'Unnamed Library'}
|
||||
</Text>
|
||||
</ToggleGroup.Item>
|
||||
)
|
||||
}),
|
||||
[selectedLibraryId, musicLibraries],
|
||||
)
|
||||
return (
|
||||
<ToggleGroup.Item
|
||||
key={library.Id}
|
||||
value={library.Id!}
|
||||
aria-label={library.Name!}
|
||||
pressStyle={{
|
||||
scale: 0.9,
|
||||
}}
|
||||
backgroundColor={isSelected ? '$primary' : '$background'}
|
||||
borderWidth={hasMultipleLibraries ? 1 : 0}
|
||||
borderColor={isSelected ? '$primary' : '$borderColor'}
|
||||
>
|
||||
<Text
|
||||
fontWeight={isSelected ? 'bold' : '600'}
|
||||
color={isSelected ? '$background' : '$neutral'}
|
||||
>
|
||||
{library.Name ?? 'Unnamed Library'}
|
||||
</Text>
|
||||
</ToggleGroup.Item>
|
||||
)
|
||||
})
|
||||
|
||||
return (
|
||||
<SafeAreaView style={{ flex: 1 }}>
|
||||
<YStack
|
||||
flex={1}
|
||||
justifyContent='center'
|
||||
paddingHorizontal={'$4'}
|
||||
marginBottom={isOnboarding ? '$20' : 'unset'}
|
||||
<YStack
|
||||
flex={1}
|
||||
justifyContent='center'
|
||||
paddingHorizontal={'$4'}
|
||||
marginBottom={isOnboarding ? '$20' : '$4'}
|
||||
>
|
||||
<Animated.View
|
||||
entering={FadeInUp.springify()}
|
||||
exiting={FadeOutUp.springify()}
|
||||
style={{
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<YStack flex={1} alignItems='center' justifyContent='flex-end'>
|
||||
<H2 textAlign='center' marginBottom={'$2'}>
|
||||
{title}
|
||||
</H2>
|
||||
{!hasMultipleLibraries && !isOnboarding && (
|
||||
<Text color='$borderColor' textAlign='center'>
|
||||
Only one music library is available
|
||||
</Text>
|
||||
)}
|
||||
</YStack>
|
||||
<H3 textAlign='center' marginBottom={'$2'}>
|
||||
{title}
|
||||
</H3>
|
||||
</Animated.View>
|
||||
{!hasMultipleLibraries && !isOnboarding && (
|
||||
<Animated.View entering={FadeIn.springify()} exiting={FadeOut.springify()}>
|
||||
<Text color='$borderColor' textAlign='center'>
|
||||
Only one music library is available
|
||||
</Text>
|
||||
</Animated.View>
|
||||
)}
|
||||
|
||||
<YStack justifyContent='center' flexGrow={1} minHeight={'$12'} gap={'$4'}>
|
||||
{isPending ? (
|
||||
<Spinner size='large' />
|
||||
) : isError ? (
|
||||
<Text color='$danger' textAlign='center'>
|
||||
Unable to load libraries
|
||||
</Text>
|
||||
) : (
|
||||
<ToggleGroup
|
||||
orientation='vertical'
|
||||
type='single'
|
||||
animation={'quick'}
|
||||
disableDeactivation={true}
|
||||
value={selectedLibraryId}
|
||||
onValueChange={setSelectedLibraryId}
|
||||
disabled={!hasMultipleLibraries && !isOnboarding}
|
||||
>
|
||||
{libraryToggleItems}
|
||||
</ToggleGroup>
|
||||
)}
|
||||
</YStack>
|
||||
|
||||
<XStack alignItems='flex-end' gap={'$3'} marginTop={'$4'}>
|
||||
{showCancelButton && (
|
||||
<Button
|
||||
variant='outlined'
|
||||
icon={() => <Icon name={cancelButtonIcon} small />}
|
||||
onPress={onCancel}
|
||||
flex={1}
|
||||
>
|
||||
{cancelButtonText}
|
||||
</Button>
|
||||
)}
|
||||
<Animated.View
|
||||
style={{
|
||||
justifyContent: 'center',
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
{isPending ? (
|
||||
<Spinner size='large' enterStyle={{ opacity: 1 }} exitStyle={{ opacity: 0 }} />
|
||||
) : isError ? (
|
||||
<LoadErrorMessage />
|
||||
) : musicLibraries.length === 0 ? (
|
||||
<NoLibrariesMessage />
|
||||
) : (
|
||||
<ToggleGroup
|
||||
enterStyle={{ opacity: 1 }}
|
||||
exitStyle={{ opacity: 0 }}
|
||||
orientation='vertical'
|
||||
type='single'
|
||||
animation={'quick'}
|
||||
disableDeactivation={true}
|
||||
value={selectedLibraryId}
|
||||
onValueChange={setSelectedLibraryId}
|
||||
disabled={!hasMultipleLibraries && !isOnboarding}
|
||||
>
|
||||
{libraryToggleItems}
|
||||
</ToggleGroup>
|
||||
)}
|
||||
</Animated.View>
|
||||
|
||||
<XStack alignItems='flex-end' gap={'$3'} marginTop={'$4'}>
|
||||
{showCancelButton && (
|
||||
<Button
|
||||
variant='outlined'
|
||||
borderColor={'$primary'}
|
||||
color={'$primary'}
|
||||
disabled={!selectedLibraryId}
|
||||
icon={() => <Icon name={primaryButtonIcon} small color='$primary' />}
|
||||
onPress={handleLibrarySelection}
|
||||
testID='let_s_go_button'
|
||||
icon={() => <Icon name={cancelButtonIcon} small />}
|
||||
onPress={onCancel}
|
||||
flex={1}
|
||||
>
|
||||
{primaryButtonText}
|
||||
{cancelButtonText}
|
||||
</Button>
|
||||
</XStack>
|
||||
</YStack>
|
||||
</SafeAreaView>
|
||||
)}
|
||||
|
||||
<Button
|
||||
variant='outlined'
|
||||
borderColor={'$primary'}
|
||||
color={'$primary'}
|
||||
disabled={!selectedLibraryId}
|
||||
icon={() => <Icon name={primaryButtonIcon} small color='$primary' />}
|
||||
onPress={handleLibrarySelection}
|
||||
testID='let_s_go_button'
|
||||
flex={1}
|
||||
>
|
||||
{primaryButtonText}
|
||||
</Button>
|
||||
</XStack>
|
||||
</YStack>
|
||||
)
|
||||
}
|
||||
|
||||
function LoadErrorMessage(): React.JSX.Element {
|
||||
return (
|
||||
<Text color='$warning' textAlign='center'>
|
||||
Unable to load libraries
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
function NoLibrariesMessage(): React.JSX.Element {
|
||||
return (
|
||||
<YStack alignItems='center' gap={'$2'}>
|
||||
<Icon name='alert' color='$warning' />
|
||||
<Text color='$warning' textAlign='center'>
|
||||
No music libraries found
|
||||
</Text>
|
||||
<Text color='$borderColor' textAlign='center' fontSize={'$3'}>
|
||||
Please create a music library in Jellyfin to continue
|
||||
</Text>
|
||||
</YStack>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ export default function FrequentArtists(): React.JSX.Element {
|
||||
|
||||
return frequentArtistsInfiniteQuery.data ? (
|
||||
<Animated.View
|
||||
entering={FadeIn}
|
||||
exiting={FadeOut}
|
||||
entering={FadeIn.springify()}
|
||||
exiting={FadeOut.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
style={{
|
||||
flex: 1,
|
||||
|
||||
@@ -51,8 +51,8 @@ export default function RecentArtists(): React.JSX.Element {
|
||||
|
||||
return recentArtistsInfiniteQuery.data ? (
|
||||
<Animated.View
|
||||
entering={FadeIn}
|
||||
exiting={FadeOut}
|
||||
entering={FadeIn.springify()}
|
||||
exiting={FadeOut.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
style={{
|
||||
flex: 1,
|
||||
|
||||
@@ -34,8 +34,8 @@ export default function RecentlyPlayed(): React.JSX.Element {
|
||||
|
||||
return tracksInfiniteQuery.data ? (
|
||||
<Animated.View
|
||||
entering={FadeIn}
|
||||
exiting={FadeOut}
|
||||
entering={FadeIn.springify()}
|
||||
exiting={FadeOut.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
style={{
|
||||
flex: 1,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ScrollView, RefreshControl, Platform } from 'react-native'
|
||||
import { ScrollView, Platform, RefreshControl } from 'react-native'
|
||||
import { YStack, getToken, useTheme } from 'tamagui'
|
||||
import RecentArtists from './helpers/recent-artists'
|
||||
import RecentlyPlayed from './helpers/recently-played'
|
||||
@@ -13,10 +13,10 @@ import { useRecentlyPlayedTracks } from '../../api/queries/recents'
|
||||
const COMPONENT_NAME = 'Home'
|
||||
|
||||
export function Home(): React.JSX.Element {
|
||||
usePreventRemove(true, () => {})
|
||||
|
||||
const theme = useTheme()
|
||||
|
||||
usePreventRemove(true, () => {})
|
||||
|
||||
usePerformanceMonitor(COMPONENT_NAME, 5)
|
||||
|
||||
const { isPending: refreshing, mutateAsync: refresh } = useHomeQueries()
|
||||
@@ -33,7 +33,7 @@ export function Home(): React.JSX.Element {
|
||||
}}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing || isRestoring || loadingInitialData}
|
||||
refreshing={refreshing || loadingInitialData || isRestoring}
|
||||
onRefresh={refresh}
|
||||
tintColor={theme.primary.val}
|
||||
/>
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
import { useCallback } from 'react'
|
||||
import { InstantMixProps } from '../../screens/types'
|
||||
import Track from '../Global/components/track'
|
||||
import { Separator } from 'tamagui'
|
||||
import { Separator, useTheme } from 'tamagui'
|
||||
import { FlashList } from '@shopify/flash-list'
|
||||
import { closeAllSwipeableRows } from '../Global/components/swipeable-row-registry'
|
||||
import useInstantMix from '../../api/queries/instant-mix'
|
||||
import { Text } from '../Global/helpers/text'
|
||||
import { RefreshControl } from 'react-native'
|
||||
|
||||
export default function InstantMix({ route, navigation }: InstantMixProps): React.JSX.Element {
|
||||
const { mix } = route.params
|
||||
const handleScrollBeginDrag = useCallback(() => {
|
||||
closeAllSwipeableRows()
|
||||
}, [])
|
||||
const { data: mix, isFetching, refetch } = useInstantMix(route.params.item)
|
||||
|
||||
const theme = useTheme()
|
||||
|
||||
return (
|
||||
<FlashList
|
||||
contentInsetAdjustmentBehavior='automatic'
|
||||
data={mix}
|
||||
ItemSeparatorComponent={() => <Separator />}
|
||||
onScrollBeginDrag={handleScrollBeginDrag}
|
||||
onScrollBeginDrag={closeAllSwipeableRows}
|
||||
renderItem={({ item, index }) => (
|
||||
<Track
|
||||
showArtwork
|
||||
@@ -26,6 +27,16 @@ export default function InstantMix({ route, navigation }: InstantMixProps): Reac
|
||||
tracklist={mix}
|
||||
/>
|
||||
)}
|
||||
ListEmptyComponent={
|
||||
!isFetching ? <Text color={'$neutral'}>No mix tracks</Text> : undefined // Refresh Control will handle the spinner, which is actually called a "throbber" ;)
|
||||
}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={isFetching}
|
||||
onRefresh={refetch}
|
||||
tintColor={theme.success.val}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ const InternetConnectionWatcher = () => {
|
||||
justifyContent='center'
|
||||
alignContent='center'
|
||||
backgroundColor={
|
||||
networkStatus === networkStatusTypes.ONLINE ? '$success' : '$danger'
|
||||
networkStatus === networkStatusTypes.ONLINE ? '$success' : '$warning'
|
||||
}
|
||||
>
|
||||
<Text textAlign='center' color='$purpleDark'>
|
||||
|
||||
@@ -67,7 +67,6 @@ function PlayerArtwork(): React.JSX.Element {
|
||||
const animatedStyle = useAnimatedStyle(() => ({
|
||||
width: withSpring(artworkMaxWidth.get()),
|
||||
height: withSpring(artworkMaxWidth.get()),
|
||||
opacity: withTiming(nowPlaying ? 1 : 0),
|
||||
}))
|
||||
|
||||
const handleLayout = (event: LayoutChangeEvent) => {
|
||||
@@ -87,12 +86,7 @@ function PlayerArtwork(): React.JSX.Element {
|
||||
onLayout={handleLayout}
|
||||
>
|
||||
{nowPlaying && (
|
||||
<Animated.View
|
||||
key={`${nowPlaying!.item.AlbumId}-item-image`}
|
||||
style={{
|
||||
...animatedStyle,
|
||||
}}
|
||||
>
|
||||
<Animated.View key={`${nowPlaying!.item.AlbumId}-item-image`} style={animatedStyle}>
|
||||
<ItemImage
|
||||
item={nowPlaying!.item}
|
||||
testID='player-image-test-id'
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import React from 'react'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import { YStack, useTheme, ZStack, useWindowDimensions, View, getTokenValue } from 'tamagui'
|
||||
import { YStack, ZStack, useWindowDimensions, View, getTokenValue } from 'tamagui'
|
||||
import Scrubber from './components/scrubber'
|
||||
import Controls from './components/controls'
|
||||
import Toast from 'react-native-toast-message'
|
||||
import JellifyToastConfig from '../../configs/toast.config'
|
||||
import { useFocusEffect } from '@react-navigation/native'
|
||||
import Footer from './components/footer'
|
||||
import BlurredBackground from './components/blurred-background'
|
||||
import PlayerHeader from './components/header'
|
||||
@@ -29,22 +26,11 @@ import { useCurrentTrack } from '../../stores/player/queue'
|
||||
export default function PlayerScreen(): React.JSX.Element {
|
||||
usePerformanceMonitor('PlayerScreen', 5)
|
||||
|
||||
const [showToast, setShowToast] = useState(true)
|
||||
|
||||
const skip = useSkip()
|
||||
const previous = usePrevious()
|
||||
const trigger = useHapticFeedback()
|
||||
const nowPlaying = useCurrentTrack()
|
||||
|
||||
const theme = useTheme()
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
setShowToast(true)
|
||||
return () => setShowToast(false)
|
||||
}, []),
|
||||
)
|
||||
|
||||
const isAndroid = Platform.OS === 'android'
|
||||
|
||||
const { width, height } = useWindowDimensions()
|
||||
@@ -63,49 +49,43 @@ export default function PlayerScreen(): React.JSX.Element {
|
||||
}))
|
||||
|
||||
// Let the native sheet gesture handle vertical dismissals; we only own horizontal swipes
|
||||
const sheetDismissGesture = useMemo(() => Gesture.Native(), [])
|
||||
const sheetDismissGesture = Gesture.Native()
|
||||
|
||||
// Gesture logic for central big swipe area
|
||||
const swipeGesture = useMemo(
|
||||
() =>
|
||||
Gesture.Pan()
|
||||
.activeOffsetX([-12, 12])
|
||||
// Bail on vertical intent so native sheet dismiss keeps working
|
||||
.failOffsetY([-8, 8])
|
||||
.simultaneousWithExternalGesture(sheetDismissGesture)
|
||||
.onUpdate((e) => {
|
||||
if (Math.abs(e.translationY) < 40) {
|
||||
translateX.value = Math.max(-160, Math.min(160, e.translationX))
|
||||
}
|
||||
})
|
||||
.onEnd((e) => {
|
||||
const threshold = 120
|
||||
const minVelocity = 600
|
||||
const isHorizontal = Math.abs(e.translationY) < 40
|
||||
if (
|
||||
isHorizontal &&
|
||||
(Math.abs(e.translationX) > threshold ||
|
||||
Math.abs(e.velocityX) > minVelocity)
|
||||
) {
|
||||
if (e.translationX > 0) {
|
||||
// Inverted: swipe right = previous
|
||||
translateX.value = withSpring(220)
|
||||
runOnJS(trigger)('notificationSuccess')
|
||||
runOnJS(previous)()
|
||||
} else {
|
||||
// Inverted: swipe left = next
|
||||
translateX.value = withSpring(-220)
|
||||
runOnJS(trigger)('notificationSuccess')
|
||||
runOnJS(skip)(undefined)
|
||||
}
|
||||
translateX.value = withDelay(160, withSpring(0))
|
||||
} else {
|
||||
translateX.value = withSpring(0)
|
||||
}
|
||||
}),
|
||||
[previous, skip, trigger, translateX, sheetDismissGesture],
|
||||
)
|
||||
|
||||
const swipeGesture = Gesture.Pan()
|
||||
.activeOffsetX([-12, 12])
|
||||
// Bail on vertical intent so native sheet dismiss keeps working
|
||||
.failOffsetY([-8, 8])
|
||||
.simultaneousWithExternalGesture(sheetDismissGesture)
|
||||
.onUpdate((e) => {
|
||||
if (Math.abs(e.translationY) < 40) {
|
||||
translateX.value = Math.max(-160, Math.min(160, e.translationX))
|
||||
}
|
||||
})
|
||||
.onEnd((e) => {
|
||||
const threshold = 120
|
||||
const minVelocity = 600
|
||||
const isHorizontal = Math.abs(e.translationY) < 40
|
||||
if (
|
||||
isHorizontal &&
|
||||
(Math.abs(e.translationX) > threshold || Math.abs(e.velocityX) > minVelocity)
|
||||
) {
|
||||
if (e.translationX > 0) {
|
||||
// Inverted: swipe right = previous
|
||||
translateX.value = withSpring(220)
|
||||
runOnJS(trigger)('notificationSuccess')
|
||||
runOnJS(previous)()
|
||||
} else {
|
||||
// Inverted: swipe left = next
|
||||
translateX.value = withSpring(-220)
|
||||
runOnJS(trigger)('notificationSuccess')
|
||||
runOnJS(skip)(undefined)
|
||||
}
|
||||
translateX.value = withDelay(160, withSpring(0))
|
||||
} else {
|
||||
translateX.value = withSpring(0)
|
||||
}
|
||||
})
|
||||
/**
|
||||
* Styling for the top layer of Player ZStack
|
||||
*
|
||||
@@ -114,81 +94,69 @@ export default function PlayerScreen(): React.JSX.Element {
|
||||
*
|
||||
* Apple devices get a small amount of margin
|
||||
*/
|
||||
const mainContainerStyle = useMemo(
|
||||
() => ({
|
||||
marginTop: isAndroid ? top : getTokenValue('$4'),
|
||||
marginBottom: bottom + getTokenValue('$10'),
|
||||
}),
|
||||
[top, bottom, isAndroid],
|
||||
)
|
||||
const mainContainerStyle = {
|
||||
marginTop: isAndroid ? top : getTokenValue('$4'),
|
||||
marginBottom: bottom + getTokenValue(isAndroid ? '$10' : '$12', 'space'),
|
||||
}
|
||||
|
||||
return (
|
||||
<View flex={1}>
|
||||
{nowPlaying && (
|
||||
<ZStack fullscreen>
|
||||
<BlurredBackground width={width} height={height} />
|
||||
return nowPlaying ? (
|
||||
<ZStack width={width} height={height}>
|
||||
<BlurredBackground width={width} height={height} />
|
||||
|
||||
{/* Swipe feedback icons (topmost overlay) */}
|
||||
<Animated.View
|
||||
pointerEvents='none'
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
zIndex: 9999,
|
||||
}}
|
||||
>
|
||||
<YStack flex={1} justifyContent='center'>
|
||||
<Animated.View
|
||||
style={[{ position: 'absolute', left: 12 }, leftIconStyle]}
|
||||
>
|
||||
<Icon name='skip-next' color='$primary' large />
|
||||
</Animated.View>
|
||||
<Animated.View
|
||||
style={[{ position: 'absolute', right: 12 }, rightIconStyle]}
|
||||
>
|
||||
<Icon name='skip-previous' color='$primary' large />
|
||||
</Animated.View>
|
||||
</YStack>
|
||||
{/* Swipe feedback icons (topmost overlay) */}
|
||||
<Animated.View
|
||||
pointerEvents='none'
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
zIndex: 9999,
|
||||
}}
|
||||
>
|
||||
<YStack flex={1} justifyContent='center'>
|
||||
<Animated.View style={[{ position: 'absolute', left: 12 }, leftIconStyle]}>
|
||||
<Icon name='skip-next' color='$primary' large />
|
||||
</Animated.View>
|
||||
<Animated.View style={[{ position: 'absolute', right: 12 }, rightIconStyle]}>
|
||||
<Icon name='skip-previous' color='$primary' large />
|
||||
</Animated.View>
|
||||
</YStack>
|
||||
</Animated.View>
|
||||
|
||||
{/* Central large swipe area overlay (captures swipe like big album art) */}
|
||||
<GestureDetector
|
||||
gesture={Gesture.Simultaneous(sheetDismissGesture, swipeGesture)}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: height * 0.18,
|
||||
left: width * 0.06,
|
||||
right: width * 0.06,
|
||||
height: height * 0.36,
|
||||
zIndex: 9998,
|
||||
}}
|
||||
/>
|
||||
</GestureDetector>
|
||||
{/* Central large swipe area overlay (captures swipe like big album art) */}
|
||||
<GestureDetector gesture={Gesture.Simultaneous(sheetDismissGesture, swipeGesture)}>
|
||||
<View
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: height * 0.18,
|
||||
left: width * 0.06,
|
||||
right: width * 0.06,
|
||||
height: height * 0.36,
|
||||
zIndex: 9998,
|
||||
}}
|
||||
/>
|
||||
</GestureDetector>
|
||||
|
||||
<YStack
|
||||
justifyContent='center'
|
||||
flex={1}
|
||||
marginHorizontal={'$5'}
|
||||
{...mainContainerStyle}
|
||||
>
|
||||
{/* flexGrow 1 */}
|
||||
<PlayerHeader />
|
||||
<YStack
|
||||
justifyContent='center'
|
||||
flex={1}
|
||||
marginHorizontal={'$5'}
|
||||
{...mainContainerStyle}
|
||||
>
|
||||
{/* flexGrow 1 */}
|
||||
<PlayerHeader />
|
||||
|
||||
<YStack justifyContent='flex-start' gap={'$4'} flexShrink={1}>
|
||||
<SongInfo />
|
||||
<Scrubber />
|
||||
<Controls />
|
||||
<Footer />
|
||||
</YStack>
|
||||
</YStack>
|
||||
</ZStack>
|
||||
)}
|
||||
{showToast && <Toast config={JellifyToastConfig(theme)} />}
|
||||
</View>
|
||||
<YStack justifyContent='flex-start' gap={'$4'} flexShrink={1}>
|
||||
<SongInfo />
|
||||
<Scrubber />
|
||||
<Controls />
|
||||
<Footer />
|
||||
</YStack>
|
||||
</YStack>
|
||||
</ZStack>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -22,10 +22,10 @@ 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, useTogglePlayback } from '../../providers/Player/hooks/mutations'
|
||||
import { usePrevious, useSkip } from '../../providers/Player/hooks/mutations'
|
||||
import { useCurrentTrack } from '../../stores/player/queue'
|
||||
|
||||
export const Miniplayer = React.memo(function Miniplayer(): React.JSX.Element {
|
||||
export default function Miniplayer(): React.JSX.Element {
|
||||
const nowPlaying = useCurrentTrack()
|
||||
const skip = useSkip()
|
||||
const previous = usePrevious()
|
||||
@@ -150,7 +150,7 @@ export const Miniplayer = React.memo(function Miniplayer(): React.JSX.Element {
|
||||
</Animated.View>
|
||||
</GestureDetector>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function MiniPlayerProgress(): React.JSX.Element {
|
||||
const progress = useProgress(UPDATE_INTERVAL)
|
||||
|
||||
@@ -73,7 +73,7 @@ export default function Queue({
|
||||
await removeFromQueue(index)
|
||||
}}
|
||||
>
|
||||
<Icon name='close' color='$danger' />
|
||||
<Icon name='close' color='$warning' />
|
||||
</Sortable.Touchable>
|
||||
</XStack>
|
||||
),
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
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 { InstantMixButton } from '../../Global/components/instant-mix-button'
|
||||
import Icon from '../../Global/components/icon'
|
||||
import { useNetworkStatus } from '../../../stores/network'
|
||||
import { ActivityIndicator } from 'react-native'
|
||||
import { QueuingType } from '../../../enums/queuing-type'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import LibraryStackParamList from '@/src/screens/Library/types'
|
||||
@@ -13,9 +12,16 @@ import useStreamingDeviceProfile from '../../../stores/device-profile'
|
||||
import ItemImage from '../../Global/components/image'
|
||||
import { useApi } from '../../../stores'
|
||||
import Input from '../../Global/helpers/input'
|
||||
import Animated, { FadeInDown, FadeOutDown } from 'react-native-reanimated'
|
||||
import Animated, {
|
||||
FadeInDown,
|
||||
FadeInUp,
|
||||
FadeOutDown,
|
||||
LinearTransition,
|
||||
} from 'react-native-reanimated'
|
||||
import { Dispatch, SetStateAction } from 'react'
|
||||
import useAddToPendingDownloads, { usePendingDownloads } from '../../../stores/network/downloads'
|
||||
import Button from '../../Global/helpers/button'
|
||||
import { Text } from '../../Global/helpers/text'
|
||||
import { RunTimeTicks } from '../../Global/helpers/time-codes'
|
||||
|
||||
export default function PlaylistTracklistHeader({
|
||||
playlist,
|
||||
@@ -31,7 +37,7 @@ export default function PlaylistTracklistHeader({
|
||||
setNewName: Dispatch<SetStateAction<string>>
|
||||
}): React.JSX.Element {
|
||||
return (
|
||||
<YStack justifyContent='center' alignItems='center' paddingTop={'$1'} marginBottom={'$2'}>
|
||||
<YStack paddingTop={'$1'} marginBottom={'$2'} gap={'$2'}>
|
||||
<YStack justifyContent='center' alignContent='center' padding={'$2'}>
|
||||
<ItemImage item={playlist} width={'$20'} height={'$20'} />
|
||||
</YStack>
|
||||
@@ -47,7 +53,7 @@ export default function PlaylistTracklistHeader({
|
||||
onChangeText={setNewName}
|
||||
placeholder='Playlist Name'
|
||||
textAlign='center'
|
||||
fontSize={'$9'}
|
||||
fontSize={'$8'}
|
||||
fontWeight='bold'
|
||||
clearButtonMode='while-editing'
|
||||
marginHorizontal={'$4'}
|
||||
@@ -55,19 +61,18 @@ export default function PlaylistTracklistHeader({
|
||||
</Animated.View>
|
||||
) : (
|
||||
<Animated.View entering={FadeInDown} exiting={FadeOutDown}>
|
||||
<H5
|
||||
lineBreakStrategyIOS='standard'
|
||||
textAlign='center'
|
||||
numberOfLines={5}
|
||||
marginBottom={'$2'}
|
||||
>
|
||||
{newName ?? 'Untitled Playlist'}
|
||||
</H5>
|
||||
<YStack alignItems='center' gap={'$2'}>
|
||||
<H5 lineBreakStrategyIOS='standard' textAlign='center' numberOfLines={5}>
|
||||
{newName ?? 'Untitled Playlist'}
|
||||
</H5>
|
||||
|
||||
<RunTimeTicks>{playlist.RunTimeTicks}</RunTimeTicks>
|
||||
</YStack>
|
||||
</Animated.View>
|
||||
)}
|
||||
|
||||
{!editing ? (
|
||||
<Animated.View entering={FadeInDown} exiting={FadeOutDown}>
|
||||
<Animated.View entering={FadeInDown} exiting={FadeOutDown} style={{ flex: 1 }}>
|
||||
<PlaylistHeaderControls
|
||||
editing={editing}
|
||||
playlist={playlist}
|
||||
@@ -89,19 +94,14 @@ function PlaylistHeaderControls({
|
||||
playlist: BaseItemDto
|
||||
playlistTracks: BaseItemDto[]
|
||||
}): React.JSX.Element {
|
||||
const addToDownloadQueue = useAddToPendingDownloads()
|
||||
const pendingDownloads = usePendingDownloads()
|
||||
const streamingDeviceProfile = useStreamingDeviceProfile()
|
||||
const loadNewQueue = useLoadNewQueue()
|
||||
const isDownloading = pendingDownloads.length != 0
|
||||
const api = useApi()
|
||||
|
||||
const [networkStatus] = useNetworkStatus()
|
||||
|
||||
const navigation = useNavigation<NativeStackNavigationProp<LibraryStackParamList>>()
|
||||
|
||||
const downloadPlaylist = () => addToDownloadQueue(playlistTracks)
|
||||
|
||||
const playPlaylist = (shuffled: boolean = false) => {
|
||||
if (!playlistTracks || playlistTracks.length === 0) return
|
||||
|
||||
@@ -120,31 +120,54 @@ function PlaylistHeaderControls({
|
||||
}
|
||||
|
||||
return (
|
||||
<XStack justifyContent='center' marginVertical={'$1'} gap={'$2'} flexWrap='wrap'>
|
||||
<YStack justifyContent='center' alignContent='center'>
|
||||
<InstantMixButton item={playlist} navigation={navigation} />
|
||||
</YStack>
|
||||
<XStack justifyContent='center' marginHorizontal={'$2'} gap={'$2'}>
|
||||
<Animated.View
|
||||
style={{
|
||||
flex: 2,
|
||||
}}
|
||||
entering={FadeInUp.springify()}
|
||||
exiting={FadeOutDown.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
>
|
||||
<Button
|
||||
animation={'bouncy'}
|
||||
pressStyle={{ scale: 0.875 }}
|
||||
hoverStyle={{ scale: 0.925 }}
|
||||
borderColor={'$primary'}
|
||||
borderWidth={'$1'}
|
||||
onPress={() => playPlaylist(false)}
|
||||
icon={<Icon name='play' color='$primary' small />}
|
||||
>
|
||||
<Text bold color={'$primary'}>
|
||||
Play
|
||||
</Text>
|
||||
</Button>
|
||||
</Animated.View>
|
||||
|
||||
<YStack justifyContent='center' alignContent='center'>
|
||||
<Icon name='play' onPress={() => playPlaylist(false)} small />
|
||||
</YStack>
|
||||
<InstantMixButton item={playlist} navigation={navigation} />
|
||||
|
||||
<YStack justifyContent='center' alignContent='center'>
|
||||
<Icon name='shuffle' onPress={() => playPlaylist(true)} small />
|
||||
</YStack>
|
||||
|
||||
<YStack justifyContent='center' alignContent='center'>
|
||||
{!isDownloading ? (
|
||||
<Icon
|
||||
color={'$borderColor'}
|
||||
name={'download'}
|
||||
onPress={downloadPlaylist}
|
||||
small
|
||||
/>
|
||||
) : (
|
||||
<ActivityIndicator />
|
||||
)}
|
||||
</YStack>
|
||||
<Animated.View
|
||||
style={{
|
||||
flex: 2,
|
||||
}}
|
||||
entering={FadeInUp.springify()}
|
||||
exiting={FadeOutDown.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
>
|
||||
<Button
|
||||
animation={'bouncy'}
|
||||
pressStyle={{ scale: 0.875 }}
|
||||
hoverStyle={{ scale: 0.925 }}
|
||||
borderColor={'$primary'}
|
||||
borderWidth={'$1'}
|
||||
onPress={() => playPlaylist(true)}
|
||||
icon={<Icon name='shuffle' color='$primary' small />}
|
||||
>
|
||||
<Text bold color={'$primary'}>
|
||||
Shuffle
|
||||
</Text>
|
||||
</Button>
|
||||
</Animated.View>
|
||||
</XStack>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -17,14 +17,25 @@ import { QueuingType } from '../../enums/queuing-type'
|
||||
import { useApi } from '../../stores'
|
||||
import useStreamingDeviceProfile from '../../stores/device-profile'
|
||||
import { useCallback, useEffect, useLayoutEffect, useState } from 'react'
|
||||
import { RefreshControl } from 'react-native'
|
||||
import { updatePlaylist } from '../../../src/api/mutations/playlists'
|
||||
import { usePlaylistTracks } from '../../../src/api/queries/playlist'
|
||||
import useHapticFeedback from '../../hooks/use-haptic-feedback'
|
||||
import { useMutation } from '@tanstack/react-query'
|
||||
import Animated, { SlideInLeft, SlideOutRight } from 'react-native-reanimated'
|
||||
import Animated, {
|
||||
FadeIn,
|
||||
FadeInUp,
|
||||
FadeOut,
|
||||
FadeOutDown,
|
||||
LinearTransition,
|
||||
SlideInLeft,
|
||||
SlideOutRight,
|
||||
} from 'react-native-reanimated'
|
||||
import { FlashList, ListRenderItem } from '@shopify/flash-list'
|
||||
import { Text } from '../Global/helpers/text'
|
||||
import { RefreshControl } from 'react-native'
|
||||
import { useIsDownloaded } from '../../api/queries/download'
|
||||
import useAddToPendingDownloads, { useIsDownloading } from '../../stores/network/downloads'
|
||||
import { useStorageContext } from '../../providers/Storage'
|
||||
|
||||
export default function Playlist({
|
||||
playlist,
|
||||
@@ -128,50 +139,104 @@ export default function Playlist({
|
||||
|
||||
const [networkStatus] = useNetworkStatus()
|
||||
|
||||
const isDownloaded = useIsDownloaded(playlistTracks?.map(({ Id }) => Id) ?? [])
|
||||
|
||||
const playlistDownloadPending = useIsDownloading(playlistTracks ?? [])
|
||||
|
||||
const { deleteDownloads } = useStorageContext()
|
||||
|
||||
const addToDownloadQueue = useAddToPendingDownloads()
|
||||
|
||||
const handleDeleteDownload = () => deleteDownloads(playlistTracks?.map(({ Id }) => Id!) ?? [])
|
||||
|
||||
const handleDownload = () => addToDownloadQueue(playlistTracks ?? [])
|
||||
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerRight: () =>
|
||||
canEdit && (
|
||||
<XStack gap={'$3'}>
|
||||
{editing && (
|
||||
<>
|
||||
headerRight: () => (
|
||||
<XStack gap={'$2'}>
|
||||
{playlistTracks &&
|
||||
(isDownloaded ? (
|
||||
<Animated.View
|
||||
entering={FadeInUp.springify()}
|
||||
exiting={FadeOutDown.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
>
|
||||
<Icon
|
||||
color={'$danger'}
|
||||
name='delete-sweep-outline' // otherwise use "delete-circle"
|
||||
onPress={() => {
|
||||
navigationRef.dispatch(
|
||||
StackActions.push('DeletePlaylist', { playlist }),
|
||||
)
|
||||
}}
|
||||
color='$warning'
|
||||
name='broom'
|
||||
onPress={handleDeleteDownload}
|
||||
/>
|
||||
|
||||
</Animated.View>
|
||||
) : playlistDownloadPending ? (
|
||||
<Spinner justifyContent='center' color={'$neutral'} />
|
||||
) : (
|
||||
<Animated.View
|
||||
entering={FadeInUp.springify()}
|
||||
exiting={FadeOutDown.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
>
|
||||
<Icon
|
||||
color='$neutral'
|
||||
name='close-circle-outline'
|
||||
onPress={handleCancel}
|
||||
color='$success'
|
||||
name='download-circle-outline'
|
||||
onPress={handleDownload}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Animated.View>
|
||||
))}
|
||||
{canEdit &&
|
||||
(editing ? (
|
||||
<Animated.View
|
||||
entering={FadeIn.springify()}
|
||||
exiting={FadeOut.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
>
|
||||
<XStack gap={'$2'}>
|
||||
<Icon
|
||||
color={'$warning'}
|
||||
name='delete-sweep-outline' // otherwise use "delete-circle"
|
||||
onPress={() => {
|
||||
navigationRef.dispatch(
|
||||
StackActions.push('DeletePlaylist', {
|
||||
playlist,
|
||||
onDelete: navigation.goBack,
|
||||
}),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
|
||||
{isUpdating || isPreparingEditMode ? (
|
||||
<Icon
|
||||
color='$neutral'
|
||||
name='close-circle-outline'
|
||||
onPress={handleCancel}
|
||||
/>
|
||||
</XStack>
|
||||
</Animated.View>
|
||||
) : isUpdating || isPreparingEditMode ? (
|
||||
<Spinner color={isPreparingEditMode ? '$primary' : '$success'} />
|
||||
) : (
|
||||
<Icon
|
||||
name={editing ? 'floppy' : 'pencil'}
|
||||
color={editing ? '$success' : '$color'}
|
||||
onPress={() =>
|
||||
!editing
|
||||
? handleEnterEditMode()
|
||||
: useUpdatePlaylist({
|
||||
playlist,
|
||||
tracks: playlistTracks ?? [],
|
||||
newName,
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</XStack>
|
||||
),
|
||||
<Animated.View
|
||||
entering={FadeIn.springify()}
|
||||
exiting={FadeOut.springify()}
|
||||
layout={LinearTransition.springify()}
|
||||
>
|
||||
<Icon
|
||||
name={editing ? 'floppy' : 'pencil'}
|
||||
color={editing ? '$success' : '$color'}
|
||||
onPress={() =>
|
||||
!editing
|
||||
? handleEnterEditMode()
|
||||
: useUpdatePlaylist({
|
||||
playlist,
|
||||
tracks: playlistTracks ?? [],
|
||||
newName,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Animated.View>
|
||||
))}
|
||||
)
|
||||
</XStack>
|
||||
),
|
||||
})
|
||||
}, [
|
||||
editing,
|
||||
@@ -246,7 +311,7 @@ export default function Playlist({
|
||||
)
|
||||
}}
|
||||
>
|
||||
<Icon name='close' color={'$danger'} />
|
||||
<Icon name='close' color={'$warning'} />
|
||||
</Sortable.Touchable>
|
||||
</XStack>
|
||||
)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { useCallback } from 'react'
|
||||
import { RefreshControl } from 'react-native'
|
||||
import { Separator, useTheme } from 'tamagui'
|
||||
import { FlashList } from '@shopify/flash-list'
|
||||
import ItemRow from '../Global/components/item-row'
|
||||
@@ -9,6 +8,8 @@ import { 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'
|
||||
import { RefreshControl } from 'react-native'
|
||||
import { Text } from '../Global/helpers/text'
|
||||
|
||||
// Extracted as stable component to prevent recreation on each render
|
||||
function ListSeparatorComponent(): React.JSX.Element {
|
||||
@@ -72,6 +73,8 @@ export default function Playlists({
|
||||
renderItem={renderItem}
|
||||
onEndReached={handleEndReached}
|
||||
removeClippedSubviews
|
||||
onScrollBeginDrag={closeAllSwipeableRows}
|
||||
ListEmptyComponent={<Text color={'$neutral'}>No playlists</Text>}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@ export default function Search({
|
||||
placeholder='Seek and ye shall find'
|
||||
onChangeText={(value) => handleSearchStringUpdate(value)}
|
||||
value={searchString}
|
||||
marginHorizontal={'$2'}
|
||||
testID='search-input'
|
||||
clearButtonMode='while-editing'
|
||||
/>
|
||||
@@ -149,7 +148,7 @@ export default function Search({
|
||||
renderItem={({ item }) => <ItemRow item={item} navigation={navigation} />}
|
||||
onScrollBeginDrag={handleScrollBeginDrag}
|
||||
style={{
|
||||
marginHorizontal: getToken('$2'),
|
||||
marginHorizontal: getToken('$4'),
|
||||
marginTop: getToken('$4'),
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import ItemRow from '../Global/components/item-row'
|
||||
import { Text } from '../Global/helpers/text'
|
||||
import { H3, Separator, YStack } from 'tamagui'
|
||||
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'
|
||||
@@ -26,7 +26,7 @@ export default function Suggestions({
|
||||
data={suggestions?.filter((suggestion) => suggestion.Type !== 'MusicArtist')}
|
||||
ListHeaderComponent={
|
||||
<YStack>
|
||||
<H3>Suggestions</H3>
|
||||
<H5>Suggestions</H5>
|
||||
|
||||
<HorizontalCardList
|
||||
data={suggestions?.filter(
|
||||
@@ -51,17 +51,17 @@ export default function Suggestions({
|
||||
}
|
||||
ItemSeparatorComponent={() => <Separator />}
|
||||
ListEmptyComponent={
|
||||
<Text textAlign='center'>
|
||||
Wake now, discover that you are the eyes of the world...
|
||||
</Text>
|
||||
<YStack justifyContent='center' alignContent='center'>
|
||||
<Text textAlign='center'>
|
||||
Wake now, discover that you are the eyes of the world...
|
||||
</Text>
|
||||
<Spinner color={'$primary'} />
|
||||
</YStack>
|
||||
}
|
||||
onScrollBeginDrag={handleScrollBeginDrag}
|
||||
renderItem={({ item }) => {
|
||||
return <ItemRow item={item} navigation={navigation} />
|
||||
}}
|
||||
style={{
|
||||
marginHorizontal: 2,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,12 +5,9 @@ import { Linking } from 'react-native'
|
||||
import { ScrollView, XStack, YStack } from 'tamagui'
|
||||
import Icon from '../../Global/components/icon'
|
||||
import usePatrons from '../../../api/queries/patrons'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { INFO_CAPTIONS } from '../../../configs/info.config'
|
||||
import { ONE_HOUR } from '../../../constants/query-client'
|
||||
import { pickRandomItemFromArray } from '../../../utils/random'
|
||||
import { getStoredOtaVersion } from 'react-native-nitro-ota'
|
||||
import { downloadUpdate } from '../../OtaUpdates'
|
||||
import { useInfoCaption } from '../../../hooks/use-caption'
|
||||
|
||||
function PatronsList({ patrons }: { patrons: { fullName: string }[] | undefined }) {
|
||||
if (!patrons?.length) return null
|
||||
@@ -31,14 +28,7 @@ function PatronsList({ patrons }: { patrons: { fullName: string }[] | undefined
|
||||
export default function InfoTab() {
|
||||
const patrons = usePatrons()
|
||||
|
||||
const { data: caption } = useQuery({
|
||||
queryKey: ['Info_Caption'],
|
||||
queryFn: () => `${pickRandomItemFromArray(INFO_CAPTIONS)}`,
|
||||
staleTime: ONE_HOUR,
|
||||
initialData: 'Live and in stereo',
|
||||
refetchOnMount: 'always',
|
||||
refetchOnWindowFocus: 'always',
|
||||
})
|
||||
const { data: caption } = useInfoCaption()
|
||||
const otaVersion = getStoredOtaVersion()
|
||||
const otaVersionText = otaVersion ? `OTA Version: ${otaVersion}` : ''
|
||||
return (
|
||||
@@ -115,7 +105,7 @@ export default function InfoTab() {
|
||||
title: 'Wall of Fame',
|
||||
subTitle: 'Sponsor on GitHub, Patreon, or Ko-fi',
|
||||
iconName: 'hand-heart',
|
||||
iconColor: '$secondary',
|
||||
iconColor: '$success',
|
||||
children: (
|
||||
<YStack>
|
||||
<XStack
|
||||
|
||||
@@ -9,17 +9,17 @@ export default function LabsTab(): React.JSX.Element {
|
||||
|
||||
return (
|
||||
<SettingsListGroup
|
||||
borderColor={'$danger'}
|
||||
borderColor={'$warning'}
|
||||
settingsList={[
|
||||
{
|
||||
title: 'Clear Artists Cache',
|
||||
subTitle: 'Invalidates the artists in the library',
|
||||
iconName: 'test-tube-off',
|
||||
iconColor: '$danger',
|
||||
iconColor: '$warning',
|
||||
children: (
|
||||
<Button
|
||||
onPress={() => {
|
||||
storage.delete(QueryKeys.InfiniteArtists)
|
||||
storage.remove(QueryKeys.InfiniteArtists)
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [QueryKeys.InfiniteArtists],
|
||||
})
|
||||
|
||||
@@ -24,7 +24,7 @@ export default function PlaybackTab(): React.JSX.Element {
|
||||
subTitle: `Changes apply to new tracks`,
|
||||
iconName: 'radio-tower',
|
||||
iconColor:
|
||||
streamingQuality === StreamingQuality.Original ? '$primary' : '$danger',
|
||||
streamingQuality === StreamingQuality.Original ? '$primary' : '$warning',
|
||||
children: (
|
||||
<RadioGroup
|
||||
value={streamingQuality}
|
||||
@@ -87,18 +87,3 @@ export default function PlaybackTab(): React.JSX.Element {
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function getStreamingQualityIconColor(streamingQuality: StreamingQuality): string {
|
||||
switch (streamingQuality) {
|
||||
case 'original':
|
||||
return '$success'
|
||||
case 'high':
|
||||
return '$success'
|
||||
case 'medium':
|
||||
return '$secondary'
|
||||
case 'low':
|
||||
return '$danger'
|
||||
default:
|
||||
return '$borderColor'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,9 +98,9 @@ function ThemeOptionCard({
|
||||
padding='$3'
|
||||
gap='$2'
|
||||
hitSlop={8}
|
||||
accessibilityRole='button'
|
||||
accessibilityLabel={`${option.label} theme option`}
|
||||
accessibilityState={{ selected: isSelected }}
|
||||
role='button'
|
||||
aria-label={`${option.label} theme option`}
|
||||
aria-selected={isSelected}
|
||||
>
|
||||
<XStack alignItems='center' gap='$2'>
|
||||
<Icon small name={option.icon} color={isSelected ? '$primary' : '$borderColor'} />
|
||||
|
||||
@@ -11,15 +11,15 @@ export default function SignOut({
|
||||
}): React.JSX.Element {
|
||||
return (
|
||||
<Button
|
||||
color={'$danger'}
|
||||
icon={() => <Icon name='hand-peace' small color={'$danger'} />}
|
||||
borderColor={'$danger'}
|
||||
color={'$warning'}
|
||||
icon={() => <Icon name='hand-peace' small color={'$warning'} />}
|
||||
borderColor={'$warning'}
|
||||
marginHorizontal={'$6'}
|
||||
onPress={() => {
|
||||
navigation.navigate('SignOut')
|
||||
}}
|
||||
>
|
||||
<Text bold color={'$danger'}>
|
||||
<Text bold color={'$warning'}>
|
||||
Sign Out
|
||||
</Text>
|
||||
</Button>
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
// DownloadProgressBar.tsx
|
||||
import React from 'react'
|
||||
import { View, Text, StyleSheet } from 'react-native'
|
||||
import { useQueryClient, useQuery } from '@tanstack/react-query'
|
||||
import Animated, { useSharedValue, useAnimatedStyle, withTiming } from 'react-native-reanimated'
|
||||
|
||||
export const DownloadProgressBar = () => {
|
||||
const { data: downloads } = useQuery({
|
||||
queryKey: ['downloads'],
|
||||
initialData: {},
|
||||
})
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{/* eslint-disable @typescript-eslint/no-explicit-any */}
|
||||
{Object.entries(downloads || {}).map(([url, item]: any) => {
|
||||
const animatedWidth = useSharedValue(item.progress)
|
||||
animatedWidth.value = withTiming(item.progress, { duration: 200 })
|
||||
|
||||
const animatedStyle = useAnimatedStyle(() => ({
|
||||
width: `${animatedWidth.value * 100}%`,
|
||||
}))
|
||||
|
||||
return (
|
||||
<View key={url} style={styles.item}>
|
||||
<Text style={styles.label}>{item.name}</Text>
|
||||
<View style={styles.bar}>
|
||||
<Animated.View style={[styles.fill, animatedStyle]} />
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
})}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
padding: 12,
|
||||
backgroundColor: '#111',
|
||||
},
|
||||
item: {
|
||||
marginBottom: 12,
|
||||
},
|
||||
label: {
|
||||
color: '#fff',
|
||||
marginBottom: 4,
|
||||
fontSize: 14,
|
||||
},
|
||||
bar: {
|
||||
height: 8,
|
||||
backgroundColor: '#333',
|
||||
borderRadius: 4,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
fill: {
|
||||
height: 8,
|
||||
backgroundColor: '#00bcd4',
|
||||
borderRadius: 4,
|
||||
},
|
||||
})
|
||||
@@ -1,197 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { StyleSheet, Pressable, Alert, FlatList } from 'react-native'
|
||||
import RNFS from 'react-native-fs'
|
||||
import Animated, { useSharedValue, useAnimatedStyle, withTiming } from 'react-native-reanimated'
|
||||
import { deleteAudioCache } from '../../api/mutations/download/offlineModeUtils'
|
||||
import Icon from '../Global/components/icon'
|
||||
import { getToken, View } from 'tamagui'
|
||||
import { Text } from '../Global/helpers/text'
|
||||
import { useDownloadProgress } from '@/src/stores/network/downloads'
|
||||
|
||||
// 🔹 Single Download Item with animated progress bar
|
||||
function DownloadItem({
|
||||
name,
|
||||
progress,
|
||||
fileName,
|
||||
}: {
|
||||
name: string
|
||||
progress: number
|
||||
fileName: string
|
||||
}): React.JSX.Element {
|
||||
const progressValue = useSharedValue(progress)
|
||||
|
||||
useEffect(() => {
|
||||
progressValue.value = withTiming(progress, { duration: 300 })
|
||||
}, [progress])
|
||||
|
||||
const animatedStyle = useAnimatedStyle(() => ({
|
||||
width: `${progressValue.value * 100}%`,
|
||||
}))
|
||||
|
||||
return (
|
||||
<View style={styles.item}>
|
||||
<Text style={styles.label}>{fileName}</Text>
|
||||
<View style={styles.downloadBar}>
|
||||
<Animated.View style={[styles.downloadFill, animatedStyle]} />
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
// 🔹 Main UI Component
|
||||
export default function StorageBar(): React.JSX.Element {
|
||||
const [used, setUsed] = useState(0)
|
||||
const [total, setTotal] = useState(1)
|
||||
|
||||
const activeDownloadsArray = useDownloadProgress()
|
||||
|
||||
const usageShared = useSharedValue(0)
|
||||
const percentUsed = used / total
|
||||
|
||||
const storageBarStyle = useAnimatedStyle(() => ({
|
||||
width: `${usageShared.value * 100}%`,
|
||||
}))
|
||||
|
||||
useEffect(() => {
|
||||
usageShared.value = withTiming(percentUsed, { duration: 500 })
|
||||
}, [percentUsed])
|
||||
|
||||
// Refresh storage info
|
||||
const refreshStats = async () => {
|
||||
const files = await RNFS.readDir(RNFS.DocumentDirectoryPath)
|
||||
let usedBytes = 0
|
||||
for (const file of files) {
|
||||
const stat = await RNFS.stat(file.path)
|
||||
usedBytes += Number(stat.size)
|
||||
}
|
||||
const info = await RNFS.getFSInfo()
|
||||
setUsed(usedBytes)
|
||||
setTotal(info.totalSpace)
|
||||
}
|
||||
|
||||
const deleteAllDownloads = async () => {
|
||||
const result = await deleteAudioCache()
|
||||
Alert.alert(
|
||||
'Downloads removed',
|
||||
`Deleted ${result.deletedCount} ${result.deletedCount === 1 ? 'item' : 'items'} and freed ${(
|
||||
result.freedBytes /
|
||||
1024 /
|
||||
1024
|
||||
).toFixed(2)} MB`,
|
||||
)
|
||||
refreshStats()
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
refreshStats()
|
||||
}, [])
|
||||
const activeDownloads = Object.values(activeDownloadsArray ?? {}).map((item) => ({
|
||||
name: item.name,
|
||||
progress: item.progress,
|
||||
songName: item.songName,
|
||||
}))
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{/* Storage Usage */}
|
||||
<Text style={styles.title}>📦 Storage Usage</Text>
|
||||
<Text style={styles.usage}>
|
||||
{`${(used / 1024 / 1024).toFixed(2)} MB / ${(total / 1024 / 1024 / 1024).toFixed(
|
||||
2,
|
||||
)} GB`}
|
||||
</Text>
|
||||
<View style={styles.progressBackground}>
|
||||
<Animated.View style={[styles.progressFill, storageBarStyle]} />
|
||||
</View>
|
||||
|
||||
{/* Active Downloads */}
|
||||
{(activeDownloads ?? []).length > 0 && (
|
||||
<>
|
||||
<Text style={[styles.title, { marginTop: 24 }]}>⬇️ Active Downloads</Text>
|
||||
<FlatList
|
||||
data={activeDownloads}
|
||||
keyExtractor={(download) => download.name}
|
||||
renderItem={({ item }) => {
|
||||
return (
|
||||
<DownloadItem
|
||||
name={item.name}
|
||||
progress={item.progress}
|
||||
fileName={item.songName}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
contentContainerStyle={{ paddingBottom: 40 }}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Delete All Downloads */}
|
||||
<Pressable style={styles.deleteButton} onPress={deleteAllDownloads}>
|
||||
<Icon name='delete-outline' small color={getToken('$danger')} />
|
||||
<Text style={styles.deleteText}> Delete Downloads</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
padding: 20,
|
||||
backgroundColor: '#1c1c2e',
|
||||
},
|
||||
title: {
|
||||
color: 'white',
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
marginBottom: 4,
|
||||
},
|
||||
usage: {
|
||||
color: '#aaa',
|
||||
fontSize: 14,
|
||||
marginBottom: 12,
|
||||
},
|
||||
progressBackground: {
|
||||
height: 10,
|
||||
backgroundColor: '#333',
|
||||
borderRadius: 5,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
progressFill: {
|
||||
height: 10,
|
||||
backgroundColor: '#ff2d75',
|
||||
borderRadius: 5,
|
||||
},
|
||||
item: {
|
||||
marginTop: 16,
|
||||
},
|
||||
label: {
|
||||
color: '#ccc',
|
||||
fontSize: 14,
|
||||
marginBottom: 4,
|
||||
},
|
||||
downloadBar: {
|
||||
height: 8,
|
||||
backgroundColor: '#2e2e3f',
|
||||
borderRadius: 4,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
downloadFill: {
|
||||
height: 8,
|
||||
backgroundColor: '#00bcd4',
|
||||
},
|
||||
deleteButton: {
|
||||
marginTop: 30,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
alignSelf: 'center',
|
||||
padding: 12,
|
||||
backgroundColor: '#2a0f13',
|
||||
borderRadius: 8,
|
||||
},
|
||||
deleteText: {
|
||||
color: '#ff4d4f',
|
||||
fontSize: 15,
|
||||
fontWeight: '600',
|
||||
},
|
||||
})
|
||||
@@ -10,9 +10,9 @@ import { Text } from '../Global/helpers/text'
|
||||
import AZScroller, { useAlphabetSelector } from '../Global/components/alphabetical-selector'
|
||||
import { UseInfiniteQueryResult } from '@tanstack/react-query'
|
||||
import { isString } from 'lodash'
|
||||
import { RefreshControl } from 'react-native'
|
||||
import { closeAllSwipeableRows } from '../Global/components/swipeable-row-registry'
|
||||
import FlashListStickyHeader from '../Global/helpers/flashlist-sticky-header'
|
||||
import { RefreshControl } from 'react-native'
|
||||
|
||||
interface TracksProps {
|
||||
tracksInfiniteQuery: UseInfiniteQueryResult<(string | number | BaseItemDto)[], Error>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { MMKV } from 'react-native-mmkv'
|
||||
import { createMMKV } from 'react-native-mmkv'
|
||||
import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister'
|
||||
import { AsyncStorage as TanstackAsyncStorage } from '@tanstack/react-query-persist-client'
|
||||
import { StateStorage } from 'zustand/middleware'
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
|
||||
export const storage = new MMKV()
|
||||
export const storage = createMMKV()
|
||||
|
||||
const storageFunctions = {
|
||||
setItem: async (key: string, value: string) => {
|
||||
@@ -28,7 +28,7 @@ const mmkvStorageFunctions = {
|
||||
return value === undefined ? null : value
|
||||
},
|
||||
removeItem: (key: string) => {
|
||||
storage.delete(key)
|
||||
storage.remove(key)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MMKV } from 'react-native-mmkv'
|
||||
import { createMMKV } from 'react-native-mmkv'
|
||||
import { StateStorage } from 'zustand/middleware'
|
||||
import { storage } from './storage'
|
||||
|
||||
@@ -19,14 +19,17 @@ export const STORAGE_SCHEMA_VERSIONS: Record<string, number> = {
|
||||
* Checks if a specific store needs to be cleared due to version bump
|
||||
* and clears it if necessary
|
||||
*/
|
||||
export function migrateStorageIfNeeded(storeName: string, storage: MMKV): void {
|
||||
export function migrateStorageIfNeeded(
|
||||
storeName: string,
|
||||
storage: ReturnType<typeof createMMKV>,
|
||||
): void {
|
||||
const versionKey = `${STORAGE_VERSION_KEY}:${storeName}`
|
||||
const storedVersion = storage.getNumber(versionKey)
|
||||
const currentVersion = STORAGE_SCHEMA_VERSIONS[storeName] ?? 1
|
||||
|
||||
if (storedVersion !== currentVersion) {
|
||||
// Clear the stale storage for this specific store
|
||||
storage.delete(storeName)
|
||||
storage.remove(storeName)
|
||||
// Update the version
|
||||
storage.set(versionKey, currentVersion)
|
||||
console.log(
|
||||
@@ -56,7 +59,7 @@ export function createVersionedMmkvStorage(storeName: string): StateStorage {
|
||||
storage.set(key, value)
|
||||
},
|
||||
removeItem: (key: string) => {
|
||||
storage.delete(key)
|
||||
storage.remove(key)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -67,8 +70,8 @@ export function createVersionedMmkvStorage(storeName: string): StateStorage {
|
||||
*/
|
||||
export function clearAllVersionedStorage(): void {
|
||||
Object.keys(STORAGE_SCHEMA_VERSIONS).forEach((storeName) => {
|
||||
storage.delete(storeName)
|
||||
storage.delete(`${STORAGE_VERSION_KEY}:${storeName}`)
|
||||
storage.remove(storeName)
|
||||
storage.remove(`${STORAGE_VERSION_KEY}:${storeName}`)
|
||||
})
|
||||
console.log('[Storage] Cleared all versioned storage')
|
||||
}
|
||||
|
||||
30
src/hooks/use-caption.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { INFO_CAPTIONS } from '../configs/info.config'
|
||||
import { ONE_HOUR } from '../constants/query-client'
|
||||
import { pickRandomItemFromArray } from '../utils/random'
|
||||
import { LOADING_CAPTIONS } from '../configs/loading.config'
|
||||
|
||||
enum CaptionQueryKeys {
|
||||
InfoCaption,
|
||||
LoadingCaption,
|
||||
}
|
||||
|
||||
export const useInfoCaption = () =>
|
||||
useQuery({
|
||||
queryKey: [CaptionQueryKeys.InfoCaption],
|
||||
queryFn: () => `${pickRandomItemFromArray(INFO_CAPTIONS)}`,
|
||||
staleTime: ONE_HOUR,
|
||||
initialData: 'Live and in stereo',
|
||||
refetchOnMount: 'always',
|
||||
refetchOnWindowFocus: 'always',
|
||||
})
|
||||
|
||||
export const useLoadingCaption = () =>
|
||||
useQuery({
|
||||
queryKey: [CaptionQueryKeys.LoadingCaption],
|
||||
queryFn: () => `${pickRandomItemFromArray(LOADING_CAPTIONS)}`,
|
||||
staleTime: 0,
|
||||
initialData: 'Reticulating splines',
|
||||
refetchOnMount: 'always',
|
||||
refetchOnWindowFocus: 'always',
|
||||
})
|
||||
@@ -2,7 +2,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import Index from '../../components/Discover/component'
|
||||
import AlbumScreen from '../Album'
|
||||
import { ArtistScreen } from '../Artist'
|
||||
import { useTheme } from 'tamagui'
|
||||
import { getTokenValue, useTheme } from 'tamagui'
|
||||
import RecentlyAdded from './albums'
|
||||
import PublicPlaylists from './playlists'
|
||||
import { PlaylistScreen } from '../Playlist'
|
||||
@@ -22,8 +22,10 @@ export function Discover(): React.JSX.Element {
|
||||
name='Discover'
|
||||
component={Index}
|
||||
options={{
|
||||
headerTitleAlign: 'center',
|
||||
headerTitleStyle: {
|
||||
fontFamily: 'Figtree-Bold',
|
||||
fontSize: getTokenValue('$6'),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
@@ -55,6 +57,9 @@ export function Discover(): React.JSX.Element {
|
||||
component={PlaylistScreen}
|
||||
options={({ route }) => ({
|
||||
title: route.params.playlist.Name ?? 'Untitled Playlist',
|
||||
headerTitleStyle: {
|
||||
color: theme.background.val,
|
||||
},
|
||||
})}
|
||||
/>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import { PlaylistScreen } from '../Playlist'
|
||||
import { Home as HomeComponent } from '../../components/Home'
|
||||
import { ArtistScreen } from '../Artist'
|
||||
import { useTheme } from 'tamagui'
|
||||
import { getTokenValue, useTheme } from 'tamagui'
|
||||
import HomeArtistsScreen from './artists'
|
||||
import HomeTracksScreen from './tracks'
|
||||
import AlbumScreen from '../Album'
|
||||
@@ -28,8 +28,10 @@ export default function Home(): React.JSX.Element {
|
||||
component={HomeComponent}
|
||||
options={{
|
||||
title: 'Home',
|
||||
headerTitleAlign: 'center',
|
||||
headerTitleStyle: {
|
||||
fontFamily: 'Figtree-Bold',
|
||||
fontSize: getTokenValue('$6'),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -11,7 +11,8 @@ import Icon from '../../components/Global/components/icon'
|
||||
import LibraryStackParamList from './types'
|
||||
import useHapticFeedback from '../../hooks/use-haptic-feedback'
|
||||
import { useUserPlaylists } from '../../api/queries/playlist'
|
||||
import { useApi, useJellifyUser, useJellifyLibrary } from '../../stores'
|
||||
import { useApi, useJellifyUser } from '../../stores'
|
||||
import { isEmpty } from 'lodash'
|
||||
|
||||
export default function AddPlaylist({
|
||||
navigation,
|
||||
@@ -20,7 +21,6 @@ export default function AddPlaylist({
|
||||
}): React.JSX.Element {
|
||||
const api = useApi()
|
||||
const [user] = useJellifyUser()
|
||||
const [library] = useJellifyLibrary()
|
||||
const [name, setName] = useState<string>('')
|
||||
|
||||
const { refetch } = useUserPlaylists()
|
||||
@@ -32,12 +32,6 @@ export default function AddPlaylist({
|
||||
onSuccess: (data: void, { name }: { name: string }) => {
|
||||
trigger('notificationSuccess')
|
||||
|
||||
// Burnt.alert({
|
||||
// title: `Playlist created`,
|
||||
// message: `Created playlist ${name}`,
|
||||
// duration: 1,
|
||||
// preset: 'done',
|
||||
// })
|
||||
Toast.show({
|
||||
text1: 'Playlist created',
|
||||
text2: `Created playlist ${name}`,
|
||||
@@ -55,7 +49,7 @@ export default function AddPlaylist({
|
||||
})
|
||||
|
||||
return (
|
||||
<View margin={'$2'}>
|
||||
<View margin={'$2'} flex={1}>
|
||||
<Label size='$2' htmlFor='name'>
|
||||
Name
|
||||
</Label>
|
||||
@@ -79,6 +73,7 @@ export default function AddPlaylist({
|
||||
borderWidth={'$1'}
|
||||
borderColor={'$primary'}
|
||||
icon={() => <Icon name='content-save' small color={'$primary'} />}
|
||||
disabled={isEmpty(name)}
|
||||
>
|
||||
<Text bold color={'$primary'}>
|
||||
Save
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Spinner, View, XStack } from 'tamagui'
|
||||
import { Spinner, XStack, YStack } from 'tamagui'
|
||||
import Button from '../../components/Global/helpers/button'
|
||||
import { Text } from '../../components/Global/helpers/text'
|
||||
import { useMutation } from '@tanstack/react-query'
|
||||
@@ -6,15 +6,16 @@ import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
|
||||
import { deletePlaylist } from '../../api/mutations/playlists'
|
||||
import { queryClient } from '../../constants/query-client'
|
||||
import Icon from '../../components/Global/components/icon'
|
||||
import { LibraryDeletePlaylistProps } from './types'
|
||||
import { DeletePlaylistProps } from '../types'
|
||||
import useHapticFeedback from '../../hooks/use-haptic-feedback'
|
||||
import { useApi, useJellifyLibrary } from '../../stores'
|
||||
import { UserPlaylistsQueryKey } from '../../api/queries/playlist/keys'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
|
||||
export default function DeletePlaylist({
|
||||
navigation,
|
||||
route,
|
||||
}: LibraryDeletePlaylistProps): React.JSX.Element {
|
||||
}: DeletePlaylistProps): React.JSX.Element {
|
||||
const api = useApi()
|
||||
|
||||
const [library] = useJellifyLibrary()
|
||||
@@ -26,8 +27,9 @@ export default function DeletePlaylist({
|
||||
onSuccess: (data: void, playlist: BaseItemDto) => {
|
||||
trigger('notificationSuccess')
|
||||
|
||||
navigation.goBack()
|
||||
navigation.goBack()
|
||||
navigation.goBack() // Dismiss modal
|
||||
|
||||
route.params.onDelete()
|
||||
|
||||
// Refresh favorite playlists component in library
|
||||
queryClient.invalidateQueries({
|
||||
@@ -39,11 +41,13 @@ export default function DeletePlaylist({
|
||||
},
|
||||
})
|
||||
|
||||
const { bottom } = useSafeAreaInsets()
|
||||
|
||||
return (
|
||||
<View margin={'$4'}>
|
||||
<Text bold textAlign='center'>{`Delete playlist ${
|
||||
route.params.playlist.Name ?? 'Untitled Playlist'
|
||||
}?`}</Text>
|
||||
<YStack margin={'$4'} gap={'$4'} justifyContent='space-between' marginBottom={bottom}>
|
||||
<Text bold textAlign='center'>
|
||||
{`Delete playlist ${route.params.playlist.Name ?? 'Untitled Playlist'}?`}
|
||||
</Text>
|
||||
<XStack justifyContent='space-evenly' gap={'$2'}>
|
||||
<Button
|
||||
onPress={() => navigation.goBack()}
|
||||
@@ -60,23 +64,23 @@ export default function DeletePlaylist({
|
||||
danger
|
||||
flex={1}
|
||||
borderWidth={'$1'}
|
||||
borderColor={'$danger'}
|
||||
borderColor={'$warning'}
|
||||
onPress={() => useDeletePlaylist.mutate(route.params.playlist)}
|
||||
icon={() =>
|
||||
useDeletePlaylist.isPending && (
|
||||
<Icon name='trash-can-outline' small color={'$danger'} />
|
||||
<Icon name='trash-can-outline' small color={'$warning'} />
|
||||
)
|
||||
}
|
||||
>
|
||||
{useDeletePlaylist.isPending ? (
|
||||
<Spinner color={'$danger'} />
|
||||
<Spinner color={'$warning'} />
|
||||
) : (
|
||||
<Text bold color={'$danger'}>
|
||||
<Text bold color={'$warning'}>
|
||||
Delete
|
||||
</Text>
|
||||
)}
|
||||
</Button>
|
||||
</XStack>
|
||||
</View>
|
||||
</YStack>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,19 +2,18 @@ import React from 'react'
|
||||
import Library from '../../components/Library/component'
|
||||
import { PlaylistScreen } from '../Playlist'
|
||||
import AddPlaylist from './add-playlist'
|
||||
import DeletePlaylist from './delete-playlist'
|
||||
import { ArtistScreen } from '../Artist'
|
||||
import { useTheme } from 'tamagui'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import AlbumScreen from '../Album'
|
||||
import LibraryStackParamList from './types'
|
||||
import { LibraryTabProps } from '../Tabs/types'
|
||||
import InstantMix from '../../components/InstantMix/component'
|
||||
import { getItemName } from '../../utils/text'
|
||||
import { Platform } from 'react-native'
|
||||
|
||||
const LibraryStack = createNativeStackNavigator<LibraryStackParamList>()
|
||||
|
||||
export default function LibraryScreen({ route, navigation }: LibraryTabProps): React.JSX.Element {
|
||||
export default function LibraryScreen(): React.JSX.Element {
|
||||
const theme = useTheme()
|
||||
|
||||
return (
|
||||
@@ -73,30 +72,15 @@ export default function LibraryScreen({ route, navigation }: LibraryTabProps): R
|
||||
})}
|
||||
/>
|
||||
|
||||
<LibraryStack.Group
|
||||
screenOptions={{
|
||||
<LibraryStack.Screen
|
||||
name='AddPlaylist'
|
||||
component={AddPlaylist}
|
||||
options={{
|
||||
title: 'Add Playlist',
|
||||
presentation: 'formSheet',
|
||||
sheetAllowedDetents: 'fitToContents',
|
||||
sheetAllowedDetents: Platform.OS === 'ios' ? 'fitToContents' : [0.5],
|
||||
}}
|
||||
>
|
||||
<LibraryStack.Screen
|
||||
name='AddPlaylist'
|
||||
component={AddPlaylist}
|
||||
options={{
|
||||
title: 'Add Playlist',
|
||||
}}
|
||||
/>
|
||||
|
||||
<LibraryStack.Screen
|
||||
name='DeletePlaylist'
|
||||
component={DeletePlaylist}
|
||||
options={{
|
||||
title: 'Delete Playlist',
|
||||
headerShown: false,
|
||||
sheetGrabberVisible: true,
|
||||
}}
|
||||
/>
|
||||
</LibraryStack.Group>
|
||||
/>
|
||||
</LibraryStack.Navigator>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { BaseStackParamList } from '../types'
|
||||
import { NavigatorScreenParams } from '@react-navigation/native'
|
||||
|
||||
type LibraryStackParamList = BaseStackParamList & {
|
||||
LibraryScreen: NavigatorScreenParams<BaseStackParamList>
|
||||
LibraryScreen: NavigatorScreenParams<BaseStackParamList> | undefined
|
||||
AddPlaylist: undefined
|
||||
|
||||
DeletePlaylist: {
|
||||
@@ -14,7 +14,7 @@ type LibraryStackParamList = BaseStackParamList & {
|
||||
|
||||
export default LibraryStackParamList
|
||||
|
||||
export type LibraryScreenProps = NativeStackScreenProps<LibraryScreenParamList, 'LibraryScreen'>
|
||||
export type LibraryScreenProps = NativeStackScreenProps<LibraryStackParamList, 'LibraryScreen'>
|
||||
export type LibraryArtistProps = NativeStackScreenProps<LibraryStackParamList, 'Artist'>
|
||||
export type LibraryAlbumProps = NativeStackScreenProps<LibraryStackParamList, 'Album'>
|
||||
|
||||
@@ -23,7 +23,3 @@ export type LibraryDeletePlaylistProps = NativeStackScreenProps<
|
||||
LibraryStackParamList,
|
||||
'DeletePlaylist'
|
||||
>
|
||||
|
||||
type LibraryScreenParamList = {
|
||||
LibraryScreen: NavigatorScreenParams<LibraryStackParamList>
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import MultipleArtistsSheet from '../Context/multiple-artists'
|
||||
import { PlayerParamList } from './types'
|
||||
import Lyrics from '../../components/Player/components/lyrics'
|
||||
|
||||
export const PlayerStack = createNativeStackNavigator<PlayerParamList>()
|
||||
const PlayerStack = createNativeStackNavigator<PlayerParamList>()
|
||||
|
||||
export default function Player(): React.JSX.Element {
|
||||
return (
|
||||
|
||||
@@ -2,7 +2,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import { ArtistScreen } from '../Artist'
|
||||
import AlbumScreen from '../Album'
|
||||
import { PlaylistScreen } from '../Playlist'
|
||||
import { useTheme } from 'tamagui'
|
||||
import { getTokenValue, useTheme } from 'tamagui'
|
||||
import Search from '../../components/Search'
|
||||
import SearchParamList from './types'
|
||||
import InstantMix from '../../components/InstantMix/component'
|
||||
@@ -20,8 +20,10 @@ export default function SearchStack(): React.JSX.Element {
|
||||
component={Search}
|
||||
options={{
|
||||
title: 'Search',
|
||||
headerTitleAlign: 'center',
|
||||
headerTitleStyle: {
|
||||
fontFamily: 'Figtree-Bold',
|
||||
fontSize: getTokenValue('$6'),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -4,10 +4,9 @@ import { H5, Text } from '../../components/Global/helpers/text'
|
||||
import Button from '../../components/Global/helpers/button'
|
||||
import Icon from '../../components/Global/components/icon'
|
||||
import { useResetQueue } from '../../providers/Player/hooks/mutations'
|
||||
import navigationRef from '../../../navigation'
|
||||
import { useClearAllDownloads } from '../../api/mutations/download'
|
||||
import { useJellifyServer } from '../../stores'
|
||||
import { StackActions, useNavigation } from '@react-navigation/native'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { RootStackParamList } from '../types'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import React, { useState } from 'react'
|
||||
import { FlashList, ListRenderItem } from '@shopify/flash-list'
|
||||
import { useFocusEffect, useNavigation } from '@react-navigation/native'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import { Pressable, Alert } from 'react-native'
|
||||
import { Card, Paragraph, Separator, SizableText, Spinner, XStack, YStack, Image } from 'tamagui'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
|
||||
import { useStorageContext, CleanupSuggestion } from '../../../providers/Storage'
|
||||
import Icon from '../../../components/Global/components/icon'
|
||||
import Button from '../../../components/Global/helpers/button'
|
||||
import { formatBytes } from '../../../utils/format-bytes'
|
||||
import { JellifyDownload, JellifyDownloadProgress } from '../../../types/JellifyDownload'
|
||||
import { SettingsStackParamList } from '../types'
|
||||
import { useDeletionToast } from './useDeletionToast'
|
||||
import { Text } from '../../../components/Global/helpers/text'
|
||||
|
||||
const getDownloadSize = (download: JellifyDownload) =>
|
||||
(download.fileSizeBytes ?? 0) + (download.artworkSizeBytes ?? 0)
|
||||
@@ -44,7 +42,7 @@ export default function StorageManagementScreen(): React.JSX.Element {
|
||||
const [applyingSuggestionId, setApplyingSuggestionId] = useState<string | null>(null)
|
||||
|
||||
const insets = useSafeAreaInsets()
|
||||
const navigation = useNavigation<NativeStackNavigationProp<SettingsStackParamList>>()
|
||||
|
||||
const showDeletionToast = useDeletionToast()
|
||||
|
||||
const sortedDownloads = !downloads
|
||||
@@ -86,12 +84,12 @@ export default function StorageManagementScreen(): React.JSX.Element {
|
||||
|
||||
const handleDeleteAll = () =>
|
||||
Alert.alert(
|
||||
'Delete all downloads?',
|
||||
'Clear all downloads?',
|
||||
'This will remove all downloaded music from your device. This action cannot be undone.',
|
||||
[
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{
|
||||
text: 'Delete All',
|
||||
text: 'Clear All',
|
||||
style: 'destructive',
|
||||
onPress: async () => {
|
||||
if (!downloads) return
|
||||
@@ -109,12 +107,12 @@ export default function StorageManagementScreen(): React.JSX.Element {
|
||||
|
||||
const handleDeleteSelection = () =>
|
||||
Alert.alert(
|
||||
'Delete selected items?',
|
||||
`Are you sure you want to delete ${selectedIds.length} items?`,
|
||||
'Clear selected downloads?',
|
||||
`Are you sure you want to clear ${selectedIds.length} downloads?`,
|
||||
[
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{
|
||||
text: 'Delete',
|
||||
text: 'Clear',
|
||||
style: 'destructive',
|
||||
onPress: async () => {
|
||||
const result = await deleteDownloads(selectedIds)
|
||||
@@ -255,18 +253,20 @@ const StorageSummaryCard = ({
|
||||
)
|
||||
}
|
||||
onPress={onRefresh}
|
||||
accessibilityLabel='Refresh storage overview'
|
||||
aria-label='Refresh storage overview'
|
||||
/>
|
||||
<Button
|
||||
size='$2'
|
||||
backgroundColor='$danger'
|
||||
borderColor='$danger'
|
||||
backgroundColor='$warning'
|
||||
borderColor='$warning'
|
||||
borderWidth={1}
|
||||
color='white'
|
||||
onPress={onDeleteAll}
|
||||
icon={() => <Icon name='delete-outline' color='$color' small />}
|
||||
icon={() => <Icon name='broom' color='$background' small />}
|
||||
>
|
||||
Delete All
|
||||
<Text bold color={'$background'}>
|
||||
Clear All
|
||||
</Text>
|
||||
</Button>
|
||||
</XStack>
|
||||
</XStack>
|
||||
@@ -388,7 +388,7 @@ const DownloadRow = ({
|
||||
<XStack padding='$3' alignItems='center' gap='$3' borderRadius='$4'>
|
||||
<Icon
|
||||
name={isSelected ? 'check-circle-outline' : 'circle-outline'}
|
||||
color={isSelected ? '$primary' : '$borderColor'}
|
||||
color={isSelected ? '$color' : '$borderColor'}
|
||||
/>
|
||||
|
||||
{download.artwork ? (
|
||||
@@ -428,12 +428,12 @@ const DownloadRow = ({
|
||||
circular
|
||||
backgroundColor='transparent'
|
||||
hitSlop={10}
|
||||
icon={() => <Icon name='delete-outline' color='$danger' />}
|
||||
icon={() => <Icon name='broom' color='$warning' />}
|
||||
onPress={(event) => {
|
||||
event.stopPropagation()
|
||||
onDelete()
|
||||
}}
|
||||
accessibilityLabel='Delete download'
|
||||
aria-label='Clear download'
|
||||
/>
|
||||
</XStack>
|
||||
</Pressable>
|
||||
@@ -506,14 +506,13 @@ const SelectionReviewBanner = ({
|
||||
</XStack>
|
||||
<Button
|
||||
size='$3'
|
||||
backgroundColor='$danger'
|
||||
borderColor='$danger'
|
||||
borderColor='$warning'
|
||||
borderWidth={1}
|
||||
color='white'
|
||||
icon={() => <Icon name='delete-outline' color='$color' />}
|
||||
icon={() => <Icon small name='broom' color='$warning' />}
|
||||
onPress={onDelete}
|
||||
>
|
||||
Delete ({formatBytes(selectedBytes)})
|
||||
<Text bold color={'$warning'}>{`Clear ${formatBytes(selectedBytes)}`}</Text>
|
||||
</Button>
|
||||
</YStack>
|
||||
</Card>
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
import { Miniplayer } from '../../components/Player/mini-player'
|
||||
import Miniplayer from '../../components/Player/mini-player'
|
||||
import InternetConnectionWatcher from '../../components/Network/internetConnectionWatcher'
|
||||
import { BottomTabBar, BottomTabBarProps } from '@react-navigation/bottom-tabs'
|
||||
import useIsMiniPlayerActive from '../../hooks/use-mini-player'
|
||||
import { useIsFocused } from '@react-navigation/native'
|
||||
|
||||
export default function TabBar({ ...props }: BottomTabBarProps): React.JSX.Element {
|
||||
const isFocused = useIsFocused()
|
||||
|
||||
const isMiniPlayerActive = useIsMiniPlayerActive()
|
||||
|
||||
return (
|
||||
<>
|
||||
{isMiniPlayerActive && isFocused && <Miniplayer />}
|
||||
{isMiniPlayerActive && <Miniplayer />}
|
||||
<InternetConnectionWatcher />
|
||||
|
||||
<BottomTabBar {...props} />
|
||||
|
||||
2
src/screens/Tabs/types.d.ts
vendored
@@ -4,7 +4,7 @@ import LibraryStackParamList from '../Library/types'
|
||||
|
||||
type TabParamList = {
|
||||
HomeTab: undefined
|
||||
LibraryTab: NavigatorScreenParams<LibraryStackParamList>
|
||||
LibraryTab: undefined | NavigatorScreenParams<LibraryStackParamList>
|
||||
SearchTab: undefined
|
||||
DiscoverTab: undefined
|
||||
SettingsTab: undefined
|
||||
|
||||
@@ -13,6 +13,8 @@ import { Text } from '../components/Global/helpers/text'
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
|
||||
import AudioSpecsSheet from './Stats'
|
||||
import { useApi, useJellifyLibrary } from '../stores'
|
||||
import DeletePlaylist from './Library/delete-playlist'
|
||||
import { Platform } from 'react-native'
|
||||
|
||||
const RootStack = createNativeStackNavigator<RootStackParamList>()
|
||||
|
||||
@@ -37,8 +39,9 @@ export default function Root(): React.JSX.Element {
|
||||
name='PlayerRoot'
|
||||
component={Player}
|
||||
options={{
|
||||
presentation: 'formSheet',
|
||||
sheetAllowedDetents: [1.0],
|
||||
// Form Sheet gives swipe to dismiss for Android, but royally fucks up the display on iOS
|
||||
presentation: Platform.OS === 'android' ? 'formSheet' : 'modal',
|
||||
sheetAllowedDetents: Platform.OS === 'android' ? [1.0] : undefined,
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
@@ -82,6 +85,18 @@ export default function Root(): React.JSX.Element {
|
||||
sheetGrabberVisible: true,
|
||||
})}
|
||||
/>
|
||||
|
||||
<RootStack.Screen
|
||||
name='DeletePlaylist'
|
||||
component={DeletePlaylist}
|
||||
options={{
|
||||
title: 'Delete Playlist',
|
||||
presentation: 'formSheet',
|
||||
headerShown: false,
|
||||
sheetGrabberVisible: true,
|
||||
sheetAllowedDetents: 'fitToContents',
|
||||
}}
|
||||
/>
|
||||
</RootStack.Navigator>
|
||||
)
|
||||
}
|
||||
|
||||
8
src/screens/types.d.ts
vendored
@@ -33,7 +33,6 @@ export type BaseStackParamList = {
|
||||
|
||||
InstantMix: {
|
||||
item: BaseItemDto
|
||||
mix: BaseItemDto[]
|
||||
}
|
||||
|
||||
Tracks: {
|
||||
@@ -72,6 +71,11 @@ export type RootStackParamList = {
|
||||
streamingMediaSourceInfo?: MediaSourceInfo
|
||||
downloadedMediaSourceInfo?: MediaSourceInfo
|
||||
}
|
||||
|
||||
DeletePlaylist: {
|
||||
playlist: BaseItemDto
|
||||
onDelete: () => void
|
||||
}
|
||||
}
|
||||
|
||||
export type LoginProps = NativeStackNavigationProp<RootStackParamList, 'Login'>
|
||||
@@ -81,6 +85,8 @@ export type ContextProps = NativeStackScreenProps<RootStackParamList, 'Context'>
|
||||
export type AddToPlaylistProps = NativeStackScreenProps<RootStackParamList, 'AddToPlaylist'>
|
||||
export type AudioSpecsProps = NativeStackScreenProps<RootStackParamList, 'AudioSpecs'>
|
||||
|
||||
export type DeletePlaylistProps = NativeStackScreenProps<RootStackParamList, 'DeletePlaylist'>
|
||||
|
||||
export type GenresProps = {
|
||||
genres: InfiniteData<BaseItemDto[], unknown> | undefined
|
||||
fetchNextPage: (options?: FetchNextPageOptions | undefined) => void
|
||||
|
||||
@@ -67,9 +67,11 @@ export const useIsDownloading = (items: BaseItemDto[]) => {
|
||||
...currentDownloads.map((download) => download.item.Id),
|
||||
])
|
||||
|
||||
const itemIds = items.map((item) => item.Id)
|
||||
|
||||
return itemIds.filter((id) => downloadQueue.has(id)).length === items.length
|
||||
return (
|
||||
items.length !== 0 &&
|
||||
(pendingDownloads.length !== 0 || currentDownloads.length !== 0) &&
|
||||
items.filter((item) => downloadQueue.has(item.Id)).length > 0
|
||||
)
|
||||
}
|
||||
|
||||
export const useAddToCompletedDownloads = () => {
|
||||
|
||||
@@ -23,6 +23,18 @@ import StreamingQuality from '../enums/audio-quality'
|
||||
import { getAudioCache } from '../api/mutations/download/offlineModeUtils'
|
||||
import RNFS from 'react-native-fs'
|
||||
|
||||
/**
|
||||
* Ensures a valid session ID is returned.
|
||||
* The ?? operator doesn't catch empty strings, so we need this helper.
|
||||
* Empty session IDs cause MusicService to crash with "Session ID must be unique. ID="
|
||||
*/
|
||||
function getValidSessionId(sessionId: string | null | undefined): string {
|
||||
if (sessionId && sessionId.trim() !== '') {
|
||||
return sessionId
|
||||
}
|
||||
return uuid.v4().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the artwork URL for a track, prioritizing the track's own artwork over the album's artwork.
|
||||
* Falls back to artist image if no album artwork is available.
|
||||
@@ -169,16 +181,21 @@ function ensureFileUri(path?: string): string | undefined {
|
||||
}
|
||||
|
||||
function buildDownloadedTrack(downloadedTrack: JellifyDownload): TrackMediaInfo {
|
||||
// Safely build the image path - artwork is optional and may be undefined
|
||||
const imagePath = downloadedTrack.artwork
|
||||
? `file://${RNFS.DocumentDirectoryPath}/${downloadedTrack.artwork.split('/').pop()}`
|
||||
: undefined
|
||||
|
||||
return {
|
||||
type: TrackType.Default,
|
||||
url: `file://${RNFS.DocumentDirectoryPath}/${downloadedTrack.path!.split('/').pop()}`,
|
||||
image: `file://${RNFS.DocumentDirectoryPath}/${downloadedTrack.artwork!.split('/').pop()}`,
|
||||
image: imagePath,
|
||||
duration: convertRunTimeTicksToSeconds(
|
||||
downloadedTrack.mediaSourceInfo?.RunTimeTicks || downloadedTrack.item.RunTimeTicks || 0,
|
||||
),
|
||||
item: downloadedTrack.item,
|
||||
mediaSourceInfo: downloadedTrack.mediaSourceInfo,
|
||||
sessionId: downloadedTrack.sessionId,
|
||||
sessionId: getValidSessionId(downloadedTrack.sessionId),
|
||||
sourceType: 'download',
|
||||
}
|
||||
}
|
||||
@@ -198,7 +215,7 @@ function buildTranscodedTrack(
|
||||
duration: convertRunTimeTicksToSeconds(RunTimeTicks ?? 0),
|
||||
mediaSourceInfo,
|
||||
item,
|
||||
sessionId,
|
||||
sessionId: getValidSessionId(sessionId),
|
||||
sourceType: 'stream',
|
||||
}
|
||||
}
|
||||
@@ -228,7 +245,7 @@ function buildAudioApiUrl(
|
||||
const mediaSource = mediaInfo!.MediaSources![0]
|
||||
|
||||
urlParams = {
|
||||
playSessionId: mediaInfo?.PlaySessionId ?? uuid.v4(),
|
||||
playSessionId: getValidSessionId(mediaInfo?.PlaySessionId),
|
||||
startTimeTicks: '0',
|
||||
static: 'true',
|
||||
}
|
||||
|
||||
@@ -5,7 +5,10 @@ import { headingFont, bodyFont } from './fonts.config'
|
||||
const tokens = createTokens({
|
||||
...TamaguiTokens,
|
||||
color: {
|
||||
danger: '#ff9966',
|
||||
dangerDark: '#FF066F',
|
||||
dangerLight: '#B30077',
|
||||
warningDark: '#FF6625',
|
||||
warningLight: '#a93300ff',
|
||||
purpleDark: '#0C0622',
|
||||
tealLight: 'rgba(16, 175, 141, 1)',
|
||||
tealDark: 'rgba(87, 233, 201, 1)',
|
||||
@@ -17,9 +20,10 @@ const tokens = createTokens({
|
||||
amethyst50: 'rgba(126, 114, 175, 0.5)',
|
||||
amethyst75: 'rgba(126, 114, 175, 0.75)',
|
||||
|
||||
secondary: '#cc2f71',
|
||||
secondaryDark: 'rgba(75, 125, 215, 1)',
|
||||
secondaryLight: 'rgba(0, 58, 159, 1)',
|
||||
|
||||
primaryLight: '#6D2FFF',
|
||||
primaryLight: '#4b0fd6ff',
|
||||
primaryDark: '#887BFF',
|
||||
white: '#ffffff',
|
||||
neutral: '#77748E',
|
||||
@@ -65,9 +69,10 @@ const jellifyConfig = createTamagui({
|
||||
borderColor: tokens.color.neutral,
|
||||
color: tokens.color.white,
|
||||
success: tokens.color.tealDark,
|
||||
secondary: tokens.color.secondary,
|
||||
secondary: tokens.color.secondaryDark,
|
||||
primary: tokens.color.primaryDark,
|
||||
danger: tokens.color.danger,
|
||||
danger: tokens.color.dangerDark,
|
||||
warning: tokens.color.warningDark,
|
||||
neutral: tokens.color.neutral,
|
||||
|
||||
translucent: tokens.color.darkTranslucent,
|
||||
@@ -81,9 +86,10 @@ const jellifyConfig = createTamagui({
|
||||
borderColor: tokens.color.neutral,
|
||||
color: tokens.color.white,
|
||||
success: tokens.color.tealDark,
|
||||
secondary: tokens.color.secondary,
|
||||
secondary: tokens.color.secondaryDark,
|
||||
primary: tokens.color.primaryDark,
|
||||
danger: tokens.color.danger,
|
||||
danger: tokens.color.dangerDark,
|
||||
warning: tokens.color.warningDark,
|
||||
neutral: tokens.color.neutral,
|
||||
|
||||
translucent: tokens.color.darkTranslucent,
|
||||
@@ -96,9 +102,10 @@ const jellifyConfig = createTamagui({
|
||||
background50: tokens.color.amethyst50,
|
||||
background75: tokens.color.amethyst75,
|
||||
success: tokens.color.tealDark,
|
||||
secondary: tokens.color.secondary,
|
||||
secondary: tokens.color.secondaryDark,
|
||||
primary: tokens.color.primaryDark,
|
||||
danger: tokens.color.danger,
|
||||
danger: tokens.color.dangerDark,
|
||||
warning: tokens.color.warningDark,
|
||||
neutral: tokens.color.neutral,
|
||||
|
||||
translucent: tokens.color.darkTranslucent,
|
||||
@@ -111,9 +118,10 @@ const jellifyConfig = createTamagui({
|
||||
borderColor: tokens.color.neutral,
|
||||
color: tokens.color.purpleDark,
|
||||
success: tokens.color.tealLight,
|
||||
secondary: tokens.color.secondary,
|
||||
secondary: tokens.color.secondaryLight,
|
||||
primary: tokens.color.primaryLight,
|
||||
danger: tokens.color.danger,
|
||||
danger: tokens.color.dangerLight,
|
||||
warning: tokens.color.warningLight,
|
||||
neutral: tokens.color.neutral,
|
||||
|
||||
translucent: tokens.color.lightTranslucent,
|
||||
@@ -126,9 +134,10 @@ const jellifyConfig = createTamagui({
|
||||
background50: tokens.color.amethyst50,
|
||||
background75: tokens.color.amethyst75,
|
||||
success: tokens.color.tealLight,
|
||||
secondary: tokens.color.secondary,
|
||||
secondary: tokens.color.secondaryLight,
|
||||
primary: tokens.color.primaryLight,
|
||||
danger: tokens.color.danger,
|
||||
danger: tokens.color.dangerLight,
|
||||
warning: tokens.color.warningLight,
|
||||
neutral: tokens.color.neutral,
|
||||
|
||||
translucent: tokens.color.lightTranslucent,
|
||||
|
||||