Browse Source

add, update list columns

master
jeffvli 3 years ago
parent
commit
6deb6cbc11
  1. 2
      src/components/library/AlbumList.tsx
  2. 2
      src/components/library/AlbumView.tsx
  3. 1
      src/components/library/ArtistView.tsx
  4. 2
      src/components/player/NowPlayingView.tsx
  5. 15
      src/components/player/PlayerBar.tsx
  6. 10
      src/components/playlist/PlaylistList.tsx
  7. 2
      src/components/playlist/PlaylistView.tsx
  8. 21
      src/components/settings/Config.tsx
  9. 271
      src/components/settings/ListViewColumns.ts
  10. 4
      src/components/starred/StarredView.tsx
  11. 115
      src/components/viewtypes/ListViewTable.tsx
  12. 2
      src/components/viewtypes/ListViewType.tsx
  13. 11
      src/redux/playQueueSlice.ts
  14. 18
      src/shared/utils.ts
  15. 1
      src/styles/App.global.css

2
src/components/library/AlbumList.tsx

@ -32,7 +32,9 @@ const AlbumList = ({ data, viewType }: any) => {
cacheImages={{
enabled: settings.getSync('cacheImages'),
cacheType: 'album',
cacheIdProperty: 'albumId',
}}
listType="album"
virtualized
/>
);

2
src/components/library/AlbumView.tsx

@ -152,7 +152,9 @@ const AlbumView = () => {
cacheImages={{
enabled: settings.getSync('cacheImages'),
cacheType: 'album',
cacheIdProperty: 'albumId',
}}
listType="song"
/>
</GenericPage>
);

1
src/components/library/ArtistView.tsx

@ -184,6 +184,7 @@ const ArtistView = () => {
enabled: settings.getSync('cacheImages'),
cacheType: 'album',
}}
listType="album"
/>
)}

2
src/components/player/NowPlayingView.tsx

@ -155,7 +155,9 @@ const NowPlayingView = () => {
cacheImages={{
enabled: settings.getSync('cacheImages'),
cacheType: 'album',
cacheIdProperty: 'albumId',
}}
listType="song"
/>
</GenericPage>
);

15
src/components/player/PlayerBar.tsx

@ -213,20 +213,31 @@ const PlayerBar = () => {
const handleFavorite = async () => {
if (!playQueue.entry[playQueue.currentIndex].starred) {
star(playQueue.entry[playQueue.currentIndex].id, 'song');
dispatch(setStar('star'));
dispatch(
setStar({
id: playQueue.entry[playQueue.currentIndex].id,
type: 'star',
})
);
await queryClient.refetchQueries(['starred'], {
active: true,
exact: true,
});
} else {
unstar(playQueue.entry[playQueue.currentIndex].id, 'song');
dispatch(setStar('unstar'));
dispatch(
setStar({
id: playQueue.entry[playQueue.currentIndex].id,
type: 'unstar',
})
);
await queryClient.refetchQueries(['starred'], {
active: true,
exact: true,
});
}
};
return (
<Player ref={playersRef}>
<PlayerContainer>

10
src/components/playlist/PlaylistList.tsx

@ -120,7 +120,15 @@ const PlaylistList = () => {
})
}
handleRowClick={handleRowClick}
tableColumns={tableColumns}
tableColumns={settings.getSync('playlistListColumns')}
rowHeight={Number(settings.getSync('playlistListRowHeight'))}
fontSize={settings.getSync('playlistListFontSize')}
cacheImages={{
enabled: settings.getSync('cacheImages'),
cacheType: 'playlist',
cacheIdProperty: 'id',
}}
listType="playlist"
virtualized
/>
)}

2
src/components/playlist/PlaylistView.tsx

@ -130,7 +130,9 @@ const PlaylistView = () => {
cacheImages={{
enabled: settings.getSync('cacheImages'),
cacheType: 'album',
cacheIdProperty: 'albumId',
}}
listType="song"
/>
</GenericPage>
);

21
src/components/settings/Config.tsx

