Merge pull request #7181 from Bnyro/master

fix: various bugs when deleting single or all downloads
This commit is contained in:
Bnyro 2025-03-08 12:35:47 +01:00 committed by GitHub
commit ccc69dca2c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 32 additions and 25 deletions

View File

@ -13,6 +13,7 @@ import androidx.recyclerview.widget.ListAdapter
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.constants.IntentData import com.github.libretube.constants.IntentData
import com.github.libretube.databinding.VideoRowBinding import com.github.libretube.databinding.VideoRowBinding
import com.github.libretube.db.DatabaseHelper
import com.github.libretube.db.DatabaseHolder import com.github.libretube.db.DatabaseHolder
import com.github.libretube.db.obj.DownloadWithItems import com.github.libretube.db.obj.DownloadWithItems
import com.github.libretube.extensions.formatAsFileSize import com.github.libretube.extensions.formatAsFileSize
@ -40,6 +41,8 @@ class DownloadsAdapter(
private val downloadTab: DownloadTab, private val downloadTab: DownloadTab,
private val toggleDownload: (DownloadWithItems) -> Boolean private val toggleDownload: (DownloadWithItems) -> Boolean
) : ListAdapter<DownloadWithItems, DownloadsViewHolder>(DiffUtilItemCallback()) { ) : ListAdapter<DownloadWithItems, DownloadsViewHolder>(DiffUtilItemCallback()) {
val items get() = (0 until itemCount).map { getItem(it) }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadsViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadsViewHolder {
val binding = VideoRowBinding.inflate( val binding = VideoRowBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
@ -156,9 +159,9 @@ class DownloadsAdapter(
.show() .show()
} }
fun deleteDownload(position: Int) { private fun deleteDownloadContent(downloadWithItems: DownloadWithItems) {
val download = getItem(position).download val download = downloadWithItems.download
val items = getItem(position).downloadItems val items = downloadWithItems.downloadItems
items.forEach { items.forEach {
it.path.deleteIfExists() it.path.deleteIfExists()
@ -170,11 +173,30 @@ class DownloadsAdapter(
runBlocking(Dispatchers.IO) { runBlocking(Dispatchers.IO) {
DatabaseHolder.Database.downloadDao().deleteDownload(download) DatabaseHolder.Database.downloadDao().deleteDownload(download)
} }
}
private fun deleteDownload(position: Int) {
deleteDownloadContent(getItem(position))
submitList(currentList.toMutableList().also { submitList(currentList.toMutableList().also {
it.removeAt(position) it.removeAt(position)
}) })
} }
fun deleteAllDownloads(onlyDeleteWatched: Boolean) {
val (toDelete, toKeep) = items.partition {
!onlyDeleteWatched || runBlocking(Dispatchers.IO) {
DatabaseHelper.isVideoWatched(it.download.videoId, it.download.duration ?: 0)
}
}
for (item in toDelete) {
deleteDownloadContent(item)
}
submitList(toKeep)
}
fun restoreItem(position: Int) { fun restoreItem(position: Int) {
// moves the item back to its initial horizontal position // moves the item back to its initial horizontal position
notifyItemRemoved(position) notifyItemRemoved(position)

View File

@ -22,9 +22,7 @@ import com.github.libretube.constants.IntentData
import com.github.libretube.constants.PreferenceKeys import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.databinding.FragmentDownloadContentBinding import com.github.libretube.databinding.FragmentDownloadContentBinding
import com.github.libretube.databinding.FragmentDownloadsBinding import com.github.libretube.databinding.FragmentDownloadsBinding
import com.github.libretube.db.DatabaseHelper
import com.github.libretube.db.DatabaseHolder.Database import com.github.libretube.db.DatabaseHolder.Database
import com.github.libretube.db.obj.DownloadWithItems
import com.github.libretube.db.obj.filterByTab import com.github.libretube.db.obj.filterByTab
import com.github.libretube.extensions.ceilHalf import com.github.libretube.extensions.ceilHalf
import com.github.libretube.extensions.formatAsFileSize import com.github.libretube.extensions.formatAsFileSize
@ -108,7 +106,6 @@ class DownloadsFragmentPage : DynamicLayoutManagerFragment(R.layout.fragment_dow
private val binding get() = _binding!! private val binding get() = _binding!!
private var binder: DownloadService.LocalBinder? = null private var binder: DownloadService.LocalBinder? = null
private val downloads = mutableListOf<DownloadWithItems>()
private val downloadReceiver = DownloadReceiver() private val downloadReceiver = DownloadReceiver()
private lateinit var downloadTab: DownloadTab private lateinit var downloadTab: DownloadTab
@ -172,7 +169,6 @@ class DownloadsFragmentPage : DynamicLayoutManagerFragment(R.layout.fragment_dow
return@DownloadsAdapter isDownloading.not() return@DownloadsAdapter isDownloading.not()
} }
binding.downloadsRecView.adapter = adapter binding.downloadsRecView.adapter = adapter
adapter.submitList(downloads)
var selectedSortType = var selectedSortType =
PreferenceHelper.getInt(PreferenceKeys.SELECTED_DOWNLOAD_SORT_TYPE, 0) PreferenceHelper.getInt(PreferenceKeys.SELECTED_DOWNLOAD_SORT_TYPE, 0)
@ -197,14 +193,10 @@ class DownloadsFragmentPage : DynamicLayoutManagerFragment(R.layout.fragment_dow
Database.downloadDao().getAll() Database.downloadDao().getAll()
} }
downloads.clear() val downloads = dbDownloads.filterByTab(downloadTab)
downloads.addAll(dbDownloads.filterByTab(downloadTab)) adapter.submitList(downloads)
if (downloads.isEmpty()) return@launch
sortDownloadList(selectedSortType) sortDownloadList(selectedSortType)
binding.downloadsRecView.setOnDismissListener { position -> binding.downloadsRecView.setOnDismissListener { position ->
adapter.showDeleteDialog(requireContext(), position) adapter.showDeleteDialog(requireContext(), position)
// put the item back to the center, as it's currently out of the screen // put the item back to the center, as it's currently out of the screen
@ -242,7 +234,7 @@ class DownloadsFragmentPage : DynamicLayoutManagerFragment(R.layout.fragment_dow
private fun toggleVisibilities() { private fun toggleVisibilities() {
val binding = _binding ?: return val binding = _binding ?: return
val isEmpty = downloads.isEmpty() val isEmpty = adapter.itemCount == 0
binding.downloadsEmpty.isVisible = isEmpty binding.downloadsEmpty.isVisible = isEmpty
binding.downloadsContainer.isGone = isEmpty binding.downloadsContainer.isGone = isEmpty
binding.deleteAll.isGone = isEmpty binding.deleteAll.isGone = isEmpty
@ -251,10 +243,10 @@ class DownloadsFragmentPage : DynamicLayoutManagerFragment(R.layout.fragment_dow
private fun sortDownloadList(sortType: Int, previousSortType: Int? = null) { private fun sortDownloadList(sortType: Int, previousSortType: Int? = null) {
if (previousSortType == null && sortType == 1) { if (previousSortType == null && sortType == 1) {
adapter.submitList(downloads.reversed()) adapter.submitList(adapter.items.reversed())
} }
if (previousSortType != null && sortType != previousSortType) { if (previousSortType != null && sortType != previousSortType) {
adapter.submitList(downloads.reversed()) adapter.submitList(adapter.items.reversed())
} }
} }
@ -267,14 +259,7 @@ class DownloadsFragmentPage : DynamicLayoutManagerFragment(R.layout.fragment_dow
onlyDeleteWatchedVideos = selected onlyDeleteWatchedVideos = selected
} }
.setPositiveButton(R.string.okay) { _, _ -> .setPositiveButton(R.string.okay) { _, _ ->
lifecycleScope.launch { adapter.deleteAllDownloads(onlyDeleteWatchedVideos)
for (downloadIndex in downloads.size - 1 downTo 0) {
val download = adapter.currentList[downloadIndex].download
if (!onlyDeleteWatchedVideos || DatabaseHelper.isVideoWatched(download.videoId, download.duration ?: 0)) {
adapter.deleteDownload(downloadIndex)
}
}
}
} }
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.show() .show()
@ -312,7 +297,7 @@ class DownloadsFragmentPage : DynamicLayoutManagerFragment(R.layout.fragment_dow
} }
fun updateProgress(id: Int, status: DownloadStatus) { fun updateProgress(id: Int, status: DownloadStatus) {
val index = downloads.indexOfFirst { val index = adapter.items.indexOfFirst {
it.downloadItems.any { item -> item.id == id } it.downloadItems.any { item -> item.id == id }
} }
val view = val view =