ungana

Unnamed repository; edit this file 'description' to name the repository.
Info | Log | Files | Refs | README

commit d9755f43205d01115ee9293e0bbda3f3f6ffc3a8
parent 995f34c06c222129bf0e738d4f0fb4c6b65b2900
Author: lash <dev@holbrook.no>
Date:   Tue,  2 Sep 2025 14:47:31 +0100

Set up textview for description

Diffstat:
Mungana/attachment/attachment_manager.py | 4++--
Mungana/config.py | 3++-
Mungana/data/config.ini | 1+
Mungana/gui/event.py | 72+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mungana/gui/main.py | 1-
Mungana/gui/win.py | 37+++++++++++++++++++++++++++++++------
6 files changed, 101 insertions(+), 17 deletions(-)

diff --git a/ungana/attachment/attachment_manager.py b/ungana/attachment/attachment_manager.py @@ -41,10 +41,11 @@ class AttachmentManager: if ctx == "long" and not (mime_type and mime_type.startswith("text/")): raise ValueError(f"Long attachment must be a text file, got {mime_type}") + def digest(self, file_path: str) -> str: """Return SHA256 digest of the file content.""" h = hashlib.sha256() with open(file_path, "rb") as f: for chunk in iter(lambda: f.read(4096), b""): h.update(chunk) - return h.hexdigest() -\ No newline at end of file + return h.hexdigest() diff --git a/ungana/config.py b/ungana/config.py @@ -7,7 +7,8 @@ __datadir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data") def load(): cfg = confini.Config(__datadir) cfg.process() - if not cfg.have('BASE_DATAPATH'): + if not cfg.get('BASE_DATAPATH', None): datapath = save_data_path('ungana') cfg.add(datapath, 'BASE_DATAPATH') + return cfg diff --git a/ungana/data/config.ini b/ungana/data/config.ini @@ -1,4 +1,5 @@ [base] domain = nondominium.org zone = America/El_Salvador +uuid = '968ece79-5ce7-4e97-8cbc-67c59419222a' datapath = diff --git a/ungana/gui/event.py b/ungana/gui/event.py @@ -1,11 +1,18 @@ +import logging +import zoneinfo + import gi gi.require_version('Gtk', '4.0') gi.require_version('Adw', '1') from gi.repository import Gtk, Adw, Gio +from ungana.i18n import _ + +logg = logging.getLogger("gui.event") + class EventWindow(Gtk.Window): - def __init__(self, *args, **kwargs): + def __init__(self, zone=None, *args, **kwargs): super().__init__(*args, **kwargs) self.cal = None @@ -34,7 +41,9 @@ class EventWindow(Gtk.Window): title = Gtk.Label(label="Description") self.box_main.append(title) - entry = Gtk.Entry() + entry = Gtk.TextView() + entry.set_size_request(0, 100) + entry.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) self.box_main.append(entry) title = Gtk.Label(label="Time zone") @@ -47,7 +56,7 @@ class EventWindow(Gtk.Window): i = 0 for v in sorted(zonedata): zones.append(v) - if v == self.get_application().cfg.get('BASE_ZONE'): + if v == zone: entry.props.selected = i logg.debug("timezone default: {}".format(v)) i += 1 @@ -85,6 +94,34 @@ class EventWindow(Gtk.Window): entry.connect('clicked', self.show_open_dialog) self.box_main.append(entry) + title = Gtk.Label(label="Geo coordinates") + self.box_main.append(title) + entry = Gtk.Entry(placeholder_text="lat") + entry.set_input_purpose(Gtk.InputPurpose.NUMBER) + self.entry_geo_lat = entry + self.box_main.append(entry) + entry = Gtk.Entry(placeholder_text="lon") + entry.set_input_purpose(Gtk.InputPurpose.NUMBER) + self.entry_geo_lon = entry + self.box_main.append(entry) + + title = Gtk.Label(label="Host URL") + self.box_main.append(title) + entry = Gtk.Entry(placeholder_text="http://") + self.entry_url_host = entry + self.box_main.append(entry) + + title = Gtk.Label(label="Presenter URL") + self.box_main.append(title) + entry = Gtk.Entry(placeholder_text="http://") + self.entry_url_presenter = entry + self.box_main.append(entry) + + title = Gtk.Label(label="Location URL") + self.box_main.append(title) + entry = Gtk.Entry(placeholder_text="http://") + self.box_main.append(entry) + self.status = Gtk.Statusbar() self.box_main.append(self.status) @@ -101,11 +138,19 @@ class EventWindow(Gtk.Window): except GLib.Error as e: logg.error("error open: {}".format(e)) + def load(self, fp): self.cal = ICalManager() self.cal.load_ical_file(fp) ev = self.cal.get_first_event(self.cal.calendar) + status_id = self.status.get_context_id("ical") + self.status.push(status_id, "{} {:s}: {}@{}".format(_("Loaded event from ical file"), fp, uid, domain)) + + self.update(ev) + + + def update(self, ev): v = ev.get('summary') self.entry_summary.set_text(v) @@ -114,7 +159,20 @@ class EventWindow(Gtk.Window): self.entry_uuid.set_text(uid) self.entry_domain.set_text(domain) - status_id = self.status.get_context_id("ical") - self.status.push(status_id, "{} {:s}: {}@{}".format(_("Loaded event from ical file"), fp, uid, domain)) - - + v = ev.get('geo') + self.entry_geo_lat.set_text(str(v.latitude)) + self.entry_geo_lon.set_text(str(v.longitude)) + + for v in ev.content_lines(): + r = None + try: + r = v.parts() + except: + continue + if r[0] == 'URL': + for k in r[1].params(): + if k == 'ROLE': + if r[1][k] == 'PRESENTER': + self.entry_url_presenter.set_text(r[2]) + elif r[1][k] == 'HOST': + self.entry_url_host.set_text(r[2]) diff --git a/ungana/gui/main.py b/ungana/gui/main.py @@ -59,4 +59,3 @@ class UnganaGui(Adw.Application): logg.debug("config {} => {}".format(k, self.cfg.get(k))) self.activate() return 0 - diff --git a/ungana/gui/win.py b/ungana/gui/win.py @@ -11,10 +11,11 @@ import icalendar import gi gi.require_version('Gtk', '4.0') gi.require_version('Adw', '1') -from gi.repository import Gtk, Adw, Gio, GObject +from gi.repository import Gtk, Gdk, Adw, Gio, GObject from ungana.i18n import _ from ungana.ical import ICalManager +from .event import EventWindow logg = logging.getLogger("gui.win") @@ -49,7 +50,19 @@ class WindowEvent(GObject.GObject): def when(self): - return "fii" + s = None + for v in self.ev.decoded('dtstart'): + zone = v.tzinfo.tzname(v) + logg.debug("zz {} {}".format(zone, type(v))) + if s == None: + s = '{} (UTC)'.format(v.ctime()) + elif zone != 'UTC': + s = '{} ({})'.format(v.ctime(), v.tzname()) + return s + + + def event(self): + return self.ev def event_item_setup(widget, item): @@ -119,20 +132,32 @@ class MainWindow(Gtk.ApplicationWindow): factory_date.connect("setup", event_item_setup) factory_date.connect("bind", event_date_bind) - rendererTxt = Gtk.CellRendererText() + #rendererTxt = Gtk.CellRendererText() # TODO: is there a row equivalent to set up? col = Gtk.ColumnViewColumn.new(_("Event"), factory_head) #col = Gtk.TreeViewColumn(_("Events"), rendererTxt, text=0) self.view.append_column(col) + col = Gtk.ColumnViewColumn.new(_("Date"), factory_date) + self.view.append_column(col) col = Gtk.ColumnViewColumn.new(_("UUID"), factory_uuid) self.view.append_column(col) col = Gtk.ColumnViewColumn.new(_("Domain"), factory_domain) self.view.append_column(col) - col = Gtk.ColumnViewColumn.new(_("Date"), factory_date) - self.view.append_column(col) + self.view.connect('activate', self.event_activate) self.box_main.append(self.view) - + + def event_activate(self, widget, idx): + o = widget.get_model().get_selected_item() + ev = o.event() + cfg = self.get_application().cfg + win = EventWindow(zone=cfg.get("BASE_ZONE")) + win.set_transient_for(self) + win.set_size_request(800, 600) + win.update(ev) + win.present() + + def add_event(self, ev): logg.info("adding event {}".format(str(ev))) o = WindowEvent(ev)