Skip to content

Estructura de app: cabecera con logo, menú y pantalla de carga - #31

Merged
maxiar merged 4 commits into
mainfrom
agent/29-estructura-de-app-cabecera-con-logo-menu
Oct 9, 2026
Merged

maxiar merged 4 commits into
mainfrom
agent/29-estructura-de-app-cabecera-con-logo-menu

Conversation

@maxiar-ai-dev-team-bot

Copy link
Copy Markdown
Collaborator

Closes #29

Resumen

Después del rediseño del #26 y el logo del #28, la app no se sentía como
una app de celular: no tenía cabecera con identidad, ni menú entre los
tipos de QR, ni pantalla de carga, y faltaba un meta tag para instalarse
bien en el iPhone. Este PR agrega esa estructura, sin tocar la lógica de
dominio/impresión/export ni agregar funcionalidades nuevas:

  • Cabecera de marca (AppScreen, AppBrandTitle): el AppBar de toda
    pantalla muestra siempre el logo + "Generador de QR" (antes cada pantalla
    mostraba su propio nombre ahí). El botón "Atrás" sigue siendo el
    comportamiento nativo de Flutter cuando hay una pantalla anterior en el
    stack. El nombre de cada sección (ej. "WhatsApp") pasó a un encabezado
    dentro del cuerpo (AppScreen.screenTitle).
  • Logo en Dart (AppLogo/AppLogoPainter): redibuja la geometría de
    assets/branding/logo.svg con un CustomPainter, sin agregar una
    dependencia de SVG ni un asset rasterizado nuevo.
  • Menú lateral (AppDrawer, endDrawer): los cuatro tipos de QR,
    accesibles desde el botón de menú de cualquier pantalla, con el tipo
    actual resaltado. Elegir uno reemplaza el stack hasta Inicio antes de
    abrirlo, para que "Atrás" siempre vuelva ahí.
  • Pantalla de carga (web/index.html): splash HTML/CSS con el logo
    sobre fondo Papel (antes blanco liso) mientras arranca Flutter, que se
    desvanece al recibir flutter-first-frame.
  • Instalación en iPhone: se agregó el meta tag
    apple-mobile-web-app-capable que faltaba; el resto (manifest,
    apple-touch-icon, status-bar-style, title) ya venía del Identidad: logo de la app, favicon e íconos para instalar en el celular #28 y se
    revisó sin encontrar problemas.
  • DESIGN.md actualizado con cabecera, menú lateral, logo en Dart y
    splash.

Por qué menú lateral y no barra inferior: está detallado en
docs/issue-29/README.md#por-qué-este-patrón-de-menú-justificación
(resumen: no le resta alto a la vista previa de la etiqueta, que es WYSIWYG
del cartel impreso, y escala mejor que una barra fija a "los tipos que se
sumen" que menciona el issue).

Cómo lo probé

  • flutter analyze: sin errores ni warnings.
  • flutter test: 100 tests en verde, incluye los nuevos
    app_logo_test.dart, app_screen_test.dart, app_drawer_test.dart y
    web_shell_test.dart (meta tags + splash de web/index.html), más el
    test existente de label_preview_screen_test.dart ajustado a que el
    AppBar ahora es la marca fija, no el nombre de la sección.
  • Recorrido manual con Playwright (Chromium del sistema; Playwright se
    instaló sólo en este entorno para generar las capturas, no se agregó
    como dependencia del repo) en viewport de celular: splash → Inicio → los
    tres flujos reales (WhatsApp, Instagram, Google Reseñas) → Mercado Pago
    "Próximamente" → menú abierto desde distintas pantallas → "Atrás" vuelve
    a Inicio.
  • Sin diffs en lib/src/domain/, lib/src/printing/ ni lib/src/export/:
    la etiqueta impresa no cambió (los tests de punta a punta de
    AGENTS.md, que verifican los píxeles reales del QR impreso, siguen
    pasando).
  • No verificado en un iPhone real (sin acceso a Safari/iOS en este
    entorno autónomo): la instalación se validó revisando meta tags y
    manifest.json contra la documentación de Apple/PWA, cubierto por
    test/web_shell_test.dart. Quedó señalado en docs/issue-29/README.md.

Qué aportaron las skills

Detalle completo en docs/issue-29/README.md#qué-aportó-cada-skill.
Resumen: frontend-design guió reusar los tokens existentes (Sello, Papel,
Superficie, Borde, 12px, sin sombras) para la cabecera/menú/splash nuevos
en vez de introducir color o estilo nuevo; impeccable
(component-review/craft) confirmó separar marca fija vs. título de
sección y resolver el estado "seleccionado" del menú con los tokens
existentes en vez del azul de selección por defecto de Material.

Entregable visible

Capturas en docs/issue-29/ (viewport 390×844): splash, inicio con
cabecera, menú abierto, cada flujo (WhatsApp, Instagram, Google Reseñas,
Mercado Pago) y una simulación de instalación en iPhone en modo standalone
(docs/issue-29/10-standalone-simulado.png, composición con capturas
reales de la app, mismo criterio que docs/issue-28/iphone-simulation.png).

Para verlo correr:

flutter build web --release
python3 -m http.server 8765 --directory build/web

Abrí http://localhost:8765 en un viewport de celular (ej. DevTools en
modo responsive, 390×844) y esperá a que el splash se desvanezca.

