From f1947f3b88c8951265acb78a3b442edbf5926355 Mon Sep 17 00:00:00 2001 From: Ryan Harg Date: Fri, 13 Jan 2023 10:33:24 +0100 Subject: [PATCH] Sort Favourites by time --- .../ffa/adapters/FavoritesAdapter.kt | 52 ++++++++++--------- .../funkwhale/ffa/fragments/FFAFragment.kt | 2 +- .../ffa/fragments/FavoritesFragment.kt | 11 ++-- .../audio/funkwhale/ffa/model/CacheItem.kt | 1 + .../audio/funkwhale/ffa/model/Favorite.kt | 10 ++++ .../funkwhale/ffa/model/FavoritesResponse.kt | 9 ++++ .../ffa/repositories/FavoritesRepository.kt | 32 ++++++------ 7 files changed, 70 insertions(+), 47 deletions(-) create mode 100644 app/src/main/java/audio/funkwhale/ffa/model/Favorite.kt create mode 100644 app/src/main/java/audio/funkwhale/ffa/model/FavoritesResponse.kt diff --git a/app/src/main/java/audio/funkwhale/ffa/adapters/FavoritesAdapter.kt b/app/src/main/java/audio/funkwhale/ffa/adapters/FavoritesAdapter.kt index 041fab1..590f929 100644 --- a/app/src/main/java/audio/funkwhale/ffa/adapters/FavoritesAdapter.kt +++ b/app/src/main/java/audio/funkwhale/ffa/adapters/FavoritesAdapter.kt @@ -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() { +) : FFAAdapter() { 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") + } } } } diff --git a/app/src/main/java/audio/funkwhale/ffa/fragments/FFAFragment.kt b/app/src/main/java/audio/funkwhale/ffa/fragments/FFAFragment.kt index 375087c..84328ff 100644 --- a/app/src/main/java/audio/funkwhale/ffa/fragments/FFAFragment.kt +++ b/app/src/main/java/audio/funkwhale/ffa/fragments/FFAFragment.kt @@ -46,7 +46,7 @@ abstract class FFAAdapter : RecyclerView.Adapte abstract override fun getItemId(position: Int): Long } -abstract class FFAFragment>() : Fragment() { +abstract class FFAFragment> : Fragment() { companion object { const val OFFSCREEN_PAGES = 20 } diff --git a/app/src/main/java/audio/funkwhale/ffa/fragments/FavoritesFragment.kt b/app/src/main/java/audio/funkwhale/ffa/fragments/FavoritesFragment.kt index 8efdda1..27e65ab 100644 --- a/app/src/main/java/audio/funkwhale/ffa/fragments/FavoritesFragment.kt +++ b/app/src/main/java/audio/funkwhale/ffa/fragments/FavoritesFragment.kt @@ -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() { +class FavoritesFragment : FFAFragment() { private val exoDownloadManager: DownloadManager by inject(DownloadManager::class.java) @@ -63,7 +64,7 @@ class FavoritesFragment : FFAFragment() { 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() { } 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() { 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() { 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) } } diff --git a/app/src/main/java/audio/funkwhale/ffa/model/CacheItem.kt b/app/src/main/java/audio/funkwhale/ffa/model/CacheItem.kt index a1296db..da7928b 100644 --- a/app/src/main/java/audio/funkwhale/ffa/model/CacheItem.kt +++ b/app/src/main/java/audio/funkwhale/ffa/model/CacheItem.kt @@ -5,6 +5,7 @@ sealed class CacheItem(val data: List) class ArtistsCache(data: List) : CacheItem(data) class AlbumsCache(data: List) : CacheItem(data) class TracksCache(data: List) : CacheItem(data) +class FavoritesCache(data: List) : CacheItem(data) class PlaylistsCache(data: List) : CacheItem(data) class PlaylistTracksCache(data: List) : CacheItem(data) class RadiosCache(data: List) : CacheItem(data) diff --git a/app/src/main/java/audio/funkwhale/ffa/model/Favorite.kt b/app/src/main/java/audio/funkwhale/ffa/model/Favorite.kt new file mode 100644 index 0000000..2b7817c --- /dev/null +++ b/app/src/main/java/audio/funkwhale/ffa/model/Favorite.kt @@ -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 diff --git a/app/src/main/java/audio/funkwhale/ffa/model/FavoritesResponse.kt b/app/src/main/java/audio/funkwhale/ffa/model/FavoritesResponse.kt new file mode 100644 index 0000000..eb1a0fb --- /dev/null +++ b/app/src/main/java/audio/funkwhale/ffa/model/FavoritesResponse.kt @@ -0,0 +1,9 @@ +package audio.funkwhale.ffa.model + +data class FavoritesResponse( + override val count: Int, + override val next: String?, + val results: List +) : FFAResponse() { + override fun getData() = results +} diff --git a/app/src/main/java/audio/funkwhale/ffa/repositories/FavoritesRepository.kt b/app/src/main/java/audio/funkwhale/ffa/repositories/FavoritesRepository.kt index a9e5765..c2377c2 100644 --- a/app/src/main/java/audio/funkwhale/ffa/repositories/FavoritesRepository.kt +++ b/app/src/main/java/audio/funkwhale/ffa/repositories/FavoritesRepository.kt @@ -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() { +class FavoritesRepository(override val context: Context?) : Repository() { 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>( + override val upstream = HttpUpstream>( context!!, HttpUpstream.Behavior.AtOnce, - "/api/v1/tracks/?favorites=true&playable=true&ordering=title", - object : TypeToken() {}.type, + "/api/v1/favorites/tracks/?scope=all&ordering=-creation_date", + object : TypeToken() {}.type, oAuth ) - override fun cache(data: List) = TracksCache(data) + override fun cache(data: List) = 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): List = runBlocking { + override fun onDataFetched(data: List): List = 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 } }