diff --git a/CHANGELOG.md b/CHANGELOG.md index 6004e65a4..aa2fd9356 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/app/src/main/java/org/oxycblt/auxio/music/excluded/ExcludedDialog.kt b/app/src/main/java/org/oxycblt/auxio/music/excluded/ExcludedDialog.kt index a9442273c..c9a543230 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/excluded/ExcludedDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/excluded/ExcludedDialog.kt @@ -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) { - excludedAdapter.data.submitList(dirs) - requireBinding().excludedEmpty.isVisible = dirs.isEmpty() - } - private fun saveAndRestart() { settingsManager.excludedDirs = excludedAdapter.data.currentList diff --git a/app/src/main/java/org/oxycblt/auxio/ui/RecyclerFramework.kt b/app/src/main/java/org/oxycblt/auxio/ui/RecyclerFramework.kt index 315802d87..fbfe17c4c 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/RecyclerFramework.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/RecyclerFramework.kt @@ -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 { */ class PrimitiveBackingData(private val adapter: RecyclerView.Adapter<*>) : BackingData() { private var _currentList = mutableListOf() + /** The current list backing this adapter. */ val currentList: List get() = _currentList @@ -196,13 +198,34 @@ class PrimitiveBackingData(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) { + 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) + } } }