update: show timer in NowPlaying stacks

This commit is contained in:
Benard Mathu
2023-08-01 01:00:16 +03:00
committed by Lei Nelissen
parent 3d481a8f18
commit 05ef196cdf
11 changed files with 114 additions and 135 deletions

View File

@@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.3">
<path d="M7.99498 13.1613C10.8527 13.1613 13.1931 10.8209 13.1931 7.96316C13.1931 5.11048 10.8577 2.77008 8 2.77008C7.68861 2.77008 7.51283 2.95591 7.51283 3.25725V5.10546C7.51283 5.3616 7.69364 5.56249 7.94977 5.56249C8.20591 5.56249 8.38672 5.3616 8.38672 5.10546V3.81472C10.5112 4.01059 12.1484 5.7885 12.1484 7.96316C12.1484 10.2634 10.3052 12.1216 7.99498 12.1216C5.68973 12.1216 3.83649 10.2634 3.84152 7.96316C3.84654 6.97376 4.19308 6.05468 4.77567 5.34653C4.96652 5.08537 4.99665 4.80914 4.78069 4.59318C4.56473 4.37722 4.21819 4.39731 3.99219 4.69363C3.2539 5.5876 2.8019 6.72767 2.8019 7.96316C2.8019 10.8209 5.1423 13.1613 7.99498 13.1613ZM8.80357 8.7366C9.2154 8.29966 9.13002 7.70702 8.63783 7.37053L6.08649 5.61774C5.78515 5.41684 5.49386 5.71316 5.69475 6.0145L7.44754 8.56082C7.78404 9.05803 8.37667 9.14843 8.80357 8.7366Z" fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 983 B

View File

@@ -16,7 +16,6 @@ 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/Timer';
export function SettingsList() {
const navigation = useNavigation<SettingsNavigationProp>();
@@ -26,12 +25,10 @@ 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]);
return (
<SafeScrollView>
<ListButton onPress={handleLibraryClick}>{t('jellyfin-library')}</ListButton>
<ListButton onPress={handleTimerClick}>Set Sleep Timer</ListButton>
<ListButton onPress={handleCacheClick}>{t('setting-cache')}</ListButton>
<ListButton onPress={handleSentryClick}>{t('error-reporting')}</ListButton>
<ListButton onPress={handlePlaybackReportingClick}>{t('playback-reporting')}</ListButton>
@@ -55,7 +52,6 @@ export default function Settings() {
}}>
<Stack.Screen name="SettingList" component={SettingsList} options={{ headerTitle: t('settings') }} />
<Stack.Screen name="Library" component={Library} options={{ headerTitle: t('jellyfin-library') }} />
<Stack.Screen name="Timer" component={Timer} options={{ headerTitle: 'Set Sleep Timer' }} />
<Stack.Screen name="Cache" component={Cache} options={{ headerTitle: t('setting-cache') }} />
<Stack.Screen name="Sentry" component={Sentry} options={{ headerTitle: t('error-reporting') }} />
<Stack.Screen name="Playback Reporting" component={PlaybackReporting} options={{ headerTitle: t('playback-reporting')}} />

View File

