""" Main application controller for the AUTOPARTES console application. The :class:`App` class owns the screen lifecycle loop: it renders the current screen, reads a keypress, dispatches it, and follows any navigation instruction the screen returns. """ from console.core.navigation import Navigation from console.core.keybindings import Key class App: """Top-level application controller. Parameters: renderer: A :class:`BaseRenderer` implementation (e.g. CursesRenderer). db: A :class:`Database` instance for data access. """ def __init__(self, renderer, db): self.renderer = renderer self.db = db self.nav = Navigation() self.screens = {} self.running = False self._register_screens() # ------------------------------------------------------------------ # Screen registration # ------------------------------------------------------------------ def _register_screens(self): """Import and register all screen instances. Each screen is wrapped in a try/except so that screens not yet implemented do not prevent the application from starting. """ # --- Required screens (Task 6) -------------------------------- try: from console.screens.menu_principal import MenuPrincipalScreen s = MenuPrincipalScreen() self.screens[s.name] = s except ImportError: pass try: from console.screens.estadisticas import EstadisticasScreen s = EstadisticasScreen() self.screens[s.name] = s except ImportError: pass # --- Optional screens (added by later tasks) ------------------- try: from console.screens.vehiculo_nav import VehiculoNavScreen s = VehiculoNavScreen() self.screens[s.name] = s except ImportError: pass try: from console.screens.buscar_parte import BuscarParteScreen s = BuscarParteScreen() self.screens[s.name] = s except ImportError: pass try: from console.screens.buscar_texto import BuscarTextoScreen s = BuscarTextoScreen() self.screens[s.name] = s except ImportError: pass try: from console.screens.vin_decoder import VinDecoderScreen s = VinDecoderScreen() self.screens[s.name] = s except ImportError: pass try: from console.screens.catalogo import CatalogoScreen s = CatalogoScreen() self.screens[s.name] = s except ImportError: pass try: from console.screens.parte_detalle import ParteDetalleScreen s = ParteDetalleScreen() self.screens[s.name] = s except ImportError: pass try: from console.screens.comparador import ComparadorScreen s = ComparadorScreen() self.screens[s.name] = s except ImportError: pass try: from console.screens.admin_partes import AdminPartesScreen s = AdminPartesScreen() self.screens[s.name] = s except ImportError: pass try: from console.screens.admin_fabricantes import AdminFabricantesScreen s = AdminFabricantesScreen() self.screens[s.name] = s except ImportError: pass try: from console.screens.admin_crossref import AdminCrossrefScreen s = AdminCrossrefScreen() self.screens[s.name] = s except ImportError: pass try: from console.screens.admin_import import AdminImportScreen s = AdminImportScreen() self.screens[s.name] = s except ImportError: pass # ------------------------------------------------------------------ # Main loop # ------------------------------------------------------------------ def run(self): """Enter the main event loop. Initialises the renderer, pushes the main menu onto the navigation stack, and loops until the user quits or the stack empties. """ self.renderer.init_screen() self.running = True self.nav.push('menu', {}, label='Menu') try: while self.running: current = self.nav.current() if current is None: break screen_name, context = current screen = self.screens.get(screen_name) if screen is None: self.renderer.show_message( f'Pantalla "{screen_name}" no disponible', 'error' ) self.nav.pop() continue # Render self.renderer.clear() screen.render(context, self.db, self.renderer) self.renderer.refresh() # Input key = self.renderer.get_key() # Global key: F10 = back to main menu if key == Key.F10: self.nav.clear() self.nav.push('menu', {}, label='Menu') continue # Screen-specific key handling result = screen.on_key( key, context, self.db, self.renderer, self.nav ) if result == 'quit': self.running = False elif result == 'back': self.nav.pop() elif isinstance(result, tuple) and len(result) == 3: name, ctx, label = result self.nav.push(name, ctx, label=label) elif isinstance(result, str): self.nav.push(result, {}, label=result) except KeyboardInterrupt: pass finally: self.renderer.cleanup() self.db.close()