2021-07-12 10:14:26 +02:00
|
|
|
package audio.funkwhale.ffa.adapters
|
2019-08-19 16:50:33 +02:00
|
|
|
|
|
|
|
import android.annotation.SuppressLint
|
|
|
|
import android.content.Context
|
2021-07-16 10:03:52 +02:00
|
|
|
import android.graphics.Color
|
|
|
|
import android.graphics.PorterDuff
|
|
|
|
import android.graphics.PorterDuffColorFilter
|
2019-08-19 16:50:33 +02:00
|
|
|
import android.graphics.drawable.ColorDrawable
|
2021-07-16 10:03:52 +02:00
|
|
|
import android.view.Gravity
|
|
|
|
import android.view.LayoutInflater
|
|
|
|
import android.view.MotionEvent
|
|
|
|
import android.view.View
|
|
|
|
import android.view.ViewGroup
|
2019-08-19 16:50:33 +02:00
|
|
|
import androidx.appcompat.widget.PopupMenu
|
2020-09-02 12:04:42 +02:00
|
|
|
import androidx.core.content.ContextCompat
|
2019-08-19 16:50:33 +02:00
|
|
|
import androidx.recyclerview.widget.ItemTouchHelper
|
|
|
|
import androidx.recyclerview.widget.RecyclerView
|
2021-07-12 10:14:26 +02:00
|
|
|
import audio.funkwhale.ffa.R
|
2021-07-16 10:03:52 +02:00
|
|
|
import audio.funkwhale.ffa.databinding.RowTrackBinding
|
|
|
|
import audio.funkwhale.ffa.fragments.FFAAdapter
|
2021-09-09 09:56:15 +02:00
|
|
|
import audio.funkwhale.ffa.model.Track
|
2021-07-16 10:03:52 +02:00
|
|
|
import audio.funkwhale.ffa.utils.Command
|
|
|
|
import audio.funkwhale.ffa.utils.CommandBus
|
|
|
|
import audio.funkwhale.ffa.utils.maybeLoad
|
|
|
|
import audio.funkwhale.ffa.utils.maybeNormalizeUrl
|
|
|
|
import audio.funkwhale.ffa.utils.toast
|
2019-08-19 16:50:33 +02:00
|
|
|
import com.squareup.picasso.Picasso
|
|
|
|
import jp.wasabeef.picasso.transformations.RoundedCornersTransformation
|
2021-07-16 10:03:52 +02:00
|
|
|
import java.util.Collections
|
|
|
|
|
|
|
|
class TracksAdapter(
|
|
|
|
private val layoutInflater: LayoutInflater,
|
|
|
|
private val context: Context?,
|
2021-09-10 13:36:28 +02:00
|
|
|
private val favoriteListener: FavoriteListener,
|
2021-07-16 10:03:52 +02:00
|
|
|
val fromQueue: Boolean = false
|
|
|
|
) : FFAAdapter<Track, TracksAdapter.ViewHolder>() {
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2021-09-10 09:44:36 +02:00
|
|
|
init {
|
|
|
|
this.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
|
|
|
|
}
|
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
private lateinit var binding: RowTrackBinding
|
2019-08-19 16:50:33 +02:00
|
|
|
private lateinit var touchHelper: ItemTouchHelper
|
|
|
|
|
|
|
|
var currentTrack: Track? = null
|
|
|
|
|
2020-07-11 18:15:40 +02:00
|
|
|
override fun getItemId(position: Int): Long = data[position].id.toLong()
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2020-07-11 18:15:40 +02:00
|
|
|
override fun getItemCount() = data.size
|
2019-08-19 16:50:33 +02:00
|
|
|
|
|
|
|
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
|
|
|
|
super.onAttachedToRecyclerView(recyclerView)
|
|
|
|
|
|
|
|
if (fromQueue) {
|
|
|
|
touchHelper = ItemTouchHelper(TouchHelperCallback()).also {
|
|
|
|
it.attachToRecyclerView(recyclerView)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
binding = RowTrackBinding.inflate(layoutInflater, parent, false)
|
|
|
|
|
|
|
|
return ViewHolder(binding, context).also {
|
|
|
|
binding.root.setOnClickListener(it)
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressLint("NewApi")
|
|
|
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
|
|
|
val track = data[position]
|
|
|
|
|
|
|
|
Picasso.get()
|
2020-08-08 14:51:39 +02:00
|
|
|
.maybeLoad(maybeNormalizeUrl(track.album?.cover()))
|
2019-08-19 16:50:33 +02:00
|
|
|
.fit()
|
2020-05-29 21:40:01 +02:00
|
|
|
.transform(RoundedCornersTransformation(8, 0))
|
2019-08-19 16:50:33 +02:00
|
|
|
.into(holder.cover)
|
|
|
|
|
|
|
|
holder.title.text = track.title
|
|
|
|
holder.artist.text = track.artist.name
|
|
|
|
|
2020-06-26 19:42:10 +02:00
|
|
|
context?.let {
|
2020-09-02 12:04:42 +02:00
|
|
|
holder.itemView.background = ContextCompat.getDrawable(context, R.drawable.ripple)
|
2020-06-26 19:42:10 +02:00
|
|
|
}
|
2019-08-19 16:50:33 +02:00
|
|
|
|
|
|
|
if (track == currentTrack || track.current) {
|
2020-06-26 19:42:10 +02:00
|
|
|
context?.let {
|
2020-09-02 12:04:42 +02:00
|
|
|
holder.itemView.background = ContextCompat.getDrawable(context, R.drawable.current)
|
2020-06-26 19:42:10 +02:00
|
|
|
}
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
context?.let {
|
|
|
|
when (track.favorite) {
|
2019-11-01 13:42:15 +01:00
|
|
|
true -> holder.favorite.setColorFilter(context.getColor(R.color.colorFavorite))
|
|
|
|
false -> holder.favorite.setColorFilter(context.getColor(R.color.colorSelected))
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
holder.favorite.setOnClickListener {
|
2021-09-10 13:36:28 +02:00
|
|
|
favoriteListener.let {
|
2019-08-19 16:50:33 +02:00
|
|
|
favoriteListener.onToggleFavorite(track.id, !track.favorite)
|
|
|
|
|
2019-11-21 22:13:59 +01:00
|
|
|
data[position].favorite = !track.favorite
|
|
|
|
|
2019-08-19 16:50:33 +02:00
|
|
|
notifyItemChanged(position)
|
|
|
|
}
|
|
|
|
}
|
2020-06-13 17:44:50 +02:00
|
|
|
|
2020-06-20 15:42:10 +02:00
|
|
|
when (track.cached || track.downloaded) {
|
2020-06-13 17:44:50 +02:00
|
|
|
true -> holder.title.setCompoundDrawablesWithIntrinsicBounds(R.drawable.downloaded, 0, 0, 0)
|
|
|
|
false -> holder.title.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0)
|
|
|
|
}
|
2020-06-20 15:42:10 +02:00
|
|
|
|
|
|
|
if (track.cached && !track.downloaded) {
|
|
|
|
holder.title.compoundDrawables.forEach {
|
2021-07-16 10:03:52 +02:00
|
|
|
it?.colorFilter =
|
|
|
|
PorterDuffColorFilter(context.getColor(R.color.cached), PorterDuff.Mode.SRC_IN)
|
2020-06-20 15:42:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (track.downloaded) {
|
|
|
|
holder.title.compoundDrawables.forEach {
|
2021-07-16 10:03:52 +02:00
|
|
|
it?.colorFilter =
|
|
|
|
PorterDuffColorFilter(context.getColor(R.color.downloaded), PorterDuff.Mode.SRC_IN)
|
2020-06-20 15:42:10 +02:00
|
|
|
}
|
|
|
|
}
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
holder.actions.setOnClickListener {
|
|
|
|
context?.let { context ->
|
|
|
|
PopupMenu(context, holder.actions, Gravity.START, R.attr.actionOverflowMenuStyle, 0).apply {
|
|
|
|
inflate(if (fromQueue) R.menu.row_queue else R.menu.row_track)
|
|
|
|
|
|
|
|
setOnMenuItemClickListener {
|
|
|
|
when (it.itemId) {
|
|
|
|
R.id.track_add_to_queue -> CommandBus.send(Command.AddToQueue(listOf(track)))
|
|
|
|
R.id.track_play_next -> CommandBus.send(Command.PlayNext(track))
|
2020-06-10 16:25:20 +02:00
|
|
|
R.id.track_pin -> CommandBus.send(Command.PinTrack(track))
|
2020-09-26 17:58:06 +02:00
|
|
|
R.id.track_add_to_playlist -> CommandBus.send(Command.AddToPlaylist(listOf(track)))
|
2019-08-19 16:50:33 +02:00
|
|
|
R.id.queue_remove -> CommandBus.send(Command.RemoveFromQueue(track))
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
show()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fromQueue) {
|
|
|
|
holder.handle.visibility = View.VISIBLE
|
|
|
|
|
|
|
|
holder.handle.setOnTouchListener { _, event ->
|
|
|
|
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
|
|
|
touchHelper.startDrag(holder)
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fun onItemMove(oldPosition: Int, newPosition: Int) {
|
|
|
|
if (oldPosition < newPosition) {
|
2019-10-21 11:51:32 +02:00
|
|
|
for (i in oldPosition.until(newPosition)) {
|
2019-08-19 16:50:33 +02:00
|
|
|
Collections.swap(data, i, i + 1)
|
|
|
|
}
|
|
|
|
} else {
|
2020-09-05 00:56:39 +02:00
|
|
|
for (i in oldPosition.downTo(newPosition + 1)) {
|
2019-08-19 16:50:33 +02:00
|
|
|
Collections.swap(data, i, i - 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
notifyItemMoved(oldPosition, newPosition)
|
|
|
|
}
|
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
inner class ViewHolder(binding: RowTrackBinding, val context: Context?) :
|
|
|
|
RecyclerView.ViewHolder(binding.root),
|
|
|
|
View.OnClickListener {
|
|
|
|
|
|
|
|
val handle = binding.handle
|
|
|
|
val cover = binding.cover
|
|
|
|
val title = binding.title
|
|
|
|
val artist = binding.artist
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
val favorite = binding.favorite
|
|
|
|
val actions = binding.actions
|
2019-08-19 16:50:33 +02:00
|
|
|
|
|
|
|
override fun onClick(view: View?) {
|
|
|
|
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")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inner class TouchHelperCallback : ItemTouchHelper.Callback() {
|
2020-06-24 19:45:16 +02:00
|
|
|
var from = -1
|
|
|
|
var to = -1
|
|
|
|
|
2019-08-19 16:50:33 +02:00
|
|
|
override fun isLongPressDragEnabled() = false
|
|
|
|
|
|
|
|
override fun isItemViewSwipeEnabled() = false
|
|
|
|
|
|
|
|
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) =
|
|
|
|
makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0)
|
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
override fun onMove(
|
|
|
|
recyclerView: RecyclerView,
|
|
|
|
viewHolder: RecyclerView.ViewHolder,
|
|
|
|
target: RecyclerView.ViewHolder
|
|
|
|
): Boolean {
|
|
|
|
to = target.absoluteAdapterPosition
|
2020-06-24 19:45:16 +02:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
onItemMove(viewHolder.absoluteAdapterPosition, to)
|
2019-08-19 16:50:33 +02:00
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}
|
|
|
|
|
|
|
|
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
|
|
|
|
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
|
|
|
|
context?.let {
|
2020-06-24 19:45:16 +02:00
|
|
|
viewHolder?.let {
|
2021-08-27 13:28:23 +02:00
|
|
|
from = viewHolder.bindingAdapterPosition
|
2020-06-24 19:45:16 +02:00
|
|
|
viewHolder.itemView.background = ColorDrawable(context.getColor(R.color.colorSelected))
|
|
|
|
}
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
super.onSelectedChanged(viewHolder, actionState)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
2020-06-24 19:45:16 +02:00
|
|
|
if (from != -1 && to != -1) {
|
|
|
|
CommandBus.send(Command.MoveFromQueue(from, to))
|
|
|
|
|
|
|
|
from = -1
|
|
|
|
to = -1
|
|
|
|
}
|
|
|
|
|
2019-08-19 16:50:33 +02:00
|
|
|
viewHolder.itemView.background = ColorDrawable(Color.TRANSPARENT)
|
|
|
|
|
|
|
|
super.clearView(recyclerView, viewHolder)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|