add playhead progress indicator to player episodes list
This commit is contained in:
		@ -200,6 +200,8 @@ class PlayerActivity : AppCompatActivity() {
 | 
			
		||||
 | 
			
		||||
        // Hide the full-screen UI (controls, etc.) while in picture-in-picture mode.
 | 
			
		||||
        playerBinding.videoView.useController = !isInPictureInPictureMode
 | 
			
		||||
 | 
			
		||||
        // TODO also hide language settings/episodes list
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun initPlayer() {
 | 
			
		||||
 | 
			
		||||
@ -37,10 +37,7 @@ import kotlinx.coroutines.joinAll
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import kotlinx.coroutines.runBlocking
 | 
			
		||||
import org.mosad.teapod.R
 | 
			
		||||
import org.mosad.teapod.parser.crunchyroll.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.parser.crunchyroll.*
 | 
			
		||||
import org.mosad.teapod.preferences.Preferences
 | 
			
		||||
import org.mosad.teapod.util.metadb.EpisodeMeta
 | 
			
		||||
import org.mosad.teapod.util.metadb.Meta
 | 
			
		||||
@ -67,6 +64,8 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
 | 
			
		||||
        internal set
 | 
			
		||||
    var currentEpisodeMeta: EpisodeMeta? = null
 | 
			
		||||
        internal set
 | 
			
		||||
    var currentPlayheads: PlayheadsMap = mutableMapOf()
 | 
			
		||||
        internal set
 | 
			
		||||
//    var tmdbTVSeason: TMDBTVSeason? =null
 | 
			
		||||
//        internal set
 | 
			
		||||
 | 
			
		||||
@ -121,7 +120,15 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
 | 
			
		||||
 | 
			
		||||
    fun loadMediaAsync(seasonId: String, episodeId: String) = viewModelScope.launch {
 | 
			
		||||
        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")
 | 
			
		||||
 | 
			
		||||
@ -271,6 +278,11 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
 | 
			
		||||
            viewModelScope.launch { Crunchyroll.postPlayheads(currentEpisode.id, playhead.toInt()) }
 | 
			
		||||
            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(
 | 
			
		||||
            model.episodes.items,
 | 
			
		||||
            null,
 | 
			
		||||
            mapOf(),
 | 
			
		||||
            model.currentPlayheads.toMap(),
 | 
			
		||||
            EpisodeItemAdapter.OnClickListener { episode ->
 | 
			
		||||
                dismiss()
 | 
			
		||||
                model.setCurrentEpisode(episode.id, startPlayback = true)
 | 
			
		||||
 | 
			
		||||
@ -51,7 +51,7 @@ class EpisodeItemAdapter(
 | 
			
		||||
                (holder as EpisodeViewHolder).bind(episode, playhead, tmdbEpisode)
 | 
			
		||||
            }
 | 
			
		||||
            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) {
 | 
			
		||||
 | 
			
		||||
        // -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 titleText = if (episode.episodeNumber != null) {
 | 
			
		||||
@ -145,6 +145,14 @@ class EpisodeItemAdapter(
 | 
			
		||||
                    .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
 | 
			
		||||
            binding.imageEpisodePlay.visibility = if (currentSelected == bindingAdapterPosition) {
 | 
			
		||||
                View.GONE
 | 
			
		||||
 | 
			
		||||
@ -26,7 +26,16 @@
 | 
			
		||||
            android:background="@drawable/bg_circle__black_transparent_24dp"
 | 
			
		||||
            android:contentDescription="@string/button_play"
 | 
			
		||||
            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>
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
 | 
			
		||||
@ -51,7 +51,7 @@
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
    <!-- player theme -->
 | 
			
		||||
    <style name="PlayerTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
 | 
			
		||||
    <style name="PlayerTheme" parent="AppTheme">
 | 
			
		||||
        <item name="android:windowNoTitle">true</item>
 | 
			
		||||
        <item name="android:windowActionBar">false</item>
 | 
			
		||||
        <item name="android:windowFullscreen">true</item>
 | 
			
		||||
@ -86,7 +86,8 @@
 | 
			
		||||
        <item name="android:popupBackground">?themeSecondary</item>
 | 
			
		||||
    </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:windowIsFloating">false</item>
 | 
			
		||||
        <item name="android:windowBackground">@android:color/transparent</item>
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user