mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-02 10:53:33 +00:00
restructure files onto electron-vite boilerplate
This commit is contained in:
parent
91ce2cd8a1
commit
1cf587bc8f
457 changed files with 9927 additions and 11705 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import { Stack } from '@mantine/core';
|
||||
|
||||
import { StylesSettings } from '/@/renderer/features/settings/components/advanced/styles-settings';
|
||||
|
||||
export const AdvancedTab = () => {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
import { useState } from 'react';
|
||||
import { Button, ConfirmModal, Switch, Text, Textarea } from '/@/renderer/components';
|
||||
import { sanitizeCss } from '/@/renderer/utils/sanitize';
|
||||
import { Code } from '@mantine/core';
|
||||
import { SettingsOptions } from '/@/renderer/features/settings/components/settings-option';
|
||||
import { closeAllModals, openModal } from '@mantine/modals';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Button, ConfirmModal, Switch, Text, Textarea } from '/@/renderer/components';
|
||||
import { SettingsOptions } from '/@/renderer/features/settings/components/settings-option';
|
||||
import { useCssSettings, useSettingsStoreActions } from '/@/renderer/store';
|
||||
import { sanitizeCss } from '/@/renderer/utils/sanitize';
|
||||
|
||||
export const StylesSettings = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { enabled, content } = useCssSettings();
|
||||
const { content, enabled } = useCssSettings();
|
||||
const [css, setCss] = useState(content);
|
||||
|
||||
const { setSettings } = useSettingsStoreActions();
|
||||
|
|
@ -82,17 +83,17 @@ export const StylesSettings = () => {
|
|||
{open && (
|
||||
<Button
|
||||
compact
|
||||
onClick={handleSave}
|
||||
// disabled={isSaveButtonDisabled}
|
||||
variant="filled"
|
||||
onClick={handleSave}
|
||||
>
|
||||
{t('common.save', { postProcess: 'titleCase' })}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
compact
|
||||
variant="filled"
|
||||
onClick={() => setOpen(!open)}
|
||||
variant="filled"
|
||||
>
|
||||
{t(open ? 'common.close' : 'common.edit', {
|
||||
postProcess: 'titleCase',
|
||||
|
|
|
|||
|
|
@ -1,22 +1,24 @@
|
|||
import type { IpcRendererEvent } from 'electron';
|
||||
|
||||
import isElectron from 'is-electron';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import i18n, { languages } from '/@/i18n/i18n';
|
||||
import { FileInput, NumberInput, Select, toast } from '/@/renderer/components';
|
||||
import {
|
||||
SettingsSection,
|
||||
SettingOption,
|
||||
SettingsSection,
|
||||
} from '/@/renderer/features/settings/components/settings-section';
|
||||
import {
|
||||
useFontSettings,
|
||||
useGeneralSettings,
|
||||
useSettingsStoreActions,
|
||||
} from '/@/renderer/store/settings.store';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { FontType } from '/@/renderer/types';
|
||||
import i18n, { languages } from '/@/i18n/i18n';
|
||||
|
||||
const localSettings = isElectron() ? window.electron.localSettings : null;
|
||||
const ipc = isElectron() ? window.electron.ipc : null;
|
||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||
const ipc = isElectron() ? window.api.ipc : null;
|
||||
|
||||
type Font = {
|
||||
label: string;
|
||||
|
|
@ -158,8 +160,8 @@ export const ApplicationSettings = () => {
|
|||
control: (
|
||||
<Select
|
||||
data={languages}
|
||||
value={settings.language}
|
||||
onChange={handleChangeLanguage}
|
||||
value={settings.language}
|
||||
/>
|
||||
),
|
||||
description: t('setting.language', {
|
||||
|
|
@ -173,7 +175,6 @@ export const ApplicationSettings = () => {
|
|||
control: (
|
||||
<Select
|
||||
data={FONT_TYPES}
|
||||
value={fontSettings.type}
|
||||
onChange={(e) => {
|
||||
if (!e) return;
|
||||
setSettings({
|
||||
|
|
@ -183,6 +184,7 @@ export const ApplicationSettings = () => {
|
|||
},
|
||||
});
|
||||
}}
|
||||
value={fontSettings.type}
|
||||
/>
|
||||
),
|
||||
description: t('setting.fontType', {
|
||||
|
|
@ -195,9 +197,7 @@ export const ApplicationSettings = () => {
|
|||
{
|
||||
control: (
|
||||
<Select
|
||||
searchable
|
||||
data={FONT_OPTIONS}
|
||||
value={fontSettings.builtIn}
|
||||
onChange={(e) => {
|
||||
if (!e) return;
|
||||
setSettings({
|
||||
|
|
@ -207,6 +207,8 @@ export const ApplicationSettings = () => {
|
|||
},
|
||||
});
|
||||
}}
|
||||
searchable
|
||||
value={fontSettings.builtIn}
|
||||
/>
|
||||
),
|
||||
description: t('setting.font', { context: 'description', postProcess: 'sentenceCase' }),
|
||||
|
|
@ -216,10 +218,7 @@ export const ApplicationSettings = () => {
|
|||
{
|
||||
control: (
|
||||
<Select
|
||||
searchable
|
||||
data={localFonts}
|
||||
value={fontSettings.system}
|
||||
w={300}
|
||||
onChange={(e) => {
|
||||
if (!e) return;
|
||||
setSettings({
|
||||
|
|
@ -229,6 +228,9 @@ export const ApplicationSettings = () => {
|
|||
},
|
||||
});
|
||||
}}
|
||||
searchable
|
||||
value={fontSettings.system}
|
||||
w={300}
|
||||
/>
|
||||
),
|
||||
description: t('setting.font', { context: 'description', postProcess: 'sentenceCase' }),
|
||||
|
|
@ -239,8 +241,6 @@ export const ApplicationSettings = () => {
|
|||
control: (
|
||||
<FileInput
|
||||
accept=".ttc,.ttf,.otf,.woff,.woff2"
|
||||
placeholder={fontList}
|
||||
w={300}
|
||||
onChange={(e) =>
|
||||
setSettings({
|
||||
font: {
|
||||
|
|
@ -249,6 +249,8 @@ export const ApplicationSettings = () => {
|
|||
},
|
||||
})
|
||||
}
|
||||
placeholder={fontList}
|
||||
w={300}
|
||||
/>
|
||||
),
|
||||
description: t('setting.customFontPath', {
|
||||
|
|
@ -263,7 +265,6 @@ export const ApplicationSettings = () => {
|
|||
<NumberInput
|
||||
max={300}
|
||||
min={50}
|
||||
value={settings.zoomFactor}
|
||||
onBlur={(e) => {
|
||||
if (!e) return;
|
||||
const newVal = e.currentTarget.value
|
||||
|
|
@ -277,6 +278,7 @@ export const ApplicationSettings = () => {
|
|||
});
|
||||
localSettings!.setZoomFactor(newVal);
|
||||
}}
|
||||
value={settings.zoomFactor}
|
||||
/>
|
||||
),
|
||||
description: t('setting.zoom', {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { SettingsOptions } from '/@/renderer/features/settings/components/settings-option';
|
||||
import { useState } from 'react';
|
||||
import { Button, Checkbox } from '/@/renderer/components';
|
||||
import { Divider, Stack } from '@mantine/core';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Button, Checkbox } from '/@/renderer/components';
|
||||
import {
|
||||
CONFIGURABLE_CONTEXT_MENU_ITEMS,
|
||||
CONTEXT_MENU_ITEM_MAPPING,
|
||||
} from '/@/renderer/features/context-menu';
|
||||
import { SettingsOptions } from '/@/renderer/features/settings/components/settings-option';
|
||||
import { useSettingsStore, useSettingsStoreActions } from '/@/renderer/store';
|
||||
|
||||
export const ContextMenuSettings = () => {
|
||||
|
|
@ -21,8 +22,8 @@ export const ContextMenuSettings = () => {
|
|||
control={
|
||||
<Button
|
||||
compact
|
||||
variant="filled"
|
||||
onClick={() => setOpen(!open)}
|
||||
variant="filled"
|
||||
>
|
||||
{t(open ? 'common.close' : 'common.edit', { postProcess: 'titleCase' })}
|
||||
</Button>
|
||||
|
|
@ -39,8 +40,8 @@ export const ContextMenuSettings = () => {
|
|||
<Stack>
|
||||
{CONFIGURABLE_CONTEXT_MENU_ITEMS.map((item) => (
|
||||
<Checkbox
|
||||
key={item}
|
||||
checked={!disabledItems[item]}
|
||||
key={item}
|
||||
label={t(
|
||||
`page.contextMenu.${CONTEXT_MENU_ITEM_MAPPING[item] || item}`,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import { Group } from '@mantine/core';
|
||||
import { t } from 'i18next';
|
||||
import isElectron from 'is-electron';
|
||||
import { Select, Tooltip, NumberInput, Switch, Slider } from '/@/renderer/components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { NumberInput, Select, Slider, Switch, Tooltip } from '/@/renderer/components';
|
||||
import { SettingsSection } from '/@/renderer/features/settings/components/settings-section';
|
||||
import {
|
||||
GenreTarget,
|
||||
|
|
@ -10,9 +12,8 @@ import {
|
|||
useSettingsStoreActions,
|
||||
} from '/@/renderer/store/settings.store';
|
||||
import { Play } from '/@/renderer/types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const localSettings = isElectron() ? window.electron.localSettings : null;
|
||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||
|
||||
const SIDE_QUEUE_OPTIONS = [
|
||||
{
|
||||
|
|
@ -43,8 +44,6 @@ export const ControlSettings = () => {
|
|||
defaultValue={settings.buttonSize}
|
||||
max={30}
|
||||
min={15}
|
||||
rightSection="px"
|
||||
width={75}
|
||||
onBlur={(e) => {
|
||||
if (!e) return;
|
||||
const newVal = e.currentTarget.value
|
||||
|
|
@ -57,6 +56,8 @@ export const ControlSettings = () => {
|
|||
},
|
||||
});
|
||||
}}
|
||||
rightSection="px"
|
||||
width={75}
|
||||
/>
|
||||
),
|
||||
description: t('setting.buttonSize', {
|
||||
|
|
@ -71,10 +72,6 @@ export const ControlSettings = () => {
|
|||
<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'
|
||||
|
|
@ -82,6 +79,10 @@ export const ControlSettings = () => {
|
|||
: null;
|
||||
setSettings({ general: { ...settings, albumArtRes: newVal } });
|
||||
}}
|
||||
placeholder="0"
|
||||
rightSection="px"
|
||||
value={settings.albumArtRes ?? 0}
|
||||
width={75}
|
||||
/>
|
||||
),
|
||||
description: t('setting.playerAlbumArtResolution', {
|
||||
|
|
@ -145,7 +146,6 @@ export const ControlSettings = () => {
|
|||
<NumberInput
|
||||
defaultValue={settings.skipButtons.skipBackwardSeconds}
|
||||
min={0}
|
||||
width={75}
|
||||
onBlur={(e) =>
|
||||
setSettings({
|
||||
general: {
|
||||
|
|
@ -159,13 +159,13 @@ export const ControlSettings = () => {
|
|||
},
|
||||
})
|
||||
}
|
||||
width={75}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip label={t('common.forward', { postProcess: 'titleCase' })}>
|
||||
<NumberInput
|
||||
defaultValue={settings.skipButtons.skipForwardSeconds}
|
||||
min={0}
|
||||
width={75}
|
||||
onBlur={(e) =>
|
||||
setSettings({
|
||||
general: {
|
||||
|
|
@ -179,6 +179,7 @@ export const ControlSettings = () => {
|
|||
},
|
||||
})
|
||||
}
|
||||
width={75}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Group>
|
||||
|
|
@ -312,7 +313,6 @@ export const ControlSettings = () => {
|
|||
defaultValue={settings.volumeWheelStep}
|
||||
max={20}
|
||||
min={1}
|
||||
w={100}
|
||||
onChangeEnd={(e) => {
|
||||
setSettings({
|
||||
general: {
|
||||
|
|
@ -321,6 +321,7 @@ export const ControlSettings = () => {
|
|||
},
|
||||
});
|
||||
}}
|
||||
w={100}
|
||||
/>
|
||||
),
|
||||
description: t('setting.volumeWheelStep', {
|
||||
|
|
@ -336,14 +337,14 @@ export const ControlSettings = () => {
|
|||
defaultValue={settings.volumeWidth}
|
||||
max={180}
|
||||
min={30}
|
||||
placeholder="0"
|
||||
rightSection="px"
|
||||
width={75}
|
||||
onBlur={(e) => {
|
||||
setSettings({
|
||||
general: { ...settings, volumeWidth: Number(e.currentTarget.value) },
|
||||
});
|
||||
}}
|
||||
placeholder="0"
|
||||
rightSection="px"
|
||||
width={75}
|
||||
/>
|
||||
),
|
||||
description: t('setting.volumeWidth', {
|
||||
|
|
@ -481,8 +482,6 @@ export const ControlSettings = () => {
|
|||
label={(e) => `${e} rem`}
|
||||
max={6}
|
||||
min={0}
|
||||
step={0.5}
|
||||
w={100}
|
||||
onChangeEnd={(e) => {
|
||||
setSettings({
|
||||
general: {
|
||||
|
|
@ -491,6 +490,8 @@ export const ControlSettings = () => {
|
|||
},
|
||||
});
|
||||
}}
|
||||
step={0.5}
|
||||
w={100}
|
||||
/>
|
||||
),
|
||||
description: t('setting.albumBackgroundBlur', {
|
||||
|
|
|
|||
|
|
@ -1,30 +1,31 @@
|
|||
import { Group } from '@mantine/core';
|
||||
import { useDragControls, Reorder, DragControls } from 'framer-motion';
|
||||
import { DragControls, Reorder, useDragControls } from 'framer-motion';
|
||||
import { MdDragIndicator } from 'react-icons/md';
|
||||
|
||||
import { Checkbox } from '/@/renderer/components';
|
||||
|
||||
const DragHandle = ({ dragControls }: { dragControls: DragControls }) => {
|
||||
return (
|
||||
<MdDragIndicator
|
||||
color="white"
|
||||
style={{ cursor: 'grab' }}
|
||||
onPointerDown={(event) => dragControls.start(event)}
|
||||
style={{ cursor: 'grab' }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
interface SidebarItem {
|
||||
disabled: boolean;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface DraggableItemProps {
|
||||
handleChangeDisabled: (id: string, e: boolean) => void;
|
||||
item: SidebarItem;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const DraggableItem = ({ item, value, handleChangeDisabled }: DraggableItemProps) => {
|
||||
interface SidebarItem {
|
||||
disabled: boolean;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export const DraggableItem = ({ handleChangeDisabled, item, value }: DraggableItemProps) => {
|
||||
const dragControls = useDragControls();
|
||||
|
||||
return (
|
||||
|
|
@ -35,8 +36,8 @@ export const DraggableItem = ({ item, value, handleChangeDisabled }: DraggableIt
|
|||
value={item}
|
||||
>
|
||||
<Group
|
||||
noWrap
|
||||
h="3rem"
|
||||
noWrap
|
||||
style={{ boxShadow: '0 1px 3px rgba(0,0,0,.1)' }}
|
||||
>
|
||||
<Checkbox
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import { Divider } from '@mantine/core';
|
||||
import { Reorder } from 'framer-motion';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SortableItem } from '/@/renderer/store';
|
||||
import { useSettingSearchContext } from '/@/renderer/features/settings/context/search-context';
|
||||
import { SettingsOptions } from '/@/renderer/features/settings/components/settings-option';
|
||||
|
||||
import { Button } from '/@/renderer/components';
|
||||
import { Reorder } from 'framer-motion';
|
||||
import { Divider } from '@mantine/core';
|
||||
import { DraggableItem } from '/@/renderer/features/settings/components/general/draggable-item';
|
||||
import { SettingsOptions } from '/@/renderer/features/settings/components/settings-option';
|
||||
import { useSettingSearchContext } from '/@/renderer/features/settings/context/search-context';
|
||||
import { SortableItem } from '/@/renderer/store';
|
||||
|
||||
export type DraggableItemsProps<K, T> = {
|
||||
description: string;
|
||||
|
|
@ -20,8 +21,8 @@ export type DraggableItemsProps<K, T> = {
|
|||
export const DraggableItems = <K extends string, T extends SortableItem<K>>({
|
||||
description,
|
||||
itemLabels,
|
||||
settings,
|
||||
setItems,
|
||||
settings,
|
||||
title,
|
||||
}: DraggableItemsProps<K, T>) => {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -86,16 +87,16 @@ export const DraggableItems = <K extends string, T extends SortableItem<K>>({
|
|||
<Button
|
||||
compact
|
||||
disabled={isSaveButtonDisabled}
|
||||
variant="filled"
|
||||
onClick={handleSave}
|
||||
variant="filled"
|
||||
>
|
||||
{t('common.save', { postProcess: 'titleCase' })}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
compact
|
||||
variant="filled"
|
||||
onClick={() => setOpen(!open)}
|
||||
variant="filled"
|
||||
>
|
||||
{t(open ? 'common.close' : 'common.edit', { postProcess: 'titleCase' })}
|
||||
</Button>
|
||||
|
|
@ -107,15 +108,15 @@ export const DraggableItems = <K extends string, T extends SortableItem<K>>({
|
|||
{open && (
|
||||
<Reorder.Group
|
||||
axis="y"
|
||||
onReorder={setLocalItems}
|
||||
style={{ userSelect: 'none' }}
|
||||
values={localItems}
|
||||
onReorder={setLocalItems}
|
||||
>
|
||||
{localItems.map((item) => (
|
||||
<DraggableItem
|
||||
key={item.id}
|
||||
handleChangeDisabled={handleChangeDisabled}
|
||||
item={item}
|
||||
key={item.id}
|
||||
value={translatedItemMap[item.id]}
|
||||
/>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
import { Stack } from '@mantine/core';
|
||||
import isElectron from 'is-electron';
|
||||
|
||||
import { ApplicationSettings } from '/@/renderer/features/settings/components/general/application-settings';
|
||||
import { ArtistSettings } from '/@/renderer/features/settings/components/general/artist-settings';
|
||||
import { ContextMenuSettings } from '/@/renderer/features/settings/components/general/context-menu-settings';
|
||||
import { ControlSettings } from '/@/renderer/features/settings/components/general/control-settings';
|
||||
import { HomeSettings } from '/@/renderer/features/settings/components/general/home-settings';
|
||||
import { RemoteSettings } from '/@/renderer/features/settings/components/general/remote-settings';
|
||||
import { SidebarReorder } from '/@/renderer/features/settings/components/general/sidebar-reorder';
|
||||
import { SidebarSettings } from '/@/renderer/features/settings/components/general/sidebar-settings';
|
||||
import { ThemeSettings } from '/@/renderer/features/settings/components/general/theme-settings';
|
||||
import { RemoteSettings } from '/@/renderer/features/settings/components/general/remote-settings';
|
||||
import { CacheSettings } from '/@/renderer/features/settings/components/window/cache-settngs';
|
||||
import isElectron from 'is-electron';
|
||||
import { HomeSettings } from '/@/renderer/features/settings/components/general/home-settings';
|
||||
import { SidebarReorder } from '/@/renderer/features/settings/components/general/sidebar-reorder';
|
||||
import { ContextMenuSettings } from '/@/renderer/features/settings/components/general/context-menu-settings';
|
||||
import { ArtistSettings } from '/@/renderer/features/settings/components/general/artist-settings';
|
||||
|
||||
export const GeneralTab = () => {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import {
|
||||
useSettingsStoreActions,
|
||||
useGeneralSettings,
|
||||
HomeItem,
|
||||
useGeneralSettings,
|
||||
useSettingsStoreActions,
|
||||
} from '../../../../store/settings.store';
|
||||
|
||||
import { DraggableItems } from '/@/renderer/features/settings/components/general/draggable-items';
|
||||
|
||||
const HOME_ITEMS: Array<[string, string]> = [
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import isElectron from 'is-electron';
|
||||
import { SettingsSection } from '/@/renderer/features/settings/components/settings-section';
|
||||
import { useRemoteSettings, useSettingsStoreActions } from '/@/renderer/store';
|
||||
import { NumberInput, Switch, Text, TextInput, toast } from '/@/renderer/components';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const remote = isElectron() ? window.electron.remote : null;
|
||||
import { NumberInput, Switch, Text, TextInput, toast } from '/@/renderer/components';
|
||||
import { SettingsSection } from '/@/renderer/features/settings/components/settings-section';
|
||||
import { useRemoteSettings, useSettingsStoreActions } from '/@/renderer/store';
|
||||
|
||||
const remote = isElectron() ? window.api.remote : null;
|
||||
|
||||
export const RemoteSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -93,12 +94,12 @@ export const RemoteSettings = () => {
|
|||
control: (
|
||||
<NumberInput
|
||||
max={65535}
|
||||
value={settings.port}
|
||||
onBlur={async (e) => {
|
||||
if (!e) return;
|
||||
const port = Number(e.currentTarget.value);
|
||||
await debouncedChangeRemotePort(port);
|
||||
}}
|
||||
value={settings.port}
|
||||
/>
|
||||
),
|
||||
description: t('setting.remotePort', {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import { ChangeEvent } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useGeneralSettings, useSettingsStoreActions } from '../../../../store/settings.store';
|
||||
|
||||
import { Switch } from '/@/renderer/components';
|
||||
import { useSettingsStoreActions, useGeneralSettings } from '../../../../store/settings.store';
|
||||
import {
|
||||
SettingOption,
|
||||
SettingsSection,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
import { ColorInput, Stack } from '@mantine/core';
|
||||
import { Switch, Select } from '/@/renderer/components';
|
||||
import isElectron from 'is-electron';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Select, Switch } from '/@/renderer/components';
|
||||
import {
|
||||
SettingsSection,
|
||||
SettingOption,
|
||||
SettingsSection,
|
||||
} from '/@/renderer/features/settings/components/settings-section';
|
||||
import { THEME_DATA } from '/@/renderer/hooks';
|
||||
import { useGeneralSettings, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
||||
import { AppTheme } from '/@/renderer/themes/types';
|
||||
import isElectron from 'is-electron';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const localSettings = isElectron() ? window.electron.localSettings : null;
|
||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||
|
||||
export const ThemeSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -126,6 +127,14 @@ export const ThemeSettings = () => {
|
|||
<ColorInput
|
||||
defaultValue={settings.accent}
|
||||
format="rgb"
|
||||
onChangeEnd={(e) => {
|
||||
setSettings({
|
||||
general: {
|
||||
...settings,
|
||||
accent: e,
|
||||
},
|
||||
});
|
||||
}}
|
||||
swatches={[
|
||||
'rgb(53, 116, 252)',
|
||||
'rgb(240, 170, 22)',
|
||||
|
|
@ -135,14 +144,6 @@ export const ThemeSettings = () => {
|
|||
]}
|
||||
swatchesPerRow={5}
|
||||
withEyeDropper={false}
|
||||
onChangeEnd={(e) => {
|
||||
setSettings({
|
||||
general: {
|
||||
...settings,
|
||||
accent: e,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
import { useCallback, useMemo, useState, KeyboardEvent, ChangeEvent } from 'react';
|
||||
import { Group } from '@mantine/core';
|
||||
import isElectron from 'is-electron';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { ChangeEvent, KeyboardEvent, useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { RiDeleteBinLine, RiEditLine, RiKeyboardBoxLine } from 'react-icons/ri';
|
||||
import styled from 'styled-components';
|
||||
import { Button, TextInput, Checkbox } from '/@/renderer/components';
|
||||
import { BindingActions, useHotkeySettings, useSettingsStoreActions } from '/@/renderer/store';
|
||||
import { SettingsOptions } from '/@/renderer/features/settings/components/settings-option';
|
||||
import i18n from '/@/i18n/i18n';
|
||||
import { useSettingSearchContext } from '/@/renderer/features/settings/context/search-context';
|
||||
|
||||
const ipc = isElectron() ? window.electron.ipc : null;
|
||||
import i18n from '/@/i18n/i18n';
|
||||
import { Button, Checkbox, TextInput } from '/@/renderer/components';
|
||||
import { SettingsOptions } from '/@/renderer/features/settings/components/settings-option';
|
||||
import { useSettingSearchContext } from '/@/renderer/features/settings/context/search-context';
|
||||
import { BindingActions, useHotkeySettings, useSettingsStoreActions } from '/@/renderer/store';
|
||||
|
||||
const ipc = isElectron() ? window.api.ipc : null;
|
||||
|
||||
const BINDINGS_MAP: Record<BindingActions, string> = {
|
||||
browserBack: i18n.t('setting.hotkey', { context: 'browserBack', postProcess: 'sentenceCase' }),
|
||||
|
|
@ -258,9 +259,15 @@ export const HotkeyManagerSettings = () => {
|
|||
value={BINDINGS_MAP[binding as keyof typeof BINDINGS_MAP]}
|
||||
/>
|
||||
<TextInput
|
||||
readOnly
|
||||
icon={<RiKeyboardBoxLine />}
|
||||
id={`hotkey-${binding}`}
|
||||
onBlur={() => setSelected(null)}
|
||||
onChange={() => {}}
|
||||
onKeyDownCapture={(e) => {
|
||||
if (selected !== (binding as BindingActions)) return;
|
||||
handleSetHotkey(binding as BindingActions, e);
|
||||
}}
|
||||
readOnly
|
||||
style={{
|
||||
opacity: selected === (binding as BindingActions) ? 0.8 : 1,
|
||||
outline: duplicateHotkeyMap.includes(
|
||||
|
|
@ -270,12 +277,6 @@ export const HotkeyManagerSettings = () => {
|
|||
: undefined,
|
||||
}}
|
||||
value={bindings[binding as keyof typeof BINDINGS_MAP].hotkey}
|
||||
onBlur={() => setSelected(null)}
|
||||
onChange={() => {}}
|
||||
onKeyDownCapture={(e) => {
|
||||
if (selected !== (binding as BindingActions)) return;
|
||||
handleSetHotkey(binding as BindingActions, e);
|
||||
}}
|
||||
/>
|
||||
{isElectron() && (
|
||||
<Checkbox
|
||||
|
|
@ -283,6 +284,9 @@ export const HotkeyManagerSettings = () => {
|
|||
disabled={
|
||||
bindings[binding as keyof typeof BINDINGS_MAP].hotkey === ''
|
||||
}
|
||||
onChange={(e) =>
|
||||
handleSetGlobalHotkey(binding as BindingActions, e)
|
||||
}
|
||||
size="xl"
|
||||
style={{
|
||||
opacity: bindings[binding as keyof typeof BINDINGS_MAP]
|
||||
|
|
@ -290,24 +294,21 @@ export const HotkeyManagerSettings = () => {
|
|||
? 1
|
||||
: 0,
|
||||
}}
|
||||
onChange={(e) =>
|
||||
handleSetGlobalHotkey(binding as BindingActions, e)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
variant="default"
|
||||
w={100}
|
||||
onClick={() => {
|
||||
setSelected(binding as BindingActions);
|
||||
document.getElementById(`hotkey-${binding}`)?.focus();
|
||||
}}
|
||||
variant="default"
|
||||
w={100}
|
||||
>
|
||||
<RiEditLine />
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={() => handleClearHotkey(binding as BindingActions)}
|
||||
variant="default"
|
||||
>
|
||||
<RiDeleteBinLine />
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { Stack } from '@mantine/core';
|
||||
import isElectron from 'is-electron';
|
||||
|
||||
import { WindowHotkeySettings } from './window-hotkey-settings';
|
||||
|
||||
import { HotkeyManagerSettings } from '/@/renderer/features/settings/components/hotkeys/hotkey-manager-settings';
|
||||
|
||||
export const HotkeysTab = () => {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import isElectron from 'is-electron';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { SettingOption, SettingsSection } from '../settings-section';
|
||||
|
||||
import { Switch } from '/@/renderer/components';
|
||||
import { useHotkeySettings, useSettingsStoreActions } from '/@/renderer/store';
|
||||
|
||||
const localSettings = isElectron() ? window.electron.localSettings : null;
|
||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||
|
||||
export const WindowHotkeySettings = () => {
|
||||
const { t } = useTranslation();
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { SelectItem } from '@mantine/core';
|
||||
import isElectron from 'is-electron';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Select, Slider, Switch, toast } from '/@/renderer/components';
|
||||
import {
|
||||
SettingsSection,
|
||||
SettingOption,
|
||||
SettingsSection,
|
||||
} from '/@/renderer/features/settings/components/settings-section';
|
||||
import { useCurrentStatus, usePlayerStore } from '/@/renderer/store';
|
||||
import { usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
||||
import { PlaybackType, PlayerStatus, PlaybackStyle, CrossfadeStyle } from '/@/renderer/types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { CrossfadeStyle, PlaybackStyle, PlaybackType, PlayerStatus } from '/@/renderer/types';
|
||||
import { setQueue } from '/@/renderer/utils/set-transcoded-queue-data';
|
||||
|
||||
const getAudioDevice = async () => {
|
||||
|
|
@ -163,10 +164,10 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||
}
|
||||
max={15}
|
||||
min={0}
|
||||
w={100}
|
||||
onChangeEnd={(e) =>
|
||||
setSettings({ playback: { ...settings, crossfadeDuration: e } })
|
||||
}
|
||||
w={100}
|
||||
/>
|
||||
),
|
||||
description: t('setting.crossfadeDuration', {
|
||||
|
|
@ -202,13 +203,13 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||
settings.style !== PlaybackStyle.CROSSFADE ||
|
||||
status === PlayerStatus.PLAYING
|
||||
}
|
||||
width={200}
|
||||
onChange={(e) => {
|
||||
if (!e) return;
|
||||
setSettings({
|
||||
playback: { ...settings, crossfadeStyle: e as CrossfadeStyle },
|
||||
});
|
||||
}}
|
||||
width={200}
|
||||
/>
|
||||
),
|
||||
description: t('setting.crossfadeStyle', {
|
||||
|
|
|
|||
|
|
@ -1,23 +1,24 @@
|
|||
import isElectron from 'is-electron';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { languages } from '/@/i18n/i18n';
|
||||
import { LyricSource } from '/@/renderer/api/types';
|
||||
import {
|
||||
MultiSelect,
|
||||
MultiSelectProps,
|
||||
NumberInput,
|
||||
Select,
|
||||
Switch,
|
||||
TextInput,
|
||||
} from '/@/renderer/components';
|
||||
import {
|
||||
SettingOption,
|
||||
SettingsSection,
|
||||
} from '/@/renderer/features/settings/components/settings-section';
|
||||
import { useLyricsSettings, useSettingsStoreActions } from '/@/renderer/store';
|
||||
import {
|
||||
Select,
|
||||
MultiSelect,
|
||||
MultiSelectProps,
|
||||
TextInput,
|
||||
NumberInput,
|
||||
Switch,
|
||||
} from '/@/renderer/components';
|
||||
import isElectron from 'is-electron';
|
||||
import styled from 'styled-components';
|
||||
import { LyricSource } from '/@/renderer/api/types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { languages } from '/@/i18n/i18n';
|
||||
|
||||
const localSettings = isElectron() ? window.electron.localSettings : null;
|
||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||
|
||||
const WorkingButtonSelect = styled(MultiSelect)<MultiSelectProps>`
|
||||
& button {
|
||||
|
|
@ -77,11 +78,10 @@ export const LyricSettings = () => {
|
|||
{
|
||||
control: (
|
||||
<WorkingButtonSelect
|
||||
clearable
|
||||
aria-label="Lyric providers"
|
||||
clearable
|
||||
data={Object.values(LyricSource)}
|
||||
defaultValue={settings.sources}
|
||||
width={300}
|
||||
onChange={(e: LyricSource[]) => {
|
||||
localSettings?.set('lyrics', e);
|
||||
setSettings({
|
||||
|
|
@ -91,6 +91,7 @@ export const LyricSettings = () => {
|
|||
},
|
||||
});
|
||||
}}
|
||||
width={300}
|
||||
/>
|
||||
),
|
||||
description: t('setting.lyricFetchProvider', {
|
||||
|
|
@ -104,8 +105,6 @@ export const LyricSettings = () => {
|
|||
control: (
|
||||
<NumberInput
|
||||
defaultValue={settings.delayMs}
|
||||
step={10}
|
||||
width={100}
|
||||
onBlur={(e) => {
|
||||
const value = Number(e.currentTarget.value);
|
||||
setSettings({
|
||||
|
|
@ -115,6 +114,8 @@ export const LyricSettings = () => {
|
|||
},
|
||||
});
|
||||
}}
|
||||
step={10}
|
||||
width={100}
|
||||
/>
|
||||
),
|
||||
description: t('setting.lyricOffset', {
|
||||
|
|
@ -128,10 +129,10 @@ export const LyricSettings = () => {
|
|||
control: (
|
||||
<Select
|
||||
data={languages}
|
||||
value={settings.translationTargetLanguage}
|
||||
onChange={(value) => {
|
||||
setSettings({ lyrics: { ...settings, translationTargetLanguage: value } });
|
||||
}}
|
||||
value={settings.translationTargetLanguage}
|
||||
/>
|
||||
),
|
||||
description: t('setting.translationTargetLanguage', {
|
||||
|
|
@ -145,10 +146,10 @@ export const LyricSettings = () => {
|
|||
control: (
|
||||
<Select
|
||||
data={['Microsoft Azure', 'Google Cloud']}
|
||||
value={settings.translationApiProvider}
|
||||
onChange={(value) => {
|
||||
setSettings({ lyrics: { ...settings, translationApiProvider: value } });
|
||||
}}
|
||||
value={settings.translationApiProvider}
|
||||
/>
|
||||
),
|
||||
description: t('setting.translationApiProvider', {
|
||||
|
|
@ -161,12 +162,12 @@ export const LyricSettings = () => {
|
|||
{
|
||||
control: (
|
||||
<TextInput
|
||||
value={settings.translationApiKey}
|
||||
onChange={(e) => {
|
||||
setSettings({
|
||||
lyrics: { ...settings, translationApiKey: e.currentTarget.value },
|
||||
});
|
||||
}}
|
||||
value={settings.translationApiKey}
|
||||
/>
|
||||
),
|
||||
description: t('setting.translationApiKey', {
|
||||
|
|
|
|||
|
|
@ -1,19 +1,23 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { Group, Stack } from '@mantine/core';
|
||||
import isElectron from 'is-electron';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { RiCloseLine, RiRestartLine } from 'react-icons/ri';
|
||||
|
||||
import {
|
||||
FileInput,
|
||||
Textarea,
|
||||
Text,
|
||||
Select,
|
||||
NumberInput,
|
||||
Switch,
|
||||
Button,
|
||||
FileInput,
|
||||
NumberInput,
|
||||
Select,
|
||||
Switch,
|
||||
Text,
|
||||
Textarea,
|
||||
} from '/@/renderer/components';
|
||||
import {
|
||||
SettingsSection,
|
||||
SettingOption,
|
||||
SettingsSection,
|
||||
} from '/@/renderer/features/settings/components/settings-section';
|
||||
import { usePlayerControls, usePlayerStore, useQueueControls } from '/@/renderer/store';
|
||||
import {
|
||||
SettingsState,
|
||||
usePlaybackSettings,
|
||||
|
|
@ -21,12 +25,9 @@ import {
|
|||
useSettingsStoreActions,
|
||||
} from '/@/renderer/store/settings.store';
|
||||
import { PlaybackType } from '/@/renderer/types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { RiCloseLine, RiRestartLine } from 'react-icons/ri';
|
||||
import { usePlayerControls, usePlayerStore, useQueueControls } from '/@/renderer/store';
|
||||
|
||||
const localSettings = isElectron() ? window.electron.localSettings : null;
|
||||
const mpvPlayer = isElectron() ? window.electron.mpvPlayer : null;
|
||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
|
||||
|
||||
export const getMpvSetting = (
|
||||
key: keyof SettingsState['playback']['mpvProperties'],
|
||||
|
|
@ -39,12 +40,12 @@ export const getMpvSetting = (
|
|||
return { 'audio-samplerate': value };
|
||||
case 'gaplessAudio':
|
||||
return { 'gapless-audio': value || 'weak' };
|
||||
case 'replayGainMode':
|
||||
return { replaygain: value || 'no' };
|
||||
case 'replayGainClip':
|
||||
return { 'replaygain-clip': value || 'no' };
|
||||
case 'replayGainFallbackDB':
|
||||
return { 'replaygain-fallback': value };
|
||||
case 'replayGainMode':
|
||||
return { replaygain: value || 'no' };
|
||||
case 'replayGainPreampDB':
|
||||
return { 'replaygain-preamp': value || 0 };
|
||||
default:
|
||||
|
|
@ -150,34 +151,34 @@ export const MpvSettings = () => {
|
|||
control: (
|
||||
<Group spacing="sm">
|
||||
<Button
|
||||
onClick={handleReloadMpv}
|
||||
tooltip={{
|
||||
label: t('common.reload', { postProcess: 'titleCase' }),
|
||||
openDelay: 0,
|
||||
}}
|
||||
variant="subtle"
|
||||
onClick={handleReloadMpv}
|
||||
>
|
||||
<RiRestartLine />
|
||||
</Button>
|
||||
<FileInput
|
||||
onChange={handleSetMpvPath}
|
||||
placeholder={mpvPath}
|
||||
rightSection={
|
||||
mpvPath && (
|
||||
<Button
|
||||
compact
|
||||
onClick={() => handleSetMpvPath(null)}
|
||||
tooltip={{
|
||||
label: t('common.clear', { postProcess: 'titleCase' }),
|
||||
openDelay: 0,
|
||||
}}
|
||||
variant="subtle"
|
||||
onClick={() => handleSetMpvPath(null)}
|
||||
>
|
||||
<RiCloseLine />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
width={200}
|
||||
onChange={handleSetMpvPath}
|
||||
/>
|
||||
</Group>
|
||||
),
|
||||
|
|
@ -196,14 +197,14 @@ export const MpvSettings = () => {
|
|||
autosize
|
||||
defaultValue={settings.mpvExtraParameters.join('\n')}
|
||||
minRows={4}
|
||||
onBlur={(e) => {
|
||||
handleSetExtraParameters(e.currentTarget.value.split('\n'));
|
||||
}}
|
||||
placeholder={`(${t('setting.mpvExtraParameters', {
|
||||
context: 'help',
|
||||
postProcess: 'sentenceCase',
|
||||
})}):\n--gapless-audio=weak\n--prefetch-playlist=yes`}
|
||||
width={225}
|
||||
onBlur={(e) => {
|
||||
handleSetExtraParameters(e.currentTarget.value.split('\n'));
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
),
|
||||
|
|
@ -272,14 +273,14 @@ export const MpvSettings = () => {
|
|||
defaultValue={settings.mpvProperties.audioSampleRateHz || undefined}
|
||||
max={192000}
|
||||
min={0}
|
||||
placeholder="48000"
|
||||
rightSection="Hz"
|
||||
width={100}
|
||||
onBlur={(e) => {
|
||||
const value = Number(e.currentTarget.value);
|
||||
// Setting a value of `undefined` causes an error for MPV. Use 0 instead
|
||||
handleSetMpvProperty('audioSampleRateHz', value >= 8000 ? value : value);
|
||||
}}
|
||||
placeholder="48000"
|
||||
rightSection="Hz"
|
||||
width={100}
|
||||
/>
|
||||
),
|
||||
description: t('setting.sampleRate', {
|
||||
|
|
@ -343,32 +344,32 @@ export const MpvSettings = () => {
|
|||
/>
|
||||
),
|
||||
description: t('setting.replayGainMode', {
|
||||
ReplayGain: 'ReplayGain',
|
||||
context: 'description',
|
||||
postProcess: 'sentenceCase',
|
||||
ReplayGain: 'ReplayGain',
|
||||
}),
|
||||
note: t('common.restartRequired', { postProcess: 'sentenceCase' }),
|
||||
title: t('setting.replayGainMode', {
|
||||
ReplayGain: 'ReplayGain',
|
||||
postProcess: 'sentenceCase',
|
||||
ReplayGain: 'ReplayGain',
|
||||
}),
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<NumberInput
|
||||
defaultValue={settings.mpvProperties.replayGainPreampDB}
|
||||
width={75}
|
||||
onChange={(e) => handleSetMpvProperty('replayGainPreampDB', e)}
|
||||
width={75}
|
||||
/>
|
||||
),
|
||||
description: t('setting.replayGainMode', {
|
||||
ReplayGain: 'ReplayGain',
|
||||
context: 'description',
|
||||
postProcess: 'sentenceCase',
|
||||
ReplayGain: 'ReplayGain',
|
||||
}),
|
||||
title: t('setting.replayGainPreamp', {
|
||||
ReplayGain: 'ReplayGain',
|
||||
postProcess: 'sentenceCase',
|
||||
ReplayGain: 'ReplayGain',
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
|
@ -381,32 +382,32 @@ export const MpvSettings = () => {
|
|||
/>
|
||||
),
|
||||
description: t('setting.replayGainClipping', {
|
||||
ReplayGain: 'ReplayGain',
|
||||
context: 'description',
|
||||
postProcess: 'sentenceCase',
|
||||
ReplayGain: 'ReplayGain',
|
||||
}),
|
||||
title: t('setting.replayGainClipping', {
|
||||
ReplayGain: 'ReplayGain',
|
||||
postProcess: 'sentenceCase',
|
||||
ReplayGain: 'ReplayGain',
|
||||
}),
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<NumberInput
|
||||
defaultValue={settings.mpvProperties.replayGainFallbackDB}
|
||||
width={75}
|
||||
onBlur={(e) =>
|
||||
handleSetMpvProperty('replayGainFallbackDB', Number(e.currentTarget.value))
|
||||
}
|
||||
width={75}
|
||||
/>
|
||||
),
|
||||
description: t('setting.replayGainFallback', {
|
||||
ReplayGain: 'ReplayGain',
|
||||
postProcess: 'sentenceCase',
|
||||
ReplayGain: 'ReplayGain',
|
||||
}),
|
||||
title: t('setting.replayGainFallback', {
|
||||
ReplayGain: 'ReplayGain',
|
||||
postProcess: 'sentenceCase',
|
||||
ReplayGain: 'ReplayGain',
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import { lazy, Suspense, useMemo } from 'react';
|
||||
import { Stack } from '@mantine/core';
|
||||
import { AudioSettings } from '/@/renderer/features/settings/components/playback/audio-settings';
|
||||
import { ScrobbleSettings } from '/@/renderer/features/settings/components/playback/scrobble-settings';
|
||||
import isElectron from 'is-electron';
|
||||
import { lazy, Suspense, useMemo } from 'react';
|
||||
|
||||
import { AudioSettings } from '/@/renderer/features/settings/components/playback/audio-settings';
|
||||
import { LyricSettings } from '/@/renderer/features/settings/components/playback/lyric-settings';
|
||||
import { ScrobbleSettings } from '/@/renderer/features/settings/components/playback/scrobble-settings';
|
||||
import { TranscodeSettings } from '/@/renderer/features/settings/components/playback/transcode-settings';
|
||||
import { useSettingsStore } from '/@/renderer/store';
|
||||
import { PlaybackType } from '/@/renderer/types';
|
||||
import { TranscodeSettings } from '/@/renderer/features/settings/components/playback/transcode-settings';
|
||||
|
||||
const MpvSettings = lazy(() =>
|
||||
import('/@/renderer/features/settings/components/playback/mpv-settings').then((module) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { SettingOption, SettingsSection } from '../settings-section';
|
||||
|
||||
import { NumberInput, Slider, Switch } from '/@/renderer/components';
|
||||
import { usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
||||
import { SettingOption, SettingsSection } from '../settings-section';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const ScrobbleSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -41,7 +43,6 @@ export const ScrobbleSettings = () => {
|
|||
label={`${settings.scrobble.scrobbleAtPercentage}%`}
|
||||
max={90}
|
||||
min={25}
|
||||
w={100}
|
||||
onChange={(e) => {
|
||||
setSettings({
|
||||
playback: {
|
||||
|
|
@ -53,6 +54,7 @@ export const ScrobbleSettings = () => {
|
|||
},
|
||||
});
|
||||
}}
|
||||
w={100}
|
||||
/>
|
||||
),
|
||||
description: t('setting.minimumScrobblePercentage', {
|
||||
|
|
@ -68,7 +70,6 @@ export const ScrobbleSettings = () => {
|
|||
defaultValue={settings.scrobble.scrobbleAtDuration}
|
||||
max={1200}
|
||||
min={0}
|
||||
width={75}
|
||||
onChange={(e) => {
|
||||
if (e === '') return;
|
||||
setSettings({
|
||||
|
|
@ -81,6 +82,7 @@ export const ScrobbleSettings = () => {
|
|||
},
|
||||
});
|
||||
}}
|
||||
width={75}
|
||||
/>
|
||||
),
|
||||
description: t('setting.minimumScrobbleSeconds', {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { SettingOption, SettingsSection } from '../settings-section';
|
||||
|
||||
import { NumberInput, Switch, TextInput } from '/@/renderer/components';
|
||||
import { usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
||||
import { SettingOption, SettingsSection } from '../settings-section';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const TranscodeSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -36,7 +38,6 @@ export const TranscodeSettings = () => {
|
|||
aria-label="Transcode bitrate"
|
||||
defaultValue={transcode.bitrate}
|
||||
min={0}
|
||||
w={100}
|
||||
onBlur={(e) => {
|
||||
setTranscodingConfig({
|
||||
...transcode,
|
||||
|
|
@ -45,6 +46,7 @@ export const TranscodeSettings = () => {
|
|||
: undefined,
|
||||
});
|
||||
}}
|
||||
w={100}
|
||||
/>
|
||||
),
|
||||
description: t('setting.transcodeBitrate', {
|
||||
|
|
@ -60,14 +62,14 @@ export const TranscodeSettings = () => {
|
|||
<TextInput
|
||||
aria-label="transcoding format"
|
||||
defaultValue={transcode.format}
|
||||
placeholder="mp3, opus"
|
||||
width={100}
|
||||
onBlur={(e) => {
|
||||
setTranscodingConfig({
|
||||
...transcode,
|
||||
format: e.currentTarget.value || undefined,
|
||||
});
|
||||
}}
|
||||
placeholder="mp3, opus"
|
||||
width={100}
|
||||
/>
|
||||
),
|
||||
description: t('setting.transcodeFormat', {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import { lazy } from 'react';
|
||||
import { Tabs } from '/@/renderer/components';
|
||||
import { useSettingsStore, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
||||
import isElectron from 'is-electron';
|
||||
import { lazy } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Tabs } from '/@/renderer/components';
|
||||
import { useSettingsStore, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
||||
|
||||
const GeneralTab = lazy(() =>
|
||||
import('/@/renderer/features/settings/components/general/general-tab').then((module) => ({
|
||||
default: module.GeneralTab,
|
||||
|
|
@ -51,10 +52,10 @@ export const SettingsContent = () => {
|
|||
<TabContainer>
|
||||
<Tabs
|
||||
keepMounted={false}
|
||||
onTabChange={(e) => e && setSettings({ tab: e })}
|
||||
orientation="horizontal"
|
||||
value={currentTab}
|
||||
variant="default"
|
||||
onTabChange={(e) => e && setSettings({ tab: e })}
|
||||
>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab value="general">
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ import { Flex, Group } from '@mantine/core';
|
|||
import { closeAllModals, openModal } from '@mantine/modals';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { RiSettings2Fill } from 'react-icons/ri';
|
||||
import { Button, ConfirmModal, PageHeader, SearchInput } from '/@/renderer/components';
|
||||
import { LibraryHeaderBar } from '/@/renderer/features/shared';
|
||||
|
||||
import { useSettingsStoreActions } from '../../../store/settings.store';
|
||||
|
||||
import { Button, ConfirmModal, PageHeader, SearchInput } from '/@/renderer/components';
|
||||
import { useSettingSearchContext } from '/@/renderer/features/settings/context/search-context';
|
||||
import { LibraryHeaderBar } from '/@/renderer/features/shared';
|
||||
import { useContainerQuery } from '/@/renderer/hooks';
|
||||
|
||||
export type SettingsHeaderProps = {
|
||||
|
|
@ -52,15 +54,15 @@ export const SettingsHeader = ({ setSearch }: SettingsHeaderProps) => {
|
|||
<Group>
|
||||
<SearchInput
|
||||
defaultValue={search}
|
||||
openedWidth={cq.isMd ? 250 : cq.isSm ? 200 : 150}
|
||||
onChange={(event) =>
|
||||
setSearch(event.target.value.toLocaleLowerCase())
|
||||
}
|
||||
openedWidth={cq.isMd ? 250 : cq.isSm ? 200 : 150}
|
||||
/>
|
||||
<Button
|
||||
compact
|
||||
variant="default"
|
||||
onClick={openResetConfirmModal}
|
||||
variant="default"
|
||||
>
|
||||
{t('common.resetToDefault', { postProcess: 'sentenceCase' })}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import { Group, Stack } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { RiInformationLine } from 'react-icons/ri';
|
||||
|
||||
import { Text, Tooltip } from '/@/renderer/components';
|
||||
|
||||
interface SettingsOptionProps {
|
||||
|
|
@ -10,7 +11,7 @@ interface SettingsOptionProps {
|
|||
title: React.ReactNode | string;
|
||||
}
|
||||
|
||||
export const SettingsOptions = ({ title, description, control, note }: SettingsOptionProps) => {
|
||||
export const SettingsOptions = ({ control, description, note, title }: SettingsOptionProps) => {
|
||||
return (
|
||||
<>
|
||||
<Group
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { Divider } from '@mantine/core';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { SettingsOptions } from '/@/renderer/features/settings/components/settings-option';
|
||||
import { useSettingSearchContext } from '/@/renderer/features/settings/context/search-context';
|
||||
import { Divider } from '@mantine/core';
|
||||
|
||||
export type SettingOption = {
|
||||
control: ReactNode;
|
||||
description: string | ReactNode;
|
||||
description: ReactNode | string;
|
||||
isHidden?: boolean;
|
||||
note?: string;
|
||||
title: string;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
import { closeAllModals, openModal } from '@mantine/modals';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import isElectron from 'is-electron';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, ConfirmModal, toast } from '/@/renderer/components';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Button, ConfirmModal, toast } from '/@/renderer/components';
|
||||
import {
|
||||
SettingOption,
|
||||
SettingsSection,
|
||||
} from '/@/renderer/features/settings/components/settings-section';
|
||||
|
||||
const browser = isElectron() ? window.electron.browser : null;
|
||||
const browser = isElectron() ? window.api.browser : null;
|
||||
|
||||
export const CacheSettings = () => {
|
||||
const [isClearing, setIsClearing] = useState(false);
|
||||
|
|
@ -59,8 +60,8 @@ export const CacheSettings = () => {
|
|||
<Button
|
||||
compact
|
||||
disabled={isClearing}
|
||||
variant="filled"
|
||||
onClick={() => openResetConfirmModal(false)}
|
||||
variant="filled"
|
||||
>
|
||||
{t('common.clear', { postProcess: 'sentenceCase' })}
|
||||
</Button>
|
||||
|
|
@ -76,8 +77,8 @@ export const CacheSettings = () => {
|
|||
<Button
|
||||
compact
|
||||
disabled={isClearing}
|
||||
variant="filled"
|
||||
onClick={() => openResetConfirmModal(true)}
|
||||
variant="filled"
|
||||
>
|
||||
{t('common.clear', { postProcess: 'sentenceCase' })}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import isElectron from 'is-electron';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { NumberInput, Switch, TextInput } from '/@/renderer/components';
|
||||
import {
|
||||
SettingOption,
|
||||
|
|
@ -6,10 +8,9 @@ import {
|
|||
} from '/@/renderer/features/settings/components/settings-section';
|
||||
import {
|
||||
useDiscordSetttings,
|
||||
useSettingsStoreActions,
|
||||
useGeneralSettings,
|
||||
useSettingsStoreActions,
|
||||
} from '/@/renderer/store';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const DiscordSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -75,7 +76,6 @@ export const DiscordSettings = () => {
|
|||
{
|
||||
control: (
|
||||
<NumberInput
|
||||
value={settings.updateInterval}
|
||||
onChange={(e) => {
|
||||
let value = e ? Number(e) : 0;
|
||||
if (value < 15) {
|
||||
|
|
@ -89,6 +89,7 @@ export const DiscordSettings = () => {
|
|||
},
|
||||
});
|
||||
}}
|
||||
value={settings.updateInterval}
|
||||
/>
|
||||
),
|
||||
description: t('setting.discordUpdateInterval', {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import { SelectItem } from '@mantine/core';
|
||||
import isElectron from 'is-electron';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSettingsStoreActions, useGeneralSettings } from '../../../../store/settings.store';
|
||||
import {
|
||||
SettingsSection,
|
||||
SettingOption,
|
||||
} from '/@/renderer/features/settings/components/settings-section';
|
||||
import { Select } from '/@/renderer/components';
|
||||
|
||||
const localSettings = isElectron() ? window.electron.localSettings : null;
|
||||
import { useGeneralSettings, useSettingsStoreActions } from '../../../../store/settings.store';
|
||||
|
||||
import { Select } from '/@/renderer/components';
|
||||
import {
|
||||
SettingOption,
|
||||
SettingsSection,
|
||||
} from '/@/renderer/features/settings/components/settings-section';
|
||||
|
||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||
|
||||
const PASSWORD_SETTINGS: SelectItem[] = [
|
||||
{ label: 'libsecret', value: 'gnome_libsecret' },
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import isElectron from 'is-electron';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useWindowSettings, useSettingsStoreActions } from '../../../../store/settings.store';
|
||||
import {
|
||||
SettingsSection,
|
||||
SettingOption,
|
||||
} from '/@/renderer/features/settings/components/settings-section';
|
||||
import { Switch } from '/@/renderer/components';
|
||||
|
||||
const localSettings = isElectron() ? window.electron.localSettings : null;
|
||||
const utils = isElectron() ? window.electron.utils : null;
|
||||
import { useSettingsStoreActions, useWindowSettings } from '../../../../store/settings.store';
|
||||
|
||||
import { Switch } from '/@/renderer/components';
|
||||
import {
|
||||
SettingOption,
|
||||
SettingsSection,
|
||||
} from '/@/renderer/features/settings/components/settings-section';
|
||||
|
||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||
const utils = isElectron() ? window.api.utils : null;
|
||||
|
||||
export const UpdateSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
import isElectron from 'is-electron';
|
||||
import { Platform } from '/@/renderer/types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useWindowSettings, useSettingsStoreActions } from '../../../../store/settings.store';
|
||||
import {
|
||||
SettingsSection,
|
||||
SettingOption,
|
||||
} from '/@/renderer/features/settings/components/settings-section';
|
||||
|
||||
import { useSettingsStoreActions, useWindowSettings } from '../../../../store/settings.store';
|
||||
|
||||
import { Select, Switch, toast } from '/@/renderer/components';
|
||||
import {
|
||||
SettingOption,
|
||||
SettingsSection,
|
||||
} from '/@/renderer/features/settings/components/settings-section';
|
||||
import { Platform } from '/@/renderer/types';
|
||||
|
||||
const WINDOW_BAR_OPTIONS = [
|
||||
{ label: 'Web (hidden)', value: Platform.WEB },
|
||||
|
|
@ -15,7 +17,7 @@ const WINDOW_BAR_OPTIONS = [
|
|||
{ label: 'Native', value: Platform.LINUX },
|
||||
];
|
||||
|
||||
const localSettings = isElectron() ? window.electron.localSettings : null;
|
||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||
|
||||
export const WindowSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -28,7 +30,6 @@ export const WindowSettings = () => {
|
|||
<Select
|
||||
data={WINDOW_BAR_OPTIONS}
|
||||
disabled={!isElectron()}
|
||||
value={settings.windowBarStyle}
|
||||
onChange={(e) => {
|
||||
if (!e) return;
|
||||
|
||||
|
|
@ -49,7 +50,7 @@ export const WindowSettings = () => {
|
|||
postProcess: 'sentenceCase',
|
||||
}),
|
||||
onClose: () => {
|
||||
window.electron.ipc!.send('app-restart');
|
||||
window.api.ipc!.send('app-restart');
|
||||
},
|
||||
title: t('common.restartRequired', {
|
||||
postProcess: 'sentenceCase',
|
||||
|
|
@ -72,6 +73,7 @@ export const WindowSettings = () => {
|
|||
},
|
||||
});
|
||||
}}
|
||||
value={settings.windowBarStyle}
|
||||
/>
|
||||
),
|
||||
description: t('setting.windowBarStyle', {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { Stack } from '@mantine/core';
|
||||
import isElectron from 'is-electron';
|
||||
|
||||
import { DiscordSettings } from '/@/renderer/features/settings/components/window/discord-settings';
|
||||
import { PasswordSettings } from '/@/renderer/features/settings/components/window/password-settings';
|
||||
import { UpdateSettings } from '/@/renderer/features/settings/components/window/update-settings';
|
||||
import { WindowSettings } from '/@/renderer/features/settings/components/window/window-settings';
|
||||
import { DiscordSettings } from '/@/renderer/features/settings/components/window/discord-settings';
|
||||
import isElectron from 'is-electron';
|
||||
import { PasswordSettings } from '/@/renderer/features/settings/components/window/password-settings';
|
||||
|
||||
const utils = isElectron() ? window.electron.utils : null;
|
||||
const utils = isElectron() ? window.api.utils : null;
|
||||
|
||||
export const WindowTab = () => {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { Flex } from '@mantine/core';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { SettingsContent } from '/@/renderer/features/settings/components/settings-content';
|
||||
import { SettingsHeader } from '/@/renderer/features/settings/components/settings-header';
|
||||
import { AnimatedPage } from '/@/renderer/features/shared';
|
||||
import { SettingSearchContext } from '/@/renderer/features/settings/context/search-context';
|
||||
import { useState } from 'react';
|
||||
import { AnimatedPage } from '/@/renderer/features/shared';
|
||||
|
||||
const SettingsRoute = () => {
|
||||
const [search, setSearch] = useState('');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue