Upgrade all dependencies

(1) react-native-track-player to v2
(2) react-navigation to v6
(3) react-native to v0.66.4
This commit is contained in:
Lei Nelissen
2021-12-31 15:04:37 +01:00
parent 6440c1ac7b
commit 9668ba9c7c
28 changed files with 21769 additions and 5659 deletions

200
android/gradlew.bat vendored
View File

@@ -1,100 +1,100 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -6,8 +6,10 @@ import { name as appName } from './app.json';
import PlaybackService from './src/utility/PlaybackService';
import { setupSentry } from 'utility/Sentry';
import { enableScreens } from 'react-native-screens';
import { patchTrackPlayer } from 'utility/AddedTrackEvents';
setupSentry();
enableScreens();
patchTrackPlayer();
AppRegistry.registerComponent(appName, () => App);
TrackPlayer.registerPlaybackService(() => PlaybackService);

View File

@@ -179,7 +179,7 @@
00E356EB1AD99517003FC87E /* Frameworks */,
00E356EC1AD99517003FC87E /* Resources */,
BDE784ECF29EF861DBFF49D7 /* [CP] Copy Pods Resources */,
476A07969B11CA4E09819AC0 /* [CP] Embed Pods Frameworks */,
A02366876E56A727F566EC3A /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -203,7 +203,7 @@
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
B9FB8FC65CEFF9AFAC71127E /* [CP] Copy Pods Resources */,
1DC46C84C90B4D84A18AC142 /* Upload Debug Symbols to Sentry */,
E8FF56077B675D4D92D5CC25 /* [CP] Embed Pods Frameworks */,
2917566AA57EE087FC9FCCE9 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -305,7 +305,27 @@
shellPath = /bin/sh;
shellScript = "export SENTRY_PROPERTIES=sentry.properties\n../node_modules/@sentry/cli/bin/sentry-cli upload-dsym";
};
476A07969B11CA4E09819AC0 /* [CP] Embed Pods Frameworks */ = {
2917566AA57EE087FC9FCCE9 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-JellyfinAudioPlayer/Pods-JellyfinAudioPlayer-frameworks.sh",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/double-conversion.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-JellyfinAudioPlayer/Pods-JellyfinAudioPlayer-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
A02366876E56A727F566EC3A /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -405,26 +425,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
E8FF56077B675D4D92D5CC25 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-JellyfinAudioPlayer/Pods-JellyfinAudioPlayer-frameworks.sh",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/double-conversion.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-JellyfinAudioPlayer/Pods-JellyfinAudioPlayer-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
FD10A7F022414F080027D42C /* Start Packager */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -503,6 +503,10 @@
INFOPLIST_FILE = JellyfinAudioPlayerTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(SDKROOT)/usr/lib/swift",
"$(inherited)",
);
OTHER_LDFLAGS = (
"-ObjC",
"-lc++",
@@ -526,6 +530,10 @@
INFOPLIST_FILE = JellyfinAudioPlayerTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(SDKROOT)/usr/lib/swift",
"$(inherited)",
);
OTHER_LDFLAGS = (
"-ObjC",
"-lc++",
@@ -555,6 +563,10 @@
);
INFOPLIST_FILE = JellyfinAudioPlayer/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(SDKROOT)/usr/lib/swift",
"$(inherited)",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -581,6 +593,10 @@
DEVELOPMENT_TEAM = 238P3C58WC;
INFOPLIST_FILE = JellyfinAudioPlayer/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(SDKROOT)/usr/lib/swift",
"$(inherited)",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -629,7 +645,7 @@
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
@@ -648,6 +664,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
LIBRARY_SEARCH_PATHS = (
"$(SDKROOT)/usr/lib/swift",
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
"\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
"\"$(inherited)\"",
@@ -692,7 +709,7 @@
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@@ -704,6 +721,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
LIBRARY_SEARCH_PATHS = (
"$(SDKROOT)/usr/lib/swift",
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
"\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
"\"$(inherited)\"",

View File

@@ -1,24 +1,38 @@
platform :ios, '11.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
platform :ios, '12.0'
target 'JellyfinAudioPlayer' do
config = use_native_modules!
use_react_native!(:path => config["reactNativePath"])
use_react_native!(
:path => config[:reactNativePath],
# to enable hermes on iOS, change `false` to `true` and then install pods
:hermes_enabled => false
)
target 'JellyfinAudioPlayerTests' do
inherit! :complete
# Pods for testing
end
# Enables Flipper.
#
# Note that if you have use_frameworks! enabled, Flipper will not work and
# you should disable these next few lines.
use_flipper!
# you should disable the next line.
use_flipper!()
post_install do |installer|
flipper_post_install(installer)
installer.pods_project.build_configurations.each do |config|
config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
react_native_post_install(installer)
__apply_Xcode_12_5_M1_post_install_workaround(installer)
installer.aggregate_targets.each do |aggregate_target|
aggregate_target.user_project.native_targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['LIBRARY_SEARCH_PATHS'] = ['$(SDKROOT)/usr/lib/swift', '$(inherited)']
end
end
aggregate_target.user_project.save
end
end
end

View File

@@ -2,14 +2,14 @@ PODS:
- boost (1.76.0)
- CocoaAsyncSocket (7.6.5)
- DoubleConversion (1.1.6)
- FBLazyVector (0.66.1)
- FBReactNativeSpec (0.66.1):
- FBLazyVector (0.66.4)
- FBReactNativeSpec (0.66.4):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.66.1)
- RCTTypeSafety (= 0.66.1)
- React-Core (= 0.66.1)
- React-jsi (= 0.66.1)
- ReactCommon/turbomodule/core (= 0.66.1)
- RCTRequired (= 0.66.4)
- RCTTypeSafety (= 0.66.4)
- React-Core (= 0.66.4)
- React-jsi (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- Flipper (0.99.0):
- Flipper-Folly (~> 2.6)
- Flipper-RSocket (~> 1.4)
@@ -94,268 +94,269 @@ PODS:
- DoubleConversion
- fmt (~> 6.2.1)
- glog
- RCTRequired (0.66.1)
- RCTTypeSafety (0.66.1):
- FBLazyVector (= 0.66.1)
- RCTRequired (0.66.4)
- RCTTypeSafety (0.66.4):
- FBLazyVector (= 0.66.4)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.66.1)
- React-Core (= 0.66.1)
- React (0.66.1):
- React-Core (= 0.66.1)
- React-Core/DevSupport (= 0.66.1)
- React-Core/RCTWebSocket (= 0.66.1)
- React-RCTActionSheet (= 0.66.1)
- React-RCTAnimation (= 0.66.1)
- React-RCTBlob (= 0.66.1)
- React-RCTImage (= 0.66.1)
- React-RCTLinking (= 0.66.1)
- React-RCTNetwork (= 0.66.1)
- React-RCTSettings (= 0.66.1)
- React-RCTText (= 0.66.1)
- React-RCTVibration (= 0.66.1)
- React-callinvoker (0.66.1)
- React-Core (0.66.1):
- RCTRequired (= 0.66.4)
- React-Core (= 0.66.4)
- React (0.66.4):
- React-Core (= 0.66.4)
- React-Core/DevSupport (= 0.66.4)
- React-Core/RCTWebSocket (= 0.66.4)
- React-RCTActionSheet (= 0.66.4)
- React-RCTAnimation (= 0.66.4)
- React-RCTBlob (= 0.66.4)
- React-RCTImage (= 0.66.4)
- React-RCTLinking (= 0.66.4)
- React-RCTNetwork (= 0.66.4)
- React-RCTSettings (= 0.66.4)
- React-RCTText (= 0.66.4)
- React-RCTVibration (= 0.66.4)
- React-callinvoker (0.66.4)
- React-Core (0.66.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.66.1)
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsiexecutor (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-Core/Default (= 0.66.4)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsiexecutor (= 0.66.4)
- React-perflogger (= 0.66.4)
- Yoga
- React-Core/CoreModulesHeaders (0.66.1):
- React-Core/CoreModulesHeaders (0.66.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsiexecutor (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsiexecutor (= 0.66.4)
- React-perflogger (= 0.66.4)
- Yoga
- React-Core/Default (0.66.1):
- React-Core/Default (0.66.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsiexecutor (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsiexecutor (= 0.66.4)
- React-perflogger (= 0.66.4)
- Yoga
- React-Core/DevSupport (0.66.1):
- React-Core/DevSupport (0.66.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.66.1)
- React-Core/RCTWebSocket (= 0.66.1)
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsiexecutor (= 0.66.1)
- React-jsinspector (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-Core/Default (= 0.66.4)
- React-Core/RCTWebSocket (= 0.66.4)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsiexecutor (= 0.66.4)
- React-jsinspector (= 0.66.4)
- React-perflogger (= 0.66.4)
- Yoga
- React-Core/RCTActionSheetHeaders (0.66.1):
- React-Core/RCTActionSheetHeaders (0.66.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsiexecutor (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsiexecutor (= 0.66.4)
- React-perflogger (= 0.66.4)
- Yoga
- React-Core/RCTAnimationHeaders (0.66.1):
- React-Core/RCTAnimationHeaders (0.66.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsiexecutor (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsiexecutor (= 0.66.4)
- React-perflogger (= 0.66.4)
- Yoga
- React-Core/RCTBlobHeaders (0.66.1):
- React-Core/RCTBlobHeaders (0.66.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsiexecutor (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsiexecutor (= 0.66.4)
- React-perflogger (= 0.66.4)
- Yoga
- React-Core/RCTImageHeaders (0.66.1):
- React-Core/RCTImageHeaders (0.66.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsiexecutor (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsiexecutor (= 0.66.4)
- React-perflogger (= 0.66.4)
- Yoga
- React-Core/RCTLinkingHeaders (0.66.1):
- React-Core/RCTLinkingHeaders (0.66.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsiexecutor (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsiexecutor (= 0.66.4)
- React-perflogger (= 0.66.4)
- Yoga
- React-Core/RCTNetworkHeaders (0.66.1):
- React-Core/RCTNetworkHeaders (0.66.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsiexecutor (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsiexecutor (= 0.66.4)
- React-perflogger (= 0.66.4)
- Yoga
- React-Core/RCTSettingsHeaders (0.66.1):
- React-Core/RCTSettingsHeaders (0.66.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsiexecutor (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsiexecutor (= 0.66.4)
- React-perflogger (= 0.66.4)
- Yoga
- React-Core/RCTTextHeaders (0.66.1):
- React-Core/RCTTextHeaders (0.66.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsiexecutor (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsiexecutor (= 0.66.4)
- React-perflogger (= 0.66.4)
- Yoga
- React-Core/RCTVibrationHeaders (0.66.1):
- React-Core/RCTVibrationHeaders (0.66.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsiexecutor (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsiexecutor (= 0.66.4)
- React-perflogger (= 0.66.4)
- Yoga
- React-Core/RCTWebSocket (0.66.1):
- React-Core/RCTWebSocket (0.66.4):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.66.1)
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsiexecutor (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-Core/Default (= 0.66.4)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsiexecutor (= 0.66.4)
- React-perflogger (= 0.66.4)
- Yoga
- React-CoreModules (0.66.1):
- FBReactNativeSpec (= 0.66.1)
- React-CoreModules (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.66.1)
- React-Core/CoreModulesHeaders (= 0.66.1)
- React-jsi (= 0.66.1)
- React-RCTImage (= 0.66.1)
- ReactCommon/turbomodule/core (= 0.66.1)
- React-cxxreact (0.66.1):
- RCTTypeSafety (= 0.66.4)
- React-Core/CoreModulesHeaders (= 0.66.4)
- React-jsi (= 0.66.4)
- React-RCTImage (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-cxxreact (0.66.4):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-callinvoker (= 0.66.1)
- React-jsi (= 0.66.1)
- React-jsinspector (= 0.66.1)
- React-logger (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-runtimeexecutor (= 0.66.1)
- React-jsi (0.66.1):
- React-callinvoker (= 0.66.4)
- React-jsi (= 0.66.4)
- React-jsinspector (= 0.66.4)
- React-logger (= 0.66.4)
- React-perflogger (= 0.66.4)
- React-runtimeexecutor (= 0.66.4)
- React-jsi (0.66.4):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsi/Default (= 0.66.1)
- React-jsi/Default (0.66.1):
- React-jsi/Default (= 0.66.4)
- React-jsi/Default (0.66.4):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsiexecutor (0.66.1):
- React-jsiexecutor (0.66.4):
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-jsinspector (0.66.1)
- React-logger (0.66.1):
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-perflogger (= 0.66.4)
- React-jsinspector (0.66.4)
- React-logger (0.66.4):
- glog
- react-native-airplay-button (1.1.0):
- React-Core
- react-native-safe-area-context (3.3.2):
- React-Core
- react-native-slider (3.0.3):
- React
- react-native-track-player (1.2.7):
- react-native-slider (4.1.12):
- React-Core
- react-native-webview (11.14.1):
- react-native-track-player (2.1.2):
- React-Core
- React-perflogger (0.66.1)
- React-RCTActionSheet (0.66.1):
- React-Core/RCTActionSheetHeaders (= 0.66.1)
- React-RCTAnimation (0.66.1):
- FBReactNativeSpec (= 0.66.1)
- SwiftAudioEx (= 0.14.5)
- react-native-webview (11.15.0):
- React-Core
- React-perflogger (0.66.4)
- React-RCTActionSheet (0.66.4):
- React-Core/RCTActionSheetHeaders (= 0.66.4)
- React-RCTAnimation (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.66.1)
- React-Core/RCTAnimationHeaders (= 0.66.1)
- React-jsi (= 0.66.1)
- ReactCommon/turbomodule/core (= 0.66.1)
- React-RCTBlob (0.66.1):
- FBReactNativeSpec (= 0.66.1)
- RCTTypeSafety (= 0.66.4)
- React-Core/RCTAnimationHeaders (= 0.66.4)
- React-jsi (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-RCTBlob (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/RCTBlobHeaders (= 0.66.1)
- React-Core/RCTWebSocket (= 0.66.1)
- React-jsi (= 0.66.1)
- React-RCTNetwork (= 0.66.1)
- ReactCommon/turbomodule/core (= 0.66.1)
- React-RCTImage (0.66.1):
- FBReactNativeSpec (= 0.66.1)
- React-Core/RCTBlobHeaders (= 0.66.4)
- React-Core/RCTWebSocket (= 0.66.4)
- React-jsi (= 0.66.4)
- React-RCTNetwork (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-RCTImage (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.66.1)
- React-Core/RCTImageHeaders (= 0.66.1)
- React-jsi (= 0.66.1)
- React-RCTNetwork (= 0.66.1)
- ReactCommon/turbomodule/core (= 0.66.1)
- React-RCTLinking (0.66.1):
- FBReactNativeSpec (= 0.66.1)
- React-Core/RCTLinkingHeaders (= 0.66.1)
- React-jsi (= 0.66.1)
- ReactCommon/turbomodule/core (= 0.66.1)
- React-RCTNetwork (0.66.1):
- FBReactNativeSpec (= 0.66.1)
- RCTTypeSafety (= 0.66.4)
- React-Core/RCTImageHeaders (= 0.66.4)
- React-jsi (= 0.66.4)
- React-RCTNetwork (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-RCTLinking (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- React-Core/RCTLinkingHeaders (= 0.66.4)
- React-jsi (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-RCTNetwork (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.66.1)
- React-Core/RCTNetworkHeaders (= 0.66.1)
- React-jsi (= 0.66.1)
- ReactCommon/turbomodule/core (= 0.66.1)
- React-RCTSettings (0.66.1):
- FBReactNativeSpec (= 0.66.1)
- RCTTypeSafety (= 0.66.4)
- React-Core/RCTNetworkHeaders (= 0.66.4)
- React-jsi (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-RCTSettings (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.66.1)
- React-Core/RCTSettingsHeaders (= 0.66.1)
- React-jsi (= 0.66.1)
- ReactCommon/turbomodule/core (= 0.66.1)
- React-RCTText (0.66.1):
- React-Core/RCTTextHeaders (= 0.66.1)
- React-RCTVibration (0.66.1):
- FBReactNativeSpec (= 0.66.1)
- RCTTypeSafety (= 0.66.4)
- React-Core/RCTSettingsHeaders (= 0.66.4)
- React-jsi (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-RCTText (0.66.4):
- React-Core/RCTTextHeaders (= 0.66.4)
- React-RCTVibration (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/RCTVibrationHeaders (= 0.66.1)
- React-jsi (= 0.66.1)
- ReactCommon/turbomodule/core (= 0.66.1)
- React-runtimeexecutor (0.66.1):
- React-jsi (= 0.66.1)
- ReactCommon/turbomodule/core (0.66.1):
- React-Core/RCTVibrationHeaders (= 0.66.4)
- React-jsi (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-runtimeexecutor (0.66.4):
- React-jsi (= 0.66.4)
- ReactCommon/turbomodule/core (0.66.4):
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-callinvoker (= 0.66.1)
- React-Core (= 0.66.1)
- React-cxxreact (= 0.66.1)
- React-jsi (= 0.66.1)
- React-logger (= 0.66.1)
- React-perflogger (= 0.66.1)
- React-callinvoker (= 0.66.4)
- React-Core (= 0.66.4)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-logger (= 0.66.4)
- React-perflogger (= 0.66.4)
- RNCAsyncStorage (1.12.1):
- React-Core
- RNCMaskedView (0.1.11):
@@ -366,11 +367,11 @@ PODS:
- React-Core
- SDWebImage (~> 5.11.1)
- SDWebImageWebPCoder (~> 0.8.4)
- RNGestureHandler (1.10.3):
- RNGestureHandler (2.1.0):
- React-Core
- RNLocalize (2.1.5):
- RNLocalize (2.1.7):
- React-Core
- RNReanimated (2.2.3):
- RNReanimated (2.3.1):
- DoubleConversion
- FBLazyVector
- FBReactNativeSpec
@@ -396,15 +397,14 @@ PODS:
- React-RCTNetwork
- React-RCTSettings
- React-RCTText
- React-RCTVibration
- ReactCommon/turbomodule/core
- Yoga
- RNScreens (3.8.0):
- RNScreens (3.10.1):
- React-Core
- React-RCTImage
- RNSentry (2.6.2):
- RNSentry (3.2.10):
- React-Core
- Sentry (= 7.1.4)
- Sentry (= 7.7.0)
- RNSVG (12.2.0):
- React-Core
- SDWebImage (5.11.1):
@@ -413,9 +413,10 @@ PODS:
- SDWebImageWebPCoder (0.8.4):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.10)
- Sentry (7.1.4):
- Sentry/Core (= 7.1.4)
- Sentry/Core (7.1.4)
- Sentry (7.7.0):
- Sentry/Core (= 7.7.0)
- Sentry/Core (7.7.0)
- SwiftAudioEx (0.14.5)
- Yoga (1.14.0)
- YogaKit (1.18.1):
- Yoga (~> 1.14)
@@ -509,6 +510,7 @@ SPEC REPOS:
- SDWebImage
- SDWebImageWebPCoder
- Sentry
- SwiftAudioEx
- YogaKit
EXTERNAL SOURCES:
@@ -607,8 +609,8 @@ SPEC CHECKSUMS:
boost: a7c83b31436843459a1961bfd74b96033dc77234
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
FBLazyVector: 500821d196c3d1bd10e7e828bc93ce075234080f
FBReactNativeSpec: 74c869e2cffa2ffec685cd1bac6788c021da6005
FBLazyVector: e5569e42a1c79ca00521846c223173a57aca1fe1
FBReactNativeSpec: fe08c1cd7e2e205718d77ad14b34957cce949b58
Flipper: 30e8eeeed6abdc98edaf32af0cda2f198be4b733
Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c
Flipper-DoubleConversion: 57ffbe81ef95306cc9e69c4aa3aeeeeb58a6a28c
@@ -624,50 +626,51 @@ SPEC CHECKSUMS:
libwebp: 98a37e597e40bfdb4c911fc98f2c53d0b12d05fc
OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b
RCT-Folly: a21c126816d8025b547704b777a2ba552f3d9fa9
RCTRequired: 3cc065b52aa18db729268b9bd78a2feffb4d0f91
RCTTypeSafety: 3c4fc37d5dea452d2ef17324db5504ec2f05083a
React: 4a00720816c52a213424442954acb7e4b724804a
React-callinvoker: 911fc6570538f3bb5c61edf9dc907c1beb4355bf
React-Core: e134d3a5d7b2a1a731589be776e20dbb14868f27
React-CoreModules: 2f8588b2aa47e7fef27125c8eaaabda963b3ac62
React-cxxreact: 8f1382538cad0cc8b8eafca6d66268828e353bea
React-jsi: 9fe1854d2c0486216acebd5db3c38b4ccb23ca0b
React-jsiexecutor: db2f6e22a534d466fc0e34e622df47d9d20bab2f
React-jsinspector: 8c0517dee5e8c70cd6c3066f20213ff7ce54f176
React-logger: bfddd3418dc1d45b77b822958f3e31422e2c179b
react-native-airplay-button: 517a0248e8d8e744a42250f67bead5175a774ece
react-native-safe-area-context: 5cf05f49df9d17261e40e518481f2e334c6cd4b5
react-native-slider: b733e17fdd31186707146debf1f04b5d94aa1a93
react-native-track-player: 878d6c66e4ae3a69f6a534c57c6c34a42e9b033f
react-native-webview: 16054e7a26009b7d5944a18e19f450e26bd4c969
React-perflogger: fcac6090a80e3d967791b4c7f1b1a017f9d4a398
React-RCTActionSheet: caf5913d9f9e605f5467206cf9d1caa6d47d7ad6
React-RCTAnimation: 6539e3bf594f6a529cd861985ba6548286ae1ead
React-RCTBlob: 6e2e999d28b15fd03ed533f164ce33e0fcde571a
React-RCTImage: c6bbb10eedb6b840c4474f2108b864173b83de15
React-RCTLinking: 8fda9bb8fdb104e78110a903a9a77754318c7d11
React-RCTNetwork: 2b26daad93830501cf14aab03eac04e304f942d3
React-RCTSettings: 89c0dcee7adb706c749383596f57c1e882a27843
React-RCTText: 71734fce8e6cb854daeb4a5eec182c303ea58473
React-RCTVibration: 6600b5eed7c0fda4a433fa1198d1cb2690151791
React-runtimeexecutor: 33a949a51bec5f8a3c9e8d8092deb259600d761e
ReactCommon: 620442811dc6f707b4bf5e3b27d4f19c12d5a821
RNCAsyncStorage: cb9a623793918c6699586281f0b51cbc38f046f9
RNCMaskedView: f127cd9652acfa31b91dcff613e07ba18b774db6
RCTRequired: 4bf86c70714490bca4bf2696148638284622644b
RCTTypeSafety: c475a7059eb77935fa53d2c17db299893f057d5d
React: f64af14e3f2c50f6f2c91a5fd250e4ff1b3c3459
React-callinvoker: b74e4ae80287780dcdf0cab262bcb581eeef56e7
React-Core: 3eb7432bad96ff1d25aebc1defbae013fee2fd0e
React-CoreModules: ad9e1fd5650e16666c57a08328df86fd7e480cb9
React-cxxreact: 02633ff398cf7e91a2c1e12590d323c4a4b8668a
React-jsi: 805c41a927d6499fb811772acb971467d9204633
React-jsiexecutor: 94ce921e1d8ce7023366873ec371f3441383b396
React-jsinspector: d0374f7509d407d2264168b6d0fad0b54e300b85
React-logger: 933f80c97c633ee8965d609876848148e3fef438
react-native-airplay-button: 90c7ba52402c8e92342003b8a1ff78dfb4357a9e
react-native-safe-area-context: 584dc04881deb49474363f3be89e4ca0e854c057
react-native-slider: 6e9b86e76cce4b9e35b3403193a6432ed07e0c81
react-native-track-player: 23dd515aacf1d36a0e522ef7fdbc55f13f26d4fb
react-native-webview: e89bf2dba26a04cda967814df3ed1be99f291233
React-perflogger: 93075d8931c32cd1fce8a98c15d2d5ccc4d891bd
React-RCTActionSheet: 7d3041e6761b4f3044a37079ddcb156575fb6d89
React-RCTAnimation: 743e88b55ac62511ae5c2e22803d4f503f2a3a13
React-RCTBlob: bee3a2f98fa7fc25c957c8643494244f74bea0a0
React-RCTImage: 19fc9e29b06cc38611c553494f8d3040bf78c24e
React-RCTLinking: dc799503979c8c711126d66328e7ce8f25c2848f
React-RCTNetwork: 417e4e34cf3c19eaa5fd4e9eb20180d662a799ce
React-RCTSettings: 4df89417265af26501a7e0e9192a34d3d9848dff
React-RCTText: f8a21c3499ab322326290fa9b701ae29aa093aa5
React-RCTVibration: e3ffca672dd3772536cb844274094b0e2c31b187
React-runtimeexecutor: dec32ee6f2e2a26e13e58152271535fadff5455a
ReactCommon: 57b69f6383eafcbd7da625bfa6003810332313c4
RNCAsyncStorage: b03032fdbdb725bea0bd9e5ec5a7272865ae7398
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
RNCPicker: 914b557e20b3b8317b084aca9ff4b4edb95f61e4
RNFastImage: 1f2cab428712a4baaf78d6169eaec7f622556dd7
RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211
RNLocalize: 13a971fd888f2933504a745983f781dc52feeab6
RNReanimated: b04ef2a4f0cb61b062bbcf033f84a9e470f4f60b
RNScreens: 6e1ea5787989f92b0671049b808aef64fa1ef98c
RNSentry: 68644ef607b780551cc555f084869764f2566652
RNGestureHandler: e5c7cab5f214503dcefd6b2b0cefb050e1f51c4a
RNLocalize: f567ea0e35116a641cdffe6683b0d212d568f32a
RNReanimated: da3860204e5660c0dd66739936732197d359d753
RNScreens: 522705f2e5c9d27efb17f24aceb2bf8335bc7b8e
RNSentry: 04bb48bfdd435f5b218cf363f89e6419e9a2460c
RNSVG: 4ecc2e8f38b6ebe7889909570c26f3abe8059767
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
SDWebImageWebPCoder: f93010f3f6c031e2f8fb3081ca4ee6966c539815
Sentry: 1d3eb1a25f8c5333c88dd5603904a6d461cd9fcf
Yoga: 2b4a01651f42a32f82e6cef3830a3ba48088237f
Sentry: e58e062056a061ae1145e22ad3dff6e506bff177
SwiftAudioEx: bfaff9894c885aded7edfb0793e25165d55053d4
Yoga: e7dc4e71caba6472ff48ad7d234389b91dadc280
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
PODFILE CHECKSUM: 640720093b3030dd16ab5dd407cf5fd8c4f7f7c8
PODFILE CHECKSUM: 41246a700cf7cc0f2e61f418d64861444b3079b1
COCOAPODS: 1.11.2

26172
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -15,61 +15,62 @@
"@react-native-community/async-storage": "^1.12.1",
"@react-native-community/masked-view": "^0.1.11",
"@react-native-community/picker": "^1.8.1",
"@react-native-community/slider": "^3.0.3",
"@react-navigation/bottom-tabs": "^5.11.15",
"@react-navigation/native": "^5.9.8",
"@react-navigation/stack": "^5.14.9",
"@reduxjs/toolkit": "^1.6.2",
"@sentry/react-native": "^2.6.2",
"@types/lodash": "^4.14.176",
"date-fns": "^2.25.0",
"fuse.js": "^6.4.6",
"@react-native-community/slider": "^4.1.12",
"@react-navigation/bottom-tabs": "^6.0.9",
"@react-navigation/native": "^6.0.6",
"@react-navigation/stack": "^6.0.11",
"@reduxjs/toolkit": "^1.7.1",
"@sentry/react-native": "^3.2.10",
"@types/lodash": "^4.14.178",
"date-fns": "^2.28.0",
"events": "^3.3.0",
"fuse.js": "^6.5.3",
"i18n-js": "^3.8.0",
"lodash": "^4.17.21",
"react": "^17.0.2",
"react-native": "^0.66.1",
"react-native": "^0.66.4",
"react-native-airplay-button": "^1.1.0",
"react-native-collapsible": "^1.6.0",
"react-native-dotenv": "^2.6.2",
"react-native-dotenv": "^3.3.1",
"react-native-fast-image": "^8.5.11",
"react-native-gesture-handler": "^1.10.3",
"react-native-localize": "^2.1.5",
"react-native-reanimated": "^2.2.3",
"react-native-gesture-handler": "^2.1.0",
"react-native-localize": "^2.1.7",
"react-native-reanimated": "^2.3.1",
"react-native-safe-area-context": "^3.3.2",
"react-native-screens": "^3.8.0",
"react-native-screens": "^3.10.1",
"react-native-svg": "^12.2.0",
"react-native-svg-transformer": "^0.14.3",
"react-native-track-player": "^1.2.7",
"react-native-webview": "^11.14.1",
"react-native-svg-transformer": "^1.0.0",
"react-native-track-player": "^2.1.2",
"react-native-webview": "^11.15.0",
"react-redux": "^7.2.6",
"redux": "^4.1.1",
"redux": "^4.1.2",
"redux-logger": "^3.0.6",
"redux-persist": "^6.0.0",
"styled-components": "^5.3.3"
},
"devDependencies": {
"@babel/core": "^7.15.8",
"@babel/runtime": "^7.15.4",
"@react-native-community/eslint-config": "^2.0.0",
"@sentry/cli": "^1.70.1",
"@babel/core": "^7.16.7",
"@babel/runtime": "^7.16.7",
"@react-native-community/eslint-config": "^3.0.1",
"@sentry/cli": "^1.71.0",
"@types/i18n-js": "^3.8.2",
"@types/jest": "^26.0.24",
"@types/react-native": "^0.66.1",
"@types/react-redux": "^7.1.20",
"@types/jest": "^27.4.0",
"@types/react-native": "^0.66.10",
"@types/react-redux": "^7.1.21",
"@types/react-test-renderer": "^17.0.1",
"@types/redux-logger": "^3.0.9",
"@types/styled-components": "^5.1.15",
"@types/styled-components-react-native": "^5.1.2",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"babel-jest": "^26.6.3",
"@types/styled-components": "^5.1.19",
"@types/styled-components-react-native": "^5.1.3",
"@typescript-eslint/eslint-plugin": "^5.8.1",
"@typescript-eslint/parser": "^5.8.1",
"babel-jest": "^27.4.5",
"babel-plugin-module-resolver": "^4.1.0",
"eslint": "^7.32.0",
"eslint-plugin-react-hooks": "^4.2.0",
"jest": "^26.6.3",
"eslint": "^8.5.0",
"eslint-plugin-react-hooks": "^4.3.0",
"jest": "^27.4.5",
"metro-react-native-babel-preset": "^0.66.2",
"react-test-renderer": "^17.0.2",
"typescript": "^4.4.4"
"typescript": "^4.5.4"
},
"jest": {
"preset": "react-native",

View File

@@ -1,6 +1,6 @@
import React, { useEffect } from 'react';
import { Provider } from 'react-redux';
import TrackPlayer from 'react-native-track-player';
import TrackPlayer, { Capability } from 'react-native-track-player';
import { PersistGate } from 'redux-persist/integration/react';
import Routes from '../screens';
import store, { persistedStore } from 'store';
@@ -12,7 +12,6 @@ import {
import { useColorScheme } from 'react-native';
import { ColorSchemeContext, themes } from './Colors';
// import ErrorReportingAlert from 'utility/ErrorReportingAlert';
import PlayerStateUpdater from './PlayerStateUpdater';
export default function App(): JSX.Element {
const colorScheme = useColorScheme();
@@ -24,12 +23,12 @@ export default function App(): JSX.Element {
await TrackPlayer.setupPlayer();
await TrackPlayer.updateOptions({
capabilities: [
TrackPlayer.CAPABILITY_PLAY,
TrackPlayer.CAPABILITY_PAUSE,
TrackPlayer.CAPABILITY_SKIP_TO_NEXT,
TrackPlayer.CAPABILITY_SKIP_TO_PREVIOUS,
TrackPlayer.CAPABILITY_STOP,
TrackPlayer.CAPABILITY_SEEK_TO,
Capability.Play,
Capability.Pause,
Capability.SkipToNext,
Capability.SkipToPrevious,
Capability.Stop,
Capability.SeekTo,
]
});
}
@@ -42,7 +41,6 @@ export default function App(): JSX.Element {
<ColorSchemeContext.Provider value={theme}>
<NavigationContainer theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<Routes />
<PlayerStateUpdater />
</NavigationContainer>
</ColorSchemeContext.Provider>
</PersistGate>

View File

@@ -1,54 +0,0 @@
import { useCallback, useEffect } from 'react';
import TrackPlayer, { TrackPlayerEvents } from 'react-native-track-player';
import { shallowEqual, useDispatch } from 'react-redux';
import { useTypedSelector } from 'store';
import player from 'store/player';
function PlayerStateUpdater() {
const dispatch = useDispatch();
const trackId = useTypedSelector(state => state.player.currentTrack?.id, shallowEqual);
const handleUpdate = useCallback(async () => {
const currentTrackId = await TrackPlayer.getCurrentTrack();
// GUARD: Only retrieve new track if it is different from the one we
// have currently in state.
if (currentTrackId === trackId){
return;
}
// GUARD: Only fetch current track if there is a current track
if (!currentTrackId) {
dispatch(player.actions.setCurrentTrack(undefined));
}
// If it is different, retrieve the track and save it
try {
const currentTrack = await TrackPlayer.getTrack(currentTrackId);
dispatch(player.actions.setCurrentTrack(currentTrack));
} catch {
// Due to the async nature, a track might be removed at the
// point when we try to retrieve it. If this happens, we'll just
// smother the error and wait for a new track update to
// finish.
}
}, [trackId, dispatch]);
useEffect(() => {
function handler() {
handleUpdate();
}
handler();
const subscription = TrackPlayer.addEventListener(TrackPlayerEvents.PLAYBACK_TRACK_CHANGED, handler);
return () => {
subscription.remove();
};
}, []);
return null;
}
export default PlayerStateUpdater;

View File

@@ -1,10 +1,10 @@
import React, { useCallback } from 'react';
import React, { PropsWithChildren, useCallback } from 'react';
import { Pressable, ViewStyle } from 'react-native';
interface TouchableHandlerProps {
id: string;
onPress: (id: string) => void;
onLongPress?: (id: string) => void;
interface TouchableHandlerProps<T = number> {
id: T;
onPress: (id: T) => void;
onLongPress?: (id: T) => void;
}
function TouchableStyles({ pressed }: { pressed: boolean }): ViewStyle {
@@ -19,7 +19,12 @@ function TouchableStyles({ pressed }: { pressed: boolean }): ViewStyle {
* This is a generic handler that accepts id as a prop, and return it when it is
* pressed. This comes in handy with lists in which albums / tracks need to be selected.
*/
const TouchableHandler: React.FC<TouchableHandlerProps> = ({ id, onPress, onLongPress, children }) => {
function TouchableHandler<T>({
id,
onPress,
onLongPress,
children
}: PropsWithChildren<TouchableHandlerProps<T>>): JSX.Element {
const handlePress = useCallback(() => {
return onPress(id);
}, [id, onPress]);
@@ -37,6 +42,6 @@ const TouchableHandler: React.FC<TouchableHandlerProps> = ({ id, onPress, onLon
{children}
</Pressable>
);
};
}
export default TouchableHandler;

View File

@@ -72,27 +72,20 @@ const Album: React.FC = () => {
const dispatch = useDispatch();
const getImage = useGetImage();
const playAlbum = usePlayAlbum();
const currentTrack = useCurrentTrack();
const { track: currentTrack } = useCurrentTrack();
const navigation = useNavigation();
// Setup callbacks
const selectAlbum = useCallback(() => { playAlbum(id); }, [playAlbum, id]);
const refresh = useCallback(() => { dispatch(fetchTracksByAlbum(id)); }, [id, dispatch]);
const selectTrack = useCallback(async (trackId) => {
const tracks = await playAlbum(id, false);
if (tracks) {
const track = tracks.find((t) => t.id.startsWith(trackId));
if (track) {
await TrackPlayer.skip(track.id);
await TrackPlayer.play();
}
}
const selectTrack = useCallback(async (index: number) => {
await playAlbum(id, false);
await TrackPlayer.skip(index);
await TrackPlayer.play();
}, [playAlbum, id]);
const longPressTrack = useCallback((trackId: string) => {
navigation.navigate('TrackPopupMenu', { trackId });
}, [navigation]);
const longPressTrack = useCallback((index: number) => {
navigation.navigate('TrackPopupMenu', { trackId: album?.Tracks?.[index] });
}, [navigation, album]);
// Retrieve album tracks on load
useEffect(() => {
@@ -118,14 +111,14 @@ const Album: React.FC = () => {
<Text style={[ defaultStyles.text, styles.artist ]}>{album?.AlbumArtist}</Text>
<Button title={t('play-album')} icon={Play} onPress={selectAlbum} />
<View style={{ marginTop: 15 }}>
{album?.Tracks?.length ? album.Tracks.map((trackId) =>
{album?.Tracks?.length ? album.Tracks.map((trackId, i) =>
<TouchableHandler
key={trackId}
id={trackId}
id={i}
onPress={selectTrack}
onLongPress={longPressTrack}
>
<TrackContainer isPlaying={currentTrack?.id.startsWith(trackId) || false} style={defaultStyles.border}>
<TrackContainer isPlaying={currentTrack?.backendId === trackId || false} style={defaultStyles.border}>
<Text style={[ defaultStyles.text, styles.index ]}>
{tracks[trackId]?.IndexNumber}
</Text>

View File

@@ -1,6 +1,6 @@
import React, { useCallback, useEffect } from 'react';
import { useGetImage } from 'utility/JellyfinApi';
import { Album, NavigationProp } from '../types';
import { NavigationProp } from '../types';
import { Text, SafeAreaView, FlatList, StyleSheet } from 'react-native';
import { useDispatch } from 'react-redux';
import { useNavigation } from '@react-navigation/native';
@@ -14,6 +14,7 @@ import { Header } from 'components/Typography';
import ListButton from 'components/ListButton';
import { t } from '@localisation';
import useDefaultStyles from 'components/Colors';
import { Album } from 'store/music/types';
const styles = StyleSheet.create({
columnWrapper: {

View File

@@ -226,7 +226,7 @@ export default function Search() {
}
return (
<TouchableHandler id={album.Id} onPress={selectAlbum}>
<TouchableHandler<string> id={album.Id} onPress={selectAlbum}>
<SearchResult style={defaultStyles.border}>
<AlbumImage source={{ uri: getImage(album.Id) }} />
<View>

View File

@@ -2,6 +2,7 @@ import { StackNavigationProp } from '@react-navigation/stack';
import { Album } from 'store/music/types';
export type StackParams = {
[key: string]: Record<string, unknown> | undefined;
Albums: undefined;
Album: { id: string, album: Album };
RecentAlbums: undefined;

View File

@@ -1,5 +1,5 @@
import React, { useState, useCallback, useEffect, useRef } from 'react';
import TrackPlayer, { usePlaybackState, STATE_PLAYING, STATE_PAUSED } from 'react-native-track-player';
import React, { useState, useCallback } from 'react';
import TrackPlayer, { Event, State, usePlaybackState, useTrackPlayerEvents } from 'react-native-track-player';
import { TouchableOpacity, useColorScheme } from 'react-native';
import styled from 'styled-components/native';
import { useHasQueue } from 'utility/useQueue';
@@ -84,16 +84,12 @@ export function NextButton({ fill }: { fill: string }) {
export function RepeatButton({ fill }: { fill: string}) {
const [isRepeating, setRepeating] = useState(false);
const handlePress = useCallback(() => setRepeating(!isRepeating), [isRepeating, setRepeating]);
const listener = useRef<TrackPlayer.EmitterSubscription | null>(null);
// The callback that should determine whether we need to repeeat or not
const handleEndEvent = useCallback(async () => {
useTrackPlayerEvents([Event.PlaybackQueueEnded], async () => {
if (isRepeating) {
// Retrieve all current tracks
const tracks = await TrackPlayer.getQueue();
// Then skip to the first track
await TrackPlayer.skip(tracks[0].id);
// Skip to the first track
await TrackPlayer.skip(0);
// Cautiously reset the seek time, as there might only be a single
// item in queue.
@@ -102,19 +98,7 @@ export function RepeatButton({ fill }: { fill: string}) {
// Then play the item
await TrackPlayer.play();
}
}, [isRepeating]);
// Subscribe to ended event handler so that we can restart the queue from
// the start if looping is enabled
useEffect(() => {
// Set the event listener
listener.current = TrackPlayer.addEventListener('playback-queue-ended', handleEndEvent);
// Then clean up after
return function cleanup() {
listener?.current?.remove();
};
}, [handleEndEvent]);
});
return (
<TouchableOpacity onPress={handlePress} style={{ opacity: isRepeating ? 1 : 0.5 }}>
@@ -146,13 +130,13 @@ export function MainButton({ fill }: { fill: string }) {
const state = usePlaybackState();
switch (state) {
case STATE_PLAYING:
case State.Playing:
return (
<TouchableOpacity onPress={pause}>
<PauseIcon width={BUTTON_SIZE} height={BUTTON_SIZE} fill={fill} />
</TouchableOpacity>
);
case STATE_PAUSED:
case State.Paused:
return (
<TouchableOpacity onPress={play}>
<PlayIcon width={BUTTON_SIZE} height={BUTTON_SIZE} fill={fill} />

View File

@@ -32,7 +32,7 @@ const styles = StyleSheet.create({
export default function NowPlaying() {
const track = useCurrentTrack();
const { track } = useCurrentTrack();
const defaultStyles = useDefaultStyles();
return (
@@ -40,7 +40,7 @@ export default function NowPlaying() {
<Artwork
style={defaultStyles.imageBackground}
source={{
uri: track?.artwork,
uri: track?.artwork as string | undefined,
priority: FastImage.priority.high,
}}
/>

View File

@@ -38,10 +38,9 @@ const styles = StyleSheet.create({
export default function Queue() {
const defaultStyles = useDefaultStyles();
const queue = useQueue();
const currentTrack = useCurrentTrack();
const currentIndex = queue.findIndex(d => d.id === currentTrack?.id);
const playTrack = useCallback(async (trackId: string) => {
await TrackPlayer.skip(trackId);
const { index: currentIndex } = useCurrentTrack();
const playTrack = useCallback(async (index: number) => {
await TrackPlayer.skip(index);
await TrackPlayer.play();
}, []);
const clearQueue = useCallback(async () => {
@@ -52,14 +51,14 @@ export default function Queue() {
<View>
<Text style={{ marginTop: 20, marginBottom: 20 }}>{t('queue')}</Text>
{queue.map((track, i) => (
<TouchableHandler id={track.id} onPress={playTrack} key={i}>
<TouchableHandler id={i} onPress={playTrack} key={i}>
<QueueItem
active={currentTrack?.id === track.id}
active={currentIndex === i}
key={i}
alreadyPlayed={i < currentIndex}
alreadyPlayed={currentIndex ? i < currentIndex : false}
style={[
defaultStyles.border,
currentTrack?.id === track.id ? defaultStyles.activeBackground : {},
currentIndex === i ? defaultStyles.activeBackground : {},
]}
>
<Text style={styles.trackTitle}>{track.title}</Text>

View File

@@ -62,12 +62,11 @@ function Screens() {
}
return <Icon fill={color} width={size} height={size} />;
}
},
tabBarActiveTintColor: THEME_COLOR,
tabBarInactiveTintColor: 'gray',
headerShown: false,
})}
tabBarOptions={{
activeTintColor: THEME_COLOR,
inactiveTintColor: 'gray',
}}
>
<Tab.Screen name="NowPlaying" component={Player} options={{ tabBarLabel: t('now-playing') }} />
<Tab.Screen name="Music" component={Music} options={{ tabBarLabel: t('music') }} />
@@ -85,10 +84,12 @@ type Routes = {
export default function Routes() {
return (
<Stack.Navigator mode="modal" headerMode="none" screenOptions={{
<Stack.Navigator screenOptions={{
cardStyle: {
backgroundColor: 'transparent'
}
},
presentation: 'modal',
headerShown: false,
}}>
<Stack.Screen name="Screens" component={Screens} />
<Stack.Screen name="SetJellyfinServer" component={SetJellyfinServer} />

View File

@@ -1,4 +1,5 @@
export interface ModalStackParams {
[key: string]: Record<string, unknown> | undefined;
SetJellyfinServer: undefined;
TrackPopupMenu: { trackId: string };
}

View File

@@ -13,11 +13,9 @@ const persistConfig: PersistConfig<AppState> = {
import settings from './settings';
import music from './music';
import player from './player';
const reducers = combineReducers({
settings,
player: player.reducer,
music: music.reducer,
});

View File

@@ -1,27 +0,0 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { Track } from 'react-native-track-player';
interface State {
addedTrackCount: number,
currentTrack: Track | undefined,
}
const initialState: State = {
addedTrackCount: 0,
currentTrack: undefined,
};
const player = createSlice({
name: 'player',
initialState,
reducers: {
addNewTrackToPlayer: (state) => {
state.addedTrackCount += 1;
},
setCurrentTrack: (state, action: PayloadAction<Track | undefined>) => {
state.currentTrack = action.payload;
},
}
});
export default player;

View File

@@ -0,0 +1,43 @@
import TrackPlayer from 'react-native-track-player';
import { useEffect } from 'react';
import EventEmitter from 'events';
const eventName = 'track-added';
const addedTrackEmitter = new EventEmitter();
/**
* Emit the event that a track has been added
*/
export function emitTrackAdded() {
addedTrackEmitter.emit(eventName);
}
/**
* Call the callback whenever a track has been added to the queue
*/
export function onTrackAdded(callback: () => void) {
addedTrackEmitter.addListener(eventName, callback);
}
/**
* A hook to manage the listeners for the added track function
*/
export function useOnTrackAdded(callback: () => void) {
useEffect(() => {
addedTrackEmitter.addListener(eventName, callback);
return () => {
addedTrackEmitter.removeListener(eventName, callback);
};
});
}
/**
* Monkey-patch the track-player to also emit track added events
*/
export function patchTrackPlayer() {
const oldAddFunction = TrackPlayer.add;
TrackPlayer.add = (...args: Parameters<typeof oldAddFunction>) => {
emitTrackAdded();
return oldAddFunction(...args);
};
}

View File

@@ -44,8 +44,8 @@ export function generateTrack(track: AlbumTrack, credentials: Credentials): Trac
const url = encodeURI(`${credentials?.uri}/Audio/${track.Id}/universal?${trackParams}`);
return {
id: track.Id,
url,
backendId: track.Id,
title: track.Name,
artist: track.Artists.join(', '),
album: track.Album,

View File

@@ -7,30 +7,30 @@
* such as processing media buttons or analytics
*/
import TrackPlayer from 'react-native-track-player';
import TrackPlayer, { Event } from 'react-native-track-player';
export default async function() {
TrackPlayer.addEventListener('remote-play', () => {
TrackPlayer.addEventListener(Event.RemotePlay, () => {
TrackPlayer.play();
});
TrackPlayer.addEventListener('remote-pause', () => {
TrackPlayer.addEventListener(Event.RemotePause, () => {
TrackPlayer.pause();
});
TrackPlayer.addEventListener('remote-next', () => {
TrackPlayer.addEventListener(Event.RemoteNext, () => {
TrackPlayer.skipToNext();
});
TrackPlayer.addEventListener('remote-previous', () => {
TrackPlayer.addEventListener(Event.RemotePrevious, () => {
TrackPlayer.skipToPrevious();
});
TrackPlayer.addEventListener('remote-stop', () => {
TrackPlayer.addEventListener(Event.RemoteStop, () => {
TrackPlayer.destroy();
});
TrackPlayer.addEventListener('remote-seek', (event) => {
TrackPlayer.addEventListener(Event.RemoteSeek, (event) => {
TrackPlayer.seekTo(event.position);
});

View File

@@ -1,15 +1,29 @@
import { Track } from 'react-native-track-player';
import { useTypedSelector } from 'store';
import { useCallback, useEffect, useState } from 'react';
import TrackPlayer, { Event, Track, useTrackPlayerEvents } from 'react-native-track-player';
const idEqual = (left: Track | undefined, right: Track | undefined) => {
return left?.id === right?.id;
};
interface CurrentTrackResponse {
track: Track | undefined;
index: number | undefined;
}
/**
* This hook retrieves the current playing track from TrackPlayer
*/
export default function useCurrentTrack(): Track | undefined {
const track = useTypedSelector(state => state.player.currentTrack, idEqual);
export default function useCurrentTrack(): CurrentTrackResponse {
const [track, setTrack] = useState<Track | undefined>();
const [index, setIndex] = useState<number | undefined>();
// Retrieve the current track from the queue using the index
const retrieveCurrentTrack = useCallback(async () => {
const queue = await TrackPlayer.getQueue();
const currentTrackIndex = await TrackPlayer.getCurrentTrack();
setTrack(queue[currentTrackIndex]);
setIndex(currentTrackIndex);
}, [setTrack, setIndex]);
// Then execute the function on component mount and track changes
useEffect(() => { retrieveCurrentTrack(); }, [retrieveCurrentTrack]);
useTrackPlayerEvents([ Event.PlaybackTrackChanged ], retrieveCurrentTrack);
return track;
return { track, index };
}

View File

@@ -2,55 +2,27 @@ import { useTypedSelector } from 'store';
import { useCallback } from 'react';
import TrackPlayer, { Track } from 'react-native-track-player';
import { generateTrack } from './JellyfinApi';
import useQueue from './useQueue';
import player from 'store/player';
import { useDispatch } from 'react-redux';
/**
* Generate a callback function that starts playing a full album given its
* supplied id.
*/
export default function usePlayAlbum() {
const dispatch = useDispatch();
const credentials = useTypedSelector(state => state.settings.jellyfin);
const albums = useTypedSelector(state => state.music.albums.entities);
const tracks = useTypedSelector(state => state.music.tracks.entities);
const queue = useQueue();
return useCallback(async function playAlbum(albumId: string, play = true): Promise<TrackPlayer.Track[] | undefined> {
return useCallback(async function playAlbum(albumId: string, play: boolean = true): Promise<Track[] | undefined> {
const album = albums[albumId];
const trackIds = album?.Tracks;
const backendTrackIds = album?.Tracks;
// GUARD: Check that the album actually has tracks
if (!album || !trackIds?.length) {
// GUARD: Check if the album has songs
if (!backendTrackIds?.length) {
return;
}
// Check if the queue already contains the consecutive track listing
// that is described as part of the album
const queuedAlbum = queue.reduce<TrackPlayer.Track[]>((sum, track) => {
if (track.id.startsWith(trackIds[sum.length])) {
sum.push(track);
} else {
sum = [];
}
return sum;
}, []);
// If the entire album is already in the queue, we can just return those
// tracks, rather than adding it to the queue again.
if (queuedAlbum.length === trackIds.length) {
if (play) {
await TrackPlayer.skip(trackIds[0]);
await TrackPlayer.play();
}
return queuedAlbum;
}
// Convert all trackIds to the relevant format for react-native-track-player
const newTracks = trackIds.map((trackId) => {
// Convert all backendTrackIds to the relevant format for react-native-track-player
const newTracks = backendTrackIds.map((trackId) => {
const track = tracks[trackId];
if (!trackId || !track) {
return;
@@ -60,17 +32,14 @@ export default function usePlayAlbum() {
}).filter((t): t is Track => typeof t !== 'undefined');
// Clear the queue and add all tracks
await TrackPlayer.removeUpcomingTracks();
await TrackPlayer.reset();
await TrackPlayer.add(newTracks);
// Then, we'll dispatch the added track event
dispatch(player.actions.addNewTrackToPlayer());
// Play the queue
if (play) {
await TrackPlayer.skip(trackIds[0]);
await TrackPlayer.play();
}
return newTracks;
}, [credentials, albums, tracks, queue, dispatch]);
}, [credentials, albums, tracks]);
}

View File

@@ -3,20 +3,17 @@ import TrackPlayer from 'react-native-track-player';
import { useTypedSelector } from 'store';
import { generateTrack } from './JellyfinApi';
import useQueue from './useQueue';
import { useDispatch } from 'react-redux';
import player from 'store/player';
/**
* A hook that generates a callback that can setup and start playing a
* particular trackId in the player.
*/
export default function usePlayTrack() {
const dispatch = useDispatch();
const credentials = useTypedSelector(state => state.settings.jellyfin);
const tracks = useTypedSelector(state => state.music.tracks.entities);
const queue = useQueue();
return useCallback(async function playTrack(trackId: string, play = true, addToEnd = true) {
return useCallback(async function playTrack(trackId: string, play: boolean = true, addToEnd: boolean = true) {
// Get the relevant track
const track = tracks[trackId];
@@ -25,22 +22,21 @@ export default function usePlayTrack() {
return;
}
// GUARD: Check if the track is already in the queue
const trackInstances = queue.filter((t) => t.id.startsWith(trackId));
// Generate the new track for the queue
const newTrack = {
...(trackInstances.length ? trackInstances[0] : generateTrack(track, credentials)),
id: `${trackId}_${trackInstances.length}`
};
const newTrack = generateTrack(track, credentials);
// Then, we'll need to check where to add the track
if (addToEnd) {
await TrackPlayer.add([ newTrack ]);
// Then we'll skip to it and play it
if (play) {
await TrackPlayer.skip(await (await TrackPlayer.getQueue()).length);
await TrackPlayer.play();
}
} else {
// Try and locate the current track
const currentTrackId = await TrackPlayer.getCurrentTrack();
const currentTrackIndex = queue.findIndex(track => track.id === currentTrackId);
const currentTrackIndex = await TrackPlayer.getCurrentTrack();
// Since the argument is the id to insert the track BEFORE, we need
// to get the current track + 1
@@ -51,17 +47,13 @@ export default function usePlayTrack() {
// Depending on whether this track exists, we either add it there,
// or at the end of the queue.
await TrackPlayer.add([ newTrack ], targetTrack);
}
// Then, we'll dispatch the added track event
dispatch(player.actions.addNewTrackToPlayer());
// Then we'll skip to it and play it
if (play) {
await TrackPlayer.skip(newTrack.id);
await TrackPlayer.play();
if (play) {
await TrackPlayer.skip(currentTrackIndex + 1);
await TrackPlayer.play();
}
}
return newTrack;
}, [credentials, tracks, queue, dispatch]);
}, [credentials, tracks, queue]);
}

View File

@@ -1,18 +1,22 @@
import { useEffect, useState } from 'react';
import TrackPlayer, { usePlaybackState, Track } from 'react-native-track-player';
import { useTypedSelector } from 'store';
import { useCallback, useEffect, useState } from 'react';
import TrackPlayer, { Event, Track, useTrackPlayerEvents } from 'react-native-track-player';
import { useOnTrackAdded } from './AddedTrackEvents';
/**
* This hook retrieves the current playing track from TrackPlayer
*/
export default function useQueue(): Track[] {
const state = usePlaybackState();
const [queue, setQueue] = useState<Track[]>([]);
const addedTrackCount = useTypedSelector(state => state.player.addedTrackCount);
useEffect(() => {
TrackPlayer.getQueue().then(setQueue);
}, [state, addedTrackCount]);
// Define function that fetches the current queue
const updateQueue = useCallback(() => TrackPlayer.getQueue().then(setQueue), [setQueue]);
// Then define the triggers for updating it
useEffect(() => { updateQueue(); }, [updateQueue]);
useTrackPlayerEvents([
Event.PlaybackState,
], updateQueue);
useOnTrackAdded(updateQueue);
return queue;
}