2022-05-10 23:52:58 +02:00
|
|
|
import React, { useCallback, useEffect, useState } from 'react';
|
2020-06-21 10:30:41 +02:00
|
|
|
import useQueue from 'utility/useQueue';
|
2021-02-11 23:43:21 +01:00
|
|
|
import { View, StyleSheet } from 'react-native';
|
2020-06-16 17:51:51 +02:00
|
|
|
import styled, { css } from 'styled-components/native';
|
2020-06-21 10:30:41 +02:00
|
|
|
import useCurrentTrack from 'utility/useCurrentTrack';
|
2020-06-21 10:52:54 +02:00
|
|
|
import TouchableHandler from 'components/TouchableHandler';
|
2022-05-10 23:52:58 +02:00
|
|
|
import TrackPlayer, { RepeatMode } from 'react-native-track-player';
|
2020-11-02 22:50:00 +01:00
|
|
|
import { t } from '@localisation';
|
2021-02-11 23:43:21 +01:00
|
|
|
import useDefaultStyles from 'components/Colors';
|
2022-05-05 22:59:32 +02:00
|
|
|
import { Text } from 'components/Typography';
|
2022-05-10 23:52:58 +02:00
|
|
|
import RepeatIcon from 'assets/icons/repeat.svg';
|
2021-02-11 23:43:21 +01:00
|
|
|
import Button from 'components/Button';
|
2022-01-01 19:09:21 +01:00
|
|
|
import { THEME_COLOR } from 'CONSTANTS';
|
2022-01-02 02:28:52 +01:00
|
|
|
import DownloadIcon from 'components/DownloadIcon';
|
2022-05-10 23:52:58 +02:00
|
|
|
import Divider from 'components/Divider';
|
|
|
|
|
import ticksToDuration from 'utility/ticksToDuration';
|
|
|
|
|
|
|
|
|
|
const ICON_SIZE = 16;
|
|
|
|
|
|
|
|
|
|
const Container = styled.View`
|
|
|
|
|
margin-top: 56px;
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const Header = styled.View`
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const IconButton = styled.TouchableOpacity`
|
|
|
|
|
padding: 8px;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const TextHalfOpacity = styled(Text)`
|
|
|
|
|
opacity: 0.5;
|
|
|
|
|
`;
|
2020-06-16 17:51:51 +02:00
|
|
|
|
2020-07-26 14:45:32 +02:00
|
|
|
const QueueItem = styled.View<{ active?: boolean, alreadyPlayed?: boolean, isDark?: boolean }>`
|
2022-05-10 23:52:58 +02:00
|
|
|
padding: 8px 0;
|
2022-01-02 02:28:52 +01:00
|
|
|
flex: 0 0 auto;
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
align-items: center;
|
2020-06-16 17:51:51 +02:00
|
|
|
|
|
|
|
|
${props => props.active && css`
|
|
|
|
|
font-weight: 900;
|
2022-05-10 23:52:58 +02:00
|
|
|
padding: 8px 18px;
|
|
|
|
|
margin: 0 -18px;
|
|
|
|
|
border-radius: 8px;
|
2020-06-16 17:51:51 +02:00
|
|
|
`}
|
|
|
|
|
|
|
|
|
|
${props => props.alreadyPlayed && css`
|
2020-07-26 14:45:32 +02:00
|
|
|
opacity: 0.5;
|
2020-06-16 17:51:51 +02:00
|
|
|
`}
|
|
|
|
|
`;
|
|
|
|
|
|
2020-08-28 12:45:00 +02:00
|
|
|
const ClearQueue = styled.View`
|
|
|
|
|
margin: 20px 0;
|
|
|
|
|
`;
|
|
|
|
|
|
2020-07-26 14:45:32 +02:00
|
|
|
const styles = StyleSheet.create({
|
2021-02-11 23:43:21 +01:00
|
|
|
trackTitle: {
|
|
|
|
|
marginBottom: 2
|
2020-07-26 14:45:32 +02:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2020-06-16 17:51:51 +02:00
|
|
|
export default function Queue() {
|
2021-02-11 23:43:21 +01:00
|
|
|
const defaultStyles = useDefaultStyles();
|
2020-06-16 17:51:51 +02:00
|
|
|
const queue = useQueue();
|
2022-05-10 23:52:58 +02:00
|
|
|
const [isRepeating, setIsRepeating] = useState(false);
|
2021-12-31 15:04:37 +01:00
|
|
|
const { index: currentIndex } = useCurrentTrack();
|
2022-05-10 23:52:58 +02:00
|
|
|
|
2021-12-31 15:04:37 +01:00
|
|
|
const playTrack = useCallback(async (index: number) => {
|
|
|
|
|
await TrackPlayer.skip(index);
|
2020-07-10 15:47:03 +02:00
|
|
|
await TrackPlayer.play();
|
|
|
|
|
}, []);
|
2022-05-10 23:52:58 +02:00
|
|
|
|
2020-08-28 12:45:00 +02:00
|
|
|
const clearQueue = useCallback(async () => {
|
|
|
|
|
await TrackPlayer.reset();
|
|
|
|
|
}, []);
|
2020-06-16 17:51:51 +02:00
|
|
|
|
2022-05-10 23:52:58 +02:00
|
|
|
const toggleLoop = useCallback(() => {
|
|
|
|
|
setIsRepeating((prev) => {
|
|
|
|
|
TrackPlayer.setRepeatMode(prev ? RepeatMode.Off : RepeatMode.Queue);
|
|
|
|
|
return !prev;
|
|
|
|
|
});
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
// Retrieve the repeat mode and assign it to the state on component mount
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
TrackPlayer.getRepeatMode()
|
|
|
|
|
.then((mode) => {
|
|
|
|
|
setIsRepeating(mode === RepeatMode.Queue);
|
|
|
|
|
});
|
|
|
|
|
}, []);
|
|
|
|
|
|
2020-06-16 17:51:51 +02:00
|
|
|
return (
|
2022-05-10 23:52:58 +02:00
|
|
|
<Container>
|
|
|
|
|
<Header>
|
|
|
|
|
<Text>{t('queue')}</Text>
|
|
|
|
|
<Divider style={{ marginHorizontal: 18 }} />
|
|
|
|
|
<IconButton
|
|
|
|
|
style={isRepeating ? defaultStyles.activeBackground : undefined}
|
|
|
|
|
onPress={toggleLoop}
|
|
|
|
|
>
|
|
|
|
|
<RepeatIcon
|
|
|
|
|
fill={isRepeating ? THEME_COLOR : defaultStyles.textHalfOpacity.color}
|
|
|
|
|
width={ICON_SIZE}
|
|
|
|
|
height={ICON_SIZE}
|
|
|
|
|
/>
|
|
|
|
|
</IconButton>
|
|
|
|
|
</Header>
|
2020-06-21 10:52:54 +02:00
|
|
|
{queue.map((track, i) => (
|
2021-12-31 15:04:37 +01:00
|
|
|
<TouchableHandler id={i} onPress={playTrack} key={i}>
|
2020-07-26 14:45:32 +02:00
|
|
|
<QueueItem
|
2021-12-31 15:04:37 +01:00
|
|
|
active={currentIndex === i}
|
2020-07-26 14:45:32 +02:00
|
|
|
key={i}
|
2021-12-31 15:04:37 +01:00
|
|
|
alreadyPlayed={currentIndex ? i < currentIndex : false}
|
2021-02-11 23:43:21 +01:00
|
|
|
style={[
|
|
|
|
|
defaultStyles.border,
|
2021-12-31 15:04:37 +01:00
|
|
|
currentIndex === i ? defaultStyles.activeBackground : {},
|
2021-02-11 23:43:21 +01:00
|
|
|
]}
|
2020-07-26 14:45:32 +02:00
|
|
|
>
|
2022-05-10 23:52:58 +02:00
|
|
|
<View style={{ flex: 1, marginRight: 16 }}>
|
|
|
|
|
<Text
|
|
|
|
|
style={[currentIndex === i ? { color: THEME_COLOR, fontWeight: '500' } : styles.trackTitle, { marginBottom: 2 }]}
|
|
|
|
|
numberOfLines={1}
|
|
|
|
|
>
|
|
|
|
|
{track.title}
|
|
|
|
|
</Text>
|
|
|
|
|
<TextHalfOpacity
|
|
|
|
|
style={currentIndex === i ? { color: THEME_COLOR, fontWeight: '400' } : undefined}
|
|
|
|
|
numberOfLines={1}
|
|
|
|
|
>
|
|
|
|
|
{track.artist}{track.album && ' — ' + track.album}
|
|
|
|
|
</TextHalfOpacity>
|
2022-01-02 02:28:52 +01:00
|
|
|
</View>
|
2022-05-10 23:52:58 +02:00
|
|
|
<View style={{ marginLeft: 'auto', marginRight: 8 }}>
|
|
|
|
|
<TextHalfOpacity
|
|
|
|
|
style={currentIndex === i ? { color: THEME_COLOR, fontWeight: '400' } : undefined}
|
|
|
|
|
>
|
|
|
|
|
{ticksToDuration(track.duration || 0)}
|
|
|
|
|
</TextHalfOpacity>
|
|
|
|
|
</View>
|
|
|
|
|
<View>
|
|
|
|
|
<DownloadIcon trackId={track.backendId} fill={currentIndex === i ? THEME_COLOR + '80' : undefined} />
|
2022-01-02 02:28:52 +01:00
|
|
|
</View>
|
2020-06-21 10:52:54 +02:00
|
|
|
</QueueItem>
|
|
|
|
|
</TouchableHandler>
|
2020-06-16 17:51:51 +02:00
|
|
|
))}
|
2020-08-28 12:45:00 +02:00
|
|
|
<ClearQueue>
|
2021-02-11 23:43:21 +01:00
|
|
|
<Button title={t('clear-queue')} onPress={clearQueue} />
|
2020-08-28 12:45:00 +02:00
|
|
|
</ClearQueue>
|
2022-05-10 23:52:58 +02:00
|
|
|
</Container>
|
2020-06-16 17:51:51 +02:00
|
|
|
);
|
|
|
|
|
}
|