diff --git a/backend/src/socketio/RoomIO.ts b/backend/src/socketio/RoomIO.ts index 5536ec19..0406367f 100644 --- a/backend/src/socketio/RoomIO.ts +++ b/backend/src/socketio/RoomIO.ts @@ -2,6 +2,8 @@ import { JSONTrack } from "commons/backend-types"; import { Response } from "commons/socket.io-types"; import RoomStorage from "../RoomStorage"; import Room, { TypedSocket } from "./Room"; +import { spotify } from "../server"; +import Spotify from "../musicplatform/Spotify"; const roomStorage = RoomStorage.getRoomStorage(); @@ -187,6 +189,43 @@ export default function onRoomWSConnection(socket: TypedSocket) { resultCallback(data); } ); + + socket.on("user:playlists", async (userId, callback) => { + const playlists = await spotify.playlists.getUsersPlaylists(userId); + + const result = playlists.items.map((playlist) => { + return { name: playlist.name, playlistId: playlist.id }; + }); + + callback(result); + + // const result = playlists.items.forEach((rawPlaylist) => { + // const tracks: JSONTrack[] = []; + // + // const playlist = await spotify.playlists.getPlaylist(rawPlaylist.id); + // playlist.tracks.items.forEach((audioElement) => { + // const data = audioElement.track; + // if (data as Track) { + // const track = new Spotify().toJSON(data as Track); + // if (track !== null) tracks.push(track); + // } + // }); + // + // const result = { + // name: playlist.name, + // tracks: tracks, + // }; + // }); + // const newVar = result.; + }); + + socket.on("user:playlistTrack", async (playlistId, callback) => { + const playlist = await spotify.playlists.getPlaylist(playlistId); + const result = playlist.tracks.items + .map((playlistTrack) => new Spotify().toJSON(playlistTrack.track)) + .filter((value) => value !== null) as JSONTrack[]; + callback(result); + }); } registerHandlers(); diff --git a/commons/backend-types.ts b/commons/backend-types.ts index b540e5c7..d2f6e41d 100644 --- a/commons/backend-types.ts +++ b/commons/backend-types.ts @@ -34,3 +34,8 @@ export interface RoomJSON { queue: RoomJSONTrack[]; voteSkipActualTrack: string[]; } + +export interface Playlist { + name: string; + playlistId: string; +} diff --git a/commons/socket.io-types.ts b/commons/socket.io-types.ts index d5b320ac..428149c1 100644 --- a/commons/socket.io-types.ts +++ b/commons/socket.io-types.ts @@ -1,4 +1,9 @@ -import { JSONTrack, PlayingJSONTrack, RoomJSON } from "./backend-types"; +import { + JSONTrack, + PlayingJSONTrack, + Playlist, + RoomJSON, +} from "./backend-types"; export type Response = | { data: T; error: null } @@ -92,6 +97,14 @@ export interface ClientToServerEvents text: string, resultCallback: (args: JSONTrack[]) => void ) => void; + "user:playlists": ( + userId: string, + callback: (playlists: Playlist[]) => void + ) => void; + "user:playlistTrack": ( + playlistId: string, + callback: (tracks: JSONTrack[]) => void + ) => void; } /** diff --git a/expo/app/(tabs)/rooms/[id]/_layout.tsx b/expo/app/(tabs)/rooms/[id]/_layout.tsx index 849904d9..44e1f5b4 100644 --- a/expo/app/(tabs)/rooms/[id]/_layout.tsx +++ b/expo/app/(tabs)/rooms/[id]/_layout.tsx @@ -91,6 +91,7 @@ export default function RoomTabLayout() { }} /> + diff --git a/expo/app/(tabs)/rooms/[id]/library.tsx b/expo/app/(tabs)/rooms/[id]/library.tsx new file mode 100644 index 00000000..f3e816bf --- /dev/null +++ b/expo/app/(tabs)/rooms/[id]/library.tsx @@ -0,0 +1,93 @@ +import FontAwesome from "@expo/vector-icons/FontAwesome"; +import { JSONTrack, Playlist } from "commons/backend-types"; +import { router } from "expo-router"; +import { useEffect, useState } from "react"; +import { FlatList, Pressable, StyleSheet } from "react-native"; + +import { useWebSocket } from "./_layout"; +import { Text, View } from "../../../../components/Tamed"; +import SearchedTrackItem from "../../../../components/room/SearchedTrackItem"; +import { useSupabaseUserHook } from "../../../../lib/useSupabaseUser"; + +export default function Library() { + const [playlists, setPlaylists] = useState([]); + + const user = useSupabaseUserHook(); + const socket = useWebSocket(); + useEffect(() => { + console.log(user); + const spotifyUser = user?.identities?.filter( + (ptf) => ptf.provider === "spotify" + )[0]; + socket?.emit("user:playlists", spotifyUser?.id, setPlaylists); + }, [socket, user]); + + return ( + } + /> + ); +} + +function Item(props: { playlist: Playlist }) { + const playlist = props.playlist; + + const [showTracks, setShowTracks] = useState(false); + const [tracks, setTracks] = useState([]); + + const socket = useWebSocket(); + + useEffect(() => { + if (showTracks) + socket?.emit("user:playlistTrack", playlist.playlistId, setTracks); + }, [socket, showTracks]); + + return ( + + setShowTracks(!showTracks)} + style={styles.playlistHeader} + > + + {playlist.name} + + {showTracks && ( + { + return ( + + { + socket?.emit("queue:add", new URL(item.url).toString()); + + router.back(); + router.back(); + }} + /> + + ); + }} + /> + )} + + ); +} + +const styles = StyleSheet.create({ + playlistHeader: { + flexDirection: "row", + alignItems: "center", + paddingVertical: 15, + }, + playlistHeaderInner: { + fontFamily: "Outfit-Bold", + paddingLeft: 10, + fontSize: 15, + }, +}); diff --git a/expo/app/(tabs)/rooms/[id]/playlist.tsx b/expo/app/(tabs)/rooms/[id]/playlist.tsx new file mode 100644 index 00000000..b4036d8f --- /dev/null +++ b/expo/app/(tabs)/rooms/[id]/playlist.tsx @@ -0,0 +1,25 @@ +import React, { useEffect, useState } from "react"; +import { FlatList, Pressable } from "react-native"; + +import { useWebSocket } from "./_layout"; +import { Text } from "../../../../components/Tamed"; + +export default function Playlist(props: { playlistId: string }) { + const [tracks, setTracks] = useState([]); + + const socket = useWebSocket(); + useEffect(() => { + socket?.emit("user:playlists", props.playlistId, setTracks); + }, [socket]); + + return ( + ( + alert(item)}> + {item} + + )} + /> + ); +} diff --git a/expo/components/room/Library.tsx b/expo/components/room/Library.tsx index c5eb0fe9..7f66c1cd 100644 --- a/expo/components/room/Library.tsx +++ b/expo/components/room/Library.tsx @@ -1,6 +1,7 @@ import ClockCounterClockwise from "phosphor-react-native/src/icons/ClockCounterClockwise"; import Heart from "phosphor-react-native/src/icons/Heart"; import MusicNote from "phosphor-react-native/src/icons/MusicNote"; +import { router } from "expo-router"; import { StyleSheet, View, Text } from "react-native"; import LibraryComponent from "./LibraryComponent"; @@ -18,6 +19,7 @@ const Library = () => { title="Mes playlists" subtitle="Ajoute une musique à partir de tes playlists" icon={} + onPress={() => router.push("./library")} /> void; }) => { icon = React.cloneElement(icon, { size: 24, color: "white" }); return ( - + {title} {icon} {subtitle} - + ); };