mirror of
https://github.com/anultravioletaurora/Jellify.git
synced 2025-12-21 05:20:06 -06:00
Upgrade to React Native's New Architecture (#302)
Makes the UI operate more synchronously (read: fast 🔥🔥🔥) Upgrades several dependencies
This commit is contained in:
4
.github/workflows/build-ios.yml
vendored
4
.github/workflows/build-ios.yml
vendored
@@ -17,8 +17,8 @@ jobs:
|
||||
- name: 💬 Echo package.json version to Github ENV
|
||||
run: echo VERSION_NUMBER=$(node -p -e "require('./package.json').version") >> $GITHUB_ENV
|
||||
|
||||
- name: 🍎 Run yarn init:ios
|
||||
run: yarn init:ios
|
||||
- name: 🍎 Run yarn init-ios:new-arch
|
||||
run: yarn init-ios:new-arch
|
||||
|
||||
- name: 🍫 Install CocoaPods
|
||||
run: yarn pod:install
|
||||
|
||||
7
.github/workflows/publish-beta.yml
vendored
7
.github/workflows/publish-beta.yml
vendored
@@ -17,11 +17,8 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: 🧵 Run yarn install
|
||||
run: yarn install
|
||||
|
||||
- name: 🍫 Install CocoaPods
|
||||
run: yarn pod:install
|
||||
- name: 🍎 Run yarn init-ios:new-arch
|
||||
run: yarn init-ios:new-arch
|
||||
|
||||
- name: ➕ Version Up
|
||||
run: yarn react-native bump-version --type patch
|
||||
|
||||
4
.github/workflows/run-jest-test-suite.yml
vendored
4
.github/workflows/run-jest-test-suite.yml
vendored
@@ -19,8 +19,8 @@ jobs:
|
||||
- name: 💬 Echo package.json version to Github ENV
|
||||
run: echo VERSION_NUMBER=$(node -p -e "require('./package.json').version") >> $GITHUB_ENV
|
||||
|
||||
- name: 🟢 Run yarn init:ios
|
||||
run: yarn init:ios
|
||||
- name: 🍎 Run yarn init-ios:new-arch
|
||||
run: yarn init-ios:new-arch
|
||||
|
||||
- name: 🧪 Run npm test
|
||||
run: yarn test
|
||||
|
||||
132
README.md
132
README.md
@@ -1,16 +1,16 @@
|
||||

|
||||
|
||||
# 🪼 Jellify
|
||||
|
||||

