commit 77c97cda7c28dad92778e46a85dc36eccaee0547
parent 1a67eb53a015f59e1d5af04c31af5a44ce39871a
Author: lash <dev@holbrook.no>
Date: Sun, 31 Aug 2025 21:58:21 +0100
Introduce config, move gui to package
Diffstat:
5 files changed, 208 insertions(+), 167 deletions(-)
diff --git a/gui/base.py b/gui/base.py
@@ -1,166 +0,0 @@
-import sys
-import logging
-import gettext
-import markdown
-
-import gi
-gi.require_version('Gtk', '4.0')
-gi.require_version('Adw', '1')
-from gi.repository import Gtk, Adw, Gio
-
-from ungana.ical import ICalManager
-
-logging.basicConfig(level=logging.DEBUG)
-logg = logging.getLogger()
-
-_ = gettext.gettext
-
-menu_src = """
-<?xml version="1.0" encoding="UTF-8"?>
-<interface>
-<menu id="menubar">
- <submenu>
- <attribute name="label" translatable="yes">Edit</attribute>
- <section>
- <item>
- <attribute name="action">win.settings</attribute>
- <attribute name="target">Settings</attribute>
- <attribute name="label" translatable="yes">Settings</attribute>
- </item>
- </section>
- </submenu>
-</menu>
-</interface>
-"""
-
-class MainWindow(Gtk.ApplicationWindow):
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.props.show_menubar = True
- self.cal = None
- self.box_main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
- self.set_child(self.box_main)
-
- title = Gtk.Label(label="UUID")
- self.box_main.append(title)
- entry = Gtk.Entry()
- entry.set_editable(False)
- entry.set_sensitive(False)
- self.entry_uuid = entry
- self.box_main.append(entry)
-
- title = Gtk.Label(label="Domain")
- self.box_main.append(title)
- entry = Gtk.Entry()
- self.entry_domain = entry
- self.box_main.append(entry)
-
- title = Gtk.Label(label="Summary")
- self.box_main.append(title)
- entry = Gtk.Entry()
- self.entry_summary = entry
- self.box_main.append(entry)
-
- title = Gtk.Label(label="Description")
- self.box_main.append(title)
- entry = Gtk.Entry()
- self.box_main.append(entry)
-
- title = Gtk.Label(label="Start")
- self.box_main.append(title)
- entry = Gtk.Entry(placeholder_text="YYYY-MM-DD HH:MM")
- self.box_main.append(entry)
-
- title = Gtk.Label(label="Duration")
- self.box_main.append(title)
- entry = Gtk.Entry(placeholder_text="")
- self.box_main.append(entry)
-
- title = Gtk.Label(label="Banner")
- self.box_main.append(title)
-
-
- fltr = Gtk.FileFilter()
- fltr.set_name("Images")
- fltr.add_mime_type("image/*")
- fltrs = Gio.ListStore.new(Gtk.FileFilter)
- fltrs.append(fltr)
- self.filedialog = Gtk.FileDialog.new()
- self.filedialog.set_filters(fltrs)
- self.filedialog.set_default_filter(fltr)
-
- img = Gtk.Image()
- self.img = img
- self.box_main.append(img)
- self.img.set_size_request(0, 200)
-
- entry = Gtk.Button(label="Open")
- entry.connect('clicked', self.show_open_dialog)
- self.box_main.append(entry)
-
- self.status = Gtk.Statusbar()
- self.box_main.append(self.status)
-
-
- def show_open_dialog(self, button):
- self.filedialog.open(self, None, self.open_dialog_callback)
-
-
- def open_dialog_callback(self, dialog, result):
- try:
- f = dialog.open_finish(result)
- if f is not None:
- self.img.set_from_file(f.get_path())
- 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)
-
- v = ev.get('summary')
- self.entry_summary.set_text(v)
-
- v = ev.get('uid')
- (uid, domain) = v.split('@')
- 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))
-
-
-class Ungana(Adw.Application):
- def __init__(self, initial_calendar=None, *args, **kwargs):
- super().__init__(flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE, **kwargs)
- self.file = initial_calendar
- self.win = None
- self.connect('activate', self.on_activate)
-
- def do_startup(self):
- Adw.Application.do_startup(self)
- builder = Gtk.Builder.new_from_string(menu_src, -1)
- self.set_menubar(builder.get_object("menubar"))
-
-
- def on_activate(self, app):
- logg.debug("activate")
- self.win = MainWindow(application=app)
- self.win.load(self.file)
- self.win.present()
-
-
- def do_command_line(self, cli):
- o = cli.get_options_dict()
- logg.debug(o)
- self.activate()
- return 0
-
-
-#gettext.install(gettext.translation("ungana", localedir="locale", languages=['es']))
-gettext.bindtextdomain("messages", "locales")
-gettext.textdomain("messages")
-app = Ungana(application_id="org.defalsify.ungana", initial_calendar=sys.argv[1])
-app.run(sys.argv)
diff --git a/pyproject.toml b/pyproject.toml
@@ -8,7 +8,8 @@ version = "0.1.0"
description = "Client application that creates customized .ics files for ticket booking and event reservations"
requires-python = ">=3.8"
dependencies = [
- "icalendar>=5.0.0",
+ "icalendar>=5.0.0",
+ "confini~=0.6.5",
]
[project.optional-dependencies]
@@ -23,3 +24,8 @@ ungana = "ungana.runnable.ungana_cal_cli:main"
[tool.setuptools.packages.find]
where = ["."]
include = ["ungana*"]
+
+[tool.setuptools.package-data]
+ungana = [
+ "ungana/data/*"
+]
diff --git a/ungana/config.py b/ungana/config.py
@@ -0,0 +1,9 @@
+import os
+import confini
+
+__datadir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data")
+
+def load():
+ cfg = confini.Config(__datadir)
+ cfg.process()
+ return cfg
diff --git a/ungana/data/config.ini b/ungana/data/config.ini
@@ -0,0 +1,3 @@
+[base]
+domain = nondominium.org
+zone = America/El_Salvador
diff --git a/ungana/gui/base.py b/ungana/gui/base.py
@@ -0,0 +1,189 @@
+import sys
+import logging
+import gettext
+import zoneinfo
+
+import markdown
+import gi
+gi.require_version('Gtk', '4.0')
+gi.require_version('Adw', '1')
+from gi.repository import Gtk, Adw, Gio
+
+from ungana.ical import ICalManager
+from ungana.config import load as load_config
+
+logging.basicConfig(level=logging.DEBUG)
+logg = logging.getLogger()
+
+_ = gettext.gettext
+
+menu_src = """
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+<menu id="menubar">
+ <submenu>
+ <attribute name="label" translatable="yes">Edit</attribute>
+ <section>
+ <item>
+ <attribute name="action">win.settings</attribute>
+ <attribute name="target">Settings</attribute>
+ <attribute name="label" translatable="yes">Settings</attribute>
+ </item>
+ </section>
+ </submenu>
+</menu>
+</interface>
+"""
+
+class MainWindow(Gtk.ApplicationWindow):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+
+ self.props.show_menubar = True
+ self.cal = None
+ self.box_main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
+ self.set_child(self.box_main)
+
+ title = Gtk.Label(label="UUID")
+ self.box_main.append(title)
+ entry = Gtk.Entry()
+ entry.set_editable(False)
+ entry.set_sensitive(False)
+ self.entry_uuid = entry
+ self.box_main.append(entry)
+
+ title = Gtk.Label(label="Domain")
+ self.box_main.append(title)
+ entry = Gtk.Entry()
+ self.entry_domain = entry
+ self.box_main.append(entry)
+
+ title = Gtk.Label(label="Summary")
+ self.box_main.append(title)
+ entry = Gtk.Entry()
+ self.entry_summary = entry
+ self.box_main.append(entry)
+
+ title = Gtk.Label(label="Description")
+ self.box_main.append(title)
+ entry = Gtk.Entry()
+ self.box_main.append(entry)
+
+ title = Gtk.Label(label="Time zone")
+ self.box_main.append(title)
+ entry = Gtk.DropDown()
+ entry.set_enable_search(True)
+ zones = Gtk.StringList()
+ entry.props.model = zones
+ zonedata = zoneinfo.available_timezones()
+ i = 0
+ for v in sorted(zonedata):
+ zones.append(v)
+ if v == self.get_application().cfg.get('BASE_ZONE'):
+ entry.props.selected = i
+ logg.debug("timezone default: {}".format(v))
+ i += 1
+ self.box_main.append(entry)
+
+ title = Gtk.Label(label="Start")
+ self.box_main.append(title)
+ entry = Gtk.Entry(placeholder_text="YYYY-MM-DD HH:MM")
+ self.box_main.append(entry)
+
+ title = Gtk.Label(label="Duration")
+ self.box_main.append(title)
+ entry = Gtk.Entry(placeholder_text="")
+ self.box_main.append(entry)
+
+ title = Gtk.Label(label="Banner")
+ self.box_main.append(title)
+
+
+ fltr = Gtk.FileFilter()
+ fltr.set_name("Images")
+ fltr.add_mime_type("image/*")
+ fltrs = Gio.ListStore.new(Gtk.FileFilter)
+ fltrs.append(fltr)
+ self.filedialog = Gtk.FileDialog.new()
+ self.filedialog.set_filters(fltrs)
+ self.filedialog.set_default_filter(fltr)
+
+ img = Gtk.Image()
+ self.img = img
+ self.box_main.append(img)
+ self.img.set_size_request(0, 200)
+
+ entry = Gtk.Button(label="Open")
+ entry.connect('clicked', self.show_open_dialog)
+ self.box_main.append(entry)
+
+ self.status = Gtk.Statusbar()
+ self.box_main.append(self.status)
+
+
+ def show_open_dialog(self, button):
+ self.filedialog.open(self, None, self.open_dialog_callback)
+
+
+ def open_dialog_callback(self, dialog, result):
+ try:
+ f = dialog.open_finish(result)
+ if f is not None:
+ self.img.set_from_file(f.get_path())
+ 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)
+
+ v = ev.get('summary')
+ self.entry_summary.set_text(v)
+
+ v = ev.get('uid')
+ (uid, domain) = v.split('@')
+ 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))
+
+
+class Ungana(Adw.Application):
+ def __init__(self, initial_calendar=None, *args, **kwargs):
+ super().__init__(flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE, **kwargs)
+ self.file = initial_calendar
+ self.win = None
+ self.cfg = None
+ self.connect('activate', self.on_activate)
+
+
+ def do_startup(self):
+ Adw.Application.do_startup(self)
+ builder = Gtk.Builder.new_from_string(menu_src, -1)
+ self.set_menubar(builder.get_object("menubar"))
+
+
+ def on_activate(self, app):
+ logg.debug("activate")
+ self.win = MainWindow(application=app)
+ self.win.load(self.file)
+ self.win.present()
+
+
+ def do_command_line(self, cli):
+ o = cli.get_options_dict()
+ logg.debug(o)
+ self.cfg = load_config()
+ for k in self.cfg.all():
+ logg.debug("config {} => {}".format(k, self.cfg.get(k)))
+ self.activate()
+ return 0
+
+
+#gettext.install(gettext.translation("ungana", localedir="locale", languages=['es']))
+gettext.bindtextdomain("messages", "locales")
+gettext.textdomain("messages")
+app = Ungana(application_id="org.defalsify.ungana", initial_calendar=sys.argv[1])
+app.run(sys.argv)