AquaStream/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt

446 lines
18 KiB
Kotlin
Raw Normal View History

2021-05-12 21:51:02 +00:00
package com.lagradost.cloudstream3.ui.search
2021-05-15 23:37:42 +00:00
import android.content.res.Configuration
2021-05-12 21:51:02 +00:00
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.AbsListView
import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.ListView
2021-05-15 23:37:42 +00:00
import androidx.appcompat.widget.SearchView
2021-12-13 18:41:33 +00:00
import androidx.core.view.isVisible
2021-05-12 21:51:02 +00:00
import androidx.fragment.app.Fragment
2021-11-20 00:41:37 +00:00
import androidx.fragment.app.activityViewModels
2021-05-15 23:37:42 +00:00
import androidx.preference.PreferenceManager
2021-08-12 00:04:58 +00:00
import androidx.recyclerview.widget.GridLayoutManager
2021-05-15 23:37:42 +00:00
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.button.MaterialButton
2021-09-12 14:10:22 +00:00
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
import com.lagradost.cloudstream3.APIHolder.filterSearchResultByFilmQuality
2022-08-15 14:44:46 +00:00
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
2022-04-06 15:16:08 +00:00
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
2022-01-30 01:50:49 +00:00
import com.lagradost.cloudstream3.APIHolder.getApiSettings
2022-10-28 01:51:27 +00:00
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
2022-10-28 01:51:27 +00:00
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
2021-05-16 18:28:00 +00:00
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.logError
2021-05-16 18:28:00 +00:00
import com.lagradost.cloudstream3.mvvm.observe
2021-09-12 14:10:22 +00:00
import com.lagradost.cloudstream3.ui.APIRepository
2021-08-12 00:04:58 +00:00
import com.lagradost.cloudstream3.ui.home.HomeFragment
2022-10-28 01:51:27 +00:00
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.bindChips
2021-12-13 18:41:33 +00:00
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.currentSpan
2021-08-12 00:04:58 +00:00
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.loadHomepageList
2022-10-28 01:51:27 +00:00
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.updateChips
2021-08-12 00:04:58 +00:00
import com.lagradost.cloudstream3.ui.home.ParentItemAdapter
2022-02-18 19:29:48 +00:00
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
import com.lagradost.cloudstream3.utils.Coroutines.main
2021-08-14 19:35:26 +00:00
import com.lagradost.cloudstream3.utils.DataStore.getKey
import com.lagradost.cloudstream3.utils.DataStore.setKey
2022-04-06 15:16:08 +00:00
import com.lagradost.cloudstream3.utils.SubtitleHelper
2021-12-12 02:33:17 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
2021-08-12 00:04:58 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
2021-12-13 18:41:33 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
2021-08-04 13:30:34 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
2021-05-15 23:37:42 +00:00
import kotlinx.android.synthetic.main.fragment_search.*
2022-10-28 01:51:27 +00:00
import kotlinx.android.synthetic.main.tvtypes_chips.*
import java.util.concurrent.locks.ReentrantLock
2021-05-12 21:51:02 +00:00
const val SEARCH_PREF_TAGS = "search_pref_tags"
const val SEARCH_PREF_PROVIDERS = "search_pref_providers"
2021-10-30 18:14:12 +00:00
2021-05-12 21:51:02 +00:00
class SearchFragment : Fragment() {
2021-09-12 14:10:22 +00:00
companion object {
fun List<SearchResponse>.filterSearchResponse(): List<SearchResponse> {
return this.filter { response ->
if (response is AnimeSearchResponse) {
2022-04-13 17:29:30 +00:00
val status = response.dubStatus
(status.isNullOrEmpty()) || (status.any {
APIRepository.dubStatusActive.contains(it)
})
2021-09-12 14:10:22 +00:00
} else {
true
}
}
}
}
2021-11-20 00:41:37 +00:00
private val searchViewModel: SearchViewModel by activityViewModels()
2021-05-12 21:51:02 +00:00
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
2021-05-15 23:37:42 +00:00
savedInstanceState: Bundle?,
2021-05-12 21:51:02 +00:00
): View? {
activity?.window?.setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE
)
2021-05-12 21:51:02 +00:00
return inflater.inflate(R.layout.fragment_search, container, false)
}
2021-06-06 18:06:01 +00:00
private fun fixGrid() {
2021-12-13 18:41:33 +00:00
activity?.getSpanCount()?.let {
currentSpan = it
2021-05-15 23:37:42 +00:00
}
2021-12-13 18:41:33 +00:00
search_autofit_results.spanCount = currentSpan
currentSpan = currentSpan
2021-08-12 00:04:58 +00:00
HomeFragment.configEvent.invoke(currentSpan)
2021-06-06 18:06:01 +00:00
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
fixGrid()
}
2021-07-30 21:03:46 +00:00
override fun onDestroyView() {
2021-08-04 13:30:34 +00:00
hideKeyboard()
2021-07-30 21:03:46 +00:00
super.onDestroyView()
}
override fun onResume() {
super.onResume()
afterPluginsLoadedEvent += ::reloadRepos
}
override fun onStop() {
super.onStop()
afterPluginsLoadedEvent -= ::reloadRepos
}
var selectedSearchTypes = mutableListOf<TvType>()
var selectedApis = mutableSetOf<String>()
2022-01-30 01:50:49 +00:00
fun search(query: String?) {
if (query == null) return
context?.getApiSettings()?.let { settings ->
searchViewModel.searchAndCancel(
query = query,
providersActive = selectedApis.filter { name ->
2022-08-15 14:44:46 +00:00
settings.contains(name) && getApiFromNameNull(name)?.supportedTypes?.any {
2022-01-30 01:50:49 +00:00
selectedSearchTypes.contains(
it
)
2022-08-15 14:44:46 +00:00
} == true
2022-01-30 01:50:49 +00:00
}.toSet()
)
}
}
// Null if defined as a variable
// This needs to be run after view created
private fun reloadRepos(success: Boolean = false) = main {
searchViewModel.reloadRepos()
context?.filterProviderByPreferredMedia()?.let { validAPIs ->
2022-10-28 01:51:27 +00:00
bindChips(
home_select_group,
selectedSearchTypes,
validAPIs.flatMap { api -> api.supportedTypes }.distinct()
) { list ->
if (selectedSearchTypes.toSet() != list.toSet()) {
setKey(SEARCH_PREF_TAGS, selectedSearchTypes)
selectedSearchTypes.clear()
selectedSearchTypes.addAll(list)
search(main_search?.query?.toString())
}
}
}
}
2022-10-28 01:51:27 +00:00
2021-06-06 18:06:01 +00:00
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
2021-07-29 00:54:27 +00:00
context?.fixPaddingStatusbar(searchRoot)
2021-06-06 18:06:01 +00:00
fixGrid()
reloadRepos()
2021-05-15 23:37:42 +00:00
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? = activity?.let {
SearchAdapter(
ArrayList(),
2021-12-13 18:41:33 +00:00
search_autofit_results,
2021-07-30 23:41:54 +00:00
) { callback ->
SearchHelper.handleSearchClickCallback(activity, callback)
2021-07-29 00:54:27 +00:00
}
2021-05-15 23:37:42 +00:00
}
2021-12-13 18:41:33 +00:00
search_autofit_results.adapter = adapter
2021-05-15 23:37:42 +00:00
search_loading_bar.alpha = 0f
val searchExitIcon =
main_search.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)
2022-04-25 18:00:25 +00:00
// val searchMagIcon =
// main_search.findViewById<ImageView>(androidx.appcompat.R.id.search_mag_icon)
//searchMagIcon.scaleX = 0.65f
//searchMagIcon.scaleY = 0.65f
2021-08-14 19:35:26 +00:00
context?.let { ctx ->
val validAPIs = ctx.filterProviderByPreferredMedia()
selectedApis = ctx.getKey(
SEARCH_PREF_PROVIDERS,
defVal = validAPIs.map { it.name }
)!!.toMutableSet()
}
2021-08-14 19:35:26 +00:00
search_filter.setOnClickListener { searchView ->
searchView?.context?.let { ctx ->
2022-01-30 22:02:57 +00:00
val validAPIs = ctx.filterProviderByPreferredMedia(hasHomePageIsRequired = false)
var currentValidApis = listOf<MainAPI>()
val currentSelectedApis = if (selectedApis.isEmpty()) validAPIs.map { it.name }
.toMutableSet() else selectedApis
val builder =
BottomSheetDialog(ctx)
builder.behavior.state = BottomSheetBehavior.STATE_EXPANDED
builder.setContentView(R.layout.home_select_mainpage)
builder.show()
builder.let { dialog ->
2022-04-06 15:16:08 +00:00
val isMultiLang = ctx.getApiProviderLangSettings().size > 1
val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt)
val listView = dialog.findViewById<ListView>(R.id.listview1)
val arrayAdapter = ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
listView?.adapter = arrayAdapter
listView?.choiceMode = AbsListView.CHOICE_MODE_MULTIPLE
listView?.setOnItemClickListener { _, _, i, _ ->
if (currentValidApis.isNotEmpty()) {
val api = currentValidApis[i].name
if (currentSelectedApis.contains(api)) {
listView.setItemChecked(i, false)
currentSelectedApis -= api
} else {
listView.setItemChecked(i, true)
currentSelectedApis += api
}
}
2021-08-14 19:35:26 +00:00
}
2022-10-28 01:51:27 +00:00
fun updateList(types: List<TvType>) {
setKey(SEARCH_PREF_TAGS, types.map {it.name})
arrayAdapter.clear()
currentValidApis = validAPIs.filter { api ->
2022-01-30 22:02:57 +00:00
api.supportedTypes.any {
2022-10-28 01:51:27 +00:00
types.contains(it)
}
2022-04-06 15:16:08 +00:00
}.sortedBy { it.name.lowercase() }
2021-08-14 19:35:26 +00:00
2022-04-13 17:29:30 +00:00
val names = currentValidApis.map {
if (isMultiLang) "${
SubtitleHelper.getFlagFromIso(
it.lang
)?.plus(" ") ?: ""
}${it.name}" else it.name
}
2022-04-08 22:13:09 +00:00
for ((index, api) in currentValidApis.map { it.name }.withIndex()) {
listView?.setItemChecked(index, currentSelectedApis.contains(api))
2021-08-14 19:35:26 +00:00
}
2022-01-30 22:02:57 +00:00
//arrayAdapter.notifyDataSetChanged()
arrayAdapter.addAll(names)
arrayAdapter.notifyDataSetChanged()
2021-08-14 19:35:26 +00:00
}
2022-10-28 01:51:27 +00:00
val selectedSearchTypes = getKey<List<String>>(SEARCH_PREF_TAGS)
?.mapNotNull { listName ->
TvType.values().firstOrNull { it.name == listName }
}
?.toMutableList()
?: mutableListOf(TvType.Movie, TvType.TvSeries)
2021-08-14 19:35:26 +00:00
2022-10-28 01:51:27 +00:00
bindChips(
dialog.home_select_group,
selectedSearchTypes,
TvType.values().toList()
) { list ->
updateList(list)
}
2021-08-14 19:35:26 +00:00
2022-10-28 01:51:27 +00:00
cancelBtt?.setOnClickListener {
dialog.dismissSafe()
2021-08-14 19:35:26 +00:00
}
2022-10-28 01:51:27 +00:00
cancelBtt?.setOnClickListener {
dialog.dismissSafe()
}
applyBtt?.setOnClickListener {
//if (currentApiName != selectedApiName) {
// currentApiName?.let(callback)
//}
dialog.dismissSafe()
}
dialog.setOnDismissListener {
context?.setKey(SEARCH_PREF_PROVIDERS, currentSelectedApis.toList())
selectedApis = currentSelectedApis
}
updateList(selectedSearchTypes.toList())
2021-08-14 19:35:26 +00:00
}
}
}
2021-08-14 19:35:26 +00:00
val settingsManager = context?.let { PreferenceManager.getDefaultSharedPreferences(it) }
val isAdvancedSearch = settingsManager?.getBoolean("advanced_search", true) ?: true
selectedSearchTypes = context?.getKey<List<String>>(SEARCH_PREF_TAGS)
?.mapNotNull { listName -> TvType.values().firstOrNull { it.name == listName } }
?.toMutableList()
?: mutableListOf(TvType.Movie, TvType.TvSeries)
2022-08-28 23:52:15 +00:00
if (isTrueTvSettings()) {
2021-11-25 17:26:14 +00:00
search_filter.isFocusable = true
search_filter.isFocusableInTouchMode = true
}
2021-05-15 23:37:42 +00:00
main_search.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
2022-01-30 01:50:49 +00:00
search(query)
2021-11-20 00:41:37 +00:00
main_search?.let {
hideKeyboard(it)
}
2021-05-15 23:37:42 +00:00
return true
}
override fun onQueryTextChange(newText: String): Boolean {
2021-10-19 20:17:06 +00:00
//searchViewModel.quickSearch(newText)
val showHistory = newText.isBlank()
2022-03-29 20:17:42 +00:00
if (showHistory) {
searchViewModel.clearSearch()
searchViewModel.updateHistory()
}
search_history_recycler?.isVisible = showHistory
search_master_recycler?.isVisible = !showHistory && isAdvancedSearch
search_autofit_results?.isVisible = !showHistory && !isAdvancedSearch
2021-05-15 23:37:42 +00:00
return true
}
})
observe(searchViewModel.currentHistory) { list ->
(search_history_recycler.adapter as? SearchHistoryAdaptor?)?.updateList(list)
}
searchViewModel.updateHistory()
2021-05-16 18:28:00 +00:00
observe(searchViewModel.searchResponse) {
when (it) {
is Resource.Success -> {
it.value.let { data ->
2021-08-12 00:04:58 +00:00
if (data.isNotEmpty()) {
2022-02-05 01:05:13 +00:00
(search_autofit_results?.adapter as SearchAdapter?)?.updateList(data)
2021-07-28 19:14:45 +00:00
}
2021-06-16 16:54:07 +00:00
}
2021-07-15 16:45:25 +00:00
searchExitIcon.alpha = 1f
2021-06-16 16:54:07 +00:00
search_loading_bar.alpha = 0f
2021-05-16 18:28:00 +00:00
}
is Resource.Failure -> {
2021-07-30 21:03:46 +00:00
// Toast.makeText(activity, "Server error", Toast.LENGTH_LONG).show()
2021-07-15 16:45:25 +00:00
searchExitIcon.alpha = 1f
2021-06-16 16:54:07 +00:00
search_loading_bar.alpha = 0f
}
is Resource.Loading -> {
2021-07-15 16:45:25 +00:00
searchExitIcon.alpha = 0f
2021-06-16 16:54:07 +00:00
search_loading_bar.alpha = 1f
2021-05-16 18:28:00 +00:00
}
}
}
2021-08-12 00:04:58 +00:00
val listLock = ReentrantLock()
2021-08-12 00:04:58 +00:00
observe(searchViewModel.currentSearch) { list ->
try {
// https://stackoverflow.com/questions/6866238/concurrent-modification-exception-adding-to-an-arraylist
listLock.lock()
(search_master_recycler?.adapter as ParentItemAdapter?)?.apply {
2022-01-30 22:02:57 +00:00
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 ongoingList = HomePageList(
ongoing.apiName,
dataListFiltered
)
ongoingList
}
2022-01-30 22:02:57 +00:00
updateList(newItems)
//notifyDataSetChanged()
2021-08-12 00:04:58 +00:00
}
} catch (e: Exception) {
logError(e)
} finally {
listLock.unlock()
2021-08-12 00:04:58 +00:00
}
}
/*main_search.setOnQueryTextFocusChangeListener { _, b ->
if (b) {
// https://stackoverflow.com/questions/12022715/unable-to-show-keyboard-automatically-in-the-searchview
2021-10-30 18:14:12 +00:00
showInputMethod(view.findFocus())
}
}*/
2021-10-30 18:14:12 +00:00
//main_search.onActionViewExpanded()*/
2021-08-12 00:04:58 +00:00
val masterAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
2022-01-30 22:02:57 +00:00
ParentItemAdapter(mutableListOf(), { callback ->
SearchHelper.handleSearchClickCallback(activity, callback)
}, { item ->
activity?.loadHomepageList(item)
})
2021-08-12 00:04:58 +00:00
val historyAdapter = SearchHistoryAdaptor(mutableListOf()) { click ->
val searchItem = click.item
when (click.clickAction) {
SEARCH_HISTORY_OPEN -> {
searchViewModel.clearSearch()
if (searchItem.type.isNotEmpty())
2022-10-28 01:51:27 +00:00
updateChips(home_select_group, searchItem.type.toMutableList())
main_search?.setQuery(searchItem.searchText, true)
}
SEARCH_HISTORY_REMOVE -> {
removeKey(SEARCH_HISTORY_KEY, searchItem.key)
searchViewModel.updateHistory()
}
else -> {
// wth are you doing???
}
}
}
2021-08-12 00:04:58 +00:00
search_history_recycler?.adapter = historyAdapter
search_history_recycler?.layoutManager = GridLayoutManager(context, 1)
2021-08-12 00:04:58 +00:00
search_master_recycler?.adapter = masterAdapter
search_master_recycler?.layoutManager = GridLayoutManager(context, 1)
2021-08-12 00:04:58 +00:00
2021-08-07 02:57:46 +00:00
// SubtitlesFragment.push(activity)
2021-06-17 15:39:01 +00:00
//searchViewModel.search("iron man")
2021-07-18 13:02:30 +00:00
//(activity as AppCompatActivity).loadResult("https://shiro.is/overlord-dubbed", "overlord-dubbed", "Shiro")
2021-05-28 13:38:06 +00:00
/*
2021-07-30 21:03:46 +00:00
(activity as AppCompatActivity?)?.supportFragmentManager.beginTransaction()
2021-05-23 17:07:43 +00:00
.setCustomAnimations(R.anim.enter_anim,
R.anim.exit_anim,
R.anim.pop_enter,
R.anim.pop_exit)
2021-05-28 13:38:06 +00:00
.add(R.id.homeRoot, PlayerFragment.newInstance(PlayerData(0, null,0)))
.commit()*/
2021-05-12 21:51:02 +00:00
}
2021-08-06 20:55:11 +00:00
2021-05-12 21:51:02 +00:00
}