Skip to content

Commit

Permalink
(feat:queue) Use new queue system in UI & Add queue page
Browse files Browse the repository at this point in the history
  • Loading branch information
KingRainbow44 committed Mar 15, 2024
1 parent f27d246 commit a560fbd
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 132 deletions.
77 changes: 42 additions & 35 deletions src/Laudiolin.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { useRef } from "react";
import { SafeAreaView, StatusBar, View } from "react-native";

import { BottomTabBar, createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { NavigationContainer } from "@react-navigation/native";
import { NavigationContainerRef } from "@react-navigation/core";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { BottomTabBar, createBottomTabNavigator } from "@react-navigation/bottom-tabs";

import { HomeIcon, SearchIcon, SettingsIcon } from "@ui/Icons";

Expand All @@ -25,46 +28,50 @@ const Tab = createBottomTabNavigator();
function Laudiolin(props: IProps) {
const global = useGlobal();

const navigator = useRef<NavigationContainerRef<any>>(null);

return (
<>
<StatusBar barStyle={"light-content"} />

<SafeAreaView style={style.App} onLayout={props.onLoad}>
{
global.showTrackPage && <NowPlaying />
}
{
global.showLoginPage && <Login />
}
<GestureHandlerRootView>
{
global.showTrackPage && <NowPlaying navigation={navigator.current!} />
}
{
global.showLoginPage && <Login />
}

<View style={{
...style.App,
display: global.showingAny() ? "none" : "flex"
}}>
<NavigationContainer>
<Tab.Navigator
tabBar={props => (
<>
<MediaPlayer />
<BottomTabBar {...props} />
</>
)}
screenOptions={{
headerShown: false,
tabBarShowLabel: false,
tabBarStyle: style.App_TabBar,
}}
sceneContainerStyle={style.App_Scene}
>
<Tab.Screen options={{ tabBarIcon: ({ focused }) => HomeIcon(focused) }}
name={"Home"} component={Home} />
<Tab.Screen options={{ tabBarIcon: ({ focused }) => SearchIcon(focused) }}
name={"Search"} component={Search} />
<Tab.Screen options={{ tabBarIcon: ({ focused }) => SettingsIcon(focused) }}
name={"Settings"} component={Settings} />
</Tab.Navigator>
</NavigationContainer>
</View>
<View style={{
...style.App,
display: global.showingAny() ? "none" : "flex"
}}>
<NavigationContainer ref={navigator}>
<Tab.Navigator
tabBar={props => (
<>
<MediaPlayer />
<BottomTabBar {...props} />
</>
)}
screenOptions={{
headerShown: false,
tabBarShowLabel: false,
tabBarStyle: style.App_TabBar,
}}
sceneContainerStyle={style.App_Scene}
>
<Tab.Screen options={{ tabBarIcon: ({ focused }) => HomeIcon(focused) }}
name={"Home"} component={Home} />
<Tab.Screen options={{ tabBarIcon: ({ focused }) => SearchIcon(focused) }}
name={"Search"} component={Search} />
<Tab.Screen options={{ tabBarIcon: ({ focused }) => SettingsIcon(focused) }}
name={"Settings"} component={Settings} />
</Tab.Navigator>
</NavigationContainer>
</View>
</GestureHandlerRootView>
</SafeAreaView>
</>
);
Expand Down
57 changes: 44 additions & 13 deletions src/ui/Debug.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { useEffect, useState } from "react";
import { useState } from "react";
import { StyleProp, View, ViewStyle } from "react-native";

import { useNavigation } from "@react-navigation/native";
import TrackPlayer, { Track, useActiveTrack, usePlaybackState } from "react-native-track-player";
import TrackPlayer, { RepeatMode, useActiveTrack, usePlaybackState } from "react-native-track-player";

import StyledText from "@components/StyledText";
import StyledButton from "@components/StyledButton";

import { useDebug } from "@backend/stores";
import Player, { currentlyPlaying, useQueue } from "@backend/player";

import { colors, value } from "@style/Laudiolin";

Expand All @@ -24,14 +25,12 @@ function Debug() {

const [queueInfo, showQueueInfo] = useState(false);
const [trackInfo, showTrackInfo] = useState(false);
const [newQueueInfo, setNewQueueInfo] = useState(false);

const [queue, setQueue] = useState<Track[]>([]);
const [repeatMode, setRepeatMode] = useState(RepeatMode.Off);
const [songIndex, setSongIndex] = useState<number | undefined>(0);

useEffect(() => {
if (queueInfo) {
TrackPlayer.getQueue().then(setQueue);
}
}, [playerState]);
const queue = useQueue();

return (
<View style={{ padding: value.padding, gap: 15 }}>
Expand All @@ -55,19 +54,51 @@ function Debug() {
<StyledButton
text={"Show Queue Info"}
buttonStyle={color(queueInfo)}
onPress={() => {
showQueueInfo(!queueInfo);
TrackPlayer.getQueue().then(setQueue);
}}
onPress={() => showQueueInfo(!queueInfo)}
/>

{ queueInfo && (
<View style={{ gap: 10 }}>
<StyledText text={`Songs in queue: ${queue.length}`} bold />
<StyledButton
text={"Clear Queue"}
onPress={() => TrackPlayer.removeUpcomingTracks()}
/>
<StyledButton
text={`Current Song: ${songIndex}`}
onPress={() => TrackPlayer.getActiveTrackIndex().then(setSongIndex)}
/>
<StyledButton
text={`Current Repeat: ${repeatMode}`}
onPress={() => {
Player.nextRepeatMode().then(setRepeatMode);
}}
/>
</View>
) }

<StyledButton
text={"Show New Queue Info"}
buttonStyle={color(newQueueInfo)}
onPress={() => setNewQueueInfo(!newQueueInfo)}
/>

{ newQueueInfo && (
<View style={{ gap: 10 }}>
<StyledText text={`Songs in queue: ${queue.size()}`} bold />
<StyledText text={`Next Song: ${queue.peek()?.title ?? "No song in queue"}`} />
<StyledText text={`Currently playing song: ${currentlyPlaying?.title ?? "None"}`} />

<StyledButton
text={`Current Repeat: ${repeatMode}`}
onPress={() => {
Player.nextRepeatMode().then(setRepeatMode);
}}
/>

<StyledButton
text={"Remove Element"}
onPress={() => queue.dequeue()}
/>
</View>
) }

Expand Down
157 changes: 88 additions & 69 deletions src/ui/NowPlaying.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import TrackPlayer, {
usePlaybackState,
useProgress,
} from "react-native-track-player";
import { NavigationContainerRef } from "@react-navigation/core";
import { GestureDetector, Gesture, Directions } from "react-native-gesture-handler";

import ProgressBar from "@widgets/ProgressBar";
import StyledText, { Size } from "@components/StyledText";
Expand All @@ -36,7 +38,7 @@ function RepeatIcon({ loop }: { loop: RepeatMode }) {
}
}

function NowPlaying() {
function NowPlaying({ navigation }: { navigation: NavigationContainerRef<any> }) {
const global = useGlobal();

const track = useActiveTrack();
Expand All @@ -49,82 +51,98 @@ function NowPlaying() {
TrackPlayer.getRepeatMode().then(setRepeatMode);
});

const goBack = () => global.setShowTrackPage(false);
const openQueue = () => {
navigation.navigate("Named List", {
title: "Queue", fetcher: "queue", render: "tracks"
});
global.setShowTrackPage(false);
};
const backGesture = Gesture.Fling()
.direction(Directions.DOWN)
.onEnd(goBack);
const queueGesture = Gesture.Fling()
.direction(Directions.UP)
.onEnd(openQueue);

return (
<View style={style.NowPlaying}>
<View style={style.NowPlaying_Header}>
<TouchableOpacity onPress={() => global.setShowTrackPage(false)}>
<AdIcon name={"left"} size={28} color={"white"} />
</TouchableOpacity>

{ global.fromPlaylist && (
<View style={style.NowPlaying_Source}>
<StyledText uppercase text={"Playing from Playlist"}
<GestureDetector gesture={Gesture.Exclusive(queueGesture, backGesture)}>
<View style={style.NowPlaying}>
<View style={style.NowPlaying_Header}>
<TouchableOpacity onPress={() => global.setShowTrackPage(false)}>
<AdIcon name={"left"} size={28} color={"white"} />
</TouchableOpacity>

{ global.fromPlaylist && (
<View style={style.NowPlaying_Source}>
<StyledText uppercase text={"Playing from Playlist"}
style={{ color: colors.gray }}
/>
<StyledText bold text={global.fromPlaylist} />
</View>
) }

<TouchableOpacity onPress={() => null}>
<EnIcon name={"dots-three-vertical"} size={24} color={"white"} />
{/* TODO: Move favorite track into context menu. */}
</TouchableOpacity>
</View>

<FastImage
style={style.NowPlaying_Cover}
source={{ uri: track?.artwork }}
resizeMode={"contain"}
/>

<View style={{ flexDirection: "column" }}>
<View style={style.NowPlaying_Info}>
<StyledText text={track?.title ?? "Not Playing"}
size={Size.Header} bold
lines={value.height > 700 ? 3 : 2}
/>

<StyledText text={track?.artist ?? "---"}
style={{ color: colors.gray }}
size={Size.Text} lines={1}
/>
<StyledText bold text={global.fromPlaylist} />
</View>
) }

<TouchableOpacity onPress={() => null}>
<EnIcon name={"dots-three-vertical"} size={24} color={"white"} />
{/* TODO: Move favorite track into context menu. */}
</TouchableOpacity>
</View>

<FastImage
style={style.NowPlaying_Cover}
source={{ uri: track?.artwork }}
resizeMode={"contain"}
/>

<View style={{ flexDirection: "column" }}>
<View style={style.NowPlaying_Info}>
<StyledText text={track?.title ?? "Not Playing"}
size={Size.Header} bold
lines={value.height > 700 ? 3 : 2}
/>

<StyledText text={track?.artist ?? "---"}
style={{ color: colors.gray }}
size={Size.Text} lines={1}
<ProgressBar
progress={progress.position}
duration={progress.duration}
style={{ paddingLeft: 10, paddingRight: 10, marginBottom: 15 }}
/>
</View>

<ProgressBar
progress={progress.position}
duration={progress.duration}
style={{ paddingLeft: 10, paddingRight: 10, marginBottom: 15 }}
/>
</View>

<View style={style.NowPlaying_Controls}>
<TouchableOpacity onPress={() => Player.shuffle()}>
<FaIcon name={"shuffle"} color={"white"} size={28} />
</TouchableOpacity>

<TouchableOpacity onPress={() => TrackPlayer.skipToPrevious()}>
<IoIcon name={"play-skip-back"} color={"white"} size={28} />
</TouchableOpacity>

<TouchableOpacity onPress={async () => {
if (state == State.Paused) {
await TrackPlayer.play();
} else if (state == State.Playing) {
await TrackPlayer.pause();
}
}}>
<MdIcon name={state == State.Playing ? "pause" : "play-arrow"} color={"white"} size={32} />
</TouchableOpacity>

<TouchableOpacity onPress={() => TrackPlayer.skipToNext()}>
<IoIcon name={"play-skip-forward"} color={"white"} size={28} />
</TouchableOpacity>

<TouchableOpacity onPress={() => Player.nextRepeatMode().then(setRepeatMode)}>
<RepeatIcon loop={repeatMode} />
</TouchableOpacity>
<View style={style.NowPlaying_Controls}>
<TouchableOpacity onPress={() => Player.shuffle()}>
<FaIcon name={"shuffle"} color={"white"} size={28} />
</TouchableOpacity>

<TouchableOpacity onPress={() => Player.skipToPrevious()}>
<IoIcon name={"play-skip-back"} color={"white"} size={28} />
</TouchableOpacity>

<TouchableOpacity onPress={async () => {
if (state == State.Paused) {
await TrackPlayer.play();
} else if (state == State.Playing) {
await TrackPlayer.pause();
}
}}>
<MdIcon name={state == State.Playing ? "pause" : "play-arrow"} color={"white"} size={32} />
</TouchableOpacity>

<TouchableOpacity onPress={() => Player.skipToNext()}>
<IoIcon name={"play-skip-forward"} color={"white"} size={28} />
</TouchableOpacity>

<TouchableOpacity onPress={() => Player.nextRepeatMode().then(setRepeatMode)}>
<RepeatIcon loop={repeatMode} />
</TouchableOpacity>
</View>
</View>
</View>
</GestureDetector>
);
}

Expand Down Expand Up @@ -171,7 +189,8 @@ const style = StyleSheet.create({
bottom: 10,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
gap: 30,
alignSelf: "center",
paddingTop: 30,
paddingLeft: 25,
paddingRight: 25
Expand Down
Loading

0 comments on commit a560fbd

Please sign in to comment.