@@ -1,76 +0,0 @@
import React, { useCallback, useState } from 'react';
import Container from '../../components/Container';
import { Text } from '@/components/Typography';
import { InputContainer } from '../../components/Input';
import { useTimeStyles } from './styles';
import { Switch } from 'react-native-gesture-handler';
import { SwitchContainer, SwitchLabel } from '../../components/Switch';
import Button from '@/components/Button';
import { View } from 'react-native';
import DateTimePickerModal from 'react-native-modal-datetime-picker';
import { useTypedSelector } from '@/store';
import { useDispatch } from 'react-redux';
import { setDateTime, setEnableSleepTime } from '@/store/settings/actions';
function Timer() {
const [show, setShow] = useState<boolean>(false);
const { dateTime } = useTypedSelector(state => state.settings);
const [date, setDate] = useState<string>(dateTime === undefined ? 'Set Time' : dateTime.toString());
const timerStyles = useTimeStyles();
const { enableSleepTime } = useTypedSelector(state => state.settings);
const dispatch = useDispatch();
const handleEnabledSleeper = useCallback((value: boolean) => {
dispatch(setEnableSleepTime(value));
}, [dispatch]);
const handleConfirm = (date: Date) => {
setShow(false);
setDate(date.toString());
dispatch(setDateTime(date));
};
const showDateTimePicker = () => {
setShow(!show);
};
const handleCancelDatePicker = () => {
setShow(false);
};
return (
<Container>
<InputContainer>
<Text>{'Set Sleep Time.'}</Text>
<SwitchContainer style={timerStyles.checkbox}>
<Switch
value={enableSleepTime}
onValueChange={(value) => handleEnabledSleeper(value)}
/>
<SwitchLabel>{'Enable Timer'}</SwitchLabel>
</SwitchContainer>
<View style={enableSleepTime ? timerStyles.timerSetting : timerStyles.timerSettingsDisabled}>
<View style={timerStyles.timeInput}>
<Text>{'Set Time'}</Text>
<Button
title={date}
onPress={showDateTimePicker}
/>
</View>
<Text>{'Set this to automatically stop the audio when time runs out.'}</Text>
</View>
<DateTimePickerModal
isVisible={show}
mode='datetime'
is24Hour={true}
onConfirm={handleConfirm}
onCancel={handleCancelDatePicker}
/>
</InputContainer>
</Container>
);
}
export default Timer;

View File

@@ -1,38 +0,0 @@
import useDefaultStyles from '@/components/Colors';
import { StyleSheet } from 'react-native';
export function useTimeStyles() {
const styles = useDefaultStyles();
return StyleSheet.create({
...styles,
timer: {
display: 'flex',
flexDirection: 'row'
},
timeInput: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
gap: 3
},
checkbox: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center'
},
timerSetting: {
marginStart: 10
},
timerSettingsDisabled: {
color: '#cbcbcb',
marginStart: 10
},
showDateTime: {
display: 'flex'
},
hideDateTime: {
display: 'none'
}
});
}

View File

@@ -27,7 +27,7 @@ const Header = styled.View`
flex-direction: row;
align-items: center;
padding-bottom: 8px;
padding-top: 52px;
padding-top: 27px;
`;
const IconButton = styled.TouchableOpacity`

View File

@@ -0,0 +1,62 @@
import React, { useState } from 'react';
import DateTimePickerModal from 'react-native-modal-datetime-picker';
import styled from 'styled-components/native';
import { THEME_COLOR } from '@/CONSTANTS';
import { useDispatch } from 'react-redux';
import { setDateTime } from '@/store/settings/actions';
import { useTypedSelector } from '@/store';
import TimerIcon from '@/assets/icons/timer-icon.svg';
const Container = styled.View`
align-item: left;
margin-top: 60px;
`;
const View = styled.View`
display: flex;
flex-direction: row;
gap: 4px;
`;
const Text = styled.Text`
font-size: 10px;
`;
export default function Timer() {
const [showPicker, setShowPicker] = useState<boolean>(false);
const { remainingSleepTime } = useTypedSelector(state => state.settings);
const dispatch = useDispatch();
const handleConfirm = (date: Date) => {
date.setSeconds(0);
dispatch(setDateTime(date));
setShowPicker(false);
};
const handleCancelDatePicker = () => {
console.log('Handle cancel implement this event');
};
const showDatePicker = () => {
setShowPicker(true);
};
return (
<Container>
<View>
<TimerIcon fill={showPicker || remainingSleepTime !== '' ? THEME_COLOR : undefined} />
<Text
style={showPicker || remainingSleepTime !== '' ? {color: THEME_COLOR} : {}}
onPress={showDatePicker}
>{remainingSleepTime === '' ? 'Sleep Timer' : remainingSleepTime}</Text>
<DateTimePickerModal
isVisible={showPicker}
mode='time'
onConfirm={handleConfirm}
onCancel={handleCancelDatePicker}
/>
</View>
</Container>
);
}

View File

@@ -8,6 +8,7 @@ import { GestureHandlerRootView } from 'react-native-gesture-handler';
import StreamStatus from './components/StreamStatus';
import { Platform } from 'react-native';
import BackButton from './components/Backbutton';
import Timer from './components/Timer';
export default function Player() {
return (
@@ -20,6 +21,7 @@ export default function Player() {
<StreamStatus />
<ProgressBar />
<MediaControls />
<Timer />
</>
)} />
</GestureHandlerRootView>

View File

@@ -62,7 +62,8 @@ const persistConfig: PersistConfig<Omit<AppState, '_persist'>> = {
settings: {
...state.settings,
enableSleepTime: false,
dateTime: Date
dateTime: Date,
remainingSleepTime: String
}
};
},

View File

@@ -9,4 +9,4 @@ export const setEnablePlaybackReporting = createAction<boolean>('SET_ENABLE_PLAY
export const setColorScheme = createAction<ColorScheme>('SET_COLOR_SCHEME');
export const setDateTime = createAction<Date>('SET_DATE_TIME');
export const setEnableSleepTime = createAction<boolean>('SET_ENABLE_SLEEP_TIME');
export const setRemainingSleepTime = createAction<number>('SET_REMAINING_SLEEP_TIME');
export const setRemainingSleepTime = createAction<String>('SET_REMAINING_SLEEP_TIME');

View File

@@ -15,7 +15,7 @@ interface State {
enablePlaybackReporting: boolean;
colorScheme: ColorScheme;
dateTime?: Date;
enableSleepTime: boolean
remainingSleepTime: String
}
const initialState: State = {
@@ -24,8 +24,7 @@ const initialState: State = {
hasReceivedErrorReportingAlert: false,
enablePlaybackReporting: true,
colorScheme: ColorScheme.System,
dateTime: new Date(),
enableSleepTime: false
remainingSleepTime: ''
};
const settings = createReducer(initialState, builder => {

View File

@@ -10,6 +10,7 @@
import TrackPlayer, { Event, State } from 'react-native-track-player';
import store from '@/store';
import { sendPlaybackEvent } from './JellyfinApi';
import { setRemainingSleepTime } from '@/store/settings/actions';
export default async function() {
@@ -61,26 +62,53 @@ export default async function() {
sendPlaybackEvent('/Sessions/Playing/Progress', settings.jellyfin);
}
// regularly check if sleeper is enabled, pause the audio after 30 minutes.
if (settings.enableSleepTime && settings.dateTime !== undefined) {
const dateSet = new Date(settings.dateTime.toString());
const dateNow = new Date(Date.now());
const diff = Math.abs(dateSet.getMinutes() - dateNow.getMinutes());
// check if datetime is undefined, otherwise start timer
if (settings.dateTime === undefined) {
store.dispatch(setRemainingSleepTime(''));
} else {
const millisecondsDiff = settings.dateTime.valueOf() - new Date().valueOf();
console.log(`Difference: ${diff}`);
const timeDiff = new Date(millisecondsDiff);
let interval = setInterval(() => {});
if (diff >= 30 && dateNow >= dateSet) {
console.log('Music Paused');
TrackPlayer.pause();
if (timeDiff.getTime() > 0) {
interval = setInterval(() => {
const settings = store.getState().settings;
if (settings.dateTime !== undefined) {
const millisecondsDiff = settings.dateTime.valueOf() - new Date().valueOf();
const timeDiff = new Date(millisecondsDiff);
if (timeDiff.getTime() > 0) {
let sec = Math.floor(timeDiff.getTime() / 1000);
let min = Math.floor(sec/60);
sec = sec%60;
const hours = Math.floor(min/60);
min = min%60;
const timer = `${hours.toString().length === 1 ? '0' + hours : hours}:${min.toString().length === 1 ? '0' + min : min}:${sec.toString().length === 1 ? '0' + sec : sec}`;
store.dispatch(setRemainingSleepTime(timer));
} else {
store.dispatch(setRemainingSleepTime(''));
TrackPlayer.pause();
clearInterval(interval);
}
} else {
clearInterval(interval);
}
}, 1000);
}
}
});
TrackPlayer.addEventListener(Event.PlaybackState, (event) => {
// Retrieve the current settings from the Redux store
const settings = store.getState().settings;
// GUARD: Only respond to stopped events
if (event.state === State.Stopped) {
// Retrieve the current settings from the Redux store
const settings = store.getState().settings;
// GUARD: Only report playback when the settings is enabled
if (settings.enablePlaybackReporting) {