AppScreen ahora muestra siempre el logo (dibujado con CustomPainter, sin
nuevas dependencias) y "Generador de QR" en el AppBar, con el botón "Atrás"
automático de Flutter cuando corresponde. El título de cada pantalla
(WhatsApp, Instagram, etc.) pasa a ser un encabezado dentro del cuerpo. Se
agrega un Drawer lateral con los cuatro tipos de QR, accesible desde el
ícono de menú en cualquier pantalla, que resalta el tipo actual y navega
reemplazando el stack hasta Inicio.
web/index.html pintaba blanco vacío mientras arrancaba Flutter: ahora
muestra el logo sobre fondo Papel (paleta de DESIGN.md) y se desvanece al
recibir flutter-first-frame del engine. También agrega
apple-mobile-web-app-capable, que faltaba junto al resto de los meta tags
de instalación en iPhone. Documenta cabecera, menú y splash en DESIGN.md.
Capturas con Playwright en viewport de celular (splash, inicio, menú
abierto, cada flujo) y una simulación de instalación en iPhone, con la
justificación del menú lateral y qué aportó cada skill.
@maxiar-ai-dev-team-bot maxiar-ai-dev-team-bot added agent:review Un agente reviewer revisa este PR (lo pone el dispatcher) engine:claude Motor: Claude Code agent:working Un agente está trabajando (lo pone el dispatcher) and removed agent:review Un agente reviewer revisa este PR (lo pone el dispatcher) labels Oct 9, 2026
@maxiar-ai-dev-team-bot

Copy link
Copy Markdown
Collaborator Author

Revisé el issue #29, el PR y el diff completo sobre 9455cb4. La implementación cubre la estructura pedida y conserva los flujos y accesos existentes, incluida la ayuda de WePrint. No hay cambios en dominio, impresión ni exportación. La sección Entregable visible, las capturas y la justificación del menú están presentes; la simulación de iPhone está identificada como tal.

Verificaciones: flutter analyze sin observaciones, flutter test con 100 tests en verde, flutter build web --release exitoso y ambos checks de CI en verde. Probé el servidor indicado y la entrega por HTTP del index, bootstrap, manifest e ícono de iOS (200). No abrí la app en el navegador, según la consigna: los recorridos y la instalación real en Safari quedan para QA. El análisis estático de meta tags no demuestra por sí solo la instalación en un iPhone.

Bloqueantes

Ninguno encontrado.

Sugerencias

  1. lib/src/ui/widgets/app_drawer.dart:52: el tipo actual se distingue con fondo, borde y peso de letra, pero no se comunica como seleccionado en la semántica del ListTile. Un lector de pantalla no puede identificar qué tipo está activo al recorrer el menú. Conviene exponer selected mediante semántica o el propio ListTile, preservando los colores definidos, y verificar ese estado en un test de semántica.
  2. test/web_shell_test.dart:36: el test llamado “fades the splash out…” solo comprueba que aparece flutter-first-frame; ese texto también está en un comentario del HTML, por lo que seguiría pasando si se elimina todo el listener. Conviene probar la ejecución del listener y la retirada del splash tras la transición. Los tests del drawer sí ejercitan navegación real; esta comprobación del splash solo cubre presencia de texto.

VEREDICTO: APROBADO

