Compare commits

...

57 Commits

Author SHA1 Message Date
Lei Nelissen
8e0809bcdc chore: Release v1.2.7 2022-08-14 00:49:48 +02:00
Lei Nelissen
5b54760e4e feat: Allow FLAC playback 2022-08-14 00:30:20 +02:00
Lei Nelissen
8a9c14e940 chore: Release v1.2.6 2022-08-09 11:41:19 +02:00
Lei Nelissen
6d57ec6d9a Merge pull request #91 from HySand/master
Update /src/localisation/lang/zh/locale.json
2022-08-09 10:46:10 +02:00
HySand
afb25a0422 Update locale.json 2022-08-07 05:18:08 +08:00
HySand
64c81d1813 Update locale.json
Add full simplified Chinese translation.
2022-08-07 05:07:28 +08:00
Lei Nelissen
cb792c8dd4 Add privacy policy 2022-06-15 11:49:33 +02:00
Lei Nelissen
63bbbf2719 fix: Peer dependency chain 2022-06-12 22:06:51 +02:00
Lei Nelissen
c7f0d46b41 fix: Remove unused imports 2022-06-12 21:59:21 +02:00
Lei Nelissen
6c7b320ae8 chore: Replace async-storage package 2022-06-12 21:51:20 +02:00
Lei Nelissen
f39ab85624 Fix android crashes and add modal exit button 2022-06-09 23:37:07 +02:00
Lei Nelissen
01bd17e8cb Fix borderStyle on image compilation issue 2022-05-19 23:06:03 +02:00
Lei Nelissen
1075e31623 Apply proper padding in Android FlatList 2022-05-19 23:05:46 +02:00
Lei Nelissen
8678e3d881 Render playback text properly on Android 2022-05-19 23:05:28 +02:00
Lei Nelissen
0fc087e832 Update screenshots and README 2022-05-18 23:07:08 +02:00
Lei Nelissen
a8d563f66d Release v1.2.5 2022-05-18 22:29:57 +02:00
Lei Nelissen
1c659d7d90 Merge pull request #83 from leinelissen/feature/redesign
Feature/redesign
2022-05-18 22:13:00 +02:00
Lei Nelissen
f6835d0553 Update all dependencies 2022-05-18 22:10:06 +02:00
Lei Nelissen
21eb1dca3b Remove redundant console.log 2022-05-18 22:00:07 +02:00
Lei Nelissen
a9dcd75f96 Transform Queue component into FlatList 2022-05-18 21:55:59 +02:00
Lei Nelissen
7ef54eb06d Prioritize the pan gesture over the tap gesture 2022-05-18 21:30:10 +02:00
Lei Nelissen
fcb6b1465b Swap string literals for translatable items 2022-05-18 21:23:24 +02:00
Lei Nelissen
06ead4a00e Upgrade react-airplay to version that includes route metadata 2022-05-18 10:18:07 +02:00
Lei Nelissen
f8d5aa68c2 Add default image styles and shadow to nowpalying overlay 2022-05-17 23:55:50 +02:00
Lei Nelissen
f66b541e1b Fix linting issues 2022-05-17 23:45:57 +02:00
Lei Nelissen
b989df43f3 Make nowplaying overlay slightly draggable 2022-05-17 23:37:06 +02:00
Lei Nelissen
de07fc65c4 Restyle the downloads screen 2022-05-17 23:34:25 +02:00
Lei Nelissen
c0fa1160ae Make padding-left optional on textinput 2022-05-17 23:05:45 +02:00
Lei Nelissen
f1925347cb Animate search bar with keyboard 2022-05-17 23:05:17 +02:00
Lei Nelissen
258ac34a2c Slightly adjust light-gray color on dark mode 2022-05-17 23:04:45 +02:00
Lei Nelissen
479f701d32 Remove themed background from welcome screen 2022-05-17 23:04:04 +02:00
Lei Nelissen
0589325055 Adjust dark mode colors 2022-05-16 22:28:13 +02:00
Lei Nelissen
a719e309ad Add stubs for filters in search 2022-05-16 22:17:00 +02:00
Lei Nelissen
ccc0c211fb Add shadows to cover images 2022-05-16 22:16:45 +02:00
Lei Nelissen
d7402bb409 First overhaul of search screen 2022-05-11 23:57:30 +02:00
Lei Nelissen
b7a5c0267c Readjust track popup 2022-05-11 22:13:42 +02:00
Lei Nelissen
b9016f9ba6 Make divider somewhat more visible on light mode 2022-05-10 23:56:20 +02:00
Lei Nelissen
07adb44f19 Add some margin between track name and media button 2022-05-10 23:55:02 +02:00
Lei Nelissen
b21766a352 Revamp the pop-up player modal 2022-05-10 23:52:58 +02:00
Lei Nelissen
37ead0ec98 feat: Apply default text styles to ReText 2022-05-05 22:59:32 +02:00
Lei Nelissen
b0961d3263 feat: Tweak progress bar gestures 2022-05-05 22:54:37 +02:00
Lei Nelissen
e135b23565 Update fastlane.yml 2022-05-05 11:18:28 +02:00
Lei Nelissen
015a1fa196 Update fastlane.yml 2022-05-05 11:07:47 +02:00
Lei Nelissen
25f16a875f Update fastlane.yml 2022-05-05 11:07:09 +02:00
Lei Nelissen
47aabfa8e7 Update fastlane.yml 2022-05-05 11:04:26 +02:00
Lei Nelissen
6efc8e757c feat: Create new progress slider from scratch 2022-05-05 03:30:51 +02:00
Lei Nelissen
f48d248144 feat: Implement colored blur backgrounds 2022-05-04 22:46:19 +02:00
Lei Nelissen
76f2db19e5 Change modal to native stacks 2022-05-04 19:12:01 +02:00
Lei Nelissen
2b24a37218 chore: Upgrade all dependencies 2022-05-04 18:29:11 +02:00
Lei Nelissen
7fb7fc1925 Implement new styles 2022-05-04 18:28:15 +02:00
Lei Nelissen
c4d83d29d8 Add Inter font 2022-05-04 18:28:15 +02:00
Lei Nelissen
d141b80a77 Move search to tabbar and remove now playing 2022-05-04 18:28:15 +02:00
Lei Nelissen
3b0ea4ece7 chore: Release new iOS version 2022-05-04 17:31:47 +02:00
Lei Nelissen
89d29844b9 fix: Only pull Exoplayer from jcenter 2022-05-04 17:16:58 +02:00
Lei Nelissen
f7874410d4 chore: Release new Android build 2022-05-04 17:03:43 +02:00
Lei Nelissen
8914a26822 chore: Bump version 2022-05-04 16:56:39 +02:00
Lei Nelissen
91eaa1d864 fix: No interaction on Android webview (#59) 2022-05-04 16:55:32 +02:00
142 changed files with 11727 additions and 10215 deletions

2
.bundle/config Normal file
View File

@@ -0,0 +1,2 @@
BUNDLE_PATH: "vendor/bundle"
BUNDLE_FORCE_RUBY_PLATFORM: 1

View File

@@ -53,5 +53,10 @@ module.exports = {
'@typescript-eslint/no-unused-vars': [
'error'
]
},
settings: {
react: {
version: 'detect',
}
}
};

