mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master'
# Conflicts: # app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt
This commit is contained in:
		
						commit
						d64bf911e8
					
				
					 25 changed files with 368 additions and 129 deletions
				
			
		|  | @ -555,6 +555,7 @@ enum class TvType { | |||
|     Documentary, | ||||
|     AsianDrama, | ||||
|     Live, | ||||
|     Others | ||||
| } | ||||
| 
 | ||||
| // IN CASE OF FUTURE ANIME MOVIE OR SMTH | ||||
|  |  | |||
|  | @ -424,71 +424,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { | |||
| 
 | ||||
|     override fun onCreate(savedInstanceState: Bundle?) { | ||||
|         app.initClient(this) | ||||
| 
 | ||||
|         // Parallelize to speed up startup | ||||
|         ioSafe { | ||||
|             val settingsManager = PreferenceManager.getDefaultSharedPreferences(this@MainActivity) | ||||
|             if (settingsManager.getBoolean(getString(R.string.auto_update_plugins_key), true)) { | ||||
|                 PluginManager.updateAllOnlinePluginsAndLoadThem(this@MainActivity) | ||||
|             } else { | ||||
|                 PluginManager.loadAllOnlinePlugins(this@MainActivity) | ||||
|             } | ||||
| 
 | ||||
|             PluginManager.loadAllLocalPlugins(this@MainActivity) | ||||
|         } | ||||
| 
 | ||||
| //        ioSafe { | ||||
| //            val plugins = | ||||
| //                RepositoryParser.getRepoPlugins("https://raw.githubusercontent.com/recloudstream/TestPlugin/master/repo.json") | ||||
| //                    ?: emptyList() | ||||
| //            plugins.map { | ||||
| //                println("Load plugin: ${it.name} ${it.url}") | ||||
| //                RepositoryParser.loadSiteTemp(applicationContext, it.url, it.name) | ||||
| //            } | ||||
| //        } | ||||
| 
 | ||||
|         // init accounts | ||||
|         ioSafe { | ||||
|             for (api in accountManagers) { | ||||
|                 api.init() | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         ioSafe { | ||||
|             inAppAuths.apmap { api -> | ||||
|                 try { | ||||
|                     api.initialize() | ||||
|                 } catch (e: Exception) { | ||||
|                     logError(e) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         SearchResultBuilder.updateCache(this) | ||||
| 
 | ||||
|         ioSafe { | ||||
|             initAll() | ||||
|             apis = allProviders | ||||
|             try { | ||||
|                 getKey<Array<SettingsGeneral.CustomSite>>(USER_PROVIDER_API)?.let { list -> | ||||
|                     list.forEach { custom -> | ||||
|                         allProviders.firstOrNull { it.javaClass.simpleName == custom.parentJavaClass } | ||||
|                             ?.let { | ||||
|                                 allProviders.add(it.javaClass.newInstance().apply { | ||||
|                                     name = custom.name | ||||
|                                     lang = custom.lang | ||||
|                                     mainUrl = custom.url.trimEnd('/') | ||||
|                                     canBeOverridden = false | ||||
|                                 }) | ||||
|                             } | ||||
|                     } | ||||
|                 } | ||||
|                 apis = allProviders | ||||
|                 APIHolder.apiMap = null | ||||
|             } catch (e: Exception) { | ||||
|                 logError(e) | ||||
|             } | ||||
|         } | ||||
|         val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) | ||||
| 
 | ||||
|         loadThemes(this) | ||||
|         updateLocale() | ||||
|  | @ -511,6 +447,65 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { | |||
| 
 | ||||
|         changeStatusBarState(isEmulatorSettings()) | ||||
| 
 | ||||
|         if (settingsManager.getBoolean(getString(R.string.auto_update_plugins_key), true)) { | ||||
|             PluginManager.updateAllOnlinePluginsAndLoadThem(this) | ||||
|         } else { | ||||
|             PluginManager.loadAllOnlinePlugins(this) | ||||
|         } | ||||
| 
 | ||||
|         PluginManager.loadAllLocalPlugins(this) | ||||
| 
 | ||||
| //        ioSafe { | ||||
| //            val plugins = | ||||
| //                RepositoryParser.getRepoPlugins("https://raw.githubusercontent.com/recloudstream/TestPlugin/master/repo.json") | ||||
| //                    ?: emptyList() | ||||
| //            plugins.map { | ||||
| //                println("Load plugin: ${it.name} ${it.url}") | ||||
| //                RepositoryParser.loadSiteTemp(applicationContext, it.url, it.name) | ||||
| //            } | ||||
| //        } | ||||
| 
 | ||||
|         // init accounts | ||||
|         for (api in accountManagers) { | ||||
|             api.init() | ||||
|         } | ||||
| 
 | ||||
|         ioSafe { | ||||
|             inAppAuths.apmap { api -> | ||||
|                 try { | ||||
|                     api.initialize() | ||||
|                 } catch (e: Exception) { | ||||
|                     logError(e) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         SearchResultBuilder.updateCache(this) | ||||
| 
 | ||||
| 
 | ||||
|         initAll() | ||||
|         apis = allProviders | ||||
| 
 | ||||
|         try { | ||||
|             getKey<Array<SettingsGeneral.CustomSite>>(USER_PROVIDER_API)?.let { list -> | ||||
|                 list.forEach { custom -> | ||||
|                     allProviders.firstOrNull { it.javaClass.simpleName == custom.parentJavaClass } | ||||
|                         ?.let { | ||||
|                             allProviders.add(it.javaClass.newInstance().apply { | ||||
|                                 name = custom.name | ||||
|                                 lang = custom.lang | ||||
|                                 mainUrl = custom.url.trimEnd('/') | ||||
|                                 canBeOverridden = false | ||||
|                             }) | ||||
|                         } | ||||
|                 } | ||||
|             } | ||||
|             apis = allProviders | ||||
|             APIHolder.apiMap = null | ||||
|         } catch (e: Exception) { | ||||
|             logError(e) | ||||
|         } | ||||
| 
 | ||||
|         //  val navView: BottomNavigationView = findViewById(R.id.nav_view) | ||||
|         setUpBackup() | ||||
| 
 | ||||
|  | @ -658,7 +653,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { | |||
| 
 | ||||
|         handleAppIntent(intent) | ||||
| 
 | ||||
|         ioSafe { | ||||
|         thread { | ||||
|             runAutoUpdate() | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -42,6 +42,7 @@ import com.lagradost.cloudstream3.ui.AutofitRecyclerView | |||
| import com.lagradost.cloudstream3.ui.WatchType | ||||
| import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment | ||||
| import com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST | ||||
| import com.lagradost.cloudstream3.ui.result.setLinearListLayout | ||||
| import com.lagradost.cloudstream3.ui.search.* | ||||
| import com.lagradost.cloudstream3.ui.search.SearchHelper.handleSearchClickCallback | ||||
| import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings | ||||
|  | @ -251,6 +252,7 @@ class HomeFragment : Fragment() { | |||
|             movies: MaterialButton?, | ||||
|             asian: MaterialButton?, | ||||
|             livestream: MaterialButton?, | ||||
|             others: MaterialButton?, | ||||
|         ): List<Pair<MaterialButton?, List<TvType>>> { | ||||
|             return listOf( | ||||
|                 Pair(anime, listOf(TvType.Anime, TvType.OVA, TvType.AnimeMovie)), | ||||
|  | @ -260,6 +262,7 @@ class HomeFragment : Fragment() { | |||
|                 Pair(movies, listOf(TvType.Movie, TvType.Torrent)), | ||||
|                 Pair(asian, listOf(TvType.AsianDrama)), | ||||
|                 Pair(livestream, listOf(TvType.Live)), | ||||
|                 Pair(others, listOf(TvType.Others)), | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|  | @ -294,10 +297,11 @@ class HomeFragment : Fragment() { | |||
|                 val movies = dialog.findViewById<MaterialButton>(R.id.home_select_movies) | ||||
|                 val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian) | ||||
|                 val livestream = dialog.findViewById<MaterialButton>(R.id.home_select_livestreams) | ||||
|                 val others = dialog.findViewById<MaterialButton>(R.id.home_select_others) | ||||
|                 val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt) | ||||
|                 val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt) | ||||
| 
 | ||||
|                 val pairList = getPairList(anime, cartoons, tvs, docs, movies, asian, livestream) | ||||
|                 val pairList = getPairList(anime, cartoons, tvs, docs, movies, asian, livestream, others) | ||||
| 
 | ||||
|                 cancelBtt?.setOnClickListener { | ||||
|                     dialog.dismissSafe() | ||||
|  | @ -519,6 +523,16 @@ class HomeFragment : Fragment() { | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         home_main_poster_recyclerview?.adapter = | ||||
|             HomeChildItemAdapter( | ||||
|                 mutableListOf(), | ||||
|                 R.layout.home_result_big_grid, | ||||
|                 nextFocusUp = home_main_poster_recyclerview.nextFocusUpId, | ||||
|                 nextFocusDown = home_main_poster_recyclerview.nextFocusDownId | ||||
|             ) { callback -> | ||||
|                 homeHandleSearch(callback) | ||||
|             } | ||||
|         home_main_poster_recyclerview.setLinearListLayout() | ||||
|         observe(homeViewModel.randomItems) { items -> | ||||
|             if (items.isNullOrEmpty()) { | ||||
|                 toggleMainVisibility(false) | ||||
|  | @ -531,15 +545,7 @@ class HomeFragment : Fragment() { | |||
|                 } | ||||
| 
 | ||||
|                 val randomSize = items.size | ||||
|                 home_main_poster_recyclerview?.adapter = | ||||
|                     HomeChildItemAdapter( | ||||
|                         items.toMutableList(), | ||||
|                         R.layout.home_result_big_grid, | ||||
|                         nextFocusUp = home_main_poster_recyclerview.nextFocusUpId, | ||||
|                         nextFocusDown = home_main_poster_recyclerview.nextFocusDownId | ||||
|                     ) { callback -> | ||||
|                         homeHandleSearch(callback) | ||||
|                     } | ||||
|                 tempAdapter?.updateList(items) | ||||
|                 if (context?.isTvSettings() == false) { | ||||
|                     home_main_poster_recyclerview?.post { | ||||
|                         (home_main_poster_recyclerview?.layoutManager as CenterZoomLayoutManager?)?.let { manager -> | ||||
|  | @ -813,6 +819,8 @@ class HomeFragment : Fragment() { | |||
|                 homeHandleSearch(callback) | ||||
|             } | ||||
|         } | ||||
|         home_watch_child_recyclerview.setLinearListLayout() | ||||
|         home_bookmarked_child_recyclerview.setLinearListLayout() | ||||
| 
 | ||||
|         home_watch_child_recyclerview?.adapter = HomeChildItemAdapter( | ||||
|             ArrayList(), | ||||
|  | @ -901,6 +909,7 @@ class HomeFragment : Fragment() { | |||
|             }, { name -> | ||||
|                 homeViewModel.expand(name) | ||||
|             }) | ||||
|         home_master_recycler.setLinearListLayout() | ||||
|         home_master_recycler?.setMaxViewPoolSize(0, Int.MAX_VALUE) | ||||
|         home_master_recycler.layoutManager = object : LinearLayoutManager(context) { | ||||
|             override fun supportsPredictiveItemAnimations(): Boolean { | ||||
|  |  | |||
|  | @ -10,6 +10,8 @@ import androidx.recyclerview.widget.ListUpdateCallback | |||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import com.lagradost.cloudstream3.HomePageList | ||||
| import com.lagradost.cloudstream3.R | ||||
| import com.lagradost.cloudstream3.ui.result.LinearListLayout | ||||
| import com.lagradost.cloudstream3.ui.result.setLinearListLayout | ||||
| import com.lagradost.cloudstream3.ui.search.SearchClickCallback | ||||
| import com.lagradost.cloudstream3.ui.search.SearchFragment.Companion.filterSearchResponse | ||||
| import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings | ||||
|  | @ -153,6 +155,7 @@ class ParentItemAdapter( | |||
|                 ).apply { | ||||
|                     isHorizontal = info.isHorizontalImages | ||||
|                 } | ||||
|                 recyclerView.setLinearListLayout() | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | @ -167,7 +170,7 @@ class ParentItemAdapter( | |||
|                 isHorizontal = info.isHorizontalImages | ||||
|                 hasNext = expand.hasNext | ||||
|             } | ||||
| 
 | ||||
|             recyclerView.setLinearListLayout() | ||||
|             title.text = info.name | ||||
| 
 | ||||
|             recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ import android.annotation.SuppressLint | |||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import android.widget.FrameLayout | ||||
| import android.widget.ImageView | ||||
| import android.widget.TextView | ||||
| import androidx.annotation.LayoutRes | ||||
|  | @ -75,9 +76,12 @@ class EpisodeAdapter( | |||
|     } | ||||
| 
 | ||||
|     override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) { | ||||
|         if(holder.itemView.hasFocus()) { | ||||
|         if (holder.itemView.hasFocus()) { | ||||
|             holder.itemView.clearFocus() | ||||
|         } | ||||
|         //(holder.itemView as? FrameLayout?)?.descendantFocusability = | ||||
|         //    ViewGroup.FOCUS_BLOCK_DESCENDANTS | ||||
| 
 | ||||
|         if (holder is DownloadButtonViewHolder) { | ||||
|             holder.downloadButton.dispose() | ||||
|         } | ||||
|  | @ -87,11 +91,20 @@ class EpisodeAdapter( | |||
|         if (holder is DownloadButtonViewHolder) { | ||||
|             holder.downloadButton.dispose() | ||||
|             mBoundViewHolders.remove(holder) | ||||
|             //(holder.itemView as? FrameLayout?)?.descendantFocusability = | ||||
|             //    ViewGroup.FOCUS_BLOCK_DESCENDANTS | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) { | ||||
|         if (holder is DownloadButtonViewHolder) { | ||||
|             //println("onViewAttachedToWindow = ${holder.absoluteAdapterPosition}") | ||||
|             //holder.itemView.post { | ||||
|             //    if (holder.itemView.isAttachedToWindow) | ||||
|             //        (holder.itemView as? FrameLayout?)?.descendantFocusability = | ||||
|             //            ViewGroup.FOCUS_AFTER_DESCENDANTS | ||||
|             //} | ||||
| 
 | ||||
|             holder.reattachDownloadButton() | ||||
|         } | ||||
|     } | ||||
|  | @ -145,7 +158,6 @@ class EpisodeAdapter( | |||
|     ) : RecyclerView.ViewHolder(itemView), DownloadButtonViewHolder { | ||||
|         override var downloadButton = EasyDownloadButton() | ||||
| 
 | ||||
| 
 | ||||
|         var episodeDownloadBar: ContentLoadingProgressBar? = null | ||||
|         var episodeDownloadImage: ImageView? = null | ||||
|         var localCard: ResultEpisode? = null | ||||
|  | @ -217,17 +229,17 @@ class EpisodeAdapter( | |||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             parentView.setOnClickListener { | ||||
|             itemView.setOnClickListener { | ||||
|                 clickCallback.invoke(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card)) | ||||
|             } | ||||
| 
 | ||||
|             if (isTrueTv) { | ||||
|                 parentView.isFocusable = true | ||||
|                 parentView.isFocusableInTouchMode = true | ||||
|                 parentView.touchscreenBlocksFocus = false | ||||
|                 itemView.isFocusable = true | ||||
|                 itemView.isFocusableInTouchMode = true | ||||
|                 //itemView.touchscreenBlocksFocus = false | ||||
|             } | ||||
| 
 | ||||
|             parentView.setOnLongClickListener { | ||||
|             itemView.setOnLongClickListener { | ||||
|                 clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card)) | ||||
| 
 | ||||
|                 return@setOnLongClickListener true | ||||
|  | @ -242,6 +254,9 @@ class EpisodeAdapter( | |||
|             downloadButton.dispose() | ||||
|             val card = localCard | ||||
|             if (hasDownloadSupport && card != null) { | ||||
|                 if (episodeDownloadBar == null || | ||||
|                     episodeDownloadImage == null | ||||
|                 ) return | ||||
|                 val downloadInfo = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings( | ||||
|                     itemView.context, | ||||
|                     card.id | ||||
|  |  | |||
|  | @ -0,0 +1,129 @@ | |||
| package com.lagradost.cloudstream3.ui.result | ||||
| 
 | ||||
| import android.content.Context | ||||
| import android.view.View | ||||
| import androidx.recyclerview.widget.LinearLayoutManager | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import com.lagradost.cloudstream3.mvvm.logError | ||||
| 
 | ||||
| fun RecyclerView?.setLinearListLayout(isHorizontal: Boolean = true) { | ||||
|     if(this == null) return | ||||
|     this.layoutManager = | ||||
|         this.context?.let { LinearListLayout(it).apply { if (isHorizontal) setHorizontal() else setVertical() } } | ||||
|             ?: this.layoutManager | ||||
| } | ||||
| 
 | ||||
| class LinearListLayout(context: Context?) : | ||||
|     LinearLayoutManager(context) { | ||||
| 
 | ||||
|     fun setHorizontal() { | ||||
|         orientation = HORIZONTAL | ||||
|     } | ||||
| 
 | ||||
|     fun setVertical() { | ||||
|         orientation = VERTICAL | ||||
|     } | ||||
| 
 | ||||
|     private fun getCorrectParent(focused: View): View? { | ||||
|         var current: View? = focused | ||||
|         val last: ArrayList<View> = arrayListOf(focused) | ||||
|         while (current != null && current !is RecyclerView) { | ||||
|             current = (current.parent as? View?)?.also { last.add(it) } | ||||
|         } | ||||
|         return last.getOrNull(last.count() - 2) | ||||
|     } | ||||
| 
 | ||||
|     private fun getPosition(view: View?): Int? { | ||||
|         return (view?.layoutParams as? RecyclerView.LayoutParams?)?.absoluteAdapterPosition | ||||
|     } | ||||
| 
 | ||||
|     private fun getViewFromPos(pos: Int): View? { | ||||
|         for (i in 0 until childCount) { | ||||
|             val child = getChildAt(i) | ||||
|             if ((child?.layoutParams as? RecyclerView.LayoutParams?)?.absoluteAdapterPosition == pos) { | ||||
|                 return child | ||||
|             } | ||||
|         } | ||||
|         return null | ||||
|         //return recyclerView.children.firstOrNull { child -> (child.layoutParams as? RecyclerView.LayoutParams?)?.absoluteAdapterPosition == pos) } | ||||
|     } | ||||
| 
 | ||||
|     /* | ||||
|     private fun scrollTo(position: Int) { | ||||
|         val linearSmoothScroller = LinearSmoothScroller(recyclerView.context) | ||||
|         linearSmoothScroller.targetPosition = position | ||||
|         startSmoothScroll(linearSmoothScroller) | ||||
|     }*/ | ||||
| 
 | ||||
|     override fun onInterceptFocusSearch(focused: View, direction: Int): View? { | ||||
|         val dir = if (orientation == HORIZONTAL) { | ||||
|             if (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP) return null | ||||
|             if (direction == View.FOCUS_RIGHT) 1 else -1 | ||||
|         } else { | ||||
|             if (direction == View.FOCUS_RIGHT || direction == View.FOCUS_LEFT) return null | ||||
|             if (direction == View.FOCUS_DOWN) 1 else -1 | ||||
|         } | ||||
| 
 | ||||
|         return try { | ||||
|             getPosition(getCorrectParent(focused))?.let { position -> | ||||
|                 val lookfor = dir + position | ||||
|                 //clamp(dir + position, 0, recyclerView.adapter?.itemCount ?: return null) | ||||
|                 getViewFromPos(lookfor) ?: run { | ||||
|                     scrollToPosition(lookfor) | ||||
|                     null | ||||
|                 } | ||||
|             } | ||||
|         } catch (e: Exception) { | ||||
|             logError(e) | ||||
|             null | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /*override fun onRequestChildFocus( | ||||
|         parent: RecyclerView, | ||||
|         state: RecyclerView.State, | ||||
|         child: View, | ||||
|         focused: View? | ||||
|     ): Boolean { | ||||
|         return super.onRequestChildFocus(parent, state, child, focused) | ||||
|         getPosition(getCorrectParent(focused ?: return true))?.let { | ||||
|             val startView = findFirstVisibleChildClosestToStart(true,true) | ||||
|             val endView = findFirstVisibleChildClosestToEnd(true,true) | ||||
|             val start = getPosition(startView) | ||||
|             val end = getPosition(endView) | ||||
|             fill(parent,LayoutState()) | ||||
| 
 | ||||
|             val helper = mOrientationHelper ?: return false | ||||
|             val laidOutArea: Int = abs( | ||||
|                 helper.getDecoratedEnd(startView) | ||||
|                         - helper.getDecoratedStart(endView) | ||||
|             ) | ||||
|             val itemRange: Int = abs( | ||||
|                 (start | ||||
|                         - end) | ||||
|             ) + 1 | ||||
| 
 | ||||
|             val avgSizePerRow = laidOutArea.toFloat() / itemRange | ||||
| 
 | ||||
|             return Math.round( | ||||
|                 itemsBefore * avgSizePerRow + ((orientation.getStartAfterPadding() | ||||
|                         - orientation.getDecoratedStart(startChild))) | ||||
|             ) | ||||
|             recyclerView.scrollToPosition(it) | ||||
|         } | ||||
|         return true*/ | ||||
| 
 | ||||
|     //return super.onRequestChildFocus(parent, state, child, focused) | ||||
|     /* if (focused == null || focused == child) { | ||||
|          return super.onRequestChildFocus(parent, state, child, focused) | ||||
|      } | ||||
| 
 | ||||
|      try { | ||||
|          val pos = getPosition(getCorrectParent(focused) ?: return true) | ||||
|          scrollToPosition(pos) | ||||
|      } catch (e: Exception) { | ||||
|          logError(e) | ||||
|      } | ||||
|      return true | ||||
| }*/ | ||||
| } | ||||
|  | @ -471,31 +471,6 @@ open class ResultFragment : ResultTrailerPlayer() { | |||
|         syncModel.addFromUrl(url) | ||||
| 
 | ||||
|         val api = getApiFromName(apiName) | ||||
|         if (media_route_button != null) { | ||||
|             val chromecastSupport = api.hasChromecastSupport | ||||
|             media_route_button?.alpha = if (chromecastSupport) 1f else 0.3f | ||||
|             if (!chromecastSupport) { | ||||
|                 media_route_button?.setOnClickListener { | ||||
|                     showToast(activity, R.string.no_chromecast_support_toast, Toast.LENGTH_LONG) | ||||
|                 } | ||||
|             } | ||||
|             activity?.let { act -> | ||||
|                 if (act.isCastApiAvailable()) { | ||||
|                     try { | ||||
|                         CastButtonFactory.setUpMediaRouteButton(act, media_route_button) | ||||
|                         val castContext = CastContext.getSharedInstance(act.applicationContext) | ||||
|                         media_route_button?.isGone = | ||||
|                             castContext.castState == CastState.NO_DEVICES_AVAILABLE | ||||
|                         // this shit leaks for some reason | ||||
|                         //castContext.addCastStateListener { state -> | ||||
|                         //    media_route_button?.isGone = state == CastState.NO_DEVICES_AVAILABLE | ||||
|                         //} | ||||
|                     } catch (e: Exception) { | ||||
|                         logError(e) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         result_episodes?.adapter = | ||||
|             EpisodeAdapter( | ||||
|  |  | |||
|  | @ -5,23 +5,26 @@ import android.graphics.Rect | |||
| import android.os.Bundle | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import android.widget.Toast | ||||
| import androidx.core.view.isGone | ||||
| import androidx.core.view.isVisible | ||||
| import androidx.core.widget.NestedScrollView | ||||
| import com.discord.panels.OverlappingPanelsLayout | ||||
| import com.discord.panels.PanelsChildGestureRegionObserver | ||||
| import com.google.android.gms.cast.framework.CastButtonFactory | ||||
| import com.google.android.gms.cast.framework.CastContext | ||||
| import com.google.android.gms.cast.framework.CastState | ||||
| import com.google.android.material.bottomsheet.BottomSheetDialog | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.APIHolder.updateHasTrailers | ||||
| import com.lagradost.cloudstream3.DubStatus | ||||
| import com.lagradost.cloudstream3.LoadResponse | ||||
| import com.lagradost.cloudstream3.R | ||||
| import com.lagradost.cloudstream3.SearchResponse | ||||
| import com.lagradost.cloudstream3.mvvm.Some | ||||
| import com.lagradost.cloudstream3.mvvm.logError | ||||
| import com.lagradost.cloudstream3.mvvm.observe | ||||
| import com.lagradost.cloudstream3.ui.WatchType | ||||
| import com.lagradost.cloudstream3.ui.player.CSPlayerEvent | ||||
| import com.lagradost.cloudstream3.ui.search.SearchAdapter | ||||
| import com.lagradost.cloudstream3.ui.search.SearchHelper | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.openBrowser | ||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | ||||
| import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog | ||||
|  | @ -125,6 +128,8 @@ class ResultFragmentPhone : ResultFragment() { | |||
|     } | ||||
| 
 | ||||
|     override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||||
|         val apiName = arguments?.getString(API_NAME_BUNDLE) ?: return | ||||
| 
 | ||||
|         super.onViewCreated(view, savedInstanceState) | ||||
| 
 | ||||
|         player_open_source?.setOnClickListener { | ||||
|  | @ -192,6 +197,37 @@ class ResultFragmentPhone : ResultFragment() { | |||
|             } | ||||
|             //result_poster_blur_holder?.translationY = -scrollY.toFloat() | ||||
|         }) | ||||
|         val api = APIHolder.getApiFromName(apiName) | ||||
| 
 | ||||
|         if (media_route_button != null) { | ||||
|             val chromecastSupport = api.hasChromecastSupport | ||||
|             media_route_button?.alpha = if (chromecastSupport) 1f else 0.3f | ||||
|             if (!chromecastSupport) { | ||||
|                 media_route_button?.setOnClickListener { | ||||
|                     CommonActivity.showToast( | ||||
|                         activity, | ||||
|                         R.string.no_chromecast_support_toast, | ||||
|                         Toast.LENGTH_LONG | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|             activity?.let { act -> | ||||
|                 if (act.isCastApiAvailable()) { | ||||
|                     try { | ||||
|                         CastButtonFactory.setUpMediaRouteButton(act, media_route_button) | ||||
|                         val castContext = CastContext.getSharedInstance(act.applicationContext) | ||||
|                         media_route_button?.isGone = | ||||
|                             castContext.castState == CastState.NO_DEVICES_AVAILABLE | ||||
|                         // this shit leaks for some reason | ||||
|                         //castContext.addCastStateListener { state -> | ||||
|                         //    media_route_button?.isGone = state == CastState.NO_DEVICES_AVAILABLE | ||||
|                         //} | ||||
|                     } catch (e: Exception) { | ||||
|                         logError(e) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         observe(viewModel.episodesCountText) { count -> | ||||
|             result_episodes_text.setText(count) | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ package com.lagradost.cloudstream3.ui.result | |||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import android.view.View | ||||
| import android.widget.LinearLayout | ||||
| import androidx.core.view.isGone | ||||
| import androidx.core.view.isVisible | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
|  | @ -15,10 +16,17 @@ import com.lagradost.cloudstream3.mvvm.Some | |||
| import com.lagradost.cloudstream3.mvvm.observe | ||||
| import com.lagradost.cloudstream3.ui.search.SearchAdapter | ||||
| import com.lagradost.cloudstream3.ui.search.SearchHelper | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.setMaxViewPoolSize | ||||
| import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant | ||||
| import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe | ||||
| import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage | ||||
| import kotlinx.android.synthetic.main.fragment_home.* | ||||
| import kotlinx.android.synthetic.main.fragment_result.* | ||||
| import kotlinx.android.synthetic.main.fragment_result_tv.* | ||||
| import kotlinx.android.synthetic.main.fragment_result_tv.result_episodes | ||||
| import kotlinx.android.synthetic.main.fragment_result_tv.result_episodes_text | ||||
| import kotlinx.android.synthetic.main.fragment_result_tv.result_play_movie | ||||
| import kotlinx.android.synthetic.main.fragment_result_tv.result_root | ||||
| 
 | ||||
| class ResultFragmentTv : ResultFragment() { | ||||
|     override val resultLayout = R.layout.fragment_result_tv | ||||
|  | @ -95,13 +103,21 @@ class ResultFragmentTv : ResultFragment() { | |||
|             result_recommendations_filter_selection?.isVisible = false | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     var loadingDialog: Dialog? = null | ||||
|     var popupDialog: Dialog? = null | ||||
|     override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||||
|         super.onViewCreated(view, savedInstanceState) | ||||
| 
 | ||||
|         result_episodes?.layoutManager = | ||||
|             //LinearListLayout(result_episodes ?: return, result_episodes?.context).apply { | ||||
|             LinearListLayout(result_episodes?.context).apply { | ||||
|                 setHorizontal() | ||||
|             } | ||||
|         (result_episodes?.adapter as EpisodeAdapter?)?.apply { | ||||
|             layout = R.layout.result_episode_both_tv | ||||
|         } | ||||
|         //result_episodes?.setMaxViewPoolSize(0, Int.MAX_VALUE) | ||||
| 
 | ||||
|         result_season_selection.setAdapter() | ||||
|         result_range_selection.setAdapter() | ||||
|  |  | |||
|  | @ -197,6 +197,7 @@ fun LoadResponse.toResultData(repo: APIRepository): ResultData { | |||
|                 TvType.Torrent -> R.string.torrent_singular | ||||
|                 TvType.AsianDrama -> R.string.asian_drama_singular | ||||
|                 TvType.Live -> R.string.live_singular | ||||
|                 TvType.Others -> R.string.other_singular | ||||
|             } | ||||
|         ), | ||||
|         yearText = txt(year?.toString()), | ||||
|  | @ -549,6 +550,7 @@ class ResultViewModel2 : ViewModel() { | |||
|                 TvType.Documentary -> "Documentaries" | ||||
|                 TvType.AsianDrama -> "AsianDrama" | ||||
|                 TvType.Live -> "LiveStreams" | ||||
|                 TvType.Others -> "Others" | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -169,6 +169,7 @@ class SearchFragment : Fragment() { | |||
|                     val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian) | ||||
|                     val livestream = | ||||
|                         dialog.findViewById<MaterialButton>(R.id.home_select_livestreams) | ||||
|                     val other = dialog.findViewById<MaterialButton>(R.id.home_select_others) | ||||
|                     val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt) | ||||
|                     val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt) | ||||
| 
 | ||||
|  | @ -180,7 +181,8 @@ class SearchFragment : Fragment() { | |||
|                             docs, | ||||
|                             movies, | ||||
|                             asian, | ||||
|                             livestream | ||||
|                             livestream, | ||||
|                             other | ||||
|                         ) | ||||
| 
 | ||||
|                     cancelBtt?.setOnClickListener { | ||||
|  | @ -297,7 +299,8 @@ class SearchFragment : Fragment() { | |||
|             search_select_documentaries, | ||||
|             search_select_movies, | ||||
|             search_select_asian, | ||||
|             search_select_livestreams | ||||
|             search_select_livestreams, | ||||
|             search_select_others | ||||
|         ) | ||||
| 
 | ||||
|         val settingsManager = context?.let { PreferenceManager.getDefaultSharedPreferences(it) } | ||||
|  |  | |||
|  | @ -112,7 +112,8 @@ class PluginsFragment : Fragment() { | |||
|                 home_select_documentaries, | ||||
|                 home_select_movies, | ||||
|                 home_select_asian, | ||||
|                 home_select_livestreams | ||||
|                 home_select_livestreams, | ||||
|                 home_select_others | ||||
|             ) | ||||
| 
 | ||||
|             // Copy pasted code | ||||
|  |  | |||
|  | @ -175,7 +175,10 @@ class PluginsViewModel : ViewModel() { | |||
|     // 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 } | ||||
|         return this.filter { | ||||
|             (it.plugin.second.tvTypes?.any { type -> tvTypes.contains(type) } == true) || | ||||
|             (tvTypes.contains("Others") && (it.plugin.second.tvTypes ?: emptyList()).isEmpty()) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun List<PluginViewData>.sortByQuery(query: String?): List<PluginViewData> { | ||||
|  |  | |||
|  | @ -110,6 +110,12 @@ | |||
|                     android:nextFocusLeft="@id/home_select_documentaries" | ||||
|                     android:text="@string/livestreams" /> | ||||
| 
 | ||||
|                 <com.google.android.material.button.MaterialButton | ||||
|                     android:id="@+id/home_select_others" | ||||
|                     style="@style/RoundedSelectableButton" | ||||
|                     android:nextFocusLeft="@id/home_select_livestreams" | ||||
|                     android:text="@string/others" /> | ||||
| 
 | ||||
|             </LinearLayout> | ||||
|         </HorizontalScrollView> | ||||
|     </com.google.android.material.appbar.AppBarLayout> | ||||
|  |  | |||
|  | @ -917,7 +917,7 @@ | |||
|                                     app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" | ||||
|                                     android:descendantFocusability="afterDescendants" | ||||
|                                     android:paddingBottom="100dp" | ||||
|                                     tools:listitem="@layout/result_episode" /> | ||||
|                                     tools:listitem="@layout/result_episode_both_tv" /> | ||||
|                         </LinearLayout> | ||||
|                     </LinearLayout> | ||||
| 
 | ||||
|  |  | |||
|  | @ -146,6 +146,12 @@ | |||
|                 style="@style/RoundedSelectableButton" | ||||
|                 android:nextFocusLeft="@id/search_select_documentaries" | ||||
|                 android:text="@string/livestreams" /> | ||||
| 
 | ||||
|             <com.google.android.material.button.MaterialButton | ||||
|                 android:id="@+id/search_select_others" | ||||
|                 style="@style/RoundedSelectableButton" | ||||
|                 android:nextFocusLeft="@id/search_select_livestreams" | ||||
|                 android:text="@string/others" /> | ||||
|         </LinearLayout> | ||||
|     </HorizontalScrollView> | ||||
| 
 | ||||
|  |  | |||
|  | @ -104,6 +104,12 @@ | |||
|                 android:nextFocusLeft="@id/home_select_documentaries" | ||||
|                 android:text="@string/livestreams" /> | ||||
| 
 | ||||
|             <com.google.android.material.button.MaterialButton | ||||
|                 android:id="@+id/home_select_others" | ||||
|                 style="@style/RoundedSelectableButton" | ||||
|                 android:nextFocusLeft="@id/home_select_livestreams" | ||||
|                 android:text="@string/others" /> | ||||
| 
 | ||||
|         </LinearLayout> | ||||
|     </HorizontalScrollView> | ||||
| 
 | ||||
|  |  | |||
|  | @ -11,7 +11,6 @@ | |||
|         app:cardCornerRadius="@dimen/rounded_image_radius" | ||||
|         app:cardBackgroundColor="@color/transparent" | ||||
|         app:cardElevation="0dp" | ||||
|         android:foreground="@drawable/outline_drawable" | ||||
|         android:layout_marginBottom="5dp"> | ||||
|     <!-- | ||||
|         android:nextFocusLeft="@id/result_episode_download" | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|         android:layout_width="match_parent" | ||||
|         android:foreground="@drawable/outline_drawable" | ||||
|         android:layout_height="wrap_content"> | ||||
| 
 | ||||
|     <include android:visibility="gone" layout="@layout/result_episode" /> | ||||
|  |  | |||
|  | @ -1,8 +1,9 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|         xmlns:tools="http://schemas.android.com/tools" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         xmlns:tools="http://schemas.android.com/tools"> | ||||
|         android:foreground="@drawable/outline_drawable" | ||||
|         android:layout_height="wrap_content"> | ||||
| 
 | ||||
|     <include | ||||
|             tools:visibility="visible" | ||||
|  |  | |||
|  | @ -6,19 +6,18 @@ | |||
|         android:nextFocusRight="@id/result_episode_download" | ||||
|         android:id="@+id/episode_holder_large" | ||||
| 
 | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         app:cardCornerRadius="@dimen/rounded_image_radius" | ||||
|         app:cardBackgroundColor="?attr/boxItemBackground" | ||||
| 
 | ||||
|         android:foreground="@drawable/outline_drawable" | ||||
|         android:layout_marginBottom="10dp"> | ||||
| 
 | ||||
|     <LinearLayout | ||||
|             android:foreground="?android:attr/selectableItemBackgroundBorderless" | ||||
|             android:padding="10dp" | ||||
|             android:orientation="vertical" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content"> | ||||
| 
 | ||||
|         <LinearLayout | ||||
|  |  | |||
|  | @ -11,7 +11,6 @@ | |||
|         app:cardCornerRadius="@dimen/rounded_image_radius" | ||||
|         app:cardBackgroundColor="?attr/boxItemBackground" | ||||
| 
 | ||||
|         android:foreground="@drawable/outline_drawable" | ||||
|         android:layout_marginBottom="10dp"> | ||||
| 
 | ||||
|     <LinearLayout | ||||
|  |  | |||
|  | @ -11,7 +11,6 @@ | |||
|         app:cardCornerRadius="@dimen/rounded_image_radius" | ||||
|         app:cardBackgroundColor="@color/transparent" | ||||
|         app:cardElevation="0dp" | ||||
|         android:foreground="@drawable/outline_drawable" | ||||
|         android:layout_marginBottom="5dp"> | ||||
| 
 | ||||
|     <androidx.core.widget.ContentLoadingProgressBar | ||||
|  |  | |||
|  | @ -42,7 +42,7 @@ | |||
|     <string name="type_re_watching">Ponowne oglądanie</string> | ||||
| 
 | ||||
|     <string name="play_movie_button">Odtwórz film</string> | ||||
|     <string name="play_livestream_button">Odtwórz Livestream</string> | ||||
|     <string name="play_livestream_button">Odtwórz transmisję na żywo</string> | ||||
|     <string name="play_torrent_button">Otwórz torrent</string> | ||||
|     <string name="pick_source">Źródła</string> | ||||
|     <string name="pick_subtitle">Napisy</string> | ||||
|  | @ -60,7 +60,7 @@ | |||
|     <string name="download_canceled">Anulowano pobieranie</string> | ||||
|     <string name="download_done">Zakończono pobieranie</string> | ||||
| 
 | ||||
|     <string name="stream">Streamuj</string> | ||||
|     <string name="stream">Stream</string> | ||||
|     <string name="error_loading_links_toast">Błąd przy ładowaniu linków</string> | ||||
|     <string name="download_storage_text">Pamięć wewnętrzna</string> | ||||
| 
 | ||||
|  | @ -236,7 +236,7 @@ | |||
|     <string name="ova">OVA</string> | ||||
|     <string name="asian_drama">Filmy azjatyckie</string> | ||||
| 
 | ||||
|     <string name="livestreams">Livestreamy</string> | ||||
|     <string name="livestreams">Transmisje na żywo</string> | ||||
|     <string name="movies_singular">Film</string> | ||||
|     <string name="tv_series_singular">Serial telewizyjny</string> | ||||
|     <string name="cartoons_singular">Kreskówka</string> | ||||
|  | @ -396,4 +396,37 @@ | |||
|     <string name="app_layout_subtext">Dostosuj wygląd aplikacji do urządzenia</string> | ||||
|     <string name="preferred_media_subtext">Preferowany rodzaj filmów</string> | ||||
|     <string name="setup_done">Gotowe</string> | ||||
|     <string name="extras">Dodatki</string> | ||||
|     <string name="trailer">Zwiastun</string> | ||||
|     <string name="play_with_app_name">Odtwórz w CloudStream</string> | ||||
|     <string name="live_singular">Transmisja na żywo</string> | ||||
|     <string name="network_adress_example">Link to streamu</string> | ||||
|     <string name="referer">Odsyłacz</string> | ||||
|     <string name="crash_reporting_title">Przekazywanie błędów</string> | ||||
|     <string name="automatic_plugin_updates">Automatyczne aktualizacje rozszerzeń</string> | ||||
|     <string name="extensions">Rozszerzenia</string> | ||||
|     <string name="add_repository">Dodaj repozytorium</string> | ||||
|     <string name="repository_name_hint">Nazwa repozytorium</string> | ||||
|     <string name="repository_url_hint">Adres url repozytorium</string> | ||||
|     <string name="plugin_loaded">Rozszerzenie załadowane</string> | ||||
|     <string name="plugin_deleted">Rozszerzenie usunięte</string> | ||||
|     <string name="plugin_load_fail">Błąd ładowania %s</string> | ||||
|     <string name="is_adult">+18</string> | ||||
|     <string name="batch_download_start_format">Zaczęto pobieranie %d %s</string> | ||||
|     <string name="batch_download_finish_format">Pobrano %d %s</string> | ||||
|     <string name="batch_download_nothing_to_download_format">Wszystkie %s już pobrane</string> | ||||
|     <string name="batch_download">Pobierz wszystko</string> | ||||
|     <string name="plugin_singular">rozszerzenie</string> | ||||
|     <string name="plugin">rozszerzenia</string> | ||||
|     <string name="delete_repository_plugins">Ta akcja usunie także wszystkie rozszerzenia z repozytorium</string> | ||||
|     <string name="delete_repository">Usuń repozytorium</string> | ||||
|     <string name="setup_extensions_subtext">Pobierz strony które Cię interesują</string> | ||||
|     <string name="plugins_downloaded">Pobrano: %d</string> | ||||
|     <string name="plugins_disabled">Wyłączono: %d</string> | ||||
|     <string name="plugins_not_downloaded">Nie pobrano: %d</string> | ||||
|     <string name="blank_repo_message">Dodaj repozytorium aby zainstalować rozszerzenia</string> | ||||
|     <string name="sync_score">Ocenione</string> | ||||
|     <string name="sync_score_format">%d na 10</string> | ||||
|     <string name="others">Inne</string> | ||||
|     <string name="other_singular">Wideo</string> | ||||
| </resources> | ||||
|  |  | |||
|  | @ -333,6 +333,7 @@ | |||
|     <string name="ova">OVA</string> | ||||
|     <string name="asian_drama">Asian Dramas</string> | ||||
|     <string name="livestreams">Livestreams</string> | ||||
|     <string name="others">Others</string> | ||||
| 
 | ||||
|     <!--singular--> | ||||
|     <string name="movies_singular">Movie</string> | ||||
|  | @ -344,6 +345,7 @@ | |||
|     <string name="documentaries_singular">Documentary</string> | ||||
|     <string name="asian_drama_singular">Asian Drama</string> | ||||
|     <string name="live_singular">Livestream</string> | ||||
|     <string name="other_singular">Video</string> | ||||
| 
 | ||||
|     <string name="source_error">Source error</string> | ||||
|     <string name="remote_error">Remote error</string> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue