Add a deselect all button and move child handling to view model

This commit is contained in:
Luna712 2024-07-08 22:36:19 -06:00 committed by GitHub
parent 0a564b6f33
commit 1f37db3c63
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 105 additions and 32 deletions

View file

@ -315,13 +315,11 @@ class DownloadAdapter(
} }
} }
@SuppressLint("NotifyDataSetChanged")
fun setIsMultiDeleteState(value: Boolean) { fun setIsMultiDeleteState(value: Boolean) {
if (isMultiDeleteState == value) return if (isMultiDeleteState == value) return
isMultiDeleteState = value isMultiDeleteState = value
if (!value) { if (!value) {
selectedIds.clear() clearSelectedItems()
notifyDataSetChanged()
} else notifyItemRangeChanged(0, itemCount) } else notifyItemRangeChanged(0, itemCount)
} }
@ -335,6 +333,12 @@ class DownloadAdapter(
} }
} }
@SuppressLint("NotifyDataSetChanged")
fun clearSelectedItems() {
selectedIds.clear()
notifyDataSetChanged()
}
private fun toggleIsChecked(checkbox: CheckBox, item: VisualDownloadCached) { private fun toggleIsChecked(checkbox: CheckBox, item: VisualDownloadCached) {
val isChecked = !checkbox.isChecked val isChecked = !checkbox.isChecked
checkbox.isChecked = isChecked checkbox.isChecked = isChecked

View file

@ -60,31 +60,6 @@ class DownloadChildFragment : Fragment() {
return localBinding.root return localBinding.root
} }
private fun updateList(folder: String) = main {
context?.let { ctx ->
val data = withContext(Dispatchers.IO) { ctx.getKeys(folder) }
val eps = withContext(Dispatchers.IO) {
data.mapNotNull { key ->
context?.getKey<VideoDownloadHelper.DownloadEpisodeCached>(key)
}.mapNotNull {
val info = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(ctx, it.id)
?: return@mapNotNull null
VisualDownloadCached.Child(
currentBytes = info.fileLength,
totalBytes = info.totalBytes,
data = it,
)
}
}.sortedBy { it.data.episode + (it.data.season ?: 0) * 100000 }
if (eps.isEmpty()) {
activity?.onBackPressedDispatcher?.onBackPressed()
return@main
}
(binding?.downloadChildList?.adapter as? DownloadAdapter)?.submitList(eps)
}
}
private var downloadDeleteEventListener: ((Int) -> Unit)? = null private var downloadDeleteEventListener: ((Int) -> Unit)? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -113,6 +88,14 @@ class DownloadChildFragment : Fragment() {
setAppBarNoScrollFlagsOnTV() setAppBarNoScrollFlagsOnTV()
} }
observe(downloadsViewModel.childCards) {
if (it.isEmpty()) {
activity?.onBackPressedDispatcher?.onBackPressed()
return@observe
}
(binding?.downloadChildList?.adapter as? DownloadAdapter)?.submitList(it)
}
observe(downloadsViewModel.isMultiDeleteState) { isMultiDeleteState -> observe(downloadsViewModel.isMultiDeleteState) { isMultiDeleteState ->
val adapter = binding?.downloadChildList?.adapter as? DownloadAdapter val adapter = binding?.downloadChildList?.adapter as? DownloadAdapter
adapter?.setIsMultiDeleteState(isMultiDeleteState) adapter?.setIsMultiDeleteState(isMultiDeleteState)
@ -158,7 +141,7 @@ class DownloadChildFragment : Fragment() {
) )
} }
updateList(folder) downloadsViewModel.updateChildList(requireContext(), folder)
} }
private fun handleSelectedChange(selected: MutableList<VisualDownloadCached>) { private fun handleSelectedChange(selected: MutableList<VisualDownloadCached>) {
@ -174,11 +157,22 @@ class DownloadChildFragment : Fragment() {
downloadsViewModel.setIsMultiDeleteState(false) downloadsViewModel.setIsMultiDeleteState(false)
} }
binding?.btnSelectAll?.isVisible = !downloadsViewModel.isAllSelected()
binding?.btnDeselectAll?.isVisible = downloadsViewModel.isAllSelected()
binding?.btnSelectAll?.setOnClickListener { binding?.btnSelectAll?.setOnClickListener {
(binding?.downloadChildList?.adapter as? DownloadAdapter)?.selectAllItems() (binding?.downloadChildList?.adapter as? DownloadAdapter)?.selectAllItems()
downloadsViewModel.selectAllItems() downloadsViewModel.selectAllItems()
} }
binding?.btnDeselectAll?.setOnClickListener {
(binding?.downloadChildList?.adapter as? DownloadAdapter)?.clearSelectedItems()
downloadsViewModel.clearSelectedItems()
binding?.btnSelectAll?.isVisible = true
binding?.btnDeselectAll?.isVisible = false
}
downloadsViewModel.setIsMultiDeleteState(true) downloadsViewModel.setIsMultiDeleteState(true)
} }
} }
@ -187,7 +181,7 @@ class DownloadChildFragment : Fragment() {
downloadDeleteEventListener = { id: Int -> downloadDeleteEventListener = { id: Int ->
val list = (binding?.downloadChildList?.adapter as? DownloadAdapter)?.currentList val list = (binding?.downloadChildList?.adapter as? DownloadAdapter)?.currentList
if (list?.any { it.data.id == id } == true) { if (list?.any { it.data.id == id } == true) {
updateList(folder) context?.let { downloadsViewModel.updateChildList(it, folder) }
} }
} }
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it } downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it }

