Skip to content

Commit

Permalink
[mobile] update ContextMenu
Browse files Browse the repository at this point in the history
[mobile] update ContextMenu
  • Loading branch information
tsirysndr committed Apr 27, 2023
1 parent 3afecd9 commit 4c67a62
Show file tree
Hide file tree
Showing 6 changed files with 254 additions and 52 deletions.
184 changes: 180 additions & 4 deletions mobile/src/Components/ContextMenu/ContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,204 @@ import React, {FC} from 'react';
import {StyleSheet} from 'react-native';
import Modal from 'react-native-modal';
import styled from '@emotion/native';
import Feather from 'react-native-vector-icons/Feather';
import MaterialCommunity from 'react-native-vector-icons/MaterialCommunityIcons';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import {Album, Artist, Track} from '../../Types';
import {useCover} from '../../Hooks/useCover';
import SvgMic from '../Icons/Mic';

const Container = styled.View`
background-color: #000;
height: 300px;
height: 420px;
`;

const MetadataRow = styled.View`
height: 110px;
width: 100%;
flex-direction: row;
align-items: center;
padding-left: 20px;
background-color: #000;
`;

const Separator = styled.View`
height: 1px;
width: 100%;
background-color: #3e3e3ec4;
margin-bottom: 10px;
`;

const Cover = styled.Image`
width: 80px;
height: 80px;
`;

const NoAlbumCover = styled.View`
width: 80px;
height: 80px;
background-color: #161515;
align-items: center;
justify-content: center;
`;

const Title = styled.Text`
color: #fff;
font-family: 'Gilroy-Bold';
font-size: 16px;
`;

const ArtistName = styled.Text`
color: #a7a7a9;
font-family: 'Gilroy-Bold';
font-size: 14px;
margin-top: 2px;
`;

const MediaInfo = styled.View`
flex-direction: column;
margin-left: 15px;
flex: 1;
`;

const IconWrapper = styled.View`
height: 40px;
width: 40px;
justify-content: center;
margin-right: 10px;
`;

const Action = styled.TouchableWithoutFeedback``;

const ActionWrapper = styled.View`
height: 60px;
width: 100%;
flex-direction: row;
align-items: center;
padding-left: 20px;
background-color: #000;
`;

const ActionTitle = styled.Text`
color: #fff;
font-family: 'Gilroy-Bold';
font-size: 16px;
`;

export type ContextMenuProps = {
isVisible: boolean;
onClose: () => void;
item?: Artist | Album | Track;
type: 'artist' | 'album' | 'track' | '';
onPlayNext: (item: Album | Track) => void;
onAddToPlaylist: (item: Album | Track) => void;
onDownload: (item: Album | Track) => void;
onGoToArtist: (item: Album | Track) => void;
onGoToAlbum: (item: Album | Track) => void;
};

