mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
more result bindings + player
This commit is contained in:
parent
4f28aef8f2
commit
d5c42f7d5a
14 changed files with 1321 additions and 916 deletions
|
@ -11,6 +11,8 @@ import com.lagradost.cloudstream3.databinding.FragmentHomeBinding
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentHomeTvBinding
|
import com.lagradost.cloudstream3.databinding.FragmentHomeTvBinding
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentPlayerBinding
|
import com.lagradost.cloudstream3.databinding.FragmentPlayerBinding
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentPlayerTvBinding
|
import com.lagradost.cloudstream3.databinding.FragmentPlayerTvBinding
|
||||||
|
import com.lagradost.cloudstream3.databinding.FragmentResultBinding
|
||||||
|
import com.lagradost.cloudstream3.databinding.FragmentResultTvBinding
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentSearchBinding
|
import com.lagradost.cloudstream3.databinding.FragmentSearchBinding
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentSearchTvBinding
|
import com.lagradost.cloudstream3.databinding.FragmentSearchTvBinding
|
||||||
import com.lagradost.cloudstream3.databinding.HomeResultGridBinding
|
import com.lagradost.cloudstream3.databinding.HomeResultGridBinding
|
||||||
|
@ -22,6 +24,7 @@ import com.lagradost.cloudstream3.databinding.RepositoryItemBinding
|
||||||
import com.lagradost.cloudstream3.databinding.RepositoryItemTvBinding
|
import com.lagradost.cloudstream3.databinding.RepositoryItemTvBinding
|
||||||
import com.lagradost.cloudstream3.databinding.SearchResultGridBinding
|
import com.lagradost.cloudstream3.databinding.SearchResultGridBinding
|
||||||
import com.lagradost.cloudstream3.databinding.SearchResultGridExpandedBinding
|
import com.lagradost.cloudstream3.databinding.SearchResultGridExpandedBinding
|
||||||
|
import com.lagradost.cloudstream3.databinding.TrailerCustomLayoutBinding
|
||||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||||
import com.lagradost.cloudstream3.utils.TestingUtils
|
import com.lagradost.cloudstream3.utils.TestingUtils
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
@ -85,8 +88,12 @@ class ExampleInstrumentedTest {
|
||||||
testAllLayouts<FragmentPlayerBinding>(activity, R.layout.fragment_player,R.layout.fragment_player_tv)
|
testAllLayouts<FragmentPlayerBinding>(activity, R.layout.fragment_player,R.layout.fragment_player_tv)
|
||||||
testAllLayouts<FragmentPlayerTvBinding>(activity, R.layout.fragment_player,R.layout.fragment_player_tv)
|
testAllLayouts<FragmentPlayerTvBinding>(activity, R.layout.fragment_player,R.layout.fragment_player_tv)
|
||||||
|
|
||||||
testAllLayouts<PlayerCustomLayoutBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv)
|
// testAllLayouts<FragmentResultBinding>(activity, R.layout.fragment_result,R.layout.fragment_result_tv)
|
||||||
testAllLayouts<PlayerCustomLayoutTvBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv)
|
// testAllLayouts<FragmentResultTvBinding>(activity, R.layout.fragment_result,R.layout.fragment_result_tv)
|
||||||
|
|
||||||
|
testAllLayouts<PlayerCustomLayoutBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv, R.layout.trailer_custom_layout)
|
||||||
|
testAllLayouts<PlayerCustomLayoutTvBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv, R.layout.trailer_custom_layout)
|
||||||
|
testAllLayouts<TrailerCustomLayoutBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv, R.layout.trailer_custom_layout)
|
||||||
|
|
||||||
testAllLayouts<RepositoryItemBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)
|
testAllLayouts<RepositoryItemBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)
|
||||||
testAllLayouts<RepositoryItemTvBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)
|
testAllLayouts<RepositoryItemTvBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)
|
||||||
|
|
|
@ -14,16 +14,15 @@ import android.provider.Settings
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||||
import android.view.animation.AlphaAnimation
|
import android.view.animation.AlphaAnimation
|
||||||
import android.view.animation.Animation
|
import android.view.animation.Animation
|
||||||
import android.view.animation.AnimationUtils
|
import android.view.animation.AnimationUtils
|
||||||
import android.widget.EditText
|
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.graphics.blue
|
import androidx.core.graphics.blue
|
||||||
import androidx.core.graphics.green
|
import androidx.core.graphics.green
|
||||||
|
@ -37,10 +36,13 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||||
import com.lagradost.cloudstream3.CommonActivity.keyEventListener
|
import com.lagradost.cloudstream3.CommonActivity.keyEventListener
|
||||||
import com.lagradost.cloudstream3.CommonActivity.playerEventListener
|
import com.lagradost.cloudstream3.CommonActivity.playerEventListener
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.databinding.PlayerCustomLayoutBinding
|
||||||
|
import com.lagradost.cloudstream3.databinding.SubtitleOffsetBinding
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer.Companion.subsProvidersIsActive
|
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer.Companion.subsProvidersIsActive
|
||||||
import com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper
|
import com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper
|
||||||
import com.lagradost.cloudstream3.utils.Qualities
|
import com.lagradost.cloudstream3.ui.result.setText
|
||||||
|
import com.lagradost.cloudstream3.ui.result.txt
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.isUsingMobileData
|
import com.lagradost.cloudstream3.utils.AppUtils.isUsingMobileData
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
||||||
|
@ -52,28 +54,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.showSystemUI
|
import com.lagradost.cloudstream3.utils.UIHelper.showSystemUI
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
||||||
import com.lagradost.cloudstream3.utils.Vector2
|
import com.lagradost.cloudstream3.utils.Vector2
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.*
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.bottom_player_bar
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.exo_ffwd
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.exo_ffwd_text
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.exo_progress
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.exo_rew
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.exo_rew_text
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.player_center_menu
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.player_ffwd_holder
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.player_holder
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.player_pause_play
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.player_progressbar_left
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.player_progressbar_left_holder
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.player_progressbar_left_icon
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.player_progressbar_right
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.player_progressbar_right_holder
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.player_progressbar_right_icon
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.player_rew_holder
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.player_time_text
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.player_video_bar
|
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.shadow_overlay
|
|
||||||
import kotlinx.android.synthetic.main.trailer_custom_layout.*
|
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
const val MINIMUM_SEEK_TIME = 7000L // when swipe seeking
|
const val MINIMUM_SEEK_TIME = 7000L // when swipe seeking
|
||||||
|
@ -92,6 +72,9 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
protected open var isFullScreenPlayer = true
|
protected open var isFullScreenPlayer = true
|
||||||
protected open var isTv = false
|
protected open var isTv = false
|
||||||
|
|
||||||
|
protected var playerBinding: PlayerCustomLayoutBinding? = null
|
||||||
|
|
||||||
|
|
||||||
// state of player UI
|
// state of player UI
|
||||||
protected var isShowing = false
|
protected var isShowing = false
|
||||||
protected var isLocked = false
|
protected var isLocked = false
|
||||||
|
@ -109,6 +92,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
* This will be set in runtime based on settings.
|
* This will be set in runtime based on settings.
|
||||||
**/
|
**/
|
||||||
protected var currentQualityProfile = 1
|
protected var currentQualityProfile = 1
|
||||||
|
|
||||||
// protected var currentPrefQuality =
|
// protected var currentPrefQuality =
|
||||||
// Qualities.P2160.value // preferred maximum quality, used for ppl w bad internet or on cell
|
// Qualities.P2160.value // preferred maximum quality, used for ppl w bad internet or on cell
|
||||||
protected var fastForwardTime = 10000L
|
protected var fastForwardTime = 10000L
|
||||||
|
@ -177,6 +161,21 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
R.drawable.ic_baseline_volume_up_24,
|
R.drawable.ic_baseline_volume_up_24,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
val root = super.onCreateView(inflater, container, savedInstanceState) ?: return null
|
||||||
|
playerBinding = PlayerCustomLayoutBinding.bind(root.findViewById(R.id.player_holder))
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
playerBinding = null
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
open fun showMirrorsDialogue() {
|
open fun showMirrorsDialogue() {
|
||||||
throw NotImplementedError()
|
throw NotImplementedError()
|
||||||
}
|
}
|
||||||
|
@ -209,24 +208,24 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
if (isShowing) {
|
if (isShowing) {
|
||||||
updateUIVisibility()
|
updateUIVisibility()
|
||||||
} else {
|
} else {
|
||||||
player_holder?.postDelayed({ updateUIVisibility() }, 200)
|
playerBinding?.playerHolder?.postDelayed({ updateUIVisibility() }, 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
val titleMove = if (isShowing) 0f else -50.toPx.toFloat()
|
val titleMove = if (isShowing) 0f else -50.toPx.toFloat()
|
||||||
player_video_title?.let {
|
playerBinding?.playerVideoTitle?.let {
|
||||||
ObjectAnimator.ofFloat(it, "translationY", titleMove).apply {
|
ObjectAnimator.ofFloat(it, "translationY", titleMove).apply {
|
||||||
duration = 200
|
duration = 200
|
||||||
start()
|
start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
player_video_title_rez?.let {
|
playerBinding?.playerVideoTitleRez?.let {
|
||||||
ObjectAnimator.ofFloat(it, "translationY", titleMove).apply {
|
ObjectAnimator.ofFloat(it, "translationY", titleMove).apply {
|
||||||
duration = 200
|
duration = 200
|
||||||
start()
|
start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val playerBarMove = if (isShowing) 0f else 50.toPx.toFloat()
|
val playerBarMove = if (isShowing) 0f else 50.toPx.toFloat()
|
||||||
bottom_player_bar?.let {
|
playerBinding?.bottomPlayerBar?.let {
|
||||||
ObjectAnimator.ofFloat(it, "translationY", playerBarMove).apply {
|
ObjectAnimator.ofFloat(it, "translationY", playerBarMove).apply {
|
||||||
duration = 200
|
duration = 200
|
||||||
start()
|
start()
|
||||||
|
@ -242,7 +241,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
val sView = subView
|
val sView = subView
|
||||||
val sStyle = subStyle
|
val sStyle = subStyle
|
||||||
if (sView != null && sStyle != null) {
|
if (sView != null && sStyle != null) {
|
||||||
val move = if (isShowing) -((bottom_player_bar?.height?.toFloat()
|
val move = if (isShowing) -((playerBinding?.bottomPlayerBar?.height?.toFloat()
|
||||||
?: 0f) + 40.toPx) else -sStyle.elevation.toPx.toFloat()
|
?: 0f) + 40.toPx) else -sStyle.elevation.toPx.toFloat()
|
||||||
ObjectAnimator.ofFloat(sView, "translationY", move).apply {
|
ObjectAnimator.ofFloat(sView, "translationY", move).apply {
|
||||||
duration = 200
|
duration = 200
|
||||||
|
@ -251,23 +250,25 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
val playerSourceMove = if (isShowing) 0f else -50.toPx.toFloat()
|
val playerSourceMove = if (isShowing) 0f else -50.toPx.toFloat()
|
||||||
player_open_source?.let {
|
|
||||||
|
|
||||||
|
playerBinding?.apply {
|
||||||
|
playerOpenSource.let {
|
||||||
ObjectAnimator.ofFloat(it, "translationY", playerSourceMove).apply {
|
ObjectAnimator.ofFloat(it, "translationY", playerSourceMove).apply {
|
||||||
duration = 200
|
duration = 200
|
||||||
start()
|
start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!isLocked) {
|
if (!isLocked) {
|
||||||
player_ffwd_holder?.alpha = 1f
|
playerFfwdHolder.alpha = 1f
|
||||||
player_rew_holder?.alpha = 1f
|
playerRewHolder.alpha = 1f
|
||||||
// player_pause_play_holder?.alpha = 1f
|
// player_pause_play_holder?.alpha = 1f
|
||||||
shadow_overlay?.isVisible = true
|
shadowOverlay.isVisible = true
|
||||||
shadow_overlay?.startAnimation(fadeAnimation)
|
shadowOverlay.startAnimation(fadeAnimation)
|
||||||
player_ffwd_holder?.startAnimation(fadeAnimation)
|
playerFfwdHolder.startAnimation(fadeAnimation)
|
||||||
player_rew_holder?.startAnimation(fadeAnimation)
|
playerRewHolder.startAnimation(fadeAnimation)
|
||||||
player_pause_play?.startAnimation(fadeAnimation)
|
playerPausePlay.startAnimation(fadeAnimation)
|
||||||
|
|
||||||
/*if (isBuffering) {
|
/*if (isBuffering) {
|
||||||
player_pause_play?.isVisible = false
|
player_pause_play?.isVisible = false
|
||||||
|
@ -280,13 +281,15 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
//player_buffering?.startAnimation(fadeAnimation)
|
//player_buffering?.startAnimation(fadeAnimation)
|
||||||
}
|
}
|
||||||
|
|
||||||
bottom_player_bar?.startAnimation(fadeAnimation)
|
bottomPlayerBar.startAnimation(fadeAnimation)
|
||||||
player_open_source?.startAnimation(fadeAnimation)
|
playerOpenSource.startAnimation(fadeAnimation)
|
||||||
player_top_holder?.startAnimation(fadeAnimation)
|
playerTopHolder.startAnimation(fadeAnimation)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun subtitlesChanged() {
|
override fun subtitlesChanged() {
|
||||||
player_subtitle_offset_btt?.isGone = player.getCurrentPreferredSubtitle() == null
|
playerBinding?.playerSubtitleOffsetBtt?.isGone =
|
||||||
|
player.getCurrentPreferredSubtitle() == null
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun enterFullscreen() {
|
protected fun enterFullscreen() {
|
||||||
|
@ -332,7 +335,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
private fun setPlayBackSpeed(speed: Float) {
|
private fun setPlayBackSpeed(speed: Float) {
|
||||||
try {
|
try {
|
||||||
setKey(PLAYBACK_SPEED_KEY, speed)
|
setKey(PLAYBACK_SPEED_KEY, speed)
|
||||||
player_speed_btt?.text =
|
playerBinding?.playerSpeedBtt?.text =
|
||||||
getString(R.string.player_speed_text_format).format(speed)
|
getString(R.string.player_speed_text_format).format(speed)
|
||||||
.replace(".0x", "x")
|
.replace(".0x", "x")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -348,67 +351,68 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showSubtitleOffsetDialog() {
|
private fun showSubtitleOffsetDialog() {
|
||||||
context?.let { ctx ->
|
val ctx = context ?: return
|
||||||
|
|
||||||
|
val binding = SubtitleOffsetBinding.inflate(LayoutInflater.from(ctx), null, false)
|
||||||
|
|
||||||
val builder =
|
val builder =
|
||||||
AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
|
AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
|
||||||
.setView(R.layout.subtitle_offset)
|
.setView(binding.root)
|
||||||
val dialog = builder.create()
|
val dialog = builder.create()
|
||||||
dialog.show()
|
dialog.show()
|
||||||
|
|
||||||
val beforeOffset = subtitleDelay
|
val beforeOffset = subtitleDelay
|
||||||
|
|
||||||
val applyButton = dialog.findViewById<TextView>(R.id.apply_btt)!!
|
/*val applyButton = dialog.findViewById<TextView>(R.id.apply_btt)!!
|
||||||
val cancelButton = dialog.findViewById<TextView>(R.id.cancel_btt)!!
|
val cancelButton = dialog.findViewById<TextView>(R.id.cancel_btt)!!
|
||||||
val input = dialog.findViewById<EditText>(R.id.subtitle_offset_input)!!
|
val input = dialog.findViewById<EditText>(R.id.subtitle_offset_input)!!
|
||||||
val sub = dialog.findViewById<ImageView>(R.id.subtitle_offset_subtract)!!
|
val sub = dialog.findViewById<ImageView>(R.id.subtitle_offset_subtract)!!
|
||||||
val subMore = dialog.findViewById<ImageView>(R.id.subtitle_offset_subtract_more)!!
|
val subMore = dialog.findViewById<ImageView>(R.id.subtitle_offset_subtract_more)!!
|
||||||
val add = dialog.findViewById<ImageView>(R.id.subtitle_offset_add)!!
|
val add = dialog.findViewById<ImageView>(R.id.subtitle_offset_add)!!
|
||||||
val addMore = dialog.findViewById<ImageView>(R.id.subtitle_offset_add_more)!!
|
val addMore = dialog.findViewById<ImageView>(R.id.subtitle_offset_add_more)!!
|
||||||
val subTitle = dialog.findViewById<TextView>(R.id.subtitle_offset_sub_title)!!
|
val subTitle = dialog.findViewById<TextView>(R.id.subtitle_offset_sub_title)!!*/
|
||||||
|
binding.apply {
|
||||||
|
subtitleOffsetInput.doOnTextChanged { text, _, _, _ ->
|
||||||
|
text?.toString()?.toLongOrNull()?.let { time ->
|
||||||
|
subtitleDelay = time
|
||||||
|
val str = when {
|
||||||
|
time > 0L -> {
|
||||||
|
txt(R.string.subtitle_offset_extra_hint_later_format, time)
|
||||||
|
}
|
||||||
|
|
||||||
input.doOnTextChanged { text, _, _, _ ->
|
time < 0L -> {
|
||||||
text?.toString()?.toLongOrNull()?.let {
|
txt(R.string.subtitle_offset_extra_hint_before_format, -time)
|
||||||
subtitleDelay = it
|
|
||||||
when {
|
|
||||||
it > 0L -> {
|
|
||||||
context?.getString(R.string.subtitle_offset_extra_hint_later_format)
|
|
||||||
?.format(it)
|
|
||||||
}
|
|
||||||
it < 0L -> {
|
|
||||||
context?.getString(R.string.subtitle_offset_extra_hint_before_format)
|
|
||||||
?.format(-it)
|
|
||||||
}
|
|
||||||
it == 0L -> {
|
|
||||||
context?.getString(R.string.subtitle_offset_extra_hint_none_format)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
null
|
txt(R.string.subtitle_offset_extra_hint_none_format)
|
||||||
}
|
|
||||||
}?.let { str ->
|
|
||||||
subTitle.text = str
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
subtitleOffsetSubTitle.setText(str)
|
||||||
}
|
}
|
||||||
input.text = Editable.Factory.getInstance()?.newEditable(beforeOffset.toString())
|
}
|
||||||
|
subtitleOffsetInput.text =
|
||||||
|
Editable.Factory.getInstance()?.newEditable(beforeOffset.toString())
|
||||||
|
|
||||||
val buttonChange = 100L
|
val buttonChange = 100L
|
||||||
val buttonChangeMore = 1000L
|
val buttonChangeMore = 1000L
|
||||||
|
|
||||||
fun changeBy(by: Long) {
|
fun changeBy(by: Long) {
|
||||||
val current = (input.text?.toString()?.toLongOrNull() ?: 0) + by
|
val current = (subtitleOffsetInput.text?.toString()?.toLongOrNull() ?: 0) + by
|
||||||
input.text = Editable.Factory.getInstance()?.newEditable(current.toString())
|
subtitleOffsetInput.text =
|
||||||
|
Editable.Factory.getInstance()?.newEditable(current.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
add.setOnClickListener {
|
subtitleOffsetAdd.setOnClickListener {
|
||||||
changeBy(buttonChange)
|
changeBy(buttonChange)
|
||||||
}
|
}
|
||||||
addMore.setOnClickListener {
|
subtitleOffsetAddMore.setOnClickListener {
|
||||||
changeBy(buttonChangeMore)
|
changeBy(buttonChangeMore)
|
||||||
}
|
}
|
||||||
sub.setOnClickListener {
|
subtitleOffsetSubtract.setOnClickListener {
|
||||||
changeBy(-buttonChange)
|
changeBy(-buttonChange)
|
||||||
}
|
}
|
||||||
subMore.setOnClickListener {
|
subtitleOffsetSubtractMore.setOnClickListener {
|
||||||
changeBy(-buttonChangeMore)
|
changeBy(-buttonChangeMore)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,17 +420,18 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
if (isFullScreenPlayer)
|
if (isFullScreenPlayer)
|
||||||
activity?.hideSystemUI()
|
activity?.hideSystemUI()
|
||||||
}
|
}
|
||||||
applyButton.setOnClickListener {
|
applyBtt.setOnClickListener {
|
||||||
dialog.dismissSafe(activity)
|
dialog.dismissSafe(activity)
|
||||||
player.seekTime(1L)
|
player.seekTime(1L)
|
||||||
}
|
}
|
||||||
cancelButton.setOnClickListener {
|
cancelBtt.setOnClickListener {
|
||||||
subtitleDelay = beforeOffset
|
subtitleDelay = beforeOffset
|
||||||
dialog.dismissSafe(activity)
|
dialog.dismissSafe(activity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun showSpeedDialog() {
|
private fun showSpeedDialog() {
|
||||||
val speedsText =
|
val speedsText =
|
||||||
listOf(
|
listOf(
|
||||||
|
@ -463,22 +468,23 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetRewindText() {
|
fun resetRewindText() {
|
||||||
exo_rew_text?.text =
|
playerBinding?.exoRewText?.text =
|
||||||
getString(R.string.rew_text_regular_format).format(fastForwardTime / 1000)
|
getString(R.string.rew_text_regular_format).format(fastForwardTime / 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetFastForwardText() {
|
fun resetFastForwardText() {
|
||||||
exo_ffwd_text?.text =
|
playerBinding?.exoFfwdText?.text =
|
||||||
getString(R.string.ffw_text_regular_format).format(fastForwardTime / 1000)
|
getString(R.string.ffw_text_regular_format).format(fastForwardTime / 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun rewind() {
|
private fun rewind() {
|
||||||
try {
|
try {
|
||||||
player_center_menu?.isGone = false
|
playerBinding?.apply {
|
||||||
player_rew_holder?.alpha = 1f
|
playerCenterMenu.isGone = false
|
||||||
|
playerRewHolder.alpha = 1f
|
||||||
|
|
||||||
val rotateLeft = AnimationUtils.loadAnimation(context, R.anim.rotate_left)
|
val rotateLeft = AnimationUtils.loadAnimation(context, R.anim.rotate_left)
|
||||||
exo_rew?.startAnimation(rotateLeft)
|
exoRew.startAnimation(rotateLeft)
|
||||||
|
|
||||||
val goLeft = AnimationUtils.loadAnimation(context, R.anim.go_left)
|
val goLeft = AnimationUtils.loadAnimation(context, R.anim.go_left)
|
||||||
goLeft.setAnimationListener(object : Animation.AnimationListener {
|
goLeft.setAnimationListener(object : Animation.AnimationListener {
|
||||||
|
@ -487,15 +493,17 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
override fun onAnimationRepeat(animation: Animation?) {}
|
override fun onAnimationRepeat(animation: Animation?) {}
|
||||||
|
|
||||||
override fun onAnimationEnd(animation: Animation?) {
|
override fun onAnimationEnd(animation: Animation?) {
|
||||||
exo_rew_text?.post {
|
exoRewText.post {
|
||||||
resetRewindText()
|
resetRewindText()
|
||||||
player_center_menu?.isGone = !isShowing
|
playerCenterMenu.isGone = !isShowing
|
||||||
player_rew_holder?.alpha = if (isShowing) 1f else 0f
|
playerRewHolder.alpha = if (isShowing) 1f else 0f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
exo_rew_text?.startAnimation(goLeft)
|
exoRewText.startAnimation(goLeft)
|
||||||
exo_rew_text?.text = getString(R.string.rew_text_format).format(fastForwardTime / 1000)
|
exoRewText.text =
|
||||||
|
getString(R.string.rew_text_format).format(fastForwardTime / 1000)
|
||||||
|
}
|
||||||
player.seekTime(-fastForwardTime)
|
player.seekTime(-fastForwardTime)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
logError(e)
|
||||||
|
@ -504,11 +512,12 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
|
|
||||||
private fun fastForward() {
|
private fun fastForward() {
|
||||||
try {
|
try {
|
||||||
player_center_menu?.isGone = false
|
playerBinding?.apply {
|
||||||
player_ffwd_holder?.alpha = 1f
|
playerCenterMenu.isGone = false
|
||||||
|
playerFfwdHolder.alpha = 1f
|
||||||
|
|
||||||
val rotateRight = AnimationUtils.loadAnimation(context, R.anim.rotate_right)
|
val rotateRight = AnimationUtils.loadAnimation(context, R.anim.rotate_right)
|
||||||
exo_ffwd?.startAnimation(rotateRight)
|
exoFfwd.startAnimation(rotateRight)
|
||||||
|
|
||||||
val goRight = AnimationUtils.loadAnimation(context, R.anim.go_right)
|
val goRight = AnimationUtils.loadAnimation(context, R.anim.go_right)
|
||||||
goRight.setAnimationListener(object : Animation.AnimationListener {
|
goRight.setAnimationListener(object : Animation.AnimationListener {
|
||||||
|
@ -517,15 +526,17 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
override fun onAnimationRepeat(animation: Animation?) {}
|
override fun onAnimationRepeat(animation: Animation?) {}
|
||||||
|
|
||||||
override fun onAnimationEnd(animation: Animation?) {
|
override fun onAnimationEnd(animation: Animation?) {
|
||||||
exo_ffwd_text?.post {
|
exoFfwdText.post {
|
||||||
resetFastForwardText()
|
resetFastForwardText()
|
||||||
player_center_menu?.isGone = !isShowing
|
playerCenterMenu.isGone = !isShowing
|
||||||
player_ffwd_holder?.alpha = if (isShowing) 1f else 0f
|
playerFfwdHolder.alpha = if (isShowing) 1f else 0f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
exo_ffwd_text?.startAnimation(goRight)
|
exoFfwdText.startAnimation(goRight)
|
||||||
exo_ffwd_text?.text = getString(R.string.ffw_text_format).format(fastForwardTime / 1000)
|
exoFfwdText.text =
|
||||||
|
getString(R.string.ffw_text_format).format(fastForwardTime / 1000)
|
||||||
|
}
|
||||||
player.seekTime(fastForwardTime)
|
player.seekTime(fastForwardTime)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
logError(e)
|
||||||
|
@ -535,13 +546,13 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
private fun onClickChange() {
|
private fun onClickChange() {
|
||||||
isShowing = !isShowing
|
isShowing = !isShowing
|
||||||
if (isShowing) {
|
if (isShowing) {
|
||||||
player_intro_play?.isGone = true
|
playerBinding?.playerIntroPlay?.isGone = true
|
||||||
autoHide()
|
autoHide()
|
||||||
}
|
}
|
||||||
if (isFullScreenPlayer)
|
if (isFullScreenPlayer)
|
||||||
activity?.hideSystemUI()
|
activity?.hideSystemUI()
|
||||||
animateLayoutChanges()
|
animateLayoutChanges()
|
||||||
player_pause_play?.requestFocus()
|
playerBinding?.playerPausePlay?.requestFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleLock() {
|
private fun toggleLock() {
|
||||||
|
@ -551,7 +562,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
|
|
||||||
isLocked = !isLocked
|
isLocked = !isLocked
|
||||||
if (isLocked && isShowing) {
|
if (isLocked && isShowing) {
|
||||||
player_holder?.postDelayed({
|
playerBinding?.playerHolder?.postDelayed({
|
||||||
if (isLocked && isShowing) {
|
if (isLocked && isShowing) {
|
||||||
onClickChange()
|
onClickChange()
|
||||||
}
|
}
|
||||||
|
@ -559,8 +570,8 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
val fadeTo = if (isLocked) 0f else 1f
|
val fadeTo = if (isLocked) 0f else 1f
|
||||||
|
playerBinding?.apply {
|
||||||
val fadeAnimation = AlphaAnimation(player_video_title.alpha, fadeTo).apply {
|
val fadeAnimation = AlphaAnimation(playerVideoTitle.alpha, fadeTo).apply {
|
||||||
duration = 100
|
duration = 100
|
||||||
fillAfter = true
|
fillAfter = true
|
||||||
}
|
}
|
||||||
|
@ -568,9 +579,9 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
updateUIVisibility()
|
updateUIVisibility()
|
||||||
// MENUS
|
// MENUS
|
||||||
//centerMenu.startAnimation(fadeAnimation)
|
//centerMenu.startAnimation(fadeAnimation)
|
||||||
player_pause_play?.startAnimation(fadeAnimation)
|
playerPausePlay.startAnimation(fadeAnimation)
|
||||||
player_ffwd_holder?.startAnimation(fadeAnimation)
|
playerFfwdHolder.startAnimation(fadeAnimation)
|
||||||
player_rew_holder?.startAnimation(fadeAnimation)
|
playerRewHolder.startAnimation(fadeAnimation)
|
||||||
|
|
||||||
//if (hasEpisodes)
|
//if (hasEpisodes)
|
||||||
// player_episodes_button?.startAnimation(fadeAnimation)
|
// player_episodes_button?.startAnimation(fadeAnimation)
|
||||||
|
@ -578,17 +589,17 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
//video_bar.startAnimation(fadeAnimation)
|
//video_bar.startAnimation(fadeAnimation)
|
||||||
|
|
||||||
//TITLE
|
//TITLE
|
||||||
player_video_title_rez?.startAnimation(fadeAnimation)
|
playerVideoTitleRez.startAnimation(fadeAnimation)
|
||||||
player_episode_filler?.startAnimation(fadeAnimation)
|
playerEpisodeFiller.startAnimation(fadeAnimation)
|
||||||
player_video_title?.startAnimation(fadeAnimation)
|
playerVideoTitle.startAnimation(fadeAnimation)
|
||||||
player_top_holder?.startAnimation(fadeAnimation)
|
playerTopHolder.startAnimation(fadeAnimation)
|
||||||
// BOTTOM
|
// BOTTOM
|
||||||
player_lock_holder?.startAnimation(fadeAnimation)
|
playerLockHolder.startAnimation(fadeAnimation)
|
||||||
//player_go_back_holder?.startAnimation(fadeAnimation)
|
//player_go_back_holder?.startAnimation(fadeAnimation)
|
||||||
|
|
||||||
shadow_overlay?.isVisible = true
|
shadowOverlay.isVisible = true
|
||||||
shadow_overlay?.startAnimation(fadeAnimation)
|
shadowOverlay.startAnimation(fadeAnimation)
|
||||||
|
}
|
||||||
updateLockUI()
|
updateLockUI()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,43 +613,48 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
togglePlayerTitleGone = true
|
togglePlayerTitleGone = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
player_lock_holder?.isGone = isGone
|
playerBinding?.apply {
|
||||||
player_video_bar?.isGone = isGone
|
|
||||||
|
|
||||||
player_pause_play?.isGone = isGone
|
playerLockHolder.isGone = isGone
|
||||||
|
playerVideoBar.isGone = isGone
|
||||||
|
|
||||||
|
playerPausePlay.isGone = isGone
|
||||||
//player_buffering?.isGone = isGone
|
//player_buffering?.isGone = isGone
|
||||||
player_top_holder?.isGone = isGone
|
playerTopHolder.isGone = isGone
|
||||||
//player_episodes_button?.isVisible = !isGone && hasEpisodes
|
//player_episodes_button?.isVisible = !isGone && hasEpisodes
|
||||||
player_video_title?.isGone = togglePlayerTitleGone
|
playerVideoTitle.isGone = togglePlayerTitleGone
|
||||||
// player_video_title_rez?.isGone = isGone
|
// player_video_title_rez?.isGone = isGone
|
||||||
player_episode_filler?.isGone = isGone
|
playerEpisodeFiller.isGone = isGone
|
||||||
player_center_menu?.isGone = isGone
|
playerCenterMenu.isGone = isGone
|
||||||
player_lock?.isGone = !isShowing
|
playerLock.isGone = !isShowing
|
||||||
//player_media_route_button?.isClickable = !isGone
|
//player_media_route_button?.isClickable = !isGone
|
||||||
player_go_back_holder?.isGone = isGone
|
playerGoBackHolder.isGone = isGone
|
||||||
player_sources_btt?.isGone = isGone
|
playerSourcesBtt.isGone = isGone
|
||||||
player_skip_episode?.isClickable = !isGone
|
playerSkipEpisode.isClickable = !isGone
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateLockUI() {
|
private fun updateLockUI() {
|
||||||
player_lock?.setIconResource(if (isLocked) R.drawable.video_locked else R.drawable.video_unlocked)
|
playerBinding?.apply {
|
||||||
|
playerLock.setIconResource(if (isLocked) R.drawable.video_locked else R.drawable.video_unlocked)
|
||||||
if (layout == R.layout.fragment_player) {
|
if (layout == R.layout.fragment_player) {
|
||||||
val color = if (isLocked) context?.colorFromAttribute(R.attr.colorPrimary)
|
val color = if (isLocked) context?.colorFromAttribute(R.attr.colorPrimary)
|
||||||
else Color.WHITE
|
else Color.WHITE
|
||||||
if (color != null) {
|
if (color != null) {
|
||||||
player_lock?.setTextColor(color)
|
playerLock.setTextColor(color)
|
||||||
player_lock?.iconTint = ColorStateList.valueOf(color)
|
playerLock.iconTint = ColorStateList.valueOf(color)
|
||||||
player_lock?.rippleColor =
|
playerLock.rippleColor =
|
||||||
ColorStateList.valueOf(Color.argb(50, color.red, color.green, color.blue))
|
ColorStateList.valueOf(Color.argb(50, color.red, color.green, color.blue))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var currentTapIndex = 0
|
private var currentTapIndex = 0
|
||||||
protected fun autoHide() {
|
protected fun autoHide() {
|
||||||
currentTapIndex++
|
currentTapIndex++
|
||||||
val index = currentTapIndex
|
val index = currentTapIndex
|
||||||
player_holder?.postDelayed({
|
playerBinding?.playerHolder?.postDelayed({
|
||||||
if (!isCurrentTouchValid && isShowing && index == currentTapIndex && player.getIsPlaying()) {
|
if (!isCurrentTouchValid && isShowing && index == currentTapIndex && player.getIsPlaying()) {
|
||||||
onClickChange()
|
onClickChange()
|
||||||
}
|
}
|
||||||
|
@ -650,7 +666,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
private fun toggleShowDelayed() {
|
private fun toggleShowDelayed() {
|
||||||
if (doubleTapEnabled || doubleTapPauseEnabled) {
|
if (doubleTapEnabled || doubleTapPauseEnabled) {
|
||||||
val index = currentDoubleTapIndex
|
val index = currentDoubleTapIndex
|
||||||
player_holder?.postDelayed({
|
playerBinding?.playerHolder?.postDelayed({
|
||||||
if (index == currentDoubleTapIndex) {
|
if (index == currentDoubleTapIndex) {
|
||||||
onClickChange()
|
onClickChange()
|
||||||
}
|
}
|
||||||
|
@ -781,7 +797,10 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
if (event == null || view == null) return false
|
if (event == null || view == null) return false
|
||||||
val currentTouch = Vector2(event.x, event.y)
|
val currentTouch = Vector2(event.x, event.y)
|
||||||
val startTouch = currentTouchStart
|
val startTouch = currentTouchStart
|
||||||
player_intro_play?.isGone = true
|
|
||||||
|
playerBinding?.apply {
|
||||||
|
playerIntroPlay.isGone = true
|
||||||
|
|
||||||
when (event.action) {
|
when (event.action) {
|
||||||
MotionEvent.ACTION_DOWN -> {
|
MotionEvent.ACTION_DOWN -> {
|
||||||
// validates if the touch is inside of the player area
|
// validates if the touch is inside of the player area
|
||||||
|
@ -807,13 +826,18 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MotionEvent.ACTION_UP -> {
|
MotionEvent.ACTION_UP -> {
|
||||||
if (isCurrentTouchValid && !isLocked && isFullScreenPlayer) {
|
if (isCurrentTouchValid && !isLocked && isFullScreenPlayer) {
|
||||||
// seek time
|
// seek time
|
||||||
if (swipeHorizontalEnabled && currentTouchAction == TouchAction.Time) {
|
if (swipeHorizontalEnabled && currentTouchAction == TouchAction.Time) {
|
||||||
val startTime = currentTouchStartPlayerTime
|
val startTime = currentTouchStartPlayerTime
|
||||||
if (startTime != null) {
|
if (startTime != null) {
|
||||||
calculateNewTime(startTime, startTouch, currentTouch)?.let { seekTo ->
|
calculateNewTime(
|
||||||
|
startTime,
|
||||||
|
startTouch,
|
||||||
|
currentTouch
|
||||||
|
)?.let { seekTo ->
|
||||||
if (abs(seekTo - startTime) > MINIMUM_SEEK_TIME) {
|
if (abs(seekTo - startTime) > MINIMUM_SEEK_TIME) {
|
||||||
player.seekTo(seekTo)
|
player.seekTo(seekTo)
|
||||||
}
|
}
|
||||||
|
@ -843,10 +867,12 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
if (doubleTapEnabled)
|
if (doubleTapEnabled)
|
||||||
rewind()
|
rewind()
|
||||||
}
|
}
|
||||||
|
|
||||||
currentTouch.x > screenWidth / 2 + (DOUBLE_TAB_PAUSE_PERCENTAGE * screenWidth) -> {
|
currentTouch.x > screenWidth / 2 + (DOUBLE_TAB_PAUSE_PERCENTAGE * screenWidth) -> {
|
||||||
if (doubleTapEnabled)
|
if (doubleTapEnabled)
|
||||||
fastForward()
|
fastForward()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
player.handleEvent(CSPlayerEvent.PlayPauseToggle)
|
player.handleEvent(CSPlayerEvent.PlayPauseToggle)
|
||||||
}
|
}
|
||||||
|
@ -882,11 +908,13 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
currentTouchStartTime = null
|
currentTouchStartTime = null
|
||||||
|
|
||||||
// resets UI
|
// resets UI
|
||||||
player_time_text?.isVisible = false
|
playerTimeText.isVisible = false
|
||||||
player_progressbar_left_holder?.isVisible = false
|
playerProgressbarLeftHolder.isVisible = false
|
||||||
player_progressbar_right_holder?.isVisible = false
|
playerProgressbarRightHolder.isVisible = false
|
||||||
|
|
||||||
currentLastTouchEndTime = System.currentTimeMillis()
|
currentLastTouchEndTime = System.currentTimeMillis()
|
||||||
}
|
}
|
||||||
|
|
||||||
MotionEvent.ACTION_MOVE -> {
|
MotionEvent.ACTION_MOVE -> {
|
||||||
// if current touch is valid
|
// if current touch is valid
|
||||||
if (startTouch != null && isCurrentTouchValid && !isLocked && isFullScreenPlayer) {
|
if (startTouch != null && isCurrentTouchValid && !isLocked && isFullScreenPlayer) {
|
||||||
|
@ -925,9 +953,9 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
diffFromLast.y * VERTICAL_MULTIPLIER / screenHeight.toFloat()
|
diffFromLast.y * VERTICAL_MULTIPLIER / screenHeight.toFloat()
|
||||||
|
|
||||||
// update UI
|
// update UI
|
||||||
player_time_text?.isVisible = false
|
playerTimeText.isVisible = false
|
||||||
player_progressbar_left_holder?.isVisible = false
|
playerProgressbarLeftHolder.isVisible = false
|
||||||
player_progressbar_right_holder?.isVisible = false
|
playerProgressbarRightHolder.isVisible = false
|
||||||
|
|
||||||
when (currentTouchAction) {
|
when (currentTouchAction) {
|
||||||
TouchAction.Time -> {
|
TouchAction.Time -> {
|
||||||
|
@ -942,16 +970,19 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
currentTouch
|
currentTouch
|
||||||
)?.let { newMs ->
|
)?.let { newMs ->
|
||||||
val skipMs = newMs - startTime
|
val skipMs = newMs - startTime
|
||||||
player_time_text?.text =
|
playerTimeText.apply {
|
||||||
|
text =
|
||||||
"${convertTimeToString(newMs / 1000)} [${
|
"${convertTimeToString(newMs / 1000)} [${
|
||||||
(if (abs(skipMs) < 1000) "" else (if (skipMs > 0) "+" else "-"))
|
(if (abs(skipMs) < 1000) "" else (if (skipMs > 0) "+" else "-"))
|
||||||
}${convertTimeToString(abs(skipMs / 1000))}]"
|
}${convertTimeToString(abs(skipMs / 1000))}]"
|
||||||
player_time_text?.isVisible = true
|
isVisible = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TouchAction.Brightness -> {
|
TouchAction.Brightness -> {
|
||||||
player_progressbar_right_holder?.isVisible = true
|
playerProgressbarRightHolder.isVisible = true
|
||||||
val lastRequested = currentRequestedBrightness
|
val lastRequested = currentRequestedBrightness
|
||||||
currentRequestedBrightness =
|
currentRequestedBrightness =
|
||||||
min(
|
min(
|
||||||
|
@ -964,11 +995,11 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
setBrightness(currentRequestedBrightness)
|
setBrightness(currentRequestedBrightness)
|
||||||
|
|
||||||
// max is set high to make it smooth
|
// max is set high to make it smooth
|
||||||
player_progressbar_right?.max = 100_000
|
playerProgressbarRight.max = 100_000
|
||||||
player_progressbar_right?.progress =
|
playerProgressbarRight.progress =
|
||||||
max(2_000, (currentRequestedBrightness * 100_000f).toInt())
|
max(2_000, (currentRequestedBrightness * 100_000f).toInt())
|
||||||
|
|
||||||
player_progressbar_right_icon?.setImageResource(
|
playerProgressbarRightIcon.setImageResource(
|
||||||
brightnessIcons[min( // clamp the value just in case
|
brightnessIcons[min( // clamp the value just in case
|
||||||
brightnessIcons.size - 1,
|
brightnessIcons.size - 1,
|
||||||
max(
|
max(
|
||||||
|
@ -978,9 +1009,10 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
TouchAction.Volume -> {
|
TouchAction.Volume -> {
|
||||||
(activity?.getSystemService(Context.AUDIO_SERVICE) as? AudioManager)?.let { audioManager ->
|
(activity?.getSystemService(Context.AUDIO_SERVICE) as? AudioManager)?.let { audioManager ->
|
||||||
player_progressbar_left_holder?.isVisible = true
|
playerProgressbarLeftHolder.isVisible = true
|
||||||
val maxVolume =
|
val maxVolume =
|
||||||
audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
|
audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
|
||||||
val currentVolume =
|
val currentVolume =
|
||||||
|
@ -994,11 +1026,11 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
)
|
)
|
||||||
|
|
||||||
// max is set high to make it smooth
|
// max is set high to make it smooth
|
||||||
player_progressbar_left?.max = 100_000
|
playerProgressbarLeft.max = 100_000
|
||||||
player_progressbar_left?.progress =
|
playerProgressbarLeft.progress =
|
||||||
max(2_000, (currentRequestedVolume * 100_000f).toInt())
|
max(2_000, (currentRequestedVolume * 100_000f).toInt())
|
||||||
|
|
||||||
player_progressbar_left_icon?.setImageResource(
|
playerProgressbarLeftIcon.setImageResource(
|
||||||
volumeIcons[min( // clamp the value just in case
|
volumeIcons[min( // clamp the value just in case
|
||||||
volumeIcons.size - 1,
|
volumeIcons.size - 1,
|
||||||
max(
|
max(
|
||||||
|
@ -1023,12 +1055,14 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
currentTouchLast = currentTouch
|
currentTouchLast = currentTouch
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -1048,26 +1082,29 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent.KEYCODE_DPAD_UP -> {
|
KeyEvent.KEYCODE_DPAD_UP -> {
|
||||||
if (!isShowing) {
|
if (!isShowing) {
|
||||||
onClickChange()
|
onClickChange()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent.KEYCODE_DPAD_LEFT -> {
|
KeyEvent.KEYCODE_DPAD_LEFT -> {
|
||||||
if (!isShowing && !isLocked) {
|
if (!isShowing && !isLocked) {
|
||||||
player.seekTime(-androidTVInterfaceOffSeekTime)
|
player.seekTime(-androidTVInterfaceOffSeekTime)
|
||||||
return true
|
return true
|
||||||
} else if (player_pause_play?.isFocused == true) {
|
} else if (playerBinding?.playerPausePlay?.isFocused == true) {
|
||||||
player.seekTime(-androidTVInterfaceOnSeekTime)
|
player.seekTime(-androidTVInterfaceOnSeekTime)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
||||||
if (!isShowing && !isLocked) {
|
if (!isShowing && !isLocked) {
|
||||||
player.seekTime(androidTVInterfaceOffSeekTime)
|
player.seekTime(androidTVInterfaceOffSeekTime)
|
||||||
return true
|
return true
|
||||||
} else if (player_pause_play?.isFocused == true) {
|
} else if (playerBinding?.playerPausePlay?.isFocused == true) {
|
||||||
player.seekTime(androidTVInterfaceOnSeekTime)
|
player.seekTime(androidTVInterfaceOnSeekTime)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -1110,11 +1147,12 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
isShowing = false
|
isShowing = false
|
||||||
|
|
||||||
// if nothing has loaded these buttons should not be visible
|
// if nothing has loaded these buttons should not be visible
|
||||||
player_skip_episode?.isVisible = false
|
playerBinding?.apply {
|
||||||
player_tracks_btt?.isVisible = false
|
playerSkipEpisode.isVisible = false
|
||||||
player_skip_op?.isVisible = false
|
playerTracksBtt.isVisible = false
|
||||||
shadow_overlay?.isVisible = false
|
playerSkipOp.isVisible = false
|
||||||
|
shadowOverlay.isVisible = false
|
||||||
|
}
|
||||||
updateLockUI()
|
updateLockUI()
|
||||||
updateUIVisibility()
|
updateUIVisibility()
|
||||||
animateLayoutChanges()
|
animateLayoutChanges()
|
||||||
|
@ -1143,50 +1181,65 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
PlayerEventType.Lock -> {
|
PlayerEventType.Lock -> {
|
||||||
toggleLock()
|
toggleLock()
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.NextEpisode -> {
|
PlayerEventType.NextEpisode -> {
|
||||||
player.handleEvent(CSPlayerEvent.NextEpisode)
|
player.handleEvent(CSPlayerEvent.NextEpisode)
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.Pause -> {
|
PlayerEventType.Pause -> {
|
||||||
player.handleEvent(CSPlayerEvent.Pause)
|
player.handleEvent(CSPlayerEvent.Pause)
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.PlayPauseToggle -> {
|
PlayerEventType.PlayPauseToggle -> {
|
||||||
player.handleEvent(CSPlayerEvent.PlayPauseToggle)
|
player.handleEvent(CSPlayerEvent.PlayPauseToggle)
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.Play -> {
|
PlayerEventType.Play -> {
|
||||||
player.handleEvent(CSPlayerEvent.Play)
|
player.handleEvent(CSPlayerEvent.Play)
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.SkipCurrentChapter -> {
|
PlayerEventType.SkipCurrentChapter -> {
|
||||||
player.handleEvent(CSPlayerEvent.SkipCurrentChapter)
|
player.handleEvent(CSPlayerEvent.SkipCurrentChapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.Resize -> {
|
PlayerEventType.Resize -> {
|
||||||
nextResize()
|
nextResize()
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.PrevEpisode -> {
|
PlayerEventType.PrevEpisode -> {
|
||||||
player.handleEvent(CSPlayerEvent.PrevEpisode)
|
player.handleEvent(CSPlayerEvent.PrevEpisode)
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.SeekForward -> {
|
PlayerEventType.SeekForward -> {
|
||||||
player.handleEvent(CSPlayerEvent.SeekForward)
|
player.handleEvent(CSPlayerEvent.SeekForward)
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.ShowSpeed -> {
|
PlayerEventType.ShowSpeed -> {
|
||||||
showSpeedDialog()
|
showSpeedDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.SeekBack -> {
|
PlayerEventType.SeekBack -> {
|
||||||
player.handleEvent(CSPlayerEvent.SeekBack)
|
player.handleEvent(CSPlayerEvent.SeekBack)
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.ToggleMute -> {
|
PlayerEventType.ToggleMute -> {
|
||||||
player.handleEvent(CSPlayerEvent.ToggleMute)
|
player.handleEvent(CSPlayerEvent.ToggleMute)
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.ToggleHide -> {
|
PlayerEventType.ToggleHide -> {
|
||||||
onClickChange()
|
onClickChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.ShowMirrors -> {
|
PlayerEventType.ShowMirrors -> {
|
||||||
showMirrorsDialogue()
|
showMirrorsDialogue()
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.SearchSubtitlesOnline -> {
|
PlayerEventType.SearchSubtitlesOnline -> {
|
||||||
if (subsProvidersIsActive) {
|
if (subsProvidersIsActive) {
|
||||||
openOnlineSubPicker(view.context, null) {}
|
openOnlineSubPicker(view.context, null) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerEventType.SkipOp -> {
|
PlayerEventType.SkipOp -> {
|
||||||
skipOp()
|
skipOp()
|
||||||
}
|
}
|
||||||
|
@ -1281,94 +1334,98 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
// useSystemBrightness =
|
// useSystemBrightness =
|
||||||
// settingsManager.getBoolean(ctx.getString(R.string.use_system_brightness_key), false)
|
// settingsManager.getBoolean(ctx.getString(R.string.use_system_brightness_key), false)
|
||||||
}
|
}
|
||||||
|
playerBinding?.apply {
|
||||||
player_speed_btt?.isVisible = playBackSpeedEnabled
|
playerSpeedBtt.isVisible = playBackSpeedEnabled
|
||||||
player_resize_btt?.isVisible = playerResizeEnabled
|
playerResizeBtt.isVisible = playerResizeEnabled
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
logError(e)
|
||||||
}
|
}
|
||||||
|
playerBinding?.apply {
|
||||||
player_pause_play?.setOnClickListener {
|
playerPausePlay.setOnClickListener {
|
||||||
autoHide()
|
autoHide()
|
||||||
player.handleEvent(CSPlayerEvent.PlayPauseToggle)
|
player.handleEvent(CSPlayerEvent.PlayPauseToggle)
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_chapter_button?.setOnClickListener {
|
skipChapterButton.setOnClickListener {
|
||||||
player.handleEvent(CSPlayerEvent.SkipCurrentChapter)
|
player.handleEvent(CSPlayerEvent.SkipCurrentChapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// init clicks
|
// init clicks
|
||||||
player_resize_btt?.setOnClickListener {
|
playerResizeBtt.setOnClickListener {
|
||||||
autoHide()
|
autoHide()
|
||||||
nextResize()
|
nextResize()
|
||||||
}
|
}
|
||||||
|
|
||||||
player_speed_btt?.setOnClickListener {
|
playerSpeedBtt.setOnClickListener {
|
||||||
autoHide()
|
autoHide()
|
||||||
showSpeedDialog()
|
showSpeedDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
player_skip_op?.setOnClickListener {
|
playerSkipOp.setOnClickListener {
|
||||||
autoHide()
|
autoHide()
|
||||||
skipOp()
|
skipOp()
|
||||||
}
|
}
|
||||||
|
|
||||||
player_skip_episode?.setOnClickListener {
|
playerSkipEpisode.setOnClickListener {
|
||||||
autoHide()
|
autoHide()
|
||||||
player.handleEvent(CSPlayerEvent.NextEpisode)
|
player.handleEvent(CSPlayerEvent.NextEpisode)
|
||||||
}
|
}
|
||||||
|
|
||||||
player_lock?.setOnClickListener {
|
playerLock.setOnClickListener {
|
||||||
autoHide()
|
autoHide()
|
||||||
toggleLock()
|
toggleLock()
|
||||||
}
|
}
|
||||||
|
|
||||||
player_subtitle_offset_btt?.setOnClickListener {
|
playerSubtitleOffsetBtt.setOnClickListener {
|
||||||
showSubtitleOffsetDialog()
|
showSubtitleOffsetDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
exo_rew?.setOnClickListener {
|
exoRew.setOnClickListener {
|
||||||
autoHide()
|
autoHide()
|
||||||
rewind()
|
rewind()
|
||||||
}
|
}
|
||||||
|
|
||||||
exo_ffwd?.setOnClickListener {
|
exoFfwd.setOnClickListener {
|
||||||
autoHide()
|
autoHide()
|
||||||
fastForward()
|
fastForward()
|
||||||
}
|
}
|
||||||
|
|
||||||
player_go_back?.setOnClickListener {
|
playerGoBack.setOnClickListener {
|
||||||
activity?.popCurrentPage()
|
activity?.popCurrentPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
player_sources_btt?.setOnClickListener {
|
playerSourcesBtt.setOnClickListener {
|
||||||
showMirrorsDialogue()
|
showMirrorsDialogue()
|
||||||
}
|
}
|
||||||
|
|
||||||
player_tracks_btt?.setOnClickListener {
|
playerTracksBtt.setOnClickListener {
|
||||||
showTracksDialogue()
|
showTracksDialogue()
|
||||||
}
|
}
|
||||||
|
|
||||||
// it is !not! a bug that you cant touch the right side, it does not register inputs on navbar or status bar
|
// it is !not! a bug that you cant touch the right side, it does not register inputs on navbar or status bar
|
||||||
player_holder?.setOnTouchListener { callView, event ->
|
playerHolder.setOnTouchListener { callView, event ->
|
||||||
return@setOnTouchListener handleMotionEvent(callView, event)
|
return@setOnTouchListener handleMotionEvent(callView, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
exo_progress?.setOnTouchListener { _, event ->
|
exoProgress.setOnTouchListener { _, event ->
|
||||||
// this makes the bar not disappear when sliding
|
// this makes the bar not disappear when sliding
|
||||||
when (event.action) {
|
when (event.action) {
|
||||||
MotionEvent.ACTION_DOWN -> {
|
MotionEvent.ACTION_DOWN -> {
|
||||||
currentTapIndex++
|
currentTapIndex++
|
||||||
}
|
}
|
||||||
|
|
||||||
MotionEvent.ACTION_MOVE -> {
|
MotionEvent.ACTION_MOVE -> {
|
||||||
currentTapIndex++
|
currentTapIndex++
|
||||||
}
|
}
|
||||||
|
|
||||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_BUTTON_RELEASE -> {
|
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_BUTTON_RELEASE -> {
|
||||||
autoHide()
|
autoHide()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return@setOnTouchListener false
|
return@setOnTouchListener false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// init UI
|
// init UI
|
||||||
try {
|
try {
|
||||||
uiReset()
|
uiReset()
|
||||||
|
|
|
@ -92,7 +92,6 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
private var preferredAutoSelectSubtitles: String? = null // null means do nothing, "" means none
|
private var preferredAutoSelectSubtitles: String? = null // null means do nothing, "" means none
|
||||||
|
|
||||||
private var binding: FragmentPlayerBinding? = null
|
private var binding: FragmentPlayerBinding? = null
|
||||||
private var playerBinding: PlayerCustomLayoutBinding? = null
|
|
||||||
|
|
||||||
private fun startLoading() {
|
private fun startLoading() {
|
||||||
player.release()
|
player.release()
|
||||||
|
@ -1236,15 +1235,11 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
unwrapBundle(arguments)
|
unwrapBundle(arguments)
|
||||||
|
|
||||||
val root = super.onCreateView(inflater, container, savedInstanceState) ?: return null
|
val root = super.onCreateView(inflater, container, savedInstanceState) ?: return null
|
||||||
binding = FragmentPlayerBinding.bind(root).also { b ->
|
binding = FragmentPlayerBinding.bind(root)
|
||||||
playerBinding = PlayerCustomLayoutBinding.bind(b.playerView.findViewById(R.id.player_holder))
|
|
||||||
}
|
|
||||||
|
|
||||||
return root
|
return root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
playerBinding = null
|
|
||||||
binding = null
|
binding = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,26 +4,19 @@ import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.Intent.*
|
import android.content.Intent.*
|
||||||
import android.content.res.ColorStateList
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.AbsListView
|
|
||||||
import android.widget.ArrayAdapter
|
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.doOnTextChanged
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.discord.panels.OverlappingPanelsLayout
|
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import com.google.android.material.chip.ChipDrawable
|
import com.google.android.material.chip.ChipDrawable
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
||||||
|
@ -38,7 +31,6 @@ import com.lagradost.cloudstream3.TvType
|
||||||
import com.lagradost.cloudstream3.mvvm.*
|
import com.lagradost.cloudstream3.mvvm.*
|
||||||
import com.lagradost.cloudstream3.services.SubscriptionWorkManager
|
import com.lagradost.cloudstream3.services.SubscriptionWorkManager
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
|
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
|
||||||
import com.lagradost.cloudstream3.ui.WatchType
|
|
||||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
||||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
||||||
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
||||||
|
@ -53,7 +45,6 @@ import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getVideoWatchState
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getVideoWatchState
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||||
|
@ -364,7 +355,8 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
return@setOnLongClickListener true
|
return@setOnLongClickListener true
|
||||||
}
|
}
|
||||||
|
|
||||||
val show = viewModel.currentRepo?.api?.hasDownloadSupport == true && !isTvSettings()
|
val show =
|
||||||
|
viewModel.currentRepo?.api?.hasDownloadSupport == true && !isTvSettings()
|
||||||
if (show) {
|
if (show) {
|
||||||
download_button?.setDefaultClickListener(
|
download_button?.setDefaultClickListener(
|
||||||
VideoDownloadHelper.DownloadEpisodeCached(
|
VideoDownloadHelper.DownloadEpisodeCached(
|
||||||
|
@ -379,7 +371,6 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
)
|
)
|
||||||
) { click ->
|
) { click ->
|
||||||
println("Click:$click")
|
|
||||||
when (click.action) {
|
when (click.action) {
|
||||||
DOWNLOAD_ACTION_DOWNLOAD -> {
|
DOWNLOAD_ACTION_DOWNLOAD -> {
|
||||||
viewModel.handleAction(
|
viewModel.handleAction(
|
||||||
|
@ -393,7 +384,6 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
download_button?.isVisible = show
|
download_button?.isVisible = show
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,42 +583,6 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.watchStatus) { watchType ->
|
|
||||||
result_bookmark_button?.text = getString(watchType.stringRes)
|
|
||||||
result_bookmark_fab?.text = getString(watchType.stringRes)
|
|
||||||
|
|
||||||
if (watchType == WatchType.NONE) {
|
|
||||||
result_bookmark_fab?.context?.colorFromAttribute(R.attr.white)
|
|
||||||
} else {
|
|
||||||
result_bookmark_fab?.context?.colorFromAttribute(R.attr.colorPrimary)
|
|
||||||
}?.let {
|
|
||||||
val colorState = ColorStateList.valueOf(it)
|
|
||||||
result_bookmark_fab?.iconTint = colorState
|
|
||||||
result_bookmark_fab?.setTextColor(colorState)
|
|
||||||
}
|
|
||||||
|
|
||||||
result_bookmark_fab?.setOnClickListener { fab ->
|
|
||||||
activity?.showBottomDialog(
|
|
||||||
WatchType.values().map { fab.context.getString(it.stringRes) }.toList(),
|
|
||||||
watchType.ordinal,
|
|
||||||
fab.context.getString(R.string.action_add_to_bookmarks),
|
|
||||||
showApply = false,
|
|
||||||
{}) {
|
|
||||||
viewModel.updateWatchStatus(WatchType.values()[it])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result_bookmark_button?.setOnClickListener { fab ->
|
|
||||||
activity?.showBottomDialog(
|
|
||||||
WatchType.values().map { fab.context.getString(it.stringRes) }.toList(),
|
|
||||||
watchType.ordinal,
|
|
||||||
fab.context.getString(R.string.action_add_to_bookmarks),
|
|
||||||
showApply = false,
|
|
||||||
{}) {
|
|
||||||
viewModel.updateWatchStatus(WatchType.values()[it])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is to band-aid FireTV navigation
|
// This is to band-aid FireTV navigation
|
||||||
val isTv = isTvSettings()
|
val isTv = isTvSettings()
|
||||||
|
@ -636,152 +590,6 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
result_episode_select?.isFocusableInTouchMode = isTv
|
result_episode_select?.isFocusableInTouchMode = isTv
|
||||||
result_dub_select?.isFocusableInTouchMode = isTv
|
result_dub_select?.isFocusableInTouchMode = isTv
|
||||||
|
|
||||||
context?.let { ctx ->
|
|
||||||
val arrayAdapter = ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
|
||||||
/*
|
|
||||||
-1 -> None
|
|
||||||
0 -> Watching
|
|
||||||
1 -> Completed
|
|
||||||
2 -> OnHold
|
|
||||||
3 -> Dropped
|
|
||||||
4 -> PlanToWatch
|
|
||||||
5 -> ReWatching
|
|
||||||
*/
|
|
||||||
val items = listOf(
|
|
||||||
R.string.none,
|
|
||||||
R.string.type_watching,
|
|
||||||
R.string.type_completed,
|
|
||||||
R.string.type_on_hold,
|
|
||||||
R.string.type_dropped,
|
|
||||||
R.string.type_plan_to_watch,
|
|
||||||
R.string.type_re_watching
|
|
||||||
).map { ctx.getString(it) }
|
|
||||||
arrayAdapter.addAll(items)
|
|
||||||
result_sync_check?.choiceMode = AbsListView.CHOICE_MODE_SINGLE
|
|
||||||
result_sync_check?.adapter = arrayAdapter
|
|
||||||
UIHelper.setListViewHeightBasedOnItems(result_sync_check)
|
|
||||||
|
|
||||||
result_sync_check?.setOnItemClickListener { _, _, which, _ ->
|
|
||||||
syncModel.setStatus(which - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
result_sync_rating?.addOnChangeListener { _, value, _ ->
|
|
||||||
syncModel.setScore(value.toInt())
|
|
||||||
}
|
|
||||||
|
|
||||||
result_sync_add_episode?.setOnClickListener {
|
|
||||||
syncModel.setEpisodesDelta(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
result_sync_sub_episode?.setOnClickListener {
|
|
||||||
syncModel.setEpisodesDelta(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
result_sync_current_episodes?.doOnTextChanged { text, _, before, count ->
|
|
||||||
if (count == before) return@doOnTextChanged
|
|
||||||
text?.toString()?.toIntOrNull()?.let { ep ->
|
|
||||||
syncModel.setEpisodes(ep)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(syncModel.synced) { list ->
|
|
||||||
result_sync_names?.text =
|
|
||||||
list.filter { it.isSynced && it.hasAccount }.joinToString { it.name }
|
|
||||||
|
|
||||||
val newList = list.filter { it.isSynced && it.hasAccount }
|
|
||||||
|
|
||||||
result_mini_sync?.isVisible = newList.isNotEmpty()
|
|
||||||
(result_mini_sync?.adapter as? ImageAdapter)?.updateList(newList.mapNotNull { it.icon })
|
|
||||||
}
|
|
||||||
|
|
||||||
var currentSyncProgress = 0
|
|
||||||
|
|
||||||
fun setSyncMaxEpisodes(totalEpisodes: Int?) {
|
|
||||||
result_sync_episodes?.max = (totalEpisodes ?: 0) * 1000
|
|
||||||
|
|
||||||
normalSafeApiCall {
|
|
||||||
val ctx = result_sync_max_episodes?.context
|
|
||||||
result_sync_max_episodes?.text =
|
|
||||||
totalEpisodes?.let { episodes ->
|
|
||||||
ctx?.getString(R.string.sync_total_episodes_some)?.format(episodes)
|
|
||||||
} ?: run {
|
|
||||||
ctx?.getString(R.string.sync_total_episodes_none)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(syncModel.metadata) { meta ->
|
|
||||||
when (meta) {
|
|
||||||
is Resource.Success -> {
|
|
||||||
val d = meta.value
|
|
||||||
result_sync_episodes?.progress = currentSyncProgress * 1000
|
|
||||||
setSyncMaxEpisodes(d.totalEpisodes)
|
|
||||||
|
|
||||||
viewModel.setMeta(d, syncModel.getSyncs())
|
|
||||||
}
|
|
||||||
|
|
||||||
is Resource.Loading -> {
|
|
||||||
result_sync_max_episodes?.text =
|
|
||||||
result_sync_max_episodes?.context?.getString(R.string.sync_total_episodes_none)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(syncModel.userData) { status ->
|
|
||||||
var closed = false
|
|
||||||
when (status) {
|
|
||||||
is Resource.Failure -> {
|
|
||||||
result_sync_loading_shimmer?.stopShimmer()
|
|
||||||
result_sync_loading_shimmer?.isVisible = false
|
|
||||||
result_sync_holder?.isVisible = false
|
|
||||||
closed = true
|
|
||||||
}
|
|
||||||
|
|
||||||
is Resource.Loading -> {
|
|
||||||
result_sync_loading_shimmer?.startShimmer()
|
|
||||||
result_sync_loading_shimmer?.isVisible = true
|
|
||||||
result_sync_holder?.isVisible = false
|
|
||||||
}
|
|
||||||
|
|
||||||
is Resource.Success -> {
|
|
||||||
result_sync_loading_shimmer?.stopShimmer()
|
|
||||||
result_sync_loading_shimmer?.isVisible = false
|
|
||||||
result_sync_holder?.isVisible = true
|
|
||||||
|
|
||||||
val d = status.value
|
|
||||||
result_sync_rating?.value = d.score?.toFloat() ?: 0.0f
|
|
||||||
result_sync_check?.setItemChecked(d.status + 1, true)
|
|
||||||
val watchedEpisodes = d.watchedEpisodes ?: 0
|
|
||||||
currentSyncProgress = watchedEpisodes
|
|
||||||
|
|
||||||
d.maxEpisodes?.let {
|
|
||||||
// don't directly call it because we don't want to override metadata observe
|
|
||||||
setSyncMaxEpisodes(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
||||||
result_sync_episodes?.setProgress(watchedEpisodes * 1000, true)
|
|
||||||
} else {
|
|
||||||
result_sync_episodes?.progress = watchedEpisodes * 1000
|
|
||||||
}
|
|
||||||
result_sync_current_episodes?.text =
|
|
||||||
Editable.Factory.getInstance()?.newEditable(watchedEpisodes.toString())
|
|
||||||
normalSafeApiCall { // format might fail
|
|
||||||
context?.getString(R.string.sync_score_format)?.format(d.score ?: 0)?.let {
|
|
||||||
result_sync_score_text?.text = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
null -> {
|
|
||||||
closed = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result_overlapping_panels?.setStartPanelLockState(if (closed) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)
|
|
||||||
}
|
|
||||||
|
|
||||||
observeNullable(viewModel.resumeWatching) { resume ->
|
observeNullable(viewModel.resumeWatching) { resume ->
|
||||||
if (resume == null) {
|
if (resume == null) {
|
||||||
|
@ -841,10 +649,6 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
if (hasFocus) result_bookmark_button?.requestFocus()
|
if (hasFocus) result_bookmark_button?.requestFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
result_sync_set_score?.setOnClickListener {
|
|
||||||
syncModel.publishUserData()
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(viewModel.trailers) { trailers ->
|
observe(viewModel.trailers) { trailers ->
|
||||||
setTrailers(trailers.flatMap { it.mirros }) // I dont care about subtitles yet!
|
setTrailers(trailers.flatMap { it.mirros }) // I dont care about subtitles yet!
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,47 @@
|
||||||
package com.lagradost.cloudstream3.ui.result
|
package com.lagradost.cloudstream3.ui.result
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.text.Editable
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.animation.AlphaAnimation
|
import android.view.animation.AlphaAnimation
|
||||||
import android.view.animation.Animation
|
import android.view.animation.Animation
|
||||||
import android.view.animation.DecelerateInterpolator
|
import android.view.animation.DecelerateInterpolator
|
||||||
|
import android.widget.AbsListView
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.NestedScrollView
|
import androidx.core.widget.NestedScrollView
|
||||||
|
import androidx.core.widget.doOnTextChanged
|
||||||
import com.discord.panels.OverlappingPanelsLayout
|
import com.discord.panels.OverlappingPanelsLayout
|
||||||
import com.discord.panels.PanelsChildGestureRegionObserver
|
import com.discord.panels.PanelsChildGestureRegionObserver
|
||||||
import com.google.android.gms.cast.framework.CastButtonFactory
|
import com.google.android.gms.cast.framework.CastButtonFactory
|
||||||
import com.google.android.gms.cast.framework.CastContext
|
import com.google.android.gms.cast.framework.CastContext
|
||||||
import com.google.android.gms.cast.framework.CastState
|
import com.google.android.gms.cast.framework.CastState
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.APIHolder
|
||||||
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
||||||
|
import com.lagradost.cloudstream3.CommonActivity
|
||||||
|
import com.lagradost.cloudstream3.DubStatus
|
||||||
|
import com.lagradost.cloudstream3.LoadResponse
|
||||||
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.SearchResponse
|
||||||
|
import com.lagradost.cloudstream3.databinding.FragmentResultBinding
|
||||||
|
import com.lagradost.cloudstream3.databinding.FragmentResultSwipeBinding
|
||||||
|
import com.lagradost.cloudstream3.databinding.ResultRecommendationsBinding
|
||||||
|
import com.lagradost.cloudstream3.databinding.ResultSyncBinding
|
||||||
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
|
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||||
import com.lagradost.cloudstream3.mvvm.observe
|
import com.lagradost.cloudstream3.mvvm.observe
|
||||||
import com.lagradost.cloudstream3.mvvm.observeNullable
|
import com.lagradost.cloudstream3.mvvm.observeNullable
|
||||||
|
import com.lagradost.cloudstream3.ui.WatchType
|
||||||
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||||
|
@ -32,25 +51,35 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
||||||
|
import com.lagradost.cloudstream3.utils.UIHelper
|
||||||
|
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
||||||
import kotlinx.android.synthetic.main.fragment_result.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result.result_cast_items
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result.result_episodes_text
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result.result_resume_parent
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result.result_scroll
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result.result_smallscreen_holder
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result_swipe.result_back
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_trailer.*
|
|
||||||
import kotlinx.android.synthetic.main.result_recommendations.*
|
|
||||||
import kotlinx.android.synthetic.main.result_recommendations.result_recommendations
|
|
||||||
import kotlinx.android.synthetic.main.trailer_custom_layout.*
|
|
||||||
|
|
||||||
|
|
||||||
class ResultFragmentPhone : ResultFragment() {
|
class ResultFragmentPhone : ResultFragment() {
|
||||||
|
private var binding: FragmentResultSwipeBinding? = null
|
||||||
|
private var resultBinding: FragmentResultBinding? = null
|
||||||
|
private var recommendationBinding: ResultRecommendationsBinding? = null
|
||||||
|
private var syncBinding: ResultSyncBinding? = null
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
val root = super.onCreateView(inflater, container, savedInstanceState) ?: return null
|
||||||
|
FragmentResultSwipeBinding.bind(root).let { bind ->
|
||||||
|
resultBinding =
|
||||||
|
bind.fragmentResult//FragmentResultBinding.bind(binding.root.findViewById(R.id.fragment_result))
|
||||||
|
recommendationBinding = bind.resultRecommendations
|
||||||
|
syncBinding = bind.resultSync
|
||||||
|
binding = bind
|
||||||
|
}
|
||||||
|
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
var currentTrailers: List<ExtractorLink> = emptyList()
|
var currentTrailers: List<ExtractorLink> = emptyList()
|
||||||
var currentTrailerIndex = 0
|
var currentTrailerIndex = 0
|
||||||
|
|
||||||
|
@ -96,10 +125,11 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
//result_trailer_thumbnail?.setImageBitmap(result_poster_background?.drawable?.toBitmap())
|
//result_trailer_thumbnail?.setImageBitmap(result_poster_background?.drawable?.toBitmap())
|
||||||
|
|
||||||
|
|
||||||
result_trailer_loading?.isVisible = isSuccess
|
// result_trailer_loading?.isVisible = isSuccess
|
||||||
val turnVis = !isSuccess && !isFullScreenPlayer
|
val turnVis = !isSuccess && !isFullScreenPlayer
|
||||||
result_smallscreen_holder?.isVisible = turnVis
|
resultBinding?.apply {
|
||||||
result_poster_background_holder?.apply {
|
resultSmallscreenHolder.isVisible = turnVis
|
||||||
|
resultPosterBackgroundHolder.apply {
|
||||||
val fadeIn: Animation = AlphaAnimation(alpha, if (turnVis) 1.0f else 0.0f).apply {
|
val fadeIn: Animation = AlphaAnimation(alpha, if (turnVis) 1.0f else 0.0f).apply {
|
||||||
interpolator = DecelerateInterpolator()
|
interpolator = DecelerateInterpolator()
|
||||||
duration = 200
|
duration = 200
|
||||||
|
@ -109,6 +139,16 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
startAnimation(fadeIn)
|
startAnimation(fadeIn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't want the trailer to be focusable if it's not visible
|
||||||
|
resultSmallscreenHolder.descendantFocusability = if (isSuccess) {
|
||||||
|
ViewGroup.FOCUS_AFTER_DESCENDANTS
|
||||||
|
} else {
|
||||||
|
ViewGroup.FOCUS_BLOCK_DESCENDANTS
|
||||||
|
}
|
||||||
|
binding?.resultFullscreenHolder?.isVisible = !isSuccess && isFullScreenPlayer
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//player_view?.apply {
|
//player_view?.apply {
|
||||||
//alpha = 0.0f
|
//alpha = 0.0f
|
||||||
//ObjectAnimator.ofFloat(player_view, "alpha", 1f).apply {
|
//ObjectAnimator.ofFloat(player_view, "alpha", 1f).apply {
|
||||||
|
@ -124,13 +164,7 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
//startAnimation(fadeIn)
|
//startAnimation(fadeIn)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// We don't want the trailer to be focusable if it's not visible
|
|
||||||
result_smallscreen_holder?.descendantFocusability = if (isSuccess) {
|
|
||||||
ViewGroup.FOCUS_AFTER_DESCENDANTS
|
|
||||||
} else {
|
|
||||||
ViewGroup.FOCUS_BLOCK_DESCENDANTS
|
|
||||||
}
|
|
||||||
result_fullscreen_holder?.isVisible = !isSuccess && isFullScreenPlayer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setTrailers(trailers: List<ExtractorLink>?) {
|
override fun setTrailers(trailers: List<ExtractorLink>?) {
|
||||||
|
@ -144,12 +178,15 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
//somehow this still leaks and I dont know why????
|
//somehow this still leaks and I dont know why????
|
||||||
// todo look at https://github.com/discord/OverlappingPanels/blob/70b4a7cf43c6771873b1e091029d332896d41a1a/sample_app/src/main/java/com/discord/sampleapp/MainActivity.kt
|
// todo look at https://github.com/discord/OverlappingPanels/blob/70b4a7cf43c6771873b1e091029d332896d41a1a/sample_app/src/main/java/com/discord/sampleapp/MainActivity.kt
|
||||||
PanelsChildGestureRegionObserver.Provider.get().let { obs ->
|
PanelsChildGestureRegionObserver.Provider.get().let { obs ->
|
||||||
result_cast_items?.let {
|
resultBinding?.resultCastItems?.let {
|
||||||
obs.unregister(it)
|
obs.unregister(it)
|
||||||
}
|
}
|
||||||
obs.removeGestureRegionsUpdateListener(this)
|
obs.removeGestureRegionsUpdateListener(this)
|
||||||
}
|
}
|
||||||
|
binding = null
|
||||||
|
resultBinding = null
|
||||||
|
syncBinding = null
|
||||||
|
recommendationBinding = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,30 +210,35 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
player_open_source?.setOnClickListener {
|
|
||||||
|
|
||||||
|
playerBinding?.playerOpenSource?.setOnClickListener {
|
||||||
currentTrailers.getOrNull(currentTrailerIndex)?.let {
|
currentTrailers.getOrNull(currentTrailerIndex)?.let {
|
||||||
context?.openBrowser(it.url)
|
context?.openBrowser(it.url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result_overlapping_panels?.setStartPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
binding?.resultOverlappingPanels?.setStartPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
||||||
result_overlapping_panels?.setEndPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
binding?.resultOverlappingPanels?.setEndPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
||||||
|
|
||||||
result_recommendations?.spanCount = 3
|
recommendationBinding?.resultRecommendationsList?.apply {
|
||||||
result_recommendations?.adapter =
|
spanCount = 3
|
||||||
|
adapter =
|
||||||
SearchAdapter(
|
SearchAdapter(
|
||||||
ArrayList(),
|
ArrayList(),
|
||||||
result_recommendations,
|
this,
|
||||||
) { callback ->
|
) { callback ->
|
||||||
SearchHelper.handleSearchClickCallback(callback)
|
SearchHelper.handleSearchClickCallback(callback)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PanelsChildGestureRegionObserver.Provider.get().addGestureRegionsUpdateListener(this)
|
PanelsChildGestureRegionObserver.Provider.get().addGestureRegionsUpdateListener(this)
|
||||||
|
|
||||||
result_cast_items?.let {
|
resultBinding?.resultCastItems?.let {
|
||||||
PanelsChildGestureRegionObserver.Provider.get().register(it)
|
PanelsChildGestureRegionObserver.Provider.get().register(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
result_back?.setOnClickListener {
|
binding?.resultBack?.setOnClickListener {
|
||||||
activity?.popCurrentPage()
|
activity?.popCurrentPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,28 +253,30 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
result_mini_sync?.adapter = ImageAdapter(
|
binding?.resultMiniSync?.adapter = ImageAdapter(
|
||||||
nextFocusDown = R.id.result_sync_set_score,
|
nextFocusDown = R.id.result_sync_set_score,
|
||||||
clickCallback = { action ->
|
clickCallback = { action ->
|
||||||
if (action == IMAGE_CLICK || action == IMAGE_LONG_CLICK) {
|
if (action == IMAGE_CLICK || action == IMAGE_LONG_CLICK) {
|
||||||
if (result_overlapping_panels?.getSelectedPanel()?.ordinal == 1) {
|
if (binding?.resultOverlappingPanels?.getSelectedPanel()?.ordinal == 1) {
|
||||||
result_overlapping_panels?.openStartPanel()
|
binding?.resultOverlappingPanels?.openStartPanel()
|
||||||
} else {
|
} else {
|
||||||
result_overlapping_panels?.closePanels()
|
binding?.resultOverlappingPanels?.closePanels()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
result_scroll?.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
resultBinding?.resultScroll?.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||||
val dy = scrollY - oldScrollY
|
val dy = scrollY - oldScrollY
|
||||||
if (dy > 0) { //check for scroll down
|
if (dy > 0) { //check for scroll down
|
||||||
result_bookmark_fab?.shrink()
|
binding?.resultBookmarkFab?.shrink()
|
||||||
} else if (dy < -5) {
|
} else if (dy < -5) {
|
||||||
result_bookmark_fab?.extend()
|
binding?.resultBookmarkFab?.extend()
|
||||||
}
|
}
|
||||||
if (!isFullScreenPlayer && player.getIsPlaying()) {
|
if (!isFullScreenPlayer && player.getIsPlaying()) {
|
||||||
if (scrollY > (player_background?.height ?: scrollY)) {
|
if (scrollY > (resultBinding?.fragmentTrailer?.playerBackground?.height
|
||||||
|
?: scrollY)
|
||||||
|
) {
|
||||||
player.handleEvent(CSPlayerEvent.Pause)
|
player.handleEvent(CSPlayerEvent.Pause)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,11 +284,11 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
})
|
})
|
||||||
val api = APIHolder.getApiFromNameNull(apiName)
|
val api = APIHolder.getApiFromNameNull(apiName)
|
||||||
|
|
||||||
if (media_route_button != null) {
|
binding?.mediaRouteButton?.apply {
|
||||||
val chromecastSupport = api?.hasChromecastSupport == true
|
val chromecastSupport = api?.hasChromecastSupport == true
|
||||||
media_route_button?.alpha = if (chromecastSupport) 1f else 0.3f
|
alpha = if (chromecastSupport) 1f else 0.3f
|
||||||
if (!chromecastSupport) {
|
if (!chromecastSupport) {
|
||||||
media_route_button?.setOnClickListener {
|
setOnClickListener {
|
||||||
CommonActivity.showToast(
|
CommonActivity.showToast(
|
||||||
R.string.no_chromecast_support_toast,
|
R.string.no_chromecast_support_toast,
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
|
@ -254,10 +298,9 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
activity?.let { act ->
|
activity?.let { act ->
|
||||||
if (act.isCastApiAvailable()) {
|
if (act.isCastApiAvailable()) {
|
||||||
try {
|
try {
|
||||||
CastButtonFactory.setUpMediaRouteButton(act, media_route_button)
|
CastButtonFactory.setUpMediaRouteButton(act, this)
|
||||||
val castContext = CastContext.getSharedInstance(act.applicationContext)
|
val castContext = CastContext.getSharedInstance(act.applicationContext)
|
||||||
media_route_button?.isGone =
|
isGone = castContext.castState == CastState.NO_DEVICES_AVAILABLE
|
||||||
castContext.castState == CastState.NO_DEVICES_AVAILABLE
|
|
||||||
// this shit leaks for some reason
|
// this shit leaks for some reason
|
||||||
//castContext.addCastStateListener { state ->
|
//castContext.addCastStateListener { state ->
|
||||||
// media_route_button?.isGone = state == CastState.NO_DEVICES_AVAILABLE
|
// media_route_button?.isGone = state == CastState.NO_DEVICES_AVAILABLE
|
||||||
|
@ -270,7 +313,7 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
observeNullable(viewModel.episodesCountText) { count ->
|
observeNullable(viewModel.episodesCountText) { count ->
|
||||||
result_episodes_text.setText(count)
|
resultBinding?.resultEpisodesText.setText(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
observeNullable(viewModel.selectPopup) { popup ->
|
observeNullable(viewModel.selectPopup) { popup ->
|
||||||
|
@ -295,10 +338,189 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
observe(syncModel.synced) { list ->
|
||||||
|
syncBinding?.resultSyncNames?.text =
|
||||||
|
list.filter { it.isSynced && it.hasAccount }.joinToString { it.name }
|
||||||
|
|
||||||
|
val newList = list.filter { it.isSynced && it.hasAccount }
|
||||||
|
|
||||||
|
binding?.resultMiniSync?.isVisible = newList.isNotEmpty()
|
||||||
|
(binding?.resultMiniSync?.adapter as? ImageAdapter)?.updateList(newList.mapNotNull { it.icon })
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentSyncProgress = 0
|
||||||
|
fun setSyncMaxEpisodes(totalEpisodes: Int?) {
|
||||||
|
syncBinding?.resultSyncEpisodes?.max = (totalEpisodes ?: 0) * 1000
|
||||||
|
|
||||||
|
normalSafeApiCall {
|
||||||
|
val ctx = syncBinding?.resultSyncEpisodes?.context
|
||||||
|
syncBinding?.resultSyncMaxEpisodes?.text =
|
||||||
|
totalEpisodes?.let { episodes ->
|
||||||
|
ctx?.getString(R.string.sync_total_episodes_some)?.format(episodes)
|
||||||
|
} ?: run {
|
||||||
|
ctx?.getString(R.string.sync_total_episodes_none)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
observe(syncModel.metadata) { meta ->
|
||||||
|
when (meta) {
|
||||||
|
is Resource.Success -> {
|
||||||
|
val d = meta.value
|
||||||
|
syncBinding?.resultSyncEpisodes?.progress = currentSyncProgress * 1000
|
||||||
|
setSyncMaxEpisodes(d.totalEpisodes)
|
||||||
|
|
||||||
|
viewModel.setMeta(d, syncModel.getSyncs())
|
||||||
|
}
|
||||||
|
|
||||||
|
is Resource.Loading -> {
|
||||||
|
syncBinding?.resultSyncMaxEpisodes?.text =
|
||||||
|
syncBinding?.resultSyncMaxEpisodes?.context?.getString(R.string.sync_total_episodes_none)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
observe(syncModel.userData) { status ->
|
||||||
|
var closed = false
|
||||||
|
syncBinding?.apply {
|
||||||
|
when (status) {
|
||||||
|
is Resource.Failure -> {
|
||||||
|
resultSyncLoadingShimmer.stopShimmer()
|
||||||
|
resultSyncLoadingShimmer.isVisible = false
|
||||||
|
resultSyncHolder.isVisible = false
|
||||||
|
closed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
is Resource.Loading -> {
|
||||||
|
resultSyncLoadingShimmer.startShimmer()
|
||||||
|
resultSyncLoadingShimmer.isVisible = true
|
||||||
|
resultSyncHolder.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
is Resource.Success -> {
|
||||||
|
resultSyncLoadingShimmer.stopShimmer()
|
||||||
|
resultSyncLoadingShimmer.isVisible = false
|
||||||
|
resultSyncHolder.isVisible = true
|
||||||
|
|
||||||
|
val d = status.value
|
||||||
|
resultSyncRating.value = d.score?.toFloat() ?: 0.0f
|
||||||
|
resultSyncCheck.setItemChecked(d.status + 1, true)
|
||||||
|
val watchedEpisodes = d.watchedEpisodes ?: 0
|
||||||
|
currentSyncProgress = watchedEpisodes
|
||||||
|
|
||||||
|
d.maxEpisodes?.let {
|
||||||
|
// don't directly call it because we don't want to override metadata observe
|
||||||
|
setSyncMaxEpisodes(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
resultSyncEpisodes.setProgress(watchedEpisodes * 1000, true)
|
||||||
|
} else {
|
||||||
|
resultSyncEpisodes.progress = watchedEpisodes * 1000
|
||||||
|
}
|
||||||
|
resultSyncCurrentEpisodes.text =
|
||||||
|
Editable.Factory.getInstance()?.newEditable(watchedEpisodes.toString())
|
||||||
|
normalSafeApiCall { // format might fail
|
||||||
|
context?.getString(R.string.sync_score_format)?.format(d.score ?: 0)
|
||||||
|
?.let {
|
||||||
|
resultSyncScoreText.text = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
null -> {
|
||||||
|
closed = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding?.resultOverlappingPanels?.setStartPanelLockState(if (closed) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)
|
||||||
|
}
|
||||||
|
|
||||||
|
context?.let { ctx ->
|
||||||
|
val arrayAdapter = ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
||||||
|
/*
|
||||||
|
-1 -> None
|
||||||
|
0 -> Watching
|
||||||
|
1 -> Completed
|
||||||
|
2 -> OnHold
|
||||||
|
3 -> Dropped
|
||||||
|
4 -> PlanToWatch
|
||||||
|
5 -> ReWatching
|
||||||
|
*/
|
||||||
|
val items = listOf(
|
||||||
|
R.string.none,
|
||||||
|
R.string.type_watching,
|
||||||
|
R.string.type_completed,
|
||||||
|
R.string.type_on_hold,
|
||||||
|
R.string.type_dropped,
|
||||||
|
R.string.type_plan_to_watch,
|
||||||
|
R.string.type_re_watching
|
||||||
|
).map { ctx.getString(it) }
|
||||||
|
arrayAdapter.addAll(items)
|
||||||
|
syncBinding?.apply {
|
||||||
|
resultSyncCheck.choiceMode = AbsListView.CHOICE_MODE_SINGLE
|
||||||
|
resultSyncCheck.adapter = arrayAdapter
|
||||||
|
UIHelper.setListViewHeightBasedOnItems(resultSyncCheck)
|
||||||
|
|
||||||
|
resultSyncCheck.setOnItemClickListener { _, _, which, _ ->
|
||||||
|
syncModel.setStatus(which - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSyncRating.addOnChangeListener { _, value, _ ->
|
||||||
|
syncModel.setScore(value.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSyncAddEpisode.setOnClickListener {
|
||||||
|
syncModel.setEpisodesDelta(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSyncSubEpisode.setOnClickListener {
|
||||||
|
syncModel.setEpisodesDelta(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSyncCurrentEpisodes.doOnTextChanged { text, _, before, count ->
|
||||||
|
if (count == before) return@doOnTextChanged
|
||||||
|
text?.toString()?.toIntOrNull()?.let { ep ->
|
||||||
|
syncModel.setEpisodes(ep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syncBinding?.resultSyncSetScore?.setOnClickListener {
|
||||||
|
syncModel.publishUserData()
|
||||||
|
}
|
||||||
|
|
||||||
|
observe(viewModel.watchStatus) { watchType ->
|
||||||
|
binding?.resultBookmarkFab?.apply {
|
||||||
|
if (watchType == WatchType.NONE) {
|
||||||
|
context?.colorFromAttribute(R.attr.white)
|
||||||
|
} else {
|
||||||
|
context?.colorFromAttribute(R.attr.colorPrimary)
|
||||||
|
}?.let {
|
||||||
|
val colorState = ColorStateList.valueOf(it)
|
||||||
|
iconTint = colorState
|
||||||
|
setTextColor(colorState)
|
||||||
|
}
|
||||||
|
|
||||||
|
setOnClickListener { fab ->
|
||||||
|
activity?.showBottomDialog(
|
||||||
|
WatchType.values().map { fab.context.getString(it.stringRes) }.toList(),
|
||||||
|
watchType.ordinal,
|
||||||
|
fab.context.getString(R.string.action_add_to_bookmarks),
|
||||||
|
showApply = false,
|
||||||
|
{}) {
|
||||||
|
viewModel.updateWatchStatus(WatchType.values()[it])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
observe(viewModel.loadedLinks) { load ->
|
observe(viewModel.loadedLinks) { load ->
|
||||||
if (load == null) {
|
if (load == null) {
|
||||||
loadingDialog?.dismissSafe(activity)
|
loadingDialog?.dismissSafe(activity)
|
||||||
|
@ -327,46 +549,41 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
observeNullable(viewModel.selectedSeason) { text ->
|
observeNullable(viewModel.selectedSeason) { text ->
|
||||||
result_season_button.setText(text)
|
resultBinding?.apply {
|
||||||
|
resultSeasonButton.setText(text)
|
||||||
|
|
||||||
selectSeason =
|
selectSeason =
|
||||||
text?.asStringNull(result_season_button?.context)
|
text?.asStringNull(resultSeasonButton.context)
|
||||||
// If the season button is visible the result season button will be next focus down
|
// If the season button is visible the result season button will be next focus down
|
||||||
if (result_season_button?.isVisible == true)
|
if (resultSeasonButton.isVisible && resultResumeParent.isVisible) {
|
||||||
if (result_resume_parent?.isVisible == true)
|
setFocusUpAndDown(resultResumeSeriesButton, resultSeasonButton)
|
||||||
setFocusUpAndDown(result_resume_series_button, result_season_button)
|
}
|
||||||
//else
|
}
|
||||||
// setFocusUpAndDown(result_bookmark_button, result_season_button)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
observeNullable(viewModel.selectedDubStatus) { status ->
|
observeNullable(viewModel.selectedDubStatus) { status ->
|
||||||
result_dub_select?.setText(status)
|
resultBinding?.apply {
|
||||||
|
resultDubSelect.setText(status)
|
||||||
|
|
||||||
if (result_dub_select?.isVisible == true)
|
if (resultDubSelect.isVisible && !resultSeasonButton.isVisible && !resultEpisodeSelect.isVisible && resultResumeParent.isVisible) {
|
||||||
if (result_season_button?.isVisible != true && result_episode_select?.isVisible != true) {
|
setFocusUpAndDown(resultResumeSeriesButton, resultDubSelect)
|
||||||
if (result_resume_parent?.isVisible == true)
|
}
|
||||||
setFocusUpAndDown(result_resume_series_button, result_dub_select)
|
|
||||||
//else
|
|
||||||
// setFocusUpAndDown(result_bookmark_button, result_dub_select)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
observeNullable(viewModel.selectedRange) { range ->
|
observeNullable(viewModel.selectedRange) { range ->
|
||||||
result_episode_select.setText(range)
|
resultBinding?.apply {
|
||||||
|
resultEpisodeSelect.setText(range)
|
||||||
// If Season button is invisible then the bookmark button next focus is episode select
|
// If Season button is invisible then the bookmark button next focus is episode select
|
||||||
if (result_episode_select?.isVisible == true)
|
if (resultEpisodeSelect.isVisible && !resultSeasonButton.isVisible && resultResumeParent.isVisible) {
|
||||||
if (result_season_button?.isVisible != true) {
|
setFocusUpAndDown(resultResumeSeriesButton, resultEpisodeSelect)
|
||||||
if (result_resume_parent?.isVisible == true)
|
}
|
||||||
setFocusUpAndDown(result_resume_series_button, result_episode_select)
|
|
||||||
//else
|
|
||||||
// setFocusUpAndDown(result_bookmark_button, result_episode_select)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// val preferDub = context?.getApiDubstatusSettings()?.all { it == DubStatus.Dubbed } == true
|
// val preferDub = context?.getApiDubstatusSettings()?.all { it == DubStatus.Dubbed } == true
|
||||||
|
|
||||||
observe(viewModel.dubSubSelections) { range ->
|
observe(viewModel.dubSubSelections) { range ->
|
||||||
result_dub_select.setOnClickListener { view ->
|
resultBinding?.resultDubSelect?.setOnClickListener { view ->
|
||||||
view?.context?.let { ctx ->
|
view?.context?.let { ctx ->
|
||||||
view.popupMenuNoIconsAndNoStringRes(range
|
view.popupMenuNoIconsAndNoStringRes(range
|
||||||
.mapNotNull { (text, status) ->
|
.mapNotNull { (text, status) ->
|
||||||
|
@ -382,7 +599,7 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.rangeSelections) { range ->
|
observe(viewModel.rangeSelections) { range ->
|
||||||
result_episode_select?.setOnClickListener { view ->
|
resultBinding?.resultEpisodeSelect?.setOnClickListener { view ->
|
||||||
view?.context?.let { ctx ->
|
view?.context?.let { ctx ->
|
||||||
val names = range
|
val names = range
|
||||||
.mapNotNull { (text, r) ->
|
.mapNotNull { (text, r) ->
|
||||||
|
@ -399,7 +616,7 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.seasonSelections) { seasonList ->
|
observe(viewModel.seasonSelections) { seasonList ->
|
||||||
result_season_button?.setOnClickListener { view ->
|
resultBinding?.resultSeasonButton?.setOnClickListener { view ->
|
||||||
|
|
||||||
view?.context?.let { ctx ->
|
view?.context?.let { ctx ->
|
||||||
val names = seasonList
|
val names = seasonList
|
||||||
|
@ -433,35 +650,47 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onGestureRegionsUpdate(gestureRegions: List<Rect>) {
|
override fun onGestureRegionsUpdate(gestureRegions: List<Rect>) {
|
||||||
result_overlapping_panels?.setChildGestureRegions(gestureRegions)
|
binding?.resultOverlappingPanels?.setChildGestureRegions(gestureRegions)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||||
val isInvalid = rec.isNullOrEmpty()
|
val isInvalid = rec.isNullOrEmpty()
|
||||||
result_recommendations?.isGone = isInvalid
|
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
|
||||||
result_recommendations_btt?.isGone = isInvalid
|
|
||||||
result_recommendations_btt?.setOnClickListener {
|
recommendationBinding?.apply {
|
||||||
val nextFocusDown = if (result_overlapping_panels?.getSelectedPanel()?.ordinal == 1) {
|
root.isGone = isInvalid
|
||||||
result_overlapping_panels?.openEndPanel()
|
root.post {
|
||||||
|
rec?.let { list ->
|
||||||
|
(resultRecommendationsList.adapter as? SearchAdapter)?.updateList(list.filter { it.apiName == matchAgainst })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding?.apply {
|
||||||
|
resultRecommendationsBtt.isGone = isInvalid
|
||||||
|
resultRecommendationsBtt.setOnClickListener {
|
||||||
|
val nextFocusDown = if (resultOverlappingPanels.getSelectedPanel().ordinal == 1) {
|
||||||
|
resultOverlappingPanels.openEndPanel()
|
||||||
R.id.result_recommendations
|
R.id.result_recommendations
|
||||||
} else {
|
} else {
|
||||||
result_overlapping_panels?.closePanels()
|
resultOverlappingPanels.closePanels()
|
||||||
R.id.result_description
|
R.id.result_description
|
||||||
}
|
}
|
||||||
|
resultBinding?.apply {
|
||||||
result_recommendations_btt?.nextFocusDownId = nextFocusDown
|
resultRecommendationsBtt.nextFocusDownId = nextFocusDown
|
||||||
result_search?.nextFocusDownId = nextFocusDown
|
resultSearch.nextFocusDownId = nextFocusDown
|
||||||
result_open_in_browser?.nextFocusDownId = nextFocusDown
|
resultOpenInBrowser.nextFocusDownId = nextFocusDown
|
||||||
result_share?.nextFocusDownId = nextFocusDown
|
resultShare.nextFocusDownId = nextFocusDown
|
||||||
}
|
}
|
||||||
result_overlapping_panels?.setEndPanelLockState(if (isInvalid) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)
|
}
|
||||||
|
resultOverlappingPanels.setEndPanelLockState(if (isInvalid) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)
|
||||||
|
|
||||||
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
|
|
||||||
rec?.map { it.apiName }?.distinct()?.let { apiNames ->
|
rec?.map { it.apiName }?.distinct()?.let { apiNames ->
|
||||||
// very dirty selection
|
// very dirty selection
|
||||||
result_recommendations_filter_button?.isVisible = apiNames.size > 1
|
recommendationBinding?.resultRecommendationsFilterButton?.apply {
|
||||||
result_recommendations_filter_button?.text = matchAgainst
|
isVisible = apiNames.size > 1
|
||||||
result_recommendations_filter_button?.setOnClickListener { _ ->
|
text = matchAgainst
|
||||||
|
setOnClickListener { _ ->
|
||||||
activity?.showBottomDialog(
|
activity?.showBottomDialog(
|
||||||
apiNames,
|
apiNames,
|
||||||
apiNames.indexOf(matchAgainst),
|
apiNames.indexOf(matchAgainst),
|
||||||
|
@ -470,13 +699,9 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
setRecommendations(rec, apiNames[it])
|
setRecommendations(rec, apiNames[it])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} ?: run {
|
} ?: run {
|
||||||
result_recommendations_filter_button?.isVisible = false
|
recommendationBinding?.resultRecommendationsFilterButton?.isVisible = false
|
||||||
}
|
|
||||||
|
|
||||||
result_recommendations?.post {
|
|
||||||
rec?.let { list ->
|
|
||||||
(result_recommendations?.adapter as? SearchAdapter)?.updateList(list.filter { it.apiName == matchAgainst })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package com.lagradost.cloudstream3.ui.result
|
package com.lagradost.cloudstream3.ui.result
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
|
import android.content.res.ColorStateList
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
@ -12,23 +15,43 @@ import com.lagradost.cloudstream3.DubStatus
|
||||||
import com.lagradost.cloudstream3.LoadResponse
|
import com.lagradost.cloudstream3.LoadResponse
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.SearchResponse
|
import com.lagradost.cloudstream3.SearchResponse
|
||||||
|
import com.lagradost.cloudstream3.databinding.FragmentResultTvBinding
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
import com.lagradost.cloudstream3.mvvm.observe
|
import com.lagradost.cloudstream3.mvvm.observe
|
||||||
import com.lagradost.cloudstream3.mvvm.observeNullable
|
import com.lagradost.cloudstream3.mvvm.observeNullable
|
||||||
|
import com.lagradost.cloudstream3.ui.WatchType
|
||||||
import com.lagradost.cloudstream3.ui.player.ExtractorLinkGenerator
|
import com.lagradost.cloudstream3.ui.player.ExtractorLinkGenerator
|
||||||
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||||
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
|
||||||
|
|
||||||
class ResultFragmentTv : ResultFragment() {
|
class ResultFragmentTv : ResultFragment() {
|
||||||
override val resultLayout = R.layout.fragment_result_tv
|
override val resultLayout = R.layout.fragment_result_tv
|
||||||
|
|
||||||
|
private var binding: FragmentResultTvBinding? = null
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
binding = null
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
val root = super.onCreateView(inflater, container, savedInstanceState) ?: return null
|
||||||
|
binding = FragmentResultTvBinding.bind(root)
|
||||||
|
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
private var currentRecommendations: List<SearchResponse> = emptyList()
|
private var currentRecommendations: List<SearchResponse> = emptyList()
|
||||||
|
|
||||||
private fun handleSelection(data: Any) {
|
private fun handleSelection(data: Any) {
|
||||||
|
@ -36,12 +59,15 @@ class ResultFragmentTv : ResultFragment() {
|
||||||
is EpisodeRange -> {
|
is EpisodeRange -> {
|
||||||
viewModel.changeRange(data)
|
viewModel.changeRange(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
is Int -> {
|
is Int -> {
|
||||||
viewModel.changeSeason(data)
|
viewModel.changeSeason(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
is DubStatus -> {
|
is DubStatus -> {
|
||||||
viewModel.changeDubStatus(data)
|
viewModel.changeDubStatus(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
is String -> {
|
is String -> {
|
||||||
setRecommendations(currentRecommendations, data)
|
setRecommendations(currentRecommendations, data)
|
||||||
}
|
}
|
||||||
|
@ -66,29 +92,29 @@ class ResultFragmentTv : ResultFragment() {
|
||||||
private fun hasNoFocus(): Boolean {
|
private fun hasNoFocus(): Boolean {
|
||||||
val focus = activity?.currentFocus
|
val focus = activity?.currentFocus
|
||||||
if (focus == null || !focus.isVisible) return true
|
if (focus == null || !focus.isVisible) return true
|
||||||
return focus == this.result_root
|
return focus == binding?.resultRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateEpisodes(episodes: Resource<List<ResultEpisode>>?) {
|
override fun updateEpisodes(episodes: Resource<List<ResultEpisode>>?) {
|
||||||
super.updateEpisodes(episodes)
|
super.updateEpisodes(episodes)
|
||||||
if (episodes is Resource.Success && hasNoFocus()) {
|
if (episodes is Resource.Success && hasNoFocus()) {
|
||||||
result_episodes?.requestFocus()
|
binding?.resultEpisodes?.requestFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateMovie(data: Resource<Pair<UiText, ResultEpisode>>?) {
|
override fun updateMovie(data: Resource<Pair<UiText, ResultEpisode>>?) {
|
||||||
super.updateMovie(data)
|
super.updateMovie(data)
|
||||||
if (data is Resource.Success && hasNoFocus()) {
|
if (data is Resource.Success && hasNoFocus()) {
|
||||||
result_play_movie?.requestFocus()
|
binding?.resultPlayMovie?.requestFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setTrailers(trailers: List<ExtractorLink>?) {
|
override fun setTrailers(trailers: List<ExtractorLink>?) {
|
||||||
context?.updateHasTrailers()
|
context?.updateHasTrailers()
|
||||||
if (!LoadResponse.isTrailersEnabled) return
|
if (!LoadResponse.isTrailersEnabled) return
|
||||||
|
binding?.resultPlayTrailer?.apply {
|
||||||
result_play_trailer?.isGone = trailers.isNullOrEmpty()
|
isGone = trailers.isNullOrEmpty()
|
||||||
result_play_trailer?.setOnClickListener {
|
setOnClickListener {
|
||||||
if (trailers.isNullOrEmpty()) return@setOnClickListener
|
if (trailers.isNullOrEmpty()) return@setOnClickListener
|
||||||
activity.navigate(
|
activity.navigate(
|
||||||
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
|
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
|
||||||
|
@ -100,23 +126,26 @@ class ResultFragmentTv : ResultFragment() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||||
currentRecommendations = rec ?: emptyList()
|
currentRecommendations = rec ?: emptyList()
|
||||||
val isInvalid = rec.isNullOrEmpty()
|
val isInvalid = rec.isNullOrEmpty()
|
||||||
result_recommendations?.isGone = isInvalid
|
binding?.apply {
|
||||||
result_recommendations_holder?.isGone = isInvalid
|
resultRecommendationsList.isGone = isInvalid
|
||||||
|
resultRecommendationsHolder.isGone = isInvalid
|
||||||
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
|
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
|
||||||
(result_recommendations?.adapter as? SearchAdapter)?.updateList(rec?.filter { it.apiName == matchAgainst }
|
(resultRecommendationsList.adapter as? SearchAdapter)?.updateList(rec?.filter { it.apiName == matchAgainst }
|
||||||
?: emptyList())
|
?: emptyList())
|
||||||
|
|
||||||
rec?.map { it.apiName }?.distinct()?.let { apiNames ->
|
rec?.map { it.apiName }?.distinct()?.let { apiNames ->
|
||||||
// very dirty selection
|
// very dirty selection
|
||||||
result_recommendations_filter_selection?.isVisible = apiNames.size > 1
|
resultRecommendationsFilterSelection.isVisible = apiNames.size > 1
|
||||||
result_recommendations_filter_selection?.update(apiNames.map { txt(it) to it })
|
resultRecommendationsFilterSelection.update(apiNames.map { txt(it) to it })
|
||||||
result_recommendations_filter_selection?.select(apiNames.indexOf(matchAgainst))
|
resultRecommendationsFilterSelection.select(apiNames.indexOf(matchAgainst))
|
||||||
} ?: run {
|
} ?: run {
|
||||||
result_recommendations_filter_selection?.isVisible = false
|
resultRecommendationsFilterSelection.isVisible = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,21 +153,34 @@ class ResultFragmentTv : ResultFragment() {
|
||||||
var popupDialog: Dialog? = null
|
var popupDialog: Dialog? = null
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
binding?.apply {
|
||||||
result_episodes?.layoutManager =
|
resultEpisodes.layoutManager =
|
||||||
//LinearListLayout(result_episodes ?: return, result_episodes?.context).apply {
|
LinearListLayout(resultEpisodes.context).apply {
|
||||||
LinearListLayout(result_episodes?.context).apply {
|
|
||||||
setHorizontal()
|
setHorizontal()
|
||||||
}
|
}
|
||||||
// (result_episodes?.adapter as EpisodeAdapter?)?.apply {
|
|
||||||
// layout = R.layout.result_episode_both_tv
|
|
||||||
// }
|
|
||||||
//result_episodes?.setMaxViewPoolSize(0, Int.MAX_VALUE)
|
|
||||||
|
|
||||||
result_season_selection.setAdapter()
|
resultSeasonSelection.setAdapter()
|
||||||
result_range_selection.setAdapter()
|
resultRangeSelection.setAdapter()
|
||||||
result_dub_selection.setAdapter()
|
resultDubSelection.setAdapter()
|
||||||
result_recommendations_filter_selection.setAdapter()
|
resultRecommendationsFilterSelection.setAdapter()
|
||||||
|
}
|
||||||
|
|
||||||
|
observe(viewModel.watchStatus) { watchType ->
|
||||||
|
binding?.resultBookmarkButton?.apply {
|
||||||
|
setText(watchType.stringRes)
|
||||||
|
setOnClickListener { view ->
|
||||||
|
activity?.showBottomDialog(
|
||||||
|
WatchType.values().map { view.context.getString(it.stringRes) }.toList(),
|
||||||
|
watchType.ordinal,
|
||||||
|
view.context.getString(R.string.action_add_to_bookmarks),
|
||||||
|
showApply = false,
|
||||||
|
{}) {
|
||||||
|
viewModel.updateWatchStatus(WatchType.values()[it])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
observeNullable(viewModel.selectPopup) { popup ->
|
observeNullable(viewModel.selectPopup) { popup ->
|
||||||
if (popup == null) {
|
if (popup == null) {
|
||||||
|
@ -194,39 +236,42 @@ class ResultFragmentTv : ResultFragment() {
|
||||||
|
|
||||||
|
|
||||||
observeNullable(viewModel.episodesCountText) { count ->
|
observeNullable(viewModel.episodesCountText) { count ->
|
||||||
result_episodes_text.setText(count)
|
binding?.resultEpisodesText.setText(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.selectedRangeIndex) { selected ->
|
observe(viewModel.selectedRangeIndex) { selected ->
|
||||||
result_range_selection.select(selected)
|
binding?.resultRangeSelection.select(selected)
|
||||||
}
|
}
|
||||||
observe(viewModel.selectedSeasonIndex) { selected ->
|
observe(viewModel.selectedSeasonIndex) { selected ->
|
||||||
result_season_selection.select(selected)
|
binding?.resultSeasonSelection.select(selected)
|
||||||
}
|
}
|
||||||
observe(viewModel.selectedDubStatusIndex) { selected ->
|
observe(viewModel.selectedDubStatusIndex) { selected ->
|
||||||
result_dub_selection.select(selected)
|
binding?.resultDubSelection.select(selected)
|
||||||
}
|
}
|
||||||
observe(viewModel.rangeSelections) {
|
observe(viewModel.rangeSelections) {
|
||||||
result_range_selection.update(it)
|
binding?.resultRangeSelection.update(it)
|
||||||
}
|
}
|
||||||
observe(viewModel.dubSubSelections) {
|
observe(viewModel.dubSubSelections) {
|
||||||
result_dub_selection.update(it)
|
binding?.resultDubSelection.update(it)
|
||||||
}
|
}
|
||||||
observe(viewModel.seasonSelections) {
|
observe(viewModel.seasonSelections) {
|
||||||
result_season_selection.update(it)
|
binding?.resultSeasonSelection.update(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
result_back?.setOnClickListener {
|
binding?.apply {
|
||||||
|
resultBack.setOnClickListener {
|
||||||
activity?.popCurrentPage()
|
activity?.popCurrentPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
result_recommendations?.spanCount = 8
|
resultRecommendationsList.spanCount = 8
|
||||||
result_recommendations?.adapter =
|
resultRecommendationsList.adapter =
|
||||||
SearchAdapter(
|
SearchAdapter(
|
||||||
ArrayList(),
|
ArrayList(),
|
||||||
result_recommendations,
|
resultRecommendationsList,
|
||||||
) { callback ->
|
) { callback ->
|
||||||
SearchHelper.handleSearchClickCallback(callback)
|
SearchHelper.handleSearchClickCallback(callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -13,6 +13,7 @@ import androidx.core.view.isVisible
|
||||||
import com.discord.panels.PanelsChildGestureRegionObserver
|
import com.discord.panels.PanelsChildGestureRegionObserver
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
||||||
|
import com.lagradost.cloudstream3.ui.player.FullScreenPlayer
|
||||||
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
||||||
import com.lagradost.cloudstream3.utils.IOnBackPressed
|
import com.lagradost.cloudstream3.utils.IOnBackPressed
|
||||||
import kotlinx.android.synthetic.main.fragment_result.*
|
import kotlinx.android.synthetic.main.fragment_result.*
|
||||||
|
@ -20,10 +21,9 @@ import kotlinx.android.synthetic.main.fragment_result.result_smallscreen_holder
|
||||||
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
||||||
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
||||||
import kotlinx.android.synthetic.main.fragment_trailer.*
|
import kotlinx.android.synthetic.main.fragment_trailer.*
|
||||||
import kotlinx.android.synthetic.main.trailer_custom_layout.*
|
|
||||||
|
|
||||||
|
|
||||||
open class ResultTrailerPlayer : com.lagradost.cloudstream3.ui.player.FullScreenPlayer(),
|
open class ResultTrailerPlayer : FullScreenPlayer(),
|
||||||
PanelsChildGestureRegionObserver.GestureRegionsListener, IOnBackPressed {
|
PanelsChildGestureRegionObserver.GestureRegionsListener, IOnBackPressed {
|
||||||
|
|
||||||
override var lockRotation = false
|
override var lockRotation = false
|
||||||
|
@ -75,7 +75,7 @@ open class ResultTrailerPlayer : com.lagradost.cloudstream3.ui.player.FullScreen
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
player_intro_play?.apply {
|
playerBinding?.playerIntroPlay?.apply {
|
||||||
layoutParams =
|
layoutParams =
|
||||||
FrameLayout.LayoutParams(
|
FrameLayout.LayoutParams(
|
||||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
@ -83,7 +83,7 @@ open class ResultTrailerPlayer : com.lagradost.cloudstream3.ui.player.FullScreen
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player_intro_play?.isGone == true) {
|
if (playerBinding?.playerIntroPlay?.isGone == true) {
|
||||||
result_top_holder?.apply {
|
result_top_holder?.apply {
|
||||||
|
|
||||||
val anim = ValueAnimator.ofInt(
|
val anim = ValueAnimator.ofInt(
|
||||||
|
@ -131,7 +131,8 @@ open class ResultTrailerPlayer : com.lagradost.cloudstream3.ui.player.FullScreen
|
||||||
private fun updateFullscreen(fullscreen: Boolean) {
|
private fun updateFullscreen(fullscreen: Boolean) {
|
||||||
isFullScreenPlayer = fullscreen
|
isFullScreenPlayer = fullscreen
|
||||||
lockRotation = fullscreen
|
lockRotation = fullscreen
|
||||||
player_fullscreen?.setImageResource(if (fullscreen) R.drawable.baseline_fullscreen_exit_24 else R.drawable.baseline_fullscreen_24)
|
|
||||||
|
playerBinding?.playerFullscreen?.setImageResource(if (fullscreen) R.drawable.baseline_fullscreen_exit_24 else R.drawable.baseline_fullscreen_24)
|
||||||
if (fullscreen) {
|
if (fullscreen) {
|
||||||
enterFullscreen()
|
enterFullscreen()
|
||||||
result_top_bar?.isVisible = false
|
result_top_bar?.isVisible = false
|
||||||
|
@ -157,14 +158,14 @@ open class ResultTrailerPlayer : com.lagradost.cloudstream3.ui.player.FullScreen
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
player_fullscreen?.setOnClickListener {
|
playerBinding?.playerFullscreen?.setOnClickListener {
|
||||||
updateFullscreen(!isFullScreenPlayer)
|
updateFullscreen(!isFullScreenPlayer)
|
||||||
}
|
}
|
||||||
updateFullscreen(isFullScreenPlayer)
|
updateFullscreen(isFullScreenPlayer)
|
||||||
uiReset()
|
uiReset()
|
||||||
|
|
||||||
player_intro_play?.setOnClickListener {
|
playerBinding?.playerIntroPlay?.setOnClickListener {
|
||||||
player_intro_play?.isGone = true
|
playerBinding?.playerIntroPlay?.isGone = true
|
||||||
player.handleEvent(CSPlayerEvent.Play)
|
player.handleEvent(CSPlayerEvent.Play)
|
||||||
updateUIVisibility()
|
updateUIVisibility()
|
||||||
fixPlayerSize()
|
fixPlayerSize()
|
||||||
|
|
|
@ -277,7 +277,9 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:descendantFocusability="blocksDescendants">
|
android:descendantFocusability="blocksDescendants">
|
||||||
|
|
||||||
<include layout="@layout/fragment_trailer" />
|
<include
|
||||||
|
android:id="@+id/fragment_trailer"
|
||||||
|
layout="@layout/fragment_trailer" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
@ -721,7 +723,6 @@
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/result_episodes_tab"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
|
@ -189,7 +189,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="start">
|
android:layout_gravity="start">
|
||||||
|
|
||||||
<include layout="@layout/result_sync"/>
|
<include layout="@layout/result_sync" android:id="@+id/result_sync"/>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
@ -198,7 +198,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<include layout="@layout/fragment_result" />
|
<include layout="@layout/fragment_result" android:id="@+id/fragment_result" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="end">
|
android:layout_gravity="end">
|
||||||
|
|
||||||
<include layout="@layout/result_recommendations" />
|
<include layout="@layout/result_recommendations" android:id="@+id/result_recommendations" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
</com.discord.panels.OverlappingPanelsLayout>
|
</com.discord.panels.OverlappingPanelsLayout>
|
||||||
|
|
||||||
|
|
|
@ -746,7 +746,7 @@
|
||||||
android:layout_marginEnd="10dp"
|
android:layout_marginEnd="10dp"
|
||||||
android:nextFocusUp="@id/result_episodes"
|
android:nextFocusUp="@id/result_episodes"
|
||||||
|
|
||||||
android:nextFocusDown="@id/result_recommendations"
|
android:nextFocusDown="@id/result_recommendations_list"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
tools:itemCount="2"
|
tools:itemCount="2"
|
||||||
|
@ -763,7 +763,7 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<com.lagradost.cloudstream3.ui.AutofitRecyclerView
|
<com.lagradost.cloudstream3.ui.AutofitRecyclerView
|
||||||
android:id="@+id/result_recommendations"
|
android:id="@+id/result_recommendations_list"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
|
@ -84,6 +84,33 @@
|
||||||
style="@style/SmallBlackButton"
|
style="@style/SmallBlackButton"
|
||||||
android:text="@string/filler" />
|
android:text="@string/filler" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
<!-- atm this is useless, however it might be used for PIP one day? -->
|
||||||
|
<ImageView
|
||||||
|
android:visibility="gone"
|
||||||
|
android:id="@+id/player_fullscreen"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:src="@drawable/baseline_fullscreen_24"
|
||||||
|
app:tint="@color/white" />
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/player_intro_play"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/player_open_source"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:clickable="false"
|
||||||
|
android:focusable="false"
|
||||||
|
android:focusableInTouchMode="false"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:importantForAccessibility="no" />
|
||||||
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/player_video_holder"
|
android:id="@+id/player_video_holder"
|
||||||
|
|
|
@ -167,6 +167,34 @@
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:visibility="gone"
|
||||||
|
android:id="@+id/player_intro_play"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:visibility="gone"
|
||||||
|
android:id="@+id/player_open_source"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:clickable="false"
|
||||||
|
android:focusable="false"
|
||||||
|
android:focusableInTouchMode="false"
|
||||||
|
android:importantForAccessibility="no" />
|
||||||
|
|
||||||
|
<!-- atm this is useless, however it might be used for PIP one day? -->
|
||||||
|
<ImageView
|
||||||
|
android:visibility="gone"
|
||||||
|
android:id="@+id/player_fullscreen"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:src="@drawable/baseline_fullscreen_24"
|
||||||
|
app:tint="@color/white" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/player_video_holder"
|
android:id="@+id/player_video_holder"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
android:layout_marginBottom="10dp"
|
android:layout_marginBottom="10dp"
|
||||||
android:layout_marginStart="0dp"
|
android:layout_marginStart="0dp"
|
||||||
android:layout_marginEnd="0dp"
|
android:layout_marginEnd="0dp"
|
||||||
app:layout_constraintBottom_toTopOf="@id/result_recommendations" />
|
app:layout_constraintBottom_toTopOf="@id/result_recommendations_list" />
|
||||||
|
|
||||||
<com.lagradost.cloudstream3.ui.AutofitRecyclerView
|
<com.lagradost.cloudstream3.ui.AutofitRecyclerView
|
||||||
android:descendantFocusability="afterDescendants"
|
android:descendantFocusability="afterDescendants"
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
app:spanCount="3"
|
app:spanCount="3"
|
||||||
android:id="@+id/result_recommendations"
|
android:id="@+id/result_recommendations_list"
|
||||||
tools:listitem="@layout/search_result_grid"
|
tools:listitem="@layout/search_result_grid"
|
||||||
android:orientation="vertical" />
|
android:orientation="vertical" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -75,11 +75,118 @@
|
||||||
android:src="@drawable/play_button" />
|
android:src="@drawable/play_button" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:visibility="gone"
|
||||||
|
android:id="@+id/player_top_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="80dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:layout_marginEnd="32dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/player_video_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="Hello world" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/player_video_title_rez"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:text="1920x1080" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/player_episode_filler_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginTop="2dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_episode_filler"
|
||||||
|
style="@style/SmallBlackButton"
|
||||||
|
android:text="@string/filler" />
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Removed as it has no use anymore-->
|
||||||
|
<!--<androidx.mediarouter.app.MediaRouteButton
|
||||||
|
android:id="@+id/player_media_route_button"
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="70dp"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:mediaRouteTypes="user"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />-->
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/player_go_back_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:contentDescription="@string/go_back_img_des"
|
||||||
|
android:src="@drawable/ic_baseline_arrow_back_24"
|
||||||
|
app:tint="@android:color/white" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/player_go_back"
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="70dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:background="@drawable/video_tap_button_always_white"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/go_back_img_des"
|
||||||
|
android:focusable="true" />
|
||||||
|
</FrameLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/player_video_holder"
|
android:id="@+id/player_video_holder"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/skip_chapter_button"
|
||||||
|
style="@style/NiceButton"
|
||||||
|
android:layout_width="150dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginEnd="100dp"
|
||||||
|
android:backgroundTint="@color/skipOpTransparent"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:cornerRadius="@dimen/rounded_button_radius"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/bottom_player_bar"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:strokeColor="@color/white"
|
||||||
|
app:strokeWidth="1dp"
|
||||||
|
tools:text="Skip Opening"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<!--use for thinner app:trackThickness="3dp" com.google.android.material.progressindicator.CircularProgressIndicator-->
|
<!--use for thinner app:trackThickness="3dp" com.google.android.material.progressindicator.CircularProgressIndicator-->
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/player_buffering"
|
android:id="@+id/player_buffering"
|
||||||
|
@ -282,6 +389,11 @@
|
||||||
tools:ignore="ContentDescription" />
|
tools:ignore="ContentDescription" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/piphide"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/player_open_source"
|
android:id="@+id/player_open_source"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
|
@ -366,7 +478,110 @@
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:src="@drawable/baseline_fullscreen_24"
|
android:src="@drawable/baseline_fullscreen_24"
|
||||||
app:tint="@color/white" />
|
app:tint="@color/white" />
|
||||||
|
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingBottom="10dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_lock"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:nextFocusLeft="@id/player_skip_episode"
|
||||||
|
android:nextFocusRight="@id/player_resize_btt"
|
||||||
|
android:text="@string/video_lock"
|
||||||
|
app:icon="@drawable/video_locked"
|
||||||
|
|
||||||
|
app:iconSize="30dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/player_lock_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_resize_btt"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:nextFocusLeft="@id/player_lock"
|
||||||
|
|
||||||
|
android:nextFocusRight="@id/player_speed_btt"
|
||||||
|
android:text="@string/video_aspect_ratio_resize"
|
||||||
|
app:icon="@drawable/ic_baseline_aspect_ratio_24" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_speed_btt"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:nextFocusLeft="@id/player_resize_btt"
|
||||||
|
|
||||||
|
android:nextFocusRight="@id/player_subtitle_offset_btt"
|
||||||
|
app:icon="@drawable/ic_baseline_speed_24"
|
||||||
|
tools:text="Speed" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_subtitle_offset_btt"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:nextFocusLeft="@id/player_speed_btt"
|
||||||
|
android:nextFocusRight="@id/player_sources_btt"
|
||||||
|
android:text="@string/subtitle_offset"
|
||||||
|
|
||||||
|
android:visibility="gone"
|
||||||
|
app:icon="@drawable/ic_outline_subtitles_24"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_sources_btt"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
|
||||||
|
android:nextFocusLeft="@id/player_subtitle_offset_btt"
|
||||||
|
android:nextFocusRight="@id/player_tracks_btt"
|
||||||
|
android:text="@string/video_source"
|
||||||
|
app:icon="@drawable/ic_baseline_playlist_play_24" />
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_tracks_btt"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
|
||||||
|
android:nextFocusLeft="@id/player_sources_btt"
|
||||||
|
android:nextFocusRight="@id/player_skip_op"
|
||||||
|
android:text="@string/tracks"
|
||||||
|
app:icon="@drawable/ic_baseline_playlist_play_24" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_skip_op"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:nextFocusLeft="@id/player_sources_btt"
|
||||||
|
|
||||||
|
android:nextFocusRight="@id/player_skip_episode"
|
||||||
|
android:text="@string/video_skip_op"
|
||||||
|
app:icon="@drawable/ic_baseline_fast_forward_24" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_skip_episode"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:nextFocusLeft="@id/player_skip_op"
|
||||||
|
|
||||||
|
android:nextFocusRight="@id/player_lock"
|
||||||
|
android:text="@string/next_episode"
|
||||||
|
app:icon="@drawable/ic_baseline_skip_next_24" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|
Loading…
Reference in a new issue