fix(library): 优化观看历史标题加载

This commit is contained in:
Zhou Weidong committed 2026-10-22 12:42:58 +08:00
1 parent abfca7a3be
commit 78114fa46d
11 files changed
+135 -88

No files matched your search

-7
View File
@@ -32,13 +32,6 @@ class LibraryApi {
if (data is Map<String, dynamic>) {
return PageResult.fromJson(data, Drama.fromCardJson);
}
if (data is List) {
final list = data
.whereType<Map<String, dynamic>>()
.map(Drama.fromCardJson)
.toList(growable: false);
return PageResult(total: list.length, list: list);
}
return const PageResult();
}
-7
View File
@@ -52,13 +52,6 @@ class WatchApi {
if (data is Map<String, dynamic>) {
return PageResult.fromJson(data, WatchProgress.fromJson);
}
if (data is List) {
final list = data
.whereType<Map<String, dynamic>>()
.map(WatchProgress.fromJson)
.toList(growable: false);
return PageResult(total: list.length, list: list);
}
return const PageResult();
}
@@ -130,6 +130,15 @@ class WatchRecordsController extends ChangeNotifier {
_notify();
}
/// 点击有标题的记录时再按需加载详情,避免列表阶段产生 N+1。
Future<Drama?> detailForOpen(String dramaId) async {
final cached = _detailCache[dramaId];
if (cached != null) return cached;
await _loadDetail(dramaId);
_notify();
return _detailCache[dramaId];
}
/// 删除单条记录,先更新 UI,失败按原位置回滚。
Future<bool> remove(String dramaId) async {
final index = _recordIndex(dramaId);
@@ -201,11 +210,12 @@ class WatchRecordsController extends ChangeNotifier {
}
Future<void> _hydrate(List<String> dramaIds) async {
for (final id in dramaIds) {
final missingTitles = dramaIds.where(_hasMissingTitle).toSet().toList();
for (final id in missingTitles) {
if (_detailCache.containsKey(id)) await _loadDetail(id);
}
final queue = [
for (final id in dramaIds)
for (final id in missingTitles)
if (!_detailCache.containsKey(id)) id,
];
final workerCount = queue.length < detailConcurrency
@@ -222,9 +232,15 @@ class WatchRecordsController extends ChangeNotifier {
]);
}
Future<void> _loadDetail(String dramaId) async {
bool _hasMissingTitle(String dramaId) {
final index = _recordIndex(dramaId);
if (index < 0) return;
if (index < 0) return false;
return (records[index].progress.dramaTitle?.trim() ?? '').isEmpty;
}
Future<Drama?> _loadDetail(String dramaId) async {
final index = _recordIndex(dramaId);
if (index < 0) return null;
final cached = _detailCache[dramaId];
if (cached != null) {
_replaceAt(
@@ -235,14 +251,14 @@ class WatchRecordsController extends ChangeNotifier {
detailFailed: false,
),
);
return;
return cached;
}
try {
final detail = await _catalog.fetchDrama(dramaId);
if (_disposed) return;
if (_disposed) return null;
_detailCache[dramaId] = detail;
final current = _recordIndex(dramaId);
if (current < 0) return;
if (current < 0) return detail;
_replaceAt(
current,
records[current].copyWith(
@@ -251,6 +267,7 @@ class WatchRecordsController extends ChangeNotifier {
detailFailed: false,
),
);
return detail;
} catch (failure, stackTrace) {
debugPrint(
'[WatchRecordsController] detail failed dramaId=$dramaId '
@@ -260,13 +277,14 @@ class WatchRecordsController extends ChangeNotifier {
stackTrace: stackTrace,
label: '[WatchRecordsController] detail failed dramaId=$dramaId',
);
if (_disposed) return;
if (_disposed) return null;
final current = _recordIndex(dramaId);
if (current < 0) return;
if (current < 0) return null;
_replaceAt(
current,
records[current].copyWith(detailLoading: false, detailFailed: true),
);
return null;
}
}
@@ -140,7 +140,7 @@ class _WatchRecordsBodyState extends State<_WatchRecordsBody> {
record: record,
onRetry: () => controller.retryDetail(record.dramaId),
onRemove: () => _remove(record.dramaId),
onOpen: record.drama == null ? null : () => _open(record),
onOpen: () => _open(record),
),
],
PagedListFooter(
@@ -219,10 +219,20 @@ class _WatchRecordsBodyState extends State<_WatchRecordsBody> {
}
Future<void> _open(WatchRecord record) async {
final drama =
record.drama ?? await controller.detailForOpen(record.dramaId);
if (!mounted) return;
if (drama == null) {
final l10n = AppLocalizations.of(context)!;
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(l10n.detailLoadFailed)));
return;
}
final episodeId = record.progress.episodeId;
await playDramaFromCatalog(
context,
record.drama!,
drama,
episodeId: episodeId.isEmpty ? null : episodeId,
);
}