diff options
| author | Nihaal Sangha <nihaal.git@gmail.com> | 2026-09-25 21:32:11 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-25 16:32:11 -0400 |
| commit | 84288115c8db0abe40061df0612567ab4ac81967 (patch) | |
| tree | 216215d9aa6f709e329cd5033ea1c9fedbbf9110 /frontend/src | |
| parent | b73a094ae148ca39de5a349432f45f1bf29c0131 (diff) | |
| download | decky-loader-84288115c8db0abe40061df0612567ab4ac81967.tar.gz decky-loader-84288115c8db0abe40061df0612567ab4ac81967.zip | |
Add sort plugins setting (#859)
Diffstat (limited to 'frontend/src')
| -rw-r--r-- | frontend/src/components/DeckyState.tsx | 11 | ||||
| -rw-r--r-- | frontend/src/components/PluginView.tsx | 9 | ||||
| -rw-r--r-- | frontend/src/components/settings/pages/general/index.tsx | 13 | ||||
| -rw-r--r-- | frontend/src/components/settings/pages/plugin_list/index.tsx | 35 | ||||
| -rw-r--r-- | frontend/src/plugin-loader.tsx | 6 |
5 files changed, 64 insertions, 10 deletions
diff --git a/frontend/src/components/DeckyState.tsx b/frontend/src/components/DeckyState.tsx index d1b558c1..db938a26 100644 --- a/frontend/src/components/DeckyState.tsx +++ b/frontend/src/components/DeckyState.tsx @@ -10,6 +10,7 @@ interface PublicDeckyState { disabledPlugins: DisabledPlugin[]; installedPlugins: (Plugin | DisabledPlugin)[]; pluginOrder: string[]; + sortPlugins: boolean; frozenPlugins: string[]; hiddenPlugins: string[]; activePlugin: Plugin | null; @@ -31,6 +32,7 @@ export class DeckyState { private _disabledPlugins: DisabledPlugin[] = []; private _installedPlugins: (Plugin | DisabledPlugin)[] = []; private _pluginOrder: string[] = []; + private _sortPlugins: boolean = false; private _frozenPlugins: string[] = []; private _hiddenPlugins: string[] = []; private _activePlugin: Plugin | null = null; @@ -49,6 +51,7 @@ export class DeckyState { disabledPlugins: this._disabledPlugins, installedPlugins: this._installedPlugins, pluginOrder: this._pluginOrder, + sortPlugins: this._sortPlugins, frozenPlugins: this._frozenPlugins, hiddenPlugins: this._hiddenPlugins, activePlugin: this._activePlugin, @@ -83,6 +86,11 @@ export class DeckyState { this.notifyUpdate(); } + setSortPlugins(sortPlugins: boolean) { + this._sortPlugins = sortPlugins; + this.notifyUpdate(); + } + setFrozenPlugins(frozenPlugins: string[]) { this._frozenPlugins = frozenPlugins; this.notifyUpdate(); @@ -139,6 +147,7 @@ interface DeckyStateContext extends PublicDeckyState { setActivePlugin(name: string): void; setPluginOrder(pluginOrder: string[]): void; setDisabledPlugins(disabled: DisabledPlugin[]): void; + setSortPlugins(sortPlugins: boolean): void; closeActivePlugin(): void; } @@ -178,6 +187,7 @@ export const DeckyStateContextProvider: FC<Props> = ({ children, deckyState }) = const closeActivePlugin = deckyState.closeActivePlugin.bind(deckyState); const setPluginOrder = deckyState.setPluginOrder.bind(deckyState); const setDisabledPlugins = deckyState.setDisabledPlugins.bind(deckyState); + const setSortPlugins = deckyState.setSortPlugins.bind(deckyState); return ( <DeckyStateContext.Provider @@ -189,6 +199,7 @@ export const DeckyStateContextProvider: FC<Props> = ({ children, deckyState }) = closeActivePlugin, setPluginOrder, setDisabledPlugins, + setSortPlugins, }} > {children} diff --git a/frontend/src/components/PluginView.tsx b/frontend/src/components/PluginView.tsx index ffaa176a..fbafaf05 100644 --- a/frontend/src/components/PluginView.tsx +++ b/frontend/src/components/PluginView.tsx @@ -16,6 +16,7 @@ const PluginView: FC = () => { updates, activePlugin, pluginOrder, + sortPlugins, setActivePlugin, closeActivePlugin, } = useDeckyState(); @@ -26,10 +27,14 @@ const PluginView: FC = () => { console.log('updating PluginView after changes'); return [...plugins] - .sort((a, b) => pluginOrder.indexOf(a.name) - pluginOrder.indexOf(b.name)) + .sort((a, b) => + sortPlugins + ? a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }) + : pluginOrder.indexOf(a.name) - pluginOrder.indexOf(b.name), + ) .filter((p) => p.content) .filter(({ name }) => !hiddenPlugins.includes(name)); - }, [plugins, pluginOrder, hiddenPlugins]); + }, [plugins, pluginOrder, sortPlugins, hiddenPlugins]); const numberOfHidden = hiddenPlugins.filter((name) => !!plugins.find((p) => p.name === name)).length; diff --git a/frontend/src/components/settings/pages/general/index.tsx b/frontend/src/components/settings/pages/general/index.tsx index 84ad88f1..9bd5616d 100644 --- a/frontend/src/components/settings/pages/general/index.tsx +++ b/frontend/src/components/settings/pages/general/index.tsx @@ -1,6 +1,7 @@ import { DialogBody, DialogControlsSection, DialogControlsSectionHeader, Field, Toggle } from '@decky/ui'; import { useTranslation } from 'react-i18next'; +import { useSetting } from '../../../../utils/hooks/useSetting'; import { useDeckyState } from '../../../DeckyState'; import BranchSelect from './BranchSelect'; import NotificationSettings from './NotificationSettings'; @@ -14,7 +15,8 @@ export default function GeneralSettings({ isDeveloper: boolean; setIsDeveloper: (val: boolean) => void; }) { - const { versionInfo } = useDeckyState(); + const { versionInfo, sortPlugins, setSortPlugins } = useDeckyState(); + const [_, setSortPluginsSetting] = useSetting<boolean>('sortPlugins', false); const { t } = useTranslation(); return ( @@ -42,6 +44,15 @@ export default function GeneralSettings({ }} /> </Field> + <Field label={t('SettingsGeneralIndex.sort_plugins.label')}> + <Toggle + value={sortPlugins} + onChange={(toggleValue) => { + setSortPlugins(toggleValue); + setSortPluginsSetting(toggleValue); + }} + /> + </Field> </DialogControlsSection> <DialogControlsSection> <DialogControlsSectionHeader>{t('SettingsGeneralIndex.about.header')}</DialogControlsSectionHeader> diff --git a/frontend/src/components/settings/pages/plugin_list/index.tsx b/frontend/src/components/settings/pages/plugin_list/index.tsx index 75365ba5..71a7df6c 100644 --- a/frontend/src/components/settings/pages/plugin_list/index.tsx +++ b/frontend/src/components/settings/pages/plugin_list/index.tsx @@ -11,7 +11,7 @@ import { ReorderableList, showContextMenu, } from '@decky/ui'; -import { useEffect, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { FaDownload, FaEllipsisH, FaRecycle } from 'react-icons/fa'; @@ -171,9 +171,16 @@ type PluginData = { }; export default function PluginList({ isDeveloper }: { isDeveloper: boolean }) { - const { installedPlugins, disabledPlugins, updates, pluginOrder, setPluginOrder, frozenPlugins, hiddenPlugins } = - useDeckyState(); - + const { + installedPlugins, + disabledPlugins, + updates, + pluginOrder, + setPluginOrder, + frozenPlugins, + hiddenPlugins, + sortPlugins, + } = useDeckyState(); const [_, setPluginOrderSetting] = useSetting<string[]>( 'pluginOrder', installedPlugins.map((plugin) => plugin.name), @@ -188,6 +195,12 @@ export default function PluginList({ isDeveloper }: { isDeveloper: boolean }) { const hiddenPluginsService = DeckyPluginLoader.hiddenPluginsService; const frozenPluginsService = DeckyPluginLoader.frozenPluginsService; + const sortedPlugins = useMemo(() => { + return sortPlugins + ? [...installedPlugins].sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: 'base' })) + : installedPlugins; + }, [installedPlugins, sortPlugins]); + useEffect(() => { setPluginEntries( installedPlugins.map(({ name, version }) => { @@ -204,7 +217,7 @@ export default function PluginList({ isDeveloper }: { isDeveloper: boolean }) { disabled={disabledPlugins.find((p) => p.name == name) !== undefined} /> ), - position: pluginOrder.indexOf(name), + position: sortPlugins ? sortedPlugins.findIndex((p) => p.name === name) : pluginOrder.indexOf(name), data: { name, disabled: disabledPlugins.some((disabledPlugin) => disabledPlugin.name === name), @@ -221,7 +234,7 @@ export default function PluginList({ isDeveloper }: { isDeveloper: boolean }) { }; }), ); - }, [installedPlugins, updates, hiddenPlugins, disabledPlugins]); + }, [installedPlugins, updates, hiddenPlugins, disabledPlugins, sortPlugins, sortedPlugins]); if (installedPlugins.length === 0) { return ( @@ -232,6 +245,9 @@ export default function PluginList({ isDeveloper }: { isDeveloper: boolean }) { } function onSave(entries: ReorderableEntry<PluginTableData>[]) { + if (sortPlugins) { + return; + } const newOrder = entries.map((entry) => entry.data!.name); console.log(newOrder); setPluginOrder(newOrder); @@ -265,7 +281,12 @@ export default function PluginList({ isDeveloper }: { isDeveloper: boolean }) { </DialogButton> )} <DialogControlsSection style={{ marginTop: 0 }}> - <ReorderableList<PluginTableData> entries={pluginEntries} onSave={onSave} interactables={PluginInteractables} /> + <ReorderableList<PluginTableData> + entries={pluginEntries} + onSave={onSave} + interactables={PluginInteractables} + disableReordering={sortPlugins} + /> </DialogControlsSection> </DialogBody> ); diff --git a/frontend/src/plugin-loader.tsx b/frontend/src/plugin-loader.tsx index f0a358ef..31f4ec7e 100644 --- a/frontend/src/plugin-loader.tsx +++ b/frontend/src/plugin-loader.tsx @@ -360,6 +360,12 @@ class PluginLoader extends Logger { this.deckyState.setPluginOrder(pluginOrder); }); + // Grab and set sort plugins setting + getSetting<boolean>('sortPlugins', false).then((sortPlugins) => { + this.debug('sortPlugins: ', sortPlugins); + this.deckyState.setSortPlugins(sortPlugins); + }); + this.frozenPluginsService.init(); this.hiddenPluginsService.init(); this.notificationService.init(); |
