2021-05-16 18:28:00 +00:00
package com.lagradost.cloudstream3.ui.result
2021-05-18 13:43:32 +00:00
import android.annotation.SuppressLint
2022-08-03 00:04:03 +00:00
import android.app.Dialog
2021-09-03 09:13:34 +00:00
import android.content.Intent
2021-07-17 15:56:26 +00:00
import android.content.Intent.*
2021-12-10 19:48:21 +00:00
import android.content.res.ColorStateList
2021-12-13 18:41:33 +00:00
import android.content.res.Configuration
2022-02-04 20:49:35 +00:00
import android.graphics.Rect
2021-06-10 15:15:14 +00:00
import android.net.Uri
2022-04-02 01:38:55 +00:00
import android.os.Build
2021-05-16 18:28:00 +00:00
import android.os.Bundle
2022-04-02 01:38:55 +00:00
import android.text.Editable
2021-05-16 18:28:00 +00:00
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
2022-08-02 00:43:42 +00:00
import android.widget.AbsListView
import android.widget.ArrayAdapter
2022-08-03 00:04:03 +00:00
import android.widget.ImageView
2022-08-02 00:43:42 +00:00
import android.widget.Toast
2021-05-18 13:43:32 +00:00
import androidx.appcompat.app.AlertDialog
2021-12-10 00:20:24 +00:00
import androidx.core.view.isGone
2021-09-19 22:36:32 +00:00
import androidx.core.view.isVisible
2021-05-18 13:43:32 +00:00
import androidx.core.widget.NestedScrollView
2022-04-02 01:38:55 +00:00
import androidx.core.widget.doOnTextChanged
2022-01-07 19:27:25 +00:00
import androidx.lifecycle.ViewModelProvider
2021-09-19 22:36:32 +00:00
import androidx.preference.PreferenceManager
2022-02-04 20:49:35 +00:00
import com.discord.panels.OverlappingPanelsLayout
import com.discord.panels.PanelsChildGestureRegionObserver
2021-06-06 18:06:01 +00:00
import com.google.android.gms.cast.framework.CastButtonFactory
import com.google.android.gms.cast.framework.CastContext
import com.google.android.gms.cast.framework.CastState
2022-08-03 00:04:03 +00:00
import com.google.android.material.bottomsheet.BottomSheetDialog
2021-06-06 18:06:01 +00:00
import com.google.android.material.button.MaterialButton
2021-06-14 00:00:29 +00:00
import com.lagradost.cloudstream3.*
2021-06-16 22:31:41 +00:00
import com.lagradost.cloudstream3.APIHolder.getApiFromName
2022-06-17 20:43:42 +00:00
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
2022-01-07 19:27:25 +00:00
import com.lagradost.cloudstream3.CommonActivity.showToast
2022-08-03 00:04:03 +00:00
import com.lagradost.cloudstream3.mvvm.*
2022-06-18 23:03:25 +00:00
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
2021-06-15 23:25:58 +00:00
import com.lagradost.cloudstream3.ui.WatchType
2021-07-24 20:50:57 +00:00
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
2022-06-16 23:58:55 +00:00
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
2021-11-20 00:41:37 +00:00
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
2021-12-13 18:41:33 +00:00
import com.lagradost.cloudstream3.ui.search.SearchAdapter
import com.lagradost.cloudstream3.ui.search.SearchHelper
2022-03-29 21:50:07 +00:00
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
2021-12-10 19:48:21 +00:00
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
2022-06-29 01:20:23 +00:00
import com.lagradost.cloudstream3.utils.AppUtils.html
2021-07-30 01:14:53 +00:00
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
2022-01-07 19:27:25 +00:00
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
2021-12-16 23:45:20 +00:00
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
2022-08-02 00:43:42 +00:00
import com.lagradost.cloudstream3.utils.DataStoreHelper
2021-06-15 16:07:20 +00:00
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
2022-08-02 00:43:42 +00:00
import com.lagradost.cloudstream3.utils.ExtractorLink
2021-12-10 19:48:21 +00:00
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
2022-08-03 00:04:03 +00:00
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant
2022-08-02 00:43:42 +00:00
import com.lagradost.cloudstream3.utils.UIHelper
2021-08-24 22:19:15 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
2022-08-03 00:04:03 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
2021-08-24 22:19:15 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
2021-12-13 18:41:33 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
2021-08-24 22:19:15 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIcons
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
2021-05-18 13:43:32 +00:00
import kotlinx.android.synthetic.main.fragment_result.*
2022-02-04 20:49:35 +00:00
import kotlinx.android.synthetic.main.fragment_result_swipe.*
2022-06-16 23:58:55 +00:00
import kotlinx.android.synthetic.main.fragment_trailer.*
2022-04-18 00:26:13 +00:00
import kotlinx.android.synthetic.main.result_recommendations.*
2022-04-01 20:05:34 +00:00
import kotlinx.android.synthetic.main.result_sync.*
2022-06-16 23:58:55 +00:00
import kotlinx.android.synthetic.main.trailer_custom_layout.*
2022-08-03 00:04:03 +00:00
import kotlinx.coroutines.runBlocking
2022-06-21 00:30:55 +00:00
2021-07-29 15:16:08 +00:00
const val START _ACTION _NORMAL = 0
const val START _ACTION _RESUME _LATEST = 1
2021-08-25 15:28:25 +00:00
const val START _ACTION _LOAD _EP = 2
const val START _VALUE _NORMAL = 0
2021-07-29 15:16:08 +00:00
2021-05-18 13:43:32 +00:00
data class ResultEpisode (
2022-01-07 19:27:25 +00:00
val headerName : String ,
2021-05-18 13:43:32 +00:00
val name : String ? ,
2021-06-10 15:15:14 +00:00
val poster : String ? ,
2021-05-18 13:43:32 +00:00
val episode : Int ,
2022-08-01 01:00:48 +00:00
val seasonIndex : Int ? , // this is the "season" index used season names
val season : Int ? , // this is the display
2021-06-14 16:58:43 +00:00
val data : String ,
2021-05-18 13:43:32 +00:00
val apiName : String ,
val id : Int ,
2021-05-22 22:25:56 +00:00
val index : Int ,
2021-06-15 16:07:20 +00:00
val position : Long , // time in MS
2021-06-10 15:15:14 +00:00
val duration : Long , // duration in MS
2021-06-26 19:32:50 +00:00
val rating : Int ? ,
2021-12-10 00:20:24 +00:00
val description : String ? ,
2021-09-19 22:36:32 +00:00
val isFiller : Boolean ? ,
2022-01-07 19:27:25 +00:00
val tvType : TvType ,
2022-02-13 14:51:55 +00:00
val parentId : Int ,
2021-05-18 13:43:32 +00:00
)
2021-05-16 18:28:00 +00:00
2021-06-15 16:07:20 +00:00
fun ResultEpisode . getRealPosition ( ) : Long {
if ( duration <= 0 ) return 0
val percentage = position * 100 / duration
if ( percentage <= 5 || percentage >= 95 ) return 0
return position
}
2021-06-16 17:40:02 +00:00
fun ResultEpisode . getDisplayPosition ( ) : Long {
if ( duration <= 0 ) return 0
val percentage = position * 100 / duration
if ( percentage <= 1 ) return 0
if ( percentage <= 5 ) return 5 * duration / 100
if ( percentage >= 95 ) return duration
return position
}
2021-12-16 23:45:20 +00:00
fun buildResultEpisode (
2022-01-07 19:27:25 +00:00
headerName : String ,
2022-04-26 13:52:30 +00:00
name : String ? = null ,
poster : String ? = null ,
2021-06-15 16:07:20 +00:00
episode : Int ,
2022-08-01 01:00:48 +00:00
seasonIndex : Int ? = null ,
2022-04-26 13:52:30 +00:00
season : Int ? = null ,
2021-06-15 16:07:20 +00:00
data : String ,
apiName : String ,
id : Int ,
index : Int ,
2022-04-26 13:52:30 +00:00
rating : Int ? = null ,
description : String ? = null ,
isFiller : Boolean ? = null ,
2022-01-07 19:27:25 +00:00
tvType : TvType ,
2022-02-13 14:51:55 +00:00
parentId : Int ,
2021-06-15 16:07:20 +00:00
) : ResultEpisode {
val posDur = getViewPos ( id )
2021-06-26 19:32:50 +00:00
return ResultEpisode (
2022-01-07 19:27:25 +00:00
headerName ,
2021-06-26 19:32:50 +00:00
name ,
2021-06-15 16:07:20 +00:00
poster ,
episode ,
2022-08-01 01:00:48 +00:00
seasonIndex ,
2021-06-15 16:07:20 +00:00
season ,
data ,
apiName ,
id ,
index ,
posDur ?. position ?: 0 ,
2021-06-26 19:32:50 +00:00
posDur ?. duration ?: 0 ,
rating ,
2021-11-30 17:59:52 +00:00
description ,
2022-01-07 19:27:25 +00:00
isFiller ,
tvType ,
parentId ,
2021-06-26 19:32:50 +00:00
)
2021-06-15 16:07:20 +00:00
}
2021-07-29 15:16:08 +00:00
/** 0f-1f */
2021-06-10 15:15:14 +00:00
fun ResultEpisode . getWatchProgress ( ) : Float {
2021-07-29 15:16:08 +00:00
return ( getDisplayPosition ( ) / 1000 ) . toFloat ( ) / ( duration / 1000 ) . toFloat ( )
2021-06-10 15:15:14 +00:00
}
2022-06-16 01:04:24 +00:00
class ResultFragment : ResultTrailerPlayer ( ) {
2021-05-22 22:25:56 +00:00
companion object {
2022-05-02 21:32:28 +00:00
const val URL _BUNDLE = " url "
const val API _NAME _BUNDLE = " apiName "
const val SEASON _BUNDLE = " season "
const val EPISODE _BUNDLE = " episode "
const val START _ACTION _BUNDLE = " startAction "
const val START _VALUE _BUNDLE = " startValue "
const val RESTART _BUNDLE = " restart "
fun newInstance (
card : SearchResponse , startAction : Int = 0 , startValue : Int ? = null
) : Bundle {
return Bundle ( ) . apply {
putString ( URL _BUNDLE , card . url )
putString ( API _NAME _BUNDLE , card . apiName )
if ( card is DataStoreHelper . ResumeWatchingResult ) {
2022-05-20 18:25:56 +00:00
// println("CARD::::: $card")
2022-05-02 21:32:28 +00:00
if ( card . season != null )
putInt ( SEASON _BUNDLE , card . season )
if ( card . episode != null )
putInt ( EPISODE _BUNDLE , card . episode )
}
putInt ( START _ACTION _BUNDLE , startAction )
if ( startValue != null )
putInt ( START _VALUE _BUNDLE , startValue )
putBoolean ( RESTART _BUNDLE , true )
}
}
2021-12-17 12:42:25 +00:00
fun newInstance (
url : String ,
apiName : String ,
startAction : Int = 0 ,
startValue : Int = 0
) : Bundle {
2021-09-20 21:11:36 +00:00
return Bundle ( ) . apply {
2022-05-02 21:32:28 +00:00
putString ( URL _BUNDLE , url )
putString ( API _NAME _BUNDLE , apiName )
putInt ( START _ACTION _BUNDLE , startAction )
putInt ( START _VALUE _BUNDLE , startValue )
putBoolean ( RESTART _BUNDLE , true )
2021-05-18 13:43:32 +00:00
}
2021-09-20 21:11:36 +00:00
}
2022-01-18 14:10:01 +00:00
fun updateUI ( ) {
updateUIListener ?. invoke ( )
}
2022-01-31 20:47:59 +00:00
private var updateUIListener : ( ( ) -> Unit ) ? = null
2021-05-22 22:25:56 +00:00
}
2022-08-01 01:00:48 +00:00
private lateinit var viewModel : ResultViewModel2 //by activityViewModels()
2022-04-01 20:05:34 +00:00
private lateinit var syncModel : SyncViewModel
2021-05-16 18:28:00 +00:00
override fun onCreateView (
inflater : LayoutInflater ,
container : ViewGroup ? ,
2021-05-18 13:43:32 +00:00
savedInstanceState : Bundle ? ,
2021-05-16 18:28:00 +00:00
) : View ? {
2022-01-07 19:27:25 +00:00
viewModel =
2022-08-01 01:00:48 +00:00
ViewModelProvider ( this ) [ ResultViewModel2 :: class . java ]
2022-04-01 20:05:34 +00:00
syncModel =
ViewModelProvider ( this ) [ SyncViewModel :: class . java ]
2022-02-04 20:49:35 +00:00
return inflater . inflate ( R . layout . fragment _result _swipe , container , false )
2021-05-16 18:28:00 +00:00
}
2021-07-28 19:14:45 +00:00
override fun onDestroyView ( ) {
2022-07-17 00:41:01 +00:00
updateUIListener = null
2021-07-28 19:14:45 +00:00
( result _episodes ?. adapter as EpisodeAdapter ? ) ?. killAdapter ( )
2022-08-02 00:43:42 +00:00
//downloadButton?.dispose() //TODO READD
2022-07-17 00:41:01 +00:00
//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
PanelsChildGestureRegionObserver . Provider . get ( ) . removeGestureRegionsUpdateListener ( this )
result _cast _items ?. let {
PanelsChildGestureRegionObserver . Provider . get ( ) . unregister ( it )
}
2021-07-28 19:14:45 +00:00
super . onDestroyView ( )
}
2021-06-16 00:15:07 +00:00
override fun onResume ( ) {
super . onResume ( )
activity ?. let {
it . window ?. navigationBarColor =
2021-09-19 20:33:39 +00:00
it . colorFromAttribute ( R . attr . primaryBlackBackground )
2021-06-16 00:15:07 +00:00
}
2021-05-22 22:25:56 +00:00
}
2021-06-16 16:54:07 +00:00
/// 0 = LOADING, 1 = ERROR LOADING, 2 = LOADED
2021-07-02 18:46:18 +00:00
private fun updateVisStatus ( state : Int ) {
2021-06-16 16:54:07 +00:00
when ( state ) {
0 -> {
2021-12-10 19:48:21 +00:00
result _bookmark _fab ?. isGone = true
result _loading ?. isVisible = true
result _finish _loading ?. isVisible = false
result _loading _error ?. isVisible = false
2021-06-16 16:54:07 +00:00
}
1 -> {
2021-12-10 19:48:21 +00:00
result _bookmark _fab ?. isGone = true
result _loading ?. isVisible = false
result _finish _loading ?. isVisible = false
result _loading _error ?. isVisible = true
2022-08-02 00:43:42 +00:00
result _reload _connection _open _in _browser ?. isVisible = true
2021-06-16 16:54:07 +00:00
}
2 -> {
2021-12-10 19:48:21 +00:00
result _bookmark _fab ?. isGone = result _bookmark _fab ?. context ?. isTvSettings ( ) == true
result _bookmark _fab ?. extend ( )
2022-03-29 21:50:07 +00:00
if ( result _bookmark _button ?. context ?. isTrueTvSettings ( ) == true ) {
when {
result _play _movie ?. isVisible == true -> {
result _play _movie ?. requestFocus ( )
}
result _resume _series _button ?. isVisible == true -> {
result _resume _series _button ?. requestFocus ( )
}
else -> {
result _bookmark _button ?. requestFocus ( )
}
}
2021-12-10 19:48:21 +00:00
}
2021-10-09 21:59:37 +00:00
2021-12-10 19:48:21 +00:00
result _loading ?. isVisible = false
result _finish _loading ?. isVisible = true
result _loading _error ?. isVisible = false
2021-06-16 16:54:07 +00:00
}
}
}
2021-06-26 22:15:19 +00:00
private fun fromIndexToSeasonText ( selection : Int ? ) : String {
return when ( selection ) {
2021-09-02 13:19:50 +00:00
null -> getString ( R . string . no _season )
- 2 -> getString ( R . string . no _season )
else -> " ${getString(R.string.season)} $selection "
2021-06-26 22:15:19 +00:00
}
}
2021-07-29 15:16:08 +00:00
var startAction : Int ? = null
2021-12-13 18:41:33 +00:00
private var startValue : Int ? = null
2022-06-17 17:25:41 +00:00
var currentTrailers : List < ExtractorLink > = emptyList ( )
2022-06-16 01:04:24 +00:00
var currentTrailerIndex = 0
override fun nextMirror ( ) {
currentTrailerIndex ++
loadTrailer ( )
}
2022-07-16 01:43:10 +00:00
override fun hasNextMirror ( ) : Boolean {
return currentTrailerIndex + 1 < currentTrailers . size
}
2022-06-16 01:04:24 +00:00
override fun playerError ( exception : Exception ) {
2022-06-16 23:58:55 +00:00
if ( player . getIsPlaying ( ) ) { // because we dont want random toasts in player
2022-06-16 01:04:24 +00:00
super . playerError ( exception )
2022-06-16 23:58:55 +00:00
} else {
nextMirror ( )
}
2022-06-16 01:04:24 +00:00
}
private fun loadTrailer ( index : Int ? = null ) {
2022-06-16 23:58:55 +00:00
val isSuccess =
currentTrailers . getOrNull ( index ?: currentTrailerIndex ) ?. let { trailer ->
context ?. let { ctx ->
player . onPause ( )
player . loadPlayer (
ctx ,
false ,
2022-06-17 17:25:41 +00:00
trailer ,
2022-06-16 23:58:55 +00:00
null ,
startPosition = 0L ,
subtitles = emptySet ( ) ,
subtitle = null ,
autoPlay = false
)
true
} ?: run {
false
}
} ?: run {
false
2022-06-16 01:04:24 +00:00
}
2022-06-16 23:58:55 +00:00
result _trailer _loading ?. isVisible = isSuccess
2022-06-18 23:03:25 +00:00
result _smallscreen _holder ?. isVisible = !is Success && !is FullScreenPlayer
2022-07-01 17:10:57 +00:00
// 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
}
2022-06-18 23:03:25 +00:00
result _fullscreen _holder ?. isVisible = !is Success && isFullScreenPlayer
2022-06-16 01:04:24 +00:00
}
2022-06-17 17:25:41 +00:00
private fun setTrailers ( trailers : List < ExtractorLink > ? ) {
2022-06-17 20:43:42 +00:00
context ?. updateHasTrailers ( )
if ( ! LoadResponse . isTrailersEnabled ) return
currentTrailers = trailers ?. sortedBy { - it . quality } ?: emptyList ( )
loadTrailer ( )
2022-06-16 01:04:24 +00:00
}
2022-04-18 00:26:13 +00:00
private fun setRecommendations ( rec : List < SearchResponse > ? , validApiName : String ? ) {
2022-02-04 20:49:35 +00:00
val isInvalid = rec . isNullOrEmpty ( )
result _recommendations ?. isGone = isInvalid
result _recommendations _btt ?. isGone = isInvalid
result _recommendations _btt ?. setOnClickListener {
2022-04-18 00:26:13 +00:00
val nextFocusDown = if ( result _overlapping _panels ?. getSelectedPanel ( ) ?. ordinal == 1 ) {
2022-02-04 20:49:35 +00:00
result _overlapping _panels ?. openEndPanel ( )
2022-04-18 00:26:13 +00:00
R . id . result _recommendations
2022-02-04 20:49:35 +00:00
} else {
result _overlapping _panels ?. closePanels ( )
2022-04-18 00:26:13 +00:00
R . id . result _description
2022-02-04 20:49:35 +00:00
}
2022-04-18 00:26:13 +00:00
result _recommendations _btt ?. nextFocusDownId = nextFocusDown
result _search ?. nextFocusDownId = nextFocusDown
result _open _in _browser ?. nextFocusDownId = nextFocusDown
result _share ?. nextFocusDownId = nextFocusDown
2022-02-04 20:49:35 +00:00
}
result _overlapping _panels ?. setEndPanelLockState ( if ( isInvalid ) OverlappingPanelsLayout . LockState . CLOSE else OverlappingPanelsLayout . LockState . UNLOCKED )
2022-04-18 00:26:13 +00:00
val matchAgainst = validApiName ?: rec ?. firstOrNull ( ) ?. apiName
rec ?. map { it . apiName } ?. distinct ( ) ?. let { apiNames ->
// very dirty selection
result _recommendations _filter _button ?. isVisible = apiNames . size > 1
result _recommendations _filter _button ?. text = matchAgainst
result _recommendations _filter _button ?. setOnClickListener { _ ->
activity ?. showBottomDialog (
apiNames ,
apiNames . indexOf ( matchAgainst ) ,
getString ( R . string . home _change _provider _img _des ) , false , { }
) {
setRecommendations ( rec , apiNames [ it ] )
}
}
} ?: run {
result _recommendations _filter _button ?. isVisible = false
}
2022-04-03 21:41:28 +00:00
result _recommendations ?. post {
2022-02-05 01:05:13 +00:00
rec ?. let { list ->
2022-04-18 00:26:13 +00:00
( result _recommendations ?. adapter as SearchAdapter ? ) ?. updateList ( list . filter { it . apiName == matchAgainst } )
2021-12-13 18:41:33 +00:00
}
}
}
private fun fixGrid ( ) {
2022-02-04 20:49:35 +00:00
activity ?. getSpanCount ( ) ?. let { _ ->
//result_recommendations?.spanCount = count // this is due to discord not changing size with rotation
2021-12-13 18:41:33 +00:00
}
}
override fun onConfigurationChanged ( newConfig : Configuration ) {
super . onConfigurationChanged ( newConfig )
fixGrid ( )
}
2021-07-29 15:16:08 +00:00
2022-01-18 14:10:01 +00:00
private fun updateUI ( ) {
2022-04-08 19:38:19 +00:00
syncModel . updateUserData ( )
2022-01-18 14:10:01 +00:00
viewModel . reloadEpisodes ( )
}
2022-08-03 00:04:03 +00:00
var loadingDialog : Dialog ? = null
var popupDialog : Dialog ? = null
2022-07-17 00:41:01 +00:00
2021-05-18 13:43:32 +00:00
@SuppressLint ( " SetTextI18n " )
2021-05-16 18:28:00 +00:00
override fun onViewCreated ( view : View , savedInstanceState : Bundle ? ) {
super . onViewCreated ( view , savedInstanceState )
2022-07-17 00:41:01 +00:00
2022-02-05 22:21:45 +00:00
result _cast _items ?. let {
PanelsChildGestureRegionObserver . Provider . get ( ) . register ( it )
}
2022-07-24 02:49:15 +00:00
result _cast _items ?. adapter = ActorAdaptor ( )
2021-12-13 18:41:33 +00:00
fixGrid ( )
2022-02-04 20:49:35 +00:00
result _recommendations ?. spanCount = 3
result _overlapping _panels ?. setStartPanelLockState ( OverlappingPanelsLayout . LockState . CLOSE )
result _overlapping _panels ?. setEndPanelLockState ( OverlappingPanelsLayout . LockState . CLOSE )
2021-08-29 13:10:36 +00:00
2022-06-16 23:58:55 +00:00
player _open _source ?. setOnClickListener {
currentTrailers . getOrNull ( currentTrailerIndex ) ?. let {
2022-06-17 17:25:41 +00:00
context ?. openBrowser ( it . url )
2022-06-16 23:58:55 +00:00
}
}
2022-01-18 14:10:01 +00:00
updateUIListener = :: updateUI
2022-05-02 21:32:28 +00:00
val restart = arguments ?. getBoolean ( RESTART _BUNDLE ) ?: false
2021-09-20 21:11:36 +00:00
if ( restart ) {
2022-05-02 21:32:28 +00:00
arguments ?. putBoolean ( RESTART _BUNDLE , false )
2021-09-20 21:11:36 +00:00
}
2021-07-28 01:04:32 +00:00
activity ?. window ?. decorView ?. clearFocus ( )
hideKeyboard ( )
2022-06-17 20:43:42 +00:00
context ?. updateHasTrailers ( )
2022-01-07 19:27:25 +00:00
activity ?. loadCache ( )
2021-07-28 01:04:32 +00:00
2022-02-04 20:49:35 +00:00
activity ?. fixPaddingStatusbar ( result _top _bar )
2021-09-19 20:33:39 +00:00
//activity?.fixPaddingStatusbar(result_barstatus)
2021-06-06 18:06:01 +00:00
2021-12-10 00:20:24 +00:00
/ * val backParameter = result _back . layoutParams as FrameLayout . LayoutParams
backParameter . setMargins (
backParameter . leftMargin ,
backParameter . topMargin + requireContext ( ) . getStatusBarHeight ( ) ,
backParameter . rightMargin ,
backParameter . bottomMargin
)
result _back . layoutParams = backParameter * /
2021-06-16 16:54:07 +00:00
2021-05-20 15:22:28 +00:00
// activity?.fixPaddingStatusbar(result_toolbar)
2021-05-18 13:43:32 +00:00
2022-08-02 00:43:42 +00:00
val url = arguments ?. getString ( URL _BUNDLE )
2022-08-03 00:04:03 +00:00
val apiName = arguments ?. getString ( API _NAME _BUNDLE ) ?: return
2022-05-02 21:32:28 +00:00
startAction = arguments ?. getInt ( START _ACTION _BUNDLE ) ?: START _ACTION _NORMAL
startValue = arguments ?. getInt ( START _VALUE _BUNDLE )
val resumeEpisode = arguments ?. getInt ( EPISODE _BUNDLE )
val resumeSeason = arguments ?. getInt ( SEASON _BUNDLE )
2022-04-02 17:58:56 +00:00
syncModel . addFromUrl ( url )
2021-09-20 21:11:36 +00:00
2021-07-23 23:44:54 +00:00
val api = getApiFromName ( apiName )
if ( media _route _button != null ) {
val chromecastSupport = api . hasChromecastSupport
media _route _button ?. alpha = if ( chromecastSupport ) 1f else 0.3f
if ( ! chromecastSupport ) {
2022-04-10 22:00:03 +00:00
media _route _button ?. setOnClickListener {
2022-02-12 20:38:47 +00:00
showToast ( activity , R . string . no _chromecast _support _toast , Toast . LENGTH _LONG )
2021-07-23 23:44:54 +00:00
}
}
2022-04-10 22:00:03 +00:00
activity ?. let { act ->
if ( act . isCastApiAvailable ( ) ) {
2021-09-24 22:51:08 +00:00
try {
2022-04-10 22:00:03 +00:00
CastButtonFactory . setUpMediaRouteButton ( act , media _route _button )
val castContext = CastContext . getSharedInstance ( act . applicationContext )
2022-04-13 17:29:30 +00:00
media _route _button ?. isGone =
castContext . castState == CastState . NO _DEVICES _AVAILABLE
2022-07-17 00:41:01 +00:00
// this shit leaks for some reason
//castContext.addCastStateListener { state ->
// media_route_button?.isGone = state == CastState.NO_DEVICES_AVAILABLE
//}
2021-10-22 13:23:48 +00:00
} catch ( e : Exception ) {
2021-09-24 22:51:08 +00:00
logError ( e )
2021-07-23 23:44:54 +00:00
}
}
}
}
2021-05-18 13:43:32 +00:00
2021-12-10 19:48:21 +00:00
result _scroll . setOnScrollChangeListener ( NestedScrollView . OnScrollChangeListener { _ , _ , scrollY , _ , oldScrollY ->
val dy = scrollY - oldScrollY
if ( dy > 0 ) { //check for scroll down
result _bookmark _fab ?. shrink ( )
} else if ( dy < - 5 ) {
result _bookmark _fab ?. extend ( )
}
2022-06-16 23:58:55 +00:00
if ( !is FullScreenPlayer && player . getIsPlaying ( ) ) {
if ( scrollY > ( player _background ?. height ?: scrollY ) ) {
player . handleEvent ( CSPlayerEvent . Pause )
}
}
2022-06-16 01:04:24 +00:00
//result_poster_blur_holder?.translationY = -scrollY.toFloat()
2021-12-10 19:48:21 +00:00
} )
2021-05-18 13:43:32 +00:00
2021-06-16 16:54:07 +00:00
result _back . setOnClickListener {
2021-07-30 21:03:46 +00:00
activity ?. popCurrentPage ( )
2021-06-16 16:54:07 +00:00
}
2021-06-10 15:15:14 +00:00
2022-07-17 00:41:01 +00:00
result _episodes . adapter =
2021-06-16 16:54:07 +00:00
EpisodeAdapter (
ArrayList ( ) ,
2021-07-23 23:44:54 +00:00
api . hasDownloadSupport ,
2021-07-24 20:50:57 +00:00
{ episodeClick ->
2022-08-02 00:43:42 +00:00
viewModel . handleAction ( activity , episodeClick )
2021-07-24 20:50:57 +00:00
} ,
{ downloadClickEvent ->
2022-08-02 00:43:42 +00:00
handleDownloadClick ( activity , downloadClickEvent )
2021-07-24 20:50:57 +00:00
}
)
2021-07-17 14:14:25 +00:00
2021-06-15 23:25:58 +00:00
result _bookmark _button . setOnClickListener {
it . popupMenuNoIcons (
items = WatchType . values ( )
. map { watchType -> Pair ( watchType . internalId , watchType . stringRes ) } ,
2021-06-16 00:15:07 +00:00
//.map { watchType -> Triple(watchType.internalId, watchType.iconRes, watchType.stringRes) },
2021-06-15 23:25:58 +00:00
) {
2022-05-02 21:32:28 +00:00
viewModel . updateWatchStatus ( WatchType . fromInternalId ( this . itemId ) )
2021-06-15 23:25:58 +00:00
}
}
2021-12-10 19:48:21 +00:00
observe ( viewModel . watchStatus ) { watchType ->
result _bookmark _button ?. text = getString ( watchType . stringRes )
result _bookmark _fab ?. text = getString ( watchType . stringRes )
2021-12-12 02:33:17 +00:00
if ( watchType == WatchType . NONE ) {
2021-12-10 19:48:21 +00:00
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 ->
2021-12-12 02:33:17 +00:00
activity ?. showBottomDialog (
2021-12-10 19:48:21 +00:00
WatchType . values ( ) . map { fab . context . getString ( it . stringRes ) } . toList ( ) ,
watchType . ordinal ,
fab . context . getString ( R . string . action _add _to _bookmarks ) ,
2021-12-10 23:57:11 +00:00
showApply = false ,
2021-12-10 19:48:21 +00:00
{ } ) {
2021-12-16 23:45:20 +00:00
viewModel . updateWatchStatus ( WatchType . values ( ) [ it ] )
2021-12-10 19:48:21 +00:00
}
}
2021-06-15 23:25:58 +00:00
}
2022-03-27 16:45:02 +00:00
/ * *
* Sets next focus to allow navigation up and down between 2 views
* if either of them is null nothing happens .
* * /
fun setFocusUpAndDown ( upper : View ? , down : View ? ) {
if ( upper == null || down == null ) return
upper . nextFocusDownId = down . id
down . nextFocusUpId = upper . id
}
// This is to band-aid FireTV navigation
result _season _button ?. isFocusableInTouchMode = context ?. isTvSettings ( ) == true
result _episode _select ?. isFocusableInTouchMode = context ?. isTvSettings ( ) == true
result _dub _select ?. isFocusableInTouchMode = context ?. isTvSettings ( ) == true
2022-04-02 01:38:55 +00:00
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 )
}
2022-04-02 22:06:35 +00:00
result _sync _current _episodes ?. doOnTextChanged { text , _ , before , count ->
if ( count == before ) return @doOnTextChanged
2022-04-02 01:38:55 +00:00
text ?. toString ( ) ?. toIntOrNull ( ) ?. let { ep ->
syncModel . setEpisodes ( ep )
}
}
}
2022-07-17 00:41:01 +00:00
result _mini _sync ?. adapter = ImageAdapter (
2022-04-22 16:52:31 +00:00
R . layout . result _mini _image ,
nextFocusDown = R . id . result _sync _set _score ,
clickCallback = { action ->
if ( action == IMAGE _CLICK || action == IMAGE _LONG _CLICK ) {
if ( result _overlapping _panels ?. getSelectedPanel ( ) ?. ordinal == 1 ) {
result _overlapping _panels ?. openStartPanel ( )
} else {
result _overlapping _panels ?. closePanels ( )
}
}
} )
2022-04-02 01:38:55 +00:00
2022-04-02 22:06:35 +00:00
observe ( syncModel . synced ) { list ->
result _sync _names ?. text =
list . filter { it . isSynced && it . hasAccount } . joinToString { it . name }
2022-04-03 01:13:02 +00:00
2022-04-22 18:53:58 +00:00
val newList = list . filter { it . isSynced && it . hasAccount }
2022-04-08 19:38:19 +00:00
2022-04-03 01:13:02 +00:00
result _mini _sync ?. isVisible = newList . isNotEmpty ( )
2022-06-07 16:38:24 +00:00
( result _mini _sync ?. adapter as ? ImageAdapter ? ) ?. updateList ( newList . mapNotNull { it . icon } )
2022-04-02 22:06:35 +00:00
}
2022-04-03 01:13:02 +00:00
var currentSyncProgress = 0
2022-04-03 15:00:50 +00:00
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 )
}
}
}
2022-04-02 01:38:55 +00:00
observe ( syncModel . metadata ) { meta ->
when ( meta ) {
is Resource . Success -> {
val d = meta . value
2022-04-03 01:13:02 +00:00
result _sync _episodes ?. progress = currentSyncProgress * 1000
2022-04-03 15:00:50 +00:00
setSyncMaxEpisodes ( d . totalEpisodes )
2022-08-03 01:02:08 +00:00
2022-08-02 00:43:42 +00:00
viewModel . setMeta ( d , syncModel . getSyncs ( ) )
2022-04-02 01:38:55 +00:00
}
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 ->
2022-04-01 20:05:34 +00:00
var closed = false
when ( status ) {
is Resource . Failure -> {
result _sync _loading _shimmer ?. stopShimmer ( )
result _sync _loading _shimmer ?. isVisible = false
result _sync _holder ?. isVisible = false
2022-04-03 21:41:28 +00:00
closed = true
2022-04-01 20:05:34 +00:00
}
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
2022-04-02 01:38:55 +00:00
result _sync _check ?. setItemChecked ( d . status + 1 , true )
val watchedEpisodes = d . watchedEpisodes ?: 0
2022-04-03 01:13:02 +00:00
currentSyncProgress = watchedEpisodes
2022-04-03 15:00:50 +00:00
d . maxEpisodes ?. let {
// don't directly call it because we don't want to override metadata observe
setSyncMaxEpisodes ( it )
}
2022-04-02 01:38:55 +00:00
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
}
}
2022-04-01 20:05:34 +00:00
}
null -> {
closed = false
}
}
result _overlapping _panels ?. setStartPanelLockState ( if ( closed ) OverlappingPanelsLayout . LockState . CLOSE else OverlappingPanelsLayout . LockState . UNLOCKED )
}
2022-08-01 02:46:43 +00:00
/ *
2021-07-29 15:16:08 +00:00
observe ( viewModel . episodes ) { episodeList ->
2021-08-22 17:14:48 +00:00
lateFixDownloadButton ( episodeList . size <= 1 ) // movies can have multible parts but still be *movies* this will fix this
2022-02-04 14:46:48 +00:00
var isSeriesVisible = false
2022-02-06 15:10:45 +00:00
var isProgressVisible = false
2022-02-04 14:46:48 +00:00
DataStoreHelper . getLastWatched ( currentId ) ?. let { resume ->
2022-02-06 15:10:45 +00:00
if ( currentIsMovie == false ) {
2022-02-04 14:46:48 +00:00
isSeriesVisible = true
2022-02-05 23:58:56 +00:00
2022-02-04 14:46:48 +00:00
result _resume _series _button ?. setOnClickListener {
episodeList . firstOrNull { it . id == resume . episodeId } ?. let {
handleAction ( EpisodeClickEvent ( ACTION _PLAY _EPISODE _IN _PLAYER , it ) )
}
}
2022-02-05 23:58:56 +00:00
2022-02-04 14:46:48 +00:00
result _resume _series _title ?. text =
if ( resume . season == null )
" ${getString(R.string.episode)} ${resume.episode} "
else
" \" ${getString(R.string.season_short)} ${resume.season} : ${getString(R.string.episode_short)} ${resume.episode} \" "
2022-02-06 15:10:45 +00:00
}
2022-02-04 14:46:48 +00:00
2022-02-06 15:10:45 +00:00
getViewPos ( resume . episodeId ) ?. let { viewPos ->
2022-02-14 21:12:06 +00:00
if ( viewPos . position > 30 _000L || currentIsMovie == false ) { // first 30s will not show for movies
2022-02-04 14:46:48 +00:00
result _resume _series _progress ?. apply {
max = ( viewPos . duration / 1000 ) . toInt ( )
progress = ( viewPos . position / 1000 ) . toInt ( )
}
2022-02-04 20:49:35 +00:00
result _resume _series _progress _text ?. text =
getString ( R . string . resume _time _left ) . format ( ( viewPos . duration - viewPos . position ) / ( 60 _000 ) )
2022-02-06 15:10:45 +00:00
isProgressVisible = true
} else {
isProgressVisible = false
2022-02-05 23:58:56 +00:00
isSeriesVisible = false
2022-02-04 14:46:48 +00:00
}
2022-02-06 15:10:45 +00:00
} ?: run {
isProgressVisible = false
isSeriesVisible = false
2022-02-04 14:46:48 +00:00
}
}
2022-02-06 15:10:45 +00:00
2022-02-04 14:46:48 +00:00
result _series _parent ?. isVisible = isSeriesVisible
2022-04-03 21:41:28 +00:00
if ( isSeriesVisible && activity ?. currentFocus ?. id == R . id . result _back && context ?. isTrueTvSettings ( ) == true ) {
result _resume _series _button ?. requestFocus ( )
}
2022-03-27 16:45:02 +00:00
if ( isSeriesVisible ) {
val down = when {
result _season _button ?. isVisible == true -> result _season _button
result _episode _select ?. isVisible == true -> result _episode _select
result _dub _select ?. isVisible == true -> result _dub _select
else -> null
}
setFocusUpAndDown ( result _resume _series _button , down )
setFocusUpAndDown ( result _bookmark _button , result _resume _series _button )
}
2022-02-06 15:10:45 +00:00
result _resume _progress _holder ?. isVisible = isProgressVisible
2022-07-19 20:24:55 +00:00
context ?. getString (
when {
currentType ?. isLiveStream ( ) == true -> R . string . play _livestream _button
isProgressVisible -> R . string . resume
else -> R . string . play _movie _button
2022-02-06 15:10:45 +00:00
}
2022-07-19 20:24:55 +00:00
) ?. let {
result _play _movie ?. text = it
}
2022-07-17 00:41:01 +00:00
//println("startAction = $startAction")
2021-08-11 18:26:19 +00:00
2021-07-29 15:16:08 +00:00
when ( startAction ) {
START _ACTION _RESUME _LATEST -> {
for ( ep in episodeList ) {
2022-06-02 22:51:41 +00:00
//println("WATCH STATUS::: S${ep.season} E ${ep.episode} - ${ep.getWatchProgress()}")
2021-07-29 15:16:08 +00:00
if ( ep . getWatchProgress ( ) > 0.90f ) { // watched too much
continue
}
handleAction ( EpisodeClickEvent ( ACTION _PLAY _EPISODE _IN _PLAYER , ep ) )
break
}
}
2021-08-25 15:28:25 +00:00
START _ACTION _LOAD _EP -> {
2022-05-14 17:07:34 +00:00
if ( episodeList . size == 1 ) {
handleAction (
EpisodeClickEvent (
ACTION _PLAY _EPISODE _IN _PLAYER ,
episodeList . first ( )
)
)
2022-05-02 21:32:28 +00:00
} else {
var found = false
for ( ep in episodeList ) {
if ( ep . id == startValue ) { // watched too much
2022-06-02 22:51:41 +00:00
//println("WATCH STATUS::: START_ACTION_LOAD_EP S${ep.season} E ${ep.episode} - ${ep.getWatchProgress()}")
2022-05-02 21:32:28 +00:00
handleAction ( EpisodeClickEvent ( ACTION _PLAY _EPISODE _IN _PLAYER , ep ) )
found = true
break
}
2021-08-25 15:28:25 +00:00
}
2022-05-02 21:32:28 +00:00
if ( ! found )
for ( ep in episodeList ) {
if ( ep . episode == resumeEpisode && ep . season == resumeSeason ) {
2022-06-02 22:51:41 +00:00
//println("WATCH STATUS::: START_ACTION_LOAD_EP S${ep.season} E ${ep.episode} - ${ep.getWatchProgress()}")
2022-05-14 17:07:34 +00:00
handleAction (
EpisodeClickEvent (
ACTION _PLAY _EPISODE _IN _PLAYER ,
ep
)
)
2022-05-02 21:32:28 +00:00
break
}
}
2021-08-25 15:28:25 +00:00
}
2022-05-02 21:32:28 +00:00
2021-08-25 15:28:25 +00:00
}
2022-01-07 19:27:25 +00:00
else -> Unit
2021-07-29 15:16:08 +00:00
}
2021-09-25 13:00:59 +00:00
arguments ?. remove ( " startValue " )
arguments ?. remove ( " startAction " )
2021-08-25 15:28:25 +00:00
startAction = null
2021-09-25 13:00:59 +00:00
startValue = null
2021-07-29 15:16:08 +00:00
}
2022-08-01 02:46:43 +00:00
* /
2022-08-01 01:00:48 +00:00
observe ( viewModel . episodes ) { episodes ->
2021-09-19 22:36:32 +00:00
when ( episodes ) {
2022-08-03 00:04:03 +00:00
is ResourceSome . None -> {
2021-09-20 21:11:36 +00:00
result _episode _loading ?. isVisible = false
2022-08-03 00:04:03 +00:00
result _episodes ?. isVisible = false
2021-09-19 22:36:32 +00:00
}
2022-08-03 00:04:03 +00:00
is ResourceSome . Loading -> {
2021-09-20 21:11:36 +00:00
result _episode _loading ?. isVisible = true
2022-08-03 00:04:03 +00:00
result _episodes ?. isVisible = false
2021-09-19 22:36:32 +00:00
}
2022-08-03 00:04:03 +00:00
is ResourceSome . Success -> {
result _episodes ?. isVisible = true
2021-09-20 21:11:36 +00:00
result _episode _loading ?. isVisible = false
2022-08-02 00:43:42 +00:00
( result _episodes ?. adapter as ? EpisodeAdapter ? ) ?. updateList ( episodes . value )
2021-09-19 22:36:32 +00:00
}
}
2021-05-22 22:25:56 +00:00
}
2022-08-01 02:46:43 +00:00
observe ( viewModel . selectedSeason ) { text ->
2022-08-03 00:04:03 +00:00
result _season _button . setText ( text )
2022-08-01 02:46:43 +00:00
// If the season button is visible the result season button will be next focus down
if ( result _season _button ?. isVisible == true )
if ( result _series _parent ?. isVisible == true )
setFocusUpAndDown ( result _resume _series _button , result _season _button )
else
setFocusUpAndDown ( result _bookmark _button , result _season _button )
}
observe ( viewModel . selectedDubStatus ) { status ->
result _dub _select ?. setText ( status )
if ( result _dub _select ?. isVisible == true )
if ( result _season _button ?. isVisible != true && result _episode _select ?. isVisible != true ) {
if ( result _series _parent ?. isVisible == true )
setFocusUpAndDown ( result _resume _series _button , result _dub _select )
else
setFocusUpAndDown ( result _bookmark _button , result _dub _select )
}
}
2022-08-03 00:04:03 +00:00
observe ( viewModel . selectPopup ) { popup ->
when ( popup ) {
is Some . Success -> {
popupDialog ?. dismissSafe ( activity )
popupDialog = activity ?. let { act ->
val pop = popup . value
val options = pop . getOptions ( act )
val title = pop . getTitle ( act )
act . showBottomDialogInstant (
options , title , {
popupDialog = null
2022-08-03 01:02:08 +00:00
pop . callback ( null )
2022-08-03 00:04:03 +00:00
} , {
popupDialog = null
2022-08-03 01:02:08 +00:00
pop . callback ( it )
2022-08-03 00:04:03 +00:00
}
)
}
}
is Some . None -> {
popupDialog ?. dismissSafe ( activity )
popupDialog = null
}
}
//showBottomDialogInstant
}
observe ( viewModel . loadedLinks ) { load ->
when ( load ) {
is Some . Success -> {
2022-08-03 01:02:08 +00:00
if ( loadingDialog ?. isShowing != true ) {
2022-08-03 00:04:03 +00:00
loadingDialog ?. dismissSafe ( activity )
loadingDialog = null
}
loadingDialog = loadingDialog ?: context ?. let { ctx ->
val builder =
BottomSheetDialog ( ctx )
builder . setContentView ( R . layout . bottom _loading )
builder . setOnDismissListener {
loadingDialog = null
viewModel . cancelLinks ( )
}
//builder.setOnCancelListener {
// it?.dismiss()
//}
builder . setCanceledOnTouchOutside ( true )
builder . show ( )
builder
}
}
is Some . None -> {
loadingDialog ?. dismissSafe ( activity )
loadingDialog = null
}
}
}
2022-08-01 02:46:43 +00:00
observe ( viewModel . selectedRange ) { range ->
result _episode _select . setText ( range )
// If Season button is invisible then the bookmark button next focus is episode select
if ( result _episode _select ?. isVisible == true )
if ( result _season _button ?. isVisible != true ) {
if ( result _series _parent ?. isVisible == true )
setFocusUpAndDown ( result _resume _series _button , result _episode _select )
else
setFocusUpAndDown ( result _bookmark _button , result _episode _select )
2022-08-01 01:00:48 +00:00
}
2021-11-02 15:09:29 +00:00
}
2022-05-21 22:10:33 +00:00
// val preferDub = context?.getApiDubstatusSettings()?.all { it == DubStatus.Dubbed } == true
2022-03-27 16:45:02 +00:00
observe ( viewModel . dubSubSelections ) { range ->
2022-08-01 02:46:43 +00:00
result _dub _select . setOnClickListener { view ->
view ?. context ?. let { ctx ->
view . popupMenuNoIconsAndNoStringRes ( range
. mapNotNull { ( text , status ) ->
Pair (
status . ordinal ,
text ?. asStringNull ( ctx ) ?: return @mapNotNull null
)
} ) {
viewModel . changeDubStatus ( DubStatus . values ( ) [ itemId ] )
}
}
2022-03-27 16:45:02 +00:00
}
}
2022-08-01 02:46:43 +00:00
observe ( viewModel . rangeSelections ) { range ->
2022-08-03 00:04:03 +00:00
result _episode _select ?. setOnClickListener { view ->
2022-08-01 02:46:43 +00:00
view ?. context ?. let { ctx ->
val names = range
. mapNotNull { ( text , r ) ->
r to ( text ?. asStringNull ( ctx ) ?: return @mapNotNull null )
}
2021-11-02 15:09:29 +00:00
2022-08-01 02:46:43 +00:00
view . popupMenuNoIconsAndNoStringRes ( names . mapIndexed { index , ( _ , name ) ->
index to name
} ) {
viewModel . changeRange ( names [ itemId ] . first )
2022-03-27 16:45:02 +00:00
}
2021-11-02 15:09:29 +00:00
}
}
}
2022-08-01 02:46:43 +00:00
observe ( viewModel . seasonSelections ) { seasonList ->
result _season _button ?. setOnClickListener { view ->
view ?. context ?. let { ctx ->
val names = seasonList
. mapNotNull { ( text , r ) ->
r to ( text ?. asStringNull ( ctx ) ?: return @mapNotNull null )
}
view . popupMenuNoIconsAndNoStringRes ( names . mapIndexed { index , ( _ , name ) ->
index to name
} ) {
viewModel . changeSeason ( names [ itemId ] . first )
}
2021-07-25 20:50:16 +00:00
}
}
}
2022-08-01 02:46:43 +00:00
result _cast _items ?. setOnFocusChangeListener { _ , hasFocus ->
// Always escape focus
if ( hasFocus ) result _bookmark _button ?. requestFocus ( )
}
2022-04-01 20:05:34 +00:00
result _sync _set _score ?. setOnClickListener {
2022-04-02 01:38:55 +00:00
syncModel . publishUserData ( )
2022-04-01 20:05:34 +00:00
}
2022-08-01 02:46:43 +00:00
observe ( viewModel . episodesCountText ) { count ->
result _episodes _text . setText ( count )
2021-07-25 20:50:16 +00:00
}
2022-08-01 02:46:43 +00:00
observe ( viewModel . trailers ) { trailers ->
setTrailers ( trailers . flatMap { it . mirros } ) // I dont care about subtitles yet!
}
observe ( viewModel . recommendations ) { recommendations ->
setRecommendations ( recommendations , null )
2021-07-17 14:14:25 +00:00
}
2022-08-03 00:04:03 +00:00
observe ( viewModel . movie ) { data ->
when ( data ) {
is ResourceSome . Success -> {
data . value . let { ( text , ep ) ->
result _play _movie . setText ( text )
result _play _movie ?. setOnClickListener {
viewModel . handleAction (
activity ,
EpisodeClickEvent ( ACTION _CLICK _DEFAULT , ep )
)
}
result _play _movie ?. setOnLongClickListener {
viewModel . handleAction (
activity ,
EpisodeClickEvent ( ACTION _SHOW _OPTIONS , ep )
)
return @setOnLongClickListener true
}
}
}
else -> {
result _play _movie ?. isVisible = false
}
}
}
2022-08-01 01:00:48 +00:00
observe ( viewModel . page ) { data ->
2021-05-18 13:43:32 +00:00
when ( data ) {
is Resource . Success -> {
val d = data . value
2021-09-19 22:36:32 +00:00
2022-04-03 01:13:02 +00:00
updateVisStatus ( 2 )
2021-06-16 16:54:07 +00:00
2022-08-01 01:00:48 +00:00
result _vpn . setText ( d . vpnText )
result _info . setText ( d . metaText )
result _no _episodes . setText ( d . noEpisodesFoundText )
result _title . setText ( d . titleText )
result _meta _site . setText ( d . apiName )
result _meta _type . setText ( d . typeText )
result _meta _year . setText ( d . yearText )
result _meta _duration . setText ( d . durationText )
result _meta _rating . setText ( d . ratingText )
result _cast _text . setText ( d . actorsText )
2022-08-01 02:46:43 +00:00
result _next _airing . setText ( d . nextAiringEpisode )
2022-08-01 01:00:48 +00:00
result _next _airing _time . setText ( d . nextAiringDate )
result _poster . setImage ( d . posterImage )
2022-08-03 00:04:03 +00:00
if ( d . posterImage != null && context ?. isTrueTvSettings ( ) == false )
result _poster _holder ?. setOnClickListener {
try {
context ?. let { ctx ->
runBlocking {
val sourceBuilder = AlertDialog . Builder ( ctx )
sourceBuilder . setView ( R . layout . result _poster )
val sourceDialog = sourceBuilder . create ( )
sourceDialog . show ( )
sourceDialog . findViewById < ImageView ? > ( R . id . imgPoster )
?. apply {
setImage ( d . posterImage )
setOnClickListener {
sourceDialog . dismissSafe ( )
}
}
}
}
} catch ( e : Exception ) {
logError ( e )
}
}
2022-08-01 01:00:48 +00:00
2021-06-14 00:00:29 +00:00
2022-08-01 01:00:48 +00:00
result _cast _items ?. isVisible = d . actors != null
( result _cast _items ?. adapter as ActorAdaptor ? ) ?. apply {
updateList ( d . actors ?: emptyList ( ) )
}
2021-06-10 15:15:14 +00:00
2022-08-03 00:04:03 +00:00
result _open _in _browser ?. isGone = d . url . isBlank ( )
2022-04-03 01:13:02 +00:00
result _open _in _browser ?. setOnClickListener {
val i = Intent ( ACTION _VIEW )
i . data = Uri . parse ( d . url )
try {
startActivity ( i )
} catch ( e : Exception ) {
logError ( e )
2021-06-10 15:15:14 +00:00
}
2022-04-03 01:13:02 +00:00
}
2021-06-10 15:15:14 +00:00
2022-04-03 01:13:02 +00:00
result _search ?. setOnClickListener {
2022-08-01 01:00:48 +00:00
QuickSearchFragment . pushSearch ( activity , d . title )
2022-04-03 01:13:02 +00:00
}
2021-11-20 00:41:37 +00:00
2022-04-03 01:13:02 +00:00
result _share ?. setOnClickListener {
try {
val i = Intent ( ACTION _SEND )
i . type = " text/plain "
2022-08-01 01:00:48 +00:00
i . putExtra ( EXTRA _SUBJECT , d . title )
2022-04-03 01:13:02 +00:00
i . putExtra ( EXTRA _TEXT , d . url )
2022-08-01 01:00:48 +00:00
startActivity ( createChooser ( i , d . title ) )
2022-04-03 01:13:02 +00:00
} catch ( e : Exception ) {
logError ( e )
2021-06-10 15:15:14 +00:00
}
2022-04-03 01:13:02 +00:00
}
2021-06-10 15:15:14 +00:00
2022-05-15 18:38:32 +00:00
if ( syncModel . addSyncs ( d . syncData ) ) {
syncModel . updateMetaAndUser ( )
syncModel . updateSynced ( )
} else {
syncModel . addFromUrl ( d . url )
2022-04-03 21:41:28 +00:00
}
2022-08-02 00:43:42 +00:00
result _description . setTextHtml ( d . plotText )
2022-08-01 02:46:43 +00:00
result _description ?. setOnClickListener { view ->
view . context ?. let { ctx ->
2022-04-03 01:13:02 +00:00
val builder : AlertDialog . Builder =
2022-08-01 02:46:43 +00:00
AlertDialog . Builder ( ctx , R . style . AlertDialogCustom )
builder . setMessage ( d . plotText . asString ( ctx ) . html ( ) )
. setTitle ( d . plotHeaderText . asString ( ctx ) )
2022-04-03 01:13:02 +00:00
. show ( )
}
}
2021-05-22 22:25:56 +00:00
2022-08-01 02:46:43 +00:00
2022-04-03 01:13:02 +00:00
result _tag ?. removeAllViews ( )
2021-06-06 18:06:01 +00:00
2022-04-03 01:13:02 +00:00
d . comingSoon . let { soon ->
result _coming _soon ?. isVisible = soon
result _data _holder ?. isGone = soon
}
2022-03-20 23:59:17 +00:00
2022-04-03 01:13:02 +00:00
val tags = d . tags
2022-08-01 01:00:48 +00:00
result _tag _holder ?. isVisible = tags . isNotEmpty ( )
2022-08-01 02:46:43 +00:00
if ( tags . isNotEmpty ( ) ) {
2022-04-03 01:13:02 +00:00
//result_tag_holder?.visibility = VISIBLE
2022-04-03 21:41:28 +00:00
val isOnTv = context ?. isTrueTvSettings ( ) == true
2022-04-03 01:13:02 +00:00
for ( ( index , tag ) in tags . withIndex ( ) ) {
val viewBtt = layoutInflater . inflate ( R . layout . result _tag , null )
val btt = viewBtt . findViewById < MaterialButton > ( R . id . result _tag _card )
btt . text = tag
2022-04-03 21:41:28 +00:00
btt . isFocusable = !is OnTv
btt . isClickable = !is OnTv
2022-04-03 01:13:02 +00:00
result _tag ?. addView ( viewBtt , index )
2021-06-26 14:44:53 +00:00
}
2022-04-03 01:13:02 +00:00
}
2021-06-26 14:44:53 +00:00
2022-08-01 02:46:43 +00:00
//TODO FIX
/ *
2022-08-01 01:00:48 +00:00
if ( d . typeText . isMovieType ( ) ) {
2022-04-03 01:13:02 +00:00
val hasDownloadSupport = api . hasDownloadSupport
lateFixDownloadButton ( true )
2021-07-23 23:44:54 +00:00
2022-04-03 01:13:02 +00:00
result _play _movie ?. setOnClickListener {
val card =
currentEpisodes ?. firstOrNull ( ) ?: return @setOnClickListener
handleAction ( EpisodeClickEvent ( ACTION _CLICK _DEFAULT , card ) )
}
2021-07-25 16:08:34 +00:00
2022-04-03 01:13:02 +00:00
result _play _movie ?. setOnLongClickListener {
val card = currentEpisodes ?. firstOrNull ( )
?: return @setOnLongClickListener true
handleAction ( EpisodeClickEvent ( ACTION _SHOW _OPTIONS , card ) )
return @setOnLongClickListener true
}
2021-09-19 20:33:39 +00:00
2022-04-03 01:13:02 +00:00
result _download _movie ?. setOnLongClickListener {
val card = currentEpisodes ?. firstOrNull ( )
?: return @setOnLongClickListener true
handleAction ( EpisodeClickEvent ( ACTION _SHOW _OPTIONS , card ) )
return @setOnLongClickListener true
}
2021-11-30 17:59:52 +00:00
2022-05-05 21:50:08 +00:00
result _movie _progress _downloaded _holder ?. isVisible = hasDownloadSupport
2022-04-03 01:13:02 +00:00
if ( hasDownloadSupport ) {
val localId = d . getId ( )
2022-07-17 00:41:01 +00:00
2022-04-03 01:13:02 +00:00
val file =
VideoDownloadManager . getDownloadFileInfoAndUpdateSettings (
requireContext ( ) ,
localId
)
downloadButton ?. dispose ( )
downloadButton = EasyDownloadButton ( )
downloadButton ?. setUpMoreButton (
file ?. fileLength ,
file ?. totalBytes ,
result _movie _progress _downloaded ,
result _movie _download _icon ,
result _movie _download _text ,
result _movie _download _text _precentage ,
result _download _movie ,
true ,
VideoDownloadHelper . DownloadEpisodeCached (
d . name ,
d . posterUrl ,
0 ,
null ,
localId ,
localId ,
d . rating ,
d . plot ,
System . currentTimeMillis ( ) ,
2022-07-17 00:41:01 +00:00
) ,
:: handleDownloadButton
)
2022-02-06 14:53:39 +00:00
2022-04-03 01:13:02 +00:00
result _download _movie ?. setOnLongClickListener {
val card =
currentEpisodes ?. firstOrNull ( )
?: return @setOnLongClickListener false
handleAction ( EpisodeClickEvent ( ACTION _DOWNLOAD _MIRROR , card ) )
return @setOnLongClickListener true
}
2022-02-06 15:16:11 +00:00
2022-04-03 01:13:02 +00:00
/ * downloadButton ?. setUpMaterialButton (
file ?. fileLength ,
file ?. totalBytes ,
result _movie _progress _downloaded ,
result _download _movie ,
null , //result_movie_text_progress
VideoDownloadHelper . DownloadEpisodeCached (
d . name ,
d . posterUrl ,
0 ,
null ,
localId ,
localId ,
d . rating ,
d . plot ,
System . currentTimeMillis ( ) ,
)
) { downloadClickEvent ->
if ( downloadClickEvent . action == DOWNLOAD _ACTION _DOWNLOAD ) {
currentEpisodes ?. firstOrNull ( ) ?. let { episode ->
handleAction (
EpisodeClickEvent (
ACTION _DOWNLOAD _EPISODE ,
ResultEpisode (
d . name ,
d . name ,
null ,
0 ,
null ,
episode . data ,
d . apiName ,
localId ,
0 ,
0L ,
0L ,
null ,
null ,
null ,
d . type ,
localId ,
2022-02-06 14:53:39 +00:00
)
)
)
}
2022-04-03 01:13:02 +00:00
} else {
handleDownloadClick (
activity ,
currentHeaderName ,
downloadClickEvent
)
}
} * /
2021-06-16 16:54:07 +00:00
}
2022-04-03 01:13:02 +00:00
} else {
lateFixDownloadButton ( false )
}
2022-08-01 02:46:43 +00:00
* /
2021-05-18 13:43:32 +00:00
}
is Resource . Failure -> {
2021-08-24 22:19:15 +00:00
result _error _text . text = url ?. plus ( " \n " ) + data . errorString
2021-06-16 16:54:07 +00:00
updateVisStatus ( 1 )
}
is Resource . Loading -> {
updateVisStatus ( 0 )
2021-05-18 13:43:32 +00:00
}
}
}
2022-07-17 00:41:01 +00:00
result _recommendations ?. adapter =
2021-12-13 18:41:33 +00:00
SearchAdapter (
ArrayList ( ) ,
result _recommendations ,
) { callback ->
SearchHelper . handleSearchClickCallback ( activity , callback )
}
2021-09-19 22:36:32 +00:00
context ?. let { ctx ->
2021-12-10 19:48:21 +00:00
result _bookmark _button ?. isVisible = ctx . isTvSettings ( )
2021-09-19 22:36:32 +00:00
val settingsManager = PreferenceManager . getDefaultSharedPreferences ( ctx )
2021-12-17 12:42:25 +00:00
val showFillers =
2022-02-05 22:21:45 +00:00
settingsManager . getBoolean ( ctx . getString ( R . string . show _fillers _key ) , false )
2021-06-16 16:54:07 +00:00
2022-06-18 23:03:25 +00:00
Kitsu . isEnabled =
settingsManager . getBoolean ( ctx . getString ( R . string . show _kitsu _posters _key ) , true )
2022-08-03 00:04:03 +00:00
if ( url != null ) {
2021-09-19 22:36:32 +00:00
result _reload _connectionerror . setOnClickListener {
2022-08-03 00:04:03 +00:00
viewModel . load ( url , apiName , showFillers , DubStatus . Dubbed , 0 , 0 ) //TODO FIX
2021-08-29 17:15:09 +00:00
}
2021-06-16 16:54:07 +00:00
2021-12-10 00:20:24 +00:00
result _reload _connection _open _in _browser ?. setOnClickListener {
val i = Intent ( ACTION _VIEW )
2022-08-03 00:04:03 +00:00
i . data = Uri . parse ( url )
2022-03-14 12:44:54 +00:00
try {
startActivity ( i )
} catch ( e : Exception ) {
logError ( e )
}
}
result _open _in _browser ?. setOnClickListener {
val i = Intent ( ACTION _VIEW )
2022-08-03 00:04:03 +00:00
i . data = Uri . parse ( url )
2021-12-10 00:20:24 +00:00
try {
startActivity ( i )
} catch ( e : Exception ) {
2022-01-30 22:02:57 +00:00
logError ( e )
2021-12-10 00:20:24 +00:00
}
}
2022-04-03 21:41:28 +00:00
// bloats the navigation on tv
if ( context ?. isTrueTvSettings ( ) == false ) {
result _meta _site ?. setOnClickListener {
2022-08-03 00:04:03 +00:00
it . context ?. openBrowser ( url )
2022-04-03 21:41:28 +00:00
}
result _meta _site ?. isFocusable = true
} else {
result _meta _site ?. isFocusable = false
2021-09-19 22:36:32 +00:00
}
2022-08-01 02:46:43 +00:00
if ( restart || ! viewModel . hasLoaded ( ) ) {
2022-01-07 19:27:25 +00:00
//viewModel.clear()
2022-08-03 00:04:03 +00:00
viewModel . load ( url , apiName , showFillers , DubStatus . Dubbed , 0 , 0 ) //TODO FIX
2021-09-12 15:57:07 +00:00
}
}
2021-06-16 16:54:07 +00:00
}
2022-02-05 22:21:45 +00:00
PanelsChildGestureRegionObserver . Provider . get ( ) . addGestureRegionsUpdateListener ( this )
}
override fun onPause ( ) {
super . onPause ( )
PanelsChildGestureRegionObserver . Provider . get ( ) . addGestureRegionsUpdateListener ( this )
2021-05-16 18:28:00 +00:00
}
2022-02-04 20:49:35 +00:00
override fun onGestureRegionsUpdate ( gestureRegions : List < Rect > ) {
result _overlapping _panels ?. setChildGestureRegions ( gestureRegions )
}
2022-03-20 23:25:25 +00:00
}