From f02d959ebcf291f2fa7517e8de0aff03f6e707c5 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 25 Aug 2026 19:56:25 +0900 Subject: [PATCH 01/22] change: write config later --- dzgui/init/migrate.py | 6 +++--- dzgui/views/dialogs/wizard.py | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dzgui/init/migrate.py b/dzgui/init/migrate.py index 97c5587..19bfe8a 100644 --- a/dzgui/init/migrate.py +++ b/dzgui/init/migrate.py @@ -1,3 +1,4 @@ +import json import shutil from pathlib import Path @@ -7,11 +8,10 @@ from dzgui.config.convert import rc2json from dzgui.util._json import read_json, write_json -def migrate_legacy_conf(config: Path) -> None: +def migrate_legacy_conf(config: Path) -> dict[str, Any]: old_conf = Path.home() / LEGACY_CONFIG_PATH j = rc2json(old_conf) - config.parent.mkdir(parents=True, exist_ok=True) - config.write_text(j) + return json.loads(j) def has_new_config(config: Path) -> bool: diff --git a/dzgui/views/dialogs/wizard.py b/dzgui/views/dialogs/wizard.py index 033f7a1..7837f4c 100644 --- a/dzgui/views/dialogs/wizard.py +++ b/dzgui/views/dialogs/wizard.py @@ -305,6 +305,7 @@ class ConfigMigrationPage(EnumeratedWizardPage): ) self.migrated = False + self.migrated_conf: dict[str, Any] = {} self.config = config self.page_type = Gtk.AssistantPageType.INTRO @@ -344,8 +345,7 @@ class ConfigMigrationPage(EnumeratedWizardPage): def _on_import_clicked(self, button: Gtk.Button) -> None: self.grid.set_sensitive(False) try: - # TODO: this could be deferred to the final page (prevents accidental destruction of dialog via ESC) - migrate_legacy_conf(self.config) + self.migrated_conf = migrate_legacy_conf(self.config) self.migrated = True self.success_box.set_visible(True) except Exception: @@ -496,9 +496,9 @@ class Assistant(Gtk.Assistant): pass case ConfigMigrationPage(): if page.is_migrated(): - steam_path = lookup(self.config_path, Preferences.DEFAULT) - self.page6.set_steam_path(steam_path) - offset = 1 if not self.is_binary else 2 + sp = page.migrated_conf["default_steam_path"] + self.page_shortcuts.set_steam_path(sp) + self.write_config(self.page_migration.migrated_conf) self.setup_complete = True return self.get_n_pages() - offset case SteamPathPage(): From 8e3ce722950ecda4a95088cbfd160a5a30b545d0 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 25 Aug 2026 19:57:52 +0900 Subject: [PATCH 02/22] change: do not store pages linearly --- dzgui/views/dialogs/wizard.py | 48 ++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/dzgui/views/dialogs/wizard.py b/dzgui/views/dialogs/wizard.py index 7837f4c..b34fcf0 100644 --- a/dzgui/views/dialogs/wizard.py +++ b/dzgui/views/dialogs/wizard.py @@ -444,13 +444,13 @@ class Assistant(Gtk.Assistant): self.setup_complete = False - self.page1 = IntroductionPage() - self.page2 = ConfigMigrationPage(XDG.config) - self.page3 = SteamPathPage() - self.page4 = SteamValidationPage() - self.page5 = PreferencesPage() - self.page6 = ShortcutCreationPage(XDG.shortcut) - self.page7 = CompletionPage() + self.page_intro = IntroductionPage() + self.page_migration = ConfigMigrationPage(XDG.config) + self.page_paths = SteamPathPage() + self.page_api = SteamValidationPage() + self.page_prefs = PreferencesPage() + self.page_shortcuts = ShortcutCreationPage(XDG.shortcut) + self.page_completion = CompletionPage() self.set_forward_page_func(self._advance_page) @@ -461,13 +461,13 @@ class Assistant(Gtk.Assistant): legacy_path = Path.home().joinpath(LEGACY_CONFIG_PATH) self.has_legacy_config = legacy_path.is_file() for page in ( - self.page1, - self.page2, - self.page3, - self.page4, - self.page5, - self.page6, - self.page7, + self.page_intro, + self.page_migration, + self.page_paths, + self.page_api, + self.page_prefs, + self.page_shortcuts, + self.page_completion, ): # NOTE: skip config migration page if no legacy config file if ( @@ -486,8 +486,14 @@ class Assistant(Gtk.Assistant): self.show_all() load_css() - def write_config(self) -> None: - write_json(self.config_values, self.config_path) + def write_config(self, config: dict[str, Any]) -> None: + write_json(config, self.config_path) + + def get_final_page(self) -> int: + for page in range(0, self.get_n_pages()): + child = self.get_nth_page(page) + if child == self.page_completion: + return page def _advance_page(self, index: int) -> int: page = self.get_nth_page(index) @@ -500,19 +506,21 @@ class Assistant(Gtk.Assistant): self.page_shortcuts.set_steam_path(sp) self.write_config(self.page_migration.migrated_conf) self.setup_complete = True - return self.get_n_pages() - offset + return self.get_final_page() case SteamPathPage(): self.config_values["default_steam_path"] = page.get_path_from_radio() case SteamValidationPage(): self.config_values["steam_api"] = page.get_api_key() case PreferencesPage(): # NOTE: collects config values before advancing to last page - name, use_miles, client = self.page5.get_prefs() + name, use_miles, client = self.page_prefs.get_prefs() self.config_values["name"] = name self.config_values["use_miles"] = use_miles self.config_values["client"] = client - self.write_config() - self.page6.set_steam_path(self.config_values["default_steam_path"]) + self.write_config(self.config_values) + self.page_shortcuts.set_steam_path( + self.config_values["default_steam_path"] + ) self.setup_complete = True case ShortcutCreationPage(): page.create_shortcuts() From ca234b8dea5c2b327bdbaa61f6d2452f01653309 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 25 Aug 2026 19:58:37 +0900 Subject: [PATCH 03/22] drop: unused imports --- dzgui/views/dialogs/wizard.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/dzgui/views/dialogs/wizard.py b/dzgui/views/dialogs/wizard.py index b34fcf0..175b567 100644 --- a/dzgui/views/dialogs/wizard.py +++ b/dzgui/views/dialogs/wizard.py @@ -17,9 +17,7 @@ from dzgui.const.constants import ( ) from dzgui.const.boilerplate import config_boilerplate from dzgui.const.endpoints import STEAM_API_SETUP -from dzgui.const.enum import Preferences from dzgui.config import freedesktop -from dzgui.config.query import lookup from dzgui.init.migrate import migrate_legacy_conf from dzgui.managers.threading import call_on_thread, StoredFunc, ThreadingManager from dzgui.strings import wizard From c839672f851519d30b39b84a0c06e6d33fbafe8b Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 25 Aug 2026 20:03:32 +0900 Subject: [PATCH 04/22] chore: clear typehinting errors --- dzgui/init/migrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dzgui/init/migrate.py b/dzgui/init/migrate.py index 19bfe8a..2a5c0bc 100644 --- a/dzgui/init/migrate.py +++ b/dzgui/init/migrate.py @@ -8,7 +8,7 @@ from dzgui.config.convert import rc2json from dzgui.util._json import read_json, write_json -def migrate_legacy_conf(config: Path) -> dict[str, Any]: +def migrate_legacy_conf(config: Path) -> Any: old_conf = Path.home() / LEGACY_CONFIG_PATH j = rc2json(old_conf) return json.loads(j) From 2383f7d2aab2dfd2c435796ad467e4f54aff6099 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 25 Aug 2026 20:03:42 +0900 Subject: [PATCH 05/22] change: simplify method --- dzgui/views/dialogs/wizard.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dzgui/views/dialogs/wizard.py b/dzgui/views/dialogs/wizard.py index 175b567..8f12dd0 100644 --- a/dzgui/views/dialogs/wizard.py +++ b/dzgui/views/dialogs/wizard.py @@ -488,10 +488,8 @@ class Assistant(Gtk.Assistant): write_json(config, self.config_path) def get_final_page(self) -> int: - for page in range(0, self.get_n_pages()): - child = self.get_nth_page(page) - if child == self.page_completion: - return page + pages = self.get_n_pages() + return pages - 1 def _advance_page(self, index: int) -> int: page = self.get_nth_page(index) From f3fd7ef6ea4841373600484e93ca839fa925b8ac Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 25 Aug 2026 20:09:02 +0900 Subject: [PATCH 06/22] change: revert prior changes --- dzgui/views/dialogs/wizard.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dzgui/views/dialogs/wizard.py b/dzgui/views/dialogs/wizard.py index 8f12dd0..d978a6e 100644 --- a/dzgui/views/dialogs/wizard.py +++ b/dzgui/views/dialogs/wizard.py @@ -489,7 +489,10 @@ class Assistant(Gtk.Assistant): def get_final_page(self) -> int: pages = self.get_n_pages() - return pages - 1 + if self.is_binary: + return pages - 2 + else: + return pages - 1 def _advance_page(self, index: int) -> int: page = self.get_nth_page(index) From 687c5ac1686278b3c769cbbb3511dbcab6fbb67b Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 25 Aug 2026 20:09:56 +0900 Subject: [PATCH 07/22] chore: add comments --- dzgui/views/dialogs/wizard.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dzgui/views/dialogs/wizard.py b/dzgui/views/dialogs/wizard.py index d978a6e..1326917 100644 --- a/dzgui/views/dialogs/wizard.py +++ b/dzgui/views/dialogs/wizard.py @@ -489,6 +489,8 @@ class Assistant(Gtk.Assistant): def get_final_page(self) -> int: pages = self.get_n_pages() + # TODO: might be better to check if path is writeable + # and selectively block certain shortcut options if self.is_binary: return pages - 2 else: From 07cbf7a36a97c0523537a7ec478f1ef61aab0f69 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Wed, 26 Aug 2026 16:55:25 +0900 Subject: [PATCH 08/22] change: always show shortcuts page The expected shortcut path is already parsed by dzgui.config.xdg, which invokes is_writeable(); it will use a writeable fallback path for XDG_DATA_HOME. There is no need for a conditional check here. Even if the launcher itself is installed to a non-writeable system location, the shortcut can still copy from that. --- dzgui/views/dialogs/wizard.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/dzgui/views/dialogs/wizard.py b/dzgui/views/dialogs/wizard.py index 1326917..ae5b24d 100644 --- a/dzgui/views/dialogs/wizard.py +++ b/dzgui/views/dialogs/wizard.py @@ -1,4 +1,3 @@ -import os import textwrap from enum import Enum @@ -435,9 +434,7 @@ class Assistant(Gtk.Assistant): else: self.set_default_size(1500, 900) - self.is_binary = False if os.getenv("PYAPP") is None else True self.config_path = XDG.config - self.config_values: dict[str, Any] = config_boilerplate self.setup_complete = False @@ -456,6 +453,8 @@ class Assistant(Gtk.Assistant): EMITTER.connect("step_pending", self._mark_page_incomplete) EMITTER.connect("config", self._set_config_state) + self.pages: dict[EnumeratedWizardPage, int] = {} + legacy_path = Path.home().joinpath(LEGACY_CONFIG_PATH) self.has_legacy_config = legacy_path.is_file() for page in ( @@ -473,10 +472,8 @@ class Assistant(Gtk.Assistant): and self.has_legacy_config is False ): continue - # NOTE: disabled for now on system-provided packages - if isinstance(page, ShortcutCreationPage) and not self.is_binary: - continue - self._add_page(page, page.get_page_type()) + ind = self._add_page(page, page.get_page_type()) + self.pages[page] = ind self.connect("prepare", self._on_page_prepare) self.connect("cancel", self.destroy_and_quit) @@ -488,13 +485,7 @@ class Assistant(Gtk.Assistant): write_json(config, self.config_path) def get_final_page(self) -> int: - pages = self.get_n_pages() - # TODO: might be better to check if path is writeable - # and selectively block certain shortcut options - if self.is_binary: - return pages - 2 - else: - return pages - 1 + return self.pages[self.page_shortcuts] def _advance_page(self, index: int) -> int: page = self.get_nth_page(index) @@ -552,11 +543,12 @@ class Assistant(Gtk.Assistant): def _add_page( self, page: EnumeratedWizardPage, ptype: Gtk.AssistantPageType - ) -> None: - self.append_page(page) + ) -> int: + ind = self.append_page(page) self.set_page_type(page, ptype) self.set_page_title(page, page.get_title()) self.set_page_complete(page, True) + return ind def _set_config_state(self, emitter: "Emitter", state: bool) -> None: self.config = state From 33843becae0a81325a01f7e1ec5bd27fac32b911 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Fri, 28 Aug 2026 15:49:19 +0900 Subject: [PATCH 09/22] chore: bump version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a349a4e..cd00f7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ description = "DayZ server browser and mod manager for Linux" authors = [ {name = "aclist"} ] -version = "7.0.0b22" +version = "7.0.0b23" license = "GPL-3.0-or-later" license-files = ["LICENSE"] readme = "README.md" From 74ecc306929ee7ad6e8d11296dbfb0061acf601b Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Fri, 28 Aug 2026 15:49:50 +0900 Subject: [PATCH 10/22] feat: add badlands string support --- dzgui/api/servers.py | 13 +++++++++---- dzgui/util/strings.py | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/dzgui/api/servers.py b/dzgui/api/servers.py index 2b9e0c5..6b1b123 100644 --- a/dzgui/api/servers.py +++ b/dzgui/api/servers.py @@ -346,10 +346,15 @@ def get_details(record: Record) -> Details: try: dlc = rules.dlc_flags - if dlc == 0: - dlc = strings.none - if dlc == 2: - dlc = strings.dlc_frostline + match dlc: + case 0: + dlc = strings.none + case 2: + dlc = strings.dlc_frostline + case 3: + dlc = strings.dlc_badlands + case _: + dlc = strings.unspecified except AttributeError: dlc = strings.unspecified diff --git a/dzgui/util/strings.py b/dzgui/util/strings.py index 9056200..b77aa66 100644 --- a/dzgui/util/strings.py +++ b/dzgui/util/strings.py @@ -173,6 +173,7 @@ unspecified = "not specified" # DLC dlc_frostline = "Frostline" +dlc_badlands = "Badlands" # platform windows = "Windows" From a85c6329026af152aaea26eda6b3ad4697054a1b Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Fri, 28 Aug 2026 15:52:15 +0900 Subject: [PATCH 11/22] change: namespace dlc strings --- dzgui/api/servers.py | 2 +- dzgui/util/strings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dzgui/api/servers.py b/dzgui/api/servers.py index 6b1b123..e921d8b 100644 --- a/dzgui/api/servers.py +++ b/dzgui/api/servers.py @@ -348,7 +348,7 @@ def get_details(record: Record) -> Details: dlc = rules.dlc_flags match dlc: case 0: - dlc = strings.none + dlc = strings.dlc_none case 2: dlc = strings.dlc_frostline case 3: diff --git a/dzgui/util/strings.py b/dzgui/util/strings.py index b77aa66..da28c18 100644 --- a/dzgui/util/strings.py +++ b/dzgui/util/strings.py @@ -168,12 +168,12 @@ none_provided = "None provided" disabled = "Disabled" enabled = "Enabled" null = "-" -none = "None" unspecified = "not specified" # DLC dlc_frostline = "Frostline" dlc_badlands = "Badlands" +dlc_none = "None" # platform windows = "Windows" From 8bae2d5fb5f2949852b29143cdd60814ac74be29 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Fri, 28 Aug 2026 16:00:14 +0900 Subject: [PATCH 12/22] chore: add log output when setting start tab --- dzgui/controllers/mc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index 9effd3c..04197d9 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -523,6 +523,7 @@ class Controller(GObject.GObject): def set_start_tab(self) -> None: ind = self.config_man.get_start_tab() + logger.debug(f"Setting start tab to index {ind}") self.get_servers().notebook.set_current_page(ind) def get_debug_args(self) -> str: From b4125c5a51c861d3d7fb6d02270aab8546c0112a Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Fri, 28 Aug 2026 16:01:09 +0900 Subject: [PATCH 13/22] change: change log level --- dzgui/controllers/mc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index 04197d9..8f35fc5 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -523,7 +523,7 @@ class Controller(GObject.GObject): def set_start_tab(self) -> None: ind = self.config_man.get_start_tab() - logger.debug(f"Setting start tab to index {ind}") + logger.info(f"Setting start tab to index {ind}") self.get_servers().notebook.set_current_page(ind) def get_debug_args(self) -> str: From 572ac5d7ce9de6759d98aa1c44bf2a1a59faba04 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Fri, 28 Aug 2026 16:07:06 +0900 Subject: [PATCH 14/22] chore: drop unused code --- dzgui/util/dist.py | 1 - dzgui/util/ip.py | 7 ------- 2 files changed, 8 deletions(-) diff --git a/dzgui/util/dist.py b/dzgui/util/dist.py index 6a58d82..0bc6f2b 100644 --- a/dzgui/util/dist.py +++ b/dzgui/util/dist.py @@ -84,6 +84,5 @@ class CalcDist: except Exception: return None - # TODO: handle failed remote dist haversine = Haversine(local.lat, local.lon, remote.lat, remote.lon) return haversine diff --git a/dzgui/util/ip.py b/dzgui/util/ip.py index 9cf92cd..982f23e 100644 --- a/dzgui/util/ip.py +++ b/dzgui/util/ip.py @@ -127,10 +127,3 @@ def is_valid_port(port: str) -> bool: if not port.isdigit() or int(port) == 0 or int(port[0]) == 0 or int(port) > 65535: return True return False - - -@deprecated("use ips.csv") -def get_local_coords(ip: str) -> str: - url = COORDS_API + "/" + ip - # local res=$(curl -Ls "$url" | jq -r '"\(.lat)\n\(.lon)"') - return url From d04c20498afe78c443e22ddb2fc450d83c63ee51 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Fri, 28 Aug 2026 16:35:08 +0900 Subject: [PATCH 15/22] change: write config only on last page --- dzgui/views/dialogs/wizard.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dzgui/views/dialogs/wizard.py b/dzgui/views/dialogs/wizard.py index ae5b24d..b755b4a 100644 --- a/dzgui/views/dialogs/wizard.py +++ b/dzgui/views/dialogs/wizard.py @@ -496,8 +496,7 @@ class Assistant(Gtk.Assistant): if page.is_migrated(): sp = page.migrated_conf["default_steam_path"] self.page_shortcuts.set_steam_path(sp) - self.write_config(self.page_migration.migrated_conf) - self.setup_complete = True + self.config_values = self.page_migration.migrated_conf return self.get_final_page() case SteamPathPage(): self.config_values["default_steam_path"] = page.get_path_from_radio() @@ -509,11 +508,9 @@ class Assistant(Gtk.Assistant): self.config_values["name"] = name self.config_values["use_miles"] = use_miles self.config_values["client"] = client - self.write_config(self.config_values) self.page_shortcuts.set_steam_path( self.config_values["default_steam_path"] ) - self.setup_complete = True case ShortcutCreationPage(): page.create_shortcuts() case _: @@ -565,6 +562,10 @@ class Assistant(Gtk.Assistant): if not isinstance(page, IntroductionPage): EMITTER.emit("step_pending") + if page == self.page_completion: + self.write_config(self.config_values) + self.setup_complete = True + class CheckboxWithLabel(Gtk.Box): def __init__(self, text: str, blurb_text: str) -> None: From b7b83b3ca5211e1407c9643a7cc6d0bf060cb769 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Fri, 28 Aug 2026 16:35:34 +0900 Subject: [PATCH 16/22] chore: drop unused imports --- dzgui/util/ip.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dzgui/util/ip.py b/dzgui/util/ip.py index 982f23e..2901986 100644 --- a/dzgui/util/ip.py +++ b/dzgui/util/ip.py @@ -2,14 +2,13 @@ import a2s import requests import shutil import subprocess -from warnings import deprecated from dataclasses import dataclass from typing import TYPE_CHECKING from dzgui.api.servers import Record from dzgui.const.constants import REQUEST_TIMEOUT -from dzgui.const.endpoints import COORDS_API, IP_ECHO +from dzgui.const.endpoints import IP_ECHO if TYPE_CHECKING: From 9bc5964df28bc223bdcd4ddabc3817a3fcfb9a35 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Fri, 28 Aug 2026 16:58:44 +0900 Subject: [PATCH 17/22] chore: add XDG path conversion test --- tests/test_path_conversion.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/test_path_conversion.py diff --git a/tests/test_path_conversion.py b/tests/test_path_conversion.py new file mode 100644 index 0000000..c9b1710 --- /dev/null +++ b/tests/test_path_conversion.py @@ -0,0 +1,13 @@ +from pathlib import Path +from dzgui.config.xdg import get_xdg_paths + + +def test_path_fallback(monkeypatch) -> None: + envs = ["XDG_DATA_HOME", "XDG_STATE_HOME", "XDG_CONFIG_HOME", "XDG_CACHE_HOME"] + for env in envs: + monkeypatch.setenv(env, "/etc/dzgui") + paths = get_xdg_paths() + assert paths["XDG_CONFIG_HOME"] == Path.home().joinpath(".config/dzgui") + assert paths["XDG_STATE_HOME"] == Path.home().joinpath(".local/state/dzgui") + assert paths["XDG_DATA_HOME"] == Path.home().joinpath(".local/share/dzgui") + assert paths["XDG_CACHE_HOME"] == Path.home().joinpath(".cache/dzgui") From 00369837cbf8701934492876d46b7d8f013128e0 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Fri, 28 Aug 2026 17:35:29 +0900 Subject: [PATCH 18/22] fix: support multiple user ids --- dzgui/api/steam.py | 26 ++++++++++++------- .../api/loginusers_beta_client_multiple.vdf | 23 ++++++++++++++++ .../api/loginusers_beta_client_multiple_2.vdf | 23 ++++++++++++++++ .../api/loginusers_legacy_client_multiple.vdf | 2 +- tests/test_loginusers.py | 2 ++ 5 files changed, 66 insertions(+), 10 deletions(-) create mode 100644 tests/fixtures/api/loginusers_beta_client_multiple.vdf create mode 100644 tests/fixtures/api/loginusers_beta_client_multiple_2.vdf diff --git a/dzgui/api/steam.py b/dzgui/api/steam.py index 668def6..50786b8 100644 --- a/dzgui/api/steam.py +++ b/dzgui/api/steam.py @@ -151,7 +151,9 @@ def get_remote_signatures(mods: list[str]) -> list[tuple[str, str, int, int]]: return hashes -def connect_debug(client: str, addr: str, appid: int, name: str, mods: list[str]) -> str: +def connect_debug( + client: str, addr: str, appid: int, name: str, mods: list[str] +) -> str: concat = concat_mods(mods) client_args = concat_bash_args(client) params = [ @@ -167,6 +169,7 @@ def connect_debug(client: str, addr: str, appid: int, name: str, mods: list[str] client_args.extend(params) return " ".join(client_args) + # TODO: set config to name=user, use official server and no mods, # ensure that formatted string is identical to fixture with same hash def connect(client: str, addr: str, appid: int, name: str, mods: list[str]) -> int: @@ -235,14 +238,19 @@ def find_user_id(path: Path) -> str | None: try: with open(resolved_path, "r") as f: v = vdf.load(f) - # NOTE: beta client - # /package/beta - if len(v["users"]) == 1: - return str(list(v["users"].keys())[0]) - for user in v["users"]: - if v["users"][user]["MostRecent"] == "1": - return str(user) - return None + users = v["users"] + # NOTE: beta client: /package/beta + last_user = next(iter(users)) + if len(users) == 1: + return last_user + last_stamp = int(users[last_user]["Timestamp"]) + for user in users: + stamp = int(users[user]["Timestamp"]) + if stamp > last_stamp: + last_stamp = stamp + last_user = user + print(last_user) + return last_user except Exception as e: logger.debug(e) return None diff --git a/tests/fixtures/api/loginusers_beta_client_multiple.vdf b/tests/fixtures/api/loginusers_beta_client_multiple.vdf new file mode 100644 index 0000000..bc56e12 --- /dev/null +++ b/tests/fixtures/api/loginusers_beta_client_multiple.vdf @@ -0,0 +1,23 @@ +"users" +{ + "0" + { + "AccountName" "STEAMUSER" + "PersonaName" "STEAMUSER" + "RememberPassword" "0" + "WantsOfflineMode" "0" + "SkipOfflineModeWarning" "0" + "AutoLogin" "1" + "Timestamp" "1787904411" + } + "1" + { + "AccountName" "STEAMUSER2" + "PersonaName" "STEAMUSER2" + "RememberPassword" "0" + "WantsOfflineMode" "0" + "SkipOfflineModeWarning" "0" + "AutoLogin" "1" + "Timestamp" "1787904647" + } +} diff --git a/tests/fixtures/api/loginusers_beta_client_multiple_2.vdf b/tests/fixtures/api/loginusers_beta_client_multiple_2.vdf new file mode 100644 index 0000000..7975bde --- /dev/null +++ b/tests/fixtures/api/loginusers_beta_client_multiple_2.vdf @@ -0,0 +1,23 @@ +"users" +{ + "0" + { + "AccountName" "STEAMUSER" + "PersonaName" "STEAMUSER" + "RememberPassword" "0" + "WantsOfflineMode" "0" + "SkipOfflineModeWarning" "0" + "AutoLogin" "1" + "Timestamp" "1797904411" + } + "1" + { + "AccountName" "STEAMUSER2" + "PersonaName" "STEAMUSER2" + "RememberPassword" "0" + "WantsOfflineMode" "0" + "SkipOfflineModeWarning" "0" + "AutoLogin" "1" + "Timestamp" "1787904647" + } +} diff --git a/tests/fixtures/api/loginusers_legacy_client_multiple.vdf b/tests/fixtures/api/loginusers_legacy_client_multiple.vdf index e353f75..8a4a3b2 100644 --- a/tests/fixtures/api/loginusers_legacy_client_multiple.vdf +++ b/tests/fixtures/api/loginusers_legacy_client_multiple.vdf @@ -20,6 +20,6 @@ "SkipOfflineModeWarning" "0" "AllowAutoLogin" "1" "MostRecent" "1" - "Timestamp" "0" + "Timestamp" "10" } } diff --git a/tests/test_loginusers.py b/tests/test_loginusers.py index 34864dd..6665e79 100644 --- a/tests/test_loginusers.py +++ b/tests/test_loginusers.py @@ -14,6 +14,8 @@ pytestmark = pytest.mark.apitest ("api/loginusers_legacy_client.vdf", 0), ("api/loginusers_legacy_client_multiple.vdf", 1), ("api/loginusers_beta_client.vdf", 0), + ("api/loginusers_beta_client_multiple.vdf", 1), + ("api/loginusers_beta_client_multiple_2.vdf", 0), ], ) def test_loginusers(monkeypatch, fixture: str, expect: int) -> None: From 667203b4f90894627256d7d5da953a0fd2af675d Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Fri, 28 Aug 2026 17:36:23 +0900 Subject: [PATCH 19/22] chore: clear typehinting errors --- dzgui/api/steam.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dzgui/api/steam.py b/dzgui/api/steam.py index 50786b8..1cac60f 100644 --- a/dzgui/api/steam.py +++ b/dzgui/api/steam.py @@ -240,7 +240,7 @@ def find_user_id(path: Path) -> str | None: v = vdf.load(f) users = v["users"] # NOTE: beta client: /package/beta - last_user = next(iter(users)) + last_user = str(next(iter(users))) if len(users) == 1: return last_user last_stamp = int(users[last_user]["Timestamp"]) @@ -249,7 +249,6 @@ def find_user_id(path: Path) -> str | None: if stamp > last_stamp: last_stamp = stamp last_user = user - print(last_user) return last_user except Exception as e: logger.debug(e) From 64d784f9a0ffe297d8af3446be0dce4974eb38ae Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Sat, 29 Aug 2026 15:55:02 +0900 Subject: [PATCH 20/22] fix: apply keyword filter when refreshing (#469) --- dzgui/model/proxy_model.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dzgui/model/proxy_model.py b/dzgui/model/proxy_model.py index dec8338..94b279a 100644 --- a/dzgui/model/proxy_model.py +++ b/dzgui/model/proxy_model.py @@ -298,4 +298,6 @@ class ProxyModelManager: def push(self, data: list[Any]) -> None: self.wipe_cache() self.set_control(data) - self.filter(FilterMode.INITIAL) + cur_keyword = self.filter_man.get_active_keyword() + mode = FilterMode.TOGGLE_ON if len(cur_keyword) > 0 else FilterMode.INITIAL + self.filter(mode) From 39d8607f57f591c2d7e5d64a1421464d63c21581 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Sat, 29 Aug 2026 15:55:24 +0900 Subject: [PATCH 21/22] chore: drop unused code --- dzgui/model/proxy_model.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dzgui/model/proxy_model.py b/dzgui/model/proxy_model.py index 94b279a..44a03de 100644 --- a/dzgui/model/proxy_model.py +++ b/dzgui/model/proxy_model.py @@ -259,10 +259,6 @@ class ProxyModelManager: def set_cache(self, filters: tuple[str], filtered_rows: list[tuple]) -> None: self.filter_cache[filters] = filtered_rows - # @deprecated("Currently unused") - # def convert_model_to_list(self, model: "FastInsertListStore") -> list: - # return [[el for el in row] for row in model] - def set_filtered(self, rows: list | None) -> None: if rows is None: self.filtered = [] From 0f6f1c03ecee9484afee6d0e2f8c4c19b3a241b0 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Sat, 29 Aug 2026 15:55:36 +0900 Subject: [PATCH 22/22] chore: update changelog --- CHANGELOG.md | 1 + dzgui/data/CHANGELOG.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2c6eb2..9c38886 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,6 +90,7 @@ - Rare segfaults when changing maps (threading) - Moved dialogs out of threads - History table not being in lock-step with state file +- Current keyword filter not being applied when refreshing table ### Unreleased - Load offline mods diff --git a/dzgui/data/CHANGELOG.md b/dzgui/data/CHANGELOG.md index c2c6eb2..9c38886 100644 --- a/dzgui/data/CHANGELOG.md +++ b/dzgui/data/CHANGELOG.md @@ -90,6 +90,7 @@ - Rare segfaults when changing maps (threading) - Moved dialogs out of threads - History table not being in lock-step with state file +- Current keyword filter not being applied when refreshing table ### Unreleased - Load offline mods