mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	Faster remove downloads from adapter after deletion
This commit is contained in:
		
							parent
							
								
									145c42f1c8
								
							
						
					
					
						commit
						3e62382d3e
					
				
					 4 changed files with 92 additions and 49 deletions
				
			
		|  | @ -251,6 +251,15 @@ class DownloadAdapter( | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     fun removeItem(itemId: Int) { | ||||||
|  |         val currentList = currentList.toMutableList() | ||||||
|  |         val position = currentList.indexOfFirst { it.data.id == itemId } | ||||||
|  |         if (position != -1) { | ||||||
|  |             currentList.removeAt(position) | ||||||
|  |             notifyItemRemoved(position) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     class DiffCallback : DiffUtil.ItemCallback<VisualDownloadCached>() { |     class DiffCallback : DiffUtil.ItemCallback<VisualDownloadCached>() { | ||||||
|         override fun areItemsTheSame(oldItem: VisualDownloadCached, newItem: VisualDownloadCached): Boolean { |         override fun areItemsTheSame(oldItem: VisualDownloadCached, newItem: VisualDownloadCached): Boolean { | ||||||
|             return oldItem.data.id == newItem.data.id |             return oldItem.data.id == newItem.data.id | ||||||
|  |  | ||||||
|  | @ -127,13 +127,13 @@ class DownloadChildFragment : Fragment() { | ||||||
| 
 | 
 | ||||||
|     private fun setUpDownloadDeleteListener(folder: String) { |     private fun setUpDownloadDeleteListener(folder: String) { | ||||||
|         downloadDeleteEventListener = { id: Int -> |         downloadDeleteEventListener = { id: Int -> | ||||||
|             val list = (binding?.downloadChildList?.adapter as? DownloadAdapter)?.currentList |             val adapter = binding?.downloadChildList?.adapter as? DownloadAdapter | ||||||
|             if (list != null) { |             val list = adapter?.currentList | ||||||
|                 if (list.any { it.data.id == id }) { |             if (list?.any { it.data.id == id }) { | ||||||
|  |                 adapter.removeItem(id) | ||||||
|                 updateList(folder) |                 updateList(folder) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         } |  | ||||||
|         downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it } |         downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -170,9 +170,11 @@ class DownloadFragment : Fragment() { | ||||||
| 
 | 
 | ||||||
|     private fun setUpDownloadDeleteListener() { |     private fun setUpDownloadDeleteListener() { | ||||||
|         downloadDeleteEventListener = { id -> |         downloadDeleteEventListener = { id -> | ||||||
|             val list = (binding?.downloadList?.adapter as? DownloadAdapter)?.currentList |             val adapter = binding?.downloadList?.adapter as? DownloadAdapter | ||||||
|  |             val list = adapter?.currentList | ||||||
|             if (list?.any { it.data.id == id } == true) { |             if (list?.any { it.data.id == id } == true) { | ||||||
|                 context?.let { downloadsViewModel.updateList(it) } |                 adapter.removeItem(id) | ||||||
|  |                 downloadsViewModel.removeItem(id) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it } |         downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it } | ||||||
|  |  | ||||||
|  | @ -35,56 +35,80 @@ class DownloadViewModel : ViewModel() { | ||||||
| 
 | 
 | ||||||
|     private var previousVisual: List<VisualDownloadHeaderCached>? = null |     private var previousVisual: List<VisualDownloadHeaderCached>? = null | ||||||
| 
 | 
 | ||||||
|     fun updateList(context: Context) = viewModelScope.launchSafe { |     fun updateList(context: Context) { | ||||||
|  |         viewModelScope.launchSafe { | ||||||
|  |             try { | ||||||
|                 val children = withContext(Dispatchers.IO) { |                 val children = withContext(Dispatchers.IO) { | ||||||
|             context.getKeys(DOWNLOAD_EPISODE_CACHE) |                     fetchDownloadedEpisodes(context) | ||||||
|                 .mapNotNull { context.getKey<VideoDownloadHelper.DownloadEpisodeCached>(it) } |                 } | ||||||
|                 .distinctBy { it.id } // Remove duplicates |                 val visual = withContext(Dispatchers.IO) { | ||||||
|  |                     generateVisualList(context, children) | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|         // parentId : bytes |                 if (visual != previousVisual) { | ||||||
|  |                     previousVisual = visual | ||||||
|  |                     updateBytes(context, visual) | ||||||
|  |                     _headerCards.postValue(visual) | ||||||
|  |                 } | ||||||
|  |             } catch (e: Exception) { | ||||||
|  |                 logError(e) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun fetchDownloadedEpisodes(context: Context): List<VideoDownloadHelper.DownloadEpisodeCached> { | ||||||
|  |         return context.getKeys(DOWNLOAD_EPISODE_CACHE) | ||||||
|  |             .mapNotNull { context.getKey<VideoDownloadHelper.DownloadEpisodeCached>(it) } | ||||||
|  |             .distinctBy { it.id } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private suspend fun generateVisualList( | ||||||
|  |         context: Context, | ||||||
|  |         children: List<VideoDownloadHelper.DownloadEpisodeCached> | ||||||
|  |     ): List<VisualDownloadHeaderCached> { | ||||||
|         val totalBytesUsedByChild = HashMap<Int, Long>() |         val totalBytesUsedByChild = HashMap<Int, Long>() | ||||||
|         // parentId : bytes |  | ||||||
|         val currentBytesUsedByChild = HashMap<Int, Long>() |         val currentBytesUsedByChild = HashMap<Int, Long>() | ||||||
|         // parentId : downloadsCount |  | ||||||
|         val totalDownloads = HashMap<Int, Int>() |         val totalDownloads = HashMap<Int, Int>() | ||||||
| 
 | 
 | ||||||
|         // Gets all children downloads |  | ||||||
|         withContext(Dispatchers.IO) { |         withContext(Dispatchers.IO) { | ||||||
|             children.forEach { c -> |             children.forEach { c -> | ||||||
|                 val childFile = getDownloadFileInfoAndUpdateSettings(context, c.id) ?: return@forEach |                 val childFile = | ||||||
|  |                     getDownloadFileInfoAndUpdateSettings(context, c.id) ?: return@forEach | ||||||
| 
 | 
 | ||||||
|                 if (childFile.fileLength <= 1) return@forEach |                 if (childFile.fileLength <= 1) return@forEach | ||||||
|  | 
 | ||||||
|                 val len = childFile.totalBytes |                 val len = childFile.totalBytes | ||||||
|                 val flen = childFile.fileLength |                 val flen = childFile.fileLength | ||||||
| 
 | 
 | ||||||
|                 totalBytesUsedByChild[c.parentId] = totalBytesUsedByChild[c.parentId]?.plus(len) ?: len |                 totalBytesUsedByChild[c.parentId] = | ||||||
|                 currentBytesUsedByChild[c.parentId] = currentBytesUsedByChild[c.parentId]?.plus(flen) ?: flen |                     totalBytesUsedByChild[c.parentId]?.plus(len) ?: len | ||||||
|  |                 currentBytesUsedByChild[c.parentId] = | ||||||
|  |                     currentBytesUsedByChild[c.parentId]?.plus(flen) ?: flen | ||||||
|                 totalDownloads[c.parentId] = totalDownloads[c.parentId]?.plus(1) ?: 1 |                 totalDownloads[c.parentId] = totalDownloads[c.parentId]?.plus(1) ?: 1 | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         val cached = withContext(Dispatchers.IO) { // Won't fetch useless keys |         return totalDownloads.entries | ||||||
|             totalDownloads.entries.filter { it.value > 0 }.mapNotNull { |             .filter { it.value > 0 } | ||||||
|  |             .mapNotNull { | ||||||
|                 context.getKey<VideoDownloadHelper.DownloadHeaderCached>( |                 context.getKey<VideoDownloadHelper.DownloadHeaderCached>( | ||||||
|                     DOWNLOAD_HEADER_CACHE, |                     DOWNLOAD_HEADER_CACHE, | ||||||
|                     it.key.toString() |                     it.key.toString() | ||||||
|                 ) |                 ) | ||||||
|             } |             } | ||||||
|         } |             .mapNotNull { | ||||||
| 
 |  | ||||||
|         val visual = withContext(Dispatchers.IO) { |  | ||||||
|             cached.mapNotNull { |  | ||||||
|                 val downloads = totalDownloads[it.id] ?: 0 |                 val downloads = totalDownloads[it.id] ?: 0 | ||||||
|                 val bytes = totalBytesUsedByChild[it.id] ?: 0 |                 val bytes = totalBytesUsedByChild[it.id] ?: 0 | ||||||
|                 val currentBytes = currentBytesUsedByChild[it.id] ?: 0 |                 val currentBytes = currentBytesUsedByChild[it.id] ?: 0 | ||||||
|                 if (bytes <= 0 || downloads <= 0) return@mapNotNull null | 
 | ||||||
|                 val movieEpisode = |                 if (bytes <= 0 || downloads <= 0) null | ||||||
|                     if (!it.type.isMovieType()) null |                 else { | ||||||
|  |                     val movieEpisode = if (!it.type.isMovieType()) null | ||||||
|                     else context.getKey<VideoDownloadHelper.DownloadEpisodeCached>( |                     else context.getKey<VideoDownloadHelper.DownloadEpisodeCached>( | ||||||
|                         DOWNLOAD_EPISODE_CACHE, |                         DOWNLOAD_EPISODE_CACHE, | ||||||
|                         getFolderName(it.id.toString(), it.id.toString()) |                         getFolderName(it.id.toString(), it.id.toString()) | ||||||
|                     ) |                     ) | ||||||
|  | 
 | ||||||
|                     VisualDownloadHeaderCached( |                     VisualDownloadHeaderCached( | ||||||
|                         currentBytes = currentBytes, |                         currentBytes = currentBytes, | ||||||
|                         totalBytes = bytes, |                         totalBytes = bytes, | ||||||
|  | @ -93,16 +117,14 @@ class DownloadViewModel : ViewModel() { | ||||||
|                         currentOngoingDownloads = 0, |                         currentOngoingDownloads = 0, | ||||||
|                         totalDownloads = downloads, |                         totalDownloads = downloads, | ||||||
|                     ) |                     ) | ||||||
|             }.sortedBy { |                 } | ||||||
|                 (it.child?.episode ?: 0) + (it.child?.season?.times(10000) ?: 0) |             } | ||||||
|             } // Episode sorting by episode, lowest to highest |             .sortedBy { (it.child?.episode ?: 0) + (it.child?.season?.times(10000) ?: 0) } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|         // Only update list if different from the previous one to prevent duplicate initialization |     private suspend fun updateBytes(context: Context, visual: List<VisualDownloadHeaderCached>) { | ||||||
|         if (visual != previousVisual) { |  | ||||||
|             previousVisual = visual |  | ||||||
| 
 |  | ||||||
|         try { |         try { | ||||||
|  |             withContext(Dispatchers.IO) { | ||||||
|                 val stat = StatFs(Environment.getExternalStorageDirectory().path) |                 val stat = StatFs(Environment.getExternalStorageDirectory().path) | ||||||
|                 val localBytesAvailable = stat.availableBytes |                 val localBytesAvailable = stat.availableBytes | ||||||
|                 val localTotalBytes = stat.blockSizeLong * stat.blockCountLong |                 val localTotalBytes = stat.blockSizeLong * stat.blockCountLong | ||||||
|  | @ -111,12 +133,22 @@ class DownloadViewModel : ViewModel() { | ||||||
|                 _usedBytes.postValue(localTotalBytes - localBytesAvailable - localDownloadedBytes) |                 _usedBytes.postValue(localTotalBytes - localBytesAvailable - localDownloadedBytes) | ||||||
|                 _availableBytes.postValue(localBytesAvailable) |                 _availableBytes.postValue(localBytesAvailable) | ||||||
|                 _downloadBytes.postValue(localDownloadedBytes) |                 _downloadBytes.postValue(localDownloadedBytes) | ||||||
|  |             } | ||||||
|         } catch (t: Throwable) { |         } catch (t: Throwable) { | ||||||
|             _downloadBytes.postValue(0) |             _downloadBytes.postValue(0) | ||||||
|             logError(t) |             logError(t) | ||||||
|         } |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|  |     fun removeItem(itemId: Int) { | ||||||
|  |         val visual = _headerCards.value?.toMutableList() ?: mutableListOf() | ||||||
|  |         val position = visual.indexOfFirst { it.data.id == itemId } | ||||||
|  |         if (position != -1) { | ||||||
|  |             visual.removeAt(position) | ||||||
|  |             if (visual != previousVisual) { | ||||||
|  |                 previousVisual = visual | ||||||
|                 _headerCards.postValue(visual) |                 _headerCards.postValue(visual) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue