forked from recloudstream/cloudstream
Add tv type support
This commit is contained in:
parent
b7a11048f0
commit
bcfa3cff77
6 changed files with 203 additions and 44 deletions
|
@ -56,6 +56,7 @@ data class PluginData(
|
|||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,20 +197,10 @@ 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)
|
||||
}
|
||||
}
|
||||
_plugins.postValue(newValue)
|
||||
currentQuery = query
|
||||
_filteredPlugins.postValue(filteredPlugins.value?.sortByQuery(query))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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))
|
||||
}
|
||||
}
|
|
@ -1,38 +1,125 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/extensions_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/extensions_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
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_width="match_parent"
|
||||
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:background="?attr/primaryGrayBackground"
|
||||
app:navigationIconTint="?attr/iconColor"
|
||||
app:titleTextColor="?attr/textColor"
|
||||
app:layout_scrollFlags="scroll|enterAlways"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
android:id="@+id/settings_toolbar"
|
||||
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"
|
||||
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" />
|
||||
android:id="@+id/plugin_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:listitem="@layout/repository_item" />
|
||||
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue