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
|
#### What's New
|
||||||
- Folders on external drives can now be excluded on Android Q+ [#134]
|
- Folders on external drives can now be excluded on Android Q+ [#134]
|
||||||
|
- Added toggle for edge-to-edge mode [#149]
|
||||||
|
|
||||||
#### What's Improved
|
#### What's Improved
|
||||||
- Genre parsing now handles multiple integer values and cover/remix indicators (May wipe playback state)
|
- 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
|
binding.excludedRecycler.apply {
|
||||||
|
adapter = excludedAdapter
|
||||||
if (savedInstanceState != null) {
|
itemAnimator = null
|
||||||
val pendingDirs = savedInstanceState.getStringArrayList(KEY_PENDING_DIRS)
|
|
||||||
if (pendingDirs != null) {
|
|
||||||
updateDirectories(pendingDirs.mapNotNull(ExcludedDirectory::fromString))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
|
@ -111,7 +113,8 @@ class ExcludedDialog :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRemoveDirectory(dir: ExcludedDirectory) {
|
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?) {
|
private fun addDocTreePath(uri: Uri?) {
|
||||||
|
|
@ -123,7 +126,8 @@ class ExcludedDialog :
|
||||||
|
|
||||||
val dir = parseExcludedUri(uri)
|
val dir = parseExcludedUri(uri)
|
||||||
if (dir != null) {
|
if (dir != null) {
|
||||||
updateDirectories(excludedAdapter.data.currentList.toMutableList().also { it.add(dir) })
|
excludedAdapter.data.add(dir)
|
||||||
|
requireBinding().excludedEmpty.isVisible = false
|
||||||
} else {
|
} else {
|
||||||
requireContext().showToast(R.string.err_bad_dir)
|
requireContext().showToast(R.string.err_bad_dir)
|
||||||
}
|
}
|
||||||
|
|
@ -142,11 +146,6 @@ class ExcludedDialog :
|
||||||
return ExcludedDirectory.fromString(treeUri)
|
return ExcludedDirectory.fromString(treeUri)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateDirectories(dirs: List<ExcludedDirectory>) {
|
|
||||||
excludedAdapter.data.submitList(dirs)
|
|
||||||
requireBinding().excludedEmpty.isVisible = dirs.isEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun saveAndRestart() {
|
private fun saveAndRestart() {
|
||||||
settingsManager.excludedDirs = excludedAdapter.data.currentList
|
settingsManager.excludedDirs = excludedAdapter.data.currentList
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ package org.oxycblt.auxio.ui
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Adapter
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.recyclerview.widget.AsyncListDiffer
|
import androidx.recyclerview.widget.AsyncListDiffer
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
|
@ -188,6 +189,7 @@ abstract class BackingData<T> {
|
||||||
*/
|
*/
|
||||||
class PrimitiveBackingData<T>(private val adapter: RecyclerView.Adapter<*>) : BackingData<T>() {
|
class PrimitiveBackingData<T>(private val adapter: RecyclerView.Adapter<*>) : BackingData<T>() {
|
||||||
private var _currentList = mutableListOf<T>()
|
private var _currentList = mutableListOf<T>()
|
||||||
|
|
||||||
/** The current list backing this adapter. */
|
/** The current list backing this adapter. */
|
||||||
val currentList: List<T>
|
val currentList: List<T>
|
||||||
get() = _currentList
|
get() = _currentList
|
||||||
|
|
@ -196,13 +198,34 @@ class PrimitiveBackingData<T>(private val adapter: RecyclerView.Adapter<*>) : Ba
|
||||||
override fun getItemCount(): Int = _currentList.size
|
override fun getItemCount(): Int = _currentList.size
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the list with a [newList]. This calls [RecyclerView.Adapter.notifyDataSetChanged]
|
* Update the list with a [newList]. This does a basic animation that removes all items and
|
||||||
* internally, which is inefficient but also the most reliable update callback.
|
* replaces them with the new ones.
|
||||||
*/
|
*/
|
||||||
@Suppress("NotifyDatasetChanged")
|
@Suppress("NotifyDatasetChanged")
|
||||||
fun submitList(newList: List<T>) {
|
fun submitList(newList: List<T>) {
|
||||||
|
if (_currentList.isNotEmpty()) {
|
||||||
|
val oldListSize = _currentList.size
|
||||||
|
_currentList.clear()
|
||||||
|
adapter.notifyItemRangeRemoved(0, oldListSize)
|
||||||
|
}
|
||||||
|
|
||||||
_currentList = newList.toMutableList()
|
_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