Driver — iOS
Tela operacional do motorista durante uma viagem ativa. Mostra próxima parada, distância, instruções por voz e botões de evento (parada/incidente).
Arquivos
driver/ ├── DriverViewController.swift · UI principal └── CachedDriverSession.swift · sessão da viagem em cache local
Funcionalidades
- Carrega viagem ativa do usuário (filtrada por
user_id+ permissões 93/94). - Cacheia a sessão em
CachedDriverSessionpara sobreviver a reabertura/offline. - Instruções por voz com
AVSpeechSynthesizer. - Atualiza posição via Background Tasks + Socket.
Cache Offline da Sessão (CachedDriverSession + DriverCacheManager)
O DriverCacheManager persiste a sessão inteira da viagem num único blob (CachedDriverSession, Codable) em UserDefaults, com chave driverSession_{tripId}_{routeId} — por viagem + rota, para não misturar dados entre viagens que reusem a mesma rota. Cada save* regrava o blob inteiro, mantendo o disco sempre consistente. load() retorna false se não há cache.
| Campo do blob | Conteúdo | save* |
|---|---|---|
tripData | JSON da viagem (AnyCodable) | saveTripData |
mainCoordinates + mainInstructions | Geometria + turn-by-turn da rota principal | saveMainRoute |
alternativeRoutes | Rotas alternativas (coords + instruções) | saveAlternativeRoute |
stopPoints | Pontos de parada (MKPointAnnotation → title/subtitle/lat/lng) | saveStopPoints |
routeId, tripId, savedAt | Metadata da sessão | — |
DriverSessionCache (blob por tripId_routeId em SharedPreferences + Gson). O objetivo é comportamento offline idêntico nas duas plataformas: instruções, alternativas e pontos de parada sobrevivem sem rede.
DriverViewController renderiza os pontos autorizados e os polígonos de área de risco da viagem via fetchStopPoints → renderStopPoints/addRiskArea (riskAreaPolygonsById), buscados por GET /trip/{tripId}/rotogram (base STAGING stopPointsBase, a mesma do detalhe da entrega). A renderização detalhada está em Mapa.
Comprovação de Entregas (canhotos)
Anexação do canhoto (comprovante) de cada entrega da rota, com backend real. Paridade total com o Android: mesmos endpoints, mesmo array delivery_receipts, base v1 produção, async/await, retry 429 e desempacotamento do wrapper data.
Arquivos
trips/driverV1/deliveries/
├── DriverDeliveries.swift · models + PendingDeliveriesService / DeliveryDetailService
│ + DeliveryFormat (phone/cep) + DeliveriesPermission.hasDeliveries
└── DriverDeliveriesUI.swift · PendingDeliveriesViewController + DeliveryCardCell
+ DeliveryDetailViewController (MapKit, picker, upload)
+ RouteDeliveriesSectionView + ReplaceConfirmViewController
Pontos de entrada
| Origem | Tela / efeito | Gating |
|---|---|---|
TripDriverPremiumCell → botão Entregas | PendingDeliveriesViewController (lista da viagem). onMapTap abre o detalhe existente; onDeliveriesTap abre as entregas. Ligados em TripDriverViewController2.cellForRowAt. | Botão só com permissão 435 (DeliveriesPermission.hasDeliveries). Oculto → Mapa ocupa a linha toda (fillEqually). |
DriverViewController → seção "Entregas da rota" no bottom sheet | RouteDeliveriesSectionView inserida por código (storyboard frame-based) abaixo de "CRIADOR DA VIAGEM", ancorada via Auto Layout ao createdByTrip. Só leitura. | Reusa o payload do /trip/{id} já carregado (sem nova requisição); esconde quando não há entregas. |
tripId) — só o botão por viagem.
Telas
| Tipo Swift | Responsabilidade |
|---|---|
PendingDeliveriesViewController + DeliveryCardCell | Lista de entregas da viagem: loja, nome/endereço, badge canhoto ✓/✗, chip ROTA, "N canhotos enviados", pill horário/"Aguardando". |
DeliveryDetailViewController | Detalhe: MapKit com o ponto, telefones com máscara, miniaturas dos canhotos enviados, anexação por câmera in-app (CanhotoCameraViewController) ou galeria e upload multipart. |
ReplaceConfirmViewController | Equivalente do dialog_replace_doc.xml — confirma a substituição avisando que o canhoto atual segue no histórico; ao confirmar oculta os antigos (flag replacing) e abre o seletor. |
Câmera do canhoto (in-app)
O detalhe não usa mais o UIImagePickerController para a câmera. A captura agora é feita pela câmera custom in-app CanhotoCameraViewController (AVCaptureSession + AVCapturePhotoOutput), com CameraOverlayView desenhando um overlay estilo scanner — a tela escurece (~65%) e abre uma moldura deitada (proporção de canhoto) centralizada. A tela trava em paisagem (orientationLock) e restaura o portrait ao sair. Paridade total com o CanhotoCameraActivity do Android.
| Etapa | Comportamento |
|---|---|
| Instrução | Diálogo de orientação antes de abrir a câmera (paridade com o maybeShowCanhotoInstructions do Android). |
| Captura | Preview do AVFoundation com o overlay/moldura e botão de captura (anel branco) no rodapé. |
| Conferência | Após capturar, a foto cobre a câmera (photoPreview, aspectFit) com o título "A foto ficou boa?" e as ações Refazer / Usar foto. Só ao confirmar ("Usar foto") o onCapture dispara e a imagem é anexada. |
Substituir e Remover Canhoto
Substituir: via ReplaceConfirmViewController (acima) — mantém o canhoto atual no histórico e abre a câmera/galeria. Remover: a lixeira remove o canhoto apenas da lista visual; a imagem permanece salva no sistema. Paridade com o Android.
Endpoints (idênticos ao Android)
/v1/trip/{id}deliveries[]) com delivery_location e delivery_receipts[]. Fonte da lista, da seção do mapa e do estado "enviado" do detalhe./trip/{tripId}/rotogramDeliveryDetailService.fetchPoint) — resposta traz data[].deliveries[]; filtra type == "delivery" e o id para resolver o ponto do detalhe. Mesma chamada dos pontos autorizados/áreas de risco do mapa.http://nginx.surubim.monisat.online/v1 (DeliveriesAPI.rotogramPointsBase), HTTP e fora de produção — pendente troca para https://api.monisystem.com/v1 (DeliveriesAPI.baseURL) quando o endpoint subir. O envio de canhotos (POST abaixo) já usa a base de produção. Paridade com o Android.
/v1/trip/{tripId}/delivery-receiptsmultipart/form-data: delivery_location_id, lat, lng, photo_taken_at, files (repetido). Após sucesso, refaz GET /v1/trip/{id} para refletir o envio.Info.plist ganhou NSCameraUsageDescription e NSPhotoLibraryUsageDescription (captura/galeria). O pbxproj foi editado à mão — o projeto usa refs explícitas, sem synchronized groups.
delivery_receipts (não receipts/canhotos). photo_taken_at com fallback para registered_at; image_url é S3 pré-assinada (~1h).
Endpoints
/v1/trip/v1/rotograms/trip/{tripId}?_detail=truedata[0].rotogram_route) numa só chamada. Ver Mapa./v1/point