Skip to main content

Achado — Botão de voltar da ZzAppBar ignora onWillPop (bug pré-existente)

Severidade: Médio (feature de "alterações não salvas" não dispara no caminho mais comum de saída) Status: Documentado — fora do escopo de RF-06, tratamento a decidir separadamente

O que foi observado

ShowCaseDetailController.onWillPop() (show_case_detail_controller.dart:302-324) já implementa hoje o aviso de "alterações não salvas":

Future<bool> onWillPop() async {
if (enableEditButton) {
final answer = await BottomSheetAskLauncher.ask(
icon: PhosphorIcons.info,
title: 'A vitrine possui alterações não salvas',
description: 'Deseja salvar as alterações antes de sair?',
confirmButton: BottomSheetLauncherConfirmButton(title: 'Salvar'),
cancelButton: BottomSheetLauncherCancelButton(title: 'Não salvar'),
theme: BottomSheetLauncherTheme.info,
);
...
}
return true;
}

E é conectado via WillPopScope em ShowCaseDetailLayout (show_case_detail_layout.dart:89-92):

if (onWillPop != null) {
//TODO: refatorar e validar o uso
return WillPopScope(onWillPop: onWillPop, child: scaffold);
}

O próprio comentário //TODO: refatorar e validar o uso já sinalizava suspeita sobre esse mecanismo.

O problema

ZzAppBar (theme_widgets/app_bar/zz_app_bar.dart:25-39), usado pelo ShowCaseDetailLayout sem overrideOnTapBackButton, implementa o botão de voltar assim:

return IconButton(
onPressed: () => Navigator.of(context).pop(),
icon: const Icon(PhosphorIcons.caret_left, size: 24),
);

Confirmado na documentação oficial do Flutter (Navigator.maybePop): "This method is typically called for a user-initiated pop. For example on Android it's called by the binding for the system's back button." — ou seja, é Navigator.maybePop() (não Navigator.pop()) quem consulta route.willPop()/onWillPop. Uma chamada direta a Navigator.pop() não passa por essa checagem.

Impacto

O aviso "A vitrine possui alterações não salvas" registrado via WillPopScope/onWillPop:

  • Funciona quando o vendedor usa o botão físico/gesto de voltar do Android (que aciona o mecanismo de pop do sistema, que consulta willPop).
  • Não dispara quando o vendedor toca na seta de voltar visível na ZzAppBar — o caminho mais comum e mais visível de sair da tela.

Além disso, WillPopScope está depreciado desde o Flutter 3.12 (substituído por PopScope) e a nota oficial diz: "The Android predictive back feature will not work with WillPopScope."

Opções possíveis (a decidir, fora desta sessão)

  1. Passar overrideOnTapBackButton para o ZzAppBar dentro de ShowCaseDetailLayout, chamando o mesmo onWillPop manualmente antes de decidir se navega.
  2. Migrar de WillPopScope para PopScope (canPop/onPopInvokedWithResult), que tem semântica mais robusta e é o caminho recomendado pelo Flutter — mas exige revisão de todos os outros usos de WillPopScope no app (43 ocorrências em várias telas) se quisermos consistência.
  3. Deixar como está por ora e tratar como débito técnico à parte, já que RF-06 foi escrito para descrever o comportamento desejado, não a mecânica exata de interceptação de navegação.

Resolução

(não decidido nesta sessão — fica registrado como achado técnico para tratamento futuro, fora do escopo de RF-06)