@@ -48,10 +48,8 @@ class DownloadService : Service() {
4848 private var notificationManager: NotificationManager ? = null
4949 private var totalFileSize = 0
5050 private lateinit var preferences: SharedPreferences
51- private lateinit var urls: Array <String >
52- private var currentIndex = 0
51+ private var currentDownloadUrl: String = " "
5352 private var fromSync = false
54-
5553 private var totalDownloadsCount = 0
5654 private var completedDownloadsCount = 0
5755 private var lastNotificationUpdateTime = 0L
@@ -85,37 +83,64 @@ class DownloadService : Service() {
8583
8684 private suspend fun processDownloadQueue () {
8785 while (true ) {
88- val pendingUrls = preferences.getStringSet(PENDING_DOWNLOADS_KEY , emptySet())?.toMutableSet() ? : mutableSetOf ()
89-
90- val newUrls = pendingUrls.filter { it !in processedUrls }
86+ val nextUrl = getNextPriorityUrl() ? : getNextPendingUrl()
9187
92- if (newUrls.isEmpty() ) {
88+ if (nextUrl == null ) {
9389 if (sessionCompletedCount > 0 ) {
9490 showCompletionNotification(false )
9591 }
9692
97- preferences.edit { remove(PENDING_DOWNLOADS_KEY ) }
93+ preferences.edit {
94+ remove(PENDING_DOWNLOADS_KEY )
95+ remove(PRIORITY_DOWNLOADS_KEY )
96+ }
9897 stopSelf()
9998 return
10099 }
101100
102- urls = newUrls.toTypedArray()
103- totalDownloadsCount = urls.size
104- sessionTotalCount + = urls.size
105- completedDownloadsCount = 0
106- currentIndex = 0
101+ processedUrls.add(nextUrl.url)
102+ sessionTotalCount++
103+ totalDownloadsCount = getRemainingCount() + 1
107104
108105 updateNotificationForBatchDownload()
106+ initDownload(nextUrl.url, fromSync)
109107
110- urls.forEachIndexed { index, url ->
111- currentIndex = index
112- processedUrls.add(url)
113- initDownload(url, fromSync)
114- }
108+ completedDownloadsCount++
109+ sessionCompletedCount++
110+
111+ cleanupProcessedUrls()
112+ }
113+ }
114+
115+ private data class QueuedUrl (val url : String , val isPriority : Boolean )
116+
117+ private fun getNextPriorityUrl (): QueuedUrl ? {
118+ val priorityUrls = preferences.getStringSet(PRIORITY_DOWNLOADS_KEY , emptySet()) ? : emptySet()
119+ val next = priorityUrls.firstOrNull { it !in processedUrls && it.isNotBlank() }
120+ return next?.let { QueuedUrl (it, isPriority = true ) }
121+ }
122+
123+ private fun getNextPendingUrl (): QueuedUrl ? {
124+ val pendingUrls = preferences.getStringSet(PENDING_DOWNLOADS_KEY , emptySet()) ? : emptySet()
125+ val next = pendingUrls.firstOrNull { it !in processedUrls && it.isNotBlank() }
126+ return next?.let { QueuedUrl (it, isPriority = false ) }
127+ }
128+
129+ private fun getRemainingCount (): Int {
130+ val priorityUrls = preferences.getStringSet(PRIORITY_DOWNLOADS_KEY , emptySet()) ? : emptySet()
131+ val pendingUrls = preferences.getStringSet(PENDING_DOWNLOADS_KEY , emptySet()) ? : emptySet()
132+ val allUrls = priorityUrls + pendingUrls
133+ return allUrls.count { it !in processedUrls }
134+ }
115135
116- val remainingUrls = preferences.getStringSet(PENDING_DOWNLOADS_KEY , emptySet())?.toMutableSet() ? : mutableSetOf ()
117- remainingUrls.removeAll(processedUrls)
118- preferences.edit { putStringSet(PENDING_DOWNLOADS_KEY , remainingUrls) }
136+ private fun cleanupProcessedUrls () {
137+ val remainingPriority = preferences.getStringSet(PRIORITY_DOWNLOADS_KEY , emptySet())?.toMutableSet() ? : mutableSetOf ()
138+ remainingPriority.removeAll(processedUrls)
139+ val remainingPending = preferences.getStringSet(PENDING_DOWNLOADS_KEY , emptySet())?.toMutableSet() ? : mutableSetOf ()
140+ remainingPending.removeAll(processedUrls)
141+ preferences.edit {
142+ putStringSet(PRIORITY_DOWNLOADS_KEY , remainingPriority)
143+ putStringSet(PENDING_DOWNLOADS_KEY , remainingPending)
119144 }
120145 }
121146
@@ -135,12 +160,13 @@ class DownloadService : Service() {
135160 }
136161
137162 private suspend fun initDownload (url : String , fromSync : Boolean ) {
163+ currentDownloadUrl = url
138164 try {
139165 if (url.isBlank()) {
140166 downloadFailed(" Invalid URL - empty or blank" , fromSync)
141167 return
142168 }
143-
169+
144170 val retrofitInterface = ApiClient .client.create(ApiInterface ::class .java)
145171 if (retrofitInterface == null ) {
146172 downloadFailed(" Network client not available" , fromSync)
@@ -223,16 +249,10 @@ class DownloadService : Service() {
223249 }
224250
225251 private fun downloadFailed (message : String , fromSync : Boolean ) {
226- completedDownloadsCount++
227- sessionCompletedCount++
228-
229- val pendingUrls = preferences.getStringSet(PENDING_DOWNLOADS_KEY , emptySet()) ? : emptySet()
230- val remainingInQueue = pendingUrls.count { it !in processedUrls }
231- val totalRemaining = (totalDownloadsCount - completedDownloadsCount) + remainingInQueue
232- val displayTotal = sessionCompletedCount + totalRemaining
233-
252+ val remaining = getRemainingCount()
234253 notificationBuilder?.apply {
235- setContentText(" Error: $message ($sessionCompletedCount /$displayTotal )" )
254+ setContentText(" Error: $message " )
255+ setSubText(" $sessionCompletedCount completed, $remaining remaining" )
236256 notificationManager?.notify(ONGOING_NOTIFICATION_ID , build())
237257 }
238258
@@ -297,7 +317,6 @@ class DownloadService : Service() {
297317 }
298318 }
299319 }
300-
301320 onDownloadComplete(url)
302321 }
303322
@@ -316,16 +335,16 @@ class DownloadService : Service() {
316335 }
317336
318337 private fun sendNotification (download : Download ) {
319- val url = urls.getOrNull(currentIndex) ? : run {
320- return
321- }
338+ val url = currentDownloadUrl
339+ if (url.isBlank()) return
322340
323341 download.fileName = " Downloading: ${getFileNameFromUrl(url)} "
324342 sendIntent(download, fromSync)
325343
326344 if (NotificationManagerCompat .from(this ).areNotificationsEnabled()) {
327345 notificationBuilder?.apply {
328346 val fileName = getFileNameFromUrl(url)
347+ val remaining = getRemainingCount()
329348 val progressText = if (currentFileProgress in 0 .. 100 ) {
330349 " $fileName ($currentFileProgress %)"
331350 } else {
@@ -334,10 +353,10 @@ class DownloadService : Service() {
334353
335354 if (currentFileProgress in 0 .. 100 ) {
336355 setProgress(100 , currentFileProgress, false )
337- setSubText(" ${currentIndex + 1 } / $totalDownloadsCount files " )
356+ setSubText(" $sessionCompletedCount completed, $remaining remaining " )
338357 } else {
339358 setProgress(100 , 0 , true )
340- setSubText(" ${currentIndex + 1 } / $totalDownloadsCount files " )
359+ setSubText(" $sessionCompletedCount completed, $remaining remaining " )
341360 }
342361 setContentText(progressText)
343362 notificationManager?.notify(ONGOING_NOTIFICATION_ID , build())
@@ -360,26 +379,21 @@ class DownloadService : Service() {
360379 if ((outputFile?.length() ? : 0 ) > 0 ) {
361380 DownloadUtils .updateResourceOfflineStatus(url)
362381 }
363- completedDownloadsCount++
364- sessionCompletedCount++
365382
366- val pendingUrls = preferences.getStringSet(PENDING_DOWNLOADS_KEY , emptySet()) ? : emptySet()
367- val remainingInQueue = pendingUrls.count { it !in processedUrls }
368- val totalRemaining = (totalDownloadsCount - completedDownloadsCount) + remainingInQueue
383+ val remaining = getRemainingCount()
369384
370385 val download = Download ().apply {
371386 fileName = getFileNameFromUrl(url)
372387 fileUrl = url
373388 progress = 100
374- completeAll = (totalRemaining == 0 )
389+ completeAll = (remaining == 0 )
375390 }
376391
377392 sendIntent(download, fromSync)
378393 notificationBuilder?.apply {
379- val displayTotal = sessionCompletedCount + totalRemaining
380- setProgress(displayTotal, sessionCompletedCount, false )
381- setContentText(" Downloaded $sessionCompletedCount /$displayTotal files" )
382- setSubText(null )
394+ setProgress(sessionCompletedCount + remaining, sessionCompletedCount, false )
395+ setContentText(" Downloaded ${getFileNameFromUrl(url)} " )
396+ setSubText(" $sessionCompletedCount completed, $remaining remaining" )
383397 notificationManager?.notify(ONGOING_NOTIFICATION_ID , build())
384398 }
385399 }
@@ -414,6 +428,7 @@ class DownloadService : Service() {
414428 const val COMPLETION_NOTIFICATION_ID = 2
415429 private const val NOTIFICATION_UPDATE_INTERVAL_MS = 500L
416430 const val PENDING_DOWNLOADS_KEY = " pending_downloads_queue"
431+ const val PRIORITY_DOWNLOADS_KEY = " priority_downloads_queue"
417432
418433 fun startService (context : Context , urlsKey : String , fromSync : Boolean ) {
419434 val intent = Intent (context, DownloadService ::class .java).apply {
0 commit comments