Skip to content

Commit 5a2db28

Browse files
committed
[mobile] update ContextMenu
[mobile] update ContextMenu [mobile] update ContextMenu
1 parent 3afecd9 commit 5a2db28

File tree

6 files changed

+281
-57
lines changed

6 files changed

+281
-57
lines changed

mobile/src/Components/ContextMenu/ContextMenu.tsx

Lines changed: 182 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,206 @@ import React, {FC} from 'react';
22
import {StyleSheet} from 'react-native';
33
import Modal from 'react-native-modal';
44
import styled from '@emotion/native';
5+
import Feather from 'react-native-vector-icons/Feather';
6+
import MaterialCommunity from 'react-native-vector-icons/MaterialCommunityIcons';
7+
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
8+
import {Album, Artist, Track} from '../../Types';
9+
import {useCover} from '../../Hooks/useCover';
10+
import SvgMic from '../Icons/Mic';
511

612
const Container = styled.View`
713
background-color: #000;
8-
height: 300px;
14+
height: 420px;
15+
`;
16+
17+
const MetadataRow = styled.View`
18+
height: 110px;
19+
width: 100%;
20+
flex-direction: row;
21+
align-items: center;
22+
padding-left: 20px;
23+
background-color: #000;
24+
`;
25+
26+
const Separator = styled.View`
27+
height: 1px;
28+
width: 100%;
29+
background-color: #3e3e3ec4;
30+
margin-bottom: 10px;
31+
`;
32+
33+
const Cover = styled.Image`
34+
width: 80px;
35+
height: 80px;
36+
`;
37+
38+
const NoAlbumCover = styled.View`
39+
width: 80px;
40+
height: 80px;
41+
background-color: #161515;
42+
align-items: center;
43+
justify-content: center;
44+
`;
45+
46+
const Title = styled.Text`
47+
color: #fff;
48+
font-family: 'Gilroy-Bold';
49+
font-size: 16px;
50+
`;
51+
52+
const ArtistName = styled.Text`
53+
color: #a7a7a9;
54+
font-family: 'Gilroy-Bold';
55+
font-size: 14px;
56+
margin-top: 2px;
57+
`;
58+
59+
const MediaInfo = styled.View`
60+
flex-direction: column;
61+
margin-left: 15px;
62+
flex: 1;
63+
`;
64+
65+
const IconWrapper = styled.View`
66+
height: 40px;
67+
width: 40px;
68+
justify-content: center;
69+
margin-right: 10px;
70+
`;
71+
72+
const Action = styled.TouchableWithoutFeedback``;
73+
74+
const ActionWrapper = styled.View`
75+
height: 60px;
76+
width: 100%;
77+
flex-direction: row;
78+
align-items: center;
79+
padding-left: 20px;
80+
background-color: #000;
81+
`;
82+
83+
const ActionTitle = styled.Text`
84+
color: #fff;
85+
font-family: 'Gilroy-Bold';
86+
font-size: 16px;
987
`;
1088

1189
export type ContextMenuProps = {
1290
isVisible: boolean;
1391
onClose: () => void;
92+
item?: Artist | Album | Track;
93+
type: 'artist' | 'album' | 'track' | '';
94+
onPlayNext: (item: Album | Track) => void;
95+
onAddToPlaylist: (item: Album | Track) => void;
96+
onDownload: (item: Album | Track) => void;
97+
onGoToArtist: (item: Album | Track) => void;
98+
onGoToAlbum: (item: Album | Track) => void;
1499
};
15100

