Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@ open class HomeChildItemAdapter(
position,
holder.itemView,
nextFocusUp,
nextFocusDown
nextFocusDown,
isHorizontal = isHorizontal
)

holder.itemView.tag = position
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.lagradost.cloudstream3.APIHolder
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
import com.lagradost.cloudstream3.CommonActivity.activity
import com.lagradost.cloudstream3.HomePageList
Expand Down Expand Up @@ -146,10 +147,13 @@ class QuickSearchFragment : BaseFragment<QuickSearchBinding>(

val firstProvider = providers?.firstOrNull()
if (isSingleProvider && firstProvider != null) {
val isHorizontal = APIHolder.isApiHorizontal(firstProvider)
binding.quickSearchAutofitResults.apply {
spanCount = context.getSpanCount(isHorizontal)
setRecycledViewPool(SearchAdapter.sharedPool)
adapter = SearchAdapter(
this,
isHorizontal = isHorizontal,
) { callback ->
SearchHelper.handleSearchClickCallback(callback)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import com.lagradost.cloudstream3.ui.result.ResultFragment.updateUIEvent
import com.lagradost.cloudstream3.ui.search.SearchAdapter
import com.lagradost.cloudstream3.ui.search.SearchHelper
import com.lagradost.cloudstream3.ui.setRecycledViewPool
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
import com.lagradost.cloudstream3.ui.settings.SettingsGeneral.Companion.pickDownloadPath
import com.lagradost.cloudstream3.ui.settings.utils.getChooseFolderLauncher
import com.lagradost.cloudstream3.utils.AppContextUtils.getNameFull
Expand Down Expand Up @@ -1450,12 +1451,25 @@ open class ResultFragmentPhone : BaseFragment<FragmentResultSwipeBinding>(
private fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
val isInvalid = rec.isNullOrEmpty()
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
val isHorizontal = viewModel.isRecommendationsHorizontal(rec)

recommendationBinding?.apply {
root.isGone = isInvalid
resultRecommendationsList.spanCount = root.context.getSpanCount(isHorizontal)
val currentAdapter = resultRecommendationsList.adapter as? SearchAdapter
val adapter = if (currentAdapter != null) {
currentAdapter.apply { this.isHorizontal = isHorizontal }
} else {
SearchAdapter(
resultRecommendationsList,
isHorizontal = isHorizontal,
) { callback ->
SearchHelper.handleSearchClickCallback(callback)
}.also { resultRecommendationsList.adapter = it }
}
root.post {
rec?.let { list ->
(resultRecommendationsList.adapter as? SearchAdapter)?.submitList(list.filter { it.apiName == matchAgainst })
adapter.submitList(list.filter { it.apiName == matchAgainst })
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,26 @@ class ResultFragmentTv : BaseFragment<FragmentResultTvBinding>(
private fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
currentRecommendations = rec ?: emptyList()
val isInvalid = rec.isNullOrEmpty()
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
val isHorizontal = viewModel.isRecommendationsHorizontal(rec)
binding?.apply {
resultRecommendationsList.isGone = isInvalid
resultRecommendationsHolder.isGone = isInvalid
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
(resultRecommendationsList.adapter as? SearchAdapter)?.submitList(rec?.filter { it.apiName == matchAgainst }
resultRecommendationsList.spanCount = if (isHorizontal) 4 else 8
val currentAdapter = resultRecommendationsList.adapter as? SearchAdapter
val adapter = if (currentAdapter != null) {
currentAdapter.apply { this.isHorizontal = isHorizontal }
} else {
SearchAdapter(
resultRecommendationsList,
isHorizontal = isHorizontal,
) { callback ->
if (callback.action == SEARCH_ACTION_FOCUSED) {
toggleEpisodes(false)
} else SearchHelper.handleSearchClickCallback(callback)
}.also { resultRecommendationsList.adapter = it }
}
adapter.submitList(rec?.filter { it.apiName == matchAgainst }
?: emptyList())

rec?.map { it.apiName }?.distinct()?.let { apiNames ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.SeasonData
import com.lagradost.cloudstream3.ShowStatus
import com.lagradost.cloudstream3.SimklSyncServices
import com.lagradost.cloudstream3.isHorizontalCard
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.TorrentLoadResponse
import com.lagradost.cloudstream3.TrackerType
Expand Down Expand Up @@ -193,6 +194,7 @@ data class ResultData(
val nextAiringDate: UiText?,
val nextAiringEpisode: UiText?,
val plotHeaderText: UiText,
val isHorizontalRecommendations: Boolean = false,
val posterHeaders: Map<String, String>? = null,
)

Expand Down Expand Up @@ -305,6 +307,7 @@ fun LoadResponse.toResultData(repo: APIRepository): ResultData {
backgroundPosterUrl = backgroundPosterUrl,
logoUrl = logoUrl,
title = name,
isHorizontalRecommendations = this.isHorizontalRecommendations || APIHolder.getApiFromNameNull(this.apiName)?.hasHorizontalRecommendations == true || APIHolder.isApiHorizontal(this.apiName) || type == TvType.Live,
typeText = txt(
when (type) {
TvType.TvSeries -> R.string.tv_series_singular
Expand Down Expand Up @@ -492,6 +495,12 @@ class ResultViewModel2 : ViewModel() {
MutableLiveData(null)
val page: LiveData<Resource<ResultData>?> = _page

/** Whether the currently loaded content's recommendations should render as horizontal cards. */
fun isRecommendationsHorizontal(rec: List<SearchResponse>?): Boolean {
return (page.value as? Resource.Success)?.value?.isHorizontalRecommendations == true ||
rec?.any { it.isHorizontalCard() } == true
}

private val _episodes: MutableLiveData<Resource<List<ResultEpisode>>?> =
MutableLiveData(Resource.Loading())
val episodes: LiveData<Resource<List<ResultEpisode>>?> = _episodes
Expand Down Expand Up @@ -2559,6 +2568,7 @@ class ResultViewModel2 : ViewModel() {
override var duration: Int? = null,
override var trailers: MutableList<TrailerData> = mutableListOf(),
override var recommendations: List<SearchResponse>? = null,
override var isHorizontalRecommendations: Boolean = false,
override var actors: List<ActorData>? = null,
override var comingSoon: Boolean = false,
override var syncData: MutableMap<String, String> = mutableMapOf(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package com.lagradost.cloudstream3.ui.search
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.isHorizontalCard
import com.lagradost.cloudstream3.databinding.SearchResultGridBinding
import com.lagradost.cloudstream3.databinding.SearchResultGridExpandedBinding
import com.lagradost.cloudstream3.ui.AutofitRecyclerView
Expand Down Expand Up @@ -32,7 +32,7 @@ class SearchClickCallback(

class SearchAdapter(
private val resView: AutofitRecyclerView,
private val isHorizontal:Boolean = false,
var isHorizontal: Boolean = false,
private val clickCallback: (SearchClickCallback) -> Unit,
) : NoStateAdapter<SearchResponse>(diffCallback = BaseDiffCallback(itemSame = { a, b ->
if (a.id != null || b.id != null) {
Expand All @@ -48,10 +48,6 @@ class SearchAdapter(

var hasNext: Boolean = false

private val coverRatio = if(isHorizontal) 1.8 else 0.68

private val coverHeight: Int get() = (resView.itemWidth / coverRatio).roundToInt()

override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {
val inflater = LayoutInflater.from(parent.context)

Expand Down Expand Up @@ -79,21 +75,23 @@ class SearchAdapter(
}

override fun onBindContent(holder: ViewHolderState<Any>, item: SearchResponse, position: Int) {
val imageView = when (val binding = holder.view) {
is SearchResultGridExpandedBinding -> binding.imageView
is SearchResultGridBinding -> binding.imageView
val isCardHorizontal = item.isHorizontalCard(isHorizontal)

val currentRatio = if (isCardHorizontal) 1.8 else 0.68
val currentCoverHeight = (resView.itemWidth / currentRatio).roundToInt()

val backgroundCard = when (val binding = holder.view) {
is SearchResultGridExpandedBinding -> binding.backgroundCard
is SearchResultGridBinding -> binding.backgroundCard
else -> null
}

if (imageView != null) {
val params = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
coverHeight
)
if (imageView.layoutParams.width != params.width || imageView.layoutParams.height != params.height) {
imageView.layoutParams = params
backgroundCard?.let {
val cardParams = it.layoutParams
if (cardParams.height != currentCoverHeight) {
cardParams.height = currentCoverHeight
it.layoutParams = cardParams
}
}
SearchResultBuilder.bind(clickCallback, item, position, holder.view.root)
SearchResultBuilder.bind(clickCallback, item, position, holder.view.root, isHorizontal = isCardHorizontal)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import androidx.core.view.doOnLayout
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.button.MaterialButton
import com.lagradost.cloudstream3.APIHolder
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
import com.lagradost.cloudstream3.AllLanguagesName
import com.lagradost.cloudstream3.AnimeSearchResponse
Expand All @@ -40,6 +41,7 @@ import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.isHorizontalCard
import com.lagradost.cloudstream3.databinding.FragmentSearchBinding
import com.lagradost.cloudstream3.databinding.HomeSelectMainpageBinding
import com.lagradost.cloudstream3.mvvm.Resource
Expand All @@ -48,6 +50,7 @@ import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.ui.APIRepository
import com.lagradost.cloudstream3.ui.BaseAdapter
import com.lagradost.cloudstream3.ui.BaseFragment
import com.lagradost.cloudstream3.ui.home.HomeChildItemAdapter
import com.lagradost.cloudstream3.ui.home.HomeFragment
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.bindChips
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.currentSpan
Expand Down Expand Up @@ -234,6 +237,7 @@ class SearchFragment : BaseFragment<FragmentSearchBinding>(
binding: FragmentSearchBinding,
savedInstanceState: Bundle?
) {
context?.let { HomeChildItemAdapter.updatePosterSize(it) }
reloadRepos()
binding.apply {
val adapter =
Expand Down Expand Up @@ -469,9 +473,12 @@ class SearchFragment : BaseFragment<FragmentSearchBinding>(
it.value.let { data ->
val list = data.list
if (list.isNotEmpty()) {
(binding.searchAutofitResults.adapter as? SearchAdapter)?.submitList(
list
)
val isHorizontal = list.any { it.isHorizontalCard() }
binding.searchAutofitResults.spanCount = view?.context?.getSpanCount(isHorizontal) ?: currentSpan
(binding.searchAutofitResults.adapter as? SearchAdapter)?.apply {
this.isHorizontal = isHorizontal
submitList(list)
}
}
}
searchExitIcon?.alpha = 1f
Expand Down Expand Up @@ -512,7 +519,8 @@ class SearchFragment : BaseFragment<FragmentSearchBinding>(

val homePageList = HomePageList(
providerName,
dataListFiltered
dataListFiltered,
isHorizontalImages = false
)

HomeViewModel.ExpandableHomepageList(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.lagradost.cloudstream3.LiveSearchResponse
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.SearchQuality
import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.isHorizontalCard
import com.lagradost.cloudstream3.isMovieType
import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.ui.settings.Globals.TV
Expand Down Expand Up @@ -50,6 +51,7 @@ object SearchResultBuilder {
itemView: View,
nextFocusUp: Int? = null,
nextFocusDown: Int? = null,
isHorizontal: Boolean = false,
colorCallback: ((Palette) -> Unit)? = null
) {
val cardView: ImageView = itemView.findViewById(R.id.imageView)
Expand Down Expand Up @@ -132,8 +134,9 @@ object SearchResultBuilder {
cardText?.text = card.name
cardText?.isVisible = showTitle
cardView.isVisible = true
if (!card.posterUrl.isNullOrEmpty()) {
cardView.loadImage(card.posterUrl, card.posterHeaders) {
val poster = if (card.isHorizontalCard(isHorizontal)) card.backgroundPosterUrl ?: card.posterUrl else card.posterUrl
if (!poster.isNullOrEmpty()) {
cardView.loadImage(poster, card.posterHeaders) {
error { getImageFromDrawable(itemView.context, R.drawable.default_cover) }
}
} else cardView.loadImage(R.drawable.default_cover)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ class SyncSearchViewModel {
override var quality: SearchQuality? = null,
override var posterHeaders: Map<String, String>? = null,
override var score: Score? = null,
override var backgroundPosterUrl: String? = null,
) : SearchResponse
}
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ object DataStoreHelper {
@Transient override var score: Score? = null,
@Transient open val tags: List<String>? = null,
) : SearchResponse {
@Transient override var backgroundPosterUrl: String? = null
@JsonProperty("rating", access = JsonProperty.Access.WRITE_ONLY)
@SerialName("rating")
@Deprecated(
Expand Down Expand Up @@ -506,6 +507,7 @@ object DataStoreHelper {
@JsonProperty("quality") @SerialName("quality") override var quality: SearchQuality? = null,
@JsonProperty("posterHeaders") @SerialName("posterHeaders") override var posterHeaders: Map<String, String>? = null,
@JsonProperty("score") @SerialName("score") override var score: Score? = null,
@JsonProperty("backgroundPosterUrl") @SerialName("backgroundPosterUrl") override var backgroundPosterUrl: String? = null,
) : SearchResponse

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ object UIHelper {

fun Context.getSpanCount(isHorizontal:Boolean=false): Int {
// val compactView = false
val spanCountLandscape = if (isHorizontal) 3 else 6
val spanCountLandscape = if (isHorizontal) 5 else 6
val spanCountPortrait = if (isHorizontal) 2 else 3
val orientation = resources.configuration.orientation

Expand Down
Loading