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:
parent
d15055cc29
commit
f85f366144
3 changed files with 42 additions and 19 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue