From e78b9d2114eac00feabf1ba99f8f9eefd9b448b7 Mon Sep 17 00:00:00 2001
From: Violet Caulfield <42452695+anultravioletaurora@users.noreply.github.com>
Date: Thu, 1 May 2025 14:53:54 -0500
Subject: [PATCH] Re-enable New Architecture on Android, Remove Blurhash Deps,
Improve Album Layout on Larger Viewports (#318)
Re-enables new architecture on Android by switching to a different fork of React Native Track Player
Removes dependency on react-native-blurhash - we aren't using it as our image component can handle this for us
Improves album layout on artist screen by adjusting flex of album details and album artwork
---
.github/workflows/publish-beta.yml | 9 +-
android/gradle.properties | 2 +-
jest.config.js | 1 -
jest/setup-blurhash.ts | 5 -
package.json | 237 ++--
patches/react-native-track-player+4.1.1.patch | 1030 -----------------
src/api/queries/recents.ts | 13 +
src/components/Album/index.tsx | 5 +-
.../Global/components/blurhashed-image.tsx | 108 --
src/components/Global/components/image.tsx | 38 +-
src/components/Global/components/item.tsx | 12 +-
src/components/InstantMix/component.tsx | 2 -
src/enums/mmkv-storage-keys.ts | 3 +
src/enums/mutation-keys.ts | 3 +
src/enums/query-keys.ts | 5 +-
yarn.lock | 10 +-
16 files changed, 183 insertions(+), 1300 deletions(-)
delete mode 100644 jest/setup-blurhash.ts
delete mode 100644 patches/react-native-track-player+4.1.1.patch
delete mode 100644 src/components/Global/components/blurhashed-image.tsx
diff --git a/.github/workflows/publish-beta.yml b/.github/workflows/publish-beta.yml
index 3736ff1a..2825064f 100644
--- a/.github/workflows/publish-beta.yml
+++ b/.github/workflows/publish-beta.yml
@@ -17,9 +17,9 @@ jobs:
with:
node-version: 20
- - name: π€ Run yarn init-android
- run: yarn init-android
-
+ - name: π Run yarn init-ios:new-arch
+ run: yarn init-ios:new-arch
+
- name: β Version Up
run: yarn react-native bump-version --type patch
@@ -33,9 +33,6 @@ jobs:
- name: π Run Android fastlane build
run: yarn fastlane:android:build
- - name: π Run yarn init-ios:new-arch
- run: yarn init-ios:new-arch
-
- name: π Run iOS fastlane build and publish to TestFlight
run: yarn fastlane:ios:beta
env:
diff --git a/android/gradle.properties b/android/gradle.properties
index 0bb46a99..3e878eab 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -32,7 +32,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# your application. You should enable this flag either if you want
# to write custom TurboModules/Fabric components OR use libraries that
# are providing them.
-newArchEnabled=false
+newArchEnabled=true
# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.
diff --git a/jest.config.js b/jest.config.js
index 19b9389c..2690e262 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -5,7 +5,6 @@ module.exports = {
setupFilesAfterEnv: [
'./jest/setup.ts',
'./jest/setup-carplay.ts',
- './jest/setup-blurhash.ts',
'./jest/setup-device-info.js', // JS to prevent Typescript implicit any warning
'./jest/setup-reanimated.ts',
'./jest/setup-rnfs.ts',
diff --git a/jest/setup-blurhash.ts b/jest/setup-blurhash.ts
deleted file mode 100644
index 133028c1..00000000
--- a/jest/setup-blurhash.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-jest.mock('react-native-blurhash', () => {
- return {
- Blurhash: () => null,
- }
-})
diff --git a/package.json b/package.json
index e80a055d..7f342002 100644
--- a/package.json
+++ b/package.json
@@ -1,121 +1,120 @@
{
- "name": "jellify",
- "version": "0.11.19",
- "private": true,
- "scripts": {
- "init-android": "yarn && yarn add react-native-mmkv@2.12.0",
- "init-ios": "echo 'Please run `yarn init-ios:new-arch` to enable the new architecture'",
- "init-ios:new-arch": "yarn && yarn add react-native-mmkv@3.2.0 && yarn pod:install:new-arch",
- "reinstall": "rm -rf ./node_modules && yarn install",
- "android": "react-native run-android",
- "ios": "react-native run-ios",
- "lint": "eslint .",
- "start": "react-native start",
- "test": "jest",
- "tsc": "tsc",
- "clean:ios": "cd ios && pod deintegrate",
- "clean:android": "cd android && rm -rf app/ build/",
- "pod:install": "echo 'Please run `yarn pod:install:new-arch` to enable the new architecture'",
- "pod:install:new-arch": "cd ios && bundle install && RCT_NEW_ARCH_ENABLED=1 bundle exec pod install",
- "pod:clean": "cd ios && pod deintegrate",
- "fastlane:ios:build": "cd ios && bundle exec fastlane build",
- "fastlane:ios:match": "cd ios && bundle exec fastlane match development",
- "fastlane:ios:beta": "cd ios && bundle exec fastlane beta",
- "fastlane:android:build": "cd android && bundle install && bundle exec fastlane build",
- "androidBuild": "cd android && ./gradlew clean && ./gradlew assembleRelease && cd .. && echo 'find apk in android/app/build/outputs/apk/release'",
- "prepare": "husky",
- "format:check": "prettier --check .",
- "format": "prettier --write .",
- "postinstall": "patch-package"
- },
- "dependencies": {
- "@jellyfin/sdk": "^0.11.0",
- "@react-native-community/blur": "^4.4.1",
- "@react-native-community/cli": "^18.0.0",
- "@react-native-community/netinfo": "^11.4.1",
- "@react-native-masked-view/masked-view": "^0.3.2",
- "@react-navigation/bottom-tabs": "^7.3.10",
- "@react-navigation/material-top-tabs": "^7.2.10",
- "@react-navigation/native": "^7.1.6",
- "@react-navigation/native-stack": "^7.3.10",
- "@react-navigation/stack": "^7.2.10",
- "@tamagui/config": "^1.126.4",
- "@tanstack/query-sync-storage-persister": "^5.74.6",
- "@tanstack/react-query": "^5.74.4",
- "@tanstack/react-query-persist-client": "^5.74.6",
- "@testing-library/react-native": "^13.2.0",
- "axios": "^1.8.4",
- "bundle": "^2.1.0",
- "gem": "^2.4.3",
- "invert-color": "^2.0.0",
- "lodash": "^4.17.21",
- "react": "19.0.0",
- "react-freeze": "^1.0.4",
- "react-native": "0.79.1",
- "react-native-background-actions": "^4.0.1",
- "react-native-blurhash": "^2.1.1",
- "react-native-carplay": "^2.4.1-beta.0",
- "react-native-device-info": "^14.0.4",
- "react-native-draggable-flatlist": "^4.0.2",
- "react-native-fast-image": "^8.6.3",
- "react-native-fs": "^2.20.0",
- "react-native-gesture-handler": "^2.25.0",
- "react-native-haptic-feedback": "^2.3.3",
- "react-native-mmkv": "3.2.0",
- "react-native-pager-view": "^6.7.1",
- "react-native-reanimated": "^3.17.5",
- "react-native-safe-area-context": "^5.4.0",
- "react-native-screens": "^4.11.0-beta.2",
- "react-native-swipeable-item": "^2.0.9",
- "react-native-text-ticker": "^1.14.0",
- "react-native-toast-message": "^2.3.0",
- "react-native-track-player": "4.1.1",
- "react-native-url-polyfill": "^2.0.0",
- "react-native-uuid": "^2.0.3",
- "react-native-vector-icons": "^10.2.0",
- "ruby": "^0.6.1",
- "tamagui": "^1.126.4"
- },
- "devDependencies": {
- "@babel/core": "^7.25.2",
- "@babel/preset-env": "^7.25.3",
- "@babel/runtime": "^7.25.0",
- "@react-native-community/cli-platform-android": "18.0.0",
- "@react-native-community/cli-platform-ios": "18.0.0",
- "@react-native/babel-preset": "0.79.1",
- "@react-native/eslint-config": "0.79.1",
- "@react-native/metro-config": "0.79.1",
- "@react-native/typescript-config": "0.79.1",
- "@types/jest": "^29.5.13",
- "@types/lodash": "^4.17.10",
- "@types/react": "^19.1.2",
- "@types/react-native-vector-icons": "^6.4.18",
- "@types/react-test-renderer": "19.0.0",
- "babel-plugin-module-resolver": "^5.0.2",
- "eslint": "^8.57.1",
- "eslint-config-prettier": "^10.1.2",
- "eslint-plugin-import": "^2.31.0",
- "eslint-plugin-prettier": "^5.2.6",
- "eslint-plugin-react": "^7.37.5",
- "eslint-plugin-react-native": "^5.0.0",
- "husky": "^9.1.7",
- "jest": "^29.6.3",
- "jscodeshift": "^0.15.2",
- "lint-staged": "^15.5.0",
- "patch-package": "8.0.0",
- "prettier": "^2.8.8",
- "react-dom": "^19.1.0",
- "react-native-cli-bump-version": "^1.5.1",
- "react-test-renderer": "19.0.0",
- "typescript": "5.8.3"
- },
- "lint-staged": {
- "*.{js,jsx,ts,tsx}": [
- "prettier --write",
- "eslint --fix"
- ]
- },
- "engines": {
- "node": ">=18"
- }
+ "name": "jellify",
+ "version": "0.11.19",
+ "private": true,
+ "scripts": {
+ "init-android": "yarn",
+ "init-ios": "yarn init-ios:new-arch",
+ "init-ios:new-arch": "yarn && yarn pod:install:new-arch",
+ "reinstall": "rm -rf ./node_modules && yarn install",
+ "android": "react-native run-android",
+ "ios": "react-native run-ios",
+ "lint": "eslint .",
+ "start": "react-native start",
+ "test": "jest",
+ "tsc": "tsc",
+ "clean:ios": "cd ios && pod deintegrate",
+ "clean:android": "cd android && rm -rf app/ build/",
+ "pod:install": "echo 'Please run `yarn pod:install:new-arch` to enable the new architecture'",
+ "pod:install:new-arch": "cd ios && bundle install && RCT_NEW_ARCH_ENABLED=1 bundle exec pod install",
+ "pod:clean": "cd ios && pod deintegrate",
+ "fastlane:ios:build": "cd ios && bundle exec fastlane build",
+ "fastlane:ios:match": "cd ios && bundle exec fastlane match development",
+ "fastlane:ios:beta": "cd ios && bundle exec fastlane beta",
+ "fastlane:android:build": "cd android && bundle install && bundle exec fastlane build",
+ "androidBuild": "cd android && ./gradlew clean && ./gradlew assembleRelease && cd .. && echo 'find apk in android/app/build/outputs/apk/release'",
+ "prepare": "husky",
+ "format:check": "prettier --check .",
+ "format": "prettier --write .",
+ "postinstall": "patch-package"
+ },
+ "dependencies": {
+ "@jellyfin/sdk": "^0.11.0",
+ "@react-native-community/blur": "^4.4.1",
+ "@react-native-community/cli": "^18.0.0",
+ "@react-native-community/netinfo": "^11.4.1",
+ "@react-native-masked-view/masked-view": "^0.3.2",
+ "@react-navigation/bottom-tabs": "^7.3.10",
+ "@react-navigation/material-top-tabs": "^7.2.10",
+ "@react-navigation/native": "^7.1.6",
+ "@react-navigation/native-stack": "^7.3.10",
+ "@react-navigation/stack": "^7.2.10",
+ "@tamagui/config": "^1.126.4",
+ "@tanstack/query-sync-storage-persister": "^5.74.6",
+ "@tanstack/react-query": "^5.74.4",
+ "@tanstack/react-query-persist-client": "^5.74.6",
+ "@testing-library/react-native": "^13.2.0",
+ "axios": "^1.8.4",
+ "bundle": "^2.1.0",
+ "gem": "^2.4.3",
+ "invert-color": "^2.0.0",
+ "lodash": "^4.17.21",
+ "react": "19.0.0",
+ "react-freeze": "^1.0.4",
+ "react-native": "0.79.1",
+ "react-native-background-actions": "^4.0.1",
+ "react-native-carplay": "^2.4.1-beta.0",
+ "react-native-device-info": "^14.0.4",
+ "react-native-draggable-flatlist": "^4.0.2",
+ "react-native-fast-image": "^8.6.3",
+ "react-native-fs": "^2.20.0",
+ "react-native-gesture-handler": "^2.25.0",
+ "react-native-haptic-feedback": "^2.3.3",
+ "react-native-mmkv": "3.2.0",
+ "react-native-pager-view": "^6.7.1",
+ "react-native-reanimated": "^3.17.5",
+ "react-native-safe-area-context": "^5.4.0",
+ "react-native-screens": "^4.11.0-beta.2",
+ "react-native-swipeable-item": "^2.0.9",
+ "react-native-text-ticker": "^1.14.0",
+ "react-native-toast-message": "^2.3.0",
+ "react-native-track-player": "git+https://github.com/riteshshukla04/react-native-track-player#APM",
+ "react-native-url-polyfill": "^2.0.0",
+ "react-native-uuid": "^2.0.3",
+ "react-native-vector-icons": "^10.2.0",
+ "ruby": "^0.6.1",
+ "tamagui": "^1.126.4"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.25.2",
+ "@babel/preset-env": "^7.25.3",
+ "@babel/runtime": "^7.25.0",
+ "@react-native-community/cli-platform-android": "18.0.0",
+ "@react-native-community/cli-platform-ios": "18.0.0",
+ "@react-native/babel-preset": "0.79.1",
+ "@react-native/eslint-config": "0.79.1",
+ "@react-native/metro-config": "0.79.1",
+ "@react-native/typescript-config": "0.79.1",
+ "@types/jest": "^29.5.13",
+ "@types/lodash": "^4.17.10",
+ "@types/react": "^19.1.2",
+ "@types/react-native-vector-icons": "^6.4.18",
+ "@types/react-test-renderer": "19.0.0",
+ "babel-plugin-module-resolver": "^5.0.2",
+ "eslint": "^8.57.1",
+ "eslint-config-prettier": "^10.1.2",
+ "eslint-plugin-import": "^2.31.0",
+ "eslint-plugin-prettier": "^5.2.6",
+ "eslint-plugin-react": "^7.37.5",
+ "eslint-plugin-react-native": "^5.0.0",
+ "husky": "^9.1.7",
+ "jest": "^29.6.3",
+ "jscodeshift": "^0.15.2",
+ "lint-staged": "^15.5.0",
+ "patch-package": "8.0.0",
+ "prettier": "^2.8.8",
+ "react-dom": "^19.1.0",
+ "react-native-cli-bump-version": "^1.5.1",
+ "react-test-renderer": "19.0.0",
+ "typescript": "5.8.3"
+ },
+ "lint-staged": {
+ "*.{js,jsx,ts,tsx}": [
+ "prettier --write",
+ "eslint --fix"
+ ]
+ },
+ "engines": {
+ "node": ">=18"
+ }
}
diff --git a/patches/react-native-track-player+4.1.1.patch b/patches/react-native-track-player+4.1.1.patch
deleted file mode 100644
index 8880cf3d..00000000
--- a/patches/react-native-track-player+4.1.1.patch
+++ /dev/null
@@ -1,1030 +0,0 @@
-diff --git a/node_modules/react-native-track-player/CHANGELOG.md b/node_modules/react-native-track-player/CHANGELOG.md
-new file mode 100644
-index 0000000..15bc88c
---- /dev/null
-+++ b/node_modules/react-native-track-player/CHANGELOG.md
-@@ -0,0 +1,303 @@
-+# [4.1.1](https://github.com/doublesymmetry/react-native-track-player/compare/v4.1.0...v4.1.1) (2024-03-26)
-+
-+- **RN:** Fixes an issue when using local assets in release builds
-+
-+# [4.1.0](https://github.com/doublesymmetry/react-native-track-player/compare/v4.0.1...v4.1.0) (2024-03-25)
-+
-+- **web:** First beta version of RNTP for web
-+- **RN:** Massively reduce npm package size
-+- **android:** Fix: add namespace to support gradle 8
-+- **android:** Improvement: add http headers to notification artwork request
-+- **android:** Improvement: use http data source for local urls
-+- **android:** Improvement: use SVGs for notification icons
-+- **android:** Improvement: specify key when returning key error
-+- **ios:** Improvement: improve internal use of playWhenReady to avoid issue where we'd load two tracks at once
-+- **ios:** Fix: return correct already intialized error code
-+- **ios:** Fix: avoid emitting empty common metadata
-+- **ios:** Fix: occasional crash due to attaching metadata output
-+- **ios:** Fix: sometimes progress bar would be broken after repeat
-+
-+# [4.0.1](https://github.com/doublesymmetry/react-native-track-player/compare/v4.0.0...v4.0.1) (2023-10-31)
-+
-+- **android:** Fix: notification dissapearing in background
-+- **android:** Allow overriding notification channel name and description
-+
-+# [4.0.0](https://github.com/doublesymmetry/react-native-track-player/compare/v4.0.0-rc09...v4.0.0) (2023-10-20)
-+
-+- **RN:** New metadata events have a new `metadata` property that contains the metadata that was received
-+- **android:** Fix: allow updating duration in notification metadata
-+- **ios:** Avoid prematurely activating audio session
-+- **android:** Fix: don't emit both PlaybackTrackChanged when queue ends (parity with iOS)
-+- **android:** Fix: allow progressUpdateEventInterval to be set to a decimal value (partial seconds)
-+- **android:** Support for setting grace period before stopForeground (defaults to 5 seconds)
-+- **ios:** Fix: updating rate will immediately reflect in control center
-+- **android** Fix: issue where loading a new track after end required seek to start
-+- **ios:** Fix: crash adding output when load is called too fast
-+
-+# [4.0.0-rc09](https://github.com/doublesymmetry/react-native-track-player/compare/v4.0.0-rc08...v4.0.0-rc09) (2023-09-22)
-+
-+- **RN:** useIsPlaying hook now takes into account `none` state
-+- **ios:** Fixes issue where rate was being reset to 1 on play
-+- **ios:** Deactivates session before activating on play to avoid issues when losing focus in some scenarios
-+- **RN:** Deprecated `Event.PlaybackMetadataReceived` and introduces three new events: [`Event.AudioChapterMetadataReceived`, `Event.AudioTimedMetadataReceived`, `Event.AudioCommonMetadataReceived`]
-+- **ios:** Change default pitch algorithm to `timeDomain` instead of `lowQualityZeroLatency`
-+- **android:** Fixes progress in notification for HLS audio
-+
-+# [4.0.0-rc08](https://github.com/doublesymmetry/react-native-track-player/compare/v4.0.0-rc07...v4.0.0-rc08) (2023-09-07)
-+
-+- **RN:** Undeprecate updateNowPlayingMetadata
-+- **android:** Restore notification image caching
-+- **RN:** Fix issue with updateOptions and local images
-+- **ios:** Activate session on play to avoid issues with background audio
-+- **ios:** Second fix for repeat mode
-+- **ios:** Correctly update control center progress when pausing/playing
-+
-+# [4.0.0-rc07](https://github.com/doublesymmetry/react-native-track-player/compare/v4.0.0-rc06...v4.0.0-rc07) (2023-08-11)
-+
-+- **ios:** Fix firing of `EventType.PlaybackQueueEnded` (fixes #2038)
-+- **android:** Avoid emitting track changed when replaying the same track
-+- **android:** Fixed a regression where `reset()` wasn't clearing notification properly
-+- **android:** Resolved a where the update metadata method was not working
-+
-+# [4.0.0-rc06](https://github.com/doublesymmetry/react-native-track-player/compare/v4.0.0-rc05...v4.0.0-rc06) (2023-07-25)
-+
-+- **ios:** Fix iOS not repeating track in RepeatMode.Track
-+- **RN:** Improve types on asset types
-+- **android:** Fix foreground issues and notification item
-+- **ios** Fix race conditions in player property setting
-+- **android:** Improve notification updates when spamming notification buttons
-+- **android** Fix AudioPlayerState.IDLE when queue emptied
-+- **android** Improve metadata handling
-+
-+# [4.0.0-rc05](https://github.com/doublesymmetry/react-native-track-player/compare/v4.0.0-rc04...v4.0.0-rc05) (2023-06-26)
-+
-+- **ios:** Fix crash on getting current item
-+- **android:** Improve preciseness of seeking
-+- **android:** Improve handling of service foregrounding
-+
-+# [4.0.0-rc03](https://github.com/doublesymmetry/react-native-track-player/compare/v4.0.0-rc02...v4.0.0-rc03) (2023-03-28)
-+
-+- **android:** Fixes compilation issue due to uses of Lifecycle (updates kotlin gradle plugin)
-+
-+# [4.0.0-rc02](https://github.com/doublesymmetry/react-native-track-player/compare/v4.0.0-rc01...v4.0.0-rc02) (2023-03-27)
-+
-+### Bug Fixes
-+
-+- **android:** Fix ANR crashes ([#1974](https://github.com/doublesymmetry/react-native-track-player/issues/1974)) ([b70fbd7](https://github.com/doublesymmetry/react-native-track-player/commit/b70fbd7663921855f799a60083ca4522e913e6f8)
-+- **android:** Fix removeUpcomingItems ([#67](https://github.com/doublesymmetry/KotlinAudior/issues/67))
-+- **android:** Notification fixes
-+
-+- **ios:** Fix removing items from queue other than the current track ([#41](https://github.com/doublesymmetry/SwiftAudioEx/issues/41))
-+- **ios:** Fix player state not becoming paused after loading ([#46](https://github.com/doublesymmetry/SwiftAudioEx/issues/46))
-+- **ios:** Fix current item not being updated when removing items from queue ([#45](https://github.com/doublesymmetry/SwiftAudioEx/issues/45))
-+- **ios:** Avoid calling onSkippedToSameCurrentItem when track before is removed ([#45](https://github.com/doublesymmetry/SwiftAudioEx/issues/45))
-+
-+# [4.0.0-rc01](https://github.com/doublesymmetry/react-native-track-player/compare/v3.2.0...v4.0.0-rc01) (2023-03-14)
-+
-+### Bug Fixes
-+
-+- **android:** add deep link back ([#1872](https://github.com/doublesymmetry/react-native-track-player/issues/1872)) ([9c227fa](https://github.com/doublesymmetry/react-native-track-player/commit/9c227fa7e0748d3d43dba435ee284e01e18de9bc))
-+- **android:** fix handling of seek capability ([#1938](https://github.com/doublesymmetry/react-native-track-player/issues/1938)) ([166aa0d](https://github.com/doublesymmetry/react-native-track-player/commit/166aa0d2d4ee7d213d4a41e496592f20e4bbbede))
-+- **android:** resolve problem with StopPlaybackAndRemoveNotification not working on subsequent exists ([#1762](https://github.com/doublesymmetry/react-native-track-player/issues/1762)) ([e742959](https://github.com/doublesymmetry/react-native-track-player/commit/e742959cc1d697d69daeade39830155bce2ccde7))
-+- **android:** use βnoneβ instead of βidleβ for none state ([#1924](https://github.com/doublesymmetry/react-native-track-player/issues/1924)) ([e125045](https://github.com/doublesymmetry/react-native-track-player/commit/e125045106ad3db125a09dc60dab2acc3334f01c))
-+- clears queue on iOS when you call reset() ([#1900](https://github.com/doublesymmetry/react-native-track-player/issues/1900)) ([e3c670a](https://github.com/doublesymmetry/react-native-track-player/commit/e3c670a822488565b923300be76e70a8c492fec4))
-+- **hooks:** updates setting initial playback state in usePlaybackState hook ([417f3c4](https://github.com/doublesymmetry/react-native-track-player/commit/417f3c4cdf26c2db8551eeae6f84eed69f532e77)), closes [#1931](https://github.com/doublesymmetry/react-native-track-player/issues/1931)
-+- **ios:** emit state passed to handleAudioPlayerStateChange ([#1928](https://github.com/doublesymmetry/react-native-track-player/issues/1928)) ([a65fdcd](https://github.com/doublesymmetry/react-native-track-player/commit/a65fdcd5f913e20ffcdf45bb1d814d51ffe255ae))
-+- **ios:** prevents overwriting of forward/backward secs ([#1855](https://github.com/doublesymmetry/react-native-track-player/issues/1855)) ([fb594c7](https://github.com/doublesymmetry/react-native-track-player/commit/fb594c77b2f80ecf90995893c0158cc8cd11baa0)), closes [#1853](https://github.com/doublesymmetry/react-native-track-player/issues/1853)
-+
-+# [3.2.0](https://github.com/doublesymmetry/react-native-track-player/compare/v3.1.0...v3.2.0) (2022-09-23)
-+
-+### Bug Fixes
-+
-+- **android, events:** properly intercept and fire remote playback events ([#1668](https://github.com/doublesymmetry/react-native-track-player/issues/1668)) ([9ed308c](https://github.com/doublesymmetry/react-native-track-player/commit/9ed308c2a8f5bbd4ab69df01a7cfb86047960538))
-+- **android:** fix state constants ([#1751](https://github.com/doublesymmetry/react-native-track-player/issues/1751)) ([7215e64](https://github.com/doublesymmetry/react-native-track-player/commit/7215e641615a1526e536d5f0e7bb6b0bb2b6d0f7))
-+- **example, ios:** remove Capability.Stop ([#1671](https://github.com/doublesymmetry/react-native-track-player/issues/1671)) ([49800ab](https://github.com/doublesymmetry/react-native-track-player/commit/49800ab81f9dbc34a136632a3c7623666e1ae95d))
-+- **hooks:** fix issues with excessive number of pending callbacks ([#1686](https://github.com/doublesymmetry/react-native-track-player/issues/1686)) ([1b5bb02](https://github.com/doublesymmetry/react-native-track-player/commit/1b5bb02bbe1457902949ebd9c29829ba4998eb07))
-+- **hooks:** fix useTrackPlayerEvents dependencies ([#1672](https://github.com/doublesymmetry/react-native-track-player/issues/1672)) ([f6229d6](https://github.com/doublesymmetry/react-native-track-player/commit/f6229d68c2cdb650b90c38fa47f7e40d0028dfee))
-+- **hooks:** useProgress & usePlayback hooks ([#1723](https://github.com/doublesymmetry/react-native-track-player/issues/1723)) ([31fa40a](https://github.com/doublesymmetry/react-native-track-player/commit/31fa40acafed2d4bb09a718e4c51879fb1c7e747))
-+- **ios, events:** fix an issue with PlaybackQueueEnded resulting from a race condition ([#1750](https://github.com/doublesymmetry/react-native-track-player/issues/1750)) ([e938c68](https://github.com/doublesymmetry/react-native-track-player/commit/e938c68a1968c8a0fa4aa1019d0343c04a427d60))
-+- **ios:** fix various issues in iOS by upgrading SwiftAudioEx ([#1738](https://github.com/doublesymmetry/react-native-track-player/issues/1738)) ([224c491](https://github.com/doublesymmetry/react-native-track-player/commit/224c4910e4c3fe2164ac1cbf0bb3f61810062d48))
-+- **ts:** add `null` to getCurrentTrack return type ([#1681](https://github.com/doublesymmetry/react-native-track-player/issues/1681)) ([096ec68](https://github.com/doublesymmetry/react-native-track-player/commit/096ec68bc0c3150f02c068ed20dd07f0ddf53e35))
-+
-+### Features
-+
-+- **android:** add back option to remove notification ([#1730](https://github.com/doublesymmetry/react-native-track-player/issues/1730)) ([82a5df9](https://github.com/doublesymmetry/react-native-track-player/commit/82a5df9ec62476b05bbef6f5d18ca9b0b801d298))
-+- **android:** add string values to State enum ([#1734](https://github.com/doublesymmetry/react-native-track-player/issues/1734)) ([bd48c2d](https://github.com/doublesymmetry/react-native-track-player/commit/bd48c2d6de2a56e0a96be8dd47bc316ea0dcd8cf)), closes [#1688](https://github.com/doublesymmetry/react-native-track-player/issues/1688)
-+- **android:** default the behavior to handle audio becoming noisy ([#1732](https://github.com/doublesymmetry/react-native-track-player/issues/1732)) ([dabf715](https://github.com/doublesymmetry/react-native-track-player/commit/dabf71566cba1cc9fba48899ad6be58e59a90212))
-+- **ios:** deprecate waitForBuffer ([#1695](https://github.com/doublesymmetry/react-native-track-player/issues/1695)) ([d277182](https://github.com/doublesymmetry/react-native-track-player/commit/d27718295cecc88886db2cbe96666c9c50d34b34))
-+- **ios:** improve disabling of playback-progress-updated ([#1706](https://github.com/doublesymmetry/react-native-track-player/issues/1706)) ([57de8b5](https://github.com/doublesymmetry/react-native-track-player/commit/57de8b5e12c05bed093a754474b2e4e0e8597578))
-+
-+## 3.1.0 (18.08.22)
-+
-+##### Enhancements
-+
-+- Uses latest KotlinAudio which does not use ExoPlayer fork.
-+- Adds back support for bluetooth playback control.
-+
-+##### Bug Fixes
-+
-+- Fixes crash with `reset()` on Android.
-+- Removes `destroy()` on iOS - this was missed.
-+- Removes the `stop()` method -- use `pause()` instead.
-+
-+## 3.0.0 (11.08.22)
-+
-+We are changing how the audio service handles its lifecycle. Previously we had the stopWithApp bool that would try and stop the service when you remove the app from recents, but due to how Android handles foreground services the OS never stops the app process, as it's waiting for the foreground service to come back. We are embracing this and going with what other audio apps (Spotify, Soundcloud, Google Podcast etc.) are doing.
-+
-+##### Enhancements
-+
-+- Rewrite Android module in Kotlin and using KotlinAudio.
-+ [mpivchev](
-+
-+##### Breaking
-+
-+- stopWithApp turns into stoppingAppPausesPlayback
-+- `destroy()` is no longer available
-+-
-+
-+##### Bug Fixes
-+
-+- Fix crash with `reset()` on Android.
-+ [dcvz](https://github.com/dcvz)
-+
-+## 2.1.3 (30.03.22)
-+
-+##### Enhancements
-+
-+- Add property `isLiveStream` to `Track` for correct display in iOS control center.
-+ [dcvz](https://github.com/dcvz)
-+
-+- [iOS] Improve method documentation
-+ [alpha0010](https://github.com/alpha0010)
-+
-+- [Android] Add isServiceRunning method
-+ [biomancer](https://github.com/biomancer)
-+
-+##### Bug Fixes
-+
-+- [iOS] Fix track loop crash in certain cases
-+ [mmmoussa](https://github.com/mmmoussa)
-+
-+- [iOS] Fix seek after play
-+ [jspizziri](https://github.com/jspizziri)
-+
-+- [Android] Support Android 12 devices
-+ [abhaydee](https://github.com/abhaydee)
-+
-+- [iOS] Add method resolves promise with index
-+ [formula1](https://github.com/formula1)
-+
-+- Fix getTrack return type
-+ [puckey](https://github.com/puckey)
-+
-+- [iOS] Fix ambient session not working
-+ [grubicv](https://github.com/grubicv)
-+
-+- [Android] Android 12 and higher bug fix
-+ [martin-richter-uk](https://github.com/martin-richter-uk)
-+
-+- [iOS] Update SwiftAudioEx to 0.14.6 to avoid LICENSE warning
-+ [dcvz](https://github.com/dcvz)
-+
-+- Make react-native-windows and optional peer dependency (#1324).
-+ [jspizziri](https://github.com/jspizziri)
-+
-+## 2.1.2 (25.10.21)
-+
-+##### Enhancements
-+
-+- None.
-+
-+##### Bug Fixes
-+
-+- Update SwiftAudioEx - Fixes issues with flickering notifications + pause between loads
-+
-+- Fix cyclic require warning regression
-+ [#1057](https://github.com/DoubleSymmetry/react-native-track-player/issues/1057)
-+
-+- [ios] Fix `PlaybackQueueEnded` event to be called only when the track ends
-+ [#1243](https://github.com/DoubleSymmetry/react-native-track-player/issues/1243)
-+
-+## 2.1.1 (25.09.21)
-+
-+##### Enhancements
-+
-+- [ios] Fix getCurrentTrack returns undefined instead of null
-+- [ios] Fix getTrack returning undefined instead of nil
-+- Fix an issue with next/previous in the control center stopping playing on iOS15
-+
-+##### Bug Fixes
-+
-+- None.
-+
-+## 2.1.0 (16.09.21)
-+
-+##### Enhancements
-+
-+- None.
-+
-+##### Bug Fixes
-+
-+- Remove Support for iOS 10 & Support Xcode 13
-+ [dcvz](https://github.com/dcvz)
-+ [#1186](https://github.com/DoubleSymmetry/react-native-track-player/issues/1186)
-+
-+ - **NOTE: Requires minimum deployment target to be updated to iOS 11.**
-+
-+- Reset initialization on destroy
-+ [sreten-bild](https://github.com/sreten-bild)
-+
-+- Fix `onTaskRemoved` NullPointerException
-+ [Markario](https://github.com/Markario)
-+
-+## 2.0.3 (19.08.21)
-+
-+##### Enhancements
-+
-+- None.
-+
-+##### Bug Fixes
-+
-+- Fix `Event.PlaybackQueueEnded` firing on initialization on Android
-+ [dcvz](https://github.com/dcvz)
-+ [#1229](https://github.com/DoubleSymmetry/react-native-track-player/issues/1229)
-+
-+- Make `useProgress` unmount aware.
-+ [lyswhut](https://github.com/lyswhut)
-+
-+- Make `usePlaybackState` unmount aware.
-+ [dcvz](https://github.com/dcvz)
-+
-+## 2.0.2 (15.08.21)
-+
-+##### Enhancements
-+
-+- Import SwiftAudioEx through podspec
-+ [dcvz](https://github.com/dcvz)
-+
-+##### Bug Fixes
-+
-+- `useProgress` hook should update while paused
-+ [dcvz](https://github.com/dcvz)
-+
-+## 2.0.1 (11.08.21)
-+
-+##### Enhancements
-+
-+- None.
-+
-+##### Bug Fixes
-+
-+- Add `startForeground` to `onCreate`.
-+ [Bang9](https://github.com/Bang9)
-+ [#620](https://github.com/DoubleSymmetry/react-native-track-player/issues/620)
-+ [#524](https://github.com/DoubleSymmetry/react-native-track-player/issues/524)
-+ [#473](https://github.com/DoubleSymmetry/react-native-track-player/issues/473)
-+ [#391](https://github.com/DoubleSymmetry/react-native-track-player/issues/391)
-+
-+- Fix compilation of Windows module.
-+ [dcvz](https://github.com/dcvz)
-+
-+- Fix regression in updating artwork on `updateMetadata` and `updateNowPlayingMetadata`
-+ [dcvz](https://github.com/dcvz)
-+ [#662](https://github.com/DoubleSymmetry/react-native-track-player/issues/662#issuecomment-896370375)
-diff --git a/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt b/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt
-index b2409a0..d1fef9f 100644
---- a/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt
-+++ b/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt
-@@ -49,7 +49,7 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- override fun onServiceConnected(name: ComponentName, service: IBinder) {
-- scope.launch {
-+ launchInScope{
- // If a binder already exists, don't get a new one
- if (!::musicService.isInitialized) {
- val binder: MusicService.MusicBinder = service as MusicService.MusicBinder
-@@ -66,7 +66,7 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- * Called when a connection to the Service has been lost.
- */
- override fun onServiceDisconnected(name: ComponentName) {
-- scope.launch {
-+ launchInScope{
- isServiceBound = false
- }
- }
-@@ -250,9 +250,10 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- callback.resolve(isServiceBound)
- }
-
-+
- @ReactMethod
-- fun updateOptions(data: ReadableMap?, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun updateOptions(data: ReadableMap?, callback: Promise) = launchInScope {
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- val options = Arguments.toBundle(data)
-
-@@ -264,14 +265,14 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- @ReactMethod
-- fun add(data: ReadableArray?, insertBeforeIndex: Int, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun add(data: ReadableArray?, insertBeforeIndex: Int, callback: Promise) = launchInScope {
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- try {
- val tracks = readableArrayToTrackList(data);
- if (insertBeforeIndex < -1 || insertBeforeIndex > musicService.tracks.size) {
- callback.reject("index_out_of_bounds", "The track index is out of bounds")
-- return@launch
-+ return@launchInScope
- }
- val index = if (insertBeforeIndex == -1) musicService.tracks.size else insertBeforeIndex
- musicService.add(
-@@ -285,11 +286,11 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- @ReactMethod
-- fun load(data: ReadableMap?, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun load(data: ReadableMap?, callback: Promise) = launchInScope {
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
- if (data == null) {
- callback.resolve(null)
-- return@launch
-+ return@launchInScope
- }
- val bundle = Arguments.toBundle(data);
- if (bundle is Bundle) {
-@@ -301,15 +302,15 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- @ReactMethod
-- fun move(fromIndex: Int, toIndex: Int, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun move(fromIndex: Int, toIndex: Int, callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
- musicService.move(fromIndex, toIndex)
- callback.resolve(null)
- }
-
- @ReactMethod
-- fun remove(data: ReadableArray?, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun remove(data: ReadableArray?, callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
- val inputIndexes = Arguments.toList(data)
- if (inputIndexes != null) {
- val size = musicService.tracks.size
-@@ -321,7 +322,7 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- "index_out_of_bounds",
- "One or more indexes was out of bounds"
- )
-- return@launch
-+ return@launchInScope
- }
- indexes.add(index)
- }
-@@ -332,8 +333,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
-
- @ReactMethod
- fun updateMetadataForTrack(index: Int, map: ReadableMap?, callback: Promise) =
-- scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- if (index < 0 || index >= musicService.tracks.size) {
- callback.reject("index_out_of_bounds", "The index is out of bounds")
-@@ -348,8 +349,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- @ReactMethod
-- fun updateNowPlayingMetadata(map: ReadableMap?, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun updateNowPlayingMetadata(map: ReadableMap?, callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- if (musicService.tracks.isEmpty())
- callback.reject("no_current_item", "There is no current item in the player")
-@@ -364,8 +365,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- @ReactMethod
-- fun clearNowPlayingMetadata(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun clearNowPlayingMetadata(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- if (musicService.tracks.isEmpty())
- callback.reject("no_current_item", "There is no current item in the player")
-@@ -375,16 +376,16 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- @ReactMethod
-- fun removeUpcomingTracks(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun removeUpcomingTracks(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.removeUpcomingTracks()
- callback.resolve(null)
- }
-
- @ReactMethod
-- fun skip(index: Int, initialTime: Float, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun skip(index: Int, initialTime: Float, callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.skip(index)
-
-@@ -396,8 +397,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- @ReactMethod
-- fun skipToNext(initialTime: Float, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun skipToNext(initialTime: Float, callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.skipToNext()
-
-@@ -409,8 +410,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- @ReactMethod
-- fun skipToPrevious(initialTime: Float, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun skipToPrevious(initialTime: Float, callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.skipToPrevious()
-
-@@ -422,8 +423,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- @ReactMethod
-- fun reset(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun reset(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.stop()
- delay(300) // Allow playback to stop
-@@ -433,116 +434,116 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- @ReactMethod
-- fun play(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun play(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.play()
- callback.resolve(null)
- }
-
- @ReactMethod
-- fun pause(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun pause(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.pause()
- callback.resolve(null)
- }
-
- @ReactMethod
-- fun stop(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun stop(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.stop()
- callback.resolve(null)
- }
-
- @ReactMethod
-- fun seekTo(seconds: Float, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun seekTo(seconds: Float, callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.seekTo(seconds)
- callback.resolve(null)
- }
-
- @ReactMethod
-- fun seekBy(offset: Float, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun seekBy(offset: Float, callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.seekBy(offset)
- callback.resolve(null)
- }
-
- @ReactMethod
-- fun retry(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun retry(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.retry()
- callback.resolve(null)
- }
-
- @ReactMethod
-- fun setVolume(volume: Float, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun setVolume(volume: Float, callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.setVolume(volume)
- callback.resolve(null)
- }
-
- @ReactMethod
-- fun getVolume(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun getVolume(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- callback.resolve(musicService.getVolume())
- }
-
- @ReactMethod
-- fun setRate(rate: Float, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun setRate(rate: Float, callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.setRate(rate)
- callback.resolve(null)
- }
-
- @ReactMethod
-- fun getRate(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun getRate(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- callback.resolve(musicService.getRate())
- }
-
- @ReactMethod
-- fun setRepeatMode(mode: Int, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun setRepeatMode(mode: Int, callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.setRepeatMode(RepeatMode.fromOrdinal(mode))
- callback.resolve(null)
- }
-
- @ReactMethod
-- fun getRepeatMode(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun getRepeatMode(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- callback.resolve(musicService.getRepeatMode().ordinal)
- }
-
- @ReactMethod
-- fun setPlayWhenReady(playWhenReady: Boolean, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun setPlayWhenReady(playWhenReady: Boolean, callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- musicService.playWhenReady = playWhenReady
- callback.resolve(null)
- }
-
- @ReactMethod
-- fun getPlayWhenReady(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun getPlayWhenReady(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- callback.resolve(musicService.playWhenReady)
- }
-
- @ReactMethod
-- fun getTrack(index: Int, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun getTrack(index: Int, callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- if (index >= 0 && index < musicService.tracks.size) {
- callback.resolve(Arguments.fromBundle(musicService.tracks[index].originalItem))
-@@ -552,15 +553,15 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- @ReactMethod
-- fun getQueue(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun getQueue(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- callback.resolve(Arguments.fromList(musicService.tracks.map { it.originalItem }))
- }
-
- @ReactMethod
-- fun setQueue(data: ReadableArray?, callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun setQueue(data: ReadableArray?, callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- try {
- musicService.clear()
-@@ -572,16 +573,16 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- @ReactMethod
-- fun getActiveTrackIndex(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun getActiveTrackIndex(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
- callback.resolve(
- if (musicService.tracks.isEmpty()) null else musicService.getCurrentTrackIndex()
- )
- }
-
- @ReactMethod
-- fun getActiveTrack(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun getActiveTrack(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
- callback.resolve(
- if (musicService.tracks.isEmpty()) null
- else Arguments.fromBundle(
-@@ -591,29 +592,29 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- @ReactMethod
-- fun getDuration(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun getDuration(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- callback.resolve(musicService.getDurationInSeconds())
- }
-
- @ReactMethod
-- fun getBufferedPosition(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun getBufferedPosition(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- callback.resolve(musicService.getBufferedPositionInSeconds())
- }
-
- @ReactMethod
-- fun getPosition(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun getPosition(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
-
- callback.resolve(musicService.getPositionInSeconds())
- }
-
- @ReactMethod
-- fun getProgress(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun getProgress(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
- var bundle = Bundle()
- bundle.putDouble("duration", musicService.getDurationInSeconds());
- bundle.putDouble("position", musicService.getPositionInSeconds());
-@@ -622,8 +623,13 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
- }
-
- @ReactMethod
-- fun getPlaybackState(callback: Promise) = scope.launch {
-- if (verifyServiceBoundOrReject(callback)) return@launch
-+ fun getPlaybackState(callback: Promise) = launchInScope{
-+ if (verifyServiceBoundOrReject(callback)) return@launchInScope
- callback.resolve(Arguments.fromBundle(musicService.getPlayerStateBundle(musicService.state)))
- }
-+ private fun launchInScope(block: suspend () -> Unit) {
-+ scope.launch {
-+ block()
-+ }
-+ }
- }
-diff --git a/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt b/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt
-index 9d6d869..ededffd 100644
---- a/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt
-+++ b/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt
-@@ -120,9 +120,14 @@ class MusicService : HeadlessJsTaskService() {
- notificationBuilder.foregroundServiceBehavior = NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE
- }
- val notification = notificationBuilder.build()
-- startForeground(EMPTY_NOTIFICATION_ID, notification)
-- @Suppress("DEPRECATION")
-- stopForeground(true)
-+ try{
-+
-+ startForeground(EMPTY_NOTIFICATION_ID, notification)
-+ @Suppress("DEPRECATION")
-+ stopForeground(true)
-+ } catch (e: Exception) {
-+ Timber.e(e, "Failed to start foreground service")
-+ }
- }
-
- @MainThread
-@@ -761,7 +766,7 @@ class MusicService : HeadlessJsTaskService() {
- }
-
- @MainThread
-- override fun onBind(intent: Intent?): IBinder {
-+ override fun onBind(intent: Intent): IBinder {
- return binder
- }
-
-diff --git a/node_modules/react-native-track-player/ios/RNTrackPlayer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/node_modules/react-native-track-player/ios/RNTrackPlayer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
-deleted file mode 100644
-index 18d9810..0000000
---- a/node_modules/react-native-track-player/ios/RNTrackPlayer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
-+++ /dev/null
-@@ -1,8 +0,0 @@
--
--
--
--
-- IDEDidComputeMac32BitWarning
--
--
--
-diff --git a/node_modules/react-native-track-player/ios/RNTrackPlayer.xcodeproj/project.xcworkspace/xcuserdata/dcvz.xcuserdatad/UserInterfaceState.xcuserstate b/node_modules/react-native-track-player/ios/RNTrackPlayer.xcodeproj/project.xcworkspace/xcuserdata/dcvz.xcuserdatad/UserInterfaceState.xcuserstate
-deleted file mode 100644
-index 4a18e92..0000000
-Binary files a/node_modules/react-native-track-player/ios/RNTrackPlayer.xcodeproj/project.xcworkspace/xcuserdata/dcvz.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ
-diff --git a/node_modules/react-native-track-player/ios/RNTrackPlayer.xcodeproj/xcuserdata/dcvz.xcuserdatad/xcschemes/xcschememanagement.plist b/node_modules/react-native-track-player/ios/RNTrackPlayer.xcodeproj/xcuserdata/dcvz.xcuserdatad/xcschemes/xcschememanagement.plist
-deleted file mode 100644
-index b70cd96..0000000
---- a/node_modules/react-native-track-player/ios/RNTrackPlayer.xcodeproj/xcuserdata/dcvz.xcuserdatad/xcschemes/xcschememanagement.plist
-+++ /dev/null
-@@ -1,14 +0,0 @@
--
--
--
--
-- SchemeUserState
--
-- RNTrackPlayer.xcscheme_^#shared#^_
--
-- orderHint
-- 0
--
--
--
--
-diff --git a/node_modules/react-native-track-player/ios/RNTrackPlayer/RNTrackPlayerBridge.m b/node_modules/react-native-track-player/ios/RNTrackPlayer/RNTrackPlayerBridge.m
-index 7741994..40f161c 100644
---- a/node_modules/react-native-track-player/ios/RNTrackPlayer/RNTrackPlayerBridge.m
-+++ b/node_modules/react-native-track-player/ios/RNTrackPlayer/RNTrackPlayerBridge.m
-@@ -151,17 +151,17 @@ @interface RCT_EXTERN_REMAP_MODULE(TrackPlayerModule, RNTrackPlayer, NSObject)
- resolver:(RCTPromiseResolveBlock)resolve
- rejecter:(RCTPromiseRejectBlock)reject);
-
--RCT_EXTERN_METHOD(getSleepTimerProgress:(RCTPromiseResolveBlock)resolve
-- rejecter:(RCTPromiseRejectBlock)reject);
-+// RCT_EXTERN_METHOD(getSleepTimerProgress:(RCTPromiseResolveBlock)resolve
-+// rejecter:(RCTPromiseRejectBlock)reject);
-
--RCT_EXTERN_METHOD(setSleepTimer:(double)time
-- resolver:(RCTPromiseResolveBlock)resolve
-- rejecter:(RCTPromiseRejectBlock)reject);
-+// RCT_EXTERN_METHOD(setSleepTimer:(double)time
-+// resolver:(RCTPromiseResolveBlock)resolve
-+// rejecter:(RCTPromiseRejectBlock)reject);
-
--RCT_EXTERN_METHOD(sleepWhenActiveTrackReachesEnd:(RCTPromiseResolveBlock)resolve
-- rejecter:(RCTPromiseRejectBlock)reject);
-+// RCT_EXTERN_METHOD(sleepWhenActiveTrackReachesEnd:(RCTPromiseResolveBlock)resolve
-+// rejecter:(RCTPromiseRejectBlock)reject);
-
--RCT_EXTERN_METHOD(clearSleepTimer:(RCTPromiseResolveBlock)resolve
-- rejecter:(RCTPromiseRejectBlock)reject);
-+// RCT_EXTERN_METHOD(clearSleepTimer:(RCTPromiseResolveBlock)resolve
-+// rejecter:(RCTPromiseRejectBlock)reject);
-
- @end
-diff --git a/node_modules/react-native-track-player/lib/src/trackPlayer.d.ts b/node_modules/react-native-track-player/lib/src/trackPlayer.d.ts
-index 574f7ea..8a6d0a9 100644
---- a/node_modules/react-native-track-player/lib/src/trackPlayer.d.ts
-+++ b/node_modules/react-native-track-player/lib/src/trackPlayer.d.ts
-@@ -137,13 +137,13 @@ export declare function pause(): Promise;
- */
- export declare function stop(): Promise;
- /**
-- * Sets wether the player will play automatically when it is ready to do so.
-+ * Sets whether the player will play automatically when it is ready to do so.
- * This is the equivalent of calling `TrackPlayer.play()` when `playWhenReady = true`
- * or `TrackPlayer.pause()` when `playWhenReady = false`.
- */
- export declare function setPlayWhenReady(playWhenReady: boolean): Promise;
- /**
-- * Gets wether the player will play automatically when it is ready to do so.
-+ * Gets whether the player will play automatically when it is ready to do so.
- */
- export declare function getPlayWhenReady(): Promise;
- /**
-diff --git a/node_modules/react-native-track-player/lib/src/trackPlayer.js b/node_modules/react-native-track-player/lib/src/trackPlayer.js
-index 250cdbb..191e5de 100644
---- a/node_modules/react-native-track-player/lib/src/trackPlayer.js
-+++ b/node_modules/react-native-track-player/lib/src/trackPlayer.js
-@@ -201,7 +201,7 @@ export async function stop() {
- return TrackPlayer.stop();
- }
- /**
-- * Sets wether the player will play automatically when it is ready to do so.
-+ * Sets whether the player will play automatically when it is ready to do so.
- * This is the equivalent of calling `TrackPlayer.play()` when `playWhenReady = true`
- * or `TrackPlayer.pause()` when `playWhenReady = false`.
- */
-@@ -209,7 +209,7 @@ export async function setPlayWhenReady(playWhenReady) {
- return TrackPlayer.setPlayWhenReady(playWhenReady);
- }
- /**
-- * Gets wether the player will play automatically when it is ready to do so.
-+ * Gets whether the player will play automatically when it is ready to do so.
- */
- export async function getPlayWhenReady() {
- return TrackPlayer.getPlayWhenReady();
-diff --git a/node_modules/react-native-track-player/lib/web/TrackPlayer/Player.js b/node_modules/react-native-track-player/lib/web/TrackPlayer/Player.js
-index 76a5241..2d87015 100644
---- a/node_modules/react-native-track-player/lib/web/TrackPlayer/Player.js
-+++ b/node_modules/react-native-track-player/lib/web/TrackPlayer/Player.js
-@@ -34,10 +34,10 @@ export class Player {
- return;
- if (this.hasInitialized === true) {
- // TODO: double check the structure of this error message
-- throw { code: 'player_already_initialized', message: 'The player is not initialized. Call setupPlayer first.' };
-+ throw { code: 'player_already_initialized', message: 'The player has already been initialized via setupPlayer.' };
- }
- // @ts-ignore
-- const shaka = await import('shaka-player/dist/shaka-player.ui');
-+ const shaka = (await import('shaka-player/dist/shaka-player.ui')).default;
- // Install built-in polyfills to patch browser incompatibilities.
- shaka.polyfill.installAll();
- // Check to see if the browser supports the basic APIs Shaka needs.
-diff --git a/node_modules/react-native-track-player/lib/web/TrackPlayer/PlaylistPlayer.js b/node_modules/react-native-track-player/lib/web/TrackPlayer/PlaylistPlayer.js
-index b36ad21..67b34a4 100644
---- a/node_modules/react-native-track-player/lib/web/TrackPlayer/PlaylistPlayer.js
-+++ b/node_modules/react-native-track-player/lib/web/TrackPlayer/PlaylistPlayer.js
-@@ -24,6 +24,9 @@ export class PlaylistPlayer extends Player {
- if (this.currentIndex === this.playlist.length - 1) {
- await this.goToIndex(0);
- }
-+ else {
-+ await this.skipToNext();
-+ }
- break;
- default:
- try {
-@@ -64,7 +67,7 @@ export class PlaylistPlayer extends Player {
- }
- }
- async add(tracks, insertBeforeIndex) {
-- if (insertBeforeIndex) {
-+ if (insertBeforeIndex !== -1 && insertBeforeIndex !== undefined) {
- this.playlist.splice(insertBeforeIndex, 0, ...tracks);
- }
- else {
-diff --git a/node_modules/react-native-track-player/lib/web/TrackPlayerModule.d.ts b/node_modules/react-native-track-player/lib/web/TrackPlayerModule.d.ts
-index 6766a2a..33d40af 100644
---- a/node_modules/react-native-track-player/lib/web/TrackPlayerModule.d.ts
-+++ b/node_modules/react-native-track-player/lib/web/TrackPlayerModule.d.ts
-@@ -51,6 +51,7 @@ export declare class TrackPlayerModule extends PlaylistPlayer {
- setPlayWhenReady(pwr: boolean): boolean;
- load(track: Track): Promise;
- getQueue(): Track[];
-+ setQueue(queue: Track[]): Promise;
- getActiveTrack(): Track | undefined;
- getActiveTrackIndex(): number | undefined;
- /**
-diff --git a/node_modules/react-native-track-player/lib/web/TrackPlayerModule.js b/node_modules/react-native-track-player/lib/web/TrackPlayerModule.js
-index 1f10a40..08c7d3c 100644
---- a/node_modules/react-native-track-player/lib/web/TrackPlayerModule.js
-+++ b/node_modules/react-native-track-player/lib/web/TrackPlayerModule.js
-@@ -126,6 +126,10 @@ export class TrackPlayerModule extends PlaylistPlayer {
- getQueue() {
- return this.playlist;
- }
-+ async setQueue(queue) {
-+ await this.stop();
-+ this.playlist = queue;
-+ }
- getActiveTrack() {
- return this.current;
- }
-diff --git a/node_modules/react-native-track-player/src/trackPlayer.ts b/node_modules/react-native-track-player/src/trackPlayer.ts
-index 340c1b1..6f6d723 100644
---- a/node_modules/react-native-track-player/src/trackPlayer.ts
-+++ b/node_modules/react-native-track-player/src/trackPlayer.ts
-@@ -312,7 +312,7 @@ export async function stop(): Promise {
- }
-
- /**
-- * Sets wether the player will play automatically when it is ready to do so.
-+ * Sets whether the player will play automatically when it is ready to do so.
- * This is the equivalent of calling `TrackPlayer.play()` when `playWhenReady = true`
- * or `TrackPlayer.pause()` when `playWhenReady = false`.
- */
-@@ -323,7 +323,7 @@ export async function setPlayWhenReady(
- }
-
- /**
-- * Gets wether the player will play automatically when it is ready to do so.
-+ * Gets whether the player will play automatically when it is ready to do so.
- */
- export async function getPlayWhenReady(): Promise {
- return TrackPlayer.getPlayWhenReady();
-diff --git a/node_modules/react-native-track-player/web/TrackPlayer/Player.ts b/node_modules/react-native-track-player/web/TrackPlayer/Player.ts
-index e537c2a..1a0bc6d 100644
---- a/node_modules/react-native-track-player/web/TrackPlayer/Player.ts
-+++ b/node_modules/react-native-track-player/web/TrackPlayer/Player.ts
-@@ -39,11 +39,11 @@ export class Player {
- if (typeof window === 'undefined') return;
- if (this.hasInitialized === true) {
- // TODO: double check the structure of this error message
-- throw { code: 'player_already_initialized', message: 'The player is not initialized. Call setupPlayer first.' };
-+ throw { code: 'player_already_initialized', message: 'The player has already been initialized via setupPlayer.' };
- }
-
- // @ts-ignore
-- const shaka = await import('shaka-player/dist/shaka-player.ui');
-+ const shaka = (await import('shaka-player/dist/shaka-player.ui')).default;
- // Install built-in polyfills to patch browser incompatibilities.
- shaka.polyfill.installAll();
- // Check to see if the browser supports the basic APIs Shaka needs.
-diff --git a/node_modules/react-native-track-player/web/TrackPlayer/PlaylistPlayer.ts b/node_modules/react-native-track-player/web/TrackPlayer/PlaylistPlayer.ts
-index b2d6697..7eeae71 100644
---- a/node_modules/react-native-track-player/web/TrackPlayer/PlaylistPlayer.ts
-+++ b/node_modules/react-native-track-player/web/TrackPlayer/PlaylistPlayer.ts
-@@ -29,6 +29,8 @@ export class PlaylistPlayer extends Player {
- case RepeatMode.Playlist:
- if (this.currentIndex === this.playlist.length - 1) {
- await this.goToIndex(0);
-+ } else {
-+ await this.skipToNext();
- }
- break;
- default:
-@@ -38,7 +40,6 @@ export class PlaylistPlayer extends Player {
- if ((err as Error).message !== 'playlist_exhausted') {
- throw err;
- }
--
- this.onPlaylistEnded();
- }
- break;
-@@ -79,7 +80,7 @@ export class PlaylistPlayer extends Player {
- }
-
- public async add(tracks: Track[], insertBeforeIndex?: number) {
-- if (insertBeforeIndex) {
-+ if (insertBeforeIndex !== -1 && insertBeforeIndex !== undefined) {
- this.playlist.splice(insertBeforeIndex, 0, ...tracks);
- } else {
- this.playlist.push(...tracks);
-diff --git a/node_modules/react-native-track-player/web/TrackPlayerModule.ts b/node_modules/react-native-track-player/web/TrackPlayerModule.ts
-index 9d198a1..6150e2b 100644
---- a/node_modules/react-native-track-player/web/TrackPlayerModule.ts
-+++ b/node_modules/react-native-track-player/web/TrackPlayerModule.ts
-@@ -152,6 +152,11 @@ export class TrackPlayerModule extends PlaylistPlayer {
- return this.playlist;
- }
-
-+ public async setQueue(queue: Track[]) {
-+ await this.stop();
-+ this.playlist = queue;
-+ }
-+
- public getActiveTrack(): Track | undefined {
- return this.current;
- }
diff --git a/src/api/queries/recents.ts b/src/api/queries/recents.ts
index 527f4e2f..207607ef 100644
--- a/src/api/queries/recents.ts
+++ b/src/api/queries/recents.ts
@@ -28,6 +28,12 @@ export async function fetchRecentlyAdded(
})
}
+/**
+ * Fetches recently played tracks for a user from the Jellyfin server.
+ * @param limit The number of items to fetch. Defaults to 50
+ * @param offset The offset of the items to fetch.
+ * @returns The recently played items.
+ */
export async function fetchRecentlyPlayed(
limit: number = QueryConfig.limits.recents,
offset?: number | undefined,
@@ -56,6 +62,13 @@ export async function fetchRecentlyPlayed(
})
}
+/**
+ * Fetches recently played artists for a user from the Jellyfin server,
+ * referencing the recently played tracks.
+ * @param limit The number of items to fetch. Defaults to 50
+ * @param offset The offset of the items to fetch.
+ * @returns The recently played artists.
+ */
export function fetchRecentlyPlayedArtists(
limit: number = QueryConfig.limits.recents,
offset?: number | undefined,
diff --git a/src/components/Album/index.tsx b/src/components/Album/index.tsx
index 33066f44..097035c6 100644
--- a/src/components/Album/index.tsx
+++ b/src/components/Album/index.tsx
@@ -82,7 +82,7 @@ function AlbumTrackListHeader(
return (
-
+
@@ -91,7 +91,8 @@ function AlbumTrackListHeader(
lineBreakStrategyIOS='standard'
textAlign='center'
numberOfLines={5}
- maxWidth={width / 2}
+ minWidth={width / 2.25}
+ maxWidth={width / 2.25}
>
{album.Name ?? 'Untitled Album'}
diff --git a/src/components/Global/components/blurhashed-image.tsx b/src/components/Global/components/blurhashed-image.tsx
deleted file mode 100644
index 2c14f57c..00000000
--- a/src/components/Global/components/blurhashed-image.tsx
+++ /dev/null
@@ -1,108 +0,0 @@
-import { BaseItemDto, ImageType } from '@jellyfin/sdk/lib/generated-client/models'
-import { Blurhash } from 'react-native-blurhash'
-import { Square, View } from 'tamagui'
-import { isEmpty } from 'lodash'
-import { Image } from 'react-native'
-import { QueryKeys } from '../../../enums/query-keys'
-import { useQuery } from '@tanstack/react-query'
-import { fetchItemImage } from '../../../api/queries/images'
-
-interface BlurhashLoadingProps {
- item: BaseItemDto
- width: number
- height?: number
- type?: ImageType
- borderRadius?: number | undefined
-}
-
-/**
- * @deprecated
- *
- * Please use the `Image` component from
- * the `expo-image` module instead, as that is more performant
- *
- * A React component that will render a Blurhash
- * string as an image while loading the full image
- * from the server
- *
- * Image Query is stale after 30 minutes and collected
- * after an hour to keep the cache size down and the
- * app performant
- *
- * TODO: Keep images in offline mode
- *
- * @param param0
- * @returns
- */
-export default function BlurhashedImage({
- item,
- width,
- height,
- type,
- borderRadius,
-}: BlurhashLoadingProps): React.JSX.Element {
- const { data: image, isSuccess } = useQuery({
- queryKey: [
- QueryKeys.ItemImage,
- item.AlbumId ? item.AlbumId : item.Id!,
- type ?? ImageType.Primary,
- Math.ceil(width / 100) * 100, // Images are fetched at a higher, generic resolution
- Math.ceil(height ?? width / 100) * 100, // So these keys need to match
- ],
- queryFn: () =>
- fetchItemImage(
- item.AlbumId ? item.AlbumId : item.Id!,
- type ?? ImageType.Primary,
- width,
- height ?? width,
- ),
- staleTime: 1000 * 60 * 30, // 30 minutes
- gcTime: 1000 * 60 * 60, // 1 hour
- refetchOnMount: false,
- refetchOnWindowFocus: false,
- })
-
- const blurhash =
- !isEmpty(item.ImageBlurHashes) &&
- !isEmpty(type ? item.ImageBlurHashes[type] : item.ImageBlurHashes.Primary)
- ? Object.values(type ? item.ImageBlurHashes[type]! : item.ImageBlurHashes.Primary!)[0]
- : undefined
-
- return (
-
- {isSuccess ? (
-
- ) : blurhash ? (
-
- ) : (
-
- )}
-
- )
-}
diff --git a/src/components/Global/components/image.tsx b/src/components/Global/components/image.tsx
index fb37ee00..c78c5314 100644
--- a/src/components/Global/components/image.tsx
+++ b/src/components/Global/components/image.tsx
@@ -4,13 +4,13 @@ import { getImageApi } from '@jellyfin/sdk/lib/utils/api'
import { isUndefined } from 'lodash'
import { StyleProp } from 'react-native'
import FastImage, { ImageStyle } from 'react-native-fast-image'
-import { FontSizeTokens, getToken, getTokenValue } from 'tamagui'
+import { FontSizeTokens, getFontSizeToken, getToken, getTokenValue, Token } from 'tamagui'
interface ImageProps {
item: BaseItemDto
circular?: boolean | undefined
- width?: FontSizeTokens | undefined
- height?: FontSizeTokens | undefined
+ width?: Token | undefined
+ height?: Token | undefined
style?: ImageStyle | undefined
}
@@ -25,16 +25,34 @@ export default function ItemImage({
)
}
+
+/**
+ * Get the border radius for the image
+ * @param circular - Whether the image is circular
+ * @param width - The width of the image
+ * @returns The border radius of the image
+ */
+function getBorderRadius(circular: boolean | undefined, width: Token | undefined): number {
+ let borderRadius
+
+ if (circular) {
+ borderRadius = width ? getTokenValue(width) : getTokenValue('$12') + getToken('$5')
+ } else if (!isUndefined(width)) {
+ borderRadius = getTokenValue(width) / 10
+ }
+
+ return borderRadius
+}
diff --git a/src/components/Global/components/item.tsx b/src/components/Global/components/item.tsx
index 42c50599..77d19c0b 100644
--- a/src/components/Global/components/item.tsx
+++ b/src/components/Global/components/item.tsx
@@ -4,12 +4,12 @@ import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { getTokens, Separator, Spacer, View, XStack, YStack } from 'tamagui'
import { Text } from '../helpers/text'
import { useSafeAreaFrame } from 'react-native-safe-area-context'
-import BlurhashedImage from './blurhashed-image'
import Icon from '../helpers/icon'
import { QueuingType } from '../../../enums/queuing-type'
import { RunTimeTicks } from '../helpers/time-codes'
import { useQueueContext } from '../../../player/queue-provider'
import { usePlayerContext } from '../../../player/player-provider'
+import ItemImage from './image'
export default function Item({
item,
@@ -75,11 +75,9 @@ export default function Item({
paddingVertical={'$2'}
marginHorizontal={'$1'}
>
-
+
+
+
-
+
{item.UserData?.IsFavorite ? (
) : (
diff --git a/src/components/InstantMix/component.tsx b/src/components/InstantMix/component.tsx
index c088f64c..f849065f 100644
--- a/src/components/InstantMix/component.tsx
+++ b/src/components/InstantMix/component.tsx
@@ -1,7 +1,6 @@
import { InstantMixProps } from '../types'
import { FlatList } from 'react-native'
import Track from '../Global/components/track'
-import ItemImage from '../Global/components/image'
import { Separator } from 'tamagui'
export default function InstantMix({ route, navigation }: InstantMixProps): React.JSX.Element {
@@ -10,7 +9,6 @@ export default function InstantMix({ route, navigation }: InstantMixProps): Reac
return (
}
ItemSeparatorComponent={() => }
renderItem={({ item, index }) => (