Browse Source

Add useFavorite hook, refactor components

master
jeffvli 3 years ago
parent
commit
3633e4a62c
  1. 104
      src/components/dashboard/Dashboard.tsx
  2. 41
      src/components/library/AlbumList.tsx
  3. 83
      src/components/library/AlbumView.tsx
  4. 41
      src/components/library/ArtistList.tsx
  5. 170
      src/components/library/ArtistView.tsx
  6. 51
      src/components/library/FolderList.tsx
  7. 41
      src/components/library/MusicList.tsx
  8. 51
      src/components/player/NowPlayingInfoView.tsx
  9. 22
      src/components/player/NowPlayingMiniView.tsx
  10. 22
      src/components/player/NowPlayingView.tsx
  11. 71
      src/components/player/PlayerBar.tsx
  12. 57
      src/components/playlist/PlaylistView.tsx
  13. 44
      src/components/search/SearchView.tsx
  14. 92
      src/components/starred/StarredView.tsx
  15. 75
      src/hooks/useFavorite.ts

104
src/components/dashboard/Dashboard.tsx

@ -1,23 +1,21 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import _ from 'lodash';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { useQuery, useQueryClient } from 'react-query'; import { useQuery } from 'react-query';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import GenericPage from '../layout/GenericPage'; import GenericPage from '../layout/GenericPage';
import GenericPageHeader from '../layout/GenericPageHeader'; import GenericPageHeader from '../layout/GenericPageHeader';
import ScrollingMenu from '../scrollingmenu/ScrollingMenu'; import ScrollingMenu from '../scrollingmenu/ScrollingMenu';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import { setStar } from '../../redux/playQueueSlice';
import { apiController } from '../../api/controller'; import { apiController } from '../../api/controller';
import { Item, Server } from '../../types'; import { Item, Server } from '../../types';
import { setFilter, setPagination } from '../../redux/viewSlice'; import { setFilter, setPagination } from '../../redux/viewSlice';
import CenterLoader from '../loader/CenterLoader'; import CenterLoader from '../loader/CenterLoader';
import useFavorite from '../../hooks/useFavorite';
const Dashboard = () => { const Dashboard = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const history = useHistory(); const history = useHistory();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const queryClient = useQueryClient();
const folder = useAppSelector((state) => state.folder); const folder = useAppSelector((state) => state.folder);
const config = useAppSelector((state) => state.config); const config = useAppSelector((state) => state.config);
const [musicFolder, setMusicFolder] = useState({ loaded: false, id: undefined }); const [musicFolder, setMusicFolder] = useState({ loaded: false, id: undefined });
@ -94,87 +92,7 @@ const Dashboard = () => {
} }
); );
const handleFavorite = async (rowData: any) => { const { handleFavorite } = useFavorite();
if (!rowData.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: rowData.id, type: 'album' },
});
dispatch(setStar({ id: [rowData.id], type: 'star' }));
queryClient.setQueryData(['recentAlbums', musicFolder.id], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.data, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.data[index].starred = Date.now();
});
return oldData;
});
queryClient.setQueryData(['newestAlbums', musicFolder.id], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.data, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.data[index].starred = Date.now();
});
return oldData;
});
queryClient.setQueryData(['randomAlbums', musicFolder.id], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.data, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.data[index].starred = Date.now();
});
return oldData;
});
queryClient.setQueryData(['frequentAlbums', musicFolder.id], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.data, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.data[index].starred = Date.now();
});
return oldData;
});
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'album' },
});
dispatch(setStar({ id: [rowData.id], type: 'unstar' }));
queryClient.setQueryData(['recentAlbums', musicFolder.id], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.data, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.data[index].starred = undefined;
});
return oldData;
});
queryClient.setQueryData(['newestAlbums', musicFolder.id], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.data, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.data[index].starred = undefined;
});
return oldData;
});
queryClient.setQueryData(['randomAlbums', musicFolder.id], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.data, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.data[index].starred = undefined;
});
return oldData;
});
queryClient.setQueryData(['frequentAlbums', musicFolder.id], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.data, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.data[index].starred = undefined;
});
return oldData;
});
}
};
if ( if (
isLoadingRecent || isLoadingRecent ||
@ -213,7 +131,9 @@ const Dashboard = () => {
}, 50); }, 50);
}} }}
type="music" type="music"
handleFavorite={handleFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, { queryKey: ['recentAlbums', musicFolder.id] })
}
/> />
<ScrollingMenu <ScrollingMenu
@ -239,7 +159,9 @@ const Dashboard = () => {
}, 50); }, 50);
}} }}
type="album" type="album"
handleFavorite={handleFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, { queryKey: ['newestAlbums', musicFolder.id] })
}
/> />
<ScrollingMenu <ScrollingMenu
@ -265,7 +187,9 @@ const Dashboard = () => {
}, 50); }, 50);
}} }}
type="album" type="album"
handleFavorite={handleFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, { queryKey: ['randomAlbums', musicFolder.id] })
}
/> />
<ScrollingMenu <ScrollingMenu
@ -291,7 +215,9 @@ const Dashboard = () => {
}, 50); }, 50);
}} }}
type="music" type="music"
handleFavorite={handleFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, { queryKey: ['frequentAlbums', musicFolder.id] })
}
/> />
</> </>
)} )}

41
src/components/library/AlbumList.tsx

