Add global unified state for audio files
This commit is contained in:
parent
aa0b9f164e
commit
0f8920203d
|
@ -4,6 +4,8 @@ import moment from 'moment';
|
|||
import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake';
|
||||
// import Slider from '@react-native-community/slider';
|
||||
import TrackPlayer, { Event, useTrackPlayerEvents, State, useProgress } from 'react-native-track-player';
|
||||
import { Easing } from 'react-native-reanimated';
|
||||
import { useMMKVStorage } from 'react-native-mmkv-storage';
|
||||
|
||||
import Touchable from '../../Touchable';
|
||||
import Markdown from '../../../markdown';
|
||||
|
@ -21,6 +23,7 @@ import { IAttachment } from '../../../../definitions';
|
|||
import { TSupportedThemes } from '../../../../theme';
|
||||
import { setupService } from './services';
|
||||
import Slider from './Slider';
|
||||
import { TracksStorage, addTrack, clearTracks, getCurrentTrack, setCurrentTrack } from './tracks';
|
||||
|
||||
interface IButton {
|
||||
loading: boolean;
|
||||
|
@ -106,40 +109,48 @@ IMessageAudioProps) => {
|
|||
|
||||
const { baseUrl, user } = useContext(MessageContext);
|
||||
|
||||
const { position, duration } = useProgress();
|
||||
const { duration } = useProgress();
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentTime(position);
|
||||
}, [position]);
|
||||
const [tracks] = useMMKVStorage('tracks', TracksStorage);
|
||||
|
||||
let url = file.audio_url;
|
||||
if (url && !url.startsWith('http')) {
|
||||
url = `${baseUrl}${file.audio_url}`;
|
||||
}
|
||||
|
||||
const track = {
|
||||
id: `${url}?rc_uid=${user.id}&rc_token=${user.token}`,
|
||||
url: `${url}?rc_uid=${user.id}&rc_token=${user.token}`,
|
||||
title: file.title,
|
||||
artist: file.author_name,
|
||||
duration
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const setup = async () => {
|
||||
setupService();
|
||||
let url = file.audio_url;
|
||||
if (url && !url.startsWith('http')) {
|
||||
url = `${baseUrl}${file.audio_url}`;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
await TrackPlayer.add([
|
||||
{
|
||||
url: `${url}?rc_uid=${user.id}&rc_token=${user.token}`,
|
||||
title: file.title,
|
||||
artist: file.author_name,
|
||||
duration
|
||||
}
|
||||
]);
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
await setupService();
|
||||
addTrack({ trackId: track.id, title: file.title, artist: file.author_name, isPlaying: false });
|
||||
setLoading(false);
|
||||
};
|
||||
setup();
|
||||
return () => {
|
||||
TrackPlayer.stop();
|
||||
TrackPlayer.reset();
|
||||
clearTracks();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const currentTrack = getCurrentTrack();
|
||||
if (currentTrack && currentTrack.trackId !== track.id) {
|
||||
setPaused(true);
|
||||
}
|
||||
}, [tracks]);
|
||||
|
||||
// useEffect(() => {
|
||||
// setCurrentTime(position);
|
||||
// }, [position]);
|
||||
|
||||
useEffect(() => {
|
||||
playPause();
|
||||
}, [paused]);
|
||||
|
@ -161,7 +172,6 @@ IMessageAudioProps) => {
|
|||
// do nothing
|
||||
}
|
||||
}
|
||||
if (state === State.Ready) setLoading(false);
|
||||
});
|
||||
|
||||
const getDuration = () => formatTime(currentTime || duration);
|
||||
|
@ -171,11 +181,19 @@ IMessageAudioProps) => {
|
|||
};
|
||||
|
||||
const playPause = () => {
|
||||
const currentPlaying = getCurrentTrack();
|
||||
try {
|
||||
if (paused) {
|
||||
TrackPlayer.pause();
|
||||
} else {
|
||||
if (currentPlaying?.trackId === track.id) {
|
||||
TrackPlayer.pause();
|
||||
}
|
||||
} else if (currentPlaying?.trackId === track.id) {
|
||||
TrackPlayer.play();
|
||||
} else {
|
||||
TrackPlayer.reset();
|
||||
TrackPlayer.add(track);
|
||||
TrackPlayer.play();
|
||||
setCurrentTrack(track.id);
|
||||
}
|
||||
} catch {
|
||||
// Do nothing
|
||||
|
@ -183,9 +201,17 @@ IMessageAudioProps) => {
|
|||
};
|
||||
|
||||
const onValueChange = async (value: number) => {
|
||||
const currentTrack = getCurrentTrack();
|
||||
try {
|
||||
setCurrentTime(value);
|
||||
await TrackPlayer.seekTo(value);
|
||||
if (currentTrack && currentTrack.trackId === track.id) {
|
||||
await TrackPlayer.seekTo(value);
|
||||
} else {
|
||||
TrackPlayer.reset();
|
||||
TrackPlayer.add(track);
|
||||
TrackPlayer.seekTo(value);
|
||||
setCurrentTrack(track.id);
|
||||
}
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
|
@ -204,6 +230,11 @@ IMessageAudioProps) => {
|
|||
thumbColor = themes[theme].tintColor;
|
||||
}
|
||||
|
||||
const sliderAnimatedConfig = {
|
||||
duration: 250,
|
||||
easing: Easing.linear
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Markdown
|
||||
|
@ -228,6 +259,7 @@ IMessageAudioProps) => {
|
|||
minimumTrackTintColor={themes[theme].tintColor}
|
||||
disabled={isReply}
|
||||
maximumTrackTintColor={themes[theme].auxiliaryText}
|
||||
animationConfig={sliderAnimatedConfig}
|
||||
// thumbImage={isIOS ? { uri: 'audio_thumb', scale } : undefined}
|
||||
/>
|
||||
{/* <Slider
|
||||
|
|
|
@ -50,6 +50,8 @@ export const playbackService = async () => {
|
|||
|
||||
export const setupService = async () => {
|
||||
try {
|
||||
await TrackPlayer.getCurrentTrack();
|
||||
} catch {
|
||||
await TrackPlayer.setupPlayer();
|
||||
await TrackPlayer.updateOptions({
|
||||
stopWithApp: false,
|
||||
|
@ -66,7 +68,5 @@ export const setupService = async () => {
|
|||
// Capability.SkipToNext
|
||||
]
|
||||
});
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import MMKVStorage from 'react-native-mmkv-storage';
|
||||
|
||||
export const TracksStorage = new MMKVStorage.Loader().withInstanceID('tracks').initialize();
|
||||
|
||||
interface Track {
|
||||
trackId: string;
|
||||
isPlaying: boolean;
|
||||
title?: string;
|
||||
artist?: string;
|
||||
}
|
||||
|
||||
export const initializeTracks = () => {
|
||||
const tracks = TracksStorage.getArray('tracks');
|
||||
if (!tracks) TracksStorage.setArray('tracks', []);
|
||||
};
|
||||
|
||||
export const addTrack = (track: Track) => {
|
||||
initializeTracks();
|
||||
const tracks: Track[] = TracksStorage.getArray('tracks') || [];
|
||||
if (tracks.find((t: Track) => t.trackId === track.trackId)) {
|
||||
return;
|
||||
}
|
||||
TracksStorage.setArray('tracks', [...tracks, track]);
|
||||
};
|
||||
|
||||
export const getTrack = (track: Track) => {
|
||||
const tracks: Track[] = TracksStorage.getArray('tracks') || [];
|
||||
return tracks.find((t: Track) => t.trackId === track.trackId);
|
||||
};
|
||||
|
||||
export const updateTrack = (track: Track) => {
|
||||
const tracks: Track[] = TracksStorage.getArray('tracks') || [];
|
||||
const index = tracks.findIndex((t: Track) => t.trackId === track.trackId);
|
||||
if (index !== -1) {
|
||||
tracks[index] = track;
|
||||
}
|
||||
TracksStorage.setArray('tracks', tracks);
|
||||
};
|
||||
|
||||
export const clearTracks = () => {
|
||||
TracksStorage.setArray('tracks', []);
|
||||
};
|
||||
|
||||
export const getCurrentTrack: () => Track | undefined = () => {
|
||||
const tracks: Track[] = TracksStorage.getArray('tracks') || [];
|
||||
const currentTrack = tracks.find((t: Track) => t.isPlaying);
|
||||
return currentTrack;
|
||||
};
|
||||
|
||||
export const setCurrentTrack = (trackId: string) => {
|
||||
const tracks: Track[] = TracksStorage.getArray('tracks') || [];
|
||||
const currentTrack = tracks.find((t: Track) => t.isPlaying);
|
||||
const trackToToggle = tracks.find((t: Track) => t.trackId === trackId);
|
||||
currentTrack && updateTrack({ ...currentTrack, isPlaying: false });
|
||||
if (trackToToggle) {
|
||||
updateTrack({ ...trackToToggle, isPlaying: true });
|
||||
}
|
||||
};
|
|
@ -173,7 +173,8 @@ export default StyleSheet.create({
|
|||
marginLeft: 12
|
||||
},
|
||||
sliderContainer: {
|
||||
flex: 1
|
||||
flex: 1,
|
||||
paddingHorizontal: 10
|
||||
},
|
||||
track: {
|
||||
justifyContent: 'center'
|
||||
|
@ -185,7 +186,7 @@ export default StyleSheet.create({
|
|||
sliderThumb: {
|
||||
height: SLIDER_THUMB_RADIUS * 2,
|
||||
width: SLIDER_THUMB_RADIUS * 2,
|
||||
borderRadius: SLIDER_THUMB_RADIUS,
|
||||
borderRadius: 2 * SLIDER_THUMB_RADIUS,
|
||||
position: 'absolute',
|
||||
zIndex: 2
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue