diff --git a/src/main.py b/src/main.py index e6eab8d..0ac6e29 100644 --- a/src/main.py +++ b/src/main.py @@ -24,7 +24,6 @@ from pathology_management_window import PathologyManagementWindow from pathology_manager import PathologyManager from preferences import get_config_dir, get_pref, save_preferences, set_pref from search_filter import DataFilter -from search_filter_ui import SearchFilterWidget from settings_window import SettingsWindow from theme_manager import ThemeManager from ui_manager import UIManager @@ -346,6 +345,8 @@ class MedTrackerApp: # --- Main Frame --- main_frame: ttk.Frame = ttk.Frame(self.root, padding="10", style="Card.TFrame") main_frame.grid(row=0, column=0, sticky="nsew") + # Store for lazy child creation (search panel) + self.main_frame = main_frame # Configure root window grid self.root.grid_rowconfigure(0, weight=1) @@ -400,19 +401,14 @@ class MedTrackerApp: self.tree: ttk.Treeview = table_ui["tree"] self.tree.bind("", self.handle_double_click) - # --- Create Search/Filter Widget --- - self.search_filter_widget = SearchFilterWidget( - main_frame, - self.data_filter, - self._on_filter_update, - self.medicine_manager, - self.pathology_manager, - logger, - ) - # Restore prior visibility state from preferences + # --- Search/Filter Widget (lazy-loaded) --- + self.search_filter_widget = None # Created on demand + # Restore prior visibility preference, but only create when needed self.search_filter_visible = bool(get_pref("search_panel_visible", False)) if self.search_filter_visible: - self.search_filter_widget.show() + self._ensure_search_widget() + # mypy: widget ensured above + self.search_filter_widget.show() # type: ignore[union-attr] # --- Create Status Bar --- self.status_bar = self.ui_manager.create_status_bar(main_frame) @@ -426,9 +422,8 @@ class MedTrackerApp: # Force one-time restoration in refresh and reflect in the UI if visible try: self.refresh_data_display(apply_filters=True) - if self.search_filter_visible and hasattr( - self.search_filter_widget, "sync_ui_from_filter" - ): + if self.search_filter_visible and self.search_filter_widget is not None: + # Keep UI in sync only if panel is actually instantiated self.search_filter_widget.sync_ui_from_filter() except Exception: self.refresh_data_display() @@ -1169,18 +1164,44 @@ Use Ctrl+S to save entries and Ctrl+Q to quit.""" def _toggle_search_filter(self) -> None: """Toggle the search and filter panel.""" if self.search_filter_visible: - self.search_filter_widget.hide() + if self.search_filter_widget is not None: + self.search_filter_widget.hide() self.search_filter_visible = False self.ui_manager.update_status("Search panel hidden", "info") set_pref("search_panel_visible", False) save_preferences() else: - self.search_filter_widget.show() + self._ensure_search_widget() + # mypy: widget ensured above + self.search_filter_widget.show() # type: ignore[union-attr] self.search_filter_visible = True self.ui_manager.update_status("Search panel shown", "info") set_pref("search_panel_visible", True) save_preferences() + def _ensure_search_widget(self) -> None: + """Create the search widget on demand to support lazy-loading.""" + if getattr(self, "search_filter_widget", None) is not None: + return + try: + # Local import to defer module load cost until first use + from search_filter_ui import SearchFilterWidget # type: ignore + + self.search_filter_widget = SearchFilterWidget( + self.main_frame, + self.data_filter, + self._on_filter_update, + self.medicine_manager, + self.pathology_manager, + logger, + ) + # If filters were restored earlier, reflect state in UI now + with contextlib.suppress(Exception): + self.search_filter_widget.sync_ui_from_filter() + except Exception as exc: + logger.error(f"Failed to initialize search panel: {exc}") + self.ui_manager.update_status("Search panel unavailable", "error") + def _on_filter_update(self) -> None: """Handle filter updates from the search widget.""" # Debounce rapid filter changes to avoid repeated heavy refresh. @@ -1608,6 +1629,10 @@ Use Ctrl+S to save entries and Ctrl+Q to quit.""" if current_scroll_top > 0: self.tree.yview_moveto(current_scroll_top) + # Ensure alternating stripes are normalized after any update + with contextlib.suppress(Exception): + self.ui_manager.normalize_tree_stripes(self.tree) + except Exception as e: logger.error(f"Error updating tree efficiently: {e}")