@ -31,6 +31,7 @@ import useGridScroll from '../../hooks/useGridScroll';
import useListScroll from '../../hooks/useListScroll'; import useListScroll from '../../hooks/useListScroll';
import useListClickHandler from '../../hooks/useListClickHandler'; import useListClickHandler from '../../hooks/useListClickHandler';
import Popup from '../shared/Popup'; import Popup from '../shared/Popup';
import useFavorite from '../../hooks/useFavorite';
export const ALBUM_SORT_TYPES = [ export const ALBUM_SORT_TYPES = [
{ label: i18n.t('A-Z (Name)'), value: 'alphabeticalByName', role: i18n.t('Default') }, { label: i18n.t('A-Z (Name)'), value: 'alphabeticalByName', role: i18n.t('Default') },
@ -210,37 +211,7 @@ const AlbumList = () => {
setIsRefreshing(false); setIsRefreshing(false);
}; };
const handleRowFavorite = async (rowData: any) => { const { handleFavorite } = useFavorite();
if (!rowData.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: rowData.id, type: 'album' },
});
queryClient.setQueryData(['albumList', view.album.filter, musicFolder.id], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.data, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.data[index].starred = Date.now();
});
return oldData;
});
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'album' },
});
queryClient.setQueryData(['albumList', view.album.filter, musicFolder.id], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.data, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.data[index].starred = undefined;
});
return oldData;
});
}
};
const handleRowRating = (rowData: any, e: number) => { const handleRowRating = (rowData: any, e: number) => {
apiController({ apiController({
@ -440,7 +411,9 @@ const AlbumList = () => {
'viewInFolder', 'viewInFolder',
]} ]}
loading={isLoading} loading={isLoading}
handleFavorite={handleRowFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, { queryKey: ['albumList', view.album.filter, musicFolder.id] })
}
initialScrollOffset={Number(localStorage.getItem('scroll_list_albumList'))} initialScrollOffset={Number(localStorage.getItem('scroll_list_albumList'))}
onScroll={(scrollIndex: number) => { onScroll={(scrollIndex: number) => {
localStorage.setItem('scroll_list_albumList', String(Math.abs(scrollIndex))); localStorage.setItem('scroll_list_albumList', String(Math.abs(scrollIndex)));
@ -514,7 +487,9 @@ const AlbumList = () => {
playClick={{ type: 'album', idProperty: 'id' }} playClick={{ type: 'album', idProperty: 'id' }}
size={config.lookAndFeel.gridView.cardSize} size={config.lookAndFeel.gridView.cardSize}
cacheType="album" cacheType="album"
handleFavorite={handleRowFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, { queryKey: ['albumList', view.album.filter, musicFolder.id] })
}
initialScrollOffset={Number(localStorage.getItem('scroll_grid_albumList'))} initialScrollOffset={Number(localStorage.getItem('scroll_grid_albumList'))}
onScroll={(scrollIndex: number) => { onScroll={(scrollIndex: number) => {
localStorage.setItem('scroll_grid_albumList', String(scrollIndex)); localStorage.setItem('scroll_grid_albumList', String(scrollIndex));

83
src/components/library/AlbumView.tsx

@ -15,12 +15,7 @@ import {
PlayButton, PlayButton,
} from '../shared/ToolbarButtons'; } from '../shared/ToolbarButtons';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import { import { fixPlayer2Index, setPlayQueueByRowClick, setRate } from '../../redux/playQueueSlice';
fixPlayer2Index,
setPlayQueueByRowClick,
setRate,
setStar,
} from '../../redux/playQueueSlice';
import useSearchQuery from '../../hooks/useSearchQuery'; import useSearchQuery from '../../hooks/useSearchQuery';
import GenericPage from '../layout/GenericPage'; import GenericPage from '../layout/GenericPage';
import ListViewType from '../viewtypes/ListViewType'; import ListViewType from '../viewtypes/ListViewType';
@ -44,6 +39,7 @@ import CenterLoader from '../loader/CenterLoader';
import useListClickHandler from '../../hooks/useListClickHandler'; import useListClickHandler from '../../hooks/useListClickHandler';
import Popup from '../shared/Popup'; import Popup from '../shared/Popup';
import usePlayQueueHandler from '../../hooks/usePlayQueueHandler'; import usePlayQueueHandler from '../../hooks/usePlayQueueHandler';
import useFavorite from '../../hooks/useFavorite';
interface AlbumParams { interface AlbumParams {
id: string; id: string;
@ -95,58 +91,7 @@ const AlbumView = ({ ...rest }: any) => {
}); });
const { handlePlayQueueAdd } = usePlayQueueHandler(); const { handlePlayQueueAdd } = usePlayQueueHandler();
const { handleFavorite } = useFavorite();
const handleFavorite = async () => {
if (!data.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: data.id, type: 'album' },
});
queryClient.setQueryData(['album', id], { ...data, starred: Date.now() });
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: data.id, type: 'album' },
});
queryClient.setQueryData(['album', id], { ...data, starred: undefined });
}
};
const handleRowFavorite = async (rowData: any) => {
if (!rowData.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: rowData.id, type: 'music' },
});
dispatch(setStar({ id: [rowData.id], type: 'star' }));
queryClient.setQueryData(['album', id], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData?.song, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.song[index].starred = Date.now();
});
return oldData;
});
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'music' },
});
dispatch(setStar({ id: [rowData.id], type: 'unstar' }));
queryClient.setQueryData(['album', id], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData?.song, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.song[index].starred = undefined;
});
return oldData;
});
}
};
const handleDownload = async (type: 'copy' | 'download') => { const handleDownload = async (type: 'copy' | 'download') => {
if (config.serverType === Server.Jellyfin) { if (config.serverType === Server.Jellyfin) {
@ -271,7 +216,15 @@ const AlbumView = ({ ...rest }: any) => {
details={data} details={data}
playClick={{ type: 'album', id: data.id }} playClick={{ type: 'album', id: data.id }}
url={`/library/album/${data.id}`} url={`/library/album/${data.id}`}
handleFavorite={handleFavorite} handleFavorite={() =>
handleFavorite(data, {
custom: () =>
queryClient.setQueryData(['album', id], {
...data,
starred: data?.starred ? undefined : Date.now(),
}),
})
}
/> />
} }
cacheImages={{ cacheImages={{
@ -459,7 +412,15 @@ const AlbumView = ({ ...rest }: any) => {
size="lg" size="lg"
appearance="subtle" appearance="subtle"
isFavorite={data.starred} isFavorite={data.starred}
onClick={handleFavorite} onClick={() =>
handleFavorite(data, {
custom: () =>
queryClient.setQueryData(['album', id], {
...data,
starred: data?.starred ? undefined : Date.now(),
}),
})
}
/> />
<Whisper <Whisper
trigger="hover" trigger="hover"
@ -516,7 +477,7 @@ const AlbumView = ({ ...rest }: any) => {
'deletePlaylist', 'deletePlaylist',
'viewInModal', 'viewInModal',
]} ]}
handleFavorite={handleRowFavorite} handleFavorite={(rowData: any) => handleFavorite(rowData, { queryKey: ['album', id] })}
/> />
</GenericPage> </GenericPage>
</> </>

41
src/components/library/ArtistList.tsx

@ -19,6 +19,7 @@ import useColumnSort from '../../hooks/useColumnSort';
import { setSort } from '../../redux/artistSlice'; import { setSort } from '../../redux/artistSlice';
import { StyledTag } from '../shared/styled'; import { StyledTag } from '../shared/styled';
import useListClickHandler from '../../hooks/useListClickHandler'; import useListClickHandler from '../../hooks/useListClickHandler';
import useFavorite from '../../hooks/useFavorite';
const ArtistList = () => { const ArtistList = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -65,37 +66,7 @@ const ArtistList = () => {
setIsRefreshing(false); setIsRefreshing(false);
}; };
const handleRowFavorite = async (rowData: any) => { const { handleFavorite } = useFavorite();
if (!rowData.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: rowData.id, type: 'artist' },
});
queryClient.setQueryData(['artistList', musicFolder], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData[index].starred = Date.now();
});
return oldData;
});
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'artist' },
});
queryClient.setQueryData(['artistList', musicFolder], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData[index].starred = undefined;
});
return oldData;
});
}
};
const handleRowRating = (rowData: any, e: number) => { const handleRowRating = (rowData: any, e: number) => {
apiController({ apiController({
@ -211,7 +182,9 @@ const ArtistList = () => {
'deletePlaylist', 'deletePlaylist',
'viewInFolder', 'viewInFolder',
]} ]}
handleFavorite={handleRowFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, { queryKey: ['artistList', musicFolder] })
}
initialScrollOffset={Number(localStorage.getItem('scroll_list_artistList'))} initialScrollOffset={Number(localStorage.getItem('scroll_list_artistList'))}
onScroll={(scrollIndex: number) => { onScroll={(scrollIndex: number) => {
localStorage.setItem('scroll_list_artistList', String(Math.abs(scrollIndex))); localStorage.setItem('scroll_list_artistList', String(Math.abs(scrollIndex)));
@ -236,7 +209,9 @@ const ArtistList = () => {
playClick={{ type: 'artist', idProperty: 'id' }} playClick={{ type: 'artist', idProperty: 'id' }}
size={config.lookAndFeel.gridView.cardSize} size={config.lookAndFeel.gridView.cardSize}
cacheType="artist" cacheType="artist"
handleFavorite={handleRowFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, { queryKey: ['artistList', musicFolder] })
}
initialScrollOffset={Number(localStorage.getItem('scroll_grid_artistList'))} initialScrollOffset={Number(localStorage.getItem('scroll_grid_artistList'))}
onScroll={(scrollIndex: number) => { onScroll={(scrollIndex: number) => {
localStorage.setItem('scroll_grid_artistList', String(scrollIndex)); localStorage.setItem('scroll_grid_artistList', String(scrollIndex));

170
src/components/library/ArtistView.tsx

@ -41,6 +41,7 @@ import CenterLoader from '../loader/CenterLoader';
import useListClickHandler from '../../hooks/useListClickHandler'; import useListClickHandler from '../../hooks/useListClickHandler';
import Popup from '../shared/Popup'; import Popup from '../shared/Popup';
import usePlayQueueHandler from '../../hooks/usePlayQueueHandler'; import usePlayQueueHandler from '../../hooks/usePlayQueueHandler';
import useFavorite from '../../hooks/useFavorite';
const fac = new FastAverageColor(); const fac = new FastAverageColor();
@ -155,122 +156,9 @@ const ArtistView = ({ ...rest }: any) => {
}, },
}); });
const handleFavorite = async () => { const { handleFavorite } = useFavorite();
if (!data.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: data.id, type: 'artist' },
});
queryClient.setQueryData(['artist', artistId, musicFolder], { ...data, starred: Date.now() });
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: data.id, type: 'artist' },
});
queryClient.setQueryData(['artist', artistId, musicFolder], { ...data, starred: undefined });
}
};
const { handlePlayQueueAdd } = usePlayQueueHandler(); const { handlePlayQueueAdd } = usePlayQueueHandler();
const handleRowFavorite = async (rowData: any) => {
if (!rowData.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: rowData.id, type: 'album' },
});
queryClient.setQueryData(['artist', artistId, musicFolder], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData?.album, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.album[index].starred = Date.now();
});
return oldData;
});
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'album' },
});
queryClient.setQueryData(['artist', artistId, musicFolder], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData?.album, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.album[index].starred = undefined;
});
return oldData;
});
}
};
const handleSimilarArtistRowFavorite = async (rowData: any) => {
if (!rowData.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: rowData.id, type: 'artist' },
});
queryClient.setQueryData(['artist', artistId, musicFolder], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData?.info?.similarArtist, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.info.similarArtist[index].starred = Date.now();
});
return oldData;
});
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'artist' },
});
queryClient.setQueryData(['artist', artistId, musicFolder], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData?.info?.similarArtist, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.info.similarArtist[index].starred = undefined;
});
return oldData;
});
}
};
const handleMusicRowFavorite = async (rowData: any, query: any) => {
if (!rowData.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: rowData.id, type: 'music' },
});
queryClient.setQueryData(query, (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData[index].starred = Date.now();
});
return oldData;
});
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'music' },
});
queryClient.setQueryData(query, (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData[index].starred = undefined;
});
return oldData;
});
}
};
const handleRowRating = async (rowData: any, e: number, query: any) => { const handleRowRating = async (rowData: any, e: number, query: any) => {
apiController({ apiController({
serverType: config.serverType, serverType: config.serverType,
@ -650,7 +538,15 @@ const ArtistView = ({ ...rest }: any) => {
size="lg" size="lg"
appearance="subtle" appearance="subtle"
isFavorite={data.starred} isFavorite={data.starred}
onClick={() => handleFavorite()} onClick={() =>
handleFavorite(data, {
custom: () =>
queryClient.setQueryData(['artist', artistId, musicFolder], {
...data,
starred: data?.starred ? undefined : Date.now(),
}),
})
}
/> />
<Whisper <Whisper
trigger="hover" trigger="hover"
@ -726,7 +622,7 @@ const ArtistView = ({ ...rest }: any) => {
dnd dnd
disabledContextMenuOptions={['deletePlaylist', 'viewInModal']} disabledContextMenuOptions={['deletePlaylist', 'viewInModal']}
handleFavorite={(rowData: any) => handleFavorite={(rowData: any) =>
handleMusicRowFavorite(rowData, ['artistSongs', artistId]) handleFavorite(rowData, { queryKey: ['artistSongs', artistId] })
} }
handleRating={(rowData: any, e: number) => handleRating={(rowData: any, e: number) =>
handleRowRating(rowData, e, ['artistSongs', artistId]) handleRowRating(rowData, e, ['artistSongs', artistId])
@ -763,7 +659,9 @@ const ArtistView = ({ ...rest }: any) => {
'deletePlaylist', 'deletePlaylist',
'viewInFolder', 'viewInFolder',
]} ]}
handleFavorite={handleRowFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, { queryKey: ['artist', artistId, musicFolder] })
}
/> />
)} )}
@ -789,7 +687,9 @@ const ArtistView = ({ ...rest }: any) => {
size={config.lookAndFeel.gridView.cardSize} size={config.lookAndFeel.gridView.cardSize}
cacheType="album" cacheType="album"
isModal={rest.isModal} isModal={rest.isModal}
handleFavorite={handleRowFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, { queryKey: ['artist', artistId, musicFolder] })
}
/> />
)} )}
</> </>
@ -811,7 +711,7 @@ const ArtistView = ({ ...rest }: any) => {
dnd dnd
disabledContextMenuOptions={['deletePlaylist', 'viewInModal']} disabledContextMenuOptions={['deletePlaylist', 'viewInModal']}
handleFavorite={(rowData: any) => handleFavorite={(rowData: any) =>
handleMusicRowFavorite(rowData, ['artistTopSongs', data?.title]) handleFavorite(rowData, { queryKey: ['artistTopSongs', data?.title] })
} }
handleRating={(rowData: any, e: number) => handleRating={(rowData: any, e: number) =>
handleRowRating(rowData, e, ['artistTopSongs', data?.title]) handleRowRating(rowData, e, ['artistTopSongs', data?.title])
@ -892,7 +792,7 @@ const ArtistView = ({ ...rest }: any) => {
isModal={false} isModal={false}
miniView={false} miniView={false}
handleFavorite={(rowData: any) => handleFavorite={(rowData: any) =>
handleMusicRowFavorite(rowData, ['artistTopSongs', data.title]) handleFavorite(rowData, { queryKey: ['artistTopSongs', data.title] })
} }
handleRowClick={handleRowClick} handleRowClick={handleRowClick}
handleRowDoubleClick={(e: any) => handleRowDoubleClick(e, topSongs)} handleRowDoubleClick={(e: any) => handleRowDoubleClick(e, topSongs)}
@ -973,7 +873,9 @@ const ArtistView = ({ ...rest }: any) => {
cardSize={config.lookAndFeel.gridView.cardSize} cardSize={config.lookAndFeel.gridView.cardSize}
type="album" type="album"
noScrollbar noScrollbar
handleFavorite={handleRowFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, { queryKey: ['artist', artistId, musicFolder] })
}
/> />
</StyledPanel> </StyledPanel>
)} )}
@ -1032,7 +934,9 @@ const ArtistView = ({ ...rest }: any) => {
cardSize={config.lookAndFeel.gridView.cardSize} cardSize={config.lookAndFeel.gridView.cardSize}
type="album" type="album"
noScrollbar noScrollbar
handleFavorite={handleRowFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, { queryKey: ['artist', artistId, musicFolder] })
}
/> />
</StyledPanel> </StyledPanel>
)} )}
@ -1098,7 +1002,27 @@ const ArtistView = ({ ...rest }: any) => {
cardSize={config.lookAndFeel.gridView.cardSize} cardSize={config.lookAndFeel.gridView.cardSize}
type="artist" type="artist"
noScrollbar noScrollbar
handleFavorite={handleSimilarArtistRowFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, {
custom: () => {
queryClient.setQueryData(
['artist', artistId, musicFolder],
(oldData: any) => {
const starredIndices = _.keys(
_.pickBy(oldData?.info?.similarArtist, { id: rowData.id })
);
starredIndices.forEach((index) => {
oldData.info.similarArtist[index].starred = rowData.starred
? undefined
: Date.now();
});
return oldData;
}
);
},
})
}
/> />
</StyledPanel> </StyledPanel>
)} )}

