feat: next music from playlist
This commit is contained in:
@@ -64,6 +64,8 @@ const noop = () => {};
|
|||||||
const DEFAULT_CONTEXT = {
|
const DEFAULT_CONTEXT = {
|
||||||
currentTrack: null,
|
currentTrack: null,
|
||||||
queue: [],
|
queue: [],
|
||||||
|
queueInfo: null,
|
||||||
|
queueIndex: -1,
|
||||||
status: "idle",
|
status: "idle",
|
||||||
isPlaying: false,
|
isPlaying: false,
|
||||||
isBuffering: false,
|
isBuffering: false,
|
||||||
@@ -209,7 +211,12 @@ const normalizeTrack = (trackInput = {}, options = {}) => {
|
|||||||
const PlayerProvider = ({ children }) => {
|
const PlayerProvider = ({ children }) => {
|
||||||
const [activeRouteName] = useGlobal("activeRouteName");
|
const [activeRouteName] = useGlobal("activeRouteName");
|
||||||
const [currentTrack, setCurrentTrack] = useState(null);
|
const [currentTrack, setCurrentTrack] = useState(null);
|
||||||
const [queue, setQueue] = useState([]);
|
const queueRef = useRef([]);
|
||||||
|
const queueInfoRef = useRef({ id: null, type: null, name: null });
|
||||||
|
const queueIndexRef = useRef(-1);
|
||||||
|
const [queue, setQueueState] = useState([]);
|
||||||
|
const [queueInfo, setQueueInfoState] = useState(queueInfoRef.current);
|
||||||
|
const [queueIndex, setQueueIndexState] = useState(queueIndexRef.current);
|
||||||
const [playback, setPlayback] = useState({
|
const [playback, setPlayback] = useState({
|
||||||
status: "idle",
|
status: "idle",
|
||||||
isPlaying: false,
|
isPlaying: false,
|
||||||
@@ -222,6 +229,127 @@ const PlayerProvider = ({ children }) => {
|
|||||||
|
|
||||||
const autoPlayRef = useRef(false);
|
const autoPlayRef = useRef(false);
|
||||||
const pendingSeekValueRef = useRef(null);
|
const pendingSeekValueRef = useRef(null);
|
||||||
|
const didJustFinishRef = useRef(false);
|
||||||
|
|
||||||
|
const setQueueIndexValue = useCallback((index = -1) => {
|
||||||
|
const list = queueRef.current;
|
||||||
|
const hasItems = Array.isArray(list) && list.length > 0;
|
||||||
|
let target = Number.isInteger(index) ? index : queueIndexRef.current;
|
||||||
|
if (!hasItems) {
|
||||||
|
target = -1;
|
||||||
|
} else {
|
||||||
|
target = Math.min(Math.max(target, -1), list.length - 1);
|
||||||
|
}
|
||||||
|
if (queueIndexRef.current === target) return;
|
||||||
|
queueIndexRef.current = target;
|
||||||
|
setQueueIndexState(target);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const setQueueInfoValue = useCallback((info) => {
|
||||||
|
const next = {
|
||||||
|
id: info?.id ?? null,
|
||||||
|
type: info?.type ?? null,
|
||||||
|
name: info?.name ?? null,
|
||||||
|
};
|
||||||
|
const prev = queueInfoRef.current;
|
||||||
|
if (
|
||||||
|
prev.id === next.id &&
|
||||||
|
prev.type === next.type &&
|
||||||
|
prev.name === next.name
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queueInfoRef.current = next;
|
||||||
|
setQueueInfoState(next);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const updateQueue = useCallback(
|
||||||
|
(items = [], options = {}) => {
|
||||||
|
const normalized = Array.isArray(items)
|
||||||
|
? items
|
||||||
|
.map((item) => {
|
||||||
|
if (!item) return null;
|
||||||
|
if (typeof item === "object") {
|
||||||
|
const { metadata, context, ...rest } = item;
|
||||||
|
const safeMetadata =
|
||||||
|
metadata && typeof metadata === "object"
|
||||||
|
? { ...metadata }
|
||||||
|
: undefined;
|
||||||
|
if (safeMetadata) {
|
||||||
|
delete safeMetadata.queue;
|
||||||
|
}
|
||||||
|
const safeContext =
|
||||||
|
context && typeof context === "object"
|
||||||
|
? { ...context }
|
||||||
|
: undefined;
|
||||||
|
if (safeContext) {
|
||||||
|
delete safeContext.queue;
|
||||||
|
}
|
||||||
|
return normalizeTrack(
|
||||||
|
{
|
||||||
|
...rest,
|
||||||
|
...(safeMetadata ? { metadata: safeMetadata } : {}),
|
||||||
|
...(safeContext ? { context: safeContext } : {}),
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return normalizeTrack(item, {});
|
||||||
|
})
|
||||||
|
.filter((track) => !!track?.source)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
queueRef.current = normalized;
|
||||||
|
setQueueState(normalized);
|
||||||
|
|
||||||
|
const info = {
|
||||||
|
id: options.id ?? options.queueId ?? null,
|
||||||
|
type: options.type ?? options.queueType ?? null,
|
||||||
|
name: options.name ?? options.queueName ?? null,
|
||||||
|
};
|
||||||
|
setQueueInfoValue(info);
|
||||||
|
|
||||||
|
const currentTrackId =
|
||||||
|
options.currentTrackId && typeof options.currentTrackId === "string"
|
||||||
|
? options.currentTrackId
|
||||||
|
: null;
|
||||||
|
const indexCandidate =
|
||||||
|
typeof options.index === "number"
|
||||||
|
? options.index
|
||||||
|
: typeof options.queueIndex === "number"
|
||||||
|
? options.queueIndex
|
||||||
|
: currentTrackId
|
||||||
|
? normalized.findIndex((track) => track.id === currentTrackId)
|
||||||
|
: queueIndexRef.current;
|
||||||
|
setQueueIndexValue(indexCandidate);
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
},
|
||||||
|
[setQueueIndexValue, setQueueInfoValue]
|
||||||
|
);
|
||||||
|
|
||||||
|
const setQueue = useCallback(
|
||||||
|
(itemsOrConfig, maybeOptions = {}) => {
|
||||||
|
if (typeof itemsOrConfig === "function") {
|
||||||
|
const result = itemsOrConfig([...(queueRef.current || [])]);
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
updateQueue(result, maybeOptions);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Array.isArray(itemsOrConfig)) {
|
||||||
|
updateQueue(itemsOrConfig, maybeOptions);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (itemsOrConfig && typeof itemsOrConfig === "object") {
|
||||||
|
const { items = [], ...rest } = itemsOrConfig;
|
||||||
|
updateQueue(items, { ...rest, ...maybeOptions });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateQueue([], {});
|
||||||
|
},
|
||||||
|
[updateQueue]
|
||||||
|
);
|
||||||
|
|
||||||
const source = useMemo(() => {
|
const source = useMemo(() => {
|
||||||
if (!currentTrack?.source) return null;
|
if (!currentTrack?.source) return null;
|
||||||
@@ -328,6 +456,19 @@ const PlayerProvider = ({ children }) => {
|
|||||||
|
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
|
if (Array.isArray(options.queue)) {
|
||||||
|
updateQueue(options.queue, {
|
||||||
|
id: options.queueId,
|
||||||
|
type: options.queueType,
|
||||||
|
name: options.queueName,
|
||||||
|
queueIndex:
|
||||||
|
typeof options.queueIndex === "number"
|
||||||
|
? options.queueIndex
|
||||||
|
: undefined,
|
||||||
|
currentTrackId: normalized.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (sameTrack) {
|
if (sameTrack) {
|
||||||
setCurrentTrack((prev) => ({ ...prev, ...normalized }));
|
setCurrentTrack((prev) => ({ ...prev, ...normalized }));
|
||||||
try {
|
try {
|
||||||
@@ -371,7 +512,7 @@ const PlayerProvider = ({ children }) => {
|
|||||||
}));
|
}));
|
||||||
setCurrentTrack(normalized);
|
setCurrentTrack(normalized);
|
||||||
},
|
},
|
||||||
[currentTrack?.id, player, toPlayerSeekValue]
|
[currentTrack?.id, player, toPlayerSeekValue, updateQueue]
|
||||||
);
|
);
|
||||||
|
|
||||||
const resume = useCallback(async () => {
|
const resume = useCallback(async () => {
|
||||||
@@ -474,10 +615,65 @@ const PlayerProvider = ({ children }) => {
|
|||||||
setIsLooping((prev) => !prev);
|
setIsLooping((prev) => !prev);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!currentTrack?.id) {
|
||||||
|
if (queueIndexRef.current !== -1) {
|
||||||
|
setQueueIndexValue(-1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const idx = queueRef.current.findIndex((item) => item.id === currentTrack.id);
|
||||||
|
if (idx !== queueIndexRef.current) {
|
||||||
|
setQueueIndexValue(idx);
|
||||||
|
}
|
||||||
|
}, [currentTrack?.id, setQueueIndexValue]);
|
||||||
|
|
||||||
|
const handleTrackDidFinish = useCallback(() => {
|
||||||
|
if (isLooping) return;
|
||||||
|
const items = queueRef.current;
|
||||||
|
if (!Array.isArray(items) || items.length === 0) return;
|
||||||
|
|
||||||
|
let idx = queueIndexRef.current;
|
||||||
|
const currentId = currentTrack?.id ?? null;
|
||||||
|
if ((idx == null || idx < 0) && currentId) {
|
||||||
|
idx = items.findIndex((item) => item.id === currentId);
|
||||||
|
}
|
||||||
|
if (idx == null || idx < 0) return;
|
||||||
|
const nextIdx = idx + 1;
|
||||||
|
if (nextIdx >= items.length) return;
|
||||||
|
|
||||||
|
const nextTrack = items[nextIdx];
|
||||||
|
if (!nextTrack) return;
|
||||||
|
|
||||||
|
play(nextTrack, {
|
||||||
|
autoPlay: true,
|
||||||
|
startPositionMs: 0,
|
||||||
|
queueId: queueInfoRef.current.id,
|
||||||
|
queueType: queueInfoRef.current.type,
|
||||||
|
queueName: queueInfoRef.current.name,
|
||||||
|
}).catch((err) => {
|
||||||
|
setError(err);
|
||||||
|
});
|
||||||
|
}, [currentTrack?.id, isLooping, play]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const finished = !!status?.didJustFinish;
|
||||||
|
if (finished) {
|
||||||
|
if (!didJustFinishRef.current) {
|
||||||
|
didJustFinishRef.current = true;
|
||||||
|
handleTrackDidFinish();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
didJustFinishRef.current = false;
|
||||||
|
}
|
||||||
|
}, [status?.didJustFinish, handleTrackDidFinish]);
|
||||||
|
|
||||||
const contextValue = useMemo(
|
const contextValue = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
currentTrack,
|
currentTrack,
|
||||||
queue,
|
queue,
|
||||||
|
queueInfo,
|
||||||
|
queueIndex,
|
||||||
status: playback.status,
|
status: playback.status,
|
||||||
isPlaying: playback.isPlaying,
|
isPlaying: playback.isPlaying,
|
||||||
isBuffering: playback.isBuffering,
|
isBuffering: playback.isBuffering,
|
||||||
@@ -508,6 +704,8 @@ const PlayerProvider = ({ children }) => {
|
|||||||
playback.positionMs,
|
playback.positionMs,
|
||||||
playback.status,
|
playback.status,
|
||||||
queue,
|
queue,
|
||||||
|
queueInfo,
|
||||||
|
queueIndex,
|
||||||
resume,
|
resume,
|
||||||
seekBy,
|
seekBy,
|
||||||
seekTo,
|
seekTo,
|
||||||
@@ -516,6 +714,7 @@ const PlayerProvider = ({ children }) => {
|
|||||||
isLooping,
|
isLooping,
|
||||||
setLooping,
|
setLooping,
|
||||||
toggleLooping,
|
toggleLooping,
|
||||||
|
setQueue,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { BlurView } from "expo-blur";
|
import { BlurView } from "expo-blur";
|
||||||
import React, { useState } from "react";
|
import React, { useCallback, useMemo, useState } from "react";
|
||||||
import { Image, Pressable, Text, View } from "react-native";
|
import { Image, Pressable, Text, View } from "react-native";
|
||||||
import { SheetManager } from "react-native-actions-sheet";
|
import { SheetManager } from "react-native-actions-sheet";
|
||||||
import { useGlobal } from "reactn";
|
import { useGlobal } from "reactn";
|
||||||
@@ -9,6 +9,7 @@ import { playlistsRef, projectsRef } from "../../config/firebase";
|
|||||||
import useDataFromArrayDocId from "../../hooks/useDataFromArrayId";
|
import useDataFromArrayDocId from "../../hooks/useDataFromArrayId";
|
||||||
import useDataFromRef from "../../hooks/useDataFromRef";
|
import useDataFromRef from "../../hooks/useDataFromRef";
|
||||||
import useNavigateToMusicDetails from "../../hooks/useNavigateToMusicDetails";
|
import useNavigateToMusicDetails from "../../hooks/useNavigateToMusicDetails";
|
||||||
|
import usePlayer from "../../hooks/usePlayer";
|
||||||
import Page from "../../layouts/Page";
|
import Page from "../../layouts/Page";
|
||||||
import { useUser } from "../../providers/UserDataProvider";
|
import { useUser } from "../../providers/UserDataProvider";
|
||||||
import { gutters, Palette, Style } from "../../styles";
|
import { gutters, Palette, Style } from "../../styles";
|
||||||
@@ -42,6 +43,74 @@ const AllMyPlaylist = ({ route }) => {
|
|||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
const [selectedProjectId, setSelectedProjectId] = useState(null);
|
const [selectedProjectId, setSelectedProjectId] = useState(null);
|
||||||
const navigateToMusicDetails = useNavigateToMusicDetails();
|
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
|
// delete playlist
|
||||||
const confirmDelete = () => {
|
const confirmDelete = () => {
|
||||||
@@ -209,13 +278,7 @@ const AllMyPlaylist = ({ route }) => {
|
|||||||
imageUri={p?.coverUrl || null}
|
imageUri={p?.coverUrl || null}
|
||||||
projectId={p?.id}
|
projectId={p?.id}
|
||||||
likedBy={p?.likedBy || []}
|
likedBy={p?.likedBy || []}
|
||||||
onPress={() =>
|
onPress={() => handlePlayFromPlaylist(p)}
|
||||||
navigateToMusicDetails({
|
|
||||||
projectId: p.id,
|
|
||||||
songUrl: p?.songUrl,
|
|
||||||
project: p,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
onPressMore={(posTop) => {
|
onPressMore={(posTop) => {
|
||||||
setSelectedProjectId(p.id);
|
setSelectedProjectId(p.id);
|
||||||
setMenuPosition(posTop);
|
setMenuPosition(posTop);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useRoute } from "@react-navigation/native";
|
import { useRoute } from "@react-navigation/native";
|
||||||
import React, { useState } from "react";
|
import React, { useCallback, useMemo, useState } from "react";
|
||||||
import { Image, Pressable, View } from "react-native";
|
import { Image, Pressable, View } from "react-native";
|
||||||
import { SheetManager } from "react-native-actions-sheet";
|
import { SheetManager } from "react-native-actions-sheet";
|
||||||
import { useDataFromRef } from "react-native-minuit/src/hooks";
|
import { useDataFromRef } from "react-native-minuit/src/hooks";
|
||||||
@@ -9,6 +9,7 @@ import { background, icons } from "../../assets";
|
|||||||
import MoreMenu from "../../components/MoreMenu";
|
import MoreMenu from "../../components/MoreMenu";
|
||||||
import { playlistsRef, projectsRef } from "../../config/firebase";
|
import { playlistsRef, projectsRef } from "../../config/firebase";
|
||||||
import useNavigateToMusicDetails from "../../hooks/useNavigateToMusicDetails";
|
import useNavigateToMusicDetails from "../../hooks/useNavigateToMusicDetails";
|
||||||
|
import usePlayer from "../../hooks/usePlayer";
|
||||||
import Page from "../../layouts/Page";
|
import Page from "../../layouts/Page";
|
||||||
import { goBack } from "../../navigation/NavigationService";
|
import { goBack } from "../../navigation/NavigationService";
|
||||||
import { gutters } from "../../styles";
|
import { gutters } from "../../styles";
|
||||||
@@ -40,6 +41,74 @@ const PlaylistDetails = () => {
|
|||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
const [selectedProjectId, setSelectedProjectId] = useState(null);
|
const [selectedProjectId, setSelectedProjectId] = useState(null);
|
||||||
const navigateToMusicDetails = useNavigateToMusicDetails();
|
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: playlistId ?? null,
|
||||||
|
playlistName: playlist?.name ?? null,
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
projectId,
|
||||||
|
playlistId: playlistId ?? null,
|
||||||
|
playlistName: playlist?.name ?? null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
}, [musics, playlist?.name, playlistId]);
|
||||||
|
|
||||||
|
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: playlistId,
|
||||||
|
type: "playlist",
|
||||||
|
name: playlist?.name ?? null,
|
||||||
|
index: queueIndex,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
navigateToMusicDetails({
|
||||||
|
projectId: project.id,
|
||||||
|
songUrl: project?.songUrl,
|
||||||
|
project,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[
|
||||||
|
navigateToMusicDetails,
|
||||||
|
playlist?.name,
|
||||||
|
playlistId,
|
||||||
|
playlistQueueItems,
|
||||||
|
setQueue,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
const confirmDelete = () => {
|
const confirmDelete = () => {
|
||||||
SheetManager.show("Delete", {
|
SheetManager.show("Delete", {
|
||||||
@@ -88,13 +157,7 @@ const PlaylistDetails = () => {
|
|||||||
imageUri={p?.coverUrl || null}
|
imageUri={p?.coverUrl || null}
|
||||||
projectId={p?.id}
|
projectId={p?.id}
|
||||||
likedBy={p?.likedBy || []}
|
likedBy={p?.likedBy || []}
|
||||||
onPress={() =>
|
onPress={() => handlePlayFromPlaylist(p)}
|
||||||
navigateToMusicDetails({
|
|
||||||
projectId: p.id,
|
|
||||||
songUrl: p?.songUrl,
|
|
||||||
project: p,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
onPressMore={(posTop) => {
|
onPressMore={(posTop) => {
|
||||||
setSelectedProjectId(p.id);
|
setSelectedProjectId(p.id);
|
||||||
setMenuPosition(posTop);
|
setMenuPosition(posTop);
|
||||||
|
|||||||
Reference in New Issue
Block a user