diff --git a/src/assets/icons/heart.png b/src/assets/icons/heart.png index 0c59bc4..33bba43 100644 Binary files a/src/assets/icons/heart.png and b/src/assets/icons/heart.png differ diff --git a/src/assets/icons/heartOutline.png b/src/assets/icons/heartOutline.png index a749911..5ebc5a9 100644 Binary files a/src/assets/icons/heartOutline.png and b/src/assets/icons/heartOutline.png differ diff --git a/src/assets/icons/more.png b/src/assets/icons/more.png index 7d21747..33b707f 100644 Binary files a/src/assets/icons/more.png and b/src/assets/icons/more.png differ diff --git a/src/components/MoreMenu.js b/src/components/MoreMenu.js new file mode 100644 index 0000000..aaf6c7a --- /dev/null +++ b/src/components/MoreMenu.js @@ -0,0 +1,151 @@ +import { BlurView } from "expo-blur"; +import React from "react"; +import { Platform, Pressable, Text, View } from "react-native"; +import { SheetManager } from "react-native-actions-sheet"; +import Animated, { Easing, FadeIn, FadeOut } from "react-native-reanimated"; +import { arrayRemove, playlistsRef } from "../config/firebase"; +import useMinuit from "react-native-minuit/src/hooks/useMinuit"; +import { Palette } from "../styles"; +import { FONT_FAMILY } from "../styles/Fonts"; + +const MoreMenu = ({ + visible = false, + top = 0, + onClose = () => {}, + inPlaylist = false, + playlistId = null, + projectId = null, + extraItems = [], +}) => { + if (!visible) return null; + const { setTooltip } = useMinuit(); + + const removeFromPlaylist = async () => { + try { + if (inPlaylist && playlistId && projectId) { + await playlistsRef + .doc(playlistId) + .update({ musics: arrayRemove(projectId), updatedAt: new Date() }); + setTooltip({ type: "success", text: "Supprimé de la playlist" }); + } + } catch (e) { + console.log("Remove from playlist error", e?.message); + setTooltip({ type: "error", text: e?.message || "Suppression impossible" }); + } finally { + onClose?.(); + } + }; + + const addToPlaylist = () => { + if (projectId) { + SheetManager.show("Playlist", { payload: { projectId } }); + } else { + SheetManager.show("Playlist"); + } + onClose?.(); + }; + + return ( + + + {inPlaylist && ( + + + + Supprimer de la playlist + + + + )} + + + + + Ajouter à une playlist + + + + + {Array.isArray(extraItems) && + extraItems.map((item, idx) => ( + { + try { + item?.onPress?.(); + } finally { + onClose?.(); + } + }} + > + + + {item?.label || "Action"} + + + + ))} + + + ); +}; + +export default MoreMenu; diff --git a/src/components/modal/PlaylistModal.js b/src/components/modal/PlaylistModal.js index 79902d9..ca970a8 100644 --- a/src/components/modal/PlaylistModal.js +++ b/src/components/modal/PlaylistModal.js @@ -12,6 +12,7 @@ import { SheetManager } from "react-native-actions-sheet"; import SwiperFlatList from "react-native-swiper-flatlist"; import { icons } from "../../assets"; import { arrayUnion, playlistsRef } from "../../config/firebase"; +import useMinuit from "react-native-minuit/src/hooks/useMinuit"; import { useUserData } from "../../providers/UserDataProvider"; import { createPlaylist } from "../../screens/Library/Playlists/playlist"; import { Palette } from "../../styles"; @@ -30,6 +31,7 @@ const PlaylistModal = (props) => { const [isCreating, setIsCreating] = useState(false); const { currentUID, userPlaylists = [] } = useUserData(); const startAtCreate = props?.payload?.startAtCreate || false; + const { setTooltip } = useMinuit(); return ( @@ -104,9 +106,19 @@ const PlaylistModal = (props) => { musics: arrayUnion(projectId), updatedAt: new Date(), }); + const addedPlaylist = (Array.isArray(userPlaylists) + ? userPlaylists + : [] + ).find((p) => p?.id === selectedId); + const name = addedPlaylist?.name || "la playlist"; + setTooltip({ + type: "success", + text: `Ajouté à “${name}”`, + }); } } catch (e) { console.log("Add to playlist error", e?.message); + setTooltip({ type: "error", text: e?.message || "Ajout impossible" }); } finally { SheetManager.hide("Playlist"); } @@ -175,20 +187,28 @@ const PlaylistModal = (props) => { if (!playlist?.trim()?.length || !currentUID) return; try { setIsCreating(true); + const name = playlist.trim(); await createPlaylist({ createdBy: currentUID, - name: playlist.trim(), + name, musics: props?.payload?.projectId ? [props.payload.projectId] : [], createdAt: new Date(), updatedAt: new Date(), }); + setTooltip({ + type: "success", + text: props?.payload?.projectId + ? `Playlist “${name}” créée et musique ajoutée` + : `Playlist “${name}” créée`, + }); setPlaylist(""); SheetManager.hide("Playlist"); scrollRef.current.scrollToIndex({ index: 0, animated: true }); } catch (e) { console.log(e); + setTooltip({ type: "error", text: e?.message || "Création impossible" }); } finally { setIsCreating(false); } diff --git a/src/screens/Library/AllMyLikedMusic.js b/src/screens/Library/AllMyLikedMusic.js index fce7263..afe81f3 100644 --- a/src/screens/Library/AllMyLikedMusic.js +++ b/src/screens/Library/AllMyLikedMusic.js @@ -1,8 +1,6 @@ import { BlurView } from "expo-blur"; import React, { useState } from "react"; -import { Platform, Pressable, Text, View } from "react-native"; -import { SheetManager } from "react-native-actions-sheet"; -import Animated, { Easing, FadeIn, FadeOut } from "react-native-reanimated"; +import { View } from "react-native"; import { background } from "../../assets"; import Page from "../../layouts/Page"; import { Routes } from "../../navigation"; @@ -11,10 +9,12 @@ import { useUser } from "../../providers/UserDataProvider"; import { gutters, Palette } from "../../styles"; import { FONT_FAMILY } from "../../styles/Fonts"; import MusicCard from "./components/MusicCard"; +import MoreMenu from "../../components/MoreMenu"; const AllMyLikedMusic = () => { const [top, setTop] = useState(0); const [showMenu, setShowMenu] = useState(false); + const [selectedProjectId, setSelectedProjectId] = useState(null); const { userLikedProjects: projects } = useUser(); return ( @@ -39,65 +39,19 @@ const AllMyLikedMusic = () => { navigate(Routes.MusicDetails, { projectId: item.id }) } onPressMore={(posTop) => { + setSelectedProjectId(item.id); setTop(posTop); - if (showMenu) { - if (posTop === top) { - setShowMenu(false); - } else { - setShowMenu(false); - setTimeout(() => { - setShowMenu(true); - }, 300); - } - } else { - setShowMenu(true); - } + setShowMenu((prev) => !prev || posTop !== top); }} /> ))} - {showMenu && ( - - { - setShowMenu(false); - SheetManager.show("Delete"); - }} - > - - - Supprimer de la playlist - - - - - )} + setShowMenu(false)} + inPlaylist={false} + projectId={selectedProjectId} + /> diff --git a/src/screens/Library/PlaylistDetails.js b/src/screens/Library/PlaylistDetails.js index 7ac2f0f..b8110c3 100644 --- a/src/screens/Library/PlaylistDetails.js +++ b/src/screens/Library/PlaylistDetails.js @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState } from "react"; import { View } from "react-native"; import Page from "../../layouts/Page"; import { background } from "../../assets"; @@ -8,6 +8,7 @@ import { useDataFromRef } from "react-native-minuit/src/hooks"; import useDataFromArrayId from "react-native-minuit/src/hooks/useDataFromArrayId"; import { playlistsRef, projectsRef } from "../../config/firebase"; import MusicCard from "./components/MusicCard"; +import MoreMenu from "../../components/MoreMenu"; import { navigate } from "../../navigation/NavigationService"; import { Routes } from "../../navigation"; @@ -32,6 +33,10 @@ const PlaylistDetails = () => { refreshArray: [playlistId, playlist?.musics?.length || 0], }); + const [menuTop, setMenuTop] = useState(0); + const [showMenu, setShowMenu] = useState(false); + const [selectedProjectId, setSelectedProjectId] = useState(null); + return ( { projectId={p?.id} likedBy={p?.likedBy || []} onPress={() => navigate(Routes.MusicDetails, { projectId: p.id })} - onPressMore={() => {}} + onPressMore={(posTop) => { + setSelectedProjectId(p.id); + setMenuTop(posTop); + setShowMenu((prev) => !prev || posTop !== menuTop); + }} /> ))} + + setShowMenu(false)} + inPlaylist + playlistId={playlistId} + projectId={selectedProjectId} + /> ); }; export default PlaylistDetails; - diff --git a/src/screens/Library/Research.js b/src/screens/Library/Research.js index 0bb6730..2f4eca3 100644 --- a/src/screens/Library/Research.js +++ b/src/screens/Library/Research.js @@ -17,12 +17,16 @@ import BorderGradient from "../../components/BorderGradient/BorderGradient"; import { BlurView } from "expo-blur"; import ResearchHeader from "./components/ResearchHeader"; import MusicCard from "./components/MusicCard"; +import MoreMenu from "../../components/MoreMenu"; import { size } from "../../styles/Style"; import { navigate } from "../../navigation/NavigationService"; import { Routes } from "../../navigation"; const Research = () => { const [selected, setSelected] = useState(null); + const [menuTop, setMenuTop] = useState(0); + const [showMenu, setShowMenu] = useState(false); + const [selectedProjectId, setSelectedProjectId] = useState(null); const onPressMenu = (item) => { if (selected === item) { @@ -61,6 +65,11 @@ const Research = () => { navigate(Routes.MusicDetails)} + onPressMore={(posTop) => { + setSelectedProjectId(null); + setMenuTop(posTop); + setShowMenu((prev) => !prev || posTop !== menuTop); + }} /> ))} @@ -135,6 +144,13 @@ const Research = () => { )} + setShowMenu(false)} + inPlaylist={false} + projectId={selectedProjectId} + /> diff --git a/src/screens/Library/components/MusicCard.js b/src/screens/Library/components/MusicCard.js index be6f85b..b9b08ac 100644 --- a/src/screens/Library/components/MusicCard.js +++ b/src/screens/Library/components/MusicCard.js @@ -105,7 +105,7 @@ const MusicCard = ({ /> - + diff --git a/src/screens/Library/components/MyMusic.js b/src/screens/Library/components/MyMusic.js index 9ab04d8..5b69d2e 100644 --- a/src/screens/Library/components/MyMusic.js +++ b/src/screens/Library/components/MyMusic.js @@ -1,13 +1,17 @@ -import React from "react"; +import React, { useState } from "react"; import { View } from "react-native"; import { Routes } from "../../../navigation"; import { navigate } from "../../../navigation/NavigationService"; import { useUser } from "../../../providers/UserDataProvider"; import CardContainer from "./CardContainer"; import MusicCard from "./MusicCard"; +import MoreMenu from "../../../components/MoreMenu"; const MyMusic = () => { const { userProjects = [] } = useUser(); + const [menuTop, setMenuTop] = useState(0); + const [showMenu, setShowMenu] = useState(false); + const [selectedProjectId, setSelectedProjectId] = useState(null); const projects = Array.isArray(userProjects) ? userProjects.slice(0, 3) : []; return ( { projectId={p?.id} likedBy={p?.likedBy || []} onPress={() => navigate(Routes.MusicDetails, { projectId: p.id })} - onPressMore={() => console.log("More options for", p.id)} + onPressMore={(posTop) => { + setSelectedProjectId(p.id); + setMenuTop(posTop); + setShowMenu((prev) => !prev || posTop !== menuTop); + }} /> ))} + setShowMenu(false)} + inPlaylist={false} + projectId={selectedProjectId} + /> ); diff --git a/src/screens/Profile/Profile.js b/src/screens/Profile/Profile.js index d83cdb3..e7dff84 100644 --- a/src/screens/Profile/Profile.js +++ b/src/screens/Profile/Profile.js @@ -17,6 +17,7 @@ import { Palette } from "../../styles"; import { FONT_FAMILY } from "../../styles/Fonts"; import BorderGradient from "../../components/BorderGradient/BorderGradient"; import MusicCard from "../Library/components/MusicCard"; +import MoreMenu from "../../components/MoreMenu"; import { useUser } from "../../providers/UserDataProvider"; import { SheetManager } from "react-native-actions-sheet"; import { navigate } from "../../navigation/NavigationService"; @@ -201,96 +202,48 @@ const Profile = () => { } onPressMore={(posTop) => { setSelectedProjectId(item.id); - if (showMenu) { - if (posTop === menuTop) { - setShowMenu(false); - } else { - setShowMenu(false); - setTimeout(() => { - setMenuTop(posTop); - setShowMenu(true); - }, 200); - } - } else { - setMenuTop(posTop); - setShowMenu(true); - } + setMenuTop(posTop); + setShowMenu((prev) => !prev || posTop !== menuTop); }} /> )} /> - {showMenu && ( - - - setShowMenu(false)}> - - Annuler - - - { - setShowMenu(false); - alert( - "Confirmer la suppression", - "Cette action supprimera définitivement ce projet.", - [ - { text: "Annuler", style: "cancel", onPress: () => {} }, - { - text: "Supprimer", - onPress: async () => { - try { - if (!selectedProjectId) return; - await projectsRef.doc(selectedProjectId).delete(); - setTooltip({ type: "success", text: "Projet supprimé" }); - } catch (e) { - setTooltip({ - type: "error", - text: e?.message || "Suppression impossible", - }); - } - }, + setShowMenu(false)} + inPlaylist={false} + projectId={selectedProjectId} + extraItems={[ + { + label: "Supprimer", + onPress: () => + alert( + "Confirmer la suppression", + "Cette action supprimera définitivement ce projet.", + [ + { text: "Annuler", style: "cancel", onPress: () => {} }, + { + text: "Supprimer", + onPress: async () => { + try { + if (!selectedProjectId) return; + await projectsRef.doc(selectedProjectId).delete(); + setTooltip({ type: "success", text: "Projet supprimé" }); + } catch (e) { + setTooltip({ + type: "error", + text: e?.message || "Suppression impossible", + }); + } }, - ], - { cancelable: true }, - ); - }} - > - - Supprimer - - - - - )} + }, + ], + { cancelable: true }, + ), + }, + ]} + /> )}