add playhead progress indicator to player episodes list
This commit is contained in:
parent
fc04e8e222
commit
95c8a72c94
|
@ -200,6 +200,8 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
|
|
||||||
// Hide the full-screen UI (controls, etc.) while in picture-in-picture mode.
|
// Hide the full-screen UI (controls, etc.) while in picture-in-picture mode.
|
||||||
playerBinding.videoView.useController = !isInPictureInPictureMode
|
playerBinding.videoView.useController = !isInPictureInPictureMode
|
||||||
|
|
||||||
|
// TODO also hide language settings/episodes list
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initPlayer() {
|
private fun initPlayer() {
|
||||||
|
|
|
@ -37,10 +37,7 @@ import kotlinx.coroutines.joinAll
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.mosad.teapod.R
|
import org.mosad.teapod.R
|
||||||
import org.mosad.teapod.parser.crunchyroll.Crunchyroll
|
import org.mosad.teapod.parser.crunchyroll.*
|
||||||
import org.mosad.teapod.parser.crunchyroll.NoneEpisode
|
|
||||||
import org.mosad.teapod.parser.crunchyroll.NoneEpisodes
|
|
||||||
import org.mosad.teapod.parser.crunchyroll.NonePlayback
|
|
||||||
import org.mosad.teapod.preferences.Preferences
|
import org.mosad.teapod.preferences.Preferences
|
||||||
import org.mosad.teapod.util.metadb.EpisodeMeta
|
import org.mosad.teapod.util.metadb.EpisodeMeta
|
||||||
import org.mosad.teapod.util.metadb.Meta
|
import org.mosad.teapod.util.metadb.Meta
|
||||||
|
@ -67,6 +64,8 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
|
||||||
internal set
|
internal set
|
||||||
var currentEpisodeMeta: EpisodeMeta? = null
|
var currentEpisodeMeta: EpisodeMeta? = null
|
||||||
internal set
|
internal set
|
||||||
|
var currentPlayheads: PlayheadsMap = mutableMapOf()
|
||||||
|
internal set
|
||||||
// var tmdbTVSeason: TMDBTVSeason? =null
|
// var tmdbTVSeason: TMDBTVSeason? =null
|
||||||
// internal set
|
// internal set
|
||||||
|
|
||||||
|
@ -121,7 +120,15 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
|
||||||
|
|
||||||
fun loadMediaAsync(seasonId: String, episodeId: String) = viewModelScope.launch {
|
fun loadMediaAsync(seasonId: String, episodeId: String) = viewModelScope.launch {
|
||||||
episodes = Crunchyroll.episodes(seasonId)
|
episodes = Crunchyroll.episodes(seasonId)
|
||||||
mediaMeta = loadMediaMeta(episodes.items.first().seriesId)
|
|
||||||
|
listOf(
|
||||||
|
viewModelScope.launch { mediaMeta = loadMediaMeta(episodes.items.first().seriesId) },
|
||||||
|
viewModelScope.launch {
|
||||||
|
val episodeIDs = episodes.items.map { it.id }
|
||||||
|
currentPlayheads = Crunchyroll.playheads(episodeIDs)
|
||||||
|
}
|
||||||
|
).joinAll()
|
||||||
|
|
||||||
|
|
||||||
Log.d(classTag, "meta: $mediaMeta")
|
Log.d(classTag, "meta: $mediaMeta")
|
||||||
|
|
||||||
|
@ -271,6 +278,11 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
|
||||||
viewModelScope.launch { Crunchyroll.postPlayheads(currentEpisode.id, playhead.toInt()) }
|
viewModelScope.launch { Crunchyroll.postPlayheads(currentEpisode.id, playhead.toInt()) }
|
||||||
Log.i(javaClass.name, "Set playhead for episode ${currentEpisode.id} to $playhead sec.")
|
Log.i(javaClass.name, "Set playhead for episode ${currentEpisode.id} to $playhead sec.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
val episodeIDs = episodes.items.map { it.id }
|
||||||
|
currentPlayheads = Crunchyroll.playheads(episodeIDs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ class EpisodeListDialogFragment : DialogFragment() {
|
||||||
val adapterRecEpisodes = EpisodeItemAdapter(
|
val adapterRecEpisodes = EpisodeItemAdapter(
|
||||||
model.episodes.items,
|
model.episodes.items,
|
||||||
null,
|
null,
|
||||||
mapOf(),
|
model.currentPlayheads.toMap(),
|
||||||
EpisodeItemAdapter.OnClickListener { episode ->
|
EpisodeItemAdapter.OnClickListener { episode ->
|
||||||
dismiss()
|
dismiss()
|
||||||
model.setCurrentEpisode(episode.id, startPlayback = true)
|
model.setCurrentEpisode(episode.id, startPlayback = true)
|
||||||
|
|
|
@ -51,7 +51,7 @@ class EpisodeItemAdapter(
|
||||||
(holder as EpisodeViewHolder).bind(episode, playhead, tmdbEpisode)
|
(holder as EpisodeViewHolder).bind(episode, playhead, tmdbEpisode)
|
||||||
}
|
}
|
||||||
ViewType.PLAYER.ordinal -> {
|
ViewType.PLAYER.ordinal -> {
|
||||||
(holder as PlayerEpisodeViewHolder).bind(episode, currentSelected)
|
(holder as PlayerEpisodeViewHolder).bind(episode, playhead, currentSelected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ class EpisodeItemAdapter(
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
// -1, since position should never be < 0
|
// -1, since position should never be < 0
|
||||||
fun bind(episode: Episode, currentSelected: Int) {
|
fun bind(episode: Episode, playhead: PlayheadObject?, currentSelected: Int) {
|
||||||
val context = binding.root.context
|
val context = binding.root.context
|
||||||
|
|
||||||
val titleText = if (episode.episodeNumber != null) {
|
val titleText = if (episode.episodeNumber != null) {
|
||||||
|
@ -145,6 +145,14 @@ class EpisodeItemAdapter(
|
||||||
.into(binding.imageEpisode)
|
.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
|
||||||
|
|
||||||
// hide the play icon, if it's the current episode
|
// hide the play icon, if it's the current episode
|
||||||
binding.imageEpisodePlay.visibility = if (currentSelected == bindingAdapterPosition) {
|
binding.imageEpisodePlay.visibility = if (currentSelected == bindingAdapterPosition) {
|
||||||
View.GONE
|
View.GONE
|
||||||
|
|
|
@ -26,7 +26,16 @@
|
||||||
android:background="@drawable/bg_circle__black_transparent_24dp"
|
android:background="@drawable/bg_circle__black_transparent_24dp"
|
||||||
android:contentDescription="@string/button_play"
|
android:contentDescription="@string/button_play"
|
||||||
app:srcCompat="@drawable/ic_baseline_play_arrow_24"
|
app:srcCompat="@drawable/ic_baseline_play_arrow_24"
|
||||||
app:tint="#FFFFFF" />
|
app:tint="@color/player_white" />
|
||||||
|
|
||||||
|
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
|
android:id="@+id/progress_playhead"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:max="100"
|
||||||
|
app:trackColor="#00FFFFFF"
|
||||||
|
app:trackThickness="2dp" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- player theme -->
|
<!-- player theme -->
|
||||||
<style name="PlayerTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
|
<style name="PlayerTheme" parent="AppTheme">
|
||||||
<item name="android:windowNoTitle">true</item>
|
<item name="android:windowNoTitle">true</item>
|
||||||
<item name="android:windowActionBar">false</item>
|
<item name="android:windowActionBar">false</item>
|
||||||
<item name="android:windowFullscreen">true</item>
|
<item name="android:windowFullscreen">true</item>
|
||||||
|
@ -86,7 +86,8 @@
|
||||||
<item name="android:popupBackground">?themeSecondary</item>
|
<item name="android:popupBackground">?themeSecondary</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="FullScreenDialogStyle" parent="Theme.MaterialComponents.Light.NoActionBar">
|
<!-- fullscreen dialog fragments -->
|
||||||
|
<style name="FullScreenDialogStyle" parent="AppTheme">
|
||||||
<item name="android:windowFullscreen">true</item>
|
<item name="android:windowFullscreen">true</item>
|
||||||
<item name="android:windowIsFloating">false</item>
|
<item name="android:windowIsFloating">false</item>
|
||||||
<item name="android:windowBackground">@android:color/transparent</item>
|
<item name="android:windowBackground">@android:color/transparent</item>
|
||||||
|
|
Loading…
Reference in New Issue