ui: change adapter animations

Rework the submitList animation to be less resource intensive and nicer
looking (at the cost of scroll positioning)

notifyDatasetChanged is slow and has no animation, but list diffing is
chaotic and basically useless outside of search. However, clearing the
adapter and then populating it with new items seems to work quite well,
albeit with the scroll position being lost sadly. Switch to that.
This commit is contained in:
OxygenCobalt 2022-06-07 19:14:54 -06:00
parent d15055cc29
commit f85f366144
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
3 changed files with 42 additions and 19 deletions

View file

@ -4,6 +4,7 @@
#### What's New
- Folders on external drives can now be excluded on Android Q+ [#134]
- Added toggle for edge-to-edge mode [#149]
#### What's Improved
- Genre parsing now handles multiple integer values and cover/remix indicators (May wipe playback state)

View file

@ -86,17 +86,19 @@ class ExcludedDialog :
}
}
binding.excludedRecycler.adapter = excludedAdapter
if (savedInstanceState != null) {
val pendingDirs = savedInstanceState.getStringArrayList(KEY_PENDING_DIRS)
if (pendingDirs != null) {
updateDirectories(pendingDirs.mapNotNull(ExcludedDirectory::fromString))
return
}
binding.excludedRecycler.apply {
adapter = excludedAdapter
itemAnimator = null
}
updateDirectories(settingsManager.excludedDirs)
val dirs =
savedInstanceState
?.getStringArrayList(KEY_PENDING_DIRS)
?.mapNotNull(ExcludedDirectory::fromString)
?: settingsManager.excludedDirs
excludedAdapter.data.submitList(dirs)
requireBinding().excludedEmpty.isVisible = dirs.isEmpty()
}
override fun onSaveInstanceState(outState: Bundle) {
@ -111,7 +113,8 @@ class ExcludedDialog :
}
override fun onRemoveDirectory(dir: ExcludedDirectory) {
updateDirectories(excludedAdapter.data.currentList.toMutableList().also { it.remove(dir) })
excludedAdapter.data.remove(dir)
requireBinding().excludedEmpty.isVisible = excludedAdapter.data.currentList.isEmpty()
}
private fun addDocTreePath(uri: Uri?) {
@ -123,7 +126,8 @@ class ExcludedDialog :
val dir = parseExcludedUri(uri)
if (dir != null) {
updateDirectories(excludedAdapter.data.currentList.toMutableList().also { it.add(dir) })
excludedAdapter.data.add(dir)
requireBinding().excludedEmpty.isVisible = false
} else {
requireContext().showToast(R.string.err_bad_dir)
}
@ -142,11 +146,6 @@ class ExcludedDialog :
return ExcludedDirectory.fromString(treeUri)
}
private fun updateDirectories(dirs: List<ExcludedDirectory>) {
excludedAdapter.data.submitList(dirs)
requireBinding().excludedEmpty.isVisible = dirs.isEmpty()
}
private fun saveAndRestart() {
settingsManager.excludedDirs = excludedAdapter.data.currentList

View file

@ -20,6 +20,7 @@ package org.oxycblt.auxio.ui
import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.widget.Adapter
import androidx.annotation.StringRes
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
@ -188,6 +189,7 @@ abstract class BackingData<T> {
*/
class PrimitiveBackingData<T>(private val adapter: RecyclerView.Adapter<*>) : BackingData<T>() {
private var _currentList = mutableListOf<T>()
/** The current list backing this adapter. */
val currentList: List<T>
get() = _currentList
@ -196,13 +198,34 @@ class PrimitiveBackingData<T>(private val adapter: RecyclerView.Adapter<*>) : Ba
override fun getItemCount(): Int = _currentList.size
/**
* Update the list with a [newList]. This calls [RecyclerView.Adapter.notifyDataSetChanged]
* internally, which is inefficient but also the most reliable update callback.
* Update the list with a [newList]. This does a basic animation that removes all items and
* replaces them with the new ones.
*/
@Suppress("NotifyDatasetChanged")
fun submitList(newList: List<T>) {
if (_currentList.isNotEmpty()) {
val oldListSize = _currentList.size
_currentList.clear()
adapter.notifyItemRangeRemoved(0, oldListSize)
}
_currentList = newList.toMutableList()
adapter.notifyDataSetChanged()
adapter.notifyItemRangeInserted(0, _currentList.size)
}
/** Add an item to the list. */
fun add(item: T) {
_currentList.add(item)
adapter.notifyItemInserted(_currentList.lastIndex)
}
/** Remove an item from the list. */
fun remove(item: T) {
val idx = _currentList.indexOf(item)
if (idx != -1) {
_currentList.removeAt(idx)
adapter.notifyItemRemoved(idx)
}
}
}