Skip to content
This repository has been archived by the owner on Jun 15, 2024. It is now read-only.

Commit

Permalink
Merge pull request #46 from word-view/song-player
Browse files Browse the repository at this point in the history
Song player redesign
  • Loading branch information
64ArthurAraujo authored May 20, 2024
2 parents 50bdf7a + 0f3b9d1 commit 551280f
Show file tree
Hide file tree
Showing 11 changed files with 220 additions and 75 deletions.
7 changes: 5 additions & 2 deletions App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { apiAvailable, testing } from './App/Storage/store/state';
import { checkAPIAvailable } from './App/API/check';
import { onMountAsync } from './Framework/Components/Actions';
import { fontLoader } from './Framework/Resources/FontLoader';
import { KeysProvider } from 'react-native-hotkeys';

SplashScreen.preventAutoHideAsync();
const warn = console.warn;
Expand All @@ -49,8 +50,10 @@ export default function App() {
return (
<PaperProvider theme={CombinedDarkTheme}>
<DesktopModeProvider.Provider value={isDesktop}>
<AppNavigation hideSplashCallback={onLayoutRootView} />
<StatusBar style='light' translucent={true} />
<KeysProvider>
<AppNavigation hideSplashCallback={onLayoutRootView} />
<StatusBar style='light' translucent={true} />
</KeysProvider>
</DesktopModeProvider.Provider>
</PaperProvider>
);
Expand Down
17 changes: 7 additions & 10 deletions App/Components/Player/LyricsViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { StyleSheet, View } from 'react-native';
import { Cue } from '../../Util/webvtt/types';
import { Text } from 'react-native-paper';
import { onUpdate } from '../../../Framework/Components/Actions/update';
import { heightPercentageToDP as hp } from 'react-native-responsive-screen';

interface LyricsViewerProps {
cues: Cue[];
Expand Down Expand Up @@ -44,7 +43,7 @@ function $LyricsViewer(props: LyricsViewerProps) {
});

return (
<View style={styles.lyricsViewer}>
<View style={styles.root}>
<Text variant='titleLarge' key={caption?.id} style={styles.cue}>
{caption?.text}
</Text>
Expand All @@ -55,18 +54,16 @@ function $LyricsViewer(props: LyricsViewerProps) {
export const LyricsViewer = memo($LyricsViewer);

const styles = StyleSheet.create({
lyricsViewer: {
width: '94%',
height: '84%',
root: {
width: '100%',
height: '100%',
alignSelf: 'center',
borderRadius: 10,
backgroundColor: '#CB495E',
overflow: 'scroll',
justifyContent: 'center',
alignItems: 'center',
justifyContent: 'flex-end',
bottom: 0,
position: 'absolute',
},
cue: {
fontWeight: '800',
marginBottom: hp(8),
},
});
23 changes: 20 additions & 3 deletions App/Components/Player/PlayButton.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
import { memo } from 'react';
import { Appbar } from 'react-native-paper';
import ActionButton from '../../../Framework/Components/ActionButton';

interface PlayButtonProps {
isAudioPlaying: boolean;
size: number;
onPause: () => void;
onPlay: () => void;
}

function $PlayButton(props: PlayButtonProps) {
if (props.isAudioPlaying) {
return <Appbar.Action icon='pause' size={32} onPress={props.onPause} />;
return (
<ActionButton
tooltipTitle='Pausar (K)'
icon='pause'
style={{ padding: 0, marginRight: 0 }}
size={props.size}
onPress={props.onPause}
/>
);
} else {
return <Appbar.Action icon='play' size={32} onPress={props.onPlay} />;
return (
<ActionButton
tooltipTitle='Reproduzir (K)'
icon='play'
style={{ padding: 0, marginRight: 0 }}
size={props.size}
onPress={props.onPlay}
/>
);
}
}

Expand Down
44 changes: 30 additions & 14 deletions App/Components/Player/ProgressBar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { formatTime } from '../../Util/time';
import { Text } from 'react-native-paper';
import { StyleSheet, View } from 'react-native';
import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
import { useContext, useState } from 'react';
import { DesktopModeProvider } from '../Provider';
import {
Expand All @@ -9,10 +9,12 @@ import {
} from 'react-native-responsive-screen';
import { AVPlaybackStatusSuccess } from 'expo-av';
import { onUpdateAsync } from '../../../Framework/Components/Actions/update';
import { colors } from '../../colors';

interface ProgressBarProps {
audioPosition: number;
getAudioInfo: () => Promise<AVPlaybackStatusSuccess | undefined>;
style?: StyleProp<ViewStyle>;
}

export function ProgressBar(props: ProgressBarProps) {
Expand All @@ -31,7 +33,18 @@ export function ProgressBar(props: ProgressBarProps) {
}

return (
<View style={styles.progressBarRoot}>
<View style={[styles.progressBarRoot, props.style]}>
<Text
variant='bodySmall'
style={{
marginRight: 10,
fontFamily: 'OpenSans',
fontWeight: '600',
color: colors.icon,
}}
>
{formatTime(props.audioPosition)}
</Text>
<View style={styles.progressBar}>
<View
style={[
Expand All @@ -45,34 +58,37 @@ export function ProgressBar(props: ProgressBarProps) {
]}
/>
</View>
<View style={styles.timeContainer}>
<Text variant='bodySmall'>{formatTime(props.audioPosition)}</Text>
<Text variant='bodySmall'>
{formatTime((audioInfo?.durationMillis ?? 0) - props.audioPosition)}
</Text>
</View>
<Text
variant='bodySmall'
style={{
marginLeft: 10,
fontFamily: 'OpenSans',
fontWeight: '600',
color: colors.icon,
}}
>
{formatTime((audioInfo?.durationMillis ?? 0) - props.audioPosition)}
</Text>
</View>
);
}

const styles = StyleSheet.create({
progressBarRoot: {
height: 30,
width: wp(50),
marginBottom: 1,
width: '100%',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
},
timeContainer: {
width: wp(50),
width: '92%',
flexDirection: 'row',
justifyContent: 'space-between',
},

progressBar: {
width: wp(50),
width: '92%',
height: hp(0.8),
marginBottom: 4,
borderRadius: 20,
backgroundColor: '#4C4850',
},
Expand Down
2 changes: 1 addition & 1 deletion App/Navigation/PlayerNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function PlayerNavigation(props: Props) {
initialRouteName='Player'
screenOptions={{
animationEnabled: true,
headerStyle: styles.headerStyle,
headerStyle: navStyles.headerStyleV1,
headerTitleStyle: navStyles.headerTitleStyle,
}}
>
Expand Down
130 changes: 85 additions & 45 deletions App/Screens/Player/Player.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useContext, useEffect, useState } from 'react';
import { StyleSheet, View } from 'react-native';
import { Appbar, Dialog, List, Portal } from 'react-native-paper';
import { StyleSheet, View, Image } from 'react-native';
import { Appbar, Dialog, List, Portal, Text } from 'react-native-paper';
import { song } from '../../Storage/store/player';
import {
heightPercentageToDP as hp,
Expand All @@ -16,6 +16,8 @@ import { Navigation } from '../../Navigation/Navigation';
import { ProgressBar } from '../../Components/Player/ProgressBar';
import { onMount, onMountAsync } from '../../../Framework/Components/Actions';
import { colors } from '../../colors';
import { ReactNativeKeysKeyCode, useHotkey } from 'react-native-hotkeys';
import ActionButton from '../../../Framework/Components/ActionButton';

interface Props {
appNavigation: any;
Expand Down Expand Up @@ -50,18 +52,40 @@ function Player(props: Props) {
setAudio(sound);
});

useHotkey(ReactNativeKeysKeyCode.KeyK, () => {
if (audioPlaying) pause();
else play();
});

useHotkey(ReactNativeKeysKeyCode.KeyL, skipForward);
useHotkey(ReactNativeKeysKeyCode.KeyJ, skipBack);

onMount(() => {
showDialog();

navigation.setTitle(`${choosenSong.title} - WordView`);
navigation.emptyHeaderTitle();
navigation.setHeaderLeft(
<Appbar.Action
icon='arrow-left'
onPress={() => {
appNavigation.go('home');
}}
/>,
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Appbar.Action
style={{ marginLeft: 5 }}
icon='arrow-left'
onPress={() => {
appNavigation.go('home');
}}
/>
<View style={{ justifyContent: 'center' }}>
<Text variant='bodyLarge' style={{ fontWeight: '700', color: colors.icon }}>
{choosenSong.title}
</Text>
<Text
variant='bodySmall'
style={{ fontWeight: '600', color: colors.iconDarker }}
>
{choosenSong.artist}
</Text>
</View>
</View>,
);
});

Expand Down Expand Up @@ -185,22 +209,50 @@ function Player(props: Props) {
</Dialog.Content>
</Dialog>
</Portal>
<View style={styles.root}>
<LyricsViewer cues={cues} audioPosition={audioPosition} />
<View style={styles.musicInfo}>
<MusicInfo song={choosenSong} />
<View style={styles.playerBarCenter}>
<View style={styles.playerControlsContainer}>
<Appbar.Action icon='skip-backward' size={20} onPress={skipBack} />
<PlayButton
isAudioPlaying={audioPlaying}
onPlay={play}
onPause={pause}
/>
<Appbar.Action icon='skip-forward' size={20} onPress={skipForward} />
</View>
<ProgressBar audioPosition={audioPosition} getAudioInfo={getAudioInfo} />
</View>
<Image
style={{ height: '100%', width: '100%' }}
// for some reason source doesn't accept a string altough it supports opening a url (???)
source={`https://img.youtube.com/vi/${choosenSong.id}/maxresdefault.jpg` as any}
blurRadius={5}
/>
<View
style={{
position: 'absolute',
width: '100%',
height: '100%',
backgroundColor: '#000',
opacity: 0.6,
}}
/>
<LyricsViewer cues={cues} audioPosition={audioPosition} />

<View style={styles.controls}>
<ProgressBar
audioPosition={audioPosition}
getAudioInfo={getAudioInfo}
style={{ marginTop: 2 }}
/>
<View style={styles.playerControlsContainer}>
<ActionButton
tooltipTitle='Retroceder (J)'
icon='skip-backward'
style={{ padding: 0, marginRight: 0 }}
size={24}
onPress={skipBack}
/>
<PlayButton
isAudioPlaying={audioPlaying}
size={28}
onPlay={play}
onPause={pause}
/>
<ActionButton
tooltipTitle='Avançar (L)'
icon='skip-forward'
style={{ padding: 0, marginRight: 0 }}
size={24}
onPress={skipForward}
/>
</View>
</View>
</>
Expand All @@ -213,38 +265,26 @@ const styles = StyleSheet.create({
height: '100%',
flexDirection: 'column',
justifyContent: 'space-between',
position: 'absolute',
},
lyricsViewer: {
width: '98%',
height: '84%',
alignSelf: 'center',
borderRadius: 10,
backgroundColor: '#CB495E',
overflow: 'scroll',
},
musicInfo: {
controls: {
bottom: 0,
width: '100%',
height: 80,
backgroundColor: colors.interface,
alignSelf: 'center',
alignItems: 'center',
justifyContent: 'center',
height: hp(14),
position: 'absolute',
borderTopColor: colors.interfaceBorder,
borderTopWidth: 1,
overflow: 'hidden',
},
subtitlePickerModal: {
overflow: 'scroll',
maxHeight: hp(40),
},
playerBarCenter: {
flexDirection: 'column',
alignSelf: 'center',
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
height: '100%',
},
playerControlsContainer: {
flexDirection: 'row',
alignItems: 'center',
height: 45,
},
});

Expand Down
2 changes: 2 additions & 0 deletions App/colors.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
export const colors = {
background: '#1C1B1F',
interfaceBorder: '#322D38',
interface: '#2C2831',
accent: '#9563FF',
icon: '#CAC4D0',
iconDarker: '#89848D',
text: '#B3B3B3',
};
Loading

0 comments on commit 551280f

Please sign in to comment.