Files
Autoparts-DB/console/core/app.py

196 lines
6.0 KiB
Python

"""
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()