309 lines
10 KiB
JavaScript
309 lines
10 KiB
JavaScript
import { BlurView } from "expo-blur";
|
|
import React, { useCallback, useMemo, useState } from "react";
|
|
import { Image, Pressable, Text, View } from "react-native";
|
|
import { SheetManager } from "react-native-actions-sheet";
|
|
import { useGlobal } from "reactn";
|
|
import { background, icons } from "../../assets";
|
|
import MoreMenu from "../../components/MoreMenu";
|
|
import { playlistsRef, projectsRef } from "../../config/firebase";
|
|
import useDataFromArrayDocId from "../../hooks/useDataFromArrayId";
|
|
import useDataFromRef from "../../hooks/useDataFromRef";
|
|
import useNavigateToMusicDetails from "../../hooks/useNavigateToMusicDetails";
|
|
import usePlayer from "../../hooks/usePlayer";
|
|
import Page from "../../layouts/Page";
|
|
import { useUser } from "../../providers/UserDataProvider";
|
|
import { gutters, Palette, Style } from "../../styles";
|
|
import { FONT_FAMILY } from "../../styles/Fonts";
|
|
import { size } from "../../styles/Style";
|
|
import MusicCard from "./components/MusicCard";
|
|
|
|
const AllMyPlaylist = ({ route }) => {
|
|
const { playListId } = route?.params || {};
|
|
const [, setTooltip] = useGlobal("_tooltip");
|
|
const { userPlaylists = [] } = useUser();
|
|
const [selectedPlaylistId, setSelectedPlaylistId] = useState(
|
|
playListId || null
|
|
);
|
|
const { data: playlist } = useDataFromRef({
|
|
ref: selectedPlaylistId ? playlistsRef.doc(selectedPlaylistId) : null,
|
|
simpleRef: true,
|
|
listener: true,
|
|
condition: !!selectedPlaylistId,
|
|
refreshArray: [selectedPlaylistId],
|
|
});
|
|
|
|
// Fetch projects by ids from playlist.musics
|
|
const { data: musics } = useDataFromArrayDocId({
|
|
ref: projectsRef,
|
|
arrayId: Array.isArray(playlist?.musics) ? playlist.musics : [],
|
|
condition: Array.isArray(playlist?.musics) && playlist.musics.length > 0,
|
|
refreshArray: [selectedPlaylistId, playlist?.musics?.length || 0],
|
|
});
|
|
const [menuPosition, setMenuPosition] = useState(null);
|
|
const [showMenu, setShowMenu] = useState(false);
|
|
const [selectedProjectId, setSelectedProjectId] = useState(null);
|
|
const navigateToMusicDetails = useNavigateToMusicDetails();
|
|
const { setQueue } = usePlayer() || {};
|
|
|
|
const playlistQueueItems = useMemo(() => {
|
|
if (!Array.isArray(musics)) return [];
|
|
return musics
|
|
.map((project) => {
|
|
const projectId =
|
|
typeof project?.id === "string" ? project.id : project?.projectId ?? null;
|
|
const songUrl =
|
|
typeof project?.songUrl === "string" && project.songUrl.length > 0
|
|
? project.songUrl
|
|
: null;
|
|
if (!songUrl) return null;
|
|
const descriptorId = projectId ? `project-${projectId}` : songUrl;
|
|
return {
|
|
id: descriptorId,
|
|
uri: songUrl,
|
|
songUrl,
|
|
title: project?.title || "Sans titre",
|
|
artist: project?.userName || "",
|
|
artwork: project?.coverUrl ?? null,
|
|
coverUrl: project?.coverUrl ?? null,
|
|
metadata: {
|
|
projectId,
|
|
playlistId: selectedPlaylistId ?? null,
|
|
playlistName: playlist?.name ?? null,
|
|
},
|
|
context: {
|
|
projectId,
|
|
playlistId: selectedPlaylistId ?? null,
|
|
playlistName: playlist?.name ?? null,
|
|
},
|
|
};
|
|
})
|
|
.filter(Boolean);
|
|
}, [musics, playlist?.name, selectedPlaylistId]);
|
|
|
|
const handlePlayFromPlaylist = useCallback(
|
|
(project) => {
|
|
if (!project?.id) return;
|
|
if (Array.isArray(playlistQueueItems) && playlistQueueItems.length > 0) {
|
|
const queueIndex = playlistQueueItems.findIndex(
|
|
(item) => item?.metadata?.projectId === project.id
|
|
);
|
|
if (queueIndex >= 0 && typeof setQueue === "function") {
|
|
setQueue({
|
|
items: playlistQueueItems,
|
|
id: selectedPlaylistId,
|
|
type: "playlist",
|
|
name: playlist?.name ?? null,
|
|
index: queueIndex,
|
|
});
|
|
}
|
|
}
|
|
navigateToMusicDetails({
|
|
projectId: project.id,
|
|
songUrl: project?.songUrl,
|
|
project,
|
|
});
|
|
},
|
|
[
|
|
navigateToMusicDetails,
|
|
playlist?.name,
|
|
playlistQueueItems,
|
|
selectedPlaylistId,
|
|
setQueue,
|
|
]
|
|
);
|
|
|
|
// delete playlist
|
|
const confirmDelete = () => {
|
|
SheetManager.show("Delete", {
|
|
payload: {
|
|
title: "Supprimer la playlist",
|
|
message: "Es-tu sûr de vouloir supprimer cette playlist ?",
|
|
onConfirm: async () => {
|
|
try {
|
|
if (selectedPlaylistId) {
|
|
await playlistsRef.doc(selectedPlaylistId).delete();
|
|
setTooltip({ type: "success", text: "Playlist supprimée" });
|
|
}
|
|
} catch (e) {
|
|
console.log("Delete playlist error", e?.message);
|
|
setTooltip({
|
|
type: "error",
|
|
text: e?.message || "Suppression impossible",
|
|
});
|
|
}
|
|
},
|
|
},
|
|
});
|
|
};
|
|
|
|
return (
|
|
<Page
|
|
headerType="NAVIGATION"
|
|
backgroundImg={background.libraryBG}
|
|
title="Mes Playlists"
|
|
width={"80%"}
|
|
contentContainerStyle={{
|
|
paddingBottom: gutters * 2,
|
|
}}
|
|
rightComponent={() => (
|
|
<>
|
|
{selectedPlaylistId != null && (
|
|
<Pressable onPress={confirmDelete}>
|
|
<Image source={icons.trash} style={{ width: 24, height: 24 }} />
|
|
</Pressable>
|
|
)}
|
|
</>
|
|
)}
|
|
>
|
|
<View style={{ flexDirection: "row", gap: 20 }}>
|
|
<View
|
|
style={{
|
|
flex: 1,
|
|
padding: 10,
|
|
borderRadius: 12,
|
|
backgroundColor: Palette.ultraLightWhite,
|
|
...Style.defaultBorder,
|
|
}}
|
|
>
|
|
<View style={{ flex: 1, gap: 12 }}>
|
|
<View style={{ gap: 8 }}>
|
|
{(Array.isArray(userPlaylists) ? userPlaylists : []).map(
|
|
(item) => {
|
|
const isSelected = selectedPlaylistId === item?.id;
|
|
|
|
return (
|
|
<Pressable
|
|
key={item?.id}
|
|
onPress={() => setSelectedPlaylistId(item?.id)}
|
|
>
|
|
<View
|
|
style={{
|
|
borderRadius: 14,
|
|
overflow: "hidden",
|
|
borderWidth: 1,
|
|
borderColor: Palette.transparentWhite,
|
|
transform: [{ scaleX: isSelected ? 1.04 : 1 }],
|
|
}}
|
|
>
|
|
<BlurView
|
|
intensity={30}
|
|
style={{
|
|
...Style.containerSpaceBetween,
|
|
minHeight: 59,
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 12,
|
|
}}
|
|
>
|
|
<Text
|
|
style={{
|
|
flex: 1,
|
|
fontSize: isSelected ? 18 : 16,
|
|
color: Palette.white,
|
|
fontFamily: isSelected
|
|
? FONT_FAMILY.InterSemiBold
|
|
: FONT_FAMILY.InterRegular,
|
|
marginRight: 12,
|
|
flexShrink: 1,
|
|
}}
|
|
>
|
|
{item?.name || "Sans nom"}
|
|
</Text>
|
|
<Pressable>
|
|
<Image
|
|
source={icons.chevronDown}
|
|
style={{
|
|
...size({ size: 15 }),
|
|
transform: [{ rotate: "-90deg" }],
|
|
}}
|
|
resizeMode="contain"
|
|
/>
|
|
</Pressable>
|
|
</BlurView>
|
|
</View>
|
|
</Pressable>
|
|
);
|
|
}
|
|
)}
|
|
</View>
|
|
<Pressable
|
|
onPress={() =>
|
|
SheetManager.show("Playlist", {
|
|
payload: { startAtCreate: true },
|
|
})
|
|
}
|
|
>
|
|
<View
|
|
style={{
|
|
borderRadius: 12,
|
|
overflow: "hidden",
|
|
borderWidth: 1,
|
|
borderColor: Palette.transparentWhite,
|
|
}}
|
|
>
|
|
<BlurView
|
|
intensity={30}
|
|
style={{
|
|
...Style.containerSpaceBetween,
|
|
paddingHorizontal: 16,
|
|
minHeight: 59,
|
|
paddingVertical: 12,
|
|
}}
|
|
>
|
|
<Text
|
|
style={{
|
|
fontSize: 16,
|
|
color: Palette.white,
|
|
fontFamily: FONT_FAMILY.InterSemiBold,
|
|
}}
|
|
>
|
|
Ajouter une playlist
|
|
</Text>
|
|
<Image
|
|
source={icons.add}
|
|
style={size({ size: 20 })}
|
|
resizeMode="contain"
|
|
/>
|
|
</BlurView>
|
|
</View>
|
|
</Pressable>
|
|
</View>
|
|
</View>
|
|
<View style={{ flex: 2, gap: 10 }}>
|
|
{Array.isArray(musics) &&
|
|
musics.map((p) => (
|
|
<MusicCard
|
|
key={p.id}
|
|
title={p?.title}
|
|
subtitle={p?.userName}
|
|
imageUri={p?.coverUrl || null}
|
|
projectId={p?.id}
|
|
likedBy={p?.likedBy || []}
|
|
onPress={() => handlePlayFromPlaylist(p)}
|
|
onPressMore={(posTop) => {
|
|
setSelectedProjectId(p.id);
|
|
setMenuPosition(posTop);
|
|
setShowMenu(
|
|
(prev) =>
|
|
!prev || posTop?.top !== (menuPosition?.top ?? null)
|
|
);
|
|
}}
|
|
/>
|
|
))}
|
|
|
|
<MoreMenu
|
|
visible={showMenu}
|
|
top={menuPosition?.top ?? 0}
|
|
position={menuPosition}
|
|
onClose={() => setShowMenu(false)}
|
|
inPlaylist
|
|
playlistId={selectedPlaylistId}
|
|
projectId={selectedProjectId}
|
|
/>
|
|
</View>
|
|
</View>
|
|
</Page>
|
|
);
|
|
};
|
|
|
|
export default AllMyPlaylist;
|