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-02-02 22:12:52 +00:00
import android.app.Activity
2021-09-03 09:13:34 +00:00
import android.content.ClipData
import android.content.ClipboardManager
2022-04-03 20:14:51 +00:00
import android.content.Context
2021-07-17 15:56:26 +00:00
import android.content.Context.CLIPBOARD_SERVICE
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
2021-06-06 18:06:01 +00:00
import android.view.View.GONE
import android.view.View.VISIBLE
2021-05-16 18:28:00 +00:00
import android.view.ViewGroup
2022-04-02 01:38:55 +00:00
import android.widget.*
2021-12-13 18:41:33 +00:00
import androidx.annotation.StringRes
2021-05-18 13:43:32 +00:00
import androidx.appcompat.app.AlertDialog
2021-07-17 15:56:26 +00:00
import androidx.core.content.FileProvider
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
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
2021-07-25 16:08:34 +00:00
import com.lagradost.cloudstream3.APIHolder.getId
2022-06-21 00:30:55 +00:00
import com.lagradost.cloudstream3.APIHolder.unixTime
2022-06-17 20:43:42 +00:00
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
2022-02-02 22:12:52 +00:00
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
2022-01-07 19:27:25 +00:00
import com.lagradost.cloudstream3.CommonActivity.getCastSession
import com.lagradost.cloudstream3.CommonActivity.showToast
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
2022-07-17 00:41:01 +00:00
import com.lagradost.cloudstream3.ui.download.*
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
2022-01-07 19:27:25 +00:00
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
2022-02-02 22:12:52 +00:00
import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator
2022-01-07 19:27:25 +00:00
import com.lagradost.cloudstream3.ui.player.SubtitleData
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
2021-08-22 17:14:48 +00:00
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment.Companion.getDownloadSubsLanguageISO639_1
2021-07-17 14:14:25 +00:00
import com.lagradost.cloudstream3.utils.*
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.isAppInstalled
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
import com.lagradost.cloudstream3.utils.AppUtils.isConnectedToChromecast
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
2021-06-14 16:58:43 +00:00
import com.lagradost.cloudstream3.utils.CastHelper.startCast
2022-04-03 20:14:51 +00:00
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
2021-07-17 14:14:25 +00:00
import com.lagradost.cloudstream3.utils.Coroutines.main
2021-07-18 23:57:04 +00:00
import com.lagradost.cloudstream3.utils.DataStore.getFolderName
2021-07-17 14:14:25 +00:00
import com.lagradost.cloudstream3.utils.DataStore.setKey
2021-06-15 16:07:20 +00:00
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
2021-12-10 19:48:21 +00:00
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
2021-08-24 22:19:15 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.checkWrite
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
2021-12-12 02:33:17 +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
2021-09-20 21:11:36 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.navigate
2021-08-24 22:19:15 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIcons
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
2021-08-19 20:05:18 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.setImage
2022-04-03 20:14:51 +00:00
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getFileName
2021-07-04 17:00:04 +00:00
import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename
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-07-16 01:43:10 +00:00
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
2021-07-17 15:56:26 +00:00
import java.io.File
2022-06-21 00:30:55 +00:00
import java.util.concurrent.TimeUnit
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 ,
2021-05-28 13:38:06 +00:00
val season : Int ? ,
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-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 ,
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
2022-02-02 22:12:52 +00:00
2022-04-03 20:14:51 +00:00
private fun downloadSubtitle (
context : Context ? ,
link : SubtitleData ,
meta : VideoDownloadManager . DownloadEpisodeMetadata ,
) {
context ?. let { ctx ->
val fileName = getFileName ( ctx , meta )
val folder = getFolder ( meta . type ?: return , meta . mainName )
downloadSubtitle (
ctx ,
ExtractorSubtitleLink ( link . name , link . url , " " ) ,
fileName ,
folder
)
}
}
private fun downloadSubtitle (
context : Context ? ,
link : ExtractorSubtitleLink ,
fileName : String ,
folder : String
2022-02-02 22:12:52 +00:00
) {
2022-04-03 20:14:51 +00:00
ioSafe {
VideoDownloadManager . downloadThing (
context ?: return @ioSafe ,
link ,
" $fileName ${link.name} " ,
folder ,
if ( link . url . contains ( " .srt " ) ) " .srt " else " vtt " ,
false ,
null
) {
// no notification
}
}
}
2022-02-02 22:12:52 +00:00
2022-04-03 20:14:51 +00:00
private fun getMeta (
episode : ResultEpisode ,
titleName : String ,
apiName : String ,
currentPoster : String ,
currentIsMovie : Boolean ,
tvType : TvType ,
) : VideoDownloadManager . DownloadEpisodeMetadata {
return VideoDownloadManager . DownloadEpisodeMetadata (
2022-02-02 22:12:52 +00:00
episode . id ,
2022-04-03 20:14:51 +00:00
sanitizeFilename ( titleName ) ,
2022-02-02 22:12:52 +00:00
apiName ,
episode . poster ?: currentPoster ,
episode . name ,
if ( currentIsMovie ) null else episode . season ,
2022-04-03 20:14:51 +00:00
if ( currentIsMovie ) null else episode . episode ,
tvType ,
2022-02-02 22:12:52 +00:00
)
2022-04-03 20:14:51 +00:00
}
2022-02-02 22:12:52 +00:00
2022-04-03 20:14:51 +00:00
private fun getFolder ( currentType : TvType , titleName : String ) : String {
2022-04-29 22:48:05 +00:00
val sanitizedFileName = sanitizeFilename ( titleName )
2022-04-03 20:14:51 +00:00
return when ( currentType ) {
2022-04-29 22:48:05 +00:00
TvType . Anime -> " Anime/ $sanitizedFileName "
2022-02-02 22:12:52 +00:00
TvType . Movie -> " Movies "
TvType . AnimeMovie -> " Movies "
2022-04-29 22:48:05 +00:00
TvType . TvSeries -> " TVSeries/ $sanitizedFileName "
2022-02-02 22:12:52 +00:00
TvType . OVA -> " OVA "
2022-04-29 22:48:05 +00:00
TvType . Cartoon -> " Cartoons/ $sanitizedFileName "
2022-02-02 22:12:52 +00:00
TvType . Torrent -> " Torrent "
TvType . Documentary -> " Documentaries "
2022-03-21 11:07:36 +00:00
TvType . AsianDrama -> " AsianDrama "
2022-07-19 20:24:55 +00:00
TvType . Live -> " LiveStreams "
2022-02-02 22:12:52 +00:00
}
2022-04-03 20:14:51 +00:00
}
2022-02-02 22:12:52 +00:00
2022-04-03 20:14:51 +00:00
fun startDownload (
context : Context ? ,
episode : ResultEpisode ,
currentIsMovie : Boolean ,
currentHeaderName : String ,
currentType : TvType ,
currentPoster : String ,
apiName : String ,
parentId : Int ,
url : String ,
links : List < ExtractorLink > ,
subs : List < SubtitleData > ?
) {
try {
if ( context == null ) return
val meta =
getMeta (
episode ,
currentHeaderName ,
apiName ,
currentPoster ,
currentIsMovie ,
currentType
)
2022-02-02 22:12:52 +00:00
2022-04-03 20:14:51 +00:00
val folder = getFolder ( currentType , currentHeaderName )
val src = " $DOWNLOAD _NAVIGATE_TO/ $parentId " // url ?: return@let
// SET VISUAL KEYS
setKey (
DOWNLOAD _HEADER _CACHE ,
parentId . toString ( ) ,
VideoDownloadHelper . DownloadHeaderCached (
apiName ,
url ,
currentType ,
currentHeaderName ,
currentPoster ,
parentId ,
System . currentTimeMillis ( ) ,
)
2022-02-02 22:12:52 +00:00
)
2022-04-03 20:14:51 +00:00
setKey (
getFolderName (
DOWNLOAD _EPISODE _CACHE ,
parentId . toString ( )
) , // 3 deep folder for faster acess
episode . id . toString ( ) ,
VideoDownloadHelper . DownloadEpisodeCached (
episode . name ,
episode . poster ,
episode . episode ,
episode . season ,
episode . id ,
parentId ,
episode . rating ,
episode . description ,
System . currentTimeMillis ( ) ,
)
2022-02-02 22:12:52 +00:00
)
2022-04-03 20:14:51 +00:00
// DOWNLOAD VIDEO
VideoDownloadManager . downloadEpisodeUsingWorker (
context ,
src , //url ?: return,
folder ,
meta ,
links
)
// 1. Checks if the lang should be downloaded
// 2. Makes it into the download format
// 3. Downloads it as a .vtt file
val downloadList = getDownloadSubsLanguageISO639 _1 ( )
subs ?. let { subsList ->
subsList . filter {
downloadList . contains (
SubtitleHelper . fromLanguageToTwoLetters (
it . name ,
true
)
2022-02-02 22:12:52 +00:00
)
}
2022-04-03 20:14:51 +00:00
. map { ExtractorSubtitleLink ( it . name , it . url , " " ) }
. forEach { link ->
val fileName = getFileName ( context , meta )
downloadSubtitle ( context , link , fileName , folder )
}
}
} catch ( e : Exception ) {
logError ( e )
2022-02-02 22:12:52 +00:00
}
}
suspend fun downloadEpisode (
activity : Activity ? ,
episode : ResultEpisode ,
currentIsMovie : Boolean ,
currentHeaderName : String ,
currentType : TvType ,
currentPoster : String ,
apiName : String ,
parentId : Int ,
url : String ,
) {
safeApiCall {
val generator = RepoLinkGenerator ( listOf ( episode ) )
val currentLinks = mutableSetOf < ExtractorLink > ( )
val currentSubs = mutableSetOf < SubtitleData > ( )
generator . generateLinks ( clearCache = false , isCasting = false , callback = {
it . first ?. let { link ->
currentLinks . add ( link )
}
} , subtitleCallback = { sub ->
currentSubs . add ( sub )
} )
if ( currentLinks . isEmpty ( ) ) {
2022-05-14 17:07:34 +00:00
main {
showToast ( activity , R . string . no _links _found _toast , Toast . LENGTH _SHORT )
}
2022-02-02 22:12:52 +00:00
return @safeApiCall
}
startDownload (
2022-04-03 20:14:51 +00:00
activity ,
2022-02-02 22:12:52 +00:00
episode ,
currentIsMovie ,
currentHeaderName ,
currentType ,
currentPoster ,
apiName ,
parentId ,
url ,
sortUrls ( currentLinks ) ,
sortSubs ( currentSubs ) ,
)
}
}
2021-05-22 22:25:56 +00:00
}
2021-12-17 12:42:25 +00:00
private var currentLoadingCount =
0 // THIS IS USED TO PREVENT LATE EVENTS, AFTER DISMISS WAS CLICKED
2022-01-07 19:27:25 +00:00
private lateinit var viewModel : ResultViewModel //by activityViewModels()
2022-04-01 20:05:34 +00:00
private lateinit var syncModel : SyncViewModel
2021-06-15 16:07:20 +00:00
private var currentHeaderName : String ? = null
2021-07-04 00:59:51 +00:00
private var currentType : TvType ? = null
2021-06-15 16:07:20 +00:00
private var currentEpisodes : List < ResultEpisode > ? = null
2022-04-08 19:38:19 +00:00
private var downloadButton : EasyDownloadButton ? = null
private var syncdata : Map < String , String > ? = null
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 =
ViewModelProvider ( this ) [ ResultViewModel :: 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-07-17 00:41:01 +00:00
downloadButton ?. dispose ( )
//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-05-22 22:25:56 +00:00
override fun onDestroy ( ) {
//requireActivity().viewModelStore.clear() // REMEMBER THE CLEAR
2022-07-17 00:41:01 +00:00
2022-02-05 22:21:45 +00:00
2021-05-22 22:25:56 +00:00
super . onDestroy ( )
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
result _reload _connection _open _in _browser ?. isVisible = url != null
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-15 16:07:20 +00:00
private var currentPoster : String ? = null
2021-07-17 14:14:25 +00:00
private var currentId : Int ? = null
2021-06-16 22:31:41 +00:00
private var currentIsMovie : Boolean ? = null
2021-07-25 20:50:16 +00:00
private var episodeRanges : List < String > ? = null
2021-11-02 15:09:29 +00:00
private var dubRange : Set < DubStatus > ? = null
2021-06-16 16:54:07 +00:00
var url : String ? = null
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
private fun setFormatText ( textView : TextView ? , @StringRes format : Int , arg : Any ? ) {
2021-12-17 12:42:25 +00:00
// java.util.IllegalFormatConversionException: f != java.lang.Integer
// This can fail with malformed formatting
normalSafeApiCall {
if ( arg == null ) {
2021-12-13 18:41:33 +00:00
textView ?. isVisible = false
} else {
2021-12-17 12:42:25 +00:00
val text = context ?. getString ( format ) ?. format ( arg )
if ( text == null ) {
textView ?. isVisible = false
} else {
textView ?. isVisible = true
textView ?. text = text
}
2021-12-13 18:41:33 +00:00
}
}
}
private fun setDuration ( duration : Int ? ) {
setFormatText ( result _meta _duration , R . string . duration _format , duration )
}
2022-02-06 14:53:39 +00:00
private fun setShow ( showStatus : ShowStatus ? ) {
2022-02-05 22:21:45 +00:00
val status = when ( showStatus ) {
null -> null
ShowStatus . Ongoing -> R . string . status _ongoing
ShowStatus . Completed -> R . string . status _completed
}
if ( status == null ) {
result _meta _status ?. isVisible = false
} else {
context ?. getString ( status ) ?. let {
result _meta _status ?. text = it
}
}
}
2021-12-13 18:41:33 +00:00
private fun setYear ( year : Int ? ) {
setFormatText ( result _meta _year , R . string . year _format , year )
}
private fun setRating ( rating : Int ? ) {
2021-12-17 12:42:25 +00:00
setFormatText ( result _meta _rating , R . string . rating _format , rating ?. div ( 1000f ) )
2021-12-13 18:41:33 +00:00
}
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
}
2022-07-17 00:41:01 +00:00
private fun handleDownloadButton ( downloadClickEvent : DownloadClickEvent ) {
if ( downloadClickEvent . action == DOWNLOAD _ACTION _DOWNLOAD ) {
currentEpisodes ?. firstOrNull ( ) ?. let { episode ->
handleAction (
EpisodeClickEvent (
ACTION _DOWNLOAD _EPISODE ,
ResultEpisode (
currentHeaderName ?: return @let ,
currentHeaderName ,
null ,
0 ,
null ,
episode . data ,
apiName ,
currentId ?: return @let ,
0 ,
0L ,
0L ,
null ,
null ,
null ,
currentType ?: return @let ,
currentId ?: return @let ,
)
)
)
}
} else {
DownloadButtonSetup . handleDownloadClick (
activity ,
currentHeaderName ,
downloadClickEvent
)
}
}
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-06-21 00:30:55 +00:00
private fun setNextEpisode ( nextAiring : NextAiring ? ) {
result _next _airing _holder ?. isVisible =
if ( nextAiring == null || nextAiring . episode <= 0 || nextAiring . unixTime <= unixTime ) {
false
} else {
val seconds = nextAiring . unixTime - unixTime
val days = TimeUnit . SECONDS . toDays ( seconds )
val hours : Long = TimeUnit . SECONDS . toHours ( seconds ) - days * 24
val minute =
TimeUnit . SECONDS . toMinutes ( seconds ) - TimeUnit . SECONDS . toHours ( seconds ) * 60
// val second =
// TimeUnit.SECONDS.toSeconds(seconds) - TimeUnit.SECONDS.toMinutes(seconds) * 60
try {
val ctx = context
if ( ctx == null ) {
false
} else {
when {
days > 0 -> {
ctx . getString ( R . string . next _episode _time _day _format ) . format (
days ,
hours ,
minute
)
}
hours > 0 -> ctx . getString ( R . string . next _episode _time _hour _format )
. format (
hours ,
minute
)
minute > 0 -> ctx . getString ( R . string . next _episode _time _min _format )
. format (
minute
)
else -> null
} ?. also { text ->
result _next _airing _time ?. text = text
result _next _airing ?. text =
2022-07-16 01:43:10 +00:00
ctx . getString ( R . string . next _episode _format )
. format ( nextAiring . episode )
2022-06-21 00:30:55 +00:00
} != null
}
} catch ( e : Exception ) { // mistranslation
result _next _airing _holder ?. isVisible = false
logError ( e )
false
}
}
}
2022-02-05 22:21:45 +00:00
private fun setActors ( actors : List < ActorData > ? ) {
if ( actors . isNullOrEmpty ( ) ) {
result _cast _text ?. isVisible = false
result _cast _items ?. isVisible = false
} else {
val isImage = actors . first ( ) . actor . image != null
if ( isImage ) {
( result _cast _items ?. adapter as ActorAdaptor ? ) ?. apply {
updateList ( actors )
}
result _cast _text ?. isVisible = false
result _cast _items ?. isVisible = true
} else {
result _cast _text ?. isVisible = true
result _cast _items ?. isVisible = false
setFormatText ( result _cast _text , R . string . cast _format ,
actors . joinToString { it . actor . name } )
}
}
}
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
2021-08-11 18:26:19 +00:00
private fun lateFixDownloadButton ( show : Boolean ) {
2021-08-22 17:14:48 +00:00
if ( ! show || currentType ?. isMovieType ( ) == false ) {
2021-08-11 18:26:19 +00:00
result _movie _parent . visibility = GONE
result _episodes _text . visibility = VISIBLE
result _episodes . visibility = VISIBLE
2021-08-14 17:31:27 +00:00
} else {
result _movie _parent . visibility = VISIBLE
result _episodes _text . visibility = GONE
result _episodes . visibility = GONE
2021-08-11 18:26:19 +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-07-17 00:41:01 +00:00
var apiName : String = " "
private fun handleAction ( episodeClick : EpisodeClickEvent ) : Job = main {
if ( episodeClick . action == ACTION _DOWNLOAD _EPISODE ) {
val isMovie = currentIsMovie ?: return @main
val headerName = currentHeaderName ?: return @main
val tvType = currentType ?: return @main
val poster = currentPoster ?: return @main
val id = currentId ?: return @main
val curl = url ?: return @main
showToast ( activity , R . string . download _started , Toast . LENGTH _SHORT )
downloadEpisode (
activity ,
episodeClick . data ,
isMovie ,
headerName ,
tvType ,
poster ,
apiName ,
id ,
curl ,
)
return @main
}
var currentLinks : Set < ExtractorLink > ? = null
var currentSubs : Set < SubtitleData > ? = null
//val id = episodeClick.data.id
currentLoadingCount ++
val showTitle =
episodeClick . data . name ?: context ?. getString ( R . string . episode _name _format )
?. format (
getString ( R . string . episode ) ,
episodeClick . data . episode
)
fun acquireSingleExtractorLink (
links : List < ExtractorLink > ,
title : String ,
callback : ( ExtractorLink ) -> Unit
) {
val builder = AlertDialog . Builder ( requireContext ( ) , R . style . AlertDialogCustom )
builder . setTitle ( title )
builder . setItems ( links . map { " ${it.name} ${Qualities.getStringByInt(it.quality)} " }
. toTypedArray ( ) ) { dia , which ->
callback . invoke ( links [ which ] )
dia ?. dismiss ( )
}
builder . create ( ) . show ( )
}
fun acquireSingleSubtitleLink (
links : List < SubtitleData > ,
title : String ,
callback : ( SubtitleData ) -> Unit
) {
val builder = AlertDialog . Builder ( requireContext ( ) , R . style . AlertDialogCustom )
builder . setTitle ( title )
builder . setItems ( links . map { it . name } . toTypedArray ( ) ) { dia , which ->
callback . invoke ( links [ which ] )
dia ?. dismiss ( )
}
builder . create ( ) . show ( )
}
fun acquireSingeExtractorLink ( title : String , callback : ( ExtractorLink ) -> Unit ) {
acquireSingleExtractorLink ( sortUrls ( currentLinks ?: return ) , title , callback )
}
fun startChromecast ( startIndex : Int ) {
val eps = currentEpisodes ?: return
activity ?. getCastSession ( ) ?. startCast (
apiName ,
currentIsMovie ?: return ,
currentHeaderName ,
currentPoster ,
episodeClick . data . index ,
eps ,
sortUrls ( currentLinks ?: return ) ,
sortSubs ( currentSubs ?: return ) ,
startTime = episodeClick . data . getRealPosition ( ) ,
startIndex = startIndex
)
}
suspend fun requireLinks ( isCasting : Boolean , displayLoading : Boolean = true ) : Boolean {
val skipLoading = getApiFromName ( apiName ) . instantLinkLoading
var loadingDialog : AlertDialog ? = null
val currentLoad = currentLoadingCount
if ( ! skipLoading && displayLoading ) {
val builder =
AlertDialog . Builder ( requireContext ( ) , R . style . AlertDialogCustomTransparent )
val customLayout = layoutInflater . inflate ( R . layout . dialog _loading , null )
builder . setView ( customLayout )
loadingDialog = builder . create ( )
loadingDialog . show ( )
2022-07-17 00:43:49 +00:00
loadingDialog . setOnDismissListener {
currentLoadingCount ++
}
2022-07-17 00:41:01 +00:00
}
val data = viewModel . loadEpisode ( episodeClick . data , isCasting )
if ( currentLoadingCount != currentLoad ) return false
loadingDialog ?. dismissSafe ( activity )
when ( data ) {
is Resource . Success -> {
currentLinks = data . value . first
currentSubs = data . value . second
return true
}
is Resource . Failure -> {
showToast (
activity ,
R . string . error _loading _links _toast ,
Toast . LENGTH _SHORT
)
}
else -> Unit
}
return false
}
val isLoaded = when ( episodeClick . action ) {
ACTION _PLAY _EPISODE _IN _PLAYER -> true
ACTION _CLICK _DEFAULT -> true
ACTION _SHOW _TOAST -> true
ACTION _DOWNLOAD _EPISODE -> {
showToast ( activity , R . string . download _started , Toast . LENGTH _SHORT )
requireLinks ( false , false )
}
ACTION _CHROME _CAST _EPISODE -> requireLinks ( true )
ACTION _CHROME _CAST _MIRROR -> requireLinks ( true )
ACTION _SHOW _DESCRIPTION -> true
else -> requireLinks ( false )
}
if ( !is Loaded ) return @main // CANT LOAD
when ( episodeClick . action ) {
ACTION _SHOW _TOAST -> {
showToast ( activity , R . string . play _episode _toast , Toast . LENGTH _SHORT )
}
ACTION _SHOW _DESCRIPTION -> {
val builder : AlertDialog . Builder =
AlertDialog . Builder ( requireContext ( ) , R . style . AlertDialogCustom )
builder . setMessage ( episodeClick . data . description ?: return @main )
. setTitle ( R . string . torrent _plot )
. show ( )
}
ACTION _CLICK _DEFAULT -> {
context ?. let { ctx ->
if ( ctx . isConnectedToChromecast ( ) ) {
handleAction (
EpisodeClickEvent (
ACTION _CHROME _CAST _EPISODE ,
episodeClick . data
)
)
} else {
handleAction (
EpisodeClickEvent (
ACTION _PLAY _EPISODE _IN _PLAYER ,
episodeClick . data
)
)
}
}
}
ACTION _DOWNLOAD _EPISODE _SUBTITLE -> {
acquireSingleSubtitleLink (
sortSubs (
currentSubs ?: return @main
) , //(currentLinks ?: return@main).filter { !it.isM3u8 },
getString ( R . string . episode _action _download _subtitle )
) { link ->
downloadSubtitle (
context ,
link ,
getMeta (
episodeClick . data ,
currentHeaderName ?: return @acquireSingleSubtitleLink ,
apiName ,
currentPoster ?: return @acquireSingleSubtitleLink ,
currentIsMovie ?: return @acquireSingleSubtitleLink ,
currentType ?: return @acquireSingleSubtitleLink
)
)
showToast ( activity , R . string . download _started , Toast . LENGTH _SHORT )
}
}
ACTION _SHOW _OPTIONS -> {
context ?. let { ctx ->
val builder = AlertDialog . Builder ( ctx , R . style . AlertDialogCustom )
var dialog : AlertDialog ? = null
builder . setTitle ( showTitle )
val options =
requireContext ( ) . resources . getStringArray ( R . array . episode _long _click _options )
val optionsValues =
requireContext ( ) . resources . getIntArray ( R . array . episode _long _click _options _values )
val verifiedOptions = ArrayList < String > ( )
val verifiedOptionsValues = ArrayList < Int > ( )
val hasDownloadSupport = getApiFromName ( apiName ) . hasDownloadSupport
for ( i in options . indices ) {
val opv = optionsValues [ i ]
val op = options [ i ]
val isConnected = ctx . isConnectedToChromecast ( )
val add = when ( opv ) {
ACTION _CHROME _CAST _EPISODE -> isConnected
ACTION _CHROME _CAST _MIRROR -> isConnected
ACTION _DOWNLOAD _EPISODE _SUBTITLE -> ! currentSubs . isNullOrEmpty ( )
ACTION _DOWNLOAD _EPISODE -> hasDownloadSupport
ACTION _DOWNLOAD _MIRROR -> hasDownloadSupport
ACTION _PLAY _EPISODE _IN _VLC _PLAYER -> context ?. isAppInstalled (
VLC _PACKAGE
) ?: false
else -> true
}
if ( add ) {
verifiedOptions . add ( op )
verifiedOptionsValues . add ( opv )
}
}
builder . setItems (
verifiedOptions . toTypedArray ( )
) { _ , which ->
handleAction (
EpisodeClickEvent (
verifiedOptionsValues [ which ] ,
episodeClick . data
)
)
dialog ?. dismissSafe ( activity )
}
dialog = builder . create ( )
dialog . show ( )
}
}
ACTION _COPY _LINK -> {
activity ?. let { act ->
try {
acquireSingeExtractorLink ( act . getString ( R . string . episode _action _copy _link ) ) { link ->
val serviceClipboard =
( act . getSystemService ( CLIPBOARD _SERVICE ) as ? ClipboardManager ? )
?: return @acquireSingeExtractorLink
val clip = ClipData . newPlainText ( link . name , link . url )
serviceClipboard . setPrimaryClip ( clip )
showToast ( act , R . string . copy _link _toast , Toast . LENGTH _SHORT )
}
} catch ( e : Exception ) {
showToast ( act , e . toString ( ) , Toast . LENGTH _LONG )
logError ( e )
}
}
}
ACTION _PLAY _EPISODE _IN _BROWSER -> {
acquireSingeExtractorLink ( getString ( R . string . episode _action _play _in _browser ) ) { link ->
try {
val i = Intent ( ACTION _VIEW )
i . data = Uri . parse ( link . url )
startActivity ( i )
} catch ( e : Exception ) {
logError ( e )
}
}
}
ACTION _CHROME _CAST _MIRROR -> {
acquireSingeExtractorLink ( getString ( R . string . episode _action _chromecast _mirror ) ) { link ->
val mirrorIndex = currentLinks ?. indexOf ( link ) ?: - 1
startChromecast ( if ( mirrorIndex == - 1 ) 0 else mirrorIndex )
}
}
ACTION _CHROME _CAST _EPISODE -> {
startChromecast ( 0 )
}
ACTION _PLAY _EPISODE _IN _VLC _PLAYER -> {
activity ?. let { act ->
try {
if ( ! act . checkWrite ( ) ) {
act . requestRW ( )
if ( act . checkWrite ( ) ) return @main
}
val data = currentLinks ?: return @main
val subs = currentSubs ?: return @main
val outputDir = act . cacheDir
val outputFile = withContext ( Dispatchers . IO ) {
File . createTempFile ( " mirrorlist " , " .m3u8 " , outputDir )
}
var text = " #EXTM3U "
for ( sub in sortSubs ( subs ) ) {
text += " \n #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID= \" subs \" ,NAME= \" ${sub.name} \" ,DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE= \" ${sub.name} \" ,URI= \" ${sub.url} \" "
}
for ( link in data . sortedBy { - it . quality } ) {
text += " \n #EXTINF:, ${link.name} \n ${link.url} "
}
outputFile . writeText ( text )
val vlcIntent = Intent ( VLC _INTENT _ACTION _RESULT )
vlcIntent . setPackage ( VLC _PACKAGE )
vlcIntent . addFlags ( FLAG _GRANT _PERSISTABLE _URI _PERMISSION )
vlcIntent . addFlags ( FLAG _GRANT _PREFIX _URI _PERMISSION )
vlcIntent . addFlags ( FLAG _GRANT _READ _URI _PERMISSION )
vlcIntent . addFlags ( FLAG _GRANT _WRITE _URI _PERMISSION )
vlcIntent . setDataAndType (
FileProvider . getUriForFile (
act ,
act . applicationContext . packageName + " .provider " ,
outputFile
) , " video/* "
)
val startId = VLC _FROM _PROGRESS
var position = startId
if ( startId == VLC _FROM _START ) {
position = 1
} else if ( startId == VLC _FROM _PROGRESS ) {
position = 0
}
vlcIntent . putExtra ( " position " , position )
vlcIntent . component = VLC _COMPONENT
act . setKey ( VLC _LAST _ID _KEY , episodeClick . data . id )
act . startActivityForResult ( vlcIntent , VLC _REQUEST _CODE )
} catch ( e : Exception ) {
logError ( e )
showToast ( act , e . toString ( ) , Toast . LENGTH _LONG )
}
}
}
ACTION _PLAY _EPISODE _IN _PLAYER -> {
viewModel . getGenerator ( episodeClick . data )
?. let { generator ->
activity ?. navigate (
R . id . global _to _navigation _player ,
GeneratorPlayer . newInstance (
generator , syncdata ?. let { HashMap ( it ) }
)
)
}
}
ACTION _RELOAD _EPISODE -> {
viewModel . loadEpisode ( episodeClick . data , false , clearCache = true )
}
ACTION _DOWNLOAD _MIRROR -> {
acquireSingleExtractorLink (
sortUrls (
currentLinks ?: return @main
) , //(currentLinks ?: return@main).filter { !it.isM3u8 },
2022-07-20 23:48:40 +00:00
context ?. getString ( R . string . episode _action _download _mirror ) ?: " "
2022-07-17 00:41:01 +00:00
) { link ->
startDownload (
context ,
episodeClick . data ,
currentIsMovie ?: return @acquireSingleExtractorLink ,
currentHeaderName ?: return @acquireSingleExtractorLink ,
currentType ?: return @acquireSingleExtractorLink ,
currentPoster ?: return @acquireSingleExtractorLink ,
apiName ,
currentId ?: return @acquireSingleExtractorLink ,
url ?: return @acquireSingleExtractorLink ,
listOf ( link ) ,
sortSubs ( currentSubs ?: return @acquireSingleExtractorLink ) ,
)
showToast ( activity , R . string . download _started , Toast . LENGTH _SHORT )
}
}
}
}
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-05-02 21:32:28 +00:00
url = arguments ?. getString ( URL _BUNDLE )
2022-07-17 00:41:01 +00:00
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 ->
handleAction ( episodeClick )
} ,
{ downloadClickEvent ->
handleDownloadClick ( activity , currentHeaderName , downloadClickEvent )
}
)
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
observe ( viewModel . selectedSeason ) { season ->
result _season _button ?. text = fromIndexToSeasonText ( season )
}
observe ( viewModel . seasonSelections ) { seasonList ->
result _season _button ?. visibility = if ( seasonList . size <= 1 ) GONE else VISIBLE . also {
// If the season button is visible the result season button will be next focus down
if ( result _series _parent ?. isVisible == true )
setFocusUpAndDown ( result _resume _series _button , result _season _button )
else
setFocusUpAndDown ( result _bookmark _button , result _season _button )
}
result _season _button ?. setOnClickListener {
result _season _button ?. popupMenuNoIconsAndNoStringRes (
items = seasonList
. map { Pair ( it ?: - 2 , fromIndexToSeasonText ( it ) ) } ,
) {
val id = this . itemId
viewModel . changeSeason ( if ( id == - 2 ) null else id )
}
}
}
observe ( viewModel . selectedRange ) { range ->
result _episode _select ?. text = range
}
observe ( viewModel . rangeOptions ) { range ->
episodeRanges = range
result _episode _select ?. visibility = if ( range . size <= 1 ) GONE else VISIBLE . also {
// If Season button is invisible then the bookmark button next focus is episode select
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-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-08 19:38:19 +00:00
observe ( syncModel . syncIds ) {
syncdata = it
}
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-06-18 00:30:39 +00:00
viewModel . setMeta ( d , syncdata )
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 )
}
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-03-27 16:45:02 +00:00
observe ( viewModel . publicEpisodes ) { episodes ->
2021-09-19 22:36:32 +00:00
when ( episodes ) {
is Resource . Failure -> {
2021-09-20 21:11:36 +00:00
result _episode _loading ?. isVisible = false
//result_episodes?.isVisible = false
2021-09-19 22:36:32 +00:00
}
is Resource . Loading -> {
2021-09-20 21:11:36 +00:00
result _episode _loading ?. isVisible = true
2021-10-22 13:23:48 +00:00
// result_episodes?.isVisible = false
2021-09-19 22:36:32 +00:00
}
is Resource . Success -> {
2021-09-20 21:11:36 +00:00
//result_episodes?.isVisible = true
result _episode _loading ?. isVisible = false
2021-09-19 22:36:32 +00:00
if ( result _episodes == null || result _episodes . adapter == null ) return @observe
currentEpisodes = episodes . value
2022-02-13 00:53:40 +00:00
( result _episodes ?. adapter as ? EpisodeAdapter ? ) ?. cardList = episodes . value
( result _episodes ?. adapter as ? EpisodeAdapter ? ) ?. updateLayout ( )
( result _episodes ?. adapter as ? EpisodeAdapter ? ) ?. notifyDataSetChanged ( )
2021-09-19 22:36:32 +00:00
}
}
2021-05-22 22:25:56 +00:00
}
2022-03-27 16:45:02 +00:00
observe ( viewModel . dubStatus ) { status ->
2021-11-02 15:09:29 +00:00
result _dub _select ?. text = status . toString ( )
}
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 ->
2021-11-02 15:09:29 +00:00
dubRange = range
2022-03-27 16:45:02 +00:00
2022-05-21 22:10:33 +00:00
// if (preferDub && dubRange?.contains(DubStatus.Dubbed) == true) {
// viewModel.changeDubStatus(DubStatus.Dubbed)
// }
2022-03-27 16:45:02 +00:00
2021-11-02 15:09:29 +00:00
result _dub _select ?. visibility = if ( range . size <= 1 ) GONE else VISIBLE
2022-03-27 16:45:02 +00:00
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-07-17 00:41:01 +00:00
result _cast _items ?. setOnFocusChangeListener { _ , hasFocus ->
2022-03-27 16:45:02 +00:00
// Always escape focus
if ( hasFocus ) result _bookmark _button ?. requestFocus ( )
2021-11-02 15:09:29 +00:00
}
result _dub _select . setOnClickListener {
val ranges = dubRange
if ( ranges != null ) {
2022-03-27 16:45:02 +00:00
it . popupMenuNoIconsAndNoStringRes ( ranges
. map { status ->
Pair (
status . ordinal ,
status . toString ( )
)
}
2021-11-02 15:09:29 +00:00
. toList ( ) ) {
2021-12-16 23:45:20 +00:00
viewModel . changeDubStatus ( DubStatus . values ( ) [ itemId ] )
2021-11-02 15:09:29 +00:00
}
}
}
2022-04-01 20:05:34 +00:00
result _episode _select ?. setOnClickListener {
2021-07-25 20:50:16 +00:00
val ranges = episodeRanges
if ( ranges != null ) {
2021-12-17 12:42:25 +00:00
it . popupMenuNoIconsAndNoStringRes ( ranges . mapIndexed { index , s -> Pair ( index , s ) }
. toList ( ) ) {
2021-12-16 23:45:20 +00:00
viewModel . changeRange ( itemId )
2021-07-25 20:50:16 +00:00
}
}
}
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
}
2021-07-25 20:50:16 +00:00
observe ( viewModel . publicEpisodesCount ) { count ->
2021-09-20 21:11:36 +00:00
if ( count < 0 ) {
result _episodes _text ?. isVisible = false
} else {
2021-10-22 13:23:48 +00:00
// result_episodes_text?.isVisible = true
2021-09-20 21:11:36 +00:00
result _episodes _text ?. text =
" $count ${if (count == 1) getString(R.string.episode) else getString(R.string.episodes)} "
}
2021-07-25 20:50:16 +00:00
}
2021-07-17 14:14:25 +00:00
observe ( viewModel . id ) {
currentId = it
}
2022-04-03 01:13:02 +00:00
observe ( viewModel . result ) { data ->
2021-05-18 13:43:32 +00:00
when ( data ) {
is Resource . Success -> {
val d = data . value
2022-04-03 01:13:02 +00:00
if ( d !is AnimeLoadResponse && result _episode _loading . isVisible ) { // no episode loading when not anime
result _episode _loading . isVisible = false
}
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-04-03 01:13:02 +00:00
result _vpn ?. text = when ( api . vpnStatus ) {
VPNStatus . MightBeNeeded -> getString ( R . string . vpn _might _be _needed )
VPNStatus . Torrent -> getString ( R . string . vpn _torrent )
else -> " "
}
result _vpn ?. isGone = api . vpnStatus == VPNStatus . None
2021-08-29 13:10:36 +00:00
2022-04-03 01:13:02 +00:00
result _info ?. text = when ( api . providerType ) {
ProviderType . MetaProvider -> getString ( R . string . provider _info _meta )
else -> " "
}
result _info ?. isVisible = api . providerType == ProviderType . MetaProvider
if ( d . type . isEpisodeBased ( ) ) {
val ep = d as ? TvSeriesLoadResponse
val epCount = ep ?. episodes ?. size ?: 1
if ( epCount < 1 ) {
result _info ?. text = getString ( R . string . no _episodes _found )
result _info ?. isVisible = true
2022-01-11 12:53:08 +00:00
}
2022-04-03 01:13:02 +00:00
}
2022-01-11 12:53:08 +00:00
2022-04-03 01:13:02 +00:00
currentHeaderName = d . name
currentType = d . type
2021-06-14 00:00:29 +00:00
2022-04-03 01:13:02 +00:00
currentPoster = d . posterUrl
currentIsMovie = ! d . isEpisodeBased ( )
2021-06-10 15:15:14 +00:00
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 {
QuickSearchFragment . pushSearch ( activity , d . name )
}
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 "
i . putExtra ( EXTRA _SUBJECT , d . name )
i . putExtra ( EXTRA _TEXT , d . url )
startActivity ( createChooser ( i , d . name ) )
} 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
val showStatus = when ( d ) {
is TvSeriesLoadResponse -> d . showStatus
is AnimeLoadResponse -> d . showStatus
else -> null
}
2022-04-01 20:05:34 +00:00
2022-04-03 01:13:02 +00:00
setShow ( showStatus )
setDuration ( d . duration )
setYear ( d . year )
setRating ( d . rating )
2022-04-18 00:26:13 +00:00
setRecommendations ( d . recommendations , null )
2022-04-03 01:13:02 +00:00
setActors ( d . actors )
2022-06-21 00:30:55 +00:00
setNextEpisode ( if ( d is EpisodeResponse ) d . nextAiring else null )
2022-07-27 17:36:31 +00:00
setTrailers ( d . trailers . flatMap { it . mirros } ) // I dont care about subtitles yet!
2022-06-16 01:04:24 +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-04-03 01:13:02 +00:00
result _meta _site ?. text = d . apiName
2022-04-01 20:05:34 +00:00
2022-04-03 01:13:02 +00:00
val posterImageLink = d . posterUrl
if ( ! posterImageLink . isNullOrEmpty ( ) ) {
2022-04-13 17:29:30 +00:00
result _poster ?. setImage ( posterImageLink , d . posterHeaders )
2022-06-16 01:04:24 +00:00
//result_poster_blur?.setImageBlur(posterImageLink, 10, 3, d.posterHeaders)
2022-04-03 01:13:02 +00:00
//Full screen view of Poster image
2022-04-03 21:41:28 +00:00
if ( context ?. isTrueTvSettings ( ) == false ) // Poster not clickable on tv
result _poster _holder ?. setOnClickListener {
try {
context ?. let { ctx ->
2022-05-22 09:06:52 +00:00
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 ( posterImageLink )
setOnClickListener {
sourceDialog . dismissSafe ( )
}
2022-04-03 21:41:28 +00:00
}
2022-05-22 09:06:52 +00:00
}
2022-04-03 21:41:28 +00:00
}
} catch ( e : Exception ) {
logError ( e )
2022-03-20 23:25:25 +00:00
}
}
2022-04-03 21:41:28 +00:00
2022-04-03 01:13:02 +00:00
} else {
result _poster ?. setImageResource ( R . drawable . default _cover )
2022-06-16 01:04:24 +00:00
//result_poster_blur?.setImageResource(R.drawable.default_cover)
2022-04-03 01:13:02 +00:00
}
2021-12-10 00:20:24 +00:00
2022-04-03 01:13:02 +00:00
result _poster _holder ?. visibility = VISIBLE
2022-07-19 20:24:55 +00:00
result _play _movie ?. text =
if ( d . type == TvType . Live ) getString ( R . string . play _livestream _button ) else getString (
2022-04-03 01:13:02 +00:00
R . string . play _movie _button
2022-07-19 20:24:55 +00:00
)
2022-04-03 01:13:02 +00:00
//result_plot_header?.text =
// if (d.type == TvType.Torrent) getString(R.string.torrent_plot) else getString(R.string.result_plot)
2022-06-29 01:20:23 +00:00
val syno = d . plot
if ( ! syno . isNullOrEmpty ( ) ) {
result _description ?. setOnClickListener {
2022-04-03 01:13:02 +00:00
val builder : AlertDialog . Builder =
2022-06-09 13:50:55 +00:00
AlertDialog . Builder ( requireContext ( ) , R . style . AlertDialogCustom )
2022-06-29 01:20:23 +00:00
builder . setMessage ( syno . html ( ) )
2022-04-03 01:13:02 +00:00
. setTitle ( if ( d . type == TvType . Torrent ) R . string . torrent _plot else R . string . result _plot )
. show ( )
}
2022-06-29 01:20:23 +00:00
result _description ?. text = syno . html ( )
2022-04-03 01:13:02 +00:00
} else {
2022-06-29 01:20:23 +00:00
result _description ?. text =
2022-04-03 01:13:02 +00:00
if ( d . type == TvType . Torrent ) getString ( R . string . torrent _no _plot ) else getString (
R . string . normal _no _plot
)
}
2021-05-22 22:25:56 +00:00
2022-04-03 01:13:02 +00:00
result _tag ?. removeAllViews ( )
//result_tag_holder?.visibility = GONE
// result_status.visibility = GONE
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
if ( tags . isNullOrEmpty ( ) ) {
//result_tag_holder?.visibility = GONE
} else {
//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-04-03 01:13:02 +00:00
if ( d . type . isMovieType ( ) ) {
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
2021-07-25 16:08:34 +00:00
// result_options.setOnClickListener {
// val card = currentEpisodes?.first() ?: return@setOnClickListener
// handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
// }
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 )
}
2021-06-16 16:54:07 +00:00
2022-04-03 01:13:02 +00:00
context ?. getString (
when ( d . type ) {
TvType . TvSeries -> R . string . tv _series _singular
TvType . Anime -> R . string . anime _singular
TvType . OVA -> R . string . ova _singular
TvType . AnimeMovie -> R . string . movies _singular
TvType . Cartoon -> R . string . cartoons _singular
TvType . Documentary -> R . string . documentaries _singular
TvType . Movie -> R . string . movies _singular
TvType . Torrent -> R . string . torrent _singular
TvType . AsianDrama -> R . string . asian _drama _singular
2022-07-19 20:24:55 +00:00
TvType . Live -> R . string . live _singular
2022-01-31 20:47:59 +00:00
}
2022-04-03 01:13:02 +00:00
) ?. let {
result _meta _type ?. text = it
}
2022-01-31 20:47:59 +00:00
2022-04-03 01:13:02 +00:00
when ( d ) {
is AnimeLoadResponse -> {
2022-01-31 20:47:59 +00:00
2022-04-03 01:13:02 +00:00
// val preferEnglish = true
//val titleName = (if (preferEnglish) d.engName else d.japName) ?: d.name
val titleName = d . name
result _title . text = titleName
//result_toolbar.title = titleName
2021-05-18 13:43:32 +00:00
}
2022-04-03 01:13:02 +00:00
else -> result _title . text = d . name
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 )
2021-09-19 22:36:32 +00:00
val tempUrl = url
if ( tempUrl != null ) {
result _reload _connectionerror . setOnClickListener {
2021-12-16 23:45:20 +00:00
viewModel . load ( tempUrl , apiName , showFillers )
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-03-14 12:44:54 +00:00
i . data = Uri . parse ( tempUrl )
try {
startActivity ( i )
} catch ( e : Exception ) {
logError ( e )
}
}
result _open _in _browser ?. setOnClickListener {
val i = Intent ( ACTION _VIEW )
2021-12-10 00:20:24 +00:00
i . data = Uri . parse ( tempUrl )
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 {
it . context ?. openBrowser ( tempUrl )
}
result _meta _site ?. isFocusable = true
} else {
result _meta _site ?. isFocusable = false
2021-09-19 22:36:32 +00:00
}
2022-04-03 01:13:02 +00:00
if ( restart || viewModel . result . value == null ) {
2022-01-07 19:27:25 +00:00
//viewModel.clear()
2021-12-16 23:45:20 +00:00
viewModel . load ( tempUrl , apiName , showFillers )
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
}