@@ -11,10 +11,13 @@ import 'package:anytime/entities/episode.dart';
1111import 'package:anytime/repository/repository.dart' ;
1212import 'package:anytime/services/download/download_manager.dart' ;
1313import 'package:anytime/services/download/download_service.dart' ;
14+ import 'package:anytime/services/settings/settings_service.dart' ;
1415import 'package:collection/collection.dart' show IterableExtension;
16+ import 'package:flutter_downloader/flutter_downloader.dart' ;
1517import 'package:logging/logging.dart' ;
1618import 'package:mp3_info/mp3_info.dart' ;
1719import 'package:rxdart/rxdart.dart' ;
20+ import 'package:synchronized/synchronized.dart' ;
1821
1922/// An implementation of a [DownloadService] that handles downloading
2023/// of episodes on mobile.
@@ -23,18 +26,33 @@ class MobileDownloadService extends DownloadService {
2326
2427 final log = Logger ('MobileDownloadService' );
2528 final Repository repository;
29+ final SettingsService settingsService;
2630 final DownloadManager downloadManager;
27-
28- MobileDownloadService ({required this .repository, required this .downloadManager}) {
29- downloadManager.downloadProgress.pipe (downloadProgress);
30- downloadProgress.listen ((progress) {
31- _updateDownloadProgress (progress);
32- });
31+ late final StreamSubscription _downloadProgressSubscription;
32+
33+ /// Lock ensures we wait for task creation and local save
34+ /// before handling subsequent [Download update events] .
35+ final _downloadProgressLock = Lock ();
36+
37+ MobileDownloadService ({
38+ required this .repository,
39+ required this .downloadManager,
40+ required this .settingsService,
41+ }) {
42+ _downloadProgressSubscription = downloadManager.downloadProgress.listen (
43+ (event) async => await _downloadProgressLock.synchronized (
44+ () {
45+ downloadProgress.add (event);
46+ _updateDownloadProgress (event);
47+ },
48+ ),
49+ );
3350 }
3451
3552 @override
3653 void dispose () {
3754 downloadManager.dispose ();
55+ _downloadProgressSubscription.cancel ();
3856 }
3957
4058 @override
@@ -92,16 +110,18 @@ class MobileDownloadService extends DownloadService {
92110 /// the URL before calling download and ensure it is https.
93111 var url = await resolveUrl (episode.contentUrl! , forceHttps: true );
94112
95- final taskId = await downloadManager.enqueueTask (url, downloadPath, filename);
113+ await _downloadProgressLock.synchronized (() async {
114+ final taskId = await downloadManager.enqueueTask (url, downloadPath, filename! );
96115
97- // Update the episode with download data
98- episode.filepath = episodePath;
99- episode.filename = filename;
100- episode.downloadTaskId = taskId;
101- episode.downloadState = DownloadState .downloading;
102- episode.downloadPercentage = 0 ;
116+ // Update the episode with download data
117+ episode.filepath = episodePath;
118+ episode.filename = filename;
119+ episode.downloadTaskId = taskId;
120+ episode.downloadState = DownloadState .downloading;
121+ episode.downloadPercentage = 0 ;
103122
104- await repository.saveEpisode (episode);
123+ await repository.saveEpisode (episode);
124+ });
105125
106126 return true ;
107127 }
@@ -114,6 +134,41 @@ class MobileDownloadService extends DownloadService {
114134 }
115135 }
116136
137+ @override
138+ Future <void > deleteDownload (Episode episode) async => _downloadProgressLock.synchronized (() async {
139+ // If this episode is currently downloading, cancel the download first.
140+ if (episode.downloadState == DownloadState .downloaded) {
141+ if (settingsService.markDeletedEpisodesAsPlayed) {
142+ episode.played = true ;
143+ }
144+ } else if (episode.downloadState == DownloadState .downloading && episode.downloadPercentage! < 100 ) {
145+ await FlutterDownloader .cancel (taskId: episode.downloadTaskId! );
146+ }
147+
148+ episode.downloadTaskId = null ;
149+ episode.downloadPercentage = 0 ;
150+ episode.position = 0 ;
151+ episode.downloadState = DownloadState .none;
152+
153+ if (episode.transcriptId != null && episode.transcriptId! > 0 ) {
154+ await repository.deleteTranscriptById (episode.transcriptId! );
155+ }
156+
157+ await repository.saveEpisode (episode);
158+
159+ if (await hasStoragePermission ()) {
160+ final f = File .fromUri (Uri .file (await resolvePath (episode)));
161+
162+ log.fine ('Deleting file ${f .path }' );
163+
164+ if (await f.exists ()) {
165+ f.delete ();
166+ }
167+ }
168+
169+ return ;
170+ });
171+
117172 @override
118173 Future <Episode ?> findEpisodeByTaskId (String taskId) {
119174 return repository.findEpisodeByTaskId (taskId);
0 commit comments