anime player update!

-added double tap to skip 10 seconds forwards/backwards
-added skip 85 seconds button
-added next and previous episode buttons
-TODO: those buttons need to account for different episode sorting
-TODO: next and previous buttons should be greyed out when there is no
 next/previous episode
This commit is contained in:
jmir1 2021-05-12 19:32:56 +02:00
parent a4e245f4c9
commit 7592c621d0
7 changed files with 134 additions and 23 deletions

View file

@ -273,6 +273,9 @@ dependencies {
implementation("com.google.android.exoplayer:exoplayer-dash:$exoplayerVersion")
implementation("com.google.android.exoplayer:exoplayer-hls:$exoplayerVersion")
implementation("com.google.android.exoplayer:exoplayer-ui:$exoplayerVersion")
//player doubletap
implementation("com.github.vkay94:DoubleTapPlayerView:1.0.2")
}
tasks {

View file

@ -24,6 +24,7 @@ import eu.kanade.tachiyomi.source.AnimeSourceManager
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.toEpisodeInfo
import eu.kanade.tachiyomi.ui.anime.AnimeController
import eu.kanade.tachiyomi.ui.anime.episode.EpisodeItem
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
@ -39,6 +40,7 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import java.io.File
import java.util.Collections.emptyList
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
@ -453,7 +455,8 @@ class NotificationReceiver : BroadcastReceiver() {
}
}
}
val newIntent = WatcherActivity.newIntent(context, anime, episode, link)
val episodeList: List<EpisodeItem> = emptyList()
val newIntent = WatcherActivity.newIntent(context, anime, episode, episodeList, link)
return PendingIntent.getActivity(context, anime.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT)
}

View file

