feat(app): album banner picker in edit form — show current banner, pick & upload on save

- api_client:uploadAlbumAssetFromFile 泛化(cover 为薄壳)+ fetchAlbumAssetUrl
  (GET /albums/{id}/assets → 指定 kind 全局行 URL)
- 编辑页 Details:封面下方新增「宣传图」3:1 选择器——编辑模式异步加载现有
  banner 预览(失败静默);保存成功后上传(同封面:失败不阻塞表单结果)
- 未保存变更判断纳入 banner;l10n zh/en
- 测试适配:编辑用例 pumpForm 后清空 banner 现状预检请求(397/397 全绿)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-23 11:07:54 +08:00
parent 3d45350711
commit c2143e1f94
10 changed files with 288 additions and 39 deletions
@@ -244,6 +244,7 @@ void main() {
),
);
await pumpForm(tester, clientOf(adapter), existing: existing);
adapter.requests.clear();
// 顶栏 TabBar(Details/Access)+ 内容区语言 TabBar。
expect(find.text('Edit album'), findsOneWidget);
@@ -275,6 +276,9 @@ void main() {
clientOf(adapter),
existing: Album.fromJson(albumJson()),
);
adapter.requests.clear();
// UI06:banner 现状预检(GET /assets)已记录——清空后断言只看用户动作。
adapter.requests.clear();
// Details 页签输入标题。
await tester.enterText(find.byType(TextFormField).at(1), '闭幕演出');
@@ -302,6 +306,9 @@ void main() {
clientOf(adapter),
existing: Album.fromJson(albumJson()),
);
adapter.requests.clear();
// UI06:banner 现状预检(GET /assets)已记录——清空后断言只看用户动作。
adapter.requests.clear();
await openAccessTab(tester);
@@ -367,6 +374,7 @@ void main() {
final existing =
Album.fromJson(albumJson(originalDownloadEnabled: true));
await pumpForm(tester, clientOf(adapter), existing: existing);
adapter.requests.clear();
await openAccessTab(tester);
@@ -398,6 +406,7 @@ void main() {
);
final existing = Album.fromJson(albumJson());
await pumpForm(tester, clientOf(adapter), existing: existing);
adapter.requests.clear();
await openAccessTab(tester);
await tester
@@ -427,6 +436,7 @@ void main() {
albumJson(endAt: '2026-09-19T10:00:00Z'),
);
await pumpForm(tester, clientOf(adapter), existing: existing);
adapter.requests.clear();
await tapVisible(tester, find.byTooltip('Clear end time'));
await tester.pump();
@@ -446,6 +456,7 @@ void main() {
);
final existing = Album.fromJson(albumJson());
await pumpForm(tester, clientOf(adapter), existing: existing);
adapter.requests.clear();
await tester.enterText(
find.byType(TextFormField).at(1),