Compare commits

..
1 Commits
Author SHA1 Message Date
aclist 9354ed7df5 Merge fb36425083 into d3f64c1ba5 2026-05-18 21:24:02 +00:00
22 changed files with 38 additions and 95 deletions

No files matched your search

+1
View File
@@ -11,3 +11,4 @@ uv.lock
.coverage .coverage
pyapp-latest/ pyapp-latest/
dist/ dist/
cpython
-1
View File
@@ -34,7 +34,6 @@
- Early load alerts button - Early load alerts button
- Preconnect dialog - Preconnect dialog
- Preconnect warnings/failsafes like filesize - Preconnect warnings/failsafes like filesize
- Save filters per server context between sessions
## Changed ## Changed
+3 -3
View File
@@ -1,14 +1,14 @@
# TODO: link to here from sphinx docs # TODO: link to here from sphinx docs
# Installing dev dependencies
uv pip install -e .[dev]
# Setting up precommit hooks # Setting up precommit hooks
pre-commit install pre-commit install
# Fetching submodules # Fetching submodules
git submodule update --recursive --init git submodule update --recursive --init
# Installing dev dependencies
uv pip install -e .[dev]
# Building documentation # Building documentation
sphinx-build -M html source build -a sphinx-build -M html source build -a
+1 -2
View File
@@ -106,7 +106,7 @@ class A2SInfo:
def get_netmask() -> str: def get_netmask() -> str:
hostname = os.uname()[1] hostname = os.uname()[1]
i = socket.gethostbyname(f"{hostname}.local") i = socket.gethostbyname(hostname)
netmask = i.rsplit(".", 1)[0] netmask = i.rsplit(".", 1)[0]
return netmask return netmask
@@ -472,7 +472,6 @@ def query_by_ip(addr: str) -> A2SInfo:
return A2SInfo(Record("0", 0, 0), None) return A2SInfo(Record("0", 0, 0), None)
return query_by_record(record, update_gameport=True) return query_by_record(record, update_gameport=True)
def query_by_id(server_id: int, key: str) -> A2SInfo: def query_by_id(server_id: int, key: str) -> A2SInfo:
""" """
Used with numeric Battlemetrics IDs Used with numeric Battlemetrics IDs
+3 -3
View File
@@ -17,7 +17,6 @@ class Xdg:
system: Path system: Path
debug: Path debug: Path
ips: Path ips: Path
filters: Path
def is_writeable(path_str: str) -> bool: def is_writeable(path_str: str) -> bool:
@@ -64,6 +63,9 @@ def get_xdg_paths() -> dict:
def parse_filepaths(xdg: dict) -> Xdg: def parse_filepaths(xdg: dict) -> Xdg:
# cache = xdg["XDG_CACHE_HOME"]
# data = xdg["XDG_DATA_HOME"]
config = xdg["XDG_CONFIG_HOME"] config = xdg["XDG_CONFIG_HOME"]
state = xdg["XDG_STATE_HOME"] state = xdg["XDG_STATE_HOME"]
@@ -78,7 +80,6 @@ def parse_filepaths(xdg: dict) -> Xdg:
history = state / "dzg.history" history = state / "dzg.history"
versions = state / "dzg.versions" versions = state / "dzg.versions"
ips = state / "ips.csv" ips = state / "ips.csv"
filters = state / "dzg.filters.json"
return Xdg( return Xdg(
config, config,
@@ -90,5 +91,4 @@ def parse_filepaths(xdg: dict) -> Xdg:
system, system,
debug, debug,
ips, ips,
filters
) )
-4
View File
@@ -12,7 +12,6 @@ if TYPE_CHECKING:
# TODO: if servers fail to load, may leave dangling widgets waiting for a signal # TODO: if servers fail to load, may leave dangling widgets waiting for a signal
class Emitter(GObject.GObject): class Emitter(GObject.GObject):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
@@ -151,6 +150,3 @@ class Emitter(GObject.GObject):
def keyword_set(self, keyword: str) -> None: def keyword_set(self, keyword: str) -> None:
pass pass
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=())
def lan_page_initialized(self) -> None:
pass
-28
View File
@@ -260,21 +260,6 @@ class Controller(GObject.GObject):
def select_colorized(self) -> None: def select_colorized(self) -> None:
self.mod_man.select_colorized() self.mod_man.select_colorized()
def get_all_tree_filters(self) -> dict[str, dict[str, bool]]:
servers = self.get_servers()
all_filters: dict[str, dict[str, bool]] = {}
trees = (
servers.get_browser(),
servers.get_saved(),
servers.get_recent(),
servers.get_lan(),
)
for tree in trees:
enum = str(tree.get_enum())
filters = tree.get_filter_man().get_filters()
all_filters[enum] = filters
return all_filters
def get_filter_man(self) -> "FilterManager": def get_filter_man(self) -> "FilterManager":
"""Each ServerTreeView has an atomic FilterManager""" """Each ServerTreeView has an atomic FilterManager"""
return self.get_active_treeview().get_filter_man() return self.get_active_treeview().get_filter_man()
@@ -318,21 +303,8 @@ class Controller(GObject.GObject):
self.emitter.emit("servers_loaded", tv.get_enum()) self.emitter.emit("servers_loaded", tv.get_enum())
return return
self.mediator.statusbar.set_by_context(tv.get_enum(), "") self.mediator.statusbar.set_by_context(tv.get_enum(), "")
self.mediator.filters.button_grid.block_toggles(True)
self.populate_filter_prefs()
self.mediator.filters.button_grid.block_toggles(False)
ServerModelManager(self, tv).load() ServerModelManager(self, tv).load()
def populate_filter_prefs(self) -> None:
tv = self.get_active_treeview()
filters = self.config_man.get_filters(tv)
if filters is None:
return
filter_man = self.get_filter_man()
for filt, state in filters.items():
filter_man.set_filter(filt, state)
self.mediator.filters.set_filters(filters)
def get_dist_cache(self) -> dict[str, "Haversine"]: def get_dist_cache(self) -> dict[str, "Haversine"]:
return self.dist_cache return self.dist_cache
-1
View File
@@ -34,7 +34,6 @@
- Early load alerts button - Early load alerts button
- Preconnect dialog - Preconnect dialog
- Preconnect warnings/failsafes like filesize - Preconnect warnings/failsafes like filesize
- Save filters per server context between sessions
## Changed ## Changed
+1 -13
View File
@@ -22,6 +22,7 @@ import gi
gi.require_version("Gtk", "3.0") gi.require_version("Gtk", "3.0")
from gi.repository.Gtk import main_quit # noqa E402 from gi.repository.Gtk import main_quit # noqa E402
# import dzgui.api.servers as Servers
if TYPE_CHECKING: if TYPE_CHECKING:
from dzgui.config.userprefs import UserPrefs from dzgui.config.userprefs import UserPrefs
from dzgui.controllers.mc import Controller from dzgui.controllers.mc import Controller
@@ -159,9 +160,6 @@ class ConfigManager:
def save_res_and_quit(self, tv: "ServerTreeView", window: "OuterWindow") -> None: def save_res_and_quit(self, tv: "ServerTreeView", window: "OuterWindow") -> None:
columns = tv.get_columns() columns = tv.get_columns()
filters = self.controller.get_all_tree_filters()
filters_file = self.prefs.paths.filters
columns_file = self.prefs.paths.columns columns_file = self.prefs.paths.columns
try: try:
data = read_json(columns_file) data = read_json(columns_file)
@@ -176,7 +174,6 @@ class ConfigManager:
try: try:
write_json(data, columns_file) write_json(data, columns_file)
write_json(filters, filters_file)
except Exception as e: except Exception as e:
logger.critical(e) logger.critical(e)
@@ -220,12 +217,3 @@ class ConfigManager:
h = WINDOW_DEFAULT_Y h = WINDOW_DEFAULT_Y
logger.info(f"Using default window size {w},{h}") logger.info(f"Using default window size {w},{h}")
window.set_default_size(w, h) window.set_default_size(w, h)
def get_filters(self, tv: "ServerTreeView") -> Any | None:
filters = self.prefs.paths.filters
try:
enum = tv.get_enum()
filters = read_json(filters)
return filters[str(enum)]
except Exception:
return None
+7 -11
View File
@@ -73,7 +73,6 @@ class ServerModelManager:
self._dump_history() self._dump_history()
case ServerTab.LAN: case ServerTab.LAN:
# NOTE: LAN tab is only loaded on demand # NOTE: LAN tab is only loaded on demand
self.emitter.emit("lan_page_initialized")
pass pass
case _: case _:
pass pass
@@ -124,10 +123,8 @@ class ServerModelManager:
parsed = Servers.parse_json(servers) parsed = Servers.parse_json(servers)
self._push_data(parsed) self._push_data(parsed)
@call_on_thread(dialog.scanning, show_cancel=True) @call_on_thread(dialog.scanning)
def dump_lan(self, port: int, early_abort: bool) -> None: def dump_lan(self, port: int, early_abort: bool) -> None:
self.first_iteration = True
servers = [] servers = []
ports = range(1, 256) ports = range(1, 256)
failure_func = StoredFunc(self._cleanup_on_failure) failure_func = StoredFunc(self._cleanup_on_failure)
@@ -138,20 +135,19 @@ class ServerModelManager:
for future in as_completed(futures): for future in as_completed(futures):
try: try:
if self.controller.get_exit_event().is_set(): if self.controller.get_exit_event().is_set():
event.set()
return
if self.controller.get_cancel_event().is_set():
event.set()
self.controller.clear_cancel_event()
return return
res = future.result(timeout=LAN_TIMEOUT) res = future.result(timeout=LAN_TIMEOUT)
if res is None: if res is None:
continue continue
servers.append(res)
if early_abort is True: if early_abort is True:
# NOTE: on first non-empty hit, flag pending threads to close # NOTE: on first non-empty hit, flag pending threads to close
event.set() event.set()
break servers.append(res)
self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_success)
)
return
servers.append(res)
except Exception as e: except Exception as e:
logger.critical(e) logger.critical(e)
self.thread_man.set_cleanup_func(failure_func, destroy_first=True) self.thread_man.set_cleanup_func(failure_func, destroy_first=True)
+4 -2
View File
@@ -2,13 +2,15 @@ import json
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
def read_json(path: Path) -> Any: def read_json(path: Path) -> Any:
try: try:
with open(path, "r") as infile: with open(path, "r") as infile:
try:
data = json.load(infile) data = json.load(infile)
return data return data
except Exception as e: except json.decoder.JSONDecodeError as e:
raise e
except OSError as e:
raise e raise e
+1 -1
View File
@@ -101,7 +101,7 @@ build_corrupted = (
"Steam settings or DayZ installation may be corrupted. Try restarting Steam." "Steam settings or DayZ installation may be corrupted. Try restarting Steam."
) )
api_warn_msg = """No servers returned. Please wait and try again. api_warn_msg = """No servers returned. Please wait and try again.
This usually indicates a transitory network timeout. If this issue persists, your API key or network may be malfunctioning. If this issue persists, your API key may be defunct or your network is blocking requests.
""" """
server_timeout = "Timed out when querying server, check IP or try again later." server_timeout = "Timed out when querying server, check IP or try again later."
server_error = ( server_error = (
+1 -1
View File
@@ -262,8 +262,8 @@ class Grid(Gtk.Grid):
self.emitter.connect("server_page_toggled", self.toggle_filter_panels) self.emitter.connect("server_page_toggled", self.toggle_filter_panels)
# TODO: drop, use map/signal
def hide_widgets_on_init(self) -> None: def hide_widgets_on_init(self) -> None:
self.conpan.set_lan_visible(False)
self.right_panel.sel_panel.hide() self.right_panel.sel_panel.hide()
def toggle_filter_panels(self, emitter: "Emitter", state: bool) -> None: def toggle_filter_panels(self, emitter: "Emitter", state: bool) -> None:
+4 -2
View File
@@ -278,7 +278,9 @@ class ConnectPanel(Gtk.Box):
for el in self.lan, self.fav, self.add_panel: for el in self.lan, self.fav, self.add_panel:
self.add(el) self.add(el)
self.lan.set_visible(False)
def set_lan_visible(self, state: bool) -> None:
self.lan.set_visible(state)
def _on_lan_tab_toggled(self, emitter: "Emitter", state: bool) -> None: def _on_lan_tab_toggled(self, emitter: "Emitter", state: bool) -> None:
self.lan.set_visible(state) self.set_lan_visible(state)
-6
View File
@@ -68,7 +68,6 @@ class ButtonGrid(Gtk.Grid):
) )
def reload_filters(self) -> None: def reload_filters(self) -> None:
# TODO: may be superfluous
checkboxes = self.checks checkboxes = self.checks
self.block_toggles(True) self.block_toggles(True)
filters = self.controller.get_enabled_filters() filters = self.controller.get_enabled_filters()
@@ -331,8 +330,3 @@ class FilterPanel(Gtk.Box):
self.block_map_change_propagation = False self.block_map_change_propagation = False
return return
self.emitter.emit("map_selection_changed", name) self.emitter.emit("map_selection_changed", name)
def set_filters(self, filters: dict[str, bool]) -> None:
for check in self.button_grid.checks:
label = check.get_label()
check.set_active(filters[label])
+1 -7
View File
@@ -52,7 +52,6 @@ class RightPanel(Gtk.Box):
emitter = controller.get_emitter() emitter = controller.get_emitter()
emitter.connect("servers_loaded", self._on_servers_loaded) emitter.connect("servers_loaded", self._on_servers_loaded)
emitter.connect("server_page_changed", self._on_server_page_changed) emitter.connect("server_page_changed", self._on_server_page_changed)
emitter.connect("lan_page_initialized", self._on_lan_page_init)
self.button_vbox = ButtonBox(controller) self.button_vbox = ButtonBox(controller)
self.filters_vbox = FilterPanel(controller) self.filters_vbox = FilterPanel(controller)
@@ -153,15 +152,10 @@ class RightPanel(Gtk.Box):
return return
self.filters_vbox.set_sensitive(False) self.filters_vbox.set_sensitive(False)
def _on_lan_page_init(self, emitter: "Emitter") -> None:
self.filters_vbox.set_sensitive(False)
self.refresh_button.set_sensitive(False)
def _on_servers_loaded(self, emitter: "Emitter", context: "ServerTab") -> None: def _on_servers_loaded(self, emitter: "Emitter", context: "ServerTab") -> None:
# TODO: similar logic on notebook page change # TODO: similar logic on notebook page change
state = self.controller.has_server_model() state = self.controller.has_server_model()
for el in self.filters_vbox, self.refresh_button: self.filters_vbox.set_sensitive(state)
el.set_sensitive(state)
def _on_version_clicked(self, widget: Gtk.EventBox, event: Gdk.EventButton) -> None: def _on_version_clicked(self, widget: Gtk.EventBox, event: Gdk.EventButton) -> None:
def revert() -> Literal[False]: def revert() -> Literal[False]:
+2 -2
View File
@@ -111,9 +111,9 @@ class Statusbar(Gtk.Grid):
context: Union["ServerTab", NotebookPage], context: Union["ServerTab", NotebookPage],
) -> None: ) -> None:
self.spinner.stop() self.spinner.stop()
# FIXME: CalcDist is being called when table is not loaded # TODO: CalcDist is being called when table is not loaded
if dist is None: if dist is None:
return self.set_by_context(context, "")
else: else:
pretty = self.append_distance(dist) pretty = self.append_distance(dist)
self.set_by_context(context, pretty) self.set_by_context(context, pretty)
+2 -2
View File
@@ -11,5 +11,5 @@ class ModsMixin:
self, tree: TreeView, path: Gtk.TreePath, column: Gtk.TreeViewColumn self, tree: TreeView, path: Gtk.TreePath, column: Gtk.TreeViewColumn
) -> None: ) -> None:
mod = self.get_value_at_index(2) # type: ignore path = self.get_focused_row_path() # type: ignore
self.controller.open_workshop_page(mod) # type: ignore self.controller.open_mod_page(path) # type: ignore
+1 -1
View File
@@ -17,7 +17,7 @@ from dzgui.views.trees.tree_server_mods import ServerModTreeView
import gi import gi
gi.require_version("Gtk", "3.0") gi.require_version("Gtk", "3.0")
from gi.repository import Gdk, Gtk # noqa E402 from gi.repository import Gdk, Gtk # type: ignore # noqa E402
if TYPE_CHECKING: if TYPE_CHECKING:
+4 -2
View File
@@ -162,8 +162,8 @@ class ServerTreeView(ContextMixin, TreeView): # type: ignore
def _on_map(self, widget: Self) -> None: def _on_map(self, widget: Self) -> None:
# TODO: disable filter panel if current model is None # TODO: disable filter panel if current model is None
state = self.get_enum() is ServerTab.LAN if self.get_enum() is ServerTab.LAN:
self.emitter.emit("lan_tab_toggled", state) self.emitter.emit("lan_tab_toggled", True)
store = self.filter_man.get_map_store() store = self.filter_man.get_map_store()
@@ -178,6 +178,8 @@ class ServerTreeView(ContextMixin, TreeView): # type: ignore
# NOTE: removes queue checker for this tab # NOTE: removes queue checker for this tab
GLib.Source.remove(self.queue_id) GLib.Source.remove(self.queue_id)
self.emitter.disconnect(self.handler_id) self.emitter.disconnect(self.handler_id)
if self.get_enum() is ServerTab.LAN:
self.emitter.emit("lan_tab_toggled", False)
def _on_col_width_changed( def _on_col_width_changed(
self, col: Gtk.TreeViewColumn, width: GObject.ParamSpecInt self, col: Gtk.TreeViewColumn, width: GObject.ParamSpecInt
+1 -1
View File
@@ -4,7 +4,7 @@ description = "DayZ server browser and mod manager for Linux"
authors = [ authors = [
{name = "aclist"} {name = "aclist"}
] ]
version = "7.0.0b4" version = "7.0.0b3"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
license-files = ["LICENSE"] license-files = ["LICENSE"]
readme = "README.md" readme = "README.md"
+1 -2
View File
@@ -9,7 +9,6 @@ root = Path(__file__).resolve().parents[1]
output = root.joinpath("dist") output = root.joinpath("dist")
pyapp_dir = root.joinpath("pyapp-latest") pyapp_dir = root.joinpath("pyapp-latest")
cpython = root.joinpath("build/cpython/airgapped.tar.gz")
builder = build.ProjectBuilder(root) builder = build.ProjectBuilder(root)
wheel = builder.build("wheel", output_directory=output) wheel = builder.build("wheel", output_directory=output)
@@ -34,7 +33,7 @@ env["PYAPP_PASS_LOCATION"] = "true"
env["PYAPP_SKIP_INSTALL"] = "true" env["PYAPP_SKIP_INSTALL"] = "true"
env["PYAPP_DISTRIBUTION_EMBED"] = "true" env["PYAPP_DISTRIBUTION_EMBED"] = "true"
env["PYAPP_FULL_ISOLATION"] = "true" env["PYAPP_FULL_ISOLATION"] = "true"
env["PYAPP_DISTRIBUTION_PATH"] = str(cpython) env["PYAPP_DISTRIBUTION_PATH"] = "cpython/airgapped.tar.gz"
env["PYAPP_DISTRIBUTION_PYTHON_PATH"] = "python/bin/python3" env["PYAPP_DISTRIBUTION_PYTHON_PATH"] = "python/bin/python3"
proc = subprocess.run(["cargo", "build", "--release"], env=env, cwd=pyapp_dir) proc = subprocess.run(["cargo", "build", "--release"], env=env, cwd=pyapp_dir)