feat: play from dropdown

This commit is contained in:
2025-12-03 16:39:26 +01:00
parent 13f34d3ef1
commit 74e02fef79
3 changed files with 169 additions and 130 deletions
+122 -107
View File
@@ -1,8 +1,10 @@
import { BlurView } from "expo-blur";
import { Portal } from "@gorhom/portal";
import React, {
forwardRef,
useCallback,
useEffect,
useImperativeHandle,
useMemo,
useRef,
useState,
@@ -78,21 +80,25 @@ const defaultFormatDate = (timestamp) => {
}
};
const ProjectDropDown = ({
style,
projects = [],
selectedProject,
onSelectProject,
onModifyProject,
onCreateProject,
formatDate = defaultFormatDate,
allowEmptySelection = false,
}) => {
const [isOpen, setIsOpen] = useState(false);
const [triggerLayout, setTriggerLayout] = useState(null);
const [triggerWindowLayout, setTriggerWindowLayout] = useState(null);
const triggerRef = useRef(null);
const dropdownAnimation = useRef(new Animated.Value(0)).current;
const ProjectDropDown = forwardRef(
(
{
style,
projects = [],
selectedProject,
onSelectProject,
onModifyProject,
onCreateProject,
formatDate = defaultFormatDate,
allowEmptySelection = false,
},
ref
) => {
const [isOpen, setIsOpen] = useState(false);
const [triggerLayout, setTriggerLayout] = useState(null);
const [triggerWindowLayout, setTriggerWindowLayout] = useState(null);
const triggerRef = useRef(null);
const dropdownAnimation = useRef(new Animated.Value(0)).current;
const measureTriggerPosition = useCallback(() => {
if (triggerRef.current?.measureInWindow) {
@@ -133,39 +139,47 @@ const ProjectDropDown = ({
})
: normalizedProjects;
const toggleDropdown = useCallback(() => {
if (isDisabled) {
return;
}
if (!isOpen) {
measureTriggerPosition();
}
setIsOpen((prev) => !prev);
}, [isDisabled, isOpen, measureTriggerPosition]);
const toggleDropdown = useCallback(() => {
if (isDisabled) {
return;
}
if (!isOpen) {
measureTriggerPosition();
}
setIsOpen((prev) => !prev);
}, [isDisabled, isOpen, measureTriggerPosition]);
const closeDropdown = useCallback(() => setIsOpen(false), []);
const closeDropdown = useCallback(() => setIsOpen(false), []);
const handleSelect = useCallback(
(project) => {
if (!project?.id) return;
onSelectProject?.(project);
useImperativeHandle(
ref,
() => ({
close: closeDropdown,
}),
[closeDropdown]
);
const handleSelect = useCallback(
(project) => {
if (!project?.id) return;
onSelectProject?.(project);
closeDropdown();
},
[closeDropdown, onSelectProject]
);
const handleModify = useCallback(
(project, anchor) => {
if (!project?.id) return;
onModifyProject?.(project, anchor);
},
[onModifyProject]
);
const handleCreate = useCallback(() => {
onCreateProject?.();
closeDropdown();
},
[closeDropdown, onSelectProject]
);
const handleModify = useCallback(
(project, anchor) => {
if (!project?.id) return;
onModifyProject?.(project, anchor);
},
[onModifyProject]
);
const handleCreate = useCallback(() => {
onCreateProject?.();
closeDropdown();
}, [closeDropdown, onCreateProject]);
}, [closeDropdown, onCreateProject]);
const dropdownWidth = useMemo(
() => triggerLayout?.width || 0,
@@ -286,74 +300,75 @@ const ProjectDropDown = ({
</ThemedBlurView>
);
return (
<View style={[styles.container, style]}>
<View
ref={triggerRef}
style={styles.triggerWrapper}
onLayout={(event) => {
setTriggerLayout(event.nativeEvent.layout);
measureTriggerPosition();
}}
>
<Animated.View
pointerEvents={isOpen ? "none" : "auto"}
style={[
styles.dropdownTriggerContainer,
{
opacity: triggerOpacity,
transform: [{ translateY: triggerTranslateY }],
},
]}
return (
<View style={[styles.container, style]}>
<View
ref={triggerRef}
style={styles.triggerWrapper}
onLayout={(event) => {
setTriggerLayout(event.nativeEvent.layout);
measureTriggerPosition();
}}
>
<ThemedBlurView
<Animated.View
pointerEvents={isOpen ? "none" : "auto"}
style={[
styles.dropdownBlur,
isDisabled && styles.dropdownBlurDisabled,
styles.dropdownTriggerContainer,
{
opacity: triggerOpacity,
transform: [{ translateY: triggerTranslateY }],
},
]}
>
<ProjectRow
isTitle={true}
isOpen={isOpen}
project={currentProject}
formatDate={formatDate}
onSelect={toggleDropdown}
/>
</ThemedBlurView>
</Animated.View>
<ThemedBlurView
style={[
styles.dropdownBlur,
isDisabled && styles.dropdownBlurDisabled,
]}
>
<ProjectRow
isTitle={true}
isOpen={isOpen}
project={currentProject}
formatDate={formatDate}
onSelect={toggleDropdown}
/>
</ThemedBlurView>
</Animated.View>
{isOpen && triggerWindowLayout ? (
<Portal>
<View style={styles.portalContainer}>
<Pressable style={styles.backdrop} onPress={closeDropdown}>
<ThemedBlurView
pointerEvents="none"
style={styles.backdropBlur}
/>
</Pressable>
<Animated.View
pointerEvents="auto"
style={[
styles.dropdownOverlayContainer,
overlayPositionStyle,
{
opacity: dropdownAnimation,
transform: [
{ translateY: overlayTranslateY },
{ scale: overlayScale },
],
},
]}
>
{dropdownContent}
</Animated.View>
</View>
</Portal>
) : null}
{isOpen && triggerWindowLayout ? (
<Portal>
<View style={styles.portalContainer}>
<Pressable style={styles.backdrop} onPress={closeDropdown}>
<ThemedBlurView
pointerEvents="none"
style={styles.backdropBlur}
/>
</Pressable>
<Animated.View
pointerEvents="auto"
style={[
styles.dropdownOverlayContainer,
overlayPositionStyle,
{
opacity: dropdownAnimation,
transform: [
{ translateY: overlayTranslateY },
{ scale: overlayScale },
],
},
]}
>
{dropdownContent}
</Animated.View>
</View>
</Portal>
) : null}
</View>
</View>
</View>
);
};
);
}
);
export default ProjectDropDown;