mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-07-11 00:32:06 +00:00
[Feature] File picker improvements (#454)
* First iteration for internationalization of the loader * First iteration for internationalization of the loader * Cleanup node mess * Cleanup node mess pt2 * Additional touches * Latest decky changed merged into i18n and updated translation. * Styling fixes * Initial backend hosting implementation * Added correct url path of the loopback server. * Added correct url path of the loopback server. * Some better namespaced text. * Added whitelist for locales path. * Refactor languages and fix hooks logic bugs. * Small typo in language translation structure. * Working backend, automatically swtich languages with steam and language fixes. * Fix to languages * Key fixes * Additional language fixes. * Additional json changes * Final text revision and added a vscode tasks to automatically extract text from code. * Typo in the middleware * Remove unused imports * Cleanup whitespaces. * Import changes * Revert "Import changes" This reverts commit8e8231950f. * Update index.d.ts * Clean up unused imports * Delete pnpm-lock.yaml * Update rollup.config.js * Update PluginInstallModal.tsx * Update index.tsx * Update plugin-loader.tsx * Update plugin-loader.tsx * Revert "Delete pnpm-lock.yaml" This reverts commit3a39f36f21. * Additional strings reworks. * Fixes for issues coming from github merge. * Fixes for master * Styling fixes * Styling pt2 * Missed a few strings in master, * Styling fixes * Additional master merge fixes. * Final cleanup and adaptation to master. * Final empty language cleanup and few string added * Small changes to italian translation * Disabled translation on a few components inside plugin-loader for missing react hooks. * Fixed passing tag to translation. * Disable debug output for reducing console spam. * Return correct content type * Small italian language change * Added support for country code * Fixed missing translation for uninstall popup. * Fix class name shenanigans for toast notification * Update dependencies * Fixed github workflow to include the new locales folder * Update dependencies to latest version (unless it's React) and fixed the new small errors that cropped up * Missed a file name change * Updated dev dependencies to latest version * Missed a few dev dependencies * Revert "Update dependencies to latest version (unless it's React) and fixed the new small errors that cropped up" Messed up merge with a different main branch * Messed up deletion of rollup config. * Fix broken pnpm lock file * Missed a localized string during the merge * Fixed a parameter mistake in the uninstall text parameter * Fix pnpm random issues * Small italian language tweaks * Fix wrong parameter passed to the uninstall function call * Another fix on a wrong function parameter * Additional translation text on the store and branch selection channels * Changed the default type passed to map to being able to index the two arrays. * Reverted and reworked the last changes * Distinguish events in UI for installing vs reinstalling plugins * Additional fixes for reinstall prompt * Revert the use of intevalPlural since the parser doesn't seem to support that. * Missed a routing path in the backend * Small bugfixes * Small fixes * Correctly adding the parameter to the request headers. * Refactoring of the UI popup modal * Fix pnpm shenanigans * Final fixes for the install UI localization * Clean up unnedeed backend code * Small rework on text selection. * Cleaned up parser configuration * Removed extracttext dependency to pnpmsetup * Merged translation and cleaned up parser * Fixed JSON structure after manual merge. * Added translation to the file picker * First iteration for merging the new filepicker. * Revert changes to PluginInstallModal * Reworked the text modal for the final time * Missed the proper linted text * Missed the backend change * Final branch cleanup * First iteration for porting the new file picker * Hotfix for i18n where the detector was overriding localStorage * Please, pnpm, cooperate * Small fix regarding the backend getting hammered when switching to not supported languages plus a small english typo * Initial working upstream iteration for file picker * Typo on translation variable * File picker final improvements * Stylistic fixes and fix on wrong bool passed to fp * Fixup merge from main * Other merge errors fixed * Minor cleanups * Fixed missing padding under text label extension * Implement pagination backend side * First draft for filtering backend side * Implemented matching on file names. * Fix for unable to order per size on folders. * Hard checking a return value * Added a missing import. * Implemented show more as a frontend button * Whoops, python typo * Fixed python backend * Rendering bug fix and small qol improvement * Added missing parameter to openFilePicker call * Fixed path on windows and unknown error on wrong path * Small backend fixes * Extension fix * Simplified extension logic * Less string conversions. * Optimize backend code and removed additional components. * Take correctly into account the max value The button will now respect the actual maximum desired number of entries. * Bugfix for ordering logic and ignore cases during sorting * Regex call was missing an argument * Fixed issues with filtering extensions * Rollback testing changes * Minor cleanup and attempt at fixing the not updating multimodal. * Cleanup variable types. * Mantains the same api format from the original source code. * Removing hardcoded paths in the code * Additional fixes for resolving the user path * Cleanup useless modifications * Final fixes for avoid path hardcoding * Update lockfile and i18next version
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
import {
|
||||
DialogButton,
|
||||
DialogCheckbox,
|
||||
DialogCheckboxProps,
|
||||
Marquee,
|
||||
Menu,
|
||||
MenuItem,
|
||||
findModuleChild,
|
||||
showContextMenu,
|
||||
} from 'decky-frontend-lib';
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaChevronDown } from 'react-icons/fa';
|
||||
|
||||
const dropDownControlButtonClass = findModuleChild((m) => {
|
||||
if (typeof m !== 'object') return undefined;
|
||||
for (const prop in m) {
|
||||
if (m[prop]?.toString()?.includes('gamepaddropdown_DropDownControlButton')) {
|
||||
return m[prop];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const DropdownMultiselectItem: FC<
|
||||
{
|
||||
value: any;
|
||||
onSelect: (checked: boolean, value: any) => void;
|
||||
checked: boolean;
|
||||
} & DialogCheckboxProps
|
||||
> = ({ value, onSelect, checked: defaultChecked, ...rest }) => {
|
||||
const [checked, setChecked] = useState(defaultChecked);
|
||||
|
||||
useEffect(() => {
|
||||
onSelect?.(checked, value);
|
||||
}, [checked, onSelect, value]);
|
||||
|
||||
return (
|
||||
<MenuItem bInteractableItem onClick={() => setChecked((x) => !x)}>
|
||||
<DialogCheckbox
|
||||
style={{ marginBottom: 0, padding: 0 }}
|
||||
className="decky_DropdownMultiselectItem_DialogCheckbox"
|
||||
bottomSeparator="none"
|
||||
{...rest}
|
||||
onClick={() => setChecked((x) => !x)}
|
||||
onChange={(checked) => setChecked(checked)}
|
||||
controlled
|
||||
checked={checked}
|
||||
/>
|
||||
</MenuItem>
|
||||
);
|
||||
};
|
||||
|
||||
const DropdownMultiselect: FC<{
|
||||
items: {
|
||||
label: string;
|
||||
value: string;
|
||||
}[];
|
||||
selected: string[];
|
||||
onSelect: (selected: any[]) => void;
|
||||
label: string;
|
||||
}> = ({ label, items, selected, onSelect }) => {
|
||||
const [itemsSelected, setItemsSelected] = useState<any>(selected);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleItemSelect = useCallback((checked, value) => {
|
||||
setItemsSelected((x: any) =>
|
||||
checked ? [...x.filter((y: any) => y !== value), value] : x.filter((y: any) => y !== value),
|
||||
);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
onSelect(itemsSelected);
|
||||
}, [itemsSelected, onSelect]);
|
||||
|
||||
return (
|
||||
<DialogButton
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
maxWidth: '100%',
|
||||
}}
|
||||
className={dropDownControlButtonClass}
|
||||
onClick={(evt) => {
|
||||
evt.preventDefault();
|
||||
showContextMenu(
|
||||
<Menu label={label} cancelText={t('DropdownMultiselect.button.back') as string}>
|
||||
<style>
|
||||
{`
|
||||
/* Inherit color from ".basiccontextmenu" */
|
||||
.decky_DropdownMultiselectItem_DialogCheckbox > .DialogToggle_Label {
|
||||
color: inherit;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
<div style={{ marginTop: '10px' }}>{/*FIXME: Hack for missing padding under label menu*/}</div>
|
||||
{items.map((x) => (
|
||||
<DropdownMultiselectItem
|
||||
key={x.value}
|
||||
label={x.label}
|
||||
value={x.value}
|
||||
checked={itemsSelected.includes(x.value)}
|
||||
onSelect={handleItemSelect}
|
||||
/>
|
||||
))}
|
||||
</Menu>,
|
||||
evt.currentTarget ?? window,
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Marquee>
|
||||
{selected.length > 0
|
||||
? selected.map((x: any) => items[items.findIndex((v) => v.value === x)].label).join(', ')
|
||||
: '…'}
|
||||
</Marquee>
|
||||
<div style={{ flexGrow: 1, minWidth: '1ch' }} />
|
||||
<FaChevronDown style={{ height: '1em', flex: '0 0 1em' }} />
|
||||
</DialogButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default DropdownMultiselect;
|
||||
Reference in New Issue
Block a user