Sort Favourites by time
This commit is contained in:
parent
3c21c0baec
commit
f1947f3b88
|
@ -8,11 +8,13 @@ import android.view.Gravity
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import audio.funkwhale.ffa.R
|
||||
import audio.funkwhale.ffa.databinding.RowTrackBinding
|
||||
import audio.funkwhale.ffa.fragments.FFAAdapter
|
||||
import audio.funkwhale.ffa.model.Favorite
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
|
@ -27,7 +29,7 @@ class FavoritesAdapter(
|
|||
private val context: Context?,
|
||||
private val favoriteListener: FavoriteListener,
|
||||
val fromQueue: Boolean = false,
|
||||
) : FFAAdapter<Track, FavoritesAdapter.ViewHolder>() {
|
||||
) : FFAAdapter<Favorite, FavoritesAdapter.ViewHolder>() {
|
||||
|
||||
init {
|
||||
this.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
|
||||
|
@ -47,7 +49,7 @@ class FavoritesAdapter(
|
|||
override fun applyFilter() {
|
||||
data.clear()
|
||||
getUnfilteredData().map {
|
||||
if (it.matchesFilter(filter)) {
|
||||
if (it.track.matchesFilter(filter)) {
|
||||
data.add(it)
|
||||
}
|
||||
}
|
||||
|
@ -65,45 +67,43 @@ class FavoritesAdapter(
|
|||
@SuppressLint("NewApi")
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val favorite = data[position]
|
||||
val track = favorite.track
|
||||
|
||||
CoverArt.withContext(layoutInflater.context, maybeNormalizeUrl(favorite.cover()))
|
||||
CoverArt.withContext(layoutInflater.context, maybeNormalizeUrl(track.cover()))
|
||||
.fit()
|
||||
.placeholder(R.drawable.cover)
|
||||
.transform(RoundedCornersTransformation(16, 0))
|
||||
.into(holder.cover)
|
||||
|
||||
holder.title.text = favorite.title
|
||||
holder.artist.text = favorite.artist.name
|
||||
holder.title.text = track.title
|
||||
holder.artist.text = track.artist.name
|
||||
|
||||
context?.let {
|
||||
holder.itemView.background = context.getDrawable(R.drawable.ripple)
|
||||
holder.itemView.background = AppCompatResources.getDrawable(context, R.drawable.ripple)
|
||||
}
|
||||
|
||||
if (favorite.id == currentTrack?.id) {
|
||||
if (track.id == currentTrack?.id) {
|
||||
context?.let {
|
||||
holder.itemView.background = context.getDrawable(R.drawable.current)
|
||||
holder.itemView.background = AppCompatResources.getDrawable(context, R.drawable.current)
|
||||
}
|
||||
}
|
||||
|
||||
context?.let {
|
||||
when (favorite.favorite) {
|
||||
true -> holder.favorite.setColorFilter(context.getColor(R.color.colorFavorite))
|
||||
false -> holder.favorite.setColorFilter(context.getColor(R.color.colorSelected))
|
||||
}
|
||||
holder.favorite.setColorFilter(context.getColor(R.color.colorFavorite))
|
||||
|
||||
when (favorite.cached || favorite.downloaded) {
|
||||
when (track.cached || track.downloaded) {
|
||||
true -> holder.title.setCompoundDrawablesWithIntrinsicBounds(R.drawable.downloaded, 0, 0, 0)
|
||||
false -> holder.title.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
if (favorite.cached && !favorite.downloaded) {
|
||||
if (track.cached && !track.downloaded) {
|
||||
holder.title.compoundDrawables.forEach {
|
||||
it?.colorFilter =
|
||||
PorterDuffColorFilter(context.getColor(R.color.cached), PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
}
|
||||
|
||||
if (favorite.downloaded) {
|
||||
if (track.downloaded) {
|
||||
holder.title.compoundDrawables.forEach {
|
||||
it?.colorFilter =
|
||||
PorterDuffColorFilter(context.getColor(R.color.downloaded), PorterDuff.Mode.SRC_IN)
|
||||
|
@ -111,8 +111,7 @@ class FavoritesAdapter(
|
|||
}
|
||||
|
||||
holder.favorite.setOnClickListener {
|
||||
favoriteListener.onToggleFavorite(favorite.id, !favorite.favorite)
|
||||
|
||||
favoriteListener.onToggleFavorite(track.id, !track.favorite)
|
||||
data.remove(favorite)
|
||||
notifyItemRemoved(holder.bindingAdapterPosition)
|
||||
}
|
||||
|
@ -125,10 +124,10 @@ class FavoritesAdapter(
|
|||
|
||||
setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.track_add_to_queue -> CommandBus.send(Command.AddToQueue(listOf(favorite)))
|
||||
R.id.track_play_next -> CommandBus.send(Command.PlayNext(favorite))
|
||||
R.id.track_pin -> CommandBus.send(Command.PinTrack(favorite))
|
||||
R.id.queue_remove -> CommandBus.send(Command.RemoveFromQueue(favorite))
|
||||
R.id.track_add_to_queue -> CommandBus.send(Command.AddToQueue(listOf(track)))
|
||||
R.id.track_play_next -> CommandBus.send(Command.PlayNext(track))
|
||||
R.id.track_pin -> CommandBus.send(Command.PinTrack(track))
|
||||
R.id.queue_remove -> CommandBus.send(Command.RemoveFromQueue(track))
|
||||
}
|
||||
|
||||
true
|
||||
|
@ -169,10 +168,13 @@ class FavoritesAdapter(
|
|||
when (fromQueue) {
|
||||
true -> CommandBus.send(Command.PlayTrack(layoutPosition))
|
||||
false -> {
|
||||
data.subList(layoutPosition, data.size).plus(data.subList(0, layoutPosition)).apply {
|
||||
CommandBus.send(Command.ReplaceQueue(this))
|
||||
context.toast("All tracks were added to your queue")
|
||||
}
|
||||
data
|
||||
.subList(layoutPosition, data.size).plus(data.subList(0, layoutPosition))
|
||||
.map { it.track }
|
||||
.apply {
|
||||
CommandBus.send(Command.ReplaceQueue(this))
|
||||
context.toast("All tracks were added to your queue")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ abstract class FFAAdapter<D, VH : RecyclerView.ViewHolder> : RecyclerView.Adapte
|
|||
abstract override fun getItemId(position: Int): Long
|
||||
}
|
||||
|
||||
abstract class FFAFragment<D : Any, A : FFAAdapter<D, *>>() : Fragment() {
|
||||
abstract class FFAFragment<D : Any, A : FFAAdapter<D, *>> : Fragment() {
|
||||
companion object {
|
||||
const val OFFSCREEN_PAGES = 20
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import audio.funkwhale.ffa.adapters.FavoriteListener
|
||||
import audio.funkwhale.ffa.adapters.FavoritesAdapter
|
||||
import audio.funkwhale.ffa.databinding.FragmentFavoritesBinding
|
||||
import audio.funkwhale.ffa.model.Favorite
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.repositories.FavoritesRepository
|
||||
import audio.funkwhale.ffa.repositories.TracksRepository
|
||||
|
@ -31,7 +32,7 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.withContext
|
||||
import org.koin.java.KoinJavaComponent.inject
|
||||
|
||||
class FavoritesFragment : FFAFragment<Track, FavoritesAdapter>() {
|
||||
class FavoritesFragment : FFAFragment<Favorite, FavoritesAdapter>() {
|
||||
|
||||
private val exoDownloadManager: DownloadManager by inject(DownloadManager::class.java)
|
||||
|
||||
|
@ -63,7 +64,7 @@ class FavoritesFragment : FFAFragment<Track, FavoritesAdapter>() {
|
|||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { }
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
adapter.filter = s.toString()
|
||||
|
@ -93,7 +94,7 @@ class FavoritesFragment : FFAFragment<Track, FavoritesAdapter>() {
|
|||
}
|
||||
|
||||
binding.play.setOnClickListener {
|
||||
CommandBus.send(Command.ReplaceQueue(adapter.data.shuffled()))
|
||||
CommandBus.send(Command.ReplaceQueue(adapter.data.map { it.track }.shuffled()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,7 +123,7 @@ class FavoritesFragment : FFAFragment<Track, FavoritesAdapter>() {
|
|||
|
||||
withContext(Main) {
|
||||
val data = adapter.data.map {
|
||||
it.downloaded = downloaded.contains(it.id)
|
||||
it.track.downloaded = downloaded.contains(it.id)
|
||||
it
|
||||
}.toMutableList()
|
||||
|
||||
|
@ -138,7 +139,7 @@ class FavoritesFragment : FFAFragment<Track, FavoritesAdapter>() {
|
|||
adapter.data.withIndex().associate { it.value to it.index }.filter { it.key.id == info.id }
|
||||
.toList().getOrNull(0)?.let { match ->
|
||||
withContext(Main) {
|
||||
adapter.data[match.second].downloaded = true
|
||||
adapter.data[match.second].track.downloaded = true
|
||||
adapter.notifyItemChanged(match.second)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ sealed class CacheItem<D : Any>(val data: List<D>)
|
|||
class ArtistsCache(data: List<Artist>) : CacheItem<Artist>(data)
|
||||
class AlbumsCache(data: List<Album>) : CacheItem<Album>(data)
|
||||
class TracksCache(data: List<Track>) : CacheItem<Track>(data)
|
||||
class FavoritesCache(data: List<Favorite>) : CacheItem<Favorite>(data)
|
||||
class PlaylistsCache(data: List<Playlist>) : CacheItem<Playlist>(data)
|
||||
class PlaylistTracksCache(data: List<PlaylistTrack>) : CacheItem<PlaylistTrack>(data)
|
||||
class RadiosCache(data: List<Radio>) : CacheItem<Radio>(data)
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package audio.funkwhale.ffa.model
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class Favorite(
|
||||
val id: Int = 0,
|
||||
val track: Track
|
||||
) : Parcelable
|
|
@ -0,0 +1,9 @@
|
|||
package audio.funkwhale.ffa.model
|
||||
|
||||
data class FavoritesResponse(
|
||||
override val count: Int,
|
||||
override val next: String?,
|
||||
val results: List<Favorite>
|
||||
) : FFAResponse<Favorite>() {
|
||||
override fun getData() = results
|
||||
}
|
|
@ -2,11 +2,11 @@ package audio.funkwhale.ffa.repositories
|
|||
|
||||
import android.content.Context
|
||||
import audio.funkwhale.ffa.model.FFAResponse
|
||||
import audio.funkwhale.ffa.model.Favorite
|
||||
import audio.funkwhale.ffa.model.FavoritesResponse
|
||||
import audio.funkwhale.ffa.model.FavoritedCache
|
||||
import audio.funkwhale.ffa.model.FavoritedResponse
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.model.TracksCache
|
||||
import audio.funkwhale.ffa.model.TracksResponse
|
||||
import audio.funkwhale.ffa.model.FavoritesCache
|
||||
import audio.funkwhale.ffa.utils.FFACache
|
||||
import audio.funkwhale.ffa.utils.OAuth
|
||||
import audio.funkwhale.ffa.utils.Settings
|
||||
|
@ -28,7 +28,7 @@ import kotlinx.coroutines.runBlocking
|
|||
import org.koin.core.qualifier.named
|
||||
import org.koin.java.KoinJavaComponent.inject
|
||||
|
||||
class FavoritesRepository(override val context: Context?) : Repository<Track, TracksCache>() {
|
||||
class FavoritesRepository(override val context: Context?) : Repository<Favorite, FavoritesCache>() {
|
||||
|
||||
private val exoDownloadManager: DownloadManager by inject(DownloadManager::class.java)
|
||||
private val exoCache: Cache by inject(Cache::class.java, named("exoCache"))
|
||||
|
@ -36,34 +36,34 @@ class FavoritesRepository(override val context: Context?) : Repository<Track, Tr
|
|||
|
||||
override val cacheId = "favorites.v2"
|
||||
|
||||
override val upstream = HttpUpstream<Track, FFAResponse<Track>>(
|
||||
override val upstream = HttpUpstream<Favorite, FFAResponse<Favorite>>(
|
||||
context!!,
|
||||
HttpUpstream.Behavior.AtOnce,
|
||||
"/api/v1/tracks/?favorites=true&playable=true&ordering=title",
|
||||
object : TypeToken<TracksResponse>() {}.type,
|
||||
"/api/v1/favorites/tracks/?scope=all&ordering=-creation_date",
|
||||
object : TypeToken<FavoritesResponse>() {}.type,
|
||||
oAuth
|
||||
)
|
||||
|
||||
override fun cache(data: List<Track>) = TracksCache(data)
|
||||
override fun cache(data: List<Favorite>) = FavoritesCache(data)
|
||||
override fun uncache(json: String) =
|
||||
gsonDeserializerOf(TracksCache::class.java).deserialize(json.reader())
|
||||
gsonDeserializerOf(FavoritesCache::class.java).deserialize(json.reader())
|
||||
|
||||
private val favoritedRepository = FavoritedRepository(context!!)
|
||||
|
||||
override fun onDataFetched(data: List<Track>): List<Track> = runBlocking {
|
||||
override fun onDataFetched(data: List<Favorite>): List<Favorite> = runBlocking {
|
||||
val downloaded = TracksRepository.getDownloadedIds(exoDownloadManager) ?: listOf()
|
||||
|
||||
data.map { track ->
|
||||
track.favorite = true
|
||||
track.downloaded = downloaded.contains(track.id)
|
||||
data.map { favorite ->
|
||||
favorite.track.favorite = true
|
||||
favorite.track.downloaded = downloaded.contains(favorite.track.id)
|
||||
|
||||
track.bestUpload()?.let { upload ->
|
||||
favorite.track.bestUpload()?.let { upload ->
|
||||
maybeNormalizeUrl(upload.listen_url)?.let { url ->
|
||||
track.cached = exoCache.isCached(url, 0, upload.duration * 1000L)
|
||||
favorite.track.cached = exoCache.isCached(url, 0, upload.duration * 1000L)
|
||||
}
|
||||
}
|
||||
|
||||
track
|
||||
favorite
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue