2021-12-22 21:44:34 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import sys
|
2021-12-26 19:57:59 +00:00
|
|
|
import os
|
|
|
|
import logging
|
|
|
|
import threading
|
|
|
|
|
|
|
|
import task_manager
|
2022-03-27 22:44:33 +00:00
|
|
|
import emacs_client
|
2021-12-26 19:57:59 +00:00
|
|
|
|
2022-03-27 21:46:17 +00:00
|
|
|
APP_TITLE = "Org-Convergence"
|
2021-12-26 19:57:59 +00:00
|
|
|
DOCS_PATH = os.environ["ORG_PATH"]
|
2021-12-26 20:09:20 +00:00
|
|
|
STYLE_FILE_PATH = os.path.join(
|
|
|
|
os.path.dirname(os.path.abspath(__file__)),
|
|
|
|
"style.css")
|
2021-12-26 19:57:59 +00:00
|
|
|
|
2021-12-27 19:28:24 +00:00
|
|
|
MIN_TITLE_WIDTH_CHARS = 10
|
|
|
|
|
2021-12-22 21:44:34 +00:00
|
|
|
import gi
|
|
|
|
|
|
|
|
gi.require_version("Gtk", "4.0")
|
|
|
|
gi.require_version('Polkit', '1.0')
|
2021-12-26 19:57:59 +00:00
|
|
|
gi.require_version(namespace='Adw', version='1')
|
|
|
|
|
2021-12-26 20:09:20 +00:00
|
|
|
from gi.repository import Gtk, Polkit, GObject, Gio, Adw, Gdk
|
2021-12-22 21:44:34 +00:00
|
|
|
|
|
|
|
class MainWindow(Gtk.Window):
|
2022-03-27 22:44:33 +00:00
|
|
|
__gsignals__ = {
|
|
|
|
"open-in-emacs": (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (object, )),
|
|
|
|
}
|
2021-12-27 19:28:24 +00:00
|
|
|
|
|
|
|
## Setup
|
|
|
|
def __init__(self, *, title, application, task_manager, with_titlebar=True):
|
2021-12-22 21:44:34 +00:00
|
|
|
super().__init__(title=title, application=application)
|
2021-12-26 19:57:59 +00:00
|
|
|
self.application = application
|
|
|
|
self.task_manager = task_manager
|
2021-12-27 19:28:24 +00:00
|
|
|
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
|
|
|
|
|
2022-03-25 00:47:20 +00:00
|
|
|
# self.main_box = Gtk.Box(name='main-box', vexpand=True, hexpand=True)
|
|
|
|
self.scrollview = Gtk.ScrolledWindow(vexpand=True, hexpand=True)
|
|
|
|
|
2021-12-27 19:28:24 +00:00
|
|
|
self.task_list = Gtk.ListBox(name='task-list')
|
2022-03-25 00:47:20 +00:00
|
|
|
self.scrollview.set_child(self.task_list)
|
2022-03-27 22:44:33 +00:00
|
|
|
self.item_rows = []
|
2021-12-27 19:28:24 +00:00
|
|
|
|
2022-03-25 00:47:20 +00:00
|
|
|
# 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)
|
2021-12-27 19:28:24 +00:00
|
|
|
|
|
|
|
self.loading += 1
|
2022-03-27 21:44:58 +00:00
|
|
|
self.task_manager.get_task_list(
|
|
|
|
self.on_task_list_update,
|
|
|
|
self.on_task_list_ready,
|
|
|
|
)
|
2021-12-22 21:44:34 +00:00
|
|
|
|
2022-03-27 22:44:33 +00:00
|
|
|
## Keyboard shortcuts
|
|
|
|
def open_in_emacs(self, *args):
|
|
|
|
row = self.task_list.get_selected_row()
|
|
|
|
if row is None:
|
|
|
|
return
|
|
|
|
item = self.item_rows[row.get_index()]
|
|
|
|
item_id = item.id
|
|
|
|
if item_id is None:
|
|
|
|
logging.warning("No ID found for item: {}".format(item))
|
|
|
|
return
|
|
|
|
emacs_client.navigate_emacs_to_id(item_id)
|
|
|
|
|
|
|
|
|
2021-12-27 19:28:24 +00:00
|
|
|
## Rendering
|
2021-12-26 19:57:59 +00:00
|
|
|
def build_agenda_task_row(self, task):
|
2021-12-22 21:44:34 +00:00
|
|
|
row = Gtk.ListBoxRow()
|
2021-12-27 19:28:24 +00:00
|
|
|
hbox = Gtk.Box()
|
2021-12-22 21:44:34 +00:00
|
|
|
|
2021-12-26 19:57:59 +00:00
|
|
|
state_button = Gtk.Button.new_with_label(task.state or '')
|
2021-12-27 19:28:24 +00:00
|
|
|
state_button.props.css_classes = ('state-button',)
|
|
|
|
state_button.connect("clicked", self.on_status_button_clicked)
|
2021-12-26 19:57:59 +00:00
|
|
|
hbox.append(state_button)
|
|
|
|
|
2021-12-27 19:28:24 +00:00
|
|
|
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)
|
|
|
|
|
2022-03-25 00:47:20 +00:00
|
|
|
# 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)
|
2021-12-27 19:28:24 +00:00
|
|
|
task_name_label.props.css_classes = ('task-name',)
|
2021-12-26 19:57:59 +00:00
|
|
|
hbox.append(task_name_label)
|
|
|
|
|
|
|
|
row.set_child(hbox)
|
2022-03-25 00:47:20 +00:00
|
|
|
|
2022-03-27 21:44:58 +00:00
|
|
|
return row
|
2021-12-22 21:44:34 +00:00
|
|
|
|
2021-12-27 19:28:24 +00:00
|
|
|
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
|
2022-03-27 21:44:58 +00:00
|
|
|
def on_task_list_update(self, new_rows):
|
|
|
|
for item in new_rows.with_hour:
|
2021-12-26 19:57:59 +00:00
|
|
|
self.task_list.append(self.build_agenda_task_row(item))
|
2022-03-27 22:44:33 +00:00
|
|
|
self.item_rows.append(item)
|
2021-12-22 21:44:34 +00:00
|
|
|
|
2022-03-27 21:44:58 +00:00
|
|
|
for item in new_rows.no_hour:
|
2021-12-26 19:57:59 +00:00
|
|
|
self.task_list.append(self.build_agenda_task_row(item))
|
2022-03-27 22:44:33 +00:00
|
|
|
self.item_rows.append(item)
|
2022-03-27 21:44:58 +00:00
|
|
|
|
|
|
|
def on_task_list_ready(self, success):
|
2021-12-27 19:28:24 +00:00
|
|
|
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))
|
2021-12-22 21:44:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Application(Gtk.Application):
|
|
|
|
""" Main Aplication class """
|
|
|
|
|
|
|
|
def __init__(self):
|
2022-03-27 21:46:17 +00:00
|
|
|
super().__init__(application_id='com.codigoparallevar.org-convergence',
|
2021-12-22 21:44:34 +00:00
|
|
|
flags=Gio.ApplicationFlags.FLAGS_NONE)
|
2021-12-26 19:57:59 +00:00
|
|
|
self.task_manager = task_manager.TaskManager(DOCS_PATH)
|
2021-12-22 21:44:34 +00:00
|
|
|
|
|
|
|
def do_activate(self):
|
|
|
|
win = self.props.active_window
|
|
|
|
if not win:
|
2021-12-26 20:09:20 +00:00
|
|
|
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)
|
|
|
|
|
2021-12-26 19:57:59 +00:00
|
|
|
win = MainWindow(
|
|
|
|
title=APP_TITLE,
|
|
|
|
application=self,
|
|
|
|
task_manager=self.task_manager,
|
|
|
|
)
|
2022-03-27 21:34:01 +00:00
|
|
|
|
|
|
|
# PinePhone screen is 720x1440 (portrait) but, has 2x pixel density
|
|
|
|
win.set_default_size(360, 720)
|
2021-12-26 20:09:20 +00:00
|
|
|
|
2022-03-27 22:44:33 +00:00
|
|
|
## Load shortcuts
|
|
|
|
# Open in emacs
|
|
|
|
action = Gio.SimpleAction.new("open-in-emacs", None)
|
|
|
|
action.connect("activate", win.open_in_emacs)
|
|
|
|
self.add_action(action)
|
|
|
|
|
|
|
|
self.set_accels_for_action('app.open-in-emacs', ["<Ctrl>e"])
|
|
|
|
|
|
|
|
|
2021-12-22 21:44:34 +00:00
|
|
|
win.present()
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
""" Run the main application"""
|
2022-03-25 00:47:20 +00:00
|
|
|
# GObject.threads_init()
|
2021-12-26 19:57:59 +00:00
|
|
|
logging.basicConfig(level=logging.INFO, format="%(levelname)-8s %(message)s")
|
2021-12-22 21:44:34 +00:00
|
|
|
app = Application()
|
|
|
|
return app.run(sys.argv)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|