fix issue based on review
This commit is contained in:
committed by
Lei Nelissen
parent
7d54f00811
commit
47d9995a8f
7
package-lock.json
generated
7
package-lock.json
generated
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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';
|
||||||
@@ -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>;
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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');
|
||||||
@@ -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,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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');
|
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user