Browse Source

Refactor list click/doubleclick to hook

master
jeffvli 3 years ago
committed by Jeff
parent
commit
b58d2c677a
  1. 33
      src/components/library/AlbumList.tsx
  2. 55
      src/components/library/AlbumView.tsx
  3. 33
      src/components/library/ArtistList.tsx
  4. 78
      src/components/library/ArtistView.tsx
  5. 67
      src/components/library/FolderList.tsx
  6. 48
      src/components/library/GenreList.tsx
  7. 55
      src/components/library/MusicList.tsx
  8. 55
      src/components/player/NowPlayingInfoView.tsx
  9. 36
      src/components/player/NowPlayingMiniView.tsx
  10. 36
      src/components/player/NowPlayingView.tsx
  11. 33
      src/components/playlist/PlaylistList.tsx
  12. 57
      src/components/playlist/PlaylistView.tsx
  13. 63
      src/components/search/SearchView.tsx
  14. 24
      src/components/settings/ConfigPanels/ListViewConfig.tsx
  15. 67
      src/components/starred/StarredView.tsx
  16. 52
      src/hooks/useListClickHandler.ts

33
src/components/library/AlbumList.tsx

@ -12,12 +12,6 @@ import useSearchQuery from '../../hooks/useSearchQuery';
import GenericPageHeader from '../layout/GenericPageHeader'; import GenericPageHeader from '../layout/GenericPageHeader';
import GenericPage from '../layout/GenericPage'; import GenericPage from '../layout/GenericPage';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import {
toggleSelected,
setRangeSelected,
toggleRangeSelected,
clearSelected,
} from '../../redux/multiSelectSlice';
import { import {
StyledInputPicker, StyledInputPicker,
StyledInputPickerContainer, StyledInputPickerContainer,
@ -36,6 +30,7 @@ import useColumnSort from '../../hooks/useColumnSort';
import { setFilter, setPagination, setAdvancedFilters, setColumnSort } from '../../redux/viewSlice'; import { setFilter, setPagination, setAdvancedFilters, setColumnSort } from '../../redux/viewSlice';
import useGridScroll from '../../hooks/useGridScroll'; import useGridScroll from '../../hooks/useGridScroll';
import useListScroll from '../../hooks/useListScroll'; import useListScroll from '../../hooks/useListScroll';
import useListClickHandler from '../../hooks/useListClickHandler';
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') },
@ -205,29 +200,9 @@ const AlbumList = () => {
} }
}, [albums, config.serverType, dispatch, sortedData?.length, view.album.pagination]); }, [albums, config.serverType, dispatch, sortedData?.length, view.album.pagination]);
let timeout: any = null; const { handleRowClick, handleRowDoubleClick } = useListClickHandler({
const handleRowClick = (e: any, rowData: any, tableData: any) => { doubleClick: (rowData: any) => history.push(`/library/album/${rowData.id}`),
if (timeout === null) { });
timeout = window.setTimeout(() => {
timeout = null;
if (e.ctrlKey) {
dispatch(toggleSelected(rowData));
} else if (e.shiftKey) {
dispatch(setRangeSelected(rowData));
dispatch(toggleRangeSelected(tableData));
}
}, 100);
}
};
const handleRowDoubleClick = (rowData: any) => {
window.clearTimeout(timeout);
timeout = null;
dispatch(clearSelected());
history.push(`/library/album/${rowData.id}`);
};
const handleRefresh = async () => { const handleRefresh = async () => {
setIsRefreshing(true); setIsRefreshing(true);

55
src/components/library/AlbumView.tsx

@ -24,12 +24,6 @@ import {
setRate, setRate,
setStar, setStar,
} from '../../redux/playQueueSlice'; } from '../../redux/playQueueSlice';
import {
toggleSelected,
setRangeSelected,
toggleRangeSelected,
clearSelected,
} from '../../redux/multiSelectSlice';
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';
@ -63,6 +57,7 @@ import { setPlaylistRate } from '../../redux/playlistSlice';
import Card from '../card/Card'; import Card from '../card/Card';
import { setFilter, setPagination } from '../../redux/viewSlice'; import { setFilter, setPagination } from '../../redux/viewSlice';
import CenterLoader from '../loader/CenterLoader'; import CenterLoader from '../loader/CenterLoader';
import useListClickHandler from '../../hooks/useListClickHandler';
interface AlbumParams { interface AlbumParams {
id: string; id: string;
@ -97,39 +92,21 @@ const AlbumView = ({ ...rest }: any) => {
'path', 'path',
]); ]);
let timeout: any = null; const { handleRowClick, handleRowDoubleClick } = useListClickHandler({
const handleRowClick = (e: any, rowData: any, tableData: any) => { doubleClick: (rowData: any) => {
if (timeout === null) { dispatch(
timeout = window.setTimeout(() => { setPlayQueueByRowClick({
timeout = null; entries: data.song,
currentIndex: rowData.rowIndex,
if (e.ctrlKey) { currentSongId: rowData.id,
dispatch(toggleSelected(rowData)); uniqueSongId: rowData.uniqueId,
} else if (e.shiftKey) { filters: config.playback.filters,
dispatch(setRangeSelected(rowData)); })
dispatch(toggleRangeSelected(tableData)); );
} dispatch(setStatus('PLAYING'));
}, 100); dispatch(fixPlayer2Index());
} },
}; });
const handleRowDoubleClick = (rowData: any) => {
window.clearTimeout(timeout);
timeout = null;
dispatch(clearSelected());
dispatch(
setPlayQueueByRowClick({
entries: data.song,
currentIndex: rowData.rowIndex,
currentSongId: rowData.id,
uniqueSongId: rowData.uniqueId,
filters: config.playback.filters,
})
);
dispatch(setStatus('PLAYING'));
dispatch(fixPlayer2Index());
};
const handlePlay = () => { const handlePlay = () => {
const songs = filterPlayQueue(config.playback.filters, data.song); const songs = filterPlayQueue(config.playback.filters, data.song);

33
src/components/library/ArtistList.tsx

@ -10,12 +10,6 @@ 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';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import {
clearSelected,
setRangeSelected,
toggleRangeSelected,
toggleSelected,
} from '../../redux/multiSelectSlice';
import GridViewType from '../viewtypes/GridViewType'; import GridViewType from '../viewtypes/GridViewType';
import { FilterButton, RefreshButton } from '../shared/ToolbarButtons'; import { FilterButton, RefreshButton } from '../shared/ToolbarButtons';
import { apiController } from '../../api/controller'; import { apiController } from '../../api/controller';
@ -24,6 +18,7 @@ import ColumnSortPopover from '../shared/ColumnSortPopover';
import useColumnSort from '../../hooks/useColumnSort'; 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';
const ArtistList = () => { const ArtistList = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -60,29 +55,9 @@ const ArtistList = () => {
const filteredData = useSearchQuery(misc.searchQuery, artists, ['title']); const filteredData = useSearchQuery(misc.searchQuery, artists, ['title']);
const { sortedData, sortColumns } = useColumnSort(artists, Item.Artist, artist.active.list.sort); const { sortedData, sortColumns } = useColumnSort(artists, Item.Artist, artist.active.list.sort);
let timeout: any = null; const { handleRowClick, handleRowDoubleClick } = useListClickHandler({
const handleRowClick = (e: any, rowData: any, tableData: any) => { doubleClick: (rowData: any) => history.push(`/library/artist/${rowData.id}`),
if (timeout === null) { });
timeout = window.setTimeout(() => {
timeout = null;
if (e.ctrlKey) {
dispatch(toggleSelected(rowData));
} else if (e.shiftKey) {
dispatch(setRangeSelected(rowData));
dispatch(toggleRangeSelected(tableData));
}
}, 100);
}
};
const handleRowDoubleClick = (rowData: any) => {
window.clearTimeout(timeout);
timeout = null;
dispatch(clearSelected());
history.push(`/library/artist/${rowData.id}`);
};
const handleRefresh = async () => { const handleRefresh = async () => {
setIsRefreshing(true); setIsRefreshing(true);

78
src/components/library/ArtistView.tsx

@ -17,12 +17,6 @@ import {
PlayButton, PlayButton,
} from '../shared/ToolbarButtons'; } from '../shared/ToolbarButtons';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import {
toggleSelected,
setRangeSelected,
toggleRangeSelected,
clearSelected,
} from '../../redux/multiSelectSlice';
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';
@ -63,6 +57,7 @@ import { setPlaylistRate } from '../../redux/playlistSlice';
import CustomTooltip from '../shared/CustomTooltip'; import CustomTooltip from '../shared/CustomTooltip';
import { setFilter, setPagination } from '../../redux/viewSlice'; import { setFilter, setPagination } from '../../redux/viewSlice';
import CenterLoader from '../loader/CenterLoader'; import CenterLoader from '../loader/CenterLoader';
import useListClickHandler from '../../hooks/useListClickHandler';
const fac = new FastAverageColor(); const fac = new FastAverageColor();
@ -151,50 +146,31 @@ const ArtistView = ({ ...rest }: any) => {
} }
}, [artistId, history, rest.isModal]); }, [artistId, history, rest.isModal]);
let timeout: any = null; const { handleRowClick, handleRowDoubleClick } = useListClickHandler({
const handleRowClick = (e: any, rowData: any, tableData: any) => { doubleClick: (rowData: any, songs: any) => {
if (timeout === null) { if (rowData.type === Item.Album) {
timeout = window.setTimeout(() => { history.push(`/library/album/${rowData.id}`);
timeout = null; }
if (e.ctrlKey) { if (rowData.type === Item.Music) {
dispatch(toggleSelected(rowData)); if (rowData.isDir) {
} else if (e.shiftKey) { history.push(`/library/folder?folderId=${rowData.parent}`);
dispatch(setRangeSelected(rowData)); } else {
dispatch(toggleRangeSelected(tableData)); dispatch(
setPlayQueueByRowClick({
entries: songs.filter((entry: any) => entry.isDir !== true),
currentIndex: rowData.rowIndex,
currentSongId: rowData.id,
uniqueSongId: rowData.uniqueId,
filters: config.playback.filters,
})
);
dispatch(setStatus('PLAYING'));
dispatch(fixPlayer2Index());
} }
}, 100); }
} },
}; });
const handleRowDoubleClick = (rowData: any) => {
window.clearTimeout(timeout);
timeout = null;
dispatch(clearSelected());
history.push(`/library/album/${rowData.id}`);
};
const handleMusicRowDoubleClick = (rowData: any, songs: any[]) => {
window.clearTimeout(timeout);
timeout = null;
dispatch(clearSelected());
if (rowData.isDir) {
history.push(`/library/folder?folderId=${rowData.parent}`);
} else {
dispatch(
setPlayQueueByRowClick({
entries: songs.filter((entry: any) => entry.isDir !== true),
currentIndex: rowData.rowIndex,
currentSongId: rowData.id,
uniqueSongId: rowData.uniqueId,
filters: config.playback.filters,
})
);
dispatch(setStatus('PLAYING'));
dispatch(fixPlayer2Index());
}
};
const handleFavorite = async () => { const handleFavorite = async () => {
if (!data.starred) { if (!data.starred) {
@ -789,7 +765,7 @@ const ArtistView = ({ ...rest }: any) => {
data={allSongs || []} data={allSongs || []}
tableColumns={config.lookAndFeel.listView.music.columns} tableColumns={config.lookAndFeel.listView.music.columns}
handleRowClick={handleRowClick} handleRowClick={handleRowClick}
handleRowDoubleClick={(e: any) => handleMusicRowDoubleClick(e, allSongs)} handleRowDoubleClick={(e: any) => handleRowDoubleClick(e, allSongs)}
virtualized virtualized
rowHeight={config.lookAndFeel.listView.music.rowHeight} rowHeight={config.lookAndFeel.listView.music.rowHeight}
fontSize={config.lookAndFeel.listView.music.fontSize} fontSize={config.lookAndFeel.listView.music.fontSize}
@ -874,7 +850,7 @@ const ArtistView = ({ ...rest }: any) => {
data={topSongs || []} data={topSongs || []}
tableColumns={config.lookAndFeel.listView.music.columns} tableColumns={config.lookAndFeel.listView.music.columns}
handleRowClick={handleRowClick} handleRowClick={handleRowClick}
handleRowDoubleClick={(e: any) => handleMusicRowDoubleClick(e, topSongs)} handleRowDoubleClick={(e: any) => handleRowDoubleClick(e, topSongs)}
virtualized virtualized
rowHeight={config.lookAndFeel.listView.music.rowHeight} rowHeight={config.lookAndFeel.listView.music.rowHeight}
fontSize={config.lookAndFeel.listView.music.fontSize} fontSize={config.lookAndFeel.listView.music.fontSize}
@ -956,7 +932,7 @@ const ArtistView = ({ ...rest }: any) => {
handleMusicRowFavorite(rowData, ['artistTopSongs', data.title]) handleMusicRowFavorite(rowData, ['artistTopSongs', data.title])
} }
handleRowClick={handleRowClick} handleRowClick={handleRowClick}
handleRowDoubleClick={(e: any) => handleMusicRowDoubleClick(e, topSongs)} handleRowDoubleClick={(e: any) => handleRowDoubleClick(e, topSongs)}
handleRating={(rowData: any, e: number) => handleRating={(rowData: any, e: number) =>
handleRowRating(rowData, e, ['artistTopSongs', data?.title]) handleRowRating(rowData, e, ['artistTopSongs', data?.title])
} }

67
src/components/library/FolderList.tsx

@ -7,12 +7,6 @@ import { ButtonToolbar, Icon } from 'rsuite';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import ListViewType from '../viewtypes/ListViewType'; import ListViewType from '../viewtypes/ListViewType';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import {
clearSelected,
setRangeSelected,
toggleRangeSelected,
toggleSelected,
} from '../../redux/multiSelectSlice';
import GenericPage from '../layout/GenericPage'; import GenericPage from '../layout/GenericPage';
import GenericPageHeader from '../layout/GenericPageHeader'; import GenericPageHeader from '../layout/GenericPageHeader';
import { StyledButton, StyledInputPicker, StyledInputPickerContainer } from '../shared/styled'; import { StyledButton, StyledInputPicker, StyledInputPickerContainer } from '../shared/styled';
@ -25,6 +19,7 @@ import { Server } from '../../types';
import { apiController } from '../../api/controller'; 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';
const FolderList = () => { const FolderList = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -77,45 +72,27 @@ const FolderList = () => {
} }
}, [dispatch, query]); }, [dispatch, query]);
let timeout: any = null; const { handleRowClick, handleRowDoubleClick } = useListClickHandler({
const handleRowClick = (e: any, rowData: any, tableData: any) => { doubleClick: (rowData: any) => {
if (timeout === null) { if (rowData.isDir) {
timeout = window.setTimeout(() => { history.push(`/library/folder?folderId=${rowData.id}`);
timeout = null; dispatch(setCurrentViewedFolder(rowData.id));
} else {
if (e.ctrlKey) { const selected = folderData?.id ? folderData?.child : indexData?.child;
dispatch(toggleSelected(rowData)); dispatch(
} else if (e.shiftKey) { setPlayQueueByRowClick({
dispatch(setRangeSelected(rowData)); entries: selected.filter((entry: any) => entry?.isDir === false),
dispatch(toggleRangeSelected(tableData)); currentIndex: rowData.rowIndex,
} currentSongId: rowData.id,
}, 100); uniqueSongId: rowData.uniqueId,
} filters: config.playback.filters,
}; })
);
const handleRowDoubleClick = (rowData: any) => { dispatch(setStatus('PLAYING'));
window.clearTimeout(timeout); dispatch(fixPlayer2Index());
timeout = null; }
},
dispatch(clearSelected()); });
if (rowData.isDir) {
history.push(`/library/folder?folderId=${rowData.id}`);
dispatch(setCurrentViewedFolder(rowData.id));
} else {
const selected = folderData?.id ? folderData?.child : indexData?.child;
dispatch(
setPlayQueueByRowClick({
entries: selected.filter((entry: any) => entry?.isDir === false),
currentIndex: rowData.rowIndex,
currentSongId: rowData.id,
uniqueSongId: rowData.uniqueId,
filters: config.playback.filters,
})
);
dispatch(setStatus('PLAYING'));
dispatch(fixPlayer2Index());
}
};
const handleRowFavorite = async (rowData: any) => { const handleRowFavorite = async (rowData: any) => {
if (!rowData.starred) { if (!rowData.starred) {

48
src/components/library/GenreList.tsx

@ -8,17 +8,12 @@ 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';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import {
clearSelected,
setRangeSelected,
toggleRangeSelected,
toggleSelected,
} from '../../redux/multiSelectSlice';
import { apiController } from '../../api/controller'; import { apiController } from '../../api/controller';
import { StyledTag } from '../shared/styled'; import { StyledTag } from '../shared/styled';
import { setFilter, setPagination } from '../../redux/viewSlice'; import { setFilter, setPagination } from '../../redux/viewSlice';
import { Item } from '../../types'; import { Item } from '../../types';
import CenterLoader from '../loader/CenterLoader'; import CenterLoader from '../loader/CenterLoader';
import useListClickHandler from '../../hooks/useListClickHandler';
const GenreList = () => { const GenreList = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -37,36 +32,19 @@ const GenreList = () => {
}); });
const filteredData = useSearchQuery(misc.searchQuery, genres, ['title']); const filteredData = useSearchQuery(misc.searchQuery, genres, ['title']);
let timeout: any = null; const { handleRowClick, handleRowDoubleClick } = useListClickHandler({
const handleRowClick = (e: any, rowData: any, tableData: any) => { doubleClick: (rowData: any) => {
if (timeout === null) { dispatch(setFilter({ listType: Item.Album, data: rowData.title }));
timeout = window.setTimeout(() => { dispatch(setPagination({ listType: Item.Album, data: { activePage: 1 } }));
timeout = null; localStorage.setItem('scroll_list_albumList', '0');
localStorage.setItem('scroll_grid_albumList', '0');
if (e.ctrlKey) { // Needs a small delay or the filter won't set properly when navigating to the album list
dispatch(toggleSelected(rowData)); setTimeout(() => {
} else if (e.shiftKey) { history.push(`/library/album?sortType=${rowData.title}`);
dispatch(setRangeSelected(rowData)); }, 50);
dispatch(toggleRangeSelected(tableData)); },
} });
}, 100);
}
};
const handleRowDoubleClick = (rowData: any) => {
window.clearTimeout(timeout);
timeout = null;
dispatch(setFilter({ listType: Item.Album, data: rowData.title }));
dispatch(setPagination({ listType: Item.Album, data: { activePage: 1 } }));
localStorage.setItem('scroll_list_albumList', '0');
localStorage.setItem('scroll_grid_albumList', '0');
dispatch(clearSelected());
// Needs a small delay or the filter won't set properly when navigating to the album list
setTimeout(() => {
history.push(`/library/album?sortType=${rowData.title}`);
}, 50);
};
return ( return (
<GenericPage <GenericPage

55
src/components/library/MusicList.tsx

@ -10,12 +10,6 @@ import useSearchQuery from '../../hooks/useSearchQuery';
import GenericPageHeader from '../layout/GenericPageHeader'; import GenericPageHeader from '../layout/GenericPageHeader';
import GenericPage from '../layout/GenericPage'; import GenericPage from '../layout/GenericPage';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import {
toggleSelected,
setRangeSelected,
toggleRangeSelected,
clearSelected,
} from '../../redux/multiSelectSlice';
import { StyledInputPicker, StyledInputPickerContainer, StyledTag } from '../shared/styled'; import { StyledInputPicker, StyledInputPickerContainer, StyledTag } from '../shared/styled';
import { RefreshButton } from '../shared/ToolbarButtons'; import { RefreshButton } from '../shared/ToolbarButtons';
import { setSearchQuery } from '../../redux/miscSlice'; import { setSearchQuery } from '../../redux/miscSlice';
@ -26,6 +20,7 @@ import { fixPlayer2Index, setPlayQueueByRowClick, setStar } from '../../redux/pl
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';
// prettier-ignore // prettier-ignore
export const MUSIC_SORT_TYPES = [ export const MUSIC_SORT_TYPES = [
@ -162,39 +157,21 @@ const MusicList = () => {
view.music.pagination.serverSide, view.music.pagination.serverSide,
]); ]);
let timeout: any = null; const { handleRowClick, handleRowDoubleClick } = useListClickHandler({
const handleRowClick = (e: any, rowData: any, tableData: any) => { doubleClick: (rowData: any) => {
if (timeout === null) { dispatch(
timeout = window.setTimeout(() => { setPlayQueueByRowClick({
timeout = null; entries: songs.data,
currentIndex: rowData.rowIndex,
if (e.ctrlKey) { currentSongId: rowData.id,
dispatch(toggleSelected(rowData)); uniqueSongId: rowData.uniqueId,
} else if (e.shiftKey) { filters: config.playback.filters,
dispatch(setRangeSelected(rowData)); })
dispatch(toggleRangeSelected(tableData)); );
} dispatch(setStatus('PLAYING'));
}, 100); dispatch(fixPlayer2Index());
} },
}; });
const handleRowDoubleClick = (rowData: any) => {
window.clearTimeout(timeout);
timeout = null;
dispatch(clearSelected());
dispatch(
setPlayQueueByRowClick({
entries: songs.data,
currentIndex: rowData.rowIndex,
currentSongId: rowData.id,
uniqueSongId: rowData.uniqueId,
filters: config.playback.filters,
})
);
dispatch(setStatus('PLAYING'));
dispatch(fixPlayer2Index());
};
const handleRefresh = async () => { const handleRefresh = async () => {
setIsRefreshing(true); setIsRefreshing(true);

55
src/components/player/NowPlayingInfoView.tsx

@ -13,12 +13,6 @@ import { SecondaryTextWrapper, StyledPanel, StyledTag } from '../shared/styled';
import ScrollingMenu from '../scrollingmenu/ScrollingMenu'; import ScrollingMenu from '../scrollingmenu/ScrollingMenu';
import ListViewTable from '../viewtypes/ListViewTable'; import ListViewTable from '../viewtypes/ListViewTable';
import CenterLoader from '../loader/CenterLoader'; import CenterLoader from '../loader/CenterLoader';
import {
clearSelected,
setRangeSelected,
toggleRangeSelected,
toggleSelected,
} from '../../redux/multiSelectSlice';
import { fixPlayer2Index, setPlayQueueByRowClick, setRate } from '../../redux/playQueueSlice'; import { fixPlayer2Index, setPlayQueueByRowClick, setRate } from '../../redux/playQueueSlice';
import { setStatus } from '../../redux/playerSlice'; import { setStatus } from '../../redux/playerSlice';
import useColumnSort from '../../hooks/useColumnSort'; import useColumnSort from '../../hooks/useColumnSort';
@ -34,6 +28,7 @@ import {
import Card from '../card/Card'; 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';
const NowPlayingInfoView = () => { const NowPlayingInfoView = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -83,39 +78,21 @@ const NowPlayingInfoView = () => {
type: 'desc', type: 'desc',
}); });
let timeout: any = null; const { handleRowClick, handleRowDoubleClick } = useListClickHandler({
const handleRowClick = (e: any, rowData: any, tableData: any) => { doubleClick: (rowData: any, songs: any) => {
if (timeout === null) { dispatch(
timeout = window.setTimeout(() => { setPlayQueueByRowClick({
timeout = null; entries: songs.data,
currentIndex: rowData.rowIndex,
if (e.ctrlKey) { currentSongId: rowData.id,
dispatch(toggleSelected(rowData)); uniqueSongId: rowData.uniqueId,
} else if (e.shiftKey) { filters: config.playback.filters,
dispatch(setRangeSelected(rowData)); })
dispatch(toggleRangeSelected(tableData)); );
} dispatch(setStatus('PLAYING'));
}, 100); dispatch(fixPlayer2Index());
} },
}; });
const handleRowDoubleClick = (rowData: any) => {
window.clearTimeout(timeout);
timeout = null;
dispatch(clearSelected());
dispatch(
setPlayQueueByRowClick({
entries: similarToSong,
currentIndex: rowData.rowIndex,
currentSongId: rowData.id,
uniqueSongId: rowData.uniqueId,
filters: config.playback.filters,
})
);
dispatch(setStatus('PLAYING'));
dispatch(fixPlayer2Index());
};
const handleRowFavorite = async (rowData: any, queryKey: any) => { const handleRowFavorite = async (rowData: any, queryKey: any) => {
console.log(rowData); console.log(rowData);

36
src/components/player/NowPlayingMiniView.tsx

@ -6,15 +6,8 @@ import { useHotkeys } from 'react-hotkeys-hook';
import { useQuery } from 'react-query'; import { useQuery } from 'react-query';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import { clearSelected, setIsDragging } from '../../redux/multiSelectSlice';
import { import {
toggleSelected,
setRangeSelected,
toggleRangeSelected,
clearSelected,
setIsDragging,
} from '../../redux/multiSelectSlice';
import {
setPlayerIndex,
fixPlayer2Index, fixPlayer2Index,
clearPlayQueue, clearPlayQueue,
shuffleInPlace, shuffleInPlace,
@ -59,6 +52,7 @@ import {
import { notifyToast } from '../shared/toast'; import { notifyToast } from '../shared/toast';
import { apiController } from '../../api/controller'; import { apiController } from '../../api/controller';
import { Server, Song } from '../../types'; import { Server, Song } from '../../types';
import useListClickHandler from '../../hooks/useListClickHandler';
const NowPlayingMiniView = () => { const NowPlayingMiniView = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -135,31 +129,7 @@ const NowPlayingMiniView = () => {
} }
}, [playQueue.currentIndex, tableRef, playQueue.displayQueue, playQueue.scrollWithCurrentSong]); }, [playQueue.currentIndex, tableRef, playQueue.displayQueue, playQueue.scrollWithCurrentSong]);
let timeout: any = null; const { handleRowClick, handleRowDoubleClick } = useListClickHandler();
const handleRowClick = (e: any, rowData: any, tableData: any) => {
if (timeout === null) {
timeout = window.setTimeout(() => {
timeout = null;
if (e.ctrlKey) {
dispatch(toggleSelected(rowData));
} else if (e.shiftKey) {
dispatch(setRangeSelected(rowData));
dispatch(toggleRangeSelected(tableData));
}
}, 100);
}
};
const handleRowDoubleClick = (rowData: any) => {
window.clearTimeout(timeout);
timeout = null;
dispatch(clearSelected());
dispatch(setPlayerIndex(rowData));
dispatch(fixPlayer2Index());
dispatch(setStatus('PLAYING'));
};
const handleDragEnd = () => { const handleDragEnd = () => {
if (multiSelect.isDragging) { if (multiSelect.isDragging) {

36
src/components/player/NowPlayingView.tsx

@ -8,7 +8,6 @@ import { useTranslation } from 'react-i18next';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import useSearchQuery from '../../hooks/useSearchQuery'; import useSearchQuery from '../../hooks/useSearchQuery';
import { import {
setPlayerIndex,
fixPlayer2Index, fixPlayer2Index,
clearPlayQueue, clearPlayQueue,
shuffleInPlace, shuffleInPlace,
@ -23,13 +22,7 @@ import {
moveToTop, moveToTop,
moveToBottom, moveToBottom,
} from '../../redux/playQueueSlice'; } from '../../redux/playQueueSlice';
import { import { clearSelected, setIsDragging } from '../../redux/multiSelectSlice';
toggleSelected,
setRangeSelected,
toggleRangeSelected,
clearSelected,
setIsDragging,
} from '../../redux/multiSelectSlice';
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';
@ -64,6 +57,7 @@ import { Server, Song } from '../../types';
import { setPlaylistRate } from '../../redux/playlistSlice'; import { setPlaylistRate } from '../../redux/playlistSlice';
import NowPlayingInfoView from './NowPlayingInfoView'; import NowPlayingInfoView from './NowPlayingInfoView';
import CenterLoader from '../loader/CenterLoader'; import CenterLoader from '../loader/CenterLoader';
import useListClickHandler from '../../hooks/useListClickHandler';
const NowPlayingView = () => { const NowPlayingView = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -149,31 +143,7 @@ const NowPlayingView = () => {
} }
}, [playQueue.currentIndex, playQueue.scrollWithCurrentSong, tableRef]); }, [playQueue.currentIndex, playQueue.scrollWithCurrentSong, tableRef]);
let timeout: any = null; const { handleRowClick, handleRowDoubleClick } = useListClickHandler();
const handleRowClick = (e: any, rowData: any, tableData: any) => {
if (timeout === null) {
timeout = window.setTimeout(() => {
timeout = null;
if (e.ctrlKey) {
dispatch(toggleSelected(rowData));
} else if (e.shiftKey) {
dispatch(setRangeSelected(rowData));
dispatch(toggleRangeSelected(tableData));
}
}, 100);
}
};
const handleRowDoubleClick = (rowData: any) => {
window.clearTimeout(timeout);
timeout = null;
dispatch(clearSelected());
dispatch(setPlayerIndex(rowData));
dispatch(fixPlayer2Index());
dispatch(setStatus('PLAYING'));
};
const handleDragEnd = () => { const handleDragEnd = () => {
if (multiSelect.isDragging) { if (multiSelect.isDragging) {

33
src/components/playlist/PlaylistList.tsx

@ -20,17 +20,12 @@ import { errorMessages, isFailedResponse } from '../../shared/utils';
import { notifyToast } from '../shared/toast'; import { notifyToast } from '../shared/toast';
import { AddPlaylistButton, FilterButton } from '../shared/ToolbarButtons'; import { AddPlaylistButton, FilterButton } from '../shared/ToolbarButtons';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import {
clearSelected,
setRangeSelected,
toggleRangeSelected,
toggleSelected,
} from '../../redux/multiSelectSlice';
import { apiController } from '../../api/controller'; import { apiController } from '../../api/controller';
import useColumnSort from '../../hooks/useColumnSort'; import useColumnSort from '../../hooks/useColumnSort';
import { Item, Server } from '../../types'; import { Item, Server } from '../../types';
import { setSort } from '../../redux/playlistSlice'; import { setSort } from '../../redux/playlistSlice';
import ColumnSortPopover from '../shared/ColumnSortPopover'; import ColumnSortPopover from '../shared/ColumnSortPopover';
import useListClickHandler from '../../hooks/useListClickHandler';
const PlaylistList = () => { const PlaylistList = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -74,29 +69,9 @@ const PlaylistList = () => {
} }
}; };
let timeout: any = null; const { handleRowClick, handleRowDoubleClick } = useListClickHandler({
const handleRowClick = (e: any, rowData: any, tableData: any) => { doubleClick: (rowData: any) => history.push(`playlist/${rowData.id}`),
if (timeout === null) { });
timeout = window.setTimeout(() => {
timeout = null;
if (e.ctrlKey) {
dispatch(toggleSelected(rowData));
} else if (e.shiftKey) {
dispatch(setRangeSelected(rowData));
dispatch(toggleRangeSelected(tableData));
}
}, 100);
}
};
const handleRowDoubleClick = (rowData: any) => {
window.clearTimeout(timeout);
timeout = null;
dispatch(clearSelected());
history.push(`playlist/${rowData.id}`);
};
if (isError) { if (isError) {
return <span>{t('Error: {{error}}', { error: error.message })}</span>; return <span>{t('Error: {{error}}', { error: error.message })}</span>;

57
src/components/playlist/PlaylistView.tsx

@ -27,13 +27,7 @@ import {
setRate, setRate,
clearPlayQueue, clearPlayQueue,
} from '../../redux/playQueueSlice'; } from '../../redux/playQueueSlice';
import { import { clearSelected, setIsDragging } from '../../redux/multiSelectSlice';
toggleSelected,
setRangeSelected,
toggleRangeSelected,
clearSelected,
setIsDragging,
} from '../../redux/multiSelectSlice';
import { import {
createRecoveryFile, createRecoveryFile,
errorMessages, errorMessages,
@ -75,6 +69,7 @@ import { apiController } from '../../api/controller';
import { Server } from '../../types'; import { Server } from '../../types';
import Card from '../card/Card'; import Card from '../card/Card';
import CenterLoader from '../loader/CenterLoader'; import CenterLoader from '../loader/CenterLoader';
import useListClickHandler from '../../hooks/useListClickHandler';
interface PlaylistParams { interface PlaylistParams {
id: string; id: string;
@ -153,39 +148,21 @@ const PlaylistView = ({ ...rest }) => {
} }
}, [data?.song, playlist]); }, [data?.song, playlist]);
let timeout: any = null; const { handleRowClick, handleRowDoubleClick } = useListClickHandler({
const handleRowClick = (e: any, rowData: any, tableData: any) => { doubleClick: (rowData: any) => {
if (timeout === null) { dispatch(
timeout = window.setTimeout(() => { setPlayQueueByRowClick({
timeout = null; entries: playlist[getCurrentEntryList(playlist)],
currentIndex: rowData.rowIndex,
if (e.ctrlKey) { currentSongId: rowData.id,
dispatch(toggleSelected(rowData)); uniqueSongId: rowData.uniqueId,
} else if (e.shiftKey) { filters: config.playback.filters,
dispatch(setRangeSelected(rowData)); })
dispatch(toggleRangeSelected(tableData)); );
} dispatch(setStatus('PLAYING'));
}, 100); dispatch(fixPlayer2Index());
} },
}; });
const handleRowDoubleClick = (rowData: any) => {
window.clearTimeout(timeout);
timeout = null;
dispatch(clearSelected());
dispatch(
setPlayQueueByRowClick({
entries: playlist[getCurrentEntryList(playlist)],
currentIndex: rowData.rowIndex,
currentSongId: rowData.id,
uniqueSongId: rowData.uniqueId,
filters: config.playback.filters,
})
);
dispatch(setStatus('PLAYING'));
dispatch(fixPlayer2Index());
};
const handlePlay = () => { const handlePlay = () => {
const songs = filterPlayQueue(config.playback.filters, playlist[getCurrentEntryList(playlist)]); const songs = filterPlayQueue(config.playback.filters, playlist[getCurrentEntryList(playlist)]);

63
src/components/search/SearchView.tsx

@ -9,12 +9,6 @@ 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 {
clearSelected,
setRangeSelected,
toggleRangeSelected,
toggleSelected,
} from '../../redux/multiSelectSlice';
import { fixPlayer2Index, setPlayQueueByRowClick, setRate } from '../../redux/playQueueSlice'; import { fixPlayer2Index, setPlayQueueByRowClick, setRate } from '../../redux/playQueueSlice';
import { setStatus } from '../../redux/playerSlice'; import { setStatus } from '../../redux/playerSlice';
import ListViewTable from '../viewtypes/ListViewTable'; import ListViewTable from '../viewtypes/ListViewTable';
@ -23,6 +17,7 @@ import { apiController } from '../../api/controller';
import { Server } from '../../types'; import { Server } from '../../types';
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';
const SearchView = () => { const SearchView = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -51,43 +46,25 @@ const SearchView = () => {
}) })
); );
let timeout: any = null; const { handleRowClick, handleRowDoubleClick } = useListClickHandler({
const handleRowClick = (e: any, rowData: any, tableData: any) => { doubleClick: (rowData: any) => {
if (timeout === null) { if (rowData.isDir) {
timeout = window.setTimeout(() => { history.push(`/library/folder?folderId=${rowData.parent}`);
timeout = null; } else {
dispatch(
if (e.ctrlKey) { setPlayQueueByRowClick({
dispatch(toggleSelected(rowData)); entries: data.song.filter((entry: any) => entry.isDir !== true),
} else if (e.shiftKey) { currentIndex: rowData.rowIndex,
dispatch(setRangeSelected(rowData)); currentSongId: rowData.id,
dispatch(toggleRangeSelected(tableData)); uniqueSongId: rowData.uniqueId,
} filters: config.playback.filters,
}, 100); })
} );
}; dispatch(setStatus('PLAYING'));
dispatch(fixPlayer2Index());
const handleRowDoubleClick = (rowData: any) => { }
window.clearTimeout(timeout); },
timeout = null; });
dispatch(clearSelected());
if (rowData.isDir) {
history.push(`/library/folder?folderId=${rowData.parent}`);
} else {
dispatch(
setPlayQueueByRowClick({
entries: data.song.filter((entry: any) => entry.isDir !== true),
currentIndex: rowData.rowIndex,
currentSongId: rowData.id,
uniqueSongId: rowData.uniqueId,
filters: config.playback.filters,
})
);
dispatch(setStatus('PLAYING'));
dispatch(fixPlayer2Index());
}
};
const handleRowFavorite = async (rowData: any) => { const handleRowFavorite = async (rowData: any) => {
if (!rowData.starred) { if (!rowData.starred) {

24
src/components/settings/ConfigPanels/ListViewConfig.tsx

@ -11,12 +11,7 @@ import {
} from '../../shared/styled'; } from '../../shared/styled';
import ListViewTable from '../../viewtypes/ListViewTable'; import ListViewTable from '../../viewtypes/ListViewTable';
import { useAppDispatch, useAppSelector } from '../../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../../redux/hooks';
import { import { setIsDragging } from '../../../redux/multiSelectSlice';
setIsDragging,
setRangeSelected,
toggleRangeSelected,
toggleSelected,
} from '../../../redux/multiSelectSlice';
import { import {
ColumnList, ColumnList,
moveToIndex, moveToIndex,
@ -25,6 +20,7 @@ import {
setRowHeight, setRowHeight,
} from '../../../redux/configSlice'; } from '../../../redux/configSlice';
import ConfigOption from '../ConfigOption'; import ConfigOption from '../ConfigOption';
import useListClickHandler from '../../../hooks/useListClickHandler';
const columnSelectorColumns = [ const columnSelectorColumns = [
{ {
@ -83,21 +79,7 @@ const ListViewConfig = ({
); );
}, [columnListType, config.lookAndFeel.listView, settingsConfig.columnList]); }, [columnListType, config.lookAndFeel.listView, settingsConfig.columnList]);
let timeout: any = null; const { handleRowClick } = useListClickHandler({});
const handleRowClick = (e: any, rowData: any, tableData: any) => {
if (timeout === null) {
timeout = window.setTimeout(() => {
timeout = null;
if (e.ctrlKey) {
dispatch(toggleSelected(rowData));
} else if (e.shiftKey) {
dispatch(setRangeSelected(rowData));
dispatch(toggleRangeSelected(tableData));
}
}, 100);
}
};
const handleDragEnd = (listType: ColumnList) => { const handleDragEnd = (listType: ColumnList) => {
if (multiSelect.isDragging) { if (multiSelect.isDragging) {

67
src/components/starred/StarredView.tsx

@ -12,12 +12,6 @@ import {
setRate, setRate,
setStar, setStar,
} from '../../redux/playQueueSlice'; } from '../../redux/playQueueSlice';
import {
clearSelected,
toggleSelected,
toggleRangeSelected,
setRangeSelected,
} from '../../redux/multiSelectSlice';
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';
@ -32,6 +26,7 @@ import { Item, Server } from '../../types';
import { FilterButton } from '../shared/ToolbarButtons'; 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';
const StarredView = () => { const StarredView = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -79,45 +74,27 @@ const StarredView = () => {
favorite.active.tab === 'albums' ? favorite.active.album.sort : favorite.active.artist.sort favorite.active.tab === 'albums' ? favorite.active.album.sort : favorite.active.artist.sort
); );
let timeout: any = null; const { handleRowClick, handleRowDoubleClick } = useListClickHandler({
const handleRowClick = (e: any, rowData: any, tableData: any) => { doubleClick: (rowData: any) => {
if (timeout === null) { if (favorite.active.tab === 'tracks') {
timeout = window.setTimeout(() => { dispatch(
timeout = null; setPlayQueueByRowClick({
entries: data.song,
if (e.ctrlKey) { currentIndex: rowData.rowIndex,
dispatch(toggleSelected(rowData)); currentSongId: rowData.id,
} else if (e.shiftKey) { uniqueSongId: rowData.uniqueId,
dispatch(setRangeSelected(rowData)); filters: config.playback.filters,
dispatch(toggleRangeSelected(tableData)); })
} );
}, 100); dispatch(setStatus('PLAYING'));
} dispatch(fixPlayer2Index());
}; } else if (favorite.active.tab === 'albums') {
history.push(`/library/album/${rowData.id}`);
const handleRowDoubleClick = (rowData: any) => { } else {
window.clearTimeout(timeout); history.push(`/library/artist/${rowData.id}`);
timeout = null; }
dispatch(clearSelected()); },
});
if (favorite.active.tab === 'tracks') {
dispatch(
setPlayQueueByRowClick({
entries: data.song,
currentIndex: rowData.rowIndex,
currentSongId: rowData.id,
uniqueSongId: rowData.uniqueId,
filters: config.playback.filters,
})
);
dispatch(setStatus('PLAYING'));
dispatch(fixPlayer2Index());
} else if (favorite.active.tab === 'albums') {
history.push(`/library/album/${rowData.id}`);
} else {
history.push(`/library/artist/${rowData.id}`);
}
};
const handleRowFavorite = async (rowData: any) => { const handleRowFavorite = async (rowData: any) => {
await apiController({ await apiController({

52
src/hooks/useListClickHandler.ts

@ -0,0 +1,52 @@
import { useAppDispatch, useAppSelector } from '../redux/hooks';
import { clearSelected, setSelected, toggleSelected } from '../redux/multiSelectSlice';
import { setStatus } from '../redux/playerSlice';
import { fixPlayer2Index, setPlayerIndex } from '../redux/playQueueSlice';
import { sliceRangeByUniqueId } from '../shared/utils';
const useListClickHandler = (options?: { singleClick?: any; doubleClick?: any }) => {
const dispatch = useAppDispatch();
const multiSelect = useAppSelector((state) => state.multiSelect);
let timeout: any = null;
const handleRowClick = (e: any, rowData: any, tableData: any) => {
if (timeout === null) {
timeout = window.setTimeout(() => {
timeout = null;
if (!options?.singleClick) {
if (e.ctrlKey) {
dispatch(toggleSelected(rowData));
} else if (e.shiftKey) {
dispatch(
setSelected(
sliceRangeByUniqueId(tableData, multiSelect.lastSelected.uniqueId, rowData.uniqueId)
)
);
}
} else {
options.singleClick(e, rowData, tableData);
}
}, 100);
}
};
const handleRowDoubleClick = (rowData: any, e?: any) => {
window.clearTimeout(timeout);
timeout = null;
dispatch(clearSelected());
if (!options?.doubleClick) {
dispatch(setPlayerIndex(rowData));
dispatch(fixPlayer2Index());
dispatch(setStatus('PLAYING'));
} else {
options.doubleClick(rowData, e);
}
};
return { handleRowClick, handleRowDoubleClick };
};
export default useListClickHandler;
Loading…
Cancel
Save