#!/usr/bin/env python3 import sys import os import logging import threading import task_manager APP_TITLE = "Org-mob" DOCS_PATH = os.environ["ORG_PATH"] STYLE_FILE_PATH = os.path.join( os.path.dirname(os.path.abspath(__file__)), "style.css") MIN_TITLE_WIDTH_CHARS = 10 import gi gi.require_version("Gtk", "4.0") gi.require_version('Polkit', '1.0') gi.require_version(namespace='Adw', version='1') from gi.repository import Gtk, Polkit, GObject, Gio, Adw, Gdk class MainWindow(Gtk.Window): ## Setup def __init__(self, *, title, application, task_manager, with_titlebar=True): super().__init__(title=title, application=application) self.application = application self.task_manager = task_manager self.loading = 0 if with_titlebar: self.header_bar = Gtk.HeaderBar() # self.header_bar.set_show_close_button(True) # self.header_bar.props.title = APP_TITLE self.set_titlebar(self.header_bar) self.progress_spinner = Gtk.Spinner() self.progress_spinner.start() self.header_bar.pack_end(self.progress_spinner) else: self.header_bar = None self.progress_spinner = None # self.main_box = Gtk.Box(name='main-box', vexpand=True, hexpand=True) self.scrollview = Gtk.ScrolledWindow(vexpand=True, hexpand=True) self.task_list = Gtk.ListBox(name='task-list') self.scrollview.set_child(self.task_list) # self.main_box.props.valign = Gtk.Align.CENTER # self.main_box.props.halign = Gtk.Align.CENTER # self.main_box.append(self.scrollview) # self.set_child(self.main_box) self.set_child(self.scrollview) self.loading += 1 self.task_manager.get_task_list(self.on_task_list_ready) ## Rendering def build_agenda_task_row(self, task): row = Gtk.ListBoxRow() hbox = Gtk.Box() state_button = Gtk.Button.new_with_label(task.state or '') state_button.props.css_classes = ('state-button',) state_button.connect("clicked", self.on_status_button_clicked) hbox.append(state_button) clock_button = Gtk.Button.new_with_label('C') clock_button.props.css_classes = ('clock-button',) clock_button.connect("clicked", self.on_clock_button_clicked) hbox.append(clock_button) # task_name_label = Gtk.Entry(text=task.title, width_chars=max(MIN_TITLE_WIDTH_CHARS, len(task.title))) task_name_label = Gtk.Label() task_name_label.set_text(task.title) task_name_label.props.css_classes = ('task-name',) hbox.append(task_name_label) row.set_child(hbox) return row def on_ready(self): self.loading -= 1 if self.loading < 0: self.loading = 0 elif self.loading == 0: if self.progress_spinner is not None: self.progress_spinner.stop() ## Callbacks def on_task_list_ready(self, agenda): # TODO: Avoid reconstructing the whole list every time i = 0 child = self.task_list.get_first_child() while child is not None: was = child child = child.get_next_sibling() i += 1 self.task_list.remove(was) for item in agenda.with_hour: self.task_list.append(self.build_agenda_task_row(item)) for item in agenda.no_hour: self.task_list.append(self.build_agenda_task_row(item)) self.on_ready() ## Reactions def on_status_button_clicked(self, button): print('Status button clicked: {}'.format(button)) def on_clock_button_clicked(self, button): print('Clock button clicked: {}'.format(button)) class Application(Gtk.Application): """ Main Aplication class """ def __init__(self): super().__init__(application_id='com.codigoparallevar.gtk4-organizer', flags=Gio.ApplicationFlags.FLAGS_NONE) self.task_manager = task_manager.TaskManager(DOCS_PATH) def do_activate(self): win = self.props.active_window if not win: if os.path.exists(STYLE_FILE_PATH): style_provider = Gtk.CssProvider() Gtk.StyleContext.add_provider_for_display(Gdk.Display.get_default(), style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) style_provider.load_from_path(STYLE_FILE_PATH) win = MainWindow( title=APP_TITLE, application=self, task_manager=self.task_manager, ) win.set_default_size(600, 400) win.present() def main(): """ Run the main application""" # GObject.threads_init() logging.basicConfig(level=logging.INFO, format="%(levelname)-8s %(message)s") app = Application() return app.run(sys.argv) if __name__ == '__main__': main()