refactor(detail): share the season-download filter and the download-retry pipeline
The downloaded-episodes-for-a-season filter+sort was written out three times in media_detail_screen (with drifting show-id expressions, preserved per call site), and the failed/cancelled download branches in the action buttons duplicated the same six-step retry pipeline verbatim. One helper each.
This commit is contained in:
@@ -437,6 +437,27 @@ extension _MediaDetailActionButtons on _MediaDetailScreenState {
|
||||
);
|
||||
}
|
||||
|
||||
/// Shared retry pipeline for failed/cancelled downloads: confirm download
|
||||
/// restrictions, re-resolve the version, then replace the existing download
|
||||
/// with a fresh queue entry.
|
||||
Future<void> _retryDownload(DownloadProvider downloadProvider, MediaItem metadata, String globalKey) async {
|
||||
if (!await confirmBackgroundDownloadRestrictions(context) || !mounted) return;
|
||||
|
||||
final client = _getMediaClientForMetadata(context);
|
||||
if (client == null) return;
|
||||
|
||||
final versionConfig = await _resolveDownloadVersion(context, metadata, client);
|
||||
if (versionConfig == null || !mounted) return;
|
||||
|
||||
await downloadProvider.deleteDownload(globalKey);
|
||||
try {
|
||||
await downloadProvider.queueDownload(metadata, client, versionConfig: versionConfig);
|
||||
if (mounted) showSuccessSnackBar(context, t.downloads.downloadQueued);
|
||||
} on CellularDownloadBlockedException {
|
||||
if (mounted) showErrorSnackBar(context, t.settings.cellularDownloadBlocked);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleDownloadButtonPressed(MediaItem metadata) async {
|
||||
final downloadProvider = context.read<DownloadProvider>();
|
||||
final globalKey = metadata.globalKey;
|
||||
@@ -460,21 +481,7 @@ extension _MediaDetailActionButtons on _MediaDetailScreenState {
|
||||
if (progress?.status == DownloadStatus.failed) {
|
||||
// A failed download is the likeliest moment for the restriction to be
|
||||
// the actual cause, so check before spending another attempt on it.
|
||||
if (!await confirmBackgroundDownloadRestrictions(context) || !mounted) return;
|
||||
|
||||
final client = _getMediaClientForMetadata(context);
|
||||
if (client == null) return;
|
||||
|
||||
final versionConfig = await _resolveDownloadVersion(context, metadata, client);
|
||||
if (versionConfig == null || !mounted) return;
|
||||
|
||||
await downloadProvider.deleteDownload(globalKey);
|
||||
try {
|
||||
await downloadProvider.queueDownload(metadata, client, versionConfig: versionConfig);
|
||||
if (mounted) showSuccessSnackBar(context, t.downloads.downloadQueued);
|
||||
} on CellularDownloadBlockedException {
|
||||
if (mounted) showErrorSnackBar(context, t.settings.cellularDownloadBlocked);
|
||||
}
|
||||
await _retryDownload(downloadProvider, metadata, globalKey);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -491,20 +498,7 @@ extension _MediaDetailActionButtons on _MediaDetailScreenState {
|
||||
await downloadProvider.deleteDownload(globalKey);
|
||||
if (mounted) showSuccessSnackBar(context, t.downloads.downloadDeleted);
|
||||
} else if (retry && mounted) {
|
||||
if (!await confirmBackgroundDownloadRestrictions(context) || !mounted) return;
|
||||
final client = _getMediaClientForMetadata(context);
|
||||
if (client == null) return;
|
||||
|
||||
final versionConfig = await _resolveDownloadVersion(context, metadata, client);
|
||||
if (versionConfig == null || !mounted) return;
|
||||
|
||||
await downloadProvider.deleteDownload(globalKey);
|
||||
try {
|
||||
await downloadProvider.queueDownload(metadata, client, versionConfig: versionConfig);
|
||||
if (mounted) showSuccessSnackBar(context, t.downloads.downloadQueued);
|
||||
} on CellularDownloadBlockedException {
|
||||
if (mounted) showErrorSnackBar(context, t.settings.cellularDownloadBlocked);
|
||||
}
|
||||
await _retryDownload(downloadProvider, metadata, globalKey);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1540,12 +1540,16 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
|
||||
}
|
||||
}
|
||||
|
||||
/// Downloaded episodes of [showId] belonging to the season with [seasonIndex], sorted by episode number.
|
||||
List<MediaItem> _downloadedEpisodesForSeason(DownloadProvider downloadProvider, String showId, int? seasonIndex) {
|
||||
return downloadProvider.getDownloadedEpisodesForShow(showId).where((ep) => ep.parentIndex == seasonIndex).toList()
|
||||
..sort((a, b) => (a.index ?? 0).compareTo(b.index ?? 0));
|
||||
}
|
||||
|
||||
/// Load episodes from downloaded content for a season
|
||||
void _loadEpisodesFromDownloads() {
|
||||
final downloadProvider = context.read<DownloadProvider>();
|
||||
final allEpisodes = downloadProvider.getDownloadedEpisodesForShow(_metadata.parentId ?? '');
|
||||
final seasonEpisodes = allEpisodes.where((ep) => ep.parentIndex == _metadata.index).toList()
|
||||
..sort((a, b) => (a.index ?? 0).compareTo(b.index ?? 0));
|
||||
final seasonEpisodes = _downloadedEpisodesForSeason(downloadProvider, _metadata.parentId ?? '', _metadata.index);
|
||||
|
||||
setState(() {
|
||||
_allEpisodes = _allEpisodes.completeInitialLoad(seasonEpisodes, seasonEpisodes.length);
|
||||
@@ -1619,9 +1623,7 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
|
||||
if (widget.isOffline) {
|
||||
// Offline: load from downloads (already the complete set).
|
||||
final downloadProvider = context.read<DownloadProvider>();
|
||||
final allEpisodes = downloadProvider.getDownloadedEpisodesForShow(_metadata.id);
|
||||
final seasonEpisodes = allEpisodes.where((ep) => ep.parentIndex == season.index).toList()
|
||||
..sort((a, b) => (a.index ?? 0).compareTo(b.index ?? 0));
|
||||
final seasonEpisodes = _downloadedEpisodesForSeason(downloadProvider, _metadata.id, season.index);
|
||||
_completeSeasonEpisodesLoad(
|
||||
seasonIndex: seasonIndex,
|
||||
seasonId: seasonId,
|
||||
@@ -2895,12 +2897,9 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
|
||||
MediaItem? firstEpisode;
|
||||
if (!mounted) return;
|
||||
if (widget.isOffline) {
|
||||
// In offline mode, get episodes from downloads
|
||||
// In offline mode, get episodes from downloads (filtered to this season).
|
||||
final downloadProvider = context.read<DownloadProvider>();
|
||||
final allEpisodes = downloadProvider.getDownloadedEpisodesForShow(_metadata.id);
|
||||
// Filter to episodes of this season
|
||||
final episodes = allEpisodes.where((ep) => ep.parentIndex == firstSeason.index).toList()
|
||||
..sort((a, b) => (a.index ?? 0).compareTo(b.index ?? 0));
|
||||
final episodes = _downloadedEpisodesForSeason(downloadProvider, _metadata.id, firstSeason.index);
|
||||
firstEpisode = episodes.isEmpty ? null : episodes.first;
|
||||
} else {
|
||||
final client = getServerBoundMediaClient(context);
|
||||
|
||||
Reference in New Issue
Block a user