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