Compare commits

...
36 Commits
Author SHA1 Message Date
aclist 3c92108ac3 Merge pull request #468 from aclist/fix/wizard-config-exit
Mirror to Codeberg / mirror-to-codeberg (push) Has been cancelled
fix: write config later in install wizard
2026-08-29 16:21:57 +09:00
aclist 0f6f1c03ec chore: update changelog
Mirror to Codeberg / mirror-to-codeberg (push) Has been cancelled
2026-08-29 15:55:36 +09:00
aclist 39d8607f57 chore: drop unused code 2026-08-29 15:55:24 +09:00
aclist 64d784f9a0 fix: apply keyword filter when refreshing (#469) 2026-08-29 15:55:02 +09:00
aclist 667203b4f9 chore: clear typehinting errors
Mirror to Codeberg / mirror-to-codeberg (push) Waiting to run
2026-08-28 17:36:23 +09:00
aclist 00369837cb fix: support multiple user ids 2026-08-28 17:35:29 +09:00
aclist 9bc5964df2 chore: add XDG path conversion test 2026-08-28 16:58:44 +09:00
aclist b7b83b3ca5 chore: drop unused imports 2026-08-28 16:35:34 +09:00
aclist d04c20498a change: write config only on last page 2026-08-28 16:35:08 +09:00
aclist 572ac5d7ce chore: drop unused code 2026-08-28 16:07:06 +09:00
aclist b4125c5a51 change: change log level 2026-08-28 16:01:09 +09:00
aclist 8bae2d5fb5 chore: add log output when setting start tab 2026-08-28 16:00:14 +09:00
aclist a85c632902 change: namespace dlc strings 2026-08-28 15:52:15 +09:00
aclist 74ecc30692 feat: add badlands string support 2026-08-28 15:49:50 +09:00
aclist 33843becae chore: bump version 2026-08-28 15:49:19 +09:00
aclist 07cbf7a36a change: always show shortcuts page
Mirror to Codeberg / mirror-to-codeberg (push) Has been cancelled
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.
2026-08-26 16:55:25 +09:00
aclist 687c5ac168 chore: add comments 2026-08-25 20:09:56 +09:00
aclist f3fd7ef6ea change: revert prior changes 2026-08-25 20:09:02 +09:00
aclist 2383f7d2aa change: simplify method 2026-08-25 20:03:42 +09:00
aclist c839672f85 chore: clear typehinting errors 2026-08-25 20:03:32 +09:00
aclist ca234b8dea drop: unused imports 2026-08-25 19:58:37 +09:00
aclist 8e3ce72295 change: do not store pages linearly 2026-08-25 19:57:52 +09:00
aclist f02d959ebc change: write config later 2026-08-25 19:57:07 +09:00
aclist 04e9e5dcf0 Merge pull request #467 from aclist/change/baseline-cpu-arch
Mirror to Codeberg / mirror-to-codeberg (push) Has been cancelled
change: target baseline cpu architecture
2026-08-25 16:21:36 +09:00
aclist 1b06fcae42 change: target baseline cpu architecture 2026-08-25 16:20:48 +09:00
aclist 9759c39fd7 Merge pull request #466 from aclist/feat/color-aware-app
feat: color scheme aware app
2026-08-23 20:22:58 +09:00
aclist 4451eee849 docs: update changelog 2026-08-23 20:22:10 +09:00
aclist 3f587f64a0 chore: drop extraneous newline 2026-08-23 19:33:33 +09:00
aclist b00523661f chore: update exclusions 2026-08-23 19:30:10 +09:00
aclist f24b3574b8 chore: clear typehinting errors 2026-08-23 19:29:51 +09:00
aclist fad8d2f43b feat: add ColorAwareApp mixin (resolves #465) 2026-08-23 19:28:42 +09:00
aclist e1e034fffd chore: initialize and run app 2026-08-23 19:26:41 +09:00
aclist ea2ca684d6 chore: restructure as Gtk.Application and drop Gtk.main loop 2026-08-23 19:26:16 +09:00
aclist 2e2d3484c4 chore: drop unused imports 2026-08-23 19:24:06 +09:00
aclist 1254044ef8 chore: drop Gtk.main_quit call 2026-08-23 19:23:39 +09:00
aclist 7d651e9653 feat: add GIO property constants 2026-08-23 19:22:28 +09:00
29 changed files with 297 additions and 101 deletions

No files matched your search

+2
View File
@@ -51,6 +51,7 @@
- Update map count (-u flag)
- Filter button tooltips
- Expand/collapse changelog versions
- Support local light/dark mode changes on system theme
### Changed
- Conform to PEP 440 versioning for beta versions
@@ -89,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
+9 -4
View File
@@ -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.dlc_none
case 2:
dlc = strings.dlc_frostline
case 3:
dlc = strings.dlc_badlands
case _:
dlc = strings.unspecified
except AttributeError:
dlc = strings.unspecified
+16 -9
View File
@@ -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,18 @@ 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 = str(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
return last_user
except Exception as e:
logger.debug(e)
return None
+2 -1
View File
@@ -154,4 +154,5 @@ def load_gui(version: str, is_debug: bool) -> None:
use_miles=use_miles,
)
print(boot.all_ok)
App(prefs)
app = App(prefs)
app.run(None)
+6
View File
@@ -30,6 +30,7 @@ BETA_REPO = "testing"
APP_NAME = "DZGUI"
APP_NAME_LOWER = "dzgui"
APP_NAME_ABBR = "dzg"
GTK_APP_ID = "io.github.aclist.dzgui"
HEX_GREEN = "#32CD32"
HEX_RED = "#FF0000"
@@ -91,3 +92,8 @@ TMP_TARBALL = "/tmp/dzgui.tar.gz"
TMP_EXE = "/tmp/dzgui/dzgui"
DAYZ_COMMUNITY_ROOT = "Missions"
GIO_SETTINGS_INTERFACE = "org.gnome.desktop.interface"
GIO_SETTINGS_PROP = "color-scheme"
GIO_SETTINGS_KEY = "gtk-application-prefer-dark-theme"
GIO_SETTINGS_VAL = "prefer-dark"
+1
View File
@@ -523,6 +523,7 @@ class Controller(GObject.GObject):
def set_start_tab(self) -> None:
ind = self.config_man.get_start_tab()
logger.info(f"Setting start tab to index {ind}")
self.get_servers().notebook.set_current_page(ind)
def get_debug_args(self) -> str:
+2
View File
@@ -51,6 +51,7 @@
- Update map count (-u flag)
- Filter button tooltips
- Expand/collapse changelog versions
- Support local light/dark mode changes on system theme
### Changed
- Conform to PEP 440 versioning for beta versions
@@ -89,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
+3 -3
View File
@@ -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) -> 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:
+8 -7
View File
@@ -19,11 +19,6 @@ from dzgui.views.dialogs.generic import ExceptionDialog
from dzgui.strings import dialogs
from dzgui.util._json import read_json, write_json
import gi
gi.require_version("Gtk", "3.0")
from gi.repository.Gtk import main_quit # noqa E402
if TYPE_CHECKING:
from dzgui.config.userprefs import UserPrefs
from dzgui.controllers.mc import Controller
@@ -206,7 +201,10 @@ class ConfigManager:
logger.info("Normal user exit")
if window.props.is_maximized:
main_quit()
app = window.get_application()
if app is None:
return
app.quit()
return
w, h = window.get_size()
@@ -218,7 +216,10 @@ class ConfigManager:
except Exception as e:
logger.critical(e)
main_quit()
app = window.get_application()
if app is None:
return
app.quit()
def set_resolution(self, window: "OuterWindow") -> None:
if self.prefs.is_game_mode:
-5
View File
@@ -1,4 +1,3 @@
import gi
import logging
from typing import TYPE_CHECKING
@@ -14,10 +13,6 @@ from dzgui.views.trees.tree_servers import ServerTreeView
from dzgui.views.trees.tree_server_mods import ServerModTreeView
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GLib, GObject # noqa E402
logger = logging.getLogger(APP_NAME)
if TYPE_CHECKING:
+3 -5
View File
@@ -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 = []
@@ -298,4 +294,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)
-1
View File
@@ -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
+1 -9
View File
@@ -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:
@@ -127,10 +126,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
+2 -1
View File
@@ -168,11 +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"
+20 -10
View File
@@ -2,9 +2,14 @@ import logging
import signal
import warnings
from typing import TYPE_CHECKING, Literal
from typing import TYPE_CHECKING, Literal, Self
from dzgui.const.constants import APP_NAME, APP_NAME_LOWER, STEAM_ICON
from dzgui.const.constants import (
APP_NAME,
APP_NAME_LOWER,
GTK_APP_ID,
STEAM_ICON,
)
from dzgui.const.enum import NotebookPage
from dzgui.controllers.emitter import Emitter
from dzgui.controllers.mc import Controller
@@ -14,6 +19,7 @@ from dzgui.views.components.connect_panel import ConnectPanel
from dzgui.views.components.crumbs import Breadcrumbs
from dzgui.views.components.right_panel import RightPanel
from dzgui.views.components.statusbar import Statusbar
from dzgui.views.mixins.colorscheme import ColorAwareApp
from dzgui.views.mixins.scrollable_mixin import ScrollableMixin
# TODO: import notebook only and add components there?
@@ -46,9 +52,11 @@ logger = logging.getLogger(APP_NAME)
warnings.filterwarnings("ignore", ".*g_value_get_int", Warning)
class OuterWindow(Gtk.Window):
def __init__(self) -> None:
super().__init__(title=APP_NAME, border_width=10, icon_name=APP_NAME_LOWER)
class OuterWindow(Gtk.ApplicationWindow):
def __init__(self, app: Gtk.Application) -> None:
super().__init__(
application=app, title=APP_NAME, border_width=10, icon_name=APP_NAME_LOWER
)
self.hb = AppHeaderBar()
MainController.register_widget("window", self)
@@ -279,13 +287,18 @@ class Grid(Gtk.Grid):
self.right_panel.refresh_button.set_visible(state)
class App(Gtk.Application):
class App(ColorAwareApp, Gtk.Application): # type: ignore
def __init__(self, prefs: "UserPrefs") -> None:
super().__init__(application_id=GTK_APP_ID)
GLib.set_prgname(APP_NAME)
MainController.set_prefs(prefs)
self.win = OuterWindow()
self._setup_signals()
self.connect("activate", self._on_activate)
def _on_activate(self, app: Self) -> None:
self.win = OuterWindow(app)
accel = Gtk.AccelGroup()
accel.connect(
@@ -296,9 +309,6 @@ class App(Gtk.Application):
)
self.win.add_accel_group(accel)
self._setup_signals()
Gtk.main()
def _setup_signals(self) -> None:
SIGNAL_ADD = "signal_add"
SIGNAL_ADD_FULL = "signal_add_full"
+4 -1
View File
@@ -4,6 +4,9 @@ from typing import Any, Literal, Self, TYPE_CHECKING
# import time
from enum import Enum
from dzgui.views.mixins.colorscheme import ColorAwareApp
# TODO: import dialog titles
from dzgui.api.mods import remove_stale_signatures as remove_stale
from dzgui.config.ipdb import get_ipdb
@@ -37,7 +40,7 @@ class Success(Enum):
# TODO: strings for "Running", "Failed", etc.
# TODO: add margins to tree
class BootDialog(Gtk.Dialog):
class BootDialog(ColorAwareApp, Gtk.Dialog): # type: ignore
def __init__(self, parent: "BootWindow", xdg: "Xdg", version: str) -> None:
super().__init__(
title=dialog_header,
+2 -1
View File
@@ -3,6 +3,7 @@ import sys
from typing import Self
from dzgui.util.strings import dialog_error, dialog_header
from dzgui.views.mixins.colorscheme import ColorAwareApp
import gi
@@ -10,7 +11,7 @@ gi.require_version("Gtk", "3.0")
from gi.repository import Gtk # noqa E402
class AbortDialog(Gtk.MessageDialog):
class AbortDialog(ColorAwareApp, Gtk.MessageDialog): # type: ignore
def __init__(self, string: str, buttons: Gtk.ButtonsType) -> None:
super().__init__(
title=dialog_header,
+2 -1
View File
@@ -13,6 +13,7 @@ from dzgui.util.css import load_css
from dzgui.util.format import format_exception
from dzgui.views.components.box import HBox
from dzgui.views.dialogs.wizard import ScrolledWizardPage, CheckboxWithLabel
from dzgui.views.mixins.colorscheme import ColorAwareApp
import gi
@@ -217,7 +218,7 @@ class UninstallPage(ScrolledWizardPage):
pass
class UninstallWizard(Gtk.Application):
class UninstallWizard(ColorAwareApp, Gtk.Application): # type: ignore
def __init__(self, is_deck: bool, paths: dict[str, str]) -> None:
super().__init__()
config = Path(paths["XDG_CONFIG_HOME"])
+42 -39
View File
@@ -1,4 +1,3 @@
import os
import textwrap
from enum import Enum
@@ -17,9 +16,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
@@ -29,6 +26,7 @@ from dzgui.util.css import add_class, load_css
from dzgui.views.components.buttons import WebButton
from dzgui.views.components.entry import APIEntry
from dzgui.views.components.misc import ClientCombo
from dzgui.views.mixins.colorscheme import ColorAwareApp
import gi
@@ -304,6 +302,7 @@ class ConfigMigrationPage(EnumeratedWizardPage):
)
self.migrated = False
self.migrated_conf: dict[str, Any] = {}
self.config = config
self.page_type = Gtk.AssistantPageType.INTRO
@@ -343,8 +342,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:
@@ -436,20 +434,18 @@ 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
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)
@@ -457,16 +453,18 @@ 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 (
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 (
@@ -474,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)
@@ -485,8 +481,11 @@ 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:
return self.pages[self.page_shortcuts]
def _advance_page(self, index: int) -> int:
page = self.get_nth_page(index)
@@ -495,24 +494,23 @@ 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
self.setup_complete = True
return self.get_n_pages() - offset
sp = page.migrated_conf["default_steam_path"]
self.page_shortcuts.set_steam_path(sp)
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()
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.setup_complete = True
self.page_shortcuts.set_steam_path(
self.config_values["default_steam_path"]
)
case ShortcutCreationPage():
page.create_shortcuts()
case _:
@@ -542,11 +540,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
@@ -563,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:
@@ -706,7 +709,7 @@ class SteamPathPage(EnumeratedWizardPage):
self.err_box.set_visible(False)
class SetupWizard(Gtk.Application):
class SetupWizard(ColorAwareApp, Gtk.Application): # type: ignore
def __init__(self, is_deck: bool, XDG: "Xdg") -> None:
super().__init__()
GLib.set_prgname(APP_NAME)
+37
View File
@@ -0,0 +1,37 @@
from typing import Any
from dzgui.const.constants import (
GIO_SETTINGS_KEY,
GIO_SETTINGS_INTERFACE,
GIO_SETTINGS_PROP,
GIO_SETTINGS_VAL,
)
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gio # noqa
class ColorAwareApp:
"""
Polls the local theme's color scheme settings.
Intended to be consumed by Gtk.Applications (or ephemeral widgets like EarlyAlertDialogs)
on initialization, prior to being realized. Applying scheme changes too late in the chain
may cause a blinking effect.
"""
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.interface_settings = Gio.Settings.new(GIO_SETTINGS_INTERFACE)
self.interface_settings.connect(
"changed::color-scheme", self._on_color_scheme_changed
)
self.default_settings = Gtk.Settings.get_default()
self._on_color_scheme_changed(self.interface_settings, GIO_SETTINGS_PROP)
def _on_color_scheme_changed(self, settings: Gio.Settings, prop: str) -> None:
state = self.interface_settings.get_string(prop) == GIO_SETTINGS_VAL
if self.default_settings is None:
return
self.default_settings.set_property(GIO_SETTINGS_KEY, state)
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -27,7 +27,7 @@ def fetch(url: str, destination: str) -> None:
def get_cpython() -> None:
source = f"https://github.com/astral-sh/python-build-standalone/releases/download/{DATE}/"
build = f"{CPYTHON_BUILD}%2B{DATE}-x86_64_v3-unknown-linux-gnu-install_only_stripped.tar.gz"
build = f"{CPYTHON_BUILD}%2B{DATE}-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz"
url = f"{source}{build}"
outfile = unquote(build)
fetch(url, outfile)
+12 -1
View File
@@ -1,12 +1,23 @@
from pathlib import Path
def iterate(search_str: str) -> None:
# TODO: exclude files from .gitignore
print()
print(f"Searching for '{search_str}'")
print()
files = Path(".").rglob("*")
ignore = [".git", ".mypy", "build/", "test.py"]
ignore = [
"scripts/",
".git",
"egg",
"CHANGELOG",
".mypy",
"build/",
"test.py",
"bugs",
"pyproject.toml",
]
for file in files:
if file.is_dir():
continue
+23
View File
@@ -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"
}
}
@@ -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"
}
}
+1 -1
View File
@@ -20,6 +20,6 @@
"SkipOfflineModeWarning" "0"
"AllowAutoLogin" "1"
"MostRecent" "1"
"Timestamp" "0"
"Timestamp" "10"
}
}
+59
View File
@@ -0,0 +1,59 @@
import pytest
import subprocess
from dzgui.const.constants import GIO_SETTINGS_KEY
from dzgui.views.mixins.colorscheme import ColorAwareApp
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gio, GLib # noqa
class TestWidget(ColorAwareApp, Gtk.Button):
def __init__(self) -> None:
super().__init__()
self.state: bool
def check_theme(self) -> None:
self.state = self.get_settings().get_property(GIO_SETTINGS_KEY)
Gtk.main_quit()
@pytest.fixture
def widget() -> TestWidget:
return TestWidget()
@pytest.mark.integration
@pytest.mark.parametrize("key, expect", [("default", False), ("prefer-dark", True)])
def test_light_mode(widget, key: str, expect: bool) -> None:
local_pref = subprocess.run(
["gsettings", "get", "org.gnome.desktop.interface", "color-scheme"],
capture_output=True,
text=True,
).stdout
subprocess.run(
[
"gsettings",
"set",
"org.gnome.desktop.interface",
"color-scheme",
key,
],
)
# NOTE: allow changes to propagate
GLib.idle_add(widget.check_theme)
Gtk.main()
subprocess.run(
[
"gsettings",
"set",
"org.gnome.desktop.interface",
"color-scheme",
local_pref,
]
)
assert widget.state is expect
+2
View File
@@ -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:
+13
View File
@@ -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")