mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	Fix searching race condition with loading plugins
This commit is contained in:
		
							parent
							
								
									4832421bd2
								
							
						
					
					
						commit
						e9e4298a7a
					
				
					 2 changed files with 91 additions and 60 deletions
				
			
		|  | @ -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 | ||||
|  |  | |||
|  | @ -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>() | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue