package com.lagradost.cloudstream3.ui.result import android.annotation.SuppressLint import android.content.Intent import android.content.Intent.* import android.content.res.ColorStateList import android.net.Uri import android.os.Build import android.os.Bundle import android.text.Editable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.* import androidx.appcompat.app.AlertDialog import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.core.widget.doOnTextChanged import androidx.lifecycle.ViewModelProvider import androidx.preference.PreferenceManager import com.discord.panels.OverlappingPanelsLayout 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 import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings import com.lagradost.cloudstream3.APIHolder.getApiFromName import com.lagradost.cloudstream3.APIHolder.updateHasTrailers import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.DubStatus import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.SearchResponse import com.lagradost.cloudstream3.TvType import com.lagradost.cloudstream3.mvvm.* import com.lagradost.cloudstream3.syncproviders.providers.Kitsu import com.lagradost.cloudstream3.ui.WatchType import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick import com.lagradost.cloudstream3.ui.download.EasyDownloadButton import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.AppUtils.getNameFull import com.lagradost.cloudstream3.utils.AppUtils.html import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable import com.lagradost.cloudstream3.utils.AppUtils.loadCache import com.lagradost.cloudstream3.utils.AppUtils.openBrowser import com.lagradost.cloudstream3.utils.Coroutines.ioWork import com.lagradost.cloudstream3.utils.Coroutines.main import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard import kotlinx.android.synthetic.main.fragment_result.* import kotlinx.android.synthetic.main.fragment_result.result_cast_items import kotlinx.android.synthetic.main.fragment_result.result_cast_text import kotlinx.android.synthetic.main.fragment_result.result_coming_soon import kotlinx.android.synthetic.main.fragment_result.result_data_holder import kotlinx.android.synthetic.main.fragment_result.result_description import kotlinx.android.synthetic.main.fragment_result.result_download_movie import kotlinx.android.synthetic.main.fragment_result.result_episode_loading import kotlinx.android.synthetic.main.fragment_result.result_episodes import kotlinx.android.synthetic.main.fragment_result.result_error_text import kotlinx.android.synthetic.main.fragment_result.result_finish_loading import kotlinx.android.synthetic.main.fragment_result.result_info import kotlinx.android.synthetic.main.fragment_result.result_loading import kotlinx.android.synthetic.main.fragment_result.result_loading_error import kotlinx.android.synthetic.main.fragment_result.result_meta_duration import kotlinx.android.synthetic.main.fragment_result.result_meta_rating import kotlinx.android.synthetic.main.fragment_result.result_meta_site import kotlinx.android.synthetic.main.fragment_result.result_meta_type import kotlinx.android.synthetic.main.fragment_result.result_meta_year import kotlinx.android.synthetic.main.fragment_result.result_movie_download_icon import kotlinx.android.synthetic.main.fragment_result.result_movie_download_text import kotlinx.android.synthetic.main.fragment_result.result_movie_download_text_precentage import kotlinx.android.synthetic.main.fragment_result.result_movie_progress_downloaded import kotlinx.android.synthetic.main.fragment_result.result_movie_progress_downloaded_holder import kotlinx.android.synthetic.main.fragment_result.result_next_airing import kotlinx.android.synthetic.main.fragment_result.result_next_airing_time import kotlinx.android.synthetic.main.fragment_result.result_no_episodes import kotlinx.android.synthetic.main.fragment_result.result_play_movie import kotlinx.android.synthetic.main.fragment_result.result_reload_connection_open_in_browser import kotlinx.android.synthetic.main.fragment_result.result_reload_connectionerror import kotlinx.android.synthetic.main.fragment_result.result_resume_parent import kotlinx.android.synthetic.main.fragment_result.result_resume_progress_holder import kotlinx.android.synthetic.main.fragment_result.result_resume_series_progress import kotlinx.android.synthetic.main.fragment_result.result_resume_series_progress_text import kotlinx.android.synthetic.main.fragment_result.result_resume_series_title import kotlinx.android.synthetic.main.fragment_result.result_tag import kotlinx.android.synthetic.main.fragment_result.result_tag_holder import kotlinx.android.synthetic.main.fragment_result.result_title import kotlinx.android.synthetic.main.fragment_result.result_vpn import kotlinx.android.synthetic.main.fragment_result_swipe.* import kotlinx.android.synthetic.main.fragment_result_tv.* import kotlinx.android.synthetic.main.fragment_trailer.* import kotlinx.android.synthetic.main.result_sync.* import kotlinx.coroutines.runBlocking import android.widget.EditText import android.widget.AbsListView const val START_ACTION_RESUME_LATEST = 1 const val START_ACTION_LOAD_EP = 2 data class ResultEpisode( val headerName: String, val name: String?, val poster: String?, val episode: Int, val seasonIndex: Int?, // this is the "season" index used season names val season: Int?, // this is the display val data: String, val apiName: String, val id: Int, val index: Int, val position: Long, // time in MS val duration: Long, // duration in MS val rating: Int?, val description: String?, val isFiller: Boolean?, val tvType: TvType, val parentId: Int, ) fun ResultEpisode.getRealPosition(): Long { if (duration <= 0) return 0 val percentage = position * 100 / duration if (percentage <= 5 || percentage >= 95) return 0 return position } 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 } fun buildResultEpisode( headerName: String, name: String? = null, poster: String? = null, episode: Int, seasonIndex: Int? = null, season: Int? = null, data: String, apiName: String, id: Int, index: Int, rating: Int? = null, description: String? = null, isFiller: Boolean? = null, tvType: TvType, parentId: Int, ): ResultEpisode { val posDur = getViewPos(id) return ResultEpisode( headerName, name, poster, episode, seasonIndex, season, data, apiName, id, index, posDur?.position ?: 0, posDur?.duration ?: 0, rating, description, isFiller, tvType, parentId, ) } /** 0f-1f */ fun ResultEpisode.getWatchProgress(): Float { return (getDisplayPosition() / 1000).toFloat() / (duration / 1000).toFloat() } open class ResultFragment : ResultTrailerPlayer() { companion object { 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) { 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) } } fun newInstance( url: String, apiName: String, startAction: Int = 0, startValue: Int = 0 ): Bundle { return Bundle().apply { putString(URL_BUNDLE, url) putString(API_NAME_BUNDLE, apiName) putInt(START_ACTION_BUNDLE, startAction) putInt(START_VALUE_BUNDLE, startValue) putBoolean(RESTART_BUNDLE, true) } } fun updateUI() { updateUIListener?.invoke() } private var updateUIListener: (() -> Unit)? = null } open fun setTrailers(trailers: List?) {} protected lateinit var viewModel: ResultViewModel2 //by activityViewModels() protected lateinit var syncModel: SyncViewModel protected open val resultLayout = R.layout.fragment_result_swipe override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View? { viewModel = ViewModelProvider(this)[ResultViewModel2::class.java] syncModel = ViewModelProvider(this)[SyncViewModel::class.java] return inflater.inflate(resultLayout, container, false) } private var downloadButton: EasyDownloadButton? = null override fun onDestroyView() { updateUIListener = null (result_episodes?.adapter as EpisodeAdapter?)?.killAdapter() downloadButton?.dispose() super.onDestroyView() } override fun onResume() { super.onResume() activity?.let { it.window?.navigationBarColor = it.colorFromAttribute(R.attr.primaryBlackBackground) } } /// 0 = LOADING, 1 = ERROR LOADING, 2 = LOADED private fun updateVisStatus(state: Int) { when (state) { 0 -> { result_bookmark_fab?.isGone = true result_loading?.isVisible = true result_finish_loading?.isVisible = false result_loading_error?.isVisible = false } 1 -> { 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 = true } 2 -> { result_bookmark_fab?.isGone = result_bookmark_fab?.context?.isTvSettings() == true result_bookmark_fab?.extend() 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() } } } result_loading?.isVisible = false result_finish_loading?.isVisible = true result_loading_error?.isVisible = false } } } open fun setRecommendations(rec: List?, validApiName: String?) { } private fun updateUI() { syncModel.updateUserData() viewModel.reloadEpisodes() } open fun updateMovie(data: ResourceSome>) { 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 } main { val file = ioWork { context?.let { VideoDownloadManager.getDownloadFileInfoAndUpdateSettings( it, ep.id ) } } 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( ep.name, ep.poster, 0, null, ep.id, ep.id, null, null, System.currentTimeMillis(), ) ) { click -> when (click.action) { DOWNLOAD_ACTION_DOWNLOAD -> { viewModel.handleAction( activity, EpisodeClickEvent(ACTION_DOWNLOAD_EPISODE, ep) ) } else -> handleDownloadClick(activity, click) } } result_movie_progress_downloaded_holder?.isVisible = true } } } else -> { result_movie_progress_downloaded_holder?.isVisible = false result_play_movie?.isVisible = false } } } open fun updateEpisodes(episodes: ResourceSome>) { when (episodes) { is ResourceSome.None -> { result_episode_loading?.isVisible = false result_episodes?.isVisible = false } is ResourceSome.Loading -> { result_episode_loading?.isVisible = true result_episodes?.isVisible = false } is ResourceSome.Success -> { result_episodes?.isVisible = true result_episode_loading?.isVisible = false (result_episodes?.adapter as? EpisodeAdapter?)?.updateList(episodes.value) } } } @SuppressLint("SetTextI18n") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) result_cast_items?.adapter = ActorAdaptor() updateUIListener = ::updateUI val restart = arguments?.getBoolean(RESTART_BUNDLE) ?: false if (restart) { arguments?.putBoolean(RESTART_BUNDLE, false) } activity?.window?.decorView?.clearFocus() hideKeyboard() context?.updateHasTrailers() activity?.loadCache() activity?.fixPaddingStatusbar(result_top_bar) //activity?.fixPaddingStatusbar(result_barstatus) /* val backParameter = result_back.layoutParams as FrameLayout.LayoutParams backParameter.setMargins( backParameter.leftMargin, backParameter.topMargin + requireContext().getStatusBarHeight(), backParameter.rightMargin, backParameter.bottomMargin ) result_back.layoutParams = backParameter*/ // activity?.fixPaddingStatusbar(result_toolbar) val url = arguments?.getString(URL_BUNDLE) val apiName = arguments?.getString(API_NAME_BUNDLE) ?: return val startAction = arguments?.getInt(START_ACTION_BUNDLE) val start = startAction?.let { action -> val startValue = arguments?.getInt(START_VALUE_BUNDLE) val resumeEpisode = arguments?.getInt(EPISODE_BUNDLE) val resumeSeason = arguments?.getInt(SEASON_BUNDLE) arguments?.remove(START_VALUE_BUNDLE) arguments?.remove(START_ACTION_BUNDLE) AutoResume( startAction = action, id = startValue, episode = resumeEpisode, season = resumeSeason ) } syncModel.addFromUrl(url) 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) { media_route_button?.setOnClickListener { showToast(activity, R.string.no_chromecast_support_toast, Toast.LENGTH_LONG) } } activity?.let { act -> if (act.isCastApiAvailable()) { try { CastButtonFactory.setUpMediaRouteButton(act, media_route_button) val castContext = CastContext.getSharedInstance(act.applicationContext) media_route_button?.isGone = castContext.castState == CastState.NO_DEVICES_AVAILABLE // this shit leaks for some reason //castContext.addCastStateListener { state -> // media_route_button?.isGone = state == CastState.NO_DEVICES_AVAILABLE //} } catch (e: Exception) { logError(e) } } } } result_episodes?.adapter = EpisodeAdapter( api.hasDownloadSupport, { episodeClick -> viewModel.handleAction(activity, episodeClick) }, { downloadClickEvent -> handleDownloadClick(activity, downloadClickEvent) } ) observe(viewModel.watchStatus) { watchType -> result_bookmark_button?.text = getString(watchType.stringRes) result_bookmark_fab?.text = getString(watchType.stringRes) if (watchType == WatchType.NONE) { result_bookmark_fab?.context?.colorFromAttribute(R.attr.white) } else { result_bookmark_fab?.context?.colorFromAttribute(R.attr.colorPrimary) }?.let { val colorState = ColorStateList.valueOf(it) result_bookmark_fab?.iconTint = colorState result_bookmark_fab?.setTextColor(colorState) } result_bookmark_fab?.setOnClickListener { fab -> activity?.showBottomDialog( WatchType.values().map { fab.context.getString(it.stringRes) }.toList(), watchType.ordinal, fab.context.getString(R.string.action_add_to_bookmarks), showApply = false, {}) { viewModel.updateWatchStatus(WatchType.values()[it]) } } } // This is to band-aid FireTV navigation val isTv = context?.isTvSettings() == true result_season_button?.isFocusableInTouchMode = isTv result_episode_select?.isFocusableInTouchMode = isTv result_dub_select?.isFocusableInTouchMode = isTv context?.let { ctx -> val arrayAdapter = ArrayAdapter(ctx, R.layout.sort_bottom_single_choice) /* -1 -> None 0 -> Watching 1 -> Completed 2 -> OnHold 3 -> Dropped 4 -> PlanToWatch 5 -> ReWatching */ val items = listOf( R.string.none, R.string.type_watching, R.string.type_completed, R.string.type_on_hold, R.string.type_dropped, R.string.type_plan_to_watch, R.string.type_re_watching ).map { ctx.getString(it) } arrayAdapter.addAll(items) result_sync_check?.choiceMode = AbsListView.CHOICE_MODE_SINGLE result_sync_check?.adapter = arrayAdapter UIHelper.setListViewHeightBasedOnItems(result_sync_check) result_sync_check?.setOnItemClickListener { _, _, which, _ -> syncModel.setStatus(which - 1) } result_sync_rating?.addOnChangeListener { _, value, _ -> syncModel.setScore(value.toInt()) } result_sync_add_episode?.setOnClickListener { syncModel.setEpisodesDelta(1) } result_sync_sub_episode?.setOnClickListener { syncModel.setEpisodesDelta(-1) } result_sync_current_episodes?.doOnTextChanged { text, _, before, count -> if (count == before) return@doOnTextChanged text?.toString()?.toIntOrNull()?.let { ep -> syncModel.setEpisodes(ep) } } } observe(syncModel.synced) { list -> result_sync_names?.text = list.filter { it.isSynced && it.hasAccount }.joinToString { it.name } val newList = list.filter { it.isSynced && it.hasAccount } result_mini_sync?.isVisible = newList.isNotEmpty() (result_mini_sync?.adapter as? ImageAdapter?)?.updateList(newList.mapNotNull { it.icon }) } var currentSyncProgress = 0 fun setSyncMaxEpisodes(totalEpisodes: Int?) { result_sync_episodes?.max = (totalEpisodes ?: 0) * 1000 normalSafeApiCall { val ctx = result_sync_max_episodes?.context result_sync_max_episodes?.text = totalEpisodes?.let { episodes -> ctx?.getString(R.string.sync_total_episodes_some)?.format(episodes) } ?: run { ctx?.getString(R.string.sync_total_episodes_none) } } } observe(syncModel.metadata) { meta -> when (meta) { is Resource.Success -> { val d = meta.value result_sync_episodes?.progress = currentSyncProgress * 1000 setSyncMaxEpisodes(d.totalEpisodes) viewModel.setMeta(d, syncModel.getSyncs()) } is Resource.Loading -> { result_sync_max_episodes?.text = result_sync_max_episodes?.context?.getString(R.string.sync_total_episodes_none) } else -> {} } } observe(syncModel.userData) { status -> var closed = false when (status) { is Resource.Failure -> { result_sync_loading_shimmer?.stopShimmer() result_sync_loading_shimmer?.isVisible = false result_sync_holder?.isVisible = false closed = true } is Resource.Loading -> { result_sync_loading_shimmer?.startShimmer() result_sync_loading_shimmer?.isVisible = true result_sync_holder?.isVisible = false } is Resource.Success -> { result_sync_loading_shimmer?.stopShimmer() result_sync_loading_shimmer?.isVisible = false result_sync_holder?.isVisible = true val d = status.value result_sync_rating?.value = d.score?.toFloat() ?: 0.0f result_sync_check?.setItemChecked(d.status + 1, true) val watchedEpisodes = d.watchedEpisodes ?: 0 currentSyncProgress = watchedEpisodes d.maxEpisodes?.let { // don't directly call it because we don't want to override metadata observe setSyncMaxEpisodes(it) } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { result_sync_episodes?.setProgress(watchedEpisodes * 1000, true) } else { result_sync_episodes?.progress = watchedEpisodes * 1000 } result_sync_current_episodes?.text = Editable.Factory.getInstance()?.newEditable(watchedEpisodes.toString()) normalSafeApiCall { // format might fail context?.getString(R.string.sync_score_format)?.format(d.score ?: 0)?.let { result_sync_score_text?.text = it } } } null -> { closed = false } } result_overlapping_panels?.setStartPanelLockState(if (closed) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED) } observe(viewModel.resumeWatching) { resume -> when (resume) { is Some.Success -> { result_resume_parent?.isVisible = true val value = resume.value value.progress?.let { progress -> result_resume_series_title?.apply { isVisible = !value.isMovie text = if (value.isMovie) null else activity?.getNameFull( value.result.name, value.result.episode, value.result.season ) } result_resume_series_progress_text.setText(progress.progressLeft) result_resume_series_progress?.apply { isVisible = true this.max = progress.maxProgress this.progress = progress.progress } result_resume_progress_holder?.isVisible = true } ?: run { result_resume_progress_holder?.isVisible = false result_resume_series_progress?.isVisible = false result_resume_series_title?.isVisible = false result_resume_series_progress_text?.isVisible = false } result_resume_series_button?.isVisible = !value.isMovie result_resume_series_button_play?.isVisible = !value.isMovie val click = View.OnClickListener { viewModel.handleAction( activity, EpisodeClickEvent( ACTION_PLAY_EPISODE_IN_PLAYER, value.result ) ) } result_resume_series_button?.setOnClickListener(click) result_resume_series_button_play?.setOnClickListener(click) } is Some.None -> { result_resume_parent?.isVisible = false } } } observe(viewModel.episodes) { episodes -> updateEpisodes(episodes) } result_cast_items?.setOnFocusChangeListener { _, hasFocus -> // Always escape focus if (hasFocus) result_bookmark_button?.requestFocus() } result_sync_set_score?.setOnClickListener { syncModel.publishUserData() } observe(viewModel.trailers) { trailers -> setTrailers(trailers.flatMap { it.mirros }) // I dont care about subtitles yet! } observe(viewModel.recommendations) { recommendations -> setRecommendations(recommendations, null) } observe(viewModel.movie) { data -> updateMovie(data) } observe(viewModel.page) { data -> when (data) { is Resource.Success -> { val d = data.value updateVisStatus(2) 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) result_next_airing.setText(d.nextAiringEpisode) result_next_airing_time.setText(d.nextAiringDate) result_poster.setImage(d.posterImage) 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(R.id.imgPoster) ?.apply { setImage(d.posterImage) setOnClickListener { sourceDialog.dismissSafe() } } } } } catch (e: Exception) { logError(e) } } result_cast_items?.isVisible = d.actors != null (result_cast_items?.adapter as ActorAdaptor?)?.apply { updateList(d.actors ?: emptyList()) } result_open_in_browser?.isVisible = d.url.startsWith("http") result_open_in_browser?.setOnClickListener { val i = Intent(ACTION_VIEW) i.data = Uri.parse(d.url) try { startActivity(i) } catch (e: Exception) { logError(e) } } result_search?.setOnClickListener { QuickSearchFragment.pushSearch(activity, d.title) } result_share?.setOnClickListener { try { val i = Intent(ACTION_SEND) i.type = "text/plain" i.putExtra(EXTRA_SUBJECT, d.title) i.putExtra(EXTRA_TEXT, d.url) startActivity(createChooser(i, d.title)) } catch (e: Exception) { logError(e) } } if (syncModel.addSyncs(d.syncData)) { syncModel.updateMetaAndUser() syncModel.updateSynced() } else { syncModel.addFromUrl(d.url) } result_description.setTextHtml(d.plotText) if (this !is ResultFragmentTv) // dont want this clickable on tv layout result_description?.setOnClickListener { view -> view.context?.let { ctx -> val builder: AlertDialog.Builder = AlertDialog.Builder(ctx, R.style.AlertDialogCustom) builder.setMessage(d.plotText.asString(ctx).html()) .setTitle(d.plotHeaderText.asString(ctx)) .show() } } result_tag?.removeAllViews() d.comingSoon.let { soon -> result_coming_soon?.isVisible = soon result_data_holder?.isGone = soon } val tags = d.tags result_tag_holder?.isVisible = tags.isNotEmpty() if (tags.isNotEmpty()) { //result_tag_holder?.visibility = VISIBLE val isOnTv = context?.isTrueTvSettings() == true for ((index, tag) in tags.withIndex()) { val viewBtt = layoutInflater.inflate(R.layout.result_tag, null) val btt = viewBtt.findViewById(R.id.result_tag_card) btt.text = tag btt.isFocusable = !isOnTv btt.isClickable = !isOnTv result_tag?.addView(viewBtt, index) } } } is Resource.Failure -> { result_error_text.text = url?.plus("\n") + data.errorString updateVisStatus(1) } is Resource.Loading -> { updateVisStatus(0) } } } context?.let { ctx -> val dubStatus = if (ctx.getApiDubstatusSettings() .contains(DubStatus.Dubbed) ) DubStatus.Dubbed else DubStatus.Subbed result_bookmark_button?.isVisible = ctx.isTvSettings() val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx) val showFillers = settingsManager.getBoolean(ctx.getString(R.string.show_fillers_key), false) Kitsu.isEnabled = settingsManager.getBoolean(ctx.getString(R.string.show_kitsu_posters_key), true) if (url != null) { result_reload_connectionerror.setOnClickListener { viewModel.load(activity, url, apiName, showFillers, dubStatus, start) } result_reload_connection_open_in_browser?.setOnClickListener { val i = Intent(ACTION_VIEW) i.data = Uri.parse(url) try { startActivity(i) } catch (e: Exception) { logError(e) } } result_open_in_browser?.isVisible = url.startsWith("http") result_open_in_browser?.setOnClickListener { val i = Intent(ACTION_VIEW) i.data = Uri.parse(url) try { startActivity(i) } catch (e: Exception) { logError(e) } } // bloats the navigation on tv if (context?.isTrueTvSettings() == false) { result_meta_site?.setOnClickListener { it.context?.openBrowser(url) } result_meta_site?.isFocusable = true } else { result_meta_site?.isFocusable = false } if (restart || !viewModel.hasLoaded()) { //viewModel.clear() viewModel.load(activity, url, apiName, showFillers, dubStatus, start) } } } } }