Files
Projeto-Portaria/docs/04-DESIGN-SYSTEM-UX.md
2026-07-22 15:55:55 -03:00

9.6 KiB
Raw Blame History

04 — Design system e UX

Material 3 Expressive nos apps Compose; os mesmos tokens exportados como CSS custom properties nos webs. Uma linguagem visual, duas implementações.

1. Princípios

1. O visitante está no sol, com pressa, e não vai instalar nada. Cada tela dele tem uma ação. Tipografia grande, contraste alto, área de toque generosa.

2. Espera precisa ter narração. Um spinner de 35 segundos é indistinguível de um app quebrado. O visitante sempre lê o que está acontecendo: "Chamando o morador", "Tentando outros moradores", "Transferindo para a portaria".

3. O morador decide em um toque. A maior parte das decisões acontece na notificação, sem abrir o app.

4. Densidade é para o admin, não para o campo. Painel administrativo pode ter tabela densa e filtro complexo. Tela de portaria, nunca.

2. Tokens

Fonte única em web/shared-ui/tokens.json, gerada para os dois mundos no build:

tokens.json ──► tokens.css      (custom properties)  → web/visitor, web/admin
            └─► Theme.kt        (Material 3 Color)   → apps Compose

Cor

brand/primary      #2563EB   ações principais, foco
brand/on-primary   #FFFFFF
semantic/success   #15803D   autorizado, dentro do geofence
semantic/danger    #B91C1C   negado, expirado
semantic/warning   #B45309   fora do geofence, degradado
semantic/info      #0369A1   fila, estado transitório
neutral/0..1000    escala de superfície e texto

Contraste mínimo 4.5:1 em tema claro e escuro — verificado em CI, não no olho. A tela do visitante frequentemente é lida sob sol direto, onde o contraste efetivo despenca; por isso ela usa apenas os extremos da escala neutra, nunca tons médios.

Decisão nunca depende só de cor: autorizado é verde + ícone de check + a palavra "Autorizado". Daltonismo e sol forte quebram codificação puramente cromática.

Tipografia

Inter (web) / Roboto Flex (Compose), variáveis, com fallback de sistema.

Papel Tamanho Uso
display 3240 Estado da chamada na tela do visitante
headline 2428 Título de tela
title 1820 Nome do morador, unidade
body 16 Mínimo absoluto no fluxo do visitante
label 14 Rótulos de admin
caption 12 Só metadados no admin. Nunca na portaria

Espaço, raio, elevação

Escala 4px (0,1,2,3,4,6,8,12,16,24 × 4px). Raios: sm 8 · md 12 · lg 16 · full 999. Elevação por sombra suave no web e tonalElevation no Compose — nunca sombra dura.

Alvo de toque mínimo 48×48dp em todo o fluxo do visitante, sem exceção. Mão trêmula, luva de entregador, celular escorregando.

3. Telas do visitante

Cinco telas, uma ação cada.

┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
│ Res. Bela Vista │  │  ┌───────────┐  │  │  Quem procura?  │
│                 │  │  │  câmera   │  │  │                 │
│ Este acesso     │  │  │  frontal  │  │  │ Seu nome        │
│ registra sua    │  │  └───────────┘  │  │ [____________]  │
│ imagem e        │  │                 │  │                 │
│ localização     │  │ Centralize o    │  │ Bloco  Unidade  │
│ para segurança. │  │ rosto           │  │ [__]   [_____]  │
│                 │  │                 │  │                 │
│ [Como funciona] │  │  ( ◎ tirar )    │  │  [ Continuar ]  │
│ [  Continuar  ] │  │                 │  │                 │
└─────────────────┘  └─────────────────┘  └─────────────────┘
   1. Aviso LGPD        3. Foto              4. Destino
   (2 = permissões,     (após permissão)     (busca cega)
    nativa do browser)

┌─────────────────┐  ┌─────────────────┐
│   ◐             │  │       ✓         │
│                 │  │                 │
│ Chamando o      │  │   Autorizado    │
│ morador...      │  │                 │
│                 │  │  Mostre o código│
│ ▓▓▓▓▓▓░░░░ 12s  │  │                 │
│                 │  │    4 8 2 9 1 7  │
│ Aguarde na      │  │                 │
│ entrada         │  │  válido 4:52    │
│                 │  │                 │
│  [ Cancelar ]   │  │   [QR grande]   │
└─────────────────┘  └─────────────────┘
   5. Espera narrada    6. Resultado

Tela 1 não é um modal de consentimento com checkbox. A base legal é legítimo interesse — o que se deve é informar com clareza, não colher aceite. Ver 06-LGPD-E-SEGURANCA.md.

Tela 5 troca o texto conforme o estado real (TOCANDOESCALONADAFILA_OPERADOR), com barra de progresso ligada ao tempo restante. É a tela onde o produto se ganha ou se perde.

Entrega — dois toques a menos

┌─────────────────┐
│ O que você faz  │
│ aqui hoje?      │
│                 │
│ ┌─────────────┐ │
│ │ 📦 Entrega  │ │  ← primeiro, é a maioria
│ └─────────────┘ │
│ ┌─────────────┐ │
│ │ 👤 Visita   │ │
│ └─────────────┘ │
└─────────────────┘

Entrega pula a foto do rosto (fotografa o pacote) e vai direto ao destino. Meta de 10s do QR à resposta.

4. App do morador

A notificação é a interface principal

Android — CallStyle              iOS — CallKit (tela cheia)
┌──────────────────────────┐    ┌──────────────────────────┐
│ 📦 Entrega · Apto 101-A  │    │      Portaria            │
│ [foto do pacote]         │    │   Entrega · Apto 101-A   │
│                          │    │                          │
│ [Autorizar] [Chamar]     │    │   [Recusar]  [Aceitar]   │
└──────────────────────────┘    └──────────────────────────┘

No iOS, chamada de visita usa PushKit + CallKit e ocupa a tela como ligação telefônica — o único caminho para tocar de verdade com o app fechado. Entrega usa notificação comum com ações, porque CallKit para uma entrega seria intrusivo e a Apple pode reprovar o uso.

Tela de chamada

Vídeo do visitante em tela cheia; auto-preview pequeno no canto. Sobreposto: nome informado, unidade de destino, e selo de geofence✓ Na entrada (verde) ou ⚠ A 340m da portaria (âmbar). Esse selo é a informação de segurança mais útil da tela: alguém tentando entrar de longe é sinal claro.

Ações: Autorizar (verde, primária), Negar (contorno vermelho), Mudo, Encerrar.

5. App do operador

Densidade maior, feito para várias visitas em paralelo. Fila à esquerda com foto, unidade, tempo de espera e por que escalonou; contexto à direita antes de assumir — histórico da unidade, visitas recentes, regra de entrega. O operador nunca atende sem contexto.

6. Painel admin

Layout de aplicação: navegação lateral, conteúdo denso, filtros persistentes na URL.

A tela mais importante é a auditoria de visitas: tabela virtualizada, filtro por período/unidade/estado/tipo/geofence, e detalhe com foto, mapa (Leaflet) do ponto do visitante contra o raio do portão, timeline de tentativas (visit_attempts), e player do recado. Todo acesso a mídia gera linha em audit_log e usa URL assinada de 5 minutos.

7. Movimento

Transição Duração Curva
Troca de tela do visitante 280ms emphasized
Estado de chamada 200ms standard
Entrada de card na fila 180ms decelerate
Feedback de toque 100ms linear

Compose usa spring(dampingRatio = 0.8f); web usa cubic-bezier(0.2, 0, 0, 1).

prefers-reduced-motion respeitado em todos os webs e Settings.Global.ANIMATOR_DURATION_SCALE no Android. Pulso e transição viram fade.

8. Acessibilidade

  • Contraste ≥ 4.5:1 verificado em CI, claro e escuro
  • Alvos ≥ 48×48dp no fluxo do visitante
  • Rótulos semânticos em todo controle (contentDescription / aria-label)
  • Foco visível e ordem de tabulação correta no web
  • Suporte a fonte ampliada até 200% sem quebra de layout
  • Nenhuma informação transmitida só por cor
  • lang="pt-BR" e textos prontos para i18n desde o início (visitante estrangeiro é caso real)

9. Estados vazios, de erro e degradado

Todo erro exibido ao visitante vem do campo detail do problem+json, em português e acionável: "Aproxime-se da entrada e tente novamente", nunca "OUTSIDE_GEOFENCE".

Modo degradado é comunicado, não escondido:

┌──────────────────────────────┐
│ ⚠ Vídeo indisponível         │
│ Continuando por áudio.       │
└──────────────────────────────┘

Esconder a degradação faz o usuário achar que o produto está quebrado. Nomear a degradação faz o produto parecer resiliente — que é o que ele é.