Merge remote-tracking branch 'origin/master'

# Conflicts:
#	app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt
This commit is contained in:
Blatzar 2022-08-14 18:09:47 +02:00
commit d64bf911e8
25 changed files with 368 additions and 129 deletions

View File

@ -555,6 +555,7 @@ enum class TvType {
Documentary, Documentary,
AsianDrama, AsianDrama,
Live, Live,
Others
} }
// IN CASE OF FUTURE ANIME MOVIE OR SMTH // IN CASE OF FUTURE ANIME MOVIE OR SMTH

View File

@ -424,71 +424,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
app.initClient(this) app.initClient(this)
val settingsManager = PreferenceManager.getDefaultSharedPreferences(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)
}
}
loadThemes(this) loadThemes(this)
updateLocale() updateLocale()
@ -511,6 +447,65 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
changeStatusBarState(isEmulatorSettings()) 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) // val navView: BottomNavigationView = findViewById(R.id.nav_view)
setUpBackup() setUpBackup()
@ -658,7 +653,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
handleAppIntent(intent) handleAppIntent(intent)
ioSafe { thread {
runAutoUpdate() runAutoUpdate()
} }

View File

@ -42,6 +42,7 @@ import com.lagradost.cloudstream3.ui.AutofitRecyclerView
import com.lagradost.cloudstream3.ui.WatchType import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
import com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST 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.*
import com.lagradost.cloudstream3.ui.search.SearchHelper.handleSearchClickCallback import com.lagradost.cloudstream3.ui.search.SearchHelper.handleSearchClickCallback
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
@ -251,6 +252,7 @@ class HomeFragment : Fragment() {
movies: MaterialButton?, movies: MaterialButton?,
asian: MaterialButton?, asian: MaterialButton?,
livestream: MaterialButton?, livestream: MaterialButton?,
others: MaterialButton?,
): List<Pair<MaterialButton?, List<TvType>>> { ): List<Pair<MaterialButton?, List<TvType>>> {
return listOf( return listOf(
Pair(anime, listOf(TvType.Anime, TvType.OVA, TvType.AnimeMovie)), Pair(anime, listOf(TvType.Anime, TvType.OVA, TvType.AnimeMovie)),
@ -260,6 +262,7 @@ class HomeFragment : Fragment() {
Pair(movies, listOf(TvType.Movie, TvType.Torrent)), Pair(movies, listOf(TvType.Movie, TvType.Torrent)),
Pair(asian, listOf(TvType.AsianDrama)), Pair(asian, listOf(TvType.AsianDrama)),
Pair(livestream, listOf(TvType.Live)), 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 movies = dialog.findViewById<MaterialButton>(R.id.home_select_movies)
val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian) val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian)
val livestream = dialog.findViewById<MaterialButton>(R.id.home_select_livestreams) 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 cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_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 { cancelBtt?.setOnClickListener {
dialog.dismissSafe() 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 -> observe(homeViewModel.randomItems) { items ->
if (items.isNullOrEmpty()) { if (items.isNullOrEmpty()) {
toggleMainVisibility(false) toggleMainVisibility(false)
@ -531,15 +545,7 @@ class HomeFragment : Fragment() {
} }
val randomSize = items.size val randomSize = items.size
home_main_poster_recyclerview?.adapter = tempAdapter?.updateList(items)
HomeChildItemAdapter(
items.toMutableList(),
R.layout.home_result_big_grid,
nextFocusUp = home_main_poster_recyclerview.nextFocusUpId,
nextFocusDown = home_main_poster_recyclerview.nextFocusDownId
) { callback ->
homeHandleSearch(callback)
}
if (context?.isTvSettings() == false) { if (context?.isTvSettings() == false) {
home_main_poster_recyclerview?.post { home_main_poster_recyclerview?.post {
(home_main_poster_recyclerview?.layoutManager as CenterZoomLayoutManager?)?.let { manager -> (home_main_poster_recyclerview?.layoutManager as CenterZoomLayoutManager?)?.let { manager ->
@ -813,6 +819,8 @@ class HomeFragment : Fragment() {
homeHandleSearch(callback) homeHandleSearch(callback)
} }
} }
home_watch_child_recyclerview.setLinearListLayout()
home_bookmarked_child_recyclerview.setLinearListLayout()
home_watch_child_recyclerview?.adapter = HomeChildItemAdapter( home_watch_child_recyclerview?.adapter = HomeChildItemAdapter(
ArrayList(), ArrayList(),
@ -901,6 +909,7 @@ class HomeFragment : Fragment() {
}, { name -> }, { name ->
homeViewModel.expand(name) homeViewModel.expand(name)
}) })
home_master_recycler.setLinearListLayout()
home_master_recycler?.setMaxViewPoolSize(0, Int.MAX_VALUE) home_master_recycler?.setMaxViewPoolSize(0, Int.MAX_VALUE)
home_master_recycler.layoutManager = object : LinearLayoutManager(context) { home_master_recycler.layoutManager = object : LinearLayoutManager(context) {
override fun supportsPredictiveItemAnimations(): Boolean { override fun supportsPredictiveItemAnimations(): Boolean {

View File

@ -10,6 +10,8 @@ import androidx.recyclerview.widget.ListUpdateCallback
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.HomePageList import com.lagradost.cloudstream3.HomePageList
import com.lagradost.cloudstream3.R 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.SearchClickCallback
import com.lagradost.cloudstream3.ui.search.SearchFragment.Companion.filterSearchResponse import com.lagradost.cloudstream3.ui.search.SearchFragment.Companion.filterSearchResponse
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
@ -153,6 +155,7 @@ class ParentItemAdapter(
).apply { ).apply {
isHorizontal = info.isHorizontalImages isHorizontal = info.isHorizontalImages
} }
recyclerView.setLinearListLayout()
} }
} }
@ -167,7 +170,7 @@ class ParentItemAdapter(
isHorizontal = info.isHorizontalImages isHorizontal = info.isHorizontalImages
hasNext = expand.hasNext hasNext = expand.hasNext
} }
recyclerView.setLinearListLayout()
title.text = info.name title.text = info.name
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {

View File

@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
@ -75,9 +76,12 @@ class EpisodeAdapter(
} }
override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) { override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
if(holder.itemView.hasFocus()) { if (holder.itemView.hasFocus()) {
holder.itemView.clearFocus() holder.itemView.clearFocus()
} }
//(holder.itemView as? FrameLayout?)?.descendantFocusability =
// ViewGroup.FOCUS_BLOCK_DESCENDANTS
if (holder is DownloadButtonViewHolder) { if (holder is DownloadButtonViewHolder) {
holder.downloadButton.dispose() holder.downloadButton.dispose()
} }
@ -87,11 +91,20 @@ class EpisodeAdapter(
if (holder is DownloadButtonViewHolder) { if (holder is DownloadButtonViewHolder) {
holder.downloadButton.dispose() holder.downloadButton.dispose()
mBoundViewHolders.remove(holder) mBoundViewHolders.remove(holder)
//(holder.itemView as? FrameLayout?)?.descendantFocusability =
// ViewGroup.FOCUS_BLOCK_DESCENDANTS
} }
} }
override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) { override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
if (holder is DownloadButtonViewHolder) { 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() holder.reattachDownloadButton()
} }
} }
@ -145,7 +158,6 @@ class EpisodeAdapter(
) : RecyclerView.ViewHolder(itemView), DownloadButtonViewHolder { ) : RecyclerView.ViewHolder(itemView), DownloadButtonViewHolder {
override var downloadButton = EasyDownloadButton() override var downloadButton = EasyDownloadButton()
var episodeDownloadBar: ContentLoadingProgressBar? = null var episodeDownloadBar: ContentLoadingProgressBar? = null
var episodeDownloadImage: ImageView? = null var episodeDownloadImage: ImageView? = null
var localCard: ResultEpisode? = null var localCard: ResultEpisode? = null
@ -217,17 +229,17 @@ class EpisodeAdapter(
} }
} }
parentView.setOnClickListener { itemView.setOnClickListener {
clickCallback.invoke(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card)) clickCallback.invoke(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card))
} }
if (isTrueTv) { if (isTrueTv) {
parentView.isFocusable = true itemView.isFocusable = true
parentView.isFocusableInTouchMode = true itemView.isFocusableInTouchMode = true
parentView.touchscreenBlocksFocus = false //itemView.touchscreenBlocksFocus = false
} }
parentView.setOnLongClickListener { itemView.setOnLongClickListener {
clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card)) clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
return@setOnLongClickListener true return@setOnLongClickListener true
@ -242,6 +254,9 @@ class EpisodeAdapter(
downloadButton.dispose() downloadButton.dispose()
val card = localCard val card = localCard
if (hasDownloadSupport && card != null) { if (hasDownloadSupport && card != null) {
if (episodeDownloadBar == null ||
episodeDownloadImage == null
) return
val downloadInfo = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings( val downloadInfo = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
itemView.context, itemView.context,
card.id card.id

View File

@ -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
}*/
}

View File

@ -471,31 +471,6 @@ open class ResultFragment : ResultTrailerPlayer() {
syncModel.addFromUrl(url) syncModel.addFromUrl(url)
val api = getApiFromName(apiName) 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 = result_episodes?.adapter =
EpisodeAdapter( EpisodeAdapter(

View File

@ -5,23 +5,26 @@ import android.graphics.Rect
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.widget.NestedScrollView import androidx.core.widget.NestedScrollView
import com.discord.panels.OverlappingPanelsLayout import com.discord.panels.OverlappingPanelsLayout
import com.discord.panels.PanelsChildGestureRegionObserver 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.google.android.material.bottomsheet.BottomSheetDialog
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers 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.Some
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.ui.WatchType import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
import com.lagradost.cloudstream3.ui.search.SearchAdapter import com.lagradost.cloudstream3.ui.search.SearchAdapter
import com.lagradost.cloudstream3.ui.search.SearchHelper 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.AppUtils.openBrowser
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
@ -125,6 +128,8 @@ class ResultFragmentPhone : ResultFragment() {
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val apiName = arguments?.getString(API_NAME_BUNDLE) ?: return
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
player_open_source?.setOnClickListener { player_open_source?.setOnClickListener {
@ -192,6 +197,37 @@ class ResultFragmentPhone : ResultFragment() {
} }
//result_poster_blur_holder?.translationY = -scrollY.toFloat() //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 -> observe(viewModel.episodesCountText) { count ->
result_episodes_text.setText(count) result_episodes_text.setText(count)

View File

@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.ui.result
import android.app.Dialog import android.app.Dialog
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.widget.LinearLayout
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView 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.mvvm.observe
import com.lagradost.cloudstream3.ui.search.SearchAdapter import com.lagradost.cloudstream3.ui.search.SearchAdapter
import com.lagradost.cloudstream3.ui.search.SearchHelper 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.SingleSelectionHelper.showBottomDialogInstant
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage 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.*
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() { class ResultFragmentTv : ResultFragment() {
override val resultLayout = R.layout.fragment_result_tv override val resultLayout = R.layout.fragment_result_tv
@ -95,13 +103,21 @@ class ResultFragmentTv : ResultFragment() {
result_recommendations_filter_selection?.isVisible = false result_recommendations_filter_selection?.isVisible = false
} }
} }
var loadingDialog: Dialog? = null var loadingDialog: Dialog? = null
var popupDialog: Dialog? = null var popupDialog: Dialog? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) 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 { (result_episodes?.adapter as EpisodeAdapter?)?.apply {
layout = R.layout.result_episode_both_tv layout = R.layout.result_episode_both_tv
} }
//result_episodes?.setMaxViewPoolSize(0, Int.MAX_VALUE)
result_season_selection.setAdapter() result_season_selection.setAdapter()
result_range_selection.setAdapter() result_range_selection.setAdapter()

View File

@ -197,6 +197,7 @@ fun LoadResponse.toResultData(repo: APIRepository): ResultData {
TvType.Torrent -> R.string.torrent_singular TvType.Torrent -> R.string.torrent_singular
TvType.AsianDrama -> R.string.asian_drama_singular TvType.AsianDrama -> R.string.asian_drama_singular
TvType.Live -> R.string.live_singular TvType.Live -> R.string.live_singular
TvType.Others -> R.string.other_singular
} }
), ),
yearText = txt(year?.toString()), yearText = txt(year?.toString()),
@ -549,6 +550,7 @@ class ResultViewModel2 : ViewModel() {
TvType.Documentary -> "Documentaries" TvType.Documentary -> "Documentaries"
TvType.AsianDrama -> "AsianDrama" TvType.AsianDrama -> "AsianDrama"
TvType.Live -> "LiveStreams" TvType.Live -> "LiveStreams"
TvType.Others -> "Others"
} }
} }

