Add tv type support

This commit is contained in:
Blatzar 2022-08-13 23:49:16 +02:00
parent b7a11048f0
commit bcfa3cff77
6 changed files with 203 additions and 44 deletions

View file

@ -56,6 +56,7 @@ data class PluginData(
null,
null,
null,
null,
null
)
}

View file

@ -57,7 +57,7 @@ data class SitePlugin(
// Might be used to go directly to the plugin repo in the future
@JsonProperty("repositoryUrl") val repositoryUrl: String?,
// These types are yet to be mapped and used, ignore for now
// @JsonProperty("tvTypes") val tvTypes: List<String>?,
@JsonProperty("tvTypes") val tvTypes: List<String>?,
@JsonProperty("language") val language: String?,
@JsonProperty("iconUrl") val iconUrl: String?,
// Set to true to get an 18+ symbol next to the plugin

View file

@ -3,10 +3,12 @@ package com.lagradost.cloudstream3.ui.settings.extensions
import android.content.Context
import android.os.Bundle
import android.view.*
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.getPairList
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
import kotlinx.android.synthetic.main.fragment_plugins.*
@ -55,7 +57,7 @@ class PluginsFragment : Fragment() {
// Don't go back if active query
settings_toolbar?.setNavigationOnClickListener {
if (searchView?.isIconified == false) {
searchView?.isIconified = true
searchView.isIconified = true
} else {
activity?.onBackPressed()
}
@ -88,7 +90,7 @@ class PluginsFragment : Fragment() {
pluginViewModel.handlePluginAction(activity, url, it, isLocal)
}
observe(pluginViewModel.plugins) {
observe(pluginViewModel.filteredPlugins) {
(plugin_recycler_view?.adapter as? PluginAdapter?)?.updateList(it)
plugin_recycler_view?.scrollToPosition(0)
}
@ -100,6 +102,55 @@ class PluginsFragment : Fragment() {
} else {
pluginViewModel.updatePluginList(url)
}
// 💀💀💀💀💀💀💀 Recyclerview when
val pairList = getPairList(
home_select_anime,
home_select_cartoons,
home_select_tv_series,
home_select_documentaries,
home_select_movies,
home_select_asian,
home_select_livestreams
)
// Copy pasted code
for ((button, validTypes) in pairList) {
val validTypesMapped = validTypes.map { it.name }
val isValid =
true //validAPIs.any { api -> validTypes.any { api.supportedTypes.contains(it) } }
button?.isVisible = isValid
if (isValid) {
fun buttonContains(): Boolean {
return pluginViewModel.tvTypes.any { validTypesMapped.contains(it) }
}
button?.isSelected = buttonContains()
button?.setOnClickListener {
pluginViewModel.tvTypes.clear()
pluginViewModel.tvTypes.addAll(validTypesMapped)
for ((otherButton, _) in pairList) {
otherButton?.isSelected = false
}
button.isSelected = true
pluginViewModel.updateFilteredPlugins()
}
button?.setOnLongClickListener {
if (!buttonContains()) {
button.isSelected = true
pluginViewModel.tvTypes.addAll(validTypesMapped)
} else {
button.isSelected = false
pluginViewModel.tvTypes.removeAll(validTypesMapped)
}
pluginViewModel.updateFilteredPlugins()
return@setOnLongClickListener true
}
}
}
}
companion object {

View file

@ -24,8 +24,15 @@ import me.xdrop.fuzzywuzzy.FuzzySearch
typealias Plugin = Pair<String, SitePlugin>
class PluginsViewModel : ViewModel() {
private val _plugins = MutableLiveData<List<PluginViewData>>()
val plugins: LiveData<List<PluginViewData>> = _plugins
/** plugins is an unaltered list of plugins */
private var plugins: List<PluginViewData> = emptyList()
/** filteredPlugins is a subset of plugins following the current search query and tv type selection */
private var _filteredPlugins = MutableLiveData<List<PluginViewData>>()
var filteredPlugins: LiveData<List<PluginViewData>> = _filteredPlugins
val tvTypes = mutableListOf<String>()
private var currentQuery: String? = null
companion object {
private val repositoryCache: MutableMap<String, List<Plugin>> = mutableMapOf()
@ -161,7 +168,27 @@ class PluginsViewModel : ViewModel() {
PluginViewData(plugin, isDownloaded(plugin, stored))
}
_plugins.postValue(list)
this.plugins = list
_filteredPlugins.postValue(list.filterTvTypes().sortByQuery(currentQuery))
}
// Perhaps can be optimized?
private fun List<PluginViewData>.filterTvTypes(): List<PluginViewData> {
if (tvTypes.isEmpty()) return this
return this.filter { it.plugin.second.tvTypes?.any { type -> tvTypes.contains(type) } == true }
}
private fun List<PluginViewData>.sortByQuery(query: String?): List<PluginViewData> {
return if (query == null) {
// Return list to base state if no query
this.sortedBy { it.plugin.second.name }
} else {
this.sortedBy { -FuzzySearch.ratio(it.plugin.second.name, query) }
}
}
fun updateFilteredPlugins() {
_filteredPlugins.postValue(plugins.filterTvTypes().sortByQuery(currentQuery))
}
fun updatePluginList(repositoryUrl: String) = viewModelScope.launch {
@ -170,19 +197,9 @@ class PluginsViewModel : ViewModel() {
}
fun search(query: String?) {
val currentPlugins = plugins.value ?: return
// Return list to base state if no query
val newValue = if (query == null) {
currentPlugins.sortedBy { it.plugin.second.name }
} else {
currentPlugins.sortedBy {
-FuzzySearch.ratio(it.plugin.second.name, query)
currentQuery = query
_filteredPlugins.postValue(filteredPlugins.value?.sortByQuery(query))
}
}
_plugins.postValue(newValue)
}
/**
* Update the list but only with the local data. Used for file management.
@ -196,6 +213,7 @@ class PluginsViewModel : ViewModel() {
PluginViewData("" to it.toSitePlugin(), true)
}
_plugins.postValue(downloadedPlugins)
plugins = downloadedPlugins
_filteredPlugins.postValue(downloadedPlugins.filterTvTypes().sortByQuery(currentQuery))
}
}

View file

@ -9,30 +9,117 @@
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:background="@android:color/transparent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:background="@android:color/transparent">
<com.google.android.material.appbar.MaterialToolbar
app:menu="@menu/repository"
android:id="@+id/settings_toolbar"
android:paddingTop="@dimen/navbar_height"
tools:title="Overlord"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/primaryGrayBackground"
android:paddingTop="@dimen/navbar_height"
app:layout_scrollFlags="scroll|enterAlways"
app:menu="@menu/repository"
app:navigationIconTint="?attr/iconColor"
app:titleTextColor="?attr/textColor"
app:layout_scrollFlags="scroll|enterAlways"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
tools:title="Overlord" />
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/primaryGrayBackground"
android:clipToPadding="true"
android:fadingEdge="horizontal"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:requiresFadingEdge="horizontal"
app:layout_scrollFlags="scroll|enterAlways">
<!-- Man what the fuck we need a recyclerview -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<!-- android:minWidth="0dp"
app:iconTint="?attr/textColor"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
app:iconGravity="textStart"
app:iconPadding="0dp"
android:layout_height="35dp"-->
<!-- <com.google.android.material.button.MaterialButton
android:nextFocusRight="@id/home_select_tv_series"
app:icon="@drawable/ic_baseline_close_24"
android:id="@+id/home_select_none"
style="@style/RoundedSelectableButtonIcon"/>-->
<com.google.android.material.button.MaterialButton
android:id="@+id/home_select_movies"
style="@style/RoundedSelectableButton"
android:nextFocusRight="@id/home_select_tv_series"
android:text="@string/movies" />
<com.google.android.material.button.MaterialButton
android:id="@+id/home_select_tv_series"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/home_select_movies"
android:nextFocusRight="@id/home_select_anime"
android:text="@string/tv_series" />
<com.google.android.material.button.MaterialButton
android:id="@+id/home_select_anime"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/home_select_tv_series"
android:nextFocusRight="@id/home_select_asian"
android:text="@string/anime" />
<com.google.android.material.button.MaterialButton
android:id="@+id/home_select_asian"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/home_select_anime"
android:nextFocusRight="@id/home_select_cartoons"
android:text="@string/asian_drama" />
<com.google.android.material.button.MaterialButton
android:id="@+id/home_select_cartoons"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/home_select_asian"
android:nextFocusRight="@id/home_select_documentaries"
android:text="@string/cartoons" />
<com.google.android.material.button.MaterialButton
android:id="@+id/home_select_documentaries"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/home_select_cartoons"
android:text="@string/documentaries" />
<com.google.android.material.button.MaterialButton
android:id="@+id/home_select_livestreams"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/home_select_documentaries"
android:text="@string/livestreams" />
</LinearLayout>
</HorizontalScrollView>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:listitem="@layout/repository_item"
android:id="@+id/plugin_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:listitem="@layout/repository_item" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -31,6 +31,8 @@
android:paddingEnd="10dp"
android:requiresFadingEdge="horizontal">
<!-- Man what the fuck we need a recyclerview -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"