View File

@@ -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
View File

@@ -61,6 +61,7 @@ buck-out/
# CocoaPods
/ios/Pods/
/vendor/bundle/
build/
fastlane/report.xml

1
.ruby-version Normal file
View File

@@ -0,0 +1 @@
2.7.4

View File

@@ -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')

View File

@@ -7,8 +7,10 @@ This is a [React Native](https://reactnative.dev/)-based audio streaming app for
## ❗Now open for beta testing on iOS
Please follow this link to enroll for the TestFlight beta release of Jellyfin Audio Player: https://testflight.apple.com/join/cf2AMDpx.
|![](./docs/images/now-playing.png)|![](./docs/images/recent-albums.png)|![](./docs/images/album-list.png)|![](./docs/images/search.png)|
|-|-|-|-|
|![](./docs/images/now-playing.png)|![](./docs/images/recent-albums.png)|![](./docs/images/album-list.png)
|-|-|-|
|![](./docs/images/album.png)|![](./docs/images/downloads.png)|![](./docs/images/search.png)
## Features
* Sorting by recent albums
@@ -18,14 +20,12 @@ Please follow this link to enroll for the TestFlight beta release of Jellyfin Au
* AirPlay and Chromecast support
* Background audio
* Native Dark Mode
### Features being considered
* Downloading music for offline playback
* Searching based on track names
* Looping and shuffling queue
## Getting Started
This piece of software is in alpha. I am working on getting this app in ~~TestFlight and~~ Google Play Developer Console, but this is contingent on keys being available. In the meantime, IPAs and APK are intermittenly released on the [Releases page](https://github.com/leinelissen/jellyfin-audio-player/releases). Alternatively, you can build this app from source using the build instructions.
This piece of software is in beta. I am working on getting this app in ~~TestFlight and~~ Google Play Developer Console, but this is contingent on keys being available. In the meantime, IPAs and APK are intermittenly released on the [Releases page](https://github.com/leinelissen/jellyfin-audio-player/releases). Alternatively, you can build this app from source using the build instructions.
### Using the app
You will need to setup your Jellyfin account for the application to be able to pull in all your audio. To do this, go over to the "Settings" tab and click the "Set Jellyfin server"-button. A modal will pop up in which you will enter your Jellyfin server url, after which you enter your credentials in the provided browser view. When the app detects your credentials, they will automatically be remembered for the future.

View File

@@ -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 11
versionName "1.2.7"
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"
}

View File

@@ -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>

View File

@@ -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);

View File

@@ -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>

View File

@@ -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

View File

@@ -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.*")
}
}
}
}
}

View File

@@ -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

View File

@@ -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
View File

@@ -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" "$@"

View File

@@ -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')
}

View File

@@ -31,6 +31,7 @@ module.exports = {
],
[
'module:react-native-dotenv'
]
],
'react-native-reanimated/plugin'
]
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

After

Width:  |  Height:  |  Size: 2.9 MiB

