mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	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…
	
	Add table
		Add a link
		
	
		Reference in a new issue