diff options
Diffstat (limited to 'frontend/src/components/settings')
3 files changed, 81 insertions, 28 deletions
diff --git a/frontend/src/components/settings/pages/plugin_list/PluginListLabel.tsx b/frontend/src/components/settings/pages/plugin_list/PluginListLabel.tsx index fec03e56..59171b39 100644 --- a/frontend/src/components/settings/pages/plugin_list/PluginListLabel.tsx +++ b/frontend/src/components/settings/pages/plugin_list/PluginListLabel.tsx @@ -1,15 +1,16 @@ import { FC } from 'react'; import { useTranslation } from 'react-i18next'; -import { FaEyeSlash, FaLock } from 'react-icons/fa'; +import { FaBan, FaEyeSlash, FaLock } from 'react-icons/fa'; interface PluginListLabelProps { frozen: boolean; hidden: boolean; + disabled: boolean; name: string; version?: string; } -const PluginListLabel: FC<PluginListLabelProps> = ({ name, frozen, hidden, version }) => { +const PluginListLabel: FC<PluginListLabelProps> = ({ name, frozen, hidden, version, disabled }) => { const { t } = useTranslation(); return ( <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}> @@ -43,6 +44,20 @@ const PluginListLabel: FC<PluginListLabelProps> = ({ name, frozen, hidden, versi {t('PluginListLabel.hidden')} </div> )} + {disabled && ( + <div + style={{ + fontSize: '0.8rem', + color: '#dcdedf', + display: 'flex', + alignItems: 'center', + gap: '10px', + }} + > + <FaBan /> + {t('PluginListLabel.disabled')} + </div> + )} </div> ); }; diff --git a/frontend/src/components/settings/pages/plugin_list/index.tsx b/frontend/src/components/settings/pages/plugin_list/index.tsx index 9a7cb076..43d79709 100644 --- a/frontend/src/components/settings/pages/plugin_list/index.tsx +++ b/frontend/src/components/settings/pages/plugin_list/index.tsx @@ -2,9 +2,11 @@ import { DialogBody, DialogButton, DialogControlsSection, + Focusable, GamepadEvent, Menu, MenuItem, + NavEntryPositionPreferences, ReorderableEntry, ReorderableList, showContextMenu, @@ -13,7 +15,7 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { FaDownload, FaEllipsisH, FaRecycle } from 'react-icons/fa'; -import { InstallType } from '../../../../plugin'; +import { InstallType, enablePlugin } from '../../../../plugin'; import { StorePluginVersion, getPluginList, @@ -35,6 +37,7 @@ async function reinstallPlugin(pluginName: string, currentVersion?: string) { type PluginTableData = PluginData & { name: string; + disabled: boolean; frozen: boolean; onFreeze(): void; onUnfreeze(): void; @@ -54,22 +57,25 @@ function PluginInteractables(props: { entry: ReorderableEntry<PluginTableData> } return null; } - const { name, update, version, onHide, onShow, hidden, onFreeze, onUnfreeze, frozen, isDeveloper } = props.entry.data; + const { name, update, version, onHide, onShow, hidden, onFreeze, onUnfreeze, frozen, isDeveloper, disabled } = + props.entry.data; const showCtxMenu = (e: MouseEvent | GamepadEvent) => { showContextMenu( <Menu label={t('PluginListIndex.plugin_actions')}> - <MenuItem - onSelected={async () => { - try { - await reloadPluginBackend(name); - } catch (err) { - console.error('Error Reloading Plugin Backend', err); - } - }} - > - {t('PluginListIndex.reload')} - </MenuItem> + {!disabled && ( + <MenuItem + onSelected={async () => { + try { + await reloadPluginBackend(name); + } catch (err) { + console.error('Error Reloading Plugin Backend', err); + } + }} + > + {t('PluginListIndex.reload')} + </MenuItem> + )} <MenuItem onSelected={() => DeckyPluginLoader.uninstallPlugin( @@ -82,11 +88,28 @@ function PluginInteractables(props: { entry: ReorderableEntry<PluginTableData> } > {t('PluginListIndex.uninstall')} </MenuItem> - {hidden ? ( - <MenuItem onSelected={onShow}>{t('PluginListIndex.show')}</MenuItem> + {disabled ? ( + <MenuItem onSelected={() => enablePlugin(name)}>{t('PluginListIndex.enable')}</MenuItem> ) : ( - <MenuItem onSelected={onHide}>{t('PluginListIndex.hide')}</MenuItem> + <MenuItem + onSelected={() => + DeckyPluginLoader.disablePlugin( + name, + t('PluginLoader.plugin_disable.title', { name }), + t('PluginLoader.plugin_disable.button'), + t('PluginLoader.plugin_disable.desc', { name }), + ) + } + > + {t('PluginListIndex.disable')} + </MenuItem> )} + {!disabled && + (hidden ? ( + <MenuItem onSelected={onShow}>{t('PluginListIndex.show')}</MenuItem> + ) : ( + <MenuItem onSelected={onHide}>{t('PluginListIndex.hide')}</MenuItem> + ))} {frozen ? ( <MenuItem onSelected={onUnfreeze}>{t('PluginListIndex.unfreeze')}</MenuItem> ) : ( @@ -98,7 +121,7 @@ function PluginInteractables(props: { entry: ReorderableEntry<PluginTableData> } }; return ( - <> + <Focusable navEntryPreferPosition={NavEntryPositionPreferences.MAINTAIN_X} style={{ display: 'flex' }}> {update ? ( <DialogButton style={{ height: '40px', minWidth: '60px', marginRight: '10px' }} @@ -137,7 +160,7 @@ function PluginInteractables(props: { entry: ReorderableEntry<PluginTableData> } > <FaEllipsisH /> </DialogButton> - </> + </Focusable> ); } @@ -147,16 +170,18 @@ type PluginData = { }; export default function PluginList({ isDeveloper }: { isDeveloper: boolean }) { - const { plugins, updates, pluginOrder, setPluginOrder, frozenPlugins, hiddenPlugins } = useDeckyState(); + const { installedPlugins, disabledPlugins, updates, pluginOrder, setPluginOrder, frozenPlugins, hiddenPlugins } = + useDeckyState(); + const [_, setPluginOrderSetting] = useSetting<string[]>( 'pluginOrder', - plugins.map((plugin) => plugin.name), + installedPlugins.map((plugin) => plugin.name), ); const { t } = useTranslation(); useEffect(() => { DeckyPluginLoader.checkPluginUpdates(); - }, []); + }, [installedPlugins, frozenPlugins]); const [pluginEntries, setPluginEntries] = useState<ReorderableEntry<PluginTableData>[]>([]); const hiddenPluginsService = DeckyPluginLoader.hiddenPluginsService; @@ -164,15 +189,24 @@ export default function PluginList({ isDeveloper }: { isDeveloper: boolean }) { useEffect(() => { setPluginEntries( - plugins.map(({ name, version }) => { + installedPlugins.map(({ name, version }) => { const frozen = frozenPlugins.includes(name); const hidden = hiddenPlugins.includes(name); return { - label: <PluginListLabel name={name} frozen={frozen} hidden={hidden} version={version} />, + label: ( + <PluginListLabel + name={name} + frozen={frozen} + hidden={hidden} + version={version} + disabled={disabledPlugins.find((p) => p.name == name) !== undefined} + /> + ), position: pluginOrder.indexOf(name), data: { name, + disabled: disabledPlugins.some((disabledPlugin) => disabledPlugin.name === name), frozen, hidden, isDeveloper, @@ -186,9 +220,9 @@ export default function PluginList({ isDeveloper }: { isDeveloper: boolean }) { }; }), ); - }, [plugins, updates, hiddenPlugins]); + }, [installedPlugins, updates, hiddenPlugins, disabledPlugins]); - if (plugins.length === 0) { + if (installedPlugins.length === 0) { return ( <div> <p>{t('PluginListIndex.no_plugin')}</p> diff --git a/frontend/src/components/settings/pages/testing/index.tsx b/frontend/src/components/settings/pages/testing/index.tsx index 8f02c207..3c032361 100644 --- a/frontend/src/components/settings/pages/testing/index.tsx +++ b/frontend/src/components/settings/pages/testing/index.tsx @@ -4,6 +4,7 @@ import { DialogControlsSection, Field, Focusable, + NavEntryPositionPreferences, Navigation, ProgressBar, SteamSpinner, @@ -87,7 +88,10 @@ export default function TestingVersionList() { </> } > - <Focusable style={{ height: '40px', marginLeft: 'auto', display: 'flex' }}> + <Focusable + style={{ height: '40px', marginLeft: 'auto', display: 'flex' }} + navEntryPreferPosition={NavEntryPositionPreferences.MAINTAIN_X} + > <DialogButton style={{ height: '40px', minWidth: '60px', marginRight: '10px' }} onClick={async () => { |
