diff options
| -rw-r--r-- | py_modules/lsfg_vk/flatpak_service.py | 29 | ||||
| -rw-r--r-- | py_modules/lsfg_vk/installation.py | 24 | ||||
| -rw-r--r-- | py_modules/lsfg_vk/plugin.py | 10 | ||||
| -rw-r--r-- | src/components/ConfigurationTab.tsx | 11 | ||||
| -rw-r--r-- | src/i18n/i18n.ts | 25 | ||||
| -rw-r--r-- | tests/test_plugin_migration.py | 50 | ||||
| -rw-r--r-- | tsconfig.json | 1 |
7 files changed, 74 insertions, 76 deletions
diff --git a/py_modules/lsfg_vk/flatpak_service.py b/py_modules/lsfg_vk/flatpak_service.py index 6f8a596..6aebf11 100644 --- a/py_modules/lsfg_vk/flatpak_service.py +++ b/py_modules/lsfg_vk/flatpak_service.py @@ -323,32 +323,3 @@ class FlatpakService(BaseService): app_id=app_id, operation="remove", ) - - def migrate_v2(self) -> None: - if not self.check_flatpak_available(): - return - - apps_result = self._run_flatpak_command( - ["list", "--user", "--app", "--columns=application"], - capture_output=True, - text=True, - ) - if apps_result.returncode != 0: - return - - for app_id in apps_result.stdout.splitlines(): - app_id = app_id.strip() - if not app_id: - continue - output = self._override_output(app_id) - paths = self._override_paths() - legacy_markers = ( - "LSFG_CONFIG=", - paths["legacy_home"], - paths["legacy_dll"], - paths["legacy_script"], - ) - if any(marker in output for marker in legacy_markers): - result = self.set_app_override(app_id) - if not result.get("success"): - self.log.warning(result.get("error")) diff --git a/py_modules/lsfg_vk/installation.py b/py_modules/lsfg_vk/installation.py index 09bd3a3..b583cc7 100644 --- a/py_modules/lsfg_vk/installation.py +++ b/py_modules/lsfg_vk/installation.py @@ -171,30 +171,6 @@ class InstallationService(BaseService): for path in (self.legacy_lib_file, self.legacy_json_file): self._remove_if_exists(path) - def needs_v2_migration(self) -> bool: - legacy_layer = self.legacy_lib_file.exists() or self.legacy_json_file.exists() - legacy_config = False - if self.config_file_path.exists(): - try: - legacy_config = ConfigurationManager.is_legacy_v1( - self.config_file_path.read_text(encoding="utf-8") - ) - except OSError: - legacy_config = False - if legacy_layer or legacy_config: - return True - try: - if self.config_file_path.exists(): - data = ConfigurationManager.parse_toml_content_multi_profile( - self.config_file_path.read_text(encoding="utf-8") - ) - configured = str(data["global_config"].get("dll") or "") - if (not configured or not Path(configured).is_file()) and self.steam_service.find_lsfg_vk_dll(): - return True - return not self.runtime_service.is_healthy() - except Exception: - return True - def check_installation(self) -> InstallationCheckResponse: try: installation_error = None diff --git a/py_modules/lsfg_vk/plugin.py b/py_modules/lsfg_vk/plugin.py index 6977b9c..0472e42 100644 --- a/py_modules/lsfg_vk/plugin.py +++ b/py_modules/lsfg_vk/plugin.py @@ -236,14 +236,4 @@ class Plugin: os.path.join(decky.DECKY_HOME, "lossless-scaling-vk"), os.path.join(decky.DECKY_USER_HOME, ".local", "share", "decky-lossless-scaling-vk")) - if self.installation_service.needs_v2_migration(): - result = self.installation_service.install() - if not result.get("success"): - decky.logger.warning(f"Native v2 migration failed: {result.get('error')}") - - try: - self.flatpak_service.migrate_v2() - except Exception as error: - decky.logger.warning(f"Flatpak v2 migration skipped: {error}") - decky.logger.info("decky-lsfg-vk plugin migrations completed") diff --git a/src/components/ConfigurationTab.tsx b/src/components/ConfigurationTab.tsx index 2175eb9..b3c0281 100644 --- a/src/components/ConfigurationTab.tsx +++ b/src/components/ConfigurationTab.tsx @@ -1,5 +1,6 @@ -import { ButtonItem, Field, Focusable, PanelSection, PanelSectionRow } from "@decky/ui"; +import { ButtonItem, DialogButton, Field, Focusable, PanelSection, PanelSectionRow } from "@decky/ui"; import { useCallback, useEffect, useRef, useState } from "react"; +import { FaArrowLeft } from "react-icons/fa"; import { RiArrowDownSFill, RiArrowUpSFill } from "react-icons/ri"; import { ConfigurationData } from "../config/configSchema"; import { GameTarget } from "../hooks/useGameConfiguration"; @@ -116,7 +117,13 @@ export function ConfigurationTab({ )} <PanelSectionRow> <Focusable ref={backToGamesRef} noFocusRing> - <ButtonItem layout="below" onClick={closeDetails}>Back to games</ButtonItem> + <DialogButton + aria-label="Back to games" + onClick={closeDetails} + style={{ width: "48px", minWidth: "48px", height: "48px", padding: "10px" }} + > + <FaArrowLeft /> + </DialogButton> </Focusable> </PanelSectionRow> </PanelSection> diff --git a/src/i18n/i18n.ts b/src/i18n/i18n.ts index dc8de8b..31a55cb 100644 --- a/src/i18n/i18n.ts +++ b/src/i18n/i18n.ts @@ -2,8 +2,16 @@ // to generate for localhost/dev, run `build_i18n_json.sh` script import * as languages from "./languages.json"; -const steamLanguageMap: Record<string, string> = - languages.steam_language_map as Record<string, string>; +type LanguageStrings = Record<string, string>; +type Language = { name: string; strings?: LanguageStrings }; +type LanguageData = { + language_metadata: Record<string, Language>; + steam_language_map: Record<string, string>; + [language: string]: LanguageStrings | Record<string, Language> | Record<string, string>; +}; + +const languageData = languages as unknown as LanguageData; +const steamLanguageMap = languageData.steam_language_map; const normalizeLanguage = (language: string): string => { const normalized = language.trim().toLowerCase(); @@ -11,13 +19,13 @@ const normalizeLanguage = (language: string): string => { }; function getLangs() { - const langs = languages.language_metadata; + const langs = languageData.language_metadata; - Object.keys(languages).map((lang) => { + Object.keys(languageData).forEach((lang) => { if (lang === "language_metadata" || lang == "steam_language_map") { return; } - const strs = languages[lang]; + const strs = languageData[lang] as LanguageStrings; if (lang && strs && langs[lang]?.name) { langs[lang].strings = strs; } @@ -27,12 +35,7 @@ function getLangs() { } export const LANGS: { - [key: string]: { - name: string; - strings: { - [key: string]: string; - }; - }; + [key: string]: Language; } = getLangs(); let cachedLang: string | undefined; diff --git a/tests/test_plugin_migration.py b/tests/test_plugin_migration.py new file mode 100644 index 0000000..a392f85 --- /dev/null +++ b/tests/test_plugin_migration.py @@ -0,0 +1,50 @@ +import asyncio +import sys +import types +import unittest +from unittest.mock import Mock + + +class PluginMigrationTests(unittest.TestCase): + def test_migration_only_runs_decky_path_migrations(self): + decky = types.SimpleNamespace( + DECKY_HOME="/decky", + DECKY_USER_HOME="/home/deck", + migrate_logs=Mock(), + migrate_settings=Mock(), + migrate_runtime=Mock(), + logger=Mock(), + ) + previous_decky = sys.modules.get("decky") + previous_tomllib = sys.modules.get("tomllib") + sys.modules["decky"] = decky + sys.modules["tomllib"] = types.SimpleNamespace(loads=Mock()) + try: + sys.path.insert(0, "py_modules") + from lsfg_vk.plugin import Plugin + + plugin = Plugin.__new__(Plugin) + plugin.installation_service = Mock() + plugin.flatpak_service = Mock() + + asyncio.run(plugin._migration()) + + decky.migrate_logs.assert_called_once() + decky.migrate_settings.assert_called_once() + decky.migrate_runtime.assert_called_once() + plugin.installation_service.install.assert_not_called() + plugin.flatpak_service.migrate_v2.assert_not_called() + finally: + sys.path.remove("py_modules") + if previous_decky is None: + sys.modules.pop("decky", None) + else: + sys.modules["decky"] = previous_decky + if previous_tomllib is None: + sys.modules.pop("tomllib", None) + else: + sys.modules["tomllib"] = previous_tomllib + + +if __name__ == "__main__": + unittest.main() diff --git a/tsconfig.json b/tsconfig.json index 626c60f..f4b795f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,7 @@ "jsxFragmentFactory": "window.SP_REACT.Fragment", "declaration": false, "moduleResolution": "node", + "resolveJsonModule": true, "noUnusedLocals": true, "noUnusedParameters": true, "esModuleInterop": true, |
