mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
playlist play, optimized layout & better player style implemented
This commit is contained in:
parent
23394e437b
commit
b97a8edc5b
@ -1,3 +0,0 @@
|
||||
[Dolphin]
|
||||
Timestamp=2021,2,13,23,13,52
|
||||
Version=4
|
24
src/app.tsx
24
src/app.tsx
@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { Window, hot, BoxView, View } from "@nodegui/react-nodegui";
|
||||
import { Direction, QIcon, QMainWindow, WidgetEventTypes, WindowState } from "@nodegui/nodegui";
|
||||
import { Window, hot, View } from "@nodegui/react-nodegui";
|
||||
import { QIcon, QMainWindow, WidgetEventTypes, WindowState } from "@nodegui/nodegui";
|
||||
import nodeguiIcon from "../assets/nodegui.jpg";
|
||||
import { MemoryRouter } from "react-router";
|
||||
import Routes from "./routes";
|
||||
@ -19,7 +19,7 @@ export interface Credentials {
|
||||
clientSecret: string;
|
||||
}
|
||||
|
||||
const minSize = { width: 700, height: 520 };
|
||||
const minSize = { width: 700, height: 750 };
|
||||
const winIcon = new QIcon(nodeguiIcon);
|
||||
global.localStorage = new LocalStorage("./local");
|
||||
|
||||
@ -35,13 +35,21 @@ function RootApp() {
|
||||
const credentialStr = localStorage.getItem(CredentialKeys.credentials);
|
||||
|
||||
useEffect(() => {
|
||||
windowRef.current?.addEventListener(WidgetEventTypes.Close, () => {
|
||||
setIsLoggedIn(!!credentialStr);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const onWindowClose = () => {
|
||||
if (audioPlayer.isRunning()) {
|
||||
audioPlayer.stop().catch((e) => console.error("Failed to quit MPV player: ", e));
|
||||
}
|
||||
};
|
||||
|
||||
windowRef.current?.addEventListener(WidgetEventTypes.Close, onWindowClose);
|
||||
return () => {
|
||||
windowRef.current?.removeEventListener(WidgetEventTypes.Close, onWindowClose);
|
||||
};
|
||||
});
|
||||
setIsLoggedIn(!!credentialStr);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoggedIn) {
|
||||
@ -67,10 +75,10 @@ function RootApp() {
|
||||
<MemoryRouter>
|
||||
<authContext.Provider value={{ isLoggedIn, setIsLoggedIn, access_token }}>
|
||||
<playerContext.Provider value={{ spotifyApi, currentPlaylist, currentTrack, setCurrentPlaylist, setCurrentTrack }}>
|
||||
<BoxView direction={Direction.TopToBottom}>
|
||||
<View style={`flex: 1; flex-direction: 'column'; justify-content: 'center'; align-items: 'stretch'; height: '100%';`}>
|
||||
<Routes />
|
||||
{isLoggedIn && <Player />}
|
||||
</BoxView>
|
||||
</View>
|
||||
</playerContext.Provider>
|
||||
</authContext.Provider>
|
||||
</MemoryRouter>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import { Button, Text, View, ScrollArea } from "@nodegui/react-nodegui";
|
||||
import { Button, View, ScrollArea } from "@nodegui/react-nodegui";
|
||||
import playerContext from "../context/playerContext";
|
||||
import authContext from "../context/authContext";
|
||||
import { useHistory } from "react-router";
|
||||
@ -7,7 +7,7 @@ import CachedImage from "./shared/CachedImage";
|
||||
import { CursorShape } from "@nodegui/nodegui";
|
||||
|
||||
function Home() {
|
||||
const { spotifyApi, currentPlaylist, currentTrack } = useContext(playerContext);
|
||||
const { spotifyApi } = useContext(playerContext);
|
||||
const { isLoggedIn, access_token } = useContext(authContext);
|
||||
const [categories, setCategories] = useState<SpotifyApi.CategoryObject[]>([]);
|
||||
|
||||
@ -26,8 +26,8 @@ function Home() {
|
||||
}, [access_token]);
|
||||
|
||||
return (
|
||||
<ScrollArea style={`flex-grow: 1; border: none;`}>
|
||||
<View style={`flex-direction: 'column'; justify-content: 'center'; align-items: 'stretch';`}>
|
||||
<ScrollArea style={`flex-grow: 1; border: none; flex: 1;`}>
|
||||
<View style={`flex-direction: 'column'; justify-content: 'center'; flex: 1;`}>
|
||||
<CategoryCard key={((Math.random() * Date.now()) / Math.random()) * 100} id="current" name="Currently Playing" />
|
||||
{isLoggedIn &&
|
||||
categories.map(({ id, name }, index) => {
|
||||
@ -75,6 +75,7 @@ function CategoryCard({ id, name }: CategoryCardProps) {
|
||||
|
||||
const categoryStylesheet = `
|
||||
#container{
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: 'center';
|
||||
margin-bottom: 20px;
|
||||
@ -94,7 +95,10 @@ function CategoryCard({ id, name }: CategoryCardProps) {
|
||||
text-decoration: underline;
|
||||
}
|
||||
#child-view{
|
||||
flex: 1;
|
||||
justify-content: 'space-evenly';
|
||||
align-items: 'center';
|
||||
flex-wrap: 'wrap';
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -23,7 +23,7 @@ export const audioPlayer = new NodeMpv(
|
||||
|
||||
function Player(): ReactElement {
|
||||
const { currentTrack, currentPlaylist, setCurrentTrack, setCurrentPlaylist } = useContext(playerContext);
|
||||
const [volume, setVolume] = useState(55);
|
||||
const [volume, setVolume] = useState<number>(parseFloat(localStorage.getItem("volume") ?? "55"));
|
||||
const [totalDuration, setTotalDuration] = useState(0);
|
||||
const [shuffle, setShuffle] = useState<boolean>(false);
|
||||
const [realPlaylist, setRealPlaylist] = useState<CurrentPlaylist["tracks"]>([]);
|
||||
@ -34,6 +34,9 @@ function Player(): ReactElement {
|
||||
sliderMoved: (value) => {
|
||||
setVolume(value);
|
||||
},
|
||||
sliderReleased: () => {
|
||||
localStorage.setItem("volume", volume.toString());
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
@ -47,10 +50,8 @@ function Player(): ReactElement {
|
||||
if (!playerRunning) {
|
||||
await audioPlayer.start();
|
||||
}
|
||||
await audioPlayer.volume(55);
|
||||
} catch (error) {
|
||||
console.error("Failed to start audio player");
|
||||
console.error(error);
|
||||
console.error("Failed to start audio player", error);
|
||||
}
|
||||
})();
|
||||
|
||||
@ -157,9 +158,9 @@ function Player(): ReactElement {
|
||||
}
|
||||
}
|
||||
|
||||
const artistsNames = currentTrack?.artists.map((x) => x.name);
|
||||
const artistsNames = currentTrack?.artists?.map((x) => x.name);
|
||||
return (
|
||||
<GridView style="flex: 1; max-height: 100px;">
|
||||
<GridView enabled={!!currentTrack} style="flex: 1; max-height: 100px;">
|
||||
<GridRow>
|
||||
<GridColumn width={2}>
|
||||
<Text ref={titleRef} wordWrap>
|
||||
|
@ -1,11 +1,14 @@
|
||||
import React, { FC, useContext, useEffect, useState } from "react";
|
||||
import { BoxView, Button, ScrollArea, Text, View } from "@nodegui/react-nodegui";
|
||||
import { BoxView, Button, GridView, ScrollArea, Text, View } from "@nodegui/react-nodegui";
|
||||
import BackButton from "./BackButton";
|
||||
import { useLocation, useParams } from "react-router";
|
||||
import { Direction, QAbstractButtonSignals } from "@nodegui/nodegui";
|
||||
import { Direction, QAbstractButtonSignals, QIcon } from "@nodegui/nodegui";
|
||||
import { WidgetEventListeners } from "@nodegui/react-nodegui/dist/components/View/RNView";
|
||||
import authContext from "../context/authContext";
|
||||
import playerContext from "../context/playerContext";
|
||||
import IconButton from "./shared/IconButton";
|
||||
import { heartRegular, play, stop } from "../icons";
|
||||
import { audioPlayer } from "./Player";
|
||||
|
||||
export interface PlaylistTrackRes {
|
||||
name: string;
|
||||
@ -21,20 +24,9 @@ const PlaylistView: FC<PlaylistViewProps> = () => {
|
||||
const { isLoggedIn, access_token } = useContext(authContext);
|
||||
const { spotifyApi, setCurrentTrack, currentPlaylist, currentTrack, setCurrentPlaylist } = useContext(playerContext);
|
||||
const params = useParams<{ id: string }>();
|
||||
const location = useLocation<{ name: string, thumbnail: string }>();
|
||||
const location = useLocation<{ name: string; thumbnail: string }>();
|
||||
const [tracks, setTracks] = useState<SpotifyApi.PlaylistTrackObject[]>([]);
|
||||
|
||||
const trackClickHandler = async (track: SpotifyApi.TrackObjectFull) => {
|
||||
try {
|
||||
setCurrentTrack(track);
|
||||
if (currentPlaylist?.id !== params.id) {
|
||||
setCurrentPlaylist({...params, ...location.state, tracks});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to resolve track's youtube url: ", error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoggedIn) {
|
||||
(async () => {
|
||||
@ -49,9 +41,34 @@ const PlaylistView: FC<PlaylistViewProps> = () => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handlePlaylistPlayPause = () => {
|
||||
if (currentPlaylist?.id !== params.id) {
|
||||
setCurrentPlaylist({ ...params, ...location.state, tracks });
|
||||
setCurrentTrack(tracks[0].track);
|
||||
} else {
|
||||
audioPlayer.stop().catch((error) => console.error("Failed to stop audio player: ", error));
|
||||
setCurrentTrack(undefined);
|
||||
setCurrentPlaylist(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
const trackClickHandler = async (track: SpotifyApi.TrackObjectFull) => {
|
||||
try {
|
||||
setCurrentTrack(track);
|
||||
} catch (error) {
|
||||
console.error("Failed to resolve track's youtube url: ", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<BoxView direction={Direction.TopToBottom}>
|
||||
<View style={`flex-direction: 'column'; flex-grow: 1;`}>
|
||||
<View style={`justify-content: 'space-between'; padding-bottom: 10px; padding-left: 10px;`}>
|
||||
<BackButton />
|
||||
<View style={`height: 50px; justify-content: 'space-between'; width: 100px; padding-right: 20px;`}>
|
||||
<IconButton icon={new QIcon(heartRegular)} />
|
||||
<IconButton style={`background-color: #00be5f; color: white;`} on={{ clicked: handlePlaylistPlayPause }} icon={new QIcon(currentPlaylist?.id === params.id ? stop : play)} />
|
||||
</View>
|
||||
</View>
|
||||
<Text>{`<center><h2>${location.state.name[0].toUpperCase()}${location.state.name.slice(1)}</h2></center>`}</Text>
|
||||
<ScrollArea style={`flex-grow: 1; border: none;`}>
|
||||
<View style={`flex-direction:column;`}>
|
||||
@ -70,7 +87,7 @@ const PlaylistView: FC<PlaylistViewProps> = () => {
|
||||
})}
|
||||
</View>
|
||||
</ScrollArea>
|
||||
</BoxView>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user