From 47d9995a8f3f507fa1257e5db5a06d083e66906b Mon Sep 17 00:00:00 2001 From: Benard Mathu Date: Tue, 26 Sep 2023 09:48:11 +0300 Subject: [PATCH] fix issue based on review --- package-lock.json | 7 ++- package.json | 1 + src/CONSTANTS.ts | 2 +- src/screens/Settings/types.ts | 1 - .../modals/Player/components/Timer.tsx | 62 ++++++++++++------- src/store/index.ts | 8 +-- src/store/music/actions.ts | 6 +- src/store/music/index.ts | 14 ++++- src/store/settings/actions.ts | 3 - src/store/settings/index.ts | 19 +----- src/utility/PlaybackService.ts | 50 +++------------ 11 files changed, 75 insertions(+), 98 deletions(-) diff --git a/package-lock.json b/package-lock.json index 18bc3a5..13ba60c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@react-native-async-storage/async-storage": "^1.17.11", "@react-native-community/blur": "^4.3.0", + "@react-native-community/datetimepicker": "^7.6.0", "@react-native-community/netinfo": "^9.3.6", "@react-navigation/bottom-tabs": "^6.4.0", "@react-navigation/elements": "^1.3.17", @@ -2966,9 +2967,9 @@ } }, "node_modules/@react-native-community/datetimepicker": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@react-native-community/datetimepicker/-/datetimepicker-7.4.1.tgz", - "integrity": "sha512-S7KdiWt0VgL93vy8sAlxPtyq8yNTRCNvoVJPkPlKzwuDY1Q5f+E0rsnNvfP0Y/UMhXAUnUo/THGR2qfrsJ9vNg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@react-native-community/datetimepicker/-/datetimepicker-7.6.2.tgz", + "integrity": "sha512-ogZnvCmNG/lGHhEQypqz/mPymiIWD5jv6uKczg/l/aWgiKs1RDPQH1abh+R0I26aKoXmgamJJPuXKeC5eRWtZg==", "dependencies": { "invariant": "^2.2.4" } diff --git a/package.json b/package.json index 8aa76a7..994f79d 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "dependencies": { "@react-native-async-storage/async-storage": "^1.17.11", "@react-native-community/blur": "^4.3.0", + "@react-native-community/datetimepicker": "^7.6.0", "@react-native-community/netinfo": "^9.3.6", "@react-navigation/bottom-tabs": "^6.4.0", "@react-navigation/elements": "^1.3.17", diff --git a/src/CONSTANTS.ts b/src/CONSTANTS.ts index 73a26c7..05637da 100644 --- a/src/CONSTANTS.ts +++ b/src/CONSTANTS.ts @@ -1,4 +1,4 @@ export const ALBUM_CACHE_AMOUNT_OF_DAYS = 7; export const PLAYLIST_CACHE_AMOUNT_OF_DAYS = 7; export const ALPHABET_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ '; -export const THEME_COLOR = '#4DFF3C00'; \ No newline at end of file +export const THEME_COLOR = '#FF3C00'; \ No newline at end of file diff --git a/src/screens/Settings/types.ts b/src/screens/Settings/types.ts index 246e41c..a915946 100644 --- a/src/screens/Settings/types.ts +++ b/src/screens/Settings/types.ts @@ -6,7 +6,6 @@ export type SettingsStackParams = { Library: undefined; Cache: undefined; Sentry: undefined; - Timer: undefined; }; export type SettingsNavigationProp = StackNavigationProp; diff --git a/src/screens/modals/Player/components/Timer.tsx b/src/screens/modals/Player/components/Timer.tsx index 33952ad..d072795 100644 --- a/src/screens/modals/Player/components/Timer.tsx +++ b/src/screens/modals/Player/components/Timer.tsx @@ -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 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'; +import { Text } from '@/components/Typography'; +import { setTimerDate } from '@/store/music/actions'; const Container = styled.View` - align-item: left; + align-items: flex-start; margin-top: 60px; `; const View = styled.View` display: flex; flex-direction: row; + align-items: center; gap: 4px; `; -const Text = styled.Text` - font-size: 10px; -`; - export default function Timer() { const [showPicker, setShowPicker] = useState(false); - const { remainingSleepTime } = useTypedSelector(state => state.settings); + const [remainingTime, setRemainingTime] = useState(); + const { timerDate } = useTypedSelector(state => state.music); const dispatch = useDispatch(); - const handleConfirm = (date: Date) => { + const handleConfirm = useCallback((date: Date) => { date.setSeconds(0); - dispatch(setDateTime(date)); + dispatch(setTimerDate(date)); setShowPicker(false); - }; + }, [dispatch]); - const handleCancelDatePicker = () => { - console.log('Handle cancel implement this event'); - }; + const handleCancelDatePicker = useCallback(() => { + 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 ( - + {remainingSleepTime === '' ? 'Sleep Timer' : remainingSleepTime} + >{!timerDate ? 'Sleep Timer' : remainingTime} > = { 4: (state: AppState) => { return { ...state, - settings: { - ...state.settings, - enableSleepTime: false, - dateTime: Date, - remainingSleepTime: String + music: { + ...state.music, + timerDate: Date } }; }, diff --git a/src/store/music/actions.ts b/src/store/music/actions.ts index 8cb8085..4b99cad 100644 --- a/src/store/music/actions.ts +++ b/src/store/music/actions.ts @@ -1,4 +1,4 @@ -import { createAsyncThunk, createEntityAdapter } from '@reduxjs/toolkit'; +import { createAction, createAsyncThunk, createEntityAdapter } from '@reduxjs/toolkit'; import { Album, AlbumTrack, Playlist } from './types'; import { AsyncThunkAPI } from '..'; import { retrieveAllAlbums, retrieveAlbumTracks, retrieveRecentAlbums, searchItem, retrieveAlbum, retrieveAllPlaylists, retrievePlaylistTracks } from '@/utility/JellyfinApi'; @@ -111,4 +111,6 @@ export const fetchTracksByPlaylist = createAsyncThunk; } -); \ No newline at end of file +); + +export const setTimerDate = createAction('SET_TIMER_DATE'); \ No newline at end of file diff --git a/src/store/music/index.ts b/src/store/music/index.ts index 7777913..a736b93 100644 --- a/src/store/music/index.ts +++ b/src/store/music/index.ts @@ -8,7 +8,8 @@ import { playlistAdapter, fetchAllPlaylists, fetchTracksByPlaylist, - fetchAlbum + fetchAlbum, + setTimerDate } from './actions'; import { createSlice, Dictionary, EntityId } from '@reduxjs/toolkit'; import { Album, AlbumTrack, Playlist } from './types'; @@ -33,7 +34,8 @@ export interface State { entities: Dictionary; ids: EntityId[]; lastRefreshed?: number, - } + }, + timerDate?: Date | null; } export const initialState: State = { @@ -50,7 +52,8 @@ export const initialState: State = { playlists: { ...playlistAdapter.getInitialState(), isLoading: false, - } + }, + timerDate: null }; const music = createSlice({ @@ -153,6 +156,11 @@ const music = createSlice({ // Reset any caches we have when a new server is set builder.addCase(setJellyfinCredentials, () => initialState); + + builder.addCase(setTimerDate, (state, action) => ({ + ...state, + timerDate: action.payload, + })); } }); diff --git a/src/store/settings/actions.ts b/src/store/settings/actions.ts index 06607f7..7a5bcad 100644 --- a/src/store/settings/actions.ts +++ b/src/store/settings/actions.ts @@ -7,6 +7,3 @@ 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 setDateTime = createAction('SET_DATE_TIME'); -export const setEnableSleepTime = createAction('SET_ENABLE_SLEEP_TIME'); -export const setRemainingSleepTime = createAction('SET_REMAINING_SLEEP_TIME'); diff --git a/src/store/settings/index.ts b/src/store/settings/index.ts index 4928f3e..0c074ee 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, setDateTime, setEnableSleepTime, setRemainingSleepTime } from './actions'; +import { setReceivedErrorReportingAlert, setBitrate, setJellyfinCredentials, setOnboardingStatus, setEnablePlaybackReporting, setColorScheme } from './actions'; import { ColorScheme } from './types'; interface State { @@ -14,8 +14,6 @@ interface State { hasReceivedErrorReportingAlert: boolean; enablePlaybackReporting: boolean; colorScheme: ColorScheme; - dateTime?: Date; - remainingSleepTime: String } const initialState: State = { @@ -23,8 +21,7 @@ const initialState: State = { isOnboardingComplete: false, hasReceivedErrorReportingAlert: false, enablePlaybackReporting: true, - colorScheme: ColorScheme.System, - remainingSleepTime: '' + colorScheme: ColorScheme.System }; const settings = createReducer(initialState, builder => { @@ -52,18 +49,6 @@ const settings = createReducer(initialState, builder => { ...state, 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; \ No newline at end of file diff --git a/src/utility/PlaybackService.ts b/src/utility/PlaybackService.ts index 84799db..fafe850 100644 --- a/src/utility/PlaybackService.ts +++ b/src/utility/PlaybackService.ts @@ -10,7 +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'; +import { setTimerDate } from '@/store/music/actions'; export default async function() { @@ -56,59 +56,25 @@ export default async function() { TrackPlayer.addEventListener(Event.PlaybackProgressUpdated, () => { // Retrieve the current settings from the Redux store const settings = store.getState().settings; + const music = store.getState().music; // GUARD: Only report playback when the settings is enabled if (settings.enablePlaybackReporting) { sendPlaybackEvent('/Sessions/Playing/Progress', settings.jellyfin); } - // check if datetime is undefined, otherwise start timer - if (settings.dateTime === undefined) { - store.dispatch(setRemainingSleepTime('')); - } else { - 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); - } + // check if timerDate is undefined, otherwise start timer + if (music.timerDate && music.timerDate.valueOf() < new Date().valueOf()) { + TrackPlayer.pause(); + store.dispatch(setTimerDate(null)); } }); 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) {