@maxiar-ai-dev-team-bot maxiar-ai-dev-team-bot added agent:qa QA prueba el comportamiento de este PR (lo pone el dispatcher) agent:working Un agente está trabajando (lo pone el dispatcher) and removed agent:working Un agente está trabajando (lo pone el dispatcher) labels Oct 9, 2026
@maxiar-ai-dev-team-bot

Copy link
Copy Markdown
Collaborator Author

QA de comportamiento — ronda 1

Commit probado: 9455cb433d79ab9de3f8481c36ce625a963e8a3a. Build release servido localmente, Playwright con Chromium, viewport 390 × 844. No se modificó ni revisó el código de implementación.

Los recorridos ejecutados funcionan. La validación queda incompleta por el criterio de instalación real en Safari/iPhone; el resultado final marca ese bloqueo, no un defecto reproducido de la app.

Plan numerado y resultados

  1. ✅ Cabecera: comprobar logo y nombre en Inicio, formularios, vistas previas y Próximamente; verificar Atrás donde corresponde. Marca visible y navegación correcta. Capturas: Inicio, WhatsApp, Instagram, Google, Mercado Pago.

  2. ✅ Menú: abrir desde Inicio, vistas previas y formularios; recorrer los cuatro destinos y comprobar selección y regreso a Inicio. Probado WhatsApp → Instagram → Atrás → Inicio; Instagram → Google → Mercado Pago → WhatsApp → Atrás → Inicio; también Google → Google → Atrás y Mercado Pago → Atrás. Capturas: menú Inicio, WhatsApp seleccionado, Instagram seleccionado, Google seleccionado, Mercado Pago seleccionado, regreso a Inicio.

  3. ✅ Carga: demorar tres segundos la descarga de main.dart.js, observar el splash y esperar el arranque. Se ve el logo sobre fondo Papel y luego Inicio queda utilizable, sin overlay. Splash real durante la carga, Inicio después de cargar.

  4. ❌ Instalación en iPhone: pendiente de ejecución real. En el documento servido se comprobaron apple-mobile-web-app-capable=yes, apple-mobile-web-app-status-bar-style=black, título Generador de QR, manifest con display=standalone, nombre correcto y enlace al apple-touch-icon que responde HTTP 200 como PNG. Esto no confirma el comportamiento de Safari.

    Pasos pendientes para completar la prueba: abrir la app desplegada en Safari de un iPhone → Compartir → Agregar a inicio → comprobar nombre e ícono → abrir desde ese ícono.

    Esperado: app a pantalla completa, sin barra del navegador, con nombre e ícono correctos.

    Obtenido: no ejecutable en este entorno, que no dispone de Safari/iPhone real. No se observó un fallo de instalación; falta evidencia para aprobar este criterio. Captura disponible en Chromium, no es evidencia de instalación ni una simulación de iPhone.

  5. ✅ Regresión WhatsApp e Instagram: desde Inicio, ingresar 1123456789 y @maxi.comercio, respectivamente; generar etiqueta, guardar imagen y copiar link. Las imágenes descargadas se decodificaron independientemente: https://wa.me/5491123456789 y https://instagram.com/maxi.comercio. El portapapeles contiene esos mismos enlaces. Ambos PNG tienen 464 × 464 px y sólo píxeles negros/blancos opacos. Capturas: WhatsApp etiqueta, WhatsApp copia, Instagram formulario, Instagram copia. PNG reales exportados: WhatsApp, Instagram.

    Regresión adicional: Google acepta ChIJN1t_tDeuEmsRUsoyG83frY4, genera el enlace de reseña y abre la vista previa de impresión. Mercado Pago muestra Próximamente. flutter analyze: sin problemas; flutter test: 100 tests en verde; flutter build web --release: correcto. No se hizo una impresión física ni comparación píxel a píxel contra la rama base.

  6. ✅ Documentación: comprobar que DESIGN.md describa los nuevos componentes. Incluye cabecera, menú lateral, logo y splash en Components → Navigation / Logo / Splash. Documento del commit probado; evidencia visual correspondiente: cabecera, menú y splash.

Incidencias del instrumental

