Browse Source

Add regex queue filters component, state, settings

master
jeffvli 3 years ago
committed by Jeff
parent
commit
b07154539e
  1. 3
      src/__tests__/App.test.tsx
  2. 119
      src/components/settings/ConfigPanels/PlayerConfig.tsx
  3. 13
      src/components/shared/setDefaultSettings.ts
  4. 44
      src/components/viewtypes/ListViewTable.tsx
  5. 42
      src/redux/configSlice.ts
  6. 6
      src/shared/mockSettings.ts

3
src/__tests__/App.test.tsx

@ -110,6 +110,9 @@ const configState: ConfigPage = {
tab: 'playback',
columnSelectorTab: 'music',
},
playback: {
filters: [],
},
lookAndFeel: {
listView: {
music: {

119
src/components/settings/ConfigPanels/PlayerConfig.tsx

@ -1,17 +1,70 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import settings from 'electron-settings';
import { ControlLabel } from 'rsuite';
import { ControlLabel, Form } from 'rsuite';
import { ConfigPanel } from '../styled';
import { StyledCheckbox, StyledInputNumber } from '../../shared/styled';
import { useAppDispatch } from '../../../redux/hooks';
import {
StyledButton,
StyledCheckbox,
StyledInput,
StyledInputGroup,
StyledInputNumber,
StyledPanel,
} from '../../shared/styled';
import { useAppDispatch, useAppSelector } from '../../../redux/hooks';
import { setPlaybackSetting } from '../../../redux/playQueueSlice';
import ListViewTable from '../../viewtypes/ListViewTable';
import { appendPlaybackFilter } from '../../../redux/configSlice';
const playbackFilterColumns = [
{
id: '#',
dataKey: 'index',
alignment: 'center',
resizable: false,
width: 50,
label: '#',
},
{
id: 'Filter',
dataKey: 'filter',
alignment: 'left',
resizable: false,
flexGrow: 2,
label: 'Filter',
},
{
id: 'Enabled',
dataKey: 'filterEnabled',
alignment: 'left',
resizable: false,
width: 100,
label: 'Enabled',
},
{
id: 'Delete',
dataKey: 'filterDelete',
alignment: 'left',
resizable: false,
width: 100,
label: 'Delete',
},
];
const PlayerConfig = () => {
const dispatch = useAppDispatch();
const playQueue = useAppSelector((state) => state.playQueue);
const multiSelect = useAppSelector((state) => state.multiSelect);
const config = useAppSelector((state) => state.config);
const [newFilter, setNewFilter] = useState('');
const [globalMediaHotkeys, setGlobalMediaHotkeys] = useState(
Boolean(settings.getSync('globalMediaHotkeys'))
);
const [scrobble, setScrobble] = useState(Boolean(settings.getSync('scrobble')));
useEffect(() => {
settings.setSync('playbackFilters', config.playback.filters);
}, [config.playback.filters]);
return (
<ConfigPanel header="Player" bordered>
<p>
@ -62,6 +115,64 @@ const PlayerConfig = () => {
>
Enable scrobbling
</StyledCheckbox>
<br />
<h6>Filters</h6>
<p>
Any song title that matches a filter will be automatically removed when being added to the
queue.
</p>
<p style={{ fontSize: 'smaller' }}>
* Adding to the queue by double-clicking a song will ignore filters for that one song
</p>
<br />
<StyledPanel bordered bodyFill>
<Form fluid>
<StyledInputGroup>
<StyledInput
value={newFilter}
onChange={(e: string) => setNewFilter(e)}
placeholder="Enter regex string"
/>
<StyledButton
type="submit"
disabled={newFilter === ''}
onClick={() => {
dispatch(appendPlaybackFilter({ filter: newFilter, enabled: true }));
settings.setSync(
'playbackFilters',
config.playback.filters.concat({
filter: newFilter,
enabled: true,
})
);
setNewFilter('');
}}
>
Add
</StyledButton>
</StyledInputGroup>
</Form>
<ListViewTable
data={config.playback.filters || []}
height={200}
columns={playbackFilterColumns}
rowHeight={35}
fontSize={12}
listType="column"
cacheImages={{ enabled: false }}
playQueue={playQueue}
multiSelect={multiSelect}
isModal={false}
miniView={false}
disableContextMenu
disableRowClick
handleRowClick={() => {}}
handleRowDoubleClick={() => {}}
config={[]}
virtualized
/>
</StyledPanel>
</ConfigPanel>
);
};

13
src/components/shared/setDefaultSettings.ts

@ -146,6 +146,19 @@ const setDefaultSettings = (force: boolean) => {
settings.setSync('randomPlaylistTrackCount', 50);
}
if (force || !settings.hasSync('playbackFilters')) {
settings.setSync('playbackFilters', [
{
filter: '(\\(|\\[|~|-|()[Oo]ff [Vv]ocal(\\)|\\]|~|-|))',
enabled: true,
},
{
filter: '((|\\(|\\[|~|-)[Ii]nst(rumental)?(\\)|\\]|~|-|))',
enabled: true,
},
]);
}
if (force || !settings.hasSync('musicListColumns')) {
settings.setSync('musicListColumns', [
{

44
src/components/viewtypes/ListViewTable.tsx

@ -25,7 +25,7 @@ import {
import cacheImage from '../shared/cacheImage';
import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import { fixPlayer2Index, setSort, sortPlayQueue } from '../../redux/playQueueSlice';
import { StyledCheckbox, StyledIconToggle, StyledRate } from '../shared/styled';
import { StyledCheckbox, StyledIconButton, StyledIconToggle, StyledRate } from '../shared/styled';
import { addModalPage, setContextMenu } from '../../redux/miscSlice';
import {
clearSelected,
@ -40,7 +40,7 @@ import {
} from '../../redux/multiSelectSlice';
import CustomTooltip from '../shared/CustomTooltip';
import { sortPlaylist } from '../../redux/playlistSlice';
import { setColumnList } from '../../redux/configSlice';
import { removePlaybackFilter, setColumnList, setPlaybackFilter } from '../../redux/configSlice';
import { setActive } from '../../redux/albumSlice';
const StyledTable = styled(Table)<{ rowHeight: number; $isDragging: boolean }>`
@ -902,6 +902,46 @@ const ListViewTable = ({
)
) : column.dataKey === 'custom' ? (
<div>{column.custom}</div>
) : column.dataKey === 'filter' ? (
<div style={{ userSelect: 'text' }}>{rowData.filter}</div>
) : column.dataKey === 'filterDelete' ? (
<>
<StyledIconButton
appearance="subtle"
icon={<Icon icon="trash2" />}
onClick={() => {
dispatch(removePlaybackFilter({ filterName: rowData.filter }));
}}
/>
</>
) : column.dataKey === 'filterEnabled' ? (
<>
<StyledCheckbox
defaultChecked={
configState.playback.filters.find(
(f: any) => f.filter === rowData.filter
)?.enabled === true
}
checked={
configState.playback.filters.find(
(f: any) => f.filter === rowData.filter
)?.enabled === true
}
onChange={(_v: any, e: boolean) => {
dispatch(
setPlaybackFilter({
filterName: rowData.filter,
newFilter: {
...configState.playback.filters.find(
(f: any) => f.filter === rowData.filter
),
enabled: e,
},
})
);
}}
/>
</>
) : column.dataKey === 'columnResizable' ? (
<div>
<StyledCheckbox

42
src/redux/configSlice.ts

@ -11,6 +11,9 @@ export interface ConfigPage {
tab: string;
columnSelectorTab: string;
};
playback: {
filters: PlaybackFilter[];
};
lookAndFeel: {
listView: {
music: { columns: any; rowHeight: number; fontSize: number };
@ -26,6 +29,11 @@ export interface ConfigPage {
};
}
interface PlaybackFilter {
filter: string;
enabled: boolean;
}
export type ColumnList = 'music' | 'album' | 'playlist' | 'artist' | 'genre' | 'mini';
const initialState: ConfigPage = {
@ -33,6 +41,9 @@ const initialState: ConfigPage = {
tab: 'playback',
columnSelectorTab: 'music',
},
playback: {
filters: parsedSettings.playbackFilters,
},
lookAndFeel: {
listView: {
music: {
@ -92,6 +103,33 @@ const configSlice = createSlice({
state.active = action.payload;
},
appendPlaybackFilter: (state, action: PayloadAction<PlaybackFilter>) => {
if (!state.playback.filters.find((f: PlaybackFilter) => f.filter === action.payload.filter)) {
state.playback.filters.push(action.payload);
}
},
setPlaybackFilter: (
state,
action: PayloadAction<{ filterName: string; newFilter: PlaybackFilter }>
) => {
const selectedFilterIndex = state.playback.filters.findIndex(
(f: PlaybackFilter) => f.filter === action.payload.filterName
);
state.playback.filters[selectedFilterIndex] = action.payload.newFilter;
},
removePlaybackFilter: (state, action: PayloadAction<{ filterName: string }>) => {
state.playback.filters = state.playback.filters.filter(
(f: PlaybackFilter) => f.filter !== action.payload.filterName
);
},
setPlaybackFilters: (state, action: PayloadAction<any>) => {
state.playback.filters = action.payload;
},
setColumnList: (state, action: PayloadAction<{ listType: ColumnList; entries: any }>) => {
state.lookAndFeel.listView[action.payload.listType].columns = action.payload.entries;
},
@ -127,6 +165,10 @@ const configSlice = createSlice({
export const {
setActive,
appendPlaybackFilter,
removePlaybackFilter,
setPlaybackFilter,
setPlaybackFilters,
setColumnList,
setRowHeight,
setFontSize,

6
src/shared/mockSettings.ts

@ -16,6 +16,12 @@ export const mockSettings = {
fadeDuration: 9,
fadeType: 'equalPower',
scrobble: false,
playbackFilters: [
{
filter: '((|\\(|\\[|~|-)[Ii]nst(rumental)?(\\)|\\]|~|-|))',
enabled: true,
},
],
musicFolder: {
id: null,
albums: true,

Loading…
Cancel
Save