473 lines
17 KiB
TypeScript
473 lines
17 KiB
TypeScript
import { Group } from '@mantine/core';
|
|
import { t } from 'i18next';
|
|
import isElectron from 'is-electron';
|
|
import { Select, Tooltip, NumberInput, Switch, Slider } from '/@/renderer/components';
|
|
import { SettingsSection } from '/@/renderer/features/settings/components/settings-section';
|
|
import {
|
|
GenreTarget,
|
|
SideQueueType,
|
|
useGeneralSettings,
|
|
useSettingsStoreActions,
|
|
} from '/@/renderer/store/settings.store';
|
|
import { Play } from '/@/renderer/types';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
const localSettings = isElectron() ? window.electron.localSettings : null;
|
|
|
|
const SIDE_QUEUE_OPTIONS = [
|
|
{
|
|
label: t('setting.sidePlayQueueStyle', {
|
|
context: 'optionAttached',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
value: 'sideQueue',
|
|
},
|
|
{
|
|
label: t('setting.sidePlayQueueStyle', {
|
|
context: 'optionDetached',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
value: 'sideDrawerQueue',
|
|
},
|
|
];
|
|
|
|
export const ControlSettings = () => {
|
|
const { t } = useTranslation();
|
|
const settings = useGeneralSettings();
|
|
const { setSettings } = useSettingsStoreActions();
|
|
|
|
const controlOptions = [
|
|
{
|
|
control: (
|
|
<NumberInput
|
|
defaultValue={settings.buttonSize}
|
|
max={30}
|
|
min={15}
|
|
rightSection="px"
|
|
width={75}
|
|
onBlur={(e) => {
|
|
if (!e) return;
|
|
const newVal = e.currentTarget.value
|
|
? Math.min(Math.max(Number(e.currentTarget.value), 15), 30)
|
|
: settings.buttonSize;
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
buttonSize: newVal,
|
|
},
|
|
});
|
|
}}
|
|
/>
|
|
),
|
|
description: t('setting.buttonSize', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: false,
|
|
title: t('setting.buttonSize', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<NumberInput
|
|
defaultValue={settings.albumArtRes || undefined}
|
|
max={2500}
|
|
placeholder="0"
|
|
rightSection="px"
|
|
value={settings.albumArtRes ?? 0}
|
|
width={75}
|
|
onBlur={(e) => {
|
|
const newVal =
|
|
e.currentTarget.value !== '0'
|
|
? Math.min(Math.max(Number(e.currentTarget.value), 175), 2500)
|
|
: null;
|
|
setSettings({ general: { ...settings, albumArtRes: newVal } });
|
|
}}
|
|
/>
|
|
),
|
|
description: t('setting.playerAlbumArtResolution', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: false,
|
|
title: t('setting.playerAlbumArtResolution', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<Switch
|
|
aria-label="Toggle using native aspect ratio"
|
|
defaultChecked={settings.nativeAspectRatio}
|
|
onChange={(e) =>
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
nativeAspectRatio: e.currentTarget.checked,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
),
|
|
description: t('setting.imageAspectRatio', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: false,
|
|
title: t('setting.imageAspectRatio', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<Switch
|
|
aria-label="Toggle skip buttons"
|
|
defaultChecked={settings.skipButtons?.enabled}
|
|
onChange={(e) =>
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
skipButtons: {
|
|
...settings.skipButtons,
|
|
enabled: e.currentTarget.checked,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
),
|
|
description: t('setting.showSkipButtons', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: false,
|
|
title: t('setting.showSkipButtons', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<Group>
|
|
<Tooltip label={t('common.backward', { postProcess: 'titleCase' })}>
|
|
<NumberInput
|
|
defaultValue={settings.skipButtons.skipBackwardSeconds}
|
|
min={0}
|
|
width={75}
|
|
onBlur={(e) =>
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
skipButtons: {
|
|
...settings.skipButtons,
|
|
skipBackwardSeconds: e.currentTarget.value
|
|
? Number(e.currentTarget.value)
|
|
: 0,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</Tooltip>
|
|
<Tooltip label={t('common.forward', { postProcess: 'titleCase' })}>
|
|
<NumberInput
|
|
defaultValue={settings.skipButtons.skipForwardSeconds}
|
|
min={0}
|
|
width={75}
|
|
onBlur={(e) =>
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
skipButtons: {
|
|
...settings.skipButtons,
|
|
skipForwardSeconds: e.currentTarget.value
|
|
? Number(e.currentTarget.value)
|
|
: 0,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</Tooltip>
|
|
</Group>
|
|
),
|
|
description: t('setting.skipDuration', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: false,
|
|
title: t('setting.skipDuration', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<Select
|
|
data={[
|
|
{
|
|
label: t('setting.playButtonBehavior', {
|
|
context: 'optionPlay',
|
|
postProcess: 'titleCase',
|
|
}),
|
|
value: Play.NOW,
|
|
},
|
|
{
|
|
label: t('setting.playButtonBehavior', {
|
|
context: 'optionAddNext',
|
|
postProcess: 'titleCase',
|
|
}),
|
|
value: Play.NEXT,
|
|
},
|
|
{
|
|
label: t('setting.playButtonBehavior', {
|
|
context: 'optionAddLast',
|
|
postProcess: 'titleCase',
|
|
}),
|
|
value: Play.LAST,
|
|
},
|
|
]}
|
|
defaultValue={settings.playButtonBehavior}
|
|
onChange={(e) =>
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
playButtonBehavior: e as Play,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
),
|
|
description: t('setting.playButtonBehavior', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: false,
|
|
title: t('setting.playButtonBehavior', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<Switch
|
|
aria-label="Whether double clicking a track should queue all matching songs"
|
|
defaultChecked={settings.doubleClickQueueAll}
|
|
onChange={(e) =>
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
doubleClickQueueAll: e.currentTarget.checked,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
),
|
|
description: t('setting.doubleClickBehavior', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: false,
|
|
title: t('setting.doubleClickBehavior', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<Select
|
|
data={SIDE_QUEUE_OPTIONS}
|
|
defaultValue={settings.sideQueueType}
|
|
onChange={(e) => {
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
sideQueueType: e as SideQueueType,
|
|
},
|
|
});
|
|
}}
|
|
/>
|
|
),
|
|
description: t('setting.sidePlayQueueStyle', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: false,
|
|
title: t('setting.sidePlayQueueStyle', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<Switch
|
|
defaultChecked={settings.showQueueDrawerButton}
|
|
onChange={(e) => {
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
showQueueDrawerButton: e.currentTarget.checked,
|
|
},
|
|
});
|
|
}}
|
|
/>
|
|
),
|
|
description: t('setting.sidePlayQueueStyle', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: false,
|
|
title: t('setting.floatingQueueArea', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<Slider
|
|
defaultValue={settings.volumeWheelStep}
|
|
max={20}
|
|
min={1}
|
|
w={100}
|
|
onChangeEnd={(e) => {
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
volumeWheelStep: e,
|
|
},
|
|
});
|
|
}}
|
|
/>
|
|
),
|
|
description: t('setting.volumeWheelStep', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: false,
|
|
title: t('setting.volumeWheelStep', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<NumberInput
|
|
defaultValue={settings.volumeWidth}
|
|
max={180}
|
|
min={30}
|
|
placeholder="0"
|
|
rightSection="px"
|
|
width={75}
|
|
onBlur={(e) => {
|
|
setSettings({
|
|
general: { ...settings, volumeWidth: Number(e.currentTarget.value) },
|
|
});
|
|
}}
|
|
/>
|
|
),
|
|
description: t('setting.volumeWidth', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: false,
|
|
title: t('setting.volumeWidth', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<Switch
|
|
defaultChecked={settings.resume}
|
|
onChange={(e) => {
|
|
localSettings?.set('resume', e.target.checked);
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
resume: e.currentTarget.checked,
|
|
},
|
|
});
|
|
}}
|
|
/>
|
|
),
|
|
description: t('setting.savePlayQueue', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: !isElectron(),
|
|
title: t('setting.savePlayQueue', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<Switch
|
|
aria-label="Go to playlist songs page by default"
|
|
defaultChecked={settings.defaultFullPlaylist}
|
|
onChange={(e) =>
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
defaultFullPlaylist: e.currentTarget.checked,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
),
|
|
description: t('setting.skipPlaylistPage', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: false,
|
|
title: t('setting.skipPlaylistPage', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<Switch
|
|
defaultChecked={settings.externalLinks}
|
|
onChange={(e) => {
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
externalLinks: e.currentTarget.checked,
|
|
},
|
|
});
|
|
}}
|
|
/>
|
|
),
|
|
description: t('setting.externalLinks', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
title: t('setting.externalLinks', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<Select
|
|
data={[
|
|
{
|
|
label: t('entity.album_other', {
|
|
postProcess: 'titleCase',
|
|
}),
|
|
value: GenreTarget.ALBUM,
|
|
},
|
|
{
|
|
label: t('entity.track_other', {
|
|
postProcess: 'titleCase',
|
|
}),
|
|
value: GenreTarget.TRACK,
|
|
},
|
|
]}
|
|
defaultValue={settings.genreTarget}
|
|
onChange={(e) =>
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
genreTarget: e as GenreTarget,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
),
|
|
description: t('setting.genreBehavior', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: false,
|
|
title: t('setting.genreBehavior', { postProcess: 'sentenceCase' }),
|
|
},
|
|
{
|
|
control: (
|
|
<Switch
|
|
aria-label={t('setting.homeFeature', { postProcess: 'sentenceCase' })}
|
|
defaultChecked={settings.homeFeature}
|
|
onChange={(e) =>
|
|
setSettings({
|
|
general: {
|
|
...settings,
|
|
homeFeature: e.currentTarget.checked,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
),
|
|
description: t('setting.homeFeature', {
|
|
context: 'description',
|
|
postProcess: 'sentenceCase',
|
|
}),
|
|
isHidden: false,
|
|
title: t('setting.homeFeature', { postProcess: 'sentenceCase' }),
|
|
},
|
|
];
|
|
|
|
return <SettingsSection options={controlOptions} />;
|
|
};
|