mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	new quicksearch
This commit is contained in:
		
							parent
							
								
									3b4915444a
								
							
						
					
					
						commit
						30fddb0360
					
				
					 6 changed files with 147 additions and 61 deletions
				
			
		| 
						 | 
				
			
			@ -103,11 +103,13 @@ open class WcoStream : ExtractorApi() {
 | 
			
		|||
                        ).apmap { serverurl ->
 | 
			
		||||
                            val testurl = app.get(serverurl, headers = mapOf("Referer" to url)).text
 | 
			
		||||
                            if (testurl.contains("EXTM3")) {
 | 
			
		||||
                                val quality = if (serverurl.contains("H4")) "1080p"
 | 
			
		||||
                                else if (serverurl.contains("H3")) "720p"
 | 
			
		||||
                                else if (serverurl.contains("H2")) "480p"
 | 
			
		||||
                                else if (serverurl.contains("H1")) "360p"
 | 
			
		||||
                                else "Auto"
 | 
			
		||||
                                val quality = when {
 | 
			
		||||
                                    serverurl.contains("H4") -> "1080p"
 | 
			
		||||
                                    serverurl.contains("H3") -> "720p"
 | 
			
		||||
                                    serverurl.contains("H2") -> "480p"
 | 
			
		||||
                                    serverurl.contains("H1") -> "360p"
 | 
			
		||||
                                    else -> "Auto"
 | 
			
		||||
                                }
 | 
			
		||||
                                sources.add(
 | 
			
		||||
                                    ExtractorLink(
 | 
			
		||||
                                        "VidStream",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -474,7 +474,7 @@ class HomeFragment : Fragment() {
 | 
			
		|||
 | 
			
		||||
        home_search?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
 | 
			
		||||
            override fun onQueryTextSubmit(query: String): Boolean {
 | 
			
		||||
                QuickSearchFragment.pushSearch(activity, query)
 | 
			
		||||
                QuickSearchFragment.pushSearch(activity, query, currentApiName?.let { arrayOf(it) })
 | 
			
		||||
 | 
			
		||||
                return true
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,8 @@
 | 
			
		|||
package com.lagradost.cloudstream3.ui.quicksearch
 | 
			
		||||
 | 
			
		||||
import android.app.Activity
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.res.Configuration
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
| 
						 | 
				
			
			@ -8,16 +10,19 @@ import android.view.ViewGroup
 | 
			
		|||
import android.view.WindowManager
 | 
			
		||||
import android.widget.ImageView
 | 
			
		||||
import androidx.appcompat.widget.SearchView
 | 
			
		||||
import androidx.core.view.isGone
 | 
			
		||||
import androidx.core.view.isVisible
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.fragment.app.activityViewModels
 | 
			
		||||
import androidx.lifecycle.ViewModelProvider
 | 
			
		||||
import androidx.recyclerview.widget.GridLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
 | 
			
		||||
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
 | 
			
		||||
import com.lagradost.cloudstream3.HomePageList
 | 
			
		||||
import com.lagradost.cloudstream3.R
 | 
			
		||||
import com.lagradost.cloudstream3.mvvm.Resource
 | 
			
		||||
import com.lagradost.cloudstream3.mvvm.logError
 | 
			
		||||
import com.lagradost.cloudstream3.mvvm.observe
 | 
			
		||||
import com.lagradost.cloudstream3.ui.home.HomeFragment
 | 
			
		||||
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.loadHomepageList
 | 
			
		||||
import com.lagradost.cloudstream3.ui.home.ParentItemAdapter
 | 
			
		||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
 | 
			
		||||
| 
						 | 
				
			
			@ -27,19 +32,29 @@ import com.lagradost.cloudstream3.ui.search.SearchHelper
 | 
			
		|||
import com.lagradost.cloudstream3.ui.search.SearchViewModel
 | 
			
		||||
import com.lagradost.cloudstream3.utils.UIHelper
 | 
			
		||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
 | 
			
		||||
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
 | 
			
		||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
 | 
			
		||||
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
 | 
			
		||||
import kotlinx.android.synthetic.main.fragment_search.*
 | 
			
		||||
import kotlinx.android.synthetic.main.quick_search.*
 | 
			
		||||
import java.util.concurrent.locks.ReentrantLock
 | 
			
		||||
 | 
			
		||||
class QuickSearchFragment : Fragment() {
 | 
			
		||||
    companion object {
 | 
			
		||||
        fun pushSearch(activity: Activity?, autoSearch: String? = null) {
 | 
			
		||||
        const val AUTOSEARCH_KEY = "autosearch"
 | 
			
		||||
        const val PROVIDER_KEY = "providers"
 | 
			
		||||
 | 
			
		||||
        fun pushSearch(
 | 
			
		||||
            activity: Activity?,
 | 
			
		||||
            autoSearch: String? = null,
 | 
			
		||||
            providers: Array<String>? = null
 | 
			
		||||
        ) {
 | 
			
		||||
            activity.navigate(R.id.global_to_navigation_quick_search, Bundle().apply {
 | 
			
		||||
                providers?.let {
 | 
			
		||||
                    putStringArray(PROVIDER_KEY, it)
 | 
			
		||||
                }
 | 
			
		||||
                autoSearch?.let {
 | 
			
		||||
                    putString(
 | 
			
		||||
                        "autosearch",
 | 
			
		||||
                        AUTOSEARCH_KEY,
 | 
			
		||||
                        it.trim()
 | 
			
		||||
                            .removeSuffix("(DUB)")
 | 
			
		||||
                            .removeSuffix("(SUB)")
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +68,8 @@ class QuickSearchFragment : Fragment() {
 | 
			
		|||
        var clickCallback: ((SearchClickCallback) -> Unit)? = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val searchViewModel: SearchViewModel by activityViewModels()
 | 
			
		||||
    private var providers: Set<String>? = null
 | 
			
		||||
    private lateinit var searchViewModel: SearchViewModel
 | 
			
		||||
 | 
			
		||||
    override fun onCreateView(
 | 
			
		||||
        inflater: LayoutInflater,
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +79,7 @@ class QuickSearchFragment : Fragment() {
 | 
			
		|||
        activity?.window?.setSoftInputMode(
 | 
			
		||||
            WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE
 | 
			
		||||
        )
 | 
			
		||||
        searchViewModel = ViewModelProvider(this)[SearchViewModel::class.java]
 | 
			
		||||
 | 
			
		||||
        return inflater.inflate(R.layout.quick_search, container, false)
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -72,9 +89,75 @@ class QuickSearchFragment : Fragment() {
 | 
			
		|||
        clickCallback = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun search(context: Context?, query: String, isQuickSearch: Boolean): Boolean {
 | 
			
		||||
        (providers ?: context?.filterProviderByPreferredMedia(hasHomePageIsRequired = false)
 | 
			
		||||
            ?.map { it.name }?.toSet())?.let { active ->
 | 
			
		||||
            searchViewModel.searchAndCancel(
 | 
			
		||||
                query = query,
 | 
			
		||||
                ignoreSettings = false,
 | 
			
		||||
                providersActive = active,
 | 
			
		||||
                isQuickSearch = isQuickSearch
 | 
			
		||||
            )
 | 
			
		||||
            return true
 | 
			
		||||
        }
 | 
			
		||||
        return false
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun fixGrid() {
 | 
			
		||||
        activity?.getSpanCount()?.let {
 | 
			
		||||
            HomeFragment.currentSpan = it
 | 
			
		||||
        }
 | 
			
		||||
        quick_search_autofit_results.spanCount = HomeFragment.currentSpan
 | 
			
		||||
        HomeFragment.currentSpan = HomeFragment.currentSpan
 | 
			
		||||
        HomeFragment.configEvent.invoke(HomeFragment.currentSpan)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onConfigurationChanged(newConfig: Configuration) {
 | 
			
		||||
        super.onConfigurationChanged(newConfig)
 | 
			
		||||
        fixGrid()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onViewCreated(view, savedInstanceState)
 | 
			
		||||
        context?.fixPaddingStatusbar(quick_search_root)
 | 
			
		||||
        fixGrid()
 | 
			
		||||
 | 
			
		||||
        arguments?.getStringArray(PROVIDER_KEY)?.let {
 | 
			
		||||
            providers = it.toSet()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val isSingleProvider = providers?.size == 1
 | 
			
		||||
        val isSingleProviderQuickSearch = if (isSingleProvider) {
 | 
			
		||||
            getApiFromNameNull(providers?.first())?.hasQuickSearch ?: false
 | 
			
		||||
        } else false
 | 
			
		||||
 | 
			
		||||
        if (isSingleProvider) {
 | 
			
		||||
            quick_search_autofit_results.adapter = activity?.let {
 | 
			
		||||
                SearchAdapter(
 | 
			
		||||
                    ArrayList(),
 | 
			
		||||
                    quick_search_autofit_results,
 | 
			
		||||
                ) { callback ->
 | 
			
		||||
                    SearchHelper.handleSearchClickCallback(activity, callback)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            quick_search_master_recycler?.adapter =
 | 
			
		||||
                ParentItemAdapter(mutableListOf(), { callback ->
 | 
			
		||||
                    SearchHelper.handleSearchClickCallback(activity, callback)
 | 
			
		||||
                    //when (callback.action) {
 | 
			
		||||
                    //SEARCH_ACTION_LOAD -> {
 | 
			
		||||
                    //    clickCallback?.invoke(callback)
 | 
			
		||||
                    //}
 | 
			
		||||
                    //    else -> SearchHelper.handleSearchClickCallback(activity, callback)
 | 
			
		||||
                    //}
 | 
			
		||||
                }, { item ->
 | 
			
		||||
                    activity?.loadHomepageList(item)
 | 
			
		||||
                })
 | 
			
		||||
            quick_search_master_recycler?.layoutManager = GridLayoutManager(context, 1)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        quick_search_autofit_results?.isVisible = isSingleProvider
 | 
			
		||||
        quick_search_master_recycler?.isGone = isSingleProvider
 | 
			
		||||
 | 
			
		||||
        val listLock = ReentrantLock()
 | 
			
		||||
        observe(searchViewModel.currentSearch) { list ->
 | 
			
		||||
| 
						 | 
				
			
			@ -97,19 +180,6 @@ class QuickSearchFragment : Fragment() {
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val masterAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
 | 
			
		||||
            ParentItemAdapter(mutableListOf(), { callback ->
 | 
			
		||||
                SearchHelper.handleSearchClickCallback(activity, callback)
 | 
			
		||||
                //when (callback.action) {
 | 
			
		||||
                    //SEARCH_ACTION_LOAD -> {
 | 
			
		||||
                    //    clickCallback?.invoke(callback)
 | 
			
		||||
                    //}
 | 
			
		||||
                //    else -> SearchHelper.handleSearchClickCallback(activity, callback)
 | 
			
		||||
                //}
 | 
			
		||||
            }, { item ->
 | 
			
		||||
                activity?.loadHomepageList(item)
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
        val searchExitIcon =
 | 
			
		||||
            quick_search?.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -119,25 +189,17 @@ class QuickSearchFragment : Fragment() {
 | 
			
		|||
        //searchMagIcon?.scaleX = 0.65f
 | 
			
		||||
        //searchMagIcon?.scaleY = 0.65f
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        quick_search?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
 | 
			
		||||
            override fun onQueryTextSubmit(query: String): Boolean {
 | 
			
		||||
                context?.filterProviderByPreferredMedia(hasHomePageIsRequired = false)
 | 
			
		||||
                    ?.map { it.name }?.toSet()?.let { active ->
 | 
			
		||||
                    searchViewModel.searchAndCancel(
 | 
			
		||||
                        query = query,
 | 
			
		||||
                        ignoreSettings = false,
 | 
			
		||||
                        providersActive = active
 | 
			
		||||
                    )
 | 
			
		||||
                    quick_search?.let {
 | 
			
		||||
                        UIHelper.hideKeyboard(it)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (search(context, query, false))
 | 
			
		||||
                    UIHelper.hideKeyboard(quick_search)
 | 
			
		||||
                return true
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            override fun onQueryTextChange(newText: String): Boolean {
 | 
			
		||||
                //searchViewModel.quickSearch(newText)
 | 
			
		||||
                if (isSingleProviderQuickSearch)
 | 
			
		||||
                    search(context, newText, true)
 | 
			
		||||
                return true
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
| 
						 | 
				
			
			@ -147,9 +209,10 @@ class QuickSearchFragment : Fragment() {
 | 
			
		|||
            when (it) {
 | 
			
		||||
                is Resource.Success -> {
 | 
			
		||||
                    it.value.let { data ->
 | 
			
		||||
                        if (data.isNotEmpty()) {
 | 
			
		||||
                            (search_autofit_results?.adapter as? SearchAdapter?)?.updateList(data)
 | 
			
		||||
                        }
 | 
			
		||||
                        println("DATA: $data")
 | 
			
		||||
                        (quick_search_autofit_results?.adapter as? SearchAdapter?)?.updateList(
 | 
			
		||||
                            data
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                    searchExitIcon?.alpha = 1f
 | 
			
		||||
                    quick_search_loading_bar?.alpha = 0f
 | 
			
		||||
| 
						 | 
				
			
			@ -166,8 +229,6 @@ class QuickSearchFragment : Fragment() {
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        quick_search_master_recycler?.adapter = masterAdapter
 | 
			
		||||
        quick_search_master_recycler?.layoutManager = GridLayoutManager(context, 1)
 | 
			
		||||
 | 
			
		||||
        //quick_search.setOnQueryTextFocusChangeListener { _, b ->
 | 
			
		||||
        //    if (b) {
 | 
			
		||||
| 
						 | 
				
			
			@ -180,9 +241,9 @@ class QuickSearchFragment : Fragment() {
 | 
			
		|||
            activity?.popCurrentPage()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        arguments?.getString("autosearch")?.let {
 | 
			
		||||
        arguments?.getString(AUTOSEARCH_KEY)?.let {
 | 
			
		||||
            quick_search?.setQuery(it, true)
 | 
			
		||||
            arguments?.remove("autosearch")
 | 
			
		||||
            arguments?.remove(AUTOSEARCH_KEY)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -47,10 +47,11 @@ class SearchViewModel : ViewModel() {
 | 
			
		|||
    fun searchAndCancel(
 | 
			
		||||
        query: String,
 | 
			
		||||
        providersActive: Set<String> = setOf(),
 | 
			
		||||
        ignoreSettings: Boolean = false
 | 
			
		||||
        ignoreSettings: Boolean = false,
 | 
			
		||||
        isQuickSearch: Boolean = false,
 | 
			
		||||
    ) {
 | 
			
		||||
        onGoingSearch?.cancel()
 | 
			
		||||
        onGoingSearch = search(query, providersActive, ignoreSettings)
 | 
			
		||||
        onGoingSearch = search(query, providersActive, ignoreSettings, isQuickSearch)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun updateHistory() = viewModelScope.launch {
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +66,8 @@ class SearchViewModel : ViewModel() {
 | 
			
		|||
    private fun search(
 | 
			
		||||
        query: String,
 | 
			
		||||
        providersActive: Set<String>,
 | 
			
		||||
        ignoreSettings: Boolean = false
 | 
			
		||||
        ignoreSettings: Boolean = false,
 | 
			
		||||
        isQuickSearch: Boolean = false,
 | 
			
		||||
    ) =
 | 
			
		||||
        viewModelScope.launch {
 | 
			
		||||
            if (query.length <= 1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -73,17 +75,19 @@ class SearchViewModel : ViewModel() {
 | 
			
		|||
                return@launch
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            val key = query.hashCode().toString()
 | 
			
		||||
            setKey(
 | 
			
		||||
                SEARCH_HISTORY_KEY,
 | 
			
		||||
                key,
 | 
			
		||||
                SearchHistoryItem(
 | 
			
		||||
                    searchedAt = System.currentTimeMillis(),
 | 
			
		||||
                    searchText = query,
 | 
			
		||||
                    type = emptyList(), // TODO implement tv type
 | 
			
		||||
                    key = key,
 | 
			
		||||
            if (!isQuickSearch) {
 | 
			
		||||
                val key = query.hashCode().toString()
 | 
			
		||||
                setKey(
 | 
			
		||||
                    SEARCH_HISTORY_KEY,
 | 
			
		||||
                    key,
 | 
			
		||||
                    SearchHistoryItem(
 | 
			
		||||
                        searchedAt = System.currentTimeMillis(),
 | 
			
		||||
                        searchText = query,
 | 
			
		||||
                        type = emptyList(), // TODO implement tv type
 | 
			
		||||
                        key = key,
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _searchResponse.postValue(Resource.Loading())
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -93,9 +97,9 @@ class SearchViewModel : ViewModel() {
 | 
			
		|||
 | 
			
		||||
            withContext(Dispatchers.IO) { // This interrupts UI otherwise
 | 
			
		||||
                repos.filter { a ->
 | 
			
		||||
                    ignoreSettings || (providersActive.isEmpty() || providersActive.contains(a.name))
 | 
			
		||||
                    (ignoreSettings || (providersActive.isEmpty() || providersActive.contains(a.name))) && (!isQuickSearch || a.hasQuickSearch)
 | 
			
		||||
                }.apmap { a -> // Parallel
 | 
			
		||||
                    val search = a.search(query)
 | 
			
		||||
                    val search = if (isQuickSearch) a.quickSearch(query) else a.search(query)
 | 
			
		||||
                    currentList.add(OnGoingSearch(a.name, search))
 | 
			
		||||
                    _currentSearch.postValue(currentList)
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -384,7 +384,9 @@ object UIHelper {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun hideKeyboard(view: View) {
 | 
			
		||||
    fun hideKeyboard(view: View?) {
 | 
			
		||||
        if(view == null) return
 | 
			
		||||
 | 
			
		||||
        val inputMethodManager =
 | 
			
		||||
            view.context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager?
 | 
			
		||||
        inputMethodManager?.hideSoftInputFromWindow(view.windowToken, 0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,4 +83,21 @@
 | 
			
		|||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            tools:listitem="@layout/homepage_parent" />
 | 
			
		||||
 | 
			
		||||
    <com.lagradost.cloudstream3.ui.AutofitRecyclerView
 | 
			
		||||
            android:visibility="gone"
 | 
			
		||||
            android:nextFocusLeft="@id/nav_rail_view"
 | 
			
		||||
            android:descendantFocusability="afterDescendants"
 | 
			
		||||
 | 
			
		||||
            android:background="?attr/primaryBlackBackground"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            android:clipToPadding="false"
 | 
			
		||||
            android:paddingStart="8dp"
 | 
			
		||||
            android:paddingTop="5dp"
 | 
			
		||||
            app:spanCount="3"
 | 
			
		||||
            android:paddingEnd="8dp"
 | 
			
		||||
            android:id="@+id/quick_search_autofit_results"
 | 
			
		||||
            tools:listitem="@layout/search_result_grid"
 | 
			
		||||
            android:orientation="vertical" />
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue