171 lines
6.6 KiB
Kotlin
171 lines
6.6 KiB
Kotlin
package org.mosad.teapod.util.adapter
|
|
|
|
import android.graphics.Color
|
|
import android.graphics.drawable.ColorDrawable
|
|
import android.graphics.drawable.Drawable
|
|
import android.view.LayoutInflater
|
|
import android.view.View
|
|
import android.view.ViewGroup
|
|
import androidx.core.content.ContextCompat
|
|
import androidx.recyclerview.widget.RecyclerView
|
|
import com.bumptech.glide.Glide
|
|
import com.bumptech.glide.request.RequestOptions
|
|
import jp.wasabeef.glide.transformations.RoundedCornersTransformation
|
|
import org.mosad.teapod.R
|
|
import org.mosad.teapod.databinding.ItemEpisodeBinding
|
|
import org.mosad.teapod.databinding.ItemEpisodePlayerBinding
|
|
import org.mosad.teapod.parser.crunchyroll.Episode
|
|
import org.mosad.teapod.parser.crunchyroll.PlayheadObject
|
|
import org.mosad.teapod.parser.crunchyroll.PlayheadsMap
|
|
import org.mosad.teapod.util.tmdb.TMDBTVEpisode
|
|
|
|
class EpisodeItemAdapter(
|
|
private val episodes: List<Episode>,
|
|
private val tmdbEpisodes: List<TMDBTVEpisode>?,
|
|
private val playheads: PlayheadsMap,
|
|
private val onClickListener: OnClickListener,
|
|
private val viewType: ViewType
|
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|
|
|
var currentSelected: Int = -1 // -1, since position should never be < 0
|
|
|
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
|
return when (viewType) {
|
|
ViewType.PLAYER.ordinal -> {
|
|
PlayerEpisodeViewHolder((ItemEpisodePlayerBinding.inflate(LayoutInflater.from(parent.context), parent, false)))
|
|
}
|
|
else -> {
|
|
// media fragment episode list is default
|
|
EpisodeViewHolder(ItemEpisodeBinding.inflate(LayoutInflater.from(parent.context), parent, false))
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
|
val episode = episodes[position]
|
|
val playhead = playheads[episode.id]
|
|
val tmdbEpisode = tmdbEpisodes?.getOrNull(position)
|
|
|
|
when (holder.itemViewType) {
|
|
ViewType.MEDIA_FRAGMENT.ordinal -> {
|
|
(holder as EpisodeViewHolder).bind(episode, playhead, tmdbEpisode)
|
|
}
|
|
ViewType.PLAYER.ordinal -> {
|
|
(holder as PlayerEpisodeViewHolder).bind(episode, currentSelected)
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun getItemViewType(position: Int): Int {
|
|
return when (viewType) {
|
|
ViewType.MEDIA_FRAGMENT -> ViewType.MEDIA_FRAGMENT.ordinal
|
|
ViewType.PLAYER -> ViewType.PLAYER.ordinal
|
|
}
|
|
}
|
|
|
|
override fun getItemCount(): Int {
|
|
return episodes.size
|
|
}
|
|
|
|
inner class EpisodeViewHolder(val binding: ItemEpisodeBinding) :
|
|
RecyclerView.ViewHolder(binding.root) {
|
|
|
|
fun bind(episode: Episode, playhead: PlayheadObject?, tmdbEpisode: TMDBTVEpisode?) {
|
|
val context = binding.root.context
|
|
|
|
val titleText = if (episode.episodeNumber != null) {
|
|
// for tv shows add ep prefix and episode number
|
|
if (episode.isDubbed) {
|
|
context.getString(R.string.component_episode_title, episode.episode, episode.title)
|
|
} else {
|
|
context.getString(R.string.component_episode_title_sub, episode.episode, episode.title)
|
|
}
|
|
} else {
|
|
episode.title
|
|
}
|
|
|
|
binding.textEpisodeTitle.text = titleText
|
|
binding.textEpisodeDesc.text = episode.description.ifEmpty {
|
|
tmdbEpisode?.overview ?: ""
|
|
}
|
|
|
|
if (episode.images.thumbnail[0][0].source.isNotEmpty()) {
|
|
Glide.with(context).load(episode.images.thumbnail[0][0].source)
|
|
.apply(RequestOptions.placeholderOf(ColorDrawable(Color.DKGRAY)))
|
|
.apply(RequestOptions.bitmapTransform(RoundedCornersTransformation(10, 0)))
|
|
.into(binding.imageEpisode)
|
|
}
|
|
|
|
// add watched progress
|
|
val playheadProgress = playhead?.playhead?.let {
|
|
((it.toFloat() / (episode.durationMs / 1000)) * 100).toInt()
|
|
} ?: 0
|
|
binding.progressPlayhead.setProgressCompat(playheadProgress, false)
|
|
binding.progressPlayhead.visibility = if (playheadProgress <= 0)
|
|
View.GONE else View.VISIBLE
|
|
|
|
// add watched icon to episode, if the episode id is present in playheads and fullyWatched
|
|
val watchedImage: Drawable? = if (playhead?.fullyWatched == true) {
|
|
ContextCompat.getDrawable(context, R.drawable.ic_baseline_check_circle_24)
|
|
} else {
|
|
null
|
|
}
|
|
binding.imageWatched.setImageDrawable(watchedImage)
|
|
|
|
binding.imageEpisode.setOnClickListener {
|
|
onClickListener.onClick(episode)
|
|
}
|
|
}
|
|
}
|
|
|
|
inner class PlayerEpisodeViewHolder(val binding: ItemEpisodePlayerBinding) :
|
|
RecyclerView.ViewHolder(binding.root) {
|
|
|
|
// -1, since position should never be < 0
|
|
fun bind(episode: Episode, currentSelected: Int) {
|
|
val context = binding.root.context
|
|
|
|
val titleText = if (episode.episodeNumber != null) {
|
|
// for tv shows add ep prefix and episode number
|
|
if (episode.isDubbed) {
|
|
context.getString(R.string.component_episode_title, episode.episode, episode.title)
|
|
} else {
|
|
context.getString(R.string.component_episode_title_sub, episode.episode, episode.title)
|
|
}
|
|
} else {
|
|
episode.title
|
|
}
|
|
|
|
binding.textEpisodeTitle2.text = titleText
|
|
binding.textEpisodeDesc2.text = episode.description.ifEmpty { "" }
|
|
|
|
if (episode.images.thumbnail[0][0].source.isNotEmpty()) {
|
|
Glide.with(context).load(episode.images.thumbnail[0][0].source)
|
|
.apply(RequestOptions.bitmapTransform(RoundedCornersTransformation(10, 0)))
|
|
.into(binding.imageEpisode)
|
|
}
|
|
|
|
// hide the play icon, if it's the current episode
|
|
binding.imageEpisodePlay.visibility = if (currentSelected == bindingAdapterPosition) {
|
|
View.GONE
|
|
} else {
|
|
View.VISIBLE
|
|
}
|
|
|
|
if (currentSelected != bindingAdapterPosition) {
|
|
binding.imageEpisode.setOnClickListener {
|
|
onClickListener.onClick(episode)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class OnClickListener(val clickListener: (episode: Episode) -> Unit) {
|
|
fun onClick(episode: Episode) = clickListener(episode)
|
|
}
|
|
|
|
enum class ViewType {
|
|
MEDIA_FRAGMENT,
|
|
PLAYER
|
|
}
|
|
} |