Dotfiles/desktopenvs/hyprlua/astal-menu/modules/location.py

77 lines
2.7 KiB
Python

"""Location quad: a static OpenStreetMap image centred on the device's IP-geolocated
position, with a marker.
We render a static map (backend/staticmap.py) rather than an interactive libshumate
map: Shumate does not paint tiles in this environment (the official shumate-demo
shows the same blank map), while tile downloads themselves work fine. Consumes the
shared LocationService, which the Weather quad also uses.
"""
from __future__ import annotations
import sys
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk # noqa: E402
from lib.proc import run_text
from module_base import Feature, ModuleContext, ModuleInstance, ModuleSpec
from paths import BACKEND_DIR, CACHE_DIR
_SCRIPT = str(BACKEND_DIR / "staticmap.py")
class _MapView(Gtk.Box):
def __init__(self, ctx: ModuleContext, zoom: int, size: tuple[int, int],
tag: str, show_info: bool):
super().__init__(orientation=Gtk.Orientation.VERTICAL)
self.add_css_class("map-view")
self.ctx = ctx
self.zoom = zoom
self.size = size
self._out = str(CACHE_DIR / f"map_{tag}.png")
self.picture = Gtk.Picture(content_fit=Gtk.ContentFit.COVER, vexpand=True)
self.picture.add_css_class("map-picture")
self.append(self.picture)
self._info = None
if show_info:
self._info = Gtk.Label(label="Locating…", xalign=0.0)
self._info.add_css_class("map-info")
self.append(self._info)
ctx.services.location.subscribe(self._on_location)
def _on_location(self, data: dict) -> None:
lat, lon = data["lat"], data["lon"]
w, h = self.size
run_text([sys.executable, _SCRIPT, str(lat), str(lon), str(self.zoom),
str(w), str(h), self._out], self._on_rendered)
if self._info is not None:
city = data.get("city") or "Unknown"
country = data.get("country") or ""
self._info.set_text(f"{city}, {country} · {lat:.3f}, {lon:.3f}")
def _on_rendered(self, ok: bool, out: str, err: str) -> None:
if ok:
self.picture.set_filename(self._out)
def build(ctx: ModuleContext) -> ModuleInstance:
ctx.services.location.get() # kick off geolocation if not started
compact = _MapView(ctx, zoom=12, size=(640, 340), tag="compact", show_info=False)
expanded = _MapView(ctx, zoom=13, size=(1100, 620), tag="expanded", show_info=True)
return ModuleInstance(compact=compact, expanded=expanded, scroll_expanded=False)
SPEC = ModuleSpec(
id="location",
title="Location",
icon="", # nf-fa-map_marker
build=build,
features=[Feature("ip_locate", "Locate via IP", True)],
)