diff --git a/src/localisation/lang/en/locale.json b/src/localisation/lang/en/locale.json index bbf005b..788c9fa 100644 --- a/src/localisation/lang/en/locale.json +++ b/src/localisation/lang/en/locale.json @@ -41,6 +41,7 @@ "more-info": "More Info", "track": "Track", "playlists": "Playlists", + "timer": "Set Sleep Timer", "playlist": "Playlist", "play-playlist": "Play Playlist", "shuffle-album": "Shuffle Album", diff --git a/src/localisation/lang/nl/locale.json b/src/localisation/lang/nl/locale.json index 485d822..67cef3e 100644 --- a/src/localisation/lang/nl/locale.json +++ b/src/localisation/lang/nl/locale.json @@ -41,6 +41,7 @@ "more-info": "Meer informatie", "track": "Track", "playlists": "Playlists", + "timer": "Set Sleep Timer", "playlist": "Playlist", "play-playlist": "Speel Playlist", "shuffle-album": "Shuffle Album", diff --git a/src/localisation/types.ts b/src/localisation/types.ts index 34e431d..5f85594 100644 --- a/src/localisation/types.ts +++ b/src/localisation/types.ts @@ -69,3 +69,4 @@ export type LocaleKeys = 'play-next' | 'color-scheme-dark' | 'artists' | 'privacy-policy' +| 'timer' diff --git a/src/screens/Settings/index.tsx b/src/screens/Settings/index.tsx index aeb2e77..4738aa6 100644 --- a/src/screens/Settings/index.tsx +++ b/src/screens/Settings/index.tsx @@ -1,5 +1,5 @@ import React, { useCallback } from 'react'; -import { StyleSheet } from 'react-native'; +import { StyleSheet, View } from 'react-native'; import { t } from '@/localisation'; import { createStackNavigator } from '@react-navigation/stack'; import { useNavigation } from '@react-navigation/native'; @@ -16,8 +16,12 @@ import ColorScheme from './stacks/ColorScheme'; import PlaybackReporting from './stacks/PlaybackReporting'; import { SafeScrollView } from '@/components/SafeNavigatorView'; import PrivacyPolicy from './components/PrivacyPolicy'; +import Timer from './stacks/Timer'; +import { Paragraph, Text } from '@/components/Typography'; +import { useTypedSelector } from '@/store'; export function SettingsList() { + const defaultStyles = useDefaultStyles(); const navigation = useNavigation(); const handleLibraryClick = useCallback(() => { navigation.navigate('Library'); }, [navigation]); const handleCacheClick = useCallback(() => { navigation.navigate('Cache'); }, [navigation]); @@ -25,10 +29,14 @@ export function SettingsList() { const handlePlaybackReportingClick = useCallback(() => { navigation.navigate('Playback Reporting'); }, [navigation]); const handleColorSchemeClick = useCallback(() => { navigation.navigate('Color Scheme'); }, [navigation]); const handlePrivacyPolicyClick = useCallback(() => { navigation.navigate('PrivacyPolicy'); }, [navigation]); + const handleTimerClick = useCallback(() => { navigation.navigate('Timer'); }, [navigation]); + + const { sleepTime } = useTypedSelector(state => state.settings); return ( {t('jellyfin-library')} + {t('timer')} Set Time: {sleepTime} {t('setting-cache')} {t('error-reporting')} {t('playback-reporting')} @@ -52,6 +60,7 @@ export default function Settings() { }}> + diff --git a/src/screens/Settings/stacks/Timer.tsx b/src/screens/Settings/stacks/Timer.tsx new file mode 100644 index 0000000..b63b94e --- /dev/null +++ b/src/screens/Settings/stacks/Timer.tsx @@ -0,0 +1,37 @@ +import React, { useCallback, useState } from 'react'; +import Container from '../components/Container'; +import { Text } from '@/components/Typography'; +import { InputContainer } from '../components/Input'; +import Input from '@/components/Input'; +import useDefaultStyles from '@/components/Colors'; +import { setSleepTime } from '@/store/settings/actions'; +import { useNavigation } from '@react-navigation/native'; +import { useDispatch } from 'react-redux'; + +function Timer() { + const defaultStyles = useDefaultStyles(); + + const navigation = useNavigation(); + const dispatch = useDispatch(); + + const setSleeper = useCallback((sleepTime) => { + dispatch(setSleepTime(Number.parseInt(sleepTime))); + }, [navigation, dispatch]); + + return ( + + + Set Sleep Timer (min) + + + Set this to automatically stop the audio when time runs out. + + + ); +} + +export default Timer; \ No newline at end of file diff --git a/src/screens/Settings/types.ts b/src/screens/Settings/types.ts index a915946..246e41c 100644 --- a/src/screens/Settings/types.ts +++ b/src/screens/Settings/types.ts @@ -6,6 +6,7 @@ export type SettingsStackParams = { Library: undefined; Cache: undefined; Sentry: undefined; + Timer: undefined; }; export type SettingsNavigationProp = StackNavigationProp; diff --git a/src/store/index.ts b/src/store/index.ts index 195a775..e70428e 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -55,6 +55,18 @@ const persistConfig: PersistConfig> = { } }; }, + // @ts-expect-error migrations are poorly typed + 4: (state: AppState) => { + return { + ...state, + settings: { + ...state.settings, + enableSleepTimer: false, + sleepTime: 60, + remainingSleepTime: 0 + } + }; + }, }) }; diff --git a/src/store/settings/actions.ts b/src/store/settings/actions.ts index 7a5bcad..029ef86 100644 --- a/src/store/settings/actions.ts +++ b/src/store/settings/actions.ts @@ -7,3 +7,6 @@ export const setOnboardingStatus = createAction('SET_ONBOARDING_STATUS' export const setReceivedErrorReportingAlert = createAction('SET_RECEIVED_ERROR_REPORTING_ALERT'); export const setEnablePlaybackReporting = createAction('SET_ENABLE_PLAYBACK_REPORTING'); export const setColorScheme = createAction('SET_COLOR_SCHEME'); +export const setSleepTime = createAction('SET_SLEEP_TIME'); +export const setEnableSleepTimer = createAction('SET_ENABLE_SLEEP_TIMER'); +export const setRemainingSleepTime = createAction('SET_REMAINING_SLEEP_TIME'); diff --git a/src/store/settings/index.ts b/src/store/settings/index.ts index fd7a183..6e0dd32 100644 --- a/src/store/settings/index.ts +++ b/src/store/settings/index.ts @@ -1,5 +1,5 @@ import { createReducer } from '@reduxjs/toolkit'; -import { setReceivedErrorReportingAlert, setBitrate, setJellyfinCredentials, setOnboardingStatus, setEnablePlaybackReporting, setColorScheme } from './actions'; +import { setReceivedErrorReportingAlert, setBitrate, setJellyfinCredentials, setOnboardingStatus, setEnablePlaybackReporting, setColorScheme, setSleepTime, setEnableSleepTimer, setRemainingSleepTime } from './actions'; import { ColorScheme } from './types'; interface State { @@ -14,6 +14,7 @@ interface State { hasReceivedErrorReportingAlert: boolean; enablePlaybackReporting: boolean; colorScheme: ColorScheme; + sleepTime: number; } const initialState: State = { @@ -22,6 +23,7 @@ const initialState: State = { hasReceivedErrorReportingAlert: false, enablePlaybackReporting: true, colorScheme: ColorScheme.System, + sleepTime: 60, }; const settings = createReducer(initialState, builder => { @@ -49,6 +51,18 @@ const settings = createReducer(initialState, builder => { ...state, colorScheme: action.payload, })); + builder.addCase(setSleepTime, (state, action) => ({ + ...state, + sleepTime: action.payload, + })); + builder.addCase(setEnableSleepTimer, (state, action) => ({ + ...state, + enableSleepTimer: action.payload, + })); + builder.addCase(setRemainingSleepTime, (state, action) => ({ + ...state, + remainingSleepTime: action.payload, + })); }); export default settings; \ No newline at end of file