navi: honor Screen.canPop across back/swipe pop paths

canPop was documented as gating the back button / swipe but was ignored by
ScreenBackHandler, XRouterBack.didPopRoute, and XRouter.canPop, so a stack
entry with canPop=false was still poppable by gesture or system back. Make it
authoritative in all three so a non-poppable pushed entry (e.g. an activation
screen) can't be backed out from under the user.
This commit is contained in:
agra
2026-05-29 20:05:37 +03:00
parent 2398c8ad35
commit e8f8882f2e
2 changed files with 5 additions and 4 deletions

View File

@@ -77,7 +77,8 @@ class XRouter extends BackButtonDispatcher
late final _overlayEntry = OverlayEntry(builder: _buildContent);
bool get canPop {
if (stack.isNotEmpty) return true;
final top = stack.lastOrNull;
if (top != null) return top.canPop;
if (home is ScreenShell) {
for (final screen in (home as ScreenShell).pages) {
if (!screen.popped) return true;
@@ -225,7 +226,7 @@ class XRouterBack extends RootBackButtonDispatcher {
}
if (router.home.handleBack()) return true;
final page = router.stack.lastOrNull;
if (page != null) {
if (page != null && page.canPop) {
page.pop();
return true;
}

View File

@@ -75,7 +75,7 @@ class ScreenStackState extends State<ScreenStack> with TickerProviderStateMixin
}
void _updateCanPop() {
final canPop = _entries.any((e) => !e.removing);
final canPop = _entries.any((e) => !e.removing && e.page.canPop);
if (canPop == _canPop) return;
_canPop = canPop;
WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -258,7 +258,7 @@ class ScreenStackState extends State<ScreenStack> with TickerProviderStateMixin
ScreenBackHandler(
key: entry.key,
entry: entry,
enabled: entry == top && _canPop,
enabled: entry == top && _canPop && entry.page.canPop,
onPop: () => entry.page.pop(),
),
],