From 1fe66076c6b1ac1f8d17a33ccaa71049bf79760d Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Wed, 17 Jun 2026 22:12:12 +0900 Subject: [PATCH 1/2] fix: validate custom folders before launch --- dzgui/managers/offline.py | 10 +++++++++- dzgui/strings/offline.py | 1 + dzgui/views/pages/offline.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/dzgui/managers/offline.py b/dzgui/managers/offline.py index 5f49f09..0e50fe7 100644 --- a/dzgui/managers/offline.py +++ b/dzgui/managers/offline.py @@ -34,10 +34,18 @@ class OfflineManager: self.thread_man = ThreadingManager(controller) self.appid: int - self.mission_folder: str self.local_mods: list[str] | None self.custom_mods: list[str] | None + # TODO; more robust test + def is_custom_folder_valid(self, folder: str) -> bool: + return Path(folder).exists() + + # TODO: set properties as members of offline manager on demand and check them here + # rather than passing strings again + def is_mission_valid(self, folder: str) -> bool: + return is_mission(Path(folder)) + def get_mission(self) -> None: folder = self.open_folderpicker(dialogs.mission_dialog) if folder is None: diff --git a/dzgui/strings/offline.py b/dzgui/strings/offline.py index 875c574..3ee1202 100644 --- a/dzgui/strings/offline.py +++ b/dzgui/strings/offline.py @@ -13,6 +13,7 @@ local_frame = "Installed mods" no_local_mods = "No local mods found" no_mods = "No valid mods found" no_mission = "Not a valid mission" +folder_changed = "Folder missing or changed on disk" custom_eventbox = "Set the root folder. Mods must be in atomic folders and have a meta.cpp file at a minimum." mission_eventbox = "Select a single mission folder containing an init.c file." diff --git a/dzgui/views/pages/offline.py b/dzgui/views/pages/offline.py index fe20d5f..e10aa3e 100644 --- a/dzgui/views/pages/offline.py +++ b/dzgui/views/pages/offline.py @@ -38,6 +38,7 @@ if TYPE_CHECKING: class FolderError(Enum): NO_VALID_MODS = 1 NO_VALID_MISSION = 2 + FOLDER_CHANGED = 3 class PageHeading(Gtk.Label): @@ -65,6 +66,10 @@ class ErrorPopover(Gtk.Popover): prefix = offline.no_mods case FolderError.NO_VALID_MISSION: prefix = offline.no_mission + case FolderError.FOLDER_CHANGED: + prefix = offline.folder_changed + self.label.set_label(prefix) + return self.label.set_label(f"{prefix}: '{msg}'") @@ -105,6 +110,11 @@ class FolderHBox(HBox): self.pop.set_relative_to(self.button) self.pop.connect("unmap", lambda _: self.grab_focus()) + self.sidepop = ErrorPopover() + self.sidepop.set_position(Gtk.PositionType.BOTTOM) + self.sidepop.set_relative_to(self.scrolled_label) + self.sidepop.connect("unmap", lambda _: self.grab_focus()) + self.connect("map", self._on_map) self.connect("unmap", self._on_unmap) @@ -150,6 +160,10 @@ class FolderHBox(HBox): self.unset_button.show() def present_error(self, error: FolderError, msg: str) -> None: + if error == FolderError.FOLDER_CHANGED: + self.sidepop.set_label(error, msg) + self.sidepop.popup() + return self.folder = "" self.label.set_text("") self.unset_button.hide() @@ -300,6 +314,9 @@ class CustomModFrame(ModFrame): self.tree_vbox.hide() self.no_mods.hide() + def present_folder_changed(self, folder: str) -> None: + self.custom_hbox.present_error(FolderError.FOLDER_CHANGED, folder) + def present_error(self, folder: str) -> None: self.hide_tree() self.custom_hbox.present_error(FolderError.NO_VALID_MODS, folder) @@ -363,6 +380,9 @@ class MissionFrame(HeadingFrame): def get_mission(self) -> str: return self.mission_hbox.get_folder() + def present_folder_changed(self, folder: str) -> None: + self.mission_hbox.present_error(FolderError.FOLDER_CHANGED, folder) + class RadioFrame(HeadingFrame): def __init__(self, parent: OfflineLoader, controller: "Controller") -> None: @@ -482,4 +502,12 @@ class OfflineLoader(Gtk.Box): local_mods = self.local_frame.get_mods() custom_folder = self.custom_frame.get_folder() custom_mods = self.custom_frame.get_mods() + + if custom_folder and not self.offline_man.is_custom_folder_valid(custom_folder): + self.custom_frame.present_folder_changed(mission) + return + + if mission and not self.offline_man.is_mission_valid(mission): + self.mission_frame.present_folder_changed(mission) + return self.offline_man.launch(appid, mission, local_mods, custom_folder, custom_mods) From f4d065d766885364b7c9e3415510dbc41563311d Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Wed, 17 Jun 2026 22:13:17 +0900 Subject: [PATCH 2/2] fix: typo --- dzgui/managers/offline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dzgui/managers/offline.py b/dzgui/managers/offline.py index 0e50fe7..15d8ece 100644 --- a/dzgui/managers/offline.py +++ b/dzgui/managers/offline.py @@ -37,7 +37,7 @@ class OfflineManager: self.local_mods: list[str] | None self.custom_mods: list[str] | None - # TODO; more robust test + # TODO: more robust test def is_custom_folder_valid(self, folder: str) -> bool: return Path(folder).exists()