@ -81,7 +81,6 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import okhttp3.Callback
import reactivecircus.flowbinding.recyclerview.scrollEvents
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
import timber.log.Timber
@ -641,11 +640,24 @@ class AnimeController :
}
if (requestCode == REQUEST_SECONDS) {
val seconds = data!!.getLongExtra("seconds_result", 0)
val total_seconds = data.getLongExtra("total_seconds_result", 0)
val totalSeconds = data.getLongExtra("total_seconds_result", 0)
val episode: Episode = data.getSerializableExtra("episode") as Episode
episode.last_second_seen = seconds
episode.total_seconds = total_seconds
episode.total_seconds = totalSeconds
presenter.setEpisodesProgress(arrayListOf(EpisodeItem(episode, anime!!)))
// if next or previous episode was pressed
if (data.getBooleanExtra("nextResult", false)) {
val episodeList = presenter.episodes.sortedWith(presenter.getEpisodeSort())
val idx = episodeList.indexOfFirst { it.episode_number == episode.episode_number }
val nextEpisode = episodeList[idx - 1].episode
openEpisode(nextEpisode)
}
if (data.getBooleanExtra("previousResult", false)) {
val episodeList = presenter.episodes.sortedWith(presenter.getEpisodeSort())
val idx = episodeList.indexOfFirst { it.episode_number == episode.episode_number }
val previousEpisode = episodeList[idx + 1].episode
openEpisode(previousEpisode)
}
}
}
@ -744,7 +756,8 @@ class AnimeController :
runBlocking {
launch {
val url = fetchEpisodeLinksFromSource(false, episode)
val intent = WatcherActivity.newIntent(activity, presenter.anime, episode, url)
val episodeList = presenter.episodes.sortedWith(presenter.getEpisodeSort())
val intent = WatcherActivity.newIntent(activity, presenter.anime, episode, episodeList, url)
if (hasAnimation) {
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
}

View file

@ -3,11 +3,15 @@ package eu.kanade.tachiyomi.ui.watcher
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.ImageButton
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.github.vkay94.dtpv.DoubleTapPlayerView
import com.github.vkay94.dtpv.youtube.YouTubeOverlay
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.source.TrackGroupArray
import com.google.android.exoplayer2.trackselection.TrackSelectionArray
import com.google.android.exoplayer2.ui.PlayerView
import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.util.MimeTypes
@ -15,6 +19,7 @@ import com.google.android.exoplayer2.util.Util
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Anime
import eu.kanade.tachiyomi.data.database.models.Episode
import eu.kanade.tachiyomi.ui.anime.episode.EpisodeItem
import eu.kanade.tachiyomi.util.view.hideBar
const val STATE_RESUME_WINDOW = "resumeWindow"
@ -26,7 +31,11 @@ class WatcherActivity : AppCompatActivity() {
private lateinit var exoPlayer: SimpleExoPlayer
private lateinit var dataSourceFactory: DataSource.Factory
private lateinit var playerView: PlayerView
private lateinit var playerView: DoubleTapPlayerView
private lateinit var youTubeDoubleTap: YouTubeOverlay
private lateinit var skipBtn: TextView
private lateinit var nextBtn: ImageButton
private lateinit var prevBtn: ImageButton
private var duration: Long = 0
private var currentWindow = 0
@ -45,6 +54,23 @@ class WatcherActivity : AppCompatActivity() {
window.hideBar()
}
playerView = findViewById(R.id.player_view)
youTubeDoubleTap = findViewById(R.id.youtube_overlay)
youTubeDoubleTap
.performListener(object : YouTubeOverlay.PerformListener {
override fun onAnimationStart() {
// Do UI changes when circle scaling animation starts (e.g. hide controller views)
youTubeDoubleTap.visibility = View.VISIBLE
}
override fun onAnimationEnd() {
// Do UI changes when circle scaling animation starts (e.g. show controller views)
youTubeDoubleTap.visibility = View.GONE
}
})
skipBtn = findViewById(R.id.watcher_controls_skip_btn)
nextBtn = findViewById(R.id.watcher_controls_next)
prevBtn = findViewById(R.id.watcher_controls_prev)
dataSourceFactory = DefaultDataSourceFactory(this, Util.getUserAgent(this, "xyz.jmir.tachiyomi.mi"))
mediaItem = MediaItem.Builder()
.setUri(intent.getStringExtra("uri"))
@ -81,6 +107,18 @@ class WatcherActivity : AppCompatActivity() {
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters) {}
}
exoPlayer.addListener(PlayerEventListener())
skipBtn.setOnClickListener { exoPlayer.seekTo(exoPlayer.currentPosition + 85000) }
if (intent.getBooleanExtra("hasNextEpisode", false)) {
nextBtn.setOnClickListener {
nextEpisode()
}
}
if (intent.getBooleanExtra("hasPreviousEpisode", false)) {
prevBtn.setOnClickListener {
previousEpisode()
}
}
youTubeDoubleTap.player(exoPlayer)
playerView.player = exoPlayer
duration = exoPlayer.duration
}
@ -91,6 +129,7 @@ class WatcherActivity : AppCompatActivity() {
}
private fun releasePlayer() {
youTubeDoubleTap.player(exoPlayer)
isPlayerPlaying = exoPlayer.playWhenReady
playbackPosition = exoPlayer.currentPosition
currentWindow = exoPlayer.currentWindowIndex
@ -101,6 +140,38 @@ class WatcherActivity : AppCompatActivity() {
returnIntent.putExtra("episode", episode)
setResult(RESULT_OK, returnIntent)
exoPlayer.release()
super.onBackPressed()
}
private fun nextEpisode() {
youTubeDoubleTap.player(exoPlayer)
isPlayerPlaying = exoPlayer.playWhenReady
playbackPosition = exoPlayer.currentPosition
currentWindow = exoPlayer.currentWindowIndex
val episode = intent.getSerializableExtra("episode") as Episode
val returnIntent = intent
returnIntent.putExtra("seconds_result", playbackPosition)
returnIntent.putExtra("total_seconds_result", exoPlayer.duration)
returnIntent.putExtra("episode", episode)
returnIntent.putExtra("nextResult", true)
setResult(RESULT_OK, returnIntent)
exoPlayer.release()
super.onBackPressed()
}
private fun previousEpisode() {
youTubeDoubleTap.player(exoPlayer)
isPlayerPlaying = exoPlayer.playWhenReady
playbackPosition = exoPlayer.currentPosition
currentWindow = exoPlayer.currentWindowIndex
val episode = intent.getSerializableExtra("episode") as Episode
val returnIntent = intent
returnIntent.putExtra("seconds_result", playbackPosition)
returnIntent.putExtra("total_seconds_result", exoPlayer.duration)
returnIntent.putExtra("episode", episode)
returnIntent.putExtra("previousResult", true)
setResult(RESULT_OK, returnIntent)
exoPlayer.release()
}
override fun onSaveInstanceState(outState: Bundle) {
@ -144,12 +215,19 @@ class WatcherActivity : AppCompatActivity() {
}
companion object {
fun newIntent(context: Context, anime: Anime, episode: Episode, url: String): Intent {
fun newIntent(context: Context, anime: Anime, episode: Episode, episodeList: List<EpisodeItem>, url: String): Intent {
return Intent(context, WatcherActivity::class.java).apply {
putExtra("anime", anime.id)
putExtra("episode", episode)
putExtra("second", episode.last_second_seen)
putExtra("uri", url)
if (episodeList.isNotEmpty()) {
putExtra("hasNextEpisode", episode.episode_number < episodeList[0].episode_number)
putExtra("hasPreviousEpisode", episode.episode_number > episodeList[episodeList.size - 1].episode_number)
} else {
putExtra("hasNextEpisode", false)
putExtra("hasPreviousEpisode", false)
}
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
}
}

View file

@ -5,19 +5,33 @@
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
<FrameLayout xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_media_frame"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.5"
android:background="#000000">
<com.google.android.exoplayer2.ui.PlayerView
<com.github.vkay94.dtpv.DoubleTapPlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center" />
app:controller_layout_id="@layout/watcher_controls_view"
app:fastforward_increment="85000"
app:dtpv_controller="@+id/youtube_overlay"
app:show_buffering="when_playing"/>
<com.github.vkay94.dtpv.youtube.YouTubeOverlay
android:id="@+id/youtube_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
app:yt_playerView="@+id/player_view" />
</FrameLayout>
</LinearLayout>

View file

@ -25,27 +25,26 @@
android:paddingTop="4dp"
android:orientation="horizontal">
<ImageButton android:id="@id/exo_prev"
<ImageButton android:id="@+id/watcher_controls_prev"
style="@style/ExoMediaButton.Previous"/>
<ImageButton android:id="@id/exo_rew"
style="@style/ExoMediaButton.Rewind"/>
<ImageButton android:id="@id/exo_repeat_toggle"
style="@style/ExoMediaButton"/>
<ImageButton android:id="@id/exo_play"
style="@style/ExoMediaButton.Play"/>
<ImageButton android:id="@id/exo_pause"
style="@style/ExoMediaButton.Pause"/>
<ImageButton android:id="@id/exo_ffwd"
style="@style/ExoMediaButton.FastForward"/>
<ImageButton android:id="@id/exo_next"
<ImageButton android:id="@+id/watcher_controls_next"
style="@style/ExoMediaButton.Next"/>
<TextView
android:id="@+id/watcher_controls_skip_btn"
android:text="@string/watcher_controls_skip_text"
android:textColor="#ffffff"
android:textStyle="bold"
android:gravity="center"
style="@style/ExoMediaButton" />
</LinearLayout>
<LinearLayout

View file

@ -809,4 +809,5 @@
<!-- S Pen actions -->
<string name="spen_previous_page">Previous page</string>
<string name="spen_next_page">Next page</string>
<string name="watcher_controls_skip_text">+85 s</string>
</resources>