diff --git a/package-lock.json b/package-lock.json index 67f580f..16c944c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,6 +42,7 @@ "react-native-reanimated": "^3.6.2", "react-native-safe-area-context": "^4.4.1", "react-native-screens": "^3.18.2", + "react-native-select-dropdown": "^3.3.4", "react-native-shadow-2": "^7.0.6", "react-native-skia": "^0.0.1", "react-native-svg": "^13.5.0", @@ -13762,6 +13763,11 @@ "react-native": "*" } }, + "node_modules/react-native-select-dropdown": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/react-native-select-dropdown/-/react-native-select-dropdown-3.3.4.tgz", + "integrity": "sha512-Ld6BGGgCnbiv7uORAP+KnvDQiqeuqdlasKk9woJH9XtFMD44rwjKwelGzsDxFUM9hIAwZdac4UAFmOmXRaMeRg==" + }, "node_modules/react-native-shadow-2": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/react-native-shadow-2/-/react-native-shadow-2-7.0.6.tgz", @@ -26664,6 +26670,11 @@ "warn-once": "^0.1.0" } }, + "react-native-select-dropdown": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/react-native-select-dropdown/-/react-native-select-dropdown-3.3.4.tgz", + "integrity": "sha512-Ld6BGGgCnbiv7uORAP+KnvDQiqeuqdlasKk9woJH9XtFMD44rwjKwelGzsDxFUM9hIAwZdac4UAFmOmXRaMeRg==" + }, "react-native-shadow-2": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/react-native-shadow-2/-/react-native-shadow-2-7.0.6.tgz", diff --git a/package.json b/package.json index 2e0eed1..bcbc2a5 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "react-native-reanimated": "^3.6.2", "react-native-safe-area-context": "^4.4.1", "react-native-screens": "^3.18.2", + "react-native-select-dropdown": "^3.3.4", "react-native-shadow-2": "^7.0.6", "react-native-skia": "^0.0.1", "react-native-svg": "^13.5.0", diff --git a/src/components/ListButton.tsx b/src/components/ListButton.tsx index 5abfc19..1f05fd6 100644 --- a/src/components/ListButton.tsx +++ b/src/components/ListButton.tsx @@ -1,9 +1,10 @@ import React, { useCallback, useState } from 'react'; -import { TouchableOpacityProps } from 'react-native'; +import { StyleSheet, TouchableOpacityProps, View } from 'react-native'; import ChevronRight from '@/assets/icons/chevron-right.svg'; import styled from 'styled-components/native'; import { THEME_COLOR } from '@/CONSTANTS'; import useDefaultStyles from './Colors'; +import { Text } from './Typography'; const BUTTON_SIZE = 14; @@ -19,10 +20,28 @@ const Container = styled.Pressable<{ active?: boolean }>` const Label = styled.Text<{ active?: boolean }>` color: ${THEME_COLOR}; font-size: 16px; + display: flex; `; +function generateListButtonStyles() { + const styles = useDefaultStyles(); + return StyleSheet.create({ + ...styles, + descriptionNote: { + display: 'flex', + flexDirection: 'column' + }, + showDescription: { + display: 'flex' + }, + hideDescription: { + display: 'none' + } + }) +} + const ListButton: React.FC = ({ children, ...props }) => { - const defaultStyles = useDefaultStyles(); + const defaultStyles = generateListButtonStyles(); const [isPressed, setPressed] = useState(false); const handlePressIn = useCallback(() => setPressed(true), []); const handlePressOut = useCallback(() => setPressed(false), []); diff --git a/src/screens/Settings/index.tsx b/src/screens/Settings/index.tsx index 4738aa6..3782895 100644 --- a/src/screens/Settings/index.tsx +++ b/src/screens/Settings/index.tsx @@ -16,12 +16,11 @@ 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 Timer from './stacks/timer/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]); @@ -33,10 +32,28 @@ export function SettingsList() { const { sleepTime } = useTypedSelector(state => state.settings); + const getTime = () => { + if (!Number.isNaN(sleepTime)) { + const hours = Math.round(sleepTime / 3600); + const timeRemaining = sleepTime % 3600; + let minutes = 0; + + if (timeRemaining > 60) { + minutes = Math.round(timeRemaining / 60); + } + return `${hours} hrs ${minutes} min`; + } else { + return 0; + } + } + return ( {t('jellyfin-library')} - {t('timer')} Set Time: {sleepTime} + + {t('timer')} + {`Set Time: ${getTime()}s`} + {t('setting-cache')} {t('error-reporting')} {t('playback-reporting')} diff --git a/src/screens/Settings/stacks/Timer.tsx b/src/screens/Settings/stacks/Timer.tsx deleted file mode 100644 index b63b94e..0000000 --- a/src/screens/Settings/stacks/Timer.tsx +++ /dev/null @@ -1,37 +0,0 @@ -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/stacks/timer/Timer.tsx b/src/screens/Settings/stacks/timer/Timer.tsx new file mode 100644 index 0000000..b02bcfc --- /dev/null +++ b/src/screens/Settings/stacks/timer/Timer.tsx @@ -0,0 +1,90 @@ +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'; +import { ScrollView, ToastAndroid, View } from 'react-native'; +import { generateTimerStyles } from './styles'; +import { useTypedSelector } from '@/store'; +import SelectableFilter from '@/screens/Search/stacks/Search/components/SelectableFilter'; +import MicrophoneIcon from '@/assets/icons/microphone.svg'; +import AlbumIcon from '@/assets/icons/collection.svg'; +import TrackIcon from '@/assets/icons/note.svg'; +import SelectDropdown from 'react-native-select-dropdown'; +import { time } from 'console'; + +function Timer() { + const { sleepTime } = useTypedSelector(state => state.settings); + + const [minutes, setMinutes] = useState(); + const [hours, setHours] = useState(); + + const timerStyles = generateTimerStyles(); + + const navigation = useNavigation(); + const dispatch = useDispatch(); + + const setSleeper = useCallback((value: number, timeType: string) => { + if (timeType == 'Hours' && value > 0) { + dispatch(setSleepTime(value * 3600)); + } else if (timeType == 'Minutes' && value > 0) { + dispatch(setSleepTime(value * 60)); + } + }, [navigation, dispatch]); + + const getTime = () => { + if (!Number.isNaN(sleepTime)) { + const hours = Math.round(sleepTime / 3600); + const timeRemaining = sleepTime % 3600; + let minutes = 0; + + if (timeRemaining > 60) { + minutes = Math.round(timeRemaining / 60); + } + return `${hours} hrs ${minutes} min`; + } else { + return 0; + } + } + + return ( + + + Set Sleep Timer. Time Set Previously: {getTime()} + + + H: + { + setSleeper(parseInt(value), 'Hours'); + }} + /> + + + M: + { + setSleeper(parseInt(value), 'Minutes'); + }} + /> + + + 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/stacks/timer/styles.tsx b/src/screens/Settings/stacks/timer/styles.tsx new file mode 100644 index 0000000..78f0c44 --- /dev/null +++ b/src/screens/Settings/stacks/timer/styles.tsx @@ -0,0 +1,21 @@ +import useDefaultStyles from "@/components/Colors"; +import { ColorScheme } from "@/store/settings/types"; +import { StyleSheet } from "react-native"; + +export function generateTimerStyles() { + const styles = useDefaultStyles(); + + return StyleSheet.create({ + ...styles, + timer: { + display: 'flex', + flexDirection: 'row' + }, + timeInput: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + gap: 3 + } + }) +} \ No newline at end of file diff --git a/src/store/index.ts b/src/store/index.ts index e70428e..c5aa4fa 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -62,7 +62,7 @@ const persistConfig: PersistConfig> = { settings: { ...state.settings, enableSleepTimer: false, - sleepTime: 60, + sleepTime: 0, remainingSleepTime: 0 } };