fix(library): 优化观看历史标题加载
This commit is contained in:
1 parent
abfca7a3be
commit
78114fa46d
11 files changed
+135
-88
No files matched your search
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user