Skip to content

Commit 1fa4b13

Browse files
committed
FIX: 避免文件详情覆盖合集排序
1 parent 681481a commit 1fa4b13

4 files changed

Lines changed: 30 additions & 33 deletions

File tree

‎TASKS.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
> 当前待办与本次完成记录;此前完成任务“随心听字幕列表按当前句定位和自动聚焦”(2026-09-29)已归档,详见 [2026-09-29 归档](./docs/tasks-archive/tasks-2026-09-29-completed.md)。
44
55
## 本次完成
6+
- [x] 修复社区合集文件详情覆盖本地排序(2026-10-24):下载和更新字幕收到文件详情后只刷新音频元数据,不再写入 `collection_audio_items.sort_order`;合集排序仍由合集列表加入/同步流程维护。新增回归断言:本地排序为 220、文件详情返回 0 时,下载后排序仍为 220;合集同步则以列表返回的 0 更新原有排序 220。下载通知与合集同步两个定向测试文件共 13 项通过;3 个改动 Dart 文件定向分析无问题,`dart format` 与 `git diff --check` 通过。测试输出 media_kit 原生依赖初始化告警,但用例全部通过。未运行 `scripts/check.sh`:改动局限于客户端元数据持久化,定向测试覆盖受影响流程;未运行 Maestro:未改 UI、路由或首启流程。**完成时间**: 2026-10-24 13:44
67
- [x] 修复复述后台取消转录处理中回合时遗留录音文件(2026-10-24):`RecordingService.cancelRecording` 新增显式 `discardStoppedRecording` 选项;复述后台收尾启用该选项,删除 `stopSession` 已结束但尚未完成转录的录音文件,同时默认取消路径仍保留已停止录音。新增 RecordingService 与复述控制器回归断言;先确认旧实现下控制器用例因删除列表为空而失败,修复后两个定向测试文件共 16 项通过。4 个相关 Dart 文件定向分析无问题,格式与 `git diff --check` 通过。测试输出 media_kit 原生依赖初始化告警,但用例全部通过。未运行 `scripts/check.sh`:改动局限于后台取消的临时录音清理,定向测试与分析覆盖受影响路径。**完成时间**: 2026-10-24 12:52
78
- [x] 修复复述后台取消的处理中与启动竞态(2026-10-24):后台事件现在让当前录音回合代际失效,取消录音中、启动中及识别处理中底层会话;旧识别结果不能在状态重置后写回。保存后台收尾 future,新录音等待旧启动/识别收尾后再开始。新增录音中取消、处理中取消与丢弃迟到结果、取消收尾期间立即重试三项回归测试;旧实现下处理中状态迟到写回和立即重试均复现失败,修复后复述录音控制器与播放器测试共 40 项通过。4 个相关 Dart 文件定向分析无问题,格式与 `git diff --check` 通过。测试有 media_kit 原生依赖初始化告警,但用例全部通过。未运行 `scripts/check.sh`:改动范围局限于复述后台录音收尾,定向测试与分析覆盖相关路径。**完成时间**: 2026-10-24 12:45
89
- [x] 修复复述以外的后台事件污染复述录音状态(2026-10-24):移除复述录音控制器的全局生命周期监听,改由仍活动的 `RetellPlayer` 在进入后台时显式通知录音控制器取消当前录音并设置等待开口超时标记;释放播放器后的生命周期事件仍由现有播放器守卫忽略。检查跟读与难句补练共用的 `SpeechRecordingController`:它保留自身后台取消录音并回到 idle 的行为,没有复述专用的粘性超时标记,因此未见同类状态泄漏。新增录音控制器与播放器生命周期回归断言。复述录音、复述播放器、跟读录音、跟读流程及难句补练测试共 120 项通过;4 个改动 Dart 文件定向分析无问题,格式与 `git diff --check` 通过。测试运行有 media_kit 原生依赖初始化告警,但用例全部通过。未运行 `scripts/check.sh`:改动限于复述生命周期所有权与状态隔离,定向测试覆盖受影响链路。**完成时间**: 2026-10-24 12:36