16-
const ContextMenu: FC<ContextMenuProps> = ({isVisible, onClose}) => {
101+
const ContextMenu: FC<ContextMenuProps> = props => {
102+
const {
103+
isVisible,
104+
onClose,
105+
onAddToPlaylist,
106+
onDownload,
107+
onGoToAlbum,
108+
onGoToArtist,
109+
onPlayNext,
110+
item,
111+
type,
112+
} = props;
113+
const itemCover = {
114+
artist: (item as Artist)?.picture,
115+
album: (item as Album)?.cover,
116+
track: (item as Track)?.cover,
117+
'': undefined,
118+
};
119+
const cover = useCover(itemCover[type]);
17120
return (
18121
<Modal
19122
isVisible={isVisible}
20123
backdropOpacity={0.03}
21124
onBackdropPress={onClose}
22125
onSwipeComplete={onClose}
23-
swipeThreshold={500}
24126
swipeDirection={['down']}
25127
style={styles.modal}>
26-
<Container></Container>
128+
<Container>
129+
<MetadataRow>
130+
{itemCover[type] && <Cover source={{uri: cover}} />}
131+
{!itemCover[type] && (
132+
<NoAlbumCover>
133+
<Feather name="disc" size={40} color="#a7a7a9" />
134+
</NoAlbumCover>
135+
)}
136+
<MediaInfo>
137+
<Title numberOfLines={1} ellipsizeMode="tail">
138+
{type === 'artist'
139+
? (item as Artist)?.name
140+
: (item as Album)?.title}
141+
</Title>
142+
<ArtistName numberOfLines={1} ellipsizeMode="tail">
143+
{type === 'artist'
144+
? (item as Artist)?.name
145+
: (item as Album)?.artist}
146+
</ArtistName>
147+
</MediaInfo>
148+
</MetadataRow>
149+
<Separator />
150+
<Action onPress={() => onPlayNext(item as Album | Track)}>
151+
<ActionWrapper>
152+
<IconWrapper>
153+
<MaterialIcons name="playlist-play" size={31} color="#ab28fc" />
154+
</IconWrapper>
155+
<ActionTitle>Play next</ActionTitle>
156+
</ActionWrapper>
157+
</Action>
158+
{(type === 'track' || type === 'album') && (
159+
<>
160+
<Action onPress={() => onDownload(item as Album | Track)}>
161+
<ActionWrapper>
162+
<IconWrapper>
163+
<MaterialCommunity
164+
name="download"
165+
size={25}
166+
color="#ab28fc"
167+
/>
168+
</IconWrapper>
169+
<ActionTitle>Download</ActionTitle>
170+
</ActionWrapper>
171+
</Action>
172+
<Action onPress={() => onAddToPlaylist(item as Album | Track)}>
173+
<ActionWrapper>
174+
<IconWrapper>
175+
<MaterialIcons
176+
name="playlist-add"
177+
size={28}
178+
color="#ab28fc"
179+
/>
180+
</IconWrapper>
181+
<ActionTitle>Add to playlist</ActionTitle>
182+
</ActionWrapper>
183+
</Action>
184+
{type !== 'album' && (
185+
<Action onPress={() => onGoToAlbum(item as Album | Track)}>
186+
<ActionWrapper>
187+
<IconWrapper>
188+
<Feather name="disc" size={24} color="#ab28fc" />
189+
</IconWrapper>
190+
<ActionTitle>Go to Album</ActionTitle>
191+
</ActionWrapper>
192+
</Action>
193+
)}
194+
<Action onPress={() => onGoToArtist(item as Album | Track)}>
195+
<ActionWrapper>
196+
<IconWrapper>
197+
<SvgMic height={26} width={26} fill="#ab28fc" />
198+
</IconWrapper>
199+
<ActionTitle>Go to Artist</ActionTitle>
200+
</ActionWrapper>
201+
</Action>
202+
</>
203+
)}
204+
</Container>
27205
</Modal>
28206
);
29207
};

mobile/src/Components/ContextMenu/ContextMenuState.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {Album, Track} from '../../Types';
33

44
export const contextMenuState = atom<{
55
visible: boolean;
6-
type: string;
6+
type: 'album' | 'track' | 'artist' | '';
77
item?: Album | Track;
88
}>({
99
key: 'contextMenuState',

mobile/src/Components/ContextMenu/ContextMenuWithData.tsx

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,70 @@ import React, {FC} from 'react';
22
import ContextMenu from './ContextMenu';
33
import {useRecoilState} from 'recoil';
44
import {contextMenuState} from './ContextMenuState';
5+
import {Album, Track} from '../../Types';
6+
import {useNavigation} from '@react-navigation/native';
57

68
const ContextMenuWithData: FC = () => {
9+
const navigation = useNavigation<any>();
710
const [contextMenu, setContextMenu] = useRecoilState(contextMenuState);
811
const onClose = () => {
912
setContextMenu({
1013
...contextMenu,
1114
visible: false,
1215
});
1316
};
14-
return <ContextMenu isVisible={contextMenu.visible} onClose={onClose} />;
17+
const onPlayNext = (item: Album | Track) => {
18+
onClose();
19+
console.log(item);
20+
};
21+
const onDownload = (item: Album | Track) => {
22+
onClose();
23+
console.log(item);
24+
};
25+
const onAddToPlaylist = (item: Album | Track) => {
26+
onClose();
27+
console.log(item);
28+
};
29+
const onGoToArtist = (item: Album | Track) => {
30+
onClose();
31+
switch (contextMenu.type) {
32+
case 'album':
33+
navigation.navigate('ArtistDetails', {artist: {}});
34+
break;
35+
case 'track':
36+
navigation.navigate('ArtistDetails', {artist: {}});
37+
break;
38+
default:
39+
break;
40+
}
41+
};
42+
const onGoToAlbum = (item: Album | Track) => {
43+
onClose();
44+
switch (contextMenu.type) {
45+
case 'album':
46+
navigation.navigate('AlbumDetails', {album: {}});
47+
break;
48+
case 'track':
49+
navigation.navigate('AlbumDetails', {album: {}});
50+
break;
51+
default:
52+
break;
53+
}
54+
};
55+
56+
return (
57+
<ContextMenu
58+
isVisible={contextMenu.visible}
59+
onClose={onClose}
60+
item={contextMenu.item}
61+
type={contextMenu.type}
62+
onPlayNext={onPlayNext}
63+
onDownload={onDownload}
64+
onAddToPlaylist={onAddToPlaylist}
65+
onGoToArtist={onGoToArtist}
66+
onGoToAlbum={onGoToAlbum}
67+
/>
68+
);
1569
};
1670

1771
export default ContextMenuWithData;

mobile/src/Components/TrackRow/TrackRow.tsx

Lines changed: 35 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import styled, {css} from '@emotion/native';
44
import Feather from 'react-native-vector-icons/Feather';
55
import Ionicons from 'react-native-vector-icons/Ionicons';
66
import {useCover} from '../../Hooks/useCover';
7-
import ContextMenu from '../ContextMenu';
87

98
const Container = styled.View`
109
height: 80px;
@@ -92,48 +91,41 @@ const TrackRow: FC<TrackRowProps> = props => {
9291
const {track, currentTrack, onPlay, showAlbum, onPressContextMenu} = props;
9392
const cover = useCover(track.cover);
9493
return (
95-
<>
96-
<TrackWrapper>
97-
<TouchableTrack onPress={() => onPlay(track)}>
98-
<Container>
99-
{showAlbum && (
100-
<>
101-
{track.cover && <Cover source={{uri: cover}} />}
102-
{!track.cover && (
103-
<NoAlbumCover>
104-
<Feather name="disc" size={40} color="#a7a7a9" />
105-
</NoAlbumCover>
106-
)}
107-
</>
108-
)}
109-
{!showAlbum && (
110-
<TrackNumberWrapper>
111-
<TrackNumber>{track.trackNumber}</TrackNumber>
112-
</TrackNumberWrapper>
113-
)}
114-
<AlbumInfo>
115-
<Title
116-
numberOfLines={1}
117-
ellipsizeMode="tail"
118-
active={track.id === currentTrack?.id}>
119-
{track.title}
120-
</Title>
121-
<Artist numberOfLines={1} ellipsizeMode="tail">
122-
{track.artist}
123-
</Artist>
124-
</AlbumInfo>
125-
<Button onPress={() => onPressContextMenu(track)}>
126-
<Ionicons
127-
name="ellipsis-vertical"
128-
color={'#ffffff99'}
129-
size={18}
130-
/>
131-
</Button>
132-
</Container>
133-
</TouchableTrack>
134-
</TrackWrapper>
135-
<ContextMenu />
136-
</>
94+
<TrackWrapper>
95+
<TouchableTrack onPress={() => onPlay(track)}>
96+
<Container>
97+
{showAlbum && (
98+
<>
99+
{track.cover && <Cover source={{uri: cover}} />}
100+
{!track.cover && (
101+
<NoAlbumCover>
102+
<Feather name="disc" size={40} color="#a7a7a9" />
103+
</NoAlbumCover>
104+
)}
105+
</>
106+
)}
107+
{!showAlbum && (
108+
<TrackNumberWrapper>
109+
<TrackNumber>{track.trackNumber}</TrackNumber>
110+
</TrackNumberWrapper>
111+
)}
112+
<AlbumInfo>
113+
<Title
114+
numberOfLines={1}
115+
ellipsizeMode="tail"
116+
active={track.id === currentTrack?.id}>
117+
{track.title}
118+
</Title>
119+
<Artist numberOfLines={1} ellipsizeMode="tail">
120+
{track.artist}
121+
</Artist>
122+
</AlbumInfo>
123+
<Button onPress={() => onPressContextMenu(track)}>
124+
<Ionicons name="ellipsis-vertical" color={'#ffffff99'} size={18} />
125+
</Button>
126+
</Container>
127+
</TouchableTrack>
128+
</TrackWrapper>
137129
);
138130
};
139131

0 commit comments

Comments
 (0)