Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions backend/decky_loader/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@
"developer_mode": {
"label": "Developer mode"
},
"sort_plugins": {
"label": "Sort plugins alphabetically"
},
"notifications": {
"decky_updates_label": "Decky update available",
"header": "Notifications",
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/components/DeckyState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface PublicDeckyState {
disabledPlugins: DisabledPlugin[];
installedPlugins: (Plugin | DisabledPlugin)[];
pluginOrder: string[];
sortPlugins: boolean;
frozenPlugins: string[];
hiddenPlugins: string[];
activePlugin: Plugin | null;
Expand All @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand All @@ -189,6 +199,7 @@ export const DeckyStateContextProvider: FC<Props> = ({ children, deckyState }) =
closeActivePlugin,
setPluginOrder,
setDisabledPlugins,
setSortPlugins,
}}
>
{children}
Expand Down
9 changes: 7 additions & 2 deletions frontend/src/components/PluginView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const PluginView: FC = () => {
updates,
activePlugin,
pluginOrder,
sortPlugins,
setActivePlugin,
closeActivePlugin,
} = useDeckyState();
Expand All @@ -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;

Expand Down
13 changes: 12 additions & 1 deletion frontend/src/components/settings/pages/general/index.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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 (
Expand Down Expand Up @@ -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>
Expand Down
28 changes: 22 additions & 6 deletions frontend/src/components/settings/pages/plugin_list/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -170,9 +170,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),
Expand All @@ -187,6 +194,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 }) => {
Expand All @@ -203,7 +216,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),
Expand All @@ -220,7 +233,7 @@ export default function PluginList({ isDeveloper }: { isDeveloper: boolean }) {
};
}),
);
}, [installedPlugins, updates, hiddenPlugins, disabledPlugins]);
}, [installedPlugins, updates, hiddenPlugins, disabledPlugins, sortPlugins, sortedPlugins]);

if (installedPlugins.length === 0) {
return (
Expand All @@ -231,6 +244,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);
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/plugin-loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,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();
Expand Down