feat: 旅行伙伴发放与编组、修复退登卡死、优化宽屏布局、加 CI
自动退出登录卡死:_performLogoutAndExit 只 pop() 一层,而解锁/收藏品页是 push
在 HomePage 之上的,退登后被弹回「风险」hub,同时 _loggingOut 仍为 true,
PopScope(canPop:false) + 返回键转圈形成死局。改为 popUntil(isFirst)。
旅行伙伴发不了:它是 ItemKind.Character = 9,与搭档 Partner = 10 是两种东西,
原先收藏品的类型列表 [1,2,3,10,11,12] 里根本没有 9。按客户端实现,角色不走
userItemList(ExportUserItems 不导出 itemKind 9),而是
upsertUserAll.userCharacterList 的 {characterId, level, awakening, useCount},
配 isNewCharacterList 一行一字符。新增发放与 5 槽 charaSlot 编组页,
含「把槽 0 复制到其他槽位」,并校验所选角色确为已拥有或本次待发放。
宽屏布局:各页只有 ConstrainedBox 限宽、没有居中容器,1440 窗口下内容贴左、
右侧大片空白。抽出 responsiveBody 统一居中;B50 预览改用按宽度适配
(InteractiveViewer constrained:false + FittedBox fitWidth),横屏下不再被
contain 缩成中间一小块,导出仍是原始 1762x1850。
CI:.github/workflows/build.yml 先跑 analyze+test 作为门槛,再产出
Windows exe、Android apk、iOS 未签名 ipa(macOS runner,无证书故不可安装)。
README 从 Flutter 模板改写为实际文档,含 path_provider/jni 与 JBR jlink
两个构建环境坑的说明。
This commit is contained in:
1 parent
ebd1fdddaa
commit
8dda399f76
24 files changed
+1832
-134
No files matched your search
@@ -0,0 +1,77 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:ichino/config/strings.dart';
|
||||
import 'package:ichino/config/title_server_config.dart';
|
||||
import 'package:ichino/pages/travel_partner_page.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
Future<void> _pumpPage(WidgetTester tester, {required bool loggedIn}) async {
|
||||
SharedPreferences.setMockInitialValues({});
|
||||
await TitleServerConfigHolder().update(
|
||||
const TitleServerConfig(
|
||||
titleServerUrl: 'http://127.0.0.1:9999',
|
||||
aesKey: '0123456789abcdef',
|
||||
aesIv: '0123456789abcdef',
|
||||
clientId: 'A63E01C2805',
|
||||
),
|
||||
);
|
||||
|
||||
tester.view.physicalSize = loggedIn ? const Size(420, 1500) : const Size(1440, 900);
|
||||
tester.view.devicePixelRatio = 1.0;
|
||||
addTearDown(tester.view.reset);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: TravelPartnerPage(
|
||||
userId: 42,
|
||||
cookies: 'JSESSIONID=X',
|
||||
loginDateTime: loggedIn ? 1 : null,
|
||||
loginId: loggedIn ? 7 : null,
|
||||
onExitToTitle: () async {},
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('已登录时渲染 5 个槽位与一键复制,且无溢出', (tester) async {
|
||||
await _pumpPage(tester, loggedIn: true);
|
||||
|
||||
expect(tester.takeException(), isNull);
|
||||
for (var i = 0; i < 5; i++) {
|
||||
expect(
|
||||
find.text(AppStrings.travelPartnerSlotLabel(i)),
|
||||
findsOneWidget,
|
||||
reason: '缺少槽位 $i 的下拉框',
|
||||
);
|
||||
}
|
||||
expect(find.text(AppStrings.travelPartnerCopySlot0), findsOneWidget);
|
||||
expect(find.text(AppStrings.travelPartnerGrantTitle), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('未登录时给出提示并禁用执行', (tester) async {
|
||||
await _pumpPage(tester, loggedIn: false);
|
||||
|
||||
expect(tester.takeException(), isNull);
|
||||
expect(find.text(AppStrings.travelPartnerNotLoggedIn), findsOneWidget);
|
||||
|
||||
final run = tester.widget<FilledButton>(
|
||||
find.ancestor(
|
||||
of: find.text(AppStrings.travelPartnerRun),
|
||||
matching: find.byType(FilledButton),
|
||||
),
|
||||
);
|
||||
expect(run.onPressed, isNull);
|
||||
});
|
||||
|
||||
testWidgets('槽 0 未选择时复制按钮不改动槽位', (tester) async {
|
||||
await _pumpPage(tester, loggedIn: true);
|
||||
|
||||
await tester.tap(find.text(AppStrings.travelPartnerCopySlot0));
|
||||
await tester.pump();
|
||||
|
||||
// 未拥有任何角色时,复制应被拦下并提示,而不是写入非法槽位。
|
||||
expect(find.text(AppStrings.travelPartnerCopyNeedSlot0), findsOneWidget);
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user