Skip to content

Commit 3b9d899

Browse files
committed
added functionality to edit artist/title for tracks in a playlist
1 parent 7fb19e5 commit 3b9d899

File tree

6 files changed

+606
-350
lines changed

6 files changed

+606
-350
lines changed

packages/app/app/components/PlaylistView/index.tsx

+95-51
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,15 @@ import { useTranslation } from 'react-i18next';
44
import { useHistory } from 'react-router';
55
import { Icon } from 'semantic-ui-react';
66

7-
import { Playlist } from '@nuclear/core';
8-
import { Button, ContextPopup, PopupButton, InputDialog, timestampToTimeString, Tooltip } from '@nuclear/ui';
7+
import { Playlist, PlaylistTrack } from '@nuclear/core';
8+
import {
9+
Button,
10+
ContextPopup,
11+
PopupButton,
12+
InputDialog,
13+
timestampToTimeString,
14+
Tooltip
15+
} from '@nuclear/ui';
916
import { Track } from '@nuclear/ui/lib/types';
1017

1118
import artPlaceholder from '../../../resources/media/art_placeholder.png';
@@ -26,7 +33,7 @@ export type PlaylistViewProps = {
2633
onReorderTracks: (isource: number, idest: number) => void;
2734
isExternal?: boolean;
2835
externalSourceName?: string;
29-
}
36+
};
3037