View File

@ -169,6 +169,7 @@ class SearchFragment : Fragment() {
val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian) val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian)
val livestream = val livestream =
dialog.findViewById<MaterialButton>(R.id.home_select_livestreams) 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 cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt) val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt)
@ -180,7 +181,8 @@ class SearchFragment : Fragment() {
docs, docs,
movies, movies,
asian, asian,
livestream livestream,
other
) )
cancelBtt?.setOnClickListener { cancelBtt?.setOnClickListener {
@ -297,7 +299,8 @@ class SearchFragment : Fragment() {
search_select_documentaries, search_select_documentaries,
search_select_movies, search_select_movies,
search_select_asian, search_select_asian,
search_select_livestreams search_select_livestreams,
search_select_others
) )
val settingsManager = context?.let { PreferenceManager.getDefaultSharedPreferences(it) } val settingsManager = context?.let { PreferenceManager.getDefaultSharedPreferences(it) }

View File

@ -112,7 +112,8 @@ class PluginsFragment : Fragment() {
home_select_documentaries, home_select_documentaries,
home_select_movies, home_select_movies,
home_select_asian, home_select_asian,
home_select_livestreams home_select_livestreams,
home_select_others
) )
// Copy pasted code // Copy pasted code

View File

@ -175,7 +175,10 @@ class PluginsViewModel : ViewModel() {
// Perhaps can be optimized? // Perhaps can be optimized?
private fun List<PluginViewData>.filterTvTypes(): List<PluginViewData> { private fun List<PluginViewData>.filterTvTypes(): List<PluginViewData> {
if (tvTypes.isEmpty()) return this 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> { private fun List<PluginViewData>.sortByQuery(query: String?): List<PluginViewData> {

View File

@ -110,6 +110,12 @@
android:nextFocusLeft="@id/home_select_documentaries" android:nextFocusLeft="@id/home_select_documentaries"
android:text="@string/livestreams" /> 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> </LinearLayout>
</HorizontalScrollView> </HorizontalScrollView>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>

View File

@ -917,7 +917,7 @@
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:descendantFocusability="afterDescendants" android:descendantFocusability="afterDescendants"
android:paddingBottom="100dp" android:paddingBottom="100dp"
tools:listitem="@layout/result_episode" /> tools:listitem="@layout/result_episode_both_tv" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -146,6 +146,12 @@
style="@style/RoundedSelectableButton" style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/search_select_documentaries" android:nextFocusLeft="@id/search_select_documentaries"
android:text="@string/livestreams" /> 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> </LinearLayout>
</HorizontalScrollView> </HorizontalScrollView>

View File

@ -104,6 +104,12 @@
android:nextFocusLeft="@id/home_select_documentaries" android:nextFocusLeft="@id/home_select_documentaries"
android:text="@string/livestreams" /> 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> </LinearLayout>
</HorizontalScrollView> </HorizontalScrollView>

View File

@ -11,7 +11,6 @@
app:cardCornerRadius="@dimen/rounded_image_radius" app:cardCornerRadius="@dimen/rounded_image_radius"
app:cardBackgroundColor="@color/transparent" app:cardBackgroundColor="@color/transparent"
app:cardElevation="0dp" app:cardElevation="0dp"
android:foreground="@drawable/outline_drawable"
android:layout_marginBottom="5dp"> android:layout_marginBottom="5dp">
<!-- <!--
android:nextFocusLeft="@id/result_episode_download" android:nextFocusLeft="@id/result_episode_download"

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:foreground="@drawable/outline_drawable"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<include android:visibility="gone" layout="@layout/result_episode" /> <include android:visibility="gone" layout="@layout/result_episode" />

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:foreground="@drawable/outline_drawable"
xmlns:tools="http://schemas.android.com/tools"> android:layout_height="wrap_content">
<include <include
tools:visibility="visible" tools:visibility="visible"

View File

@ -6,19 +6,18 @@
android:nextFocusRight="@id/result_episode_download" android:nextFocusRight="@id/result_episode_download"
android:id="@+id/episode_holder_large" android:id="@+id/episode_holder_large"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:cardCornerRadius="@dimen/rounded_image_radius" app:cardCornerRadius="@dimen/rounded_image_radius"
app:cardBackgroundColor="?attr/boxItemBackground" app:cardBackgroundColor="?attr/boxItemBackground"
android:foreground="@drawable/outline_drawable"
android:layout_marginBottom="10dp"> android:layout_marginBottom="10dp">
<LinearLayout <LinearLayout
android:foreground="?android:attr/selectableItemBackgroundBorderless" android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:padding="10dp" android:padding="10dp"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<LinearLayout <LinearLayout

View File

@ -11,7 +11,6 @@
app:cardCornerRadius="@dimen/rounded_image_radius" app:cardCornerRadius="@dimen/rounded_image_radius"
app:cardBackgroundColor="?attr/boxItemBackground" app:cardBackgroundColor="?attr/boxItemBackground"
android:foreground="@drawable/outline_drawable"
android:layout_marginBottom="10dp"> android:layout_marginBottom="10dp">
<LinearLayout <LinearLayout

View File

@ -11,7 +11,6 @@
app:cardCornerRadius="@dimen/rounded_image_radius" app:cardCornerRadius="@dimen/rounded_image_radius"
app:cardBackgroundColor="@color/transparent" app:cardBackgroundColor="@color/transparent"
app:cardElevation="0dp" app:cardElevation="0dp"
android:foreground="@drawable/outline_drawable"
android:layout_marginBottom="5dp"> android:layout_marginBottom="5dp">
<androidx.core.widget.ContentLoadingProgressBar <androidx.core.widget.ContentLoadingProgressBar

View File

@ -42,7 +42,7 @@
<string name="type_re_watching">Ponowne oglądanie</string> <string name="type_re_watching">Ponowne oglądanie</string>
<string name="play_movie_button">Odtwórz film</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="play_torrent_button">Otwórz torrent</string>
<string name="pick_source">Źródła</string> <string name="pick_source">Źródła</string>
<string name="pick_subtitle">Napisy</string> <string name="pick_subtitle">Napisy</string>
@ -60,7 +60,7 @@
<string name="download_canceled">Anulowano pobieranie</string> <string name="download_canceled">Anulowano pobieranie</string>
<string name="download_done">Zakończono 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="error_loading_links_toast">Błąd przy ładowaniu linków</string>
<string name="download_storage_text">Pamięć wewnętrzna</string> <string name="download_storage_text">Pamięć wewnętrzna</string>
@ -236,7 +236,7 @@
<string name="ova">OVA</string> <string name="ova">OVA</string>
<string name="asian_drama">Filmy azjatyckie</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="movies_singular">Film</string>
<string name="tv_series_singular">Serial telewizyjny</string> <string name="tv_series_singular">Serial telewizyjny</string>
<string name="cartoons_singular">Kreskówka</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="app_layout_subtext">Dostosuj wygląd aplikacji do urządzenia</string>
<string name="preferred_media_subtext">Preferowany rodzaj filmów</string> <string name="preferred_media_subtext">Preferowany rodzaj filmów</string>
<string name="setup_done">Gotowe</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> </resources>

View File

@ -333,6 +333,7 @@
<string name="ova">OVA</string> <string name="ova">OVA</string>
<string name="asian_drama">Asian Dramas</string> <string name="asian_drama">Asian Dramas</string>
<string name="livestreams">Livestreams</string> <string name="livestreams">Livestreams</string>
<string name="others">Others</string>
<!--singular--> <!--singular-->
<string name="movies_singular">Movie</string> <string name="movies_singular">Movie</string>
@ -344,6 +345,7 @@
<string name="documentaries_singular">Documentary</string> <string name="documentaries_singular">Documentary</string>
<string name="asian_drama_singular">Asian Drama</string> <string name="asian_drama_singular">Asian Drama</string>
<string name="live_singular">Livestream</string> <string name="live_singular">Livestream</string>
<string name="other_singular">Video</string>
<string name="source_error">Source error</string> <string name="source_error">Source error</string>
<string name="remote_error">Remote error</string> <string name="remote_error">Remote error</string>