API v1

Driver — iOS

DriverViewController · CachedDriverSession Equivalente Android: DriverFragment

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 CachedDriverSession para sobreviver a reabertura/offline.
  • Instruções por voz com AVSpeechSynthesizer.
  • Atualiza posição via Background Tasks + Socket.

Cache Offline da Sessão (CachedDriverSession + DriverCacheManager)

Atualizado junho/2026 Equivalente Android: DriverSessionCache

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 blobConteúdosave*
tripDataJSON da viagem (AnyCodable)saveTripData
mainCoordinates + mainInstructionsGeometria + turn-by-turn da rota principalsaveMainRoute
alternativeRoutesRotas alternativas (coords + instruções)saveAlternativeRoute
stopPointsPontos de parada (MKPointAnnotation → title/subtitle/lat/lng)saveStopPoints
routeId, tripId, savedAtMetadata da sessão
Paridade Android: mesma estrutura do 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.
Pontos autorizados e áreas de risco no mapa: o DriverViewController renderiza os pontos autorizados e os polígonos de área de risco da viagem via fetchStopPointsrenderStopPoints/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)

Atualizado junho/2026 Equivalente Android: Comprovação de Entregas

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

OrigemTela / efeitoGating
TripDriverPremiumCell → botão EntregasPendingDeliveriesViewController (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 sheetRouteDeliveriesSectionView 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.
Divergência consciente Android × iOS: no iOS não existe o botão "Entregas Pendentes" da Home (sem tripId) — só o botão por viagem.

Telas

Tipo SwiftResponsabilidade
PendingDeliveriesViewController + DeliveryCardCellLista de entregas da viagem: loja, nome/endereço, badge canhoto ✓/✗, chip ROTA, "N canhotos enviados", pill horário/"Aguardando".
DeliveryDetailViewControllerDetalhe: 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.
ReplaceConfirmViewControllerEquivalente 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.

EtapaComportamento
InstruçãoDiálogo de orientação antes de abrir a câmera (paridade com o maybeShowCanhotoInstructions do Android).
CapturaPreview do AVFoundation com o overlay/moldura e botão de captura (anel branco) no rodapé.
ConferênciaApó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.

Sem NF e sem "código único" nesta tela. A comprovação de entrega é feita exclusivamente por foto de canhoto — a NF foi descontinuada nesta tela e não existe campo de "código único"/código de confirmação de entrega. Paridade com o Android.

Endpoints (idênticos ao Android)

GET/v1/trip/{id}
Lista de entregas (deliveries[]) com delivery_location e delivery_receipts[]. Fonte da lista, da seção do mapa e do estado "enviado" do detalhe.
GET/trip/{tripId}/rotogram
Endpoint dedicado a pontos (DeliveryDetailService.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.
Aponta para STAGING (nginx), não para produção. A base é 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.
POST/v1/trip/{tripId}/delivery-receipts
multipart/form-data: delivery_location_id, lat, lng, photo_taken_at, files (repetido). Após sucesso, refaz GET /v1/trip/{id} para refletir o envio.
Permissões do app: Info.plist ganhou NSCameraUsageDescription e NSPhotoLibraryUsageDescription (captura/galeria). O pbxproj foi editado à mão — o projeto usa refs explícitas, sem synchronized groups.
Chave correta = delivery_receipts (não receipts/canhotos). photo_taken_at com fallback para registered_at; image_url é S3 pré-assinada (~1h).

Endpoints

GET/v1/trip
Filtra a viagem ativa do motorista logado.
GET/v1/rotograms/trip/{tripId}?_detail=true
Endpoint consolidado — rotograma principal + alternativas da viagem (data[0].rotogram_route) numa só chamada. Ver Mapa.
GET/v1/point
Pontos da rota — usado para próxima parada.