mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Simplification of VisualDownloadCached handling and fix a bug
This commit is contained in:
parent
595588aeca
commit
5ed9eee407
4 changed files with 64 additions and 99 deletions
app/src/main/java/com/lagradost/cloudstream3/ui/download
|
@ -32,47 +32,27 @@ const val DOWNLOAD_ACTION_LONG_CLICK = 5
|
|||
const val DOWNLOAD_ACTION_GO_TO_CHILD = 0
|
||||
const val DOWNLOAD_ACTION_LOAD_RESULT = 1
|
||||
|
||||
abstract class VisualDownloadCached(
|
||||
open val currentBytes: Long,
|
||||
open val totalBytes: Long,
|
||||
open val data: VideoDownloadHelper.DownloadCached
|
||||
) {
|
||||
sealed class VisualDownloadCached {
|
||||
abstract val currentBytes: Long
|
||||
abstract val totalBytes: Long
|
||||
abstract val data: VideoDownloadHelper.DownloadCached
|
||||
|
||||
// Just to be extra-safe with areContentsTheSame
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is VisualDownloadCached) return false
|
||||
data class Child(
|
||||
override val currentBytes: Long,
|
||||
override val totalBytes: Long,
|
||||
override val data: VideoDownloadHelper.DownloadEpisodeCached,
|
||||
) : VisualDownloadCached()
|
||||
|
||||
if (currentBytes != other.currentBytes) return false
|
||||
if (totalBytes != other.totalBytes) return false
|
||||
if (data != other.data) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = currentBytes.hashCode()
|
||||
result = 31 * result + totalBytes.hashCode()
|
||||
result = 31 * result + data.hashCode()
|
||||
return result
|
||||
}
|
||||
data class Header(
|
||||
override val currentBytes: Long,
|
||||
override val totalBytes: Long,
|
||||
override val data: VideoDownloadHelper.DownloadHeaderCached,
|
||||
val child: VideoDownloadHelper.DownloadEpisodeCached?,
|
||||
val currentOngoingDownloads: Int,
|
||||
val totalDownloads: Int
|
||||
) : VisualDownloadCached()
|
||||
}
|
||||
|
||||
data class VisualDownloadChildCached(
|
||||
override val currentBytes: Long,
|
||||
override val totalBytes: Long,
|
||||
override val data: VideoDownloadHelper.DownloadEpisodeCached,
|
||||
): VisualDownloadCached(currentBytes, totalBytes, data)
|
||||
|
||||
data class VisualDownloadHeaderCached(
|
||||
override val currentBytes: Long,
|
||||
override val totalBytes: Long,
|
||||
override val data: VideoDownloadHelper.DownloadHeaderCached,
|
||||
val child: VideoDownloadHelper.DownloadEpisodeCached?,
|
||||
val currentOngoingDownloads: Int,
|
||||
val totalDownloads: Int,
|
||||
): VisualDownloadCached(currentBytes, totalBytes, data)
|
||||
|
||||
data class DownloadClickEvent(
|
||||
val action: Int,
|
||||
val data: VideoDownloadHelper.DownloadEpisodeCached
|
||||
|
@ -83,16 +63,11 @@ 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: (VisualDownloadItem, Boolean) -> Unit,
|
||||
private val multiDeleteStateCallback: (VisualDownloadItem) -> Unit,
|
||||
private val selectedChangedCallback: (VisualDownloadCached, Boolean) -> Unit,
|
||||
private val multiDeleteStateCallback: (VisualDownloadCached) -> Unit,
|
||||
) : ListAdapter<VisualDownloadCached, DownloadAdapter.DownloadViewHolder>(DiffCallback()) {
|
||||
|
||||
private var isMultiDeleteState: Boolean = false
|
||||
|
@ -109,12 +84,12 @@ class DownloadAdapter(
|
|||
|
||||
fun bind(card: VisualDownloadCached?) {
|
||||
when (binding) {
|
||||
is DownloadHeaderEpisodeBinding -> bindHeader(card as? VisualDownloadHeaderCached)
|
||||
is DownloadChildEpisodeBinding -> bindChild(card as? VisualDownloadChildCached)
|
||||
is DownloadHeaderEpisodeBinding -> bindHeader(card as? VisualDownloadCached.Header)
|
||||
is DownloadChildEpisodeBinding -> bindChild(card as? VisualDownloadCached.Child)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindHeader(card: VisualDownloadHeaderCached?) {
|
||||
private fun bindHeader(card: VisualDownloadCached.Header?) {
|
||||
if (binding !is DownloadHeaderEpisodeBinding || card == null) return
|
||||
|
||||
val data = card.data
|
||||
|
@ -123,7 +98,7 @@ class DownloadAdapter(
|
|||
setImage(data.poster)
|
||||
if (isMultiDeleteState) {
|
||||
setOnClickListener {
|
||||
toggleIsChecked(deleteCheckbox, VisualDownloadItem.Header(card))
|
||||
toggleIsChecked(deleteCheckbox, card)
|
||||
}
|
||||
} else {
|
||||
setOnClickListener {
|
||||
|
@ -132,7 +107,7 @@ class DownloadAdapter(
|
|||
}
|
||||
|
||||
setOnLongClickListener {
|
||||
multiDeleteStateCallback.invoke(VisualDownloadItem.Header(card))
|
||||
multiDeleteStateCallback.invoke(card)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +121,7 @@ class DownloadAdapter(
|
|||
if (isMultiDeleteState) {
|
||||
deleteCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
selectedIds[data.id] = isChecked
|
||||
selectedChangedCallback.invoke(VisualDownloadItem.Header(card), isChecked)
|
||||
selectedChangedCallback.invoke(card, isChecked)
|
||||
}
|
||||
} else deleteCheckbox.setOnCheckedChangeListener(null)
|
||||
|
||||
|
@ -158,7 +133,7 @@ class DownloadAdapter(
|
|||
}
|
||||
|
||||
private fun DownloadHeaderEpisodeBinding.handleChildDownload(
|
||||
card: VisualDownloadHeaderCached,
|
||||
card: VisualDownloadCached.Header,
|
||||
formattedSize: String
|
||||
) {
|
||||
card.child ?: return
|
||||
|
@ -188,14 +163,14 @@ class DownloadAdapter(
|
|||
downloadButton.isVisible = !isMultiDeleteState
|
||||
|
||||
downloadButton.setOnLongClickListener {
|
||||
multiDeleteStateCallback.invoke(VisualDownloadItem.Header(card))
|
||||
multiDeleteStateCallback.invoke(card)
|
||||
true
|
||||
}
|
||||
|
||||
episodeHolder.apply {
|
||||
if (isMultiDeleteState) {
|
||||
setOnClickListener {
|
||||
toggleIsChecked(deleteCheckbox, VisualDownloadItem.Header(card))
|
||||
toggleIsChecked(deleteCheckbox, card)
|
||||
}
|
||||
} else {
|
||||
setOnClickListener {
|
||||
|
@ -204,7 +179,7 @@ class DownloadAdapter(
|
|||
}
|
||||
|
||||
setOnLongClickListener {
|
||||
multiDeleteStateCallback.invoke(VisualDownloadItem.Header(card))
|
||||
multiDeleteStateCallback.invoke(card)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -212,7 +187,7 @@ class DownloadAdapter(
|
|||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun DownloadHeaderEpisodeBinding.handleParentDownload(
|
||||
card: VisualDownloadHeaderCached,
|
||||
card: VisualDownloadCached.Header,
|
||||
formattedSize: String
|
||||
) {
|
||||
downloadButton.isVisible = false
|
||||
|
@ -232,7 +207,7 @@ class DownloadAdapter(
|
|||
episodeHolder.apply {
|
||||
if (isMultiDeleteState) {
|
||||
setOnClickListener {
|
||||
toggleIsChecked(deleteCheckbox, VisualDownloadItem.Header(card))
|
||||
toggleIsChecked(deleteCheckbox, card)
|
||||
}
|
||||
} else {
|
||||
setOnClickListener {
|
||||
|
@ -241,13 +216,13 @@ class DownloadAdapter(
|
|||
}
|
||||
|
||||
setOnLongClickListener {
|
||||
multiDeleteStateCallback.invoke(VisualDownloadItem.Header(card))
|
||||
multiDeleteStateCallback.invoke(card)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindChild(card: VisualDownloadChildCached?) {
|
||||
private fun bindChild(card: VisualDownloadCached.Child?) {
|
||||
if (binding !is DownloadChildEpisodeBinding || card == null) return
|
||||
|
||||
val data = card.data
|
||||
|
@ -286,7 +261,7 @@ class DownloadAdapter(
|
|||
downloadButton.isVisible = !isMultiDeleteState
|
||||
|
||||
downloadButton.setOnLongClickListener {
|
||||
multiDeleteStateCallback.invoke(VisualDownloadItem.Child(card))
|
||||
multiDeleteStateCallback.invoke(card)
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -302,7 +277,7 @@ class DownloadAdapter(
|
|||
downloadChildEpisodeHolder.apply {
|
||||
if (isMultiDeleteState) {
|
||||
setOnClickListener {
|
||||
toggleIsChecked(deleteCheckbox, VisualDownloadItem.Child(card))
|
||||
toggleIsChecked(deleteCheckbox, card)
|
||||
}
|
||||
} else {
|
||||
setOnClickListener {
|
||||
|
@ -311,7 +286,7 @@ class DownloadAdapter(
|
|||
}
|
||||
|
||||
setOnLongClickListener {
|
||||
multiDeleteStateCallback.invoke(VisualDownloadItem.Child(card))
|
||||
multiDeleteStateCallback.invoke(card)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -319,7 +294,7 @@ class DownloadAdapter(
|
|||
if (isMultiDeleteState) {
|
||||
deleteCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
selectedIds[data.id] = isChecked
|
||||
selectedChangedCallback.invoke(VisualDownloadItem.Child(card), isChecked)
|
||||
selectedChangedCallback.invoke(card, isChecked)
|
||||
}
|
||||
} else deleteCheckbox.setOnCheckedChangeListener(null)
|
||||
|
||||
|
@ -347,8 +322,8 @@ class DownloadAdapter(
|
|||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return when (getItem(position)) {
|
||||
is VisualDownloadChildCached -> VIEW_TYPE_CHILD
|
||||
is VisualDownloadHeaderCached -> VIEW_TYPE_HEADER
|
||||
is VisualDownloadCached.Child -> VIEW_TYPE_CHILD
|
||||
is VisualDownloadCached.Header -> VIEW_TYPE_HEADER
|
||||
else -> throw IllegalArgumentException("Invalid data type at position $position")
|
||||
}
|
||||
}
|
||||
|
@ -383,13 +358,10 @@ class DownloadAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun toggleIsChecked(checkbox: CheckBox, item: VisualDownloadItem) {
|
||||
private fun toggleIsChecked(checkbox: CheckBox, item: VisualDownloadCached) {
|
||||
val isChecked = !checkbox.isChecked
|
||||
checkbox.isChecked = isChecked
|
||||
when (item) {
|
||||
is VisualDownloadItem.Header -> selectedIds[item.header.data.id] = isChecked
|
||||
is VisualDownloadItem.Child -> selectedIds[item.child.data.id] = isChecked
|
||||
}
|
||||
selectedIds[item.data.id] = isChecked
|
||||
selectedChangedCallback.invoke(item, isChecked)
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ class DownloadChildFragment : Fragment() {
|
|||
}.mapNotNull {
|
||||
val info = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(ctx, it.id)
|
||||
?: return@mapNotNull null
|
||||
VisualDownloadChildCached(
|
||||
VisualDownloadCached.Child(
|
||||
currentBytes = info.fileLength,
|
||||
totalBytes = info.totalBytes,
|
||||
data = it,
|
||||
|
@ -131,10 +131,9 @@ class DownloadChildFragment : Fragment() {
|
|||
} else downloadsViewModel.removeSelected(card)
|
||||
},
|
||||
{ card ->
|
||||
if (card !is VisualDownloadItem.Child) return@DownloadAdapter
|
||||
downloadsViewModel.addSelected(card)
|
||||
(binding?.downloadChildList?.adapter as? DownloadAdapter)?.updateSelectedItem(
|
||||
card.child.data.id,
|
||||
card.data.id,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
@ -154,7 +153,7 @@ class DownloadChildFragment : Fragment() {
|
|||
updateList(folder)
|
||||
}
|
||||
|
||||
private fun handleSelectedChange(selected: MutableList<VisualDownloadItem>) {
|
||||
private fun handleSelectedChange(selected: MutableList<VisualDownloadCached>) {
|
||||
val adapter = binding?.downloadChildList?.adapter as? DownloadAdapter
|
||||
if (selected.isNotEmpty()) {
|
||||
binding?.downloadDeleteAppbar?.isVisible = true
|
||||
|
|
|
@ -130,10 +130,9 @@ class DownloadFragment : Fragment() {
|
|||
} 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,
|
||||
card.data.id,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
@ -188,7 +187,7 @@ class DownloadFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleSelectedChange(selected: MutableList<VisualDownloadItem>) {
|
||||
private fun handleSelectedChange(selected: MutableList<VisualDownloadCached>) {
|
||||
val adapter = binding?.downloadList?.adapter as? DownloadAdapter
|
||||
if (selected.isNotEmpty()) {
|
||||
binding?.downloadDeleteAppbar?.isVisible = true
|
||||
|
@ -211,10 +210,10 @@ class DownloadFragment : Fragment() {
|
|||
adapter?.setIsMultiDeleteState(true)
|
||||
} else {
|
||||
binding?.downloadDeleteAppbar?.isVisible = false
|
||||
binding?.downloadStorageAppbar?.isVisible =
|
||||
// Make sure we don't display it early
|
||||
!downloadsViewModel.headerCards.value.isNullOrEmpty() &&
|
||||
downloadsViewModel.usedBytes.value?.let { it > 0 } == true
|
||||
// Make sure we don't display it early
|
||||
if (downloadsViewModel.usedBytes.value?.let { it > 0 } == true) {
|
||||
binding?.downloadStorageAppbar?.isVisible = true
|
||||
}
|
||||
|
||||
adapter?.setIsMultiDeleteState(false)
|
||||
downloadsViewModel.clearSelectedItems()
|
||||
|
|
|
@ -27,24 +27,24 @@ import kotlinx.coroutines.withContext
|
|||
|
||||
class DownloadViewModel : ViewModel() {
|
||||
private val _headerCards =
|
||||
MutableLiveData<List<VisualDownloadHeaderCached>>().apply { listOf<VisualDownloadHeaderCached>() }
|
||||
val headerCards: LiveData<List<VisualDownloadHeaderCached>> = _headerCards
|
||||
MutableLiveData<List<VisualDownloadCached.Header>>().apply { listOf<VisualDownloadCached.Header>() }
|
||||
val headerCards: LiveData<List<VisualDownloadCached.Header>> = _headerCards
|
||||
|
||||
private val _usedBytes = MutableLiveData<Long>()
|
||||
private val _availableBytes = MutableLiveData<Long>()
|
||||
private val _downloadBytes = MutableLiveData<Long>()
|
||||
|
||||
private val _selectedItems = MutableLiveData<MutableList<VisualDownloadItem>>(mutableListOf())
|
||||
private val _selectedItems = MutableLiveData<MutableList<VisualDownloadCached>>(mutableListOf())
|
||||
|
||||
val usedBytes: LiveData<Long> = _usedBytes
|
||||
val availableBytes: LiveData<Long> = _availableBytes
|
||||
val downloadBytes: LiveData<Long> = _downloadBytes
|
||||
|
||||
val selectedItems: LiveData<MutableList<VisualDownloadItem>> = _selectedItems
|
||||
val selectedItems: LiveData<MutableList<VisualDownloadCached>> = _selectedItems
|
||||
|
||||
private var previousVisual: List<VisualDownloadHeaderCached>? = null
|
||||
private var previousVisual: List<VisualDownloadCached.Header>? = null
|
||||
|
||||
fun addSelected(item: VisualDownloadItem) {
|
||||
fun addSelected(item: VisualDownloadCached) {
|
||||
val currentSelected = selectedItems.value ?: mutableListOf()
|
||||
if (!currentSelected.contains(item)) {
|
||||
currentSelected.add(item)
|
||||
|
@ -52,7 +52,7 @@ class DownloadViewModel : ViewModel() {
|
|||
}
|
||||
}
|
||||
|
||||
fun removeSelected(item: VisualDownloadItem) {
|
||||
fun removeSelected(item: VisualDownloadCached) {
|
||||
selectedItems.value?.let { selected ->
|
||||
selected.remove(item)
|
||||
_selectedItems.postValue(selected)
|
||||
|
@ -63,8 +63,8 @@ class DownloadViewModel : ViewModel() {
|
|||
val currentSelected = selectedItems.value ?: mutableListOf()
|
||||
val items = headerCards.value ?: return
|
||||
items.forEach { item ->
|
||||
if (!currentSelected.contains(VisualDownloadItem.Header(item))) {
|
||||
currentSelected.add(VisualDownloadItem.Header(item))
|
||||
if (!currentSelected.contains(item)) {
|
||||
currentSelected.add(item)
|
||||
}
|
||||
}
|
||||
_selectedItems.postValue(currentSelected)
|
||||
|
@ -124,7 +124,7 @@ class DownloadViewModel : ViewModel() {
|
|||
DOWNLOAD_EPISODE_CACHE,
|
||||
getFolderName(it.id.toString(), it.id.toString())
|
||||
)
|
||||
VisualDownloadHeaderCached(
|
||||
VisualDownloadCached.Header(
|
||||
currentBytes = currentBytes,
|
||||
totalBytes = bytes,
|
||||
data = it,
|
||||
|
@ -145,7 +145,7 @@ class DownloadViewModel : ViewModel() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateStorageStats(visual: List<VisualDownloadHeaderCached>) {
|
||||
private fun updateStorageStats(visual: List<VisualDownloadCached.Header>) {
|
||||
try {
|
||||
val stat = StatFs(Environment.getExternalStorageDirectory().path)
|
||||
val localBytesAvailable = stat.availableBytes
|
||||
|
@ -164,17 +164,12 @@ class DownloadViewModel : ViewModel() {
|
|||
fun handleMultiDelete(context: Context) = viewModelScope.launchSafe {
|
||||
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 ids = selectedItemsList.map { it.data.id }
|
||||
|
||||
val names = selectedItemsList.mapNotNull {
|
||||
when (it) {
|
||||
is VisualDownloadItem.Header -> it.header.data.name
|
||||
is VisualDownloadItem.Child -> it.child.data.name
|
||||
is VisualDownloadCached.Header -> it.data.name
|
||||
is VisualDownloadCached.Child -> it.data.name
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue