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:
@@ -199,15 +199,25 @@ class ImageViewerController extends State<ImageViewer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => PopScope<Object?>(
|
Widget build(BuildContext context) => BackButtonListener(
|
||||||
// Claim the system back button (and predictive back gesture) for the
|
// A [PopScope] alone is not enough here: go_router's `popRoute()` asks
|
||||||
// viewer. Without this, the request can reach go_router instead, which
|
// `GoRouterDelegate._findCurrentNavigators()`, which returns the shell
|
||||||
// pops the chat room out of the shell and leaves the image on screen.
|
// navigator BEFORE the root one. The viewer is a dialog on the root
|
||||||
canPop: false,
|
// navigator, so the shell navigator never sees its [PopEntry], pops the
|
||||||
onPopInvokedWithResult: (didPop, _) {
|
// chat room instead and returns `true`, leaving the image on screen.
|
||||||
if (didPop) return;
|
// A [BackButtonListener] is asked before the router gets the request at
|
||||||
|
// all, so the viewer gets to close itself first.
|
||||||
|
onBackButtonPressed: () async {
|
||||||
closeAction();
|
closeAction();
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
child: ImageViewerView(this),
|
child: PopScope<Object?>(
|
||||||
|
canPop: false,
|
||||||
|
onPopInvokedWithResult: (didPop, _) {
|
||||||
|
if (didPop) return;
|
||||||
|
closeAction();
|
||||||
|
},
|
||||||
|
child: ImageViewerView(this),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,49 +24,57 @@ class MxcImageViewer extends StatelessWidget {
|
|||||||
backgroundColor: Colors.black.withAlpha(200),
|
backgroundColor: Colors.black.withAlpha(200),
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
);
|
);
|
||||||
return PopScope<Object?>(
|
return BackButtonListener(
|
||||||
// Claim the system back button for the viewer so that it is dismissed
|
// Same reason as the room image viewer: this dialog lives on the root
|
||||||
// instead of letting the router navigate away underneath it.
|
// navigator, but go_router asks the shell navigator first, so only a
|
||||||
canPop: false,
|
// [BackButtonListener] (which runs before the router) can keep the back
|
||||||
onPopInvokedWithResult: (didPop, _) {
|
// button from popping the page underneath.
|
||||||
if (didPop) return;
|
onBackButtonPressed: () async {
|
||||||
_close(context);
|
_close(context);
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
child: GestureDetector(
|
child: PopScope<Object?>(
|
||||||
onTap: () => _close(context),
|
canPop: false,
|
||||||
child: Scaffold(
|
onPopInvokedWithResult: (didPop, _) {
|
||||||
backgroundColor: Colors.black.withAlpha(128),
|
if (didPop) return;
|
||||||
extendBodyBehindAppBar: true,
|
_close(context);
|
||||||
appBar: AppBar(
|
},
|
||||||
elevation: 0,
|
child: GestureDetector(
|
||||||
leading: IconButton(
|
onTap: () => _close(context),
|
||||||
style: iconButtonStyle,
|
child: Scaffold(
|
||||||
icon: const Icon(Icons.close),
|
backgroundColor: Colors.black.withAlpha(128),
|
||||||
onPressed: () => _close(context),
|
extendBodyBehindAppBar: true,
|
||||||
color: Colors.white,
|
appBar: AppBar(
|
||||||
tooltip: L10n.of(context).close,
|
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,
|
||||||
body: InteractiveViewer(
|
maxScale: 10.0,
|
||||||
minScale: 1.0,
|
onInteractionEnd: (endDetails) {
|
||||||
maxScale: 10.0,
|
if (endDetails.velocity.pixelsPerSecond.dy >
|
||||||
onInteractionEnd: (endDetails) {
|
MediaQuery.sizeOf(context).height * 1.5) {
|
||||||
if (endDetails.velocity.pixelsPerSecond.dy >
|
_close(context);
|
||||||
MediaQuery.sizeOf(context).height * 1.5) {
|
}
|
||||||
_close(context);
|
},
|
||||||
}
|
child: Center(
|
||||||
},
|
child: GestureDetector(
|
||||||
child: Center(
|
// Ignore taps to not go back here:
|
||||||
child: GestureDetector(
|
onTap: () {},
|
||||||
// Ignore taps to not go back here:
|
child: MxcImage(
|
||||||
onTap: () {},
|
key: ValueKey(mxContent.toString()),
|
||||||
child: MxcImage(
|
uri: mxContent,
|
||||||
key: ValueKey(mxContent.toString()),
|
fit: BoxFit.contain,
|
||||||
uri: mxContent,
|
isThumbnail: false,
|
||||||
fit: BoxFit.contain,
|
animated: true,
|
||||||
isThumbnail: false,
|
),
|
||||||
animated: true,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user