fix: 主页的系统返回手势不再退回登录页
PopScope 的 canPop 写的是 !_loggingOut,平时即为 true,所以原生返回手势会 直接把 HomePage 弹出、落回 Login Page;同时因为 didPop==true,回调里的 退登分支根本不会执行 —— 一个原因同时造成「回到登录页」和「账号没退出」, 留下一个会话仍在线的半退出状态。 改为 canPop:false 把根路由锁死在主页,返回意图交给 _exitApp:非 iOS 平台 走 SystemNavigator.pop 结束应用(iOS 不允许程序化退出,根路由也没有返回手势)。 AppBar 的退出按钮与风险操作完成后的 onExitToTitle 仍走 _performLogoutAndExit, 那两处是明确要回主标题。 新增回归用例:把 HomePage push 在占位根路由之上,触发 handlePopRoute, 断言 HomePage 仍在栈上且调用了 SystemNavigator.pop。
This commit is contained in:
1 parent
cb50426a61
commit
6b2efaebba
2 files changed
+63
-4
No files matched your search
@@ -1,4 +1,7 @@
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart' show SystemNavigator;
|
||||
|
||||
import '../config/responsive.dart';
|
||||
import '../config/strings.dart';
|
||||
@@ -169,6 +172,9 @@ class _HomePageState extends State<HomePage> {
|
||||
await _session.logoutGame(userId: widget.userId);
|
||||
}
|
||||
|
||||
/// 退登并回到主标题页。供 AppBar 的退出按钮与风险操作完成后的
|
||||
/// onExitToTitle 使用——这两处都是「明确要回标题」,与主页上的
|
||||
/// 系统返回手势不同(后者见 [_exitApp])。
|
||||
Future<void> _performLogoutAndExit() async {
|
||||
setState(() => _loggingOut = true);
|
||||
if (_session.gameLogin != null) {
|
||||
@@ -184,6 +190,13 @@ class _HomePageState extends State<HomePage> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 主页上的原生返回手势 = 结束应用。
|
||||
void _exitApp() {
|
||||
// iOS 不允许程序化退出,且根路由本来也没有返回手势。
|
||||
if (Platform.isIOS) return;
|
||||
SystemNavigator.pop();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
@@ -192,11 +205,13 @@ class _HomePageState extends State<HomePage> {
|
||||
listenable: _session,
|
||||
builder: (context, _) {
|
||||
return PopScope(
|
||||
canPop: !_loggingOut,
|
||||
// 根路由锁死在主页。之前 canPop 为 !_loggingOut(平时即 true),系统返回
|
||||
// 手势会直接把 HomePage 弹掉、落回 Login Page,而且因为 didPop==true,
|
||||
// 回调里的退登根本不会执行——既回错页面又没退登。
|
||||
canPop: false,
|
||||
onPopInvokedWithResult: (didPop, _) {
|
||||
if (!didPop && !_loggingOut) {
|
||||
_performLogoutAndExit();
|
||||
}
|
||||
if (didPop || _loggingOut) return;
|
||||
_exitApp();
|
||||
},
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:ichino/pages/home_page.dart';
|
||||
|
||||
/// 主页上的系统返回手势不能把 HomePage 弹掉(那会落回 Login Page,
|
||||
/// 而且退登逻辑因为 didPop==true 根本不会跑)。
|
||||
void main() {
|
||||
testWidgets('主页收到系统返回时结束应用而不是退回上一页', (tester) async {
|
||||
final calls = <String>[];
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(SystemChannels.platform, (call) async {
|
||||
calls.add(call.method);
|
||||
return null;
|
||||
});
|
||||
addTearDown(() {
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(SystemChannels.platform, null);
|
||||
});
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(home: Text('login-root')),
|
||||
);
|
||||
|
||||
final navigator = tester.state<NavigatorState>(find.byType(Navigator));
|
||||
navigator.push(
|
||||
MaterialPageRoute(builder: (_) => const HomePage(userId: 1, token: 't')),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('login-root'), findsNothing);
|
||||
expect(find.byType(HomePage), findsOneWidget);
|
||||
|
||||
await tester.binding.handlePopRoute();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// HomePage 仍在栈上:根路由被锁死。
|
||||
expect(find.byType(HomePage), findsOneWidget);
|
||||
expect(find.text('login-root'), findsNothing);
|
||||
|
||||
// 非 iOS 上应当走 SystemNavigator.pop 结束应用。
|
||||
expect(calls, contains('SystemNavigator.pop'));
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user