Add Episodes List to Player #18
@ -29,6 +29,7 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.mosad.teapod.R
|
import org.mosad.teapod.R
|
||||||
import org.mosad.teapod.preferences.Preferences
|
import org.mosad.teapod.preferences.Preferences
|
||||||
|
import org.mosad.teapod.ui.components.EpisodesPlayer
|
||||||
import org.mosad.teapod.util.DataTypes
|
import org.mosad.teapod.util.DataTypes
|
||||||
import org.mosad.teapod.util.Episode
|
import org.mosad.teapod.util.Episode
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -151,6 +152,7 @@ class PlayerActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state == ExoPlayer.STATE_ENDED && model.nextEpisode != null && Preferences.autoplay) {
|
if (state == ExoPlayer.STATE_ENDED && model.nextEpisode != null && Preferences.autoplay) {
|
||||||
|
// if next episode btn was clicked, skipp playNextEpisode() on STATE_ENDED
|
||||||
if (nextEpManually) {
|
if (nextEpManually) {
|
||||||
nextEpManually = false
|
nextEpManually = false
|
||||||
} else {
|
} else {
|
||||||
@ -187,6 +189,7 @@ class PlayerActivity : AppCompatActivity() {
|
|||||||
ffwd_10.setOnButtonClickListener { fastForward() }
|
ffwd_10.setOnButtonClickListener { fastForward() }
|
||||||
button_next_ep.setOnClickListener { playNextEpisode() }
|
button_next_ep.setOnClickListener { playNextEpisode() }
|
||||||
button_next_ep_c.setOnClickListener { playNextEpisode() }
|
button_next_ep_c.setOnClickListener { playNextEpisode() }
|
||||||
|
button_episodes.setOnClickListener { showEpisodesList() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initTimeUpdates() {
|
private fun initTimeUpdates() {
|
||||||
@ -314,7 +317,11 @@ class PlayerActivity : AppCompatActivity() {
|
|||||||
private fun playCurrentMedia(seekToPosition: Boolean) {
|
private fun playCurrentMedia(seekToPosition: Boolean) {
|
||||||
// update the gui
|
// update the gui
|
||||||
exo_text_title.text = if (model.media.type == DataTypes.MediaType.TVSHOW) {
|
exo_text_title.text = if (model.media.type == DataTypes.MediaType.TVSHOW) {
|
||||||
getString(R.string.component_episode_title, model.currentEpisode.number, model.currentEpisode.description)
|
getString(
|
||||||
|
R.string.component_episode_title,
|
||||||
|
model.currentEpisode.number,
|
||||||
|
model.currentEpisode.description
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
model.currentEpisode.title
|
model.currentEpisode.title
|
||||||
}
|
}
|
||||||
@ -401,6 +408,11 @@ class PlayerActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showEpisodesList() {
|
||||||
|
val rootView = window.decorView.rootView as ViewGroup
|
||||||
|
EpisodesPlayer(rootView, model)
|
||||||
|
}
|
||||||
|
|
||||||
inner class PlayerGestureListener : GestureDetector.SimpleOnGestureListener() {
|
inner class PlayerGestureListener : GestureDetector.SimpleOnGestureListener() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package org.mosad.teapod.ui.components
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import org.mosad.teapod.databinding.PlayerEpisodesBinding
|
||||||
|
import org.mosad.teapod.player.PlayerViewModel
|
||||||
|
import org.mosad.teapod.util.adapter.PlayerEpisodeItemAdapter
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO toggle play/pause on close/open
|
||||||
|
* TODO play selected episode
|
||||||
|
* TODO scroll to current episode
|
||||||
|
*/
|
||||||
|
class EpisodesPlayer(val parent: ViewGroup, private val model: PlayerViewModel) {
|
||||||
|
|
||||||
|
private val binding = PlayerEpisodesBinding.inflate(LayoutInflater.from(parent.context), parent, true)
|
||||||
|
private var adapterRecEpisodes = PlayerEpisodeItemAdapter(model.media.episodes)
|
||||||
|
|
||||||
|
init {
|
||||||
|
binding.recyclerEpisodesPlayer.adapter = adapterRecEpisodes
|
||||||
|
|
||||||
|
initActions()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initActions() {
|
||||||
|
binding.buttonCloseEpisodesList.setOnClickListener {
|
||||||
|
parent.removeView(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
adapterRecEpisodes.onImageClick = { _, position ->
|
||||||
|
println(model.media.episodes[position])
|
||||||
|
//playEpisode(media.episodes[position])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package org.mosad.teapod.util.adapter
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
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.ItemEpisodePlayerBinding
|
||||||
|
import org.mosad.teapod.util.Episode
|
||||||
|
|
||||||
|
class PlayerEpisodeItemAdapter(private val episodes: List<Episode>) : RecyclerView.Adapter<PlayerEpisodeItemAdapter.EpisodeViewHolder>() {
|
||||||
|
|
||||||
|
var onImageClick: ((String, Int) -> Unit)? = null
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EpisodeViewHolder {
|
||||||
|
return EpisodeViewHolder(ItemEpisodePlayerBinding.inflate(LayoutInflater.from(parent.context), parent, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: EpisodeViewHolder, position: Int) {
|
||||||
|
val context = holder.binding.root.context
|
||||||
|
val ep = episodes[position]
|
||||||
|
|
||||||
|
val titleText = if (ep.priStreamUrl.isEmpty() && ep.secStreamOmU) {
|
||||||
|
context.getString(R.string.component_episode_title_sub, ep.number, ep.description)
|
||||||
|
} else {
|
||||||
|
context.getString(R.string.component_episode_title, ep.number, ep.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.binding.textEpisodeTitle2.text = titleText
|
||||||
|
holder.binding.textEpisodeDesc2.text = ep.shortDesc
|
||||||
|
|
||||||
|
if (episodes[position].posterUrl.isNotEmpty()) {
|
||||||
|
Glide.with(context).load(ep.posterUrl)
|
||||||
|
.apply(RequestOptions.bitmapTransform(RoundedCornersTransformation(10, 0)))
|
||||||
|
.into(holder.binding.imageEpisode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
return episodes.size
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class EpisodeViewHolder(val binding: ItemEpisodePlayerBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
init {
|
||||||
|
binding.imageEpisode.setOnClickListener {
|
||||||
|
onImageClick?.invoke(episodes[adapterPosition].title, adapterPosition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
50
app/src/main/res/layout/item_episode_player.xml
Normal file
50
app/src/main/res/layout/item_episode_player.xml
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="7dp" >
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
|
android:id="@+id/image_episode"
|
||||||
|
android:layout_width="192dp"
|
||||||
|
android:layout_height="108dp"
|
||||||
|
android:contentDescription="@string/component_poster_desc"
|
||||||
|
app:shapeAppearance="@style/ShapeAppearance.Teapod.RoundedPoster"
|
||||||
|
app:srcCompat="@color/md_disabled_text_dark_theme" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/image_episode_play"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:background="@drawable/bg_circle__black_transparent_24dp"
|
||||||
|
android:contentDescription="@string/button_play"
|
||||||
|
app:srcCompat="@drawable/ic_baseline_play_arrow_24"
|
||||||
|
app:tint="#FFFFFF" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_episode_title2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="7dp"
|
||||||
|
android:text="@string/component_episode_title"
|
||||||
|
android:textColor="@color/textPrimaryDark"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_episode_desc2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:text="@string/text_overview_ex"
|
||||||
|
android:textColor="@color/textPrimaryDark"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
43
app/src/main/res/layout/player_episodes.xml
Normal file
43
app/src/main/res/layout/player_episodes.xml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="#73000000">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/linearLayout3"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginTop="7dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/button_close_episodes_list"
|
||||||
|
style="@style/ExoStyledControls.Button.Center"
|
||||||
|
android:layout_width="44dp"
|
||||||
|
android:layout_height="44dp"
|
||||||
|
android:contentDescription="@string/close_player"
|
||||||
|
android:padding="10dp"
|
||||||
|
app:srcCompat="@drawable/ic_baseline_arrow_back_24" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler_episodes_player"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/linearLayout3"
|
||||||
|
tools:listitem="@layout/item_episode_player" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in New Issue
Block a user