| 1 | import { MenuView } from "@react-native-menu/menu"; |
| 2 | import type { ReactElement } from "react"; |
| 3 | import { Platform, View, type PressableProps, type StyleProp, type ViewStyle } from "react-native"; |
| 4 | |
| 5 | import type { useMediaActions } from "../state/mediaActions"; |
| 6 | import { SymbolView } from "./AppSymbol"; |
| 7 | import { ControlPillMenu } from "./ControlPill"; |
| 8 | |
| 9 | export function MediaActionsMenu(props: { |
| 10 | readonly media: ReturnType<typeof useMediaActions>; |
| 11 | readonly inModal?: boolean; |
| 12 | readonly children?: ReactElement<PressableProps>; |
| 13 | readonly style?: StyleProp<ViewStyle>; |
| 14 | }) { |
| 15 | if (props.media.actions.length === 0) return props.children ?? null; |
| 16 | // Android's normal anchored menu lives in the app-root portal, behind native modals. |
| 17 | const nativeAndroidMenu = props.inModal && Platform.OS === "android"; |
| 18 | const Menu = nativeAndroidMenu ? MenuView : ControlPillMenu; |
| 19 | return ( |
| 20 | <Menu |
| 21 | title={props.media.title} |
| 22 | style={props.style} |
| 23 | shouldOpenOnLongPress={props.children !== undefined} |
| 24 | actions={props.media.actions.map(({ id, title, disabled }) => ({ |
| 25 | id, |
| 26 | title, |
| 27 | attributes: { disabled: disabled ?? false }, |
| 28 | }))} |
| 29 | onPressAction={({ nativeEvent }) => { |
| 30 | props.media.actions.find(({ id }) => id === nativeEvent.event)?.run(); |
| 31 | }} |
| 32 | > |
| 33 | {props.children ?? ( |
| 34 | <View |
| 35 | accessible |
| 36 | accessibilityRole="button" |
| 37 | accessibilityLabel="Media actions" |
| 38 | className="min-h-11 min-w-11 items-center justify-center rounded-md bg-black/60" |
| 39 | > |
| 40 | <SymbolView name="ellipsis" size={20} tintColor="#ffffff" type="monochrome" /> |
| 41 | </View> |
| 42 | )} |
| 43 | </Menu> |
| 44 | ); |
| 45 | } |