fix issue based on review

This commit is contained in:
Benard Mathu
2023-09-26 09:48:11 +03:00
committed by Lei Nelissen
parent 7d54f00811
commit 47d9995a8f
11 changed files with 75 additions and 98 deletions

7
package-lock.json generated
View File

@@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"@react-native-async-storage/async-storage": "^1.17.11", "@react-native-async-storage/async-storage": "^1.17.11",
"@react-native-community/blur": "^4.3.0", "@react-native-community/blur": "^4.3.0",
"@react-native-community/datetimepicker": "^7.6.0",
"@react-native-community/netinfo": "^9.3.6", "@react-native-community/netinfo": "^9.3.6",
"@react-navigation/bottom-tabs": "^6.4.0", "@react-navigation/bottom-tabs": "^6.4.0",
"@react-navigation/elements": "^1.3.17", "@react-navigation/elements": "^1.3.17",
@@ -2966,9 +2967,9 @@
} }
}, },
"node_modules/@react-native-community/datetimepicker": { "node_modules/@react-native-community/datetimepicker": {
"version": "7.4.1", "version": "7.6.2",
"resolved": "https://registry.npmjs.org/@react-native-community/datetimepicker/-/datetimepicker-7.4.1.tgz", "resolved": "https://registry.npmjs.org/@react-native-community/datetimepicker/-/datetimepicker-7.6.2.tgz",
"integrity": "sha512-S7KdiWt0VgL93vy8sAlxPtyq8yNTRCNvoVJPkPlKzwuDY1Q5f+E0rsnNvfP0Y/UMhXAUnUo/THGR2qfrsJ9vNg==", "integrity": "sha512-ogZnvCmNG/lGHhEQypqz/mPymiIWD5jv6uKczg/l/aWgiKs1RDPQH1abh+R0I26aKoXmgamJJPuXKeC5eRWtZg==",
"dependencies": { "dependencies": {
"invariant": "^2.2.4" "invariant": "^2.2.4"
} }

View File

@@ -15,6 +15,7 @@
"dependencies": { "dependencies": {
"@react-native-async-storage/async-storage": "^1.17.11", "@react-native-async-storage/async-storage": "^1.17.11",
"@react-native-community/blur": "^4.3.0", "@react-native-community/blur": "^4.3.0",
"@react-native-community/datetimepicker": "^7.6.0",
"@react-native-community/netinfo": "^9.3.6", "@react-native-community/netinfo": "^9.3.6",
"@react-navigation/bottom-tabs": "^6.4.0", "@react-navigation/bottom-tabs": "^6.4.0",
"@react-navigation/elements": "^1.3.17", "@react-navigation/elements": "^1.3.17",

View File

@@ -1,4 +1,4 @@
export const ALBUM_CACHE_AMOUNT_OF_DAYS = 7; export const ALBUM_CACHE_AMOUNT_OF_DAYS = 7;
export const PLAYLIST_CACHE_AMOUNT_OF_DAYS = 7; export const PLAYLIST_CACHE_AMOUNT_OF_DAYS = 7;
export const ALPHABET_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ '; export const ALPHABET_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ';
export const THEME_COLOR = '#4DFF3C00'; export const THEME_COLOR = '#FF3C00';

View File

@@ -6,7 +6,6 @@ export type SettingsStackParams = {
Library: undefined; Library: undefined;
Cache: undefined; Cache: undefined;
Sentry: undefined; Sentry: undefined;
Timer: undefined;
}; };
export type SettingsNavigationProp = StackNavigationProp<SettingsStackParams>; export type SettingsNavigationProp = StackNavigationProp<SettingsStackParams>;

View File

@@ -1,55 +1,75 @@
import React, { useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import DateTimePickerModal from 'react-native-modal-datetime-picker'; import DateTimePickerModal from 'react-native-modal-datetime-picker';
import styled from 'styled-components/native'; import styled from 'styled-components/native';
import { THEME_COLOR } from '@/CONSTANTS'; import { THEME_COLOR } from '@/CONSTANTS';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { setDateTime } from '@/store/settings/actions';
import { useTypedSelector } from '@/store'; import { useTypedSelector } from '@/store';
import TimerIcon from '@/assets/icons/timer-icon.svg'; import TimerIcon from '@/assets/icons/timer-icon.svg';
import { Text } from '@/components/Typography';
import { setTimerDate } from '@/store/music/actions';
const Container = styled.View` const Container = styled.View`
align-item: left; align-items: flex-start;
margin-top: 60px; margin-top: 60px;
`; `;
const View = styled.View` const View = styled.View`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center;
gap: 4px; gap: 4px;
`; `;
const Text = styled.Text`
font-size: 10px;
`;
export default function Timer() { export default function Timer() {
const [showPicker, setShowPicker] = useState<boolean>(false); const [showPicker, setShowPicker] = useState<boolean>(false);
const { remainingSleepTime } = useTypedSelector(state => state.settings); const [remainingTime, setRemainingTime] = useState<String|null>();
const { timerDate } = useTypedSelector(state => state.music);
const dispatch = useDispatch(); const dispatch = useDispatch();
const handleConfirm = (date: Date) => { const handleConfirm = useCallback((date: Date) => {
date.setSeconds(0); date.setSeconds(0);
dispatch(setDateTime(date)); dispatch(setTimerDate(date));
setShowPicker(false); setShowPicker(false);
}; }, [dispatch]);
const handleCancelDatePicker = () => { const handleCancelDatePicker = useCallback(() => {
console.log('Handle cancel implement this event'); setShowPicker(false);
}; }, []);
const showDatePicker = useCallback(() => {
setShowPicker(!showPicker);
}, [showPicker]);
useEffect(() => {
if (!timerDate) {
setRemainingTime(null);
return;
}
const interval = setInterval(() => {
const dateSet = timerDate ? timerDate : new Date();
const millisecondsDiff = dateSet.valueOf() - new Date().valueOf();
let sec = Math.floor(millisecondsDiff / 1000);
let min = Math.floor(sec/60);
sec = sec%60;
const hours = Math.floor(min/60);
min = min%60;
const ticks = `${hours.toString().length === 1 ? '0' + hours : hours}:${min.toString().length === 1 ? '0' + min : min}:${sec.toString().length === 1 ? '0' + sec : sec}`;
setRemainingTime(ticks);
}, 1000);
return () => clearInterval(interval);
}, [setRemainingTime, timerDate]);
const showDatePicker = () => {
setShowPicker(true);
};
return ( return (
<Container> <Container>
<View> <View>
<TimerIcon fill={showPicker || remainingSleepTime !== '' ? THEME_COLOR : undefined} /> <TimerIcon fill={showPicker || timerDate ? THEME_COLOR : undefined} />
<Text <Text
style={showPicker || remainingSleepTime !== '' ? {color: THEME_COLOR} : {}} style={showPicker || timerDate ? {color: THEME_COLOR} : {}}
onPress={showDatePicker} onPress={showDatePicker}
>{remainingSleepTime === '' ? 'Sleep Timer' : remainingSleepTime}</Text> >{!timerDate ? 'Sleep Timer' : remainingTime}</Text>
<DateTimePickerModal <DateTimePickerModal
isVisible={showPicker} isVisible={showPicker}
mode='time' mode='time'

View File

@@ -59,11 +59,9 @@ const persistConfig: PersistConfig<Omit<AppState, '_persist'>> = {
4: (state: AppState) => { 4: (state: AppState) => {
return { return {
...state, ...state,
settings: { music: {
...state.settings, ...state.music,
enableSleepTime: false, timerDate: Date
dateTime: Date,
remainingSleepTime: String
} }
}; };
}, },

View File

@@ -1,4 +1,4 @@
import { createAsyncThunk, createEntityAdapter } from '@reduxjs/toolkit'; import { createAction, createAsyncThunk, createEntityAdapter } from '@reduxjs/toolkit';
import { Album, AlbumTrack, Playlist } from './types'; import { Album, AlbumTrack, Playlist } from './types';
import { AsyncThunkAPI } from '..'; import { AsyncThunkAPI } from '..';
import { retrieveAllAlbums, retrieveAlbumTracks, retrieveRecentAlbums, searchItem, retrieveAlbum, retrieveAllPlaylists, retrievePlaylistTracks } from '@/utility/JellyfinApi'; import { retrieveAllAlbums, retrieveAlbumTracks, retrieveRecentAlbums, searchItem, retrieveAlbum, retrieveAllPlaylists, retrievePlaylistTracks } from '@/utility/JellyfinApi';
@@ -111,4 +111,6 @@ export const fetchTracksByPlaylist = createAsyncThunk<AlbumTrack[], string, Asyn
const credentials = thunkAPI.getState().settings.jellyfin; const credentials = thunkAPI.getState().settings.jellyfin;
return retrievePlaylistTracks(ItemId, credentials) as Promise<AlbumTrack[]>; return retrievePlaylistTracks(ItemId, credentials) as Promise<AlbumTrack[]>;
} }
); );
export const setTimerDate = createAction<Date|null>('SET_TIMER_DATE');

View File

@@ -8,7 +8,8 @@ import {
playlistAdapter, playlistAdapter,
fetchAllPlaylists, fetchAllPlaylists,
fetchTracksByPlaylist, fetchTracksByPlaylist,
fetchAlbum fetchAlbum,
setTimerDate
} from './actions'; } from './actions';
import { createSlice, Dictionary, EntityId } from '@reduxjs/toolkit'; import { createSlice, Dictionary, EntityId } from '@reduxjs/toolkit';
import { Album, AlbumTrack, Playlist } from './types'; import { Album, AlbumTrack, Playlist } from './types';
@@ -33,7 +34,8 @@ export interface State {
entities: Dictionary<Playlist>; entities: Dictionary<Playlist>;
ids: EntityId[]; ids: EntityId[];
lastRefreshed?: number, lastRefreshed?: number,
} },
timerDate?: Date | null;
} }
export const initialState: State = { export const initialState: State = {
@@ -50,7 +52,8 @@ export const initialState: State = {
playlists: { playlists: {
...playlistAdapter.getInitialState(), ...playlistAdapter.getInitialState(),
isLoading: false, isLoading: false,
} },
timerDate: null
}; };
const music = createSlice({ const music = createSlice({
@@ -153,6 +156,11 @@ const music = createSlice({
// Reset any caches we have when a new server is set // Reset any caches we have when a new server is set
builder.addCase(setJellyfinCredentials, () => initialState); builder.addCase(setJellyfinCredentials, () => initialState);
builder.addCase(setTimerDate, (state, action) => ({
...state,
timerDate: action.payload,
}));
} }
}); });

View File

@@ -7,6 +7,3 @@ export const setOnboardingStatus = createAction<boolean>('SET_ONBOARDING_STATUS'
export const setReceivedErrorReportingAlert = createAction<void>('SET_RECEIVED_ERROR_REPORTING_ALERT'); export const setReceivedErrorReportingAlert = createAction<void>('SET_RECEIVED_ERROR_REPORTING_ALERT');
export const setEnablePlaybackReporting = createAction<boolean>('SET_ENABLE_PLAYBACK_REPORTING'); export const setEnablePlaybackReporting = createAction<boolean>('SET_ENABLE_PLAYBACK_REPORTING');
export const setColorScheme = createAction<ColorScheme>('SET_COLOR_SCHEME'); 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<String>('SET_REMAINING_SLEEP_TIME');

View File

@@ -1,5 +1,5 @@
import { createReducer } from '@reduxjs/toolkit'; import { createReducer } from '@reduxjs/toolkit';
import { setReceivedErrorReportingAlert, setBitrate, setJellyfinCredentials, setOnboardingStatus, setEnablePlaybackReporting, setColorScheme, setDateTime, setEnableSleepTime, setRemainingSleepTime } from './actions'; import { setReceivedErrorReportingAlert, setBitrate, setJellyfinCredentials, setOnboardingStatus, setEnablePlaybackReporting, setColorScheme } from './actions';
import { ColorScheme } from './types'; import { ColorScheme } from './types';
interface State { interface State {
@@ -14,8 +14,6 @@ interface State {
hasReceivedErrorReportingAlert: boolean; hasReceivedErrorReportingAlert: boolean;
enablePlaybackReporting: boolean; enablePlaybackReporting: boolean;
colorScheme: ColorScheme; colorScheme: ColorScheme;
dateTime?: Date;
remainingSleepTime: String
} }
const initialState: State = { const initialState: State = {
@@ -23,8 +21,7 @@ const initialState: State = {
isOnboardingComplete: false, isOnboardingComplete: false,
hasReceivedErrorReportingAlert: false, hasReceivedErrorReportingAlert: false,
enablePlaybackReporting: true, enablePlaybackReporting: true,
colorScheme: ColorScheme.System, colorScheme: ColorScheme.System
remainingSleepTime: ''
}; };
const settings = createReducer(initialState, builder => { const settings = createReducer(initialState, builder => {
@@ -52,18 +49,6 @@ const settings = createReducer(initialState, builder => {
...state, ...state,
colorScheme: action.payload, colorScheme: action.payload,
})); }));
builder.addCase(setDateTime, (state, action) => ({
...state,
dateTime: action.payload,
}));
builder.addCase(setEnableSleepTime, (state, action) => ({
...state,
enableSleepTime: action.payload,
}));
builder.addCase(setRemainingSleepTime, (state, action) => ({
...state,
remainingSleepTime: action.payload,
}));
}); });
export default settings; export default settings;

View File

@@ -10,7 +10,7 @@
import TrackPlayer, { Event, State } from 'react-native-track-player'; import TrackPlayer, { Event, State } from 'react-native-track-player';
import store from '@/store'; import store from '@/store';
import { sendPlaybackEvent } from './JellyfinApi'; import { sendPlaybackEvent } from './JellyfinApi';
import { setRemainingSleepTime } from '@/store/settings/actions'; import { setTimerDate } from '@/store/music/actions';
export default async function() { export default async function() {
@@ -56,59 +56,25 @@ export default async function() {
TrackPlayer.addEventListener(Event.PlaybackProgressUpdated, () => { TrackPlayer.addEventListener(Event.PlaybackProgressUpdated, () => {
// Retrieve the current settings from the Redux store // Retrieve the current settings from the Redux store
const settings = store.getState().settings; const settings = store.getState().settings;
const music = store.getState().music;
// GUARD: Only report playback when the settings is enabled // GUARD: Only report playback when the settings is enabled
if (settings.enablePlaybackReporting) { if (settings.enablePlaybackReporting) {
sendPlaybackEvent('/Sessions/Playing/Progress', settings.jellyfin); sendPlaybackEvent('/Sessions/Playing/Progress', settings.jellyfin);
} }
// check if datetime is undefined, otherwise start timer // check if timerDate is undefined, otherwise start timer
if (settings.dateTime === undefined) { if (music.timerDate && music.timerDate.valueOf() < new Date().valueOf()) {
store.dispatch(setRemainingSleepTime('')); TrackPlayer.pause();
} else { store.dispatch(setTimerDate(null));
const millisecondsDiff = settings.dateTime.valueOf() - new Date().valueOf();
const timeDiff = new Date(millisecondsDiff);
let interval = setInterval(() => {});
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) => { TrackPlayer.addEventListener(Event.PlaybackState, (event) => {
// Retrieve the current settings from the Redux store
const settings = store.getState().settings;
// GUARD: Only respond to stopped events // GUARD: Only respond to stopped events
if (event.state === State.Stopped) { 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 // GUARD: Only report playback when the settings is enabled
if (settings.enablePlaybackReporting) { if (settings.enablePlaybackReporting) {