diff --git a/core/domain/src/main/kotlin/org/moire/ultrasonic/domain/GenericEntry.kt b/core/domain/src/main/kotlin/org/moire/ultrasonic/domain/GenericEntry.kt index 194408e6..37bd863f 100644 --- a/core/domain/src/main/kotlin/org/moire/ultrasonic/domain/GenericEntry.kt +++ b/core/domain/src/main/kotlin/org/moire/ultrasonic/domain/GenericEntry.kt @@ -1,7 +1,19 @@ package org.moire.ultrasonic.domain abstract class GenericEntry { - // TODO Should be non-null! + // TODO: Should be non-null! abstract val id: String? open val name: String? = null + + // These are just a formality and will never be called, + // because Kotlin data classes will have autogenerated equals() and hashCode() functions + override operator fun equals(other: Any?): Boolean { + return this === other + } + + override fun hashCode(): Int { + var result = id?.hashCode() ?: 0 + result = 31 * result + (name?.hashCode() ?: 0) + return result + } } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/AlbumListFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/AlbumListFragment.kt index 75b93057..97285d68 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/AlbumListFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/AlbumListFragment.kt @@ -49,8 +49,9 @@ class AlbumListFragment : GenericListFragment> = MutableLiveData() + val albumList: MutableLiveData> = MutableLiveData(listOf()) + var lastType: String? = null private var loadedUntil: Int = 0 fun getAlbumList( @@ -21,8 +22,14 @@ class AlbumListModel(application: Application) : GenericListModel(application) { swipe: SwipeRefreshLayout, args: Bundle ): LiveData> { + // Don't reload the data if navigating back to the view that was active before. + // This way, we keep the scroll position + val albumListType = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE)!! - backgroundLoadFromServer(refresh, swipe, args) + if (refresh || albumList.value!!.isEmpty() || albumListType != lastType) { + lastType = albumListType + backgroundLoadFromServer(refresh, swipe, args) + } return albumList } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ArtistListModel.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ArtistListModel.kt index d58e97ca..a774ebcd 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ArtistListModel.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ArtistListModel.kt @@ -30,13 +30,17 @@ import org.moire.ultrasonic.service.MusicService * Provides ViewModel which contains the list of available Artists */ class ArtistListModel(application: Application) : GenericListModel(application) { - private val artists: MutableLiveData> = MutableLiveData() + private val artists: MutableLiveData> = MutableLiveData(listOf()) /** * Retrieves all available Artists in a LiveData */ fun getItems(refresh: Boolean, swipe: SwipeRefreshLayout): LiveData> { - backgroundLoadFromServer(refresh, swipe) + // Don't reload the data if navigating back to the view that was active before. + // This way, we keep the scroll position + if (artists.value!!.isEmpty() || refresh) { + backgroundLoadFromServer(refresh, swipe) + } return artists } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/GenericRowAdapter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/GenericRowAdapter.kt index 2a26463c..b825fcac 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/GenericRowAdapter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/GenericRowAdapter.kt @@ -16,20 +16,24 @@ import android.widget.ImageView import android.widget.PopupMenu import android.widget.RelativeLayout import android.widget.TextView +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import org.moire.ultrasonic.R import org.moire.ultrasonic.data.ActiveServerProvider +import org.moire.ultrasonic.domain.GenericEntry import org.moire.ultrasonic.domain.MusicFolder import org.moire.ultrasonic.view.SelectMusicFolderView /* * An abstract Adapter, which can be extended to display a List of in a RecyclerView */ -abstract class GenericRowAdapter( +abstract class GenericRowAdapter( val onItemClick: (T) -> Unit, val onContextMenuClick: (MenuItem, T) -> Boolean, private val onMusicFolderUpdate: (String?) -> Unit -) : RecyclerView.Adapter() { +) : ListAdapter(GenericDiffCallback()) { + open var itemList: List = listOf() protected abstract val layout: Int protected abstract val contextMenuLayout: Int @@ -40,11 +44,12 @@ abstract class GenericRowAdapter( var selectedFolder: String? = null /** - * Sets the data to be displayed in the RecyclerView + * Sets the data to be displayed in the RecyclerView, + * using DiffUtil to efficiently calculate the minimum required changes.. */ open fun setData(data: List) { + submitList(data) itemList = data - notifyDataSetChanged() } /** @@ -136,5 +141,17 @@ abstract class GenericRowAdapter( companion object { internal const val TYPE_HEADER = 0 internal const val TYPE_ITEM = 1 + + /** + * Calculates the differences between data sets + */ + class GenericDiffCallback : DiffUtil.ItemCallback() { + override fun areContentsTheSame(oldItem: T, newItem: T): Boolean { + return oldItem == newItem + } + override fun areItemsTheSame(oldItem: T, newItem: T): Boolean { + return oldItem.id == newItem.id + } + } } }