View file

@ -213,11 +213,22 @@ class DownloadFragment : Fragment() {
downloadsViewModel.setIsMultiDeleteState(false) downloadsViewModel.setIsMultiDeleteState(false)
} }
binding?.btnSelectAll?.isVisible = !downloadsViewModel.isAllSelected()
binding?.btnDeselectAll?.isVisible = downloadsViewModel.isAllSelected()
binding?.btnSelectAll?.setOnClickListener { binding?.btnSelectAll?.setOnClickListener {
(binding?.downloadList?.adapter as? DownloadAdapter)?.selectAllItems() (binding?.downloadList?.adapter as? DownloadAdapter)?.selectAllItems()
downloadsViewModel.selectAllItems() downloadsViewModel.selectAllItems()
} }
binding?.btnDeselectAll?.setOnClickListener {
(binding?.downloadList?.adapter as? DownloadAdapter)?.clearSelectedItems()
downloadsViewModel.clearSelectedItems()
binding?.btnSelectAll?.isVisible = true
binding?.btnDeselectAll?.isVisible = false
}
downloadsViewModel.setIsMultiDeleteState(true) downloadsViewModel.setIsMultiDeleteState(true)
} }
} }

View file

@ -31,6 +31,10 @@ class DownloadViewModel : ViewModel() {
MutableLiveData<List<VisualDownloadCached.Header>>().apply { listOf<VisualDownloadCached.Header>() } MutableLiveData<List<VisualDownloadCached.Header>>().apply { listOf<VisualDownloadCached.Header>() }
val headerCards: LiveData<List<VisualDownloadCached.Header>> = _headerCards val headerCards: LiveData<List<VisualDownloadCached.Header>> = _headerCards
private val _childCards =
MutableLiveData<List<VisualDownloadCached.Child>>().apply { listOf<VisualDownloadCached.Child>() }
val childCards: LiveData<List<VisualDownloadCached.Child>> = _childCards
private val _usedBytes = MutableLiveData<Long>() private val _usedBytes = MutableLiveData<Long>()
val usedBytes: LiveData<Long> = _usedBytes val usedBytes: LiveData<Long> = _usedBytes
@ -46,7 +50,7 @@ class DownloadViewModel : ViewModel() {
private val _selectedItems = MutableLiveData<MutableList<VisualDownloadCached>>(mutableListOf()) private val _selectedItems = MutableLiveData<MutableList<VisualDownloadCached>>(mutableListOf())
val selectedItems: LiveData<MutableList<VisualDownloadCached>> = _selectedItems val selectedItems: LiveData<MutableList<VisualDownloadCached>> = _selectedItems
private var previousVisual: List<VisualDownloadCached.Header>? = null private var previousVisual: List<VisualDownloadCached>? = null
fun setIsMultiDeleteState(value: Boolean) { fun setIsMultiDeleteState(value: Boolean) {
_isMultiDeleteState.postValue(value) _isMultiDeleteState.postValue(value)
@ -69,7 +73,8 @@ class DownloadViewModel : ViewModel() {
fun selectAllItems() { fun selectAllItems() {
val currentSelected = selectedItems.value ?: mutableListOf() val currentSelected = selectedItems.value ?: mutableListOf()
val items = headerCards.value ?: return val items = (headerCards.value ?: emptyList()) + (childCards.value ?: emptyList())
if(items.isEmpty()) return
items.forEach { item -> items.forEach { item ->
if (!currentSelected.contains(item)) { if (!currentSelected.contains(item)) {
currentSelected.add(item) currentSelected.add(item)
@ -82,6 +87,22 @@ class DownloadViewModel : ViewModel() {
_selectedItems.postValue(mutableListOf()) _selectedItems.postValue(mutableListOf())
} }
fun isAllSelected(): Boolean {
val currentSelected = selectedItems.value ?: return false
val headerItems = headerCards.value
val childItems = childCards.value
val isAllHeadersSelected = headerItems != null &&
headerItems.count() == currentSelected.count() &&
headerItems.containsAll(currentSelected)
val isAllChildrenSelected = childItems != null &&
childItems.count() == currentSelected.count() &&
childItems.containsAll(currentSelected)
return isAllHeadersSelected || isAllChildrenSelected
}
fun updateList(context: Context) = viewModelScope.launchSafe { fun updateList(context: Context) = viewModelScope.launchSafe {
val children = withContext(Dispatchers.IO) { val children = withContext(Dispatchers.IO) {
context.getKeys(DOWNLOAD_EPISODE_CACHE) context.getKeys(DOWNLOAD_EPISODE_CACHE)
@ -153,6 +174,28 @@ class DownloadViewModel : ViewModel() {
} }
} }
fun updateChildList(context: Context, folder: String) = viewModelScope.launchSafe {
val data = withContext(Dispatchers.IO) { context.getKeys(folder) }
val visual = withContext(Dispatchers.IO) {
data.mapNotNull { key ->
context.getKey<VideoDownloadHelper.DownloadEpisodeCached>(key)
}.mapNotNull {
val info = getDownloadFileInfoAndUpdateSettings(context, it.id)
?: return@mapNotNull null
VisualDownloadCached.Child(
currentBytes = info.fileLength,
totalBytes = info.totalBytes,
data = it,
)
}
}.sortedBy { it.data.episode + (it.data.season ?: 0) * 100000 }
if (previousVisual != visual) {
previousVisual = visual
_childCards.postValue(visual)
}
}
private fun updateStorageStats(visual: List<VisualDownloadCached.Header>) { private fun updateStorageStats(visual: List<VisualDownloadCached.Header>) {
try { try {
val stat = StatFs(Environment.getExternalStorageDirectory().path) val stat = StatFs(Environment.getExternalStorageDirectory().path)

View file

@ -70,6 +70,16 @@
android:text="@string/select_all" android:text="@string/select_all"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:layout_marginEnd="8dp" /> android:layout_marginEnd="8dp" />
<Button
android:id="@+id/btnDeselectAll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:text="@string/deselect_all"
android:textColor="@android:color/white"
android:layout_marginEnd="8dp"
android:visibility="gone" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout

View file

@ -73,6 +73,16 @@
android:text="@string/select_all" android:text="@string/select_all"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:layout_marginEnd="8dp" /> android:layout_marginEnd="8dp" />
<Button
android:id="@+id/btnDeselectAll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:text="@string/deselect_all"
android:textColor="@android:color/white"
android:layout_marginEnd="8dp"
android:visibility="gone" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout

View file

@ -153,6 +153,7 @@
<string name="downloads_empty">There are currently no downloads.</string> <string name="downloads_empty">There are currently no downloads.</string>
<string name="offline_file">Available for watching offline</string> <string name="offline_file">Available for watching offline</string>
<string name="select_all">Select All</string> <string name="select_all">Select All</string>
<string name="deselect_all">Deselect All</string>
<string name="update_started">Update Started</string> <string name="update_started">Update Started</string>
<string name="stream">Network stream</string> <string name="stream">Network stream</string>
<string name="open_local_video">Open local video</string> <string name="open_local_video">Open local video</string>