feat(console): add app controller, main menu and statistics screen

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-15 01:45:03 +00:00
parent 269bb9030b
commit e3ad101d56
3 changed files with 499 additions and 0 deletions

View File

@@ -0,0 +1,137 @@
"""
Main menu screen for the AUTOPARTES console application.
Displays a numbered Pick-style menu with navigation options for all
application sections. Number keys jump directly; arrow keys move the
selection; ENTER activates.
"""
from console.core.screens import Screen
from console.core.keybindings import Key
from console.config import APP_NAME, APP_SUBTITLE, VERSION
# Menu items: list of (display_number, label, screen_name).
# Separators use display_number None and screen_name None.
_MENU_ITEMS = [
("1", "Consulta por Vehiculo", "vehiculo_nav"),
("2", "Busqueda por Numero de Parte", "buscar_parte"),
("3", "Busqueda por Descripcion", "buscar_texto"),
("4", "Decodificador VIN", "vin_decoder"),
("5", "Catalogo de Categorias", "catalogo"),
(None, None, None), # separator
("6", "Administracion de Partes", "admin_partes"),
("7", "Administracion de Fabricantes", "admin_fabricantes"),
("8", "Cross-References", "admin_crossref"),
("9", "Importar / Exportar Datos", "admin_import"),
(None, None, None), # separator
("0", "Estadisticas del Sistema", "estadisticas"),
]
# Quick lookup: digit character -> screen name
_KEY_MAP = {item[0]: item[2] for item in _MENU_ITEMS if item[0] is not None}
# Footer key labels
_FOOTER = [
("F1", "Ayuda"),
("F3", "Buscar"),
("F10", "Menu"),
("ESC", "Salir"),
]
class MenuPrincipalScreen(Screen):
"""Main menu screen with numbered items and arrow-key navigation."""
def __init__(self):
super().__init__(name="menu", title="Menu Principal")
self._selected = 0 # index into _MENU_ITEMS (skipping separators)
# ------------------------------------------------------------------
# Helpers
# ------------------------------------------------------------------
def _selectable_indices(self):
"""Return list of indices in _MENU_ITEMS that are not separators."""
return [i for i, item in enumerate(_MENU_ITEMS) if item[0] is not None]
def _move_selection(self, direction):
"""Move selection up (-1) or down (+1), skipping separators."""
indices = self._selectable_indices()
if not indices:
return
try:
pos = indices.index(self._selected)
except ValueError:
pos = 0
pos = max(0, min(len(indices) - 1, pos + direction))
self._selected = indices[pos]
# ------------------------------------------------------------------
# Screen interface
# ------------------------------------------------------------------
def render(self, context, db, renderer):
# Header
renderer.draw_header(
f" {APP_NAME} v{VERSION}",
f"{APP_SUBTITLE} ",
)
# Build items list for draw_menu.
# Separators use the special "---" marker understood by the renderer.
menu_items = []
for num, label, _screen in _MENU_ITEMS:
if num is None:
menu_items.append(("---", ""))
else:
menu_items.append((num, label))
renderer.draw_menu(
menu_items,
selected_index=self._selected,
title="MENU PRINCIPAL",
)
# Footer
renderer.draw_footer(_FOOTER)
def on_key(self, key, context, db, renderer, nav):
# --- Number keys: direct navigation ---
if 48 <= key <= 57: # ord('0') .. ord('9')
digit = chr(key)
screen_name = _KEY_MAP.get(digit)
if screen_name:
label = next(
(lbl for num, lbl, _ in _MENU_ITEMS if num == digit),
screen_name,
)
return (screen_name, {}, label)
# --- Arrow keys ---
if key == Key.UP:
self._move_selection(-1)
return None
if key == Key.DOWN:
self._move_selection(1)
return None
# --- ENTER: activate selected ---
if key == Key.ENTER:
item = _MENU_ITEMS[self._selected]
num, label, screen_name = item
if screen_name is not None:
return (screen_name, {}, label)
return None
# --- ESC: quit confirmation ---
if key == Key.ESCAPE:
confirmed = renderer.show_message(
"Desea salir de la aplicacion?", "confirm"
)
if confirmed:
return "quit"
return None
return None