Merge branch 'develop' into fix-save-playlist
This commit is contained in:
commit
1132ec6c87
|
@ -1,7 +1,19 @@
|
||||||
package org.moire.ultrasonic.domain
|
package org.moire.ultrasonic.domain
|
||||||
|
|
||||||
abstract class GenericEntry {
|
abstract class GenericEntry {
|
||||||
// TODO Should be non-null!
|
// TODO: Should be non-null!
|
||||||
abstract val id: String?
|
abstract val id: String?
|
||||||
open val name: String? = null
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,9 @@ class AlbumListFragment : GenericListFragment<MusicDirectory.Entry, AlbumRowAdap
|
||||||
if (args == null) throw IllegalArgumentException("Required arguments are missing")
|
if (args == null) throw IllegalArgumentException("Required arguments are missing")
|
||||||
|
|
||||||
val refresh = args.getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH)
|
val refresh = args.getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH)
|
||||||
|
val append = args.getBoolean(Constants.INTENT_EXTRA_NAME_APPEND)
|
||||||
|
|
||||||
return listModel.getAlbumList(refresh, refreshListView!!, args)
|
return listModel.getAlbumList(refresh or append, refreshListView!!, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,7 +13,8 @@ import org.moire.ultrasonic.util.Util
|
||||||
|
|
||||||
class AlbumListModel(application: Application) : GenericListModel(application) {
|
class AlbumListModel(application: Application) : GenericListModel(application) {
|
||||||
|
|
||||||
val albumList: MutableLiveData<List<MusicDirectory.Entry>> = MutableLiveData()
|
val albumList: MutableLiveData<List<MusicDirectory.Entry>> = MutableLiveData(listOf())
|
||||||
|
var lastType: String? = null
|
||||||
private var loadedUntil: Int = 0
|
private var loadedUntil: Int = 0
|
||||||
|
|
||||||
fun getAlbumList(
|
fun getAlbumList(
|
||||||
|
@ -21,8 +22,14 @@ class AlbumListModel(application: Application) : GenericListModel(application) {
|
||||||
swipe: SwipeRefreshLayout,
|
swipe: SwipeRefreshLayout,
|
||||||
args: Bundle
|
args: Bundle
|
||||||
): LiveData<List<MusicDirectory.Entry>> {
|
): LiveData<List<MusicDirectory.Entry>> {
|
||||||
|
// 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
|
return albumList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,13 +30,17 @@ import org.moire.ultrasonic.service.MusicService
|
||||||
* Provides ViewModel which contains the list of available Artists
|
* Provides ViewModel which contains the list of available Artists
|
||||||
*/
|
*/
|
||||||
class ArtistListModel(application: Application) : GenericListModel(application) {
|
class ArtistListModel(application: Application) : GenericListModel(application) {
|
||||||
private val artists: MutableLiveData<List<Artist>> = MutableLiveData()
|
private val artists: MutableLiveData<List<Artist>> = MutableLiveData(listOf())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves all available Artists in a LiveData
|
* Retrieves all available Artists in a LiveData
|
||||||
*/
|
*/
|
||||||
fun getItems(refresh: Boolean, swipe: SwipeRefreshLayout): LiveData<List<Artist>> {
|
fun getItems(refresh: Boolean, swipe: SwipeRefreshLayout): LiveData<List<Artist>> {
|
||||||
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
|
return artists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,20 +16,24 @@ import android.widget.ImageView
|
||||||
import android.widget.PopupMenu
|
import android.widget.PopupMenu
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.moire.ultrasonic.R
|
import org.moire.ultrasonic.R
|
||||||
import org.moire.ultrasonic.data.ActiveServerProvider
|
import org.moire.ultrasonic.data.ActiveServerProvider
|
||||||
|
import org.moire.ultrasonic.domain.GenericEntry
|
||||||
import org.moire.ultrasonic.domain.MusicFolder
|
import org.moire.ultrasonic.domain.MusicFolder
|
||||||
import org.moire.ultrasonic.view.SelectMusicFolderView
|
import org.moire.ultrasonic.view.SelectMusicFolderView
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* An abstract Adapter, which can be extended to display a List of <T> in a RecyclerView
|
* An abstract Adapter, which can be extended to display a List of <T> in a RecyclerView
|
||||||
*/
|
*/
|
||||||
abstract class GenericRowAdapter<T>(
|
abstract class GenericRowAdapter<T : GenericEntry>(
|
||||||
val onItemClick: (T) -> Unit,
|
val onItemClick: (T) -> Unit,
|
||||||
val onContextMenuClick: (MenuItem, T) -> Boolean,
|
val onContextMenuClick: (MenuItem, T) -> Boolean,
|
||||||
private val onMusicFolderUpdate: (String?) -> Unit
|
private val onMusicFolderUpdate: (String?) -> Unit
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
) : ListAdapter<T, RecyclerView.ViewHolder>(GenericDiffCallback()) {
|
||||||
|
|
||||||
open var itemList: List<T> = listOf()
|
open var itemList: List<T> = listOf()
|
||||||
protected abstract val layout: Int
|
protected abstract val layout: Int
|
||||||
protected abstract val contextMenuLayout: Int
|
protected abstract val contextMenuLayout: Int
|
||||||
|
@ -40,11 +44,12 @@ abstract class GenericRowAdapter<T>(
|
||||||
var selectedFolder: String? = null
|
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<T>) {
|
open fun setData(data: List<T>) {
|
||||||
|
submitList(data)
|
||||||
itemList = data
|
itemList = data
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -136,5 +141,17 @@ abstract class GenericRowAdapter<T>(
|
||||||
companion object {
|
companion object {
|
||||||
internal const val TYPE_HEADER = 0
|
internal const val TYPE_HEADER = 0
|
||||||
internal const val TYPE_ITEM = 1
|
internal const val TYPE_ITEM = 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the differences between data sets
|
||||||
|
*/
|
||||||
|
class GenericDiffCallback<T : GenericEntry> : DiffUtil.ItemCallback<T>() {
|
||||||
|
override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
|
||||||
|
return oldItem == newItem
|
||||||
|
}
|
||||||
|
override fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
|
||||||
|
return oldItem.id == newItem.id
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue