mirror of
https://github.com/aclist/dztui.git
synced 2026-08-29 03:06:56 +02:00
feat: preconnect dialog warnings (WIP)
This commit is contained in:
parent
7523bffbd8
commit
e2022fdee7
@ -88,6 +88,17 @@ class A2SInfo:
|
|||||||
qport = self.record.qport
|
qport = self.record.qport
|
||||||
return source_info_to_dict(ip, qport, self.info)
|
return source_info_to_dict(ip, qport, self.info)
|
||||||
|
|
||||||
|
def is_modded(self) -> bool:
|
||||||
|
if self.info is None:
|
||||||
|
raise ValueError("Cannot call this method on Nonetype")
|
||||||
|
try:
|
||||||
|
kw = self.info.keywords.split(",")
|
||||||
|
state = True if "mod" in kw else False
|
||||||
|
return state
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(e)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
def get_netmask() -> str:
|
def get_netmask() -> str:
|
||||||
hostname = os.uname()[1]
|
hostname = os.uname()[1]
|
||||||
|
|||||||
@ -84,6 +84,9 @@ def get_needs_update(
|
|||||||
|
|
||||||
|
|
||||||
def get_remote_signatures(mods: list[str]) -> list[tuple[str, int]]:
|
def get_remote_signatures(mods: list[str]) -> list[tuple[str, int]]:
|
||||||
|
"""
|
||||||
|
Attempts to continue connecting even if signatures are empty
|
||||||
|
"""
|
||||||
payload: dict[str, str] = {}
|
payload: dict[str, str] = {}
|
||||||
payload["itemcount"] = len(mods)
|
payload["itemcount"] = len(mods)
|
||||||
for i, mod in enumerate(mods):
|
for i, mod in enumerate(mods):
|
||||||
|
|||||||
@ -36,9 +36,9 @@ from gi.repository import Gtk, Gdk, GLib, GObject # noqa E402
|
|||||||
logger = logging.getLogger(APP_NAME)
|
logger = logging.getLogger(APP_NAME)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from dayzquery import DayzMod
|
from dzgui.api.servers import Record
|
||||||
from dzgui.api.servers import A2SInfo, Record
|
|
||||||
from dzgui.const.enum import ServerTab
|
from dzgui.const.enum import ServerTab
|
||||||
|
from dzgui.managers.connection import Prerequisites
|
||||||
from dzgui.managers.filter import FilterManager
|
from dzgui.managers.filter import FilterManager
|
||||||
from dzgui.util.dist import Haversine
|
from dzgui.util.dist import Haversine
|
||||||
from dzgui.views.base import Notebook, Grid, OuterWindow
|
from dzgui.views.base import Notebook, Grid, OuterWindow
|
||||||
@ -88,6 +88,7 @@ class Controller(GObject.GObject):
|
|||||||
self.pending_jobs = 1
|
self.pending_jobs = 1
|
||||||
|
|
||||||
self.exit_event = threading.Event()
|
self.exit_event = threading.Event()
|
||||||
|
self.connection_man: ConnectionManager
|
||||||
|
|
||||||
def get_emitter(self) -> Emitter:
|
def get_emitter(self) -> Emitter:
|
||||||
return self.emitter
|
return self.emitter
|
||||||
@ -104,6 +105,7 @@ class Controller(GObject.GObject):
|
|||||||
def set_prefs(self, prefs: UserPrefs) -> None:
|
def set_prefs(self, prefs: UserPrefs) -> None:
|
||||||
self.config_man = ConfigManager(prefs, self)
|
self.config_man = ConfigManager(prefs, self)
|
||||||
self.notes_man = NoteManager(self, prefs.paths.notes)
|
self.notes_man = NoteManager(self, prefs.paths.notes)
|
||||||
|
|
||||||
self.prefs = prefs
|
self.prefs = prefs
|
||||||
|
|
||||||
def query_config(self, key: Preferences) -> Any:
|
def query_config(self, key: Preferences) -> Any:
|
||||||
@ -393,12 +395,15 @@ class Controller(GObject.GObject):
|
|||||||
if addr.isdigit():
|
if addr.isdigit():
|
||||||
config_man = self.get_config_man()
|
config_man = self.get_config_man()
|
||||||
key = config_man.lookup(Preferences.BM)
|
key = config_man.lookup(Preferences.BM)
|
||||||
ConnectionManager(self).connect_by_id(int(addr), key)
|
self.connection_man = ConnectionManager(self)
|
||||||
|
self.connection_man.connect_by_id(int(addr), key)
|
||||||
else:
|
else:
|
||||||
ConnectionManager(self).connect_by_ip(addr)
|
self.connection_man = ConnectionManager(self)
|
||||||
|
self.connection_man.connect_by_ip(addr)
|
||||||
|
|
||||||
def connect_by_record(self, record: "Record") -> None:
|
def connect_by_record(self, record: "Record") -> None:
|
||||||
ConnectionManager(self).connect_by_record(record)
|
self.connection_man = ConnectionManager(self)
|
||||||
|
self.connection_man.connect_by_record(record)
|
||||||
|
|
||||||
def get_details(self, record: "Record") -> None:
|
def get_details(self, record: "Record") -> None:
|
||||||
ConnectionManager(self).query_details(record)
|
ConnectionManager(self).query_details(record)
|
||||||
@ -458,10 +463,13 @@ class Controller(GObject.GObject):
|
|||||||
def set_exit_event(self) -> None:
|
def set_exit_event(self) -> None:
|
||||||
self.exit_event.set()
|
self.exit_event.set()
|
||||||
|
|
||||||
def open_connection_assistant(self, res: "A2SInfo", mods: list["DayzMod"]) -> None:
|
def open_connection_assistant(self, prereqs: "Prerequisites") -> None:
|
||||||
self.open_page(NotebookPage.CONNECTION)
|
self.open_page(NotebookPage.CONNECTION)
|
||||||
self.mediator.preconnect.populate(res, mods)
|
self.mediator.preconnect.populate(prereqs)
|
||||||
|
|
||||||
def set_start_tab(self) -> None:
|
def set_start_tab(self) -> None:
|
||||||
ind = self.config_man.get_start_tab()
|
ind = self.config_man.get_start_tab()
|
||||||
self.get_servers().notebook.set_current_page(ind)
|
self.get_servers().notebook.set_current_page(ind)
|
||||||
|
|
||||||
|
def update_and_connect(self) -> None:
|
||||||
|
self.connection_man.update_and_connect()
|
||||||
|
|||||||
@ -6,14 +6,19 @@ from dzgui.views.dialogs.early_alert import EarlyAlertDialog
|
|||||||
from dzgui.util.strings import init
|
from dzgui.util.strings import init
|
||||||
|
|
||||||
|
|
||||||
def is_dayz_running() -> None:
|
# TODO: simplify
|
||||||
|
def is_dayz_running(dialog: bool = False) -> None:
|
||||||
|
if dialog is False:
|
||||||
|
return is_running(DAYZ_BINARY)
|
||||||
if is_running(DAYZ_BINARY) is True:
|
if is_running(DAYZ_BINARY) is True:
|
||||||
EarlyAlertDialog(init.is_dayz_running)
|
EarlyAlertDialog(init.is_dayz_running)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def is_steam_running() -> None:
|
def is_steam_running(dialog: bool = False) -> None:
|
||||||
# TODO: check proc name of flatpak steam
|
# TODO: check proc name of flatpak steam
|
||||||
|
if dialog is False:
|
||||||
|
return is_running(STEAM_CMD)
|
||||||
if is_running(STEAM_CMD) is False:
|
if is_running(STEAM_CMD) is False:
|
||||||
EarlyAlertDialog(init.is_steam_running)
|
EarlyAlertDialog(init.is_steam_running)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
@ -130,8 +130,8 @@ def main() -> None:
|
|||||||
EarlyAlertDialog(init.requires_steam)
|
EarlyAlertDialog(init.requires_steam)
|
||||||
|
|
||||||
is_dayz_installed(XDG.config)
|
is_dayz_installed(XDG.config)
|
||||||
is_dayz_running()
|
is_dayz_running(dialog=True)
|
||||||
is_steam_running()
|
is_steam_running(dialog=True)
|
||||||
|
|
||||||
# NOTE: clear versions file of unlinked mods
|
# NOTE: clear versions file of unlinked mods
|
||||||
rebuild_symlinks(XDG.config)
|
rebuild_symlinks(XDG.config)
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import logging
|
import logging
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from packaging.version import Version
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
@ -9,9 +11,17 @@ import dzgui.api.servers as Servers
|
|||||||
from dzgui.api.steam import get_remote_signatures, get_needs_update
|
from dzgui.api.steam import get_remote_signatures, get_needs_update
|
||||||
|
|
||||||
from dzgui.api.mods import get_local_mod_ids
|
from dzgui.api.mods import get_local_mod_ids
|
||||||
from dzgui.const.constants import APP_NAME
|
from dzgui.const.constants import (
|
||||||
|
APP_NAME,
|
||||||
|
APPID_DAYZ,
|
||||||
|
APPID_DAYZ_EXP,
|
||||||
|
APPNAME_DAYZ,
|
||||||
|
APPNAME_DAYZ_EXP,
|
||||||
|
)
|
||||||
from dzgui.const.enum import Preferences
|
from dzgui.const.enum import Preferences
|
||||||
|
from dzgui.init.proc import is_dayz_running, is_steam_running
|
||||||
from dzgui.managers.threading import call_on_thread, StoredFunc, ThreadingManager
|
from dzgui.managers.threading import call_on_thread, StoredFunc, ThreadingManager
|
||||||
|
from dzgui.util.format import format_mib
|
||||||
from dzgui.util.strings import dialog, server_timeout, checkmark
|
from dzgui.util.strings import dialog, server_timeout, checkmark
|
||||||
from dzgui.views.dialogs.generic import ExceptionDialog
|
from dzgui.views.dialogs.generic import ExceptionDialog
|
||||||
from dzgui.views.dialogs.servers import ServerDetailsDialog, ServerModDialog
|
from dzgui.views.dialogs.servers import ServerDetailsDialog, ServerModDialog
|
||||||
@ -22,18 +32,40 @@ gi.require_version("Gtk", "3.0")
|
|||||||
from gi.repository import Gtk # noqa E402
|
from gi.repository import Gtk # noqa E402
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from dzgui.api.servers import A2SInfo
|
from dzgui.api.servers import A2SInfo, Record
|
||||||
from dzgui.controllers.mc import Controller
|
from dzgui.controllers.mc import Controller
|
||||||
|
|
||||||
logger = logging.getLogger(APP_NAME)
|
logger = logging.getLogger(APP_NAME)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(slots=True, frozen=True)
|
||||||
|
class Prerequisites:
|
||||||
|
name: str
|
||||||
|
appid: int
|
||||||
|
local_version: Version
|
||||||
|
remote_version: Version
|
||||||
|
build: str
|
||||||
|
binary_missing: bool
|
||||||
|
required_space: float
|
||||||
|
available_space: float
|
||||||
|
passworded: bool
|
||||||
|
dayz_running: bool
|
||||||
|
steam_running: bool
|
||||||
|
mods: list[str]
|
||||||
|
|
||||||
|
|
||||||
class ConnectionManager:
|
class ConnectionManager:
|
||||||
def __init__(self, controller: "Controller") -> None:
|
def __init__(self, controller: "Controller") -> None:
|
||||||
|
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.thread_man = ThreadingManager(controller)
|
self.thread_man = ThreadingManager(controller)
|
||||||
|
|
||||||
|
self.appid: int
|
||||||
|
self.record: Record
|
||||||
|
|
||||||
|
self.remote_mod_ids: list[str] = []
|
||||||
|
self.missing_mods: list[str] = []
|
||||||
|
|
||||||
@call_on_thread(dialog.querying)
|
@call_on_thread(dialog.querying)
|
||||||
def connect_by_id(self, _id: int, key: str) -> None:
|
def connect_by_id(self, _id: int, key: str) -> None:
|
||||||
res = Servers.query_by_id(_id, key)
|
res = Servers.query_by_id(_id, key)
|
||||||
@ -56,52 +88,66 @@ class ConnectionManager:
|
|||||||
return
|
return
|
||||||
|
|
||||||
record = res.get_record()
|
record = res.get_record()
|
||||||
try:
|
info = res.get_info()
|
||||||
remote_mods = self._query_modlist(record)
|
|
||||||
remote_mod_ids = [mod[1] for mod in remote_mods]
|
# NOTE: store metadata for later connection
|
||||||
except Exception as e:
|
self.appid = info.game_id
|
||||||
print(e)
|
self.record = record
|
||||||
self.thread_man.set_cleanup_func(failure_func, destroy_first=True)
|
|
||||||
return
|
builds = {APPID_DAYZ: APPNAME_DAYZ, APPID_DAYZ_EXP: APPNAME_DAYZ_EXP}
|
||||||
|
build = builds[self.appid]
|
||||||
|
binary_missing = False
|
||||||
|
required_mib = 0.0
|
||||||
|
free_mib = 0.0
|
||||||
|
|
||||||
steam_path = Path(self.controller.query_config(Preferences.DEFAULT))
|
steam_path = Path(self.controller.query_config(Preferences.DEFAULT))
|
||||||
|
local_version = PeFile.get_pretty_version(steam_path, info.game_id)
|
||||||
|
if local_version is None:
|
||||||
|
local_version = "0.0.0"
|
||||||
|
binary_missing = True
|
||||||
|
|
||||||
hashes = get_remote_signatures(remote_mod_ids)
|
remote_mods: list[str, str, str] = []
|
||||||
version_file = self.controller.get_prefs().paths.version
|
if res.is_modded():
|
||||||
needs_update = get_needs_update(version_file, hashes)
|
try:
|
||||||
|
remote_mods = self._query_modlist(record)
|
||||||
|
self.remote_mod_ids = [mod[1] for mod in remote_mods]
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(e)
|
||||||
|
self.thread_man.set_cleanup_func(failure_func, destroy_first=True)
|
||||||
|
return
|
||||||
|
|
||||||
# TODO: store mods that need update in class object for referencing later
|
hashes = get_remote_signatures(self.remote_mod_ids)
|
||||||
# TODO: store remote destination to connect to
|
version_file = self.controller.get_prefs().paths.version
|
||||||
|
self.missing_mods = get_needs_update(version_file, hashes)
|
||||||
|
|
||||||
# missing mods should be the totality of all mods with no signature
|
if local_version is not None:
|
||||||
# missing = get_missing_mods(local_mod_ids, remote_mod_ids)
|
pefile_path = PeFile.get_pefile_path(steam_path, info.game_id)
|
||||||
# print(missing)
|
total, used, free = shutil.disk_usage(pefile_path)
|
||||||
# TODO: when downloading mods, create symlinks if missing
|
if len(self.missing_mods) > 0:
|
||||||
|
required_size = sum(int(row[2]) for row in self.missing_mods)
|
||||||
|
required_mib = format_mib(required_size)
|
||||||
|
free_mib = format_mib(required_size)
|
||||||
|
|
||||||
# TODO: get missing mod sizes, warn if not enough space
|
dayz_running = is_dayz_running()
|
||||||
info = res.get_info()
|
steam_running = is_steam_running()
|
||||||
try:
|
# TODO: is dayz downloading
|
||||||
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)
|
|
||||||
if len(needs_update) > 0:
|
|
||||||
# TODO: generic mib function
|
|
||||||
required_size = sum(int(row[2]) for row in needs_update)
|
|
||||||
required_mib = round(required_size / (1024**2), 3)
|
|
||||||
free_mib = round(free / (1024**2), 3)
|
|
||||||
print(required_mib)
|
|
||||||
print(free_mib)
|
|
||||||
except Exception:
|
|
||||||
# TODO: if this fails, need to show missing build warning, not failure func
|
|
||||||
# build up list of warnings/errors
|
|
||||||
# logger.warning(e)
|
|
||||||
self.thread_man.set_cleanup_func(failure_func, destroy_first=True)
|
|
||||||
|
|
||||||
# TODO: number separator func
|
prereqs = Prerequisites(
|
||||||
# TODO: pack a final PreReq struct with pre-processed values
|
name=info.server_name,
|
||||||
|
appid=info.game_id,
|
||||||
|
local_version=Version(local_version),
|
||||||
|
remote_version=Version(info.version),
|
||||||
|
build=build,
|
||||||
|
binary_missing=binary_missing,
|
||||||
|
required_space=required_mib,
|
||||||
|
available_space=free_mib,
|
||||||
|
passworded=info.password_protected,
|
||||||
|
dayz_running=dayz_running,
|
||||||
|
steam_running=steam_running,
|
||||||
|
mods=remote_mods,
|
||||||
|
)
|
||||||
|
|
||||||
# TODO: connection assistant only receives user-facing warnings and list of mods
|
func = StoredFunc(self.controller.open_connection_assistant, prereqs)
|
||||||
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)
|
||||||
|
|
||||||
@call_on_thread(dialog.querying)
|
@call_on_thread(dialog.querying)
|
||||||
@ -157,10 +203,24 @@ class ConnectionManager:
|
|||||||
dialog = ExceptionDialog(self.controller, server_timeout)
|
dialog = ExceptionDialog(self.controller, server_timeout)
|
||||||
dialog.run()
|
dialog.run()
|
||||||
|
|
||||||
|
def connect(self) -> None:
|
||||||
|
print(self.record.ip)
|
||||||
|
print(self.record.gameport)
|
||||||
|
print(self.appid)
|
||||||
|
# TODO: convert mod ids to symlink hashes
|
||||||
|
# steam api, concat mods
|
||||||
|
|
||||||
|
# TODO: custom threading with glib idle callback
|
||||||
def update_mods(self) -> None:
|
def update_mods(self) -> None:
|
||||||
|
print(self.missing_mods)
|
||||||
|
# TODO: when downloading mods, create symlinks if missing
|
||||||
|
# TODO: pack a final PreReq struct with pre-processed values
|
||||||
# self.needs_update
|
# self.needs_update
|
||||||
|
# then connect
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def connect(self) -> None:
|
def update_and_connect(self) -> None:
|
||||||
# steam api, concat mods
|
if len(self.missing_mods) > 0:
|
||||||
pass
|
self.update_mods()
|
||||||
|
else:
|
||||||
|
self.connect()
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
update_mods = "Update mods and connect"
|
update_mods = "Update mods and connect"
|
||||||
|
connect = "Connect"
|
||||||
back = "Back"
|
back = "Back"
|
||||||
cancel = "Cancel"
|
cancel = "Cancel"
|
||||||
warnings = "Warnings"
|
warnings = "Warnings"
|
||||||
|
|||||||
@ -51,6 +51,10 @@ def format_mods(size: int, mods: int) -> str:
|
|||||||
return f"Found {mods:n} {plural} taking up {l_size} MiB. {suffix}"
|
return f"Found {mods:n} {plural} taking up {l_size} MiB. {suffix}"
|
||||||
|
|
||||||
|
|
||||||
|
def format_mib(bits: int) -> float:
|
||||||
|
return round(bits / (1024**2), 3)
|
||||||
|
|
||||||
|
|
||||||
def format_server_mods(mods: int) -> str:
|
def format_server_mods(mods: int) -> str:
|
||||||
plural = pluralize("mods", mods)
|
plural = pluralize("mods", mods)
|
||||||
return f"Found {mods:n} {plural}. {workshop}"
|
return f"Found {mods:n} {plural}. {workshop}"
|
||||||
|
|||||||
@ -1,16 +1,12 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Self, TYPE_CHECKING
|
from typing import Self, Sequence, TYPE_CHECKING
|
||||||
|
|
||||||
from dzgui.const.constants import (
|
from dzgui.const.constants import (
|
||||||
APPID_DAYZ,
|
|
||||||
APPID_DAYZ_EXP,
|
|
||||||
APPNAME_DAYZ,
|
|
||||||
APPNAME_DAYZ_EXP,
|
|
||||||
ERROR,
|
ERROR,
|
||||||
WARNING,
|
WARNING,
|
||||||
)
|
)
|
||||||
from dayzquery import DayzMod
|
|
||||||
from dzgui.util.css import add_class
|
from dzgui.util.css import add_class
|
||||||
|
from dzgui.util.localize import number
|
||||||
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.trees.tree_server_mods import ServerModTreeView
|
from dzgui.views.trees.tree_server_mods import ServerModTreeView
|
||||||
@ -22,7 +18,7 @@ from gi.repository import Gdk, Gtk # type: ignore # noqa E402
|
|||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from dzgui.api.servers import A2SInfo
|
from dzgui.managers.connection import Prerequisites
|
||||||
from dzgui.controllers.mc import Controller
|
from dzgui.controllers.mc import Controller
|
||||||
|
|
||||||
|
|
||||||
@ -41,6 +37,17 @@ class Errors:
|
|||||||
no_dayz: bool
|
no_dayz: bool
|
||||||
|
|
||||||
|
|
||||||
|
class Placeholder(Gtk.Label):
|
||||||
|
def __init__(self, text: str) -> None:
|
||||||
|
super().__init__(
|
||||||
|
label=text,
|
||||||
|
halign=Gtk.Align.START,
|
||||||
|
valign=Gtk.Align.START,
|
||||||
|
margin_start=10,
|
||||||
|
margin_bottom=5,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MaskedTree(Gtk.TreeView):
|
class MaskedTree(Gtk.TreeView):
|
||||||
def __init__(self, icon: str) -> None:
|
def __init__(self, icon: str) -> None:
|
||||||
super().__init__(headers_visible=False, can_focus=False)
|
super().__init__(headers_visible=False, can_focus=False)
|
||||||
@ -64,7 +71,12 @@ class MaskedTree(Gtk.TreeView):
|
|||||||
self.append_column(text_column)
|
self.append_column(text_column)
|
||||||
add_class(self, "masked-tree")
|
add_class(self, "masked-tree")
|
||||||
|
|
||||||
def append(self, items: list[str]) -> None:
|
def append(self, item: Sequence[str]) -> None:
|
||||||
|
if len(item) > 1:
|
||||||
|
raise ValueError("This method only accepts one item")
|
||||||
|
self.store.append([self.icon, item])
|
||||||
|
|
||||||
|
def extend(self, items: list[str]) -> None:
|
||||||
self.store.clear()
|
self.store.clear()
|
||||||
for item in items:
|
for item in items:
|
||||||
self.store.append([self.icon, item])
|
self.store.append([self.icon, item])
|
||||||
@ -87,11 +99,11 @@ class PreConnectionAssistant(Gtk.ScrolledWindow):
|
|||||||
|
|
||||||
self.controller.register_widget("preconnect", self)
|
self.controller.register_widget("preconnect", self)
|
||||||
|
|
||||||
# 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(
|
||||||
label=preconnect.cancel, halign=Gtk.Align.END, sensitive=False, hexpand=True
|
label=preconnect.cancel, halign=Gtk.Align.END, sensitive=False, hexpand=True
|
||||||
)
|
)
|
||||||
|
# TODO: dynamic button text if no mods needed
|
||||||
self.ok = Gtk.Button(label=preconnect.update_mods, halign=Gtk.Align.END)
|
self.ok = Gtk.Button(label=preconnect.update_mods, halign=Gtk.Align.END)
|
||||||
|
|
||||||
self.button_box = Gtk.Box(
|
self.button_box = Gtk.Box(
|
||||||
@ -111,7 +123,6 @@ class PreConnectionAssistant(Gtk.ScrolledWindow):
|
|||||||
|
|
||||||
self.tree = ServerModTreeView(self.controller)
|
self.tree = ServerModTreeView(self.controller)
|
||||||
self.mod_count = Gtk.Label(label="", halign=Gtk.Align.START, margin_start=5)
|
self.mod_count = Gtk.Label(label="", halign=Gtk.Align.START, margin_start=5)
|
||||||
|
|
||||||
# TODO: live count of remaining downloads
|
# TODO: live count of remaining downloads
|
||||||
# "Steam is downloading: {mod_name}"
|
# "Steam is downloading: {mod_name}"
|
||||||
# mention whether manual or auto mod is active
|
# mention whether manual or auto mod is active
|
||||||
@ -124,16 +135,30 @@ class PreConnectionAssistant(Gtk.ScrolledWindow):
|
|||||||
self.tree_box.add(self.scrolled)
|
self.tree_box.add(self.scrolled)
|
||||||
self.tree_box.add(self.mod_count)
|
self.tree_box.add(self.mod_count)
|
||||||
|
|
||||||
|
# TODO: strings
|
||||||
|
self.mods_placeholder = Placeholder("This server has no mods.")
|
||||||
|
self.tree_box.add(self.mods_placeholder)
|
||||||
|
|
||||||
self.tree_frame = HeadingFrame(self.tree_box, preconnect.mods)
|
self.tree_frame = HeadingFrame(self.tree_box, preconnect.mods)
|
||||||
|
|
||||||
# TODO: abstract into components
|
# TODO: abstract into components
|
||||||
|
self.warning_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||||
self.warning_tree = MaskedTree(WARNING)
|
self.warning_tree = MaskedTree(WARNING)
|
||||||
self.warning_frame = HeadingFrame(self.warning_tree, preconnect.warnings)
|
# TODO: strings
|
||||||
|
self.warning_placeholder = Placeholder("No warnings.")
|
||||||
|
self.warning_box.add(self.warning_tree)
|
||||||
|
self.warning_box.add(self.warning_placeholder)
|
||||||
|
self.warning_frame = HeadingFrame(self.warning_box, preconnect.warnings)
|
||||||
|
|
||||||
|
self.error_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||||
self.error_tree = MaskedTree(ERROR)
|
self.error_tree = MaskedTree(ERROR)
|
||||||
self.error_frame = HeadingFrame(self.error_tree, preconnect.errors)
|
# TODO: strings
|
||||||
|
self.error_placeholder = Placeholder("No errors.")
|
||||||
|
self.error_box.add(self.error_tree)
|
||||||
|
self.error_box.add(self.error_placeholder)
|
||||||
|
self.error_frame = HeadingFrame(self.error_box, preconnect.errors)
|
||||||
|
|
||||||
self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
|
||||||
self.box.add(self.title)
|
self.box.add(self.title)
|
||||||
self.box.add(self.tree_frame)
|
self.box.add(self.tree_frame)
|
||||||
self.box.add(self.warning_frame)
|
self.box.add(self.warning_frame)
|
||||||
@ -146,8 +171,15 @@ class PreConnectionAssistant(Gtk.ScrolledWindow):
|
|||||||
self.connect("map", self._on_map)
|
self.connect("map", self._on_map)
|
||||||
|
|
||||||
def _on_map(self, widget: Self) -> None:
|
def _on_map(self, widget: Self) -> None:
|
||||||
self.tree_frame.set_visible(True)
|
widgets = (
|
||||||
self.mod_count.set_visible(True)
|
self.tree_frame,
|
||||||
|
self.mod_count,
|
||||||
|
self.error_placeholder,
|
||||||
|
self.warning_placeholder,
|
||||||
|
)
|
||||||
|
for widget in widgets:
|
||||||
|
widget.set_visible(True)
|
||||||
|
self.ok.set_sensitive(True)
|
||||||
|
|
||||||
def _on_keypress(self, widget: Self, event: Gdk.EventKey) -> None:
|
def _on_keypress(self, widget: Self, event: Gdk.EventKey) -> None:
|
||||||
if event.keyval == Gdk.KEY_Escape:
|
if event.keyval == Gdk.KEY_Escape:
|
||||||
@ -155,59 +187,84 @@ class PreConnectionAssistant(Gtk.ScrolledWindow):
|
|||||||
|
|
||||||
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
|
||||||
|
# no dialog
|
||||||
# TODO: cancel mod downloads
|
# TODO: cancel mod downloads
|
||||||
|
# TODO: add to history file and list store
|
||||||
|
# TODO: concat mods
|
||||||
|
self.controller.update_and_connect()
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _on_back_clicked(self, button: Gtk.Button) -> None:
|
def _on_back_clicked(self, button: Gtk.Button) -> None:
|
||||||
page = self.controller.get_prior_page()
|
page = self.controller.get_prior_page()
|
||||||
self.controller.open_page(page)
|
self.controller.open_page(page)
|
||||||
|
|
||||||
def populate(self, res: "A2SInfo", mods: list["DayzMod"]) -> None:
|
def _process_warnings(self, prereqs: "Prerequisites") -> None:
|
||||||
|
warnings: list[str] = []
|
||||||
|
errors: list[str] = []
|
||||||
|
|
||||||
|
if prereqs.binary_missing:
|
||||||
|
errors.append(
|
||||||
|
f"Remote server is running the build '{prereqs.build}', but it is not installed"
|
||||||
|
)
|
||||||
|
elif prereqs.local_version != prereqs.remote_version:
|
||||||
|
print("versions do not match")
|
||||||
|
errors.append(
|
||||||
|
f"Local client version '{prereqs.local_version}' does not match remote version '{prereqs.remote_version}'"
|
||||||
|
)
|
||||||
|
if prereqs.required_space > prereqs.available_space:
|
||||||
|
required_pretty = number(prereqs.required_space)
|
||||||
|
available_pretty = number(prereqs.available_space)
|
||||||
|
errors.append(
|
||||||
|
f"Need to update {required_pretty} MiB of mods, but installation path only has {available_pretty} MiB"
|
||||||
|
)
|
||||||
|
if prereqs.passworded:
|
||||||
|
warnings.append(
|
||||||
|
"Protected: you will be prompted for a password when connecting to this server"
|
||||||
|
)
|
||||||
|
if prereqs.dayz_running is True:
|
||||||
|
warnings.append(
|
||||||
|
"It looks like DayZ is already running in the background. Exit DayZ before connecting"
|
||||||
|
)
|
||||||
|
if prereqs.steam_running is False:
|
||||||
|
warnings.append(
|
||||||
|
"It looks like Steam is not running. Launch Steam before connecting"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.add_warnings(warnings)
|
||||||
|
self.add_errors(errors)
|
||||||
|
|
||||||
|
if len(warnings) > 0:
|
||||||
|
self.warning_placeholder.set_visible(False)
|
||||||
|
if len(errors) > 0:
|
||||||
|
self.error_placeholder.set_visible(False)
|
||||||
|
self.ok.set_sensitive(False)
|
||||||
|
|
||||||
|
def populate(self, prereqs: "Prerequisites") -> None:
|
||||||
|
mods = prereqs.mods
|
||||||
self.tree.populate(mods)
|
self.tree.populate(mods)
|
||||||
total = len(mods)
|
total_mods = len(mods)
|
||||||
|
|
||||||
self._set_warnings()
|
name = prereqs.name
|
||||||
|
|
||||||
info = res.get_info()
|
|
||||||
name = info.server_name
|
|
||||||
self.title.set_text(name)
|
self.title.set_text(name)
|
||||||
if total < 1:
|
|
||||||
self.tree_frame.set_visible(False)
|
if total_mods < 1:
|
||||||
|
self.scrolled.set_visible(False)
|
||||||
self.mod_count.set_visible(False)
|
self.mod_count.set_visible(False)
|
||||||
return
|
self.mods_placeholder.set_visible(True)
|
||||||
|
self.ok.set_label(preconnect.connect)
|
||||||
else:
|
else:
|
||||||
self.tree.set_visible(True)
|
self.scrolled.set_visible(True)
|
||||||
self.mod_count.set_visible(True)
|
self.mod_count.set_visible(True)
|
||||||
|
self.mods_placeholder.set_visible(False)
|
||||||
|
|
||||||
# TODO: print no. of mods that need updating
|
# 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_mods)}")
|
||||||
|
|
||||||
"""
|
self._process_warnings(prereqs)
|
||||||
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:
|
def add_errors(self, errors: list[str]) -> None:
|
||||||
self.warning_tree.append(["Password protected", "Some other error", "Error 3"])
|
self.error_tree.extend(errors)
|
||||||
self.error_tree.append(["Password protected", "Some other error", "Error 3"])
|
|
||||||
pass
|
|
||||||
|
|
||||||
def download_mods(self) -> None:
|
def add_warnings(self, warnings: list[str]) -> None:
|
||||||
pass
|
self.warning_tree.extend(warnings)
|
||||||
|
|
||||||
def connect_server(self) -> None:
|
|
||||||
# TODO: add to history file and list store
|
|
||||||
# TODO: concat mods
|
|
||||||
"""
|
|
||||||
spawn dialog in thread
|
|
||||||
watch for subprocess
|
|
||||||
return to prior page when finished
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user