3138
const PlaylistView: React.FC<PlaylistViewProps> = ({
3239
playlist,
@@ -45,16 +52,42 @@ const PlaylistView: React.FC<PlaylistViewProps> = ({
4552
const { t, i18n } = useTranslation('playlists');
4653
const history = useHistory();
4754

48-
const onRenamePlaylist = useCallback((name: string) => {
49-
const updatedPlaylist = {
50-
...playlist,
51-
name
52-
};
53-
updatePlaylist(updatedPlaylist);
54-
}, [playlist, updatePlaylist]);
55+
const onRenamePlaylist = useCallback(
56+
(name: string) => {
57+
const updatedPlaylist = {
58+
...playlist,
59+
name
60+
};
61+
updatePlaylist(updatedPlaylist);
62+
},
63+
[playlist, updatePlaylist]
64+
);
65+
const onUpdateTrack = useCallback(
66+
(index: number, updatedTrack: Track) => {
67+
const updatedTracks = playlist.tracks.map((track, i) => {
68+
if (i === index) {
69+
return {
70+
...updatedTrack,
71+
stream: (track as PlaylistTrack).stream
72+
} as PlaylistTrack;
73+
}
74+
return track;
75+
});
76+
77+
const updatedPlaylist = {
78+
...playlist,
79+
tracks: updatedTracks
80+
} as Playlist;
5581

56-
const onAddAll = useCallback(() => addTracks(playlist.tracks),
57-
[addTracks, playlist]);
82+
updatePlaylist(updatedPlaylist);
83+
},
84+
[playlist, updatePlaylist]
85+
);
86+
87+
const onAddAll = useCallback(
88+
() => addTracks(playlist.tracks),
89+
[addTracks, playlist]
90+
);
5891

5992
const onPlayAll = useCallback(() => {
6093
clearQueue();
@@ -64,13 +97,16 @@ const PlaylistView: React.FC<PlaylistViewProps> = ({
6497
}, [addTracks, clearQueue, playlist, selectSong, startPlayback]);
6598

6699
const onDeleteTrack = !isExternal
67-
? useCallback((trackToRemove: Track, trackIndex: number) => {
68-
const newPlaylist = {
69-
...playlist,
70-
tracks: playlist.tracks.filter((_, index) => index !== trackIndex)
71-
};
72-
updatePlaylist(newPlaylist);
73-
}, [playlist, updatePlaylist])
100+
? useCallback(
101+
(trackToRemove: Track, trackIndex: number) => {
102+
const newPlaylist = {
103+
...playlist,
104+
tracks: playlist.tracks.filter((_, index) => index !== trackIndex)
105+
};
106+
updatePlaylist(newPlaylist);
107+
},
108+
[playlist, updatePlaylist]
109+
)
74110
: undefined;
75111

76112
const onDeletePlaylist = useCallback(() => {
@@ -94,37 +130,42 @@ const PlaylistView: React.FC<PlaylistViewProps> = ({
94130
}, [exportPlaylist, playlist, t]);
95131

96132
return (
97-
<div
98-
data-testid='playlist-view'
99-
className={styles.playlist_view_container}
100-
>
133+
<div data-testid='playlist-view' className={styles.playlist_view_container}>
101134
<div className={styles.playlist}>
102135
<div className={styles.playlist_view_info}>
103136
<div>
104137
<img
105138
className={styles.playlist_thumbnail}
106-
src={playlist?.tracks?.[0]?.thumbnail ?? artPlaceholder as unknown as string}
139+
src={
140+
playlist?.tracks?.[0]?.thumbnail ??
141+
(artPlaceholder as unknown as string)
142+
}
107143
/>
108144
</div>
109145
<div className={styles.playlist_header}>
110-
{
111-
isExternal &&
146+
{isExternal && (
112147
<div className={styles.playlist_header_external_source}>
113148
<Tooltip
114149
on='hover'
115-
content={t('external-source-tooltip', { source: externalSourceName })}
150+
content={t('external-source-tooltip', {
151+
source: externalSourceName
152+
})}
116153
trigger={
117-
<div className={styles.playlist_header_external_source_inner}>
154+
<div
155+
className={styles.playlist_header_external_source_inner}
156+
>
118157
<Icon name='external square' />
119158
{externalSourceName}
120159
</div>
121160
}
122161
position='bottom center'
123162
/>
124163
</div>
125-
}
164+
)}
126165
<div className={styles.playlist_header_inner}>
127-
<label className={styles.playlist_header_label}>{t('playlist')}</label>
166+
<label className={styles.playlist_header_label}>
167+
{t('playlist')}
168+
</label>
128169
<div className={styles.playlist_name}>
129170
{playlist.name}
130171
<InputDialog
@@ -135,32 +176,33 @@ const PlaylistView: React.FC<PlaylistViewProps> = ({
135176
initialString={playlist.name}
136177
onAccept={onRenamePlaylist}
137178
trigger={
138-
!isExternal &&
139-
<Button
140-
basic
141-
aria-label={t('rename')}
142-
icon='pencil'
143-
data-testid='rename-button'
144-
/>
179+
!isExternal && (
180+
<Button
181+
basic
182+
aria-label={t('rename')}
183+
icon='pencil'
184+
data-testid='rename-button'
185+
/>
186+
)
145187
}
146188
/>
147189
</div>
148190
<div className={styles.playlist_details}>
149191
<span>
150192
{`${playlist.tracks.length} ${t('number-of-tracks')}`}
151193
</span>
152-
{
153-
playlist.lastModified &&
194+
{playlist.lastModified && (
154195
<>
155-
<span>
156-
·
157-
</span>
196+
<span>·</span>
158197

159198
<span>
160-
{`${t('modified-at')}${timestampToTimeString(playlist.lastModified, i18n.language)}`}
199+
{`${t('modified-at')}${timestampToTimeString(
200+
playlist.lastModified,
201+
i18n.language
202+
)}`}
161203
</span>
162204
</>
163-
}
205+
)}
164206
</div>
165207
<div className={styles.playlist_buttons}>
166208
<Button
@@ -185,32 +227,33 @@ const PlaylistView: React.FC<PlaylistViewProps> = ({
185227
}
186228
artist={null}
187229
title={playlist.name}
188-
thumb={playlist?.tracks?.[0]?.thumbnail ?? artPlaceholder as unknown as string}
230+
thumb={
231+
playlist?.tracks?.[0]?.thumbnail ??
232+
(artPlaceholder as unknown as string)
233+
}
189234
>
190235
<PopupButton
191236
onClick={onAddAll}
192237
ariaLabel={t('queue')}
193238
icon='plus'
194239
label={t('queue')}
195240
/>
196-
{
197-
!isExternal &&
241+
{!isExternal && (
198242
<PopupButton
199243
onClick={onDeletePlaylist}
200244
ariaLabel={t('delete')}
201245
icon='trash'
202246
label={t('delete')}
203247
/>
204-
}
205-
{
206-
isExternal &&
248+
)}
249+
{isExternal && (
207250
<PopupButton
208251
onClick={onSaveExternalPlaylist}
209252
ariaLabel={t('save-external-playlist')}
210253
icon='save'
211254
label={t('save-external-playlist')}
212255
/>
213-
}
256+
)}
214257
<PopupButton
215258
onClick={onExportPlaylist}
216259
ariaLabel={t('export-button')}
@@ -228,6 +271,7 @@ const PlaylistView: React.FC<PlaylistViewProps> = ({
228271
onReorder={!isExternal && onReorderTracks}
229272
displayAlbum={false}
230273
displayDeleteButton={!isExternal}
274+
onTrackUpdate={!isExternal ? onUpdateTrack : undefined}
231275
searchable
232276
/>
233277
</div>

0 commit comments

Comments
 (0)