3
3
Fork 1
mirror of https://github.com/recloudstream/cloudstream.git synced 2024-08-15 01:53:11 +00:00

Only use IDs for storing in view model

This commit is contained in:
Luna712 2024-07-17 10:00:41 -06:00 committed by GitHub
parent fb78676a81
commit 821f6e3186
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 84 additions and 69 deletions
app/src/main/java/com/lagradost/cloudstream3/ui/download

View file

@ -68,7 +68,7 @@ data class DownloadHeaderClickEvent(
class DownloadAdapter(
private val onHeaderClickEvent: (DownloadHeaderClickEvent) -> Unit,
private val onItemClickEvent: (DownloadClickEvent) -> Unit,
private val onItemSelectionChanged: (VisualDownloadCached, Boolean) -> Unit,
private val onItemSelectionChanged: (Int, Boolean) -> Unit,
) : ListAdapter<VisualDownloadCached, DownloadAdapter.DownloadViewHolder>(DiffCallback()) {
private var isMultiDeleteState: Boolean = false
@ -97,12 +97,12 @@ class DownloadAdapter(
episodeHolder.apply {
if (isMultiDeleteState) {
setOnClickListener {
toggleIsChecked(deleteCheckbox, card)
toggleIsChecked(deleteCheckbox, data.id)
}
}
setOnLongClickListener {
toggleIsChecked(deleteCheckbox, card)
toggleIsChecked(deleteCheckbox, data.id)
true
}
}
@ -111,7 +111,7 @@ class DownloadAdapter(
setImage(data.poster)
if (isMultiDeleteState) {
setOnClickListener {
toggleIsChecked(deleteCheckbox, card)
toggleIsChecked(deleteCheckbox, data.id)
}
} else {
setOnClickListener {
@ -125,7 +125,7 @@ class DownloadAdapter(
}
setOnLongClickListener {
toggleIsChecked(deleteCheckbox, card)
toggleIsChecked(deleteCheckbox, data.id)
true
}
}
@ -138,7 +138,7 @@ class DownloadAdapter(
if (isMultiDeleteState) {
deleteCheckbox.setOnCheckedChangeListener { _, isChecked ->
onItemSelectionChanged.invoke(card, isChecked)
onItemSelectionChanged.invoke(data.id, isChecked)
}
} else deleteCheckbox.setOnCheckedChangeListener(null)
@ -287,7 +287,7 @@ class DownloadAdapter(
when {
isMultiDeleteState -> {
setOnClickListener {
toggleIsChecked(deleteCheckbox, card)
toggleIsChecked(deleteCheckbox, data.id)
}
}
@ -304,14 +304,14 @@ class DownloadAdapter(
}
setOnLongClickListener {
toggleIsChecked(deleteCheckbox, card)
toggleIsChecked(deleteCheckbox, data.id)
true
}
}
if (isMultiDeleteState) {
deleteCheckbox.setOnCheckedChangeListener { _, isChecked ->
onItemSelectionChanged.invoke(card, isChecked)
onItemSelectionChanged.invoke(data.id, isChecked)
}
} else deleteCheckbox.setOnCheckedChangeListener(null)
@ -371,10 +371,10 @@ class DownloadAdapter(
}
}
private fun toggleIsChecked(checkbox: CheckBox, item: VisualDownloadCached) {
private fun toggleIsChecked(checkbox: CheckBox, id: Int) {
val isChecked = !checkbox.isChecked
checkbox.isChecked = isChecked
onItemSelectionChanged.invoke(item, isChecked)
onItemSelectionChanged.invoke(id, isChecked)
}
class DiffCallback : DiffUtil.ItemCallback<VisualDownloadCached>() {

View file

@ -118,9 +118,9 @@ class DownloadChildFragment : Fragment() {
}
}
observe(downloadsViewModel.selectedBytes) {
updateDeleteButton(downloadsViewModel.selectedItems.value?.count() ?: 0, it)
updateDeleteButton(downloadsViewModel.selectedItemIds.value?.count() ?: 0, it)
}
observe(downloadsViewModel.selectedItems) {
observe(downloadsViewModel.selectedItemIds) {
handleSelectedChange(it)
updateDeleteButton(it.count(), downloadsViewModel.selectedBytes.value ?: 0L)
@ -141,10 +141,10 @@ class DownloadChildFragment : Fragment() {
setUpDownloadDeleteListener(folder)
}
},
{ card, isChecked ->
{ itemId, isChecked ->
if (isChecked) {
downloadsViewModel.addSelected(card)
} else downloadsViewModel.removeSelected(card)
downloadsViewModel.addSelected(itemId)
} else downloadsViewModel.removeSelected(itemId)
}
)
@ -162,7 +162,7 @@ class DownloadChildFragment : Fragment() {
downloadsViewModel.updateChildList(requireContext(), folder)
}
private fun handleSelectedChange(selected: MutableList<VisualDownloadCached>) {
private fun handleSelectedChange(selected: MutableSet<Int>) {
if (selected.isNotEmpty()) {
binding?.downloadDeleteAppbar?.isVisible = true
binding?.downloadChildToolbar?.isVisible = false

View file

@ -151,7 +151,7 @@ class DownloadFragment : Fragment() {
)
}
observe(downloadsViewModel.selectedBytes) {
updateDeleteButton(downloadsViewModel.selectedItems.value?.count() ?: 0, it)
updateDeleteButton(downloadsViewModel.selectedItemIds.value?.count() ?: 0, it)
}
observe(downloadsViewModel.isMultiDeleteState) { isMultiDeleteState ->
val adapter = binding?.downloadList?.adapter as? DownloadAdapter
@ -167,7 +167,7 @@ class DownloadFragment : Fragment() {
}
}
}
observe(downloadsViewModel.selectedItems) {
observe(downloadsViewModel.selectedItemIds) {
handleSelectedChange(it)
updateDeleteButton(it.count(), downloadsViewModel.selectedBytes.value ?: 0L)
@ -188,10 +188,10 @@ class DownloadFragment : Fragment() {
setUpDownloadDeleteListener()
}
},
{ card, isChecked ->
{ itemId, isChecked ->
if (isChecked) {
downloadsViewModel.addSelected(card)
} else downloadsViewModel.removeSelected(card)
downloadsViewModel.addSelected(itemId)
} else downloadsViewModel.removeSelected(itemId)
}
)
@ -245,8 +245,8 @@ class DownloadFragment : Fragment() {
}
}
private fun handleSelectedChange(selectedItems: MutableList<VisualDownloadCached>) {
if (selectedItems.isNotEmpty()) {
private fun handleSelectedChange(selected: MutableSet<Int>) {
if (selected.isNotEmpty()) {
binding?.downloadDeleteAppbar?.isVisible = true
binding?.downloadStorageAppbar?.isVisible = false
activity?.attachBackPressedCallback {

View file

@ -52,8 +52,8 @@ class DownloadViewModel : ViewModel() {
private val _isMultiDeleteState = MutableLiveData(false)
val isMultiDeleteState: LiveData<Boolean> = _isMultiDeleteState
private val _selectedItems = MutableLiveData<MutableList<VisualDownloadCached>>(mutableListOf())
val selectedItems: LiveData<MutableList<VisualDownloadCached>> = _selectedItems
private val _selectedItemIds = MutableLiveData<MutableSet<Int>>(mutableSetOf())
val selectedItemIds: LiveData<MutableSet<Int>> = _selectedItemIds
private var previousVisual: List<VisualDownloadCached>? = null
@ -61,35 +61,35 @@ class DownloadViewModel : ViewModel() {
_isMultiDeleteState.postValue(value)
}
fun addSelected(item: VisualDownloadCached) {
val currentSelected = selectedItems.value ?: mutableListOf()
if (!currentSelected.contains(item)) {
currentSelected.add(item)
_selectedItems.postValue(currentSelected)
fun addSelected(itemId: Int) {
val currentSelected = selectedItemIds.value ?: mutableSetOf()
if (!currentSelected.contains(itemId)) {
currentSelected.add(itemId)
_selectedItemIds.postValue(currentSelected)
updateSelectedBytes()
updateSelectedCards()
}
}
fun removeSelected(item: VisualDownloadCached) {
selectedItems.value?.let { selected ->
selected.remove(item)
_selectedItems.postValue(selected)
fun removeSelected(itemId: Int) {
selectedItemIds.value?.let { selected ->
selected.remove(itemId)
_selectedItemIds.postValue(selected)
updateSelectedBytes()
updateSelectedCards()
}
}
fun selectAllItems() {
val currentSelected = selectedItems.value ?: mutableListOf()
val currentSelected = selectedItemIds.value ?: mutableSetOf()
val items = (headerCards.value ?: emptyList()) + (childCards.value ?: emptyList())
if (items.isEmpty()) return
items.forEach { item ->
if (!currentSelected.contains(item)) {
currentSelected.add(item)
if (!currentSelected.contains(item.data.id)) {
currentSelected.add(item.data.id)
}
}
_selectedItems.postValue(currentSelected)
_selectedItemIds.postValue(currentSelected)
updateSelectedBytes()
updateSelectedCards()
}
@ -97,31 +97,31 @@ class DownloadViewModel : ViewModel() {
fun clearSelectedItems() {
// We need this to be done immediately
// so we can't use postValue
_selectedItems.value = mutableListOf()
_selectedItemIds.value = mutableSetOf()
updateSelectedCards()
}
fun isAllSelected(): Boolean {
val currentSelected = selectedItems.value ?: return false
val currentSelected = selectedItemIds.value ?: return false
val headerItems = headerCards.value
val childItems = childCards.value
if (headerItems != null &&
headerItems.count() == currentSelected.count() &&
headerItems.containsAll(currentSelected)
headerItems.map { it.data.id }.containsAll(currentSelected)
) return true
if (childItems != null &&
childItems.count() == currentSelected.count() &&
childItems.containsAll(currentSelected)
childItems.map { it.data.id }.containsAll(currentSelected)
) return true
return false
}
private fun updateSelectedBytes() = viewModelScope.launchSafe {
val selectedItemsList = selectedItems.value ?: return@launchSafe
val selectedItemsList = getSelectedItemsData() ?: return@launchSafe
var totalSelectedBytes = 0L
selectedItemsList.forEach { item ->
@ -132,20 +132,16 @@ class DownloadViewModel : ViewModel() {
}
private fun updateSelectedCards() = viewModelScope.launchSafe {
val currentSelected = selectedItems.value ?: return@launchSafe
val currentSelected = selectedItemIds.value ?: return@launchSafe
val updatedHeaderCards = headerCards.value?.toMutableList()
val updatedChildCards = childCards.value?.toMutableList()
updatedHeaderCards?.forEach { header ->
header.isSelected = currentSelected.any {
it.data.id == header.data.id
}
header.isSelected = currentSelected.contains(header.data.id)
}
updatedChildCards?.forEach { child ->
child.isSelected = currentSelected.any {
it.data.id == child.data.id
}
child.isSelected = currentSelected.contains(child.data.id)
}
_headerCards.postValue(updatedHeaderCards)
@ -199,9 +195,7 @@ class DownloadViewModel : ViewModel() {
val bytes = totalBytesUsedByChild[it.id] ?: 0
val currentBytes = currentBytesUsedByChild[it.id] ?: 0
if (bytes <= 0 || downloads <= 0) return@mapNotNull null
val isSelected = selectedItems.value?.any { header ->
it.id == header.data.id
} ?: false
val isSelected = selectedItemIds.value?.contains(it.id) ?: false
val movieEpisode =
if (!it.type.isMovieType()) null
else context.getKey<VideoDownloadHelper.DownloadEpisodeCached>(
@ -239,11 +233,9 @@ class DownloadViewModel : ViewModel() {
data.mapNotNull { key ->
context.getKey<VideoDownloadHelper.DownloadEpisodeCached>(key)
}.mapNotNull {
val isSelected = selectedItemIds.value?.contains(it.id) ?: false
val info = getDownloadFileInfoAndUpdateSettings(context, it.id)
?: return@mapNotNull null
val isSelected = selectedItems.value?.any { child ->
it.id == child.data.id
} ?: false
VisualDownloadCached.Child(
currentBytes = info.fileLength,
totalBytes = info.totalBytes,
@ -279,8 +271,26 @@ class DownloadViewModel : ViewModel() {
context: Context,
onDeleteConfirm: () -> Unit
) = viewModelScope.launchSafe {
val selectedItemsList = selectedItems.value ?: emptyList()
val selectedItemsList = getSelectedItemsData() ?: emptyList()
val deleteData = processSelectedItems(context, selectedItemsList)
val message = buildDeleteMessage(context, deleteData)
showDeleteConfirmationDialog(context, message, deleteData.ids, onDeleteConfirm)
}
private fun getSelectedItemsData(): List<VisualDownloadCached>? {
val selectedIds = selectedItemIds.value ?: return null
val headers = headerCards.value ?: emptyList()
val children = childCards.value ?: emptyList()
return (headers + children).filter { item ->
selectedIds.contains(item.data.id)
}
}
private fun processSelectedItems(
context: Context,
selectedItemsList: List<VisualDownloadCached>
): DeleteData {
val ids = mutableListOf<Int>()
val seriesNames = mutableListOf<String>()
val names = mutableListOf<String>()
@ -331,20 +341,17 @@ class DownloadViewModel : ViewModel() {
}
}
val data = DeleteConfirmationData(parentName, seriesNames.toList(), names.toList())
showDeleteConfirmationDialog(context, ids, data, onDeleteConfirm)
return DeleteData(ids, seriesNames, names, parentName)
}
private fun showDeleteConfirmationDialog(
private fun buildDeleteMessage(
context: Context,
ids: List<Int>,
data: DeleteConfirmationData,
onDeleteConfirm: () -> Unit
) {
data: DeleteData
): String {
val formattedNames = data.names.joinToString(separator = "\n") { "$it" }
val formattedSeriesNames = data.seriesNames.joinToString(separator = "\n") { "$it" }
val message = when {
return when {
data.seriesNames.isNotEmpty() && data.names.isEmpty() -> {
context.getString(R.string.delete_message_series_only).format(formattedSeriesNames)
}
@ -363,7 +370,14 @@ class DownloadViewModel : ViewModel() {
else -> context.getString(R.string.delete_message_multiple).format(formattedNames)
}
}
private fun showDeleteConfirmationDialog(
context: Context,
message: String,
ids: List<Int>,
onDeleteConfirm: () -> Unit
) {
val builder = AlertDialog.Builder(context)
val dialogClickListener =
DialogInterface.OnClickListener { _, which ->
@ -393,9 +407,10 @@ class DownloadViewModel : ViewModel() {
}
}
private data class DeleteConfirmationData(
val parentName: String?,
private data class DeleteData(
val ids: List<Int>,
val seriesNames: List<String>,
val names: List<String>
val names: List<String>,
val parentName: String?
)
}