update: show timer in NowPlaying stacks
This commit is contained in:
committed by
Lei Nelissen
parent
3d481a8f18
commit
05ef196cdf
5
src/assets/icons/timer-icon.svg
Normal file
5
src/assets/icons/timer-icon.svg
Normal 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 |
@@ -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')}} />
|
||||
|
||||
@@ -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;
|
||||
@@ -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'
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -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`
|
||||
|
||||
62
src/screens/modals/Player/components/Timer.tsx
Normal file
62
src/screens/modals/Player/components/Timer.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -62,7 +62,8 @@ const persistConfig: PersistConfig<Omit<AppState, '_persist'>> = {
|
||||
settings: {
|
||||
...state.settings,
|
||||
enableSleepTime: false,
|
||||
dateTime: Date
|
||||
dateTime: Date,
|
||||
remainingSleepTime: String
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user