|
||||
|
||||
[](https://github.com/anultravioletaurora/Jellify/actions/workflows/publish-beta.yml)
|
||||
|
||||
### 🔗 Quick Links
|
||||
## 🔗 Quick Links
|
||||
|
||||
[Discord Server](https://discord.gg/yf8fBatktn)
|
||||
|
||||
[TestFlight](https://testflight.apple.com/join/etVSc7ZQ)
|
||||
|
||||
### ℹ️ About
|
||||
## ℹ️ About
|
||||
|
||||
> **jellify** (verb) - _to make gelatinous_ <br>
|
||||
> [see also](https://www.merriam-webster.com/dictionary/jellify)
|
||||
@@ -31,24 +31,24 @@ This app was designed with me and my dad in mind, since I wanted to give him a s
|
||||
|
||||
### ✨ Current
|
||||
|
||||
- Available via Testflight and Android APK
|
||||
- APKs are associated with each [release](https://github.com/anultravioletaurora/Jellify/releases)
|
||||
- Light and Dark modes
|
||||
- Home screen access to previously played tracks, artists, and your playlists
|
||||
- Quick access to similar artists and items for discovering music in your library
|
||||
- Jellyfin playback reporting and [Last.FM Plugin](https://github.com/jesseward/jellyfin-plugin-lastfm) support
|
||||
- Library of Favorited Music, not too dissimilar to how streaming services handle your 'library'
|
||||
- Full playlist support, including creating, updating, and reordering
|
||||
- Available via Testflight and Android APK
|
||||
- APKs are associated with each [release](https://github.com/anultravioletaurora/Jellify/releases)
|
||||
- Light and Dark modes
|
||||
- Home screen access to previously played tracks, artists, and your playlists
|
||||
- Quick access to similar artists and items for discovering music in your library
|
||||
- Jellyfin playback reporting and [Last.FM Plugin](https://github.com/jesseward/jellyfin-plugin-lastfm) support
|
||||
- Library of Favorited Music, not too dissimilar to how streaming services handle your 'library'
|
||||
- Full playlist support, including creating, updating, and reordering
|
||||
- Offline Playback
|
||||
|
||||
### 🛠 Roadmap
|
||||
|
||||
- [Offline Playback](https://github.com/anultravioletaurora/Jellify/issues/10)
|
||||
- [CarPlay / Android Auto Support](https://github.com/anultravioletaurora/Jellify/issues/5)
|
||||
- [Support for Jellyfin Instant Mixes](https://github.com/anultravioletaurora/Jellify/issues/50)
|
||||
- [Shared, Public, and Collaborative Playlists](https://github.com/anultravioletaurora/Jellify/issues/175)
|
||||
- [Web / Desktop support](https://github.com/anultravioletaurora/Jellify/issues/71)
|
||||
- [Watch (Apple Watch / WearOS) Support](https://github.com/anultravioletaurora/Jellify/issues/61)
|
||||
- [TV (Android, Apple, Samsung) Support](https://github.com/anultravioletaurora/Jellify/issues/85)
|
||||
- [CarPlay / Android Auto Support](https://github.com/anultravioletaurora/Jellify/issues/5)
|
||||
- [Support for Jellyfin Instant Mixes](https://github.com/anultravioletaurora/Jellify/issues/50)
|
||||
- [Shared, Public, and Collaborative Playlists](https://github.com/anultravioletaurora/Jellify/issues/175)
|
||||
- [Web / Desktop support](https://github.com/anultravioletaurora/Jellify/issues/71)
|
||||
- [Watch (Apple Watch / WearOS) Support](https://github.com/anultravioletaurora/Jellify/issues/61)
|
||||
- [TV (Android, Apple, Samsung) Support](https://github.com/anultravioletaurora/Jellify/issues/85)
|
||||
|
||||
## 👀 Lemme see!
|
||||
|
||||
@@ -80,7 +80,7 @@ Album
|
||||
|
||||
<img src="screenshots/album.png" alt="Album" width="275" height="600">
|
||||
|
||||
Offline Mode
|
||||
Album (In Offline Mode)
|
||||
|
||||
<img src="screenshots/offline_album.png" alt="Offline Album" width="275" height="600">
|
||||
|
||||
@@ -126,7 +126,7 @@ Playlist
|
||||
[React Native Reanimated](https://docs.swmansion.com/react-native-reanimated/)\
|
||||
[React Native Vector Icons](https://github.com/oblador/react-native-vector-icons)
|
||||
|
||||
- Specifically using [Material Community Icons](https://oblador.github.io/react-native-vector-icons/#MaterialCommunityIcons)
|
||||
- Specifically using [Material Community Icons](https://oblador.github.io/react-native-vector-icons/#MaterialCommunityIcons)
|
||||
|
||||
### 🎛️ Backend
|
||||
|
||||
@@ -151,86 +151,86 @@ This is undoubtedly a passion project of [mine](https://github.com/anultraviolet
|
||||
|
||||
### ⚛️ Universal Dependencies
|
||||
|
||||
- [Ruby](https://www.ruby-lang.org/en/documentation/installation/) for Fastlane
|
||||
- [NodeJS v22](https://nodejs.org/en/download) for React Native
|
||||
- [Ruby](https://www.ruby-lang.org/en/documentation/installation/) for Fastlane
|
||||
- [NodeJS v22](https://nodejs.org/en/download) for React Native
|
||||
|
||||
### 🍎 iOS
|
||||
|
||||
#### Dependencies
|
||||
|
||||
- [Xcode](https://developer.apple.com/xcode/) for building
|
||||
- [Xcode](https://developer.apple.com/xcode/) for building
|
||||
|
||||
#### Instructions
|
||||
|
||||
##### Setup
|
||||
|
||||
- Clone this repository
|
||||
- Run `yarn init:ios` to initialize the project
|
||||
- This will install `npm` packages, install `bundler` and required gems, and install required CocoaPods
|
||||
- In the `ios` directory, run `fastlane match development --readonly` to fetch the development signing certificates
|
||||
- *You will need access to the *Jellify Signing* private repository*
|
||||
- Clone this repository
|
||||
- Run `yarn init-ios:new-arch` to initialize the project
|
||||
- This will install `npm` packages, install `bundler` and required gems, and install required CocoaPods with [React Native's New Architecture](https://reactnative.dev/blog/2024/10/23/the-new-architecture-is-here#what-is-the-new-architecture)
|
||||
- In the `ios` directory, run `fastlane match development --readonly` to fetch the development signing certificates
|
||||
- _You will need access to the "Jellify Signing" private repository_
|
||||
|
||||
##### Running
|
||||
|
||||
- Run `yarn start` to start the dev server
|
||||
- Open the `Jellify.xcodeworkspace` with Xcode, _not_ the `Jellify.xcodeproject`
|
||||
- Run either on a device or in the simulator
|
||||
- _You will need to wait for Xcode to finish it's "Indexing" step_
|
||||
- Run `yarn start` to start the dev server
|
||||
- Open the `Jellify.xcodeworkspace` with Xcode, _not_ the `Jellify.xcodeproject`
|
||||
- Run either on a device or in the simulator
|
||||
- _You will need to wait for Xcode to finish it's "Indexing" step_
|
||||
|
||||
##### Building
|
||||
|
||||
- To create a build, run `yarn fastlane:ios:build` to use fastlane to compile an `.ipa`
|
||||
- To create a build, run `yarn fastlane:ios:build` to use fastlane to compile an `.ipa`
|
||||
|
||||
### 🤖 Android
|
||||
|
||||
#### Dependencies
|
||||
|
||||
- [Android Studio](https://developer.android.com/studio)
|
||||
- [Java Development Kit](https://www.oracle.com/th/java/technologies/downloads/)
|
||||
- [Android Studio](https://developer.android.com/studio)
|
||||
- [Java Development Kit](https://www.oracle.com/th/java/technologies/downloads/)
|
||||
|
||||
#### Instructions
|
||||
|
||||
##### Setup
|
||||
|
||||
- Clone this repository
|
||||
- Run `yarn install` to install `npm` packages
|
||||
- Clone this repository
|
||||
- Run `yarn install` to install `npm` packages
|
||||
|
||||
##### Running
|
||||
|
||||
- Run `yarn start` to start the dev server
|
||||
- Open the `android` folder with Android Studio
|
||||
- _Android Studio should automatically grab the "Run Configurations" and initialize Gradle_
|
||||
- Run either on a device or in the simulator
|
||||
- Run `yarn start` to start the dev server
|
||||
- Open the `android` folder with Android Studio
|
||||
- _Android Studio should automatically grab the "Run Configurations" and initialize Gradle_
|
||||
- Run either on a device or in the simulator
|
||||
|
||||
##### Building
|
||||
|
||||
- To create a build, run `yarn fastlane:android:build` to use fastlane to compile an `.apk` for all architectures
|
||||
- To create a build, run `yarn fastlane:android:build` to use fastlane to compile an `.apk` for all architectures
|
||||
|
||||
#### References
|
||||
|
||||
- [Setting up Android SDK](https://developer.android.com/about/versions/14/setup-sdk)
|
||||
- [ANDROID_HOME not being set](https://stackoverflow.com/questions/26356359/error-android-home-is-not-set-and-android-command-not-in-your-path-you-must/54888107#54888107)
|
||||
- [Android Auto app not showing up](https://www.reddit.com/r/AndroidAuto/s/LGYHoSPdXm)
|
||||
- [Setting up Android SDK](https://developer.android.com/about/versions/14/setup-sdk)
|
||||
- [ANDROID_HOME not being set](https://stackoverflow.com/questions/26356359/error-android-home-is-not-set-and-android-command-not-in-your-path-you-must/54888107#54888107)
|
||||
- [Android Auto app not showing up](https://www.reddit.com/r/AndroidAuto/s/LGYHoSPdXm)
|
||||
|
||||
## 🙏 Special Thanks To
|
||||
|
||||
- The [Jellyfin Team](https://jellyfin.org/) for making this possible with their software, SDKs, and unequivocal helpfulness.
|
||||
- Extra thanks to [Niels](https://github.com/nielsvanvelzen) and [Bill](https://github.com/thornbill)
|
||||
- [James](https://github.com/jmshrv) and all other contributors of [Finamp](https://github.com/jmshrv/finamp). _Jellify_ draws inspiration and wisdom from it, and is another fantastic music app for Jellyfin.
|
||||
- James’ [API Blog Post](https://jmshrv.com/posts/jellyfin-api/) proved to be exceptionally valuable during development
|
||||
- The folks in the [Margelo Community Discord](https://discord.com/invite/6CSHz2qAvA) for their assistance
|
||||
- [Nicolas Charpentier](https://github.com/charpeni) for his [React Native URL Polyfill](https://github.com/charpeni/react-native-url-polyfill) module and for his assistance with getting Jest working
|
||||
- The team behind [Podverse](https://github.com/podverse/podverse-rn) for their incredible open source project, of which was used as a reference extensively during development
|
||||
- My fellow [contributors](https://github.com/anultravioletaurora/Jellify/graphs/contributors) who have poured so much heart and a lot of sweat into making _Jellify_ a great experience
|
||||
- Extra thanks to [John](https://github.com/johngrantdev) and [Vali-98](https://github.com/Vali-98) for shaping and designing the user experience in many places
|
||||
- Huge thank you to [Ritesh](https://github.com/riteshshukla04) for your project automation and backend expertise (and for the memes)
|
||||
- The friends I made along the way that have been critical in fostering an amazing community around _Jellify_
|
||||
- [Thalia](https://github.com/PercyGabriel1129)
|
||||
- [BotBlake](https://github.com/BotBlake)
|
||||
- My long time friends that have heard me talk about _Jellify_ for literally **eons**. Thank you for testing _Jellify_ during it's infancy and for supporting me all the way back at the beginning of this project
|
||||
- Tony (iOS, Android)
|
||||
- Trevor (Android)
|
||||
- [Laine](https://github.com/lainie-ftw) (Android)
|
||||
- [Jordan](https://github.com/jordanbleu) (iOS)
|
||||
- My best(est) friend [Alyssa](https://www.instagram.com/uhh.lyssarae?igsh=MTRmczExempnbjBwZw==), for your design knowledge and for making various artwork for _Jellify_.
|
||||
- You’ve been instrumental in shaping it’s user experience, my rock during development, and an overall inspiration in my life
|
||||
- The [Jellyfin Team](https://jellyfin.org/) for making this possible with their software, SDKs, and unequivocal helpfulness.
|
||||
- Extra thanks to [Niels](https://github.com/nielsvanvelzen) and [Bill](https://github.com/thornbill)
|
||||
- [James](https://github.com/jmshrv) and all other contributors of [Finamp](https://github.com/jmshrv/finamp). _Jellify_ draws inspiration and wisdom from it, and is another fantastic music app for Jellyfin.
|
||||
- James’ [API Blog Post](https://jmshrv.com/posts/jellyfin-api/) proved to be exceptionally valuable during development
|
||||
- The folks in the [Margelo Community Discord](https://discord.com/invite/6CSHz2qAvA) for their assistance
|
||||
- [Nicolas Charpentier](https://github.com/charpeni) for his [React Native URL Polyfill](https://github.com/charpeni/react-native-url-polyfill) module and for his assistance with getting Jest working
|
||||
- The team behind [Podverse](https://github.com/podverse/podverse-rn) for their incredible open source project, of which was used as a reference extensively during development
|
||||
- My fellow [contributors](https://github.com/anultravioletaurora/Jellify/graphs/contributors) who have poured so much heart and a lot of sweat into making _Jellify_ a great experience
|
||||
- Extra thanks to [John](https://github.com/johngrantdev) and [Vali-98](https://github.com/Vali-98) for shaping and designing the user experience in many places
|
||||
- Huge thank you to [Ritesh](https://github.com/riteshshukla04) for your project automation and backend expertise (and for the memes)
|
||||
- The friends I made along the way that have been critical in fostering an amazing community around _Jellify_
|
||||
- [Thalia](https://github.com/PercyGabriel1129)
|
||||
- [BotBlake](https://github.com/BotBlake)
|
||||
- My long time friends that have heard me talk about _Jellify_ for literally **eons**. Thank you for testing _Jellify_ during it's infancy and for supporting me all the way back at the beginning of this project
|
||||
- Tony (iOS, Android)
|
||||
- Trevor (Android)
|
||||
- [Laine](https://github.com/lainie-ftw) (Android)
|
||||
- [Jordan](https://github.com/jordanbleu) (iOS)
|
||||
- My best(est) friend [Alyssa](https://www.instagram.com/uhh.lyssarae?igsh=MTRmczExempnbjBwZw==), for your design knowledge and for making various artwork for _Jellify_.
|
||||
- You’ve been instrumental in shaping it’s user experience, my rock during development, and an overall inspiration in my life
|
||||
|
||||
@@ -32,7 +32,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
|
||||
# your application. You should enable this flag either if you want
|
||||
# to write custom TurboModules/Fabric components OR use libraries that
|
||||
# are providing them.
|
||||
newArchEnabled=false
|
||||
newArchEnabled=true
|
||||
|
||||
# Use this property to enable or disable the Hermes JS engine.
|
||||
# If set to false, you will be using JSC instead.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -3,6 +3,8 @@ import { getModel, getUniqueIdSync } from 'react-native-device-info'
|
||||
import { name, version } from '../package.json'
|
||||
import { capitalize } from 'lodash'
|
||||
|
||||
console.debug(`Building Jellyfin Info`)
|
||||
|
||||
/**
|
||||
* Client object that represents Jellify on the Jellyfin server.
|
||||
*/
|
||||
|
||||
5
app.json
5
app.json
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"name": "Jellify",
|
||||
"displayName": "Jellify"
|
||||
"displayName": "Jellify",
|
||||
"expo": {
|
||||
"newArchEnabled": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
module.exports = {
|
||||
presets: ['module:@react-native/babel-preset'],
|
||||
plugins: [
|
||||
'react-native-boost/plugin',
|
||||
// react-native-reanimated/plugin has to be listed last
|
||||
'react-native-reanimated/plugin',
|
||||
],
|
||||
|
||||
@@ -10,6 +10,7 @@ import Client from '../../api/client'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import FrequentArtists from './helpers/frequent-artists'
|
||||
import FrequentlyPlayedTracks from './helpers/frequent-tracks'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
|
||||
export function ProvidedHome({
|
||||
navigation,
|
||||
@@ -18,6 +19,8 @@ export function ProvidedHome({
|
||||
}): React.JSX.Element {
|
||||
const { refreshing: refetching, onRefresh } = useHomeContext()
|
||||
|
||||
const insets = useSafeAreaInsets()
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
contentInsetAdjustmentBehavior='automatic'
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Playlist from '../../../components/Playlist/component'
|
||||
import { StackParamList } from '../../../components/types'
|
||||
import { RouteProp } from '@react-navigation/native'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import React from 'react'
|
||||
import Playlist from '..'
|
||||
|
||||
export function PlaylistScreen({
|
||||
route,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react'
|
||||
import { ScrollView } from 'tamagui'
|
||||
import SignOut from './helpers/sign-out'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import { StackParamList } from '../types'
|
||||
@@ -7,7 +6,7 @@ import { useSafeAreaFrame } from 'react-native-safe-area-context'
|
||||
import { FlatList } from 'react-native'
|
||||
import IconCard from '../Global/helpers/icon-card'
|
||||
import Categories from './categories'
|
||||
import { StorageBar } from '../Storage'
|
||||
import StorageBar from '../Storage'
|
||||
|
||||
export default function Root({
|
||||
navigation,
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { View, Text, StyleSheet, Pressable, Alert, FlatList } from 'react-native'
|
||||
import { StyleSheet, Pressable, Alert, FlatList } from 'react-native'
|
||||
import RNFS from 'react-native-fs'
|
||||
import Animated, { useSharedValue, useAnimatedStyle, withTiming } from 'react-native-reanimated'
|
||||
import { deleteAudioCache } from '../Network/offlineModeUtils'
|
||||
import { useNetworkContext } from '../Network/provider'
|
||||
import DownloadProgress from '../../types/DownloadProgress'
|
||||
import Icon from '../Global/helpers/icon'
|
||||
import { View } from 'tamagui'
|
||||
import { Text } from '../Global/helpers/text'
|
||||
|
||||
// 🔹 Single Download Item with animated progress bar
|
||||
const DownloadItem = ({
|
||||
function DownloadItem({
|
||||
name,
|
||||
progress,
|
||||
fileName,
|
||||
@@ -16,7 +17,7 @@ const DownloadItem = ({
|
||||
name: string
|
||||
progress: number
|
||||
fileName: string
|
||||
}) => {
|
||||
}): React.JSX.Element {
|
||||
const progressValue = useSharedValue(progress)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -38,7 +39,7 @@ const DownloadItem = ({
|
||||
}
|
||||
|
||||
// 🔹 Main UI Component
|
||||
export const StorageBar = () => {
|
||||
export default function StorageBar(): React.JSX.Element {
|
||||
const [used, setUsed] = useState(0)
|
||||
const [total, setTotal] = useState(1)
|
||||
|
||||
@@ -86,7 +87,9 @@ export const StorageBar = () => {
|
||||
{/* Storage Usage */}
|
||||
<Text style={styles.title}>📦 Storage Usage</Text>
|
||||
<Text style={styles.usage}>
|
||||
{(used / 1024 / 1024).toFixed(2)} MB / {(total / 1024 / 1024 / 1024).toFixed(2)} GB
|
||||
{`${(used / 1024 / 1024).toFixed(2)} MB / ${(total / 1024 / 1024 / 1024).toFixed(
|
||||
2,
|
||||
)} GB`}
|
||||
</Text>
|
||||
<View style={styles.progressBackground}>
|
||||
<Animated.View style={[styles.progressFill, storageBarStyle]} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import _ from 'lodash'
|
||||
import React from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import Navigation from './navigation'
|
||||
import Login from './Login/component'
|
||||
import { JellyfinAuthenticationProvider } from './Login/provider'
|
||||
@@ -11,8 +11,15 @@ import { ToastProvider } from '@tamagui/toast'
|
||||
import { JellifyUserDataProvider } from './user-data-provider'
|
||||
import { NetworkContextProvider } from './Network/provider'
|
||||
import { QueueProvider } from '../player/queue-provider'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
|
||||
export default function Jellify(): React.JSX.Element {
|
||||
const insets = useSafeAreaInsets()
|
||||
|
||||
useEffect(() => {
|
||||
console.debug(insets)
|
||||
}, [insets])
|
||||
|
||||
return (
|
||||
<PortalProvider shouldAddRootHost>
|
||||
<ToastProvider burntOptions={{ from: 'top' }}>
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import { StyleSheet } from 'react-native'
|
||||
|
||||
export const jellifyStyles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
marginHorizontal: 16,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
marginVertical: 8,
|
||||
},
|
||||
fixToText: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
separator: {
|
||||
marginVertical: 8,
|
||||
borderBottomColor: '#737373',
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
},
|
||||
})
|
||||
@@ -2,7 +2,6 @@ import React from 'react'
|
||||
import { BottomTabBar, createBottomTabNavigator } from '@react-navigation/bottom-tabs'
|
||||
import Home from './Home/stack'
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
|
||||
import Library from './Library/stack'
|
||||
import Settings from './Settings/stack'
|
||||
import { Discover } from './Discover/stack'
|
||||
import { Miniplayer } from './Player/mini-player'
|
||||
@@ -10,7 +9,7 @@ import { getToken, getTokens, Separator } from 'tamagui'
|
||||
import { usePlayerContext } from '../player/player-provider'
|
||||
import SearchStack from './Search/stack'
|
||||
import LibraryStack from './Library/stack'
|
||||
import { useColorScheme, View } from 'react-native'
|
||||
import { useColorScheme } from 'react-native'
|
||||
import InternetConnectionWatcher from './Network/internetConnectionWatcher'
|
||||
|
||||
const Tab = createBottomTabNavigator()
|
||||
@@ -20,99 +19,97 @@ export function Tabs(): React.JSX.Element {
|
||||
const { nowPlaying } = usePlayerContext()
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<Tab.Navigator
|
||||
initialRouteName='Home'
|
||||
screenOptions={{
|
||||
lazy: false,
|
||||
animation: 'shift',
|
||||
tabBarActiveTintColor: getTokens().color.telemagenta.val,
|
||||
tabBarInactiveTintColor: isDarkMode
|
||||
? getToken('$color.amethyst')
|
||||
: getToken('$color.purpleGray'),
|
||||
<Tab.Navigator
|
||||
initialRouteName='Home'
|
||||
screenOptions={{
|
||||
lazy: false,
|
||||
animation: 'shift',
|
||||
tabBarActiveTintColor: getTokens().color.telemagenta.val,
|
||||
tabBarInactiveTintColor: isDarkMode
|
||||
? getToken('$color.amethyst')
|
||||
: getToken('$color.purpleGray'),
|
||||
}}
|
||||
tabBar={(props) => (
|
||||
<>
|
||||
{nowPlaying && (
|
||||
/* Hide miniplayer if the queue is empty */
|
||||
<>
|
||||
<Separator />
|
||||
<Miniplayer navigation={props.navigation} />
|
||||
</>
|
||||
)}
|
||||
<InternetConnectionWatcher />
|
||||
|
||||
<BottomTabBar {...props} />
|
||||
</>
|
||||
)}
|
||||
>
|
||||
<Tab.Screen
|
||||
name='Home'
|
||||
component={Home}
|
||||
options={{
|
||||
headerShown: false,
|
||||
tabBarIcon: ({ color, size }) => (
|
||||
<MaterialCommunityIcons
|
||||
name='jellyfish-outline'
|
||||
color={color}
|
||||
size={size}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
tabBar={(props) => (
|
||||
<>
|
||||
{nowPlaying && (
|
||||
/* Hide miniplayer if the queue is empty */
|
||||
<>
|
||||
<Separator />
|
||||
<Miniplayer navigation={props.navigation} />
|
||||
</>
|
||||
)}
|
||||
<InternetConnectionWatcher />
|
||||
/>
|
||||
|
||||
<BottomTabBar {...props} />
|
||||
</>
|
||||
)}
|
||||
>
|
||||
<Tab.Screen
|
||||
name='Home'
|
||||
component={Home}
|
||||
options={{
|
||||
headerShown: false,
|
||||
tabBarIcon: ({ color, size }) => (
|
||||
<MaterialCommunityIcons
|
||||
name='jellyfish-outline'
|
||||
color={color}
|
||||
size={size}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name='Library'
|
||||
component={LibraryStack}
|
||||
options={{
|
||||
headerShown: false,
|
||||
tabBarIcon: ({ color, size }) => (
|
||||
<MaterialCommunityIcons
|
||||
name='book-music-outline'
|
||||
color={color}
|
||||
size={size}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
|
||||
<Tab.Screen
|
||||
name='Library'
|
||||
component={LibraryStack}
|
||||
options={{
|
||||
headerShown: false,
|
||||
tabBarIcon: ({ color, size }) => (
|
||||
<MaterialCommunityIcons
|
||||
name='book-music-outline'
|
||||
color={color}
|
||||
size={size}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name='Search'
|
||||
component={SearchStack}
|
||||
options={{
|
||||
headerShown: false,
|
||||
tabBarIcon: ({ color, size }) => (
|
||||
<MaterialCommunityIcons name='magnify' color={color} size={size} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
|
||||
<Tab.Screen
|
||||
name='Search'
|
||||
component={SearchStack}
|
||||
options={{
|
||||
headerShown: false,
|
||||
tabBarIcon: ({ color, size }) => (
|
||||
<MaterialCommunityIcons name='magnify' color={color} size={size} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name='Discover'
|
||||
component={Discover}
|
||||
options={{
|
||||
headerShown: false,
|
||||
tabBarIcon: ({ color, size }) => (
|
||||
<MaterialCommunityIcons
|
||||
name='music-box-multiple-outline'
|
||||
color={color}
|
||||
size={size}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
|
||||
<Tab.Screen
|
||||
name='Discover'
|
||||
component={Discover}
|
||||
options={{
|
||||
headerShown: false,
|
||||
tabBarIcon: ({ color, size }) => (
|
||||
<MaterialCommunityIcons
|
||||
name='music-box-multiple-outline'
|
||||
color={color}
|
||||
size={size}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
|
||||
<Tab.Screen
|
||||
name='Settings'
|
||||
component={Settings}
|
||||
options={{
|
||||
headerShown: false,
|
||||
tabBarIcon: ({ color, size }) => (
|
||||
<MaterialCommunityIcons name='dip-switch' color={color} size={size} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Tab.Navigator>
|
||||
</View>
|
||||
<Tab.Screen
|
||||
name='Settings'
|
||||
component={Settings}
|
||||
options={{
|
||||
headerShown: false,
|
||||
tabBarIcon: ({ color, size }) => (
|
||||
<MaterialCommunityIcons name='dip-switch' color={color} size={size} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Tab.Navigator>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { MMKV } from 'react-native-mmkv'
|
||||
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'
|
||||
|
||||
console.debug(`Building MMKV storage`)
|
||||
|
||||
export const storage = new MMKV()
|
||||
|
||||
const clientStorage = {
|
||||
|
||||
4
index.js
4
index.js
@@ -10,8 +10,8 @@ import Client from './api/client'
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
||||
Client.instance
|
||||
|
||||
// Enable React Navigation freeze for detaching inactive screens
|
||||
// enableFreeze();
|
||||
Client.instance
|
||||
console.debug('Created Jellify client')
|
||||
|
||||
AppRegistry.registerComponent(appName, () => App)
|
||||
AppRegistry.registerComponent('RNCarPlayScene', () => App)
|
||||
|
||||
@@ -2,36 +2,38 @@
|
||||
import UIKit
|
||||
import CarPlay
|
||||
import React
|
||||
#if DEBUG
|
||||
#if FB_SONARKIT_ENABLED
|
||||
import FlipperKit
|
||||
#endif
|
||||
#endif
|
||||
import React_RCTAppDelegate
|
||||
import ReactAppDependencyProvider
|
||||
|
||||
@main
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate, RCTBridgeDelegate {
|
||||
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
var bridge: RCTBridge?;
|
||||
var rootView: RCTRootView?;
|
||||
|
||||
static var shared: AppDelegate { return UIApplication.shared.delegate as! AppDelegate }
|
||||
|
||||
func sourceURL(for bridge: RCTBridge) -> URL? {
|
||||
#if DEBUG
|
||||
return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index");
|
||||
#else
|
||||
return Bundle.main.url(forResource:"main", withExtension:"jsbundle")
|
||||
#endif
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
initializeFlipper(with: application)
|
||||
self.bridge = RCTBridge.init(delegate: self, launchOptions: launchOptions)
|
||||
self.rootView = RCTRootView.init(bridge: self.bridge!, moduleName: "Jellify", initialProperties: nil)
|
||||
|
||||
var reactNativeDelegate: ReactNativeDelegate?
|
||||
var reactNativeFactory: RCTReactNativeFactory?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
|
||||
|
||||
let delegate = ReactNativeDelegate()
|
||||
let factory = RCTReactNativeFactory(delegate: delegate)
|
||||
|
||||
delegate.dependencyProvider = RCTAppDependencyProvider()
|
||||
|
||||
reactNativeDelegate = delegate
|
||||
reactNativeFactory = factory
|
||||
|
||||
window = UIWindow(frame: UIScreen.main.bounds)
|
||||
|
||||
factory.startReactNative(
|
||||
withModuleName: "Jellify",
|
||||
in: window,
|
||||
launchOptions: launchOptions
|
||||
)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
|
||||
if (connectingSceneSession.role == UISceneSession.Role.carTemplateApplication) {
|
||||
let scene = UISceneConfiguration(name: "CarPlay", sessionRole: connectingSceneSession.role)
|
||||
@@ -43,21 +45,22 @@ class AppDelegate: UIResponder, UIApplicationDelegate, RCTBridgeDelegate {
|
||||
return scene
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
|
||||
}
|
||||
}
|
||||
|
||||
private func initializeFlipper(with application: UIApplication) {
|
||||
class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
|
||||
|
||||
override func sourceURL(for bridge: RCTBridge) -> URL? {
|
||||
self.bundleURL()
|
||||
}
|
||||
|
||||
override func bundleURL() -> URL? {
|
||||
#if DEBUG
|
||||
#if FB_SONARKIT_ENABLED
|
||||
let client = FlipperClient.shared()
|
||||
let layoutDescriptorMapper = SKDescriptorMapper(defaults: ())
|
||||
client?.add(FlipperKitLayoutPlugin(rootNode: application, with: layoutDescriptorMapper!))
|
||||
client?.add(FKUserDefaultsPlugin(suiteName: nil))
|
||||
client?.add(FlipperKitReactPlugin())
|
||||
client?.add(FlipperKitNetworkPlugin(networkAdapter: SKIOSNetworkAdapter()))
|
||||
client?.start()
|
||||
#endif
|
||||
return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index");
|
||||
#else
|
||||
return Bundle.main.url(forResource:"main", withExtension:"jsbundle")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,20 +4,6 @@ import CarPlay
|
||||
|
||||
class CarSceneDelegate: UIResponder, CPTemplateApplicationSceneDelegate {
|
||||
func templateApplicationScene(_ templateApplicationScene: CPTemplateApplicationScene, didConnect interfaceController: CPInterfaceController) {
|
||||
|
||||
if let applicationDelegate = UIApplication.shared.delegate as? AppDelegate {
|
||||
|
||||
if applicationDelegate.bridge == nil {
|
||||
|
||||
applicationDelegate.bridge = RCTBridge.init(delegate: applicationDelegate, launchOptions: [:])
|
||||
|
||||
applicationDelegate.rootView = RCTRootView.init(
|
||||
bridge: applicationDelegate.bridge!,
|
||||
moduleName: "Jellify",
|
||||
initialProperties: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
RNCarPlay.connect(with: interfaceController, window: templateApplicationScene.carWindow);
|
||||
|
||||
|
||||
13
ios/Gemfile
13
ios/Gemfile
@@ -4,12 +4,17 @@ source 'https://rubygems.org'
|
||||
ruby ">=3.0.0"
|
||||
|
||||
# Exclude problematic versions of cocoapods and activesupport that causes build failures.
|
||||
|
||||
# Exclude problematic versions of cocoapods and activesupport that causes build failures.
|
||||
gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
|
||||
gem 'cocoapods', '>= 1.16', '!= 1.15.0', '!= 1.15.1'
|
||||
gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
|
||||
gem 'xcodeproj', '< 1.27.1'
|
||||
gem 'concurrent-ruby', '< 1.3.4'
|
||||
gem 'concurrent-ruby', '< 1.3.6'
|
||||
gem "fastlane"
|
||||
|
||||
# Ruby 3.4.0 has removed some libraries from the standard library.
|
||||
gem 'bigdecimal'
|
||||
gem 'logger'
|
||||
gem 'benchmark'
|
||||
gem 'mutex_m'
|
||||
|
||||
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
|
||||
eval_gemfile(plugins_path) if File.exist?(plugins_path)
|
||||
|
||||
@@ -330,10 +330,14 @@ PLATFORMS
|
||||
|
||||
DEPENDENCIES
|
||||
activesupport (>= 6.1.7.5, != 7.1.0)
|
||||
cocoapods (>= 1.13, != 1.15.1, != 1.15.0)
|
||||
concurrent-ruby (< 1.3.4)
|
||||
benchmark
|
||||
bigdecimal
|
||||
cocoapods (>= 1.16, != 1.15.1, != 1.15.0)
|
||||
concurrent-ruby (< 1.3.6)
|
||||
fastlane
|
||||
fastlane-plugin-discord_notifier
|
||||
logger
|
||||
mutex_m
|
||||
xcodeproj (< 1.27.1)
|
||||
|
||||
RUBY VERSION
|
||||
|
||||
@@ -1,19 +1,99 @@
|
||||
// ios/PhoneScene.swift
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
|
||||
extension UIColor {
|
||||
convenience init(hex: String) {
|
||||
var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
hexSanitized = hexSanitized.replacingOccurrences(of: "#", with: "")
|
||||
|
||||
var rgb: UInt64 = 0
|
||||
Scanner(string: hexSanitized).scanHexInt64(&rgb)
|
||||
|
||||
let r = (rgb & 0xFF0000) >> 16
|
||||
let g = (rgb & 0x00FF00) >> 8
|
||||
let b = rgb & 0x0000FF
|
||||
|
||||
self.init(
|
||||
red: CGFloat(r) / 255,
|
||||
green: CGFloat(g) / 255,
|
||||
blue: CGFloat(b) / 255,
|
||||
alpha: 1.0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class PhoneSceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
var window: UIWindow?
|
||||
|
||||
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
|
||||
guard let appDelegate = (UIApplication.shared.delegate as? AppDelegate) else { return }
|
||||
guard let windowScene = (scene as? UIWindowScene) else { return }
|
||||
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
|
||||
guard let windowScene = scene as? UIWindowScene else { return }
|
||||
guard let appRootView = appDelegate.window?.rootViewController?.view else { return }
|
||||
|
||||
let rootViewController = UIViewController()
|
||||
rootViewController.view = appDelegate.rootView;
|
||||
let containerViewController = UIViewController()
|
||||
containerViewController.view.backgroundColor = .systemBackground // dynamic light/dark
|
||||
|
||||
// Create safe area container
|
||||
let safeAreaContainer = UIView()
|
||||
safeAreaContainer.translatesAutoresizingMaskIntoConstraints = false
|
||||
containerViewController.view.addSubview(safeAreaContainer)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
safeAreaContainer.topAnchor.constraint(equalTo: containerViewController.view.safeAreaLayoutGuide.topAnchor),
|
||||
safeAreaContainer.bottomAnchor.constraint(equalTo: containerViewController.view.safeAreaLayoutGuide.bottomAnchor),
|
||||
safeAreaContainer.leadingAnchor.constraint(equalTo: containerViewController.view.safeAreaLayoutGuide.leadingAnchor),
|
||||
safeAreaContainer.trailingAnchor.constraint(equalTo: containerViewController.view.safeAreaLayoutGuide.trailingAnchor),
|
||||
])
|
||||
|
||||
// Create colored views for top and bottom safe area
|
||||
let topBar = UIView()
|
||||
let bottomBar = UIView()
|
||||
topBar.translatesAutoresizingMaskIntoConstraints = false
|
||||
bottomBar.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
// Color that automatically adapts to dark/light mode
|
||||
topBar.backgroundColor = UIColor { trait in
|
||||
return trait.userInterfaceStyle == .dark ? UIColor(hex: "#0C0622") : UIColor(hex:"#FFFFFF")
|
||||
}
|
||||
bottomBar.backgroundColor = UIColor { trait in
|
||||
return trait.userInterfaceStyle == .dark ? UIColor(hex:"#0C0622") : UIColor(hex:"#FFFFFF")
|
||||
}
|
||||
|
||||
containerViewController.view.addSubview(topBar)
|
||||
containerViewController.view.addSubview(bottomBar)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
// Top bar
|
||||
topBar.topAnchor.constraint(equalTo: containerViewController.view.topAnchor),
|
||||
topBar.leadingAnchor.constraint(equalTo: containerViewController.view.leadingAnchor),
|
||||
topBar.trailingAnchor.constraint(equalTo: containerViewController.view.trailingAnchor),
|
||||
topBar.bottomAnchor.constraint(equalTo: containerViewController.view.safeAreaLayoutGuide.topAnchor),
|
||||
|
||||
// Bottom bar
|
||||
bottomBar.topAnchor.constraint(equalTo: containerViewController.view.safeAreaLayoutGuide.bottomAnchor),
|
||||
bottomBar.leadingAnchor.constraint(equalTo: containerViewController.view.leadingAnchor),
|
||||
bottomBar.trailingAnchor.constraint(equalTo: containerViewController.view.trailingAnchor),
|
||||
bottomBar.bottomAnchor.constraint(equalTo: containerViewController.view.bottomAnchor),
|
||||
])
|
||||
|
||||
// Add appRootView inside safeAreaContainer
|
||||
appRootView.translatesAutoresizingMaskIntoConstraints = false
|
||||
safeAreaContainer.addSubview(appRootView)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
appRootView.topAnchor.constraint(equalTo: safeAreaContainer.topAnchor),
|
||||
appRootView.bottomAnchor.constraint(equalTo: safeAreaContainer.bottomAnchor),
|
||||
appRootView.leadingAnchor.constraint(equalTo: safeAreaContainer.leadingAnchor),
|
||||
appRootView.trailingAnchor.constraint(equalTo: safeAreaContainer.trailingAnchor),
|
||||
])
|
||||
|
||||
// Set up the window
|
||||
let window = UIWindow(windowScene: windowScene)
|
||||
window.rootViewController = rootViewController
|
||||
window.rootViewController = containerViewController
|
||||
self.window = window
|
||||
window.makeKeyAndVisible()
|
||||
}
|
||||
|
||||
1022
ios/Podfile.lock
1022
ios/Podfile.lock
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,6 @@
|
||||
// Learn more https://docs.expo.io/guides/customizing-metro
|
||||
const { wrapWithReanimatedMetroConfig } = require('react-native-reanimated/metro-config')
|
||||
|
||||
const { getDefaultConfig } = require('@react-native/metro-config')
|
||||
|
||||
const config = getDefaultConfig(__dirname, {
|
||||
|
||||
241
package.json
241
package.json
@@ -1,123 +1,120 @@
|
||||
{
|
||||
"name": "jellify",
|
||||
"version": "0.11.15",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"init:ios": "yarn install && yarn pod:install",
|
||||
"reinstall": "rm -rf ./node_modules && yarn install",
|
||||
"android": "react-native run-android",
|
||||
"ios": "react-native run-ios",
|
||||
"lint": "eslint .",
|
||||
"start": "react-native start",
|
||||
"test": "jest",
|
||||
"clean:ios": "cd ios && pod deintegrate",
|
||||
"clean:android": "cd android && rm -rf app/ build/",
|
||||
"pod:install": "cd ios && bundle install && RCT_NEW_ARCH_ENABLED=0 bundle exec pod install",
|
||||
"pod:install-new-arch": "cd ios && bundle install && RCT_NEW_ARCH_ENABLED=1 bundle exec pod install",
|
||||
"fastlane:ios:build": "cd ios && bundle exec fastlane build",
|
||||
"fastlane:ios:match": "cd ios && bundle exec fastlane match development",
|
||||
"fastlane:ios:beta": "cd ios && bundle exec fastlane beta",
|
||||
"fastlane:android:build": "cd android && bundle install && bundle exec fastlane build",
|
||||
"androidBuild": "cd android && ./gradlew clean && ./gradlew assembleRelease && cd .. && echo 'find apk in android/app/build/outputs/apk/release'",
|
||||
"prepare": "husky",
|
||||
"format:check": "prettier --check .",
|
||||
"format": "prettier --write .",
|
||||
"postinstall": "patch-package"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jellyfin/sdk": "^0.11.0",
|
||||
"@react-native-community/blur": "^4.4.1",
|
||||
"@react-native-community/cli": "^15.1.3",
|
||||
"@react-native-community/netinfo": "^11.4.1",
|
||||
"@react-native-masked-view/masked-view": "^0.3.2",
|
||||
"@react-navigation/bottom-tabs": "^7.3.10",
|
||||
"@react-navigation/material-top-tabs": "^7.2.10",
|
||||
"@react-navigation/native": "^7.1.6",
|
||||
"@react-navigation/native-stack": "^7.3.10",
|
||||
"@react-navigation/stack": "^7.2.10",
|
||||
"@tamagui/config": "^1.126.1",
|
||||
"@tamagui/toast": "^1.126.1",
|
||||
"@tanstack/query-sync-storage-persister": "^5.74.6",
|
||||
"@tanstack/react-query": "^5.74.4",
|
||||
"@tanstack/react-query-persist-client": "^5.74.6",
|
||||
"@testing-library/react-native": "^13.2.0",
|
||||
"axios": "^1.8.4",
|
||||
"bundle": "^2.1.0",
|
||||
"burnt": "^0.13.0",
|
||||
"expo": "^52.0.46",
|
||||
"expo-image": "^2.0.7",
|
||||
"gem": "^2.4.3",
|
||||
"invert-color": "^2.0.0",
|
||||
"jest-expo": "^52.0.6",
|
||||
"lodash": "^4.17.21",
|
||||
"npm-bundle": "^3.0.3",
|
||||
"patch-package": "^8.0.0",
|
||||
"react": "18.3.1",
|
||||
"react-freeze": "^1.0.4",
|
||||
"react-native": "0.77.0",
|
||||
"react-native-background-actions": "^4.0.1",
|
||||
"react-native-blurhash": "^2.1.1",
|
||||
"react-native-boost": "^0.5.6",
|
||||
"react-native-carplay": "^2.4.1-beta.0",
|
||||
"react-native-device-info": "^14.0.4",
|
||||
"react-native-draggable-flatlist": "^4.0.2",
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-gesture-handler": "^2.25.0",
|
||||
"react-native-haptic-feedback": "^2.3.3",
|
||||
"react-native-mmkv": "^2.12.2",
|
||||
"react-native-pager-view": "^6.7.1",
|
||||
"react-native-reanimated": "^3.17.5",
|
||||
"react-native-safe-area-context": "^5.4.0",
|
||||
"react-native-screens": "^4.10.0",
|
||||
"react-native-swipeable-item": "^2.0.9",
|
||||
"react-native-text-ticker": "^1.14.0",
|
||||
"react-native-track-player": "^4.1.1",
|
||||
"react-native-url-polyfill": "^2.0.0",
|
||||
"react-native-uuid": "^2.0.3",
|
||||
"react-native-vector-icons": "^10.2.0",
|
||||
"ruby": "^0.6.1",
|
||||
"tamagui": "^1.126.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@babel/preset-env": "^7.25.3",
|
||||
"@babel/runtime": "^7.25.0",
|
||||
"@react-native-community/cli-platform-android": "15.1.3",
|
||||
"@react-native-community/cli-platform-ios": "15.1.3",
|
||||
"@react-native/babel-preset": "0.77.0",
|
||||
"@react-native/eslint-config": "0.77.0",
|
||||
"@react-native/metro-config": "0.77.0",
|
||||
"@react-native/typescript-config": "0.77.0",
|
||||
"@types/jest": "^29.5.13",
|
||||
"@types/lodash": "^4.17.10",
|
||||
"@types/react": "^18.2.6",
|
||||
"@types/react-native-vector-icons": "^6.4.18",
|
||||
"@types/react-test-renderer": "^18.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.29.1",
|
||||
"@typescript-eslint/parser": "^8.29.1",
|
||||
"babel-plugin-module-resolver": "^5.0.2",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-prettier": "^10.1.2",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-prettier": "^5.2.6",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-native": "^5.0.0",
|
||||
"husky": "^9.1.7",
|
||||
"jest": "^29.6.3",
|
||||
"jscodeshift": "^0.15.2",
|
||||
"lint-staged": "^15.5.0",
|
||||
"prettier": "^2.8.8",
|
||||
"react-native-cli-bump-version": "^1.5.1",
|
||||
"react-test-renderer": "18.3.1",
|
||||
"typescript": "5.7.3"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,ts,tsx}": [
|
||||
"prettier --write",
|
||||
"eslint --fix"
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
}
|
||||
"name": "jellify",
|
||||
"version": "0.11.15",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"init-ios": "yarn install && yarn pod:install",
|
||||
"init-ios:new-arch": "yarn install && yarn run pod:install:new-arch",
|
||||
"reinstall": "rm -rf ./node_modules && yarn install",
|
||||
"android": "react-native run-android",
|
||||
"ios": "react-native run-ios",
|
||||
"lint": "eslint .",
|
||||
"start": "react-native start",
|
||||
"test": "jest",
|
||||
"clean:ios": "cd ios && pod deintegrate",
|
||||
"clean:android": "cd android && rm -rf app/ build/",
|
||||
"pod:install": "cd ios && bundle install && RCT_NEW_ARCH_ENABLED=0 bundle exec pod install",
|
||||
"pod:install:new-arch": "cd ios && bundle install && RCT_NEW_ARCH_ENABLED=1 bundle exec pod install",
|
||||
"pod:clean": "cd ios && pod deintegrate",
|
||||
"fastlane:ios:build": "cd ios && bundle exec fastlane build",
|
||||
"fastlane:ios:match": "cd ios && bundle exec fastlane match development",
|
||||
"fastlane:ios:beta": "cd ios && bundle exec fastlane beta",
|
||||
"fastlane:android:build": "cd android && bundle install && bundle exec fastlane build",
|
||||
"androidBuild": "cd android && ./gradlew clean && ./gradlew assembleRelease && cd .. && echo 'find apk in android/app/build/outputs/apk/release'",
|
||||
"prepare": "husky",
|
||||
"format:check": "prettier --check .",
|
||||
"format": "prettier --write .",
|
||||
"postinstall": "patch-package"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jellyfin/sdk": "^0.11.0",
|
||||
"@react-native-community/cli": "^18.0.0",
|
||||
"@react-native-community/netinfo": "^11.4.1",
|
||||
"@react-native-masked-view/masked-view": "^0.3.2",
|
||||
"@react-navigation/bottom-tabs": "^7.3.10",
|
||||
"@react-navigation/material-top-tabs": "^7.2.10",
|
||||
"@react-navigation/native": "^7.1.6",
|
||||
"@react-navigation/native-stack": "^7.3.10",
|
||||
"@react-navigation/stack": "^7.2.10",
|
||||
"@tamagui/config": "^1.126.4",
|
||||
"@tamagui/toast": "^1.126.4",
|
||||
"@tanstack/query-sync-storage-persister": "^5.74.6",
|
||||
"@tanstack/react-query": "^5.74.4",
|
||||
"@tanstack/react-query-persist-client": "^5.74.6",
|
||||
"@testing-library/react-native": "^13.2.0",
|
||||
"axios": "^1.8.4",
|
||||
"bundle": "^2.1.0",
|
||||
"burnt": "^0.13.0",
|
||||
"expo": "^53.0.1",
|
||||
"expo-image": "^2.0.7",
|
||||
"gem": "^2.4.3",
|
||||
"invert-color": "^2.0.0",
|
||||
"jest-expo": "^53.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "19.0.0",
|
||||
"react-freeze": "^1.0.4",
|
||||
"react-native": "0.79.1",
|
||||
"react-native-background-actions": "^4.0.1",
|
||||
"react-native-blurhash": "^2.1.1",
|
||||
"react-native-carplay": "^2.4.1-beta.0",
|
||||
"react-native-device-info": "^14.0.4",
|
||||
"react-native-draggable-flatlist": "^4.0.2",
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-gesture-handler": "^2.25.0",
|
||||
"react-native-haptic-feedback": "^2.3.3",
|
||||
"react-native-mmkv": "^3.2.0",
|
||||
"react-native-pager-view": "^6.7.1",
|
||||
"react-native-reanimated": "^3.17.5",
|
||||
"react-native-safe-area-context": "^5.4.0",
|
||||
"react-native-screens": "^4.11.0-beta.2",
|
||||
"react-native-swipeable-item": "^2.0.9",
|
||||
"react-native-text-ticker": "^1.14.0",
|
||||
"react-native-track-player": "4.1.1",
|
||||
"react-native-url-polyfill": "^2.0.0",
|
||||
"react-native-uuid": "^2.0.3",
|
||||
"react-native-vector-icons": "^10.2.0",
|
||||
"ruby": "^0.6.1",
|
||||
"tamagui": "^1.126.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@babel/preset-env": "^7.25.3",
|
||||
"@babel/runtime": "^7.25.0",
|
||||
"@react-native-community/cli-platform-android": "18.0.0",
|
||||
"@react-native-community/cli-platform-ios": "18.0.0",
|
||||
"@react-native/babel-preset": "0.79.1",
|
||||
"@react-native/eslint-config": "0.79.1",
|
||||
"@react-native/metro-config": "0.79.1",
|
||||
"@react-native/typescript-config": "0.79.1",
|
||||
"@types/jest": "^29.5.13",
|
||||
"@types/lodash": "^4.17.10",
|
||||
"@types/react": "^19.1.2",
|
||||
"@types/react-native-vector-icons": "^6.4.18",
|
||||
"@types/react-test-renderer": "19.0.0",
|
||||
"babel-plugin-module-resolver": "^5.0.2",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-prettier": "^10.1.2",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-prettier": "^5.2.6",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-native": "^5.0.0",
|
||||
"husky": "^9.1.7",
|
||||
"jest": "^29.6.3",
|
||||
"jscodeshift": "^0.15.2",
|
||||
"lint-staged": "^15.5.0",
|
||||
"patch-package": "8.0.0",
|
||||
"prettier": "^2.8.8",
|
||||
"react-native-cli-bump-version": "^1.5.1",
|
||||
"react-test-renderer": "19.0.0",
|
||||
"typescript": "5.8.3"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,ts,tsx}": [
|
||||
"prettier --write",
|
||||
"eslint --fix"
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user