mirror of
https://github.com/aclist/dztui.git
synced 2026-08-28 18:57:12 +02:00
feat: MaskedTree (WIP)
This commit is contained in:
parent
b42aea1e02
commit
a9863ff86b
@ -116,7 +116,8 @@ def _hash(uid: str) -> str:
|
|||||||
|
|
||||||
def remove_stale_signatures(config: Path, versions: Path) -> None:
|
def remove_stale_signatures(config: Path, versions: Path) -> None:
|
||||||
if versions.is_file() is False:
|
if versions.is_file() is False:
|
||||||
logger.warning("No mod signatures file found")
|
logger.warning("Creating new version signatures file")
|
||||||
|
versions.touch()
|
||||||
return
|
return
|
||||||
path = lookup(config, Preferences.DEFAULT)
|
path = lookup(config, Preferences.DEFAULT)
|
||||||
steam_path = Path(path)
|
steam_path = Path(path)
|
||||||
|
|||||||
@ -31,3 +31,7 @@
|
|||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.masked-tree {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|||||||
@ -70,18 +70,19 @@ class ConnectionManager:
|
|||||||
version_file = self.controller.get_prefs().paths.version
|
version_file = self.controller.get_prefs().paths.version
|
||||||
needs_update = get_needs_update(version_file, hashes)
|
needs_update = get_needs_update(version_file, hashes)
|
||||||
|
|
||||||
# TODO: populate version file at boot if nonexistent (after symlinking)
|
# TODO: store mods that need update in class object for referencing later
|
||||||
|
# TODO: store remote destination to connect to
|
||||||
|
|
||||||
# missing mods should be the totality of all mods with no signature
|
# missing mods should be the totality of all mods with no signature
|
||||||
# missing = get_missing_mods(local_mod_ids, remote_mod_ids)
|
# missing = get_missing_mods(local_mod_ids, remote_mod_ids)
|
||||||
# print(missing)
|
# print(missing)
|
||||||
|
# TODO: when downloading mods, create symlinks if missing
|
||||||
# TODO: when updating, create symlinks of everything
|
|
||||||
# contains id and signature
|
|
||||||
|
|
||||||
# TODO: get missing mod sizes, warn if not enough space
|
# TODO: get missing mod sizes, warn if not enough space
|
||||||
info = res.source
|
info = res.source
|
||||||
try:
|
try:
|
||||||
dayz_path = PeFile.get_pefile_path(steam_path, info.game_id)
|
dayz_path = PeFile.get_pefile_path(steam_path, info.game_id)
|
||||||
|
# TODO: handle missing path; do not calculate size if appid is missing
|
||||||
total, used, free = shutil.disk_usage(dayz_path)
|
total, used, free = shutil.disk_usage(dayz_path)
|
||||||
if len(needs_update) > 0:
|
if len(needs_update) > 0:
|
||||||
# TODO: generic mib function
|
# TODO: generic mib function
|
||||||
@ -97,8 +98,9 @@ class ConnectionManager:
|
|||||||
self.thread_man.set_cleanup_func(failure_func, destroy_first=True)
|
self.thread_man.set_cleanup_func(failure_func, destroy_first=True)
|
||||||
|
|
||||||
# TODO: number separator func
|
# TODO: number separator func
|
||||||
# TODO: pack a final PreReq struct with pre-process values
|
# TODO: pack a final PreReq struct with pre-processed values
|
||||||
|
|
||||||
|
# TODO: connection assistant only receives user-facing warnings and list of mods
|
||||||
func = StoredFunc(self.controller.open_connection_assistant, res, remote_mods)
|
func = StoredFunc(self.controller.open_connection_assistant, res, remote_mods)
|
||||||
self.thread_man.set_cleanup_func(func, destroy_first=True)
|
self.thread_man.set_cleanup_func(func, destroy_first=True)
|
||||||
|
|
||||||
@ -154,3 +156,11 @@ class ConnectionManager:
|
|||||||
def _server_timeout(self) -> None:
|
def _server_timeout(self) -> None:
|
||||||
dialog = ExceptionDialog(self.controller, server_timeout)
|
dialog = ExceptionDialog(self.controller, server_timeout)
|
||||||
dialog.run()
|
dialog.run()
|
||||||
|
|
||||||
|
def update_mods(self) -> None:
|
||||||
|
# self.needs_update
|
||||||
|
pass
|
||||||
|
|
||||||
|
def connect(self) -> None:
|
||||||
|
# steam api, concat mods
|
||||||
|
pass
|
||||||
|
|||||||
@ -20,7 +20,7 @@ from gi.repository import Gtk, GLib # noqa E402
|
|||||||
logger = logging.getLogger(APP_NAME)
|
logger = logging.getLogger(APP_NAME)
|
||||||
|
|
||||||
|
|
||||||
def call_on_thread(dialog_str: str) -> Callable:
|
def call_on_thread(dialog_str: str, show_dialog: bool = True) -> Callable:
|
||||||
def decorator(func: Callable) -> Callable:
|
def decorator(func: Callable) -> Callable:
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapper(*args: Any, **kwargs: Any) -> None:
|
def wrapper(*args: Any, **kwargs: Any) -> None:
|
||||||
@ -32,7 +32,7 @@ def call_on_thread(dialog_str: str) -> Callable:
|
|||||||
raise TypeError(
|
raise TypeError(
|
||||||
"Attribute 'thread_man' must be of type 'ThreadingManager'"
|
"Attribute 'thread_man' must be of type 'ThreadingManager'"
|
||||||
)
|
)
|
||||||
self.thread_man.call_on_thread(dialog_str, stored)
|
self.thread_man.call_on_thread(dialog_str, stored, show_dialog)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
@ -56,13 +56,16 @@ class ThreadingManager:
|
|||||||
self.cleanup_func: StoredFunc | None = None
|
self.cleanup_func: StoredFunc | None = None
|
||||||
self.destroy_first = False
|
self.destroy_first = False
|
||||||
|
|
||||||
def call_on_thread(self, dialog_str: str, func: StoredFunc) -> None:
|
def call_on_thread(
|
||||||
|
self, dialog_str: str, func: StoredFunc, show_dialog: bool = True
|
||||||
|
) -> None:
|
||||||
def callback() -> None:
|
def callback() -> None:
|
||||||
func.call()
|
func.call()
|
||||||
GLib.idle_add(self._destroy_on_idle)
|
GLib.idle_add(self._destroy_on_idle)
|
||||||
|
|
||||||
self.wait_dialog = WaitDialog(self.controller, dialog_str, jobs=self.jobs)
|
if show_dialog:
|
||||||
self.wait_dialog.show_all()
|
self.wait_dialog = WaitDialog(self.controller, dialog_str, jobs=self.jobs)
|
||||||
|
self.wait_dialog.show_all()
|
||||||
thread = threading.Thread(target=callback)
|
thread = threading.Thread(target=callback)
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
@ -88,16 +91,20 @@ class ThreadingManager:
|
|||||||
def get_cleanup_func(self) -> StoredFunc | None:
|
def get_cleanup_func(self) -> StoredFunc | None:
|
||||||
return self.cleanup_func
|
return self.cleanup_func
|
||||||
|
|
||||||
|
def destroy_dialog(self) -> None:
|
||||||
|
if hasattr(self, "wait_dialog"):
|
||||||
|
self.wait_dialog.destroy()
|
||||||
|
|
||||||
def _destroy_on_idle(self) -> Literal[False]:
|
def _destroy_on_idle(self) -> Literal[False]:
|
||||||
if self.destroy_first:
|
if self.destroy_first:
|
||||||
self.wait_dialog.destroy()
|
self.destroy_dialog()
|
||||||
|
|
||||||
func = self.get_cleanup_func()
|
func = self.get_cleanup_func()
|
||||||
if func is not None:
|
if func is not None:
|
||||||
func.call()
|
func.call()
|
||||||
self.set_cleanup_func(None)
|
self.set_cleanup_func(None)
|
||||||
if not self.destroy_first:
|
if not self.destroy_first:
|
||||||
self.wait_dialog.destroy()
|
self.destroy_dialog()
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from typing import Any, TYPE_CHECKING
|
from dataclasses import dataclass
|
||||||
|
from typing import Self, TYPE_CHECKING
|
||||||
|
|
||||||
from dzgui.api import pefile as PeFile
|
|
||||||
from dzgui.const.constants import (
|
from dzgui.const.constants import (
|
||||||
APPID_DAYZ,
|
APPID_DAYZ,
|
||||||
APPID_DAYZ_EXP,
|
APPID_DAYZ_EXP,
|
||||||
@ -13,7 +13,6 @@ from dayzquery import DayzMod
|
|||||||
from dzgui.util.css import add_class
|
from dzgui.util.css import add_class
|
||||||
from dzgui.strings import preconnect
|
from dzgui.strings import preconnect
|
||||||
from dzgui.views.components.frame import HeadingFrame
|
from dzgui.views.components.frame import HeadingFrame
|
||||||
from dzgui.views.components.labels import IconLabel
|
|
||||||
from dzgui.views.trees.tree_server_mods import ServerModTreeView
|
from dzgui.views.trees.tree_server_mods import ServerModTreeView
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
@ -27,14 +26,48 @@ if TYPE_CHECKING:
|
|||||||
from dzgui.controllers.mc import Controller
|
from dzgui.controllers.mc import Controller
|
||||||
|
|
||||||
|
|
||||||
class WarningLabel(IconLabel):
|
@dataclass
|
||||||
def __init__(self, text: str) -> None:
|
class Warnings:
|
||||||
super().__init__(text, WARNING)
|
passworded: bool
|
||||||
|
dayz_running: bool
|
||||||
|
no_steam: bool
|
||||||
|
wrong_version: bool
|
||||||
|
|
||||||
|
|
||||||
class ErrorLabel(IconLabel):
|
@dataclass
|
||||||
def __init__(self, text: str) -> None:
|
class Errors:
|
||||||
super().__init__(text, ERROR)
|
no_space: bool
|
||||||
|
no_dayz_exp: bool
|
||||||
|
no_dayz: bool
|
||||||
|
|
||||||
|
|
||||||
|
class MaskedTree(Gtk.TreeView):
|
||||||
|
def __init__(self, icon: str) -> None:
|
||||||
|
super().__init__(headers_visible=False, can_focus=False)
|
||||||
|
|
||||||
|
self.icon = icon
|
||||||
|
self.store = Gtk.ListStore(str, str)
|
||||||
|
self.set_model(self.store)
|
||||||
|
self.get_selection().set_mode(Gtk.SelectionMode.NONE)
|
||||||
|
|
||||||
|
icon_renderer = Gtk.CellRendererPixbuf()
|
||||||
|
# NOTE: adjust vertical offset between columns
|
||||||
|
icon_renderer.set_property("yalign", 0.6)
|
||||||
|
icon_column = Gtk.TreeViewColumn("", icon_renderer)
|
||||||
|
icon_column.add_attribute(icon_renderer, "icon-name", 0)
|
||||||
|
icon_column.set_fixed_width(50)
|
||||||
|
|
||||||
|
text_renderer = Gtk.CellRendererText()
|
||||||
|
text_column = Gtk.TreeViewColumn("", text_renderer, text=1)
|
||||||
|
|
||||||
|
self.append_column(icon_column)
|
||||||
|
self.append_column(text_column)
|
||||||
|
add_class(self, "masked-tree")
|
||||||
|
|
||||||
|
def append(self, items: list[str]) -> None:
|
||||||
|
self.store.clear()
|
||||||
|
for item in items:
|
||||||
|
self.store.append([self.icon, item])
|
||||||
|
|
||||||
|
|
||||||
class PreConnectionAssistant(Gtk.ScrolledWindow):
|
class PreConnectionAssistant(Gtk.ScrolledWindow):
|
||||||
@ -54,7 +87,6 @@ class PreConnectionAssistant(Gtk.ScrolledWindow):
|
|||||||
|
|
||||||
self.controller.register_widget("preconnect", self)
|
self.controller.register_widget("preconnect", self)
|
||||||
|
|
||||||
# TODO: strings
|
|
||||||
# TODO: dynamic button text if no mods needed
|
# TODO: dynamic button text if no mods needed
|
||||||
self.back = Gtk.Button(label=preconnect.back, halign=Gtk.Align.START)
|
self.back = Gtk.Button(label=preconnect.back, halign=Gtk.Align.START)
|
||||||
self.cancel = Gtk.Button(
|
self.cancel = Gtk.Button(
|
||||||
@ -94,28 +126,12 @@ class PreConnectionAssistant(Gtk.ScrolledWindow):
|
|||||||
|
|
||||||
self.tree_frame = HeadingFrame(self.tree_box, preconnect.mods)
|
self.tree_frame = HeadingFrame(self.tree_box, preconnect.mods)
|
||||||
|
|
||||||
self.warnings: list[WarningLabel] = []
|
|
||||||
# TODO: populate with strings and icons
|
|
||||||
# set visibility if warnings > 1
|
|
||||||
# warning category enums with matching strings
|
|
||||||
"""
|
|
||||||
blocking warning types:
|
|
||||||
- build mismatch
|
|
||||||
- version mismatch
|
|
||||||
- not enough drive space
|
|
||||||
passing warning types:
|
|
||||||
- dayz is running
|
|
||||||
- steam is not running
|
|
||||||
- server has password
|
|
||||||
"""
|
|
||||||
# TODO: abstract into components
|
# TODO: abstract into components
|
||||||
warning_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
self.warning_tree = MaskedTree(WARNING)
|
||||||
warning_box.add(WarningLabel("Warning 1"))
|
self.warning_frame = HeadingFrame(self.warning_tree, preconnect.warnings)
|
||||||
self.warning_frame = HeadingFrame(warning_box, preconnect.warnings)
|
|
||||||
|
|
||||||
error_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
self.error_tree = MaskedTree(ERROR)
|
||||||
error_box.add(ErrorLabel("Error 1"))
|
self.error_frame = HeadingFrame(self.error_tree, preconnect.errors)
|
||||||
self.error_frame = HeadingFrame(error_box, preconnect.errors)
|
|
||||||
|
|
||||||
self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||||
self.box.add(self.title)
|
self.box.add(self.title)
|
||||||
@ -126,6 +142,17 @@ class PreConnectionAssistant(Gtk.ScrolledWindow):
|
|||||||
|
|
||||||
self.add(self.box)
|
self.add(self.box)
|
||||||
|
|
||||||
|
# self.connect("key-press-event", self._on_keypress)
|
||||||
|
self.connect("map", self._on_map)
|
||||||
|
|
||||||
|
def _on_map(self, widget: Self) -> None:
|
||||||
|
self.tree_frame.set_visible(True)
|
||||||
|
self.mod_count.set_visible(True)
|
||||||
|
|
||||||
|
def _on_keypress(self, widget: Self, event: Gdk.EventKey) -> None:
|
||||||
|
if event.keyval == Gdk.KEY_Escape:
|
||||||
|
self.back.emit("clicked")
|
||||||
|
|
||||||
def _on_ok_clicked(self, button: Gtk.Button) -> None:
|
def _on_ok_clicked(self, button: Gtk.Button) -> None:
|
||||||
# TODO: update mod store in place with spinner/toast
|
# TODO: update mod store in place with spinner/toast
|
||||||
# TODO: cancel mod downloads
|
# TODO: cancel mod downloads
|
||||||
@ -139,6 +166,8 @@ class PreConnectionAssistant(Gtk.ScrolledWindow):
|
|||||||
self.tree.populate(mods)
|
self.tree.populate(mods)
|
||||||
total = len(mods)
|
total = len(mods)
|
||||||
|
|
||||||
|
self._set_warnings()
|
||||||
|
|
||||||
name = res.source.server_name
|
name = res.source.server_name
|
||||||
self.title.set_text(name)
|
self.title.set_text(name)
|
||||||
if total < 1:
|
if total < 1:
|
||||||
@ -148,10 +177,26 @@ class PreConnectionAssistant(Gtk.ScrolledWindow):
|
|||||||
else:
|
else:
|
||||||
self.tree.set_visible(True)
|
self.tree.set_visible(True)
|
||||||
self.mod_count.set_visible(True)
|
self.mod_count.set_visible(True)
|
||||||
|
# TODO: print no. of mods that need updating
|
||||||
prefix = preconnect.total_mods
|
prefix = preconnect.total_mods
|
||||||
self.mod_count.set_text(f"{prefix}{str(total)}")
|
self.mod_count.set_text(f"{prefix}{str(total)}")
|
||||||
|
|
||||||
# TODO: reset warning and error dialogs
|
"""
|
||||||
|
blocking warning types:
|
||||||
|
- build mismatch
|
||||||
|
- version mismatch
|
||||||
|
- not enough drive space
|
||||||
|
passing warning types:
|
||||||
|
- dayz is running
|
||||||
|
- steam is not running
|
||||||
|
- server has password
|
||||||
|
"""
|
||||||
|
# TODO: if errors > 1, disable buttons
|
||||||
|
|
||||||
|
def _set_warnings(self) -> None:
|
||||||
|
self.warning_tree.append(["Password protected", "Some other error", "Error 3"])
|
||||||
|
self.error_tree.append(["Password protected", "Some other error", "Error 3"])
|
||||||
|
pass
|
||||||
|
|
||||||
def download_mods(self) -> None:
|
def download_mods(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user