main_window.py (5211B)
1 import logging 2 from usawa.crypto import DemoWallet 3 from usawa.gui.components.passphrase_dialog import ( 4 PASSPHRASE_DIALOG_CSS, 5 PassphraseDialog, 6 ) 7 from .core.entry_service import EntryService 8 from usawa.storage.ledger_repository import LedgerRepository 9 from gi.repository import Adw, Gtk, Gio, GLib, Gdk 10 from usawa.gui.controllers.entry_controller import EntryController 11 from usawa.gui.views.entry_list_view import EntryListView 12 from datetime import datetime 13 import usawa.error 14 15 logg = logging.getLogger("gui.mainwindow") 16 17 18 class UsawaMainWindow(Adw.ApplicationWindow): 19 20 def __init__(self, application, ctx, **kwargs): 21 super().__init__(application=application, **kwargs) 22 23 self.set_title("Usawa") 24 self.set_default_size(1000, 600) 25 26 toolbar_view = Adw.ToolbarView() 27 self.set_content(toolbar_view) 28 29 header = Adw.HeaderBar() 30 31 menu_button = self._create_menu_button() 32 header.pack_end(menu_button) 33 34 toolbar_view.add_top_bar(header) 35 36 self.toast_overlay = Adw.ToastOverlay() 37 toolbar_view.set_content(self.toast_overlay) 38 39 self.ctx = ctx 40 41 self.nav_view = Adw.NavigationView() 42 self.toast_overlay.set_child(self.nav_view) 43 44 self._setup_actions() 45 GLib.idle_add(self._check_wallet_status) 46 47 def _create_menu_button(self): 48 menu = Gio.Menu() 49 menu.append("Export Ledger", "app.export-ledger") 50 51 menu_button = Gtk.MenuButton() 52 menu_button.set_icon_name("open-menu-symbolic") 53 menu_button.set_menu_model(menu) 54 menu_button.set_tooltip_text("Main menu") 55 56 return menu_button 57 58 def _setup_actions(self): 59 export_action = Gio.SimpleAction.new("export-ledger", None) 60 export_action.connect("activate", lambda a, p: self._on_export_clicked()) 61 self.get_application().add_action(export_action) 62 63 def _on_export_clicked(self): 64 file_dialog = Gtk.FileDialog() 65 file_dialog.set_title("Export Ledger to XML") 66 default_name = f"ledger_export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xml" 67 file_dialog.set_initial_name(default_name) 68 69 filters = Gio.ListStore.new(Gtk.FileFilter) 70 71 xml_filter = Gtk.FileFilter() 72 xml_filter.set_name("XML Files") 73 xml_filter.add_pattern("*.xml") 74 filters.append(xml_filter) 75 76 file_dialog.set_filters(filters) 77 file_dialog.set_default_filter(xml_filter) 78 79 file_dialog.save(parent=self, callback=self._on_export_file_selected) 80 81 def _on_export_file_selected(self, dialog, result): 82 try: 83 file = dialog.save_finish(result) 84 if file: 85 file_path = file.get_path() 86 success, error_msg = self.entry_controller.export_ledger(file_path) 87 88 if success: 89 self._show_success_toast(f"Exported to {file_path}") 90 else: 91 self._show_error_dialog("Export Failed", error_msg) 92 except Exception as e: 93 logg.debug(f"Export cancelled: {e}") 94 95 def _show_success_toast(self, message): 96 toast = Adw.Toast.new(message) 97 toast.set_timeout(3) 98 self.toast_overlay.add_toast(toast) 99 100 def _create_entry_list_page(self): 101 page = Adw.NavigationPage(title="Ledger Entries", tag="entry-list") 102 entries = [] 103 self.entry_list_view = EntryListView( 104 ctx=self.ctx, 105 nav_view=self.nav_view, 106 entry_controller=self.entry_controller, 107 entries=entries, 108 refresh_callback=self.refresh_entries, 109 toast_overlay=self.toast_overlay, 110 ) 111 self.entry_list_view._load_entries() 112 page.set_child(self.entry_list_view) 113 114 return page 115 116 def refresh_entries(self): 117 logg.info("MainWindow refreshing entries") 118 self.entry_list_view._load_entries() 119 120 def _check_wallet_status(self): 121 try: 122 self.ctx.load_wallet(replace=True, signing=True) 123 self._init_with_wallet() 124 except usawa.error.VerifyError: 125 dialog = PassphraseDialog( 126 # store=self.ctx.keystore, 127 ctx=self.ctx, 128 wallet_class=DemoWallet, 129 on_success=self._init_with_wallet, 130 on_cancel=self._on_wallet_cancelled, 131 ) 132 dialog.present(self) 133 134 def _init_with_wallet(self): 135 repository = LedgerRepository(self.ctx) 136 entry_service = EntryService(repository=repository) 137 self.entry_controller = EntryController( 138 ctx=self.ctx, entry_service=entry_service 139 ) 140 self.entry_controller.add_entry_created_listener(self.refresh_entries) 141 142 entry_list_page = self._create_entry_list_page() 143 self.nav_view.add(entry_list_page) 144 145 def _on_wallet_cancelled(self): 146 self.get_application().quit() 147 148 def _load_css(self): 149 css_provider = Gtk.CssProvider() 150 css_provider.load_from_string(PASSPHRASE_DIALOG_CSS) 151 Gtk.StyleContext.add_provider_for_display( 152 Gdk.Display.get_default(), 153 css_provider, 154 Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION, 155 )