forked from recloudstream/cloudstream
android tv resultview testing
This commit is contained in:
parent
cd9bdb8ba7
commit
1bc4c7e56d
11 changed files with 1287 additions and 395 deletions
|
@ -156,7 +156,11 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
|
|
||||||
// Fucks up anime info layout since that has its own layout
|
// Fucks up anime info layout since that has its own layout
|
||||||
cast_mini_controller_holder?.isVisible =
|
cast_mini_controller_holder?.isVisible =
|
||||||
!listOf(R.id.navigation_results, R.id.navigation_player).contains(destination.id)
|
!listOf(
|
||||||
|
R.id.navigation_results_phone,
|
||||||
|
R.id.navigation_results_tv,
|
||||||
|
R.id.navigation_player
|
||||||
|
).contains(destination.id)
|
||||||
|
|
||||||
val isNavVisible = listOf(
|
val isNavVisible = listOf(
|
||||||
R.id.navigation_home,
|
R.id.navigation_home,
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
package com.lagradost.cloudstream3.ui.result
|
package com.lagradost.cloudstream3.ui.result
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Dialog
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.Intent.*
|
import android.content.Intent.*
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.graphics.Rect
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -26,17 +23,18 @@ import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.discord.panels.OverlappingPanelsLayout
|
import com.discord.panels.OverlappingPanelsLayout
|
||||||
import com.discord.panels.PanelsChildGestureRegionObserver
|
|
||||||
import com.google.android.gms.cast.framework.CastButtonFactory
|
import com.google.android.gms.cast.framework.CastButtonFactory
|
||||||
import com.google.android.gms.cast.framework.CastContext
|
import com.google.android.gms.cast.framework.CastContext
|
||||||
import com.google.android.gms.cast.framework.CastState
|
import com.google.android.gms.cast.framework.CastState
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.lagradost.cloudstream3.*
|
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
||||||
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
||||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||||
|
import com.lagradost.cloudstream3.DubStatus
|
||||||
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.SearchResponse
|
||||||
|
import com.lagradost.cloudstream3.TvType
|
||||||
import com.lagradost.cloudstream3.mvvm.*
|
import com.lagradost.cloudstream3.mvvm.*
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
|
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
|
||||||
import com.lagradost.cloudstream3.ui.WatchType
|
import com.lagradost.cloudstream3.ui.WatchType
|
||||||
|
@ -45,8 +43,6 @@ import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownload
|
||||||
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
|
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
|
||||||
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
||||||
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
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.Companion.isTrueTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
import com.lagradost.cloudstream3.utils.*
|
import com.lagradost.cloudstream3.utils.*
|
||||||
|
@ -59,21 +55,56 @@ import com.lagradost.cloudstream3.utils.Coroutines.ioWork
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant
|
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
|
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIcons
|
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIcons
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result.*
|
import kotlinx.android.synthetic.main.fragment_result.*
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_cast_items
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_cast_text
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_coming_soon
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_data_holder
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_description
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_download_movie
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_episode_loading
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_episodes
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_error_text
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_finish_loading
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_info
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_loading
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_loading_error
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_meta_duration
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_meta_rating
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_meta_site
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_meta_type
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_meta_year
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_movie_download_icon
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_movie_download_text
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_movie_download_text_precentage
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_movie_progress_downloaded
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_movie_progress_downloaded_holder
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_next_airing
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_next_airing_time
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_no_episodes
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_play_movie
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_reload_connection_open_in_browser
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_reload_connectionerror
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_resume_parent
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_resume_progress_holder
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_resume_series_progress
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_resume_series_progress_text
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_resume_series_title
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_scroll
|
||||||
|
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_swipe.*
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
||||||
import kotlinx.android.synthetic.main.fragment_trailer.*
|
import kotlinx.android.synthetic.main.fragment_trailer.*
|
||||||
import kotlinx.android.synthetic.main.result_recommendations.*
|
|
||||||
import kotlinx.android.synthetic.main.result_sync.*
|
import kotlinx.android.synthetic.main.result_sync.*
|
||||||
import kotlinx.android.synthetic.main.trailer_custom_layout.*
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
const val START_ACTION_RESUME_LATEST = 1
|
const val START_ACTION_RESUME_LATEST = 1
|
||||||
|
@ -159,7 +190,7 @@ fun ResultEpisode.getWatchProgress(): Float {
|
||||||
return (getDisplayPosition() / 1000).toFloat() / (duration / 1000).toFloat()
|
return (getDisplayPosition() / 1000).toFloat() / (duration / 1000).toFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResultFragment : ResultTrailerPlayer() {
|
open class ResultFragment : ResultTrailerPlayer() {
|
||||||
companion object {
|
companion object {
|
||||||
const val URL_BUNDLE = "url"
|
const val URL_BUNDLE = "url"
|
||||||
const val API_NAME_BUNDLE = "apiName"
|
const val API_NAME_BUNDLE = "apiName"
|
||||||
|
@ -168,6 +199,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
const val START_ACTION_BUNDLE = "startAction"
|
const val START_ACTION_BUNDLE = "startAction"
|
||||||
const val START_VALUE_BUNDLE = "startValue"
|
const val START_VALUE_BUNDLE = "startValue"
|
||||||
const val RESTART_BUNDLE = "restart"
|
const val RESTART_BUNDLE = "restart"
|
||||||
|
|
||||||
fun newInstance(
|
fun newInstance(
|
||||||
card: SearchResponse, startAction: Int = 0, startValue: Int? = null
|
card: SearchResponse, startAction: Int = 0, startValue: Int? = null
|
||||||
): Bundle {
|
): Bundle {
|
||||||
|
@ -211,8 +243,11 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
private var updateUIListener: (() -> Unit)? = null
|
private var updateUIListener: (() -> Unit)? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var viewModel: ResultViewModel2 //by activityViewModels()
|
open fun setTrailers(trailers: List<ExtractorLink>?) { }
|
||||||
private lateinit var syncModel: SyncViewModel
|
|
||||||
|
protected lateinit var viewModel: ResultViewModel2 //by activityViewModels()
|
||||||
|
protected lateinit var syncModel: SyncViewModel
|
||||||
|
protected open val resultLayout = R.layout.fragment_result_swipe
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
@ -224,7 +259,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
syncModel =
|
syncModel =
|
||||||
ViewModelProvider(this)[SyncViewModel::class.java]
|
ViewModelProvider(this)[SyncViewModel::class.java]
|
||||||
|
|
||||||
return inflater.inflate(R.layout.fragment_result_swipe, container, false)
|
return inflater.inflate(resultLayout, container, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var downloadButton: EasyDownloadButton? = null
|
private var downloadButton: EasyDownloadButton? = null
|
||||||
|
@ -232,12 +267,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
updateUIListener = null
|
updateUIListener = null
|
||||||
(result_episodes?.adapter as EpisodeAdapter?)?.killAdapter()
|
(result_episodes?.adapter as EpisodeAdapter?)?.killAdapter()
|
||||||
downloadButton?.dispose()
|
downloadButton?.dispose()
|
||||||
//somehow this still leaks and I dont know why????
|
|
||||||
// todo look at https://github.com/discord/OverlappingPanels/blob/70b4a7cf43c6771873b1e091029d332896d41a1a/sample_app/src/main/java/com/discord/sampleapp/MainActivity.kt
|
|
||||||
PanelsChildGestureRegionObserver.Provider.get().removeGestureRegionsUpdateListener(this)
|
|
||||||
result_cast_items?.let {
|
|
||||||
PanelsChildGestureRegionObserver.Provider.get().unregister(it)
|
|
||||||
}
|
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,121 +319,8 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentTrailers: List<ExtractorLink> = emptyList()
|
open fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||||
var currentTrailerIndex = 0
|
|
||||||
|
|
||||||
override fun nextMirror() {
|
|
||||||
currentTrailerIndex++
|
|
||||||
loadTrailer()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasNextMirror(): Boolean {
|
|
||||||
return currentTrailerIndex + 1 < currentTrailers.size
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun playerError(exception: Exception) {
|
|
||||||
if (player.getIsPlaying()) { // because we dont want random toasts in player
|
|
||||||
super.playerError(exception)
|
|
||||||
} else {
|
|
||||||
nextMirror()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadTrailer(index: Int? = null) {
|
|
||||||
val isSuccess =
|
|
||||||
currentTrailers.getOrNull(index ?: currentTrailerIndex)?.let { trailer ->
|
|
||||||
context?.let { ctx ->
|
|
||||||
player.onPause()
|
|
||||||
player.loadPlayer(
|
|
||||||
ctx,
|
|
||||||
false,
|
|
||||||
trailer,
|
|
||||||
null,
|
|
||||||
startPosition = 0L,
|
|
||||||
subtitles = emptySet(),
|
|
||||||
subtitle = null,
|
|
||||||
autoPlay = false
|
|
||||||
)
|
|
||||||
true
|
|
||||||
} ?: run {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} ?: run {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
result_trailer_loading?.isVisible = isSuccess
|
|
||||||
result_smallscreen_holder?.isVisible = !isSuccess && !isFullScreenPlayer
|
|
||||||
|
|
||||||
// We don't want the trailer to be focusable if it's not visible
|
|
||||||
result_smallscreen_holder?.descendantFocusability = if (isSuccess) {
|
|
||||||
ViewGroup.FOCUS_AFTER_DESCENDANTS
|
|
||||||
} else {
|
|
||||||
ViewGroup.FOCUS_BLOCK_DESCENDANTS
|
|
||||||
}
|
|
||||||
result_fullscreen_holder?.isVisible = !isSuccess && isFullScreenPlayer
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setTrailers(trailers: List<ExtractorLink>?) {
|
|
||||||
context?.updateHasTrailers()
|
|
||||||
if (!LoadResponse.isTrailersEnabled) return
|
|
||||||
currentTrailers = trailers?.sortedBy { -it.quality } ?: emptyList()
|
|
||||||
loadTrailer()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
|
||||||
val isInvalid = rec.isNullOrEmpty()
|
|
||||||
result_recommendations?.isGone = isInvalid
|
|
||||||
result_recommendations_btt?.isGone = isInvalid
|
|
||||||
result_recommendations_btt?.setOnClickListener {
|
|
||||||
val nextFocusDown = if (result_overlapping_panels?.getSelectedPanel()?.ordinal == 1) {
|
|
||||||
result_overlapping_panels?.openEndPanel()
|
|
||||||
R.id.result_recommendations
|
|
||||||
} else {
|
|
||||||
result_overlapping_panels?.closePanels()
|
|
||||||
R.id.result_description
|
|
||||||
}
|
|
||||||
|
|
||||||
result_recommendations_btt?.nextFocusDownId = nextFocusDown
|
|
||||||
result_search?.nextFocusDownId = nextFocusDown
|
|
||||||
result_open_in_browser?.nextFocusDownId = nextFocusDown
|
|
||||||
result_share?.nextFocusDownId = nextFocusDown
|
|
||||||
}
|
|
||||||
result_overlapping_panels?.setEndPanelLockState(if (isInvalid) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)
|
|
||||||
|
|
||||||
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
|
|
||||||
rec?.map { it.apiName }?.distinct()?.let { apiNames ->
|
|
||||||
// very dirty selection
|
|
||||||
result_recommendations_filter_button?.isVisible = apiNames.size > 1
|
|
||||||
result_recommendations_filter_button?.text = matchAgainst
|
|
||||||
result_recommendations_filter_button?.setOnClickListener { _ ->
|
|
||||||
activity?.showBottomDialog(
|
|
||||||
apiNames,
|
|
||||||
apiNames.indexOf(matchAgainst),
|
|
||||||
getString(R.string.home_change_provider_img_des), false, {}
|
|
||||||
) {
|
|
||||||
setRecommendations(rec, apiNames[it])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ?: run {
|
|
||||||
result_recommendations_filter_button?.isVisible = false
|
|
||||||
}
|
|
||||||
|
|
||||||
result_recommendations?.post {
|
|
||||||
rec?.let { list ->
|
|
||||||
(result_recommendations?.adapter as SearchAdapter?)?.updateList(list.filter { it.apiName == matchAgainst })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fixGrid() {
|
|
||||||
activity?.getSpanCount()?.let { _ ->
|
|
||||||
//result_recommendations?.spanCount = count // this is due to discord not changing size with rotation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
|
||||||
super.onConfigurationChanged(newConfig)
|
|
||||||
fixGrid()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateUI() {
|
private fun updateUI() {
|
||||||
|
@ -411,27 +328,11 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
viewModel.reloadEpisodes()
|
viewModel.reloadEpisodes()
|
||||||
}
|
}
|
||||||
|
|
||||||
var loadingDialog: Dialog? = null
|
|
||||||
var popupDialog: Dialog? = null
|
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
result_cast_items?.let {
|
|
||||||
PanelsChildGestureRegionObserver.Provider.get().register(it)
|
|
||||||
}
|
|
||||||
result_cast_items?.adapter = ActorAdaptor()
|
result_cast_items?.adapter = ActorAdaptor()
|
||||||
fixGrid()
|
|
||||||
result_recommendations?.spanCount = 3
|
|
||||||
result_overlapping_panels?.setStartPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
|
||||||
result_overlapping_panels?.setEndPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
|
||||||
|
|
||||||
player_open_source?.setOnClickListener {
|
|
||||||
currentTrailers.getOrNull(currentTrailerIndex)?.let {
|
|
||||||
context?.openBrowser(it.url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateUIListener = ::updateUI
|
updateUIListener = ::updateUI
|
||||||
|
|
||||||
|
@ -515,10 +416,6 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
//result_poster_blur_holder?.translationY = -scrollY.toFloat()
|
//result_poster_blur_holder?.translationY = -scrollY.toFloat()
|
||||||
})
|
})
|
||||||
|
|
||||||
result_back.setOnClickListener {
|
|
||||||
activity?.popCurrentPage()
|
|
||||||
}
|
|
||||||
|
|
||||||
result_episodes.adapter =
|
result_episodes.adapter =
|
||||||
EpisodeAdapter(
|
EpisodeAdapter(
|
||||||
ArrayList(),
|
ArrayList(),
|
||||||
|
@ -531,15 +428,6 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
result_bookmark_button.setOnClickListener {
|
|
||||||
it.popupMenuNoIcons(
|
|
||||||
items = WatchType.values()
|
|
||||||
.map { watchType -> Pair(watchType.internalId, watchType.stringRes) },
|
|
||||||
//.map { watchType -> Triple(watchType.internalId, watchType.iconRes, watchType.stringRes) },
|
|
||||||
) {
|
|
||||||
viewModel.updateWatchStatus(WatchType.fromInternalId(this.itemId))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(viewModel.watchStatus) { watchType ->
|
observe(viewModel.watchStatus) { watchType ->
|
||||||
result_bookmark_button?.text = getString(watchType.stringRes)
|
result_bookmark_button?.text = getString(watchType.stringRes)
|
||||||
|
@ -567,23 +455,11 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets next focus to allow navigation up and down between 2 views
|
|
||||||
* if either of them is null nothing happens.
|
|
||||||
**/
|
|
||||||
fun setFocusUpAndDown(upper: View?, down: View?) {
|
|
||||||
if (upper == null || down == null) return
|
|
||||||
upper.nextFocusDownId = down.id
|
|
||||||
down.nextFocusUpId = upper.id
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is to band-aid FireTV navigation
|
// This is to band-aid FireTV navigation
|
||||||
result_season_button?.isFocusableInTouchMode = context?.isTvSettings() == true
|
result_season_button?.isFocusableInTouchMode = context?.isTvSettings() == true
|
||||||
result_episode_select?.isFocusableInTouchMode = context?.isTvSettings() == true
|
result_episode_select?.isFocusableInTouchMode = context?.isTvSettings() == true
|
||||||
result_dub_select?.isFocusableInTouchMode = context?.isTvSettings() == true
|
result_dub_select?.isFocusableInTouchMode = context?.isTvSettings() == true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
context?.let { ctx ->
|
context?.let { ctx ->
|
||||||
val arrayAdapter = ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
val arrayAdapter = ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
||||||
/*
|
/*
|
||||||
|
@ -633,19 +509,6 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result_mini_sync?.adapter = ImageAdapter(
|
|
||||||
R.layout.result_mini_image,
|
|
||||||
nextFocusDown = R.id.result_sync_set_score,
|
|
||||||
clickCallback = { action ->
|
|
||||||
if (action == IMAGE_CLICK || action == IMAGE_LONG_CLICK) {
|
|
||||||
if (result_overlapping_panels?.getSelectedPanel()?.ordinal == 1) {
|
|
||||||
result_overlapping_panels?.openStartPanel()
|
|
||||||
} else {
|
|
||||||
result_overlapping_panels?.closePanels()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
observe(syncModel.synced) { list ->
|
observe(syncModel.synced) { list ->
|
||||||
result_sync_names?.text =
|
result_sync_names?.text =
|
||||||
list.filter { it.isSynced && it.hasAccount }.joinToString { it.name }
|
list.filter { it.isSynced && it.hasAccount }.joinToString { it.name }
|
||||||
|
@ -769,8 +632,9 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
result_resume_series_button?.isVisible = !value.isMovie
|
result_resume_series_button?.isVisible = !value.isMovie
|
||||||
|
result_resume_series_button_play?.isVisible = !value.isMovie
|
||||||
|
|
||||||
result_resume_series_button?.setOnClickListener {
|
val click = View.OnClickListener {
|
||||||
viewModel.handleAction(
|
viewModel.handleAction(
|
||||||
activity,
|
activity,
|
||||||
EpisodeClickEvent(
|
EpisodeClickEvent(
|
||||||
|
@ -778,6 +642,9 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result_resume_series_button?.setOnClickListener(click)
|
||||||
|
result_resume_series_button_play?.setOnClickListener(click)
|
||||||
}
|
}
|
||||||
is Some.None -> {
|
is Some.None -> {
|
||||||
result_resume_parent?.isVisible = false
|
result_resume_parent?.isVisible = false
|
||||||
|
@ -803,156 +670,6 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.selectedSeason) { text ->
|
|
||||||
result_season_button.setText(text)
|
|
||||||
|
|
||||||
// If the season button is visible the result season button will be next focus down
|
|
||||||
if (result_season_button?.isVisible == true)
|
|
||||||
if (result_resume_parent?.isVisible == true)
|
|
||||||
setFocusUpAndDown(result_resume_series_button, result_season_button)
|
|
||||||
else
|
|
||||||
setFocusUpAndDown(result_bookmark_button, result_season_button)
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(viewModel.selectedDubStatus) { status ->
|
|
||||||
result_dub_select?.setText(status)
|
|
||||||
|
|
||||||
if (result_dub_select?.isVisible == true)
|
|
||||||
if (result_season_button?.isVisible != true && result_episode_select?.isVisible != true) {
|
|
||||||
if (result_resume_parent?.isVisible == true)
|
|
||||||
setFocusUpAndDown(result_resume_series_button, result_dub_select)
|
|
||||||
else
|
|
||||||
setFocusUpAndDown(result_bookmark_button, result_dub_select)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(viewModel.selectPopup) { popup ->
|
|
||||||
when (popup) {
|
|
||||||
is Some.Success -> {
|
|
||||||
popupDialog?.dismissSafe(activity)
|
|
||||||
|
|
||||||
popupDialog = activity?.let { act ->
|
|
||||||
val pop = popup.value
|
|
||||||
val options = pop.getOptions(act)
|
|
||||||
val title = pop.getTitle(act)
|
|
||||||
|
|
||||||
act.showBottomDialogInstant(
|
|
||||||
options, title, {
|
|
||||||
popupDialog = null
|
|
||||||
pop.callback(null)
|
|
||||||
}, {
|
|
||||||
popupDialog = null
|
|
||||||
pop.callback(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is Some.None -> {
|
|
||||||
popupDialog?.dismissSafe(activity)
|
|
||||||
popupDialog = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//showBottomDialogInstant
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(viewModel.loadedLinks) { load ->
|
|
||||||
when (load) {
|
|
||||||
is Some.Success -> {
|
|
||||||
if (loadingDialog?.isShowing != true) {
|
|
||||||
loadingDialog?.dismissSafe(activity)
|
|
||||||
loadingDialog = null
|
|
||||||
}
|
|
||||||
loadingDialog = loadingDialog ?: context?.let { ctx ->
|
|
||||||
val builder =
|
|
||||||
BottomSheetDialog(ctx)
|
|
||||||
builder.setContentView(R.layout.bottom_loading)
|
|
||||||
builder.setOnDismissListener {
|
|
||||||
loadingDialog = null
|
|
||||||
viewModel.cancelLinks()
|
|
||||||
}
|
|
||||||
//builder.setOnCancelListener {
|
|
||||||
// it?.dismiss()
|
|
||||||
//}
|
|
||||||
builder.setCanceledOnTouchOutside(true)
|
|
||||||
|
|
||||||
builder.show()
|
|
||||||
|
|
||||||
builder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is Some.None -> {
|
|
||||||
loadingDialog?.dismissSafe(activity)
|
|
||||||
loadingDialog = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(viewModel.selectedRange) { range ->
|
|
||||||
result_episode_select.setText(range)
|
|
||||||
|
|
||||||
// If Season button is invisible then the bookmark button next focus is episode select
|
|
||||||
if (result_episode_select?.isVisible == true)
|
|
||||||
if (result_season_button?.isVisible != true) {
|
|
||||||
if (result_resume_parent?.isVisible == true)
|
|
||||||
setFocusUpAndDown(result_resume_series_button, result_episode_select)
|
|
||||||
else
|
|
||||||
setFocusUpAndDown(result_bookmark_button, result_episode_select)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// val preferDub = context?.getApiDubstatusSettings()?.all { it == DubStatus.Dubbed } == true
|
|
||||||
|
|
||||||
observe(viewModel.dubSubSelections) { range ->
|
|
||||||
result_dub_select.setOnClickListener { view ->
|
|
||||||
view?.context?.let { ctx ->
|
|
||||||
view.popupMenuNoIconsAndNoStringRes(range
|
|
||||||
.mapNotNull { (text, status) ->
|
|
||||||
Pair(
|
|
||||||
status.ordinal,
|
|
||||||
text?.asStringNull(ctx) ?: return@mapNotNull null
|
|
||||||
)
|
|
||||||
}) {
|
|
||||||
viewModel.changeDubStatus(DubStatus.values()[itemId])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(viewModel.rangeSelections) { range ->
|
|
||||||
result_episode_select?.setOnClickListener { view ->
|
|
||||||
view?.context?.let { ctx ->
|
|
||||||
val names = range
|
|
||||||
.mapNotNull { (text, r) ->
|
|
||||||
r to (text?.asStringNull(ctx) ?: return@mapNotNull null)
|
|
||||||
}
|
|
||||||
|
|
||||||
view.popupMenuNoIconsAndNoStringRes(names.mapIndexed { index, (_, name) ->
|
|
||||||
index to name
|
|
||||||
}) {
|
|
||||||
viewModel.changeRange(names[itemId].first)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(viewModel.seasonSelections) { seasonList ->
|
|
||||||
result_season_button?.setOnClickListener { view ->
|
|
||||||
view?.context?.let { ctx ->
|
|
||||||
val names = seasonList
|
|
||||||
.mapNotNull { (text, r) ->
|
|
||||||
r to (text?.asStringNull(ctx) ?: return@mapNotNull null)
|
|
||||||
}
|
|
||||||
|
|
||||||
view.popupMenuNoIconsAndNoStringRes(names.mapIndexed { index, (_, name) ->
|
|
||||||
index to name
|
|
||||||
}) {
|
|
||||||
viewModel.changeSeason(names[itemId].first)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result_cast_items?.setOnFocusChangeListener { _, hasFocus ->
|
result_cast_items?.setOnFocusChangeListener { _, hasFocus ->
|
||||||
// Always escape focus
|
// Always escape focus
|
||||||
if (hasFocus) result_bookmark_button?.requestFocus()
|
if (hasFocus) result_bookmark_button?.requestFocus()
|
||||||
|
@ -1178,14 +895,6 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result_recommendations?.adapter =
|
|
||||||
SearchAdapter(
|
|
||||||
ArrayList(),
|
|
||||||
result_recommendations,
|
|
||||||
) { callback ->
|
|
||||||
SearchHelper.handleSearchClickCallback(activity, callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
context?.let { ctx ->
|
context?.let { ctx ->
|
||||||
val dubStatus = if(ctx.getApiDubstatusSettings().contains(DubStatus.Dubbed)) DubStatus.Dubbed else DubStatus.Subbed
|
val dubStatus = if(ctx.getApiDubstatusSettings().contains(DubStatus.Dubbed)) DubStatus.Dubbed else DubStatus.Subbed
|
||||||
|
|
||||||
|
@ -1239,16 +948,5 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelsChildGestureRegionObserver.Provider.get().addGestureRegionsUpdateListener(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
PanelsChildGestureRegionObserver.Provider.get().addGestureRegionsUpdateListener(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onGestureRegionsUpdate(gestureRegions: List<Rect>) {
|
|
||||||
result_overlapping_panels?.setChildGestureRegions(gestureRegions)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,380 @@
|
||||||
|
package com.lagradost.cloudstream3.ui.result
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isGone
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.discord.panels.OverlappingPanelsLayout
|
||||||
|
import com.discord.panels.PanelsChildGestureRegionObserver
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
||||||
|
import com.lagradost.cloudstream3.DubStatus
|
||||||
|
import com.lagradost.cloudstream3.LoadResponse
|
||||||
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.SearchResponse
|
||||||
|
import com.lagradost.cloudstream3.mvvm.Some
|
||||||
|
import com.lagradost.cloudstream3.mvvm.observe
|
||||||
|
import com.lagradost.cloudstream3.ui.WatchType
|
||||||
|
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||||
|
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
||||||
|
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.dismissSafe
|
||||||
|
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||||
|
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIcons
|
||||||
|
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.*
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
||||||
|
import kotlinx.android.synthetic.main.result_recommendations.*
|
||||||
|
import kotlinx.android.synthetic.main.trailer_custom_layout.*
|
||||||
|
|
||||||
|
class ResultFragmentPhone : ResultFragment() {
|
||||||
|
var currentTrailers: List<ExtractorLink> = emptyList()
|
||||||
|
var currentTrailerIndex = 0
|
||||||
|
|
||||||
|
override fun nextMirror() {
|
||||||
|
currentTrailerIndex++
|
||||||
|
loadTrailer()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasNextMirror(): Boolean {
|
||||||
|
return currentTrailerIndex + 1 < currentTrailers.size
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun playerError(exception: Exception) {
|
||||||
|
if (player.getIsPlaying()) { // because we dont want random toasts in player
|
||||||
|
super.playerError(exception)
|
||||||
|
} else {
|
||||||
|
nextMirror()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadTrailer(index: Int? = null) {
|
||||||
|
val isSuccess =
|
||||||
|
currentTrailers.getOrNull(index ?: currentTrailerIndex)?.let { trailer ->
|
||||||
|
context?.let { ctx ->
|
||||||
|
player.onPause()
|
||||||
|
player.loadPlayer(
|
||||||
|
ctx,
|
||||||
|
false,
|
||||||
|
trailer,
|
||||||
|
null,
|
||||||
|
startPosition = 0L,
|
||||||
|
subtitles = emptySet(),
|
||||||
|
subtitle = null,
|
||||||
|
autoPlay = false
|
||||||
|
)
|
||||||
|
true
|
||||||
|
} ?: run {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} ?: run {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
result_trailer_loading?.isVisible = isSuccess
|
||||||
|
result_smallscreen_holder?.isVisible = !isSuccess && !isFullScreenPlayer
|
||||||
|
|
||||||
|
// We don't want the trailer to be focusable if it's not visible
|
||||||
|
result_smallscreen_holder?.descendantFocusability = if (isSuccess) {
|
||||||
|
ViewGroup.FOCUS_AFTER_DESCENDANTS
|
||||||
|
} else {
|
||||||
|
ViewGroup.FOCUS_BLOCK_DESCENDANTS
|
||||||
|
}
|
||||||
|
result_fullscreen_holder?.isVisible = !isSuccess && isFullScreenPlayer
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setTrailers(trailers: List<ExtractorLink>?) {
|
||||||
|
context?.updateHasTrailers()
|
||||||
|
if (!LoadResponse.isTrailersEnabled) return
|
||||||
|
currentTrailers = trailers?.sortedBy { -it.quality } ?: emptyList()
|
||||||
|
loadTrailer()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
//somehow this still leaks and I dont know why????
|
||||||
|
// todo look at https://github.com/discord/OverlappingPanels/blob/70b4a7cf43c6771873b1e091029d332896d41a1a/sample_app/src/main/java/com/discord/sampleapp/MainActivity.kt
|
||||||
|
PanelsChildGestureRegionObserver.Provider.get().let { obs ->
|
||||||
|
result_cast_items?.let {
|
||||||
|
obs.unregister(it)
|
||||||
|
}
|
||||||
|
obs.removeGestureRegionsUpdateListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
var loadingDialog: Dialog? = null
|
||||||
|
var popupDialog: Dialog? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets next focus to allow navigation up and down between 2 views
|
||||||
|
* if either of them is null nothing happens.
|
||||||
|
**/
|
||||||
|
private fun setFocusUpAndDown(upper: View?, down: View?) {
|
||||||
|
if (upper == null || down == null) return
|
||||||
|
upper.nextFocusDownId = down.id
|
||||||
|
down.nextFocusUpId = upper.id
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
player_open_source?.setOnClickListener {
|
||||||
|
currentTrailers.getOrNull(currentTrailerIndex)?.let {
|
||||||
|
context?.openBrowser(it.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result_recommendations?.spanCount = 3
|
||||||
|
result_overlapping_panels?.setStartPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
||||||
|
result_overlapping_panels?.setEndPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
||||||
|
|
||||||
|
result_recommendations?.adapter =
|
||||||
|
SearchAdapter(
|
||||||
|
ArrayList(),
|
||||||
|
result_recommendations,
|
||||||
|
) { callback ->
|
||||||
|
SearchHelper.handleSearchClickCallback(activity, callback)
|
||||||
|
}
|
||||||
|
PanelsChildGestureRegionObserver.Provider.get().addGestureRegionsUpdateListener(this)
|
||||||
|
|
||||||
|
result_cast_items?.let {
|
||||||
|
PanelsChildGestureRegionObserver.Provider.get().register(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
result_back?.setOnClickListener {
|
||||||
|
activity?.popCurrentPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
result_bookmark_button?.setOnClickListener {
|
||||||
|
it.popupMenuNoIcons(
|
||||||
|
items = WatchType.values()
|
||||||
|
.map { watchType -> Pair(watchType.internalId, watchType.stringRes) },
|
||||||
|
//.map { watchType -> Triple(watchType.internalId, watchType.iconRes, watchType.stringRes) },
|
||||||
|
) {
|
||||||
|
viewModel.updateWatchStatus(WatchType.fromInternalId(this.itemId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result_mini_sync?.adapter = ImageAdapter(
|
||||||
|
R.layout.result_mini_image,
|
||||||
|
nextFocusDown = R.id.result_sync_set_score,
|
||||||
|
clickCallback = { action ->
|
||||||
|
if (action == IMAGE_CLICK || action == IMAGE_LONG_CLICK) {
|
||||||
|
if (result_overlapping_panels?.getSelectedPanel()?.ordinal == 1) {
|
||||||
|
result_overlapping_panels?.openStartPanel()
|
||||||
|
} else {
|
||||||
|
result_overlapping_panels?.closePanels()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
observe(viewModel.selectPopup) { popup ->
|
||||||
|
when (popup) {
|
||||||
|
is Some.Success -> {
|
||||||
|
popupDialog?.dismissSafe(activity)
|
||||||
|
|
||||||
|
popupDialog = activity?.let { act ->
|
||||||
|
val pop = popup.value
|
||||||
|
val options = pop.getOptions(act)
|
||||||
|
val title = pop.getTitle(act)
|
||||||
|
|
||||||
|
act.showBottomDialogInstant(
|
||||||
|
options, title, {
|
||||||
|
popupDialog = null
|
||||||
|
pop.callback(null)
|
||||||
|
}, {
|
||||||
|
popupDialog = null
|
||||||
|
pop.callback(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Some.None -> {
|
||||||
|
popupDialog?.dismissSafe(activity)
|
||||||
|
popupDialog = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//showBottomDialogInstant
|
||||||
|
}
|
||||||
|
|
||||||
|
observe(viewModel.loadedLinks) { load ->
|
||||||
|
when (load) {
|
||||||
|
is Some.Success -> {
|
||||||
|
if (loadingDialog?.isShowing != true) {
|
||||||
|
loadingDialog?.dismissSafe(activity)
|
||||||
|
loadingDialog = null
|
||||||
|
}
|
||||||
|
loadingDialog = loadingDialog ?: context?.let { ctx ->
|
||||||
|
val builder =
|
||||||
|
BottomSheetDialog(ctx)
|
||||||
|
builder.setContentView(R.layout.bottom_loading)
|
||||||
|
builder.setOnDismissListener {
|
||||||
|
loadingDialog = null
|
||||||
|
viewModel.cancelLinks()
|
||||||
|
}
|
||||||
|
//builder.setOnCancelListener {
|
||||||
|
// it?.dismiss()
|
||||||
|
//}
|
||||||
|
builder.setCanceledOnTouchOutside(true)
|
||||||
|
|
||||||
|
builder.show()
|
||||||
|
|
||||||
|
builder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Some.None -> {
|
||||||
|
loadingDialog?.dismissSafe(activity)
|
||||||
|
loadingDialog = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
observe(viewModel.selectedSeason) { text ->
|
||||||
|
result_season_button.setText(text)
|
||||||
|
|
||||||
|
// If the season button is visible the result season button will be next focus down
|
||||||
|
if (result_season_button?.isVisible == true)
|
||||||
|
if (result_resume_parent?.isVisible == true)
|
||||||
|
setFocusUpAndDown(result_resume_series_button, result_season_button)
|
||||||
|
else
|
||||||
|
setFocusUpAndDown(result_bookmark_button, result_season_button)
|
||||||
|
}
|
||||||
|
|
||||||
|
observe(viewModel.selectedDubStatus) { status ->
|
||||||
|
result_dub_select?.setText(status)
|
||||||
|
|
||||||
|
if (result_dub_select?.isVisible == true)
|
||||||
|
if (result_season_button?.isVisible != true && result_episode_select?.isVisible != true) {
|
||||||
|
if (result_resume_parent?.isVisible == true)
|
||||||
|
setFocusUpAndDown(result_resume_series_button, result_dub_select)
|
||||||
|
else
|
||||||
|
setFocusUpAndDown(result_bookmark_button, result_dub_select)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
observe(viewModel.selectedRange) { range ->
|
||||||
|
result_episode_select.setText(range)
|
||||||
|
|
||||||
|
// If Season button is invisible then the bookmark button next focus is episode select
|
||||||
|
if (result_episode_select?.isVisible == true)
|
||||||
|
if (result_season_button?.isVisible != true) {
|
||||||
|
if (result_resume_parent?.isVisible == true)
|
||||||
|
setFocusUpAndDown(result_resume_series_button, result_episode_select)
|
||||||
|
else
|
||||||
|
setFocusUpAndDown(result_bookmark_button, result_episode_select)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// val preferDub = context?.getApiDubstatusSettings()?.all { it == DubStatus.Dubbed } == true
|
||||||
|
|
||||||
|
observe(viewModel.dubSubSelections) { range ->
|
||||||
|
result_dub_select.setOnClickListener { view ->
|
||||||
|
view?.context?.let { ctx ->
|
||||||
|
view.popupMenuNoIconsAndNoStringRes(range
|
||||||
|
.mapNotNull { (text, status) ->
|
||||||
|
Pair(
|
||||||
|
status.ordinal,
|
||||||
|
text?.asStringNull(ctx) ?: return@mapNotNull null
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
viewModel.changeDubStatus(DubStatus.values()[itemId])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
observe(viewModel.rangeSelections) { range ->
|
||||||
|
result_episode_select?.setOnClickListener { view ->
|
||||||
|
view?.context?.let { ctx ->
|
||||||
|
val names = range
|
||||||
|
.mapNotNull { (text, r) ->
|
||||||
|
r to (text?.asStringNull(ctx) ?: return@mapNotNull null)
|
||||||
|
}
|
||||||
|
|
||||||
|
view.popupMenuNoIconsAndNoStringRes(names.mapIndexed { index, (_, name) ->
|
||||||
|
index to name
|
||||||
|
}) {
|
||||||
|
viewModel.changeRange(names[itemId].first)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
observe(viewModel.seasonSelections) { seasonList ->
|
||||||
|
result_season_button?.setOnClickListener { view ->
|
||||||
|
view?.context?.let { ctx ->
|
||||||
|
val names = seasonList
|
||||||
|
.mapNotNull { (text, r) ->
|
||||||
|
r to (text?.asStringNull(ctx) ?: return@mapNotNull null)
|
||||||
|
}
|
||||||
|
|
||||||
|
view.popupMenuNoIconsAndNoStringRes(names.mapIndexed { index, (_, name) ->
|
||||||
|
index to name
|
||||||
|
}) {
|
||||||
|
viewModel.changeSeason(names[itemId].first)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
PanelsChildGestureRegionObserver.Provider.get().addGestureRegionsUpdateListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onGestureRegionsUpdate(gestureRegions: List<Rect>) {
|
||||||
|
result_overlapping_panels?.setChildGestureRegions(gestureRegions)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||||
|
val isInvalid = rec.isNullOrEmpty()
|
||||||
|
result_recommendations?.isGone = isInvalid
|
||||||
|
result_recommendations_btt?.isGone = isInvalid
|
||||||
|
result_recommendations_btt?.setOnClickListener {
|
||||||
|
val nextFocusDown = if (result_overlapping_panels?.getSelectedPanel()?.ordinal == 1) {
|
||||||
|
result_overlapping_panels?.openEndPanel()
|
||||||
|
R.id.result_recommendations
|
||||||
|
} else {
|
||||||
|
result_overlapping_panels?.closePanels()
|
||||||
|
R.id.result_description
|
||||||
|
}
|
||||||
|
|
||||||
|
result_recommendations_btt?.nextFocusDownId = nextFocusDown
|
||||||
|
result_search?.nextFocusDownId = nextFocusDown
|
||||||
|
result_open_in_browser?.nextFocusDownId = nextFocusDown
|
||||||
|
result_share?.nextFocusDownId = nextFocusDown
|
||||||
|
}
|
||||||
|
result_overlapping_panels?.setEndPanelLockState(if (isInvalid) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)
|
||||||
|
|
||||||
|
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
|
||||||
|
rec?.map { it.apiName }?.distinct()?.let { apiNames ->
|
||||||
|
// very dirty selection
|
||||||
|
result_recommendations_filter_button?.isVisible = apiNames.size > 1
|
||||||
|
result_recommendations_filter_button?.text = matchAgainst
|
||||||
|
result_recommendations_filter_button?.setOnClickListener { _ ->
|
||||||
|
activity?.showBottomDialog(
|
||||||
|
apiNames,
|
||||||
|
apiNames.indexOf(matchAgainst),
|
||||||
|
getString(R.string.home_change_provider_img_des), false, {}
|
||||||
|
) {
|
||||||
|
setRecommendations(rec, apiNames[it])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ?: run {
|
||||||
|
result_recommendations_filter_button?.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
result_recommendations?.post {
|
||||||
|
rec?.let { list ->
|
||||||
|
(result_recommendations?.adapter as SearchAdapter?)?.updateList(list.filter { it.apiName == matchAgainst })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.lagradost.cloudstream3.ui.result
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.SearchResponse
|
||||||
|
|
||||||
|
class ResultFragmentTv : ResultFragment() {
|
||||||
|
override val resultLayout = R.layout.fragment_result_tv
|
||||||
|
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,11 +21,13 @@ sealed class UiText {
|
||||||
data class DynamicString(val value: String) : UiText() {
|
data class DynamicString(val value: String) : UiText() {
|
||||||
override fun toString(): String = value
|
override fun toString(): String = value
|
||||||
}
|
}
|
||||||
|
|
||||||
class StringResource(
|
class StringResource(
|
||||||
@StringRes val resId: Int,
|
@StringRes val resId: Int,
|
||||||
val args: List<Any>
|
val args: List<Any>
|
||||||
) : UiText() {
|
) : UiText() {
|
||||||
override fun toString(): String = "resId = $resId\nargs = ${args.toList().map { "(${it::class} = $it)" }}"
|
override fun toString(): String =
|
||||||
|
"resId = $resId\nargs = ${args.toList().map { "(${it::class} = $it)" }}"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun asStringNull(context: Context?): String? {
|
fun asStringNull(context: Context?): String? {
|
||||||
|
@ -137,7 +139,14 @@ fun TextView?.setText(text: UiText?) {
|
||||||
if (text == null) {
|
if (text == null) {
|
||||||
this.isVisible = false
|
this.isVisible = false
|
||||||
} else {
|
} else {
|
||||||
val str = text.asStringNull(context)
|
val str = text.asStringNull(context)?.let {
|
||||||
|
if (this.maxLines == 1) {
|
||||||
|
it.replace("\n", " ")
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.isGone = str.isNullOrBlank()
|
this.isGone = str.isNullOrBlank()
|
||||||
this.text = str
|
this.text = str
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@ import com.lagradost.cloudstream3.isMovieType
|
||||||
import com.lagradost.cloudstream3.mapper
|
import com.lagradost.cloudstream3.mapper
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.ui.result.ResultFragment
|
import com.lagradost.cloudstream3.ui.result.ResultFragment
|
||||||
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.FillerEpisodeCheck.toClassDir
|
import com.lagradost.cloudstream3.utils.FillerEpisodeCheck.toClassDir
|
||||||
import com.lagradost.cloudstream3.utils.JsUnpacker.Companion.load
|
import com.lagradost.cloudstream3.utils.JsUnpacker.Companion.load
|
||||||
|
@ -313,6 +315,15 @@ object AppUtils {
|
||||||
|
|
||||||
//private val viewModel: ResultViewModel by activityViewModels()
|
//private val viewModel: ResultViewModel by activityViewModels()
|
||||||
|
|
||||||
|
private fun getResultsId(context: Context) : Int {
|
||||||
|
return R.id.global_to_navigation_results_phone
|
||||||
|
//return if(context.isTvSettings()) {
|
||||||
|
// R.id.global_to_navigation_results_tv
|
||||||
|
//} else {
|
||||||
|
// R.id.global_to_navigation_results_phone
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
fun AppCompatActivity.loadResult(
|
fun AppCompatActivity.loadResult(
|
||||||
url: String,
|
url: String,
|
||||||
apiName: String,
|
apiName: String,
|
||||||
|
@ -322,7 +333,7 @@ object AppUtils {
|
||||||
this.runOnUiThread {
|
this.runOnUiThread {
|
||||||
// viewModelStore.clear()
|
// viewModelStore.clear()
|
||||||
this.navigate(
|
this.navigate(
|
||||||
R.id.global_to_navigation_results,
|
getResultsId(this.applicationContext ?: return@runOnUiThread),
|
||||||
ResultFragment.newInstance(url, apiName, startAction, startValue)
|
ResultFragment.newInstance(url, apiName, startAction, startValue)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -336,7 +347,7 @@ object AppUtils {
|
||||||
this?.runOnUiThread {
|
this?.runOnUiThread {
|
||||||
// viewModelStore.clear()
|
// viewModelStore.clear()
|
||||||
this.navigate(
|
this.navigate(
|
||||||
R.id.global_to_navigation_results,
|
getResultsId(this),
|
||||||
ResultFragment.newInstance(card, startAction, startValue)
|
ResultFragment.newInstance(card, startAction, startValue)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -465,6 +465,7 @@
|
||||||
android:textColor="?attr/grayTextColor"
|
android:textColor="?attr/grayTextColor"
|
||||||
android:textSize="15sp"
|
android:textSize="15sp"
|
||||||
tools:text="@string/provider_info_meta" />
|
tools:text="@string/provider_info_meta" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/result_no_episodes"
|
android:id="@+id/result_no_episodes"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
699
app/src/main/res/layout/fragment_result_tv.xml
Normal file
699
app/src/main/res/layout/fragment_result_tv.xml
Normal file
|
@ -0,0 +1,699 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/result_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
style="@style/DarkFragment"
|
||||||
|
android:background="?attr/primaryBlackBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true">
|
||||||
|
|
||||||
|
<com.facebook.shimmer.ShimmerFrameLayout
|
||||||
|
android:id="@+id/result_loading"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:shimmer_auto_start="true"
|
||||||
|
app:shimmer_base_alpha="0.2"
|
||||||
|
app:shimmer_duration="@integer/loading_time"
|
||||||
|
app:shimmer_highlight_alpha="0.3"
|
||||||
|
tools:visibility="gone">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/result_padding"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginBottom="@dimen/loading_margin"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<include layout="@layout/loading_poster" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="@dimen/loading_margin"
|
||||||
|
android:layout_marginEnd="@dimen/loading_margin"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include layout="@layout/loading_line" />
|
||||||
|
|
||||||
|
<include layout="@layout/loading_line" />
|
||||||
|
|
||||||
|
<include layout="@layout/loading_line" />
|
||||||
|
|
||||||
|
<include layout="@layout/loading_line" />
|
||||||
|
|
||||||
|
<include layout="@layout/loading_line_short" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<include layout="@layout/loading_episode" />
|
||||||
|
|
||||||
|
<include layout="@layout/loading_episode" />
|
||||||
|
|
||||||
|
<include layout="@layout/loading_episode" />
|
||||||
|
</LinearLayout>
|
||||||
|
</com.facebook.shimmer.ShimmerFrameLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/result_loading_error"
|
||||||
|
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="gone">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/result_reload_connectionerror"
|
||||||
|
style="@style/WhiteButton"
|
||||||
|
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:minWidth="200dp"
|
||||||
|
android:text="@string/reload_error"
|
||||||
|
app:icon="@drawable/ic_baseline_autorenew_24" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/result_reload_connection_open_in_browser"
|
||||||
|
style="@style/BlackButton"
|
||||||
|
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:minWidth="200dp"
|
||||||
|
android:text="@string/result_open_in_browser"
|
||||||
|
app:icon="@drawable/ic_baseline_public_24" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_error_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textColor="?attr/textColor" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/result_finish_loading"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:id="@+id/result_scroll"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/primaryGrayBackground">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?attr/primaryBlackBackground"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.facebook.shimmer.ShimmerFrameLayout
|
||||||
|
tools:visibility="gone"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:id="@+id/result_trailer_loading"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:shimmer_auto_start="true"
|
||||||
|
app:shimmer_base_alpha="0.2"
|
||||||
|
app:shimmer_duration="@integer/loading_time"
|
||||||
|
app:shimmer_highlight_alpha="0.3">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/result_padding"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:background="@color/grayShimmer"
|
||||||
|
app:cardCornerRadius="@dimen/loading_radius"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="150dp"
|
||||||
|
android:foreground="@drawable/outline_drawable" />
|
||||||
|
</LinearLayout>
|
||||||
|
</com.facebook.shimmer.ShimmerFrameLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:descendantFocusability="blocksDescendants"
|
||||||
|
android:id="@+id/result_smallscreen_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<include layout="@layout/fragment_trailer" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="@dimen/result_padding"
|
||||||
|
android:paddingEnd="@dimen/result_padding">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginBottom="15dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:visibility="visible">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="The Perfect Run The Perfect Run" />
|
||||||
|
|
||||||
|
<com.lagradost.cloudstream3.widget.FlowLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:itemSpacing="10dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/result_meta_site"
|
||||||
|
style="@style/SmallBlackButton"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
tools:text="Gogoanime" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_meta_type"
|
||||||
|
style="@style/ResultInfoText"
|
||||||
|
tools:text="Movie" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_meta_year"
|
||||||
|
style="@style/ResultInfoText"
|
||||||
|
tools:text="2022" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_meta_rating"
|
||||||
|
style="@style/ResultInfoText"
|
||||||
|
tools:text="Rated: 8.5/10.0" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_meta_status"
|
||||||
|
style="@style/ResultInfoText"
|
||||||
|
tools:text="Ongoing" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_meta_duration"
|
||||||
|
style="@style/ResultInfoText"
|
||||||
|
tools:text="121min" />
|
||||||
|
</com.lagradost.cloudstream3.widget.FlowLayout>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This has half margin and half padding to make TV focus on description look better.
|
||||||
|
The focus outline now settles between the poster and text.
|
||||||
|
-->
|
||||||
|
<TextView
|
||||||
|
android:padding="5dp"
|
||||||
|
android:maxLength="1000"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:id="@+id/result_description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:foreground="@drawable/outline_drawable"
|
||||||
|
android:nextFocusUp="@id/result_back"
|
||||||
|
android:nextFocusDown="@id/result_bookmark_button"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
android:textSize="15sp"
|
||||||
|
tools:text="Ryan Quicksave Romano is an eccentric adventurer with a strange power: he can create a save-point in time and redo his life whenever he dies. Arriving in New Rome, the glitzy capital of sin of a rebuilding Europe, he finds the city torn between mega-corporations, sponsored heroes, superpowered criminals, and true monsters. It's a time of chaos, where potions can grant the power to rule the world and dangers lurk everywhere. " />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_cast_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:textColor="?attr/grayTextColor"
|
||||||
|
android:textSize="15sp"
|
||||||
|
tools:text="Cast: Joe Ligma" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
tools:visibility="gone"
|
||||||
|
android:nextFocusUp="@id/result_bookmark_button"
|
||||||
|
android:nextFocusDown="@id/result_play_movie"
|
||||||
|
|
||||||
|
android:id="@+id/result_cast_items"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:descendantFocusability="afterDescendants"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fadingEdge="horizontal"
|
||||||
|
android:focusableInTouchMode="false"
|
||||||
|
android:focusable="false"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:requiresFadingEdge="horizontal"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:itemCount="2"
|
||||||
|
tools:listitem="@layout/cast_item" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_vpn"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?attr/grayTextColor"
|
||||||
|
android:textSize="15sp"
|
||||||
|
tools:text="@string/vpn_torrent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_info"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:textColor="?attr/grayTextColor"
|
||||||
|
android:textSize="15sp"
|
||||||
|
tools:text="@string/provider_info_meta" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_no_episodes"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:textColor="?attr/grayTextColor"
|
||||||
|
android:textSize="15sp"
|
||||||
|
tools:text="@string/no_episodes_found" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_tag_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:text="@string/result_tags"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
android:textSize="17sp"
|
||||||
|
android:textStyle="normal"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
|
||||||
|
<com.lagradost.cloudstream3.widget.FlowLayout
|
||||||
|
android:id="@+id/result_tag"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_coming_soon"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingTop="50dp"
|
||||||
|
android:text="@string/coming_soon"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/result_data_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/result_add_sync"
|
||||||
|
style="@style/WhiteButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:text="@string/add_sync"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:icon="@drawable/ic_baseline_add_24" />
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/result_movie_parent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/result_play_movie"
|
||||||
|
style="@style/WhiteButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:layout_marginEnd="5dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:nextFocusUp="@id/result_bookmark_button"
|
||||||
|
android:nextFocusDown="@id/result_download_movie"
|
||||||
|
android:text="@string/play_movie_button"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:icon="@drawable/ic_baseline_play_arrow_24">
|
||||||
|
|
||||||
|
<requestFocus />
|
||||||
|
|
||||||
|
</com.google.android.material.button.MaterialButton>
|
||||||
|
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:id="@+id/result_movie_progress_downloaded_holder"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/result_download_movie"
|
||||||
|
style="@style/BlackButton"
|
||||||
|
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:layout_marginEnd="0dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
|
||||||
|
android:nextFocusUp="@id/result_play_movie"
|
||||||
|
android:nextFocusDown="@id/result_season_button"
|
||||||
|
android:visibility="visible" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<androidx.core.widget.ContentLoadingProgressBar
|
||||||
|
android:id="@+id/result_movie_progress_downloaded"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="25dp"
|
||||||
|
android:layout_height="25dp"
|
||||||
|
android:layout_gravity="end|center_vertical"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:background="@drawable/circle_shape"
|
||||||
|
android:indeterminate="false"
|
||||||
|
android:max="100"
|
||||||
|
android:paddingStart="5dp"
|
||||||
|
android:paddingEnd="5dp"
|
||||||
|
android:progress="30"
|
||||||
|
android:progressDrawable="@drawable/circular_progress_bar_filled"
|
||||||
|
android:visibility="visible" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/result_movie_download_icon"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:background="?selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="@string/download"
|
||||||
|
android:src="@drawable/ic_baseline_play_arrow_24"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:tint="?attr/white" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_movie_download_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:letterSpacing="0.09"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="Downloading" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_movie_download_text_precentage"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:letterSpacing="0.09"
|
||||||
|
android:paddingStart="5dp"
|
||||||
|
android:paddingEnd="5dp"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="68%" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/result_resume_parent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/result_next_series_button"
|
||||||
|
style="@style/WhiteButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:layout_marginEnd="0dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:nextFocusUp="@id/result_bookmark_button"
|
||||||
|
android:nextFocusDown="@id/result_download_movie"
|
||||||
|
android:text="@string/next_episode"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:icon="@drawable/cast_ic_mini_controller_skip_next" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:id="@+id/result_resume_series_button_play"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
|
||||||
|
android:background="?selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="@string/download"
|
||||||
|
android:src="@drawable/ic_baseline_play_arrow_24"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:tint="?attr/white" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center"
|
||||||
|
android:id="@+id/result_resume_series_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
android:textSize="17sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="S1E1 Episode 1" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:maxLines="1"
|
||||||
|
android:id="@+id/result_resume_series_progress_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:textColor="?attr/grayTextColor"
|
||||||
|
tools:ignore="RtlSymmetry"
|
||||||
|
tools:text="69m remaining" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/result_resume_progress_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<androidx.core.widget.ContentLoadingProgressBar
|
||||||
|
android:id="@+id/result_resume_series_progress"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_gravity="end|center_vertical"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:indeterminate="false"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="0"
|
||||||
|
android:progressBackgroundTint="?attr/colorPrimary"
|
||||||
|
android:visibility="visible"
|
||||||
|
tools:progress="50"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/result_episodes_tab"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:id="@+id/result_season_selection"
|
||||||
|
tools:listitem="@layout/result_selection"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:id="@+id/result_range_selection"
|
||||||
|
tools:listitem="@layout/result_selection"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:id="@+id/result_dub_selection"
|
||||||
|
tools:listitem="@layout/result_selection"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/result_next_airing_holder"
|
||||||
|
android:layout_gravity="start"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:gravity="center"
|
||||||
|
|
||||||
|
android:id="@+id/result_next_airing"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?attr/grayTextColor"
|
||||||
|
android:textSize="17sp"
|
||||||
|
android:textStyle="normal"
|
||||||
|
tools:text="Episode 1022 will be released in" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:paddingEnd="5dp"
|
||||||
|
android:paddingStart="5dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:id="@+id/result_next_airing_time"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
android:textSize="17sp"
|
||||||
|
android:textStyle="normal"
|
||||||
|
tools:text="5d 3h 30m" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.facebook.shimmer.ShimmerFrameLayout
|
||||||
|
android:id="@+id/result_episode_loading"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:shimmer_auto_start="true"
|
||||||
|
app:shimmer_base_alpha="0.2"
|
||||||
|
app:shimmer_duration="@integer/loading_time"
|
||||||
|
app:shimmer_highlight_alpha="0.3"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include layout="@layout/loading_episode" />
|
||||||
|
|
||||||
|
<include layout="@layout/loading_episode" />
|
||||||
|
|
||||||
|
<include layout="@layout/loading_episode" />
|
||||||
|
|
||||||
|
<include layout="@layout/loading_episode" />
|
||||||
|
</LinearLayout>
|
||||||
|
</com.facebook.shimmer.ShimmerFrameLayout>
|
||||||
|
<!--<androidx.core.widget.ContentLoadingProgressBar
|
||||||
|
android:id="@+id/result_episode_loading"
|
||||||
|
|
||||||
|
style="@style/Widget.AppCompat.ProgressBar"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp" />-->
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/result_episodes"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="0dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
android:descendantFocusability="afterDescendants"
|
||||||
|
android:paddingBottom="100dp"
|
||||||
|
tools:listitem="@layout/result_episode" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
8
app/src/main/res/layout/result_selection.xml
Normal file
8
app/src/main/res/layout/result_selection.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.google.android.material.button.MaterialButton android:id="@+id/result_season_button"
|
||||||
|
style="@style/SelectableButton"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
tools:text="Season 1"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools" />
|
|
@ -4,10 +4,35 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/mobile_navigation"
|
android:id="@+id/mobile_navigation"
|
||||||
app:startDestination="@+id/navigation_home">
|
app:startDestination="@+id/navigation_home">
|
||||||
|
|
||||||
<action
|
<action
|
||||||
android:id="@+id/global_to_navigation_results"
|
android:id="@+id/global_to_navigation_results_tv"
|
||||||
app:destination="@id/navigation_results"
|
app:destination="@id/navigation_results_tv"
|
||||||
|
app:enterAnim="@anim/enter_anim"
|
||||||
|
app:exitAnim="@anim/exit_anim"
|
||||||
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
|
app:popExitAnim="@anim/exit_anim">
|
||||||
|
<argument
|
||||||
|
android:name="url"
|
||||||
|
app:argType="string" />
|
||||||
|
<argument
|
||||||
|
android:name="apiName"
|
||||||
|
app:argType="string" />
|
||||||
|
<argument
|
||||||
|
android:name="startAction"
|
||||||
|
android:defaultValue="0"
|
||||||
|
app:argType="integer" />
|
||||||
|
<argument
|
||||||
|
android:name="startValue"
|
||||||
|
android:defaultValue="0"
|
||||||
|
app:argType="integer" />
|
||||||
|
<argument
|
||||||
|
android:name="restart"
|
||||||
|
android:defaultValue="false"
|
||||||
|
app:argType="boolean" />
|
||||||
|
</action>
|
||||||
|
<action
|
||||||
|
android:id="@+id/global_to_navigation_results_phone"
|
||||||
|
app:destination="@id/navigation_results_phone"
|
||||||
app:enterAnim="@anim/enter_anim"
|
app:enterAnim="@anim/enter_anim"
|
||||||
app:exitAnim="@anim/exit_anim"
|
app:exitAnim="@anim/exit_anim"
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
|
@ -181,13 +206,6 @@
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim"
|
app:popExitAnim="@anim/exit_anim"
|
||||||
tools:layout="@layout/fragment_home">
|
tools:layout="@layout/fragment_home">
|
||||||
<action
|
|
||||||
android:id="@+id/action_navigation_home_to_navigation_results"
|
|
||||||
app:destination="@id/navigation_results"
|
|
||||||
app:enterAnim="@anim/enter_anim"
|
|
||||||
app:exitAnim="@anim/exit_anim"
|
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_navigation_home_to_navigation_quick_search"
|
android:id="@+id/action_navigation_home_to_navigation_quick_search"
|
||||||
app:destination="@id/navigation_quick_search"
|
app:destination="@id/navigation_quick_search"
|
||||||
|
@ -206,13 +224,6 @@
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim"
|
app:popExitAnim="@anim/exit_anim"
|
||||||
tools:layout="@layout/fragment_search">
|
tools:layout="@layout/fragment_search">
|
||||||
<action
|
|
||||||
android:id="@+id/action_navigation_search_to_navigation_results"
|
|
||||||
app:destination="@id/navigation_results"
|
|
||||||
app:enterAnim="@anim/enter_anim"
|
|
||||||
app:exitAnim="@anim/exit_anim"
|
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
|
@ -239,13 +250,6 @@
|
||||||
android:name="folder"
|
android:name="folder"
|
||||||
app:argType="string" />
|
app:argType="string" />
|
||||||
</action>
|
</action>
|
||||||
<action
|
|
||||||
android:id="@+id/action_navigation_downloads_to_navigation_results"
|
|
||||||
app:destination="@id/navigation_results"
|
|
||||||
app:enterAnim="@anim/enter_anim"
|
|
||||||
app:exitAnim="@anim/exit_anim"
|
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_navigation_downloads_to_navigation_player"
|
android:id="@+id/action_navigation_downloads_to_navigation_player"
|
||||||
app:destination="@id/navigation_player"
|
app:destination="@id/navigation_player"
|
||||||
|
@ -360,6 +364,56 @@
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
|
android:id="@+id/navigation_results_phone"
|
||||||
|
android:name="com.lagradost.cloudstream3.ui.result.ResultFragmentPhone"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:enterAnim="@anim/enter_anim"
|
||||||
|
app:exitAnim="@anim/exit_anim"
|
||||||
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
|
app:popExitAnim="@anim/exit_anim"
|
||||||
|
tools:layout="@layout/fragment_result_swipe">
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_navigation_results_phone_to_navigation_quick_search"
|
||||||
|
app:destination="@id/navigation_quick_search"
|
||||||
|
app:enterAnim="@anim/enter_anim"
|
||||||
|
app:exitAnim="@anim/exit_anim"
|
||||||
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_navigation_results_phone_to_navigation_player"
|
||||||
|
app:destination="@id/navigation_player"
|
||||||
|
app:enterAnim="@anim/enter_anim"
|
||||||
|
app:exitAnim="@anim/exit_anim"
|
||||||
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
|
</fragment>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/navigation_results_tv"
|
||||||
|
android:name="com.lagradost.cloudstream3.ui.result.ResultFragmentTv"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:enterAnim="@anim/enter_anim"
|
||||||
|
app:exitAnim="@anim/exit_anim"
|
||||||
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
|
app:popExitAnim="@anim/exit_anim"
|
||||||
|
tools:layout="@layout/fragment_result_swipe">
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_navigation_results_tv_to_navigation_quick_search"
|
||||||
|
app:destination="@id/navigation_quick_search"
|
||||||
|
app:enterAnim="@anim/enter_anim"
|
||||||
|
app:exitAnim="@anim/exit_anim"
|
||||||
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_navigation_results_tv_to_navigation_player"
|
||||||
|
app:destination="@id/navigation_player"
|
||||||
|
app:enterAnim="@anim/enter_anim"
|
||||||
|
app:exitAnim="@anim/exit_anim"
|
||||||
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
|
</fragment>
|
||||||
|
|
||||||
|
<!--<fragment
|
||||||
android:id="@+id/navigation_results"
|
android:id="@+id/navigation_results"
|
||||||
android:name="com.lagradost.cloudstream3.ui.result.ResultFragment"
|
android:name="com.lagradost.cloudstream3.ui.result.ResultFragment"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
@ -382,7 +436,7 @@
|
||||||
app:exitAnim="@anim/exit_anim"
|
app:exitAnim="@anim/exit_anim"
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
</fragment>
|
</fragment>-->
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/navigation_player"
|
android:id="@+id/navigation_player"
|
||||||
|
|
|
@ -338,6 +338,7 @@
|
||||||
<style name="DarkFragment" parent="AppTheme">
|
<style name="DarkFragment" parent="AppTheme">
|
||||||
<item name="android:navigationBarColor">?attr/colorPrimary</item>
|
<item name="android:navigationBarColor">?attr/colorPrimary</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="AlertDialogCustom" parent="Theme.AppCompat.Dialog.Alert">
|
<style name="AlertDialogCustom" parent="Theme.AppCompat.Dialog.Alert">
|
||||||
<item name="android:windowFullscreen">true</item>
|
<item name="android:windowFullscreen">true</item>
|
||||||
<item name="android:textColor">?attr/textColor</item>
|
<item name="android:textColor">?attr/textColor</item>
|
||||||
|
@ -476,7 +477,6 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style name="BlackButton" parent="NiceButton">
|
<style name="BlackButton" parent="NiceButton">
|
||||||
<item name="strokeColor">?attr/textColor</item>
|
<item name="strokeColor">?attr/textColor</item>
|
||||||
<item name="backgroundTint">?attr/iconGrayBackground</item>
|
<item name="backgroundTint">?attr/iconGrayBackground</item>
|
||||||
|
@ -544,6 +544,23 @@
|
||||||
<style name="MultiSelectButton" parent="BlackButton">
|
<style name="MultiSelectButton" parent="BlackButton">
|
||||||
<item name="android:layout_height">40dp</item>
|
<item name="android:layout_height">40dp</item>
|
||||||
<item name="android:layout_width">wrap_content</item>
|
<item name="android:layout_width">wrap_content</item>
|
||||||
|
|
||||||
|
<item name="strokeColor">?attr/textColor</item>
|
||||||
|
<item name="backgroundTint">?attr/iconGrayBackground</item>
|
||||||
|
<item name="iconTint">?attr/textColor</item>
|
||||||
|
<item name="android:textColor">?attr/textColor</item>
|
||||||
|
<item name="rippleColor">?attr/textColor</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="SelectableButton" parent="NiceButton">
|
||||||
|
<item name="android:layout_height">40dp</item>
|
||||||
|
<item name="android:layout_width">wrap_content</item>
|
||||||
|
|
||||||
|
<item name="strokeColor">@color/selectable_black</item>
|
||||||
|
<item name="backgroundTint">@color/selectable_white</item>
|
||||||
|
<item name="iconTint">@color/selectable_black</item>
|
||||||
|
<item name="android:textColor">@color/selectable_black</item>
|
||||||
|
<item name="rippleColor">@color/selectable_black</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="VideoButton">
|
<style name="VideoButton">
|
||||||
|
|
Loading…
Reference in a new issue