forked from recloudstream/cloudstream
made inf scrolling better + fixed search bug
This commit is contained in:
parent
625ff8c910
commit
d3b3091fe0
10 changed files with 179 additions and 47 deletions
|
@ -3,7 +3,6 @@ package com.lagradost.cloudstream3.animeproviders
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
|
@ -75,7 +74,6 @@ class AniflixProvider : MainAPI() {
|
||||||
val token = getToken()
|
val token = getToken()
|
||||||
val url = "$mainUrl/_next/data/$token/search.json?keyword=$query"
|
val url = "$mainUrl/_next/data/$token/search.json?keyword=$query"
|
||||||
val response = app.get(url)
|
val response = app.get(url)
|
||||||
println("resp: $url ===> ${response.text}")
|
|
||||||
val searchResponse =
|
val searchResponse =
|
||||||
response.parsedSafe<Search>()
|
response.parsedSafe<Search>()
|
||||||
?: throw ErrorLoadingException("No Media")
|
?: throw ErrorLoadingException("No Media")
|
||||||
|
|
|
@ -24,6 +24,7 @@ class HomeChildItemAdapter(
|
||||||
) :
|
) :
|
||||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
var isHorizontal: Boolean = false
|
var isHorizontal: Boolean = false
|
||||||
|
var hasNext : Boolean = false
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val layout = overrideLayout
|
val layout = overrideLayout
|
||||||
|
|
|
@ -22,6 +22,7 @@ import androidx.fragment.app.activityViewModels
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearSnapHelper
|
import androidx.recyclerview.widget.LinearSnapHelper
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
|
@ -46,6 +47,8 @@ import com.lagradost.cloudstream3.ui.search.SearchHelper.handleSearchClickCallba
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
|
import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.setMaxViewPoolSize
|
||||||
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||||
|
@ -119,11 +122,27 @@ class HomeFragment : Fragment() {
|
||||||
|
|
||||||
val errorProfilePic = errorProfilePics.random()
|
val errorProfilePic = errorProfilePics.random()
|
||||||
|
|
||||||
fun Activity.loadHomepageList(item: HomePageList, deleteCallback: (() -> Unit)? = null) {
|
fun Activity.loadHomepageList(
|
||||||
|
item: HomePageList,
|
||||||
|
deleteCallback: (() -> Unit)? = null,
|
||||||
|
) {
|
||||||
|
loadHomepageList(
|
||||||
|
expand = HomeViewModel.ExpandableHomepageList(item, 1, false),
|
||||||
|
deleteCallback = deleteCallback,
|
||||||
|
expandCallback = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Activity.loadHomepageList(
|
||||||
|
expand: HomeViewModel.ExpandableHomepageList,
|
||||||
|
deleteCallback: (() -> Unit)? = null,
|
||||||
|
expandCallback: (suspend (String) -> HomeViewModel.ExpandableHomepageList?)? = null
|
||||||
|
) {
|
||||||
val context = this
|
val context = this
|
||||||
val bottomSheetDialogBuilder = BottomSheetDialog(context)
|
val bottomSheetDialogBuilder = BottomSheetDialog(context)
|
||||||
bottomSheetDialogBuilder.setContentView(R.layout.home_episodes_expanded)
|
bottomSheetDialogBuilder.setContentView(R.layout.home_episodes_expanded)
|
||||||
val title = bottomSheetDialogBuilder.findViewById<TextView>(R.id.home_expanded_text)!!
|
val title = bottomSheetDialogBuilder.findViewById<TextView>(R.id.home_expanded_text)!!
|
||||||
|
val item = expand.list
|
||||||
title.text = item.name
|
title.text = item.name
|
||||||
val recycle =
|
val recycle =
|
||||||
bottomSheetDialogBuilder.findViewById<AutofitRecyclerView>(R.id.home_expanded_recycler)!!
|
bottomSheetDialogBuilder.findViewById<AutofitRecyclerView>(R.id.home_expanded_recycler)!!
|
||||||
|
@ -176,8 +195,36 @@ class HomeFragment : Fragment() {
|
||||||
if (callback.action == SEARCH_ACTION_LOAD || callback.action == SEARCH_ACTION_PLAY_FILE) {
|
if (callback.action == SEARCH_ACTION_LOAD || callback.action == SEARCH_ACTION_PLAY_FILE) {
|
||||||
bottomSheetDialogBuilder.dismissSafe(this)
|
bottomSheetDialogBuilder.dismissSafe(this)
|
||||||
}
|
}
|
||||||
|
}.apply {
|
||||||
|
hasNext = expand.hasNext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recycle.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
|
var expandCount = 0
|
||||||
|
val name = expand.list.name
|
||||||
|
|
||||||
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
|
super.onScrollStateChanged(recyclerView, newState)
|
||||||
|
|
||||||
|
val adapter = recyclerView.adapter
|
||||||
|
if (adapter !is SearchAdapter) return
|
||||||
|
|
||||||
|
val count = adapter.itemCount
|
||||||
|
val currentHasNext = adapter.hasNext
|
||||||
|
if (!recyclerView.canScrollVertically(1) && currentHasNext && expandCount != count) {
|
||||||
|
expandCount = count
|
||||||
|
ioSafe {
|
||||||
|
expandCallback?.invoke(name)?.let { newExpand ->
|
||||||
|
(recyclerView.adapter as? SearchAdapter?)?.apply {
|
||||||
|
hasNext = newExpand.hasNext
|
||||||
|
updateList(newExpand.list.list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
val spanListener = { span: Int ->
|
val spanListener = { span: Int ->
|
||||||
recycle.spanCount = span
|
recycle.spanCount = span
|
||||||
//(recycle.adapter as SearchAdapter).notifyDataSetChanged()
|
//(recycle.adapter as SearchAdapter).notifyDataSetChanged()
|
||||||
|
@ -537,7 +584,10 @@ class HomeFragment : Fragment() {
|
||||||
listHomepageItems.clear()
|
listHomepageItems.clear()
|
||||||
|
|
||||||
// println("ITEMCOUNT: ${d.values.size} ${home_master_recycler?.adapter?.itemCount}")
|
// println("ITEMCOUNT: ${d.values.size} ${home_master_recycler?.adapter?.itemCount}")
|
||||||
(home_master_recycler?.adapter as? ParentItemAdapter?)?.updateList(d.values.toMutableList())
|
(home_master_recycler?.adapter as? ParentItemAdapter?)?.updateList(
|
||||||
|
d.values.toMutableList(),
|
||||||
|
home_master_recycler
|
||||||
|
)
|
||||||
|
|
||||||
home_loading?.isVisible = false
|
home_loading?.isVisible = false
|
||||||
home_loading_error?.isVisible = false
|
home_loading_error?.isVisible = false
|
||||||
|
@ -843,15 +893,18 @@ class HomeFragment : Fragment() {
|
||||||
ParentItemAdapter(mutableListOf(), { callback ->
|
ParentItemAdapter(mutableListOf(), { callback ->
|
||||||
homeHandleSearch(callback)
|
homeHandleSearch(callback)
|
||||||
}, { item ->
|
}, { item ->
|
||||||
activity?.loadHomepageList(item)
|
activity?.loadHomepageList(item, expandCallback = {
|
||||||
|
homeViewModel.expandAndReturn(it)
|
||||||
|
})
|
||||||
}, { name ->
|
}, { name ->
|
||||||
homeViewModel.expand(name)
|
homeViewModel.expand(name)
|
||||||
})
|
})
|
||||||
|
home_master_recycler?.setMaxViewPoolSize(0, Int.MAX_VALUE)
|
||||||
home_master_recycler.layoutManager = object : LinearLayoutManager(context) {
|
home_master_recycler.layoutManager = object : LinearLayoutManager(context) {
|
||||||
override fun supportsPredictiveItemAnimations(): Boolean {
|
override fun supportsPredictiveItemAnimations(): Boolean {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}; // GridLayoutManager(context, 1).also { it.supportsPredictiveItemAnimations() }
|
} // GridLayoutManager(context, 1).also { it.supportsPredictiveItemAnimations() }
|
||||||
|
|
||||||
if (context?.isTvSettings() == false) {
|
if (context?.isTvSettings() == false) {
|
||||||
LinearSnapHelper().attachToRecyclerView(home_main_poster_recyclerview) // snap
|
LinearSnapHelper().attachToRecyclerView(home_main_poster_recyclerview) // snap
|
||||||
|
|
|
@ -6,10 +6,12 @@ import android.view.ViewGroup
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.ListUpdateCallback
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.lagradost.cloudstream3.HomePageList
|
import com.lagradost.cloudstream3.HomePageList
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
||||||
|
import com.lagradost.cloudstream3.ui.search.SearchFragment.Companion.filterSearchResponse
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
import kotlinx.android.synthetic.main.homepage_parent.view.*
|
import kotlinx.android.synthetic.main.homepage_parent.view.*
|
||||||
|
|
||||||
|
@ -17,11 +19,12 @@ import kotlinx.android.synthetic.main.homepage_parent.view.*
|
||||||
class ParentItemAdapter(
|
class ParentItemAdapter(
|
||||||
private var items: MutableList<HomeViewModel.ExpandableHomepageList>,
|
private var items: MutableList<HomeViewModel.ExpandableHomepageList>,
|
||||||
private val clickCallback: (SearchClickCallback) -> Unit,
|
private val clickCallback: (SearchClickCallback) -> Unit,
|
||||||
private val moreInfoClickCallback: (HomePageList) -> Unit,
|
private val moreInfoClickCallback: (HomeViewModel.ExpandableHomepageList) -> Unit,
|
||||||
private val expandCallback: ((String) -> Unit)? = null,
|
private val expandCallback: ((String) -> Unit)? = null,
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, i: Int): ParentViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, i: Int): ParentViewHolder {
|
||||||
|
//println("onCreateViewHolder $i")
|
||||||
val layout =
|
val layout =
|
||||||
if (parent.context.isTvSettings()) R.layout.homepage_parent_tv else R.layout.homepage_parent
|
if (parent.context.isTvSettings()) R.layout.homepage_parent_tv else R.layout.homepage_parent
|
||||||
return ParentViewHolder(
|
return ParentViewHolder(
|
||||||
|
@ -33,6 +36,8 @@ class ParentItemAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
//println("onBindViewHolder $position")
|
||||||
|
|
||||||
when (holder) {
|
when (holder) {
|
||||||
is ParentViewHolder -> {
|
is ParentViewHolder -> {
|
||||||
holder.bind(items[position])
|
holder.bind(items[position])
|
||||||
|
@ -55,14 +60,25 @@ class ParentItemAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("updateListExpandableHomepageList")
|
@JvmName("updateListExpandableHomepageList")
|
||||||
fun updateList(newList: MutableList<HomeViewModel.ExpandableHomepageList>) {
|
fun updateList(
|
||||||
|
newList: MutableList<HomeViewModel.ExpandableHomepageList>,
|
||||||
|
recyclerView: RecyclerView? = null
|
||||||
|
) {
|
||||||
|
// this
|
||||||
|
// 1. prevents deep copy that makes this.items == newList
|
||||||
|
// 2. filters out undesirable results
|
||||||
|
// 3. moves empty results to the bottom (sortedBy is a stable sort)
|
||||||
|
val new =
|
||||||
|
newList.map { it.copy(list = it.list.copy(list = it.list.list.filterSearchResponse())) }
|
||||||
|
.sortedBy { it.list.list.isEmpty() }
|
||||||
|
|
||||||
val diffResult = DiffUtil.calculateDiff(
|
val diffResult = DiffUtil.calculateDiff(
|
||||||
SearchDiffCallback(items, newList)
|
SearchDiffCallback(items, new)
|
||||||
)
|
)
|
||||||
items.clear()
|
items.clear()
|
||||||
items.addAll(newList.map { it.copy(list = it.list.copy()) }) // I have to do this otherwise it is a "copy" and dispatchUpdatesTo wont work
|
items.addAll(new)
|
||||||
|
|
||||||
/*val mAdapter = this
|
val mAdapter = this
|
||||||
diffResult.dispatchUpdatesTo(object : ListUpdateCallback {
|
diffResult.dispatchUpdatesTo(object : ListUpdateCallback {
|
||||||
override fun onInserted(position: Int, count: Int) {
|
override fun onInserted(position: Int, count: Int) {
|
||||||
mAdapter.notifyItemRangeInserted(position, count)
|
mAdapter.notifyItemRangeInserted(position, count)
|
||||||
|
@ -77,18 +93,44 @@ class ParentItemAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onChanged(position: Int, count: Int, payload: Any?) {
|
override fun onChanged(position: Int, count: Int, payload: Any?) {
|
||||||
mAdapter.notifyItemRangeChanged(position, count, payload)
|
// I know kinda messy, what this does is using the update or bind instead of onCreateViewHolder -> bind
|
||||||
}
|
recyclerView?.apply {
|
||||||
})*/
|
// this loops every viewHolder in the recycle view and checks the position to see if it is within the update range
|
||||||
|
val missingUpdates = (position until (position + count)).toMutableSet()
|
||||||
|
for (i in 0 until mAdapter.itemCount) {
|
||||||
|
val viewHolder = getChildViewHolder(getChildAt(i))
|
||||||
|
val absolutePosition = viewHolder.absoluteAdapterPosition
|
||||||
|
if (absolutePosition >= position && absolutePosition < position + count) {
|
||||||
|
val expand = items.getOrNull(absolutePosition) ?: continue
|
||||||
|
if (viewHolder is ParentViewHolder) {
|
||||||
|
missingUpdates -= absolutePosition
|
||||||
|
if (viewHolder.title.text == expand.list.name) {
|
||||||
|
viewHolder.update(expand)
|
||||||
|
} else {
|
||||||
|
viewHolder.bind(expand)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
diffResult.dispatchUpdatesTo(this)
|
// just in case some item did not get updated
|
||||||
|
for (i in missingUpdates) {
|
||||||
|
mAdapter.notifyItemChanged(i, payload)
|
||||||
|
}
|
||||||
|
} ?: run { // in case we don't have a nice
|
||||||
|
mAdapter.notifyItemRangeChanged(position, count, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//diffResult.dispatchUpdatesTo(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ParentViewHolder
|
class ParentViewHolder
|
||||||
constructor(
|
constructor(
|
||||||
itemView: View,
|
itemView: View,
|
||||||
private val clickCallback: (SearchClickCallback) -> Unit,
|
private val clickCallback: (SearchClickCallback) -> Unit,
|
||||||
private val moreInfoClickCallback: (HomePageList) -> Unit,
|
private val moreInfoClickCallback: (HomeViewModel.ExpandableHomepageList) -> Unit,
|
||||||
private val expandCallback: ((String) -> Unit)? = null,
|
private val expandCallback: ((String) -> Unit)? = null,
|
||||||
) :
|
) :
|
||||||
RecyclerView.ViewHolder(itemView) {
|
RecyclerView.ViewHolder(itemView) {
|
||||||
|
@ -96,6 +138,23 @@ class ParentItemAdapter(
|
||||||
val recyclerView: RecyclerView = itemView.home_child_recyclerview
|
val recyclerView: RecyclerView = itemView.home_child_recyclerview
|
||||||
private val moreInfo: FrameLayout? = itemView.home_child_more_info
|
private val moreInfo: FrameLayout? = itemView.home_child_more_info
|
||||||
|
|
||||||
|
fun update(expand: HomeViewModel.ExpandableHomepageList) {
|
||||||
|
val info = expand.list
|
||||||
|
(recyclerView.adapter as? HomeChildItemAdapter?)?.apply {
|
||||||
|
updateList(info.list.toMutableList())
|
||||||
|
hasNext = expand.hasNext
|
||||||
|
} ?: run {
|
||||||
|
recyclerView.adapter = HomeChildItemAdapter(
|
||||||
|
info.list.toMutableList(),
|
||||||
|
clickCallback = clickCallback,
|
||||||
|
nextFocusUp = recyclerView.nextFocusUpId,
|
||||||
|
nextFocusDown = recyclerView.nextFocusDownId,
|
||||||
|
).apply {
|
||||||
|
isHorizontal = info.isHorizontalImages
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun bind(expand: HomeViewModel.ExpandableHomepageList) {
|
fun bind(expand: HomeViewModel.ExpandableHomepageList) {
|
||||||
val info = expand.list
|
val info = expand.list
|
||||||
recyclerView.adapter = HomeChildItemAdapter(
|
recyclerView.adapter = HomeChildItemAdapter(
|
||||||
|
@ -105,6 +164,7 @@ class ParentItemAdapter(
|
||||||
nextFocusDown = recyclerView.nextFocusDownId,
|
nextFocusDown = recyclerView.nextFocusDownId,
|
||||||
).apply {
|
).apply {
|
||||||
isHorizontal = info.isHorizontalImages
|
isHorizontal = info.isHorizontalImages
|
||||||
|
hasNext = expand.hasNext
|
||||||
}
|
}
|
||||||
|
|
||||||
title.text = info.name
|
title.text = info.name
|
||||||
|
@ -116,8 +176,12 @@ class ParentItemAdapter(
|
||||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
super.onScrollStateChanged(recyclerView, newState)
|
super.onScrollStateChanged(recyclerView, newState)
|
||||||
|
|
||||||
val count = recyclerView.adapter?.itemCount ?: return
|
val adapter = recyclerView.adapter
|
||||||
if (!recyclerView.canScrollHorizontally(1) && expand.hasNext && expandCount != count) {
|
if (adapter !is HomeChildItemAdapter) return
|
||||||
|
|
||||||
|
val count = adapter.itemCount
|
||||||
|
val hasNext = adapter.hasNext
|
||||||
|
if (!recyclerView.canScrollHorizontally(1) && hasNext && expandCount != count) {
|
||||||
expandCount = count
|
expandCount = count
|
||||||
expandCallback?.invoke(name)
|
expandCallback?.invoke(name)
|
||||||
}
|
}
|
||||||
|
@ -127,7 +191,7 @@ class ParentItemAdapter(
|
||||||
//(recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged()
|
//(recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged()
|
||||||
|
|
||||||
moreInfo?.setOnClickListener {
|
moreInfo?.setOnClickListener {
|
||||||
moreInfoClickCallback.invoke(info)
|
moreInfoClickCallback.invoke(expand)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,9 +158,8 @@ class HomeViewModel : ViewModel() {
|
||||||
|
|
||||||
val lock: MutableSet<String> = mutableSetOf()
|
val lock: MutableSet<String> = mutableSetOf()
|
||||||
|
|
||||||
// this is soo over engineered, but idk how I can make it clean without making the main api harder to use :pensive:
|
suspend fun expandAndReturn(name: String) : ExpandableHomepageList? {
|
||||||
fun expand(name: String) = viewModelScope.launch {
|
if (lock.contains(name)) return null
|
||||||
if (lock.contains(name)) return@launch
|
|
||||||
lock += name
|
lock += name
|
||||||
|
|
||||||
repo?.apply {
|
repo?.apply {
|
||||||
|
@ -183,11 +182,8 @@ class HomeViewModel : ViewModel() {
|
||||||
"Expanded contained an item that was previously already in the list\n${list.name} = ${this.list.list}\n${newList.name} = ${newList.list}"
|
"Expanded contained an item that was previously already in the list\n${list.name} = ${this.list.list}\n${newList.name} = ${newList.list}"
|
||||||
}
|
}
|
||||||
|
|
||||||
val before = list.list.size
|
|
||||||
this.list.list += newList.list
|
this.list.list += newList.list
|
||||||
this.list.list.distinctBy { it.url } // just to be sure we are not adding the same shit for some reason
|
this.list.list.distinctBy { it.url } // just to be sure we are not adding the same shit for some reason
|
||||||
expandable[key] = this
|
|
||||||
val after = list.list.size
|
|
||||||
} ?: debugWarning {
|
} ?: debugWarning {
|
||||||
"Expanded an item not in main load named $key, current list is ${expandable.keys}"
|
"Expanded an item not in main load named $key, current list is ${expandable.keys}"
|
||||||
}
|
}
|
||||||
|
@ -201,6 +197,13 @@ class HomeViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
lock -= name
|
lock -= name
|
||||||
|
|
||||||
|
return expandable[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is soo over engineered, but idk how I can make it clean without making the main api harder to use :pensive:
|
||||||
|
fun expand(name: String) = viewModelScope.launch {
|
||||||
|
expandAndReturn(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun load(api: MainAPI?) = viewModelScope.launch {
|
private fun load(api: MainAPI?) = viewModelScope.launch {
|
||||||
|
|
|
@ -27,7 +27,6 @@ import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.loadHomepageLis
|
||||||
import com.lagradost.cloudstream3.ui.home.ParentItemAdapter
|
import com.lagradost.cloudstream3.ui.home.ParentItemAdapter
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchFragment.Companion.filterSearchResponse
|
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchViewModel
|
import com.lagradost.cloudstream3.ui.search.SearchViewModel
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper
|
import com.lagradost.cloudstream3.utils.UIHelper
|
||||||
|
@ -173,7 +172,7 @@ class QuickSearchFragment : Fragment() {
|
||||||
updateList(list.map { ongoing ->
|
updateList(list.map { ongoing ->
|
||||||
val ongoingList = HomePageList(
|
val ongoingList = HomePageList(
|
||||||
ongoing.apiName,
|
ongoing.apiName,
|
||||||
if (ongoing.data is Resource.Success) ongoing.data.value.filterSearchResponse() else ArrayList()
|
if (ongoing.data is Resource.Success) ongoing.data.value else ArrayList()
|
||||||
)
|
)
|
||||||
ongoingList
|
ongoingList
|
||||||
})
|
})
|
||||||
|
|
|
@ -27,6 +27,7 @@ class SearchAdapter(
|
||||||
private val resView: AutofitRecyclerView,
|
private val resView: AutofitRecyclerView,
|
||||||
private val clickCallback: (SearchClickCallback) -> Unit,
|
private val clickCallback: (SearchClickCallback) -> Unit,
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
var hasNext : Boolean = false
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val layout = if(parent.context.IsBottomLayout()) R.layout.search_result_grid_expanded else R.layout.search_result_grid
|
val layout = if(parent.context.IsBottomLayout()) R.layout.search_result_grid_expanded else R.layout.search_result_grid
|
||||||
|
|
|
@ -426,7 +426,7 @@ class SearchFragment : Fragment() {
|
||||||
val newItems = list.map { ongoing ->
|
val newItems = list.map { ongoing ->
|
||||||
val ongoingList = HomePageList(
|
val ongoingList = HomePageList(
|
||||||
ongoing.apiName,
|
ongoing.apiName,
|
||||||
if (ongoing.data is Resource.Success) ongoing.data.value.filterSearchResponse() else ArrayList()
|
if (ongoing.data is Resource.Success) ongoing.data.value else ArrayList()
|
||||||
)
|
)
|
||||||
ongoingList
|
ongoingList
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ class SearchViewModel : ViewModel() {
|
||||||
_currentSearch.postValue(emptyList())
|
_currentSearch.postValue(emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var currentSearchIndex = 0
|
||||||
private var onGoingSearch: Job? = null
|
private var onGoingSearch: Job? = null
|
||||||
fun searchAndCancel(
|
fun searchAndCancel(
|
||||||
query: String,
|
query: String,
|
||||||
|
@ -50,6 +51,7 @@ class SearchViewModel : ViewModel() {
|
||||||
ignoreSettings: Boolean = false,
|
ignoreSettings: Boolean = false,
|
||||||
isQuickSearch: Boolean = false,
|
isQuickSearch: Boolean = false,
|
||||||
) {
|
) {
|
||||||
|
currentSearchIndex++
|
||||||
onGoingSearch?.cancel()
|
onGoingSearch?.cancel()
|
||||||
onGoingSearch = search(query, providersActive, ignoreSettings, isQuickSearch)
|
onGoingSearch = search(query, providersActive, ignoreSettings, isQuickSearch)
|
||||||
}
|
}
|
||||||
|
@ -70,6 +72,7 @@ class SearchViewModel : ViewModel() {
|
||||||
isQuickSearch: Boolean = false,
|
isQuickSearch: Boolean = false,
|
||||||
) =
|
) =
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
val currentIndex = currentSearchIndex
|
||||||
if (query.length <= 1) {
|
if (query.length <= 1) {
|
||||||
clearSearch()
|
clearSearch()
|
||||||
return@launch
|
return@launch
|
||||||
|
@ -91,40 +94,44 @@ class SearchViewModel : ViewModel() {
|
||||||
|
|
||||||
_searchResponse.postValue(Resource.Loading())
|
_searchResponse.postValue(Resource.Loading())
|
||||||
|
|
||||||
val currentList = ArrayList<OnGoingSearch>()
|
|
||||||
|
|
||||||
_currentSearch.postValue(ArrayList())
|
_currentSearch.postValue(ArrayList())
|
||||||
|
|
||||||
withContext(Dispatchers.IO) { // This interrupts UI otherwise
|
withContext(Dispatchers.IO) { // This interrupts UI otherwise
|
||||||
|
val currentList = ArrayList<OnGoingSearch>()
|
||||||
|
|
||||||
repos.filter { a ->
|
repos.filter { a ->
|
||||||
(ignoreSettings || (providersActive.isEmpty() || providersActive.contains(a.name))) && (!isQuickSearch || a.hasQuickSearch)
|
(ignoreSettings || (providersActive.isEmpty() || providersActive.contains(a.name))) && (!isQuickSearch || a.hasQuickSearch)
|
||||||
}.apmap { a -> // Parallel
|
}.apmap { a -> // Parallel
|
||||||
val search = if (isQuickSearch) a.quickSearch(query) else a.search(query)
|
val search = if (isQuickSearch) a.quickSearch(query) else a.search(query)
|
||||||
|
if(currentSearchIndex != currentIndex) return@apmap
|
||||||
currentList.add(OnGoingSearch(a.name, search))
|
currentList.add(OnGoingSearch(a.name, search))
|
||||||
_currentSearch.postValue(currentList)
|
_currentSearch.postValue(currentList)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_currentSearch.postValue(currentList)
|
|
||||||
|
|
||||||
val list = ArrayList<SearchResponse>()
|
if(currentSearchIndex != currentIndex) return@withContext // this should prevent rewrite of existing data bug
|
||||||
val nestedList =
|
|
||||||
currentList.map { it.data }
|
|
||||||
.filterIsInstance<Resource.Success<List<SearchResponse>>>().map { it.value }
|
|
||||||
|
|
||||||
// I do it this way to move the relevant search results to the top
|
_currentSearch.postValue(currentList)
|
||||||
var index = 0
|
val list = ArrayList<SearchResponse>()
|
||||||
while (true) {
|
val nestedList =
|
||||||
var added = 0
|
currentList.map { it.data }
|
||||||
for (sublist in nestedList) {
|
.filterIsInstance<Resource.Success<List<SearchResponse>>>().map { it.value }
|
||||||
if (sublist.size > index) {
|
|
||||||
list.add(sublist[index])
|
// I do it this way to move the relevant search results to the top
|
||||||
added++
|
var index = 0
|
||||||
|
while (true) {
|
||||||
|
var added = 0
|
||||||
|
for (sublist in nestedList) {
|
||||||
|
if (sublist.size > index) {
|
||||||
|
list.add(sublist[index])
|
||||||
|
added++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (added == 0) break
|
||||||
|
index++
|
||||||
}
|
}
|
||||||
if (added == 0) break
|
|
||||||
index++
|
|
||||||
}
|
|
||||||
|
|
||||||
_searchResponse.postValue(Resource.Success(list))
|
_searchResponse.postValue(Resource.Success(list))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,6 +26,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.core.text.toSpanned
|
import androidx.core.text.toSpanned
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.tvprovider.media.tv.PreviewChannelHelper
|
import androidx.tvprovider.media.tv.PreviewChannelHelper
|
||||||
import androidx.tvprovider.media.tv.TvContractCompat
|
import androidx.tvprovider.media.tv.TvContractCompat
|
||||||
import androidx.tvprovider.media.tv.WatchNextProgram
|
import androidx.tvprovider.media.tv.WatchNextProgram
|
||||||
|
@ -52,6 +53,11 @@ import java.net.URL
|
||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
|
|
||||||
object AppUtils {
|
object AppUtils {
|
||||||
|
fun RecyclerView.setMaxViewPoolSize(maxViewTypeId: Int, maxPoolSize: Int) {
|
||||||
|
for (i in 0..maxViewTypeId)
|
||||||
|
recycledViewPool.setMaxRecycledViews(i, maxPoolSize)
|
||||||
|
}
|
||||||
|
|
||||||
//fun Context.deleteFavorite(data: SearchResponse) {
|
//fun Context.deleteFavorite(data: SearchResponse) {
|
||||||
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
||||||
// normalSafeApiCall {
|
// normalSafeApiCall {
|
||||||
|
|
Loading…
Reference in a new issue