mirror of
https://github.com/anultravioletaurora/Jellify.git
synced 2025-12-21 05:20:06 -06:00
add library flow, organize login files (#456)
This commit is contained in:
68
App.tsx
68
App.tsx
@@ -19,6 +19,7 @@ import { requestStoragePermission } from './src/utils/permisson-helpers'
|
||||
import ErrorBoundary from './src/components/ErrorBoundary'
|
||||
import OTAUpdateScreen from './src/components/OtaUpdates'
|
||||
import { usePerformanceMonitor } from './src/hooks/use-performance-monitor'
|
||||
import { SettingsProvider, useSettingsContext } from './src/providers/Settings'
|
||||
|
||||
export const backgroundRuntime = createWorkletRuntime('background')
|
||||
|
||||
@@ -27,7 +28,6 @@ export default function App(): React.JSX.Element {
|
||||
const performanceMetrics = usePerformanceMonitor('App', 3)
|
||||
|
||||
const [playerIsReady, setPlayerIsReady] = useState<boolean>(false)
|
||||
const isDarkMode = useColorScheme() === 'dark'
|
||||
|
||||
TrackPlayer.setupPlayer({
|
||||
autoHandleInterruptions: true,
|
||||
@@ -65,31 +65,51 @@ export default function App(): React.JSX.Element {
|
||||
<SafeAreaProvider>
|
||||
<OTAUpdateScreen />
|
||||
<ErrorBoundary reloader={reloader} onRetry={handleRetry}>
|
||||
<NavigationContainer theme={isDarkMode ? JellifyDarkTheme : JellifyLightTheme}>
|
||||
<PersistQueryClientProvider
|
||||
client={queryClient}
|
||||
persistOptions={{
|
||||
persister: clientPersister,
|
||||
|
||||
/**
|
||||
* Infinity, since data can remain the
|
||||
* same forever on the server
|
||||
*/
|
||||
maxAge: Infinity,
|
||||
buster: '0.10.99',
|
||||
}}
|
||||
>
|
||||
<GestureHandlerRootView>
|
||||
<TamaguiProvider config={jellifyConfig}>
|
||||
<Theme name={isDarkMode ? 'dark' : 'light'}>
|
||||
{playerIsReady && <Jellify />}
|
||||
</Theme>
|
||||
</TamaguiProvider>
|
||||
</GestureHandlerRootView>
|
||||
</PersistQueryClientProvider>
|
||||
</NavigationContainer>
|
||||
<SettingsProvider>
|
||||
<Container playerIsReady={playerIsReady} />
|
||||
</SettingsProvider>
|
||||
</ErrorBoundary>
|
||||
</SafeAreaProvider>
|
||||
</React.StrictMode>
|
||||
)
|
||||
}
|
||||
|
||||
function Container({ playerIsReady }: { playerIsReady: boolean }): React.JSX.Element {
|
||||
const { theme } = useSettingsContext()
|
||||
|
||||
const isDarkMode = useColorScheme() === 'dark'
|
||||
|
||||
return (
|
||||
<NavigationContainer
|
||||
theme={
|
||||
theme === 'system'
|
||||
? isDarkMode
|
||||
? JellifyDarkTheme
|
||||
: JellifyLightTheme
|
||||
: theme === 'dark'
|
||||
? JellifyDarkTheme
|
||||
: JellifyLightTheme
|
||||
}
|
||||
>
|
||||
<PersistQueryClientProvider
|
||||
client={queryClient}
|
||||
persistOptions={{
|
||||
persister: clientPersister,
|
||||
|
||||
/**
|
||||
* Infinity, since data can remain the
|
||||
* same forever on the server
|
||||
*/
|
||||
maxAge: Infinity,
|
||||
buster: '0.10.99',
|
||||
}}
|
||||
>
|
||||
<GestureHandlerRootView>
|
||||
<TamaguiProvider config={jellifyConfig}>
|
||||
{playerIsReady && <Jellify />}
|
||||
</TamaguiProvider>
|
||||
</GestureHandlerRootView>
|
||||
</PersistQueryClientProvider>
|
||||
</NavigationContainer>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
appId: com.jellify
|
||||
---
|
||||
- runFlow: ../tests/library.yaml
|
||||
- runFlow: ../tests/settings.yaml
|
||||
|
||||
17
maestro/tests/musiclibrary.yaml
Normal file
17
maestro/tests/musiclibrary.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
appId: com.jellify
|
||||
---
|
||||
# Wait for app to be ready, then navigate to Settings tab
|
||||
- assertVisible:
|
||||
id: "library-tab-button"
|
||||
|
||||
# Navigate to Library tab using text
|
||||
- tapOn:
|
||||
id: "library-tab-button"
|
||||
|
||||
# Verify we're on the library page
|
||||
- assertVisible:
|
||||
id: "library-artists-tab-button"
|
||||
|
||||
# Navigate to Artists tab
|
||||
- tapOn:
|
||||
id: "library-artists-tab-button"
|
||||
@@ -3,7 +3,6 @@ appId: com.jellify
|
||||
# Wait for app to be ready, then navigate to Settings tab
|
||||
- assertVisible:
|
||||
id: "settings-tab-button"
|
||||
# timeout: 5000
|
||||
|
||||
# Navigate to Settings tab using text
|
||||
- tapOn:
|
||||
@@ -12,7 +11,6 @@ appId: com.jellify
|
||||
# Verify we're on the settings page
|
||||
- assertVisible:
|
||||
text: "App"
|
||||
# timeout: 3000
|
||||
|
||||
# Test App (Preferences) Tab - should already be selected
|
||||
- assertVisible:
|
||||
@@ -23,6 +21,14 @@ appId: com.jellify
|
||||
text: "Reduce Haptics"
|
||||
- assertVisible:
|
||||
text: "Reduce haptic feedback"
|
||||
- assertVisible:
|
||||
text: "Theme"
|
||||
- assertVisible:
|
||||
text: "System"
|
||||
- assertVisible:
|
||||
text: "Light"
|
||||
- assertVisible:
|
||||
text: "Dark"
|
||||
|
||||
# Test Player (Playback) Tab
|
||||
- tapOn:
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import { getToken, getTokenValue, Separator, XStack, YStack } from 'tamagui'
|
||||
import { getToken, getTokenValue, Separator, useTheme, XStack, YStack } from 'tamagui'
|
||||
import { Text } from '../Global/helpers/text'
|
||||
import { RefreshControl } from 'react-native'
|
||||
import { ArtistsProps } from '../types'
|
||||
import ItemRow from '../Global/components/item-row'
|
||||
import { useLibrarySortAndFilterContext } from '../../providers/Library'
|
||||
import { useLibraryContext, useLibrarySortAndFilterContext } from '../../providers/Library'
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'
|
||||
import { FlashList } from '@shopify/flash-list'
|
||||
import { useLibraryContext } from '../../providers/Library'
|
||||
import { AZScroller } from '../Global/components/alphabetical-selector'
|
||||
import { useMutation } from '@tanstack/react-query'
|
||||
|
||||
@@ -17,7 +16,7 @@ export default function Artists({
|
||||
showAlphabeticalSelector,
|
||||
}: ArtistsProps): React.JSX.Element {
|
||||
const { artistPageParams } = useLibraryContext()
|
||||
|
||||
const theme = useTheme()
|
||||
const { isFavorites } = useLibrarySortAndFilterContext()
|
||||
|
||||
const sectionListRef = useRef<FlashList<string | number | BaseItemDto>>(null)
|
||||
@@ -32,23 +31,25 @@ export default function Artists({
|
||||
console.debug(`Alphabetical Selector Callback: ${letter}`)
|
||||
|
||||
do {
|
||||
if (artistPageParams.current.includes(letter)) break
|
||||
await artistsInfiniteQuery.fetchNextPage({ cancelRefetch: true })
|
||||
} while (
|
||||
artistsRef.current.indexOf(letter) === -1 &&
|
||||
!artistsRef.current.includes(letter) &&
|
||||
artistsInfiniteQuery.hasNextPage &&
|
||||
!artistsInfiniteQuery.isFetchNextPageError &&
|
||||
!artistsInfiniteQuery.isFetchingNextPage
|
||||
(!artistsInfiniteQuery.isFetchNextPageError || artistsInfiniteQuery.isFetchingNextPage)
|
||||
)
|
||||
}
|
||||
|
||||
const { mutate: alphabetSelectorMutate, isPending: isAlphabetSelectorPending } = useMutation({
|
||||
mutationFn: (letter: string) => alphabeticalSelectorCallback(letter),
|
||||
onSuccess: (data, letter) => {
|
||||
sectionListRef.current?.scrollToIndex({
|
||||
index: artistsRef.current!.indexOf(letter),
|
||||
viewPosition: 0.1,
|
||||
animated: true,
|
||||
})
|
||||
setTimeout(() => {
|
||||
sectionListRef.current?.scrollToIndex({
|
||||
index: artistsRef.current!.indexOf(letter),
|
||||
viewPosition: 0.1,
|
||||
animated: true,
|
||||
})
|
||||
}, 500)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -82,7 +83,7 @@ export default function Artists({
|
||||
data={artistsInfiniteQuery.data}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
colors={['$primary']}
|
||||
colors={[theme.primary.val]}
|
||||
refreshing={artistsInfiniteQuery.isPending || isAlphabetSelectorPending}
|
||||
progressViewOffset={getTokenValue('$10')}
|
||||
/>
|
||||
|
||||
@@ -44,6 +44,7 @@ export default function Library({
|
||||
small
|
||||
/>
|
||||
),
|
||||
tabBarButtonTestID: 'library-artists-tab-button',
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -58,6 +59,7 @@ export default function Library({
|
||||
small
|
||||
/>
|
||||
),
|
||||
tabBarButtonTestID: 'library-albums-tab-button',
|
||||
}}
|
||||
initialParams={{ navigation }}
|
||||
/>
|
||||
@@ -73,6 +75,7 @@ export default function Library({
|
||||
small
|
||||
/>
|
||||
),
|
||||
tabBarButtonTestID: 'library-tracks-tab-button',
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -87,6 +90,7 @@ export default function Library({
|
||||
small
|
||||
/>
|
||||
),
|
||||
tabBarButtonTestID: 'library-playlists-tab-button',
|
||||
}}
|
||||
initialParams={{ navigation }}
|
||||
/>
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||
import SettingsListGroup from './settings-list-group'
|
||||
import { RadioGroup, YStack } from 'tamagui'
|
||||
import { RadioGroupItemWithLabel } from '../../Global/helpers/radio-group-item-with-label'
|
||||
import { Text } from '../../Global/helpers/text'
|
||||
import { useJellifyContext } from '../../../providers/index'
|
||||
import { getQualityLabel, getBandwidthEstimate } from '../utils/quality'
|
||||
import { StreamingQuality, useSettingsContext } from '../../../providers/Settings'
|
||||
|
||||
export default function PlaybackTab(): React.JSX.Element {
|
||||
const { server } = useJellifyContext()
|
||||
const { streamingQuality, setStreamingQuality } = useSettingsContext()
|
||||
|
||||
return (
|
||||
@@ -21,10 +18,7 @@ export default function PlaybackTab(): React.JSX.Element {
|
||||
iconColor: getStreamingQualityIconColor(streamingQuality),
|
||||
children: (
|
||||
<YStack gap='$2' paddingVertical='$2'>
|
||||
<Text bold fontSize='$4'>
|
||||
Streaming Quality:
|
||||
</Text>
|
||||
<Text fontSize='$3' color='$gray11' marginBottom='$2'>
|
||||
<Text fontSize='$3' marginBottom='$2'>
|
||||
Higher quality uses more bandwidth. Changes apply to new tracks.
|
||||
</Text>
|
||||
<RadioGroup
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
import { useSettingsContext } from '../../../providers/Settings'
|
||||
import { RadioGroup, YStack } from 'tamagui'
|
||||
import { Theme, useSettingsContext } from '../../../providers/Settings'
|
||||
import { SwitchWithLabel } from '../../Global/helpers/switch-with-label'
|
||||
import SettingsListGroup from './settings-list-group'
|
||||
import { RadioGroupItemWithLabel } from '../../Global/helpers/radio-group-item-with-label'
|
||||
import { Text } from '../../Global/helpers/text'
|
||||
|
||||
export default function PreferencesTab(): React.JSX.Element {
|
||||
const { setSendMetrics, sendMetrics, setReducedHaptics, reducedHaptics } = useSettingsContext()
|
||||
const { setSendMetrics, sendMetrics, setReducedHaptics, reducedHaptics, theme, setTheme } =
|
||||
useSettingsContext()
|
||||
return (
|
||||
<SettingsListGroup
|
||||
settingsList={[
|
||||
{
|
||||
title: 'Send Metrics and Crash Reports',
|
||||
iconName: sendMetrics ? 'bug-check' : 'bug',
|
||||
iconColor: sendMetrics ? '$success' : '$borderColor',
|
||||
subTitle: 'Send anonymous usage and crash data',
|
||||
title: 'Theme',
|
||||
subTitle: `Current: ${theme}`,
|
||||
iconName: 'theme-light-dark',
|
||||
iconColor: `${theme === 'system' ? '$borderColor' : '$primary'}`,
|
||||
children: (
|
||||
<SwitchWithLabel
|
||||
checked={sendMetrics}
|
||||
onCheckedChange={setSendMetrics}
|
||||
size={'$2'}
|
||||
label={sendMetrics ? 'Enabled' : 'Disabled'}
|
||||
/>
|
||||
<YStack gap='$2' paddingVertical='$2'>
|
||||
<RadioGroup
|
||||
value={theme}
|
||||
onValueChange={(value) => setTheme(value as Theme)}
|
||||
>
|
||||
<RadioGroupItemWithLabel size='$3' value='system' label='System' />
|
||||
<RadioGroupItemWithLabel size='$3' value='light' label='Light' />
|
||||
<RadioGroupItemWithLabel size='$3' value='dark' label='Dark' />
|
||||
</RadioGroup>
|
||||
</YStack>
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -35,6 +43,20 @@ export default function PreferencesTab(): React.JSX.Element {
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Send Metrics and Crash Reports',
|
||||
iconName: sendMetrics ? 'bug-check' : 'bug',
|
||||
iconColor: sendMetrics ? '$success' : '$borderColor',
|
||||
subTitle: 'Send anonymous usage and crash data',
|
||||
children: (
|
||||
<SwitchWithLabel
|
||||
checked={sendMetrics}
|
||||
onCheckedChange={setSendMetrics}
|
||||
size={'$2'}
|
||||
label={sendMetrics ? 'Enabled' : 'Disabled'}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
import SettingsListGroup from './settings-list-group'
|
||||
import { SwitchWithLabel } from '../../Global/helpers/switch-with-label'
|
||||
import { RadioGroupItemWithLabel } from '../../Global/helpers/radio-group-item-with-label'
|
||||
import { useSettingsContext, DownloadQuality, StreamingQuality } from '../../../providers/Settings'
|
||||
import { useSettingsContext, DownloadQuality } from '../../../providers/Settings'
|
||||
import { useNetworkContext } from '../../../providers/Network'
|
||||
import { RadioGroup, YStack } from 'tamagui'
|
||||
import { Text } from '../../Global/helpers/text'
|
||||
import { getQualityLabel } from '../utils/quality'
|
||||
export default function StorageTab(): React.JSX.Element {
|
||||
const {
|
||||
autoDownload,
|
||||
setAutoDownload,
|
||||
downloadQuality,
|
||||
setDownloadQuality,
|
||||
streamingQuality,
|
||||
setStreamingQuality,
|
||||
} = useSettingsContext()
|
||||
const { downloadedTracks, storageUsage } = useNetworkContext()
|
||||
const { autoDownload, setAutoDownload, downloadQuality, setDownloadQuality } =
|
||||
useSettingsContext()
|
||||
const { downloadedTracks } = useNetworkContext()
|
||||
|
||||
return (
|
||||
<SettingsListGroup
|
||||
@@ -49,10 +43,7 @@ export default function StorageTab(): React.JSX.Element {
|
||||
iconColor: '$primary',
|
||||
children: (
|
||||
<YStack gap='$2' paddingVertical='$2'>
|
||||
<Text bold fontSize='$4'>
|
||||
Download Quality:
|
||||
</Text>
|
||||
<Text fontSize='$3' color='$gray11' marginBottom='$2'>
|
||||
<Text fontSize='$3' marginBottom='$2'>
|
||||
Quality used when saving tracks for offline use.
|
||||
</Text>
|
||||
<RadioGroup
|
||||
|
||||
@@ -16,18 +16,21 @@ import {
|
||||
import telemetryDeckConfig from '../../telemetrydeck.json'
|
||||
import glitchtipConfig from '../../glitchtip.json'
|
||||
import * as Sentry from '@sentry/react-native'
|
||||
import { useTheme } from 'tamagui'
|
||||
import { Theme, useTheme } from 'tamagui'
|
||||
import Toast from 'react-native-toast-message'
|
||||
import JellifyToastConfig from '../constants/toast.config'
|
||||
import { useColorScheme } from 'react-native'
|
||||
/**
|
||||
* The main component for the Jellify app. Children are wrapped in the {@link JellifyProvider}
|
||||
* @returns The {@link Jellify} component
|
||||
*/
|
||||
export default function Jellify(): React.JSX.Element {
|
||||
const theme = useTheme()
|
||||
const { theme } = useSettingsContext()
|
||||
|
||||
const isDarkMode = useColorScheme() === 'dark'
|
||||
|
||||
return (
|
||||
<SettingsProvider>
|
||||
<Theme name={theme === 'system' ? (isDarkMode ? 'dark' : 'light') : theme}>
|
||||
<JellifyLoggingWrapper>
|
||||
<DisplayProvider>
|
||||
<JellifyProvider>
|
||||
@@ -35,8 +38,7 @@ export default function Jellify(): React.JSX.Element {
|
||||
</JellifyProvider>
|
||||
</DisplayProvider>
|
||||
</JellifyLoggingWrapper>
|
||||
<Toast config={JellifyToastConfig(theme)} />
|
||||
</SettingsProvider>
|
||||
</Theme>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -67,6 +69,7 @@ function JellifyLoggingWrapper({ children }: { children: React.ReactNode }): Rea
|
||||
function App(): React.JSX.Element {
|
||||
const { sendMetrics } = useSettingsContext()
|
||||
const telemetrydeck = useTelemetryDeck()
|
||||
const theme = useTheme()
|
||||
|
||||
useEffect(() => {
|
||||
if (sendMetrics) {
|
||||
@@ -83,6 +86,7 @@ function App(): React.JSX.Element {
|
||||
</PlayerProvider>
|
||||
</QueueProvider>
|
||||
</NetworkContextProvider>
|
||||
<Toast config={JellifyToastConfig(theme)} />
|
||||
</JellifyUserDataProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -23,4 +23,5 @@ export enum MMKVStorageKeys {
|
||||
Shuffled = 'Shuffled',
|
||||
RepeatMode = 'RepeatMode',
|
||||
ReducedHaptics = 'ReducedHaptics',
|
||||
Theme = 'Theme',
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { createContext, useContext, useEffect, useState, useMemo } from 'react'
|
||||
|
||||
export type DownloadQuality = 'original' | 'high' | 'medium' | 'low'
|
||||
export type StreamingQuality = 'original' | 'high' | 'medium' | 'low'
|
||||
export type Theme = 'system' | 'light' | 'dark'
|
||||
|
||||
interface SettingsContext {
|
||||
sendMetrics: boolean
|
||||
@@ -19,6 +20,8 @@ interface SettingsContext {
|
||||
setStreamingQuality: React.Dispatch<React.SetStateAction<StreamingQuality>>
|
||||
reducedHaptics: boolean
|
||||
setReducedHaptics: React.Dispatch<React.SetStateAction<boolean>>
|
||||
theme: Theme
|
||||
setTheme: React.Dispatch<React.SetStateAction<Theme>>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,6 +42,7 @@ const SettingsContextInitializer = () => {
|
||||
const autoDownloadInit = storage.getBoolean(MMKVStorageKeys.AutoDownload)
|
||||
const devToolsInit = storage.getBoolean(MMKVStorageKeys.DevTools)
|
||||
const reducedHapticsInit = storage.getBoolean(MMKVStorageKeys.ReducedHaptics)
|
||||
const themeInit = storage.getString(MMKVStorageKeys.Theme) as Theme
|
||||
|
||||
const downloadQualityInit = storage.getString(
|
||||
MMKVStorageKeys.DownloadQuality,
|
||||
@@ -67,6 +71,8 @@ const SettingsContextInitializer = () => {
|
||||
reducedHapticsInit ?? (Platform.OS !== 'ios' && Math.random() > 0.7),
|
||||
)
|
||||
|
||||
const [theme, setTheme] = useState<Theme>(themeInit ?? 'system')
|
||||
|
||||
useEffect(() => {
|
||||
storage.set(MMKVStorageKeys.SendMetrics, sendMetrics)
|
||||
}, [sendMetrics])
|
||||
@@ -91,6 +97,10 @@ const SettingsContextInitializer = () => {
|
||||
storage.set(MMKVStorageKeys.ReducedHaptics, reducedHaptics)
|
||||
}, [reducedHaptics])
|
||||
|
||||
useEffect(() => {
|
||||
storage.set(MMKVStorageKeys.Theme, theme)
|
||||
}, [theme])
|
||||
|
||||
return {
|
||||
sendMetrics,
|
||||
setSendMetrics,
|
||||
@@ -104,6 +114,8 @@ const SettingsContextInitializer = () => {
|
||||
setStreamingQuality,
|
||||
reducedHaptics,
|
||||
setReducedHaptics,
|
||||
theme,
|
||||
setTheme,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +132,8 @@ export const SettingsContext = createContext<SettingsContext>({
|
||||
setStreamingQuality: () => {},
|
||||
reducedHaptics: false,
|
||||
setReducedHaptics: () => {},
|
||||
theme: 'system',
|
||||
setTheme: () => {},
|
||||
})
|
||||
|
||||
export const SettingsProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
@@ -135,6 +149,7 @@ export const SettingsProvider = ({ children }: { children: React.ReactNode }) =>
|
||||
context.downloadQuality,
|
||||
context.streamingQuality,
|
||||
context.reducedHaptics,
|
||||
context.theme,
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import _, { isUndefined } from 'lodash'
|
||||
import ServerAuthentication from '../../components/Login/screens/server-authentication'
|
||||
import ServerAddress from '../../components/Login/screens/server-address'
|
||||
import ServerAuthentication from './server-authentication'
|
||||
import ServerAddress from './server-address'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import ServerLibrary from '../../components/Login/screens/server-library'
|
||||
import ServerLibrary from './server-library'
|
||||
import { useJellifyContext } from '../../providers'
|
||||
|
||||
const LoginStack = createNativeStackNavigator()
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import _, { isUndefined } from 'lodash'
|
||||
import { useMutation } from '@tanstack/react-query'
|
||||
import { JellifyServer } from '../../../types/JellifyServer'
|
||||
import { JellifyServer } from '../../types/JellifyServer'
|
||||
import { Input, ListItem, Separator, Spinner, XStack, YGroup, YStack } from 'tamagui'
|
||||
import { SwitchWithLabel } from '../../Global/helpers/switch-with-label'
|
||||
import { H2, Text } from '../../Global/helpers/text'
|
||||
import Button from '../../Global/helpers/button'
|
||||
import { http, https } from '../utils/constants'
|
||||
import { SwitchWithLabel } from '../../components/Global/helpers/switch-with-label'
|
||||
import { H2, Text } from '../../components/Global/helpers/text'
|
||||
import Button from '../../components/Global/helpers/button'
|
||||
import { http, https } from '../../components/Login/utils/constants'
|
||||
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import { StackParamList } from '../../types'
|
||||
import { StackParamList } from '../../components/types'
|
||||
import Toast from 'react-native-toast-message'
|
||||
import { useJellifyContext } from '../../../providers'
|
||||
import { useSettingsContext } from '../../../providers/Settings'
|
||||
import Icon from '../../Global/components/icon'
|
||||
import { useJellifyContext } from '../../providers'
|
||||
import { useSettingsContext } from '../../providers/Settings'
|
||||
import Icon from '../../components/Global/components/icon'
|
||||
import { PublicSystemInfo } from '@jellyfin/sdk/lib/generated-client/models'
|
||||
import { connectToServer } from '../../../api/mutations/login'
|
||||
import { IS_MAESTRO_BUILD } from '../../../configs/config'
|
||||
import { sleepify } from '../../../utils/sleep'
|
||||
import { connectToServer } from '../../api/mutations/login'
|
||||
import { IS_MAESTRO_BUILD } from '../../configs/config'
|
||||
import { sleepify } from '../../utils/sleep'
|
||||
|
||||
export default function ServerAddress({
|
||||
navigation,
|
||||
@@ -44,7 +44,7 @@ export default function ServerAddress({
|
||||
}, [serverAddress])
|
||||
|
||||
useEffect(() => {
|
||||
sleepify(250).then(() => signOut())
|
||||
sleepify(500).then(() => signOut())
|
||||
}, [])
|
||||
|
||||
const useServerMutation = useMutation({
|
||||
@@ -1,19 +1,19 @@
|
||||
import React, { useState } from 'react'
|
||||
import { useMutation } from '@tanstack/react-query'
|
||||
import _ from 'lodash'
|
||||
import { JellyfinCredentials } from '../../../api/types/jellyfin-credentials'
|
||||
import { JellyfinCredentials } from '../../api/types/jellyfin-credentials'
|
||||
import { getToken, H6, Spacer, Spinner, XStack, YStack } from 'tamagui'
|
||||
import { H2, H5, Text } from '../../Global/helpers/text'
|
||||
import Button from '../../Global/helpers/button'
|
||||
import { H2, H5, Text } from '../../components/Global/helpers/text'
|
||||
import Button from '../../components/Global/helpers/button'
|
||||
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||
import { JellifyUser } from '../../../types/JellifyUser'
|
||||
import { StackParamList } from '../../types'
|
||||
import Input from '../../../components/Global/helpers/input'
|
||||
import Icon from '../../Global/components/icon'
|
||||
import { useJellifyContext } from '../../../providers'
|
||||
import { JellifyUser } from '../../types/JellifyUser'
|
||||
import { StackParamList } from '../../components/types'
|
||||
import Input from '../../components/Global/helpers/input'
|
||||
import Icon from '../../components/Global/components/icon'
|
||||
import { useJellifyContext } from '../../providers'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import Toast from 'react-native-toast-message'
|
||||
import { IS_MAESTRO_BUILD } from '../../../configs/config'
|
||||
import { IS_MAESTRO_BUILD } from '../../configs/config'
|
||||
|
||||
export default function ServerAuthentication({
|
||||
navigation,
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import { StackParamList } from '../../../components/types'
|
||||
import { useJellifyContext } from '../../../providers'
|
||||
import { StackParamList } from '../../components/types'
|
||||
import { useJellifyContext } from '../../providers'
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
|
||||
import LibrarySelector from '../../Global/components/library-selector'
|
||||
import LibrarySelector from '../../components/Global/components/library-selector'
|
||||
|
||||
export default function ServerLibrary({
|
||||
navigation,
|
||||
@@ -38,13 +38,13 @@ export default function SignOutModal({ navigation }: SignOutModalProps): React.J
|
||||
color={'$danger'}
|
||||
borderColor={'$danger'}
|
||||
onPress={() => {
|
||||
clearDownloads()
|
||||
navigation.goBack()
|
||||
navigation.navigate('Login', {
|
||||
screen: 'ServerAddress',
|
||||
})
|
||||
|
||||
TrackPlayer.reset()
|
||||
clearDownloads()
|
||||
resetQueue()
|
||||
}}
|
||||
>
|
||||
<Text bold color={'$danger'}>
|
||||
|
||||
Reference in New Issue
Block a user