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 ->
|
).apmap { serverurl ->
|
||||||
val testurl = app.get(serverurl, headers = mapOf("Referer" to url)).text
|
val testurl = app.get(serverurl, headers = mapOf("Referer" to url)).text
|
||||||
if (testurl.contains("EXTM3")) {
|
if (testurl.contains("EXTM3")) {
|
||||||
val quality = if (serverurl.contains("H4")) "1080p"
|
val quality = when {
|
||||||
else if (serverurl.contains("H3")) "720p"
|
serverurl.contains("H4") -> "1080p"
|
||||||
else if (serverurl.contains("H2")) "480p"
|
serverurl.contains("H3") -> "720p"
|
||||||
else if (serverurl.contains("H1")) "360p"
|
serverurl.contains("H2") -> "480p"
|
||||||
else "Auto"
|
serverurl.contains("H1") -> "360p"
|
||||||
|
else -> "Auto"
|
||||||
|
}
|
||||||
sources.add(
|
sources.add(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
"VidStream",
|
"VidStream",
|
||||||
|
|
|
@ -474,7 +474,7 @@ class HomeFragment : Fragment() {
|
||||||
|
|
||||||
home_search?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
home_search?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||||
override fun onQueryTextSubmit(query: String): Boolean {
|
override fun onQueryTextSubmit(query: String): Boolean {
|
||||||
QuickSearchFragment.pushSearch(activity, query)
|
QuickSearchFragment.pushSearch(activity, query, currentApiName?.let { arrayOf(it) })
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package com.lagradost.cloudstream3.ui.quicksearch
|
package com.lagradost.cloudstream3.ui.quicksearch
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.Configuration
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -8,16 +10,19 @@ import android.view.ViewGroup
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
|
import androidx.core.view.isGone
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
|
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
|
||||||
|
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
||||||
import com.lagradost.cloudstream3.HomePageList
|
import com.lagradost.cloudstream3.HomePageList
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.mvvm.observe
|
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.HomeFragment.Companion.loadHomepageList
|
||||||
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
|
||||||
|
@ -27,19 +32,29 @@ 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
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
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.navigate
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||||
import kotlinx.android.synthetic.main.fragment_search.*
|
|
||||||
import kotlinx.android.synthetic.main.quick_search.*
|
import kotlinx.android.synthetic.main.quick_search.*
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
|
|
||||||
class QuickSearchFragment : Fragment() {
|
class QuickSearchFragment : Fragment() {
|
||||||
companion object {
|
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 {
|
activity.navigate(R.id.global_to_navigation_quick_search, Bundle().apply {
|
||||||
|
providers?.let {
|
||||||
|
putStringArray(PROVIDER_KEY, it)
|
||||||
|
}
|
||||||
autoSearch?.let {
|
autoSearch?.let {
|
||||||
putString(
|
putString(
|
||||||
"autosearch",
|
AUTOSEARCH_KEY,
|
||||||
it.trim()
|
it.trim()
|
||||||
.removeSuffix("(DUB)")
|
.removeSuffix("(DUB)")
|
||||||
.removeSuffix("(SUB)")
|
.removeSuffix("(SUB)")
|
||||||
|
@ -53,7 +68,8 @@ class QuickSearchFragment : Fragment() {
|
||||||
var clickCallback: ((SearchClickCallback) -> Unit)? = null
|
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(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
@ -63,6 +79,7 @@ class QuickSearchFragment : Fragment() {
|
||||||
activity?.window?.setSoftInputMode(
|
activity?.window?.setSoftInputMode(
|
||||||
WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE
|
WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE
|
||||||
)
|
)
|
||||||
|
searchViewModel = ViewModelProvider(this)[SearchViewModel::class.java]
|
||||||
|
|
||||||
return inflater.inflate(R.layout.quick_search, container, false)
|
return inflater.inflate(R.layout.quick_search, container, false)
|
||||||
}
|
}
|
||||||
|
@ -72,9 +89,75 @@ class QuickSearchFragment : Fragment() {
|
||||||
clickCallback = null
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
context?.fixPaddingStatusbar(quick_search_root)
|
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()
|
val listLock = ReentrantLock()
|
||||||
observe(searchViewModel.currentSearch) { list ->
|
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 =
|
val searchExitIcon =
|
||||||
quick_search?.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)
|
quick_search?.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)
|
||||||
|
|
||||||
|
@ -119,25 +189,17 @@ class QuickSearchFragment : Fragment() {
|
||||||
//searchMagIcon?.scaleX = 0.65f
|
//searchMagIcon?.scaleX = 0.65f
|
||||||
//searchMagIcon?.scaleY = 0.65f
|
//searchMagIcon?.scaleY = 0.65f
|
||||||
|
|
||||||
|
|
||||||
quick_search?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
quick_search?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||||
override fun onQueryTextSubmit(query: String): Boolean {
|
override fun onQueryTextSubmit(query: String): Boolean {
|
||||||
context?.filterProviderByPreferredMedia(hasHomePageIsRequired = false)
|
if (search(context, query, false))
|
||||||
?.map { it.name }?.toSet()?.let { active ->
|
UIHelper.hideKeyboard(quick_search)
|
||||||
searchViewModel.searchAndCancel(
|
|
||||||
query = query,
|
|
||||||
ignoreSettings = false,
|
|
||||||
providersActive = active
|
|
||||||
)
|
|
||||||
quick_search?.let {
|
|
||||||
UIHelper.hideKeyboard(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onQueryTextChange(newText: String): Boolean {
|
override fun onQueryTextChange(newText: String): Boolean {
|
||||||
//searchViewModel.quickSearch(newText)
|
if (isSingleProviderQuickSearch)
|
||||||
|
search(context, newText, true)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -147,9 +209,10 @@ class QuickSearchFragment : Fragment() {
|
||||||
when (it) {
|
when (it) {
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
it.value.let { data ->
|
it.value.let { data ->
|
||||||
if (data.isNotEmpty()) {
|
println("DATA: $data")
|
||||||
(search_autofit_results?.adapter as? SearchAdapter?)?.updateList(data)
|
(quick_search_autofit_results?.adapter as? SearchAdapter?)?.updateList(
|
||||||
}
|
data
|
||||||
|
)
|
||||||
}
|
}
|
||||||
searchExitIcon?.alpha = 1f
|
searchExitIcon?.alpha = 1f
|
||||||
quick_search_loading_bar?.alpha = 0f
|
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 ->
|
//quick_search.setOnQueryTextFocusChangeListener { _, b ->
|
||||||
// if (b) {
|
// if (b) {
|
||||||
|
@ -180,9 +241,9 @@ class QuickSearchFragment : Fragment() {
|
||||||
activity?.popCurrentPage()
|
activity?.popCurrentPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
arguments?.getString("autosearch")?.let {
|
arguments?.getString(AUTOSEARCH_KEY)?.let {
|
||||||
quick_search?.setQuery(it, true)
|
quick_search?.setQuery(it, true)
|
||||||
arguments?.remove("autosearch")
|
arguments?.remove(AUTOSEARCH_KEY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -47,10 +47,11 @@ class SearchViewModel : ViewModel() {
|
||||||
fun searchAndCancel(
|
fun searchAndCancel(
|
||||||
query: String,
|
query: String,
|
||||||
providersActive: Set<String> = setOf(),
|
providersActive: Set<String> = setOf(),
|
||||||
ignoreSettings: Boolean = false
|
ignoreSettings: Boolean = false,
|
||||||
|
isQuickSearch: Boolean = false,
|
||||||
) {
|
) {
|
||||||
onGoingSearch?.cancel()
|
onGoingSearch?.cancel()
|
||||||
onGoingSearch = search(query, providersActive, ignoreSettings)
|
onGoingSearch = search(query, providersActive, ignoreSettings, isQuickSearch)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateHistory() = viewModelScope.launch {
|
fun updateHistory() = viewModelScope.launch {
|
||||||
|
@ -65,7 +66,8 @@ class SearchViewModel : ViewModel() {
|
||||||
private fun search(
|
private fun search(
|
||||||
query: String,
|
query: String,
|
||||||
providersActive: Set<String>,
|
providersActive: Set<String>,
|
||||||
ignoreSettings: Boolean = false
|
ignoreSettings: Boolean = false,
|
||||||
|
isQuickSearch: Boolean = false,
|
||||||
) =
|
) =
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (query.length <= 1) {
|
if (query.length <= 1) {
|
||||||
|
@ -73,6 +75,7 @@ class SearchViewModel : ViewModel() {
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isQuickSearch) {
|
||||||
val key = query.hashCode().toString()
|
val key = query.hashCode().toString()
|
||||||
setKey(
|
setKey(
|
||||||
SEARCH_HISTORY_KEY,
|
SEARCH_HISTORY_KEY,
|
||||||
|
@ -84,6 +87,7 @@ class SearchViewModel : ViewModel() {
|
||||||
key = key,
|
key = key,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
_searchResponse.postValue(Resource.Loading())
|
_searchResponse.postValue(Resource.Loading())
|
||||||
|
|
||||||
|
@ -93,9 +97,9 @@ class SearchViewModel : ViewModel() {
|
||||||
|
|
||||||
withContext(Dispatchers.IO) { // This interrupts UI otherwise
|
withContext(Dispatchers.IO) { // This interrupts UI otherwise
|
||||||
repos.filter { a ->
|
repos.filter { a ->
|
||||||
ignoreSettings || (providersActive.isEmpty() || providersActive.contains(a.name))
|
(ignoreSettings || (providersActive.isEmpty() || providersActive.contains(a.name))) && (!isQuickSearch || a.hasQuickSearch)
|
||||||
}.apmap { a -> // Parallel
|
}.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))
|
currentList.add(OnGoingSearch(a.name, search))
|
||||||
_currentSearch.postValue(currentList)
|
_currentSearch.postValue(currentList)
|
||||||
}
|
}
|
||||||
|
|
|
@ -384,7 +384,9 @@ object UIHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hideKeyboard(view: View) {
|
fun hideKeyboard(view: View?) {
|
||||||
|
if(view == null) return
|
||||||
|
|
||||||
val inputMethodManager =
|
val inputMethodManager =
|
||||||
view.context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager?
|
view.context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager?
|
||||||
inputMethodManager?.hideSoftInputFromWindow(view.windowToken, 0)
|
inputMethodManager?.hideSoftInputFromWindow(view.windowToken, 0)
|
||||||
|
|
|
@ -83,4 +83,21 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:listitem="@layout/homepage_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>
|
</LinearLayout>
|
Loading…
Reference in a new issue