@ -13,6 +13,8 @@ import {
songColumnPicker,
albumColumnList,
albumColumnPicker,
playlistColumnList,
playlistColumnPicker,
} from './ListViewColumns';
const fsUtils = require('nodejs-fs-utils');
@ -26,9 +28,12 @@ const Config = () => {
const songCols: any = settings.getSync('songListColumns');
const albumCols: any = settings.getSync('albumListColumns');
const playlistCols: any = settings.getSync('playlistListColumns');
const currentSongColumns = songCols?.map((column: any) => column.label) || [];
const currentAlbumColumns =
albumCols?.map((column: any) => column.label) || [];
const currentPlaylistColumns =
playlistCols?.map((column: any) => column.label) || [];
useEffect(() => {
// Retrieve cache sizes on render
@ -126,7 +131,7 @@ const Config = () => {
<ControlLabel>Crossfade duration (seconds)</ControlLabel>
<InputNumber
defaultValue={String(settings.getSync('fadeDuration')) || '0'}
step={0.1}
step={0.05}
min={0}
max={100}
onChange={(e) => {
@ -177,6 +182,20 @@ const Config = () => {
}}
/>
)}
{currentLAFTab === 'playlistList' && (
<ListViewConfig
title="Playlist List"
defaultColumns={currentPlaylistColumns}
columnPicker={playlistColumnPicker}
columnList={playlistColumnList}
settingsConfig={{
columnList: 'playlistListColumns',
rowHeight: 'playlistListRowHeight',
fontSize: 'playlistListFontSize',
}}
/>
)}
</ConfigPanel>
<ConfigPanel header="Cache" bordered>
<div style={{ overflow: 'auto' }}>

271
src/components/settings/ListViewColumns.ts

@ -43,6 +43,17 @@ export const songColumnList = [
label: 'Bitrate',
},
},
{
label: 'CoverArt',
value: {
id: 'Art',
dataKey: 'coverart',
alignment: 'center',
resizable: true,
width: 100,
label: 'CoverArt',
},
},
{
label: 'Created',
value: {
@ -65,6 +76,28 @@ export const songColumnList = [
label: 'Duration',
},
},
{
label: 'Favorite',
value: {
id: 'Favorite',
dataKey: 'starred',
alignment: 'center',
resizable: true,
width: 60,
label: 'Favorite',
},
},
{
label: 'Path',
value: {
id: 'Path',
dataKey: 'path',
alignment: 'center',
resizable: true,
width: 200,
label: 'Path',
},
},
{
label: 'Play Count',
value: {
@ -98,38 +131,35 @@ export const songColumnList = [
label: 'Title (Combined)',
},
},
];
export const songColumnPicker = [
{
label: '#',
},
{
label: 'Album',
},
{
label: 'Artist',
},
{
label: 'Bitrate',
},
{
label: 'Created',
},
{
label: 'Duration',
},
{
label: 'Play Count',
},
{
label: 'Title',
label: 'Year',
value: {
id: 'Year',
dataKey: 'year',
alignment: 'left',
resizable: true,
width: 60,
label: 'Year',
},
{
label: 'Title (Combined)',
},
];
export const songColumnPicker = [
{ label: '#' },
{ label: 'Album' },
{ label: 'Artist' },
{ label: 'Bitrate' },
{ label: 'CoverArt' },
{ label: 'Created' },
{ label: 'Duration' },
{ label: 'Favorite' },
{ label: 'Path' },
{ label: 'Play Count' },
{ label: 'Title' },
{ label: 'Title (Combined)' },
{ label: 'Year' },
];
export const albumColumnList = [
{
label: '#',
@ -153,6 +183,17 @@ export const albumColumnList = [
label: 'Artist',
},
},
{
label: 'CoverArt',
value: {
id: 'Art',
dataKey: 'coverart',
alignment: 'center',
resizable: true,
width: 100,
label: 'CoverArt',
},
},
{
label: 'Created',
value: {
@ -175,12 +216,23 @@ export const albumColumnList = [
label: 'Duration',
},
},
{
label: 'Favorite',
value: {
id: 'Favorite',
dataKey: 'starred',
alignment: 'center',
resizable: true,
width: 60,
label: 'Favorite',
},
},
{
label: 'Genre',
value: {
id: 'Genre',
dataKey: 'genre',
alignment: 'center',
alignment: 'left',
resizable: true,
width: 70,
label: 'Genre',
@ -219,31 +271,190 @@ export const albumColumnList = [
label: 'Title (Combined)',
},
},
{
label: 'Year',
value: {
id: 'Year',
dataKey: 'year',
alignment: 'left',
resizable: true,
width: 60,
label: 'Year',
},
},
];
export const albumColumnPicker = [
{ label: '#' },
{ label: 'Artist' },
{ label: 'CoverArt' },
{ label: 'Created' },
{ label: 'Duration' },
{ label: 'Favorite' },
{ label: 'Genre' },
{ label: 'Play Count' },
{ label: 'Title' },
{ label: 'Title (Combined)' },
{ label: 'Track Count' },
{ label: 'Year' },
];
export const playlistColumnList = [
{
label: '#',
value: {
id: '#',
dataKey: 'index',
alignment: 'center',
resizable: true,
width: 50,
label: '#',
},
},
{
label: 'Artist',
label: 'CoverArt',
value: {
id: 'Art',
dataKey: 'coverart',
alignment: 'center',
resizable: true,
width: 100,
label: 'CoverArt',
},
},
{
label: 'Created',
value: {
id: 'Created',
dataKey: 'created',
alignment: 'left',
resizable: true,
width: 100,
label: 'Created',
},
},
{
label: 'Description',
value: {
id: 'Description',
dataKey: 'comment',
alignment: 'left',
resizable: true,
width: 200,
label: 'Description',
},
},
{
label: 'Duration',
value: {
id: 'Duration',
dataKey: 'duration',
alignment: 'center',
resizable: true,
width: 80,
label: 'Duration',
},
},
{
label: 'Genre',
value: {
id: 'Genre',
dataKey: 'genre',
alignment: 'left',
resizable: true,
width: 70,
label: 'Genre',
},
},
{
label: 'Modified',
value: {
id: 'Modified',
dataKey: 'changed',
alignment: 'left',
resizable: true,
width: 70,
label: 'Modified',
},
},
{
label: 'Owner',
value: {
id: 'Owner',
dataKey: 'owner',
alignment: 'left',
resizable: true,
width: 100,
label: 'Owner',
},
},
{
label: 'Play Count',
value: {
id: 'Plays',
dataKey: 'playCount',
alignment: 'center',
resizable: true,
width: 60,
label: 'Play Count',
},
},
{
label: 'Track Count',
value: {
id: 'Tracks',
dataKey: 'songCount',
alignment: 'center',
resizable: true,
width: 70,
label: 'Track Count',
},
},
{
label: 'Title',
value: {
id: 'Title',
dataKey: 'name',
alignment: 'left',
resizable: true,
width: 300,
label: 'Title',
},
},
{
label: 'Title (Combined)',
value: {
id: 'Title',
dataKey: 'combinedtitle',
alignment: 'left',
resizable: true,
width: 300,
label: 'Title (Combined)',
},
},
{
label: 'Track Count',
label: 'Visibility',
value: {
id: 'Visibility',
dataKey: 'public',
alignment: 'left',
resizable: true,
width: 100,
label: 'Visibility',
},
},
];
export const playlistColumnPicker = [
{ label: '#' },
{ label: 'CoverArt' },
{ label: 'Created' },
{ label: 'Description' },
{ label: 'Duration' },
{ label: 'Modified' },
{ label: 'Owner' },
{ label: 'Title' },
{ label: 'Title (Combined)' },
{ label: 'Track Count' },
{ label: 'Visiblity' },
];

4
src/components/starred/StarredView.tsx

@ -125,7 +125,9 @@ const StarredView = () => {
cacheImages={{
enabled: settings.getSync('cacheImages'),
cacheType: 'album',
cacheIdProperty: 'albumId',
}}
listType="song"
virtualized
/>
)}
@ -141,7 +143,9 @@ const StarredView = () => {
cacheImages={{
enabled: settings.getSync('cacheImages'),
cacheType: 'album',
cacheIdProperty: 'albumId',
}}
listType="album"
virtualized
/>
)}

115
src/components/viewtypes/ListViewTable.tsx

@ -3,8 +3,9 @@
import React from 'react';
import path from 'path';
import settings from 'electron-settings';
import { useQueryClient } from 'react-query';
import { nanoid } from 'nanoid';
import { Table, Grid, Row, Col } from 'rsuite';
import { Table, Grid, Row, Col, Icon } from 'rsuite';
import { useHistory } from 'react-router';
import { LazyLoadImage } from 'react-lazy-load-image-component';
import { RsuiteLinkButton } from './styled';
@ -12,8 +13,12 @@ import {
formatSongDuration,
isCached,
getImageCachePath,
formatDate,
} from '../../shared/utils';
import cacheImage from '../shared/cacheImage';
import { star, unstar } from '../../api/api';
import { useAppDispatch } from '../../redux/hooks';
import { setStar } from '../../redux/playQueueSlice';
const ListViewTable = ({
tableRef,
@ -29,8 +34,30 @@ const ListViewTable = ({
multiSelect,
cacheImages,
autoHeight,
listType,
}: any) => {
const history = useHistory();
const dispatch = useAppDispatch();
const queryClient = useQueryClient();
const handleFavorite = async (rowData: any) => {
if (!rowData.starred) {
star(rowData.id, listType);
dispatch(setStar({ id: rowData.id, type: 'star' }));
await queryClient.refetchQueries(['starred'], {
active: true,
exact: true,
});
} else {
unstar(rowData.id, listType);
dispatch(setStar({ id: rowData.id, type: 'unstar' }));
await queryClient.refetchQueries(['starred'], {
active: true,
exact: true,
});
}
};
return (
<Table
ref={tableRef}
@ -55,14 +82,12 @@ const ListViewTable = ({
fixed={column.fixed}
verticalAlign="middle"
onResize={(width: any) => {
const resizedColumn: any = settings.getSync('songListColumns');
const resizedColumnIndex = resizedColumn.findIndex(
const resizedColumnIndex = columns.findIndex(
(c: any) => c.dataKey === column.dataKey
);
settings.setSync(
`songListColumns[${resizedColumnIndex}].width`,
`${listType}ListColumns[${resizedColumnIndex}].width`,
width
);
}}
@ -155,12 +180,16 @@ const ListViewTable = ({
isCached(
path.join(
getImageCachePath(),
`${cacheImages.cacheType}_${rowData.albumId}.jpg`
`${cacheImages.cacheType}_${
rowData[cacheImages.cacheIdProperty]
}.jpg`
)
)
? path.join(
getImageCachePath(),
`${cacheImages.cacheType}_${rowData.albumId}.jpg`
`${cacheImages.cacheType}_${
rowData[cacheImages.cacheIdProperty]
}.jpg`
)
: rowData.image
}
@ -254,6 +283,60 @@ const ListViewTable = ({
);
}}
</Table.Cell>
) : column.dataKey === 'coverart' ? (
<Table.Cell>
{(rowData: any) => {
return (
<div
style={
multiSelect?.selected.find(
(e: any) => e.id === rowData.id
)
? {
background: '#4D5156',
lineHeight: `${rowHeight}px`,
}
: {
lineHeight: `${rowHeight}px`,
}
}
>
<LazyLoadImage
src={
isCached(
path.join(
getImageCachePath(),
`${cacheImages.cacheType}_${
rowData[cacheImages.cacheIdProperty]
}.jpg`
)
)
? path.join(
getImageCachePath(),
`${cacheImages.cacheType}_${
rowData[cacheImages.cacheIdProperty]
}.jpg`
)
: rowData.image
}
alt="track-img"
effect="opacity"
width={rowHeight - 10}
height={rowHeight - 10}
visibleByDefault={cacheImages.enabled}
afterLoad={() => {
if (cacheImages.enabled) {
cacheImage(
`${cacheImages.cacheType}_${rowData.albumId}.jpg`,
rowData.image.replace(/size=\d+/, 'size=350')
);
}
}}
/>
</div>
);
}}
</Table.Cell>
) : (
<Table.Cell>
{(rowData: any, rowIndex: any) => {
@ -292,6 +375,7 @@ const ListViewTable = ({
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
overflow: 'hidden',
paddingRight: '20px',
}}
>
{column.dataKey === 'album' ||
@ -319,7 +403,22 @@ const ListViewTable = ({
{rowData[column.dataKey]}
</RsuiteLinkButton>
) : column.dataKey === 'duration' ? (
formatSongDuration(rowData.duration)
formatSongDuration(rowData[column.dataKey])
) : column.dataKey === 'changed' ||
column.dataKey === 'created' ? (
formatDate(rowData[column.dataKey])
) : column.dataKey === 'starred' ? (
<Icon
tabIndex={0}
icon={rowData?.starred ? 'heart' : 'heart-o'}
size="lg"
fixedWidth
style={{
color: rowData?.starred ? '#1179ac' : undefined,
cursor: 'pointer',
}}
onClick={() => handleFavorite(rowData)}
/>
) : (
rowData[column.dataKey]
)}

2
src/components/viewtypes/ListViewType.tsx

@ -30,6 +30,7 @@ const ListViewType = (
fontSize,
cacheImages,
children,
listType,
...rest
}: any,
ref: any
@ -238,6 +239,7 @@ const ListViewType = (
playQueue={playQueue}
multiSelect={multiSelect}
cacheImages={cacheImages}
listType={listType}
/>
)}
</div>

11
src/redux/playQueueSlice.ts

@ -116,11 +116,14 @@ const playQueueSlice = createSlice({
state.autoIncremented = action.payload;
},
setStar: (state, action: PayloadAction<string>) => {
if (action.payload === 'unstar') {
state.entry[state.currentIndex].starred = undefined;
setStar: (state, action: PayloadAction<{ id: string; type: string }>) => {
const findIndex = state.entry.findIndex(
(track) => track.id === action.payload.id
);
if (action.payload.type === 'unstar') {
state.entry[findIndex].starred = undefined;
} else {
state.entry[state.currentIndex].starred = String(Date.now());
state.entry[findIndex].starred = String(Date.now());
}
},

18
src/shared/utils.ts

@ -1,6 +1,7 @@
import fs from 'fs';
import path from 'path';
import settings from 'electron-settings';
import moment from 'moment';
export const isCached = (filePath: string) => {
return fs.existsSync(filePath);
@ -43,12 +44,27 @@ export const shuffle = (array: any[]) => {
};
export const formatSongDuration = (duration: number) => {
const minutes = Math.floor(duration / 60);
const hours = Math.floor(duration / 60 / 60);
const minutes = Math.floor((duration / 60) % 60);
const seconds = String(duration % 60).padStart(2, '0');
// if (minutes > 60) {
// const hours = Math.floor(minutes / 60);
// const newMinutes = Math.floor(minutes % 60);
// const newSeconds = String(duration % 60).padStart(2, '0');
// return `${hours}:${newMinutes}:${newSeconds}`;
// }
if (hours > 0) {
return `${hours}:${String(minutes).padStart(2, '0')}:${seconds}`;
}
return `${minutes}:${seconds}`;
};
export const formatDate = (date: string) => {
return moment(date).format('L');
};
// https://www.geeksforgeeks.org/check-if-array-elements-are-consecutive/
const getMin = (arr: number[], n: number) => {
let min = arr[0];

1
src/styles/App.global.css

@ -37,6 +37,7 @@ h1 {
.rs-table-cell-content > div::selection,
.rs-table-cell-content > div > div::selection,
.rs-table-cell-content > div > span > img::selection,
.rs-table-cell-content > div > div > div > div > div > span::selection,
.rs-table-cell-content > div > div > div > div > span > img::selection,
.rs-table-cell-content > div > div > div > div > img::selection {

Loading…
Cancel
Save