search providers settings

This commit is contained in:
LagradOst 2021-08-14 21:35:26 +02:00
parent 4780935d55
commit 3290fceb47
13 changed files with 289 additions and 25 deletions

View file

@ -69,6 +69,23 @@ object APIHolder {
setOf(apis[defProvider].name)
)?.toHashSet() ?: hashSetOf(apis[defProvider].name)
}
fun Activity.getApiTypeSettings(): HashSet<TvType> {
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
val list = settingsManager.getStringSet(
this.getString(R.string.search_types_list_key),
setOf(apis[defProvider].name)
)
val hashSet = HashSet<TvType>()
hashSet.addAll(TvType.values())
if(list.isNullOrEmpty()) return hashSet
val names = TvType.values().map { it.name }.toHashSet()
val realSet = list.filter { names.contains(it) }.map { TvType.valueOf(it) }.toHashSet()
if(realSet.isEmpty()) return hashSet
return realSet
}
}
/**Every provider will **not** have try catch built in, so handle exceptions when calling these functions*/
@ -186,6 +203,7 @@ enum class DubStatus {
enum class TvType {
Movie,
AnimeMovie,
TvSeries,
Cartoon,
Anime,
@ -194,7 +212,7 @@ enum class TvType {
// IN CASE OF FUTURE ANIME MOVIE OR SMTH
fun TvType.isMovieType(): Boolean {
return this == TvType.Movie
return this == TvType.Movie || this == TvType.AnimeMovie
}
data class SubtitleFile(val lang: String, val url: String)

View file

@ -20,7 +20,7 @@ class DubbedAnimeProvider : MainAPI() {
override val supportedTypes: Set<TvType>
get() = setOf(
TvType.Movie,
TvType.AnimeMovie,
TvType.Anime,
)
@ -90,7 +90,7 @@ class DubbedAnimeProvider : MainAPI() {
returnValue.add(
if (getIsMovie(href)) {
MovieSearchResponse(
title, href, this.name, TvType.Movie, img, null
title, href, this.name, TvType.AnimeMovie, img, null
)
} else {
AnimeSearchResponse(
@ -127,7 +127,7 @@ class DubbedAnimeProvider : MainAPI() {
returnValue.add(
if (getIsMovie(href)) {
MovieSearchResponse(
title, href, this.name, TvType.Movie, img, null
title, href, this.name, TvType.AnimeMovie, img, null
)
} else {
AnimeSearchResponse(
@ -197,7 +197,7 @@ class DubbedAnimeProvider : MainAPI() {
episode.title,
realSlug,
this.name,
TvType.Movie,
TvType.AnimeMovie,
episode.serversHTML,
if (poster == null) null else fixUrl(poster),
episode.year?.toIntOrNull(),

View file

@ -17,7 +17,7 @@ class TenshiProvider : MainAPI() {
fun getType(t: String): TvType {
return if (t.contains("OVA") || t.contains("Special")) TvType.ONA
else if (t.contains("Movie")) TvType.Movie
else if (t.contains("Movie")) TvType.AnimeMovie
else TvType.Anime
}
}
@ -30,7 +30,7 @@ class TenshiProvider : MainAPI() {
get() = false
override val supportedTypes: Set<TvType>
get() = setOf(TvType.Anime, TvType.Movie, TvType.ONA)
get() = setOf(TvType.Anime, TvType.AnimeMovie, TvType.ONA)
private fun autoLoadToken(): Boolean {
if (token != null) return true

View file

@ -13,7 +13,7 @@ class WcoProvider : MainAPI() {
companion object {
fun getType(t: String): TvType {
return if (t.contains("OVA") || t.contains("Special")) TvType.ONA
else if (t.contains("Movie")) TvType.Movie
else if (t.contains("Movie")) TvType.AnimeMovie
else TvType.Anime
}
}
@ -29,7 +29,7 @@ class WcoProvider : MainAPI() {
override val supportedTypes: Set<TvType>
get() = setOf(
TvType.Movie,
TvType.AnimeMovie,
TvType.Anime,
TvType.ONA
)
@ -91,9 +91,9 @@ class WcoProvider : MainAPI() {
val type = i.selectFirst(".film-detail.film-detail-fix > div > span:nth-child(3)").text()
returnValue.add(
if (getType(type) == TvType.Movie) {
if (getType(type) == TvType.AnimeMovie) {
MovieSearchResponse(
title, href, this.name, TvType.Movie, img, year
title, href, this.name, TvType.AnimeMovie, img, year
)
} else {
AnimeSearchResponse(
@ -152,9 +152,9 @@ class WcoProvider : MainAPI() {
val type = filmInfo?.select("span")?.get(1)?.text().toString()
if (title != "null") {
returnValue.add(
if (getType(type) == TvType.Movie) {
if (getType(type) == TvType.AnimeMovie) {
MovieSearchResponse(
title, href, this.name, TvType.Movie, img, year
title, href, this.name, TvType.AnimeMovie, img, year
)
} else {
AnimeSearchResponse(

View file

@ -9,6 +9,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
class APIRepository(val api: MainAPI) {
companion object {
var providersActive = HashSet<String>()
var typesActive = HashSet<TvType>()
}
val name: String get() = api.name
@ -22,9 +23,10 @@ class APIRepository(val api: MainAPI) {
}
}
suspend fun search(query: String): Resource<ArrayList<SearchResponse>> {
suspend fun search(query: String): Resource<List<SearchResponse>> {
return safeApiCall {
api.search(query) ?: throw ErrorLoadingException()
return@safeApiCall (api.search(query)
?: throw ErrorLoadingException()).filter { typesActive.contains(it.type) }.toList()
}
}

View file

@ -59,6 +59,7 @@ class HomeChildItemAdapter(
textType?.text = when (card.type) {
TvType.Anime -> "Anime"
TvType.Movie -> "Movie"
TvType.AnimeMovie -> "Movie"
TvType.ONA -> "ONA"
TvType.TvSeries -> "TV"
TvType.Cartoon -> "Cartoon"

View file

@ -899,7 +899,7 @@ class ResultFragment : Fragment() {
}
}
if (d.type == TvType.Movie) {
if (d.type.isMovieType()) {
val hasDownloadSupport = api.hasDownloadSupport
lateFixDownloadButton(true)

View file

@ -91,6 +91,7 @@ class SearchAdapter(
textType?.text = when (card.type) {
TvType.Anime -> "Anime"
TvType.Movie -> "Movie"
TvType.AnimeMovie -> "Movie"
TvType.ONA -> "ONA"
TvType.TvSeries -> "TV"
TvType.Cartoon -> "Cartoon"

View file

@ -8,7 +8,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.ImageView
import android.widget.*
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
@ -16,20 +16,28 @@ import androidx.lifecycle.ViewModelProvider
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.switchmaterial.SwitchMaterial
import com.lagradost.cloudstream3.APIHolder.apis
import com.lagradost.cloudstream3.APIHolder.getApiSettings
import com.lagradost.cloudstream3.APIHolder.getApiTypeSettings
import com.lagradost.cloudstream3.HomePageList
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.ui.APIRepository.Companion.providersActive
import com.lagradost.cloudstream3.ui.APIRepository.Companion.typesActive
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.utils.DataStore.getKey
import com.lagradost.cloudstream3.utils.DataStore.setKey
import com.lagradost.cloudstream3.utils.SEARCH_PROVIDER_TOGGLE
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
import com.lagradost.cloudstream3.utils.UIHelper.getGridIsCompact
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import kotlinx.android.synthetic.main.fragment_search.*
import java.util.HashSet
class SearchFragment : Fragment() {
private lateinit var searchViewModel: SearchViewModel
@ -95,10 +103,175 @@ class SearchFragment : Fragment() {
val searchMagIcon = main_search.findViewById<ImageView>(androidx.appcompat.R.id.search_mag_icon)
searchMagIcon.scaleX = 0.65f
searchMagIcon.scaleY = 0.65f
search_filter.setOnClickListener {
search_filter.setOnClickListener { view ->
val apiNamesSetting = activity?.getApiSettings()
if (apiNamesSetting != null) {
val apiNames = apis.map { it.name }
val builder =
AlertDialog.Builder(view.context, R.style.AlertDialogCustom).setView(R.layout.provider_list)
val dialog = builder.create()
dialog.show()
val listView = dialog.findViewById<ListView>(R.id.listview1)!!
val listView2 = dialog.findViewById<ListView>(R.id.listview2)!!
val toggle = dialog.findViewById<SwitchMaterial>(R.id.toggle1)!!
val applyButton = dialog.findViewById<TextView>(R.id.apply_btt)!!
val cancelButton = dialog.findViewById<TextView>(R.id.cancel_btt)!!
// val applyHolder = dialog.findViewById<LinearLayout>(R.id.apply_btt_holder)!!
toggle.text = getString(R.string.search_provider_text)
val arrayAdapter = ArrayAdapter<String>(view.context, R.layout.sort_bottom_single_choice)
arrayAdapter.addAll(apiNames)
listView.adapter = arrayAdapter
listView.choiceMode = AbsListView.CHOICE_MODE_MULTIPLE
val typeChoices = listOf(
Pair("Movies", listOf(TvType.Movie)),
Pair("TvSeries", listOf(TvType.TvSeries)),
Pair("Cartoons", listOf(TvType.Cartoon)),
Pair("Anime", listOf(TvType.Anime, TvType.ONA, TvType.AnimeMovie))
)
val arrayAdapter2 = ArrayAdapter<String>(view.context, R.layout.sort_bottom_single_choice)
arrayAdapter2.addAll(typeChoices.map { it.first })
listView2.adapter = arrayAdapter2
listView2.choiceMode = AbsListView.CHOICE_MODE_MULTIPLE
/*fun updateMulti() {
val set = HashSet<TvType>()
for ((index, api) in apis.withIndex()) {
if (listView?.checkedItemPositions[index]) {
set.addAll(api.supportedTypes)
}
}
if (set.size == 0) {
set.addAll(TvType.values())
}
for ((index, choice) in typeChoices.withIndex()) {
listView2?.setItemChecked(index, choice.second.any { set.contains(it) })
}
}*/
for ((index, item) in apiNames.withIndex()) {
listView.setItemChecked(index, apiNamesSetting.contains(item))
}
for ((index, item) in typeChoices.withIndex()) {
listView2.setItemChecked(index, item.second.any { typesActive.contains(it) })
}
fun toggleSearch(isOn: Boolean) {
if (isOn) {
listView2?.visibility = View.VISIBLE
listView?.visibility = View.GONE
} else {
listView?.visibility = View.VISIBLE
listView2?.visibility = View.GONE
}
}
val defVal = context?.getKey(SEARCH_PROVIDER_TOGGLE, true) ?: true
toggleSearch(defVal)
toggle.isChecked = defVal
toggle.setOnCheckedChangeListener { _, isOn ->
toggleSearch(isOn)
}
listView.setOnItemClickListener { _, _, i, _ ->
val types = HashSet<TvType>()
for ((index, api) in apis.withIndex()) {
if (listView?.checkedItemPositions[index]) {
types.addAll(api.supportedTypes)
}
}
for ((typeIndex, type) in typeChoices.withIndex()) {
listView2.setItemChecked(typeIndex, type.second.any { types.contains(it) })
}
}
listView2.setOnItemClickListener { _, _, i, _ ->
for ((index, api) in apis.withIndex()) {
var isSupported = false
for ((typeIndex, type) in typeChoices.withIndex()) {
if (listView2?.checkedItemPositions[typeIndex]) {
if (api.supportedTypes.any { type.second.contains(it) }) {
isSupported = true
}
}
}
listView?.setItemChecked(
index,
isSupported
)
}
//updateMulti()
}
dialog.setOnDismissListener {
context?.setKey(SEARCH_PROVIDER_TOGGLE, toggle.isChecked ?: true)
}
applyButton.setOnClickListener {
val settingsManagerLocal = PreferenceManager.getDefaultSharedPreferences(activity)
val activeTypes = HashSet<TvType>()
for ((index, name) in typeChoices.withIndex()) {
if (listView2?.checkedItemPositions[index]) {
activeTypes.addAll(typeChoices[index].second)
}
}
if (activeTypes.size == 0) {
activeTypes.addAll(TvType.values())
}
val activeApis = HashSet<String>()
for ((index, name) in apiNames.withIndex()) {
if (listView?.checkedItemPositions[index]) {
activeApis.add(name)
}
}
if (activeApis.size == 0) {
activeApis.addAll(apiNames)
}
val edit = settingsManagerLocal.edit()
edit.putStringSet(
getString(R.string.search_providers_list_key),
activeApis
)
edit.putStringSet(
getString(R.string.search_types_list_key),
activeTypes.map { it.name }.toSet()
)
edit.apply()
providersActive = activeApis
typesActive = activeTypes
dialog.dismiss()
}
cancelButton.setOnClickListener {
dialog.dismiss()
}
//listView.setSelection(selectedIndex)
// listView.setItemChecked(selectedIndex, true)
/*
val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
builder.setMultiChoiceItems(
@ -125,7 +298,7 @@ class SearchFragment : Fragment() {
}
builder.setTitle("Search Providers")
builder.setNegativeButton("Ok") { _, _ -> }
builder.show()
builder.show()*/
}
}
@ -178,6 +351,7 @@ class SearchFragment : Fragment() {
activity?.let {
providersActive = it.getApiSettings()
typesActive = it.getApiTypeSettings()
}
main_search.setOnQueryTextFocusChangeListener { searchView, b ->

View file

@ -13,7 +13,7 @@ import kotlinx.coroutines.launch
data class OnGoingSearch(
val apiName: String,
val data: Resource<ArrayList<SearchResponse>>
val data: Resource<List<SearchResponse>>
)
class SearchViewModel : ViewModel() {
@ -56,7 +56,7 @@ class SearchViewModel : ViewModel() {
if (localSearchCounter != searchCounter) return@launch
val list = ArrayList<SearchResponse>()
val nestedList = currentList.map { it.data }.filterIsInstance<Resource.Success<ArrayList<SearchResponse>>>().map { it.value }
val nestedList = currentList.map { it.data }.filterIsInstance<Resource.Success<List<SearchResponse>>>().map { it.value }
// I do it this way to move the relevant search results to the top
var index = 0

View file

@ -10,6 +10,7 @@ const val DOWNLOAD_HEADER_CACHE = "download_header_cache"
const val DOWNLOAD_EPISODE_CACHE = "download_episode_cache"
const val VIDEO_PLAYER_BRIGHTNESS = "video_player_alpha"
const val HOMEPAGE_API = "home_api_used"
const val SEARCH_PROVIDER_TOGGLE = "settings_providers_toggle"
const val PREFERENCES_NAME: String = "rebuild_preference"

View file

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:background="?attr/bitDarkerGrayBackground"
android:layout_height="match_parent">
<com.google.android.material.switchmaterial.SwitchMaterial
android:layout_marginTop="10dp"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:textStyle="bold"
android:textSize="20sp"
android:textColor="?attr/textColor"
android:id="@+id/toggle1"
tools:text="Search" android:layout_width="match_parent" android:layout_height="wrap_content">
</com.google.android.material.switchmaterial.SwitchMaterial>
<ListView
android:id="@+id/listview1"
android:layout_marginTop="-10dp"
android:layout_marginBottom="60dp"
android:paddingTop="10dp"
tools:listitem="@layout/sort_bottom_single_choice"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_rowWeight="1"
/>
<ListView
android:id="@+id/listview2"
android:layout_marginTop="-10dp"
android:layout_marginBottom="60dp"
android:paddingTop="10dp"
tools:listitem="@layout/sort_bottom_single_choice"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_rowWeight="1"
/>
<LinearLayout
android:id="@+id/apply_btt_holder"
android:orientation="horizontal"
android:layout_gravity="bottom"
android:gravity="bottom|end"
android:layout_marginTop="-60dp"
android:layout_width="match_parent"
android:layout_height="60dp">
<com.google.android.material.button.MaterialButton
style="@style/WhiteButton"
android:layout_gravity="center_vertical|end"
android:text="@string/sort_apply"
android:id="@+id/apply_btt"
android:layout_width="wrap_content"
/>
<com.google.android.material.button.MaterialButton
style="@style/BlackButton"
android:layout_gravity="center_vertical|end"
android:text="@string/sort_cancel"
android:id="@+id/cancel_btt"
android:layout_width="wrap_content"
/>
</LinearLayout>
</LinearLayout>

View file

@ -4,9 +4,10 @@
<string name="title_search">Search</string>
<string name="title_downloads">Downloads</string>
<string name="title_settings">Settings</string>
<string name="search_hint">Search...</string>
<string name="search_hint">Search</string>
<string name="change_providers_descript">Change Providers</string>
<string name="search_providers_list_key">search_providers_list</string>
<string name="search_types_list_key">search_type_list</string>
<string name="grid_format_key">grid_format</string>
<string name="search_poster_descript">Poster</string>
<string name="no_data">No Data</string>
@ -80,4 +81,5 @@
<string name="subs_default_reset_toast">Reset to default value</string>
<string name="preview_background">Preview Background</string>
<string name="subs_font">Font</string>
<string name="search_provider_text">Search Providers</string>
</resources>