const ContextMenu: FC<ContextMenuProps> = ({isVisible, onClose}) => {
const ContextMenu: FC<ContextMenuProps> = props => {
const {
isVisible,
onClose,
onAddToPlaylist,
onDownload,
onGoToAlbum,
onGoToArtist,
onPlayNext,
item,
type,
} = props;
const itemCover = {
artist: (item as Artist)?.picture,
album: (item as Album)?.cover,
track: (item as Track)?.cover,
'': undefined,
};
const cover = useCover(itemCover[type]);
return (
<Modal
isVisible={isVisible}
backdropOpacity={0.03}
onBackdropPress={onClose}
onSwipeComplete={onClose}
swipeThreshold={500}
swipeDirection={['down']}
style={styles.modal}>
<Container></Container>
<Container>
<MetadataRow>
{itemCover[type] && <Cover source={{uri: cover}} />}
{!itemCover[type] && (
<NoAlbumCover>
<Feather name="disc" size={40} color="#a7a7a9" />
</NoAlbumCover>
)}
<MediaInfo>
<Title numberOfLines={1} ellipsizeMode="tail">
{type === 'artist'
? (item as Artist)?.name
: (item as Album)?.title}
</Title>
<ArtistName numberOfLines={1} ellipsizeMode="tail">
{type === 'artist'
? (item as Artist)?.name
: (item as Album)?.artist}
</ArtistName>
</MediaInfo>
</MetadataRow>
<Separator />
<Action onPress={() => onPlayNext(item as Album | Track)}>
<ActionWrapper>
<IconWrapper>
<MaterialIcons name="playlist-play" size={31} color="#ab28fc" />
</IconWrapper>
<ActionTitle>Play next</ActionTitle>
</ActionWrapper>
</Action>
{(type === 'track' || type === 'album') && (
<>
<Action onPress={() => onDownload(item as Album | Track)}>
<ActionWrapper>
<IconWrapper>
<MaterialCommunity
name="download"
size={25}
color="#ab28fc"
/>
</IconWrapper>
<ActionTitle>Download</ActionTitle>
</ActionWrapper>
</Action>
<Action onPress={() => onAddToPlaylist(item as Album | Track)}>
<ActionWrapper>
<IconWrapper>
<MaterialIcons
name="playlist-add"
size={28}
color="#ab28fc"
/>
</IconWrapper>
<ActionTitle>Add to playlist</ActionTitle>
</ActionWrapper>
</Action>
<Action onPress={() => onGoToAlbum(item as Album | Track)}>
<ActionWrapper>
<IconWrapper>
<Feather name="disc" size={24} color="#ab28fc" />
</IconWrapper>
<ActionTitle>Go to Album</ActionTitle>
</ActionWrapper>
</Action>
<Action onPress={() => onGoToArtist(item as Album | Track)}>
<ActionWrapper>
<IconWrapper>
<SvgMic height={26} width={26} fill="#ab28fc" />
</IconWrapper>
<ActionTitle>Go to Artist</ActionTitle>
</ActionWrapper>
</Action>
</>
)}
</Container>
</Modal>
);
};
Expand Down
2 changes: 1 addition & 1 deletion mobile/src/Components/ContextMenu/ContextMenuState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {Album, Track} from '../../Types';

export const contextMenuState = atom<{
visible: boolean;
type: string;
type: 'album' | 'track' | 'artist' | '';
item?: Album | Track;
}>({
key: 'contextMenuState',
Expand Down
36 changes: 35 additions & 1 deletion mobile/src/Components/ContextMenu/ContextMenuWithData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, {FC} from 'react';
import ContextMenu from './ContextMenu';
import {useRecoilState} from 'recoil';
import {contextMenuState} from './ContextMenuState';
import {Album, Track} from '../../Types';

const ContextMenuWithData: FC = () => {
const [contextMenu, setContextMenu] = useRecoilState(contextMenuState);
Expand All @@ -11,7 +12,40 @@ const ContextMenuWithData: FC = () => {
visible: false,
});
};
return <ContextMenu isVisible={contextMenu.visible} onClose={onClose} />;
const onPlayNext = (item: Album | Track) => {
onClose();
console.log(item);
};
const onDownload = (item: Album | Track) => {
onClose();
console.log(item);
};
const onAddToPlaylist = (item: Album | Track) => {
onClose();
console.log(item);
};
const onGoToArtist = (item: Album | Track) => {
onClose();
console.log(item);
};
const onGoToAlbum = (item: Album | Track) => {
onClose();
console.log(item);
};

return (
<ContextMenu
isVisible={contextMenu.visible}
onClose={onClose}
item={contextMenu.item}
type={contextMenu.type}
onPlayNext={onPlayNext}
onDownload={onDownload}
onAddToPlaylist={onAddToPlaylist}
onGoToArtist={onGoToArtist}
onGoToAlbum={onGoToAlbum}
/>
);
};

export default ContextMenuWithData;
78 changes: 35 additions & 43 deletions mobile/src/Components/TrackRow/TrackRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import styled, {css} from '@emotion/native';
import Feather from 'react-native-vector-icons/Feather';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {useCover} from '../../Hooks/useCover';
import ContextMenu from '../ContextMenu';

const Container = styled.View`
height: 80px;
Expand Down Expand Up @@ -92,48 +91,41 @@ const TrackRow: FC<TrackRowProps> = props => {
const {track, currentTrack, onPlay, showAlbum, onPressContextMenu} = props;
const cover = useCover(track.cover);
return (
<>
<TrackWrapper>
<TouchableTrack onPress={() => onPlay(track)}>
<Container>
{showAlbum && (
<>
{track.cover && <Cover source={{uri: cover}} />}
{!track.cover && (
<NoAlbumCover>
<Feather name="disc" size={40} color="#a7a7a9" />
</NoAlbumCover>
)}
</>
)}
{!showAlbum && (
<TrackNumberWrapper>
<TrackNumber>{track.trackNumber}</TrackNumber>
</TrackNumberWrapper>
)}
<AlbumInfo>
<Title
numberOfLines={1}
ellipsizeMode="tail"
active={track.id === currentTrack?.id}>
{track.title}
</Title>
<Artist numberOfLines={1} ellipsizeMode="tail">
{track.artist}
</Artist>
</AlbumInfo>
<Button onPress={() => onPressContextMenu(track)}>
<Ionicons
name="ellipsis-vertical"
color={'#ffffff99'}
size={18}
/>
</Button>
</Container>
</TouchableTrack>
</TrackWrapper>
<ContextMenu />
</>
<TrackWrapper>
<TouchableTrack onPress={() => onPlay(track)}>
<Container>
{showAlbum && (
<>
{track.cover && <Cover source={{uri: cover}} />}
{!track.cover && (
<NoAlbumCover>
<Feather name="disc" size={40} color="#a7a7a9" />
</NoAlbumCover>
)}
</>
)}
{!showAlbum && (
<TrackNumberWrapper>
<TrackNumber>{track.trackNumber}</TrackNumber>
</TrackNumberWrapper>
)}
<AlbumInfo>
<Title
numberOfLines={1}
ellipsizeMode="tail"
active={track.id === currentTrack?.id}>
{track.title}
</Title>
<Artist numberOfLines={1} ellipsizeMode="tail">
{track.artist}
</Artist>
</AlbumInfo>
<Button onPress={() => onPressContextMenu(track)}>
<Ionicons name="ellipsis-vertical" color={'#ffffff99'} size={18} />
</Button>
</Container>
</TouchableTrack>
</TrackWrapper>
);
};

Expand Down
2 changes: 2 additions & 0 deletions mobile/src/Containers/Home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Artists from '../../Components/Artists';
import Songs from '../../Components/Songs';
import MiniPlayer from '../../Components/MiniPlayer';
import {useNavigation} from '@react-navigation/native';
import ContextMenu from '../../Components/ContextMenu';

const MainContainer = styled.View`
flex: 1;
Expand Down Expand Up @@ -64,6 +65,7 @@ const Home: FC = () => {
<MiniPlayerWrapper>
<MiniPlayer />
</MiniPlayerWrapper>
<ContextMenu />
</MainContainer>
);
};
Expand Down
4 changes: 1 addition & 3 deletions mobile/src/Navigation/AppNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import ArtistDetails from '../Containers/ArtistDetails';
import AlbumDetails from '../Containers/AlbumDetails';
import Settings from '../Containers/Settings';
import Filter from '../Containers/Filter';
import ContextMenu from '../Components/ContextMenu';

const RootStack = createStackNavigator();
const MainStack = createStackNavigator();
Expand Down Expand Up @@ -146,10 +145,9 @@ const AppNavigator: FC = () => (
headerShown: false,
gestureEnabled: true,
animationEnabled: true,
presentation: 'transparentModal',
presentation: 'modal',
}}>
<RootStack.Screen name="Player" component={Player} />
<RootStack.Screen name="ContextMenu" component={ContextMenu} />
</RootStack.Group>
</RootStack.Navigator>
</NavigationContainer>
Expand Down

0 comments on commit 4c67a62

Please sign in to comment.