main_window.py (4471B)
1 import logging 2 from usawa.service import UnixClient 3 from usawa.core.entry_service import EntryService 4 from usawa.storage.ledger_repository import LedgerRepository 5 from gi.repository import Adw, Gtk, Gio 6 7 from usawa.gui.controllers.entry_controller import EntryController 8 from usawa.gui.views.entry_list_view import EntryListView 9 from datetime import datetime 10 from whee.valkey import ValkeyStore 11 12 logg = logging.getLogger("gui.mainwindow") 13 14 15 class UsawaMainWindow(Adw.ApplicationWindow): 16 17 def __init__(self, application, ledger_path=None, **kwargs): 18 super().__init__(application=application, **kwargs) 19 20 self.set_title("Usawa") 21 self.set_default_size(1000, 600) 22 23 toolbar_view = Adw.ToolbarView() 24 self.set_content(toolbar_view) 25 26 header = Adw.HeaderBar() 27 28 menu_button = self._create_menu_button() 29 header.pack_end(menu_button) 30 31 toolbar_view.add_top_bar(header) 32 33 self.toast_overlay = Adw.ToastOverlay() 34 toolbar_view.set_content(self.toast_overlay) 35 36 cfg = self.get_application().cfg 37 self.client = UnixClient(path=cfg.get("SERVER_SOCKET_FILE_PATH")) 38 self.valkey_store = ValkeyStore( 39 "", host=cfg.get("VALKEY_HOST"), port=cfg.get("VALKEY_PORT") 40 ) 41 42 repository = LedgerRepository( 43 ledger_path=ledger_path, 44 unix_client=self.client, 45 valkey_store=self.valkey_store, 46 cfg=cfg, 47 ) 48 entry_service = EntryService(repository=repository) 49 self.entry_controller = EntryController(entry_service=entry_service) 50 self.entry_controller.add_entry_created_listener(self.refresh_entries) 51 52 self.nav_view = Adw.NavigationView() 53 self.toast_overlay.set_child(self.nav_view) 54 55 entry_list_page = self._create_entry_list_page() 56 self.nav_view.add(entry_list_page) 57 58 self._setup_actions() 59 60 def _create_menu_button(self): 61 menu = Gio.Menu() 62 menu.append("Export Ledger", "app.export-ledger") 63 64 menu_button = Gtk.MenuButton() 65 menu_button.set_icon_name("open-menu-symbolic") 66 menu_button.set_menu_model(menu) 67 menu_button.set_tooltip_text("Main menu") 68 69 return menu_button 70 71 def _setup_actions(self): 72 export_action = Gio.SimpleAction.new("export-ledger", None) 73 export_action.connect("activate", lambda a, p: self._on_export_clicked()) 74 self.get_application().add_action(export_action) 75 76 def _on_export_clicked(self): 77 file_dialog = Gtk.FileDialog() 78 file_dialog.set_title("Export Ledger to XML") 79 default_name = f"ledger_export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xml" 80 file_dialog.set_initial_name(default_name) 81 82 filters = Gio.ListStore.new(Gtk.FileFilter) 83 84 xml_filter = Gtk.FileFilter() 85 xml_filter.set_name("XML Files") 86 xml_filter.add_pattern("*.xml") 87 filters.append(xml_filter) 88 89 file_dialog.set_filters(filters) 90 file_dialog.set_default_filter(xml_filter) 91 92 file_dialog.save(parent=self, callback=self._on_export_file_selected) 93 94 def _on_export_file_selected(self, dialog, result): 95 try: 96 file = dialog.save_finish(result) 97 if file: 98 file_path = file.get_path() 99 success, error_msg = self.entry_controller.export_ledger(file_path) 100 101 if success: 102 self._show_success_toast(f"Exported to {file_path}") 103 else: 104 self._show_error_dialog("Export Failed", error_msg) 105 except Exception as e: 106 logg.debug(f"Export cancelled: {e}") 107 108 def _show_success_toast(self, message): 109 toast = Adw.Toast.new(message) 110 toast.set_timeout(3) 111 self.toast_overlay.add_toast(toast) 112 113 def _create_entry_list_page(self): 114 page = Adw.NavigationPage(title="Ledger Entries", tag="entry-list") 115 entries = [] 116 self.entry_list_view = EntryListView( 117 nav_view=self.nav_view, 118 entry_controller=self.entry_controller, 119 entries=entries, 120 refresh_callback=self.refresh_entries, 121 toast_overlay=self.toast_overlay, 122 ) 123 self.entry_list_view._load_entries() 124 page.set_child(self.entry_list_view) 125 126 return page 127 128 def refresh_entries(self): 129 logg.info("MainWindow refreshing entries") 130 self.entry_list_view._load_entries()