Files
jellyfin-audio-player/src/screens/Player/components/MediaControls.tsx

152 lines
4.9 KiB
TypeScript
Raw Normal View History

import React, { useState, useCallback } from 'react';
import TrackPlayer, { Event, State, usePlaybackState, useTrackPlayerEvents } from 'react-native-track-player';
import { TouchableOpacity, useColorScheme } from 'react-native';
2020-06-16 17:51:51 +02:00
import styled from 'styled-components/native';
import { useHasNextQueue, useHasPreviousQueue } from 'utility/useQueue';
2020-07-07 13:21:03 +02:00
import ForwardIcon from 'assets/forwards.svg';
import BackwardIcon from 'assets/backwards.svg';
import PlayIcon from 'assets/play.svg';
import PauseIcon from 'assets/pause.svg';
2020-08-28 14:17:54 +02:00
import RepeatIcon from 'assets/repeat.svg';
// import ShuffleIcon from 'assets/shuffle.svg';
import { THEME_COLOR } from 'CONSTANTS';
2021-03-21 22:42:04 +01:00
import Casting from './Casting';
2020-06-16 17:51:51 +02:00
2020-07-07 13:21:03 +02:00
const BUTTON_SIZE = 40;
2020-08-28 14:17:54 +02:00
const BUTTON_SIZE_SMALL = 25;
2020-06-16 17:51:51 +02:00
const pause = TrackPlayer.pause;
const play = TrackPlayer.play;
const next = TrackPlayer.skipToNext;
const previous = TrackPlayer.skipToPrevious;
2020-06-16 17:51:51 +02:00
const Container = styled.View`
align-items: center;
margin: 20px 0;
`;
const Buttons = styled.View`
flex-direction: row;
align-items: center;
2020-06-16 21:41:02 +02:00
justify-content: space-between;
width: 100%;
2020-06-16 17:51:51 +02:00
`;
const Button = styled.View`
2020-06-16 21:41:02 +02:00
margin: 20px 40px;
2020-06-16 17:51:51 +02:00
`;
export default function MediaControls() {
2020-07-26 17:02:18 +02:00
const scheme = useColorScheme();
const fill = scheme === 'dark' ? '#ffffff' : '#000000';
2020-06-16 17:51:51 +02:00
return (
<Container>
<Buttons>
<Button>
2020-07-26 17:02:18 +02:00
<PreviousButton fill={fill} />
2020-06-16 17:51:51 +02:00
</Button>
2020-07-26 17:02:18 +02:00
<MainButton fill={fill} />
2020-06-16 17:51:51 +02:00
<Button>
2020-07-26 17:02:18 +02:00
<NextButton fill={fill} />
2020-06-16 17:51:51 +02:00
</Button>
</Buttons>
2020-08-28 14:17:54 +02:00
<Buttons>
<Button>
<RepeatButton fill={fill} />
</Button>
2021-03-21 22:42:04 +01:00
<Casting fill={fill} />
2020-08-28 14:17:54 +02:00
</Buttons>
2020-06-16 17:51:51 +02:00
</Container>
);
}
2020-07-26 17:02:18 +02:00
export function PreviousButton({ fill }: { fill: string }) {
const hasQueue = useHasPreviousQueue();
2020-06-16 17:51:51 +02:00
return (
<TouchableOpacity onPress={previous} disabled={!hasQueue} style={{ opacity: hasQueue ? 1 : 0.5 }}>
2020-07-26 17:02:18 +02:00
<BackwardIcon width={BUTTON_SIZE} height={BUTTON_SIZE} fill={fill} />
2020-06-16 17:51:51 +02:00
</TouchableOpacity>
);
}
2020-07-26 17:02:18 +02:00
export function NextButton({ fill }: { fill: string }) {
const hasQueue = useHasNextQueue();
2020-06-16 17:51:51 +02:00
return (
<TouchableOpacity onPress={next} disabled={!hasQueue} style={{ opacity: hasQueue ? 1 : 0.5 }}>
2020-07-26 17:02:18 +02:00
<ForwardIcon width={BUTTON_SIZE} height={BUTTON_SIZE} fill={fill} />
2020-06-16 17:51:51 +02:00
</TouchableOpacity>
);
}
2020-08-28 14:17:54 +02:00
export function RepeatButton({ fill }: { fill: string}) {
const [isRepeating, setRepeating] = useState(false);
const handlePress = useCallback(() => setRepeating(!isRepeating), [isRepeating, setRepeating]);
// The callback that should determine whether we need to repeeat or not
useTrackPlayerEvents([Event.PlaybackQueueEnded], async () => {
2020-08-28 14:17:54 +02:00
if (isRepeating) {
// Skip to the first track
await TrackPlayer.skip(0);
2020-08-28 14:17:54 +02:00
// Cautiously reset the seek time, as there might only be a single
// item in queue.
await TrackPlayer.seekTo(0);
// Then play the item
await TrackPlayer.play();
}
});
2020-08-28 14:17:54 +02:00
return (
<TouchableOpacity onPress={handlePress} style={{ opacity: isRepeating ? 1 : 0.5 }}>
<RepeatIcon
width={BUTTON_SIZE_SMALL}
height={BUTTON_SIZE_SMALL}
fill={isRepeating ? THEME_COLOR : fill}
/>
</TouchableOpacity>
);
}
// export function ShuffleButton({ fill }: { fill: string}) {
// const [isShuffling, setShuffling] = useState(false);
// const handlePress = useCallback(() => setShuffling(!isShuffling), [isShuffling, setShuffling]);
// return (
// <TouchableOpacity onPress={handlePress} style={{ opacity: isShuffling ? 1 : 0.5 }}>
// <ShuffleIcon
// width={BUTTON_SIZE_SMALL}
// height={BUTTON_SIZE_SMALL}
// fill={isShuffling ? THEME_COLOR : fill}
// />
// </TouchableOpacity>
// );
// }
2020-07-26 17:02:18 +02:00
export function MainButton({ fill }: { fill: string }) {
2020-06-16 17:51:51 +02:00
const state = usePlaybackState();
switch (state) {
case State.Playing:
2020-06-16 17:51:51 +02:00
return (
<TouchableOpacity onPress={pause}>
2020-07-26 17:02:18 +02:00
<PauseIcon width={BUTTON_SIZE} height={BUTTON_SIZE} fill={fill} />
2020-06-16 17:51:51 +02:00
</TouchableOpacity>
);
case State.Paused:
2020-06-16 17:51:51 +02:00
return (
<TouchableOpacity onPress={play}>
2020-07-26 17:02:18 +02:00
<PlayIcon width={BUTTON_SIZE} height={BUTTON_SIZE} fill={fill} />
2020-06-16 17:51:51 +02:00
</TouchableOpacity>
);
default:
return (
<TouchableOpacity onPress={pause} disabled>
2020-07-26 17:02:18 +02:00
<PauseIcon width={BUTTON_SIZE} height={BUTTON_SIZE} fill={fill} />
2020-06-16 17:51:51 +02:00
</TouchableOpacity>
);
}
}