AquaStream/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt

1380 lines
57 KiB
Kotlin
Raw Normal View History

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
2021-09-03 09:13:34 +00:00
import android.content.ClipData
import android.content.ClipboardManager
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
2021-06-10 15:15:14 +00:00
import android.net.Uri
2021-05-16 18:28:00 +00:00
import android.os.Bundle
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
2021-12-13 18:41:33 +00:00
import android.widget.TextView
2021-06-10 15:15:14 +00:00
import android.widget.Toast
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
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
2021-05-16 18:28:00 +00:00
import androidx.fragment.app.Fragment
2021-11-05 21:39:56 +00:00
import androidx.fragment.app.activityViewModels
2021-09-19 22:36:32 +00:00
import androidx.preference.PreferenceManager
2021-05-18 13:43:32 +00:00
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
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.*
import com.lagradost.cloudstream3.APIHolder.getApiFromName
2021-07-25 16:08:34 +00:00
import com.lagradost.cloudstream3.APIHolder.getId
2021-09-30 12:55:56 +00:00
import com.lagradost.cloudstream3.MainActivity.Companion.getCastSession
import com.lagradost.cloudstream3.MainActivity.Companion.showToast
2021-05-18 13:43:32 +00:00
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.logError
2021-10-22 13:23:48 +00:00
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
2021-05-18 13:43:32 +00:00
import com.lagradost.cloudstream3.mvvm.observe
2021-12-13 18:41:33 +00:00
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.SyncApis
import com.lagradost.cloudstream3.syncproviders.SyncAPI
2021-06-15 23:25:58 +00:00
import com.lagradost.cloudstream3.ui.WatchType
2021-07-24 20:50:57 +00:00
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
2021-07-24 20:50:57 +00:00
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
2021-05-22 22:25:56 +00:00
import com.lagradost.cloudstream3.ui.player.PlayerData
import com.lagradost.cloudstream3.ui.player.PlayerFragment
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
2021-12-10 19:48:21 +00:00
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment.Companion.getDownloadSubsLanguageISO639_1
2021-07-17 14:14:25 +00:00
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.isAppInstalled
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
import com.lagradost.cloudstream3.utils.AppUtils.isConnectedToChromecast
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
2021-06-14 16:58:43 +00:00
import com.lagradost.cloudstream3.utils.CastHelper.startCast
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-12-13 18:41:33 +00:00
import com.lagradost.cloudstream3.utils.DataStoreHelper.addSync
import com.lagradost.cloudstream3.utils.DataStoreHelper.getSync
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
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
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
2021-12-13 18:41:33 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
2021-09-20 21:11:36 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.navigate
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
import com.lagradost.cloudstream3.utils.UIHelper.setImageBlur
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.*
2021-07-30 21:03:46 +00:00
import kotlinx.coroutines.Dispatchers
2021-07-17 14:14:25 +00:00
import kotlinx.coroutines.Job
2021-07-30 21:03:46 +00:00
import kotlinx.coroutines.withContext
2021-07-17 15:56:26 +00:00
import java.io.File
2021-06-14 00:00:29 +00:00
const val MAX_SYNO_LENGH = 1000
2021-05-18 13:43:32 +00:00
2021-07-29 15:16:08 +00:00
const val START_ACTION_NORMAL = 0
const val START_ACTION_RESUME_LATEST = 1
2021-08-25 15:28:25 +00:00
const val START_ACTION_LOAD_EP = 2
const val START_VALUE_NORMAL = 0
2021-07-29 15:16:08 +00:00
2021-05-18 13:43:32 +00:00
data class ResultEpisode(
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?,
val description: String?,
2021-09-19 22:36:32 +00:00
val isFiller: Boolean?,
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
}
fun buildResultEpisode(
2021-06-15 16:07:20 +00:00
name: String?,
poster: String?,
episode: Int,
season: Int?,
data: String,
apiName: String,
id: Int,
index: Int,
2021-06-26 19:32:50 +00:00
rating: Int?,
2021-11-30 17:59:52 +00:00
description: String?,
2021-09-19 22:36:32 +00:00
isFiller: Boolean?,
2021-06-15 16:07:20 +00:00
): ResultEpisode {
val posDur = getViewPos(id)
2021-06-26 19:32:50 +00:00
return ResultEpisode(
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,
2021-09-19 22:36:32 +00:00
isFiller
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
}
2021-05-16 18:28:00 +00:00
class ResultFragment : Fragment() {
2021-05-22 22:25:56 +00:00
companion object {
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 {
putString("url", url)
putString("apiName", apiName)
putInt("startAction", startAction)
putInt("startValue", startValue)
putBoolean("restart", true)
2021-05-18 13:43:32 +00:00
}
2021-09-20 21:11:36 +00:00
}
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
2021-11-05 21:39:56 +00:00
private val viewModel: ResultViewModel by activityViewModels()
2021-11-30 17:59:52 +00:00
private var allEpisodes: HashMap<Int, List<ExtractorLink>> = HashMap()
private var allEpisodesSubs: HashMap<Int, HashMap<String, SubtitleFile>> = HashMap()
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
2021-07-29 15:16:08 +00:00
var downloadButton: EasyDownloadButton? = 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? {
// viewModel =
// ViewModelProvider(activity ?: this).get(ResultViewModel::class.java)
2021-05-16 18:28:00 +00:00
return inflater.inflate(R.layout.fragment_result, container, false)
}
2021-07-28 19:14:45 +00:00
override fun onDestroyView() {
(result_episodes?.adapter as EpisodeAdapter?)?.killAdapter()
super.onDestroyView()
}
2021-05-22 22:25:56 +00:00
override fun onDestroy() {
//requireActivity().viewModelStore.clear() // REMEMBER THE CLEAR
2021-07-28 19:14:45 +00:00
downloadButton?.dispose()
2021-05-22 22:25:56 +00:00
super.onDestroy()
2021-06-16 00:15:07 +00:00
activity?.let {
it.window?.navigationBarColor =
2021-10-31 01:17:56 +00:00
it.colorFromAttribute(R.attr.primaryGrayBackground)
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()
if (result_bookmark_button?.context?.isTvSettings() == true) {
result_bookmark_button?.requestFocus()
}
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
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 updateSync(id: Int) {
val syncList = getSync(id, SyncApis.map { it.idPrefix }) ?: return
2021-12-13 18:41:33 +00:00
val list = ArrayList<Pair<SyncAPI, String>>()
for (i in 0 until SyncApis.count()) {
val res = syncList[i] ?: continue
list.add(Pair(SyncApis[i], res))
}
viewModel.updateSync(context, list)
}
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)
}
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
}
private fun setRecommendations(rec: List<SearchResponse>?) {
return
result_recommendations?.isGone = rec.isNullOrEmpty()
rec?.let { list ->
(result_recommendations?.adapter as SearchAdapter?)?.apply {
cardList = list
notifyDataSetChanged()
}
}
}
private fun fixGrid() {
activity?.getSpanCount()?.let { count ->
result_recommendations?.spanCount = count
}
}
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) {
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
}
}
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)
2021-12-13 18:41:33 +00:00
fixGrid()
2021-09-20 21:11:36 +00:00
val restart = arguments?.getBoolean("restart") ?: false
if (restart) {
arguments?.putBoolean("restart", false)
}
activity?.window?.decorView?.clearFocus()
hideKeyboard()
2021-05-18 13:43:32 +00:00
activity?.fixPaddingStatusbar(result_scroll)
2021-09-19 20:33:39 +00:00
//activity?.fixPaddingStatusbar(result_barstatus)
2021-06-06 18:06:01 +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
2021-06-16 16:54:07 +00:00
url = arguments?.getString("url")
2021-07-23 23:44:54 +00:00
val apiName = arguments?.getString("apiName") ?: return
2021-07-29 15:16:08 +00:00
startAction = arguments?.getInt("startAction") ?: START_ACTION_NORMAL
2021-08-25 15:28:25 +00:00
startValue = arguments?.getInt("startValue") ?: START_VALUE_NORMAL
2021-07-23 23:44:54 +00:00
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) {
media_route_button.setOnClickListener {
2021-09-02 13:19:50 +00:00
showToast(activity, R.string.no_chomecast_support_toast, Toast.LENGTH_LONG)
2021-07-23 23:44:54 +00:00
}
}
2021-07-30 21:03:46 +00:00
activity?.let {
if (it.isCastApiAvailable()) {
try {
CastButtonFactory.setUpMediaRouteButton(it, media_route_button)
val castContext = CastContext.getSharedInstance(it.applicationContext)
2021-10-22 13:23:48 +00:00
if (castContext.castState != CastState.NO_DEVICES_AVAILABLE) media_route_button.visibility =
VISIBLE
castContext.addCastStateListener { state ->
if (media_route_button != null) {
2021-12-17 12:42:25 +00:00
if (state == CastState.NO_DEVICES_AVAILABLE) media_route_button.visibility =
GONE else {
if (media_route_button.visibility == GONE) media_route_button.visibility =
VISIBLE
}
2021-07-30 21:03:46 +00:00
}
2021-07-23 23:44:54 +00:00
}
2021-10-22 13:23:48 +00:00
} catch (e: Exception) {
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()
}
result_poster_blur_holder?.translationY = -scrollY.toFloat()
})
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
2021-07-17 14:14:25 +00:00
fun handleAction(episodeClick: EpisodeClickEvent): Job = main {
2021-06-16 16:54:07 +00:00
//val id = episodeClick.data.id
val index = episodeClick.data.index
val buildInPlayer = true
currentLoadingCount++
2021-11-30 17:59:52 +00:00
var currentLinks: List<ExtractorLink>? = null
var currentSubs: HashMap<String, SubtitleFile>? = null
2021-07-17 14:14:25 +00:00
2021-09-02 13:19:50 +00:00
val showTitle =
2021-12-11 00:26:54 +00:00
episodeClick.data.name ?: context?.getString(R.string.episode_name_format)?.format(
2021-09-02 13:19:50 +00:00
getString(R.string.episode),
episodeClick.data.episode
)
2021-07-17 15:56:26 +00:00
suspend fun requireLinks(isCasting: Boolean): Boolean {
2021-07-17 14:14:25 +00:00
val currentLinksTemp =
if (allEpisodes.containsKey(episodeClick.data.id)) allEpisodes[episodeClick.data.id] else null
val currentSubsTemp =
2021-07-17 15:56:26 +00:00
if (allEpisodesSubs.containsKey(episodeClick.data.id)) allEpisodesSubs[episodeClick.data.id] else null
2021-12-10 19:48:21 +00:00
if (currentLinksTemp != null && currentLinksTemp.isNotEmpty()) {
2021-07-17 14:14:25 +00:00
currentLinks = currentLinksTemp
2021-07-17 15:56:26 +00:00
currentSubs = currentSubsTemp
2021-07-17 14:14:25 +00:00
return true
}
2021-08-06 20:55:11 +00:00
val skipLoading = getApiFromName(apiName).instantLinkLoading
2021-06-16 16:54:07 +00:00
2021-07-17 14:14:25 +00:00
var loadingDialog: AlertDialog? = null
val currentLoad = currentLoadingCount
2021-07-17 14:14:25 +00:00
if (!skipLoading) {
2021-12-17 12:42:25 +00:00
val builder =
AlertDialog.Builder(requireContext(), R.style.AlertDialogCustomTransparent)
2021-07-17 14:14:25 +00:00
val customLayout = layoutInflater.inflate(R.layout.dialog_loading, null)
builder.setView(customLayout)
2021-06-16 16:54:07 +00:00
2021-07-17 14:14:25 +00:00
loadingDialog = builder.create()
loadingDialog.show()
loadingDialog.setOnDismissListener {
currentLoadingCount++
2021-06-10 15:15:14 +00:00
}
2021-07-17 14:14:25 +00:00
}
2021-07-17 14:14:25 +00:00
val data = viewModel.loadEpisode(episodeClick.data, isCasting)
if (currentLoadingCount != currentLoad) return false
2021-12-12 02:33:17 +00:00
loadingDialog?.dismissSafe(activity)
2021-06-16 16:54:07 +00:00
2021-07-17 14:14:25 +00:00
when (data) {
is Resource.Success -> {
currentLinks = data.value.links
currentSubs = data.value.subs
return true
}
is Resource.Failure -> {
showToast(
activity,
R.string.error_loading_links_toast,
Toast.LENGTH_SHORT
)
2021-07-17 14:14:25 +00:00
}
else -> {
2021-07-17 14:14:25 +00:00
}
}
return false
}
fun acquireSingeExtractorLink(
links: List<ExtractorLink>,
title: String,
callback: (ExtractorLink) -> Unit
) {
2021-07-17 15:56:26 +00:00
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) {
acquireSingeExtractorLink(currentLinks ?: return, title, callback)
2021-07-17 15:56:26 +00:00
}
fun startChromecast(startIndex: Int) {
val eps = currentEpisodes ?: return
2021-09-30 12:55:56 +00:00
activity?.getCastSession()?.startCast(
2021-08-19 20:05:18 +00:00
apiName,
2021-07-17 15:56:26 +00:00
currentIsMovie ?: return,
currentHeaderName,
currentPoster,
episodeClick.data.index,
eps,
sortUrls(currentLinks ?: return),
2021-11-30 17:59:52 +00:00
currentSubs?.values?.toList() ?: emptyList(),
2021-07-17 15:56:26 +00:00
startTime = episodeClick.data.getRealPosition(),
startIndex = startIndex
)
}
fun startDownload(links: List<ExtractorLink>, subs: List<SubtitleFile>?) {
2021-07-17 15:56:26 +00:00
val isMovie = currentIsMovie ?: return
val titleName = sanitizeFilename(currentHeaderName ?: return)
val meta = VideoDownloadManager.DownloadEpisodeMetadata(
episodeClick.data.id,
titleName,
2021-07-25 14:25:09 +00:00
apiName,
2021-07-17 15:56:26 +00:00
episodeClick.data.poster ?: currentPoster,
episodeClick.data.name,
if (isMovie) null else episodeClick.data.season,
if (isMovie) null else episodeClick.data.episode
)
val folder = when (currentType) {
TvType.Anime -> "Anime/$titleName"
TvType.Movie -> "Movies"
2021-09-19 22:36:32 +00:00
TvType.AnimeMovie -> "Movies"
2021-07-17 15:56:26 +00:00
TvType.TvSeries -> "TVSeries/$titleName"
TvType.ONA -> "ONA"
2021-08-14 17:31:27 +00:00
TvType.Cartoon -> "Cartoons/$titleName"
2021-08-30 17:11:04 +00:00
TvType.Torrent -> "Torrent"
TvType.Documentary -> "Documentaries"
null -> null
2021-07-17 15:56:26 +00:00
}
context?.let { ctx ->
val parentId = currentId ?: return@let
val src = "$DOWNLOAD_NAVIGATE_TO/$parentId" // url ?: return@let
2021-07-17 15:56:26 +00:00
// SET VISUAL KEYS
ctx.setKey(
2021-08-25 15:28:25 +00:00
DOWNLOAD_HEADER_CACHE,
parentId.toString(),
2021-07-17 15:56:26 +00:00
VideoDownloadHelper.DownloadHeaderCached(
apiName,
url ?: return@let,
currentType ?: return@let,
currentHeaderName ?: return@let,
2021-08-30 17:11:04 +00:00
currentPoster,
2021-07-30 21:03:46 +00:00
currentId ?: return@let,
System.currentTimeMillis(),
2021-07-17 15:56:26 +00:00
)
)
val epData = episodeClick.data
ctx.setKey(
2021-07-23 23:44:54 +00:00
getFolderName(
DOWNLOAD_EPISODE_CACHE,
parentId.toString()
2021-07-23 23:44:54 +00:00
), // 3 deep folder for faster acess
2021-07-17 15:56:26 +00:00
epData.id.toString(),
VideoDownloadHelper.DownloadEpisodeCached(
epData.name,
epData.poster,
epData.episode,
epData.season,
epData.id,
parentId,
2021-07-17 15:56:26 +00:00
epData.rating,
epData.description,
2021-07-30 21:03:46 +00:00
System.currentTimeMillis(),
2021-07-17 15:56:26 +00:00
)
)
// DOWNLOAD VIDEO
VideoDownloadManager.downloadEpisodeUsingWorker(
ctx,
src,//url ?: return,
2021-07-17 15:56:26 +00:00
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()
main {
subs?.let { subsList ->
subsList.filter {
downloadList.contains(
SubtitleHelper.fromLanguageToTwoLetters(
it.lang,
true
)
)
}
.map { ExtractorSubtitleLink(it.lang, it.url, "") }
.forEach { link ->
2021-12-17 12:42:25 +00:00
val epName = meta.name
?: "${context?.getString(R.string.episode)} ${meta.episode}"
val fileName =
sanitizeFilename(epName + if (downloadList.size > 1) " ${link.name}" else "")
val topFolder = "$folder"
withContext(Dispatchers.IO) {
2021-10-22 13:23:48 +00:00
normalSafeApiCall {
VideoDownloadManager.downloadThing(
ctx,
link,
fileName,
topFolder,
"vtt",
false,
null
) {
// no notification
}
}
}
}
}
}
2021-07-17 15:56:26 +00:00
}
}
2021-07-17 14:14:25 +00:00
val isLoaded = when (episodeClick.action) {
ACTION_PLAY_EPISODE_IN_PLAYER -> true
2021-07-29 15:16:08 +00:00
ACTION_CLICK_DEFAULT -> true
ACTION_SHOW_TOAST -> true
2021-07-17 14:14:25 +00:00
ACTION_CHROME_CAST_EPISODE -> requireLinks(true)
ACTION_CHROME_CAST_MIRROR -> requireLinks(true)
2021-07-17 15:56:26 +00:00
else -> requireLinks(false)
2021-07-17 14:14:25 +00:00
}
if (!isLoaded) return@main // CANT LOAD
when (episodeClick.action) {
ACTION_SHOW_TOAST -> {
showToast(activity, R.string.play_episode_toast, Toast.LENGTH_SHORT)
}
2021-07-23 23:44:54 +00:00
ACTION_CLICK_DEFAULT -> {
context?.let { ctx ->
if (ctx.isConnectedToChromecast()) {
2021-12-17 12:42:25 +00:00
handleAction(
EpisodeClickEvent(
ACTION_CHROME_CAST_EPISODE,
episodeClick.data
)
)
2021-07-23 23:44:54 +00:00
} else {
2021-12-17 12:42:25 +00:00
handleAction(
EpisodeClickEvent(
ACTION_PLAY_EPISODE_IN_PLAYER,
episodeClick.data
)
)
2021-07-23 23:44:54 +00:00
}
}
}
2021-07-17 14:14:25 +00:00
ACTION_SHOW_OPTIONS -> {
2021-09-12 15:57:07 +00:00
context?.let { ctx ->
val builder = AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
var dialog: AlertDialog? = null
builder.setTitle(showTitle)
2021-12-17 12:42:25 +00:00
val options =
requireContext().resources.getStringArray(R.array.episode_long_click_options)
2021-09-12 15:57:07 +00:00
val optionsValues =
requireContext().resources.getIntArray(R.array.episode_long_click_options_values)
val verifiedOptions = ArrayList<String>()
val verifiedOptionsValues = ArrayList<Int>()
val hasDownloadSupport = api.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 -> hasDownloadSupport
ACTION_DOWNLOAD_MIRROR -> hasDownloadSupport
2021-12-17 12:42:25 +00:00
ACTION_PLAY_EPISODE_IN_VLC_PLAYER -> context?.isAppInstalled(
VLC_PACKAGE
) ?: false
2021-09-12 15:57:07 +00:00
else -> true
}
if (add) {
verifiedOptions.add(op)
verifiedOptionsValues.add(opv)
}
2021-07-17 14:14:25 +00:00
}
2021-09-12 15:57:07 +00:00
builder.setItems(
verifiedOptions.toTypedArray()
) { _, which ->
2021-12-17 12:42:25 +00:00
handleAction(
EpisodeClickEvent(
verifiedOptionsValues[which],
episodeClick.data
)
)
2021-12-12 02:33:17 +00:00
dialog?.dismissSafe(activity)
2021-06-16 16:54:07 +00:00
}
2021-07-17 14:14:25 +00:00
2021-09-12 15:57:07 +00:00
dialog = builder.create()
dialog.show()
2021-07-17 14:14:25 +00:00
}
}
2021-07-17 15:56:26 +00:00
ACTION_COPY_LINK -> {
2021-09-12 15:57:07 +00:00
activity?.let { act ->
2021-12-12 02:33:17 +00:00
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)
2021-09-12 15:57:07 +00:00
}
2021-07-17 15:56:26 +00:00
}
}
ACTION_PLAY_EPISODE_IN_BROWSER -> {
2021-09-02 13:19:50 +00:00
acquireSingeExtractorLink(getString(R.string.episode_action_play_in_browser)) { link ->
2021-07-23 23:44:54 +00:00
val i = Intent(ACTION_VIEW)
2021-07-17 15:56:26 +00:00
i.data = Uri.parse(link.url)
startActivity(i)
}
}
2021-07-17 14:14:25 +00:00
2021-07-17 15:56:26 +00:00
ACTION_CHROME_CAST_MIRROR -> {
2021-09-02 13:19:50 +00:00
acquireSingeExtractorLink(getString(R.string.episode_action_chomecast_mirror)) { link ->
2021-07-17 15:56:26 +00:00
val mirrorIndex = currentLinks?.indexOf(link) ?: -1
startChromecast(if (mirrorIndex == -1) 0 else mirrorIndex)
}
}
2021-07-17 14:14:25 +00:00
ACTION_CHROME_CAST_EPISODE -> {
2021-07-17 15:56:26 +00:00
startChromecast(0)
}
2021-07-17 14:14:25 +00:00
2021-07-17 21:36:50 +00:00
ACTION_PLAY_EPISODE_IN_VLC_PLAYER -> {
2021-07-30 21:03:46 +00:00
activity?.let { act ->
2021-12-12 02:33:17 +00:00
try {
if (!act.checkWrite()) {
act.requestRW()
if (act.checkWrite()) return@main
}
val data = currentLinks ?: return@main
val subs = currentSubs
2021-07-30 21:03:46 +00:00
2021-12-12 02:33:17 +00:00
val outputDir = act.cacheDir
val outputFile = withContext(Dispatchers.IO) {
File.createTempFile("mirrorlist", ".m3u8", outputDir)
2021-07-30 21:03:46 +00:00
}
2021-12-12 02:33:17 +00:00
var text = "#EXTM3U"
if (subs != null) {
for (sub in subs.values) {
text += "\n#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"${sub.lang}\",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE=\"${sub.lang}\",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/*"
)
2021-07-17 15:56:26 +00:00
2021-12-12 02:33:17 +00:00
val startId = VLC_FROM_PROGRESS
2021-07-17 15:56:26 +00:00
2021-12-12 02:33:17 +00:00
var position = startId
if (startId == VLC_FROM_START) {
position = 1
} else if (startId == VLC_FROM_PROGRESS) {
position = 0
}
2021-07-17 15:56:26 +00:00
2021-12-12 02:33:17 +00:00
vlcIntent.putExtra("position", position)
2021-07-17 15:56:26 +00:00
2021-12-12 02:33:17 +00:00
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)
}
2021-07-30 21:03:46 +00:00
}
2021-06-16 16:54:07 +00:00
}
2021-06-10 15:15:14 +00:00
2021-06-16 16:54:07 +00:00
ACTION_PLAY_EPISODE_IN_PLAYER -> {
if (buildInPlayer) {
2021-09-20 21:11:36 +00:00
activity.navigate(
R.id.global_to_navigation_player, PlayerFragment.newInstance(
PlayerData(index, null, 0),
episodeClick.data.getRealPosition()
)
)
2021-06-16 16:54:07 +00:00
}
2021-05-23 17:07:43 +00:00
}
2021-07-17 15:56:26 +00:00
2021-06-16 16:54:07 +00:00
ACTION_RELOAD_EPISODE -> {
2021-07-17 14:14:25 +00:00
viewModel.loadEpisode(episodeClick.data, false)
2021-06-16 16:54:07 +00:00
}
2021-07-17 14:14:25 +00:00
2021-07-17 15:56:26 +00:00
ACTION_DOWNLOAD_EPISODE -> {
2021-12-17 12:42:25 +00:00
startDownload(
currentLinks ?: return@main,
currentSubs?.values?.toList() ?: emptyList()
)
2021-07-17 15:56:26 +00:00
}
2021-07-17 14:14:25 +00:00
2021-07-17 15:56:26 +00:00
ACTION_DOWNLOAD_MIRROR -> {
2021-09-02 13:19:50 +00:00
currentLinks?.let { links ->
acquireSingeExtractorLink(
links,//(currentLinks ?: return@main).filter { !it.isM3u8 },
getString(R.string.episode_action_download_mirror)
) { link ->
2021-12-17 12:42:25 +00:00
startDownload(
listOf(link),
currentSubs?.values?.toList() ?: emptyList()
)
2021-09-02 13:19:50 +00:00
}
2021-06-29 23:14:48 +00:00
}
}
2021-06-16 16:54:07 +00:00
}
}
2021-07-17 14:14:25 +00:00
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
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-05-23 17:07:43 +00:00
result_episodes.adapter = adapter
result_episodes.layoutManager = GridLayoutManager(context, 1)
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
) {
context?.let { localContext ->
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
{}) {
viewModel.updateWatchStatus(WatchType.values()[it])
2021-12-10 19:48:21 +00:00
}
}
2021-06-15 23:25:58 +00:00
}
2021-07-29 15:16:08 +00:00
observe(viewModel.episodes) { episodeList ->
lateFixDownloadButton(episodeList.size <= 1) // movies can have multible parts but still be *movies* this will fix this
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) {
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 -> {
for (ep in episodeList) {
if (ep.id == startValue) { // watched too much
handleAction(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, ep))
break
}
}
}
2021-07-29 15:16:08 +00:00
else -> {
}
}
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
}
2021-05-20 20:56:21 +00:00
observe(viewModel.allEpisodes) {
allEpisodes = it
}
2021-07-17 14:14:25 +00:00
observe(viewModel.allEpisodesSubs) {
allEpisodesSubs = it
}
2021-06-26 22:15:19 +00:00
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
result_season_button?.setOnClickListener {
2021-07-25 20:50:16 +00:00
result_season_button?.popupMenuNoIconsAndNoStringRes(
2021-06-26 22:15:19 +00:00
items = seasonList
.map { Pair(it ?: -2, fromIndexToSeasonText(it)) },
) {
val id = this.itemId
viewModel.changeSeason(if (id == -2) null else id)
2021-06-26 22:15:19 +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
(result_episodes?.adapter as EpisodeAdapter?)?.cardList = episodes.value
(result_episodes?.adapter as EpisodeAdapter?)?.updateLayout()
(result_episodes?.adapter as EpisodeAdapter?)?.notifyDataSetChanged()
}
}
2021-05-22 22:25:56 +00:00
}
2021-11-02 15:09:29 +00:00
observe(viewModel.dubStatus) { status ->
result_dub_select?.text = status.toString()
}
observe(viewModel.dubSubSelections) { range ->
dubRange = range
result_dub_select?.visibility = if (range.size <= 1) GONE else VISIBLE
}
result_dub_select.setOnClickListener {
val ranges = dubRange
if (ranges != null) {
2021-12-17 12:42:25 +00:00
it.popupMenuNoIconsAndNoStringRes(ranges.map { status ->
Pair(
status.ordinal,
status.toString()
)
}
2021-11-02 15:09:29 +00:00
.toList()) {
viewModel.changeDubStatus(DubStatus.values()[itemId])
2021-11-02 15:09:29 +00:00
}
}
}
2021-07-25 20:50:16 +00:00
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
}
result_episode_select.setOnClickListener {
val ranges = episodeRanges
if (ranges != null) {
2021-12-17 12:42:25 +00:00
it.popupMenuNoIconsAndNoStringRes(ranges.mapIndexed { index, s -> Pair(index, s) }
.toList()) {
viewModel.changeRange(itemId)
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
}
2021-12-13 18:41:33 +00:00
observe(viewModel.sync) { sync ->
for (s in sync) {
when (s) {
is Resource.Success -> {
val d = s.value ?: continue
setDuration(d.duration)
setRating(d.publicScore)
}
else -> {
}
}
}
}
2021-05-18 13:43:32 +00:00
observe(viewModel.resultResponse) { data ->
when (data) {
is Resource.Success -> {
val d = data.value
if (d is LoadResponse) {
2021-09-19 22:36:32 +00:00
if (d !is AnimeLoadResponse && result_episode_loading.isVisible) { // no episode loading when not anime
result_episode_loading.isVisible = false
}
2021-06-16 16:54:07 +00:00
updateVisStatus(2)
2021-09-01 13:16:49 +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 -> ""
}
2021-12-13 18:41:33 +00:00
result_vpn?.isGone = api.vpnStatus == VPNStatus.None
result_info?.text = when (api.providerType) {
ProviderType.MetaProvider -> getString(R.string.provider_info_meta)
else -> ""
}
result_info?.isVisible = api.providerType == ProviderType.MetaProvider
2021-06-14 00:00:29 +00:00
currentHeaderName = d.name
2021-07-04 00:59:51 +00:00
currentType = d.type
2021-06-14 00:00:29 +00:00
2021-06-10 15:15:14 +00:00
currentPoster = d.posterUrl
currentIsMovie = !d.isEpisodeBased()
2021-06-10 15:15:14 +00:00
2021-09-01 13:16:49 +00:00
result_openinbrower?.setOnClickListener {
2021-07-23 23:44:54 +00:00
val i = Intent(ACTION_VIEW)
2021-06-10 15:15:14 +00:00
i.data = Uri.parse(d.url)
2021-08-29 17:15:09 +00:00
try {
startActivity(i)
2021-08-30 17:11:04 +00:00
} catch (e: Exception) {
2021-08-29 17:15:09 +00:00
e.printStackTrace()
}
2021-06-10 15:15:14 +00:00
}
2021-11-20 00:41:37 +00:00
result_search?.setOnClickListener {
2021-12-13 18:41:33 +00:00
QuickSearchFragment.pushSearch(activity, d.name)
2021-11-20 00:41:37 +00:00
}
2021-09-01 13:16:49 +00:00
result_share?.setOnClickListener {
2021-07-23 23:44:54 +00:00
val i = Intent(ACTION_SEND)
2021-06-10 15:15:14 +00:00
i.type = "text/plain"
2021-07-23 23:44:54 +00:00
i.putExtra(EXTRA_SUBJECT, d.name)
i.putExtra(EXTRA_TEXT, d.url)
startActivity(createChooser(i, d.name))
2021-06-10 15:15:14 +00:00
}
2021-12-13 18:41:33 +00:00
updateSync(d.getId())
result_add_sync?.setOnClickListener {
QuickSearchFragment.pushSync(activity, d.name) { click ->
addSync(d.getId(), click.card.apiName, click.card.url)
showToast(
activity,
2021-12-17 12:42:25 +00:00
context?.getString(R.string.added_sync_format)
?.format(click.card.name),
Toast.LENGTH_SHORT
)
2021-12-13 18:41:33 +00:00
updateSync(d.getId())
}
}
2021-09-02 13:19:50 +00:00
val metadataInfoArray = ArrayList<Pair<Int, String>>()
2021-06-26 17:03:22 +00:00
if (d is AnimeLoadResponse) {
val status = when (d.showStatus) {
null -> null
2021-09-02 13:19:50 +00:00
ShowStatus.Ongoing -> R.string.status_ongoing
ShowStatus.Completed -> R.string.status_completed
2021-06-26 17:03:22 +00:00
}
if (status != null) {
2021-09-02 13:19:50 +00:00
metadataInfoArray.add(Pair(R.string.status, getString(status)))
2021-06-26 17:03:22 +00:00
}
}
2021-12-13 18:41:33 +00:00
setDuration(d.duration)
setYear(d.year)
setRating(d.rating)
setRecommendations(d.recommendations)
2021-05-18 13:43:32 +00:00
result_meta_site?.text = d.apiName
2021-10-31 01:17:56 +00:00
2021-08-30 17:11:04 +00:00
result_poster?.setImage(d.posterUrl)
result_poster_blur?.setImageBlur(d.posterUrl, 10, 3)
2021-12-17 12:42:25 +00:00
result_poster_holder?.visibility =
if (d.posterUrl.isNullOrBlank()) GONE else VISIBLE
2021-05-20 20:56:21 +00:00
2021-08-30 17:11:04 +00:00
result_play_movie?.text =
2021-12-17 12:42:25 +00:00
if (d.type == TvType.Torrent) getString(R.string.play_torrent_button) else getString(
R.string.play_movie_button
)
//result_plot_header?.text =
// if (d.type == TvType.Torrent) getString(R.string.torrent_plot) else getString(R.string.result_plot)
2021-09-02 22:27:22 +00:00
if (!d.plot.isNullOrEmpty()) {
2021-05-22 22:25:56 +00:00
var syno = d.plot!!
if (syno.length > MAX_SYNO_LENGH) {
syno = syno.substring(0, MAX_SYNO_LENGH) + "..."
2021-05-18 13:43:32 +00:00
}
2021-05-22 22:25:56 +00:00
result_descript.setOnClickListener {
2021-12-17 12:42:25 +00:00
val builder: AlertDialog.Builder =
AlertDialog.Builder(requireContext())
2021-09-12 15:57:07 +00:00
builder.setMessage(d.plot)
.setTitle(if (d.type == TvType.Torrent) R.string.torrent_plot else R.string.result_plot)
2021-05-22 22:25:56 +00:00
.show()
2021-05-18 13:43:32 +00:00
}
2021-05-22 22:25:56 +00:00
result_descript.text = syno
2021-05-18 13:43:32 +00:00
} else {
2021-08-30 17:11:04 +00:00
result_descript.text =
2021-12-17 12:42:25 +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
}
2021-09-02 22:27:22 +00:00
result_tag?.removeAllViews()
//result_tag_holder?.visibility = GONE
2021-06-26 17:03:22 +00:00
// result_status.visibility = GONE
2021-06-06 18:06:01 +00:00
2021-06-26 14:44:53 +00:00
val tags = d.tags
2021-09-02 22:27:22 +00:00
if (tags.isNullOrEmpty()) {
//result_tag_holder?.visibility = GONE
2021-06-26 14:44:53 +00:00
} else {
//result_tag_holder?.visibility = VISIBLE
2021-06-26 14:44:53 +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
2021-09-02 22:27:22 +00:00
result_tag?.addView(viewBtt, index)
2021-06-26 14:44:53 +00:00
}
}
2021-08-14 19:35:26 +00:00
if (d.type.isMovieType()) {
2021-07-25 20:50:16 +00:00
val hasDownloadSupport = api.hasDownloadSupport
2021-08-11 18:26:19 +00:00
lateFixDownloadButton(true)
2021-07-23 23:44:54 +00:00
2021-09-02 22:27:22 +00:00
result_play_movie?.setOnClickListener {
2021-12-17 12:42:25 +00:00
val card =
currentEpisodes?.firstOrNull() ?: return@setOnClickListener
2021-07-23 23:44:54 +00:00
handleAction(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card))
2021-06-16 16:54:07 +00:00
}
2021-07-25 16:08:34 +00:00
2021-09-02 22:27:22 +00:00
result_play_movie?.setOnLongClickListener {
2021-12-17 12:42:25 +00:00
val card = currentEpisodes?.firstOrNull()
?: return@setOnLongClickListener true
2021-07-23 23:44:54 +00:00
handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
2021-07-25 16:08:34 +00:00
return@setOnLongClickListener true
}
2021-09-19 20:33:39 +00:00
2021-11-30 17:59:52 +00:00
result_download_movie?.setOnLongClickListener {
2021-12-17 12:42:25 +00:00
val card = currentEpisodes?.firstOrNull()
?: return@setOnLongClickListener true
2021-11-30 17:59:52 +00:00
handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
return@setOnLongClickListener true
}
2021-07-25 16:08:34 +00:00
// result_options.setOnClickListener {
// val card = currentEpisodes?.first() ?: return@setOnClickListener
// handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
// }
2021-12-17 12:42:25 +00:00
result_download_movie?.visibility =
if (hasDownloadSupport) VISIBLE else GONE
2021-07-25 20:50:16 +00:00
if (hasDownloadSupport) {
val localId = d.getId()
val file =
2021-12-17 12:42:25 +00:00
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
requireContext(),
localId
)
2021-07-28 19:14:45 +00:00
downloadButton?.dispose()
downloadButton = EasyDownloadButton()
downloadButton?.setUpMaterialButton(
2021-07-25 20:50:16 +00:00
file?.fileLength,
file?.totalBytes,
result_movie_progress_downloaded,
result_download_movie,
result_movie_text_progress,
VideoDownloadHelper.DownloadEpisodeCached(
d.name,
d.posterUrl,
0,
null,
localId,
localId,
d.rating,
2021-07-30 21:03:46 +00:00
d.plot,
System.currentTimeMillis(),
2021-07-25 20:50:16 +00:00
)
) { downloadClickEvent ->
if (downloadClickEvent.action == DOWNLOAD_ACTION_DOWNLOAD) {
2021-09-01 12:02:32 +00:00
currentEpisodes?.firstOrNull()?.let { episode ->
2021-08-11 18:26:19 +00:00
handleAction(
EpisodeClickEvent(
ACTION_DOWNLOAD_EPISODE,
ResultEpisode(
d.name,
null,
0,
null,
episode.data,
d.apiName,
localId,
0,
0L,
0L,
null,
2021-09-19 22:36:32 +00:00
null,
null,
2021-08-11 18:26:19 +00:00
)
2021-07-25 20:50:16 +00:00
)
2021-07-25 16:08:34 +00:00
)
2021-08-11 18:26:19 +00:00
}
2021-07-25 20:50:16 +00:00
} else {
2021-12-17 12:42:25 +00:00
handleDownloadClick(
activity,
currentHeaderName,
downloadClickEvent
)
2021-07-25 20:50:16 +00:00
}
2021-07-25 16:08:34 +00:00
}
2021-06-16 16:54:07 +00:00
}
2021-07-23 23:44:54 +00:00
} else {
2021-08-11 18:26:19 +00:00
lateFixDownloadButton(false)
2021-06-16 16:54:07 +00:00
}
2021-05-22 22:25:56 +00:00
when (d) {
is AnimeLoadResponse -> {
2021-06-06 18:06:01 +00:00
// val preferEnglish = true
//val titleName = (if (preferEnglish) d.engName else d.japName) ?: d.name
val titleName = d.name
2021-05-22 22:25:56 +00:00
result_title.text = titleName
2021-09-19 20:33:39 +00:00
//result_toolbar.title = titleName
2021-05-22 22:25:56 +00:00
}
else -> result_title.text = d.name
2021-05-18 13:43:32 +00:00
}
2021-06-16 16:54:07 +00:00
} else {
updateVisStatus(1)
2021-05-18 13:43:32 +00:00
}
}
is Resource.Failure -> {
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
}
}
}
2021-12-13 18:41:33 +00:00
val recAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? = activity?.let {
SearchAdapter(
ArrayList(),
result_recommendations,
) { callback ->
SearchHelper.handleSearchClickCallback(activity, callback)
}
}
result_recommendations.adapter = recAdapter
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 =
settingsManager.getBoolean(ctx.getString(R.string.show_fillers_key), true)
2021-06-16 16:54:07 +00:00
2021-09-19 22:36:32 +00:00
val tempUrl = url
if (tempUrl != null) {
result_reload_connectionerror.setOnClickListener {
viewModel.load(tempUrl, apiName, showFillers)
2021-08-29 17:15:09 +00:00
}
2021-06-16 16:54:07 +00:00
result_reload_connection_open_in_browser?.setOnClickListener {
val i = Intent(ACTION_VIEW)
i.data = Uri.parse(tempUrl)
try {
startActivity(i)
} catch (e: Exception) {
e.printStackTrace()
}
}
result_meta_site?.setOnClickListener {
it.context?.openBrowser(tempUrl)
2021-09-19 22:36:32 +00:00
}
2021-09-20 21:11:36 +00:00
if (restart || viewModel.resultResponse.value == null) {
2021-11-05 21:39:56 +00:00
viewModel.clear()
viewModel.load(tempUrl, apiName, showFillers)
2021-09-12 15:57:07 +00:00
}
}
2021-06-16 16:54:07 +00:00
}
2021-05-16 18:28:00 +00:00
}
}