fix: back do android saia da sala em vez de fechar o viewer de imagem

O PopScope sozinho nao resolvia: GoRouterDelegate.popRoute() itera
_findCurrentNavigators(), que devolve [root, shell] e retorna
states.reversed, ou seja, o shell navigator e consultado primeiro. O
viewer e um showDialog no root navigator, entao o shell nunca ve o
PopEntry dele, popa a sala e retorna true antes de chegar no dialog.

BackButtonListener registra no BackButtonDispatcher raiz, que e
consultado antes do RouterDelegate.popRoute(), entao o viewer fecha
primeiro. Aplicado tambem no MxcImageViewer (avatar/sticker), que tinha
o mesmo defeito.
This commit is contained in:
2026-09-27 17:30:37 -03:00
parent 9f8877a741
commit d65be8a1ef
2 changed files with 66 additions and 48 deletions

View File

@@ -24,49 +24,57 @@ class MxcImageViewer extends StatelessWidget {
backgroundColor: Colors.black.withAlpha(200),
foregroundColor: Colors.white,
);
return PopScope<Object?>(
// Claim the system back button for the viewer so that it is dismissed
// instead of letting the router navigate away underneath it.
canPop: false,
onPopInvokedWithResult: (didPop, _) {
if (didPop) return;
return BackButtonListener(
// Same reason as the room image viewer: this dialog lives on the root
// navigator, but go_router asks the shell navigator first, so only a
// [BackButtonListener] (which runs before the router) can keep the back
// button from popping the page underneath.
onBackButtonPressed: () async {
_close(context);
return true;
},
child: GestureDetector(
onTap: () => _close(context),
child: Scaffold(
backgroundColor: Colors.black.withAlpha(128),
extendBodyBehindAppBar: true,
appBar: AppBar(
elevation: 0,
leading: IconButton(
style: iconButtonStyle,
icon: const Icon(Icons.close),
onPressed: () => _close(context),
color: Colors.white,
tooltip: L10n.of(context).close,
child: PopScope<Object?>(
canPop: false,
onPopInvokedWithResult: (didPop, _) {
if (didPop) return;
_close(context);
},
child: GestureDetector(
onTap: () => _close(context),
child: Scaffold(
backgroundColor: Colors.black.withAlpha(128),
extendBodyBehindAppBar: true,
appBar: AppBar(
elevation: 0,
leading: IconButton(
style: iconButtonStyle,
icon: const Icon(Icons.close),
onPressed: () => _close(context),
color: Colors.white,
tooltip: L10n.of(context).close,
),
backgroundColor: Colors.transparent,
),
backgroundColor: Colors.transparent,
),
body: InteractiveViewer(
minScale: 1.0,
maxScale: 10.0,
onInteractionEnd: (endDetails) {
if (endDetails.velocity.pixelsPerSecond.dy >
MediaQuery.sizeOf(context).height * 1.5) {
_close(context);
}
},
child: Center(
child: GestureDetector(
// Ignore taps to not go back here:
onTap: () {},
child: MxcImage(
key: ValueKey(mxContent.toString()),
uri: mxContent,
fit: BoxFit.contain,
isThumbnail: false,
animated: true,
body: InteractiveViewer(
minScale: 1.0,
maxScale: 10.0,
onInteractionEnd: (endDetails) {
if (endDetails.velocity.pixelsPerSecond.dy >
MediaQuery.sizeOf(context).height * 1.5) {
_close(context);
}
},
child: Center(
child: GestureDetector(
// Ignore taps to not go back here:
onTap: () {},
child: MxcImage(
key: ValueKey(mxContent.toString()),
uri: mxContent,
fit: BoxFit.contain,
isThumbnail: false,
animated: true,
),
),
),
),