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 },
+ ),
+ },
+ ]}
+ />
)}