Browse Source

Add drag/drop component for column selector

master
jeffvli 3 years ago
committed by Jeff
parent
commit
70518e12f5
  1. 251
      src/__tests__/App.test.tsx
  2. 164
      src/components/settings/ConfigPanels/ListViewConfig.tsx
  3. 72
      src/components/settings/ConfigPanels/LookAndFeelConfig.tsx
  4. 89
      src/components/viewtypes/ListViewTable.tsx
  5. 86
      src/redux/configSlice.ts
  6. 105
      src/shared/mockSettings.ts

251
src/__tests__/App.test.tsx

@ -108,6 +108,257 @@ const folderState: FolderSelection = {
const configState: ConfigPage = { const configState: ConfigPage = {
active: { active: {
tab: 'playback', tab: 'playback',
columnSelectorTab: 'music',
},
lookAndFeel: {
listView: {
music: {
columns: [
{
id: '#',
dataKey: 'index',
alignment: 'center',
resizable: true,
width: 50,
label: '# (Drag/Drop)',
},
{
id: 'Title',
dataKey: 'combinedtitle',
alignment: 'left',
flexGrow: 5,
label: 'Title (Combined)',
},
{
id: 'Album',
dataKey: 'album',
alignment: 'left',
flexGrow: 3,
label: 'Album',
},
{
id: 'Duration',
dataKey: 'duration',
alignment: 'center',
flexGrow: 2,
label: 'Duration',
},
{
id: 'Bitrate',
dataKey: 'bitRate',
alignment: 'left',
flexGrow: 1,
label: 'Bitrate',
},
{
id: 'Fav',
dataKey: 'starred',
alignment: 'center',
flexGrow: 1,
label: 'Favorite',
},
],
rowHeight: 40,
fontSize: 14,
},
album: {
columns: [
{
id: '#',
dataKey: 'index',
alignment: 'center',
resizable: true,
width: 50,
label: '#',
},
{
id: 'Title',
dataKey: 'combinedtitle',
alignment: 'left',
flexGrow: 5,
label: 'Title (Combined)',
},
{
id: 'Tracks',
dataKey: 'songCount',
alignment: 'center',
flexGrow: 1,
label: 'Track Count',
},
{
id: 'Duration',
dataKey: 'duration',
alignment: 'center',
flexGrow: 2,
label: 'Duration',
},
{
id: 'Fav',
dataKey: 'starred',
alignment: 'center',
flexGrow: 1,
label: 'Favorite',
},
],
rowHeight: 40,
fontSize: 14,
},
playlist: {
columns: [
{
id: '#',
dataKey: 'index',
alignment: 'center',
resizable: true,
width: 50,
label: '#',
},
{
id: 'Title',
dataKey: 'name',
alignment: 'left',
flexGrow: 5,
label: 'Title',
},
{
id: 'Description',
dataKey: 'comment',
alignment: 'left',
flexGrow: 3,
label: 'Description',
},
{
id: 'Tracks',
dataKey: 'songCount',
alignment: 'center',
flexGrow: 1,
label: 'Track Count',
},
{
id: 'Owner',
dataKey: 'owner',
alignment: 'left',
flexGrow: 2,
label: 'Owner',
},
{
id: 'Modified',
dataKey: 'changed',
alignment: 'left',
flexGrow: 1,
label: 'Modified',
},
],
rowHeight: 40,
fontSize: 14,
},
artist: {
columns: [
{
id: '#',
dataKey: 'index',
alignment: 'center',
resizable: true,
width: 50,
label: '#',
},
{
id: 'Art',
dataKey: 'coverart',
alignment: 'center',
resizable: true,
width: 50,
label: 'CoverArt',
},
{
id: 'Name',
dataKey: 'name',
alignment: 'left',
flexGrow: 5,
label: 'Name',
},
{
id: 'Albums',
dataKey: 'albumCount',
alignment: 'left',
flexGrow: 1,
label: 'Album Count',
},
{
id: 'Fav',
dataKey: 'starred',
alignment: 'center',
flexGrow: 1,
label: 'Favorite',
},
],
rowHeight: 40,
fontSize: 14,
},
genre: {
columns: [
{
id: '#',
dataKey: 'index',
alignment: 'center',
resizable: true,
width: 50,
label: '#',
},
{
id: 'Name',
dataKey: 'name',
alignment: 'left',
flexGrow: 5,
label: 'Name',
},
{
id: 'Albums',
dataKey: 'albumCount',
alignment: 'left',
flexGrow: 3,
label: 'Album Count',
},
{
id: 'Tracks',
dataKey: 'songCount',
alignment: 'left',
flexGrow: 1,
label: 'Song Count',
},
],
rowHeight: 40,
fontSize: 14,
},
mini: {
columns: [
{
id: '#',
dataKey: 'index',
alignment: 'center',
resizable: true,
width: 50,
label: '# (Drag/Drop)',
},
{
id: 'Title',
dataKey: 'combinedtitle',
alignment: 'left',
flexGrow: 5,
label: 'Title (Combined)',
},
{
id: 'Duration',
dataKey: 'duration',
alignment: 'center',
flexGrow: 2,
label: 'Duration',
},
],
rowHeight: 40,
fontSize: 14,
},
},
}, },
}; };

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

@ -1,58 +1,188 @@
import React from 'react'; import React, { useEffect, useState } from 'react';
import { nanoid } from 'nanoid/non-secure';
import settings from 'electron-settings'; import settings from 'electron-settings';
import { TagPicker, ControlLabel } from 'rsuite'; import { TagPicker, ControlLabel, Panel } from 'rsuite';
import { StyledInputNumber } from '../../shared/styled'; import { StyledInputNumber } from '../../shared/styled';
import ListViewTable from '../../viewtypes/ListViewTable';
import { useAppDispatch, useAppSelector } from '../../../redux/hooks';
import {
setIsDragging,
setRangeSelected,
toggleRangeSelected,
toggleSelected,
} from '../../../redux/multiSelectSlice';
import { ColumnList, moveToIndex, setColumnList } from '../../../redux/configSlice';
const columnSelectorColumns = [
{
id: '#',
dataKey: 'index',
alignment: 'center',
resizable: false,
width: 50,
label: '#',
},
{
id: 'Column',
dataKey: 'label',
alignment: 'left',
resizable: false,
flexGrow: 2,
label: 'Column',
},
{
id: 'Resizable',
dataKey: 'columnResizable',
alignment: 'left',
resizable: false,
width: 100,
label: 'Resizable',
},
];
const ListViewConfig = ({ defaultColumns, columnPicker, columnList, settingsConfig }: any) => { const ListViewConfig = ({ defaultColumns, columnPicker, columnList, settingsConfig }: any) => {
const dispatch = useAppDispatch();
const playQueue = useAppSelector((state) => state.playQueue);
const multiSelect = useAppSelector((state) => state.multiSelect);
const config = useAppSelector((state) => state.config);
const [selectedColumns, setSelectedColumns] = useState([]);
const columnListType = settingsConfig.columnList.split('List')[0];
useEffect(() => {
const cols = config.lookAndFeel.listView[columnListType].columns.map((col: any) => {
return col.label;
});
setSelectedColumns(cols);
settings.setSync(
settingsConfig.columnList,
config.lookAndFeel.listView[columnListType].columns
);
}, [columnListType, config.lookAndFeel.listView, settingsConfig.columnList]);
let timeout: any = null;
const handleRowClick = (e: any, rowData: any) => {
if (timeout === null) {
timeout = window.setTimeout(() => {
timeout = null;
if (e.ctrlKey) {
dispatch(toggleSelected(rowData));
} else if (e.shiftKey) {
dispatch(setRangeSelected(rowData));
dispatch(toggleRangeSelected(config.lookAndFeel.listView[columnListType].columns));
}
}, 100);
}
};
const handleDragEnd = (listType: ColumnList) => {
if (multiSelect.isDragging) {
dispatch(
moveToIndex({
entries: multiSelect.selected,
moveBeforeId: multiSelect.currentMouseOverId,
listType,
})
);
dispatch(setIsDragging(false));
}
};
return ( return (
<div style={{ width: '100%' }}> <div style={{ width: '100%' }}>
<br /> <div>
<Panel bordered bodyFill>
<TagPicker <TagPicker
data={columnPicker} data={columnPicker}
defaultValue={defaultColumns} defaultValue={defaultColumns}
style={{ width: '500px' }} value={selectedColumns}
style={{ width: '100%' }}
onChange={(e) => { onChange={(e) => {
const columns: any[] = []; const columns: any[] = [];
if (e) { if (e) {
e.map((selected: string) => { e.forEach((selected: string) => {
const selectedColumn = columnList.find((column: any) => column.label === selected); const alreadySelectedColumn = config.lookAndFeel.listView[
columnListType
].columns.find((column: any) => column.label === selected);
if (alreadySelectedColumn) {
return columns.push(alreadySelectedColumn);
}
const selectedColumn = columnList.find(
(column: any) => column.label === selected
);
if (selectedColumn) { if (selectedColumn) {
return columns.push(selectedColumn.value); return columns.push({ ...selectedColumn.value, uniqueId: nanoid() });
} }
return null; return null;
}); });
} }
settings.setSync(settingsConfig.columnList, columns); const cleanColumns = columns.map((col) => {
const { uniqueId, ...rest } = col;
return rest;
});
dispatch(setColumnList({ listType: columnListType, entries: columns }));
settings.setSync(settingsConfig.columnList, cleanColumns);
}} }}
labelKey="label" labelKey="label"
valueKey="label" valueKey="label"
/> />
<div style={{ marginTop: '20px' }}>
<ListViewTable
data={config.lookAndFeel.listView[columnListType].columns || []}
height={300}
handleRowClick={handleRowClick}
handleRowDoubleClick={() => {}}
handleDragEnd={() => handleDragEnd(columnListType)}
columns={columnSelectorColumns}
rowHeight={35}
fontSize={12}
listType="column"
cacheImages={{ enabled: false }}
playQueue={playQueue}
multiSelect={multiSelect}
isModal={false}
miniView={false}
dnd
disableContextMenu
config={{ option: columnListType, columnList }}
virtualized
/>
</Panel>
</div>
<br />
<div>
<ControlLabel>Row height</ControlLabel> <ControlLabel>Row height</ControlLabel>
<StyledInputNumber <StyledInputNumber
defaultValue={String(settings.getSync(settingsConfig.rowHeight)) || '0'} defaultValue={Number(settings.getSync(settingsConfig.rowHeight)) || 0}
step={1} step={1}
min={15} min={15}
max={250} max={250}
width={150} width={150}
onChange={(e: any) => { onChange={(e: number) => {
settings.setSync(settingsConfig.rowHeight, e); settings.setSync(settingsConfig.rowHeight, Number(e));
}} }}
/> />
</div> </div>
<div style={{ marginTop: '20px' }}> <br />
<div>
<ControlLabel>Font size</ControlLabel> <ControlLabel>Font size</ControlLabel>
<StyledInputNumber <StyledInputNumber
defaultValue={String(settings.getSync(settingsConfig.fontSize)) || '0'} defaultValue={Number(settings.getSync(settingsConfig.fontSize)) || 0}
step={0.5} step={0.5}
min={1} min={1}
max={100} max={100}
width={150} width={150}
onChange={(e: any) => { onChange={(e: number) => {
settings.setSync(settingsConfig.fontSize, e); settings.setSync(settingsConfig.fontSize, Number(e));
}} }}
/> />
</div> </div>

72
src/components/settings/ConfigPanels/LookAndFeelConfig.tsx

@ -56,6 +56,7 @@ const LookAndFeelConfig = () => {
const currentGenreColumns = genreCols?.map((column: any) => column.label) || []; const currentGenreColumns = genreCols?.map((column: any) => column.label) || [];
return ( return (
<>
<ConfigPanel header="Look & Feel" bordered> <ConfigPanel header="Look & Feel" bordered>
<div style={{ width: '300px' }}> <div style={{ width: '300px' }}>
<p>Select the main application theme.</p> <p>Select the main application theme.</p>
@ -72,21 +73,7 @@ const LookAndFeelConfig = () => {
<StyledRadio value="defaultLight">Default Light</StyledRadio> <StyledRadio value="defaultLight">Default Light</StyledRadio>
</RadioGroup> </RadioGroup>
<br /> <br />
<StyledCheckbox
defaultChecked={dynamicBackgroundChk}
checked={dynamicBackgroundChk}
onChange={(_v: any, e: boolean) => {
settings.setSync('dynamicBackground', e);
dispatch(setDynamicBackground(e));
setDynamicBackgroundChk(e);
}}
>
Enable dynamic background
</StyledCheckbox>
<br />
<ControlLabel>Font</ControlLabel> <ControlLabel>Font</ControlLabel>
<br /> <br />
<StyledInputPicker <StyledInputPicker
data={Fonts} data={Fonts}
@ -102,7 +89,6 @@ const LookAndFeelConfig = () => {
<br /> <br />
<div> <div>
<ControlLabel>Titlebar style (requires app restart)</ControlLabel> <ControlLabel>Titlebar style (requires app restart)</ControlLabel>
<br /> <br />
<StyledInputPicker <StyledInputPicker
data={[ data={[
@ -124,38 +110,20 @@ const LookAndFeelConfig = () => {
/> />
</div> </div>
<br /> <br />
<ConfigPanel header="List-View" bordered>
<StyledCheckbox <StyledCheckbox
defaultChecked={highlightOnRowHoverChk} defaultChecked={dynamicBackgroundChk}
checked={highlightOnRowHoverChk} checked={dynamicBackgroundChk}
onChange={(_v: any, e: boolean) => {
settings.setSync('highlightOnRowHover', e);
dispatch(
setMiscSetting({
setting: 'highlightOnRowHover',
value: e,
})
);
setHighlightOnRowHoverChk(e);
}}
>
Show highlight on row hover
</StyledCheckbox>
<br />
<p>Select the columns you want displayed on pages with a list-view.</p>
<StyledCheckbox
defaultChecked={resizableColumn}
onChange={(_v: any, e: boolean) => { onChange={(_v: any, e: boolean) => {
setResizableColumn(e); settings.setSync('dynamicBackground', e);
dispatch(setDynamicBackground(e));
setDynamicBackgroundChk(e);
}} }}
> >
Use resizable columns (check/uncheck this before selecting columns) Enable dynamic background
</StyledCheckbox> </StyledCheckbox>
<Nav </ConfigPanel>
style={{ paddingTop: '10px' }} <ConfigPanel header="List-View" bordered>
activeKey={currentLAFTab} <Nav activeKey={currentLAFTab} onSelect={(e) => setCurrentLAFTab(e)}>
onSelect={(e) => setCurrentLAFTab(e)}
>
<StyledNavItem eventKey="songList">Songs</StyledNavItem> <StyledNavItem eventKey="songList">Songs</StyledNavItem>
<StyledNavItem eventKey="albumList">Albums</StyledNavItem> <StyledNavItem eventKey="albumList">Albums</StyledNavItem>
<StyledNavItem eventKey="playlistList">Playlists</StyledNavItem> <StyledNavItem eventKey="playlistList">Playlists</StyledNavItem>
@ -246,6 +214,24 @@ const LookAndFeelConfig = () => {
}} }}
/> />
)} )}
<br />
<StyledCheckbox
defaultChecked={highlightOnRowHoverChk}
checked={highlightOnRowHoverChk}
onChange={(_v: any, e: boolean) => {
settings.setSync('highlightOnRowHover', e);
dispatch(
setMiscSetting({
setting: 'highlightOnRowHover',
value: e,
})
);
setHighlightOnRowHoverChk(e);
}}
>
Show highlight on row hover
</StyledCheckbox>
</ConfigPanel> </ConfigPanel>
<ConfigPanel header="Grid-View" bordered> <ConfigPanel header="Grid-View" bordered>
<ControlLabel>Card size</ControlLabel> <ControlLabel>Card size</ControlLabel>
@ -260,7 +246,7 @@ const LookAndFeelConfig = () => {
}} }}
/> />
</ConfigPanel> </ConfigPanel>
</ConfigPanel> </>
); );
}; };

89
src/components/viewtypes/ListViewTable.tsx

@ -25,7 +25,7 @@ import {
import cacheImage from '../shared/cacheImage'; import cacheImage from '../shared/cacheImage';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import { fixPlayer2Index, setSort, sortPlayQueue } from '../../redux/playQueueSlice'; import { fixPlayer2Index, setSort, sortPlayQueue } from '../../redux/playQueueSlice';
import { StyledIconToggle, StyledRate } from '../shared/styled'; import { StyledCheckbox, StyledIconToggle, StyledRate } from '../shared/styled';
import { addModalPage, setContextMenu } from '../../redux/miscSlice'; import { addModalPage, setContextMenu } from '../../redux/miscSlice';
import { import {
clearSelected, clearSelected,
@ -40,6 +40,7 @@ import {
} from '../../redux/multiSelectSlice'; } from '../../redux/multiSelectSlice';
import CustomTooltip from '../shared/CustomTooltip'; import CustomTooltip from '../shared/CustomTooltip';
import { sortPlaylist } from '../../redux/playlistSlice'; import { sortPlaylist } from '../../redux/playlistSlice';
import { setColumnList } from '../../redux/configSlice';
const StyledTable = styled(Table)<{ rowHeight: number; $isDragging: boolean }>` const StyledTable = styled(Table)<{ rowHeight: number; $isDragging: boolean }>`
.rs-table-row.selected { .rs-table-row.selected {
@ -97,6 +98,7 @@ const ListViewTable = ({
const history = useHistory(); const history = useHistory();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const misc = useAppSelector((state) => state.misc); const misc = useAppSelector((state) => state.misc);
const configState = useAppSelector((state) => state.config);
const [sortColumn, setSortColumn] = useState<any>(); const [sortColumn, setSortColumn] = useState<any>();
const [sortType, setSortType] = useState<any>(); const [sortType, setSortType] = useState<any>();
const [sortedData, setSortedData] = useState(data); const [sortedData, setSortedData] = useState(data);
@ -379,16 +381,31 @@ const ListViewTable = ({
fixed={column.fixed} fixed={column.fixed}
verticalAlign="middle" verticalAlign="middle"
sortable sortable
onResize={(width: any) => { onResize={(newWidth: any) => {
const resizedColumnIndex = columns.findIndex( const resizedColumnIndex = columns.findIndex(
(c: any) => c.dataKey === column.dataKey (c: any) => c.dataKey === column.dataKey
); );
if (!miniView) { if (!miniView) {
settings.setSync(`${listType}ListColumns[${resizedColumnIndex}].width`, width); settings.setSync(`${listType}ListColumns[${resizedColumnIndex}].width`, newWidth);
} else { } else {
settings.setSync(`miniListColumns[${resizedColumnIndex}].width`, width); settings.setSync(`miniListColumns[${resizedColumnIndex}].width`, newWidth);
} }
const newCols = configState.lookAndFeel.listView[listType].columns.map((c: any) => {
if (c.dataKey === column.dataKey) {
const { width, ...rest } = c;
return { width: newWidth, ...rest };
}
return { ...c };
});
dispatch(
setColumnList({
listType,
entries: newCols,
})
);
}} }}
> >
<StyledTableHeaderCell>{column.id}</StyledTableHeaderCell> <StyledTableHeaderCell>{column.id}</StyledTableHeaderCell>
@ -730,7 +747,11 @@ const ListViewTable = ({
} }
height={rowHeight} height={rowHeight}
onClick={(e: any) => { onClick={(e: any) => {
if (!column.dataKey?.match(/starred|songCount|duration|userRating/)) { if (
!column.dataKey?.match(
/starred|songCount|duration|userRating|columnResizable|columnDefaultSort/
)
) {
handleRowClick(e, { handleRowClick(e, {
...rowData, ...rowData,
rowIndex, rowIndex,
@ -738,7 +759,11 @@ const ListViewTable = ({
} }
}} }}
onDoubleClick={() => { onDoubleClick={() => {
if (!column.dataKey?.match(/starred|songCount|duration|userRating/)) { if (
!column.dataKey?.match(
/starred|songCount|duration|userRating|columnResizable|columnDefaultSort/
)
) {
handleRowDoubleClick({ handleRowDoubleClick({
...rowData, ...rowData,
rowIndex, rowIndex,
@ -761,7 +786,7 @@ const ListViewTable = ({
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
overflow: 'hidden', overflow: 'hidden',
paddingRight: !column.dataKey?.match( paddingRight: !column.dataKey?.match(
/starred|songCount|duration|userRating/ /starred|songCount|duration|userRating|columnResizable|columnDefaultSort/
) )
? '10px' ? '10px'
: undefined, : undefined,
@ -846,7 +871,55 @@ const ListViewTable = ({
`${rowData[column.dataKey]} kbps` `${rowData[column.dataKey]} kbps`
) )
) : column.dataKey === 'custom' ? ( ) : column.dataKey === 'custom' ? (
<>{rowData.uniqueId}</> <div>{column.custom}</div>
) : column.dataKey === 'columnResizable' ? (
<div>
<StyledCheckbox
defaultChecked={
configState.lookAndFeel.listView[config.option].columns[
configState.lookAndFeel.listView[config.option].columns.findIndex(
(col: any) => col.dataKey === rowData.dataKey
)
]?.resizable === true
}
checked={
configState.lookAndFeel.listView[config.option].columns[
configState.lookAndFeel.listView[config.option].columns.findIndex(
(col: any) => col.dataKey === rowData.dataKey
)
]?.resizable === true
}
onChange={(_v: any, e: any) => {
const cols = configState.lookAndFeel.listView[
config.option
].columns.map((col: any) => {
if (rowData.dataKey === col.dataKey) {
if (e === true) {
const { flexGrow, ...newCols } = col;
return { ...newCols, resizable: e };
}
const columnPickerMatch = config.columnList.findIndex(
(picker: any) => picker.value.dataKey === rowData.dataKey
);
const matchedFlexGrowValue =
config.columnList[columnPickerMatch]?.value.flexGrow || 1;
const { width, rowIndex: r, ...newCols } = col;
return {
...newCols,
flexGrow: matchedFlexGrowValue,
resizable: e,
};
}
return { ...col };
});
dispatch(setColumnList({ listType: config.option, entries: cols }));
}}
/>
</div>
) : rowData[column.dataKey] ? ( ) : rowData[column.dataKey] ? (
rowData[column.dataKey] rowData[column.dataKey]
) : ( ) : (

86
src/redux/configSlice.ts

@ -1,15 +1,80 @@
import { nanoid } from 'nanoid/non-secure';
import _ from 'lodash';
import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import settings from 'electron-settings';
import { mockSettings } from '../shared/mockSettings';
import { moveSelectedToIndex } from '../shared/utils';
const parsedSettings: any = process.env.NODE_ENV === 'test' ? mockSettings : settings.getSync();
export interface ConfigPage { export interface ConfigPage {
active: { active: {
tab: string; tab: string;
}; };
lookAndFeel: {
listView: {
music: { columns: any; rowHeight: number; fontSize: number };
album: { columns: any; rowHeight: number; fontSize: number };
playlist: { columns: any; rowHeight: number; fontSize: number };
artist: { columns: any; rowHeight: number; fontSize: number };
genre: { columns: any; rowHeight: number; fontSize: number };
mini: { columns: any; rowHeight: number; fontSize: number };
};
};
} }
export type ColumnList = 'music' | 'album' | 'playlist' | 'artist' | 'genre' | 'mini';
const initialState: ConfigPage = { const initialState: ConfigPage = {
active: { active: {
tab: 'playback', tab: 'playback',
}, },
lookAndFeel: {
listView: {
music: {
columns: parsedSettings.musicListColumns!.map((col: any) => {
return { ...col, uniqueId: nanoid() };
}),
rowHeight: Number(parsedSettings.musicListRowHeight),
fontSize: Number(parsedSettings.musicListFontSize),
},
album: {
columns: parsedSettings.albumListColumns!.map((col: any) => {
return { ...col, uniqueId: nanoid() };
}),
rowHeight: Number(parsedSettings.albumListRowHeight),
fontSize: Number(parsedSettings.albumListFontSize),
},
playlist: {
columns: parsedSettings.playlistListColumns!.map((col: any) => {
return { ...col, uniqueId: nanoid() };
}),
rowHeight: Number(parsedSettings.playlistListRowHeight),
fontSize: Number(parsedSettings.playlistListFontSize),
},
artist: {
columns: parsedSettings.artistListColumns!.map((col: any) => {
return { ...col, uniqueId: nanoid() };
}),
rowHeight: Number(parsedSettings.artistListRowHeight),
fontSize: Number(parsedSettings.artistListFontSize),
},
genre: {
columns: parsedSettings.genreListColumns!.map((col: any) => {
return { ...col, uniqueId: nanoid() };
}),
rowHeight: Number(parsedSettings.genreListRowHeight),
fontSize: Number(parsedSettings.genreListFontSize),
},
mini: {
columns: parsedSettings.miniListColumns!.map((col: any) => {
return { ...col, uniqueId: nanoid() };
}),
rowHeight: Number(parsedSettings.miniListRowHeight),
fontSize: Number(parsedSettings.miniListFontSize),
},
},
},
}; };
const configSlice = createSlice({ const configSlice = createSlice({
@ -19,8 +84,27 @@ const configSlice = createSlice({
setActive: (state, action: PayloadAction<{ tab: string }>) => { setActive: (state, action: PayloadAction<{ tab: string }>) => {
state.active.tab = action.payload.tab; state.active.tab = action.payload.tab;
}, },
setColumnList: (state, action: PayloadAction<{ listType: ColumnList; entries: any }>) => {
state.lookAndFeel.listView[action.payload.listType].columns = action.payload.entries;
},
moveToIndex: (
state,
action: PayloadAction<{
entries: any;
moveBeforeId: string;
listType: 'music' | 'album' | 'playlist' | 'artist' | 'genre' | 'mini';
}>
) => {
state.lookAndFeel.listView[action.payload.listType].columns = moveSelectedToIndex(
state.lookAndFeel.listView[action.payload.listType].columns,
action.payload.entries,
action.payload.moveBeforeId
);
},
}, },
}); });
export const { setActive } = configSlice.actions; export const { setActive, setColumnList, moveToIndex } = configSlice.actions;
export default configSlice.reducer; export default configSlice.reducer;

105
src/shared/mockSettings.ts

@ -27,8 +27,8 @@ export const mockSettings = {
gridCardSize: 200, gridCardSize: 200,
playlistViewType: 'grid', playlistViewType: 'grid',
albumViewType: 'grid', albumViewType: 'grid',
musicListFontSize: '13', musicListFontSize: 13,
musicListRowHeight: '50', musicListRowHeight: 50,
musicListColumns: [ musicListColumns: [
{ {
id: '#', id: '#',
@ -79,8 +79,8 @@ export const mockSettings = {
label: 'Favorite', label: 'Favorite',
}, },
], ],
albumListFontSize: '14', albumListFontSize: 14,
albumListRowHeight: '60', albumListRowHeight: 60,
albumListColumns: [ albumListColumns: [
{ {
id: '#', id: '#',
@ -123,8 +123,91 @@ export const mockSettings = {
label: 'Favorite', label: 'Favorite',
}, },
], ],
playlistListFontSize: '14', artistListFontSize: 14,
playlistListRowHeight: '80', artistListRowHeight: 60,
artistListColumns: [
{
id: '#',
dataKey: 'index',
alignment: 'center',
resizable: true,
width: 50,
label: '#',
uniqueId: 'bOCYMfNieUHtjl1XhM-GT',
},
{
id: 'Art',
dataKey: 'coverart',
alignment: 'center',
resizable: true,
width: 74,
label: 'CoverArt',
uniqueId: '2Z8rUZi47VnlQSBfZzRk8',
},
{
id: 'Name',
dataKey: 'name',
alignment: 'left',
flexGrow: 5,
label: 'Name',
uniqueId: 'Vv_luiyR3rp5b07Szd0zd',
},
{
id: 'Album Count',
dataKey: 'albumCount',
alignment: 'left',
flexGrow: 1,
label: 'Album Count',
uniqueId: 'IScD9714XLFrQYSAFkmoL',
},
{
id: 'Fav',
dataKey: 'starred',
alignment: 'center',
flexGrow: 1,
label: 'Favorite',
uniqueId: 'eFrudHQBTnBXNuD3mL-c1',
},
],
genreListFontSize: 14,
genreListRowHeight: 50,
genreListColumns: [
{
id: '#',
dataKey: 'index',
alignment: 'center',
resizable: true,
width: 66,
label: '#',
uniqueId: 'ZXNE6gsaLm0kVRyueOBHS',
},
{
id: 'Name',
dataKey: 'name',
alignment: 'left',
flexGrow: 5,
label: 'Name',
uniqueId: 'FTY1gWAjc0i6NVjim_8aZ',
},
{
id: 'Album Count',
dataKey: 'albumCount',
alignment: 'left',
flexGrow: 1,
label: 'Album Count',
uniqueId: 'oHqG0mGN_E7iLairZGnZL',
},
{
id: 'Tracks',
dataKey: 'songCount',
alignment: 'center',
flexGrow: 1,
label: 'Track Count',
uniqueId: 'c1qxv4S5YC7YUvbOG_WJF',
},
],
playlistListFontSize: 14,
playlistListRowHeight: 80,
playlistListColumns: [ playlistListColumns: [
{ {
id: '#', id: '#',
@ -183,7 +266,8 @@ export const mockSettings = {
label: 'Modified', label: 'Modified',
}, },
], ],
miniListFontSize: '14', miniListFontSize: 14,
miniListRowHeight: 40,
miniListColumns: [ miniListColumns: [
{ {
id: '#', id: '#',
@ -213,6 +297,11 @@ export const mockSettings = {
font: 'Poppins', font: 'Poppins',
server: 'http://192.168.14.11:4040', server: 'http://192.168.14.11:4040',
serverBase64: 'aHR0cDovLzE5Mi4xNjguMTQuMTE6NDA0MA==', serverBase64: 'aHR0cDovLzE5Mi4xNjguMTQuMTE6NDA0MA==',
miniListRowHeight: '30',
dynamicBackground: false, dynamicBackground: false,
minimizeToTray: true,
exitToTray: true,
windowPosition: { x: 0, y: 0, width: 960, height: 1560 },
windowMaximize: false,
highlightOnRowHover: false,
titleBarStyle: 'windows',
}; };

Loading…
Cancel
Save