more menu

This commit is contained in:
2025-10-01 11:16:03 +02:00
parent 75375942b7
commit 08e02a752a
9 changed files with 117 additions and 42 deletions
+28 -7
View File
@@ -12,6 +12,7 @@ import { Portal } from "@gorhom/portal";
const MoreMenu = ({
visible = false,
top = 0,
position = null,
onClose = () => {},
inPlaylist = false,
playlistId = null,
@@ -21,6 +22,17 @@ const MoreMenu = ({
const { setTooltip } = useMinuit();
if (!visible) return null;
const resolvedTop =
typeof position?.top === "number"
? position.top
: typeof top === "number"
? top
: 0;
const resolvedRight =
typeof position?.right === "number" ? Math.max(position.right, 0) : null;
const resolvedLeft =
typeof position?.left === "number" ? Math.max(position.left, 0) : null;
const removeFromPlaylist = async () => {
try {
if (inPlaylist && playlistId && projectId) {
@@ -49,6 +61,21 @@ const MoreMenu = ({
onClose?.();
};
const anchorStyle = {
position: "absolute",
top: resolvedTop,
zIndex: 2,
elevation: 2,
};
if (resolvedRight != null) {
anchorStyle.right = resolvedRight;
} else if (resolvedLeft != null) {
anchorStyle.left = resolvedLeft;
} else {
anchorStyle.right = 0;
}
return (
<Portal>
<View
@@ -77,13 +104,7 @@ const MoreMenu = ({
<Animated.View
entering={FadeIn.duration(300).easing(Easing.ease)}
exiting={FadeOut.duration(300).easing(Easing.ease)}
style={{
position: "absolute",
right: 0,
top,
zIndex: 2,
elevation: 2,
}}
style={anchorStyle}
>
<View style={{ gap: 2 }}>
{inPlaylist && (
+8 -4
View File
@@ -23,7 +23,7 @@ const HomeSave = () => {
[userProjects],
);
const [, setTooltip] = useGlobal("_tooltip");
const [menuTop, setMenuTop] = useState(0);
const [menuPosition, setMenuPosition] = useState(null);
const [showMenu, setShowMenu] = useState(false);
const [menuProjectId, setMenuProjectId] = useState(null);
@@ -83,15 +83,19 @@ const HomeSave = () => {
}}
onPressMore={(posTop) => {
setMenuProjectId(item.id);
setMenuTop(posTop);
setShowMenu((prev) => !prev || posTop !== menuTop);
setMenuPosition(posTop);
setShowMenu(
(prev) =>
!prev || posTop?.top !== (menuPosition?.top ?? null),
);
}}
/>
)}
/>
<MoreMenu
visible={showMenu}
top={menuTop}
top={menuPosition?.top ?? 0}
position={menuPosition}
onClose={() => setShowMenu(false)}
inPlaylist={false}
projectId={menuProjectId}
+8 -4
View File
@@ -37,7 +37,7 @@ export default function AllMyList() {
: [];
})();
const [top, setTop] = useState(0);
const [menuPosition, setMenuPosition] = useState(null);
const [showMenu, setShowMenu] = useState(false);
const [selectedProjectId, setSelectedProjectId] = useState(null);
@@ -70,14 +70,18 @@ export default function AllMyList() {
onPress={() => onPressItem(item)}
onPressMore={(posTop) => {
setSelectedProjectId(item.id);
setTop(posTop);
setShowMenu((prev) => !prev || posTop !== top);
setMenuPosition(posTop);
setShowMenu(
(prev) =>
!prev || posTop?.top !== (menuPosition?.top ?? null),
);
}}
/>
))}
<MoreMenu
visible={showMenu}
top={top}
top={menuPosition?.top ?? 0}
position={menuPosition}
onClose={() => setShowMenu(false)}
inPlaylist={false}
projectId={selectedProjectId}
+8 -4
View File
@@ -37,7 +37,7 @@ const AllMyPlaylist = ({ route }) => {
condition: Array.isArray(playlist?.musics) && playlist.musics.length > 0,
refreshArray: [selectedPlaylistId, playlist?.musics?.length || 0],
});
const [menuTop, setMenuTop] = useState(0);
const [menuPosition, setMenuPosition] = useState(null);
const [showMenu, setShowMenu] = useState(false);
const [selectedProjectId, setSelectedProjectId] = useState(null);
console.log("musics are : ", musics);
@@ -174,15 +174,19 @@ const AllMyPlaylist = ({ route }) => {
}
onPressMore={(posTop) => {
setSelectedProjectId(p.id);
setMenuTop(posTop);
setShowMenu((prev) => !prev || posTop !== menuTop);
setMenuPosition(posTop);
setShowMenu(
(prev) =>
!prev || posTop?.top !== (menuPosition?.top ?? null),
);
}}
/>
))}
<MoreMenu
visible={showMenu}
top={menuTop}
top={menuPosition?.top ?? 0}
position={menuPosition}
onClose={() => setShowMenu(false)}
inPlaylist
playlistId={selectedPlaylistId}
+8 -4
View File
@@ -36,7 +36,7 @@ const PlaylistDetails = () => {
refreshArray: [playlistId, playlist?.musics?.length || 0],
});
const [menuTop, setMenuTop] = useState(0);
const [menuPosition, setMenuPosition] = useState(null);
const [showMenu, setShowMenu] = useState(false);
const [selectedProjectId, setSelectedProjectId] = useState(null);
@@ -90,15 +90,19 @@ const PlaylistDetails = () => {
onPress={() => navigate(Routes.MusicDetails, { projectId: p.id })}
onPressMore={(posTop) => {
setSelectedProjectId(p.id);
setMenuTop(posTop);
setShowMenu((prev) => !prev || posTop !== menuTop);
setMenuPosition(posTop);
setShowMenu(
(prev) =>
!prev || posTop?.top !== (menuPosition?.top ?? null),
);
}}
/>
))}
<MoreMenu
visible={showMenu}
top={menuTop}
top={menuPosition?.top ?? 0}
position={menuPosition}
onClose={() => setShowMenu(false)}
inPlaylist
playlistId={playlistId}
+7 -4
View File
@@ -194,7 +194,7 @@ const Research = () => {
}
}
}, [filteredUsers.length, usersLoading, usersQueryRef, autoLoads]);
const [menuTop, setMenuTop] = useState(0);
const [menuPosition, setMenuPosition] = useState(null);
const [showMenu, setShowMenu] = useState(false);
const [selectedProjectId, setSelectedProjectId] = useState(null);
@@ -264,9 +264,11 @@ const Research = () => {
}
onPressMore={(posTop) => {
setSelectedProjectId(p.id);
setMenuTop(posTop);
setMenuPosition(posTop);
setShowMenu(
(prev) => !prev || posTop !== menuTop,
(prev) =>
!prev ||
posTop?.top !== (menuPosition?.top ?? null),
);
}}
/>
@@ -391,7 +393,8 @@ const Research = () => {
)}
<MoreMenu
visible={showMenu}
top={menuTop}
top={menuPosition?.top ?? 0}
position={menuPosition}
onClose={() => setShowMenu(false)}
inPlaylist={false}
projectId={selectedProjectId}
+34 -7
View File
@@ -6,6 +6,7 @@ import {
Text,
View,
Image as RNImage,
Dimensions,
} from "react-native";
import { Image as ExpoImage } from "expo-image";
import { useGlobal } from "reactn";
@@ -28,13 +29,20 @@ const MusicCard = ({
const [currentUID] = useGlobal("currentUID");
const [selected, setSelected] = useState(false);
const [layout, setLayout] = useState(null);
const [menuPos, setMenuPos] = useState(0);
const [menuPos, setMenuPos] = useState({
top: 0,
right: 0,
left: 0,
width: 0,
height: 0,
});
const cardRef = useRef(null);
const moreButtonRef = useRef(null);
useEffect(() => {
if (layout) {
const top = layout?.y + 45;
setMenuPos(top);
const top = (layout?.y || 0) + 45;
setMenuPos((prev) => ({ ...prev, top }));
}
}, [layout]);
@@ -59,13 +67,32 @@ const MusicCard = ({
};
const onPressMenu = () => {
const computeAnchor = (x = 0, y = 0, width = 0, height = 0) => {
const windowWidth = Dimensions.get("window").width || 0;
const top = (y || 0) + (height || 0) + 8;
const right = Math.max(0, windowWidth - ((x || 0) + (width || 0)));
const left = Math.max(0, x || 0);
const anchor = { top, right, left, width, height };
setMenuPos(anchor);
onPressMore?.(anchor);
};
if (moreButtonRef?.current?.measureInWindow) {
try {
moreButtonRef.current.measureInWindow((x, y, width, height) => {
computeAnchor(x, y, width, height);
});
return;
} catch (e) {
// fallback to card measurement below
}
}
// Prefer absolute screen position when available (Portal rendering)
if (cardRef?.current?.measureInWindow) {
try {
cardRef.current.measureInWindow((x, y, width, height) => {
const top = (y || 0) + 45;
setMenuPos(top);
onPressMore?.(top);
computeAnchor(x, y, width, height);
});
return;
} catch (e) {
@@ -132,7 +159,7 @@ const MusicCard = ({
resizeMode="contain"
/>
</Pressable>
<Pressable onPress={onPressMenu}>
<Pressable ref={moreButtonRef} onPress={onPressMenu}>
<RNImage source={icons.more} style={size({ size: 24 })} />
</Pressable>
</View>
+8 -4
View File
@@ -9,7 +9,7 @@ import MoreMenu from "../../../components/MoreMenu";
const MyMusic = () => {
const { userProjects = [] } = useUser();
const [menuTop, setMenuTop] = useState(0);
const [menuPosition, setMenuPosition] = useState(null);
const [showMenu, setShowMenu] = useState(false);
const [selectedProjectId, setSelectedProjectId] = useState(null);
const projects = Array.isArray(userProjects) ? userProjects.slice(0, 3) : [];
@@ -37,14 +37,18 @@ const MyMusic = () => {
onPress={() => navigate(Routes.MusicDetails, { projectId: p.id })}
onPressMore={(posTop) => {
setSelectedProjectId(p.id);
setMenuTop(posTop);
setShowMenu((prev) => !prev || posTop !== menuTop);
setMenuPosition(posTop);
setShowMenu(
(prev) =>
!prev || posTop?.top !== (menuPosition?.top ?? null),
);
}}
/>
))}
<MoreMenu
visible={showMenu}
top={menuTop}
top={menuPosition?.top ?? 0}
position={menuPosition}
onClose={() => setShowMenu(false)}
inPlaylist={false}
projectId={selectedProjectId}
+8 -4
View File
@@ -49,7 +49,7 @@ const Profile = () => {
const [isFollowing, setIsFollowing] = useState(false);
const [followers, setFollowers] = useState(0);
const [following, setFollowing] = useState(0);
const [menuTop, setMenuTop] = useState(0);
const [menuPosition, setMenuPosition] = useState(null);
const [showMenu, setShowMenu] = useState(false);
const [selectedProjectId, setSelectedProjectId] = useState(null);
const onPressMenu = (item) => {
@@ -137,8 +137,11 @@ const Profile = () => {
}
onPressMore={(posTop) => {
setSelectedProjectId(item.id);
setMenuTop(posTop);
setShowMenu((prev) => !prev || posTop !== menuTop);
setMenuPosition(posTop);
setShowMenu(
(prev) =>
!prev || posTop?.top !== (menuPosition?.top ?? null),
);
}}
/>
)}
@@ -148,7 +151,8 @@ const Profile = () => {
)}
<MoreMenu
visible={showMenu}
top={menuTop}
top={menuPosition?.top ?? 0}
position={menuPosition}
onClose={() => setShowMenu(false)}
inPlaylist={false}
projectId={selectedProjectId}