mirror of
https://github.com/aclist/dztui.git
synced 2026-08-28 02:37:20 +02:00
feat: dynamic haversine calc
This commit is contained in:
parent
775ca2a8d9
commit
10037b86d8
@ -38,9 +38,10 @@ from dzgui.config import update
|
||||
from dzgui.config.query import lookup
|
||||
from dzgui.config.userprefs import UserPrefs
|
||||
from dzgui.controllers.model import ModelManager
|
||||
from dzgui.util.diag import write_diagnostic
|
||||
from dzgui.util import cooldown, strings
|
||||
from dzgui.util.diag import write_diagnostic
|
||||
from dzgui.util._json import read_json, write_json
|
||||
from dzgui.util.localize import number
|
||||
from dzgui.util.open_links import open_workshop_page, open_user_workshop
|
||||
from dzgui.util.format import format_mods, format_player_count, pluralize
|
||||
from dzgui.util.redact import redact_log
|
||||
@ -55,16 +56,17 @@ from gi.repository import Gtk, Gdk, GLib, GObject # noqa E402
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from dzgui.views.components.buttonbox import ContextualButton
|
||||
from dzgui.views.base import OuterWindow
|
||||
from dzgui.views.trees.tree_base import TreeView
|
||||
from dzgui.views.trees.tree_mods import ModTreeView
|
||||
from dzgui.views.trees.tree_servers import ServerTreeView
|
||||
from dzgui.views.trees.tree_log import LogTreeView
|
||||
from dzgui.util.dist import Haversine
|
||||
from dzgui.views.base import Notebook, Grid, OuterWindow
|
||||
from dzgui.views.components.buttonbox import ContextualButton
|
||||
from dzgui.views.components.statusbar import Statusbar
|
||||
from dzgui.views.components.right_panel import RightPanel
|
||||
from dzgui.views.pages.servers import ServerNotebook
|
||||
from dzgui.views.trees.tree_base import TreeView
|
||||
from dzgui.views.trees.tree_menu import MenuTreeView
|
||||
from dzgui.views.trees.tree_mods import ModTreeView
|
||||
from dzgui.views.trees.tree_servers import ServerTreeView
|
||||
from dzgui.views.trees.tree_log import LogTreeView
|
||||
|
||||
class AppNavigation:
|
||||
window: "OuterWindow"
|
||||
@ -79,13 +81,11 @@ class AppNavigation:
|
||||
saved: "ServerTreeView"
|
||||
recent: "ServerTreeView"
|
||||
lan: "ServerTreeView"
|
||||
modtreeview: "ModTreeView"
|
||||
logtreeview: "LogTreeView"
|
||||
|
||||
# TODO: most server contexts can be dropped from this struct
|
||||
|
||||
class Controller:
|
||||
def __init__(self) -> None:
|
||||
self.dist_cache: dict[str, "Haversine"] = {}
|
||||
self.crumbs_cache = ""
|
||||
self.mediator = AppNavigation()
|
||||
self.prefs: UserPrefs
|
||||
@ -238,10 +238,29 @@ class Controller:
|
||||
Gtk.main_quit()
|
||||
|
||||
def get_statusbar(self) -> str:
|
||||
return self.mediator.grid.statusbar.get_text()
|
||||
return self.mediator.statusbar.get_text()
|
||||
|
||||
def set_statusbar(self, text: str) -> None:
|
||||
self.mediator.grid.statusbar.set_text(text)
|
||||
self.mediator.statusbar.set_text(text)
|
||||
|
||||
def set_statusbar_placeholder(self, text: str) -> None:
|
||||
self.statusbar_placeholder = text
|
||||
|
||||
def set_statusbar_dist(self, haversine: "Haversine") -> None:
|
||||
dist: str
|
||||
if haversine is None:
|
||||
dist = "Unknown"
|
||||
else:
|
||||
if self.query_config(Preferences.DIST) is True:
|
||||
raw = round(haversine.as_miles())
|
||||
separated = number(raw)
|
||||
dist = str(separated) + " mi"
|
||||
else:
|
||||
raw = round(haversine.as_kilometers())
|
||||
separated = number(raw)
|
||||
dist = str(separated) + " km"
|
||||
text = self.statusbar_placeholder
|
||||
self.set_statusbar(f"{text} | Distance: {dist}")
|
||||
|
||||
def delete_multiple_mods(self) -> None:
|
||||
sel = self.mediator.modtreeview.get_selection()
|
||||
@ -327,7 +346,7 @@ class Controller:
|
||||
return False
|
||||
|
||||
def set_statusbar_by_row(self, row: "RowType") -> None:
|
||||
self.mediator.grid.statusbar.refresh(row)
|
||||
self.mediator.statusbar.refresh(row)
|
||||
|
||||
def toggle_server_panels(self, state: bool) -> None:
|
||||
self.mediator.grid.toggle_filter_panel(state)
|
||||
@ -357,7 +376,7 @@ class Controller:
|
||||
case ButtonType.MODS:
|
||||
self.load_mods()
|
||||
case ButtonType.HELP:
|
||||
self.mediator.grid.statusbar.refresh(RowType.CHANGELOG)
|
||||
self.mediator.statusbar.refresh(RowType.CHANGELOG)
|
||||
pass
|
||||
case ButtonType.SERVERS:
|
||||
self.mediator.notebook.set_page_by_enum(button.opens)
|
||||
@ -432,7 +451,7 @@ class Controller:
|
||||
def update_mod_statusbar(self) -> None:
|
||||
total_mods, total_size = self.calc_mod_size()
|
||||
msg = format_mods(total_size, total_mods)
|
||||
self.mediator.grid.statusbar.set_text(msg)
|
||||
self.mediator.statusbar.set_text(msg)
|
||||
|
||||
def calc_mod_size(self) -> tuple[int, int]:
|
||||
model = self.model_manager.get_mod_store()
|
||||
@ -614,7 +633,8 @@ class Controller:
|
||||
treeview = self.mediator.notebook.servers.get_active_treeview()
|
||||
model = treeview.get_model()
|
||||
status = format_player_count(model)
|
||||
self.mediator.statusbar.set_text(status)
|
||||
self.set_statusbar_placeholder(status)
|
||||
self.set_statusbar(status + "| Calculating...")
|
||||
|
||||
def propagate_column_width(self, col: Gtk.TreeViewColumn) -> None:
|
||||
GLib.idle_add(self.mediator.servers.update_tab_widths, col)
|
||||
@ -651,10 +671,13 @@ class Controller:
|
||||
self.mediator.right_panel.focus_button_box()
|
||||
|
||||
def present_servers(self) -> None:
|
||||
tree = self.get_active_treeview()
|
||||
# TODO: abstract
|
||||
self.grab_active_treeview()
|
||||
self.update_server_status()
|
||||
crumbs = self.mediator.servers.get_cached_label()
|
||||
self.set_crumbs(crumbs)
|
||||
tree.emit("on_distcalc_started")
|
||||
|
||||
def toggle_check(self, event: Gdk.EventKey) -> None:
|
||||
keyname = Gdk.keyval_name(event.keyval)
|
||||
@ -677,3 +700,6 @@ class Controller:
|
||||
if len(fav) < 1:
|
||||
return None
|
||||
return fav
|
||||
|
||||
def get_dist_cache(self) -> dict[str, "Haversine"]:
|
||||
return self.dist_cache
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import logging
|
||||
import multiprocessing
|
||||
from math import radians, cos, sin, asin, sqrt
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
||||
import dzgui.util.ip as ip
|
||||
from dzgui.util.ip import GeolocationError
|
||||
from dzgui.util.ip import GeolocationError, get_coords
|
||||
from dzgui.util.localize import number
|
||||
|
||||
import gi
|
||||
@ -13,6 +12,9 @@ from gi.repository import Gtk # noqa E402
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from dzgui.util.ip import Coords
|
||||
from dzgui.controllers.mc import Controller
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Haversine():
|
||||
def __init__(self, lat1: float, lon1: float, lat2: float, lon2: float) -> None:
|
||||
@ -35,53 +37,40 @@ class Haversine():
|
||||
def as_miles(self) -> float:
|
||||
return self.dist / 1609.344
|
||||
|
||||
def compare(local: "Coords", remote_c: str, fmt: str) -> int | None:
|
||||
if local is None:
|
||||
return None
|
||||
try:
|
||||
# FIXME: expects XDG.ips
|
||||
remote = ip.get_coords(remote_c)
|
||||
except GeolocationError:
|
||||
return None
|
||||
|
||||
haversine = Haversine(local.lat, local.lon, remote.lat, remote.lon)
|
||||
if fmt == "km":
|
||||
dist = haversine.as_kilometers()
|
||||
else:
|
||||
dist = haversine.as_miles()
|
||||
return round(dist)
|
||||
|
||||
class CalcDist(multiprocessing.Process):
|
||||
def __init__(
|
||||
self,
|
||||
widget: Gtk.Widget,
|
||||
addr: str,
|
||||
result_queue: multiprocessing.Queue,
|
||||
cache: dict,
|
||||
):
|
||||
controller: "Controller",
|
||||
) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.controller = controller
|
||||
self.result_queue = result_queue
|
||||
self.addr = addr
|
||||
self.ip = addr.split(":")[0]
|
||||
|
||||
# TODO: pass controller correctly
|
||||
def run(self) -> None:
|
||||
use_miles = MainController.query_config("use_miles")
|
||||
fmt = "mi" if use_miles else "km"
|
||||
|
||||
# TODO: get cache accordingly
|
||||
cache = self.controller.get_dist_cache()
|
||||
if self.addr in cache:
|
||||
if fmt in cache[self.addr]:
|
||||
logger.info(f"Address '{self.addr}' already in cache")
|
||||
self.result_queue.put([self.addr, cache[self.addr]])
|
||||
return
|
||||
logger.info(f"Address '{self.addr}' already in cache")
|
||||
self.result_queue.put([self.addr, cache[self.addr]])
|
||||
return
|
||||
|
||||
prefs = MainController.get_prefs()
|
||||
dist = compare(prefs.coords, prefs.paths.ips, self.ip, fmt)
|
||||
if dist is None:
|
||||
dist_pretty = "Unknown"
|
||||
else:
|
||||
d = number(dist)
|
||||
dist_pretty = f"{d} {fmt}"
|
||||
self.result_queue.put([self.addr, dist_pretty])
|
||||
dist = self.compare(self.ip)
|
||||
self.result_queue.put([self.addr, dist])
|
||||
|
||||
def compare(self, remote: str) -> int | None:
|
||||
prefs = self.controller.get_prefs()
|
||||
local = prefs.coords
|
||||
if local is None:
|
||||
return None
|
||||
try:
|
||||
remote = get_coords(prefs.paths.ips, remote)
|
||||
except GeolocationError:
|
||||
return None
|
||||
|
||||
# TODO: handle failed remote dist
|
||||
haversine = Haversine(local.lat, local.lon, remote.lat, remote.lon)
|
||||
return haversine
|
||||
|
||||
@ -64,6 +64,7 @@ def format_player_count(model: Gtk.TreeModel | None) -> str:
|
||||
hits_pretty = pluralize("matches", hits)
|
||||
suffix = distance_suffix
|
||||
status = f"Found {hits:n} {hits_pretty} with {players:n} {players_pretty}"
|
||||
return status
|
||||
return f"{status} | {suffix}"
|
||||
|
||||
|
||||
|
||||
@ -52,22 +52,22 @@ class ServerNotebook(Gtk.ScrolledWindow):
|
||||
pass
|
||||
#store.append(["BAR", "a", "a", "a", 1, 1, 1, "1:1", 0, 0, "a", False])
|
||||
else:
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "1:1", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
store.append(["BAR", "a", "a", "a", 0, 0, 0, "189.127.165.207:2302", 0, 0, "a", False])
|
||||
tree.loaded = True
|
||||
# TODO: set model on init of servertreeview
|
||||
tree.set_model(store)
|
||||
@ -110,12 +110,13 @@ class ServerNotebook(Gtk.ScrolledWindow):
|
||||
child.grab_focus()
|
||||
|
||||
# FIXME: doesn't fire on first run
|
||||
self.controller.update_server_status()
|
||||
#self.controller.update_server_status()
|
||||
self.controller.present_servers()
|
||||
self.controller.populate_model()
|
||||
|
||||
# TODO: put in controller
|
||||
def query_test(self) -> None:
|
||||
data = (["BAR", "a", "a", "a", 1, 1, 1, "1:1", 0, 0, "a", False])
|
||||
data = (["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False])
|
||||
return data
|
||||
|
||||
def get_cached_label(self) -> str:
|
||||
|
||||
@ -92,7 +92,7 @@ class ServerTreeView(TreeView):
|
||||
column.connect("notify::fixed-width", self._on_col_width_changed)
|
||||
self.append_column(column)
|
||||
|
||||
self.connect("on_distcalc_started", self._on_calclat_started)
|
||||
self.connect("on_distcalc_started", self._on_distcalc_started)
|
||||
self.connect("button-release-event", self._on_server_button_release)
|
||||
self.connect("key-press-event", self._on_server_keypress)
|
||||
self.connect("generic_row_activated", self._parent_row_activated)
|
||||
@ -150,22 +150,28 @@ class ServerTreeView(TreeView):
|
||||
if self.current_proc and self.current_proc.is_alive():
|
||||
self.current_proc.terminate()
|
||||
|
||||
def _on_calclat_started(self, treeview):
|
||||
server_tooltip[0] = format_tooltip()
|
||||
server_tooltip[1] = server_tooltip[0] + "| Distance: calculating..."
|
||||
self.update_statusbar(server_tooltip[1])
|
||||
def _on_distcalc_started(self, treeview):
|
||||
record = self.get_record()
|
||||
if record is None:
|
||||
return
|
||||
ip = record.ip
|
||||
self.current_proc = CalcDist(record.ip, self.queue, self.controller)
|
||||
self.current_proc.start()
|
||||
|
||||
def _check_result_queue(self) -> Literal[True]:
|
||||
# TODO: trigger signal when changing page contexts
|
||||
# TODO: delegate to controller
|
||||
latest_result = None
|
||||
while not self.queue.empty():
|
||||
latest_result = self.queue.get()
|
||||
|
||||
cache = self.controller.get_dist_cache()
|
||||
if latest_result:
|
||||
addr = latest_result[0]
|
||||
km = latest_result[1]
|
||||
cache[addr] = km
|
||||
haversine = latest_result[1]
|
||||
cache[addr] = haversine
|
||||
# FIXME
|
||||
self.statusbar.append_distance(km)
|
||||
self.controller.set_statusbar_dist(haversine)
|
||||
return True
|
||||
|
||||
def _on_server_keypress(
|
||||
@ -261,23 +267,8 @@ class ServerTreeView(TreeView):
|
||||
print(self.get_value_at_index(0))
|
||||
|
||||
def _parent_selection_changed(self, base_class: TreeView, sel: Gtk.TreeSelection):
|
||||
|
||||
self.terminate_process()
|
||||
record = self.get_record()
|
||||
|
||||
if record is None:
|
||||
return
|
||||
|
||||
#model = self.get_model()
|
||||
#if record is None:
|
||||
# self.controller.update_server_status(model)
|
||||
# return
|
||||
|
||||
ip = record.ip
|
||||
# TODO
|
||||
#self.emit("on_distcalc_started")
|
||||
#self.current_proc = CalcDist(self, record.ip, self.queue, cache)
|
||||
#self.current_proc.start()
|
||||
self.emit("on_distcalc_started")
|
||||
|
||||
def get_record_string(self) -> str:
|
||||
addr = self.get_value_at_index(7)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user