自动退出登录卡死:_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
两个构建环境坑的说明。
121 lines
3.9 KiB
Dart
121 lines
3.9 KiB
Dart
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/music_risk_feature_view.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
Future<void> _seedConfig() async {
|
|
SharedPreferences.setMockInitialValues({});
|
|
await TitleServerConfigHolder().update(
|
|
const TitleServerConfig(
|
|
titleServerUrl: 'http://127.0.0.1:9999',
|
|
aesKey: '0123456789abcdef',
|
|
aesIv: '0123456789abcdef',
|
|
clientId: 'A63E01C2805',
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> _pumpView(WidgetTester tester, MusicRiskFeatureMode mode) async {
|
|
await _seedConfig();
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: MusicRiskFeatureView(
|
|
userId: 123,
|
|
cookies: 'JSESSIONID=X',
|
|
loginDateTime: 1,
|
|
loginId: 2,
|
|
mode: mode,
|
|
featureTitle: 't',
|
|
featureDesc: 'd',
|
|
onExitToTitle: () async {},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pump();
|
|
}
|
|
|
|
Future<void> _addById(WidgetTester tester, String label, String id) async {
|
|
await tester.enterText(find.widgetWithText(TextField, label), id);
|
|
await tester.tap(find.text(AppStrings.listAddButton).first);
|
|
await tester.pump();
|
|
}
|
|
|
|
void main() {
|
|
setUp(() => addTearDown(TitleServerConfigHolder().clear));
|
|
|
|
testWidgets('收藏品列表可累加多行并可移除', (tester) async {
|
|
await _pumpView(tester, MusicRiskFeatureMode.collectibles);
|
|
|
|
expect(find.textContaining(AppStrings.collectiblesPendingEmpty), findsOne);
|
|
|
|
await _addById(tester, AppStrings.collectiblesItemIdLabel, '250103');
|
|
await _addById(tester, AppStrings.collectiblesItemIdLabel, '30021');
|
|
|
|
expect(find.textContaining('#250103'), findsOneWidget);
|
|
expect(find.textContaining('#30021'), findsOneWidget);
|
|
expect(
|
|
find.textContaining('${AppStrings.collectiblesPendingTitle} (2)'),
|
|
findsOneWidget,
|
|
);
|
|
|
|
// 同一类型同一 ID 不应重复入列。
|
|
await _addById(tester, AppStrings.collectiblesItemIdLabel, '30021');
|
|
expect(
|
|
find.textContaining('${AppStrings.collectiblesPendingTitle} (2)'),
|
|
findsOneWidget,
|
|
);
|
|
|
|
await tester.tap(find.byTooltip(AppStrings.listRemoveTooltip).first);
|
|
await tester.pump();
|
|
expect(find.textContaining('#250103'), findsNothing);
|
|
expect(
|
|
find.textContaining('${AppStrings.collectiblesPendingTitle} (1)'),
|
|
findsOneWidget,
|
|
);
|
|
});
|
|
|
|
testWidgets('解锁列表按勾选展开难度且添加后清空输入', (tester) async {
|
|
await _pumpView(tester, MusicRiskFeatureMode.unlockMusic);
|
|
|
|
await tester.enterText(
|
|
find.widgetWithText(TextField, AppStrings.unlockMusicIdLabel),
|
|
'834',
|
|
);
|
|
await tester.tap(find.text(AppStrings.unlockMusicOption).first);
|
|
await tester.tap(find.text(AppStrings.unlockMasterOption).first);
|
|
await tester.pump();
|
|
await tester.tap(find.text(AppStrings.listAddButton).first);
|
|
await tester.pump();
|
|
|
|
final row = find.textContaining('#834');
|
|
expect(row, findsOneWidget);
|
|
expect(tester.widget<Text>(row.first).data, contains('Master'));
|
|
// 添加后输入与勾选应被清空,方便连续添加下一条。
|
|
expect(
|
|
tester.widget<TextField>(
|
|
find.widgetWithText(TextField, AppStrings.unlockMusicIdLabel),
|
|
).controller!.text,
|
|
isEmpty,
|
|
);
|
|
});
|
|
|
|
testWidgets('自动退出登录并返回标题页默认勾选', (tester) async {
|
|
await _pumpView(tester, MusicRiskFeatureMode.collectibles);
|
|
|
|
expect(
|
|
find.text(AppStrings.autoLogoutAndExit),
|
|
findsOneWidget,
|
|
);
|
|
// 未勾选任何解锁项时,唯一处于选中态的复选框就是自动退登。
|
|
final checked = tester
|
|
.widgetList<Checkbox>(find.byType(Checkbox))
|
|
.where((c) => c.value == true)
|
|
.toList();
|
|
expect(checked, hasLength(1));
|
|
});
|
|
}
|