Compare commits
40 Commits
v1.2.3
...
feature/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6835d0553 | ||
|
|
21eb1dca3b | ||
|
|
a9dcd75f96 | ||
|
|
7ef54eb06d | ||
|
|
fcb6b1465b | ||
|
|
06ead4a00e | ||
|
|
f8d5aa68c2 | ||
|
|
f66b541e1b | ||
|
|
b989df43f3 | ||
|
|
de07fc65c4 | ||
|
|
c0fa1160ae | ||
|
|
f1925347cb | ||
|
|
258ac34a2c | ||
|
|
479f701d32 | ||
|
|
0589325055 | ||
|
|
a719e309ad | ||
|
|
ccc0c211fb | ||
|
|
d7402bb409 | ||
|
|
b7a5c0267c | ||
|
|
b9016f9ba6 | ||
|
|
07adb44f19 | ||
|
|
b21766a352 | ||
|
|
37ead0ec98 | ||
|
|
b0961d3263 | ||
|
|
e135b23565 | ||
|
|
015a1fa196 | ||
|
|
25f16a875f | ||
|
|
47aabfa8e7 | ||
|
|
6efc8e757c | ||
|
|
f48d248144 | ||
|
|
76f2db19e5 | ||
|
|
2b24a37218 | ||
|
|
7fb7fc1925 | ||
|
|
c4d83d29d8 | ||
|
|
d141b80a77 | ||
|
|
3b0ea4ece7 | ||
|
|
89d29844b9 | ||
|
|
f7874410d4 | ||
|
|
8914a26822 | ||
|
|
91eaa1d864 |
2
.bundle/config
Normal file
@@ -0,0 +1,2 @@
|
||||
BUNDLE_PATH: "vendor/bundle"
|
||||
BUNDLE_FORCE_RUBY_PLATFORM: 1
|
||||
@@ -53,5 +53,10 @@ module.exports = {
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error'
|
||||
]
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
}
|
||||
}
|
||||
};
|
||||
34
.github/workflows/fastlane.yml
vendored
@@ -3,26 +3,6 @@ name: Fastlane
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
# build-ios:
|
||||
# runs-on: macos-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v1
|
||||
# - name: Install Node dependencies
|
||||
# run: npm install
|
||||
# - name: Install CocoaPods dependencies
|
||||
# run: pod install --project-directory=./ios
|
||||
# - name: Run fastlane setup
|
||||
# env:
|
||||
# APPLE_ACCOUNT: ${{ secrets.APPLE_ACCOUNT }}
|
||||
# TEAM_ID: ${{ secrets.TEAM_ID }}
|
||||
# run: |
|
||||
# cd ios
|
||||
# fastlane beta --verbose
|
||||
# - name: Upload artifact
|
||||
# uses: actions/upload-artifact@v2
|
||||
# with:
|
||||
# name: my-artifact
|
||||
# path: output/*.ipa
|
||||
build-android:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -30,14 +10,12 @@ jobs:
|
||||
- name: Set outputs
|
||||
id: vars
|
||||
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
|
||||
- name: Set up Ruby 2.6
|
||||
uses: actions/setup-ruby@v1
|
||||
- name: Set up Ruby 2.7
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 2.6.x
|
||||
ruby-version: 2.7
|
||||
- name: Install fastlane
|
||||
run: |
|
||||
gem install bundler
|
||||
bundle install -j 6
|
||||
run: bundle install -j 6
|
||||
- name: Install Node dependencies
|
||||
run: npm install
|
||||
- name: Generate APK
|
||||
@@ -47,9 +25,9 @@ jobs:
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
SENTRY_URL: ${{ secrets.SENTRY_URL }}
|
||||
run: fastlane android beta
|
||||
run: bundle exec fastlane android beta
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: jellyfin-audio-player-android-${{ steps.vars.outputs.sha_short }}.apk
|
||||
path: android/app/build/outputs/**/*.apk
|
||||
path: android/app/build/outputs/**/*.apk
|
||||
|
||||
1
.gitignore
vendored
@@ -61,6 +61,7 @@ buck-out/
|
||||
|
||||
# CocoaPods
|
||||
/ios/Pods/
|
||||
/vendor/bundle/
|
||||
|
||||
build/
|
||||
fastlane/report.xml
|
||||
|
||||
1
.ruby-version
Normal file
@@ -0,0 +1 @@
|
||||
2.7.4
|
||||
3
Gemfile
@@ -4,8 +4,7 @@ source "https://rubygems.org"
|
||||
|
||||
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
||||
|
||||
# gem "rails"
|
||||
|
||||
gem 'cocoapods', '~> 1.11', '>= 1.11.2'
|
||||
gem "fastlane", "~> 2.153"
|
||||
|
||||
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
apply plugin: "com.android.application"
|
||||
|
||||
import com.android.build.OutputFile
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
/**
|
||||
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
|
||||
@@ -20,7 +21,7 @@ import com.android.build.OutputFile
|
||||
* // default. Can be overridden with ENTRY_FILE environment variable.
|
||||
* entryFile: "index.android.js",
|
||||
*
|
||||
* // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format
|
||||
* // https://reactnative.dev/docs/performance#enable-the-ram-format
|
||||
* bundleCommand: "ram-bundle",
|
||||
*
|
||||
* // whether to bundle JS and assets in debug mode
|
||||
@@ -79,11 +80,9 @@ import com.android.build.OutputFile
|
||||
|
||||
project.ext.react = [
|
||||
enableHermes: false, // clean and rebuild if changing
|
||||
entryFile: 'index.js'
|
||||
]
|
||||
|
||||
apply from: "../../node_modules/react-native/react.gradle"
|
||||
apply from: "../../node_modules/@sentry/react-native/sentry.gradle"
|
||||
|
||||
/**
|
||||
* Set this to true to create two separate APKs instead of one:
|
||||
@@ -116,16 +115,19 @@ def jscFlavor = 'org.webkit:android-jsc:+'
|
||||
/**
|
||||
* Whether to enable the Hermes VM.
|
||||
*
|
||||
* This should be set on project.ext.react and mirrored here. If it is not set
|
||||
* This should be set on project.ext.react and that value will be read here. If it is not set
|
||||
* on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
|
||||
* and the benefits of using Hermes will therefore be sharply reduced.
|
||||
*/
|
||||
def enableHermes = project.ext.react.get("enableHermes", false);
|
||||
|
||||
/**
|
||||
* Architectures to build native code for in debug.
|
||||
* Architectures to build native code for.
|
||||
*/
|
||||
def nativeArchitectures = project.getProperties().get("reactNativeDebugArchitectures")
|
||||
def reactNativeArchitectures() {
|
||||
def value = project.getProperties().get("reactNativeArchitectures")
|
||||
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
|
||||
}
|
||||
|
||||
android {
|
||||
ndkVersion rootProject.ext.ndkVersion
|
||||
@@ -136,16 +138,89 @@ android {
|
||||
applicationId "com.jellyfinaudioplayer"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 5
|
||||
versionName "1.2.3"
|
||||
multiDexEnabled true
|
||||
versionCode 8
|
||||
versionName "1.2.4"
|
||||
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
||||
|
||||
if (isNewArchitectureEnabled()) {
|
||||
// We configure the NDK build only if you decide to opt-in for the New Architecture.
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "APP_PLATFORM=android-21",
|
||||
"APP_STL=c++_shared",
|
||||
"NDK_TOOLCHAIN_VERSION=clang",
|
||||
"GENERATED_SRC_DIR=$buildDir/generated/source",
|
||||
"PROJECT_BUILD_DIR=$buildDir",
|
||||
"REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
|
||||
"REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build"
|
||||
cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
|
||||
cppFlags "-std=c++17"
|
||||
// Make sure this target name is the same you specify inside the
|
||||
// src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
|
||||
targets "rndiffapp_appmodules"
|
||||
|
||||
// Fix for windows limit on number of character in file paths and in command lines
|
||||
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
arguments "NDK_OUT=${rootProject.projectDir.getParent()}\\.cxx",
|
||||
"NDK_APP_SHORT_COMMANDS=true"
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!enableSeparateBuildPerCPUArchitecture) {
|
||||
ndk {
|
||||
abiFilters (*reactNativeArchitectures())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isNewArchitectureEnabled()) {
|
||||
// We configure the NDK build only if you decide to opt-in for the New Architecture.
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
path "$projectDir/src/main/jni/Android.mk"
|
||||
}
|
||||
}
|
||||
def reactAndroidProjectDir = project(':ReactAndroid').projectDir
|
||||
def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
|
||||
dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
|
||||
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
|
||||
into("$buildDir/react-ndk/exported")
|
||||
}
|
||||
def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
|
||||
dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
|
||||
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
|
||||
into("$buildDir/react-ndk/exported")
|
||||
}
|
||||
afterEvaluate {
|
||||
// If you wish to add a custom TurboModule or component locally,
|
||||
// you should uncomment this line.
|
||||
// preBuild.dependsOn("generateCodegenArtifactsFromSchema")
|
||||
preDebugBuild.dependsOn(packageReactNdkDebugLibs)
|
||||
preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
|
||||
|
||||
// Due to a bug inside AGP, we have to explicitly set a dependency
|
||||
// between configureNdkBuild* tasks and the preBuild tasks.
|
||||
// This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
|
||||
configureNdkBuildRelease.dependsOn(preReleaseBuild)
|
||||
configureNdkBuildDebug.dependsOn(preDebugBuild)
|
||||
reactNativeArchitectures().each { architecture ->
|
||||
tasks.findByName("configureNdkBuildDebug[${architecture}]")?.configure {
|
||||
dependsOn("preDebugBuild")
|
||||
}
|
||||
tasks.findByName("configureNdkBuildRelease[${architecture}]")?.configure {
|
||||
dependsOn("preReleaseBuild")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
splits {
|
||||
abi {
|
||||
reset()
|
||||
enable enableSeparateBuildPerCPUArchitecture
|
||||
universalApk false // If true, also generate a universal APK
|
||||
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
include (*reactNativeArchitectures())
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
@@ -159,15 +234,10 @@ android {
|
||||
buildTypes {
|
||||
debug {
|
||||
signingConfig signingConfigs.debug
|
||||
if (nativeArchitectures) {
|
||||
ndk {
|
||||
abiFilters nativeArchitectures.split(',')
|
||||
}
|
||||
}
|
||||
}
|
||||
release {
|
||||
// Caution! In production, you need to generate your own keystore file.
|
||||
// see https://facebook.github.io/react-native/docs/signed-apk-android.
|
||||
// see https://reactnative.dev/docs/signed-apk-android.
|
||||
signingConfig signingConfigs.debug
|
||||
minifyEnabled enableProguardInReleaseBuilds
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
@@ -193,17 +263,19 @@ android {
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
|
||||
//noinspection GradleDynamicVersion
|
||||
implementation "com.facebook.react:react-native:+" // From node_modules
|
||||
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
|
||||
|
||||
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
|
||||
exclude group:'com.facebook.fbjni'
|
||||
exclude group:'com.facebook.fbjni'
|
||||
}
|
||||
|
||||
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
|
||||
exclude group:'com.facebook.flipper'
|
||||
exclude group:'com.squareup.okhttp3', module:'okhttp'
|
||||
}
|
||||
|
||||
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
|
||||
@@ -219,6 +291,22 @@ dependencies {
|
||||
}
|
||||
}
|
||||
|
||||
if (isNewArchitectureEnabled()) {
|
||||
// If new architecture is enabled, we let you build RN from source
|
||||
// Otherwise we fallback to a prebuilt .aar bundled in the NPM package.
|
||||
// This will be applied to all the imported transtitive dependency.
|
||||
configurations.all {
|
||||
resolutionStrategy.dependencySubstitution {
|
||||
substitute(module("com.facebook.react:react-native"))
|
||||
.using(project(":ReactAndroid")).because("On New Architecture we're building React Native from source")
|
||||
}
|
||||
resolutionStrategy {
|
||||
force 'com.google.android.exoplayer:exoplayer-core:2.11.4'
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Run this once to be able to run the application with BUCK
|
||||
// puts all compile dependencies into folder libs for BUCK to use
|
||||
task copyDownloadableDepsToLibs(type: Copy) {
|
||||
@@ -227,3 +315,11 @@ task copyDownloadableDepsToLibs(type: Copy) {
|
||||
}
|
||||
|
||||
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
|
||||
|
||||
def isNewArchitectureEnabled() {
|
||||
// To opt-in for the New Architecture, you can either:
|
||||
// - Set `newArchEnabled` to true inside the `gradle.properties` file
|
||||
// - Invoke gradle with `-newArchEnabled=true`
|
||||
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
|
||||
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
|
||||
}
|
||||
@@ -8,6 +8,8 @@
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:targetApi="28"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||
<activity
|
||||
android:name="com.facebook.react.devsupport.DevSettingsActivity"
|
||||
android:exported="false" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
||||
* directory of this source tree.
|
||||
@@ -19,6 +19,7 @@ import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
|
||||
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
|
||||
import com.facebook.react.ReactInstanceEventListener;
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.modules.network.NetworkingModule;
|
||||
@@ -51,7 +52,7 @@ public class ReactNativeFlipper {
|
||||
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
|
||||
if (reactContext == null) {
|
||||
reactInstanceManager.addReactInstanceEventListener(
|
||||
new ReactInstanceManager.ReactInstanceEventListener() {
|
||||
new ReactInstanceEventListener() {
|
||||
@Override
|
||||
public void onReactContextInitialized(ReactContext reactContext) {
|
||||
reactInstanceManager.removeReactInstanceEventListener(this);
|
||||
|
||||
@@ -14,13 +14,14 @@
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||
android:launchMode="singleTask"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
</manifest>
|
||||
@@ -11,6 +11,9 @@ import com.facebook.soloader.SoLoader;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
|
||||
import com.facebook.react.bridge.JSIModulePackage;
|
||||
import com.swmansion.reanimated.ReanimatedJSIModulePackage;
|
||||
|
||||
public class MainApplication extends Application implements ReactApplication {
|
||||
|
||||
private final ReactNativeHost mReactNativeHost =
|
||||
@@ -33,6 +36,11 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
protected String getJSMainModuleName() {
|
||||
return "index";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JSIModulePackage getJSIModulePackage() {
|
||||
return new ReanimatedJSIModulePackage();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,20 +1,34 @@
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext {
|
||||
buildToolsVersion = "30.0.2"
|
||||
buildToolsVersion = "31.0.0"
|
||||
minSdkVersion = 21
|
||||
compileSdkVersion = 30
|
||||
targetSdkVersion = 30
|
||||
ndkVersion = "21.4.7075529"
|
||||
compileSdkVersion = 31
|
||||
targetSdkVersion = 31
|
||||
|
||||
if (System.properties['os.arch'] == "aarch64") {
|
||||
// For M1 Users we need to use the NDK 24 which added support for aarch64
|
||||
ndkVersion = "24.0.8215888"
|
||||
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
// For Android Users, we need to use NDK 23, otherwise the build will
|
||||
// fail due to paths longer than the OS limit
|
||||
ndkVersion = "23.1.7779620"
|
||||
} else {
|
||||
// Otherwise we default to the side-by-side NDK version from AGP.
|
||||
ndkVersion = "21.4.7075529"
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:4.2.2")
|
||||
|
||||
classpath("com.android.tools.build:gradle:7.0.4")
|
||||
classpath("com.facebook.react:react-native-gradle-plugin")
|
||||
classpath("de.undercouch:gradle-download-task:4.1.2")
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
@@ -22,8 +36,6 @@ buildscript {
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven {
|
||||
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
||||
url("$rootDir/../node_modules/react-native/android")
|
||||
@@ -32,9 +44,21 @@ allprojects {
|
||||
// Android JSC is installed from npm
|
||||
url("$rootDir/../node_modules/jsc-android/dist")
|
||||
}
|
||||
|
||||
mavenCentral {
|
||||
// We don't want to fetch react-native from Maven Central as there are
|
||||
// older versions over there.
|
||||
content {
|
||||
excludeGroup "com.facebook.react"
|
||||
}
|
||||
}
|
||||
google()
|
||||
jcenter()
|
||||
maven { url 'https://www.jitpack.io' }
|
||||
|
||||
jcenter() {
|
||||
content {
|
||||
includeGroup("com.google.android.exoplayer")
|
||||
includeGroupByRegex("com.eightbitlab.*")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
# Default value: -Xmx10248m -XX:MaxPermSize=256m
|
||||
org.gradle.jvmargs=-Xmx4g -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
|
||||
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
@@ -25,4 +25,16 @@ android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
# Version of flipper SDK to use with React Native
|
||||
FLIPPER_VERSION=0.99.0
|
||||
FLIPPER_VERSION=0.125.0
|
||||
|
||||
# Use this property to specify which architecture you want to build.
|
||||
# You can also override it from the CLI using
|
||||
# ./gradlew <task> -PreactNativeArchitectures=x86_64
|
||||
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
|
||||
|
||||
# Use this property to enable support to the new architecture.
|
||||
# This will allow you to use TurboModules and the Fabric render in
|
||||
# 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
|
||||
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
272
android/gradlew
vendored
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -17,67 +17,101 @@
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
@@ -106,85 +140,95 @@ location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
@@ -1,3 +1,9 @@
|
||||
rootProject.name = 'JellyfinAudioPlayer'
|
||||
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
|
||||
include ':app'
|
||||
includeBuild('../node_modules/react-native-gradle-plugin')
|
||||
|
||||
if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
|
||||
include(":ReactAndroid")
|
||||
project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ module.exports = {
|
||||
],
|
||||
[
|
||||
'module:react-native-dotenv'
|
||||
]
|
||||
],
|
||||
'react-native-reanimated/plugin'
|
||||
]
|
||||
};
|
||||
|
||||
@@ -1,38 +1,45 @@
|
||||
fastlane documentation
|
||||
================
|
||||
----
|
||||
|
||||
# Installation
|
||||
|
||||
Make sure you have the latest version of the Xcode command line tools installed:
|
||||
|
||||
```
|
||||
```sh
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
Install _fastlane_ using
|
||||
```
|
||||
[sudo] gem install fastlane -NV
|
||||
```
|
||||
or alternatively using `brew install fastlane`
|
||||
For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
|
||||
|
||||
# Available Actions
|
||||
|
||||
## iOS
|
||||
|
||||
### ios beta
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane ios beta
|
||||
```
|
||||
fastlane ios beta
|
||||
```
|
||||
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
## Android
|
||||
|
||||
### android beta
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane android beta
|
||||
```
|
||||
fastlane android beta
|
||||
```
|
||||
|
||||
Generate beta build
|
||||
|
||||
----
|
||||
|
||||
This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
|
||||
More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
|
||||
The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
|
||||
|
||||
More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
|
||||
|
||||
The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
463612208457EBB4B723000A /* libPods-JellyfinAudioPlayer-JellyfinAudioPlayerTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 842AB597D56E84A4ACDC4735 /* libPods-JellyfinAudioPlayer-JellyfinAudioPlayerTests.a */; };
|
||||
4C04FC6E055249ABB204D3BC /* Inter-VariableFont_slnt,wght.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 4B4A0465FF364579B28CF5D7 /* Inter-VariableFont_slnt,wght.ttf */; };
|
||||
4FA1B23D2550A94C007A035E /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FA1B23C2550A94C007A035E /* File.swift */; };
|
||||
A807E2BB233D6F9347D8A95C /* libPods-JellyfinAudioPlayer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 71370E61E2CC6BD9372ADCF3 /* libPods-JellyfinAudioPlayer.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
@@ -40,6 +41,7 @@
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = JellyfinAudioPlayer/main.m; sourceTree = "<group>"; };
|
||||
2710519FCC41B05FDE6738DF /* Pods-JellyfinAudioPlayer.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JellyfinAudioPlayer.release.xcconfig"; path = "Target Support Files/Pods-JellyfinAudioPlayer/Pods-JellyfinAudioPlayer.release.xcconfig"; sourceTree = "<group>"; };
|
||||
39572B38534BBDBB596C8C95 /* Pods-JellyfinAudioPlayer-JellyfinAudioPlayerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JellyfinAudioPlayer-JellyfinAudioPlayerTests.release.xcconfig"; path = "Target Support Files/Pods-JellyfinAudioPlayer-JellyfinAudioPlayerTests/Pods-JellyfinAudioPlayer-JellyfinAudioPlayerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
4B4A0465FF364579B28CF5D7 /* Inter-VariableFont_slnt,wght.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-VariableFont_slnt,wght.ttf"; path = "../src/assets/fonts/Inter-VariableFont_slnt,wght.ttf"; sourceTree = "<group>"; };
|
||||
4FA1B23B2550A94B007A035E /* JellyfinAudioPlayer-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JellyfinAudioPlayer-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
4FA1B23C2550A94C007A035E /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = "<group>"; };
|
||||
590BEA7DE65819C5B5FDAD06 /* Pods-JellyfinAudioPlayer-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JellyfinAudioPlayer-tvOSTests.release.xcconfig"; path = "Target Support Files/Pods-JellyfinAudioPlayer-tvOSTests/Pods-JellyfinAudioPlayer-tvOSTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
@@ -152,6 +154,7 @@
|
||||
83CBBA001A601CBA00E9B192 /* Products */,
|
||||
2D16E6871FA4F8E400B85C8A /* Frameworks */,
|
||||
46001D7383D71A837AAF6E07 /* Pods */,
|
||||
CFCEB457E84E4C5195253CD7 /* Resources */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
@@ -167,6 +170,14 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CFCEB457E84E4C5195253CD7 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B4A0465FF364579B28CF5D7 /* Inter-VariableFont_slnt,wght.ttf */,
|
||||
);
|
||||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -202,7 +213,6 @@
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
||||
B9FB8FC65CEFF9AFAC71127E /* [CP] Copy Pods Resources */,
|
||||
1DC46C84C90B4D84A18AC142 /* Upload Debug Symbols to Sentry */,
|
||||
2917566AA57EE087FC9FCCE9 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
@@ -268,6 +278,7 @@
|
||||
files = (
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
|
||||
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
|
||||
4C04FC6E055249ABB204D3BC /* Inter-VariableFont_slnt,wght.ttf in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -289,21 +300,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "export SENTRY_PROPERTIES=sentry.properties\nexport EXTRA_PACKAGER_ARGS=\"--sourcemap-output $DERIVED_FILE_DIR/main.jsbundle.map\"\nexport NODE_BINARY=$(which node)\n../node_modules/@sentry/cli/bin/sentry-cli react-native xcode ../node_modules/react-native/scripts/react-native-xcode.sh\n";
|
||||
};
|
||||
1DC46C84C90B4D84A18AC142 /* Upload Debug Symbols to Sentry */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Upload Debug Symbols to Sentry";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "export SENTRY_PROPERTIES=sentry.properties\n../node_modules/@sentry/cli/bin/sentry-cli upload-dsym";
|
||||
shellScript = "set -e\n\nexport NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
|
||||
};
|
||||
2917566AA57EE087FC9FCCE9 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -313,11 +310,13 @@
|
||||
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}/Flipper-Glog/glog.framework/glog",
|
||||
"${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}/glog.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -333,11 +332,13 @@
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-JellyfinAudioPlayer-JellyfinAudioPlayerTests/Pods-JellyfinAudioPlayer-JellyfinAudioPlayerTests-frameworks.sh",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-Glog/glog.framework/glog",
|
||||
"${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}/glog.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -554,7 +555,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 34;
|
||||
CURRENT_PROJECT_VERSION = 36;
|
||||
DEVELOPMENT_TEAM = 238P3C58WC;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -590,7 +591,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 34;
|
||||
CURRENT_PROJECT_VERSION = 36;
|
||||
DEVELOPMENT_TEAM = 238P3C58WC;
|
||||
INFOPLIST_FILE = JellyfinAudioPlayer/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -667,7 +668,6 @@
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
|
||||
"\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
|
||||
"\"$(inherited)\"",
|
||||
);
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
@@ -724,7 +724,6 @@
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
|
||||
"\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
|
||||
"\"$(inherited)\"",
|
||||
);
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
|
||||
@@ -4,43 +4,49 @@
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import <React/RCTRootView.h>
|
||||
|
||||
#if DEBUG
|
||||
#import <FlipperKit/FlipperClient.h>
|
||||
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
|
||||
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
|
||||
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
|
||||
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
|
||||
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
|
||||
#import <RNFSManager.h>
|
||||
#import <React/RCTAppSetupUtils.h>
|
||||
|
||||
static void InitializeFlipper(UIApplication *application) {
|
||||
FlipperClient *client = [FlipperClient sharedClient];
|
||||
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
|
||||
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
|
||||
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
|
||||
[client addPlugin:[FlipperKitReactPlugin new]];
|
||||
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
|
||||
[client start];
|
||||
#if RCT_NEW_ARCH_ENABLED
|
||||
#import <React/CoreModulesPlugins.h>
|
||||
#import <React/RCTCxxBridgeDelegate.h>
|
||||
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
|
||||
#import <React/RCTSurfacePresenter.h>
|
||||
#import <React/RCTSurfacePresenterBridgeAdapter.h>
|
||||
#import <ReactCommon/RCTTurboModuleManager.h>
|
||||
|
||||
#import <react/config/ReactNativeConfig.h>
|
||||
|
||||
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
|
||||
RCTTurboModuleManager *_turboModuleManager;
|
||||
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
|
||||
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
|
||||
facebook::react::ContextContainer::Shared _contextContainer;
|
||||
}
|
||||
@end
|
||||
#endif
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
#if DEBUG
|
||||
InitializeFlipper(application);
|
||||
#endif
|
||||
RCTAppSetupPrepareApp(application);
|
||||
|
||||
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
|
||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
|
||||
moduleName:@"JellyfinAudioPlayer"
|
||||
initialProperties:nil];
|
||||
|
||||
#if RCT_NEW_ARCH_ENABLED
|
||||
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
|
||||
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
|
||||
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
|
||||
_bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
|
||||
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
|
||||
#endif
|
||||
|
||||
UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"JellyfinAudioPlayer", nil);
|
||||
|
||||
if (@available(iOS 13.0, *)) {
|
||||
rootView.backgroundColor = [UIColor systemBackgroundColor];
|
||||
rootView.backgroundColor = [UIColor systemBackgroundColor];
|
||||
} else {
|
||||
rootView.backgroundColor = [UIColor whiteColor];
|
||||
rootView.backgroundColor = [UIColor whiteColor];
|
||||
}
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
@@ -54,10 +60,49 @@ static void InitializeFlipper(UIApplication *application) {
|
||||
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
||||
{
|
||||
#if DEBUG
|
||||
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
|
||||
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
|
||||
#else
|
||||
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
#if RCT_NEW_ARCH_ENABLED
|
||||
|
||||
#pragma mark - RCTCxxBridgeDelegate
|
||||
|
||||
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
|
||||
{
|
||||
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
|
||||
delegate:self
|
||||
jsInvoker:bridge.jsCallInvoker];
|
||||
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
|
||||
}
|
||||
|
||||
#pragma mark RCTTurboModuleManagerDelegate
|
||||
|
||||
- (Class)getModuleClassFromName:(const char *)name
|
||||
{
|
||||
return RCTCoreModulesClassProvider(name);
|
||||
}
|
||||
|
||||
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
|
||||
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
|
||||
initParams:
|
||||
(const facebook::react::ObjCTurboModule::InitParams &)params
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
|
||||
{
|
||||
return RCTAppSetupDefaultModuleFromClass(moduleClass);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
@@ -17,11 +17,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.2.3</string>
|
||||
<string>1.2.4</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>34</string>
|
||||
<string>36</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
@@ -30,7 +30,7 @@
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<string/>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>audio</string>
|
||||
@@ -50,5 +50,9 @@
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>Inter-VariableFont_slnt,wght.ttf</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.2.3</string>
|
||||
<string>1.2.4</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>34</string>
|
||||
<string>36</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
18
ios/Podfile
@@ -1,15 +1,21 @@
|
||||
require_relative '../node_modules/react-native/scripts/react_native_pods'
|
||||
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
|
||||
require_relative '../node_modules/react-native/node_modules/@react-native-community/cli-platform-ios/native_modules'
|
||||
|
||||
platform :ios, '12.0'
|
||||
|
||||
target 'JellyfinAudioPlayer' do
|
||||
config = use_native_modules!
|
||||
|
||||
# Flags change depending on the env values.
|
||||
flags = get_default_flags()
|
||||
|
||||
use_react_native!(
|
||||
:path => config[:reactNativePath],
|
||||
# to enable hermes on iOS, change `false` to `true` and then install pods
|
||||
:hermes_enabled => false
|
||||
:hermes_enabled => flags[:hermes_enabled],
|
||||
:fabric_enabled => flags[:fabric_enabled],
|
||||
# An absolute path to your application root.
|
||||
:app_path => "#{Pod::Config.instance.installation_root}/.."
|
||||
)
|
||||
|
||||
target 'JellyfinAudioPlayerTests' do
|
||||
@@ -26,13 +32,5 @@ target 'JellyfinAudioPlayer' do
|
||||
post_install do |installer|
|
||||
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
|
||||
816
ios/Podfile.lock
@@ -2,72 +2,73 @@ PODS:
|
||||
- boost (1.76.0)
|
||||
- CocoaAsyncSocket (7.6.5)
|
||||
- DoubleConversion (1.1.6)
|
||||
- FBLazyVector (0.66.4)
|
||||
- FBReactNativeSpec (0.66.4):
|
||||
- FBLazyVector (0.68.1)
|
||||
- FBReactNativeSpec (0.68.1):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- 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):
|
||||
- RCTRequired (= 0.68.1)
|
||||
- RCTTypeSafety (= 0.68.1)
|
||||
- React-Core (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- ReactCommon/turbomodule/core (= 0.68.1)
|
||||
- Flipper (0.125.0):
|
||||
- Flipper-Folly (~> 2.6)
|
||||
- Flipper-RSocket (~> 1.4)
|
||||
- Flipper-Boost-iOSX (1.76.0.1.11)
|
||||
- Flipper-DoubleConversion (3.1.7)
|
||||
- Flipper-DoubleConversion (3.2.0)
|
||||
- Flipper-Fmt (7.1.7)
|
||||
- Flipper-Folly (2.6.7):
|
||||
- Flipper-Folly (2.6.10):
|
||||
- Flipper-Boost-iOSX
|
||||
- Flipper-DoubleConversion
|
||||
- Flipper-Fmt (= 7.1.7)
|
||||
- Flipper-Glog
|
||||
- libevent (~> 2.1.12)
|
||||
- OpenSSL-Universal (= 1.1.180)
|
||||
- Flipper-Glog (0.3.6)
|
||||
- OpenSSL-Universal (= 1.1.1100)
|
||||
- Flipper-Glog (0.5.0.4)
|
||||
- Flipper-PeerTalk (0.0.4)
|
||||
- Flipper-RSocket (1.4.3):
|
||||
- Flipper-Folly (~> 2.6)
|
||||
- FlipperKit (0.99.0):
|
||||
- FlipperKit/Core (= 0.99.0)
|
||||
- FlipperKit/Core (0.99.0):
|
||||
- Flipper (~> 0.99.0)
|
||||
- FlipperKit (0.125.0):
|
||||
- FlipperKit/Core (= 0.125.0)
|
||||
- FlipperKit/Core (0.125.0):
|
||||
- Flipper (~> 0.125.0)
|
||||
- FlipperKit/CppBridge
|
||||
- FlipperKit/FBCxxFollyDynamicConvert
|
||||
- FlipperKit/FBDefines
|
||||
- FlipperKit/FKPortForwarding
|
||||
- FlipperKit/CppBridge (0.99.0):
|
||||
- Flipper (~> 0.99.0)
|
||||
- FlipperKit/FBCxxFollyDynamicConvert (0.99.0):
|
||||
- SocketRocket (~> 0.6.0)
|
||||
- FlipperKit/CppBridge (0.125.0):
|
||||
- Flipper (~> 0.125.0)
|
||||
- FlipperKit/FBCxxFollyDynamicConvert (0.125.0):
|
||||
- Flipper-Folly (~> 2.6)
|
||||
- FlipperKit/FBDefines (0.99.0)
|
||||
- FlipperKit/FKPortForwarding (0.99.0):
|
||||
- FlipperKit/FBDefines (0.125.0)
|
||||
- FlipperKit/FKPortForwarding (0.125.0):
|
||||
- CocoaAsyncSocket (~> 7.6)
|
||||
- Flipper-PeerTalk (~> 0.0.4)
|
||||
- FlipperKit/FlipperKitHighlightOverlay (0.99.0)
|
||||
- FlipperKit/FlipperKitLayoutHelpers (0.99.0):
|
||||
- FlipperKit/FlipperKitHighlightOverlay (0.125.0)
|
||||
- FlipperKit/FlipperKitLayoutHelpers (0.125.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitHighlightOverlay
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable
|
||||
- FlipperKit/FlipperKitLayoutIOSDescriptors (0.99.0):
|
||||
- FlipperKit/FlipperKitLayoutIOSDescriptors (0.125.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitHighlightOverlay
|
||||
- FlipperKit/FlipperKitLayoutHelpers
|
||||
- YogaKit (~> 1.18)
|
||||
- FlipperKit/FlipperKitLayoutPlugin (0.99.0):
|
||||
- FlipperKit/FlipperKitLayoutPlugin (0.125.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitHighlightOverlay
|
||||
- FlipperKit/FlipperKitLayoutHelpers
|
||||
- FlipperKit/FlipperKitLayoutIOSDescriptors
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable
|
||||
- YogaKit (~> 1.18)
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable (0.99.0)
|
||||
- FlipperKit/FlipperKitNetworkPlugin (0.99.0):
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable (0.125.0)
|
||||
- FlipperKit/FlipperKitNetworkPlugin (0.125.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitReactPlugin (0.99.0):
|
||||
- FlipperKit/FlipperKitReactPlugin (0.125.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitUserDefaultsPlugin (0.99.0):
|
||||
- FlipperKit/FlipperKitUserDefaultsPlugin (0.125.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/SKIOSNetworkPlugin (0.99.0):
|
||||
- FlipperKit/SKIOSNetworkPlugin (0.125.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitNetworkPlugin
|
||||
- fmt (6.2.1)
|
||||
@@ -82,7 +83,7 @@ PODS:
|
||||
- libwebp/mux (1.2.1):
|
||||
- libwebp/demux
|
||||
- libwebp/webp (1.2.1)
|
||||
- OpenSSL-Universal (1.1.180)
|
||||
- OpenSSL-Universal (1.1.1100)
|
||||
- RCT-Folly (2021.06.28.00-v2):
|
||||
- boost
|
||||
- DoubleConversion
|
||||
@@ -94,273 +95,317 @@ PODS:
|
||||
- DoubleConversion
|
||||
- fmt (~> 6.2.1)
|
||||
- glog
|
||||
- RCTRequired (0.66.4)
|
||||
- RCTTypeSafety (0.66.4):
|
||||
- FBLazyVector (= 0.66.4)
|
||||
- RCTRequired (0.68.1)
|
||||
- RCTTypeSafety (0.68.1):
|
||||
- FBLazyVector (= 0.68.1)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- 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.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.4):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- 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.4):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- 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.4):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- 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.4):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- 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.4):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- 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.4):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- 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.4):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- 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.4):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- 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.4):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- 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.4):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- 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.4):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- 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.4):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- 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.4):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- 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.4):
|
||||
- FBReactNativeSpec (= 0.66.4)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- 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.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.4)
|
||||
- React-jsi/Default (0.66.4):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-jsiexecutor (0.66.4):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- 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):
|
||||
- RCTRequired (= 0.68.1)
|
||||
- React-Core (= 0.68.1)
|
||||
- React (0.68.1):
|
||||
- React-Core (= 0.68.1)
|
||||
- React-Core/DevSupport (= 0.68.1)
|
||||
- React-Core/RCTWebSocket (= 0.68.1)
|
||||
- React-RCTActionSheet (= 0.68.1)
|
||||
- React-RCTAnimation (= 0.68.1)
|
||||
- React-RCTBlob (= 0.68.1)
|
||||
- React-RCTImage (= 0.68.1)
|
||||
- React-RCTLinking (= 0.68.1)
|
||||
- React-RCTNetwork (= 0.68.1)
|
||||
- React-RCTSettings (= 0.68.1)
|
||||
- React-RCTText (= 0.68.1)
|
||||
- React-RCTVibration (= 0.68.1)
|
||||
- react-airplay (1.1.2):
|
||||
- React-Core
|
||||
- React-callinvoker (0.68.1)
|
||||
- React-Codegen (0.68.1):
|
||||
- FBReactNativeSpec (= 0.68.1)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTRequired (= 0.68.1)
|
||||
- RCTTypeSafety (= 0.68.1)
|
||||
- React-Core (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- ReactCommon/turbomodule/core (= 0.68.1)
|
||||
- React-Core (0.68.1):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default (= 0.68.1)
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- Yoga
|
||||
- React-Core/CoreModulesHeaders (0.68.1):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- Yoga
|
||||
- React-Core/Default (0.68.1):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- Yoga
|
||||
- React-Core/DevSupport (0.68.1):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default (= 0.68.1)
|
||||
- React-Core/RCTWebSocket (= 0.68.1)
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- React-jsinspector (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- Yoga
|
||||
- React-Core/RCTActionSheetHeaders (0.68.1):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- Yoga
|
||||
- React-Core/RCTAnimationHeaders (0.68.1):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- Yoga
|
||||
- React-Core/RCTBlobHeaders (0.68.1):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- Yoga
|
||||
- React-Core/RCTImageHeaders (0.68.1):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- Yoga
|
||||
- React-Core/RCTLinkingHeaders (0.68.1):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- Yoga
|
||||
- React-Core/RCTNetworkHeaders (0.68.1):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- Yoga
|
||||
- React-Core/RCTSettingsHeaders (0.68.1):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- Yoga
|
||||
- React-Core/RCTTextHeaders (0.68.1):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- Yoga
|
||||
- React-Core/RCTVibrationHeaders (0.68.1):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- Yoga
|
||||
- React-Core/RCTWebSocket (0.68.1):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default (= 0.68.1)
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsiexecutor (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- Yoga
|
||||
- React-CoreModules (0.68.1):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.68.1)
|
||||
- React-Codegen (= 0.68.1)
|
||||
- React-Core/CoreModulesHeaders (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-RCTImage (= 0.68.1)
|
||||
- ReactCommon/turbomodule/core (= 0.68.1)
|
||||
- React-cxxreact (0.68.1):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-callinvoker (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-jsinspector (= 0.68.1)
|
||||
- React-logger (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- React-runtimeexecutor (= 0.68.1)
|
||||
- React-jsi (0.68.1):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-jsi/Default (= 0.68.1)
|
||||
- React-jsi/Default (0.68.1):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-jsiexecutor (0.68.1):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- React-jsinspector (0.68.1)
|
||||
- React-logger (0.68.1):
|
||||
- glog
|
||||
- react-native-blur (0.8.0):
|
||||
- React
|
||||
- react-native-flipper (0.127.0):
|
||||
- React-Core
|
||||
- react-native-netinfo (7.1.7):
|
||||
- react-native-netinfo (8.3.0):
|
||||
- React-Core
|
||||
- react-native-safe-area-context (3.3.2):
|
||||
- react-native-safe-area-context (4.2.5):
|
||||
- RCT-Folly
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
- React
|
||||
- ReactCommon/turbomodule/core
|
||||
- react-native-skia (0.1.123):
|
||||
- React
|
||||
- React-callinvoker
|
||||
- React-Core
|
||||
- react-native-slider (4.1.12):
|
||||
- react-native-skia/Api (= 0.1.123)
|
||||
- react-native-skia/Jsi (= 0.1.123)
|
||||
- react-native-skia/RNSkia (= 0.1.123)
|
||||
- react-native-skia/SkiaHeaders (= 0.1.123)
|
||||
- react-native-skia/Utils (= 0.1.123)
|
||||
- react-native-skia/Api (0.1.123):
|
||||
- React
|
||||
- React-callinvoker
|
||||
- React-Core
|
||||
- react-native-track-player (2.1.2):
|
||||
- react-native-skia/Jsi (0.1.123):
|
||||
- React
|
||||
- React-callinvoker
|
||||
- React-Core
|
||||
- SwiftAudioEx (= 0.14.5)
|
||||
- react-native-webview (11.15.0):
|
||||
- react-native-skia/RNSkia (0.1.123):
|
||||
- React
|
||||
- React-callinvoker
|
||||
- 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)
|
||||
- react-native-skia/SkiaHeaders (0.1.123):
|
||||
- React
|
||||
- React-callinvoker
|
||||
- React-Core
|
||||
- react-native-skia/Utils (0.1.123):
|
||||
- React
|
||||
- React-callinvoker
|
||||
- React-Core
|
||||
- react-native-slider (4.2.2):
|
||||
- React-Core
|
||||
- react-native-track-player (2.1.3):
|
||||
- React-Core
|
||||
- SwiftAudioEx (= 0.14.7)
|
||||
- react-native-webview (11.18.2):
|
||||
- React-Core
|
||||
- React-perflogger (0.68.1)
|
||||
- React-RCTActionSheet (0.68.1):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.68.1)
|
||||
- React-RCTAnimation (0.68.1):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- 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)
|
||||
- RCTTypeSafety (= 0.68.1)
|
||||
- React-Codegen (= 0.68.1)
|
||||
- React-Core/RCTAnimationHeaders (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- ReactCommon/turbomodule/core (= 0.68.1)
|
||||
- React-RCTBlob (0.68.1):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- 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)
|
||||
- React-Codegen (= 0.68.1)
|
||||
- React-Core/RCTBlobHeaders (= 0.68.1)
|
||||
- React-Core/RCTWebSocket (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-RCTNetwork (= 0.68.1)
|
||||
- ReactCommon/turbomodule/core (= 0.68.1)
|
||||
- React-RCTImage (0.68.1):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- 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)
|
||||
- RCTTypeSafety (= 0.68.1)
|
||||
- React-Codegen (= 0.68.1)
|
||||
- React-Core/RCTImageHeaders (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-RCTNetwork (= 0.68.1)
|
||||
- ReactCommon/turbomodule/core (= 0.68.1)
|
||||
- React-RCTLinking (0.68.1):
|
||||
- React-Codegen (= 0.68.1)
|
||||
- React-Core/RCTLinkingHeaders (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- ReactCommon/turbomodule/core (= 0.68.1)
|
||||
- React-RCTNetwork (0.68.1):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- 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)
|
||||
- RCTTypeSafety (= 0.68.1)
|
||||
- React-Codegen (= 0.68.1)
|
||||
- React-Core/RCTNetworkHeaders (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- ReactCommon/turbomodule/core (= 0.68.1)
|
||||
- React-RCTSettings (0.68.1):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- 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)
|
||||
- RCTTypeSafety (= 0.68.1)
|
||||
- React-Codegen (= 0.68.1)
|
||||
- React-Core/RCTSettingsHeaders (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- ReactCommon/turbomodule/core (= 0.68.1)
|
||||
- React-RCTText (0.68.1):
|
||||
- React-Core/RCTTextHeaders (= 0.68.1)
|
||||
- React-RCTVibration (0.68.1):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- 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):
|
||||
- React-Codegen (= 0.68.1)
|
||||
- React-Core/RCTVibrationHeaders (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- ReactCommon/turbomodule/core (= 0.68.1)
|
||||
- React-runtimeexecutor (0.68.1):
|
||||
- React-jsi (= 0.68.1)
|
||||
- ReactCommon/turbomodule/core (0.68.1):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- 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)
|
||||
- React-callinvoker (= 0.68.1)
|
||||
- React-Core (= 0.68.1)
|
||||
- React-cxxreact (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- React-logger (= 0.68.1)
|
||||
- React-perflogger (= 0.68.1)
|
||||
- RNCAsyncStorage (1.12.1):
|
||||
- React-Core
|
||||
- RNCMaskedView (0.1.11):
|
||||
@@ -371,19 +416,46 @@ PODS:
|
||||
- React-Core
|
||||
- SDWebImage (~> 5.11.1)
|
||||
- SDWebImageWebPCoder (~> 0.8.4)
|
||||
- RNFS (2.18.0):
|
||||
- React
|
||||
- RNGestureHandler (2.1.0):
|
||||
- RNFS (2.19.0):
|
||||
- React-Core
|
||||
- RNLocalize (2.1.7):
|
||||
- RNGestureHandler (2.4.1):
|
||||
- React-Core
|
||||
- RNScreens (3.10.1):
|
||||
- RNLocalize (2.2.1):
|
||||
- React-Core
|
||||
- RNReanimated (2.8.0):
|
||||
- DoubleConversion
|
||||
- FBLazyVector
|
||||
- FBReactNativeSpec
|
||||
- glog
|
||||
- RCT-Folly
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
- React-callinvoker
|
||||
- React-Core
|
||||
- React-Core/DevSupport
|
||||
- React-Core/RCTWebSocket
|
||||
- React-CoreModules
|
||||
- React-cxxreact
|
||||
- React-jsi
|
||||
- React-jsiexecutor
|
||||
- React-jsinspector
|
||||
- React-RCTActionSheet
|
||||
- React-RCTAnimation
|
||||
- React-RCTBlob
|
||||
- React-RCTImage
|
||||
- React-RCTLinking
|
||||
- React-RCTNetwork
|
||||
- React-RCTSettings
|
||||
- React-RCTText
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- RNScreens (3.13.1):
|
||||
- React-Core
|
||||
- React-RCTImage
|
||||
- RNSentry (3.2.10):
|
||||
- RNSentry (3.4.2):
|
||||
- React-Core
|
||||
- Sentry (= 7.7.0)
|
||||
- RNSVG (12.2.0):
|
||||
- Sentry (= 7.11.0)
|
||||
- RNSVG (12.3.0):
|
||||
- React-Core
|
||||
- SDWebImage (5.11.1):
|
||||
- SDWebImage/Core (= 5.11.1)
|
||||
@@ -391,10 +463,11 @@ PODS:
|
||||
- SDWebImageWebPCoder (0.8.4):
|
||||
- libwebp (~> 1.0)
|
||||
- SDWebImage/Core (~> 5.10)
|
||||
- Sentry (7.7.0):
|
||||
- Sentry/Core (= 7.7.0)
|
||||
- Sentry/Core (7.7.0)
|
||||
- SwiftAudioEx (0.14.5)
|
||||
- Sentry (7.11.0):
|
||||
- Sentry/Core (= 7.11.0)
|
||||
- Sentry/Core (7.11.0)
|
||||
- SocketRocket (0.6.0)
|
||||
- SwiftAudioEx (0.14.7)
|
||||
- Yoga (1.14.0)
|
||||
- YogaKit (1.18.1):
|
||||
- Yoga (~> 1.14)
|
||||
@@ -404,33 +477,36 @@ DEPENDENCIES:
|
||||
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
|
||||
- FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`)
|
||||
- Flipper (= 0.99.0)
|
||||
- Flipper (= 0.125.0)
|
||||
- Flipper-Boost-iOSX (= 1.76.0.1.11)
|
||||
- Flipper-DoubleConversion (= 3.1.7)
|
||||
- Flipper-DoubleConversion (= 3.2.0)
|
||||
- Flipper-Fmt (= 7.1.7)
|
||||
- Flipper-Folly (= 2.6.7)
|
||||
- Flipper-Glog (= 0.3.6)
|
||||
- Flipper-Folly (= 2.6.10)
|
||||
- Flipper-Glog (= 0.5.0.4)
|
||||
- Flipper-PeerTalk (= 0.0.4)
|
||||
- Flipper-RSocket (= 1.4.3)
|
||||
- FlipperKit (= 0.99.0)
|
||||
- FlipperKit/Core (= 0.99.0)
|
||||
- FlipperKit/CppBridge (= 0.99.0)
|
||||
- FlipperKit/FBCxxFollyDynamicConvert (= 0.99.0)
|
||||
- FlipperKit/FBDefines (= 0.99.0)
|
||||
- FlipperKit/FKPortForwarding (= 0.99.0)
|
||||
- FlipperKit/FlipperKitHighlightOverlay (= 0.99.0)
|
||||
- FlipperKit/FlipperKitLayoutPlugin (= 0.99.0)
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable (= 0.99.0)
|
||||
- FlipperKit/FlipperKitNetworkPlugin (= 0.99.0)
|
||||
- FlipperKit/FlipperKitReactPlugin (= 0.99.0)
|
||||
- FlipperKit/FlipperKitUserDefaultsPlugin (= 0.99.0)
|
||||
- FlipperKit/SKIOSNetworkPlugin (= 0.99.0)
|
||||
- FlipperKit (= 0.125.0)
|
||||
- FlipperKit/Core (= 0.125.0)
|
||||
- FlipperKit/CppBridge (= 0.125.0)
|
||||
- FlipperKit/FBCxxFollyDynamicConvert (= 0.125.0)
|
||||
- FlipperKit/FBDefines (= 0.125.0)
|
||||
- FlipperKit/FKPortForwarding (= 0.125.0)
|
||||
- FlipperKit/FlipperKitHighlightOverlay (= 0.125.0)
|
||||
- FlipperKit/FlipperKitLayoutPlugin (= 0.125.0)
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable (= 0.125.0)
|
||||
- FlipperKit/FlipperKitNetworkPlugin (= 0.125.0)
|
||||
- FlipperKit/FlipperKitReactPlugin (= 0.125.0)
|
||||
- FlipperKit/FlipperKitUserDefaultsPlugin (= 0.125.0)
|
||||
- FlipperKit/SKIOSNetworkPlugin (= 0.125.0)
|
||||
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||
- OpenSSL-Universal (= 1.1.1100)
|
||||
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
|
||||
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
|
||||
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
|
||||
- React (from `../node_modules/react-native/`)
|
||||
- react-airplay (from `../node_modules/react-airplay`)
|
||||
- React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
|
||||
- React-Codegen (from `build/generated/ios`)
|
||||
- React-Core (from `../node_modules/react-native/`)
|
||||
- React-Core/DevSupport (from `../node_modules/react-native/`)
|
||||
- React-Core/RCTWebSocket (from `../node_modules/react-native/`)
|
||||
@@ -440,10 +516,11 @@ DEPENDENCIES:
|
||||
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
|
||||
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
|
||||
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
|
||||
- react-native-airplay-button (from `../node_modules/react-native-airplay-button`)
|
||||
- "react-native-blur (from `../node_modules/@react-native-community/blur`)"
|
||||
- react-native-flipper (from `../node_modules/react-native-flipper`)
|
||||
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
|
||||
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
|
||||
- "react-native-skia (from `../node_modules/@shopify/react-native-skia`)"
|
||||
- "react-native-slider (from `../node_modules/@react-native-community/slider`)"
|
||||
- react-native-track-player (from `../node_modules/react-native-track-player`)
|
||||
- react-native-webview (from `../node_modules/react-native-webview`)
|
||||
@@ -466,6 +543,7 @@ DEPENDENCIES:
|
||||
- RNFS (from `../node_modules/react-native-fs`)
|
||||
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
|
||||
- RNLocalize (from `../node_modules/react-native-localize`)
|
||||
- RNReanimated (from `../node_modules/react-native-reanimated`)
|
||||
- RNScreens (from `../node_modules/react-native-screens`)
|
||||
- "RNSentry (from `../node_modules/@sentry/react-native`)"
|
||||
- RNSVG (from `../node_modules/react-native-svg`)
|
||||
@@ -490,6 +568,7 @@ SPEC REPOS:
|
||||
- SDWebImage
|
||||
- SDWebImageWebPCoder
|
||||
- Sentry
|
||||
- SocketRocket
|
||||
- SwiftAudioEx
|
||||
- YogaKit
|
||||
|
||||
@@ -512,8 +591,12 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native/Libraries/TypeSafety"
|
||||
React:
|
||||
:path: "../node_modules/react-native/"
|
||||
react-airplay:
|
||||
:path: "../node_modules/react-airplay"
|
||||
React-callinvoker:
|
||||
:path: "../node_modules/react-native/ReactCommon/callinvoker"
|
||||
React-Codegen:
|
||||
:path: build/generated/ios
|
||||
React-Core:
|
||||
:path: "../node_modules/react-native/"
|
||||
React-CoreModules:
|
||||
@@ -528,14 +611,16 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native/ReactCommon/jsinspector"
|
||||
React-logger:
|
||||
:path: "../node_modules/react-native/ReactCommon/logger"
|
||||
react-native-airplay-button:
|
||||
:path: "../node_modules/react-native-airplay-button"
|
||||
react-native-blur:
|
||||
:path: "../node_modules/@react-native-community/blur"
|
||||
react-native-flipper:
|
||||
:path: "../node_modules/react-native-flipper"
|
||||
react-native-netinfo:
|
||||
:path: "../node_modules/@react-native-community/netinfo"
|
||||
react-native-safe-area-context:
|
||||
:path: "../node_modules/react-native-safe-area-context"
|
||||
react-native-skia:
|
||||
:path: "../node_modules/@shopify/react-native-skia"
|
||||
react-native-slider:
|
||||
:path: "../node_modules/@react-native-community/slider"
|
||||
react-native-track-player:
|
||||
@@ -580,6 +665,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native-gesture-handler"
|
||||
RNLocalize:
|
||||
:path: "../node_modules/react-native-localize"
|
||||
RNReanimated:
|
||||
:path: "../node_modules/react-native-reanimated"
|
||||
RNScreens:
|
||||
:path: "../node_modules/react-native-screens"
|
||||
RNSentry:
|
||||
@@ -593,70 +680,75 @@ SPEC CHECKSUMS:
|
||||
boost: a7c83b31436843459a1961bfd74b96033dc77234
|
||||
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
|
||||
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
|
||||
FBLazyVector: e5569e42a1c79ca00521846c223173a57aca1fe1
|
||||
FBReactNativeSpec: fe08c1cd7e2e205718d77ad14b34957cce949b58
|
||||
Flipper: 30e8eeeed6abdc98edaf32af0cda2f198be4b733
|
||||
FBLazyVector: 2c76493a346ef8cacf1f442926a39f805fffec1f
|
||||
FBReactNativeSpec: 371350f24afa87b6aba606972ec959dcd4a95c9a
|
||||
Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0
|
||||
Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c
|
||||
Flipper-DoubleConversion: 57ffbe81ef95306cc9e69c4aa3aeeeeb58a6a28c
|
||||
Flipper-DoubleConversion: 3d3d04a078d4f3a1b6c6916587f159dc11f232c4
|
||||
Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b
|
||||
Flipper-Folly: 83af37379faa69497529e414bd43fbfc7cae259a
|
||||
Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6
|
||||
Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3
|
||||
Flipper-Glog: 87bc98ff48de90cb5b0b5114ed3da79d85ee2dd4
|
||||
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
|
||||
Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541
|
||||
FlipperKit: d8d346844eca5d9120c17d441a2f38596e8ed2b9
|
||||
FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86
|
||||
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
||||
glog: 5337263514dd6f09803962437687240c5dc39aa4
|
||||
glog: 476ee3e89abb49e07f822b48323c51c57124b572
|
||||
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
||||
libwebp: 98a37e597e40bfdb4c911fc98f2c53d0b12d05fc
|
||||
OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b
|
||||
RCT-Folly: a21c126816d8025b547704b777a2ba552f3d9fa9
|
||||
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
|
||||
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
|
||||
RCT-Folly: 4d8508a426467c48885f1151029bc15fa5d7b3b8
|
||||
RCTRequired: 00581111c53531e39e3c6346ef0d2c0cf52a5a37
|
||||
RCTTypeSafety: 07e03ee7800e7dd65cba8e52ad0c2edb06c96604
|
||||
React: e61f4bf3c573d0c61c56b53dc3eb1d9daf0768a0
|
||||
react-airplay: 19bc646b4cc698c00772f4cb0e45ca8e280d4c6e
|
||||
React-callinvoker: 047d47230bb6fd66827f8cb0bea4e944ffd1309b
|
||||
React-Codegen: bb0403cde7374af091530e84e492589485aab480
|
||||
React-Core: a4a3a8e10d004b08e013c3d0438259dd89a3894c
|
||||
React-CoreModules: bb9f8bc36f1ae6d780b856927fa9d4aa01ccccc0
|
||||
React-cxxreact: 7dd472aefb8629d6080cbb859240bafccd902704
|
||||
React-jsi: b25808afe821b607d51c779bdd1717be8393b7ec
|
||||
React-jsiexecutor: 4a4bae5671b064a2248a690cf75957669489d08c
|
||||
React-jsinspector: 218a2503198ff28a085f8e16622a8d8f507c8019
|
||||
React-logger: f79dd3cc0f9b44f5611c6c7862badd891a862cf8
|
||||
react-native-blur: cad4d93b364f91e7b7931b3fa935455487e5c33c
|
||||
react-native-flipper: b9e2e817604af8da0d5a9ba20a8516e780e30f3c
|
||||
react-native-netinfo: 27f287f2d191693f3b9d01a4273137fcf91c3b5d
|
||||
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
|
||||
react-native-netinfo: 3671b091c4843fda5e153612866ef4024b8f5d62
|
||||
react-native-safe-area-context: ebf8c413eb8b5f7c392a036a315eb7b46b96845f
|
||||
react-native-skia: 8a3e1b513020e2c9b0b4e49404f396d2a88f9ac7
|
||||
react-native-slider: 2f25c919f1dc309b90e2cc8346b8042ecec2102f
|
||||
react-native-track-player: c4147afddd29de936caa06561f78a32d6502eb12
|
||||
react-native-webview: 8ec7ddf9eb4ddcd92b32cee7907efec19a9ec7cb
|
||||
React-perflogger: 30ab8d6db10e175626069e742eead3ebe8f24fd5
|
||||
React-RCTActionSheet: 4b45da334a175b24dabe75f856b98fed3dfd6201
|
||||
React-RCTAnimation: d6237386cb04500889877845b3e9e9291146bc2e
|
||||
React-RCTBlob: bc9e2cd738c43bd2948e862e371402ef9584730a
|
||||
React-RCTImage: 9f8cac465c6e5837007f59ade2a0a741016dd6a3
|
||||
React-RCTLinking: 5073abb7d30cc0824b2172bd4582fc15bfc40510
|
||||
React-RCTNetwork: 28ff94aa7d8fc117fc800b87dd80869a00d2bef3
|
||||
React-RCTSettings: f27aa036f7270fe6ca43f8cdd1819e821fa429a0
|
||||
React-RCTText: 7cb6f86fa7bc86f22f16333ad243b158e63b2a68
|
||||
React-RCTVibration: 9e344c840176b0af9c84d5019eb4fed8b3c105a1
|
||||
React-runtimeexecutor: 7285b499d0339104b2813a1f58ad1ada4adbd6c0
|
||||
ReactCommon: bf2888a826ceedf54b99ad1b6182d1bc4a8a3984
|
||||
RNCAsyncStorage: b03032fdbdb725bea0bd9e5ec5a7272865ae7398
|
||||
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
|
||||
RNCPicker: 914b557e20b3b8317b084aca9ff4b4edb95f61e4
|
||||
RNFastImage: 1f2cab428712a4baaf78d6169eaec7f622556dd7
|
||||
RNFS: 3ab21fa6c56d65566d1fb26c2228e2b6132e5e32
|
||||
RNGestureHandler: e5c7cab5f214503dcefd6b2b0cefb050e1f51c4a
|
||||
RNLocalize: f567ea0e35116a641cdffe6683b0d212d568f32a
|
||||
RNScreens: 522705f2e5c9d27efb17f24aceb2bf8335bc7b8e
|
||||
RNSentry: 04bb48bfdd435f5b218cf363f89e6419e9a2460c
|
||||
RNSVG: 4ecc2e8f38b6ebe7889909570c26f3abe8059767
|
||||
RNFS: fc610f78fdf8bfc89a9e5cc2f898519f4dba1002
|
||||
RNGestureHandler: 4f4986408310a43f1606c391f38f76e0d6e790d5
|
||||
RNLocalize: cbcb55d0e19c78086ea4eea20e03fe8000bbbced
|
||||
RNReanimated: 64573e25e078ae6bec03b891586d50b9ec284393
|
||||
RNScreens: 40a2cb40a02a609938137a1e0acfbf8fc9eebf19
|
||||
RNSentry: 2cd1daa124b0d9fd0dfc2cb6094fdd168cb579bc
|
||||
RNSVG: 302bfc9905bd8122f08966dc2ce2d07b7b52b9f8
|
||||
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
|
||||
SDWebImageWebPCoder: f93010f3f6c031e2f8fb3081ca4ee6966c539815
|
||||
Sentry: e58e062056a061ae1145e22ad3dff6e506bff177
|
||||
SwiftAudioEx: bfaff9894c885aded7edfb0793e25165d55053d4
|
||||
Yoga: e7dc4e71caba6472ff48ad7d234389b91dadc280
|
||||
Sentry: 0c5cd63d714187b4a39c331c1f0eb04ba7868341
|
||||
SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
|
||||
SwiftAudioEx: 3a4024e48f3b3e45dac6bf2668d7adbe7b83f50e
|
||||
Yoga: 17cd9a50243093b547c1e539c749928dd68152da
|
||||
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
|
||||
|
||||
PODFILE CHECKSUM: 41246a700cf7cc0f2e61f418d64861444b3079b1
|
||||
PODFILE CHECKSUM: 85fc028e296eda015f9e9d002b5f5c9dbff66827
|
||||
|
||||
COCOAPODS: 1.11.2
|
||||
COCOAPODS: 1.11.3
|
||||
|
||||
18464
package-lock.json
generated
93
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "JellyfinAudioPlayer",
|
||||
"version": "1.2.3",
|
||||
"version": "1.2.4",
|
||||
"main": "src/index.js",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -13,67 +13,76 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-native-community/async-storage": "^1.12.1",
|
||||
"@react-native-community/blur": "^3.6.0",
|
||||
"@react-native-community/masked-view": "^0.1.11",
|
||||
"@react-native-community/netinfo": "^7.1.7",
|
||||
"@react-native-community/netinfo": "^8.3.0",
|
||||
"@react-native-community/picker": "^1.8.1",
|
||||
"@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",
|
||||
"@react-native-community/slider": "^4.2.2",
|
||||
"@react-native/normalize-color": "^2.0.0",
|
||||
"@react-navigation/bottom-tabs": "^6.3.1",
|
||||
"@react-navigation/native": "^6.0.10",
|
||||
"@react-navigation/native-stack": "^6.6.2",
|
||||
"@react-navigation/stack": "^6.2.1",
|
||||
"@reduxjs/toolkit": "^1.8.1",
|
||||
"@sentry/react-native": "^3.4.2",
|
||||
"@shopify/react-native-skia": "^0.1.124",
|
||||
"@types/lodash": "^4.14.182",
|
||||
"date-fns": "^2.28.0",
|
||||
"events": "^3.3.0",
|
||||
"fuse.js": "^6.5.3",
|
||||
"i18n-js": "^3.8.0",
|
||||
"fuse.js": "^6.6.2",
|
||||
"hermes-engine": "^0.11.0",
|
||||
"i18n-js": "^3.9.2",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^17.0.2",
|
||||
"react-native": "^0.66.4",
|
||||
"react-native-airplay-button": "^1.1.0",
|
||||
"react-airplay": "^1.2.0",
|
||||
"react-native": "^0.68.2",
|
||||
"react-native-collapsible": "^1.6.0",
|
||||
"react-native-dotenv": "^3.3.1",
|
||||
"react-native-fast-image": "^8.5.11",
|
||||
"react-native-flipper": "^0.127.0",
|
||||
"react-native-fs": "^2.18.0",
|
||||
"react-native-gesture-handler": "^2.1.0",
|
||||
"react-native-localize": "^2.1.7",
|
||||
"react-native-safe-area-context": "^3.3.2",
|
||||
"react-native-screens": "^3.10.1",
|
||||
"react-native-svg": "^12.2.0",
|
||||
"react-native-flipper": "^0.146.0",
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-gesture-handler": "^2.4.2",
|
||||
"react-native-localize": "^2.2.1",
|
||||
"react-native-reanimated": "^2.8.0",
|
||||
"react-native-safe-area-context": "^4.2.5",
|
||||
"react-native-screens": "^3.13.1",
|
||||
"react-native-shadow-2": "^6.0.5",
|
||||
"react-native-svg": "^12.3.0",
|
||||
"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.2",
|
||||
"react-native-track-player": "^2.1.3",
|
||||
"react-native-webview": "^11.18.2",
|
||||
"react-redux": "^8.0.1",
|
||||
"redux": "^4.2.0",
|
||||
"redux-flipper": "^2.0.1",
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-persist": "^6.0.0",
|
||||
"styled-components": "^5.3.3"
|
||||
"styled-components": "^5.3.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.16.7",
|
||||
"@babel/runtime": "^7.16.7",
|
||||
"@react-native-community/eslint-config": "^3.0.1",
|
||||
"@sentry/cli": "^1.71.0",
|
||||
"@babel/core": "^7.17.12",
|
||||
"@babel/runtime": "^7.17.9",
|
||||
"@react-native-community/eslint-config": "^3.0.2",
|
||||
"@sentry/cli": "^2.0.4",
|
||||
"@types/i18n-js": "^3.8.2",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@types/react-native": "^0.66.10",
|
||||
"@types/react-redux": "^7.1.21",
|
||||
"@types/jest": "^27.5.1",
|
||||
"@types/react-native": "^0.67.7",
|
||||
"@types/react-test-renderer": "^17.0.1",
|
||||
"@types/redux-logger": "^3.0.9",
|
||||
"@types/styled-components": "^5.1.19",
|
||||
"@types/styled-components": "^5.1.25",
|
||||
"@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",
|
||||
"@typescript-eslint/eslint-plugin": "^5.25.0",
|
||||
"@typescript-eslint/parser": "^5.25.0",
|
||||
"babel-jest": "^28.1.0",
|
||||
"babel-plugin-module-resolver": "^4.1.0",
|
||||
"eslint": "^8.5.0",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"jest": "^27.4.5",
|
||||
"metro-react-native-babel-preset": "^0.66.2",
|
||||
"eslint": "^8.15.0",
|
||||
"eslint-plugin-react-hooks": "^4.5.0",
|
||||
"jest": "^28.1.0",
|
||||
"metro-config": "^0.70.3",
|
||||
"metro-react-native-babel-preset": "^0.70.3",
|
||||
"metro-react-native-babel-transformer": "^0.70.3",
|
||||
"react-native-codegen": "^0.69.1",
|
||||
"react-test-renderer": "^17.0.2",
|
||||
"typescript": "^4.5.4"
|
||||
"typescript": "^4.6.4"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "react-native",
|
||||
@@ -87,6 +96,6 @@
|
||||
]
|
||||
},
|
||||
"overrides": {
|
||||
"@types/react-native": "^0.66.10"
|
||||
"@types/react-native": "^0.67.7"
|
||||
}
|
||||
}
|
||||
|
||||
7
react-native.config.js
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
project: {
|
||||
ios: {},
|
||||
android: {}
|
||||
},
|
||||
assets: ['./src/assets/fonts/'],
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg viewBox="0 0 20 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 18.7334C14.9658 18.7334 19.0791 14.6289 19.0791 9.6543C19.0791 4.68848 14.9658 0.575195 9.99121 0.575195C5.02539 0.575195 0.920898 4.68848 0.920898 9.6543C0.920898 14.6289 5.03418 18.7334 10 18.7334ZM10 16.9492C5.95703 16.9492 2.71387 13.6973 2.71387 9.6543C2.71387 5.61133 5.94824 2.36816 9.99121 2.36816C14.0342 2.36816 17.2861 5.61133 17.2949 9.6543C17.2949 13.6973 14.043 16.9492 10 16.9492ZM9.98242 12.335C10.1758 12.335 10.3428 12.2559 10.4834 12.124L13.3838 9.20605C13.542 9.05664 13.5947 8.88965 13.5947 8.71387C13.5947 8.35352 13.3398 8.07227 12.9707 8.07227C12.7861 8.07227 12.6191 8.14258 12.4873 8.27441L11.9336 8.82812L10.5449 10.4014L10.6416 8.90723V5.24219C10.6416 4.85547 10.3691 4.57422 9.98242 4.57422C9.58691 4.57422 9.32324 4.85547 9.32324 5.24219V8.90723L9.42871 10.4102L8.01367 8.81934L7.50391 8.27441C7.38086 8.13379 7.22266 8.07227 7.02051 8.07227C6.65137 8.07227 6.3877 8.33594 6.3877 8.72266C6.3877 8.87207 6.4668 9.07422 6.58984 9.19727L9.49023 12.124C9.63086 12.2646 9.79785 12.335 9.98242 12.335ZM6.7832 14.2598H13.208C13.5859 14.2598 13.8584 13.9785 13.8584 13.6006C13.8584 13.2314 13.5859 12.959 13.208 12.959H6.7832C6.40527 12.959 6.13281 13.2314 6.13281 13.6006C6.13281 13.9785 6.40527 14.2598 6.7832 14.2598Z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
BIN
src/assets/fonts/Inter-VariableFont_slnt,wght.ttf
Normal file
93
src/assets/fonts/OFL.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
1
src/assets/icons/airplay-audio.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 56 56"><defs><clipPath id="clip-path"><path d="M39.31 44.79a.73.73 0 0 1-.54 1.21H17.23a.73.73 0 0 1-.54-1.21l10.68-12.3a.84.84 0 0 1 1.26 0Z"/></clipPath><clipPath id="clip-path-2"><path style="fill:none" d="M-4-3h64v64H-4z"/></clipPath><clipPath id="clip-path-3"><path d="M28 22a6 6 0 0 0-3.65 10.76.16.16 0 0 1 0 .23l-.86 1-.19.21a.18.18 0 0 1-.27 0l-.32-.2a8 8 0 1 1 10.56 0l-.31.25a.18.18 0 0 1-.27 0l-.2-.22-.85-1a.17.17 0 0 1 0-.24A6 6 0 0 0 28 22Zm0-5a11 11 0 0 0-7 19.49l.1.07a.15.15 0 0 1 0 .21L21 37l-.88 1a.2.2 0 0 1-.28 0h-.14a13 13 0 1 1 16.6 0l-.12.09a.14.14 0 0 1-.2 0L35.9 38l-.89-1-.14-.16a.14.14 0 0 1 0-.21l.14-.11A11 11 0 0 0 28 17ZM17.82 40.33a.21.21 0 0 1 0 .29l-.06.07-.92 1.07-.06.07a.2.2 0 0 1-.28 0l-.08-.07a18 18 0 1 1 23 .07.16.16 0 0 1-.21 0l-1-1.2-.05-.05a.16.16 0 0 1 0-.21h.06a16 16 0 1 0-20.49-.07Z"/></clipPath></defs><path d="M11.51 27.21h32.97V51H11.51z" style="clip-path:url(#clip-path)"/><path d="M5 5h46v41.92H5z" style="clip-path:url(#clip-path-3)"/></svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
BIN
src/assets/icons/app-icon.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
3
src/assets/icons/arrow-down-to-line.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="12" height="13" viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.77493 11.4212C0.325905 11.4212 0 11.7543 0 12.2106C0 12.6669 0.325905 13 0.77493 13H10.3203C10.7766 13 11.1097 12.6669 11.1097 12.2106C11.1097 11.7543 10.7766 11.4212 10.3203 11.4212H5.72145C5.88802 11.385 6.03287 11.2981 6.15599 11.1749L10.7694 6.61226C10.9432 6.43844 11.0301 6.23565 11.0301 6.02563C11.0301 5.56936 10.6969 5.23621 10.2552 5.23621C10.0234 5.23621 9.82061 5.33036 9.67577 5.47521L8.19109 6.93816L6.28635 9.02396L6.35877 7.50306V0.818384C6.35877 0.325905 6.03287 0 5.55487 0C5.07688 0 4.74373 0.325905 4.74373 0.818384V7.50306L4.8234 9.0312L2.91866 6.93816L1.44123 5.47521C1.28914 5.33036 1.08635 5.23621 0.861838 5.23621C0.412813 5.23621 0.0869081 5.56936 0.0869081 6.02563C0.0869081 6.23565 0.173816 6.43844 0.347632 6.61226L4.95376 11.1749C5.07688 11.2981 5.22173 11.385 5.38106 11.4212H0.77493Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 935 B |
10
src/assets/icons/backward-end.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_3_22)">
|
||||
<path d="M0.689175 29.9526H3.63979C4.83259 29.9526 5.44782 29.3373 5.44782 28.1445V20.0084C5.3976 19.8451 5.38505 19.6819 5.38505 19.4936C5.38505 19.3178 5.3976 19.142 5.44782 18.9913V10.8677C5.44782 9.64983 4.83259 9.07226 3.63979 9.05971H0.689175C-0.503626 9.05971 -1.11886 9.67494 -1.11886 10.8677V28.1445C-1.13142 29.3373 -0.516182 29.9526 0.689175 29.9526ZM21.243 29.6136C22.3479 29.6136 23.2771 28.7849 23.2771 27.2531V20.0084C23.4403 20.6236 23.9049 21.1384 24.6456 21.5778L37.5153 29.1364C38.0552 29.4503 38.5324 29.6136 39.0848 29.6136C40.1897 29.6136 41.1189 28.7849 41.1189 27.2531V11.7592C41.1189 10.2274 40.1897 9.39871 39.0848 9.39871C38.5324 9.39871 38.0552 9.56194 37.5153 9.87583L24.6456 17.4344C23.8923 17.8864 23.4403 18.3761 23.2771 18.9913V11.7592C23.2771 10.2274 22.3605 9.39871 21.2556 9.39871C20.7031 9.39871 20.226 9.56194 19.6735 9.87583L6.80385 17.4344C6.06306 17.8864 5.59849 18.3761 5.44782 18.9913V20.0084C5.61105 20.6236 6.06306 21.1384 6.80385 21.5778L19.6735 29.1364C20.226 29.4503 20.6906 29.6136 21.243 29.6136Z"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_3_22">
|
||||
<rect width="40" height="40" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 531 B After Width: | Height: | Size: 531 B |
|
Before Width: | Height: | Size: 422 B After Width: | Height: | Size: 422 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 808 B After Width: | Height: | Size: 808 B |
|
Before Width: | Height: | Size: 483 B After Width: | Height: | Size: 483 B |
3
src/assets/icons/collection.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="8" height="10" viewBox="0 0 8 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1.37245 10H6.29172C6.67206 10 6.96987 9.88698 7.18515 9.66093C7.40044 9.43488 7.50808 9.09581 7.50808 8.64371V3.84285C7.50808 3.39074 7.39416 3.05257 7.16632 2.82831C6.93847 2.60406 6.59491 2.49193 6.13564 2.49193H1.37245C0.916756 2.49193 0.574092 2.60406 0.344454 2.82831C0.114818 3.05257 0 3.39074 0 3.84285V8.64371C0 9.09581 0.114818 9.43488 0.344454 9.66093C0.574092 9.88698 0.916756 10 1.37245 10ZM0.963407 1.83531H6.54467C6.50521 1.61644 6.42806 1.44959 6.31324 1.33477C6.19842 1.21995 6.02081 1.16254 5.78041 1.16254H1.72767C1.48727 1.16254 1.30966 1.21995 1.19484 1.33477C1.08002 1.44959 1.00288 1.61644 0.963407 1.83531ZM1.72228 0.613563H5.7858C5.77144 0.409042 5.70596 0.255651 5.58934 0.153391C5.47273 0.0511304 5.3032 0 5.08074 0H2.42734C2.20488 0 2.03535 0.0511304 1.91874 0.153391C1.80212 0.255651 1.73663 0.409042 1.72228 0.613563Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 962 B |
10
src/assets/icons/forward-end.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_3_26)">
|
||||
<path d="M0.915182 29.5759C1.46764 29.5759 1.94476 29.4127 2.48466 29.0988L15.3544 21.5402C16.0951 21.1007 16.5597 20.5859 16.7104 19.9707V27.2154C16.7104 28.7347 17.6395 29.5759 18.7444 29.5759C19.2969 29.5759 19.774 29.4127 20.3139 29.0988L33.1836 21.5402C33.9369 21.1007 34.389 20.5859 34.5522 19.9707V28.1445C34.5522 29.3373 35.1549 29.9526 36.3602 29.9526H39.3108C40.5036 29.9526 41.1189 29.3373 41.1189 28.1445V10.8677C41.1189 9.64983 40.5036 9.05971 39.3108 9.05971H36.3602C35.1674 9.05971 34.5522 9.67494 34.5522 10.8677V18.9537C34.389 18.3384 33.9369 17.8488 33.1836 17.3968L20.3139 9.83817C19.774 9.52427 19.2969 9.36105 18.7444 9.36105C17.6395 9.36105 16.7104 10.1897 16.7104 11.7215V18.9537C16.5597 18.3384 16.1077 17.8488 15.3544 17.3968L2.48466 9.83817C1.9322 9.52427 1.46764 9.36105 0.902626 9.36105C-0.202285 9.36105 -1.11886 10.1897 -1.11886 11.7215V27.2154C-1.11886 28.7347 -0.189729 29.5759 0.915182 29.5759Z"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_3_26">
|
||||
<rect width="40" height="40" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 558 B After Width: | Height: | Size: 558 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 806 B After Width: | Height: | Size: 806 B |
3
src/assets/icons/magnifying-glass.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.50859 13.0172C7.82354 13.0172 9.05579 12.6202 10.0813 11.9421L13.7036 15.5727C13.9434 15.8042 14.2494 15.92 14.5802 15.92C15.2667 15.92 15.7711 15.3824 15.7711 14.7043C15.7711 14.39 15.6636 14.084 15.4321 13.8525L11.8346 10.2384C12.5789 9.17984 13.0172 7.89797 13.0172 6.50859C13.0172 2.92763 10.0896 0 6.50859 0C2.9359 0 0 2.92763 0 6.50859C0 10.0896 2.92763 13.0172 6.50859 13.0172ZM6.50859 11.2805C3.88696 11.2805 1.73673 9.13022 1.73673 6.50859C1.73673 3.88696 3.88696 1.73673 6.50859 1.73673C9.13022 1.73673 11.2805 3.88696 11.2805 6.50859C11.2805 9.13022 9.13022 11.2805 6.50859 11.2805Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 713 B |
3
src/assets/icons/microphone.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.03813 10C5.17148 10 5.28504 9.95416 5.3788 9.86248C5.47256 9.77081 5.51944 9.65621 5.51944 9.51869V5.90574L6.96337 4.56808C7.54261 4.63475 8.08226 4.42014 8.58233 3.92424L5.85698 1.19265C5.61112 1.43851 5.43506 1.7 5.32879 1.97712C5.22253 2.25424 5.18606 2.5324 5.2194 2.81161L0.662578 7.70597C0.570901 7.81015 0.518811 7.92891 0.506309 8.06226C0.493814 8.19561 0.543822 8.31854 0.656331 8.43105L0.050007 9.23115C0.0166691 9.27699 0 9.33012 0 9.39055C0 9.45097 0.0250033 9.50827 0.0750098 9.56245L0.218772 9.70621C0.268783 9.75205 0.324001 9.77706 0.384425 9.78122C0.444848 9.78539 0.500061 9.76664 0.550065 9.72497L1.35016 9.11864C1.45852 9.23115 1.58041 9.28116 1.71584 9.26866C1.85127 9.25616 1.969 9.20198 2.06901 9.10614L4.55057 6.80585V9.51869C4.55057 9.65621 4.59745 9.77081 4.69122 9.86248C4.78498 9.95416 4.90061 10 5.03813 10ZM1.25641 8.14351L5.52569 3.6242C5.5632 3.68671 5.60591 3.74713 5.65383 3.80547C5.70175 3.86381 5.7528 3.92007 5.80698 3.97425C5.85698 4.02842 5.91115 4.07946 5.9695 4.12739C6.02784 4.17531 6.0841 4.21802 6.13827 4.25552L1.6377 8.52482L1.25641 8.14351ZM6.39455 0.648827L9.11989 3.38042C9.40326 3.10122 9.59495 2.79909 9.69497 2.47405C9.79498 2.14901 9.80227 1.82397 9.71684 1.49893C9.63142 1.17389 9.4491 0.875935 9.1699 0.60507C8.89487 0.33004 8.59691 0.14877 8.27604 0.0612579C7.95516 -0.0262539 7.6322 -0.0200025 7.30716 0.0800122C6.98212 0.180018 6.67792 0.369624 6.39455 0.648827Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 684 B After Width: | Height: | Size: 684 B |
3
src/assets/icons/note.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="7" height="10" viewBox="0 0 7 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.11802 2.2789V0.406546C6.11802 0.268775 6.07001 0.161274 5.974 0.084044C5.87798 0.00681376 5.76317 -0.0171898 5.62958 0.0120333L3.04962 0.575614C2.70312 0.650758 2.52987 0.83236 2.52987 1.12042V6.63102C2.55909 6.8648 2.46725 7.00048 2.25434 7.03805L1.47158 7.20087C0.97062 7.30941 0.600115 7.48996 0.360063 7.74253C0.120021 7.9951 0 8.31133 0 8.69123C0 9.0753 0.13359 9.38945 0.400769 9.63367C0.667949 9.87789 1.01027 10 1.42774 10C1.66988 10 1.93393 9.93425 2.2199 9.80275C2.50586 9.67124 2.75113 9.45938 2.95569 9.16715C3.16025 8.87492 3.26253 8.48667 3.26253 8.00241V3.46868C3.26253 3.34344 3.27819 3.26204 3.3095 3.22446C3.3408 3.18689 3.41282 3.15767 3.52554 3.13679L5.83623 2.6233C5.9239 2.60661 5.99278 2.56695 6.04288 2.50433C6.09298 2.44171 6.11802 2.36657 6.11802 2.2789Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 898 B |
|
Before Width: | Height: | Size: 714 B After Width: | Height: | Size: 714 B |
|
Before Width: | Height: | Size: 444 B After Width: | Height: | Size: 444 B |
|
Before Width: | Height: | Size: 666 B After Width: | Height: | Size: 666 B |
|
Before Width: | Height: | Size: 732 B After Width: | Height: | Size: 732 B |
|
Before Width: | Height: | Size: 363 B After Width: | Height: | Size: 363 B |
|
Before Width: | Height: | Size: 758 B After Width: | Height: | Size: 758 B |
|
Before Width: | Height: | Size: 848 B After Width: | Height: | Size: 848 B |
|
Before Width: | Height: | Size: 717 B After Width: | Height: | Size: 717 B |
|
Before Width: | Height: | Size: 695 B After Width: | Height: | Size: 695 B |
|
Before Width: | Height: | Size: 964 B After Width: | Height: | Size: 964 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -7,13 +7,29 @@ import store, { persistedStore } from 'store';
|
||||
import {
|
||||
NavigationContainer,
|
||||
DefaultTheme,
|
||||
DarkTheme,
|
||||
DarkTheme as BaseDarkTheme,
|
||||
} from '@react-navigation/native';
|
||||
import { useColorScheme } from 'react-native';
|
||||
import { ColorSchemeContext, themes } from './Colors';
|
||||
import DownloadManager from './DownloadManager';
|
||||
// import ErrorReportingAlert from 'utility/ErrorReportingAlert';
|
||||
|
||||
const LightTheme = {
|
||||
...DefaultTheme,
|
||||
colors: {
|
||||
...DefaultTheme.colors,
|
||||
background: themes.light.view.backgroundColor,
|
||||
}
|
||||
};
|
||||
|
||||
const DarkTheme = {
|
||||
...BaseDarkTheme,
|
||||
colors: {
|
||||
...BaseDarkTheme.colors,
|
||||
background: themes.dark.view.backgroundColor,
|
||||
}
|
||||
};
|
||||
|
||||
export default function App(): JSX.Element {
|
||||
const colorScheme = useColorScheme();
|
||||
// const colorScheme = 'dark';
|
||||
@@ -30,7 +46,8 @@ export default function App(): JSX.Element {
|
||||
Capability.SkipToPrevious,
|
||||
Capability.Stop,
|
||||
Capability.SeekTo,
|
||||
]
|
||||
],
|
||||
stopWithApp: true
|
||||
});
|
||||
}
|
||||
setupTrackPlayer();
|
||||
@@ -40,7 +57,9 @@ export default function App(): JSX.Element {
|
||||
<Provider store={store}>
|
||||
<PersistGate loading={null} persistor={persistedStore}>
|
||||
<ColorSchemeContext.Provider value={theme}>
|
||||
<NavigationContainer theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
|
||||
<NavigationContainer
|
||||
theme={colorScheme === 'dark' ? DarkTheme : LightTheme}
|
||||
>
|
||||
<Routes />
|
||||
<DownloadManager />
|
||||
</NavigationContainer>
|
||||
|
||||
@@ -7,14 +7,17 @@ import { THEME_COLOR } from 'CONSTANTS';
|
||||
import styled, { css } from 'styled-components/native';
|
||||
import useDefaultStyles from './Colors';
|
||||
|
||||
type ButtonSize = 'default' | 'small';
|
||||
|
||||
interface ButtonProps extends PressableProps {
|
||||
icon?: React.FC<SvgProps>;
|
||||
title: string;
|
||||
title?: string;
|
||||
style?: ViewProps['style'];
|
||||
size?: ButtonSize;
|
||||
}
|
||||
|
||||
const BaseButton = styled.Pressable`
|
||||
padding: 16px;
|
||||
const BaseButton = styled.Pressable<{ size: ButtonSize }>`
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
@@ -24,19 +27,25 @@ const BaseButton = styled.Pressable`
|
||||
${(props) => props.disabled && css`
|
||||
opacity: 0.25;
|
||||
`}
|
||||
|
||||
${(props) => props.size === 'small' && css`
|
||||
flex-grow: 0;
|
||||
padding: 10px;
|
||||
`}
|
||||
`;
|
||||
|
||||
const ButtonText = styled.Text<{ active?: boolean }>`
|
||||
const ButtonText = styled.Text<{ active?: boolean, size: ButtonSize }>`
|
||||
color: ${THEME_COLOR};
|
||||
font-weight: 600;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
|
||||
${props => props.active && css`
|
||||
color: white;
|
||||
${(props) => props.size === 'small' && css`
|
||||
font-size: 12px;
|
||||
`}
|
||||
`;
|
||||
|
||||
const Button = React.forwardRef<View, ButtonProps>(function Button(props, ref) {
|
||||
const { icon: Icon, title, disabled, ...rest } = props;
|
||||
const { icon: Icon, title, disabled, size = 'default', ...rest } = props;
|
||||
const defaultStyles = useDefaultStyles();
|
||||
const [isPressed, setPressed] = useState(false);
|
||||
const handlePressIn = useCallback(() => setPressed(true), []);
|
||||
@@ -46,26 +55,31 @@ const Button = React.forwardRef<View, ButtonProps>(function Button(props, ref) {
|
||||
<BaseButton
|
||||
{...rest}
|
||||
disabled={disabled}
|
||||
// @ts-expect-error styled-components has outdated react-native typings
|
||||
ref={ref}
|
||||
onPressIn={handlePressIn}
|
||||
onPressOut={handlePressOut}
|
||||
style={[
|
||||
props.style,
|
||||
{ backgroundColor: isPressed ? THEME_COLOR : defaultStyles.button.backgroundColor }
|
||||
{ backgroundColor: isPressed
|
||||
? defaultStyles.activeBackground.backgroundColor
|
||||
: defaultStyles.button.backgroundColor
|
||||
}
|
||||
]}
|
||||
size={size}
|
||||
>
|
||||
{Icon &&
|
||||
<Icon
|
||||
width={14}
|
||||
height={14}
|
||||
fill={isPressed ? '#fff' : THEME_COLOR}
|
||||
fill={THEME_COLOR}
|
||||
style={{
|
||||
marginRight: 8,
|
||||
marginRight: title ? 8 : 0,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
<ButtonText active={isPressed}>{title}</ButtonText>
|
||||
{title ? (
|
||||
<ButtonText active={isPressed} size={size}>{title}</ButtonText>
|
||||
) : undefined}
|
||||
</BaseButton>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { BlurView, BlurViewProperties } from '@react-native-community/blur';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import React from 'react';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { ColorSchemeName, StyleSheet } from 'react-native';
|
||||
import { ColorSchemeName, Platform, StyleSheet, useColorScheme } from 'react-native';
|
||||
|
||||
const majorPlatformVersion = typeof Platform.Version === 'string' ? parseInt(Platform.Version, 10) : Platform.Version;
|
||||
|
||||
/**
|
||||
* Function for generating both the dark and light stylesheets, so that they
|
||||
@@ -11,12 +14,20 @@ function generateStyles(scheme: ColorSchemeName) {
|
||||
return StyleSheet.create({
|
||||
text: {
|
||||
color: scheme === 'dark' ? '#fff' : '#000',
|
||||
fontSize: 14,
|
||||
fontFamily: 'Inter',
|
||||
},
|
||||
textHalfOpacity: {
|
||||
color: scheme === 'dark' ? '#ffffff88' : '#00000088',
|
||||
fontSize: 14,
|
||||
// fontFamily: 'Inter',
|
||||
},
|
||||
textQuarterOpacity: {
|
||||
color: scheme === 'dark' ? '#ffffff44' : '#00000044',
|
||||
fontSize: 14,
|
||||
},
|
||||
view: {
|
||||
backgroundColor: scheme === 'dark' ? '#111' : '#f6f6f6',
|
||||
backgroundColor: scheme === 'dark' ? '#111' : '#fff',
|
||||
},
|
||||
border: {
|
||||
borderColor: scheme === 'dark' ? '#262626' : '#ddd',
|
||||
@@ -25,28 +36,35 @@ function generateStyles(scheme: ColorSchemeName) {
|
||||
backgroundColor: `${THEME_COLOR}${scheme === 'dark' ? '26' : '16'}`,
|
||||
},
|
||||
imageBackground: {
|
||||
backgroundColor: scheme === 'dark' ? '#333' : '#ddd',
|
||||
backgroundColor: scheme === 'dark' ? '#191919' : '#eee',
|
||||
borderWidth: 0.5,
|
||||
borderColor: scheme === 'dark' ? '#262626' : '#ddd',
|
||||
},
|
||||
modal: {
|
||||
backgroundColor: scheme === 'dark' ? '#22222200' : '#eeeeee00',
|
||||
backgroundColor: scheme === 'dark' ? '#000' : '#fff',
|
||||
},
|
||||
modalInner: {
|
||||
backgroundColor: scheme === 'dark' ? '#000' : '#fff',
|
||||
},
|
||||
button: {
|
||||
backgroundColor: scheme === 'dark' ? '#161616' : '#e6e6e6',
|
||||
backgroundColor: scheme === 'dark' ? '#ffffff09' : '#00000009',
|
||||
},
|
||||
input: {
|
||||
backgroundColor: scheme === 'dark' ? '#161616' : '#e6e6e6',
|
||||
backgroundColor: scheme === 'dark' ? '#191919' : '#f3f3f3',
|
||||
color: scheme === 'dark' ? '#fff' : '#000',
|
||||
},
|
||||
sectionHeading: {
|
||||
backgroundColor: scheme === 'dark' ? '#111' : '#eee',
|
||||
borderColor: scheme === 'dark' ? '#333' : '#ddd',
|
||||
},
|
||||
stackHeader: {
|
||||
color: scheme === 'dark' ? 'white' : 'black'
|
||||
}
|
||||
},
|
||||
icon: {
|
||||
color: scheme === 'dark' ? '#ffffff4d' : '#0000004d',
|
||||
},
|
||||
divider: {
|
||||
backgroundColor: scheme === 'dark' ? '#333' : '#eee',
|
||||
},
|
||||
filter: {
|
||||
backgroundColor: scheme === 'dark' ? '#191919' : '#f3f3f3',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -77,4 +95,17 @@ export function DefaultStylesProvider(props: DefaultStylesProviderProps) {
|
||||
const defaultStyles = useDefaultStyles();
|
||||
|
||||
return props.children(defaultStyles);
|
||||
}
|
||||
|
||||
export function ColoredBlurView(props: PropsWithChildren<BlurViewProperties>) {
|
||||
const scheme = useColorScheme();
|
||||
|
||||
return (
|
||||
<BlurView
|
||||
{...props}
|
||||
blurType={Platform.OS === 'ios' && majorPlatformVersion >= 13
|
||||
? 'material'
|
||||
: scheme === 'dark' ? 'extraDark' : 'xlight'
|
||||
} />
|
||||
);
|
||||
}
|
||||
85
src/components/CoverImage.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Dimensions, ViewProps } from 'react-native';
|
||||
import { Canvas, Blur, Image as SkiaImage, useImage, Offset, Mask, RoundedRect, Shadow } from '@shopify/react-native-skia';
|
||||
import useDefaultStyles from './Colors';
|
||||
import styled from 'styled-components/native';
|
||||
|
||||
const Screen = Dimensions.get('screen');
|
||||
|
||||
const Container = styled.View<{ size: number }>`
|
||||
width: ${(props) => props.size}px;
|
||||
height: ${(props) => props.size}px;
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const BlurContainer = styled(Canvas)<{ size: number, offset: number }>`
|
||||
position: absolute;
|
||||
left: -${(props) => props.offset}px;
|
||||
top: -${(props) => props.offset}px;
|
||||
width: ${(props) => props.size}px;
|
||||
height: ${(props) => props.size}px;
|
||||
z-index: 2;
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
blurRadius?: number;
|
||||
opacity?: number;
|
||||
margin?: number;
|
||||
radius?: number;
|
||||
style?: ViewProps['style'];
|
||||
src: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will take a cover image, and apply shadows and a really nice background
|
||||
* blur to the image in question. Additionally, we'll add some margin and radius
|
||||
* to the corners.
|
||||
*/
|
||||
function CoverImage({
|
||||
blurRadius = 256,
|
||||
opacity = 0.85,
|
||||
margin = 112,
|
||||
radius = 12,
|
||||
style,
|
||||
src,
|
||||
}: Props) {
|
||||
const defaultStyles = useDefaultStyles();
|
||||
|
||||
const image = useImage(src || '');
|
||||
const { canvasSize, imageSize } = useMemo(() => {
|
||||
const imageSize = Screen.width - margin;
|
||||
const canvasSize = imageSize + blurRadius * 2;
|
||||
return { imageSize, canvasSize };
|
||||
}, [blurRadius, margin]);
|
||||
|
||||
return (
|
||||
<Container size={imageSize} style={style}>
|
||||
<BlurContainer size={canvasSize} offset={blurRadius}>
|
||||
<RoundedRect x={blurRadius} y={blurRadius} width={imageSize} height={imageSize} color={defaultStyles.imageBackground.backgroundColor} r={12}>
|
||||
<Shadow dx={0} dy={1} blur={2} color="#0000000d" />
|
||||
<Shadow dx={0} dy={2} blur={4} color="#0000000d" />
|
||||
<Shadow dx={0} dy={4} blur={8} color="#0000000d" />
|
||||
<Shadow dx={0} dy={8} blur={16} color="#0000000d" />
|
||||
<Shadow dx={0} dy={16} blur={32} color="#0000000d" />
|
||||
</RoundedRect>
|
||||
{image ? (
|
||||
<>
|
||||
<SkiaImage image={image} width={imageSize} height={imageSize} opacity={opacity}>
|
||||
<Offset x={blurRadius} y={blurRadius} />
|
||||
<Blur blur={blurRadius / 2} />
|
||||
</SkiaImage>
|
||||
<Mask mask={<RoundedRect width={imageSize} height={imageSize} x={blurRadius} y={blurRadius} r={radius} />}>
|
||||
{image ? (
|
||||
<SkiaImage image={image} width={imageSize} height={imageSize}>
|
||||
<Offset x={blurRadius} y={blurRadius} />
|
||||
</SkiaImage>
|
||||
) : null}
|
||||
</Mask>
|
||||
</>
|
||||
) : null}
|
||||
</BlurContainer>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default CoverImage;
|
||||
18
src/components/Divider.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import { ViewProps } from 'react-native';
|
||||
import styled from 'styled-components/native';
|
||||
import useDefaultStyles from './Colors';
|
||||
|
||||
const Container = styled.View`
|
||||
height: 1px;
|
||||
flex: 1;
|
||||
`;
|
||||
|
||||
function Divider({ style }: ViewProps) {
|
||||
const defaultStyles = useDefaultStyles();
|
||||
return (
|
||||
<Container style={[defaultStyles.divider, style]} />
|
||||
);
|
||||
}
|
||||
|
||||
export default Divider;
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { useEffect, useMemo, useRef } from 'react';
|
||||
import { useTypedSelector } from 'store';
|
||||
import CloudIcon from 'assets/cloud.svg';
|
||||
import CloudDownArrow from 'assets/cloud-down-arrow.svg';
|
||||
import CloudExclamationMarkIcon from 'assets/cloud-exclamation-mark.svg';
|
||||
import InternalDriveIcon from 'assets/internal-drive.svg';
|
||||
import CloudIcon from 'assets/icons/cloud.svg';
|
||||
import CloudDownArrow from 'assets/icons/cloud-down-arrow.svg';
|
||||
import CloudExclamationMarkIcon from 'assets/icons/cloud-exclamation-mark.svg';
|
||||
import InternalDriveIcon from 'assets/icons/internal-drive.svg';
|
||||
import useDefaultStyles from './Colors';
|
||||
import { EntityId } from '@reduxjs/toolkit';
|
||||
import Svg, { Circle, CircleProps } from 'react-native-svg';
|
||||
@@ -30,7 +30,7 @@ const IconOverlay = styled.View`
|
||||
function DownloadIcon({ trackId, size = 16, fill }: DownloadIconProps) {
|
||||
// determine styles
|
||||
const defaultStyles = useDefaultStyles();
|
||||
const iconFill = fill || defaultStyles.textHalfOpacity.color;
|
||||
const iconFill = fill || defaultStyles.textQuarterOpacity.color;
|
||||
|
||||
// Get download icon from state
|
||||
const entity = useTypedSelector((state) => state.downloads.entities[trackId]);
|
||||
|
||||
@@ -2,8 +2,7 @@ import { EntityId } from '@reduxjs/toolkit';
|
||||
import { xor } from 'lodash';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { DocumentDirectoryPath, readDir } from 'react-native-fs';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useTypedSelector } from 'store';
|
||||
import { useAppDispatch, useTypedSelector } from 'store';
|
||||
import { completeDownload, downloadTrack } from 'store/downloads/actions';
|
||||
|
||||
/**
|
||||
@@ -20,7 +19,7 @@ function DownloadManager () {
|
||||
// Retrieve store helpers
|
||||
const { queued, ids } = useTypedSelector((state) => state.downloads);
|
||||
const rehydrated = useTypedSelector((state) => state._persist.rehydrated);
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
// Keep state for the currently active downloads (i.e. the downloads that
|
||||
// have actually been pushed out to react-native-fs).
|
||||
@@ -67,8 +66,6 @@ function DownloadManager () {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(ids);
|
||||
|
||||
/**
|
||||
* Whenever the store is cleared, existing downloads get "lost" because
|
||||
* the only reference we have is the store. This function checks for
|
||||
@@ -82,7 +79,6 @@ function DownloadManager () {
|
||||
files.filter((file) => file.isFile() && file.name.endsWith('.mp3'))
|
||||
.forEach((file) => {
|
||||
const id = file.name.replace('.mp3', '');
|
||||
console.log(id, ids.includes(id));
|
||||
|
||||
// GUARD: If the id is already in the store, there's nothing
|
||||
// left for us to do.
|
||||
@@ -94,7 +90,7 @@ function DownloadManager () {
|
||||
dispatch(completeDownload({
|
||||
id,
|
||||
location: file.path,
|
||||
size: Number.parseInt(file.size),
|
||||
size: file.size,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import styled from 'styled-components/native';
|
||||
import styled, { css } from 'styled-components/native';
|
||||
|
||||
const Input = styled.TextInput`
|
||||
const Input = styled.TextInput<{ icon?: boolean }>`
|
||||
margin: 10px 0;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
|
||||
${(props) => props.icon && css`
|
||||
padding-left: 40px;
|
||||
`}
|
||||
`;
|
||||
|
||||
export default Input;
|
||||
@@ -1,30 +1,24 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { TouchableOpacityProps } from 'react-native';
|
||||
import ChevronRight from 'assets/chevron-right.svg';
|
||||
import styled, { css } from 'styled-components/native';
|
||||
import ChevronRight from 'assets/icons/chevron-right.svg';
|
||||
import styled from 'styled-components/native';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import useDefaultStyles from './Colors';
|
||||
|
||||
const BUTTON_SIZE = 14;
|
||||
|
||||
const Container = styled.Pressable<{ active?: boolean }>`
|
||||
padding: 18px 20px;
|
||||
border-bottom-width: 1px;
|
||||
padding: 14px 16px;
|
||||
border-radius: 8px;
|
||||
margin: 4px 8px;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
${props => props.active && css`
|
||||
background-color: ${THEME_COLOR};
|
||||
`}
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const Label = styled.Text<{ active?: boolean }>`
|
||||
color: ${THEME_COLOR};
|
||||
font-size: 16px;
|
||||
|
||||
${props => props.active && css`
|
||||
color: white;
|
||||
`}
|
||||
`;
|
||||
|
||||
const ListButton: React.FC<TouchableOpacityProps> = ({ children, ...props }) => {
|
||||
@@ -34,16 +28,17 @@ const ListButton: React.FC<TouchableOpacityProps> = ({ children, ...props }) =>
|
||||
const handlePressOut = useCallback(() => setPressed(false), []);
|
||||
|
||||
return (
|
||||
// @ts-expect-error styled-components has outdated react-native typings
|
||||
<Container
|
||||
{...props}
|
||||
onPressIn={handlePressIn}
|
||||
onPressOut={handlePressOut}
|
||||
style={defaultStyles.border}
|
||||
active={isPressed}
|
||||
style={[
|
||||
defaultStyles.border,
|
||||
isPressed ? defaultStyles.activeBackground : undefined
|
||||
]}
|
||||
>
|
||||
<Label active={isPressed}>{children}</Label>
|
||||
<ChevronRight width={BUTTON_SIZE} height={BUTTON_SIZE} fill={isPressed ? '#fff' : THEME_COLOR} />
|
||||
<Label>{children}</Label>
|
||||
<ChevronRight width={BUTTON_SIZE} height={BUTTON_SIZE} fill={THEME_COLOR} />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import styled, { css } from 'styled-components/native';
|
||||
import { Pressable } from 'react-native';
|
||||
import { useNavigation, StackActions } from '@react-navigation/native';
|
||||
import useDefaultStyles from './Colors';
|
||||
|
||||
@@ -8,12 +7,12 @@ interface Props {
|
||||
fullSize?: boolean;
|
||||
}
|
||||
|
||||
const Background = styled(Pressable)`
|
||||
const Background = styled.View`
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
const Container = styled(Pressable)<Pick<Props, 'fullSize'>>`
|
||||
const Container = styled.View<Pick<Props, 'fullSize'>>`
|
||||
margin: auto 20px;
|
||||
padding: 4px;
|
||||
border-radius: 12px;
|
||||
@@ -27,6 +26,10 @@ const Container = styled(Pressable)<Pick<Props, 'fullSize'>>`
|
||||
`}
|
||||
`;
|
||||
|
||||
const Spacer = styled.Pressable`
|
||||
flex: 1;
|
||||
`;
|
||||
|
||||
const Modal: React.FC<Props> = ({ children, fullSize = true }) => {
|
||||
const defaultStyles = useDefaultStyles();
|
||||
const navigation = useNavigation();
|
||||
@@ -35,10 +38,12 @@ const Modal: React.FC<Props> = ({ children, fullSize = true }) => {
|
||||
}, [navigation]);
|
||||
|
||||
return (
|
||||
<Background style={defaultStyles.modal} onPress={closeModal}>
|
||||
<Background style={defaultStyles.modal}>
|
||||
{!fullSize && <Spacer onPress={closeModal} />}
|
||||
<Container style={defaultStyles.modalInner} fullSize={fullSize}>
|
||||
{children}
|
||||
</Container>
|
||||
{!fullSize && <Spacer onPress={closeModal} />}
|
||||
</Background>
|
||||
);
|
||||
};
|
||||
|
||||
52
src/components/Progresstrack.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import styled from 'styled-components/native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
|
||||
export function getSeconds(seconds: number): string {
|
||||
'worklet';
|
||||
return Math.floor(seconds % 60).toString().padStart(2, '0');
|
||||
}
|
||||
|
||||
export function getMinutes(seconds: number): number {
|
||||
'worklet';
|
||||
return Math.floor(seconds / 60);
|
||||
}
|
||||
|
||||
export function calculateProgressTranslation(
|
||||
position: number,
|
||||
reference: number,
|
||||
width: number,
|
||||
) {
|
||||
'worklet';
|
||||
const completion = position / reference;
|
||||
const output = (1 - (completion || 0)) * -1 * width;
|
||||
return output;
|
||||
}
|
||||
|
||||
export const ProgressTrackContainer = styled.View`
|
||||
overflow: hidden;
|
||||
height: 5px;
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
border-radius: 6px;
|
||||
`;
|
||||
|
||||
export interface ProgressTrackProps {
|
||||
opacity?: number;
|
||||
stroke?: number;
|
||||
}
|
||||
|
||||
const ProgressTrack = styled(Animated.View)<ProgressTrackProps>`
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: ${(props) => props.stroke ? props.stroke + 'px' : '100%'};
|
||||
background-color: ${THEME_COLOR};
|
||||
opacity: ${(props) => props.opacity || 1};
|
||||
border-radius: 99px;
|
||||
`;
|
||||
|
||||
export default ProgressTrack;
|
||||
44
src/components/ReText.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
import type { TextProps as RNTextProps } from 'react-native';
|
||||
import { StyleSheet, TextInput } from 'react-native';
|
||||
import Animated, { useAnimatedProps } from 'react-native-reanimated';
|
||||
import useDefaultStyles from './Colors';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
baseStyle: {
|
||||
color: 'black',
|
||||
},
|
||||
});
|
||||
Animated.addWhitelistedNativeProps({ text: true });
|
||||
|
||||
interface TextProps {
|
||||
text: Animated.SharedValue<string>;
|
||||
style?: Animated.AnimateProps<RNTextProps>['style'];
|
||||
}
|
||||
|
||||
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
|
||||
|
||||
const ReText = (props: TextProps) => {
|
||||
const { text, style } = { style: {}, ...props };
|
||||
const defaultStyles = useDefaultStyles();
|
||||
|
||||
const animatedProps = useAnimatedProps(() => {
|
||||
return {
|
||||
text: text.value,
|
||||
// Here we use any because the text prop is not available in the type
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any;
|
||||
});
|
||||
|
||||
return (
|
||||
<AnimatedTextInput
|
||||
underlineColorAndroid="transparent"
|
||||
editable={false}
|
||||
value={text.value}
|
||||
style={[styles.baseStyle, defaultStyles.text, style]}
|
||||
{...{ animatedProps }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReText;
|
||||
36
src/components/Shadow.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
export const shadow = StyleSheet.create({
|
||||
small: {
|
||||
shadowColor: '#000',
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 2,
|
||||
},
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 2.62,
|
||||
elevation: 4,
|
||||
},
|
||||
medium: {
|
||||
shadowColor: '#000',
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 3,
|
||||
},
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 4.65,
|
||||
elevation: 6,
|
||||
}
|
||||
});
|
||||
|
||||
type SizeProp = 'small' | 'medium';
|
||||
|
||||
const shadowMap: Record<SizeProp, StyleSheet.NamedStyles<unknown>> = {
|
||||
'small': shadow.small,
|
||||
'medium': shadow.medium,
|
||||
};
|
||||
|
||||
export const ShadowWrapper = ({ children, size = 'small' }: PropsWithChildren<{ size?: SizeProp }>) => (
|
||||
<View style={shadowMap[size]}>{children}</View>
|
||||
);
|
||||
@@ -1,11 +0,0 @@
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import { Text as BaseText, TextProps } from 'react-native';
|
||||
import useDefaultStyles from './Colors';
|
||||
|
||||
export default function Text(props: PropsWithChildren<TextProps>) {
|
||||
const defaultStyles = useDefaultStyles();
|
||||
|
||||
return (
|
||||
<BaseText {...props} style={[defaultStyles.text, props.style]} />
|
||||
);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import styled from 'styled-components/native';
|
||||
import Text from './Text';
|
||||
|
||||
export const Header = styled(Text)`
|
||||
margin: 24px 0 12px 0;
|
||||
font-size: 36px;
|
||||
font-weight: bold;
|
||||
`;
|
||||
|
||||
export const SubHeader = styled(Text)`
|
||||
font-size: 24px;
|
||||
margin: 12px 0;
|
||||
font-weight: 500;
|
||||
`;
|
||||
26
src/components/Typography.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components/native';
|
||||
import { Text as BaseText, TextProps } from 'react-native';
|
||||
import { PropsWithChildren } from 'react';
|
||||
import useDefaultStyles from './Colors';
|
||||
|
||||
export function Text(props: PropsWithChildren<TextProps>) {
|
||||
const defaultStyles = useDefaultStyles();
|
||||
|
||||
return (
|
||||
<BaseText {...props} style={[defaultStyles.text, props.style]} />
|
||||
);
|
||||
}
|
||||
|
||||
export const Header = styled(Text)`
|
||||
margin: 0 0 6px 0;
|
||||
font-size: 28px;
|
||||
font-weight: 400;
|
||||
`;
|
||||
|
||||
export const SubHeader = styled(Text)`
|
||||
font-size: 16px;
|
||||
margin: 0 0 6px 0;
|
||||
font-weight: 400;
|
||||
opacity: 0.5;
|
||||
`;
|
||||
@@ -5,7 +5,7 @@ export const WrappableButtonRow = styled.View`
|
||||
flex: 0 0 auto;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin: 6px -2px;
|
||||
margin: 24px -2px;
|
||||
`;
|
||||
|
||||
export const WrappableButton = styled(Button)`
|
||||
|
||||
@@ -56,5 +56,8 @@
|
||||
"delete-playlist": "Delete Playlist",
|
||||
"total-download-size": "Total Download Size",
|
||||
"retry-failed-downloads": "Retry Failed Downloads",
|
||||
"you-are-offline-message": "You are currently offline. You can only play previously downloaded music."
|
||||
"you-are-offline-message": "You are currently offline. You can only play previously downloaded music.",
|
||||
"playing-on": "Playing on",
|
||||
"local-playback": "Local playback",
|
||||
"streaming": "Streaming"
|
||||
}
|
||||
@@ -56,6 +56,8 @@
|
||||
"delete-playlist": "Verwijder Playlist",
|
||||
"total-download-size": "Totale grootte downloads",
|
||||
"retry-failed-downloads": "Probeer Mislukte Downloads Opnieuw",
|
||||
"you-are-offline-message": "Je bent op dit moment offline. Je kunt alleen eerder gedownloade nummers afspelen."
|
||||
|
||||
"you-are-offline-message": "Je bent op dit moment offline. Je kunt alleen eerder gedownloade nummers afspelen.",
|
||||
"playing-on": "Speelt af op",
|
||||
"local-playback": "Lokaal afspelen",
|
||||
"streaming": "Streamen"
|
||||
}
|
||||
@@ -54,4 +54,7 @@ export type LocaleKeys = 'play-next'
|
||||
| 'total-download-size'
|
||||
| 'no-downloads'
|
||||
| 'retry-failed-downloads'
|
||||
| 'you-are-offline-message'
|
||||
| 'you-are-offline-message'
|
||||
| 'playing-on'
|
||||
| 'local-playback'
|
||||
| 'streaming'
|
||||
@@ -1,20 +1,22 @@
|
||||
import useDefaultStyles from 'components/Colors';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { FlatListProps, Text, TouchableOpacity, View } from 'react-native';
|
||||
import { FlatListProps, View } from 'react-native';
|
||||
import { FlatList } from 'react-native-gesture-handler';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { useTypedSelector } from 'store';
|
||||
import { useAppDispatch, useTypedSelector } from 'store';
|
||||
import formatBytes from 'utility/formatBytes';
|
||||
import TrashIcon from 'assets/trash.svg';
|
||||
import ArrowClockwise from 'assets/arrow-clockwise.svg';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import TrashIcon from 'assets/icons/trash.svg';
|
||||
import ArrowClockwise from 'assets/icons/arrow-clockwise.svg';
|
||||
import { EntityId } from '@reduxjs/toolkit';
|
||||
import { queueTrackForDownload, removeDownloadedTrack } from 'store/downloads/actions';
|
||||
import Button from 'components/Button';
|
||||
import { t } from 'i18n-js';
|
||||
import DownloadIcon from 'components/DownloadIcon';
|
||||
import styled from 'styled-components/native';
|
||||
import { Text } from 'components/Typography';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import { useGetImage } from 'utility/JellyfinApi';
|
||||
import { ShadowWrapper } from 'components/Shadow';
|
||||
|
||||
const DownloadedTrack = styled.View`
|
||||
flex: 1 0 auto;
|
||||
@@ -22,12 +24,18 @@ const DownloadedTrack = styled.View`
|
||||
padding: 8px 0;
|
||||
align-items: center;
|
||||
margin: 0 20px;
|
||||
border-bottom-width: 1px;
|
||||
`;
|
||||
|
||||
const AlbumImage = styled(FastImage)`
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
border-radius: 4px;
|
||||
`;
|
||||
|
||||
function Downloads() {
|
||||
const defaultStyles = useDefaultStyles();
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useAppDispatch();
|
||||
const getImage = useGetImage();
|
||||
|
||||
const { entities, ids } = useTypedSelector((state) => state.downloads);
|
||||
const tracks = useTypedSelector((state) => state.music.tracks.entities);
|
||||
@@ -65,57 +73,68 @@ function Downloads() {
|
||||
*/
|
||||
|
||||
const ListHeaderComponent = useMemo(() => (
|
||||
<View style={{ marginHorizontal: 20, marginBottom: 12 }}>
|
||||
<Text style={[{ textAlign: 'center', marginVertical: 6 }, defaultStyles.textHalfOpacity]}>
|
||||
{t('total-download-size')}: {formatBytes(totalDownloadSize)}
|
||||
</Text>
|
||||
<Button
|
||||
icon={TrashIcon}
|
||||
title={t('delete-all-tracks')}
|
||||
onPress={handleDeleteAllTracks}
|
||||
disabled={!ids.length}
|
||||
style={{ marginTop: 8 }}
|
||||
/>
|
||||
<Button
|
||||
icon={ArrowClockwise}
|
||||
title={t('retry-failed-downloads')}
|
||||
onPress={handleRetryFailed}
|
||||
disabled={failedIds.length === 0}
|
||||
style={{ marginTop: 4 }}
|
||||
/>
|
||||
<View style={[{ paddingHorizontal: 20, paddingBottom: 12, borderBottomWidth: 0.5 }, defaultStyles.border]}>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<Text
|
||||
style={[
|
||||
defaultStyles.textHalfOpacity,
|
||||
{ marginRight: 8, flex: 1, fontSize: 12 },
|
||||
]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{t('total-download-size')}: {formatBytes(totalDownloadSize)}
|
||||
</Text>
|
||||
<Button
|
||||
icon={TrashIcon}
|
||||
title={t('delete-all-tracks')}
|
||||
onPress={handleDeleteAllTracks}
|
||||
disabled={!ids.length}
|
||||
size="small"
|
||||
/>
|
||||
</View>
|
||||
{failedIds.length > 0 && (
|
||||
<Button
|
||||
icon={ArrowClockwise}
|
||||
title={t('retry-failed-downloads')}
|
||||
onPress={handleRetryFailed}
|
||||
disabled={failedIds.length === 0}
|
||||
style={{ marginTop: 4 }}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
), [totalDownloadSize, defaultStyles, failedIds.length, handleRetryFailed, handleDeleteAllTracks, ids.length]);
|
||||
|
||||
const renderItem = useCallback<NonNullable<FlatListProps<EntityId>['renderItem']>>(({ item }) => (
|
||||
<DownloadedTrack style={defaultStyles.border}>
|
||||
<DownloadedTrack>
|
||||
<View style={{ marginRight: 12 }}>
|
||||
<DownloadIcon trackId={item} />
|
||||
<ShadowWrapper size="small">
|
||||
<AlbumImage source={{ uri: getImage(item as string) }} style={defaultStyles.imageBackground} />
|
||||
</ShadowWrapper>
|
||||
</View>
|
||||
<View style={{ flexShrink: 1, marginRight: 8 }}>
|
||||
<Text style={[{ fontSize: 16, marginBottom: 4 }, defaultStyles.text]} numberOfLines={1}>
|
||||
{tracks[item]?.Name}
|
||||
</Text>
|
||||
<Text style={[{ flexShrink: 1, fontSize: 11 }, defaultStyles.textHalfOpacity]} numberOfLines={1}>
|
||||
{tracks[item]?.AlbumArtist} ({tracks[item]?.Album})
|
||||
{tracks[item]?.AlbumArtist} {tracks[item]?.Album ? `— ${tracks[item]?.Album}` : ''}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ marginLeft: 'auto', flexDirection: 'row', alignItems: 'center' }}>
|
||||
{entities[item]?.isComplete && entities[item]?.size ? (
|
||||
<Text style={[defaultStyles.textHalfOpacity, { marginRight: 6, fontSize: 12 }]}>
|
||||
<Text style={[defaultStyles.textQuarterOpacity, { marginRight: 12, fontSize: 12 }]}>
|
||||
{formatBytes(entities[item]?.size || 0)}
|
||||
</Text>
|
||||
) : null}
|
||||
<TouchableOpacity onPress={() => handleDelete(item)}>
|
||||
<TrashIcon height={24} width={24} fill={THEME_COLOR} />
|
||||
</TouchableOpacity>
|
||||
<View style={{ marginRight: 12 }}>
|
||||
<DownloadIcon trackId={item} />
|
||||
</View>
|
||||
<Button onPress={() => handleDelete(item)} size="small" icon={TrashIcon} />
|
||||
{!entities[item]?.isComplete && (
|
||||
<TouchableOpacity onPress={() => retryTrack(item)}>
|
||||
<ArrowClockwise height={18} width={18} fill={THEME_COLOR} />
|
||||
</TouchableOpacity>
|
||||
<Button onPress={() => retryTrack(item)} size="small" icon={ArrowClockwise} style={{ marginLeft: 4 }} />
|
||||
)}
|
||||
</View>
|
||||
</DownloadedTrack>
|
||||
), [entities, retryTrack, handleDelete, defaultStyles, tracks]);
|
||||
), [entities, retryTrack, handleDelete, defaultStyles, tracks, getImage]);
|
||||
|
||||
// If no tracks have been downloaded, show a short message describing this
|
||||
if (!ids.length) {
|
||||
@@ -130,11 +149,11 @@ function Downloads() {
|
||||
|
||||
return (
|
||||
<SafeAreaView style={{ flex: 1 }}>
|
||||
{ListHeaderComponent}
|
||||
<FlatList
|
||||
data={ids}
|
||||
style={{ flex: 1 }}
|
||||
style={{ flex: 1, paddingTop: 12 }}
|
||||
contentContainerStyle={{ flexGrow: 1 }}
|
||||
ListHeaderComponent={ListHeaderComponent}
|
||||
renderItem={renderItem}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import React from 'react';
|
||||
import { createStackNavigator } from '@react-navigation/stack';
|
||||
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
||||
import { MusicStackParams } from './types';
|
||||
import Albums from './stacks/Albums';
|
||||
import Album from './stacks/Album';
|
||||
import RecentAlbums from './stacks/RecentAlbums';
|
||||
import Search from './stacks/Search';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import { t } from '@localisation';
|
||||
import useDefaultStyles from 'components/Colors';
|
||||
import Playlists from './stacks/Playlists';
|
||||
import Playlist from './stacks/Playlist';
|
||||
import NowPlaying from './overlays/NowPlaying';
|
||||
|
||||
const Stack = createStackNavigator<MusicStackParams>();
|
||||
|
||||
@@ -17,17 +18,20 @@ function MusicStack() {
|
||||
const defaultStyles = useDefaultStyles();
|
||||
|
||||
return (
|
||||
<Stack.Navigator initialRouteName="RecentAlbums" screenOptions={{
|
||||
headerTintColor: THEME_COLOR,
|
||||
headerTitleStyle: defaultStyles.stackHeader
|
||||
}}>
|
||||
<Stack.Screen name="RecentAlbums" component={RecentAlbums} options={{ headerTitle: t('recent-albums') }} />
|
||||
<Stack.Screen name="Albums" component={Albums} options={{ headerTitle: t('albums') }} />
|
||||
<Stack.Screen name="Album" component={Album} options={{ headerTitle: t('album') }} />
|
||||
<Stack.Screen name="Playlists" component={Playlists} options={{ headerTitle: t('playlists') }} />
|
||||
<Stack.Screen name="Playlist" component={Playlist} options={{ headerTitle: t('playlist') }} />
|
||||
<Stack.Screen name="Search" component={Search} options={{ headerTitle: t('search') }} />
|
||||
</Stack.Navigator>
|
||||
<GestureHandlerRootView style={{ flex: 1 }}>
|
||||
<Stack.Navigator initialRouteName="RecentAlbums" screenOptions={{
|
||||
headerTintColor: THEME_COLOR,
|
||||
headerTitleStyle: defaultStyles.stackHeader,
|
||||
cardStyle: defaultStyles.view,
|
||||
}}>
|
||||
<Stack.Screen name="RecentAlbums" component={RecentAlbums} options={{ headerTitle: t('recent-albums') }} />
|
||||
<Stack.Screen name="Albums" component={Albums} options={{ headerTitle: t('albums') }} />
|
||||
<Stack.Screen name="Album" component={Album} options={{ headerTitle: t('album') }} />
|
||||
<Stack.Screen name="Playlists" component={Playlists} options={{ headerTitle: t('playlists') }} />
|
||||
<Stack.Screen name="Playlist" component={Playlist} options={{ headerTitle: t('playlist') }} />
|
||||
</Stack.Navigator>
|
||||
<NowPlaying />
|
||||
</GestureHandlerRootView>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
182
src/screens/Music/overlays/NowPlaying/index.tsx
Normal file
@@ -0,0 +1,182 @@
|
||||
import React, { useCallback, useEffect, useRef } from 'react';
|
||||
import { ActivityIndicator, Animated, Dimensions, Easing, Pressable, View } from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import styled, { css } from 'styled-components/native';
|
||||
|
||||
import PlayIcon from 'assets/icons/play.svg';
|
||||
import PauseIcon from 'assets/icons/pause.svg';
|
||||
import useCurrentTrack from 'utility/useCurrentTrack';
|
||||
import TrackPlayer, { State, usePlaybackState, useProgress } from 'react-native-track-player';
|
||||
import { Shadow } from 'react-native-shadow-2';
|
||||
import usePrevious from 'utility/usePrevious';
|
||||
import { Text } from 'components/Typography';
|
||||
|
||||
import useDefaultStyles, { ColoredBlurView } from 'components/Colors';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { calculateProgressTranslation } from 'components/Progresstrack';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import { MusicNavigationProp } from 'screens/Music/types';
|
||||
import { ShadowWrapper } from 'components/Shadow';
|
||||
|
||||
const NOW_PLAYING_POPOVER_MARGIN = 6;
|
||||
const NOW_PLAYING_POPOVER_WIDTH = Dimensions.get('screen').width - 2 * NOW_PLAYING_POPOVER_MARGIN;
|
||||
|
||||
const PopoverPosition = css`
|
||||
position: absolute;
|
||||
bottom: ${NOW_PLAYING_POPOVER_MARGIN}px;
|
||||
left: ${NOW_PLAYING_POPOVER_MARGIN}px;
|
||||
right: ${NOW_PLAYING_POPOVER_MARGIN}px;
|
||||
border-radius: 8px;
|
||||
overflow: visible;
|
||||
`;
|
||||
|
||||
const Container = styled.ScrollView`
|
||||
${PopoverPosition};
|
||||
`;
|
||||
|
||||
const InnerContainer = styled.TouchableOpacity`
|
||||
padding: 12px;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const ProgressTrack = styled(Animated.View)<{ stroke?: number; opacity?: number}>`
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: ${(props) => props.stroke ? props.stroke + 'px' : '100%'};
|
||||
background-color: ${THEME_COLOR};
|
||||
opacity: ${(props) => props.opacity || 1};
|
||||
border-radius: 99px;
|
||||
`;
|
||||
|
||||
const ShadowOverlay = styled.View`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
`;
|
||||
|
||||
const Cover = styled(FastImage)`
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
border-radius: 4px;
|
||||
margin-right: 12px;
|
||||
`;
|
||||
|
||||
const TrackNameContainer = styled.View`
|
||||
flex: 1;
|
||||
margin-right: 12px;
|
||||
`;
|
||||
|
||||
const ActionButton = styled.Pressable`
|
||||
margin-right: 8px;
|
||||
`;
|
||||
|
||||
function SelectActionButton() {
|
||||
const state = usePlaybackState();
|
||||
const defaultStyles = useDefaultStyles();
|
||||
|
||||
switch(state) {
|
||||
case State.Playing:
|
||||
return (
|
||||
<Pressable onPress={TrackPlayer.pause}>
|
||||
<PauseIcon fill={defaultStyles.text.color} height={18} width={18} />
|
||||
</Pressable>
|
||||
);
|
||||
case State.Stopped:
|
||||
case State.Paused:
|
||||
return (
|
||||
<Pressable onPress={TrackPlayer.play}>
|
||||
<PlayIcon fill={defaultStyles.text.color} height={18} width={18} />
|
||||
</Pressable>
|
||||
);
|
||||
// @ts-expect-error For some reason buffering isn't stated right in the types
|
||||
case 'buffering':
|
||||
case State.Buffering:
|
||||
case State.Connecting:
|
||||
return (
|
||||
<Pressable onPress={TrackPlayer.stop}>
|
||||
<ActivityIndicator />
|
||||
</Pressable>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function NowPlaying() {
|
||||
const { index, track } = useCurrentTrack();
|
||||
const { buffered, duration, position } = useProgress();
|
||||
const defaultStyles = useDefaultStyles();
|
||||
const previousIndex = usePrevious(index);
|
||||
const navigation = useNavigation<MusicNavigationProp>();
|
||||
|
||||
const bufferAnimation = useRef(new Animated.Value(0));
|
||||
const progressAnimation = useRef(new Animated.Value(0));
|
||||
|
||||
const openNowPlayingModal = useCallback(() => {
|
||||
navigation.navigate('Player');
|
||||
}, [navigation]);
|
||||
|
||||
useEffect(() => {
|
||||
const hasChangedTrack = previousIndex !== index || duration === 0;
|
||||
|
||||
Animated.timing(bufferAnimation.current, {
|
||||
toValue: calculateProgressTranslation(buffered, duration, NOW_PLAYING_POPOVER_WIDTH),
|
||||
duration: hasChangedTrack ? 0 : 500,
|
||||
useNativeDriver: true,
|
||||
easing: Easing.ease,
|
||||
}).start();
|
||||
Animated.timing(progressAnimation.current, {
|
||||
toValue: calculateProgressTranslation(position, duration, NOW_PLAYING_POPOVER_WIDTH),
|
||||
duration: hasChangedTrack ? 0 : 500,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
}, [buffered, duration, position, index, previousIndex]);
|
||||
|
||||
if (!track) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<ShadowOverlay pointerEvents='none'>
|
||||
<Shadow distance={30} viewStyle={{ alignSelf: 'stretch', flexBasis: '100%' }} startColor="#00000017">
|
||||
<View style={{ flex: 1, borderRadius: 8 }} />
|
||||
</Shadow>
|
||||
</ShadowOverlay>
|
||||
<ColoredBlurView style={{ borderRadius: 8 }}>
|
||||
<InnerContainer onPress={openNowPlayingModal} activeOpacity={0.5}>
|
||||
<ShadowWrapper size="small">
|
||||
<Cover source={{ uri: (track.artwork || '') as string }} style={defaultStyles.imageBackground} />
|
||||
</ShadowWrapper>
|
||||
<TrackNameContainer>
|
||||
<Text numberOfLines={1}>{track.title}</Text>
|
||||
<Text style={{ opacity: 0.5 }} numberOfLines={1}>
|
||||
{track.artist}{track.album ? ` — ${track.album}` : ''}
|
||||
</Text>
|
||||
</TrackNameContainer>
|
||||
<ActionButton>
|
||||
<SelectActionButton />
|
||||
</ActionButton>
|
||||
<ProgressTrack
|
||||
style={{ transform: [{ translateX: bufferAnimation.current }]}}
|
||||
opacity={0.15}
|
||||
stroke={4}
|
||||
/>
|
||||
<ProgressTrack
|
||||
style={{ transform: [{ translateX: progressAnimation.current }]}}
|
||||
stroke={4}
|
||||
/>
|
||||
</InnerContainer>
|
||||
</ColoredBlurView>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default NowPlaying;
|
||||
@@ -1,19 +1,18 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { MusicStackParams } from '../types';
|
||||
import { useRoute, RouteProp } from '@react-navigation/native';
|
||||
import { useTypedSelector } from 'store';
|
||||
import { useAppDispatch, useTypedSelector } from 'store';
|
||||
import TrackListView from './components/TrackListView';
|
||||
import { fetchTracksByAlbum } from 'store/music/actions';
|
||||
import { differenceInDays } from 'date-fns';
|
||||
import { ALBUM_CACHE_AMOUNT_OF_DAYS } from 'CONSTANTS';
|
||||
import { t } from '@localisation';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
type Route = RouteProp<MusicStackParams, 'Album'>;
|
||||
|
||||
const Album: React.FC = () => {
|
||||
const { params: { id } } = useRoute<Route>();
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
// Retrieve the album data from the store
|
||||
const album = useTypedSelector((state) => state.music.albums.entities[id]);
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
import React, { useCallback, useEffect, useRef, ReactText } from 'react';
|
||||
import { useGetImage } from 'utility/JellyfinApi';
|
||||
import { MusicNavigationProp } from '../types';
|
||||
import { Text, SafeAreaView, SectionList, View } from 'react-native';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { SafeAreaView, SectionList, View } from 'react-native';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { differenceInDays } from 'date-fns';
|
||||
import { useTypedSelector } from 'store';
|
||||
import { useAppDispatch, useTypedSelector } from 'store';
|
||||
import { fetchAllAlbums } from 'store/music/actions';
|
||||
import { ALBUM_CACHE_AMOUNT_OF_DAYS } from 'CONSTANTS';
|
||||
import TouchableHandler from 'components/TouchableHandler';
|
||||
import AlbumImage, { AlbumItem } from './components/AlbumImage';
|
||||
import AlbumImage, { AlbumHeight, AlbumItem } from './components/AlbumImage';
|
||||
import { selectAlbumsByAlphabet, SectionedId } from 'store/music/selectors';
|
||||
import AlphabetScroller from 'components/AlphabetScroller';
|
||||
import { EntityId } from '@reduxjs/toolkit';
|
||||
import styled from 'styled-components/native';
|
||||
import useDefaultStyles from 'components/Colors';
|
||||
import useDefaultStyles, { ColoredBlurView } from 'components/Colors';
|
||||
import { Album } from 'store/music/types';
|
||||
import { Text } from 'components/Typography';
|
||||
import { ShadowWrapper } from 'components/Shadow';
|
||||
|
||||
const HeadingHeight = 50;
|
||||
|
||||
interface VirtualizedItemInfo {
|
||||
section: SectionedId,
|
||||
@@ -40,25 +43,25 @@ function generateSection({ section }: { section: SectionedId }) {
|
||||
}
|
||||
|
||||
const SectionContainer = styled.View`
|
||||
border-bottom-width: 1px;
|
||||
height: 50px;
|
||||
height: ${HeadingHeight}px;
|
||||
justify-content: center;
|
||||
padding: 0 10px;
|
||||
padding: 0 24px;
|
||||
`;
|
||||
|
||||
const SectionText = styled.Text`
|
||||
const SectionText = styled(Text)`
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
font-weight: 400;
|
||||
`;
|
||||
|
||||
const SectionHeading = React.memo(function SectionHeading(props: { label: string }) {
|
||||
const defaultStyles = useDefaultStyles();
|
||||
const { label } = props;
|
||||
|
||||
return (
|
||||
<SectionContainer style={defaultStyles.sectionHeading}>
|
||||
<SectionText style={defaultStyles.text}>{label}</SectionText>
|
||||
</SectionContainer>
|
||||
<ColoredBlurView>
|
||||
<SectionContainer>
|
||||
<SectionText>{label}</SectionText>
|
||||
</SectionContainer>
|
||||
</ColoredBlurView>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -81,7 +84,9 @@ const GeneratedAlbumItem = React.memo(function GeneratedAlbumItem(props: Generat
|
||||
return (
|
||||
<TouchableHandler id={id as string} onPress={onPress}>
|
||||
<AlbumItem>
|
||||
<AlbumImage source={{ uri: imageUrl }} style={defaultStyles.imageBackground} />
|
||||
<ShadowWrapper size="medium">
|
||||
<AlbumImage source={{ uri: imageUrl }} style={[defaultStyles.imageBackground]} />
|
||||
</ShadowWrapper>
|
||||
<Text numberOfLines={1} style={defaultStyles.text}>{name}</Text>
|
||||
<HalfOpacity style={defaultStyles.text} numberOfLines={1}>{artist}</HalfOpacity>
|
||||
</AlbumItem>
|
||||
@@ -97,7 +102,7 @@ const Albums: React.FC = () => {
|
||||
const sections = useTypedSelector(selectAlbumsByAlphabet);
|
||||
|
||||
// Initialise helpers
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useAppDispatch();
|
||||
const navigation = useNavigation<MusicNavigationProp>();
|
||||
const getImage = useGetImage();
|
||||
const listRef = useRef<SectionList<EntityId>>(null);
|
||||
@@ -118,21 +123,20 @@ const Albums: React.FC = () => {
|
||||
|
||||
// We can then determine the "length" (=height) of this item. Header items
|
||||
// end up with an itemIndex of -1, thus are easy to identify.
|
||||
const length = header ? 50 : (itemIndex % 2 === 0 ? 220 : 0);
|
||||
const length = header ? 50 : (itemIndex % 2 === 0 ? AlbumHeight : 0);
|
||||
|
||||
// We'll also need to account for any unevenly-ended lists up until the
|
||||
// current item.
|
||||
const previousRows = data?.filter((row, i) => i < sectionIndex)
|
||||
.reduce((sum, row) => sum + Math.ceil(row.data.length / 2), 0) || 0;
|
||||
|
||||
|
||||
// We must also calcuate the offset, total distance from the top of the
|
||||
// screen. First off, we'll account for each sectionIndex that is shown up
|
||||
// until now. This only includes the heading for the current section if the
|
||||
// item is not the section header
|
||||
const headingOffset = 50 * (header ? sectionIndex : sectionIndex + 1);
|
||||
const headingOffset = HeadingHeight * (header ? sectionIndex : sectionIndex + 1);
|
||||
const currentRows = itemIndex > 1 ? Math.ceil((itemIndex + 1) / 2) : 0;
|
||||
const itemOffset = 220 * (previousRows + currentRows);
|
||||
const itemOffset = AlbumHeight * (previousRows + currentRows);
|
||||
const offset = headingOffset + itemOffset;
|
||||
|
||||
return { index, length, offset };
|
||||
@@ -189,7 +193,7 @@ const Albums: React.FC = () => {
|
||||
onRefresh={retrieveData}
|
||||
getItemLayout={getItemLayout}
|
||||
ref={listRef}
|
||||
keyExtractor={(item, index) => `${item}_${index}`}
|
||||
keyExtractor={(item) => item as string}
|
||||
renderSectionHeader={generateSection}
|
||||
renderItem={generateItem}
|
||||
/>
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { MusicStackParams } from '../types';
|
||||
import { useRoute, RouteProp } from '@react-navigation/native';
|
||||
import { useTypedSelector } from 'store';
|
||||
import { useAppDispatch, useTypedSelector } from 'store';
|
||||
import TrackListView from './components/TrackListView';
|
||||
import { fetchTracksByPlaylist } from 'store/music/actions';
|
||||
import { differenceInDays } from 'date-fns';
|
||||
import { ALBUM_CACHE_AMOUNT_OF_DAYS } from 'CONSTANTS';
|
||||
import { t } from '@localisation';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
type Route = RouteProp<MusicStackParams, 'Album'>;
|
||||
|
||||
const Playlist: React.FC = () => {
|
||||
const { params: { id } } = useRoute<Route>();
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
// Retrieve the album data from the store
|
||||
const playlist = useTypedSelector((state) => state.music.playlists.entities[id]);
|
||||
|
||||
@@ -2,10 +2,9 @@ import React, { useCallback, useEffect, useRef, ReactText } from 'react';
|
||||
import { useGetImage } from 'utility/JellyfinApi';
|
||||
import { MusicNavigationProp } from '../types';
|
||||
import { Text, View, FlatList, ListRenderItem } from 'react-native';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { differenceInDays } from 'date-fns';
|
||||
import { useTypedSelector } from 'store';
|
||||
import { useAppDispatch, useTypedSelector } from 'store';
|
||||
import { fetchAllPlaylists } from 'store/music/actions';
|
||||
import { PLAYLIST_CACHE_AMOUNT_OF_DAYS } from 'CONSTANTS';
|
||||
import TouchableHandler from 'components/TouchableHandler';
|
||||
@@ -41,7 +40,7 @@ const Playlists: React.FC = () => {
|
||||
const lastRefreshed = useTypedSelector((state) => state.music.playlists.lastRefreshed);
|
||||
|
||||
// Initialise helpers
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useAppDispatch();
|
||||
const navigation = useNavigation<MusicNavigationProp>();
|
||||
const getImage = useGetImage();
|
||||
const listRef = useRef<FlatList<EntityId>>(null);
|
||||
|
||||
@@ -2,9 +2,8 @@ import React, { useCallback, useEffect } from 'react';
|
||||
import { useGetImage } from 'utility/JellyfinApi';
|
||||
import { MusicNavigationProp } from '../types';
|
||||
import { Text, SafeAreaView, FlatList, StyleSheet } from 'react-native';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { useTypedSelector } from 'store';
|
||||
import { useAppDispatch, useTypedSelector } from 'store';
|
||||
import { fetchRecentAlbums } from 'store/music/actions';
|
||||
import TouchableHandler from 'components/TouchableHandler';
|
||||
import ListContainer from './components/ListContainer';
|
||||
@@ -15,28 +14,36 @@ import ListButton from 'components/ListButton';
|
||||
import { t } from '@localisation';
|
||||
import useDefaultStyles from 'components/Colors';
|
||||
import { Album } from 'store/music/types';
|
||||
import Divider from 'components/Divider';
|
||||
import styled from 'styled-components/native';
|
||||
import { ShadowWrapper } from 'components/Shadow';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
columnWrapper: {
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10
|
||||
paddingHorizontal: 16,
|
||||
}
|
||||
});
|
||||
|
||||
const HeaderContainer = styled.View`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const NavigationHeader: React.FC = () => {
|
||||
const navigation = useNavigation<MusicNavigationProp>();
|
||||
const defaultStyles = useDefaultStyles();
|
||||
const handleAllAlbumsClick = useCallback(() => { navigation.navigate('Albums'); }, [navigation]);
|
||||
const handlePlaylistsClick = useCallback(() => { navigation.navigate('Playlists'); }, [navigation]);
|
||||
const handleSearchClick = useCallback(() => { navigation.navigate('Search'); }, [navigation]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ListButton onPress={handleAllAlbumsClick}>{t('all-albums')}</ListButton>
|
||||
<ListButton onPress={handlePlaylistsClick}>{t('playlists')}</ListButton>
|
||||
<ListButton onPress={handleSearchClick}>{t('search')}</ListButton>
|
||||
<ListContainer>
|
||||
<Header style={defaultStyles.text}>{t('recent-albums')}</Header>
|
||||
<HeaderContainer>
|
||||
<Header>{t('recent-albums')}</Header>
|
||||
<Divider style={{ marginLeft: 24 }} />
|
||||
</HeaderContainer>
|
||||
</ListContainer>
|
||||
</>
|
||||
);
|
||||
@@ -51,7 +58,7 @@ const RecentAlbums: React.FC = () => {
|
||||
const isLoading = useTypedSelector((state) => state.music.albums.isLoading);
|
||||
|
||||
// Initialise helpers
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useAppDispatch();
|
||||
const navigation = useNavigation<MusicNavigationProp>();
|
||||
const getImage = useGetImage();
|
||||
|
||||
@@ -75,7 +82,9 @@ const RecentAlbums: React.FC = () => {
|
||||
renderItem={({ item }) => (
|
||||
<TouchableHandler id={item} onPress={selectAlbum}>
|
||||
<AlbumItem>
|
||||
<AlbumImage source={{ uri: getImage(item) }} style={defaultStyles.imageBackground} />
|
||||
<ShadowWrapper size="medium">
|
||||
<AlbumImage source={{ uri: getImage(item) }} style={defaultStyles.imageBackground} />
|
||||
</ShadowWrapper>
|
||||
<Text style={defaultStyles.text} numberOfLines={1}>{albums[item]?.Name}</Text>
|
||||
<Text style={defaultStyles.textHalfOpacity} numberOfLines={1}>{albums[item]?.AlbumArtist}</Text>
|
||||
</AlbumItem>
|
||||
|
||||
@@ -3,17 +3,20 @@ import FastImage from 'react-native-fast-image';
|
||||
import { Dimensions } from 'react-native';
|
||||
|
||||
const Screen = Dimensions.get('screen');
|
||||
export const AlbumWidth = Screen.width / 2 - 24;
|
||||
export const AlbumHeight = AlbumWidth + 40;
|
||||
export const CoverSize = AlbumWidth - 16;
|
||||
|
||||
export const AlbumItem = styled.View`
|
||||
width: ${Screen.width / 2 - 10}px;
|
||||
padding: 10px;
|
||||
height: 220px;
|
||||
width: ${AlbumWidth}px;
|
||||
height: ${AlbumHeight}px;
|
||||
padding: 8px;
|
||||
`;
|
||||
|
||||
const AlbumImage = styled(FastImage)`
|
||||
border-radius: 10px;
|
||||
width: ${Screen.width / 2 - 40}px;
|
||||
height: ${Screen.width / 2 - 40}px;
|
||||
width: ${CoverSize}px;
|
||||
height: ${CoverSize}px;
|
||||
margin-bottom: 5px;
|
||||
`;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import styled from 'styled-components/native';
|
||||
|
||||
const ListContainer = styled.View`
|
||||
padding: 10px;
|
||||
padding: 24px;
|
||||
`;
|
||||
|
||||
export default ListContainer;
|
||||
@@ -1,62 +1,56 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { Text, ScrollView, Dimensions, RefreshControl, StyleSheet, View } from 'react-native';
|
||||
import { ScrollView, RefreshControl, StyleSheet, View } from 'react-native';
|
||||
import { useGetImage } from 'utility/JellyfinApi';
|
||||
import styled, { css } from 'styled-components/native';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import { useTypedSelector } from 'store';
|
||||
import { useAppDispatch, useTypedSelector } from 'store';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import TouchableHandler from 'components/TouchableHandler';
|
||||
import useCurrentTrack from 'utility/useCurrentTrack';
|
||||
import TrackPlayer from 'react-native-track-player';
|
||||
import Play from 'assets/play.svg';
|
||||
import Shuffle from 'assets/shuffle.svg';
|
||||
import Play from 'assets/icons/play.svg';
|
||||
import Shuffle from 'assets/icons/shuffle.svg';
|
||||
import useDefaultStyles from 'components/Colors';
|
||||
import usePlayTracks from 'utility/usePlayTracks';
|
||||
import { EntityId } from '@reduxjs/toolkit';
|
||||
import { WrappableButtonRow, WrappableButton } from 'components/WrappableButtonRow';
|
||||
import { MusicNavigationProp } from 'screens/Music/types';
|
||||
import DownloadIcon from 'components/DownloadIcon';
|
||||
import CloudDownArrow from 'assets/cloud-down-arrow.svg';
|
||||
import Trash from 'assets/trash.svg';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import CloudDownArrow from 'assets/icons/cloud-down-arrow.svg';
|
||||
import Trash from 'assets/icons/trash.svg';
|
||||
import { queueTrackForDownload, removeDownloadedTrack } from 'store/downloads/actions';
|
||||
import { selectDownloadedTracks } from 'store/downloads/selectors';
|
||||
import { Header, SubHeader } from 'components/Typography';
|
||||
import { Text } from 'components/Typography';
|
||||
|
||||
const Screen = Dimensions.get('screen');
|
||||
import CoverImage from 'components/CoverImage';
|
||||
import ticksToDuration from 'utility/ticksToDuration';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
name: {
|
||||
fontSize: 36,
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
artist: {
|
||||
fontSize: 24,
|
||||
opacity: 0.5,
|
||||
marginBottom: 12
|
||||
},
|
||||
index: {
|
||||
width: 20,
|
||||
opacity: 0.5,
|
||||
marginRight: 5
|
||||
}
|
||||
width: 16,
|
||||
marginRight: 8
|
||||
},
|
||||
activeText: {
|
||||
color: THEME_COLOR,
|
||||
fontWeight: '500',
|
||||
},
|
||||
});
|
||||
|
||||
const AlbumImage = styled(FastImage)`
|
||||
border-radius: 10px;
|
||||
width: ${Screen.width * 0.6}px;
|
||||
height: ${Screen.width * 0.6}px;
|
||||
margin: 10px auto;
|
||||
const AlbumImageContainer = styled.View`
|
||||
margin: 0 12px 24px 12px;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const TrackContainer = styled.View<{isPlaying: boolean}>`
|
||||
padding: 15px 4px;
|
||||
border-bottom-width: 1px;
|
||||
const TrackContainer = styled.View<{ isPlaying: boolean }>`
|
||||
padding: 12px 4px;
|
||||
flex-direction: row;
|
||||
border-radius: 6px;
|
||||
|
||||
${props => props.isPlaying && css`
|
||||
margin: 0 -20px;
|
||||
padding: 15px 24px;
|
||||
margin: 0 -12px;
|
||||
padding: 12px 16px;
|
||||
`}
|
||||
`;
|
||||
|
||||
@@ -97,7 +91,7 @@ const TrackListView: React.FC<TrackListViewProps> = ({
|
||||
const playTracks = usePlayTracks();
|
||||
const { track: currentTrack } = useCurrentTrack();
|
||||
const navigation = useNavigation<MusicNavigationProp>();
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
// Setup callbacks
|
||||
const playEntity = useCallback(() => { playTracks(trackIds); }, [playTracks, trackIds]);
|
||||
@@ -119,14 +113,17 @@ const TrackListView: React.FC<TrackListViewProps> = ({
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
contentContainerStyle={{ padding: 20, paddingBottom: 50 }}
|
||||
style={defaultStyles.view}
|
||||
contentContainerStyle={{ padding: 24, paddingTop: 32, paddingBottom: 64 }}
|
||||
refreshControl={
|
||||
<RefreshControl refreshing={isLoading} onRefresh={refresh} />
|
||||
}
|
||||
>
|
||||
<AlbumImage source={{ uri: getImage(entityId) }} style={defaultStyles.imageBackground} />
|
||||
<Text style={[ defaultStyles.text, styles.name ]} >{title}</Text>
|
||||
<Text style={[ defaultStyles.text, styles.artist ]}>{artist}</Text>
|
||||
<AlbumImageContainer>
|
||||
<CoverImage src={getImage(entityId)} />
|
||||
</AlbumImageContainer>
|
||||
<Header>{title}</Header>
|
||||
<SubHeader>{artist}</SubHeader>
|
||||
<WrappableButtonRow>
|
||||
<WrappableButton title={playButtonText} icon={Play} onPress={playEntity} />
|
||||
<WrappableButton title={shuffleButtonText} icon={Shuffle} onPress={shuffleEntity} />
|
||||
@@ -145,28 +142,37 @@ const TrackListView: React.FC<TrackListViewProps> = ({
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
defaultStyles.text,
|
||||
styles.index,
|
||||
currentTrack?.backendId === trackId && {
|
||||
color: THEME_COLOR,
|
||||
opacity: 1
|
||||
}
|
||||
{ opacity: 0.25 },
|
||||
currentTrack?.backendId === trackId && styles.activeText
|
||||
]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{listNumberingStyle === 'index'
|
||||
? i + 1
|
||||
: tracks[trackId]?.IndexNumber}
|
||||
</Text>
|
||||
<Text
|
||||
style={currentTrack?.backendId === trackId
|
||||
? { color: THEME_COLOR, fontWeight: '700' }
|
||||
: defaultStyles.text
|
||||
}
|
||||
style={{
|
||||
...currentTrack?.backendId === trackId && styles.activeText,
|
||||
flexShrink: 1,
|
||||
marginRight: 4,
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{tracks[trackId]?.Name}
|
||||
</Text>
|
||||
<View style={{ marginLeft: 'auto' }}>
|
||||
<DownloadIcon trackId={trackId} />
|
||||
<View style={{ marginLeft: 'auto', flexDirection: 'row' }}>
|
||||
<Text
|
||||
style={[
|
||||
{ marginRight: 12, opacity: 0.25 },
|
||||
currentTrack?.backendId === trackId && styles.activeText
|
||||
]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{ticksToDuration(tracks[trackId]?.RunTimeTicks || 0)}
|
||||
</Text>
|
||||
<DownloadIcon trackId={trackId} fill={currentTrack?.backendId === trackId ? `${THEME_COLOR}44` : undefined} />
|
||||
</View>
|
||||
</TrackContainer>
|
||||
</TouchableHandler>
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import styled from 'styled-components/native';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { NavigationProp } from 'screens';
|
||||
import { useTypedSelector } from 'store';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useAppDispatch, useTypedSelector } from 'store';
|
||||
import { setOnboardingStatus } from 'store/settings/actions';
|
||||
import { t } from '@localisation';
|
||||
import Button from 'components/Button';
|
||||
import { Header, Text as BaseText } from 'components/Typography';
|
||||
import { ShadowWrapper } from 'components/Shadow';
|
||||
|
||||
const Container = styled.SafeAreaView`
|
||||
background-color: ${THEME_COLOR};
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
`;
|
||||
@@ -19,10 +18,9 @@ const TextContainer = styled.ScrollView`
|
||||
padding: 25px;
|
||||
`;
|
||||
|
||||
const Text = styled.Text`
|
||||
const Text = styled(BaseText)`
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 16px;
|
||||
`;
|
||||
|
||||
const ButtonContainer = styled.View`
|
||||
@@ -33,12 +31,14 @@ const Logo = styled.Image`
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
margin: 0 auto 50px auto;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #e6e6e6;
|
||||
`;
|
||||
|
||||
function Onboarding() {
|
||||
// Get account from Redux and dispatcher
|
||||
const account = useTypedSelector(state => state.settings.jellyfin);
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
// Also retrieve the navigation handler so that we can open the modal in
|
||||
// which the Jellyfin server is set
|
||||
@@ -56,10 +56,12 @@ function Onboarding() {
|
||||
return (
|
||||
<Container>
|
||||
<TextContainer contentContainerStyle={{ flexGrow: 1, justifyContent: 'center' }}>
|
||||
<Logo source={require('../../assets/app-icon-white.png')} />
|
||||
<Text >
|
||||
<ShadowWrapper size="medium">
|
||||
<Logo source={require('../../assets/icons/app-icon.png')} />
|
||||
</ShadowWrapper>
|
||||
<Header style={{ textAlign: 'center', marginBottom: 24 }}>
|
||||
{t('onboarding-welcome')}
|
||||
</Text>
|
||||
</Header>
|
||||
<Text>
|
||||
{t('onboarding-intro')}
|
||||
</Text>
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import React from 'react';
|
||||
import AirPlayButton from 'react-native-airplay-button';
|
||||
import styled from 'styled-components/native';
|
||||
import { CastingProps } from './Casting';
|
||||
|
||||
const Button = styled.View`
|
||||
margin: 20px 40px;
|
||||
`;
|
||||
|
||||
function Casting({ fill }: CastingProps) {
|
||||
return (
|
||||
<>
|
||||
<Button>
|
||||
<AirPlayButton
|
||||
activeTintColor={THEME_COLOR}
|
||||
tintColor={fill}
|
||||
style={{ width: 40, height: 40 }}
|
||||
/>
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Casting;
|
||||
@@ -1,51 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Dimensions, View, StyleSheet } from 'react-native';
|
||||
import useCurrentTrack from 'utility/useCurrentTrack';
|
||||
import styled from 'styled-components/native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import useDefaultStyles from 'components/Colors';
|
||||
import Text from 'components/Text';
|
||||
|
||||
const Screen = Dimensions.get('screen');
|
||||
|
||||
const Artwork = styled(FastImage)`
|
||||
border-radius: 10px;
|
||||
width: ${Screen.width * 0.8}px;
|
||||
height: ${Screen.width * 0.8}px;
|
||||
margin: 25px auto;
|
||||
`;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
artist: {
|
||||
fontWeight: 'bold',
|
||||
fontSize: 24,
|
||||
marginBottom: 12,
|
||||
},
|
||||
title: {
|
||||
fontSize: 18,
|
||||
marginBottom: 12,
|
||||
textAlign: 'center',
|
||||
paddingLeft: 20,
|
||||
paddingRight: 20,
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export default function NowPlaying() {
|
||||
const { track } = useCurrentTrack();
|
||||
const defaultStyles = useDefaultStyles();
|
||||
|
||||
return (
|
||||
<View style={{ alignItems: 'center' }}>
|
||||
<Artwork
|
||||
style={defaultStyles.imageBackground}
|
||||
source={{
|
||||
uri: track?.artwork as string | undefined,
|
||||
priority: FastImage.priority.high,
|
||||
}}
|
||||
/>
|
||||
<Text style={styles.artist}>{track?.artist}</Text>
|
||||
<Text style={styles.title}>{track?.title}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import TrackPlayer from 'react-native-track-player';
|
||||
import styled from 'styled-components/native';
|
||||
import { Text, Platform } from 'react-native';
|
||||
import Slider from '@react-native-community/slider';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import { DefaultStylesProvider } from 'components/Colors';
|
||||
|
||||
const NumberBar = styled.View`
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 20px 0;
|
||||
`;
|
||||
|
||||
function getSeconds(seconds: number): string {
|
||||
return Math.floor(seconds % 60).toString().padStart(2, '0');
|
||||
}
|
||||
|
||||
function getMinutes(seconds: number): number {
|
||||
return Math.floor(seconds / 60);
|
||||
}
|
||||
|
||||
interface State {
|
||||
position: number;
|
||||
duration: number;
|
||||
gesture?: number;
|
||||
}
|
||||
|
||||
export default class ProgressBar extends Component<{}, State> {
|
||||
state: State = {
|
||||
position: 0,
|
||||
duration: 0,
|
||||
};
|
||||
|
||||
timer: number | null = null;
|
||||
|
||||
componentDidMount() {
|
||||
this.timer = setInterval(this.updateProgress, 500);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer);
|
||||
}
|
||||
}
|
||||
|
||||
updateProgress = async () => {
|
||||
const [position, duration] = await Promise.all([
|
||||
TrackPlayer.getPosition(),
|
||||
TrackPlayer.getDuration(),
|
||||
]);
|
||||
|
||||
this.setState({ position, duration });
|
||||
};
|
||||
|
||||
handleGesture = async (gesture: number) => {
|
||||
// Set relative translation in state
|
||||
this.setState({ gesture });
|
||||
};
|
||||
|
||||
handleEndOfGesture = (position: number) => {
|
||||
// Calculate and set the new position
|
||||
TrackPlayer.seekTo(position);
|
||||
this.setState({ gesture: undefined, position });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { position, duration, gesture } = this.state;
|
||||
|
||||
return (
|
||||
<DefaultStylesProvider>
|
||||
{defaultStyle => (
|
||||
<>
|
||||
<Slider
|
||||
value={gesture || position}
|
||||
minimumValue={0}
|
||||
maximumValue={duration || 0}
|
||||
onValueChange={this.handleGesture}
|
||||
onSlidingComplete={this.handleEndOfGesture}
|
||||
minimumTrackTintColor={THEME_COLOR}
|
||||
thumbTintColor={Platform.OS === 'android' ? THEME_COLOR : undefined}
|
||||
disabled={!duration}
|
||||
/>
|
||||
<NumberBar>
|
||||
<Text style={defaultStyle.text}>{getMinutes(gesture || position)}:{getSeconds(gesture || position)}</Text>
|
||||
<Text style={defaultStyle.text}>{getMinutes(duration)}:{getSeconds(duration)}</Text>
|
||||
</NumberBar>
|
||||
</>
|
||||
)
|
||||
}
|
||||
</DefaultStylesProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import useQueue from 'utility/useQueue';
|
||||
import { View, StyleSheet } from 'react-native';
|
||||
import styled, { css } from 'styled-components/native';
|
||||
import useCurrentTrack from 'utility/useCurrentTrack';
|
||||
import TouchableHandler from 'components/TouchableHandler';
|
||||
import TrackPlayer from 'react-native-track-player';
|
||||
import { t } from '@localisation';
|
||||
import useDefaultStyles from 'components/Colors';
|
||||
import Text from 'components/Text';
|
||||
import Button from 'components/Button';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import DownloadIcon from 'components/DownloadIcon';
|
||||
|
||||
const QueueItem = styled.View<{ active?: boolean, alreadyPlayed?: boolean, isDark?: boolean }>`
|
||||
padding: 10px;
|
||||
border-bottom-width: 1px;
|
||||
flex: 0 0 auto;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
${props => props.active && css`
|
||||
font-weight: 900;
|
||||
padding: 20px 35px;
|
||||
margin: 0 -25px;
|
||||
`}
|
||||
|
||||
${props => props.alreadyPlayed && css`
|
||||
opacity: 0.5;
|
||||
`}
|
||||
`;
|
||||
|
||||
const ClearQueue = styled.View`
|
||||
margin: 20px 0;
|
||||
`;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
trackTitle: {
|
||||
marginBottom: 2
|
||||
}
|
||||
});
|
||||
|
||||
export default function Queue() {
|
||||
const defaultStyles = useDefaultStyles();
|
||||
const queue = useQueue();
|
||||
const { index: currentIndex } = useCurrentTrack();
|
||||
const playTrack = useCallback(async (index: number) => {
|
||||
await TrackPlayer.skip(index);
|
||||
await TrackPlayer.play();
|
||||
}, []);
|
||||
const clearQueue = useCallback(async () => {
|
||||
await TrackPlayer.reset();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Text style={{ marginTop: 20, marginBottom: 20 }}>{t('queue')}</Text>
|
||||
{queue.map((track, i) => (
|
||||
<TouchableHandler id={i} onPress={playTrack} key={i}>
|
||||
<QueueItem
|
||||
active={currentIndex === i}
|
||||
key={i}
|
||||
alreadyPlayed={currentIndex ? i < currentIndex : false}
|
||||
style={[
|
||||
defaultStyles.border,
|
||||
currentIndex === i ? defaultStyles.activeBackground : {},
|
||||
]}
|
||||
>
|
||||
<View>
|
||||
<Text style={currentIndex === i ? { color: THEME_COLOR, fontWeight: '700' } : styles.trackTitle}>{track.title}</Text>
|
||||
<Text style={currentIndex === i ? { color: THEME_COLOR, fontWeight: '400' } : defaultStyles.textHalfOpacity}>{track.artist}</Text>
|
||||
</View>
|
||||
<View style={{ marginLeft: 'auto' }}>
|
||||
<DownloadIcon trackId={track.backendId} />
|
||||
</View>
|
||||
</QueueItem>
|
||||
</TouchableHandler>
|
||||
))}
|
||||
<ClearQueue>
|
||||
<Button title={t('clear-queue')} onPress={clearQueue} />
|
||||
</ClearQueue>
|
||||
</View>
|
||||
);
|
||||
}
|
||||