Initial commit

This commit is contained in:
Lei Nelissen
2020-06-16 17:51:51 +02:00
commit 50dd06a473
74 changed files with 14480 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
import React from 'react';
import TrackPlayer, { usePlaybackState, STATE_PLAYING, STATE_PAUSED, Track } from 'react-native-track-player';
import { TouchableOpacity } from 'react-native';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
import { faPlay, faPause, faBackward, faForward } from '@fortawesome/free-solid-svg-icons';
import styled from 'styled-components/native';
import { useHasQueue } from '../../../utility/useQueue';
const MAIN_SIZE = 48;
const BUTTON_SIZE = 32;
const pause = () => TrackPlayer.pause();
const play = () => TrackPlayer.play();
const next = () => TrackPlayer.skipToNext();
const previous = () => TrackPlayer.skipToPrevious();
const Container = styled.View`
/* */
align-items: center;
margin: 20px 0;
`;
const Buttons = styled.View`
flex-direction: row;
align-items: center;
`;
const Button = styled.View`
margin: 20px;
`;
export default function MediaControls() {
return (
<Container>
<Buttons>
<Button>
<PreviousButton />
</Button>
<MainButton />
<Button>
<NextButton />
</Button>
</Buttons>
</Container>
);
}
export function PreviousButton() {
const hasQueue = useHasQueue();
return (
<TouchableOpacity onPress={previous} disabled={!hasQueue} style={{ opacity: hasQueue ? 1 : 0.5 }}>
<FontAwesomeIcon icon={faBackward} size={BUTTON_SIZE} />
</TouchableOpacity>
);
}
export function NextButton() {
const hasQueue = useHasQueue();
return (
<TouchableOpacity onPress={next} disabled={!hasQueue} style={{ opacity: hasQueue ? 1 : 0.5 }}>
<FontAwesomeIcon icon={faForward} size={BUTTON_SIZE} />
</TouchableOpacity>
);
}
export function MainButton() {
const state = usePlaybackState();
switch (state) {
case STATE_PLAYING:
return (
<TouchableOpacity onPress={pause}>
<FontAwesomeIcon icon={faPause} size={MAIN_SIZE} />
</TouchableOpacity>
);
case STATE_PAUSED:
return (
<TouchableOpacity onPress={play}>
<FontAwesomeIcon icon={faPlay} size={MAIN_SIZE} />
</TouchableOpacity>
);
default:
return (
<TouchableOpacity onPress={pause} disabled>
<FontAwesomeIcon icon={faPause} size={MAIN_SIZE} />
</TouchableOpacity>
);
}
}

View File

@@ -0,0 +1,33 @@
import React from 'react';
import { Text, Dimensions, Image, View } from 'react-native';
import useCurrentTrack from '../../../utility/useCurrentTrack';
import styled from 'styled-components/native';
const Screen = Dimensions.get('screen');
const Artwork = styled.Image`
border-radius: 10px;
background-color: #fbfbfb;
width: ${Screen.width * 0.8}px;
height: ${Screen.width * 0.8}px;
margin: 25px auto;
display: flex;
`;
export default function NowPlaying() {
const track = useCurrentTrack();
// GUARD: Don't render anything if nothing is playing
if (!track) {
return null;
}
return (
<View style={{ alignItems: 'center' }}>
<Artwork style={{ flex: 1 }} source={{ uri: track.artwork }} />
<Text style={{ fontWeight: 'bold', fontSize: 24, marginBottom: 12 }} >{track.artist}</Text>
<Text style={{ fontSize: 18, marginBottom: 12, textAlign: 'center', paddingLeft: 20, paddingRight: 20 }}>{track.title}</Text>
</View>
);
}

View File

@@ -0,0 +1,65 @@
import React from 'react';
import { useTrackPlayerProgress } from 'react-native-track-player';
import styled from 'styled-components/native';
import { View, Text } from 'react-native';
import { padStart } from 'lodash';
const Container = styled.View`
width: 100%;
margin-top: 10px;
background-color: #eeeeee;
position: relative;
`;
const Bar = styled.View<{ progress: number }>`
background-color: salmon;
height: 4px;
border-radius: 2px;
width: ${props => props.progress * 100}%;
`;
const PositionIndicator = styled.View<{ progress: number }>`
width: 20px;
height: 20px;
border-radius: 100px;
border: 1px solid #eee;
background-color: white;
transform: translateX(-10px) translateY(-8.5px);
position: absolute;
top: 0;
left: ${props => props.progress * 100}%;
box-shadow: 0px 4px 8px rgba(0,0,0,0.1);
`;
const NumberBar = styled.View`
flex-direction: row;
justify-content: space-between;
width: 100%;
padding: 20px 0;
`;
function getSeconds(seconds: number): string {
return padStart(String(Math.floor(seconds % 60).toString()), 2, '0');
}
function getMinutes(seconds: number): number {
return Math.floor(seconds / 60);
}
export default function ProgressBar() {
const { position, duration } = useTrackPlayerProgress(500);
return (
<>
<Container>
<Bar progress={position / duration} />
<PositionIndicator progress={position / duration} />
</Container>
<NumberBar>
<Text>0:00</Text>
<Text>{getMinutes(position)}:{getSeconds(position)}</Text>
<Text>{getMinutes(duration)}:{getSeconds(duration)}</Text>
</NumberBar>
</>
);
}

View File

@@ -0,0 +1,40 @@
import React from 'react';
import useQueue from '../../../utility/useQueue';
import { View, Text } from 'react-native';
import styled, { css } from 'styled-components/native';
import useCurrentTrack from '../../../utility/useCurrentTrack';
const QueueItem = styled.View<{ active?: boolean, alreadyPlayed?: boolean }>`
padding: 10px;
border-bottom-width: 1px;
border-bottom-color: #eee;
${props => props.active && css`
font-weight: 900;
background-color: #ff8c6922;
padding: 20px 35px;
margin: 0 -25px;
`}
${props => props.alreadyPlayed && css`
opacity: 0.25;
`}
`;
export default function Queue() {
const queue = useQueue();
const currentTrack = useCurrentTrack();
const currentIndex = queue?.findIndex(d => d.id === currentTrack?.id);
return (
<View>
<Text style={{ marginTop: 20, marginBottom: 20 }}>Queue</Text>
{queue?.map((track, i) => (
<QueueItem active={currentTrack?.id === track.id} key={i} alreadyPlayed={i < currentIndex}>
<Text style={{marginBottom: 2}}>{track.title}</Text>
<Text style={{ opacity: 0.5 }}>{track.artist}</Text>
</QueueItem>
))}
</View>
);
}