mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
more result bindings + player
This commit is contained in:
parent
4f28aef8f2
commit
d5c42f7d5a
14 changed files with 1321 additions and 916 deletions
|
@ -11,6 +11,8 @@ import com.lagradost.cloudstream3.databinding.FragmentHomeBinding
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentHomeTvBinding
|
import com.lagradost.cloudstream3.databinding.FragmentHomeTvBinding
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentPlayerBinding
|
import com.lagradost.cloudstream3.databinding.FragmentPlayerBinding
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentPlayerTvBinding
|
import com.lagradost.cloudstream3.databinding.FragmentPlayerTvBinding
|
||||||
|
import com.lagradost.cloudstream3.databinding.FragmentResultBinding
|
||||||
|
import com.lagradost.cloudstream3.databinding.FragmentResultTvBinding
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentSearchBinding
|
import com.lagradost.cloudstream3.databinding.FragmentSearchBinding
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentSearchTvBinding
|
import com.lagradost.cloudstream3.databinding.FragmentSearchTvBinding
|
||||||
import com.lagradost.cloudstream3.databinding.HomeResultGridBinding
|
import com.lagradost.cloudstream3.databinding.HomeResultGridBinding
|
||||||
|
@ -22,6 +24,7 @@ import com.lagradost.cloudstream3.databinding.RepositoryItemBinding
|
||||||
import com.lagradost.cloudstream3.databinding.RepositoryItemTvBinding
|
import com.lagradost.cloudstream3.databinding.RepositoryItemTvBinding
|
||||||
import com.lagradost.cloudstream3.databinding.SearchResultGridBinding
|
import com.lagradost.cloudstream3.databinding.SearchResultGridBinding
|
||||||
import com.lagradost.cloudstream3.databinding.SearchResultGridExpandedBinding
|
import com.lagradost.cloudstream3.databinding.SearchResultGridExpandedBinding
|
||||||
|
import com.lagradost.cloudstream3.databinding.TrailerCustomLayoutBinding
|
||||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||||
import com.lagradost.cloudstream3.utils.TestingUtils
|
import com.lagradost.cloudstream3.utils.TestingUtils
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
@ -85,8 +88,12 @@ class ExampleInstrumentedTest {
|
||||||
testAllLayouts<FragmentPlayerBinding>(activity, R.layout.fragment_player,R.layout.fragment_player_tv)
|
testAllLayouts<FragmentPlayerBinding>(activity, R.layout.fragment_player,R.layout.fragment_player_tv)
|
||||||
testAllLayouts<FragmentPlayerTvBinding>(activity, R.layout.fragment_player,R.layout.fragment_player_tv)
|
testAllLayouts<FragmentPlayerTvBinding>(activity, R.layout.fragment_player,R.layout.fragment_player_tv)
|
||||||
|
|
||||||
testAllLayouts<PlayerCustomLayoutBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv)
|
// testAllLayouts<FragmentResultBinding>(activity, R.layout.fragment_result,R.layout.fragment_result_tv)
|
||||||
testAllLayouts<PlayerCustomLayoutTvBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv)
|
// testAllLayouts<FragmentResultTvBinding>(activity, R.layout.fragment_result,R.layout.fragment_result_tv)
|
||||||
|
|
||||||
|
testAllLayouts<PlayerCustomLayoutBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv, R.layout.trailer_custom_layout)
|
||||||
|
testAllLayouts<PlayerCustomLayoutTvBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv, R.layout.trailer_custom_layout)
|
||||||
|
testAllLayouts<TrailerCustomLayoutBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv, R.layout.trailer_custom_layout)
|
||||||
|
|
||||||
testAllLayouts<RepositoryItemBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)
|
testAllLayouts<RepositoryItemBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)
|
||||||
testAllLayouts<RepositoryItemTvBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)
|
testAllLayouts<RepositoryItemTvBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -92,7 +92,6 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
private var preferredAutoSelectSubtitles: String? = null // null means do nothing, "" means none
|
private var preferredAutoSelectSubtitles: String? = null // null means do nothing, "" means none
|
||||||
|
|
||||||
private var binding: FragmentPlayerBinding? = null
|
private var binding: FragmentPlayerBinding? = null
|
||||||
private var playerBinding: PlayerCustomLayoutBinding? = null
|
|
||||||
|
|
||||||
private fun startLoading() {
|
private fun startLoading() {
|
||||||
player.release()
|
player.release()
|
||||||
|
@ -1236,15 +1235,11 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
unwrapBundle(arguments)
|
unwrapBundle(arguments)
|
||||||
|
|
||||||
val root = super.onCreateView(inflater, container, savedInstanceState) ?: return null
|
val root = super.onCreateView(inflater, container, savedInstanceState) ?: return null
|
||||||
binding = FragmentPlayerBinding.bind(root).also { b ->
|
binding = FragmentPlayerBinding.bind(root)
|
||||||
playerBinding = PlayerCustomLayoutBinding.bind(b.playerView.findViewById(R.id.player_holder))
|
|
||||||
}
|
|
||||||
|
|
||||||
return root
|
return root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
playerBinding = null
|
|
||||||
binding = null
|
binding = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,26 +4,19 @@ import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.Intent.*
|
import android.content.Intent.*
|
||||||
import android.content.res.ColorStateList
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.AbsListView
|
|
||||||
import android.widget.ArrayAdapter
|
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.doOnTextChanged
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.discord.panels.OverlappingPanelsLayout
|
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import com.google.android.material.chip.ChipDrawable
|
import com.google.android.material.chip.ChipDrawable
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
||||||
|
@ -38,7 +31,6 @@ import com.lagradost.cloudstream3.TvType
|
||||||
import com.lagradost.cloudstream3.mvvm.*
|
import com.lagradost.cloudstream3.mvvm.*
|
||||||
import com.lagradost.cloudstream3.services.SubscriptionWorkManager
|
import com.lagradost.cloudstream3.services.SubscriptionWorkManager
|
||||||
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.download.DOWNLOAD_ACTION_DOWNLOAD
|
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
||||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
||||||
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
||||||
|
@ -53,7 +45,6 @@ import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getVideoWatchState
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getVideoWatchState
|
||||||
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.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
|
||||||
|
@ -364,8 +355,9 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
return@setOnLongClickListener true
|
return@setOnLongClickListener true
|
||||||
}
|
}
|
||||||
|
|
||||||
val show = viewModel.currentRepo?.api?.hasDownloadSupport == true && !isTvSettings()
|
val show =
|
||||||
if(show) {
|
viewModel.currentRepo?.api?.hasDownloadSupport == true && !isTvSettings()
|
||||||
|
if (show) {
|
||||||
download_button?.setDefaultClickListener(
|
download_button?.setDefaultClickListener(
|
||||||
VideoDownloadHelper.DownloadEpisodeCached(
|
VideoDownloadHelper.DownloadEpisodeCached(
|
||||||
ep.name,
|
ep.name,
|
||||||
|
@ -379,7 +371,6 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
)
|
)
|
||||||
) { click ->
|
) { click ->
|
||||||
println("Click:$click")
|
|
||||||
when (click.action) {
|
when (click.action) {
|
||||||
DOWNLOAD_ACTION_DOWNLOAD -> {
|
DOWNLOAD_ACTION_DOWNLOAD -> {
|
||||||
viewModel.handleAction(
|
viewModel.handleAction(
|
||||||
|
@ -393,7 +384,6 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
download_button?.isVisible = show
|
download_button?.isVisible = show
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,42 +583,6 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.watchStatus) { watchType ->
|
|
||||||
result_bookmark_button?.text = getString(watchType.stringRes)
|
|
||||||
result_bookmark_fab?.text = getString(watchType.stringRes)
|
|
||||||
|
|
||||||
if (watchType == WatchType.NONE) {
|
|
||||||
result_bookmark_fab?.context?.colorFromAttribute(R.attr.white)
|
|
||||||
} else {
|
|
||||||
result_bookmark_fab?.context?.colorFromAttribute(R.attr.colorPrimary)
|
|
||||||
}?.let {
|
|
||||||
val colorState = ColorStateList.valueOf(it)
|
|
||||||
result_bookmark_fab?.iconTint = colorState
|
|
||||||
result_bookmark_fab?.setTextColor(colorState)
|
|
||||||
}
|
|
||||||
|
|
||||||
result_bookmark_fab?.setOnClickListener { fab ->
|
|
||||||
activity?.showBottomDialog(
|
|
||||||
WatchType.values().map { fab.context.getString(it.stringRes) }.toList(),
|
|
||||||
watchType.ordinal,
|
|
||||||
fab.context.getString(R.string.action_add_to_bookmarks),
|
|
||||||
showApply = false,
|
|
||||||
{}) {
|
|
||||||
viewModel.updateWatchStatus(WatchType.values()[it])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result_bookmark_button?.setOnClickListener { fab ->
|
|
||||||
activity?.showBottomDialog(
|
|
||||||
WatchType.values().map { fab.context.getString(it.stringRes) }.toList(),
|
|
||||||
watchType.ordinal,
|
|
||||||
fab.context.getString(R.string.action_add_to_bookmarks),
|
|
||||||
showApply = false,
|
|
||||||
{}) {
|
|
||||||
viewModel.updateWatchStatus(WatchType.values()[it])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is to band-aid FireTV navigation
|
// This is to band-aid FireTV navigation
|
||||||
val isTv = isTvSettings()
|
val isTv = isTvSettings()
|
||||||
|
@ -636,152 +590,6 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
result_episode_select?.isFocusableInTouchMode = isTv
|
result_episode_select?.isFocusableInTouchMode = isTv
|
||||||
result_dub_select?.isFocusableInTouchMode = isTv
|
result_dub_select?.isFocusableInTouchMode = isTv
|
||||||
|
|
||||||
context?.let { ctx ->
|
|
||||||
val arrayAdapter = ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
|
||||||
/*
|
|
||||||
-1 -> None
|
|
||||||
0 -> Watching
|
|
||||||
1 -> Completed
|
|
||||||
2 -> OnHold
|
|
||||||
3 -> Dropped
|
|
||||||
4 -> PlanToWatch
|
|
||||||
5 -> ReWatching
|
|
||||||
*/
|
|
||||||
val items = listOf(
|
|
||||||
R.string.none,
|
|
||||||
R.string.type_watching,
|
|
||||||
R.string.type_completed,
|
|
||||||
R.string.type_on_hold,
|
|
||||||
R.string.type_dropped,
|
|
||||||
R.string.type_plan_to_watch,
|
|
||||||
R.string.type_re_watching
|
|
||||||
).map { ctx.getString(it) }
|
|
||||||
arrayAdapter.addAll(items)
|
|
||||||
result_sync_check?.choiceMode = AbsListView.CHOICE_MODE_SINGLE
|
|
||||||
result_sync_check?.adapter = arrayAdapter
|
|
||||||
UIHelper.setListViewHeightBasedOnItems(result_sync_check)
|
|
||||||
|
|
||||||
result_sync_check?.setOnItemClickListener { _, _, which, _ ->
|
|
||||||
syncModel.setStatus(which - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
result_sync_rating?.addOnChangeListener { _, value, _ ->
|
|
||||||
syncModel.setScore(value.toInt())
|
|
||||||
}
|
|
||||||
|
|
||||||
result_sync_add_episode?.setOnClickListener {
|
|
||||||
syncModel.setEpisodesDelta(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
result_sync_sub_episode?.setOnClickListener {
|
|
||||||
syncModel.setEpisodesDelta(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
result_sync_current_episodes?.doOnTextChanged { text, _, before, count ->
|
|
||||||
if (count == before) return@doOnTextChanged
|
|
||||||
text?.toString()?.toIntOrNull()?.let { ep ->
|
|
||||||
syncModel.setEpisodes(ep)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(syncModel.synced) { list ->
|
|
||||||
result_sync_names?.text =
|
|
||||||
list.filter { it.isSynced && it.hasAccount }.joinToString { it.name }
|
|
||||||
|
|
||||||
val newList = list.filter { it.isSynced && it.hasAccount }
|
|
||||||
|
|
||||||
result_mini_sync?.isVisible = newList.isNotEmpty()
|
|
||||||
(result_mini_sync?.adapter as? ImageAdapter)?.updateList(newList.mapNotNull { it.icon })
|
|
||||||
}
|
|
||||||
|
|
||||||
var currentSyncProgress = 0
|
|
||||||
|
|
||||||
fun setSyncMaxEpisodes(totalEpisodes: Int?) {
|
|
||||||
result_sync_episodes?.max = (totalEpisodes ?: 0) * 1000
|
|
||||||
|
|
||||||
normalSafeApiCall {
|
|
||||||
val ctx = result_sync_max_episodes?.context
|
|
||||||
result_sync_max_episodes?.text =
|
|
||||||
totalEpisodes?.let { episodes ->
|
|
||||||
ctx?.getString(R.string.sync_total_episodes_some)?.format(episodes)
|
|
||||||
} ?: run {
|
|
||||||
ctx?.getString(R.string.sync_total_episodes_none)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(syncModel.metadata) { meta ->
|
|
||||||
when (meta) {
|
|
||||||
is Resource.Success -> {
|
|
||||||
val d = meta.value
|
|
||||||
result_sync_episodes?.progress = currentSyncProgress * 1000
|
|
||||||
setSyncMaxEpisodes(d.totalEpisodes)
|
|
||||||
|
|
||||||
viewModel.setMeta(d, syncModel.getSyncs())
|
|
||||||
}
|
|
||||||
|
|
||||||
is Resource.Loading -> {
|
|
||||||
result_sync_max_episodes?.text =
|
|
||||||
result_sync_max_episodes?.context?.getString(R.string.sync_total_episodes_none)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(syncModel.userData) { status ->
|
|
||||||
var closed = false
|
|
||||||
when (status) {
|
|
||||||
is Resource.Failure -> {
|
|
||||||
result_sync_loading_shimmer?.stopShimmer()
|
|
||||||
result_sync_loading_shimmer?.isVisible = false
|
|
||||||
result_sync_holder?.isVisible = false
|
|
||||||
closed = true
|
|
||||||
}
|
|
||||||
|
|
||||||
is Resource.Loading -> {
|
|
||||||
result_sync_loading_shimmer?.startShimmer()
|
|
||||||
result_sync_loading_shimmer?.isVisible = true
|
|
||||||
result_sync_holder?.isVisible = false
|
|
||||||
}
|
|
||||||
|
|
||||||
is Resource.Success -> {
|
|
||||||
result_sync_loading_shimmer?.stopShimmer()
|
|
||||||
result_sync_loading_shimmer?.isVisible = false
|
|
||||||
result_sync_holder?.isVisible = true
|
|
||||||
|
|
||||||
val d = status.value
|
|
||||||
result_sync_rating?.value = d.score?.toFloat() ?: 0.0f
|
|
||||||
result_sync_check?.setItemChecked(d.status + 1, true)
|
|
||||||
val watchedEpisodes = d.watchedEpisodes ?: 0
|
|
||||||
currentSyncProgress = watchedEpisodes
|
|
||||||
|
|
||||||
d.maxEpisodes?.let {
|
|
||||||
// don't directly call it because we don't want to override metadata observe
|
|
||||||
setSyncMaxEpisodes(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
||||||
result_sync_episodes?.setProgress(watchedEpisodes * 1000, true)
|
|
||||||
} else {
|
|
||||||
result_sync_episodes?.progress = watchedEpisodes * 1000
|
|
||||||
}
|
|
||||||
result_sync_current_episodes?.text =
|
|
||||||
Editable.Factory.getInstance()?.newEditable(watchedEpisodes.toString())
|
|
||||||
normalSafeApiCall { // format might fail
|
|
||||||
context?.getString(R.string.sync_score_format)?.format(d.score ?: 0)?.let {
|
|
||||||
result_sync_score_text?.text = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
null -> {
|
|
||||||
closed = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result_overlapping_panels?.setStartPanelLockState(if (closed) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)
|
|
||||||
}
|
|
||||||
|
|
||||||
observeNullable(viewModel.resumeWatching) { resume ->
|
observeNullable(viewModel.resumeWatching) { resume ->
|
||||||
if (resume == null) {
|
if (resume == null) {
|
||||||
|
@ -841,10 +649,6 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
if (hasFocus) result_bookmark_button?.requestFocus()
|
if (hasFocus) result_bookmark_button?.requestFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
result_sync_set_score?.setOnClickListener {
|
|
||||||
syncModel.publishUserData()
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(viewModel.trailers) { trailers ->
|
observe(viewModel.trailers) { trailers ->
|
||||||
setTrailers(trailers.flatMap { it.mirros }) // I dont care about subtitles yet!
|
setTrailers(trailers.flatMap { it.mirros }) // I dont care about subtitles yet!
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,47 @@
|
||||||
package com.lagradost.cloudstream3.ui.result
|
package com.lagradost.cloudstream3.ui.result
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.text.Editable
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.animation.AlphaAnimation
|
import android.view.animation.AlphaAnimation
|
||||||
import android.view.animation.Animation
|
import android.view.animation.Animation
|
||||||
import android.view.animation.DecelerateInterpolator
|
import android.view.animation.DecelerateInterpolator
|
||||||
|
import android.widget.AbsListView
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.NestedScrollView
|
import androidx.core.widget.NestedScrollView
|
||||||
|
import androidx.core.widget.doOnTextChanged
|
||||||
import com.discord.panels.OverlappingPanelsLayout
|
import com.discord.panels.OverlappingPanelsLayout
|
||||||
import com.discord.panels.PanelsChildGestureRegionObserver
|
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.bottomsheet.BottomSheetDialog
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.APIHolder
|
||||||
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
||||||
|
import com.lagradost.cloudstream3.CommonActivity
|
||||||
|
import com.lagradost.cloudstream3.DubStatus
|
||||||
|
import com.lagradost.cloudstream3.LoadResponse
|
||||||
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.SearchResponse
|
||||||
|
import com.lagradost.cloudstream3.databinding.FragmentResultBinding
|
||||||
|
import com.lagradost.cloudstream3.databinding.FragmentResultSwipeBinding
|
||||||
|
import com.lagradost.cloudstream3.databinding.ResultRecommendationsBinding
|
||||||
|
import com.lagradost.cloudstream3.databinding.ResultSyncBinding
|
||||||
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
|
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||||
import com.lagradost.cloudstream3.mvvm.observe
|
import com.lagradost.cloudstream3.mvvm.observe
|
||||||
import com.lagradost.cloudstream3.mvvm.observeNullable
|
import com.lagradost.cloudstream3.mvvm.observeNullable
|
||||||
|
import com.lagradost.cloudstream3.ui.WatchType
|
||||||
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||||
|
@ -32,25 +51,35 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
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.SingleSelectionHelper.showBottomDialogInstant
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
||||||
|
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.dismissSafe
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
||||||
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_episodes_text
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result.result_resume_parent
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result.result_scroll
|
|
||||||
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_swipe.result_back
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_trailer.*
|
|
||||||
import kotlinx.android.synthetic.main.result_recommendations.*
|
|
||||||
import kotlinx.android.synthetic.main.result_recommendations.result_recommendations
|
|
||||||
import kotlinx.android.synthetic.main.trailer_custom_layout.*
|
|
||||||
|
|
||||||
|
|
||||||
class ResultFragmentPhone : ResultFragment() {
|
class ResultFragmentPhone : ResultFragment() {
|
||||||
|
private var binding: FragmentResultSwipeBinding? = null
|
||||||
|
private var resultBinding: FragmentResultBinding? = null
|
||||||
|
private var recommendationBinding: ResultRecommendationsBinding? = null
|
||||||
|
private var syncBinding: ResultSyncBinding? = null
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
val root = super.onCreateView(inflater, container, savedInstanceState) ?: return null
|
||||||
|
FragmentResultSwipeBinding.bind(root).let { bind ->
|
||||||
|
resultBinding =
|
||||||
|
bind.fragmentResult//FragmentResultBinding.bind(binding.root.findViewById(R.id.fragment_result))
|
||||||
|
recommendationBinding = bind.resultRecommendations
|
||||||
|
syncBinding = bind.resultSync
|
||||||
|
binding = bind
|
||||||
|
}
|
||||||
|
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
var currentTrailers: List<ExtractorLink> = emptyList()
|
var currentTrailers: List<ExtractorLink> = emptyList()
|
||||||
var currentTrailerIndex = 0
|
var currentTrailerIndex = 0
|
||||||
|
|
||||||
|
@ -96,19 +125,30 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
//result_trailer_thumbnail?.setImageBitmap(result_poster_background?.drawable?.toBitmap())
|
//result_trailer_thumbnail?.setImageBitmap(result_poster_background?.drawable?.toBitmap())
|
||||||
|
|
||||||
|
|
||||||
result_trailer_loading?.isVisible = isSuccess
|
// result_trailer_loading?.isVisible = isSuccess
|
||||||
val turnVis = !isSuccess && !isFullScreenPlayer
|
val turnVis = !isSuccess && !isFullScreenPlayer
|
||||||
result_smallscreen_holder?.isVisible = turnVis
|
resultBinding?.apply {
|
||||||
result_poster_background_holder?.apply {
|
resultSmallscreenHolder.isVisible = turnVis
|
||||||
val fadeIn: Animation = AlphaAnimation(alpha, if (turnVis) 1.0f else 0.0f).apply {
|
resultPosterBackgroundHolder.apply {
|
||||||
interpolator = DecelerateInterpolator()
|
val fadeIn: Animation = AlphaAnimation(alpha, if (turnVis) 1.0f else 0.0f).apply {
|
||||||
duration = 200
|
interpolator = DecelerateInterpolator()
|
||||||
fillAfter = true
|
duration = 200
|
||||||
|
fillAfter = true
|
||||||
|
}
|
||||||
|
clearAnimation()
|
||||||
|
startAnimation(fadeIn)
|
||||||
}
|
}
|
||||||
clearAnimation()
|
|
||||||
startAnimation(fadeIn)
|
// We don't want the trailer to be focusable if it's not visible
|
||||||
|
resultSmallscreenHolder.descendantFocusability = if (isSuccess) {
|
||||||
|
ViewGroup.FOCUS_AFTER_DESCENDANTS
|
||||||
|
} else {
|
||||||
|
ViewGroup.FOCUS_BLOCK_DESCENDANTS
|
||||||
|
}
|
||||||
|
binding?.resultFullscreenHolder?.isVisible = !isSuccess && isFullScreenPlayer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//player_view?.apply {
|
//player_view?.apply {
|
||||||
//alpha = 0.0f
|
//alpha = 0.0f
|
||||||
//ObjectAnimator.ofFloat(player_view, "alpha", 1f).apply {
|
//ObjectAnimator.ofFloat(player_view, "alpha", 1f).apply {
|
||||||
|
@ -124,13 +164,7 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
//startAnimation(fadeIn)
|
//startAnimation(fadeIn)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// 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>?) {
|
override fun setTrailers(trailers: List<ExtractorLink>?) {
|
||||||
|
@ -144,12 +178,15 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
//somehow this still leaks and I dont know why????
|
//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
|
// 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 ->
|
PanelsChildGestureRegionObserver.Provider.get().let { obs ->
|
||||||
result_cast_items?.let {
|
resultBinding?.resultCastItems?.let {
|
||||||
obs.unregister(it)
|
obs.unregister(it)
|
||||||
}
|
}
|
||||||
obs.removeGestureRegionsUpdateListener(this)
|
obs.removeGestureRegionsUpdateListener(this)
|
||||||
}
|
}
|
||||||
|
binding = null
|
||||||
|
resultBinding = null
|
||||||
|
syncBinding = null
|
||||||
|
recommendationBinding = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,30 +210,35 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
player_open_source?.setOnClickListener {
|
|
||||||
|
|
||||||
|
playerBinding?.playerOpenSource?.setOnClickListener {
|
||||||
currentTrailers.getOrNull(currentTrailerIndex)?.let {
|
currentTrailers.getOrNull(currentTrailerIndex)?.let {
|
||||||
context?.openBrowser(it.url)
|
context?.openBrowser(it.url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result_overlapping_panels?.setStartPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
binding?.resultOverlappingPanels?.setStartPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
||||||
result_overlapping_panels?.setEndPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
binding?.resultOverlappingPanels?.setEndPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
||||||
|
|
||||||
|
recommendationBinding?.resultRecommendationsList?.apply {
|
||||||
|
spanCount = 3
|
||||||
|
adapter =
|
||||||
|
SearchAdapter(
|
||||||
|
ArrayList(),
|
||||||
|
this,
|
||||||
|
) { callback ->
|
||||||
|
SearchHelper.handleSearchClickCallback(callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result_recommendations?.spanCount = 3
|
|
||||||
result_recommendations?.adapter =
|
|
||||||
SearchAdapter(
|
|
||||||
ArrayList(),
|
|
||||||
result_recommendations,
|
|
||||||
) { callback ->
|
|
||||||
SearchHelper.handleSearchClickCallback(callback)
|
|
||||||
}
|
|
||||||
PanelsChildGestureRegionObserver.Provider.get().addGestureRegionsUpdateListener(this)
|
PanelsChildGestureRegionObserver.Provider.get().addGestureRegionsUpdateListener(this)
|
||||||
|
|
||||||
result_cast_items?.let {
|
resultBinding?.resultCastItems?.let {
|
||||||
PanelsChildGestureRegionObserver.Provider.get().register(it)
|
PanelsChildGestureRegionObserver.Provider.get().register(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
result_back?.setOnClickListener {
|
binding?.resultBack?.setOnClickListener {
|
||||||
activity?.popCurrentPage()
|
activity?.popCurrentPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,28 +253,30 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
result_mini_sync?.adapter = ImageAdapter(
|
binding?.resultMiniSync?.adapter = ImageAdapter(
|
||||||
nextFocusDown = R.id.result_sync_set_score,
|
nextFocusDown = R.id.result_sync_set_score,
|
||||||
clickCallback = { action ->
|
clickCallback = { action ->
|
||||||
if (action == IMAGE_CLICK || action == IMAGE_LONG_CLICK) {
|
if (action == IMAGE_CLICK || action == IMAGE_LONG_CLICK) {
|
||||||
if (result_overlapping_panels?.getSelectedPanel()?.ordinal == 1) {
|
if (binding?.resultOverlappingPanels?.getSelectedPanel()?.ordinal == 1) {
|
||||||
result_overlapping_panels?.openStartPanel()
|
binding?.resultOverlappingPanels?.openStartPanel()
|
||||||
} else {
|
} else {
|
||||||
result_overlapping_panels?.closePanels()
|
binding?.resultOverlappingPanels?.closePanels()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
result_scroll?.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
resultBinding?.resultScroll?.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||||
val dy = scrollY - oldScrollY
|
val dy = scrollY - oldScrollY
|
||||||
if (dy > 0) { //check for scroll down
|
if (dy > 0) { //check for scroll down
|
||||||
result_bookmark_fab?.shrink()
|
binding?.resultBookmarkFab?.shrink()
|
||||||
} else if (dy < -5) {
|
} else if (dy < -5) {
|
||||||
result_bookmark_fab?.extend()
|
binding?.resultBookmarkFab?.extend()
|
||||||
}
|
}
|
||||||
if (!isFullScreenPlayer && player.getIsPlaying()) {
|
if (!isFullScreenPlayer && player.getIsPlaying()) {
|
||||||
if (scrollY > (player_background?.height ?: scrollY)) {
|
if (scrollY > (resultBinding?.fragmentTrailer?.playerBackground?.height
|
||||||
|
?: scrollY)
|
||||||
|
) {
|
||||||
player.handleEvent(CSPlayerEvent.Pause)
|
player.handleEvent(CSPlayerEvent.Pause)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,11 +284,11 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
})
|
})
|
||||||
val api = APIHolder.getApiFromNameNull(apiName)
|
val api = APIHolder.getApiFromNameNull(apiName)
|
||||||
|
|
||||||
if (media_route_button != null) {
|
binding?.mediaRouteButton?.apply {
|
||||||
val chromecastSupport = api?.hasChromecastSupport == true
|
val chromecastSupport = api?.hasChromecastSupport == true
|
||||||
media_route_button?.alpha = if (chromecastSupport) 1f else 0.3f
|
alpha = if (chromecastSupport) 1f else 0.3f
|
||||||
if (!chromecastSupport) {
|
if (!chromecastSupport) {
|
||||||
media_route_button?.setOnClickListener {
|
setOnClickListener {
|
||||||
CommonActivity.showToast(
|
CommonActivity.showToast(
|
||||||
R.string.no_chromecast_support_toast,
|
R.string.no_chromecast_support_toast,
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
|
@ -254,10 +298,9 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
activity?.let { act ->
|
activity?.let { act ->
|
||||||
if (act.isCastApiAvailable()) {
|
if (act.isCastApiAvailable()) {
|
||||||
try {
|
try {
|
||||||
CastButtonFactory.setUpMediaRouteButton(act, media_route_button)
|
CastButtonFactory.setUpMediaRouteButton(act, this)
|
||||||
val castContext = CastContext.getSharedInstance(act.applicationContext)
|
val castContext = CastContext.getSharedInstance(act.applicationContext)
|
||||||
media_route_button?.isGone =
|
isGone = castContext.castState == CastState.NO_DEVICES_AVAILABLE
|
||||||
castContext.castState == CastState.NO_DEVICES_AVAILABLE
|
|
||||||
// this shit leaks for some reason
|
// this shit leaks for some reason
|
||||||
//castContext.addCastStateListener { state ->
|
//castContext.addCastStateListener { state ->
|
||||||
// media_route_button?.isGone = state == CastState.NO_DEVICES_AVAILABLE
|
// media_route_button?.isGone = state == CastState.NO_DEVICES_AVAILABLE
|
||||||
|
@ -270,7 +313,7 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
observeNullable(viewModel.episodesCountText) { count ->
|
observeNullable(viewModel.episodesCountText) { count ->
|
||||||
result_episodes_text.setText(count)
|
resultBinding?.resultEpisodesText.setText(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
observeNullable(viewModel.selectPopup) { popup ->
|
observeNullable(viewModel.selectPopup) { popup ->
|
||||||
|
@ -295,10 +338,189 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
observe(syncModel.synced) { list ->
|
||||||
|
syncBinding?.resultSyncNames?.text =
|
||||||
|
list.filter { it.isSynced && it.hasAccount }.joinToString { it.name }
|
||||||
|
|
||||||
|
val newList = list.filter { it.isSynced && it.hasAccount }
|
||||||
|
|
||||||
|
binding?.resultMiniSync?.isVisible = newList.isNotEmpty()
|
||||||
|
(binding?.resultMiniSync?.adapter as? ImageAdapter)?.updateList(newList.mapNotNull { it.icon })
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentSyncProgress = 0
|
||||||
|
fun setSyncMaxEpisodes(totalEpisodes: Int?) {
|
||||||
|
syncBinding?.resultSyncEpisodes?.max = (totalEpisodes ?: 0) * 1000
|
||||||
|
|
||||||
|
normalSafeApiCall {
|
||||||
|
val ctx = syncBinding?.resultSyncEpisodes?.context
|
||||||
|
syncBinding?.resultSyncMaxEpisodes?.text =
|
||||||
|
totalEpisodes?.let { episodes ->
|
||||||
|
ctx?.getString(R.string.sync_total_episodes_some)?.format(episodes)
|
||||||
|
} ?: run {
|
||||||
|
ctx?.getString(R.string.sync_total_episodes_none)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
observe(syncModel.metadata) { meta ->
|
||||||
|
when (meta) {
|
||||||
|
is Resource.Success -> {
|
||||||
|
val d = meta.value
|
||||||
|
syncBinding?.resultSyncEpisodes?.progress = currentSyncProgress * 1000
|
||||||
|
setSyncMaxEpisodes(d.totalEpisodes)
|
||||||
|
|
||||||
|
viewModel.setMeta(d, syncModel.getSyncs())
|
||||||
|
}
|
||||||
|
|
||||||
|
is Resource.Loading -> {
|
||||||
|
syncBinding?.resultSyncMaxEpisodes?.text =
|
||||||
|
syncBinding?.resultSyncMaxEpisodes?.context?.getString(R.string.sync_total_episodes_none)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
observe(syncModel.userData) { status ->
|
||||||
|
var closed = false
|
||||||
|
syncBinding?.apply {
|
||||||
|
when (status) {
|
||||||
|
is Resource.Failure -> {
|
||||||
|
resultSyncLoadingShimmer.stopShimmer()
|
||||||
|
resultSyncLoadingShimmer.isVisible = false
|
||||||
|
resultSyncHolder.isVisible = false
|
||||||
|
closed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
is Resource.Loading -> {
|
||||||
|
resultSyncLoadingShimmer.startShimmer()
|
||||||
|
resultSyncLoadingShimmer.isVisible = true
|
||||||
|
resultSyncHolder.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
is Resource.Success -> {
|
||||||
|
resultSyncLoadingShimmer.stopShimmer()
|
||||||
|
resultSyncLoadingShimmer.isVisible = false
|
||||||
|
resultSyncHolder.isVisible = true
|
||||||
|
|
||||||
|
val d = status.value
|
||||||
|
resultSyncRating.value = d.score?.toFloat() ?: 0.0f
|
||||||
|
resultSyncCheck.setItemChecked(d.status + 1, true)
|
||||||
|
val watchedEpisodes = d.watchedEpisodes ?: 0
|
||||||
|
currentSyncProgress = watchedEpisodes
|
||||||
|
|
||||||
|
d.maxEpisodes?.let {
|
||||||
|
// don't directly call it because we don't want to override metadata observe
|
||||||
|
setSyncMaxEpisodes(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
resultSyncEpisodes.setProgress(watchedEpisodes * 1000, true)
|
||||||
|
} else {
|
||||||
|
resultSyncEpisodes.progress = watchedEpisodes * 1000
|
||||||
|
}
|
||||||
|
resultSyncCurrentEpisodes.text =
|
||||||
|
Editable.Factory.getInstance()?.newEditable(watchedEpisodes.toString())
|
||||||
|
normalSafeApiCall { // format might fail
|
||||||
|
context?.getString(R.string.sync_score_format)?.format(d.score ?: 0)
|
||||||
|
?.let {
|
||||||
|
resultSyncScoreText.text = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
null -> {
|
||||||
|
closed = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding?.resultOverlappingPanels?.setStartPanelLockState(if (closed) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)
|
||||||
|
}
|
||||||
|
|
||||||
|
context?.let { ctx ->
|
||||||
|
val arrayAdapter = ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
||||||
|
/*
|
||||||
|
-1 -> None
|
||||||
|
0 -> Watching
|
||||||
|
1 -> Completed
|
||||||
|
2 -> OnHold
|
||||||
|
3 -> Dropped
|
||||||
|
4 -> PlanToWatch
|
||||||
|
5 -> ReWatching
|
||||||
|
*/
|
||||||
|
val items = listOf(
|
||||||
|
R.string.none,
|
||||||
|
R.string.type_watching,
|
||||||
|
R.string.type_completed,
|
||||||
|
R.string.type_on_hold,
|
||||||
|
R.string.type_dropped,
|
||||||
|
R.string.type_plan_to_watch,
|
||||||
|
R.string.type_re_watching
|
||||||
|
).map { ctx.getString(it) }
|
||||||
|
arrayAdapter.addAll(items)
|
||||||
|
syncBinding?.apply {
|
||||||
|
resultSyncCheck.choiceMode = AbsListView.CHOICE_MODE_SINGLE
|
||||||
|
resultSyncCheck.adapter = arrayAdapter
|
||||||
|
UIHelper.setListViewHeightBasedOnItems(resultSyncCheck)
|
||||||
|
|
||||||
|
resultSyncCheck.setOnItemClickListener { _, _, which, _ ->
|
||||||
|
syncModel.setStatus(which - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSyncRating.addOnChangeListener { _, value, _ ->
|
||||||
|
syncModel.setScore(value.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSyncAddEpisode.setOnClickListener {
|
||||||
|
syncModel.setEpisodesDelta(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSyncSubEpisode.setOnClickListener {
|
||||||
|
syncModel.setEpisodesDelta(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSyncCurrentEpisodes.doOnTextChanged { text, _, before, count ->
|
||||||
|
if (count == before) return@doOnTextChanged
|
||||||
|
text?.toString()?.toIntOrNull()?.let { ep ->
|
||||||
|
syncModel.setEpisodes(ep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syncBinding?.resultSyncSetScore?.setOnClickListener {
|
||||||
|
syncModel.publishUserData()
|
||||||
|
}
|
||||||
|
|
||||||
|
observe(viewModel.watchStatus) { watchType ->
|
||||||
|
binding?.resultBookmarkFab?.apply {
|
||||||
|
if (watchType == WatchType.NONE) {
|
||||||
|
context?.colorFromAttribute(R.attr.white)
|
||||||
|
} else {
|
||||||
|
context?.colorFromAttribute(R.attr.colorPrimary)
|
||||||
|
}?.let {
|
||||||
|
val colorState = ColorStateList.valueOf(it)
|
||||||
|
iconTint = colorState
|
||||||
|
setTextColor(colorState)
|
||||||
|
}
|
||||||
|
|
||||||
|
setOnClickListener { fab ->
|
||||||
|
activity?.showBottomDialog(
|
||||||
|
WatchType.values().map { fab.context.getString(it.stringRes) }.toList(),
|
||||||
|
watchType.ordinal,
|
||||||
|
fab.context.getString(R.string.action_add_to_bookmarks),
|
||||||
|
showApply = false,
|
||||||
|
{}) {
|
||||||
|
viewModel.updateWatchStatus(WatchType.values()[it])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
observe(viewModel.loadedLinks) { load ->
|
observe(viewModel.loadedLinks) { load ->
|
||||||
if (load == null) {
|
if (load == null) {
|
||||||
loadingDialog?.dismissSafe(activity)
|
loadingDialog?.dismissSafe(activity)
|
||||||
|
@ -327,46 +549,41 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
observeNullable(viewModel.selectedSeason) { text ->
|
observeNullable(viewModel.selectedSeason) { text ->
|
||||||
result_season_button.setText(text)
|
resultBinding?.apply {
|
||||||
|
resultSeasonButton.setText(text)
|
||||||
|
|
||||||
selectSeason =
|
selectSeason =
|
||||||
text?.asStringNull(result_season_button?.context)
|
text?.asStringNull(resultSeasonButton.context)
|
||||||
// If the season button is visible the result season button will be next focus down
|
// If the season button is visible the result season button will be next focus down
|
||||||
if (result_season_button?.isVisible == true)
|
if (resultSeasonButton.isVisible && resultResumeParent.isVisible) {
|
||||||
if (result_resume_parent?.isVisible == true)
|
setFocusUpAndDown(resultResumeSeriesButton, resultSeasonButton)
|
||||||
setFocusUpAndDown(result_resume_series_button, result_season_button)
|
}
|
||||||
//else
|
}
|
||||||
// setFocusUpAndDown(result_bookmark_button, result_season_button)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
observeNullable(viewModel.selectedDubStatus) { status ->
|
observeNullable(viewModel.selectedDubStatus) { status ->
|
||||||
result_dub_select?.setText(status)
|
resultBinding?.apply {
|
||||||
|
resultDubSelect.setText(status)
|
||||||
|
|
||||||
if (result_dub_select?.isVisible == true)
|
if (resultDubSelect.isVisible && !resultSeasonButton.isVisible && !resultEpisodeSelect.isVisible && resultResumeParent.isVisible) {
|
||||||
if (result_season_button?.isVisible != true && result_episode_select?.isVisible != true) {
|
setFocusUpAndDown(resultResumeSeriesButton, resultDubSelect)
|
||||||
if (result_resume_parent?.isVisible == true)
|
|
||||||
setFocusUpAndDown(result_resume_series_button, result_dub_select)
|
|
||||||
//else
|
|
||||||
// setFocusUpAndDown(result_bookmark_button, result_dub_select)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
observeNullable(viewModel.selectedRange) { range ->
|
observeNullable(viewModel.selectedRange) { range ->
|
||||||
result_episode_select.setText(range)
|
resultBinding?.apply {
|
||||||
|
resultEpisodeSelect.setText(range)
|
||||||
// If Season button is invisible then the bookmark button next focus is episode select
|
// If Season button is invisible then the bookmark button next focus is episode select
|
||||||
if (result_episode_select?.isVisible == true)
|
if (resultEpisodeSelect.isVisible && !resultSeasonButton.isVisible && resultResumeParent.isVisible) {
|
||||||
if (result_season_button?.isVisible != true) {
|
setFocusUpAndDown(resultResumeSeriesButton, resultEpisodeSelect)
|
||||||
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
|
// val preferDub = context?.getApiDubstatusSettings()?.all { it == DubStatus.Dubbed } == true
|
||||||
|
|
||||||
observe(viewModel.dubSubSelections) { range ->
|
observe(viewModel.dubSubSelections) { range ->
|
||||||
result_dub_select.setOnClickListener { view ->
|
resultBinding?.resultDubSelect?.setOnClickListener { view ->
|
||||||
view?.context?.let { ctx ->
|
view?.context?.let { ctx ->
|
||||||
view.popupMenuNoIconsAndNoStringRes(range
|
view.popupMenuNoIconsAndNoStringRes(range
|
||||||
.mapNotNull { (text, status) ->
|
.mapNotNull { (text, status) ->
|
||||||
|
@ -382,7 +599,7 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.rangeSelections) { range ->
|
observe(viewModel.rangeSelections) { range ->
|
||||||
result_episode_select?.setOnClickListener { view ->
|
resultBinding?.resultEpisodeSelect?.setOnClickListener { view ->
|
||||||
view?.context?.let { ctx ->
|
view?.context?.let { ctx ->
|
||||||
val names = range
|
val names = range
|
||||||
.mapNotNull { (text, r) ->
|
.mapNotNull { (text, r) ->
|
||||||
|
@ -399,7 +616,7 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.seasonSelections) { seasonList ->
|
observe(viewModel.seasonSelections) { seasonList ->
|
||||||
result_season_button?.setOnClickListener { view ->
|
resultBinding?.resultSeasonButton?.setOnClickListener { view ->
|
||||||
|
|
||||||
view?.context?.let { ctx ->
|
view?.context?.let { ctx ->
|
||||||
val names = seasonList
|
val names = seasonList
|
||||||
|
@ -433,50 +650,58 @@ class ResultFragmentPhone : ResultFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onGestureRegionsUpdate(gestureRegions: List<Rect>) {
|
override fun onGestureRegionsUpdate(gestureRegions: List<Rect>) {
|
||||||
result_overlapping_panels?.setChildGestureRegions(gestureRegions)
|
binding?.resultOverlappingPanels?.setChildGestureRegions(gestureRegions)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||||
val isInvalid = rec.isNullOrEmpty()
|
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
|
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
|
||||||
rec?.map { it.apiName }?.distinct()?.let { apiNames ->
|
|
||||||
// very dirty selection
|
recommendationBinding?.apply {
|
||||||
result_recommendations_filter_button?.isVisible = apiNames.size > 1
|
root.isGone = isInvalid
|
||||||
result_recommendations_filter_button?.text = matchAgainst
|
root.post {
|
||||||
result_recommendations_filter_button?.setOnClickListener { _ ->
|
rec?.let { list ->
|
||||||
activity?.showBottomDialog(
|
(resultRecommendationsList.adapter as? SearchAdapter)?.updateList(list.filter { it.apiName == matchAgainst })
|
||||||
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 {
|
binding?.apply {
|
||||||
rec?.let { list ->
|
resultRecommendationsBtt.isGone = isInvalid
|
||||||
(result_recommendations?.adapter as? SearchAdapter)?.updateList(list.filter { it.apiName == matchAgainst })
|
resultRecommendationsBtt.setOnClickListener {
|
||||||
|
val nextFocusDown = if (resultOverlappingPanels.getSelectedPanel().ordinal == 1) {
|
||||||
|
resultOverlappingPanels.openEndPanel()
|
||||||
|
R.id.result_recommendations
|
||||||
|
} else {
|
||||||
|
resultOverlappingPanels.closePanels()
|
||||||
|
R.id.result_description
|
||||||
|
}
|
||||||
|
resultBinding?.apply {
|
||||||
|
resultRecommendationsBtt.nextFocusDownId = nextFocusDown
|
||||||
|
resultSearch.nextFocusDownId = nextFocusDown
|
||||||
|
resultOpenInBrowser.nextFocusDownId = nextFocusDown
|
||||||
|
resultShare.nextFocusDownId = nextFocusDown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resultOverlappingPanels.setEndPanelLockState(if (isInvalid) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)
|
||||||
|
|
||||||
|
rec?.map { it.apiName }?.distinct()?.let { apiNames ->
|
||||||
|
// very dirty selection
|
||||||
|
recommendationBinding?.resultRecommendationsFilterButton?.apply {
|
||||||
|
isVisible = apiNames.size > 1
|
||||||
|
text = matchAgainst
|
||||||
|
setOnClickListener { _ ->
|
||||||
|
activity?.showBottomDialog(
|
||||||
|
apiNames,
|
||||||
|
apiNames.indexOf(matchAgainst),
|
||||||
|
getString(R.string.home_change_provider_img_des), false, {}
|
||||||
|
) {
|
||||||
|
setRecommendations(rec, apiNames[it])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ?: run {
|
||||||
|
recommendationBinding?.resultRecommendationsFilterButton?.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package com.lagradost.cloudstream3.ui.result
|
package com.lagradost.cloudstream3.ui.result
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
|
import android.content.res.ColorStateList
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
@ -12,23 +15,43 @@ import com.lagradost.cloudstream3.DubStatus
|
||||||
import com.lagradost.cloudstream3.LoadResponse
|
import com.lagradost.cloudstream3.LoadResponse
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.SearchResponse
|
import com.lagradost.cloudstream3.SearchResponse
|
||||||
|
import com.lagradost.cloudstream3.databinding.FragmentResultTvBinding
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
import com.lagradost.cloudstream3.mvvm.observe
|
import com.lagradost.cloudstream3.mvvm.observe
|
||||||
import com.lagradost.cloudstream3.mvvm.observeNullable
|
import com.lagradost.cloudstream3.mvvm.observeNullable
|
||||||
|
import com.lagradost.cloudstream3.ui.WatchType
|
||||||
import com.lagradost.cloudstream3.ui.player.ExtractorLinkGenerator
|
import com.lagradost.cloudstream3.ui.player.ExtractorLinkGenerator
|
||||||
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
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.SingleSelectionHelper.showBottomDialogInstant
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||||
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
|
||||||
|
|
||||||
class ResultFragmentTv : ResultFragment() {
|
class ResultFragmentTv : ResultFragment() {
|
||||||
override val resultLayout = R.layout.fragment_result_tv
|
override val resultLayout = R.layout.fragment_result_tv
|
||||||
|
|
||||||
|
private var binding: FragmentResultTvBinding? = null
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
binding = null
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
val root = super.onCreateView(inflater, container, savedInstanceState) ?: return null
|
||||||
|
binding = FragmentResultTvBinding.bind(root)
|
||||||
|
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
private var currentRecommendations: List<SearchResponse> = emptyList()
|
private var currentRecommendations: List<SearchResponse> = emptyList()
|
||||||
|
|
||||||
private fun handleSelection(data: Any) {
|
private fun handleSelection(data: Any) {
|
||||||
|
@ -36,12 +59,15 @@ class ResultFragmentTv : ResultFragment() {
|
||||||
is EpisodeRange -> {
|
is EpisodeRange -> {
|
||||||
viewModel.changeRange(data)
|
viewModel.changeRange(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
is Int -> {
|
is Int -> {
|
||||||
viewModel.changeSeason(data)
|
viewModel.changeSeason(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
is DubStatus -> {
|
is DubStatus -> {
|
||||||
viewModel.changeDubStatus(data)
|
viewModel.changeDubStatus(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
is String -> {
|
is String -> {
|
||||||
setRecommendations(currentRecommendations, data)
|
setRecommendations(currentRecommendations, data)
|
||||||
}
|
}
|
||||||
|
@ -66,57 +92,60 @@ class ResultFragmentTv : ResultFragment() {
|
||||||
private fun hasNoFocus(): Boolean {
|
private fun hasNoFocus(): Boolean {
|
||||||
val focus = activity?.currentFocus
|
val focus = activity?.currentFocus
|
||||||
if (focus == null || !focus.isVisible) return true
|
if (focus == null || !focus.isVisible) return true
|
||||||
return focus == this.result_root
|
return focus == binding?.resultRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateEpisodes(episodes: Resource<List<ResultEpisode>>?) {
|
override fun updateEpisodes(episodes: Resource<List<ResultEpisode>>?) {
|
||||||
super.updateEpisodes(episodes)
|
super.updateEpisodes(episodes)
|
||||||
if (episodes is Resource.Success && hasNoFocus()) {
|
if (episodes is Resource.Success && hasNoFocus()) {
|
||||||
result_episodes?.requestFocus()
|
binding?.resultEpisodes?.requestFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateMovie(data: Resource<Pair<UiText, ResultEpisode>>?) {
|
override fun updateMovie(data: Resource<Pair<UiText, ResultEpisode>>?) {
|
||||||
super.updateMovie(data)
|
super.updateMovie(data)
|
||||||
if (data is Resource.Success && hasNoFocus()) {
|
if (data is Resource.Success && hasNoFocus()) {
|
||||||
result_play_movie?.requestFocus()
|
binding?.resultPlayMovie?.requestFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setTrailers(trailers: List<ExtractorLink>?) {
|
override fun setTrailers(trailers: List<ExtractorLink>?) {
|
||||||
context?.updateHasTrailers()
|
context?.updateHasTrailers()
|
||||||
if (!LoadResponse.isTrailersEnabled) return
|
if (!LoadResponse.isTrailersEnabled) return
|
||||||
|
binding?.resultPlayTrailer?.apply {
|
||||||
result_play_trailer?.isGone = trailers.isNullOrEmpty()
|
isGone = trailers.isNullOrEmpty()
|
||||||
result_play_trailer?.setOnClickListener {
|
setOnClickListener {
|
||||||
if (trailers.isNullOrEmpty()) return@setOnClickListener
|
if (trailers.isNullOrEmpty()) return@setOnClickListener
|
||||||
activity.navigate(
|
activity.navigate(
|
||||||
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
|
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
|
||||||
ExtractorLinkGenerator(
|
ExtractorLinkGenerator(
|
||||||
trailers,
|
trailers,
|
||||||
emptyList()
|
emptyList()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||||
currentRecommendations = rec ?: emptyList()
|
currentRecommendations = rec ?: emptyList()
|
||||||
val isInvalid = rec.isNullOrEmpty()
|
val isInvalid = rec.isNullOrEmpty()
|
||||||
result_recommendations?.isGone = isInvalid
|
binding?.apply {
|
||||||
result_recommendations_holder?.isGone = isInvalid
|
resultRecommendationsList.isGone = isInvalid
|
||||||
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
|
resultRecommendationsHolder.isGone = isInvalid
|
||||||
(result_recommendations?.adapter as? SearchAdapter)?.updateList(rec?.filter { it.apiName == matchAgainst }
|
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
|
||||||
?: emptyList())
|
(resultRecommendationsList.adapter as? SearchAdapter)?.updateList(rec?.filter { it.apiName == matchAgainst }
|
||||||
|
?: emptyList())
|
||||||
|
|
||||||
rec?.map { it.apiName }?.distinct()?.let { apiNames ->
|
rec?.map { it.apiName }?.distinct()?.let { apiNames ->
|
||||||
// very dirty selection
|
// very dirty selection
|
||||||
result_recommendations_filter_selection?.isVisible = apiNames.size > 1
|
resultRecommendationsFilterSelection.isVisible = apiNames.size > 1
|
||||||
result_recommendations_filter_selection?.update(apiNames.map { txt(it) to it })
|
resultRecommendationsFilterSelection.update(apiNames.map { txt(it) to it })
|
||||||
result_recommendations_filter_selection?.select(apiNames.indexOf(matchAgainst))
|
resultRecommendationsFilterSelection.select(apiNames.indexOf(matchAgainst))
|
||||||
} ?: run {
|
} ?: run {
|
||||||
result_recommendations_filter_selection?.isVisible = false
|
resultRecommendationsFilterSelection.isVisible = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,24 +153,37 @@ class ResultFragmentTv : ResultFragment() {
|
||||||
var popupDialog: Dialog? = null
|
var popupDialog: Dialog? = null
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
binding?.apply {
|
||||||
|
resultEpisodes.layoutManager =
|
||||||
|
LinearListLayout(resultEpisodes.context).apply {
|
||||||
|
setHorizontal()
|
||||||
|
}
|
||||||
|
|
||||||
result_episodes?.layoutManager =
|
resultSeasonSelection.setAdapter()
|
||||||
//LinearListLayout(result_episodes ?: return, result_episodes?.context).apply {
|
resultRangeSelection.setAdapter()
|
||||||
LinearListLayout(result_episodes?.context).apply {
|
resultDubSelection.setAdapter()
|
||||||
setHorizontal()
|
resultRecommendationsFilterSelection.setAdapter()
|
||||||
|
}
|
||||||
|
|
||||||
|
observe(viewModel.watchStatus) { watchType ->
|
||||||
|
binding?.resultBookmarkButton?.apply {
|
||||||
|
setText(watchType.stringRes)
|
||||||
|
setOnClickListener { view ->
|
||||||
|
activity?.showBottomDialog(
|
||||||
|
WatchType.values().map { view.context.getString(it.stringRes) }.toList(),
|
||||||
|
watchType.ordinal,
|
||||||
|
view.context.getString(R.string.action_add_to_bookmarks),
|
||||||
|
showApply = false,
|
||||||
|
{}) {
|
||||||
|
viewModel.updateWatchStatus(WatchType.values()[it])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// (result_episodes?.adapter as EpisodeAdapter?)?.apply {
|
}
|
||||||
// layout = R.layout.result_episode_both_tv
|
|
||||||
// }
|
|
||||||
//result_episodes?.setMaxViewPoolSize(0, Int.MAX_VALUE)
|
|
||||||
|
|
||||||
result_season_selection.setAdapter()
|
|
||||||
result_range_selection.setAdapter()
|
|
||||||
result_dub_selection.setAdapter()
|
|
||||||
result_recommendations_filter_selection.setAdapter()
|
|
||||||
|
|
||||||
observeNullable(viewModel.selectPopup) { popup ->
|
observeNullable(viewModel.selectPopup) { popup ->
|
||||||
if(popup == null) {
|
if (popup == null) {
|
||||||
popupDialog?.dismissSafe(activity)
|
popupDialog?.dismissSafe(activity)
|
||||||
popupDialog = null
|
popupDialog = null
|
||||||
return@observeNullable
|
return@observeNullable
|
||||||
|
@ -166,67 +208,70 @@ class ResultFragmentTv : ResultFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
observeNullable(viewModel.loadedLinks) { load ->
|
observeNullable(viewModel.loadedLinks) { load ->
|
||||||
if(load == null) {
|
if (load == null) {
|
||||||
loadingDialog?.dismissSafe(activity)
|
loadingDialog?.dismissSafe(activity)
|
||||||
loadingDialog = null
|
loadingDialog = null
|
||||||
return@observeNullable
|
return@observeNullable
|
||||||
}
|
}
|
||||||
if (loadingDialog?.isShowing != true) {
|
if (loadingDialog?.isShowing != true) {
|
||||||
loadingDialog?.dismissSafe(activity)
|
loadingDialog?.dismissSafe(activity)
|
||||||
loadingDialog = null
|
loadingDialog = null
|
||||||
}
|
}
|
||||||
loadingDialog = loadingDialog ?: context?.let { ctx ->
|
loadingDialog = loadingDialog ?: context?.let { ctx ->
|
||||||
val builder = BottomSheetDialog(ctx)
|
val builder = BottomSheetDialog(ctx)
|
||||||
builder.setContentView(R.layout.bottom_loading)
|
builder.setContentView(R.layout.bottom_loading)
|
||||||
builder.setOnDismissListener {
|
builder.setOnDismissListener {
|
||||||
loadingDialog = null
|
loadingDialog = null
|
||||||
viewModel.cancelLinks()
|
viewModel.cancelLinks()
|
||||||
}
|
}
|
||||||
//builder.setOnCancelListener {
|
//builder.setOnCancelListener {
|
||||||
// it?.dismiss()
|
// it?.dismiss()
|
||||||
//}
|
//}
|
||||||
builder.setCanceledOnTouchOutside(true)
|
builder.setCanceledOnTouchOutside(true)
|
||||||
builder.show()
|
builder.show()
|
||||||
builder
|
builder
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
observeNullable(viewModel.episodesCountText) { count ->
|
observeNullable(viewModel.episodesCountText) { count ->
|
||||||
result_episodes_text.setText(count)
|
binding?.resultEpisodesText.setText(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.selectedRangeIndex) { selected ->
|
observe(viewModel.selectedRangeIndex) { selected ->
|
||||||
result_range_selection.select(selected)
|
binding?.resultRangeSelection.select(selected)
|
||||||
}
|
}
|
||||||
observe(viewModel.selectedSeasonIndex) { selected ->
|
observe(viewModel.selectedSeasonIndex) { selected ->
|
||||||
result_season_selection.select(selected)
|
binding?.resultSeasonSelection.select(selected)
|
||||||
}
|
}
|
||||||
observe(viewModel.selectedDubStatusIndex) { selected ->
|
observe(viewModel.selectedDubStatusIndex) { selected ->
|
||||||
result_dub_selection.select(selected)
|
binding?.resultDubSelection.select(selected)
|
||||||
}
|
}
|
||||||
observe(viewModel.rangeSelections) {
|
observe(viewModel.rangeSelections) {
|
||||||
result_range_selection.update(it)
|
binding?.resultRangeSelection.update(it)
|
||||||
}
|
}
|
||||||
observe(viewModel.dubSubSelections) {
|
observe(viewModel.dubSubSelections) {
|
||||||
result_dub_selection.update(it)
|
binding?.resultDubSelection.update(it)
|
||||||
}
|
}
|
||||||
observe(viewModel.seasonSelections) {
|
observe(viewModel.seasonSelections) {
|
||||||
result_season_selection.update(it)
|
binding?.resultSeasonSelection.update(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
result_back?.setOnClickListener {
|
binding?.apply {
|
||||||
activity?.popCurrentPage()
|
resultBack.setOnClickListener {
|
||||||
}
|
activity?.popCurrentPage()
|
||||||
|
|
||||||
result_recommendations?.spanCount = 8
|
|
||||||
result_recommendations?.adapter =
|
|
||||||
SearchAdapter(
|
|
||||||
ArrayList(),
|
|
||||||
result_recommendations,
|
|
||||||
) { callback ->
|
|
||||||
SearchHelper.handleSearchClickCallback(callback)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resultRecommendationsList.spanCount = 8
|
||||||
|
resultRecommendationsList.adapter =
|
||||||
|
SearchAdapter(
|
||||||
|
ArrayList(),
|
||||||
|
resultRecommendationsList,
|
||||||
|
) { callback ->
|
||||||
|
SearchHelper.handleSearchClickCallback(callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,6 +13,7 @@ import androidx.core.view.isVisible
|
||||||
import com.discord.panels.PanelsChildGestureRegionObserver
|
import com.discord.panels.PanelsChildGestureRegionObserver
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
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.ui.player.SubtitleData
|
||||||
import com.lagradost.cloudstream3.utils.IOnBackPressed
|
import com.lagradost.cloudstream3.utils.IOnBackPressed
|
||||||
import kotlinx.android.synthetic.main.fragment_result.*
|
import kotlinx.android.synthetic.main.fragment_result.*
|
||||||
|
@ -20,10 +21,9 @@ 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_swipe.*
|
||||||
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
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.trailer_custom_layout.*
|
|
||||||
|
|
||||||
|
|
||||||
open class ResultTrailerPlayer : com.lagradost.cloudstream3.ui.player.FullScreenPlayer(),
|
open class ResultTrailerPlayer : FullScreenPlayer(),
|
||||||
PanelsChildGestureRegionObserver.GestureRegionsListener, IOnBackPressed {
|
PanelsChildGestureRegionObserver.GestureRegionsListener, IOnBackPressed {
|
||||||
|
|
||||||
override var lockRotation = false
|
override var lockRotation = false
|
||||||
|
@ -75,7 +75,7 @@ open class ResultTrailerPlayer : com.lagradost.cloudstream3.ui.player.FullScreen
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
player_intro_play?.apply {
|
playerBinding?.playerIntroPlay?.apply {
|
||||||
layoutParams =
|
layoutParams =
|
||||||
FrameLayout.LayoutParams(
|
FrameLayout.LayoutParams(
|
||||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
@ -83,7 +83,7 @@ open class ResultTrailerPlayer : com.lagradost.cloudstream3.ui.player.FullScreen
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player_intro_play?.isGone == true) {
|
if (playerBinding?.playerIntroPlay?.isGone == true) {
|
||||||
result_top_holder?.apply {
|
result_top_holder?.apply {
|
||||||
|
|
||||||
val anim = ValueAnimator.ofInt(
|
val anim = ValueAnimator.ofInt(
|
||||||
|
@ -131,7 +131,8 @@ open class ResultTrailerPlayer : com.lagradost.cloudstream3.ui.player.FullScreen
|
||||||
private fun updateFullscreen(fullscreen: Boolean) {
|
private fun updateFullscreen(fullscreen: Boolean) {
|
||||||
isFullScreenPlayer = fullscreen
|
isFullScreenPlayer = fullscreen
|
||||||
lockRotation = fullscreen
|
lockRotation = fullscreen
|
||||||
player_fullscreen?.setImageResource(if (fullscreen) R.drawable.baseline_fullscreen_exit_24 else R.drawable.baseline_fullscreen_24)
|
|
||||||
|
playerBinding?.playerFullscreen?.setImageResource(if (fullscreen) R.drawable.baseline_fullscreen_exit_24 else R.drawable.baseline_fullscreen_24)
|
||||||
if (fullscreen) {
|
if (fullscreen) {
|
||||||
enterFullscreen()
|
enterFullscreen()
|
||||||
result_top_bar?.isVisible = false
|
result_top_bar?.isVisible = false
|
||||||
|
@ -157,14 +158,14 @@ open class ResultTrailerPlayer : com.lagradost.cloudstream3.ui.player.FullScreen
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
player_fullscreen?.setOnClickListener {
|
playerBinding?.playerFullscreen?.setOnClickListener {
|
||||||
updateFullscreen(!isFullScreenPlayer)
|
updateFullscreen(!isFullScreenPlayer)
|
||||||
}
|
}
|
||||||
updateFullscreen(isFullScreenPlayer)
|
updateFullscreen(isFullScreenPlayer)
|
||||||
uiReset()
|
uiReset()
|
||||||
|
|
||||||
player_intro_play?.setOnClickListener {
|
playerBinding?.playerIntroPlay?.setOnClickListener {
|
||||||
player_intro_play?.isGone = true
|
playerBinding?.playerIntroPlay?.isGone = true
|
||||||
player.handleEvent(CSPlayerEvent.Play)
|
player.handleEvent(CSPlayerEvent.Play)
|
||||||
updateUIVisibility()
|
updateUIVisibility()
|
||||||
fixPlayerSize()
|
fixPlayerSize()
|
||||||
|
|
|
@ -277,7 +277,9 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:descendantFocusability="blocksDescendants">
|
android:descendantFocusability="blocksDescendants">
|
||||||
|
|
||||||
<include layout="@layout/fragment_trailer" />
|
<include
|
||||||
|
android:id="@+id/fragment_trailer"
|
||||||
|
layout="@layout/fragment_trailer" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
@ -721,7 +723,6 @@
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/result_episodes_tab"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
|
@ -189,7 +189,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="start">
|
android:layout_gravity="start">
|
||||||
|
|
||||||
<include layout="@layout/result_sync"/>
|
<include layout="@layout/result_sync" android:id="@+id/result_sync"/>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
@ -198,7 +198,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<include layout="@layout/fragment_result" />
|
<include layout="@layout/fragment_result" android:id="@+id/fragment_result" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="end">
|
android:layout_gravity="end">
|
||||||
|
|
||||||
<include layout="@layout/result_recommendations" />
|
<include layout="@layout/result_recommendations" android:id="@+id/result_recommendations" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
</com.discord.panels.OverlappingPanelsLayout>
|
</com.discord.panels.OverlappingPanelsLayout>
|
||||||
|
|
||||||
|
|
|
@ -746,7 +746,7 @@
|
||||||
android:layout_marginEnd="10dp"
|
android:layout_marginEnd="10dp"
|
||||||
android:nextFocusUp="@id/result_episodes"
|
android:nextFocusUp="@id/result_episodes"
|
||||||
|
|
||||||
android:nextFocusDown="@id/result_recommendations"
|
android:nextFocusDown="@id/result_recommendations_list"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
tools:itemCount="2"
|
tools:itemCount="2"
|
||||||
|
@ -763,7 +763,7 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<com.lagradost.cloudstream3.ui.AutofitRecyclerView
|
<com.lagradost.cloudstream3.ui.AutofitRecyclerView
|
||||||
android:id="@+id/result_recommendations"
|
android:id="@+id/result_recommendations_list"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
|
@ -84,6 +84,33 @@
|
||||||
style="@style/SmallBlackButton"
|
style="@style/SmallBlackButton"
|
||||||
android:text="@string/filler" />
|
android:text="@string/filler" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
<!-- atm this is useless, however it might be used for PIP one day? -->
|
||||||
|
<ImageView
|
||||||
|
android:visibility="gone"
|
||||||
|
android:id="@+id/player_fullscreen"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:src="@drawable/baseline_fullscreen_24"
|
||||||
|
app:tint="@color/white" />
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/player_intro_play"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/player_open_source"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:clickable="false"
|
||||||
|
android:focusable="false"
|
||||||
|
android:focusableInTouchMode="false"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:importantForAccessibility="no" />
|
||||||
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/player_video_holder"
|
android:id="@+id/player_video_holder"
|
||||||
|
|
|
@ -167,6 +167,34 @@
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:visibility="gone"
|
||||||
|
android:id="@+id/player_intro_play"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:visibility="gone"
|
||||||
|
android:id="@+id/player_open_source"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:clickable="false"
|
||||||
|
android:focusable="false"
|
||||||
|
android:focusableInTouchMode="false"
|
||||||
|
android:importantForAccessibility="no" />
|
||||||
|
|
||||||
|
<!-- atm this is useless, however it might be used for PIP one day? -->
|
||||||
|
<ImageView
|
||||||
|
android:visibility="gone"
|
||||||
|
android:id="@+id/player_fullscreen"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:src="@drawable/baseline_fullscreen_24"
|
||||||
|
app:tint="@color/white" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/player_video_holder"
|
android:id="@+id/player_video_holder"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
android:layout_marginBottom="10dp"
|
android:layout_marginBottom="10dp"
|
||||||
android:layout_marginStart="0dp"
|
android:layout_marginStart="0dp"
|
||||||
android:layout_marginEnd="0dp"
|
android:layout_marginEnd="0dp"
|
||||||
app:layout_constraintBottom_toTopOf="@id/result_recommendations" />
|
app:layout_constraintBottom_toTopOf="@id/result_recommendations_list" />
|
||||||
|
|
||||||
<com.lagradost.cloudstream3.ui.AutofitRecyclerView
|
<com.lagradost.cloudstream3.ui.AutofitRecyclerView
|
||||||
android:descendantFocusability="afterDescendants"
|
android:descendantFocusability="afterDescendants"
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
app:spanCount="3"
|
app:spanCount="3"
|
||||||
android:id="@+id/result_recommendations"
|
android:id="@+id/result_recommendations_list"
|
||||||
tools:listitem="@layout/search_result_grid"
|
tools:listitem="@layout/search_result_grid"
|
||||||
android:orientation="vertical" />
|
android:orientation="vertical" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -75,11 +75,118 @@
|
||||||
android:src="@drawable/play_button" />
|
android:src="@drawable/play_button" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:visibility="gone"
|
||||||
|
android:id="@+id/player_top_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="80dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:layout_marginEnd="32dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/player_video_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="Hello world" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/player_video_title_rez"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:text="1920x1080" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/player_episode_filler_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginTop="2dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_episode_filler"
|
||||||
|
style="@style/SmallBlackButton"
|
||||||
|
android:text="@string/filler" />
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Removed as it has no use anymore-->
|
||||||
|
<!--<androidx.mediarouter.app.MediaRouteButton
|
||||||
|
android:id="@+id/player_media_route_button"
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="70dp"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:mediaRouteTypes="user"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />-->
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/player_go_back_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:contentDescription="@string/go_back_img_des"
|
||||||
|
android:src="@drawable/ic_baseline_arrow_back_24"
|
||||||
|
app:tint="@android:color/white" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/player_go_back"
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="70dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:background="@drawable/video_tap_button_always_white"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/go_back_img_des"
|
||||||
|
android:focusable="true" />
|
||||||
|
</FrameLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/player_video_holder"
|
android:id="@+id/player_video_holder"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/skip_chapter_button"
|
||||||
|
style="@style/NiceButton"
|
||||||
|
android:layout_width="150dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginEnd="100dp"
|
||||||
|
android:backgroundTint="@color/skipOpTransparent"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:cornerRadius="@dimen/rounded_button_radius"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/bottom_player_bar"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:strokeColor="@color/white"
|
||||||
|
app:strokeWidth="1dp"
|
||||||
|
tools:text="Skip Opening"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<!--use for thinner app:trackThickness="3dp" com.google.android.material.progressindicator.CircularProgressIndicator-->
|
<!--use for thinner app:trackThickness="3dp" com.google.android.material.progressindicator.CircularProgressIndicator-->
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/player_buffering"
|
android:id="@+id/player_buffering"
|
||||||
|
@ -282,6 +389,11 @@
|
||||||
tools:ignore="ContentDescription" />
|
tools:ignore="ContentDescription" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/piphide"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/player_open_source"
|
android:id="@+id/player_open_source"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
|
@ -366,7 +478,110 @@
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:src="@drawable/baseline_fullscreen_24"
|
android:src="@drawable/baseline_fullscreen_24"
|
||||||
app:tint="@color/white" />
|
app:tint="@color/white" />
|
||||||
|
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingBottom="10dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_lock"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:nextFocusLeft="@id/player_skip_episode"
|
||||||
|
android:nextFocusRight="@id/player_resize_btt"
|
||||||
|
android:text="@string/video_lock"
|
||||||
|
app:icon="@drawable/video_locked"
|
||||||
|
|
||||||
|
app:iconSize="30dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/player_lock_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_resize_btt"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:nextFocusLeft="@id/player_lock"
|
||||||
|
|
||||||
|
android:nextFocusRight="@id/player_speed_btt"
|
||||||
|
android:text="@string/video_aspect_ratio_resize"
|
||||||
|
app:icon="@drawable/ic_baseline_aspect_ratio_24" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_speed_btt"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:nextFocusLeft="@id/player_resize_btt"
|
||||||
|
|
||||||
|
android:nextFocusRight="@id/player_subtitle_offset_btt"
|
||||||
|
app:icon="@drawable/ic_baseline_speed_24"
|
||||||
|
tools:text="Speed" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_subtitle_offset_btt"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:nextFocusLeft="@id/player_speed_btt"
|
||||||
|
android:nextFocusRight="@id/player_sources_btt"
|
||||||
|
android:text="@string/subtitle_offset"
|
||||||
|
|
||||||
|
android:visibility="gone"
|
||||||
|
app:icon="@drawable/ic_outline_subtitles_24"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_sources_btt"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
|
||||||
|
android:nextFocusLeft="@id/player_subtitle_offset_btt"
|
||||||
|
android:nextFocusRight="@id/player_tracks_btt"
|
||||||
|
android:text="@string/video_source"
|
||||||
|
app:icon="@drawable/ic_baseline_playlist_play_24" />
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_tracks_btt"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
|
||||||
|
android:nextFocusLeft="@id/player_sources_btt"
|
||||||
|
android:nextFocusRight="@id/player_skip_op"
|
||||||
|
android:text="@string/tracks"
|
||||||
|
app:icon="@drawable/ic_baseline_playlist_play_24" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_skip_op"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:nextFocusLeft="@id/player_sources_btt"
|
||||||
|
|
||||||
|
android:nextFocusRight="@id/player_skip_episode"
|
||||||
|
android:text="@string/video_skip_op"
|
||||||
|
app:icon="@drawable/ic_baseline_fast_forward_24" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_skip_episode"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:nextFocusLeft="@id/player_skip_op"
|
||||||
|
|
||||||
|
android:nextFocusRight="@id/player_lock"
|
||||||
|
android:text="@string/next_episode"
|
||||||
|
app:icon="@drawable/ic_baseline_skip_next_24" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|
Loading…
Reference in a new issue