Fix searching race condition with loading plugins

This commit is contained in:
Blatzar 2022-08-18 00:26:50 +02:00
parent 4832421bd2
commit e9e4298a7a
2 changed files with 91 additions and 60 deletions

View file

@ -22,11 +22,11 @@ import com.google.android.material.button.MaterialButton
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
import com.lagradost.cloudstream3.APIHolder.filterSearchResultByFilmQuality
import com.lagradost.cloudstream3.APIHolder.getApiFromName
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
import com.lagradost.cloudstream3.APIHolder.getApiSettings
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.observe
@ -36,6 +36,7 @@ import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.currentSpan
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.loadHomepageList
import com.lagradost.cloudstream3.ui.home.ParentItemAdapter
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.DataStore.getKey
import com.lagradost.cloudstream3.utils.DataStore.setKey
import com.lagradost.cloudstream3.utils.SubtitleHelper
@ -97,6 +98,16 @@ class SearchFragment : Fragment() {
super.onDestroyView()
}
override fun onResume() {
super.onResume()
afterPluginsLoadedEvent += ::reloadRepos
}
override fun onStop() {
super.onStop()
afterPluginsLoadedEvent -= ::reloadRepos
}
var selectedSearchTypes = mutableListOf<TvType>()
var selectedApis = mutableSetOf<String>()
@ -116,11 +127,73 @@ class SearchFragment : Fragment() {
}
}
// Null if defined as a variable
// This needs to be run after view created
private fun getPairList(): List<Pair<MaterialButton?, List<TvType>>> {
return HomeFragment.getPairList(
search_select_anime,
search_select_cartoons,
search_select_tv_series,
search_select_documentaries,
search_select_movies,
search_select_asian,
search_select_livestreams,
search_select_nsfw,
search_select_others
)
}
private fun reloadRepos(success: Boolean = false) = main {
val pairList = getPairList()
searchViewModel.reloadRepos()
context?.filterProviderByPreferredMedia()?.let { validAPIs ->
for ((button, validTypes) in pairList) {
val isValid =
validAPIs.any { api -> validTypes.any { api.supportedTypes.contains(it) } }
button?.isVisible = isValid
if (isValid) {
fun buttonContains(): Boolean {
return selectedSearchTypes.any { validTypes.contains(it) }
}
button?.isSelected = buttonContains()
button?.setOnClickListener {
val last = selectedSearchTypes.toSet()
selectedSearchTypes.clear()
selectedSearchTypes.addAll(validTypes)
for ((otherButton, _) in pairList) {
otherButton?.isSelected = false
}
it?.context?.setKey(SEARCH_PREF_TAGS, selectedSearchTypes)
it?.isSelected = true
if (last != selectedSearchTypes.toSet()) // if you click the same button again the it does nothing
search(main_search?.query?.toString())
}
button?.setOnLongClickListener {
if (!buttonContains()) {
it?.isSelected = true
selectedSearchTypes.addAll(validTypes)
} else {
it?.isSelected = false
selectedSearchTypes.removeAll(validTypes)
}
it?.context?.setKey(SEARCH_PREF_TAGS, selectedSearchTypes)
search(main_search?.query?.toString())
return@setOnLongClickListener true
}
}
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
context?.fixPaddingStatusbar(searchRoot)
fixGrid()
reloadRepos()
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? = activity?.let {
SearchAdapter(
@ -155,6 +228,7 @@ class SearchFragment : Fragment() {
var currentValidApis = listOf<MainAPI>()
val currentSelectedApis = if (selectedApis.isEmpty()) validAPIs.map { it.name }
.toMutableSet() else selectedApis
val builder =
BottomSheetDialog(ctx)
@ -169,7 +243,8 @@ class SearchFragment : Fragment() {
val docs = dialog.findViewById<MaterialButton>(R.id.home_select_documentaries)
val movies = dialog.findViewById<MaterialButton>(R.id.home_select_movies)
val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian)
val livestream = dialog.findViewById<MaterialButton>(R.id.home_select_livestreams)
val livestream =
dialog.findViewById<MaterialButton>(R.id.home_select_livestreams)
val nsfw = dialog.findViewById<MaterialButton>(R.id.home_select_nsfw)
val other = dialog.findViewById<MaterialButton>(R.id.home_select_others)
val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
@ -221,7 +296,7 @@ class SearchFragment : Fragment() {
listView?.choiceMode = AbsListView.CHOICE_MODE_MULTIPLE
listView?.setOnItemClickListener { _, _, i, _ ->
if (!currentValidApis.isNullOrEmpty()) {
if (currentValidApis.isNotEmpty()) {
val api = currentValidApis[i].name
if (currentSelectedApis.contains(api)) {
listView.setItemChecked(i, false)
@ -295,18 +370,6 @@ class SearchFragment : Fragment() {
}
}
val pairList = HomeFragment.getPairList(
search_select_anime,
search_select_cartoons,
search_select_tv_series,
search_select_documentaries,
search_select_movies,
search_select_asian,
search_select_livestreams,
search_select_nsfw,
search_select_others
)
val settingsManager = context?.let { PreferenceManager.getDefaultSharedPreferences(it) }
val isAdvancedSearch = settingsManager?.getBoolean("advanced_search", true) ?: true
@ -315,6 +378,7 @@ class SearchFragment : Fragment() {
?.toMutableList()
?: mutableListOf(TvType.Movie, TvType.TvSeries)
val pairList = getPairList()
fun updateSelectedList(list: MutableList<TvType>) {
selectedSearchTypes = list
for ((button, validTypes) in pairList) {
@ -322,46 +386,6 @@ class SearchFragment : Fragment() {
}
}
context?.filterProviderByPreferredMedia()?.let { validAPIs ->
for ((button, validTypes) in pairList) {
val isValid =
validAPIs.any { api -> validTypes.any { api.supportedTypes.contains(it) } }
button?.isVisible = isValid
if (isValid) {
fun buttonContains(): Boolean {
return selectedSearchTypes.any { validTypes.contains(it) }
}
button?.isSelected = buttonContains()
button?.setOnClickListener {
val last = selectedSearchTypes.toSet()
selectedSearchTypes.clear()
selectedSearchTypes.addAll(validTypes)
for ((otherButton, _) in pairList) {
otherButton?.isSelected = false
}
it?.context?.setKey(SEARCH_PREF_TAGS, selectedSearchTypes)
it?.isSelected = true
if (last != selectedSearchTypes.toSet()) // if you click the same button again the it does nothing
search(main_search?.query?.toString())
}
button?.setOnLongClickListener {
if (!buttonContains()) {
it?.isSelected = true
selectedSearchTypes.addAll(validTypes)
} else {
it?.isSelected = false
selectedSearchTypes.removeAll(validTypes)
}
it?.context?.setKey(SEARCH_PREF_TAGS, selectedSearchTypes)
search(main_search?.query?.toString())
return@setOnLongClickListener true
}
}
}
}
if (context?.isTrueTvSettings() == true) {
search_filter.isFocusable = true
search_filter.isFocusableInTouchMode = true
@ -431,8 +455,10 @@ class SearchFragment : Fragment() {
listLock.lock()
(search_master_recycler?.adapter as ParentItemAdapter?)?.apply {
val newItems = list.map { ongoing ->
val dataList = if (ongoing.data is Resource.Success) ongoing.data.value else ArrayList()
val dataListFiltered = context?.filterSearchResultByFilmQuality(dataList) ?: dataList
val dataList =
if (ongoing.data is Resource.Success) ongoing.data.value else ArrayList()
val dataListFiltered =
context?.filterSearchResultByFilmQuality(dataList) ?: dataList
val ongoingList = HomePageList(
ongoing.apiName,
dataListFiltered

View file

@ -36,7 +36,7 @@ class SearchViewModel : ViewModel() {
private val _currentHistory: MutableLiveData<List<SearchHistoryItem>> = MutableLiveData()
val currentHistory: LiveData<List<SearchHistoryItem>> get() = _currentHistory
private val repos = apis.map { APIRepository(it) }
private var repos = apis.map { APIRepository(it) }
fun clearSearch() {
_searchResponse.postValue(Resource.Success(ArrayList()))
@ -45,6 +45,11 @@ class SearchViewModel : ViewModel() {
private var currentSearchIndex = 0
private var onGoingSearch: Job? = null
fun reloadRepos() {
repos = apis.map { APIRepository(it) }
}
fun searchAndCancel(
query: String,
providersActive: Set<String> = setOf(),
@ -104,12 +109,12 @@ class SearchViewModel : ViewModel() {
(ignoreSettings || (providersActive.isEmpty() || providersActive.contains(a.name))) && (!isQuickSearch || a.hasQuickSearch)
}.apmap { a -> // Parallel
val search = if (isQuickSearch) a.quickSearch(query) else a.search(query)
if(currentSearchIndex != currentIndex) return@apmap
if (currentSearchIndex != currentIndex) return@apmap
currentList.add(OnGoingSearch(a.name, search))
_currentSearch.postValue(currentList)
}
if(currentSearchIndex != currentIndex) return@withContext // this should prevent rewrite of existing data bug
if (currentSearchIndex != currentIndex) return@withContext // this should prevent rewrite of existing data bug
_currentSearch.postValue(currentList)
val list = ArrayList<SearchResponse>()