‎lib/features/community_collections/download/community_download_notifier.dart‎

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ class CommunityDownload extends _$CommunityDownload {
113113
await _persistFileMetadata(
114114
database,
115115
audioItemId: audioItemId,
116-
localCollectionId: collection.id,
117116
file: subtitle.file,
118117
);
119118
await ref.read(audioLibraryProvider.notifier).loadLibrary();
@@ -189,12 +188,7 @@ class CommunityDownload extends _$CommunityDownload {
189188
if (localCollection == null) {
190189
throw StateError('Community collection was removed during download');
191190
}
192-
await _persistFileMetadata(
193-
database,
194-
audioItemId: item.id,
195-
localCollectionId: localCollection.id,
196-
file: file,
197-
);
191+
await _persistFileMetadata(database, audioItemId: item.id, file: file);
198192
await ref.read(audioLibraryProvider.notifier).loadLibrary();
199193
await ref.read(collectionListProvider.notifier).loadCollections();
200194
final srt = _toSrt(subtitle);
@@ -273,36 +267,26 @@ class CommunityDownload extends _$CommunityDownload {
273267
}
274268
}
275269

270+
/// 持久化文件详情中的音频元数据,不修改合集关联排序。
276271
Future<void> _persistFileMetadata(
277272
db.AppDatabase database, {
278273
required String audioItemId,
279-
required String localCollectionId,
280274
required CommunityCollectionFile file,
281275
}) async {
282276
final duration = file.durationSec;
283-
await database.transaction(() async {
284-
await (database.update(
285-
database.audioItems,
286-
)..where((table) => table.id.equals(audioItemId))).write(
287-
db.AudioItemsCompanion(
288-
name: Value(file.title),
289-
totalDuration: duration == null
290-
? const Value.absent()
291-
: Value(duration),
292-
originalDate: Value(file.publishedAt),
293-
communityUnavailableAt: const Value(null),
294-
updatedAt: Value(DateTime.now()),
295-
),
296-
);
297-
await (database.update(database.collectionAudioItems)..where(
298-
(table) =>
299-
table.collectionId.equals(localCollectionId) &
300-
table.audioItemId.equals(audioItemId),
301-
))
302-
.write(
303-
db.CollectionAudioItemsCompanion(sortOrder: Value(file.sortOrder)),
304-
);
305-
});
277+
await (database.update(
278+
database.audioItems,
279+
)..where((table) => table.id.equals(audioItemId))).write(
280+
db.AudioItemsCompanion(
281+
name: Value(file.title),
282+
totalDuration: duration == null
283+
? const Value.absent()
284+
: Value(duration),
285+
originalDate: Value(file.publishedAt),
286+
communityUnavailableAt: const Value(null),
287+
updatedAt: Value(DateTime.now()),
288+
),
289+
);
306290
}
307291

308292
Future<void> _markFileUnavailable(

‎test/features/community_collections/community_download_notifier_test.dart‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ void main() {
165165
);
166166
});
167167

168-
test('社区文件大小元数据不准确时仍按后台任务完成状态入库', () async {
168+
test('文件大小元数据不准仍完成下载,且详情排序不覆盖合集排序', () async {
169169
final database = db.AppDatabase(NativeDatabase.memory());
170170
final dataDirectory = await Directory.systemTemp.createTemp(
171171
'community-download-success-',
@@ -197,6 +197,7 @@ void main() {
197197
collectionId: const Value('collection-1'),
198198
audioItemId: const Value('audio-1'),
199199
addedAt: Value(DateTime(2026, 1, 1)),
200+
sortOrder: const Value(220),
200201
),
201202
);
202203

@@ -241,5 +242,9 @@ void main() {
241242
expect(item?.totalDuration, 12);
242243
expect(item?.audioPath, 'audios/community/audio-1.mp3');
243244
expect(await File('${dataDirectory.path}/${item?.audioPath}').length(), 3);
245+
final collectionAudioItem = await (database.select(
246+
database.collectionAudioItems,
247+
)..where((row) => row.collectionId.equals('collection-1'))).getSingle();
248+
expect(collectionAudioItem.sortOrder, 220);
244249
});
245250
}

‎test/features/community_collections/community_sync_service_test.dart‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,12 @@ void main() {
161161
expect(api.detailCalls, ['remote-1']);
162162
});
163163

164-
test('已有文件的远端空时长不会覆盖本地时长', () async {
164+
test('合集同步更新列表排序,同时保留已有本地时长', () async {
165165
await _insertCollection(database, 'local-1', 'remote-1', 'One');
166166
await _insertFile(database, 'local-1', 'file-1', 'Old one', duration: 42);
167+
await (database.update(database.collectionAudioItems)
168+
..where((row) => row.audioItemId.equals('local-file-1')))
169+
.write(const db.CollectionAudioItemsCompanion(sortOrder: Value(220)));
167170

168171
final api = _FakeCommunityApi(
169172
[_catalogEntry('remote-1', 'One')],
@@ -178,7 +181,11 @@ void main() {
178181
).syncAll(force: true);
179182

180183
final row = await database.audioItemDao.getByRemoteAudioId('file-1');
184+
final collectionAudioItem = await (database.select(
185+
database.collectionAudioItems,
186+
)..where((row) => row.collectionId.equals('local-1'))).getSingle();
181187
expect(row?.totalDuration, 42);
188+
expect(collectionAudioItem.sortOrder, 0);
182189
});
183190

184191
test('同步写入服务端难度并在服务端清空时移除本地难度', () async {

0 commit comments

Comments
 (0)