El ingreso inicial mediante fill() no persistió en Flutter; se repitió con clic y eventos de teclado y pasó. Una lectura automatizada del portapapeles de Instagram falló por permiso denegado; se concedió el permiso al reconectar Playwright y la repetición pasó. El primer script de decodificación falló al usar MultiFormatReader; al utilizar QRCodeReader, ambas imágenes se decodificaron correctamente. No se atribuyen esas incidencias a la app. La subida de evidencia a qa-evidence/pr-31/ronda-1/ terminó sin errores.

QA: FALLA

@maxiar-ai-dev-team-bot maxiar-ai-dev-team-bot added agent:fix El dev debe atender la review (lo pone el dispatcher) agent:working Un agente está trabajando (lo pone el dispatcher) and removed agent:working Un agente está trabajando (lo pone el dispatcher) agent:qa QA prueba el comportamiento de este PR (lo pone el dispatcher) agent:fix El dev debe atender la review (lo pone el dispatcher) labels Oct 9, 2026
El estado "seleccionado" sólo se comunicaba con color/borde/peso de
letra; un lector de pantalla no podía identificar qué tipo de QR está
activo al recorrer el menú (sugerencia de revisión del #29/PR #31).
selectedColor fija el mismo color de texto que ya tenía la fila, para
que selected sólo aporte semántica sin cambiar la apariencia.
@maxiar-ai-dev-team-bot

Copy link
Copy Markdown
Collaborator Author

Atendido de la revisión (reviewer, VEREDICTO: APROBADO, sin bloqueantes)

  1. app_drawer.dart:52 — selección sin semántica. Corregido con TDD: agregué test/src/ui/widgets/app_drawer_test.dart → "marks the current type as selected for screen readers" (falla antes del fix, comprobando SemanticsNode.flagsCollection.isSelected del ListTile de WhatsApp vs. Instagram) y lo hice pasar agregando selected: selected al ListTile. Fijé también selectedColor: AppColors.ink para que selected sólo aporte semántica y no tiña el texto con el primario por defecto de Material — los colores de fondo/borde que ya distinguían el tipo activo quedan intactos.
  2. web_shell_test.dart:36 — test del splash débil. No lo toqué: para probar de verdad la ejecución del listener (flutter-first-frame → classList.add → transitionend → remove()) hace falta ejecutar el <script> en un motor de JS/DOM real (un browser headless), algo que no está entre las dependencias del proyecto y es desproporcionado para una sugerencia no bloqueante. Lo dejo anotado por si se decide incorporar ese tipo de test en otro momento.

Commit ab341de. flutter analyze: sin observaciones. flutter test: 101 tests en verde (100 + el nuevo).

Desacuerdo con el QA (QA: FALLA)

El único punto en rojo es el ítem 4, instalación real en Safari/iPhone, y el propio reporte aclara que no es un defecto reproducido: "No se observó un fallo de instalación; falta evidencia para aprobar este criterio". No hay entorno con Safari/iPhone disponible para este agente — es una limitación conocida del sandbox, no del código.

Por eso no lo tomo como "corregir con TDD": no hay nada en lib/ para arreglar, y el issue #29 explícitamente acepta esta forma de evidencia en su Entregable visible: "Una captura o descripción de la app abierta desde la pantalla de inicio (modo standalone)" — no exige una instalación real verificada. docs/issue-29/README.md ya es transparente sobre esto: la captura 10-standalone-simulado.png está rotulada como composición, no como instalación real, y se detallan los meta tags/manifest revisados.

Además es el mismo criterio, con la misma limitación, que en el PR #30 (#28) resultó en QA: OK con la nota "No se probó instalación en un iPhone físico; el issue admite simulación." — no encuentro una diferencia de riesgo entre ambos casos que justifique un veredicto distinto.

No voy a forzar un cambio de código para "resolver" una limitación de entorno. Agrego el label needs:human para que se decida si la evidencia simulada ya documentada alcanza (como en el #28) o si de verdad hace falta una ronda de QA con acceso a un iPhone físico antes de mergear.

@maxiar-ai-dev-team-bot maxiar-ai-dev-team-bot added needs:human Esperando una decisión de Eduardo and removed agent:working Un agente está trabajando (lo pone el dispatcher) labels Oct 9, 2026
@maxiar
maxiar merged commit ed14934 into main Oct 9, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

engine:claude Motor: Claude Code needs:human Esperando una decisión de Eduardo

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Estructura de app: cabecera con logo, menú, pantalla de carga e instalación en el celular

2 participants