import PressableOpacity from '@app/components/PressableOpacity' import { useStar } from '@app/hooks/query' import { StarrableItemType, Song, Artist, Album } from '@app/models/library' import colors from '@app/styles/colors' import font from '@app/styles/font' import { NavigationProp, useNavigation } from '@react-navigation/native' import { ReactComponentLike } from 'prop-types' import React from 'react' import { useTranslation } from 'react-i18next' import { ScrollView, StyleProp, StyleSheet, Text, View, ViewStyle } from 'react-native' import { Menu, MenuOption, MenuOptions, MenuTrigger, renderers } from 'react-native-popup-menu' import IconFA from 'react-native-vector-icons/FontAwesome' import IconFA5 from 'react-native-vector-icons/FontAwesome5' import CoverArt from './CoverArt' import { Star } from './Star' import { withSuspenseMemo } from './withSuspense' const { SlideInMenu } = renderers type ContextMenuProps = { menuStyle?: StyleProp triggerWrapperStyle?: StyleProp triggerOuterWrapperStyle?: StyleProp triggerTouchableStyle?: StyleProp onPress?: () => any triggerOnLongPress?: boolean disabled?: boolean } type InternalContextMenuProps = ContextMenuProps & { menuHeader: React.ReactNode menuOptions: React.ReactNode } const ContextMenu: React.FC = ({ menuStyle, triggerWrapperStyle, triggerOuterWrapperStyle, triggerTouchableStyle, onPress, menuHeader, menuOptions, children, triggerOnLongPress, disabled, }) => { menuStyle = menuStyle || { flex: 1 } triggerWrapperStyle = triggerWrapperStyle || { flex: 1 } triggerOuterWrapperStyle = triggerOuterWrapperStyle || { flex: 1 } triggerTouchableStyle = triggerTouchableStyle || { flex: 1 } return ( {children} ( {menuHeader} {options} )}> {menuOptions} ) } type ContextMenuOptionProps = { onSelect?: () => any } const ContextMenuOption: React.FC = ({ onSelect, children }) => ( {children} ) type ContextMenuIconTextOptionProps = ContextMenuOptionProps & { IconComponent?: ReactComponentLike IconComponentRaw?: React.ReactNode name?: string size?: number color?: string text: string } const ContextMenuIconTextOption = React.memo( ({ onSelect, IconComponent, IconComponentRaw, name, color, size, text }) => { let Icon: React.ReactNode if (IconComponentRaw) { Icon = IconComponentRaw } else if (IconComponent) { Icon = } else { Icon = <> } return ( {Icon} {text} ) }, ) const MenuHeader = React.memo<{ coverArt?: string artistId?: string albumId?: string title: string subtitle?: string }>(({ coverArt, artistId, albumId, title, subtitle }) => { let CoverArtComponent = <> if (artistId) { CoverArtComponent = ( ) } else if (albumId) { CoverArtComponent = ( ) } else { CoverArtComponent = ( ) } return ( {CoverArtComponent} {title} {subtitle ? ( {subtitle} ) : ( <> )} ) }) const OptionStar = withSuspenseMemo<{ id: string type: StarrableItemType additionalText?: string }>(({ id, type, additionalText: text }) => { const { query, toggle } = useStar(id, type) const { t } = useTranslation() return ( } text={(query.data ? t('context.actions.unstar') : t('context.actions.star')) + (text ? ` ${text}` : '')} onSelect={() => toggle.mutate()} /> ) }) const OptionViewArtist = withSuspenseMemo<{ navigation: NavigationProp artist?: string artistId?: string }>(({ navigation, artist, artistId }) => { const { t } = useTranslation() if (!artist || !artistId) { return <> } return ( navigation.navigate('artist', { id: artistId, title: artist })} /> ) }) const OptionViewAlbum = withSuspenseMemo<{ navigation: NavigationProp album?: string albumId?: string }>(({ navigation, album, albumId }) => { const { t } = useTranslation() if (!album || !albumId) { return <> } return ( navigation.navigate('album', { id: albumId, title: album })} /> ) }) // const OptionDownload = React.memo<{ // itemType: string // }>(({ itemType }) => ( // // )) export type AlbumContextPressableProps = ContextMenuProps & { album: Album } export const AlbumContextPressable: React.FC = props => { const navigation = useNavigation() const { album, children } = props return ( } menuOptions={ <> {/* */} }> {children} ) } export type SongContextPressableProps = ContextMenuProps & { song: Song } export const SongContextPressable: React.FC = props => { const navigation = useNavigation() const { song, children } = props return ( } menuOptions={ <> {/* */} }> {children} ) } export type ArtistContextPressableProps = ContextMenuProps & { artist: Artist } export const ArtistContextPressable: React.FC = props => { const { artist, children } = props return ( } menuOptions={ <> {/* */} }> {children} ) } export type NowPlayingContextPressableProps = ContextMenuProps & { song: Song } export const NowPlayingContextPressable: React.FC = props => { const navigation = useNavigation() const { song, children } = props return ( } menuOptions={ <> }> {children} ) } const styles = StyleSheet.create({ optionsContainer: { backgroundColor: 'rgba(45, 45, 45, 0.95)', maxHeight: 365, }, optionsWrapper: { // marginBottom: 10, paddingHorizontal: 20, // backgroundColor: 'purple', }, menuHeader: { paddingTop: 14, paddingBottom: 10, paddingHorizontal: 20, flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', }, coverArt: { width: 42, height: 42, }, menuHeaderText: { flex: 1, marginLeft: 10, }, menuTitle: { fontFamily: font.semiBold, fontSize: 16, color: colors.text.primary, }, menuSubtitle: { fontFamily: font.regular, fontSize: 14, color: colors.text.secondary, }, option: { paddingVertical: 8, // paddingHorizontal: 100, flexDirection: 'row', alignItems: 'center', // backgroundColor: 'blue', overflow: 'hidden', }, icon: { marginRight: 10, width: 32, height: 32, justifyContent: 'center', alignItems: 'center', // backgroundColor: 'red', }, optionText: { fontFamily: font.semiBold, fontSize: 16, color: colors.text.primary, // backgroundColor: 'green', }, })