mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Initial basic support for child downloads
This commit is contained in:
parent
9a1949e452
commit
f6bfdefe15
4 changed files with 80 additions and 61 deletions
|
@ -85,10 +85,16 @@ data class DownloadHeaderClickEvent(
|
|||
val data: VideoDownloadHelper.DownloadHeaderCached
|
||||
)
|
||||
|
||||
sealed class VisualDownloadItem {
|
||||
data class Header(val header: VisualDownloadHeaderCached) : VisualDownloadItem()
|
||||
data class Child(val child: VisualDownloadChildCached) : VisualDownloadItem()
|
||||
}
|
||||
|
||||
class DownloadAdapter(
|
||||
private val headerClickCallback: (DownloadHeaderClickEvent) -> Unit,
|
||||
private val mediaClickCallback: (DownloadClickEvent) -> Unit,
|
||||
private val selectedChangedCallback: (Int, String, Boolean) -> Unit,
|
||||
private val selectedChangedCallback: (VisualDownloadItem, Boolean) -> Unit,
|
||||
private val multiDeleteStateCallback: (VisualDownloadItem) -> Unit,
|
||||
) : ListAdapter<VisualDownloadCached, DownloadAdapter.DownloadViewHolder>(DiffCallback()) {
|
||||
|
||||
private var isMultiDeleteState: Boolean = false
|
||||
|
@ -119,7 +125,7 @@ class DownloadAdapter(
|
|||
setImage(data.poster)
|
||||
if (isMultiDeleteState) {
|
||||
setOnClickListener {
|
||||
toggleIsChecked(deleteCheckbox, data.id, data.name)
|
||||
toggleIsChecked(deleteCheckbox, VisualDownloadItem.Header(card))
|
||||
}
|
||||
} else {
|
||||
setOnClickListener {
|
||||
|
@ -128,7 +134,7 @@ class DownloadAdapter(
|
|||
}
|
||||
|
||||
setOnLongClickListener {
|
||||
headerClickCallback.invoke(DownloadHeaderClickEvent(DOWNLOAD_ACTION_LONG_CLICK, data))
|
||||
multiDeleteStateCallback.invoke(VisualDownloadItem.Header(card))
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +148,7 @@ class DownloadAdapter(
|
|||
if (isMultiDeleteState) {
|
||||
deleteCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
selectedIds[data.id] = isChecked
|
||||
selectedChangedCallback.invoke(data.id, data.name, isChecked)
|
||||
selectedChangedCallback.invoke(VisualDownloadItem.Header(card), isChecked)
|
||||
}
|
||||
} else deleteCheckbox.setOnCheckedChangeListener(null)
|
||||
|
||||
|
@ -183,10 +189,15 @@ class DownloadAdapter(
|
|||
downloadButton.setDefaultClickListener(card.child, downloadHeaderInfo, mediaClickCallback)
|
||||
downloadButton.isVisible = !isMultiDeleteState
|
||||
|
||||
downloadButton.setOnLongClickListener {
|
||||
multiDeleteStateCallback.invoke(VisualDownloadItem.Header(card))
|
||||
true
|
||||
}
|
||||
|
||||
episodeHolder.apply {
|
||||
if (isMultiDeleteState) {
|
||||
setOnClickListener {
|
||||
toggleIsChecked(deleteCheckbox, card.data.id, card.data.name)
|
||||
toggleIsChecked(deleteCheckbox, VisualDownloadItem.Header(card))
|
||||
}
|
||||
} else {
|
||||
setOnClickListener {
|
||||
|
@ -195,7 +206,7 @@ class DownloadAdapter(
|
|||
}
|
||||
|
||||
setOnLongClickListener {
|
||||
mediaClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_LONG_CLICK, card.child))
|
||||
multiDeleteStateCallback.invoke(VisualDownloadItem.Header(card))
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -223,7 +234,7 @@ class DownloadAdapter(
|
|||
episodeHolder.apply {
|
||||
if (isMultiDeleteState) {
|
||||
setOnClickListener {
|
||||
toggleIsChecked(deleteCheckbox, card.data.id, card.data.name)
|
||||
toggleIsChecked(deleteCheckbox, VisualDownloadItem.Header(card))
|
||||
}
|
||||
} else {
|
||||
setOnClickListener {
|
||||
|
@ -232,7 +243,7 @@ class DownloadAdapter(
|
|||
}
|
||||
|
||||
setOnLongClickListener {
|
||||
headerClickCallback.invoke(DownloadHeaderClickEvent(DOWNLOAD_ACTION_LONG_CLICK, card.data))
|
||||
multiDeleteStateCallback.invoke(VisualDownloadItem.Header(card))
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -340,11 +351,14 @@ class DownloadAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun toggleIsChecked(checkbox: CheckBox, id: Int, name: String) {
|
||||
private fun toggleIsChecked(checkbox: CheckBox, item: VisualDownloadItem) {
|
||||
val isChecked = !checkbox.isChecked
|
||||
checkbox.isChecked = isChecked
|
||||
selectedIds[id] = isChecked
|
||||
selectedChangedCallback.invoke(id, name, isChecked)
|
||||
when (item) {
|
||||
is VisualDownloadItem.Header -> selectedIds[item.header.data.id] = isChecked
|
||||
is VisualDownloadItem.Child -> selectedIds[item.child.data.id] = isChecked
|
||||
}
|
||||
selectedChangedCallback.invoke(item, isChecked)
|
||||
}
|
||||
|
||||
class DiffCallback : DiffUtil.ItemCallback<VisualDownloadCached>() {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.lagradost.cloudstream3.ui.download
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -113,7 +112,9 @@ class DownloadChildFragment : Fragment() {
|
|||
if (downloadClickEvent.action == DOWNLOAD_ACTION_DELETE_FILE) {
|
||||
setUpDownloadDeleteListener(folder)
|
||||
}
|
||||
}, { _, _, _ -> }
|
||||
},
|
||||
{ _, _ -> },
|
||||
{ _ -> }
|
||||
)
|
||||
|
||||
binding?.downloadChildList?.apply {
|
||||
|
|
|
@ -93,7 +93,7 @@ class DownloadFragment : Fragment() {
|
|||
|
||||
// We always want fresh selections
|
||||
// when navigating to downloads
|
||||
downloadsViewModel.clearSelectedIds()
|
||||
downloadsViewModel.clearSelectedItems()
|
||||
|
||||
observe(downloadsViewModel.headerCards) {
|
||||
(binding?.downloadList?.adapter as? DownloadAdapter)?.submitList(it)
|
||||
|
@ -110,7 +110,7 @@ class DownloadFragment : Fragment() {
|
|||
observe(downloadsViewModel.downloadBytes) {
|
||||
updateStorageInfo(view.context, it, R.string.app_storage, binding?.downloadAppTxt, binding?.downloadApp)
|
||||
}
|
||||
observe(downloadsViewModel.selectedIds) {
|
||||
observe(downloadsViewModel.selectedItems) {
|
||||
handleSelectedChange(it)
|
||||
binding?.btnDelete?.text =
|
||||
getString(R.string.delete_count).format(it.count())
|
||||
|
@ -120,24 +120,22 @@ class DownloadFragment : Fragment() {
|
|||
{ click -> handleItemClick(click) },
|
||||
{ downloadClickEvent ->
|
||||
handleDownloadClick(downloadClickEvent)
|
||||
when (downloadClickEvent.action) {
|
||||
DOWNLOAD_ACTION_DELETE_FILE -> setUpDownloadDeleteListener()
|
||||
DOWNLOAD_ACTION_LONG_CLICK -> downloadClickEvent.data.name?.let {
|
||||
downloadsViewModel.addSelected(
|
||||
downloadClickEvent.data.id,
|
||||
it
|
||||
)
|
||||
(binding?.downloadList?.adapter as? DownloadAdapter)?.updateSelectedItem(
|
||||
downloadClickEvent.data.id,
|
||||
true
|
||||
)
|
||||
}
|
||||
if (downloadClickEvent.action == DOWNLOAD_ACTION_DELETE_FILE) {
|
||||
setUpDownloadDeleteListener()
|
||||
}
|
||||
},
|
||||
{ id, name, isChecked ->
|
||||
{ card, isChecked ->
|
||||
if (isChecked) {
|
||||
downloadsViewModel.addSelected(id, name)
|
||||
} else downloadsViewModel.removeSelected(id)
|
||||
downloadsViewModel.addSelected(card)
|
||||
} else downloadsViewModel.removeSelected(card)
|
||||
},
|
||||
{ card ->
|
||||
if (card !is VisualDownloadItem.Header) return@DownloadAdapter
|
||||
downloadsViewModel.addSelected(card)
|
||||
(binding?.downloadList?.adapter as? DownloadAdapter)?.updateSelectedItem(
|
||||
card.header.data.id,
|
||||
true
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -187,20 +185,10 @@ class DownloadFragment : Fragment() {
|
|||
DOWNLOAD_ACTION_LOAD_RESULT -> {
|
||||
(activity as AppCompatActivity?)?.loadResult(click.data.url, click.data.apiName)
|
||||
}
|
||||
DOWNLOAD_ACTION_LONG_CLICK -> {
|
||||
downloadsViewModel.addSelected(
|
||||
click.data.id,
|
||||
click.data.name
|
||||
)
|
||||
(binding?.downloadList?.adapter as? DownloadAdapter)?.updateSelectedItem(
|
||||
click.data.id,
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSelectedChange(selected: HashMap<Int, String>) {
|
||||
private fun handleSelectedChange(selected: MutableList<VisualDownloadItem>) {
|
||||
val adapter = binding?.downloadList?.adapter as? DownloadAdapter
|
||||
if (selected.isNotEmpty()) {
|
||||
binding?.downloadDeleteAppbar?.isVisible = true
|
||||
|
@ -212,7 +200,7 @@ class DownloadFragment : Fragment() {
|
|||
|
||||
binding?.btnCancel?.setOnClickListener {
|
||||
adapter?.setIsMultiDeleteState(false)
|
||||
downloadsViewModel.clearSelectedIds()
|
||||
downloadsViewModel.clearSelectedItems()
|
||||
}
|
||||
|
||||
binding?.btnSelectAll?.setOnClickListener {
|
||||
|
@ -229,7 +217,7 @@ class DownloadFragment : Fragment() {
|
|||
downloadsViewModel.usedBytes.value?.let { it > 0 } == true
|
||||
|
||||
adapter?.setIsMultiDeleteState(false)
|
||||
downloadsViewModel.clearSelectedIds()
|
||||
downloadsViewModel.clearSelectedItems()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,41 +34,44 @@ class DownloadViewModel : ViewModel() {
|
|||
private val _availableBytes = MutableLiveData<Long>()
|
||||
private val _downloadBytes = MutableLiveData<Long>()
|
||||
|
||||
private val _selectedIds = MutableLiveData<HashMap<Int, String>>(HashMap())
|
||||
private val _selectedItems = MutableLiveData<MutableList<VisualDownloadItem>>(mutableListOf())
|
||||
|
||||
val usedBytes: LiveData<Long> = _usedBytes
|
||||
val availableBytes: LiveData<Long> = _availableBytes
|
||||
val downloadBytes: LiveData<Long> = _downloadBytes
|
||||
|
||||
val selectedIds: LiveData<HashMap<Int, String>> = _selectedIds
|
||||
val selectedItems: LiveData<MutableList<VisualDownloadItem>> = _selectedItems
|
||||
|
||||
private var previousVisual: List<VisualDownloadHeaderCached>? = null
|
||||
|
||||
fun addSelected(id: Int, name: String) {
|
||||
val currentSelected = selectedIds.value ?: HashMap()
|
||||
currentSelected[id] = name
|
||||
_selectedIds.postValue(currentSelected)
|
||||
fun addSelected(item: VisualDownloadItem) {
|
||||
val currentSelected = selectedItems.value ?: mutableListOf()
|
||||
if (!currentSelected.contains(item)) {
|
||||
currentSelected.add(item)
|
||||
_selectedItems.postValue(currentSelected)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeSelected(id: Int) {
|
||||
selectedIds.value?.let { selectedIds ->
|
||||
selectedIds.remove(id)
|
||||
_selectedIds.postValue(selectedIds)
|
||||
fun removeSelected(item: VisualDownloadItem) {
|
||||
selectedItems.value?.let { selected ->
|
||||
selected.remove(item)
|
||||
_selectedItems.postValue(selected)
|
||||
}
|
||||
}
|
||||
|
||||
fun selectAllItems() {
|
||||
val currentSelected = selectedIds.value ?: HashMap()
|
||||
val currentSelected = selectedItems.value ?: mutableListOf()
|
||||
val items = headerCards.value ?: return
|
||||
items.forEach { item ->
|
||||
if (currentSelected.containsKey(item.data.id)) return@forEach
|
||||
currentSelected[item.data.id] = item.data.name
|
||||
if (!currentSelected.contains(VisualDownloadItem.Header(item))) {
|
||||
currentSelected.add(VisualDownloadItem.Header(item))
|
||||
}
|
||||
}
|
||||
_selectedIds.postValue(currentSelected)
|
||||
_selectedItems.postValue(currentSelected)
|
||||
}
|
||||
|
||||
fun clearSelectedIds() {
|
||||
_selectedIds.postValue(HashMap())
|
||||
fun clearSelectedItems() {
|
||||
_selectedItems.postValue(mutableListOf())
|
||||
}
|
||||
|
||||
fun updateList(context: Context) = viewModelScope.launchSafe {
|
||||
|
@ -159,8 +162,21 @@ class DownloadViewModel : ViewModel() {
|
|||
}
|
||||
|
||||
fun handleMultiDelete(context: Context) = viewModelScope.launchSafe {
|
||||
val ids: List<Int> = selectedIds.value?.keys?.toList() ?: emptyList()
|
||||
val names: List<String> = selectedIds.value?.values?.toList() ?: emptyList()
|
||||
val selectedItemsList = selectedItems.value ?: mutableListOf()
|
||||
|
||||
val ids = selectedItemsList.map {
|
||||
when (it) {
|
||||
is VisualDownloadItem.Header -> it.header.data.id
|
||||
is VisualDownloadItem.Child -> it.child.data.id
|
||||
}
|
||||
}
|
||||
|
||||
val names = selectedItemsList.mapNotNull {
|
||||
when (it) {
|
||||
is VisualDownloadItem.Header -> it.header.data.name
|
||||
is VisualDownloadItem.Child -> it.child.data.name
|
||||
}
|
||||
}
|
||||
|
||||
showDeleteConfirmationDialog(context, ids, names)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue