usawa

Signed, immutable accounting.
Info | Log | Files | Refs | Submodules | LICENSE

commit c31162f69a68d11b9f79f137733bcfab3eace569
parent b5fda6e33acaa6dc3c34098a917aa9f537c3b405
Author: Carlosokumu <carlosokumu254@gmail.com>
Date:   Sat,  7 Mar 2026 15:27:54 +0300

show toast message on export

Diffstat:
Mdummy/usawa/gui/main_window.py | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 87 insertions(+), 18 deletions(-)

diff --git a/dummy/usawa/gui/main_window.py b/dummy/usawa/gui/main_window.py @@ -2,51 +2,120 @@ import logging from usawa.service import UnixClient from usawa.core.entry_service import EntryService from usawa.storage.ledger_repository import LedgerRepository -from gi.repository import Adw, Gtk +from gi.repository import Adw, Gtk, Gio from usawa.gui.controllers.entry_controller import EntryController from usawa.gui.views.entry_list_view import EntryListView +from datetime import datetime logg = logging.getLogger("gui.mainwindow") -class UsawaMainWindow(Gtk.ApplicationWindow): +class UsawaMainWindow(Adw.ApplicationWindow): - def __init__(self, application,ledger_path=None, **kwargs): + def __init__(self, application, ledger_path=None, **kwargs): super().__init__(application=application, **kwargs) - + self.set_title("Usawa") self.set_default_size(1000, 600) - # Main box - main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) - self.set_child(main_box) + + toolbar_view = Adw.ToolbarView() + self.set_content(toolbar_view) + + header = Adw.HeaderBar() + + menu_button = self._create_menu_button() + header.pack_end(menu_button) + + toolbar_view.add_top_bar(header) + + self.toast_overlay = Adw.ToastOverlay() + toolbar_view.set_content(self.toast_overlay) cfg = self.get_application().cfg self.client = UnixClient(path=cfg.get("SERVER_SOCKET_FILE_PATH")) - repository = LedgerRepository(ledger_path=ledger_path,unix_client=self.client,fs_path=cfg.get("FS_RESOLVER_STORE_PATH")) - + repository = LedgerRepository( + ledger_path=ledger_path, + unix_client=self.client, + fs_path=cfg.get("FS_RESOLVER_STORE_PATH"), + ) entry_service = EntryService(repository=repository) self.entry_controller = EntryController(entry_service=entry_service) self.entry_controller.add_entry_created_listener(self.refresh_entries) - # Navigation view self.nav_view = Adw.NavigationView() - main_box.append(self.nav_view) - + self.toast_overlay.set_child(self.nav_view) + entry_list_page = self._create_entry_list_page() self.nav_view.add(entry_list_page) + self._setup_actions() + + def _create_menu_button(self): + menu = Gio.Menu() + menu.append("Export Ledger", "app.export-ledger") + + menu_button = Gtk.MenuButton() + menu_button.set_icon_name("open-menu-symbolic") + menu_button.set_menu_model(menu) + menu_button.set_tooltip_text("Main menu") + + return menu_button + + def _setup_actions(self): + export_action = Gio.SimpleAction.new("export-ledger", None) + export_action.connect("activate", lambda a, p: self._on_export_clicked()) + self.get_application().add_action(export_action) + + def _on_export_clicked(self): + file_dialog = Gtk.FileDialog() + file_dialog.set_title("Export Ledger to XML") + default_name = f"ledger_export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xml" + file_dialog.set_initial_name(default_name) + + filters = Gio.ListStore.new(Gtk.FileFilter) + + xml_filter = Gtk.FileFilter() + xml_filter.set_name("XML Files") + xml_filter.add_pattern("*.xml") + filters.append(xml_filter) + + file_dialog.set_filters(filters) + file_dialog.set_default_filter(xml_filter) + + file_dialog.save(parent=self, callback=self._on_export_file_selected) + + def _on_export_file_selected(self, dialog, result): + try: + file = dialog.save_finish(result) + if file: + file_path = file.get_path() + success, error_msg = self.entry_controller.export_ledger(file_path) + + if success: + self._show_success_toast(f"Exported to {file_path}") + else: + self._show_error_dialog("Export Failed", error_msg) + except Exception as e: + logg.debug(f"Export cancelled: {e}") + + def _show_success_toast(self, message): + toast = Adw.Toast.new(message) + toast.set_timeout(3) + self.toast_overlay.add_toast(toast) def _create_entry_list_page(self): - page = Adw.NavigationPage( - title="Ledger Entries", - tag="entry-list" - ) + page = Adw.NavigationPage(title="Ledger Entries", tag="entry-list") entries = [] - self.entry_list_view = EntryListView(nav_view=self.nav_view,entry_controller=self.entry_controller,entries=entries,refresh_callback=self.refresh_entries) + self.entry_list_view = EntryListView( + nav_view=self.nav_view, + entry_controller=self.entry_controller, + entries=entries, + refresh_callback=self.refresh_entries, + ) self.entry_list_view._load_entries() page.set_child(self.entry_list_view) - + return page def refresh_entries(self):