mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-29 09:39:03 +03:00
parent
a14cd93279
commit
56b2c12a97
14 changed files with 299 additions and 71 deletions
|
@ -96,11 +96,12 @@
|
|||
<activity
|
||||
android:name=".ui.player.PlayerActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="userLandscape"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:configChanges="orientation|screenLayout|screenSize|smallestScreenSize|keyboardHidden|keyboard"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:resizeableActivity="true"
|
||||
android:exported="false">
|
||||
android:exported="false"
|
||||
tools:targetApi="n">
|
||||
<intent-filter>
|
||||
<action android:name="com.samsung.android.support.REMOTE_ACTION" />
|
||||
</intent-filter>
|
||||
|
|
|
@ -25,8 +25,6 @@ object PreferenceKeys {
|
|||
|
||||
const val alwaysUseExternalPlayer = "pref_always_use_external_player"
|
||||
|
||||
const val pipPlayerPreference = "pref_pip_player"
|
||||
|
||||
const val externalPlayerPreference = "external_player_preference"
|
||||
|
||||
const val jumpToChapters = "jump_to_chapters"
|
||||
|
|
|
@ -136,8 +136,6 @@ class PreferencesHelper(val context: Context) {
|
|||
putInt(Keys.playerViewMode, newMode)
|
||||
}
|
||||
|
||||
fun pipPlayerPreference() = prefs.getBoolean(Keys.pipPlayerPreference, false)
|
||||
|
||||
fun alwaysUseExternalPlayer() = prefs.getBoolean(Keys.alwaysUseExternalPlayer, false)
|
||||
|
||||
fun externalPlayerPreference() = prefs.getString(Keys.externalPlayerPreference, "")
|
||||
|
|
|
@ -2,10 +2,18 @@ package eu.kanade.tachiyomi.ui.player
|
|||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.PendingIntent
|
||||
import android.app.PictureInPictureParams
|
||||
import android.app.RemoteAction
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.ColorStateList
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Icon
|
||||
import android.media.AudioFocusRequest
|
||||
import android.media.AudioManager
|
||||
import android.os.Build
|
||||
|
@ -13,11 +21,15 @@ import android.os.Bundle
|
|||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Rational
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewAnimationUtils
|
||||
import android.view.WindowManager
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.SeekBar
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
|
@ -62,6 +74,27 @@ class PlayerActivity :
|
|||
}
|
||||
}
|
||||
}
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
// TODO: When in PiP mode, selecting an episode from list should load new episode
|
||||
// Currently, below finish simply closes the activity. I don't know how to return a new Intent to update the activity
|
||||
finish()
|
||||
super.onNewIntent(intent)
|
||||
}
|
||||
|
||||
private val ACTION_MEDIA_CONTROL = "media_control"
|
||||
private val EXTRA_CONTROL_TYPE = "control_type"
|
||||
private val REQUEST_PLAY = 1
|
||||
private val REQUEST_PAUSE = 2
|
||||
private val CONTROL_TYPE_PLAY = 1
|
||||
private val CONTROL_TYPE_PAUSE = 2
|
||||
private val REQUEST_PREVIOUS = 3
|
||||
private val REQUEST_NEXT = 4
|
||||
private val CONTROL_TYPE_PREVIOUS = 3
|
||||
private val CONTROL_TYPE_NEXT = 4
|
||||
|
||||
private var isInPipMode: Boolean = false
|
||||
|
||||
private var mReceiver: BroadcastReceiver? = null
|
||||
|
||||
lateinit var binding: PlayerActivityBinding
|
||||
|
||||
|
@ -254,8 +287,14 @@ class PlayerActivity :
|
|||
mDetector.onTouchEvent(event)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
binding.pipBtn.isVisible = packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
}
|
||||
|
||||
binding.backArrowBtn.setOnClickListener { onBackPressed() }
|
||||
|
||||
binding.pipBtn.setOnClickListener { startPiP() }
|
||||
|
||||
// Lock and Unlock controls
|
||||
binding.lockBtn.setOnClickListener { isLocked = true; toggleControls() }
|
||||
binding.unlockBtn.setOnClickListener { isLocked = false; toggleControls() }
|
||||
|
@ -268,26 +307,8 @@ class PlayerActivity :
|
|||
binding.playbackSeekbar.setOnSeekBarChangeListener(seekBarChangeListener)
|
||||
// player.playFile(currentVideoList!!.first().videoUrl!!.toString())
|
||||
|
||||
binding.nextBtn.setOnClickListener {
|
||||
val wasPlayerPaused = player.paused
|
||||
player.paused = true
|
||||
showLoadingIndicator(true)
|
||||
presenter.nextEpisode {
|
||||
if (wasPlayerPaused == false) {
|
||||
player.paused = false
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.prevBtn.setOnClickListener {
|
||||
val wasPlayerPaused = player.paused
|
||||
player.paused = true
|
||||
showLoadingIndicator(true)
|
||||
presenter.previousEpisode {
|
||||
if (wasPlayerPaused == false) {
|
||||
player.paused = false
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.nextBtn.setOnClickListener { goNextEpisode() }
|
||||
binding.prevBtn.setOnClickListener { goPreviousEpisode() }
|
||||
|
||||
if (presenter?.needsInit() == true) {
|
||||
val anime = intent.extras!!.getLong("anime", -1)
|
||||
|
@ -302,6 +323,42 @@ class PlayerActivity :
|
|||
playerIsDestroyed = false
|
||||
}
|
||||
|
||||
private fun goNextEpisode() {
|
||||
val wasPlayerPaused = player.paused
|
||||
player.paused = true
|
||||
showLoadingIndicator(true)
|
||||
|
||||
val nEpTxt = presenter.nextEpisode {
|
||||
if (wasPlayerPaused == false) {
|
||||
player.paused = false
|
||||
}
|
||||
}
|
||||
|
||||
when {
|
||||
nEpTxt == "Invalid" -> return
|
||||
nEpTxt == null -> { launchUI { toast(R.string.no_next_episode) }; showLoadingIndicator(false) }
|
||||
isInPipMode -> launchUI { toast(nEpTxt) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun goPreviousEpisode() {
|
||||
val wasPlayerPaused = player.paused
|
||||
player.paused = true
|
||||
showLoadingIndicator(true)
|
||||
|
||||
val pEpTxt = presenter.previousEpisode {
|
||||
if (wasPlayerPaused == false) {
|
||||
player.paused = false
|
||||
}
|
||||
}
|
||||
|
||||
when {
|
||||
pEpTxt == "Invalid" -> return
|
||||
pEpTxt == null -> { launchUI { toast(R.string.no_previous_episode) }; showLoadingIndicator(false) }
|
||||
isInPipMode -> launchUI { toast(pEpTxt) }
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleControls() {
|
||||
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
|
||||
if (isLocked) {
|
||||
|
@ -312,15 +369,38 @@ class PlayerActivity :
|
|||
// Toggle unlock button
|
||||
binding.unlockBtn.isVisible = !binding.unlockBtn.isVisible
|
||||
} else {
|
||||
var animation = R.anim.fade_in_medium
|
||||
if (binding.background.isVisible) {
|
||||
animation = R.anim.fade_out_medium
|
||||
}
|
||||
AnimationUtils.loadAnimation(this, animation).also { fadeAnimation ->
|
||||
findViewById<RelativeLayout>(R.id.controls_top).startAnimation(fadeAnimation)
|
||||
findViewById<RelativeLayout>(R.id.controls_bottom).startAnimation(fadeAnimation)
|
||||
findViewById<View>(R.id.background).startAnimation(fadeAnimation)
|
||||
|
||||
binding.controlsTop.isVisible = !binding.controlsTop.isVisible
|
||||
binding.controlsBottom.isVisible = !binding.controlsBottom.isVisible
|
||||
binding.background.isVisible = !binding.background.isVisible
|
||||
}
|
||||
// Toggle controls
|
||||
binding.controlsTop.isVisible = !binding.controlsTop.isVisible
|
||||
binding.controlsBottom.isVisible = !binding.controlsBottom.isVisible
|
||||
binding.background.isVisible = !binding.background.isVisible
|
||||
|
||||
// Hide unlock button
|
||||
binding.unlockBtn.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideControls(hide: Boolean) {
|
||||
if (hide) {
|
||||
binding.controlsTop.isVisible = false
|
||||
binding.controlsBottom.isVisible = false
|
||||
binding.background.isVisible = false
|
||||
} else {
|
||||
binding.controlsTop.isVisible = true
|
||||
binding.controlsBottom.isVisible = true
|
||||
binding.background.isVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLoadingIndicator(visible: Boolean) {
|
||||
if (binding.loadingIndicator.isVisible == visible) return
|
||||
binding.playBtn.isVisible = !visible
|
||||
|
@ -598,7 +678,7 @@ class PlayerActivity :
|
|||
0 -> 1
|
||||
1 -> 2
|
||||
2 -> 0
|
||||
else -> 1
|
||||
else -> 0
|
||||
}
|
||||
preferences.setPlayerViewMode(playerViewMode)
|
||||
setViewMode()
|
||||
|
@ -695,15 +775,6 @@ class PlayerActivity :
|
|||
val plCount = presenter.episodeList.size
|
||||
val plPos = presenter.getCurrentEpisodeIndex()
|
||||
|
||||
if (plCount == 1) {
|
||||
// use View.GONE so the buttons won't take up any space
|
||||
binding.prevBtn.visibility = View.GONE
|
||||
binding.nextBtn.visibility = View.GONE
|
||||
return
|
||||
}
|
||||
binding.prevBtn.visibility = View.VISIBLE
|
||||
binding.nextBtn.visibility = View.VISIBLE
|
||||
|
||||
val g = ContextCompat.getColor(this, R.color.tint_disabled)
|
||||
val w = ContextCompat.getColor(this, R.color.tint_normal)
|
||||
binding.prevBtn.imageTintList = ColorStateList.valueOf(if (plPos == 0) g else w)
|
||||
|
@ -711,7 +782,7 @@ class PlayerActivity :
|
|||
}
|
||||
|
||||
private fun updatePlaybackStatus(paused: Boolean) {
|
||||
val r = if (paused) R.drawable.ic_play_arrow_100dp else R.drawable.ic_pause_100dp
|
||||
val r = if (paused) R.drawable.ic_play_arrow_80dp else R.drawable.ic_pause_80dp
|
||||
binding.playBtn.setImageResource(r)
|
||||
|
||||
if (paused) {
|
||||
|
@ -729,6 +800,9 @@ class PlayerActivity :
|
|||
player.destroy()
|
||||
}
|
||||
abandonAudioFocus()
|
||||
if (packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
finishAndRemoveTask()
|
||||
}
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
|
@ -738,9 +812,139 @@ class PlayerActivity :
|
|||
presenter.saveEpisodeProgress(player.timePos, player.duration)
|
||||
player.paused = true
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isInPipMode) finishAndRemoveTask()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setVisibilities()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) player.paused?.let { updatePictureInPictureActions(!it) }
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration?) {
|
||||
isInPipMode = isInPictureInPictureMode
|
||||
hideControls(!isInPictureInPictureMode)
|
||||
if (isInPictureInPictureMode) binding.loadingIndicator.indicatorSize = binding.loadingIndicator.indicatorSize / 2
|
||||
else binding.loadingIndicator.indicatorSize = binding.loadingIndicator.indicatorSize * 2
|
||||
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
|
||||
|
||||
if (isInPictureInPictureMode) {
|
||||
// On Android TV it is required to hide controller in this PIP change callback
|
||||
hideControls(true)
|
||||
mReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent == null || ACTION_MEDIA_CONTROL != intent.action) {
|
||||
return
|
||||
}
|
||||
when (intent.getIntExtra(EXTRA_CONTROL_TYPE, 0)) {
|
||||
CONTROL_TYPE_PLAY -> {
|
||||
player.paused = false
|
||||
updatePictureInPictureActions(true)
|
||||
}
|
||||
CONTROL_TYPE_PAUSE -> {
|
||||
player.paused = true
|
||||
updatePictureInPictureActions(false)
|
||||
}
|
||||
CONTROL_TYPE_PREVIOUS -> {
|
||||
goPreviousEpisode()
|
||||
player.paused?.let { updatePictureInPictureActions(!it) }
|
||||
}
|
||||
CONTROL_TYPE_NEXT -> {
|
||||
goNextEpisode()
|
||||
player.paused?.let { updatePictureInPictureActions(!it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
registerReceiver(mReceiver, IntentFilter(ACTION_MEDIA_CONTROL))
|
||||
} else {
|
||||
if (mReceiver != null) {
|
||||
unregisterReceiver(mReceiver)
|
||||
mReceiver = null
|
||||
}
|
||||
hideControls(false)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun startPiP() {
|
||||
if (packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
hideControls(true)
|
||||
player.paused?.let { updatePictureInPictureActions(!it) }
|
||||
?.let { this.enterPictureInPictureMode(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private fun createRemoteAction(
|
||||
iconResId: Int,
|
||||
titleResId: Int,
|
||||
requestCode: Int,
|
||||
controlType: Int
|
||||
): RemoteAction {
|
||||
return RemoteAction(
|
||||
Icon.createWithResource(this, iconResId),
|
||||
getString(titleResId),
|
||||
getString(titleResId),
|
||||
PendingIntent.getBroadcast(
|
||||
this,
|
||||
requestCode,
|
||||
Intent(ACTION_MEDIA_CONTROL)
|
||||
.putExtra(EXTRA_CONTROL_TYPE, controlType),
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
fun updatePictureInPictureActions(
|
||||
playing: Boolean
|
||||
): PictureInPictureParams {
|
||||
val mPictureInPictureParams = PictureInPictureParams.Builder()
|
||||
// Set action items for the picture-in-picture mode. These are the only custom controls
|
||||
// available during the picture-in-picture mode.
|
||||
.setActions(
|
||||
arrayListOf(
|
||||
|
||||
createRemoteAction(
|
||||
R.drawable.ic_skip_previous_24dp,
|
||||
R.string.action_previous_episode,
|
||||
CONTROL_TYPE_PREVIOUS,
|
||||
REQUEST_PREVIOUS
|
||||
),
|
||||
|
||||
if (playing) {
|
||||
createRemoteAction(
|
||||
R.drawable.ic_pause_24dp,
|
||||
R.string.action_pause,
|
||||
CONTROL_TYPE_PAUSE,
|
||||
REQUEST_PAUSE
|
||||
)
|
||||
} else {
|
||||
createRemoteAction(
|
||||
R.drawable.ic_play_arrow_24dp,
|
||||
R.string.action_play,
|
||||
CONTROL_TYPE_PLAY,
|
||||
REQUEST_PLAY
|
||||
)
|
||||
},
|
||||
createRemoteAction(
|
||||
R.drawable.ic_skip_next_24dp,
|
||||
R.string.action_next_episode,
|
||||
CONTROL_TYPE_NEXT,
|
||||
REQUEST_NEXT
|
||||
)
|
||||
|
||||
)
|
||||
)
|
||||
.setAspectRatio(player.videoAspect?.times(10000)?.let { Rational(it.toInt(), 10000) })
|
||||
.build()
|
||||
setPictureInPictureParams(mPictureInPictureParams)
|
||||
return mPictureInPictureParams
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the presenter if the initial load couldn't load the videos of the episode. In
|
||||
* this case the activity is closed and a toast is shown to the user.
|
||||
|
@ -811,7 +1015,6 @@ class PlayerActivity :
|
|||
}
|
||||
|
||||
private fun fileLoaded() {
|
||||
launchUI { showLoadingIndicator(false) }
|
||||
clearTracks()
|
||||
player.loadTracks()
|
||||
subTracks += player.tracks.getValue("sub")
|
||||
|
@ -864,6 +1067,8 @@ class PlayerActivity :
|
|||
selectedAudio = audioTracks.indexOfFirst { it.url == mpvAudio.mpvId.toString() }
|
||||
}
|
||||
}
|
||||
launchUI { showLoadingIndicator(false) }
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) player.paused?.let { updatePictureInPictureActions(!it) }
|
||||
}
|
||||
|
||||
// mpv events
|
||||
|
|
|
@ -185,12 +185,12 @@ class PlayerPresenter(
|
|||
return source is AnimeHttpSource && !EpisodeLoader.isDownloaded(currentEpisode, anime)
|
||||
}
|
||||
|
||||
fun nextEpisode(callback: () -> Unit) {
|
||||
val anime = anime ?: return
|
||||
fun nextEpisode(callback: () -> Unit): String? {
|
||||
val anime = anime ?: return "Invalid"
|
||||
val source = sourceManager.getOrStub(anime.source)
|
||||
|
||||
val index = getCurrentEpisodeIndex()
|
||||
if (index == episodeList.lastIndex) return
|
||||
if (index == episodeList.lastIndex) return null
|
||||
currentEpisode = episodeList[index + 1]
|
||||
launchIO {
|
||||
try {
|
||||
|
@ -208,14 +208,15 @@ class PlayerPresenter(
|
|||
logcat(LogPriority.ERROR, e) { e.message ?: "error getting links" }
|
||||
}
|
||||
}
|
||||
return anime.title + " - " + episodeList[index + 1].name
|
||||
}
|
||||
|
||||
fun previousEpisode(callback: () -> Unit) {
|
||||
val anime = anime ?: return
|
||||
fun previousEpisode(callback: () -> Unit): String? {
|
||||
val anime = anime ?: return "Invalid"
|
||||
val source = sourceManager.getOrStub(anime.source)
|
||||
|
||||
val index = getCurrentEpisodeIndex()
|
||||
if (index == 0) return
|
||||
if (index == 0) return null
|
||||
currentEpisode = episodeList[index - 1]
|
||||
launchIO {
|
||||
try {
|
||||
|
@ -233,6 +234,7 @@ class PlayerPresenter(
|
|||
logcat(LogPriority.ERROR, e) { e.message ?: "error getting links" }
|
||||
}
|
||||
}
|
||||
return anime.title + " - " + episodeList[index - 1].name
|
||||
}
|
||||
|
||||
fun saveEpisodeHistory() {
|
||||
|
|
|
@ -6,7 +6,6 @@ import eu.kanade.tachiyomi.R
|
|||
import eu.kanade.tachiyomi.util.preference.defaultValue
|
||||
import eu.kanade.tachiyomi.util.preference.entriesRes
|
||||
import eu.kanade.tachiyomi.util.preference.listPreference
|
||||
import eu.kanade.tachiyomi.util.preference.summaryRes
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
@ -105,12 +104,5 @@ class SettingsPlayerController : SettingsController() {
|
|||
|
||||
summary = "%s"
|
||||
}
|
||||
|
||||
switchPreference {
|
||||
key = Keys.pipPlayerPreference
|
||||
titleRes = R.string.pref_pip_player
|
||||
summaryRes = R.string.pref_pip_player_summary
|
||||
defaultValue = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
6
app/src/main/res/anim/fade_in_medium.xml
Normal file
6
app/src/main/res/anim/fade_in_medium.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="150"
|
||||
android:fromAlpha="0.0"
|
||||
android:toAlpha="1.0"
|
||||
android:interpolator="@android:interpolator/linear"/>
|
6
app/src/main/res/anim/fade_out_medium.xml
Normal file
6
app/src/main/res/anim/fade_out_medium.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="150"
|
||||
android:fromAlpha="1.0"
|
||||
android:toAlpha="0.0"
|
||||
android:interpolator="@android:interpolator/linear"/>
|
|
@ -1,5 +0,0 @@
|
|||
<vector android:height="100dp" android:tint="?attr/colorControlNormal"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="100dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_pause_80dp.xml
Normal file
10
app/src/main/res/drawable/ic_pause_80dp.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="80dp"
|
||||
android:width="80dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24" >
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
|
||||
</vector>
|
|
@ -1,5 +0,0 @@
|
|||
<vector android:height="100dp" android:tint="?attr/colorControlNormal"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="100dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M8,5v14l11,-7z"/>
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_play_arrow_80dp.xml
Normal file
10
app/src/main/res/drawable/ic_play_arrow_80dp.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="80dp"
|
||||
android:width="80dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24" >
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M8,5v14l11,-7z"/>
|
||||
</vector>
|
|
@ -14,6 +14,7 @@
|
|||
android:id="@+id/player"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/background"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -178,8 +179,8 @@
|
|||
|
||||
<ImageButton
|
||||
android:id="@+id/play_btn"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="Play/Pause"
|
||||
|
@ -187,7 +188,7 @@
|
|||
android:textColor="@android:color/white"
|
||||
android:visibility="gone"
|
||||
app:tint="?attr/colorOnPrimarySurface"
|
||||
tools:src="@drawable/ic_play_arrow_100dp"
|
||||
tools:src="@drawable/ic_play_arrow_80dp"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
||||
|
@ -264,6 +265,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right"
|
||||
android:layout_marginRight="10dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
|
@ -279,13 +281,21 @@
|
|||
android:id="@+id/cycleViewModeBtn"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginRight="10dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="Cycle view modes"
|
||||
android:onClick="cycleViewMode"
|
||||
android:src="@drawable/ic_fullscreen_black_24dp"
|
||||
app:tint="?attr/colorOnPrimarySurface" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/pipBtn"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="match_parent"
|
||||
android:src="@drawable/ic_picture_in_picture_24dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:visibility="visible"
|
||||
android:contentDescription="@string/action_player_pip" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
<string name="action_next_chapter">Next chapter</string>
|
||||
<string name="action_next_episode">Next episode</string>
|
||||
<string name="action_screen_fit">Screen fit mode</string>
|
||||
<string name="action_player_pip">PiP mode</string>
|
||||
<string name="action_retry">Retry</string>
|
||||
<string name="action_remove">Remove</string>
|
||||
<string name="action_start">Start</string>
|
||||
|
@ -441,8 +442,6 @@
|
|||
<string name="pref_skip_20">20s</string>
|
||||
<string name="pref_skip_10">10s</string>
|
||||
<string name="pref_skip_5">5s</string>
|
||||
<string name="pref_pip_player">Enable picture in picture mode</string>
|
||||
<string name="pref_pip_player_summary">Note: this is still an experimental feature!</string>
|
||||
<string name="pref_always_use_external_player">Always use external player</string>
|
||||
<string name="pref_player_fullscreen">Show content in display cutout</string>
|
||||
<string name="pref_external_player_preference">External player preference</string>
|
||||
|
@ -953,6 +952,7 @@
|
|||
|
||||
<string name="player_controls_skip_intro_text">+85 s</string>
|
||||
<string name="no_next_episode">Next Episode not found!</string>
|
||||
<string name="no_previous_episode">Previous Episode not found!</string>
|
||||
<string name="anime_description_cover">Cover of Anime</string>
|
||||
<string name="label_history">Manga</string>
|
||||
<string name="label_animehistory">Anime</string>
|
||||
|
|
Loading…
Reference in a new issue