51
src/components/library/FolderList.tsx

@ -20,6 +20,7 @@ import { apiController } from '../../api/controller';
import { setPlaylistRate } from '../../redux/playlistSlice'; import { setPlaylistRate } from '../../redux/playlistSlice';
import CenterLoader from '../loader/CenterLoader'; import CenterLoader from '../loader/CenterLoader';
import useListClickHandler from '../../hooks/useListClickHandler'; import useListClickHandler from '../../hooks/useListClickHandler';
import useFavorite from '../../hooks/useFavorite';
const FolderList = () => { const FolderList = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -94,37 +95,7 @@ const FolderList = () => {
}, },
}); });
const handleRowFavorite = async (rowData: any) => { const { handleFavorite } = useFavorite();
if (!rowData.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: rowData.id, type: 'album' },
});
queryClient.setQueryData(['folder', folder.currentViewedFolder], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.child, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.child[index].starred = Date.now();
});
return oldData;
});
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'album' },
});
queryClient.setQueryData(['folder', folder.currentViewedFolder], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.child, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.child[index].starred = undefined;
});
return oldData;
});
}
};
const handleRowRating = (rowData: any, e: number) => { const handleRowRating = (rowData: any, e: number) => {
apiController({ apiController({
@ -218,7 +189,23 @@ const FolderList = () => {
fontSize={Number(settings.getSync('musicListFontSize'))} fontSize={Number(settings.getSync('musicListFontSize'))}
handleRowClick={handleRowClick} handleRowClick={handleRowClick}
handleRowDoubleClick={handleRowDoubleClick} handleRowDoubleClick={handleRowDoubleClick}
handleFavorite={handleRowFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, {
custom: () => {
queryClient.setQueryData(
['folder', folder.currentViewedFolder],
(oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.child, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.child[index].starred = rowData.starred ? undefined : Date.now();
});
return oldData;
}
);
},
})
}
handleRating={handleRowRating} handleRating={handleRowRating}
cacheImages={{ cacheImages={{
enabled: settings.getSync('cacheImages'), enabled: settings.getSync('cacheImages'),

41
src/components/library/MusicList.tsx

@ -16,11 +16,12 @@ import { setSearchQuery } from '../../redux/miscSlice';
import { apiController } from '../../api/controller'; import { apiController } from '../../api/controller';
import { Item } from '../../types'; import { Item } from '../../types';
import useColumnSort from '../../hooks/useColumnSort'; import useColumnSort from '../../hooks/useColumnSort';
import { fixPlayer2Index, setPlayQueueByRowClick, setStar } from '../../redux/playQueueSlice'; import { fixPlayer2Index, setPlayQueueByRowClick } from '../../redux/playQueueSlice';
import { setFilter, setPagination } from '../../redux/viewSlice'; import { setFilter, setPagination } from '../../redux/viewSlice';
import { setStatus } from '../../redux/playerSlice'; import { setStatus } from '../../redux/playerSlice';
import useListScroll from '../../hooks/useListScroll'; import useListScroll from '../../hooks/useListScroll';
import useListClickHandler from '../../hooks/useListClickHandler'; import useListClickHandler from '../../hooks/useListClickHandler';
import useFavorite from '../../hooks/useFavorite';
// prettier-ignore // prettier-ignore
export const MUSIC_SORT_TYPES = [ export const MUSIC_SORT_TYPES = [
@ -179,41 +180,7 @@ const MusicList = () => {
setIsRefreshing(false); setIsRefreshing(false);
}; };
const handleRowFavorite = async (rowData: any) => { const { handleFavorite } = useFavorite();
if (!rowData.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: rowData.id, type: 'music' },
});
dispatch(setStar({ id: [rowData.id], type: 'star' }));
queryClient.setQueryData(currentQueryKey, (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.data, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.data[index].starred = Date.now();
});
return oldData;
});
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'music' },
});
dispatch(setStar({ id: [rowData.id], type: 'unstar' }));
queryClient.setQueryData(currentQueryKey, (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.data, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.data[index].starred = undefined;
});
return oldData;
});
}
};
const handleRowRating = (rowData: any, e: number) => { const handleRowRating = (rowData: any, e: number) => {
apiController({ apiController({
@ -316,7 +283,7 @@ const MusicList = () => {
'viewInFolder', 'viewInFolder',
]} ]}
loading={isLoading} loading={isLoading}
handleFavorite={handleRowFavorite} handleFavorite={(rowData: any) => handleFavorite(rowData, { queryKey: currentQueryKey })}
initialScrollOffset={Number(localStorage.getItem('scroll_list_musicList'))} initialScrollOffset={Number(localStorage.getItem('scroll_list_musicList'))}
onScroll={(scrollIndex: number) => { onScroll={(scrollIndex: number) => {
localStorage.setItem('scroll_list_musicList', String(Math.abs(scrollIndex))); localStorage.setItem('scroll_list_musicList', String(Math.abs(scrollIndex)));

51
src/components/player/NowPlayingInfoView.tsx

@ -29,6 +29,7 @@ import Card from '../card/Card';
import { setFilter, setPagination } from '../../redux/viewSlice'; import { setFilter, setPagination } from '../../redux/viewSlice';
import { setPlaylistRate } from '../../redux/playlistSlice'; import { setPlaylistRate } from '../../redux/playlistSlice';
import useListClickHandler from '../../hooks/useListClickHandler'; import useListClickHandler from '../../hooks/useListClickHandler';
import useFavorite from '../../hooks/useFavorite';
const NowPlayingInfoView = () => { const NowPlayingInfoView = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -94,24 +95,7 @@ const NowPlayingInfoView = () => {
}, },
}); });
const handleRowFavorite = async (rowData: any, queryKey: any) => { const { handleFavorite } = useFavorite();
console.log(rowData);
if (!rowData.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: rowData.id, type: rowData.type },
});
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: rowData.type },
});
}
await queryClient.refetchQueries(queryKey);
};
const handleRowRating = async (rowData: any, e: number) => { const handleRowRating = async (rowData: any, e: number) => {
apiController({ apiController({
@ -298,12 +282,9 @@ const NowPlayingInfoView = () => {
miniView={false} miniView={false}
loading={isLoadingSimilarToSong} loading={isLoadingSimilarToSong}
handleFavorite={(rowData: any) => handleFavorite={(rowData: any) =>
handleRowFavorite(rowData, [ handleFavorite(rowData, {
'similarSongs', queryKey: ['similarSongs', currentArtistId, musicFolder, 50],
currentArtistId, })
musicFolder,
50,
])
} }
handleRowClick={handleRowClick} handleRowClick={handleRowClick}
handleRowDoubleClick={(e: any) => handleRowDoubleClick(e)} handleRowDoubleClick={(e: any) => handleRowDoubleClick(e)}
@ -339,7 +320,7 @@ const NowPlayingInfoView = () => {
type="album" type="album"
noScrollbar noScrollbar
handleFavorite={(rowData: any) => handleFavorite={(rowData: any) =>
handleRowFavorite(rowData, ['artist', currentArtistId, musicFolder]) handleFavorite(rowData, { queryKey: ['artist', currentArtistId, musicFolder] })
} }
/> />
</InfoViewPanel> </InfoViewPanel>
@ -359,7 +340,25 @@ const NowPlayingInfoView = () => {
type="artist" type="artist"
noScrollbar noScrollbar
handleFavorite={(rowData: any) => handleFavorite={(rowData: any) =>
handleRowFavorite(rowData, ['artist', currentArtistId, musicFolder]) handleFavorite(rowData, {
custom: () => {
queryClient.setQueryData(
['artist', currentArtistId, musicFolder],
(oldData: any) => {
const starredIndices = _.keys(
_.pickBy(oldData?.info?.similarArtist, { id: rowData.id })
);
starredIndices.forEach((index) => {
oldData.info.similarArtist[index].starred = rowData.starred
? undefined
: Date.now();
});
return oldData;
}
);
},
})
} }
/> />
</InfoViewPanel> </InfoViewPanel>

22
src/components/player/NowPlayingMiniView.tsx

@ -14,7 +14,6 @@ import {
toggleShuffle, toggleShuffle,
setPlaybackSetting, setPlaybackSetting,
removeFromPlayQueue, removeFromPlayQueue,
setStar,
setPlayQueue, setPlayQueue,
appendPlayQueue, appendPlayQueue,
moveToTop, moveToTop,
@ -52,6 +51,7 @@ import { apiController } from '../../api/controller';
import { Server, Song } from '../../types'; import { Server, Song } from '../../types';
import useListClickHandler from '../../hooks/useListClickHandler'; import useListClickHandler from '../../hooks/useListClickHandler';
import Popup from '../shared/Popup'; import Popup from '../shared/Popup';
import useFavorite from '../../hooks/useFavorite';
const NowPlayingMiniView = () => { const NowPlayingMiniView = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -216,23 +216,7 @@ const NowPlayingMiniView = () => {
return notifyToast('warning', t('No songs found, adjust your filters')); return notifyToast('warning', t('No songs found, adjust your filters'));
}; };
const handleRowFavorite = async (rowData: any) => { const { handleFavorite } = useFavorite();
if (!rowData.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: rowData.id, type: 'music' },
});
dispatch(setStar({ id: [rowData.id], type: 'star' }));
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'music' },
});
dispatch(setStar({ id: [rowData.id], type: 'unstar' }));
}
};
return ( return (
<> <>
@ -474,7 +458,7 @@ const NowPlayingMiniView = () => {
nowPlaying nowPlaying
dnd dnd
disabledContextMenuOptions={['deletePlaylist', 'viewInModal']} disabledContextMenuOptions={['deletePlaylist', 'viewInModal']}
handleFavorite={handleRowFavorite} handleFavorite={handleFavorite}
/> />
</GenericPage> </GenericPage>
</MiniViewContainer> </MiniViewContainer>

22
src/components/player/NowPlayingView.tsx

@ -16,7 +16,6 @@ import {
removeFromPlayQueue, removeFromPlayQueue,
setPlayQueue, setPlayQueue,
appendPlayQueue, appendPlayQueue,
setStar,
setRate, setRate,
moveToTop, moveToTop,
moveToBottom, moveToBottom,
@ -57,6 +56,7 @@ import NowPlayingInfoView from './NowPlayingInfoView';
import CenterLoader from '../loader/CenterLoader'; import CenterLoader from '../loader/CenterLoader';
import useListClickHandler from '../../hooks/useListClickHandler'; import useListClickHandler from '../../hooks/useListClickHandler';
import Popup from '../shared/Popup'; import Popup from '../shared/Popup';
import useFavorite from '../../hooks/useFavorite';
const NowPlayingView = () => { const NowPlayingView = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -229,23 +229,7 @@ const NowPlayingView = () => {
return notifyToast('warning', t('No songs found, adjust your filters')); return notifyToast('warning', t('No songs found, adjust your filters'));
}; };
const handleRowFavorite = async (rowData: any) => { const { handleFavorite } = useFavorite();
if (!rowData.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: rowData.id, type: 'music' },
});
dispatch(setStar({ id: [rowData.id], type: 'star' }));
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'music' },
});
dispatch(setStar({ id: [rowData.id], type: 'unstar' }));
}
};
const handleRowRating = (rowData: any, e: number) => { const handleRowRating = (rowData: any, e: number) => {
apiController({ apiController({
@ -529,7 +513,7 @@ const NowPlayingView = () => {
nowPlaying nowPlaying
dnd dnd
disabledContextMenuOptions={['deletePlaylist', 'viewInModal']} disabledContextMenuOptions={['deletePlaylist', 'viewInModal']}
handleFavorite={handleRowFavorite} handleFavorite={handleFavorite}
handleRating={handleRowRating} handleRating={handleRowRating}
initialScrollOffset={ initialScrollOffset={
playQueue.scrollWithCurrentSong playQueue.scrollWithCurrentSong

71
src/components/player/PlayerBar.tsx

@ -19,7 +19,7 @@ import {
LinkButton, LinkButton,
CoverArtContainer, CoverArtContainer,
} from './styled'; } from './styled';
import { setVolume, setStar, setRate } from '../../redux/playQueueSlice'; import { setVolume, setRate } from '../../redux/playQueueSlice';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import Player from './Player'; import Player from './Player';
import CustomTooltip from '../shared/CustomTooltip'; import CustomTooltip from '../shared/CustomTooltip';
@ -36,6 +36,7 @@ import useGetLyrics from '../../hooks/useGetLyrics';
import usePlayerControls from '../../hooks/usePlayerControls'; import usePlayerControls from '../../hooks/usePlayerControls';
import { setSidebar } from '../../redux/configSlice'; import { setSidebar } from '../../redux/configSlice';
import Popup from '../shared/Popup'; import Popup from '../shared/Popup';
import useFavorite from '../../hooks/useFavorite';
const DiscordRPC = require('discord-rpc'); const DiscordRPC = require('discord-rpc');
@ -295,43 +296,7 @@ const PlayerBar = () => {
return () => clearTimeout(debounce); return () => clearTimeout(debounce);
}, [config.serverType, isDragging, manualSeek, playQueue.currentPlayer]); }, [config.serverType, isDragging, manualSeek, playQueue.currentPlayer]);
const handleFavorite = async () => { const { handleFavorite } = useFavorite();
if (!playQueue[currentEntryList][playQueue.currentIndex].starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: playQueue[currentEntryList][playQueue.currentIndex].id, type: 'music' },
});
dispatch(
setStar({
id: [playQueue[currentEntryList][playQueue.currentIndex].id],
type: 'star',
})
);
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: playQueue[currentEntryList][playQueue.currentIndex].id, type: 'music' },
});
dispatch(
setStar({
id: [playQueue[currentEntryList][playQueue.currentIndex].id],
type: 'unstar',
})
);
}
await queryClient.refetchQueries(['album'], {
active: true,
});
await queryClient.refetchQueries(['starred'], {
active: true,
});
await queryClient.refetchQueries(['playlist'], {
active: true,
});
};
const handleRating = (e: number) => { const handleRating = (e: number) => {
apiController({ apiController({
@ -710,10 +675,36 @@ const PlayerBar = () => {
? 'true' ? 'true'
: 'false' : 'false'
} }
onClick={handleFavorite} onClick={() =>
handleFavorite(playQueue[currentEntryList][playQueue.currentIndex], {
custom: async () => {
await queryClient.refetchQueries(['album'], {
active: true,
});
await queryClient.refetchQueries(['starred'], {
active: true,
});
await queryClient.refetchQueries(['playlist'], {
active: true,
});
},
})
}
onKeyDown={(e: any) => { onKeyDown={(e: any) => {
if (e.key === ' ') { if (e.key === ' ') {
handleFavorite(); handleFavorite(playQueue[currentEntryList][playQueue.currentIndex].id, {
custom: async () => {
await queryClient.refetchQueries(['album'], {
active: true,
});
await queryClient.refetchQueries(['starred'], {
active: true,
});
await queryClient.refetchQueries(['playlist'], {
active: true,
});
},
});
} }
}} }}
/> />

57
src/components/playlist/PlaylistView.tsx

@ -18,12 +18,7 @@ import {
UndoButton, UndoButton,
} from '../shared/ToolbarButtons'; } from '../shared/ToolbarButtons';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import { import { fixPlayer2Index, setPlayQueueByRowClick, setRate } from '../../redux/playQueueSlice';
fixPlayer2Index,
setPlayQueueByRowClick,
setStar,
setRate,
} from '../../redux/playQueueSlice';
import { clearSelected } from '../../redux/multiSelectSlice'; import { clearSelected } from '../../redux/multiSelectSlice';
import { import {
createRecoveryFile, createRecoveryFile,
@ -45,12 +40,7 @@ import { setStatus } from '../../redux/playerSlice';
import { notifyToast } from '../shared/toast'; import { notifyToast } from '../shared/toast';
import { addProcessingPlaylist, removeProcessingPlaylist } from '../../redux/miscSlice'; import { addProcessingPlaylist, removeProcessingPlaylist } from '../../redux/miscSlice';
import { StyledButton, StyledCheckbox, StyledInput, StyledLink } from '../shared/styled'; import { StyledButton, StyledCheckbox, StyledInput, StyledLink } from '../shared/styled';
import { import { removeFromPlaylist, setPlaylistData, setPlaylistRate } from '../../redux/playlistSlice';
removeFromPlaylist,
setPlaylistData,
setPlaylistRate,
setPlaylistStar,
} from '../../redux/playlistSlice';
import { PageHeaderSubtitleDataLine } from '../layout/styled'; import { PageHeaderSubtitleDataLine } from '../layout/styled';
import CustomTooltip from '../shared/CustomTooltip'; import CustomTooltip from '../shared/CustomTooltip';
import { apiController } from '../../api/controller'; import { apiController } from '../../api/controller';
@ -60,6 +50,7 @@ import CenterLoader from '../loader/CenterLoader';
import useListClickHandler from '../../hooks/useListClickHandler'; import useListClickHandler from '../../hooks/useListClickHandler';
import Popup from '../shared/Popup'; import Popup from '../shared/Popup';
import usePlayQueueHandler from '../../hooks/usePlayQueueHandler'; import usePlayQueueHandler from '../../hooks/usePlayQueueHandler';
import useFavorite from '../../hooks/useFavorite';
interface PlaylistParams { interface PlaylistParams {
id: string; id: string;
@ -359,43 +350,7 @@ const PlaylistView = ({ ...rest }) => {
} }
}; };
const handleRowFavorite = async (rowData: any) => { const { handleFavorite } = useFavorite();
if (!rowData.starred) {
await apiController({
serverType: config.serverType,
endpoint: 'star',
args: { id: rowData.id, type: 'music' },
});
dispatch(setStar({ id: [rowData.id], type: 'star' }));
dispatch(setPlaylistStar({ id: [rowData.id], type: 'star' }));
queryClient.setQueryData(['playlist', playlistId], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.song, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.song[index].starred = Date.now();
});
return oldData;
});
} else {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'music' },
});
dispatch(setStar({ id: [rowData.id], type: 'unstar' }));
dispatch(setPlaylistStar({ id: [rowData.id], type: 'unstar' }));
queryClient.setQueryData(['playlist', playlistId], (oldData: any) => {
const starredIndices = _.keys(_.pickBy(oldData.song, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.song[index].starred = undefined;
});
return oldData;
});
}
};
const handleRowRating = (rowData: any, e: number) => { const handleRowRating = (rowData: any, e: number) => {
apiController({ apiController({
@ -653,7 +608,9 @@ const PlaylistView = ({ ...rest }) => {
dnd dnd
isModal={rest.isModal} isModal={rest.isModal}
disabledContextMenuOptions={['deletePlaylist', 'viewInModal']} disabledContextMenuOptions={['deletePlaylist', 'viewInModal']}
handleFavorite={handleRowFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, { queryKey: ['playlist', playlistId] })
}
handleRating={handleRowRating} handleRating={handleRowRating}
loading={isLoading} loading={isLoading}
/> />

44
src/components/search/SearchView.tsx

@ -3,7 +3,7 @@ import _ from 'lodash';
import settings from 'electron-settings'; import settings from 'electron-settings';
import { Icon, Nav } from 'rsuite'; import { Icon, Nav } from 'rsuite';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { useInfiniteQuery } from 'react-query'; import { useInfiniteQuery, useQueryClient } from 'react-query';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import useRouterQuery from '../../hooks/useRouterQuery'; import useRouterQuery from '../../hooks/useRouterQuery';
import GenericPage from '../layout/GenericPage'; import GenericPage from '../layout/GenericPage';
@ -22,10 +22,12 @@ import { apiController } from '../../api/controller';
import { Album, Artist, Item, Song } from '../../types'; import { Album, Artist, Item, Song } from '../../types';
import useListClickHandler from '../../hooks/useListClickHandler'; import useListClickHandler from '../../hooks/useListClickHandler';
import ListViewType from '../viewtypes/ListViewType'; import ListViewType from '../viewtypes/ListViewType';
import useFavorite from '../../hooks/useFavorite';
const SearchView = () => { const SearchView = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const queryClient = useQueryClient();
const history = useHistory(); const history = useHistory();
const query = useRouterQuery(); const query = useRouterQuery();
const urlQuery = query.get('query') || ''; const urlQuery = query.get('query') || '';
@ -58,8 +60,6 @@ const SearchView = () => {
[history] [history]
); );
useEffect(() => {});
const { const {
data: songResults, data: songResults,
isLoading: isLoadingSongs, isLoading: isLoadingSongs,
@ -174,6 +174,8 @@ const SearchView = () => {
); );
}, [artistResults]); }, [artistResults]);
const { handleFavorite } = useFavorite();
const { handleRowClick, handleRowDoubleClick } = useListClickHandler({ const { handleRowClick, handleRowDoubleClick } = useListClickHandler({
doubleClick: (rowData: any) => { doubleClick: (rowData: any) => {
if (rowData.isDir) { if (rowData.isDir) {
@ -314,7 +316,17 @@ const SearchView = () => {
handleRowClick={handleRowClick} handleRowClick={handleRowClick}
handleRowDoubleClick={handleRowDoubleClick} handleRowDoubleClick={handleRowDoubleClick}
handleRating={() => {}} handleRating={() => {}}
handleFavorite={() => {}} handleFavorite={(rowData: any) =>
handleFavorite(rowData, {
custom: () =>
queryClient.refetchQueries([
'searchpage',
debouncedSearchQuery,
{ type: Item.Music, count: 50 },
musicFolder.id,
]),
})
}
listType="music" listType="music"
cacheImages={{ cacheImages={{
enabled: settings.getSync('cacheImages'), enabled: settings.getSync('cacheImages'),
@ -341,7 +353,17 @@ const SearchView = () => {
handleRowClick={handleAlbumRowClick} handleRowClick={handleAlbumRowClick}
handleRowDoubleClick={handleAlbumRowDoubleClick} handleRowDoubleClick={handleAlbumRowDoubleClick}
handleRating={() => {}} handleRating={() => {}}
handleFavorite={() => {}} handleFavorite={(rowData: any) =>
handleFavorite(rowData, {
custom: () =>
queryClient.refetchQueries([
'searchpage',
debouncedSearchQuery,
{ type: Item.Album, count: 25 },
musicFolder.id,
]),
})
}
listType="album" listType="album"
cacheImages={{ cacheImages={{
enabled: settings.getSync('cacheImages'), enabled: settings.getSync('cacheImages'),
@ -368,7 +390,17 @@ const SearchView = () => {
handleRowClick={handleArtistRowClick} handleRowClick={handleArtistRowClick}
handleRowDoubleClick={handleArtistRowDoubleClick} handleRowDoubleClick={handleArtistRowDoubleClick}
handleRating={() => {}} handleRating={() => {}}
handleFavorite={() => {}} handleFavorite={(rowData: any) =>
handleFavorite(rowData, {
custom: () =>
queryClient.refetchQueries([
'searchpage',
debouncedSearchQuery,
{ type: Item.Artist, count: 15 },
musicFolder.id,
]),
})
}
listType="artist" listType="artist"
cacheImages={{ cacheImages={{
enabled: settings.getSync('cacheImages'), enabled: settings.getSync('cacheImages'),

92
src/components/starred/StarredView.tsx

@ -6,12 +6,7 @@ import settings from 'electron-settings';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import useSearchQuery from '../../hooks/useSearchQuery'; import useSearchQuery from '../../hooks/useSearchQuery';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import { import { fixPlayer2Index, setPlayQueueByRowClick, setRate } from '../../redux/playQueueSlice';
fixPlayer2Index,
setPlayQueueByRowClick,
setRate,
setStar,
} from '../../redux/playQueueSlice';
import GenericPage from '../layout/GenericPage'; import GenericPage from '../layout/GenericPage';
import GenericPageHeader from '../layout/GenericPageHeader'; import GenericPageHeader from '../layout/GenericPageHeader';
import ListViewType from '../viewtypes/ListViewType'; import ListViewType from '../viewtypes/ListViewType';
@ -27,6 +22,7 @@ import { FilterButton } from '../shared/ToolbarButtons';
import ColumnSortPopover from '../shared/ColumnSortPopover'; import ColumnSortPopover from '../shared/ColumnSortPopover';
import CenterLoader from '../loader/CenterLoader'; import CenterLoader from '../loader/CenterLoader';
import useListClickHandler from '../../hooks/useListClickHandler'; import useListClickHandler from '../../hooks/useListClickHandler';
import useFavorite from '../../hooks/useFavorite';
const StarredView = () => { const StarredView = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -96,39 +92,7 @@ const StarredView = () => {
}, },
}); });
const handleRowFavorite = async (rowData: any) => { const { handleFavorite } = useFavorite();
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'music' },
});
dispatch(setStar({ id: [rowData.id], type: 'unstar' }));
await queryClient.refetchQueries(['starred', musicFolder], {
active: true,
});
};
const handleRowFavoriteAlbum = async (rowData: any) => {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'album' },
});
await queryClient.refetchQueries(['starred', musicFolder], {
active: true,
});
};
const handleRowFavoriteArtist = async (rowData: any) => {
await apiController({
serverType: config.serverType,
endpoint: 'unstar',
args: { id: rowData.id, type: 'artist' },
});
await queryClient.refetchQueries(['starred', musicFolder], {
active: true,
});
};
const handleRowRating = async (rowData: any, e: number) => { const handleRowRating = async (rowData: any, e: number) => {
apiController({ apiController({
@ -323,7 +287,15 @@ const StarredView = () => {
'deletePlaylist', 'deletePlaylist',
'viewInModal', 'viewInModal',
]} ]}
handleFavorite={handleRowFavorite} handleFavorite={(rowData: any) =>
handleFavorite(rowData, {
custom: async () => {
await queryClient.refetchQueries(['starred', musicFolder], {
active: true,
});
},
})
}
initialScrollOffset={Number(localStorage.getItem('scroll_list_starredMusicList'))} initialScrollOffset={Number(localStorage.getItem('scroll_list_starredMusicList'))}
onScroll={(scrollIndex: number) => { onScroll={(scrollIndex: number) => {
localStorage.setItem('scroll_list_starredMusicList', String(Math.abs(scrollIndex))); localStorage.setItem('scroll_list_starredMusicList', String(Math.abs(scrollIndex)));
@ -355,7 +327,15 @@ const StarredView = () => {
'moveSelectedTo', 'moveSelectedTo',
'deletePlaylist', 'deletePlaylist',
]} ]}
handleFavorite={handleRowFavoriteAlbum} handleFavorite={(rowData: any) =>
handleFavorite(rowData, {
custom: async () => {
await queryClient.refetchQueries(['starred', musicFolder], {
active: true,
});
},
})
}
initialScrollOffset={Number(localStorage.getItem('scroll_list_starredAlbumList'))} initialScrollOffset={Number(localStorage.getItem('scroll_list_starredAlbumList'))}
onScroll={(scrollIndex: number) => { onScroll={(scrollIndex: number) => {
localStorage.setItem( localStorage.setItem(
@ -383,7 +363,15 @@ const StarredView = () => {
playClick={{ type: 'album', idProperty: 'id' }} playClick={{ type: 'album', idProperty: 'id' }}
size={config.lookAndFeel.gridView.cardSize} size={config.lookAndFeel.gridView.cardSize}
cacheType="album" cacheType="album"
handleFavorite={handleRowFavoriteAlbum} handleFavorite={(rowData: any) =>
handleFavorite(rowData, {
custom: async () => {
await queryClient.refetchQueries(['starred', musicFolder], {
active: true,
});
},
})
}
initialScrollOffset={Number(localStorage.getItem('scroll_grid_starredAlbumList'))} initialScrollOffset={Number(localStorage.getItem('scroll_grid_starredAlbumList'))}
onScroll={(scrollIndex: number) => { onScroll={(scrollIndex: number) => {
localStorage.setItem('scroll_grid_starredAlbumList', String(scrollIndex)); localStorage.setItem('scroll_grid_starredAlbumList', String(scrollIndex));
@ -418,7 +406,15 @@ const StarredView = () => {
'addToPlaylist', 'addToPlaylist',
'deletePlaylist', 'deletePlaylist',
]} ]}
handleFavorite={handleRowFavoriteArtist} handleFavorite={(rowData: any) =>
handleFavorite(rowData, {
custom: async () => {
await queryClient.refetchQueries(['starred', musicFolder], {
active: true,
});
},
})
}
initialScrollOffset={Number( initialScrollOffset={Number(
localStorage.getItem('scroll_list_starredArtistList') localStorage.getItem('scroll_list_starredArtistList')
)} )}
@ -446,7 +442,15 @@ const StarredView = () => {
playClick={{ type: 'artist', idProperty: 'id' }} playClick={{ type: 'artist', idProperty: 'id' }}
size={config.lookAndFeel.gridView.cardSize} size={config.lookAndFeel.gridView.cardSize}
cacheType="artist" cacheType="artist"
handleFavorite={handleRowFavoriteArtist} handleFavorite={(rowData: any) =>
handleFavorite(rowData, {
custom: async () => {
await queryClient.refetchQueries(['starred', musicFolder], {
active: true,
});
},
})
}
initialScrollOffset={Number( initialScrollOffset={Number(
localStorage.getItem('scroll_grid_starredArtistList') localStorage.getItem('scroll_grid_starredArtistList')
)} )}

75
src/hooks/useFavorite.ts

@ -0,0 +1,75 @@
import _ from 'lodash';
import { useCallback } from 'react';
import { useQueryClient } from 'react-query';
import { useAppDispatch, useAppSelector } from '../redux/hooks';
import { apiController } from '../api/controller';
import { setStar } from '../redux/playQueueSlice';
import { setPlaylistStar } from '../redux/playlistSlice';
const useFavorite = () => {
const dispatch = useAppDispatch();
const config = useAppSelector((state) => state.config);
const queryClient = useQueryClient();
const handleFavorite = useCallback(
async (rowData, options?: { queryKey?: any; custom?: any }) => {
const favorite = !rowData.starred;
await apiController({
serverType: config.serverType,
endpoint: favorite ? 'star' : 'unstar',
args: { id: rowData.id, type: rowData.type },
});
if (options?.queryKey) {
queryClient.setQueryData(options.queryKey, (oldData: any) => {
if (oldData?.data) {
const starredIndices = _.keys(_.pickBy(oldData.data, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.data[index].starred = favorite ? Date.now() : undefined;
});
return oldData;
}
if (oldData?.album) {
const starredIndices = _.keys(_.pickBy(oldData.album, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.album[index].starred = favorite ? Date.now() : undefined;
});
return oldData;
}
if (oldData?.song) {
const starredIndices = _.keys(_.pickBy(oldData.song, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData.song[index].starred = favorite ? Date.now() : undefined;
});
return oldData;
}
const starredIndices = _.keys(_.pickBy(oldData, { id: rowData.id }));
starredIndices.forEach((index) => {
oldData[index].starred = favorite ? Date.now() : undefined;
});
return oldData;
});
}
if (options?.custom) {
options.custom();
}
dispatch(setStar({ id: [rowData.id], type: favorite ? 'star' : 'unstar' }));
dispatch(setPlaylistStar({ id: [rowData.id], type: favorite ? 'star' : 'unstar' }));
},
[config.serverType, dispatch, queryClient]
);
return { handleFavorite };
};
export default useFavorite;
Loading…
Cancel
Save