mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
result -> result specific
This commit is contained in:
parent
d5c42f7d5a
commit
03d50a943a
14 changed files with 704 additions and 680 deletions
|
@ -223,7 +223,7 @@ dependencies {
|
|||
//implementation("com.github.HaarigerHarald:android-youtubeExtractor:master-SNAPSHOT")
|
||||
|
||||
// newpipe yt taken from https://github.com/TeamNewPipe/NewPipe/blob/dev/app/build.gradle#L204
|
||||
implementation("com.github.TeamNewPipe:NewPipeExtractor:master-SNAPSHOT")
|
||||
implementation("com.github.TeamNewPipe:NewPipeExtractor:8495ad619e")
|
||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.6")
|
||||
|
||||
// Library/extensions searching with Levenshtein distance
|
||||
|
|
|
@ -361,14 +361,11 @@ class HomeFragment : Fragment() {
|
|||
?.toMutableList()
|
||||
?: mutableListOf(TvType.Movie, TvType.TvSeries)
|
||||
|
||||
val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
|
||||
val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt)
|
||||
|
||||
cancelBtt?.setOnClickListener {
|
||||
binding.cancelBtt.setOnClickListener {
|
||||
dialog.dismissSafe()
|
||||
}
|
||||
|
||||
applyBtt?.setOnClickListener {
|
||||
binding.applyBtt.setOnClickListener {
|
||||
if (currentApiName != selectedApiName) {
|
||||
currentApiName?.let(callback)
|
||||
}
|
||||
|
@ -493,15 +490,54 @@ class HomeFragment : Fragment() {
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
fixGrid()
|
||||
|
||||
binding?.homeChangeApiLoading?.setOnClickListener(apiChangeClickListener)
|
||||
binding?.homeChangeApiLoading?.setOnClickListener(apiChangeClickListener)
|
||||
binding?.homeApiFab?.setOnClickListener(apiChangeClickListener)
|
||||
binding?.homeRandom?.setOnClickListener {
|
||||
if (listHomepageItems.isNotEmpty()) {
|
||||
activity.loadSearchResult(listHomepageItems.random())
|
||||
binding?.apply {
|
||||
homeChangeApiLoading.setOnClickListener(apiChangeClickListener)
|
||||
//homeChangeApiLoading.setOnClickListener(apiChangeClickListener)
|
||||
homeApiFab.setOnClickListener(apiChangeClickListener)
|
||||
homeRandom.setOnClickListener {
|
||||
if (listHomepageItems.isNotEmpty()) {
|
||||
activity.loadSearchResult(listHomepageItems.random())
|
||||
}
|
||||
}
|
||||
|
||||
homeMasterRecycler.adapter =
|
||||
HomeParentItemAdapterPreview(
|
||||
mutableListOf(),
|
||||
homeViewModel
|
||||
)
|
||||
fixPaddingStatusbar(homeLoadingStatusbar)
|
||||
|
||||
if (isTvSettings()) {
|
||||
homeApiFab.isVisible = false
|
||||
if (isTrueTvSettings()) {
|
||||
homeChangeApiLoading.isVisible = true
|
||||
homeChangeApiLoading.isFocusable = true
|
||||
homeChangeApiLoading.isFocusableInTouchMode = true
|
||||
}
|
||||
// home_bookmark_select?.isFocusable = true
|
||||
// home_bookmark_select?.isFocusableInTouchMode = true
|
||||
} else {
|
||||
homeApiFab.isVisible = true
|
||||
homeChangeApiLoading.isVisible = false
|
||||
}
|
||||
|
||||
homeMasterRecycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
if (dy > 0) { //check for scroll down
|
||||
homeApiFab.shrink() // hide
|
||||
homeRandom.shrink()
|
||||
} else if (dy < -5) {
|
||||
if (!isTvSettings()) {
|
||||
homeApiFab.extend() // show
|
||||
homeRandom.extend()
|
||||
}
|
||||
}
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//Load value for toggling Random button. Hide at startup
|
||||
context?.let {
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(it)
|
||||
|
@ -551,13 +587,9 @@ class HomeFragment : Fragment() {
|
|||
}
|
||||
|
||||
is Resource.Failure -> {
|
||||
|
||||
homeLoadingShimmer.stopShimmer()
|
||||
|
||||
resultErrorText.text = data.errorString
|
||||
|
||||
homeReloadConnectionerror.setOnClickListener(apiChangeClickListener)
|
||||
|
||||
homeReloadConnectionOpenInBrowser.setOnClickListener { view ->
|
||||
val validAPIs = apis//.filter { api -> api.hasMainPage }
|
||||
|
||||
|
@ -598,7 +630,6 @@ class HomeFragment : Fragment() {
|
|||
|
||||
//context?.fixPaddingStatusbarView(home_statusbar)
|
||||
//context?.fixPaddingStatusbar(home_padding)
|
||||
fixPaddingStatusbar(binding?.homeLoadingStatusbar)
|
||||
|
||||
observeNullable(homeViewModel.popup) { item ->
|
||||
if (item == null) {
|
||||
|
@ -620,52 +651,13 @@ class HomeFragment : Fragment() {
|
|||
})
|
||||
}
|
||||
|
||||
binding?.homeMasterRecycler?.adapter =
|
||||
HomeParentItemAdapterPreview(
|
||||
mutableListOf(),
|
||||
homeViewModel
|
||||
)
|
||||
|
||||
homeViewModel.reloadStored()
|
||||
//loadHomePage(false)
|
||||
binding?.homeMasterRecycler?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
|
||||
binding?.apply {
|
||||
if (dy > 0) { //check for scroll down
|
||||
homeApiFab.shrink() // hide
|
||||
homeRandom.shrink()
|
||||
} else if (dy < -5) {
|
||||
if (!isTvSettings()) {
|
||||
homeApiFab.extend() // show
|
||||
homeRandom.extend()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
}
|
||||
})
|
||||
|
||||
// nice profile pic on homepage
|
||||
//home_profile_picture_holder?.isVisible = false
|
||||
// just in case
|
||||
binding?.apply {
|
||||
if (isTvSettings()) {
|
||||
homeApiFab.isVisible = false
|
||||
if (isTrueTvSettings()) {
|
||||
homeChangeApiLoading.isVisible = true
|
||||
homeChangeApiLoading.isFocusable = true
|
||||
homeChangeApiLoading.isFocusableInTouchMode = true
|
||||
}
|
||||
// home_bookmark_select?.isFocusable = true
|
||||
// home_bookmark_select?.isFocusableInTouchMode = true
|
||||
} else {
|
||||
homeApiFab.isVisible = true
|
||||
homeChangeApiLoading.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
//TODO READD THIS
|
||||
/*for (syncApi in OAuth2Apis) {
|
||||
val login = syncApi.loginInfo()
|
||||
|
|
|
@ -401,7 +401,7 @@ class HomeParentItemAdapterPreview(
|
|||
observe(viewModel.bookmarks) {
|
||||
updateBookmarks(it)
|
||||
}
|
||||
observe(viewModel.availableWatchStatusTypes) { (visible, checked) ->
|
||||
observe(viewModel.availableWatchStatusTypes) { (checked, visible) ->
|
||||
for ((chip, watch) in toggleList) {
|
||||
chip.apply {
|
||||
isVisible = visible.contains(watch)
|
||||
|
|
|
@ -74,15 +74,15 @@ abstract class AbstractPlayerFragment(
|
|||
var isBuffering = true
|
||||
protected open var hasPipModeSupport = true
|
||||
|
||||
lateinit var playerPausePlayHolderHolder : FrameLayout
|
||||
lateinit var playerPausePlay : ImageView
|
||||
lateinit var playerBuffering : ProgressBar
|
||||
var playerPausePlayHolderHolder : FrameLayout? = null
|
||||
var playerPausePlay : ImageView? = null
|
||||
var playerBuffering : ProgressBar? = null
|
||||
var playerView : PlayerView? = null
|
||||
var piphide : FrameLayout? = null
|
||||
var subtitleHolder : FrameLayout? = null
|
||||
|
||||
@LayoutRes
|
||||
protected var layout: Int = R.layout.fragment_player
|
||||
protected open var layout: Int = R.layout.fragment_player
|
||||
|
||||
open fun nextEpisode() {
|
||||
throw NotImplementedError()
|
||||
|
@ -141,15 +141,15 @@ abstract class AbstractPlayerFragment(
|
|||
|
||||
isBuffering = CSPlayerLoading.IsBuffering == isPlaying
|
||||
if (isBuffering) {
|
||||
playerPausePlayHolderHolder.isVisible = false
|
||||
playerBuffering.isVisible = true
|
||||
playerPausePlayHolderHolder?.isVisible = false
|
||||
playerBuffering?.isVisible = true
|
||||
} else {
|
||||
playerPausePlayHolderHolder.isVisible = true
|
||||
playerBuffering.isVisible = false
|
||||
playerPausePlayHolderHolder?.isVisible = true
|
||||
playerBuffering?.isVisible = false
|
||||
|
||||
if (wasPlaying != isPlaying) {
|
||||
playerPausePlay.setImageResource(if (isPlayingRightNow) R.drawable.play_to_pause else R.drawable.pause_to_play)
|
||||
val drawable = playerPausePlay.drawable
|
||||
playerPausePlay?.setImageResource(if (isPlayingRightNow) R.drawable.play_to_pause else R.drawable.pause_to_play)
|
||||
val drawable = playerPausePlay?.drawable
|
||||
|
||||
var startedAnimation = false
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
||||
|
@ -171,10 +171,10 @@ abstract class AbstractPlayerFragment(
|
|||
|
||||
// somehow the phone is wacked
|
||||
if (!startedAnimation) {
|
||||
playerPausePlay.setImageResource(if (isPlayingRightNow) R.drawable.netflix_pause else R.drawable.netflix_play)
|
||||
playerPausePlay?.setImageResource(if (isPlayingRightNow) R.drawable.netflix_pause else R.drawable.netflix_play)
|
||||
}
|
||||
} else {
|
||||
playerPausePlay.setImageResource(if (isPlayingRightNow) R.drawable.netflix_pause else R.drawable.netflix_play)
|
||||
playerPausePlay?.setImageResource(if (isPlayingRightNow) R.drawable.netflix_pause else R.drawable.netflix_play)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
|
@ -22,18 +21,16 @@ import com.google.android.material.chip.ChipDrawable
|
|||
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
||||
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
||||
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.DubStatus
|
||||
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.SearchResponse
|
||||
import com.lagradost.cloudstream3.TvType
|
||||
import com.lagradost.cloudstream3.mvvm.*
|
||||
import com.lagradost.cloudstream3.services.SubscriptionWorkManager
|
||||
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
|
||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
||||
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
||||
import com.lagradost.cloudstream3.ui.player.FullScreenPlayer
|
||||
import com.lagradost.cloudstream3.ui.result.EpisodeAdapter.Companion.getPlayerAction
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
|
@ -47,7 +44,6 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.getVideoWatchState
|
|||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
||||
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.download_button
|
||||
import kotlinx.android.synthetic.main.fragment_result.result_cast_items
|
||||
|
@ -89,10 +85,8 @@ 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.result_sync.*
|
||||
import kotlinx.android.synthetic.main.trailer_custom_layout.*
|
||||
import kotlinx.android.synthetic.main.fragment_result_tv.result_resume_series_button_play
|
||||
import kotlinx.android.synthetic.main.fragment_result_tv.temporary_no_focus
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
|
@ -194,7 +188,7 @@ fun ResultEpisode.getWatchProgress(): Float {
|
|||
return (getDisplayPosition() / 1000).toFloat() / (duration / 1000).toFloat()
|
||||
}
|
||||
|
||||
open class ResultFragment : ResultTrailerPlayer() {
|
||||
open class ResultFragment : FullScreenPlayer() {
|
||||
companion object {
|
||||
const val URL_BUNDLE = "url"
|
||||
const val API_NAME_BUNDLE = "apiName"
|
||||
|
@ -251,7 +245,9 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
|
||||
protected lateinit var viewModel: ResultViewModel2 //by activityViewModels()
|
||||
protected lateinit var syncModel: SyncViewModel
|
||||
protected open val resultLayout = R.layout.fragment_result_swipe
|
||||
//protected open val resultLayout = R.layout.fragment_result_swipe
|
||||
|
||||
override var layout = R.layout.fragment_result_swipe
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
@ -263,7 +259,8 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
syncModel =
|
||||
ViewModelProvider(this)[SyncViewModel::class.java]
|
||||
|
||||
return inflater.inflate(resultLayout, container, false)
|
||||
return super.onCreateView(inflater, container, savedInstanceState)
|
||||
//return inflater.inflate(resultLayout, container, false)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -285,167 +282,12 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
super.onDestroy()
|
||||
}
|
||||
|
||||
/// 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 = isTrueTvSettings()
|
||||
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<SearchResponse>?, validApiName: String?) {
|
||||
|
||||
}
|
||||
|
||||
private fun updateUI() {
|
||||
syncModel.updateUserData()
|
||||
viewModel.reloadEpisodes()
|
||||
}
|
||||
|
||||
open fun updateMovie(data: Resource<Pair<UiText, ResultEpisode>>?) {
|
||||
when (data) {
|
||||
is Resource.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
|
||||
}
|
||||
|
||||
val show =
|
||||
viewModel.currentRepo?.api?.hasDownloadSupport == true && !isTvSettings()
|
||||
if (show) {
|
||||
download_button?.setDefaultClickListener(
|
||||
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(click)
|
||||
}
|
||||
}
|
||||
}
|
||||
download_button?.isVisible = show
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
download_button?.isVisible = false
|
||||
result_play_movie?.isVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open fun updateEpisodes(episodes: Resource<List<ResultEpisode>>?) {
|
||||
when (episodes) {
|
||||
is Resource.Loading -> {
|
||||
result_episode_loading?.isVisible = true
|
||||
result_episodes?.isVisible = false
|
||||
}
|
||||
|
||||
is Resource.Success -> {
|
||||
result_episodes?.isVisible = true
|
||||
result_episode_loading?.isVisible = false
|
||||
|
||||
/*
|
||||
* Okay so what is this fuckery?
|
||||
* Basically Android TV will crash if you request a new focus while
|
||||
* the adapter gets updated.
|
||||
*
|
||||
* This means that if you load thumbnails and request a next focus at the same time
|
||||
* the app will crash without any way to catch it!
|
||||
*
|
||||
* How to bypass this?
|
||||
* This code basically steals the focus for 500ms and puts it in an inescapable view
|
||||
* then lets out the focus by requesting focus to result_episodes
|
||||
*/
|
||||
|
||||
// Do not use this.isTv, that is the player
|
||||
val isTv = isTvSettings()
|
||||
val hasEpisodes =
|
||||
!(result_episodes?.adapter as? EpisodeAdapter?)?.cardList.isNullOrEmpty()
|
||||
|
||||
if (isTv && hasEpisodes) {
|
||||
// Make it impossible to focus anywhere else!
|
||||
temporary_no_focus?.isFocusable = true
|
||||
temporary_no_focus?.requestFocus()
|
||||
}
|
||||
|
||||
(result_episodes?.adapter as? EpisodeAdapter)?.updateList(episodes.value)
|
||||
|
||||
if (isTv && hasEpisodes) main {
|
||||
delay(500)
|
||||
temporary_no_focus?.isFocusable = false
|
||||
// This might make some people sad as it changes the focus when leaving an episode :(
|
||||
result_episodes?.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
result_episode_loading?.isVisible = false
|
||||
result_episodes?.isVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class StoredData(
|
||||
val url: String?,
|
||||
val apiName: String,
|
||||
|
@ -455,7 +297,7 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
val playerAction: Int
|
||||
)
|
||||
|
||||
private fun getStoredData(context: Context): StoredData? {
|
||||
fun getStoredData(context: Context): StoredData? {
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val url = arguments?.getString(URL_BUNDLE)
|
||||
val apiName = arguments?.getString(API_NAME_BUNDLE) ?: return null
|
||||
|
@ -537,7 +379,6 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
context?.updateHasTrailers()
|
||||
activity?.loadCache()
|
||||
|
||||
fixPaddingStatusbar(result_top_bar)
|
||||
//activity?.fixPaddingStatusbar(result_barstatus)
|
||||
|
||||
/* val backParameter = result_back.layoutParams as FrameLayout.LayoutParams
|
||||
|
@ -554,35 +395,6 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
val storedData = (activity ?: context)?.let {
|
||||
getStoredData(it)
|
||||
}
|
||||
syncModel.addFromUrl(storedData?.url)
|
||||
|
||||
val api = getApiFromNameNull(storedData?.apiName)
|
||||
|
||||
result_episodes?.adapter =
|
||||
EpisodeAdapter(
|
||||
api?.hasDownloadSupport == true && !isTvSettings(),
|
||||
{ episodeClick ->
|
||||
viewModel.handleAction(activity, episodeClick)
|
||||
},
|
||||
{ downloadClickEvent ->
|
||||
handleDownloadClick(downloadClickEvent)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
observe(viewModel.episodeSynopsis) { description ->
|
||||
view.context?.let { ctx ->
|
||||
val builder: AlertDialog.Builder =
|
||||
AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
|
||||
builder.setMessage(description.html())
|
||||
.setTitle(R.string.synopsis)
|
||||
.setOnDismissListener {
|
||||
viewModel.releaseEpisodeSynopsis()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This is to band-aid FireTV navigation
|
||||
val isTv = isTvSettings()
|
||||
|
@ -638,215 +450,6 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
result_resume_series_button_play?.setOnClickListener(click)
|
||||
}
|
||||
|
||||
|
||||
|
||||
observeNullable(viewModel.episodes) { episodes ->
|
||||
updateEpisodes(episodes)
|
||||
}
|
||||
|
||||
result_cast_items?.setOnFocusChangeListener { _, hasFocus ->
|
||||
// Always escape focus
|
||||
if (hasFocus) result_bookmark_button?.requestFocus()
|
||||
}
|
||||
|
||||
observe(viewModel.trailers) { trailers ->
|
||||
setTrailers(trailers.flatMap { it.mirros }) // I dont care about subtitles yet!
|
||||
}
|
||||
|
||||
observe(viewModel.recommendations) { recommendations ->
|
||||
setRecommendations(recommendations, null)
|
||||
}
|
||||
|
||||
observeNullable(viewModel.movie) { data ->
|
||||
updateMovie(data)
|
||||
}
|
||||
|
||||
observe(viewModel.page) { data ->
|
||||
if (data == null) return@observe
|
||||
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)
|
||||
result_poster_background.setImage(d.posterBackgroundImage)
|
||||
//result_trailer_thumbnail.setImage(d.posterBackgroundImage, fadeIn = false)
|
||||
|
||||
if (d.posterImage != null && !isTrueTvSettings())
|
||||
result_poster_holder?.setOnClickListener {
|
||||
try {
|
||||
context?.let { ctx ->
|
||||
runBlocking {
|
||||
val sourceBuilder = AlertDialog.Builder(ctx)
|
||||
sourceBuilder.setView(R.layout.result_poster)
|
||||
|
||||
val sourceDialog = sourceBuilder.create()
|
||||
sourceDialog.show()
|
||||
|
||||
sourceDialog.findViewById<ImageView?>(R.id.imgPoster)
|
||||
?.apply {
|
||||
setImage(d.posterImage)
|
||||
setOnClickListener {
|
||||
sourceDialog.dismissSafe()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
result_cast_items?.isVisible = d.actors != null
|
||||
(result_cast_items?.adapter as? ActorAdaptor)?.apply {
|
||||
updateList(d.actors ?: emptyList())
|
||||
}
|
||||
|
||||
observeNullable(viewModel.subscribeStatus) { isSubscribed ->
|
||||
result_subscribe?.isVisible = isSubscribed != null
|
||||
if (isSubscribed == null) return@observeNullable
|
||||
|
||||
val drawable = if (isSubscribed) {
|
||||
R.drawable.ic_baseline_notifications_active_24
|
||||
} else {
|
||||
R.drawable.baseline_notifications_none_24
|
||||
}
|
||||
|
||||
result_subscribe?.setImageResource(drawable)
|
||||
}
|
||||
|
||||
result_subscribe?.setOnClickListener {
|
||||
val isSubscribed =
|
||||
viewModel.toggleSubscriptionStatus() ?: return@setOnClickListener
|
||||
|
||||
val message = if (isSubscribed) {
|
||||
// Kinda icky to have this here, but it works.
|
||||
SubscriptionWorkManager.enqueuePeriodicWork(context)
|
||||
R.string.subscription_new
|
||||
} else {
|
||||
R.string.subscription_deleted
|
||||
}
|
||||
|
||||
val name = (viewModel.page.value as? Resource.Success)?.value?.title
|
||||
?: txt(R.string.no_data).asStringNull(context) ?: ""
|
||||
showToast(txt(message, name), Toast.LENGTH_SHORT)
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
d.comingSoon.let { soon ->
|
||||
result_coming_soon?.isVisible = soon
|
||||
result_data_holder?.isGone = soon
|
||||
}
|
||||
|
||||
val tags = d.tags
|
||||
result_tag_holder?.isVisible = tags.isNotEmpty()
|
||||
result_tag?.apply {
|
||||
removeAllViews()
|
||||
tags.forEach { tag ->
|
||||
val chip = Chip(context)
|
||||
val chipDrawable = ChipDrawable.createFromAttributes(
|
||||
context,
|
||||
null,
|
||||
0,
|
||||
R.style.ChipFilled
|
||||
)
|
||||
chip.setChipDrawable(chipDrawable)
|
||||
chip.text = tag
|
||||
chip.isChecked = false
|
||||
chip.isCheckable = false
|
||||
chip.isFocusable = false
|
||||
chip.isClickable = false
|
||||
chip.setTextColor(context.colorFromAttribute(R.attr.textColor))
|
||||
addView(chip)
|
||||
}
|
||||
}
|
||||
// if (tags.isNotEmpty()) {
|
||||
//result_tag_holder?.visibility = VISIBLE
|
||||
//val isOnTv = isTrueTvSettings()
|
||||
|
||||
|
||||
/*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
|
||||
btt.isFocusable = !isOnTv
|
||||
btt.isClickable = !isOnTv
|
||||
result_tag?.addView(viewBtt, index)
|
||||
}*/
|
||||
//}
|
||||
}
|
||||
|
||||
is Resource.Failure -> {
|
||||
result_error_text.text = storedData?.url?.plus("\n") + data.errorString
|
||||
updateVisStatus(1)
|
||||
}
|
||||
|
||||
is Resource.Loading -> {
|
||||
updateVisStatus(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context?.let { ctx ->
|
||||
|
||||
//result_bookmark_button?.isVisible = ctx.isTvSettings()
|
||||
|
@ -879,17 +482,6 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
}
|
||||
}
|
||||
|
||||
result_open_in_browser?.isVisible = storedData.url.startsWith("http")
|
||||
result_open_in_browser?.setOnClickListener {
|
||||
val i = Intent(ACTION_VIEW)
|
||||
i.data = Uri.parse(storedData.url)
|
||||
try {
|
||||
startActivity(i)
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
|
||||
// bloats the navigation on tv
|
||||
if (!isTrueTvSettings()) {
|
||||
result_meta_site?.setOnClickListener {
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package com.lagradost.cloudstream3.ui.result
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
|
@ -15,6 +18,7 @@ import android.view.animation.DecelerateInterpolator
|
|||
import android.widget.AbsListView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.NestedScrollView
|
||||
|
@ -41,12 +45,19 @@ import com.lagradost.cloudstream3.mvvm.logError
|
|||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.mvvm.observeNullable
|
||||
import com.lagradost.cloudstream3.services.SubscriptionWorkManager
|
||||
import com.lagradost.cloudstream3.ui.WatchType
|
||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup
|
||||
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
||||
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.html
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant
|
||||
|
@ -55,14 +66,25 @@ import com.lagradost.cloudstream3.utils.UIHelper
|
|||
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.populateChips
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
import kotlinx.android.synthetic.main.download_button.result_download_movie
|
||||
import kotlinx.android.synthetic.main.fragment_result.download_button
|
||||
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_play_movie
|
||||
import kotlinx.android.synthetic.main.fragment_result_tv.temporary_no_focus
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
|
||||
class ResultFragmentPhone : ResultFragment() {
|
||||
private var binding: FragmentResultSwipeBinding? = null
|
||||
private var resultBinding: FragmentResultBinding? = null
|
||||
private var recommendationBinding: ResultRecommendationsBinding? = null
|
||||
private var syncBinding: ResultSyncBinding? = null
|
||||
open class ResultFragmentPhone : ResultFragment(),
|
||||
PanelsChildGestureRegionObserver.GestureRegionsListener {
|
||||
protected var binding: FragmentResultSwipeBinding? = null
|
||||
protected var resultBinding: FragmentResultBinding? = null
|
||||
protected var recommendationBinding: ResultRecommendationsBinding? = null
|
||||
protected var syncBinding: ResultSyncBinding? = null
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
@ -205,43 +227,158 @@ class ResultFragmentPhone : ResultFragment() {
|
|||
|
||||
var selectSeason: String? = null
|
||||
|
||||
private fun setUrl(url : String?) {
|
||||
if(url == null) {
|
||||
binding?.resultOpenInBrowser?.isVisible = false
|
||||
return
|
||||
}
|
||||
|
||||
binding?.resultOpenInBrowser?.apply {
|
||||
isVisible = url.startsWith("http")
|
||||
setOnClickListener {
|
||||
val i = Intent(Intent.ACTION_VIEW)
|
||||
i.data = Uri.parse(url)
|
||||
try {
|
||||
startActivity(i)
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
val apiName = arguments?.getString(API_NAME_BUNDLE) ?: return
|
||||
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
UIHelper.fixPaddingStatusbar(binding?.resultTopBar)
|
||||
val storedData = (activity ?: context)?.let {
|
||||
getStoredData(it)
|
||||
}
|
||||
|
||||
setUrl(storedData?.url)
|
||||
syncModel.addFromUrl(storedData?.url)
|
||||
|
||||
playerBinding?.playerOpenSource?.setOnClickListener {
|
||||
currentTrailers.getOrNull(currentTrailerIndex)?.let {
|
||||
context?.openBrowser(it.url)
|
||||
val api = APIHolder.getApiFromNameNull(apiName)
|
||||
|
||||
resultBinding?.apply {
|
||||
resultEpisodes.adapter =
|
||||
EpisodeAdapter(
|
||||
api?.hasDownloadSupport == true,
|
||||
{ episodeClick ->
|
||||
viewModel.handleAction(activity, episodeClick)
|
||||
},
|
||||
{ downloadClickEvent ->
|
||||
DownloadButtonSetup.handleDownloadClick(downloadClickEvent)
|
||||
}
|
||||
)
|
||||
resultCastItems.let {
|
||||
PanelsChildGestureRegionObserver.Provider.get().register(it)
|
||||
}
|
||||
resultScroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||
val dy = scrollY - oldScrollY
|
||||
if (dy > 0) { //check for scroll down
|
||||
binding?.resultBookmarkFab?.shrink()
|
||||
} else if (dy < -5) {
|
||||
binding?.resultBookmarkFab?.extend()
|
||||
}
|
||||
if (!isFullScreenPlayer && player.getIsPlaying()) {
|
||||
if (scrollY > (resultBinding?.fragmentTrailer?.playerBackground?.height
|
||||
?: scrollY)
|
||||
) {
|
||||
player.handleEvent(CSPlayerEvent.Pause)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
binding?.apply {
|
||||
resultOverlappingPanels.setStartPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
||||
resultOverlappingPanels.setEndPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
||||
resultBack.setOnClickListener {
|
||||
activity?.popCurrentPage()
|
||||
}
|
||||
resultMiniSync.adapter = ImageAdapter(
|
||||
nextFocusDown = R.id.result_sync_set_score,
|
||||
clickCallback = { action ->
|
||||
if (action == IMAGE_CLICK || action == IMAGE_LONG_CLICK) {
|
||||
if (binding?.resultOverlappingPanels?.getSelectedPanel()?.ordinal == 1) {
|
||||
binding?.resultOverlappingPanels?.openStartPanel()
|
||||
} else {
|
||||
binding?.resultOverlappingPanels?.closePanels()
|
||||
}
|
||||
}
|
||||
})
|
||||
resultSubscribe.setOnClickListener {
|
||||
val isSubscribed =
|
||||
viewModel.toggleSubscriptionStatus() ?: return@setOnClickListener
|
||||
|
||||
val message = if (isSubscribed) {
|
||||
// Kinda icky to have this here, but it works.
|
||||
SubscriptionWorkManager.enqueuePeriodicWork(context)
|
||||
R.string.subscription_new
|
||||
} else {
|
||||
R.string.subscription_deleted
|
||||
}
|
||||
|
||||
val name = (viewModel.page.value as? Resource.Success)?.value?.title
|
||||
?: txt(R.string.no_data).asStringNull(context) ?: ""
|
||||
CommonActivity.showToast(txt(message, name), Toast.LENGTH_SHORT)
|
||||
}
|
||||
mediaRouteButton.apply {
|
||||
val chromecastSupport = api?.hasChromecastSupport == true
|
||||
alpha = if (chromecastSupport) 1f else 0.3f
|
||||
if (!chromecastSupport) {
|
||||
setOnClickListener {
|
||||
CommonActivity.showToast(
|
||||
R.string.no_chromecast_support_toast,
|
||||
Toast.LENGTH_LONG
|
||||
)
|
||||
}
|
||||
}
|
||||
activity?.let { act ->
|
||||
if (act.isCastApiAvailable()) {
|
||||
try {
|
||||
CastButtonFactory.setUpMediaRouteButton(act, this)
|
||||
val castContext = CastContext.getSharedInstance(act.applicationContext)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
binding?.resultOverlappingPanels?.setStartPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
||||
binding?.resultOverlappingPanels?.setEndPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
||||
|
||||
recommendationBinding?.resultRecommendationsList?.apply {
|
||||
spanCount = 3
|
||||
adapter =
|
||||
SearchAdapter(
|
||||
ArrayList(),
|
||||
this,
|
||||
) { callback ->
|
||||
SearchHelper.handleSearchClickCallback(callback)
|
||||
playerBinding?.apply {
|
||||
playerOpenSource.setOnClickListener {
|
||||
currentTrailers.getOrNull(currentTrailerIndex)?.let {
|
||||
context?.openBrowser(it.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recommendationBinding?.apply {
|
||||
resultRecommendationsList.apply {
|
||||
spanCount = 3
|
||||
adapter =
|
||||
SearchAdapter(
|
||||
ArrayList(),
|
||||
this,
|
||||
) { callback ->
|
||||
SearchHelper.handleSearchClickCallback(callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PanelsChildGestureRegionObserver.Provider.get().addGestureRegionsUpdateListener(this)
|
||||
|
||||
resultBinding?.resultCastItems?.let {
|
||||
PanelsChildGestureRegionObserver.Provider.get().register(it)
|
||||
}
|
||||
|
||||
|
||||
binding?.resultBack?.setOnClickListener {
|
||||
activity?.popCurrentPage()
|
||||
}
|
||||
|
||||
/*
|
||||
result_bookmark_button?.setOnClickListener {
|
||||
it.popupMenuNoIcons(
|
||||
|
@ -253,62 +390,165 @@ class ResultFragmentPhone : ResultFragment() {
|
|||
}
|
||||
}*/
|
||||
|
||||
binding?.resultMiniSync?.adapter = ImageAdapter(
|
||||
nextFocusDown = R.id.result_sync_set_score,
|
||||
clickCallback = { action ->
|
||||
if (action == IMAGE_CLICK || action == IMAGE_LONG_CLICK) {
|
||||
if (binding?.resultOverlappingPanels?.getSelectedPanel()?.ordinal == 1) {
|
||||
binding?.resultOverlappingPanels?.openStartPanel()
|
||||
observeNullable(viewModel.subscribeStatus) { isSubscribed ->
|
||||
binding?.resultSubscribe?.isVisible = isSubscribed != null
|
||||
if (isSubscribed == null) return@observeNullable
|
||||
|
||||
val drawable = if (isSubscribed) {
|
||||
R.drawable.ic_baseline_notifications_active_24
|
||||
} else {
|
||||
R.drawable.baseline_notifications_none_24
|
||||
}
|
||||
|
||||
binding?.resultSubscribe?.setImageResource(drawable)
|
||||
}
|
||||
|
||||
observe(viewModel.trailers) { trailers ->
|
||||
setTrailers(trailers.flatMap { it.mirros }) // I dont care about subtitles yet!
|
||||
}
|
||||
|
||||
observeNullable(viewModel.episodes) { episodes ->
|
||||
resultBinding?.apply {
|
||||
// no failure?
|
||||
resultEpisodeLoading.isVisible = episodes is Resource.Loading
|
||||
resultEpisodes.isVisible = episodes is Resource.Success
|
||||
if(episodes is Resource.Success) {
|
||||
(resultEpisodes.adapter as? EpisodeAdapter)?.updateList(episodes.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
observeNullable(viewModel.movie) { data ->
|
||||
resultBinding?.apply {
|
||||
resultPlayMovie.isVisible = data is Resource.Success
|
||||
downloadButton.isVisible =
|
||||
data is Resource.Success && viewModel.currentRepo?.api?.hasDownloadSupport == true
|
||||
|
||||
(data as? Resource.Success)?.value?.let { (text, ep) ->
|
||||
resultPlayMovie.setText(text)
|
||||
resultPlayMovie.setOnClickListener {
|
||||
viewModel.handleAction(
|
||||
activity,
|
||||
EpisodeClickEvent(ACTION_CLICK_DEFAULT, ep)
|
||||
)
|
||||
}
|
||||
resultPlayMovie.setOnLongClickListener {
|
||||
viewModel.handleAction(
|
||||
activity,
|
||||
EpisodeClickEvent(ACTION_SHOW_OPTIONS, ep)
|
||||
)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
downloadButton.setDefaultClickListener(
|
||||
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 -> DownloadButtonSetup.handleDownloadClick(click)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
observe(viewModel.page) { data ->
|
||||
if (data == null) return@observe
|
||||
resultBinding?.apply {
|
||||
(data as? Resource.Success)?.value?.let { d ->
|
||||
resultVpn.setText(d.vpnText)
|
||||
resultInfo.setText(d.metaText)
|
||||
resultNoEpisodes.setText(d.noEpisodesFoundText)
|
||||
resultTitle.setText(d.titleText)
|
||||
resultMetaSite.setText(d.apiName)
|
||||
resultMetaType.setText(d.typeText)
|
||||
resultMetaYear.setText(d.yearText)
|
||||
resultMetaDuration.setText(d.durationText)
|
||||
resultMetaRating.setText(d.ratingText)
|
||||
resultCastText.setText(d.actorsText)
|
||||
resultNextAiring.setText(d.nextAiringEpisode)
|
||||
resultNextAiringTime.setText(d.nextAiringDate)
|
||||
resultPoster.setImage(d.posterImage)
|
||||
resultPosterBackground.setImage(d.posterBackgroundImage)
|
||||
resultDescription.setTextHtml(d.plotText)
|
||||
resultDescription.setOnClickListener { view ->
|
||||
// todo bottom 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()
|
||||
}
|
||||
}
|
||||
|
||||
populateChips(resultTag, d.tags)
|
||||
|
||||
resultComingSoon.isVisible = d.comingSoon
|
||||
resultDataHolder.isGone = d.comingSoon
|
||||
|
||||
resultCastItems.isGone = d.actors.isNullOrEmpty()
|
||||
(resultCastItems.adapter as? ActorAdaptor)?.updateList(d.actors ?: emptyList())
|
||||
|
||||
if (syncModel.addSyncs(d.syncData)) {
|
||||
syncModel.updateMetaAndUser()
|
||||
syncModel.updateSynced()
|
||||
} else {
|
||||
binding?.resultOverlappingPanels?.closePanels()
|
||||
syncModel.addFromUrl(d.url)
|
||||
}
|
||||
|
||||
binding?.apply {
|
||||
resultSearch.setOnClickListener {
|
||||
QuickSearchFragment.pushSearch(activity, d.title)
|
||||
}
|
||||
|
||||
resultShare.setOnClickListener {
|
||||
try {
|
||||
val i = Intent(Intent.ACTION_SEND)
|
||||
i.type = "text/plain"
|
||||
i.putExtra(Intent.EXTRA_SUBJECT, d.title)
|
||||
i.putExtra(Intent.EXTRA_TEXT, d.url)
|
||||
startActivity(Intent.createChooser(i, d.title))
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
|
||||
setUrl(d.url)
|
||||
resultBookmarkFab.apply {
|
||||
isVisible = true
|
||||
extend()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
(data as? Resource.Failure)?.let { data ->
|
||||
resultErrorText.text = (storedData?.url?.plus("\n") ?: "") + data.errorString
|
||||
}
|
||||
|
||||
resultBinding?.resultScroll?.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||
val dy = scrollY - oldScrollY
|
||||
if (dy > 0) { //check for scroll down
|
||||
binding?.resultBookmarkFab?.shrink()
|
||||
} else if (dy < -5) {
|
||||
binding?.resultBookmarkFab?.extend()
|
||||
}
|
||||
if (!isFullScreenPlayer && player.getIsPlaying()) {
|
||||
if (scrollY > (resultBinding?.fragmentTrailer?.playerBackground?.height
|
||||
?: scrollY)
|
||||
) {
|
||||
player.handleEvent(CSPlayerEvent.Pause)
|
||||
}
|
||||
}
|
||||
//result_poster_blur_holder?.translationY = -scrollY.toFloat()
|
||||
})
|
||||
val api = APIHolder.getApiFromNameNull(apiName)
|
||||
binding?.resultBookmarkFab?.isVisible = data is Resource.Success
|
||||
resultFinishLoading.isVisible = data is Resource.Success
|
||||
|
||||
binding?.mediaRouteButton?.apply {
|
||||
val chromecastSupport = api?.hasChromecastSupport == true
|
||||
alpha = if (chromecastSupport) 1f else 0.3f
|
||||
if (!chromecastSupport) {
|
||||
setOnClickListener {
|
||||
CommonActivity.showToast(
|
||||
R.string.no_chromecast_support_toast,
|
||||
Toast.LENGTH_LONG
|
||||
)
|
||||
}
|
||||
}
|
||||
activity?.let { act ->
|
||||
if (act.isCastApiAvailable()) {
|
||||
try {
|
||||
CastButtonFactory.setUpMediaRouteButton(act, this)
|
||||
val castContext = CastContext.getSharedInstance(act.applicationContext)
|
||||
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)
|
||||
}
|
||||
}
|
||||
resultLoading.isVisible = data is Resource.Loading
|
||||
|
||||
resultLoadingError.isVisible = data is Resource.Failure
|
||||
resultErrorText.isVisible = data is Resource.Failure
|
||||
resultReloadConnectionOpenInBrowser.isVisible = data is Resource.Failure
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,6 +590,7 @@ class ResultFragmentPhone : ResultFragment() {
|
|||
(binding?.resultMiniSync?.adapter as? ImageAdapter)?.updateList(newList.mapNotNull { it.icon })
|
||||
}
|
||||
|
||||
|
||||
var currentSyncProgress = 0
|
||||
fun setSyncMaxEpisodes(totalEpisodes: Int?) {
|
||||
syncBinding?.resultSyncEpisodes?.max = (totalEpisodes ?: 0) * 1000
|
||||
|
@ -439,7 +680,22 @@ class ResultFragmentPhone : ResultFragment() {
|
|||
}
|
||||
binding?.resultOverlappingPanels?.setStartPanelLockState(if (closed) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)
|
||||
}
|
||||
|
||||
observe(viewModel.recommendations) { recommendations ->
|
||||
setRecommendations(recommendations, null)
|
||||
}
|
||||
observe(viewModel.episodeSynopsis) { description ->
|
||||
// TODO bottom dialog
|
||||
view.context?.let { ctx ->
|
||||
val builder: AlertDialog.Builder =
|
||||
AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
|
||||
builder.setMessage(description.html())
|
||||
.setTitle(R.string.synopsis)
|
||||
.setOnDismissListener {
|
||||
viewModel.releaseEpisodeSynopsis()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
context?.let { ctx ->
|
||||
val arrayAdapter = ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
||||
/*
|
||||
|
@ -653,7 +909,7 @@ class ResultFragmentPhone : ResultFragment() {
|
|||
binding?.resultOverlappingPanels?.setChildGestureRegions(gestureRegions)
|
||||
}
|
||||
|
||||
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||
private fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||
val isInvalid = rec.isNullOrEmpty()
|
||||
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
|
||||
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package com.lagradost.cloudstream3.ui.result
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
@ -20,19 +22,32 @@ import com.lagradost.cloudstream3.mvvm.Resource
|
|||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.mvvm.observeNullable
|
||||
import com.lagradost.cloudstream3.ui.WatchType
|
||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup
|
||||
import com.lagradost.cloudstream3.ui.player.ExtractorLinkGenerator
|
||||
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.html
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant
|
||||
import com.lagradost.cloudstream3.utils.UIHelper
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
import kotlinx.android.synthetic.main.fragment_result.download_button
|
||||
import kotlinx.android.synthetic.main.fragment_result.result_episodes
|
||||
import kotlinx.android.synthetic.main.fragment_result.result_play_movie
|
||||
import kotlinx.android.synthetic.main.fragment_result_tv.temporary_no_focus
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
class ResultFragmentTv : ResultFragment() {
|
||||
override val resultLayout = R.layout.fragment_result_tv
|
||||
override var layout = R.layout.fragment_result_tv
|
||||
|
||||
private var binding: FragmentResultTvBinding? = null
|
||||
|
||||
|
@ -95,20 +110,6 @@ class ResultFragmentTv : ResultFragment() {
|
|||
return focus == binding?.resultRoot
|
||||
}
|
||||
|
||||
override fun updateEpisodes(episodes: Resource<List<ResultEpisode>>?) {
|
||||
super.updateEpisodes(episodes)
|
||||
if (episodes is Resource.Success && hasNoFocus()) {
|
||||
binding?.resultEpisodes?.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateMovie(data: Resource<Pair<UiText, ResultEpisode>>?) {
|
||||
super.updateMovie(data)
|
||||
if (data is Resource.Success && hasNoFocus()) {
|
||||
binding?.resultPlayMovie?.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setTrailers(trailers: List<ExtractorLink>?) {
|
||||
context?.updateHasTrailers()
|
||||
if (!LoadResponse.isTrailersEnabled) return
|
||||
|
@ -128,7 +129,7 @@ class ResultFragmentTv : ResultFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||
private fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||
currentRecommendations = rec ?: emptyList()
|
||||
val isInvalid = rec.isNullOrEmpty()
|
||||
binding?.apply {
|
||||
|
@ -151,6 +152,8 @@ class ResultFragmentTv : ResultFragment() {
|
|||
|
||||
var loadingDialog: Dialog? = null
|
||||
var popupDialog: Dialog? = null
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding?.apply {
|
||||
|
@ -163,6 +166,34 @@ class ResultFragmentTv : ResultFragment() {
|
|||
resultRangeSelection.setAdapter()
|
||||
resultDubSelection.setAdapter()
|
||||
resultRecommendationsFilterSelection.setAdapter()
|
||||
|
||||
resultCastItems.setOnFocusChangeListener { _, hasFocus ->
|
||||
// Always escape focus
|
||||
if (hasFocus) binding?.resultBookmarkButton?.requestFocus()
|
||||
}
|
||||
resultBack.setOnClickListener {
|
||||
activity?.popCurrentPage()
|
||||
}
|
||||
|
||||
resultRecommendationsList.spanCount = 8
|
||||
resultRecommendationsList.adapter =
|
||||
SearchAdapter(
|
||||
ArrayList(),
|
||||
resultRecommendationsList,
|
||||
) { callback ->
|
||||
SearchHelper.handleSearchClickCallback(callback)
|
||||
}
|
||||
|
||||
resultEpisodes.adapter =
|
||||
EpisodeAdapter(
|
||||
false,
|
||||
{ episodeClick ->
|
||||
viewModel.handleAction(activity, episodeClick)
|
||||
},
|
||||
{ downloadClickEvent ->
|
||||
DownloadButtonSetup.handleDownloadClick(downloadClickEvent)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
observe(viewModel.watchStatus) { watchType ->
|
||||
|
@ -181,6 +212,30 @@ class ResultFragmentTv : ResultFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
observeNullable(viewModel.movie) { data ->
|
||||
binding?.apply {
|
||||
resultPlayMovie.isVisible = data is Resource.Success
|
||||
(data as? Resource.Success)?.value?.let { (text, ep) ->
|
||||
resultPlayMovie.setText(text)
|
||||
resultPlayMovie.setOnClickListener {
|
||||
viewModel.handleAction(
|
||||
activity,
|
||||
EpisodeClickEvent(ACTION_CLICK_DEFAULT, ep)
|
||||
)
|
||||
}
|
||||
resultPlayMovie.setOnLongClickListener {
|
||||
viewModel.handleAction(
|
||||
activity,
|
||||
EpisodeClickEvent(ACTION_SHOW_OPTIONS, ep)
|
||||
)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
if (hasNoFocus()) {
|
||||
resultPlayMovie.requestFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
observeNullable(viewModel.selectPopup) { popup ->
|
||||
if (popup == null) {
|
||||
|
@ -257,21 +312,111 @@ class ResultFragmentTv : ResultFragment() {
|
|||
observe(viewModel.seasonSelections) {
|
||||
binding?.resultSeasonSelection.update(it)
|
||||
}
|
||||
|
||||
binding?.apply {
|
||||
resultBack.setOnClickListener {
|
||||
activity?.popCurrentPage()
|
||||
observe(viewModel.recommendations) { recommendations ->
|
||||
setRecommendations(recommendations, null)
|
||||
}
|
||||
observe(viewModel.episodeSynopsis) { description ->
|
||||
view.context?.let { ctx ->
|
||||
val builder: AlertDialog.Builder =
|
||||
AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
|
||||
builder.setMessage(description.html())
|
||||
.setTitle(R.string.synopsis)
|
||||
.setOnDismissListener {
|
||||
viewModel.releaseEpisodeSynopsis()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
observeNullable(viewModel.episodes) { episodes ->
|
||||
binding?.apply {
|
||||
resultEpisodes.isVisible = episodes is Resource.Success
|
||||
resultEpisodeLoading.isVisible = episodes is Resource.Loading
|
||||
if (episodes is Resource.Success) {
|
||||
/*
|
||||
* Okay so what is this fuckery?
|
||||
* Basically Android TV will crash if you request a new focus while
|
||||
* the adapter gets updated.
|
||||
*
|
||||
* This means that if you load thumbnails and request a next focus at the same time
|
||||
* the app will crash without any way to catch it!
|
||||
*
|
||||
* How to bypass this?
|
||||
* This code basically steals the focus for 500ms and puts it in an inescapable view
|
||||
* then lets out the focus by requesting focus to result_episodes
|
||||
*/
|
||||
|
||||
resultRecommendationsList.spanCount = 8
|
||||
resultRecommendationsList.adapter =
|
||||
SearchAdapter(
|
||||
ArrayList(),
|
||||
resultRecommendationsList,
|
||||
) { callback ->
|
||||
SearchHelper.handleSearchClickCallback(callback)
|
||||
val hasEpisodes =
|
||||
!(resultEpisodes.adapter as? EpisodeAdapter?)?.cardList.isNullOrEmpty()
|
||||
|
||||
if (hasEpisodes) {
|
||||
// Make it impossible to focus anywhere else!
|
||||
temporaryNoFocus.isFocusable = true
|
||||
temporaryNoFocus.requestFocus()
|
||||
}
|
||||
|
||||
(resultEpisodes.adapter as? EpisodeAdapter)?.updateList(episodes.value)
|
||||
|
||||
if (hasEpisodes) main {
|
||||
delay(500)
|
||||
temporaryNoFocus.isFocusable = false
|
||||
// This might make some people sad as it changes the focus when leaving an episode :(
|
||||
temporaryNoFocus.requestFocus()
|
||||
}
|
||||
|
||||
if (hasNoFocus())
|
||||
binding?.resultEpisodes?.requestFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
observeNullable(viewModel.page) { data ->
|
||||
if (data == null) return@observeNullable
|
||||
binding?.apply {
|
||||
when (data) {
|
||||
is Resource.Success -> {
|
||||
val d = data.value
|
||||
resultVpn.setText(d.vpnText)
|
||||
resultInfo.setText(d.metaText)
|
||||
resultNoEpisodes.setText(d.noEpisodesFoundText)
|
||||
resultTitle.setText(d.titleText)
|
||||
resultMetaSite.setText(d.apiName)
|
||||
resultMetaType.setText(d.typeText)
|
||||
resultMetaYear.setText(d.yearText)
|
||||
resultMetaDuration.setText(d.durationText)
|
||||
resultMetaRating.setText(d.ratingText)
|
||||
resultCastText.setText(d.actorsText)
|
||||
resultNextAiring.setText(d.nextAiringEpisode)
|
||||
resultNextAiringTime.setText(d.nextAiringDate)
|
||||
resultPoster.setImage(d.posterImage)
|
||||
resultDescription.setTextHtml(d.plotText)
|
||||
|
||||
resultComingSoon.isVisible = d.comingSoon
|
||||
resultDataHolder.isGone = d.comingSoon
|
||||
UIHelper.populateChips(resultTag, d.tags)
|
||||
resultCastItems.isGone = d.actors.isNullOrEmpty()
|
||||
(resultCastItems.adapter as? ActorAdaptor)?.updateList(
|
||||
d.actors ?: emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
is Resource.Loading -> {
|
||||
|
||||
}
|
||||
|
||||
is Resource.Failure -> {
|
||||
resultErrorText.text =
|
||||
(this@ResultFragmentTv.context?.let { getStoredData(it) }?.url?.plus("\n")
|
||||
?: "") + data.errorString
|
||||
}
|
||||
}
|
||||
|
||||
resultFinishLoading.isVisible = data is Resource.Success
|
||||
|
||||
resultLoading.isVisible = data is Resource.Loading
|
||||
|
||||
resultLoadingError.isVisible = data is Resource.Failure
|
||||
resultReloadConnectionOpenInBrowser.isVisible = data is Resource.Failure
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,21 +10,13 @@ import android.view.ViewGroup
|
|||
import android.widget.FrameLayout
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import com.discord.panels.PanelsChildGestureRegionObserver
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
||||
import com.lagradost.cloudstream3.ui.player.FullScreenPlayer
|
||||
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
||||
import com.lagradost.cloudstream3.utils.IOnBackPressed
|
||||
import kotlinx.android.synthetic.main.fragment_result.*
|
||||
import kotlinx.android.synthetic.main.fragment_result.result_smallscreen_holder
|
||||
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
||||
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
||||
import kotlinx.android.synthetic.main.fragment_trailer.*
|
||||
|
||||
|
||||
open class ResultTrailerPlayer : FullScreenPlayer(),
|
||||
PanelsChildGestureRegionObserver.GestureRegionsListener, IOnBackPressed {
|
||||
open class ResultTrailerPlayer : ResultFragmentPhone(), IOnBackPressed {
|
||||
|
||||
override var lockRotation = false
|
||||
override var isFullScreenPlayer = false
|
||||
|
@ -60,13 +52,13 @@ open class ResultTrailerPlayer : FullScreenPlayer(),
|
|||
screenHeight
|
||||
}
|
||||
|
||||
result_trailer_loading?.isVisible = false
|
||||
result_smallscreen_holder?.isVisible = !isFullScreenPlayer
|
||||
result_fullscreen_holder?.isVisible = isFullScreenPlayer
|
||||
//result_trailer_loading?.isVisible = false
|
||||
resultBinding?.resultSmallscreenHolder?.isVisible = !isFullScreenPlayer
|
||||
binding?.resultFullscreenHolder?.isVisible = isFullScreenPlayer
|
||||
|
||||
val to = sw * h / w
|
||||
|
||||
player_background?.apply {
|
||||
resultBinding?.fragmentTrailer?.playerBackground?.apply {
|
||||
isVisible = true
|
||||
layoutParams =
|
||||
FrameLayout.LayoutParams(
|
||||
|
@ -79,12 +71,13 @@ open class ResultTrailerPlayer : FullScreenPlayer(),
|
|||
layoutParams =
|
||||
FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
result_top_holder?.measuredHeight ?: FrameLayout.LayoutParams.MATCH_PARENT
|
||||
resultBinding?.resultTopHolder?.measuredHeight
|
||||
?: FrameLayout.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
|
||||
if (playerBinding?.playerIntroPlay?.isGone == true) {
|
||||
result_top_holder?.apply {
|
||||
resultBinding?.resultTopHolder?.apply {
|
||||
|
||||
val anim = ValueAnimator.ofInt(
|
||||
measuredHeight,
|
||||
|
@ -135,20 +128,26 @@ open class ResultTrailerPlayer : FullScreenPlayer(),
|
|||
playerBinding?.playerFullscreen?.setImageResource(if (fullscreen) R.drawable.baseline_fullscreen_exit_24 else R.drawable.baseline_fullscreen_24)
|
||||
if (fullscreen) {
|
||||
enterFullscreen()
|
||||
result_top_bar?.isVisible = false
|
||||
result_fullscreen_holder?.isVisible = true
|
||||
result_main_holder?.isVisible = false
|
||||
player_background?.let { view ->
|
||||
(view.parent as ViewGroup?)?.removeView(view)
|
||||
result_fullscreen_holder?.addView(view)
|
||||
binding?.apply {
|
||||
resultTopBar.isVisible = false
|
||||
resultFullscreenHolder.isVisible = true
|
||||
resultMainHolder.isVisible = false
|
||||
}
|
||||
} else {
|
||||
result_top_bar?.isVisible = true
|
||||
result_fullscreen_holder?.isVisible = false
|
||||
result_main_holder?.isVisible = true
|
||||
player_background?.let { view ->
|
||||
|
||||
resultBinding?.fragmentTrailer?.playerBackground?.let { view ->
|
||||
(view.parent as ViewGroup?)?.removeView(view)
|
||||
result_smallscreen_holder?.addView(view)
|
||||
binding?.resultFullscreenHolder?.addView(view)
|
||||
}
|
||||
|
||||
} else {
|
||||
binding?.apply {
|
||||
resultTopBar.isVisible = true
|
||||
resultFullscreenHolder.isVisible = false
|
||||
resultMainHolder.isVisible = true
|
||||
resultBinding?.fragmentTrailer?.playerBackground?.let { view ->
|
||||
(view.parent as ViewGroup?)?.removeView(view)
|
||||
resultBinding?.resultSmallscreenHolder?.addView(view)
|
||||
}
|
||||
}
|
||||
exitFullscreen()
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import java.util.concurrent.TimeUnit
|
|||
|
||||
object SyncUtil {
|
||||
private val regexs = listOf(
|
||||
Regex("""(9anime)\.(?:to|center|id)/watch/(?:.*?)\.([^/?]*)"""),
|
||||
Regex("""(9anime)\.(?:to|center|id)/watch/.*?\.([^/?]*)"""),
|
||||
Regex("""(gogoanime|gogoanimes)\..*?/category/([^/?]*)"""),
|
||||
Regex("""(twist\.moe)/a/([^/?]*)"""),
|
||||
)
|
||||
|
@ -44,6 +44,13 @@ object SyncUtil {
|
|||
matchList[site]?.let { realSite ->
|
||||
getIdsFromSlug(slug, realSite)?.let {
|
||||
return it
|
||||
} ?: kotlin.run {
|
||||
if (slug.endsWith("-dub")) {
|
||||
println("testing non -dub slug $slug")
|
||||
getIdsFromSlug(slug.removeSuffix("-dub"), realSite)?.let {
|
||||
return it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,12 +46,16 @@ import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
|
|||
import com.bumptech.glide.request.RequestListener
|
||||
import com.bumptech.glide.request.RequestOptions.bitmapTransform
|
||||
import com.bumptech.glide.request.target.Target
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.chip.ChipDrawable
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import com.lagradost.cloudstream3.CommonActivity.activity
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.ui.result.UiImage
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
||||
import jp.wasabeef.glide.transformations.BlurTransformation
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
@ -73,6 +77,30 @@ object UIHelper {
|
|||
|| Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
|
||||
}
|
||||
|
||||
fun populateChips(view: ChipGroup?, tags : List<String>) {
|
||||
if(view == null) return
|
||||
view.removeAllViews()
|
||||
val context = view.context ?: return
|
||||
|
||||
tags.forEach { tag ->
|
||||
val chip = Chip(context)
|
||||
val chipDrawable = ChipDrawable.createFromAttributes(
|
||||
context,
|
||||
null,
|
||||
0,
|
||||
R.style.ChipFilled
|
||||
)
|
||||
chip.setChipDrawable(chipDrawable)
|
||||
chip.text = tag
|
||||
chip.isChecked = false
|
||||
chip.isCheckable = false
|
||||
chip.isFocusable = false
|
||||
chip.isClickable = false
|
||||
chip.setTextColor(context.colorFromAttribute(R.attr.textColor))
|
||||
view.addView(chip)
|
||||
}
|
||||
}
|
||||
|
||||
fun Activity.requestRW() {
|
||||
ActivityCompat.requestPermissions(
|
||||
this,
|
||||
|
|
|
@ -465,6 +465,7 @@
|
|||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
<com.lagradost.cloudstream3.ui.download.button.DownloadButton
|
||||
android:visibility="gone"
|
||||
android:id="@+id/download_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -216,32 +216,6 @@
|
|||
tools:visibility="visible" />
|
||||
|
||||
<!-- This nested layout is necessary because of buffering and clicking-->
|
||||
<FrameLayout
|
||||
android:id="@+id/player_pause_play_holder_holder"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/player_pause_play"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/video_tap_button"
|
||||
android:nextFocusLeft="@id/exo_rew"
|
||||
|
||||
android:nextFocusRight="@id/exo_ffwd"
|
||||
|
||||
android:nextFocusUp="@id/player_go_back"
|
||||
android:nextFocusDown="@id/player_lock"
|
||||
|
||||
android:src="@drawable/netflix_pause"
|
||||
app:tint="@color/white"
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/player_center_menu"
|
||||
|
@ -298,7 +272,32 @@
|
|||
app:tint="@color/white"
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
<FrameLayout
|
||||
android:id="@+id/player_pause_play_holder_holder"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/player_pause_play"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/video_tap_button"
|
||||
android:nextFocusLeft="@id/exo_rew"
|
||||
|
||||
android:nextFocusRight="@id/exo_ffwd"
|
||||
|
||||
android:nextFocusUp="@id/player_go_back"
|
||||
android:nextFocusDown="@id/player_lock"
|
||||
|
||||
android:src="@drawable/netflix_pause"
|
||||
app:tint="@color/white"
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
<FrameLayout
|
||||
android:id="@+id/player_ffwd_holder"
|
||||
android:layout_width="0dp"
|
||||
|
|
|
@ -76,10 +76,10 @@
|
|||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:visibility="gone"
|
||||
android:id="@+id/player_top_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -113,7 +113,8 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="2dp">
|
||||
android:layout_marginTop="2dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/player_episode_filler"
|
||||
|
@ -136,9 +137,13 @@
|
|||
|
||||
<FrameLayout
|
||||
android:id="@+id/player_go_back_holder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_margin="5dp"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
|
@ -206,33 +211,7 @@
|
|||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<!-- This nested layout is necessary because of buffering and clicking-->
|
||||
<FrameLayout
|
||||
android:id="@+id/player_pause_play_holder_holder"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/player_pause_play"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/video_tap_button"
|
||||
android:nextFocusLeft="@id/exo_rew"
|
||||
|
||||
android:nextFocusRight="@id/exo_ffwd"
|
||||
|
||||
android:nextFocusUp="@id/player_go_back"
|
||||
android:nextFocusDown="@id/player_lock"
|
||||
|
||||
android:src="@drawable/netflix_pause"
|
||||
app:tint="@color/white"
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/player_center_menu"
|
||||
|
@ -288,7 +267,33 @@
|
|||
app:tint="@color/white"
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
<!-- This nested layout is necessary because of buffering and clicking-->
|
||||
<FrameLayout
|
||||
android:id="@+id/player_pause_play_holder_holder"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/player_pause_play"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/video_tap_button"
|
||||
android:nextFocusLeft="@id/exo_rew"
|
||||
|
||||
android:nextFocusRight="@id/exo_ffwd"
|
||||
|
||||
android:nextFocusUp="@id/player_go_back"
|
||||
android:nextFocusDown="@id/player_lock"
|
||||
|
||||
android:src="@drawable/netflix_pause"
|
||||
app:tint="@color/white"
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
<FrameLayout
|
||||
android:id="@+id/player_ffwd_holder"
|
||||
android:layout_width="0dp"
|
||||
|
|
|
@ -436,7 +436,7 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/navigation_results_phone"
|
||||
android:name="com.lagradost.cloudstream3.ui.result.ResultFragmentPhone"
|
||||
android:name="com.lagradost.cloudstream3.ui.result.ResultTrailerPlayer"
|
||||
android:layout_height="match_parent"
|
||||
app:enterAnim="@anim/enter_anim"
|
||||
app:exitAnim="@anim/exit_anim"
|
||||
|
|
Loading…
Reference in a new issue