BIN
docs/images/album.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
docs/images/downloads.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 KiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 KiB

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 261 KiB

8
docs/privacy-policy.md Normal file
View File

@@ -0,0 +1,8 @@
Fintunes does not collect any personal data. Period. We respect your right to
autonomy and vow to not collect any information without user consent at all.
If you opt-in to crash logging, we will collect analytics data from your device,
every time a crash occurs. This data includes debugging information such as
devices, versions and the specific error. All data is sent to a server
controlled by the first party. No third parties can access this data in any
form. No personal data is included in the analytics data.

View File

@@ -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).

View File

@@ -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 = 39;
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 = 39;
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;

View File

@@ -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

View File

@@ -17,11 +17,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.2.3</string>
<string>1.2.7</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>34</string>
<string>39</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>

View File

@@ -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]));
}

View File

@@ -15,10 +15,10 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.2.3</string>
<string>1.2.7</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>34</string>
<string>39</string>
</dict>
</plist>

View File

@@ -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

View File

@@ -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.2)
- FBReactNativeSpec (0.68.2):
- 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.2)
- RCTTypeSafety (= 0.68.2)
- React-Core (= 0.68.2)
- React-jsi (= 0.68.2)
- ReactCommon/turbomodule/core (= 0.68.2)
- 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,296 +95,361 @@ PODS:
- DoubleConversion
- fmt (~> 6.2.1)
- glog
- RCTRequired (0.66.4)
- RCTTypeSafety (0.66.4):
- FBLazyVector (= 0.66.4)
- RCTRequired (0.68.2)
- RCTTypeSafety (0.68.2):
- FBLazyVector (= 0.68.2)
- 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):
- RCTRequired (= 0.68.2)
- React-Core (= 0.68.2)
- React (0.68.2):
- React-Core (= 0.68.2)
- React-Core/DevSupport (= 0.68.2)
- React-Core/RCTWebSocket (= 0.68.2)
- React-RCTActionSheet (= 0.68.2)
- React-RCTAnimation (= 0.68.2)
- React-RCTBlob (= 0.68.2)
- React-RCTImage (= 0.68.2)
- React-RCTLinking (= 0.68.2)
- React-RCTNetwork (= 0.68.2)
- React-RCTSettings (= 0.68.2)
- React-RCTText (= 0.68.2)
- React-RCTVibration (= 0.68.2)
- react-airplay (1.2.0):
- React-Core
- React-callinvoker (0.68.2)
- React-Codegen (0.68.2):
- FBReactNativeSpec (= 0.68.2)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.68.2)
- RCTTypeSafety (= 0.68.2)
- React-Core (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- ReactCommon/turbomodule/core (= 0.68.2)
- React-Core (0.68.2):
- 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)
- React-Core/Default (= 0.68.2)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- React-perflogger (= 0.68.2)
- Yoga
- React-Core/CoreModulesHeaders (0.66.4):
- React-Core/CoreModulesHeaders (0.68.2):
- 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)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- React-perflogger (= 0.68.2)
- Yoga
- React-Core/Default (0.66.4):
- React-Core/Default (0.68.2):
- 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)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- React-perflogger (= 0.68.2)
- Yoga
- React-Core/DevSupport (0.66.4):
- React-Core/DevSupport (0.68.2):
- 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)
- React-Core/Default (= 0.68.2)
- React-Core/RCTWebSocket (= 0.68.2)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- React-jsinspector (= 0.68.2)
- React-perflogger (= 0.68.2)
- Yoga
- React-Core/RCTActionSheetHeaders (0.66.4):
- React-Core/RCTActionSheetHeaders (0.68.2):
- 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)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- React-perflogger (= 0.68.2)
- Yoga
- React-Core/RCTAnimationHeaders (0.66.4):
- React-Core/RCTAnimationHeaders (0.68.2):
- 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)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- React-perflogger (= 0.68.2)
- Yoga
- React-Core/RCTBlobHeaders (0.66.4):
- React-Core/RCTBlobHeaders (0.68.2):
- 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)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- React-perflogger (= 0.68.2)
- Yoga
- React-Core/RCTImageHeaders (0.66.4):
- React-Core/RCTImageHeaders (0.68.2):
- 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)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- React-perflogger (= 0.68.2)
- Yoga
- React-Core/RCTLinkingHeaders (0.66.4):
- React-Core/RCTLinkingHeaders (0.68.2):
- 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)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- React-perflogger (= 0.68.2)
- Yoga
- React-Core/RCTNetworkHeaders (0.66.4):
- React-Core/RCTNetworkHeaders (0.68.2):
- 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)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- React-perflogger (= 0.68.2)
- Yoga
- React-Core/RCTSettingsHeaders (0.66.4):
- React-Core/RCTSettingsHeaders (0.68.2):
- 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)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- React-perflogger (= 0.68.2)
- Yoga
- React-Core/RCTTextHeaders (0.66.4):
- React-Core/RCTTextHeaders (0.68.2):
- 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)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- React-perflogger (= 0.68.2)
- Yoga
- React-Core/RCTVibrationHeaders (0.66.4):
- React-Core/RCTVibrationHeaders (0.68.2):
- 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)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- React-perflogger (= 0.68.2)
- Yoga
- React-Core/RCTWebSocket (0.66.4):
- React-Core/RCTWebSocket (0.68.2):
- 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)
- React-Core/Default (= 0.68.2)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsiexecutor (= 0.68.2)
- React-perflogger (= 0.68.2)
- Yoga
- React-CoreModules (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- React-CoreModules (0.68.2):
- 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):
- RCTTypeSafety (= 0.68.2)
- React-Codegen (= 0.68.2)
- React-Core/CoreModulesHeaders (= 0.68.2)
- React-jsi (= 0.68.2)
- React-RCTImage (= 0.68.2)
- ReactCommon/turbomodule/core (= 0.68.2)
- React-cxxreact (0.68.2):
- 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):
- React-callinvoker (= 0.68.2)
- React-jsi (= 0.68.2)
- React-jsinspector (= 0.68.2)
- React-logger (= 0.68.2)
- React-perflogger (= 0.68.2)
- React-runtimeexecutor (= 0.68.2)
- React-jsi (0.68.2):
- 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):
- React-jsi/Default (= 0.68.2)
- React-jsi/Default (0.68.2):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsiexecutor (0.66.4):
- React-jsiexecutor (0.68.2):
- 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):
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-perflogger (= 0.68.2)
- React-jsinspector (0.68.2)
- React-logger (0.68.2):
- glog
- react-native-airplay-button (1.1.0):
- React-Core
- react-native-flipper (0.127.0):
- React-Core
- react-native-netinfo (7.1.7):
- React-Core
- react-native-safe-area-context (3.3.2):
- React-Core
- react-native-slider (4.1.12):
- React-Core
- react-native-track-player (2.1.2):
- React-Core
- SwiftAudioEx (= 0.14.5)
- react-native-webview (11.15.0):
- React-Core
- React-perflogger (0.66.4)
- React-RCTActionSheet (0.66.4):
- React-Core/RCTActionSheetHeaders (= 0.66.4)
- React-RCTAnimation (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.66.4)
- React-Core/RCTAnimationHeaders (= 0.66.4)
- React-jsi (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-RCTBlob (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/RCTBlobHeaders (= 0.66.4)
- React-Core/RCTWebSocket (= 0.66.4)
- React-jsi (= 0.66.4)
- React-RCTNetwork (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-RCTImage (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.66.4)
- React-Core/RCTImageHeaders (= 0.66.4)
- React-jsi (= 0.66.4)
- React-RCTNetwork (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-RCTLinking (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- React-Core/RCTLinkingHeaders (= 0.66.4)
- React-jsi (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-RCTNetwork (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.66.4)
- React-Core/RCTNetworkHeaders (= 0.66.4)
- React-jsi (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-RCTSettings (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.66.4)
- React-Core/RCTSettingsHeaders (= 0.66.4)
- React-jsi (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-RCTText (0.66.4):
- React-Core/RCTTextHeaders (= 0.66.4)
- React-RCTVibration (0.66.4):
- FBReactNativeSpec (= 0.66.4)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/RCTVibrationHeaders (= 0.66.4)
- React-jsi (= 0.66.4)
- ReactCommon/turbomodule/core (= 0.66.4)
- React-runtimeexecutor (0.66.4):
- React-jsi (= 0.66.4)
- ReactCommon/turbomodule/core (0.66.4):
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-callinvoker (= 0.66.4)
- React-Core (= 0.66.4)
- React-cxxreact (= 0.66.4)
- React-jsi (= 0.66.4)
- React-logger (= 0.66.4)
- React-perflogger (= 0.66.4)
- RNCAsyncStorage (1.12.1):
- React-Core
- RNCMaskedView (0.1.11):
- react-native-blur (0.8.0):
- React
- RNCPicker (1.8.1):
- react-native-flipper (0.146.0):
- React-Core
- react-native-netinfo (8.3.0):
- React-Core
- react-native-safe-area-context (4.2.5):
- RCT-Folly
- RCTRequired
- RCTTypeSafety
- React
- ReactCommon/turbomodule/core
- react-native-skia (0.1.124):
- React
- React-callinvoker
- React-Core
- react-native-skia/Api (= 0.1.124)
- react-native-skia/Jsi (= 0.1.124)
- react-native-skia/RNSkia (= 0.1.124)
- react-native-skia/SkiaHeaders (= 0.1.124)
- react-native-skia/Utils (= 0.1.124)
- react-native-skia/Api (0.1.124):
- React
- React-callinvoker
- React-Core
- react-native-skia/Jsi (0.1.124):
- React
- React-callinvoker
- React-Core
- react-native-skia/RNSkia (0.1.124):
- React
- React-callinvoker
- React-Core
- react-native-skia/SkiaHeaders (0.1.124):
- React
- React-callinvoker
- React-Core
- react-native-skia/Utils (0.1.124):
- React
- React-callinvoker
- React-Core
- react-native-track-player (2.2.0-rc3):
- React-Core
- SwiftAudioEx (= 0.14.7)
- react-native-webview (11.18.2):
- React-Core
- React-perflogger (0.68.2)
- React-RCTActionSheet (0.68.2):
- React-Core/RCTActionSheetHeaders (= 0.68.2)
- React-RCTAnimation (0.68.2):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.68.2)
- React-Codegen (= 0.68.2)
- React-Core/RCTAnimationHeaders (= 0.68.2)
- React-jsi (= 0.68.2)
- ReactCommon/turbomodule/core (= 0.68.2)
- React-RCTBlob (0.68.2):
- RCT-Folly (= 2021.06.28.00-v2)
- React-Codegen (= 0.68.2)
- React-Core/RCTBlobHeaders (= 0.68.2)
- React-Core/RCTWebSocket (= 0.68.2)
- React-jsi (= 0.68.2)
- React-RCTNetwork (= 0.68.2)
- ReactCommon/turbomodule/core (= 0.68.2)
- React-RCTImage (0.68.2):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.68.2)
- React-Codegen (= 0.68.2)
- React-Core/RCTImageHeaders (= 0.68.2)
- React-jsi (= 0.68.2)
- React-RCTNetwork (= 0.68.2)
- ReactCommon/turbomodule/core (= 0.68.2)
- React-RCTLinking (0.68.2):
- React-Codegen (= 0.68.2)
- React-Core/RCTLinkingHeaders (= 0.68.2)
- React-jsi (= 0.68.2)
- ReactCommon/turbomodule/core (= 0.68.2)
- React-RCTNetwork (0.68.2):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.68.2)
- React-Codegen (= 0.68.2)
- React-Core/RCTNetworkHeaders (= 0.68.2)
- React-jsi (= 0.68.2)
- ReactCommon/turbomodule/core (= 0.68.2)
- React-RCTSettings (0.68.2):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.68.2)
- React-Codegen (= 0.68.2)
- React-Core/RCTSettingsHeaders (= 0.68.2)
- React-jsi (= 0.68.2)
- ReactCommon/turbomodule/core (= 0.68.2)
- React-RCTText (0.68.2):
- React-Core/RCTTextHeaders (= 0.68.2)
- React-RCTVibration (0.68.2):
- RCT-Folly (= 2021.06.28.00-v2)
- React-Codegen (= 0.68.2)
- React-Core/RCTVibrationHeaders (= 0.68.2)
- React-jsi (= 0.68.2)
- ReactCommon/turbomodule/core (= 0.68.2)
- React-runtimeexecutor (0.68.2):
- React-jsi (= 0.68.2)
- ReactCommon/turbomodule/core (0.68.2):
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-callinvoker (= 0.68.2)
- React-Core (= 0.68.2)
- React-cxxreact (= 0.68.2)
- React-jsi (= 0.68.2)
- React-logger (= 0.68.2)
- React-perflogger (= 0.68.2)
- RNCAsyncStorage (1.17.6):
- React-Core
- RNFastImage (8.5.11):
- React-Core
- SDWebImage (~> 5.11.1)
- SDWebImageWebPCoder (~> 0.8.4)
- RNFS (2.18.0):
- React
- RNGestureHandler (2.1.0):
- RNFS (2.20.0):
- React-Core
- RNLocalize (2.1.7):
- RNGestureHandler (2.4.2):
- 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 +457,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 +471,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,11 +510,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-slider (from `../node_modules/@react-native-community/slider`)"
- "react-native-skia (from `../node_modules/@shopify/react-native-skia`)"
- react-native-track-player (from `../node_modules/react-native-track-player`)
- react-native-webview (from `../node_modules/react-native-webview`)
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
@@ -459,13 +529,12 @@ DEPENDENCIES:
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
- React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`)
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
- "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
- "RNCPicker (from `../node_modules/@react-native-community/picker`)"
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- RNFastImage (from `../node_modules/react-native-fast-image`)
- 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 +559,7 @@ SPEC REPOS:
- SDWebImage
- SDWebImageWebPCoder
- Sentry
- SocketRocket
- SwiftAudioEx
- YogaKit
@@ -512,8 +582,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,16 +602,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-slider:
:path: "../node_modules/@react-native-community/slider"
react-native-skia:
:path: "../node_modules/@shopify/react-native-skia"
react-native-track-player:
:path: "../node_modules/react-native-track-player"
react-native-webview:
@@ -567,11 +641,7 @@ EXTERNAL SOURCES:
ReactCommon:
:path: "../node_modules/react-native/ReactCommon"
RNCAsyncStorage:
:path: "../node_modules/@react-native-community/async-storage"
RNCMaskedView:
:path: "../node_modules/@react-native-community/masked-view"
RNCPicker:
:path: "../node_modules/@react-native-community/picker"
:path: "../node_modules/@react-native-async-storage/async-storage"
RNFastImage:
:path: "../node_modules/react-native-fast-image"
RNFS:
@@ -580,6 +650,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 +665,72 @@ SPEC CHECKSUMS:
boost: a7c83b31436843459a1961bfd74b96033dc77234
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
FBLazyVector: e5569e42a1c79ca00521846c223173a57aca1fe1
FBReactNativeSpec: fe08c1cd7e2e205718d77ad14b34957cce949b58
Flipper: 30e8eeeed6abdc98edaf32af0cda2f198be4b733
FBLazyVector: a7a655862f6b09625d11c772296b01cd5164b648
FBReactNativeSpec: 81ce99032d5b586fddd6a38d450f8595f7e04be4
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
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
RNCAsyncStorage: b03032fdbdb725bea0bd9e5ec5a7272865ae7398
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
RNCPicker: 914b557e20b3b8317b084aca9ff4b4edb95f61e4
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
RCT-Folly: 4d8508a426467c48885f1151029bc15fa5d7b3b8
RCTRequired: 3e917ea5377751094f38145fdece525aa90545a0
RCTTypeSafety: c43c072a4bd60feb49a9570b0517892b4305c45e
React: 176dd882de001854ced260fad41bb68a31aa4bd0
react-airplay: 8197767f12cae11a7623b1507d29a89482a720ad
React-callinvoker: c2864d1818d6e64928d2faf774a3800dfc38fe1f
React-Codegen: 98b6f97f0a7abf7d67e4ce435c77c05b7a95cf05
React-Core: fdaa2916b1c893f39f02cff0476d1fb0cab1e352
React-CoreModules: fd8705b80699ec36c2cdd635c2ce9d874b9cfdfc
React-cxxreact: 1832d971f7b0cb2c7b943dc0ec962762c90c906e
React-jsi: 72af715135abe8c3f0dcf3b2548b71d048b69a7e
React-jsiexecutor: b7b553412f2ec768fe6c8f27cd6bafdb9d8719e6
React-jsinspector: c5989c77cb89ae6a69561095a61cce56a44ae8e8
React-logger: a0833912d93b36b791b7a521672d8ee89107aff1
react-native-blur: cad4d93b364f91e7b7931b3fa935455487e5c33c
react-native-flipper: 5b0191d194d8581f1a25efd07fd6048323dc9c04
react-native-netinfo: 3671b091c4843fda5e153612866ef4024b8f5d62
react-native-safe-area-context: ebf8c413eb8b5f7c392a036a315eb7b46b96845f
react-native-skia: 69a2b9b42999325db20e18ef459bf4dfc1b51a69
react-native-track-player: c4a4c5ec8090aec5b97a3f634dab8bdb657491a0
react-native-webview: 8ec7ddf9eb4ddcd92b32cee7907efec19a9ec7cb
React-perflogger: a18b4f0bd933b8b24ecf9f3c54f9bf65180f3fe6
React-RCTActionSheet: 547fe42fdb4b6089598d79f8e1d855d7c23e2162
React-RCTAnimation: bc9440a1c37b06ae9ebbb532d244f607805c6034
React-RCTBlob: a1295c8e183756d7ef30ba6e8f8144dfe8a19215
React-RCTImage: a30d1ee09b1334067fbb6f30789aae2d7ac150c9
React-RCTLinking: ffc6d5b88d1cb9aca13c54c2ec6507fbf07f2ac4
React-RCTNetwork: f807a2facab6cf5cf36d592e634611de9cf12d81
React-RCTSettings: 861806819226ed8332e6a8f90df2951a34bb3e7f
React-RCTText: f3fb464cc41a50fc7a1aba4deeb76a9ad8282cb9
React-RCTVibration: 79040b92bfa9c3c2d2cb4f57e981164ec7ab9374
React-runtimeexecutor: b960b687d2dfef0d3761fbb187e01812ebab8b23
ReactCommon: 095366164a276d91ea704ce53cb03825c487a3f2
RNCAsyncStorage: 466b9df1a14bccda91da86e0b7d9a345d78e1673
RNFastImage: 1f2cab428712a4baaf78d6169eaec7f622556dd7
RNFS: 3ab21fa6c56d65566d1fb26c2228e2b6132e5e32
RNGestureHandler: e5c7cab5f214503dcefd6b2b0cefb050e1f51c4a
RNLocalize: f567ea0e35116a641cdffe6683b0d212d568f32a
RNScreens: 522705f2e5c9d27efb17f24aceb2bf8335bc7b8e
RNSentry: 04bb48bfdd435f5b218cf363f89e6419e9a2460c
RNSVG: 4ecc2e8f38b6ebe7889909570c26f3abe8059767
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: 61628a2c859172551aa2100d3e73d1e57878392f
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: 99652481fcd320aefa4a7ef90095b95acd181952
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
PODFILE CHECKSUM: 41246a700cf7cc0f2e61f418d64861444b3079b1
PODFILE CHECKSUM: 85fc028e296eda015f9e9d002b5f5c9dbff66827
COCOAPODS: 1.11.2
COCOAPODS: 1.11.3

17651
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "JellyfinAudioPlayer",
"version": "1.2.3",
"version": "1.2.7",
"main": "src/index.js",
"private": true,
"scripts": {
@@ -12,68 +12,74 @@
"build:ios": "react-native bundle --entry-file='index.ts' --bundle-output='./ios/main.jsbundle' --dev=false --platform='ios'"
},
"dependencies": {
"@react-native-community/async-storage": "^1.12.1",
"@react-native-community/masked-view": "^0.1.11",
"@react-native-community/netinfo": "^7.1.7",
"@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-async-storage/async-storage": "^1.17.6",
"@react-native-community/blur": "^3.6.0",
"@react-native-community/netinfo": "^8.3.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.2.0-rc3",
"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-dom": "^17.0.2",
"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 +93,6 @@
]
},
"overrides": {
"@types/react-native": "^0.66.10"
"@types/react-native": "^0.67.7"
}
}

7
react-native.config.js Normal file
View File

@@ -0,0 +1,7 @@
module.exports = {
project: {
ios: {},
android: {}
},
assets: ['./src/assets/fonts/'],
};

View File

@@ -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

Binary file not shown.

93
src/assets/fonts/OFL.txt Normal file
View 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.

View 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

View File

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View 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

View 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

View File

Before

Width:  |  Height:  |  Size: 531 B

After

Width:  |  Height:  |  Size: 531 B

View File

Before

Width:  |  Height:  |  Size: 422 B

After

Width:  |  Height:  |  Size: 422 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 808 B

After

Width:  |  Height:  |  Size: 808 B

View File

Before

Width:  |  Height:  |  Size: 483 B

After

Width:  |  Height:  |  Size: 483 B

View 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

View 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

View File

Before

Width:  |  Height:  |  Size: 558 B

After

Width:  |  Height:  |  Size: 558 B

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 806 B

After

Width:  |  Height:  |  Size: 806 B

View 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

View 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

View File

Before

Width:  |  Height:  |  Size: 684 B

After

Width:  |  Height:  |  Size: 684 B

View 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

View File

Before

Width:  |  Height:  |  Size: 714 B

After

Width:  |  Height:  |  Size: 714 B

View File

Before

Width:  |  Height:  |  Size: 444 B

After

Width:  |  Height:  |  Size: 444 B

View File

Before

Width:  |  Height:  |  Size: 666 B

After

Width:  |  Height:  |  Size: 666 B

View File

Before

Width:  |  Height:  |  Size: 732 B

After

Width:  |  Height:  |  Size: 732 B

View File

Before

Width:  |  Height:  |  Size: 363 B

After

Width:  |  Height:  |  Size: 363 B

View File

Before

Width:  |  Height:  |  Size: 758 B

After

Width:  |  Height:  |  Size: 758 B

View File

Before

Width:  |  Height:  |  Size: 848 B

After

Width:  |  Height:  |  Size: 848 B

View File

Before

Width:  |  Height:  |  Size: 717 B

After

Width:  |  Height:  |  Size: 717 B

View File

Before

Width:  |  Height:  |  Size: 695 B

After

Width:  |  Height:  |  Size: 695 B

View File

Before

Width:  |  Height:  |  Size: 964 B

After

Width:  |  Height:  |  Size: 964 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,3 @@
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.18849 19.0509C6.81935 19.4201 6.80177 20.0792 7.19728 20.466C7.58399 20.8527 8.24317 20.8439 8.61231 20.4747L13.9912 15.087L19.3789 20.4747C19.7568 20.8527 20.4072 20.8527 20.794 20.466C21.1719 20.0704 21.1807 19.4288 20.794 19.0509L15.415 13.6632L20.794 8.28431C21.1807 7.90638 21.1807 7.25599 20.794 6.86927C20.3984 6.49134 19.7568 6.48255 19.3789 6.86048L13.9912 12.2482L8.61231 6.86048C8.24317 6.49134 7.5752 6.47376 7.19728 6.86927C6.81056 7.25599 6.81935 7.91517 7.18849 8.28431L12.5762 13.6632L7.18849 19.0509Z" fill="#1C1C1E"/>
</svg>

After

Width:  |  Height:  |  Size: 651 B

View File

@@ -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>

View File

@@ -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>
);
});

View File

@@ -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, View } 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,21 @@ export function DefaultStylesProvider(props: DefaultStylesProviderProps) {
const defaultStyles = useDefaultStyles();
return props.children(defaultStyles);
}
export function ColoredBlurView(props: PropsWithChildren<BlurViewProperties>) {
const scheme = useColorScheme();
return Platform.OS === 'ios' ? (
<BlurView
{...props}
blurType={Platform.OS === 'ios' && majorPlatformVersion >= 13
? 'material'
: scheme === 'dark' ? 'extraDark' : 'xlight'
} />
) : (
<View {...props} style={[ props.style, {
backgroundColor: scheme === 'light' ? '#f6f6f6f6' : '#333333f6',
} ]} />
);
}

View 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;

View 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;

View File

@@ -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]);

View File

@@ -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,
}));
});
}

View File

@@ -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;

View File

@@ -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>
);
};

View File

@@ -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>
);
};

View 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
View 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
View 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>
);

View File

@@ -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]} />
);
}

View File

@@ -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;
`;

View 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;
`;

View File

@@ -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)`

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -1,6 +1,6 @@
{
"play-next": "播放下一首",
"play-album": "播放专辑",
"play-album": "播放全部",
"queue": "歌曲队列",
"add-to-queue": "加入队列",
"clear-queue": "清除队列",
@@ -12,8 +12,8 @@
"music": "歌曲",
"now-playing": "正在播放",
"onboarding-welcome": "欢迎",
"onboarding-intro": "Jellyfin Audio Player will allow you to stream your music library from anywhere, with full support for background audio and casting.",
"onboarding-cta": "In order to get started, you need a Jellyfin server. Click the button below to enter your Jellyfin server address and login to it.",
"onboarding-intro": "Jellyfin Audio Player可以在任何地方播放Jellyfin库中的音乐。",
"onboarding-cta": "在开始前你需要一个Jellyfin服务器。点击下方的按钮连接到服务器并登录。",
"set-jellyfin-server": "设置Jellyfin服务器",
"set-jellyfin-server-instruction": "设置Jellyfin服务器的完整网址包括HTTP/HTTS和端口。",
"settings": "设置",
@@ -22,21 +22,42 @@
"jellyfin-access-token": "Jellyfin Access Token",
"jellyfin-user-id": "Jellyfin用户ID",
"setting-cache": "缓存",
"setting-cache-description": "If you have updated your Jellyfin library, but the app is holding on to cached assets, you can forcefully clear the cache using this button. This will force the app to fetch the library from scratch.",
"setting-cache-description": "如果你更新了Jellyfin库但软件仍显示之前的内容你可以点击下面的按钮强制刷新。这将强制软件重新从服务器获取信息。",
"reset-cache": "清除缓存",
"recent-albums": "最近专辑",
"error-reporting": "Error Reporting",
"error-reporting-description": "During use of this app, you may encounter errors. Reporting these errors helps in creating a more secure and stable app experience.",
"error-reporting-rationale": "When you enable error reporting, every time an error occurs, a report is automatically created and sent to a server, along with helpful debugging information such as devices, versions and the specific error.",
"why-use-tracking": "Why use tracking?",
"why-use-tracking-description": "Tracking helps speed up development for this app by reporting weird edge cases and oversights. This helps make the app more stable and robust, thus increasing the app experience for everyone.",
"what-data-is-gathered": "What data is gathered?",
"what-data-is-gathered-description": "We log the error, device type, OS version, app version and device id. No application state is sent in any error reporting. The device id is a unique hash that can be reset in your device settings, and we cannot deduce any personal information from this identifier.",
"where-is-data-stored": "Where is data stored?",
"where-is-data-stored-description": "The Sentry backend is self-hosted on our own infrastructure. No-one but us has access to the servers, databases, application and data logs, least of all any Sentry staff. The infrastructure is hosted in the European Union.",
"enable-error-reporting": "Do you want to enable error reporting?",
"enable-error-reporting-description": "This helps improve the app experience by sending crash and error reports to us.",
"error-reporting": "报告错误",
"error-reporting-description": "在使用本软件过程中,你可能遇到一些问题。报告这些问题可以使日后的使用更稳定。",
"error-reporting-rationale": "启用错误报告后,每当错误发生时会自动发送错误信息、设备信息、版本等到服务器。",
"why-use-tracking": "为什么要求追踪?",
"why-use-tracking-description": "追踪帮助我们收集那些易被忽略的错误信息以加快我们的开发。这将让软件更稳定从而提高每个人的使用体验。",
"what-data-is-gathered": "收集什么信息?",
"what-data-is-gathered-description": "我们收集错误日志、设备型号、系统版本、软件版本和设备ID在任何情况下都不会发送软件状况。设备ID是你设备的唯一散列值它可以被重置且我们无法从中推断出你的任何个人信息。",
"where-is-data-stored": "数据被收集到哪?",
"where-is-data-stored-description": "数据在我们在欧洲的后端服务器上保存,除了我们没有其他人能访问这些服务器、数据库和应用程序及数据日志。",
"enable-error-reporting": "是否开启错误信息发送",
"enable-error-reporting-description": "这将帮助你在遇到错误时发送报告以提升使用体验。",
"enable": "启用",
"disable": "禁用",
"more-info": "更多信息"
"more-info": "更多信息",
"track": "歌曲",
"playlists": "播放列表",
"playlist": "播放列表",
"play-playlist": "播放全部",
"shuffle-album": "随机播放",
"shuffle-playlist": "随机播放",
"downloads": "下载",
"download-track": "下载歌曲",
"download-album": "下载专辑",
"download-playlist": "下载播放列表",
"no-downloads": "你还没有下载任何歌曲",
"delete-track": "删除歌曲",
"delete-all-tracks": "删除所有歌曲",
"delete-album": "删除专辑",
"delete-playlist": "删除播放列表",
"total-download-size": "总体积",
"retry-failed-downloads": "重试失败下载",
"you-are-offline-message": "你当前处于离线状态,仅能播放缓存的歌曲。",
"playing-on": "播放",
"local-playback": "本地播放",
"streaming": "远程串流"
}

View File

@@ -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'

View File

@@ -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>

View File

@@ -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>
);
}

View 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;

View File

@@ -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]);

View File

@@ -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}
/>

View File

@@ -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]);

Some files were not shown because too many files have changed in this diff Show More