mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
play any stream & a bit of work on invideoplayer episodes & no links found last error
This commit is contained in:
parent
bb7400638a
commit
e7e63b4855
17 changed files with 585 additions and 528 deletions
|
@ -36,7 +36,7 @@ android {
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
|
|
||||||
versionCode 48
|
versionCode 48
|
||||||
versionName "2.10.30"
|
versionName "2.10.31"
|
||||||
|
|
||||||
resValue "string", "app_version",
|
resValue "string", "app_version",
|
||||||
"${defaultConfig.versionName}${versionNameSuffix ?: ""}"
|
"${defaultConfig.versionName}${versionNameSuffix ?: ""}"
|
||||||
|
|
|
@ -8,7 +8,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
|
|
||||||
class HDMovie5 : MainAPI() {
|
class HDMovie5 : MainAPI() {
|
||||||
override var mainUrl = "https://hdmovie2.org"
|
override var mainUrl = "https://Hdmovie2.biz"
|
||||||
override var name = "HDMovie"
|
override var name = "HDMovie"
|
||||||
override var lang = "hi"
|
override var lang = "hi"
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,11 @@ package com.lagradost.cloudstream3.movieproviders
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.lagradost.cloudstream3.*
|
|
||||||
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
|
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
|
||||||
|
import com.lagradost.cloudstream3.SubtitleFile
|
||||||
|
import com.lagradost.cloudstream3.TvType
|
||||||
|
import com.lagradost.cloudstream3.apmap
|
||||||
|
import com.lagradost.cloudstream3.app
|
||||||
import com.lagradost.cloudstream3.metaproviders.TmdbLink
|
import com.lagradost.cloudstream3.metaproviders.TmdbLink
|
||||||
import com.lagradost.cloudstream3.metaproviders.TmdbProvider
|
import com.lagradost.cloudstream3.metaproviders.TmdbProvider
|
||||||
import com.lagradost.cloudstream3.movieproviders.SflixProvider.Companion.extractRabbitStream
|
import com.lagradost.cloudstream3.movieproviders.SflixProvider.Companion.extractRabbitStream
|
||||||
|
@ -15,7 +18,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
class TwoEmbedProvider : TmdbProvider() {
|
class TwoEmbedProvider : TmdbProvider() {
|
||||||
override val apiName = "2Embed"
|
override val apiName = "2Embed"
|
||||||
override var name = "2Embed"
|
override var name = "2Embed"
|
||||||
override var mainUrl = "https://www.2embed.to"
|
override var mainUrl = "https://www.2embed.org"
|
||||||
override val useMetaLoadResponse = true
|
override val useMetaLoadResponse = true
|
||||||
override val instantLinkLoading = false
|
override val instantLinkLoading = false
|
||||||
override val supportedTypes = setOf(
|
override val supportedTypes = setOf(
|
||||||
|
|
|
@ -12,21 +12,40 @@ import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.adjustAlpha
|
import com.lagradost.cloudstream3.utils.UIHelper.adjustAlpha
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
|
|
||||||
class MyMiniControllerFragment : MiniControllerFragment() {
|
class MyMiniControllerFragment : MiniControllerFragment() {
|
||||||
var currentColor: Int = 0
|
var currentColor: Int = 0
|
||||||
|
|
||||||
// I KNOW, KINDA SPAGHETTI SOLUTION, BUT IT WORKS
|
override fun onDestroy() {
|
||||||
override fun onInflate(context: Context, attributeSet: AttributeSet, bundle: Bundle?) {
|
currentColor = 0
|
||||||
val obtainStyledAttributes = context.obtainStyledAttributes(attributeSet, R.styleable.CustomCast, 0, 0)
|
super.onDestroy()
|
||||||
if (obtainStyledAttributes.hasValue(R.styleable.CustomCast_customCastBackgroundColor)) {
|
|
||||||
currentColor = obtainStyledAttributes.getColor(R.styleable.CustomCast_customCastBackgroundColor, 0)
|
|
||||||
}
|
|
||||||
obtainStyledAttributes.recycle()
|
|
||||||
super.onInflate(context, attributeSet, bundle)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// I KNOW, KINDA SPAGHETTI SOLUTION, BUT IT WORKS
|
||||||
|
override fun onInflate(context: Context, attributeSet: AttributeSet, bundle: Bundle?) {
|
||||||
|
super.onInflate(context, attributeSet, bundle)
|
||||||
|
|
||||||
|
// somehow this leaks and I really dont know why, it seams like if you go back to a fragment with this, it leaks????
|
||||||
|
if (currentColor == 0) {
|
||||||
|
WeakReference(
|
||||||
|
context.obtainStyledAttributes(
|
||||||
|
attributeSet,
|
||||||
|
R.styleable.CustomCast
|
||||||
|
)
|
||||||
|
).apply {
|
||||||
|
if (get()
|
||||||
|
?.hasValue(R.styleable.CustomCast_customCastBackgroundColor) == true
|
||||||
|
) {
|
||||||
|
currentColor =
|
||||||
|
get()
|
||||||
|
?.getColor(R.styleable.CustomCast_customCastBackgroundColor, 0) ?: 0
|
||||||
|
}
|
||||||
|
get()?.recycle()
|
||||||
|
}.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
@ -38,18 +57,24 @@ class MyMiniControllerFragment : MiniControllerFragment() {
|
||||||
val containerCurrent: RelativeLayout? = view.findViewById(R.id.container_current)
|
val containerCurrent: RelativeLayout? = view.findViewById(R.id.container_current)
|
||||||
|
|
||||||
context?.let { ctx ->
|
context?.let { ctx ->
|
||||||
progressBar?.setBackgroundColor(adjustAlpha(ctx.colorFromAttribute(R.attr.colorPrimary), 0.35f))
|
progressBar?.setBackgroundColor(
|
||||||
val params = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 2.toPx)
|
adjustAlpha(
|
||||||
|
ctx.colorFromAttribute(R.attr.colorPrimary),
|
||||||
|
0.35f
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val params = RelativeLayout.LayoutParams(
|
||||||
|
RelativeLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
2.toPx
|
||||||
|
)
|
||||||
|
|
||||||
progressBar?.layoutParams = params
|
progressBar?.layoutParams = params
|
||||||
|
val color = currentColor
|
||||||
if (currentColor != 0) {
|
if (color != 0)
|
||||||
containerCurrent?.setBackgroundColor(currentColor)
|
containerCurrent?.setBackgroundColor(color)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val child = containerAll?.getChildAt(0)
|
val child = containerAll?.getChildAt(0)
|
||||||
child?.alpha = 0f // REMOVE GRADIENT
|
child?.alpha = 0f // REMOVE GRADIENT
|
||||||
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// JUST IN CASE
|
// JUST IN CASE
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,8 @@ class DownloadChildFragment : Fragment() {
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
(download_child_list?.adapter as DownloadChildAdapter?)?.killAdapter()
|
(download_child_list?.adapter as DownloadChildAdapter?)?.killAdapter()
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent -= it }
|
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent -= it }
|
||||||
super.onDestroy()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
|
|
@ -65,16 +65,12 @@ class DownloadFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
(download_list?.adapter as DownloadHeaderAdapter?)?.killAdapter()
|
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
if (downloadDeleteEventListener != null) {
|
if (downloadDeleteEventListener != null) {
|
||||||
VideoDownloadManager.downloadDeleteEvent -= downloadDeleteEventListener!!
|
VideoDownloadManager.downloadDeleteEvent -= downloadDeleteEventListener!!
|
||||||
downloadDeleteEventListener = null
|
downloadDeleteEventListener = null
|
||||||
}
|
}
|
||||||
super.onDestroy()
|
(download_list?.adapter as DownloadHeaderAdapter?)?.killAdapter()
|
||||||
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
|
@ -83,7 +79,17 @@ class DownloadFragment : Fragment() {
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View? {
|
||||||
downloadsViewModel =
|
downloadsViewModel =
|
||||||
ViewModelProvider(this).get(DownloadViewModel::class.java)
|
ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
|
|
||||||
|
return inflater.inflate(R.layout.fragment_downloads, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var downloadDeleteEventListener: ((Int) -> Unit)? = null
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
hideKeyboard()
|
||||||
|
|
||||||
observe(downloadsViewModel.noDownloadsText) {
|
observe(downloadsViewModel.noDownloadsText) {
|
||||||
text_no_downloads.text = it
|
text_no_downloads.text = it
|
||||||
}
|
}
|
||||||
|
@ -114,16 +120,8 @@ class DownloadFragment : Fragment() {
|
||||||
getBytesAsText(it)
|
getBytesAsText(it)
|
||||||
)
|
)
|
||||||
download_app?.setLayoutWidth(it)
|
download_app?.setLayoutWidth(it)
|
||||||
download_storage_appbar?.visibility = View.VISIBLE
|
download_storage_appbar?.isVisible = it > 0
|
||||||
}
|
}
|
||||||
return inflater.inflate(R.layout.fragment_downloads, container, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var downloadDeleteEventListener: ((Int) -> Unit)? = null
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
hideKeyboard()
|
|
||||||
|
|
||||||
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
|
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
|
||||||
DownloadHeaderAdapter(
|
DownloadHeaderAdapter(
|
||||||
|
|
|
@ -8,6 +8,7 @@ import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.lagradost.cloudstream3.isMovieType
|
import com.lagradost.cloudstream3.isMovieType
|
||||||
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE
|
import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE
|
||||||
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
|
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.getFolderName
|
import com.lagradost.cloudstream3.utils.DataStore.getFolderName
|
||||||
|
@ -100,7 +101,7 @@ class DownloadViewModel : ViewModel() {
|
||||||
(it.child?.episode ?: 0) + (it.child?.season?.times(10000) ?: 0)
|
(it.child?.episode ?: 0) + (it.child?.season?.times(10000) ?: 0)
|
||||||
} // episode sorting by episode, lowest to highest
|
} // episode sorting by episode, lowest to highest
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
val stat = StatFs(Environment.getExternalStorageDirectory().path)
|
val stat = StatFs(Environment.getExternalStorageDirectory().path)
|
||||||
|
|
||||||
val localBytesAvailable = stat.availableBytes//stat.blockSizeLong * stat.blockCountLong
|
val localBytesAvailable = stat.availableBytes//stat.blockSizeLong * stat.blockCountLong
|
||||||
|
@ -110,6 +111,10 @@ class DownloadViewModel : ViewModel() {
|
||||||
_usedBytes.postValue(localTotalBytes - localBytesAvailable - localDownloadedBytes)
|
_usedBytes.postValue(localTotalBytes - localBytesAvailable - localDownloadedBytes)
|
||||||
_availableBytes.postValue(localBytesAvailable)
|
_availableBytes.postValue(localBytesAvailable)
|
||||||
_downloadBytes.postValue(localDownloadedBytes)
|
_downloadBytes.postValue(localDownloadedBytes)
|
||||||
|
} catch (e : Exception) {
|
||||||
|
_downloadBytes.postValue(0)
|
||||||
|
logError(e)
|
||||||
|
}
|
||||||
|
|
||||||
_headerCards.postValue(visual)
|
_headerCards.postValue(visual)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,13 @@ class EasyDownloadButton : IDisposable {
|
||||||
val id: Int
|
val id: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var _clickCallback: ((DownloadClickEvent) -> Unit)? = null
|
||||||
|
private var _imageChangeCallback: ((Pair<Int, String>) -> Unit)? = null
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
try {
|
try {
|
||||||
|
_clickCallback = null
|
||||||
|
_imageChangeCallback = null
|
||||||
downloadProgressEventListener?.let { VideoDownloadManager.downloadProgressEvent -= it }
|
downloadProgressEventListener?.let { VideoDownloadManager.downloadProgressEvent -= it }
|
||||||
downloadStatusEventListener?.let { VideoDownloadManager.downloadStatusEvent -= it }
|
downloadStatusEventListener?.let { VideoDownloadManager.downloadStatusEvent -= it }
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -119,6 +124,8 @@ class EasyDownloadButton : IDisposable {
|
||||||
clickCallback: (DownloadClickEvent) -> Unit,
|
clickCallback: (DownloadClickEvent) -> Unit,
|
||||||
isTextPercentage: Boolean = false
|
isTextPercentage: Boolean = false
|
||||||
) {
|
) {
|
||||||
|
_clickCallback = clickCallback
|
||||||
|
_imageChangeCallback = downloadImageChangeCallback
|
||||||
var lastState: VideoDownloadManager.DownloadType? = null
|
var lastState: VideoDownloadManager.DownloadType? = null
|
||||||
var currentBytes = setupCurrentBytes ?: 0
|
var currentBytes = setupCurrentBytes ?: 0
|
||||||
var totalBytes = setupTotalBytes ?: 0
|
var totalBytes = setupTotalBytes ?: 0
|
||||||
|
@ -142,7 +149,7 @@ class EasyDownloadButton : IDisposable {
|
||||||
} else {
|
} else {
|
||||||
Pair(R.drawable.netflix_download, R.string.download)
|
Pair(R.drawable.netflix_download, R.string.download)
|
||||||
}
|
}
|
||||||
downloadImageChangeCallback.invoke(
|
_imageChangeCallback?.invoke(
|
||||||
Pair(
|
Pair(
|
||||||
img.first,
|
img.first,
|
||||||
downloadView.context.getString(img.second)
|
downloadView.context.getString(img.second)
|
||||||
|
@ -223,7 +230,7 @@ class EasyDownloadButton : IDisposable {
|
||||||
|
|
||||||
downloadView.setOnClickListener {
|
downloadView.setOnClickListener {
|
||||||
if (currentBytes <= 0) {
|
if (currentBytes <= 0) {
|
||||||
clickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_DOWNLOAD, data))
|
_clickCallback?.invoke(DownloadClickEvent(DOWNLOAD_ACTION_DOWNLOAD, data))
|
||||||
} else {
|
} else {
|
||||||
val list = arrayListOf(
|
val list = arrayListOf(
|
||||||
Pair(DOWNLOAD_ACTION_PLAY_FILE, R.string.popup_play_file),
|
Pair(DOWNLOAD_ACTION_PLAY_FILE, R.string.popup_play_file),
|
||||||
|
@ -243,7 +250,7 @@ class EasyDownloadButton : IDisposable {
|
||||||
it.popupMenuNoIcons(
|
it.popupMenuNoIcons(
|
||||||
list
|
list
|
||||||
) {
|
) {
|
||||||
clickCallback.invoke(DownloadClickEvent(itemId, data))
|
_clickCallback?.invoke(DownloadClickEvent(itemId, data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -350,6 +350,7 @@ abstract class AbstractPlayerFragment(
|
||||||
resizeMode = getKey(RESIZE_MODE_KEY) ?: 0
|
resizeMode = getKey(RESIZE_MODE_KEY) ?: 0
|
||||||
resize(resizeMode, false)
|
resize(resizeMode, false)
|
||||||
|
|
||||||
|
player.releaseCallbacks()
|
||||||
player.initCallbacks(
|
player.initCallbacks(
|
||||||
playerUpdated = ::playerUpdated,
|
playerUpdated = ::playerUpdated,
|
||||||
updateIsPlaying = ::updateIsPlaying,
|
updateIsPlaying = ::updateIsPlaying,
|
||||||
|
|
|
@ -108,6 +108,21 @@ class CS3IPlayer : IPlayer {
|
||||||
private var playerUpdated: ((Any?) -> Unit)? = null
|
private var playerUpdated: ((Any?) -> Unit)? = null
|
||||||
private var embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null
|
private var embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null
|
||||||
|
|
||||||
|
override fun releaseCallbacks() {
|
||||||
|
playerUpdated = null
|
||||||
|
updateIsPlaying = null
|
||||||
|
requestAutoFocus = null
|
||||||
|
playerError = null
|
||||||
|
playerDimensionsLoaded = null
|
||||||
|
requestedListeningPercentages = null
|
||||||
|
playerPositionChanged = null
|
||||||
|
nextEpisode = null
|
||||||
|
prevEpisode = null
|
||||||
|
subtitlesUpdates = null
|
||||||
|
embeddedSubtitlesFetched = null
|
||||||
|
requestSubtitleUpdate = null
|
||||||
|
}
|
||||||
|
|
||||||
override fun initCallbacks(
|
override fun initCallbacks(
|
||||||
playerUpdated: (Any?) -> Unit,
|
playerUpdated: (Any?) -> Unit,
|
||||||
updateIsPlaying: ((Pair<CSPlayerLoading, CSPlayerLoading>) -> Unit)?,
|
updateIsPlaying: ((Pair<CSPlayerLoading, CSPlayerLoading>) -> Unit)?,
|
||||||
|
|
|
@ -315,6 +315,8 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
exitFullscreen()
|
exitFullscreen()
|
||||||
|
player.release()
|
||||||
|
player.releaseCallbacks()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1104,7 +1106,6 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
// init variables
|
// init variables
|
||||||
setPlayBackSpeed(getKey(PLAYBACK_SPEED_KEY) ?: 1.0f)
|
setPlayBackSpeed(getKey(PLAYBACK_SPEED_KEY) ?: 1.0f)
|
||||||
|
|
||||||
|
|
|
@ -359,12 +359,12 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
dialog.search_filter.setOnClickListener {
|
dialog.search_filter.setOnClickListener { view ->
|
||||||
val lang639_1 = languages.map { it.ISO_639_1 }
|
val lang639_1 = languages.map { it.ISO_639_1 }
|
||||||
activity?.showDialog(
|
activity?.showDialog(
|
||||||
languages.map { it.languageName },
|
languages.map { it.languageName },
|
||||||
lang639_1.indexOf(currentLanguageTwoLetters),
|
lang639_1.indexOf(currentLanguageTwoLetters),
|
||||||
context.getString(R.string.subs_subtitle_languages),
|
view?.context?.getString(R.string.subs_subtitle_languages) ?: return@setOnClickListener,
|
||||||
true,
|
true,
|
||||||
{ }
|
{ }
|
||||||
) { index ->
|
) { index ->
|
||||||
|
@ -609,7 +609,7 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
|
|
||||||
val currentPrefMedia =
|
val currentPrefMedia =
|
||||||
settingsManager.getString(
|
settingsManager.getString(
|
||||||
getString(R.string.subtitles_encoding_key),
|
ctx.getString(R.string.subtitles_encoding_key),
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,7 @@ interface IPlayer {
|
||||||
subtitlesUpdates: (() -> Unit)? = null, // callback from player to inform that subtitles have updated in some way
|
subtitlesUpdates: (() -> Unit)? = null, // callback from player to inform that subtitles have updated in some way
|
||||||
embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null, // callback from player to give all embedded subtitles
|
embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null, // callback from player to give all embedded subtitles
|
||||||
)
|
)
|
||||||
|
fun releaseCallbacks()
|
||||||
|
|
||||||
fun updateSubtitleStyle(style: SaveCaptionStyle)
|
fun updateSubtitleStyle(style: SaveCaptionStyle)
|
||||||
fun saveData()
|
fun saveData()
|
||||||
|
|
|
@ -30,8 +30,6 @@ import androidx.core.widget.NestedScrollView
|
||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
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.CastButtonFactory
|
||||||
|
@ -49,10 +47,8 @@ import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||||
import com.lagradost.cloudstream3.mvvm.*
|
import com.lagradost.cloudstream3.mvvm.*
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
|
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
|
||||||
import com.lagradost.cloudstream3.ui.WatchType
|
import com.lagradost.cloudstream3.ui.WatchType
|
||||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
import com.lagradost.cloudstream3.ui.download.*
|
||||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
|
|
||||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
||||||
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
|
|
||||||
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
||||||
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
||||||
import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator
|
import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator
|
||||||
|
@ -478,17 +474,21 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
updateUIListener = null
|
||||||
(result_episodes?.adapter as EpisodeAdapter?)?.killAdapter()
|
(result_episodes?.adapter as EpisodeAdapter?)?.killAdapter()
|
||||||
|
downloadButton?.dispose()
|
||||||
|
//somehow this still leaks and I dont know why????
|
||||||
|
// todo look at https://github.com/discord/OverlappingPanels/blob/70b4a7cf43c6771873b1e091029d332896d41a1a/sample_app/src/main/java/com/discord/sampleapp/MainActivity.kt
|
||||||
|
PanelsChildGestureRegionObserver.Provider.get().removeGestureRegionsUpdateListener(this)
|
||||||
|
result_cast_items?.let {
|
||||||
|
PanelsChildGestureRegionObserver.Provider.get().unregister(it)
|
||||||
|
}
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
//requireActivity().viewModelStore.clear() // REMEMBER THE CLEAR
|
//requireActivity().viewModelStore.clear() // REMEMBER THE CLEAR
|
||||||
downloadButton?.dispose()
|
|
||||||
updateUIListener = null
|
|
||||||
result_cast_items?.let {
|
|
||||||
PanelsChildGestureRegionObserver.Provider.get().unregister(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
@ -625,6 +625,42 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleDownloadButton(downloadClickEvent: DownloadClickEvent) {
|
||||||
|
if (downloadClickEvent.action == DOWNLOAD_ACTION_DOWNLOAD) {
|
||||||
|
currentEpisodes?.firstOrNull()?.let { episode ->
|
||||||
|
handleAction(
|
||||||
|
EpisodeClickEvent(
|
||||||
|
ACTION_DOWNLOAD_EPISODE,
|
||||||
|
ResultEpisode(
|
||||||
|
currentHeaderName ?: return@let,
|
||||||
|
currentHeaderName,
|
||||||
|
null,
|
||||||
|
0,
|
||||||
|
null,
|
||||||
|
episode.data,
|
||||||
|
apiName,
|
||||||
|
currentId ?: return@let,
|
||||||
|
0,
|
||||||
|
0L,
|
||||||
|
0L,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
currentType ?: return@let,
|
||||||
|
currentId ?: return@let,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DownloadButtonSetup.handleDownloadClick(
|
||||||
|
activity,
|
||||||
|
currentHeaderName,
|
||||||
|
downloadClickEvent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadTrailer(index: Int? = null) {
|
private fun loadTrailer(index: Int? = null) {
|
||||||
val isSuccess =
|
val isSuccess =
|
||||||
currentTrailers.getOrNull(index ?: currentTrailerIndex)?.let { trailer ->
|
currentTrailers.getOrNull(index ?: currentTrailerIndex)?.let { trailer ->
|
||||||
|
@ -810,109 +846,8 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
viewModel.reloadEpisodes()
|
viewModel.reloadEpisodes()
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
var apiName: String = ""
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
private fun handleAction(episodeClick: EpisodeClickEvent): Job = main {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
result_cast_items?.let {
|
|
||||||
PanelsChildGestureRegionObserver.Provider.get().register(it)
|
|
||||||
}
|
|
||||||
result_cast_items?.adapter = ActorAdaptor()
|
|
||||||
fixGrid()
|
|
||||||
result_recommendations?.spanCount = 3
|
|
||||||
result_overlapping_panels?.setStartPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
|
||||||
result_overlapping_panels?.setEndPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
|
||||||
|
|
||||||
player_open_source?.setOnClickListener {
|
|
||||||
currentTrailers.getOrNull(currentTrailerIndex)?.let {
|
|
||||||
context?.openBrowser(it.url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateUIListener = ::updateUI
|
|
||||||
|
|
||||||
val restart = arguments?.getBoolean(RESTART_BUNDLE) ?: false
|
|
||||||
if (restart) {
|
|
||||||
arguments?.putBoolean(RESTART_BUNDLE, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
activity?.window?.decorView?.clearFocus()
|
|
||||||
hideKeyboard()
|
|
||||||
context?.updateHasTrailers()
|
|
||||||
activity?.loadCache()
|
|
||||||
|
|
||||||
activity?.fixPaddingStatusbar(result_top_bar)
|
|
||||||
//activity?.fixPaddingStatusbar(result_barstatus)
|
|
||||||
|
|
||||||
/* val backParameter = result_back.layoutParams as FrameLayout.LayoutParams
|
|
||||||
backParameter.setMargins(
|
|
||||||
backParameter.leftMargin,
|
|
||||||
backParameter.topMargin + requireContext().getStatusBarHeight(),
|
|
||||||
backParameter.rightMargin,
|
|
||||||
backParameter.bottomMargin
|
|
||||||
)
|
|
||||||
result_back.layoutParams = backParameter*/
|
|
||||||
|
|
||||||
// activity?.fixPaddingStatusbar(result_toolbar)
|
|
||||||
|
|
||||||
url = arguments?.getString(URL_BUNDLE)
|
|
||||||
val apiName = arguments?.getString(API_NAME_BUNDLE) ?: return
|
|
||||||
startAction = arguments?.getInt(START_ACTION_BUNDLE) ?: START_ACTION_NORMAL
|
|
||||||
startValue = arguments?.getInt(START_VALUE_BUNDLE)
|
|
||||||
val resumeEpisode = arguments?.getInt(EPISODE_BUNDLE)
|
|
||||||
val resumeSeason = arguments?.getInt(SEASON_BUNDLE)
|
|
||||||
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
|
|
||||||
|
|
||||||
castContext.addCastStateListener { state ->
|
|
||||||
media_route_button?.isGone = state == CastState.NO_DEVICES_AVAILABLE
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
logError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result_scroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
|
||||||
val dy = scrollY - oldScrollY
|
|
||||||
if (dy > 0) { //check for scroll down
|
|
||||||
result_bookmark_fab?.shrink()
|
|
||||||
} else if (dy < -5) {
|
|
||||||
result_bookmark_fab?.extend()
|
|
||||||
}
|
|
||||||
if (!isFullScreenPlayer && player.getIsPlaying()) {
|
|
||||||
if (scrollY > (player_background?.height ?: scrollY)) {
|
|
||||||
player.handleEvent(CSPlayerEvent.Pause)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//result_poster_blur_holder?.translationY = -scrollY.toFloat()
|
|
||||||
})
|
|
||||||
|
|
||||||
result_back.setOnClickListener {
|
|
||||||
activity?.popCurrentPage()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun handleAction(episodeClick: EpisodeClickEvent): Job = main {
|
|
||||||
if (episodeClick.action == ACTION_DOWNLOAD_EPISODE) {
|
if (episodeClick.action == ACTION_DOWNLOAD_EPISODE) {
|
||||||
val isMovie = currentIsMovie ?: return@main
|
val isMovie = currentIsMovie ?: return@main
|
||||||
val headerName = currentHeaderName ?: return@main
|
val headerName = currentHeaderName ?: return@main
|
||||||
|
@ -1015,9 +950,9 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
loadingDialog = builder.create()
|
loadingDialog = builder.create()
|
||||||
|
|
||||||
loadingDialog.show()
|
loadingDialog.show()
|
||||||
loadingDialog.setOnDismissListener {
|
//loadingDialog.setOnDismissListener {
|
||||||
currentLoadingCount++
|
// currentLoadingCount++
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
val data = viewModel.loadEpisode(episodeClick.data, isCasting)
|
val data = viewModel.loadEpisode(episodeClick.data, isCasting)
|
||||||
|
@ -1126,7 +1061,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
val verifiedOptions = ArrayList<String>()
|
val verifiedOptions = ArrayList<String>()
|
||||||
val verifiedOptionsValues = ArrayList<Int>()
|
val verifiedOptionsValues = ArrayList<Int>()
|
||||||
|
|
||||||
val hasDownloadSupport = api.hasDownloadSupport
|
val hasDownloadSupport = getApiFromName(apiName).hasDownloadSupport
|
||||||
|
|
||||||
for (i in options.indices) {
|
for (i in options.indices) {
|
||||||
val opv = optionsValues[i]
|
val opv = optionsValues[i]
|
||||||
|
@ -1309,7 +1244,106 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
|
@SuppressLint("SetTextI18n")
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
result_cast_items?.let {
|
||||||
|
PanelsChildGestureRegionObserver.Provider.get().register(it)
|
||||||
|
}
|
||||||
|
//result_cast_items?.adapter = ActorAdaptor()
|
||||||
|
fixGrid()
|
||||||
|
result_recommendations?.spanCount = 3
|
||||||
|
result_overlapping_panels?.setStartPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
||||||
|
result_overlapping_panels?.setEndPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
||||||
|
|
||||||
|
player_open_source?.setOnClickListener {
|
||||||
|
currentTrailers.getOrNull(currentTrailerIndex)?.let {
|
||||||
|
context?.openBrowser(it.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUIListener = ::updateUI
|
||||||
|
|
||||||
|
val restart = arguments?.getBoolean(RESTART_BUNDLE) ?: false
|
||||||
|
if (restart) {
|
||||||
|
arguments?.putBoolean(RESTART_BUNDLE, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
activity?.window?.decorView?.clearFocus()
|
||||||
|
hideKeyboard()
|
||||||
|
context?.updateHasTrailers()
|
||||||
|
activity?.loadCache()
|
||||||
|
|
||||||
|
activity?.fixPaddingStatusbar(result_top_bar)
|
||||||
|
//activity?.fixPaddingStatusbar(result_barstatus)
|
||||||
|
|
||||||
|
/* val backParameter = result_back.layoutParams as FrameLayout.LayoutParams
|
||||||
|
backParameter.setMargins(
|
||||||
|
backParameter.leftMargin,
|
||||||
|
backParameter.topMargin + requireContext().getStatusBarHeight(),
|
||||||
|
backParameter.rightMargin,
|
||||||
|
backParameter.bottomMargin
|
||||||
|
)
|
||||||
|
result_back.layoutParams = backParameter*/
|
||||||
|
|
||||||
|
// activity?.fixPaddingStatusbar(result_toolbar)
|
||||||
|
|
||||||
|
url = arguments?.getString(URL_BUNDLE)
|
||||||
|
apiName = arguments?.getString(API_NAME_BUNDLE) ?: return
|
||||||
|
startAction = arguments?.getInt(START_ACTION_BUNDLE) ?: START_ACTION_NORMAL
|
||||||
|
startValue = arguments?.getInt(START_VALUE_BUNDLE)
|
||||||
|
val resumeEpisode = arguments?.getInt(EPISODE_BUNDLE)
|
||||||
|
val resumeSeason = arguments?.getInt(SEASON_BUNDLE)
|
||||||
|
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_scroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||||
|
val dy = scrollY - oldScrollY
|
||||||
|
if (dy > 0) { //check for scroll down
|
||||||
|
result_bookmark_fab?.shrink()
|
||||||
|
} else if (dy < -5) {
|
||||||
|
result_bookmark_fab?.extend()
|
||||||
|
}
|
||||||
|
if (!isFullScreenPlayer && player.getIsPlaying()) {
|
||||||
|
if (scrollY > (player_background?.height ?: scrollY)) {
|
||||||
|
player.handleEvent(CSPlayerEvent.Pause)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//result_poster_blur_holder?.translationY = -scrollY.toFloat()
|
||||||
|
})
|
||||||
|
|
||||||
|
result_back.setOnClickListener {
|
||||||
|
activity?.popCurrentPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
result_episodes.adapter =
|
||||||
EpisodeAdapter(
|
EpisodeAdapter(
|
||||||
ArrayList(),
|
ArrayList(),
|
||||||
api.hasDownloadSupport,
|
api.hasDownloadSupport,
|
||||||
|
@ -1321,9 +1355,6 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
result_episodes.adapter = adapter
|
|
||||||
result_episodes.layoutManager = GridLayoutManager(context, 1)
|
|
||||||
|
|
||||||
result_bookmark_button.setOnClickListener {
|
result_bookmark_button.setOnClickListener {
|
||||||
it.popupMenuNoIcons(
|
it.popupMenuNoIcons(
|
||||||
items = WatchType.values()
|
items = WatchType.values()
|
||||||
|
@ -1467,7 +1498,8 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val imgAdapter = ImageAdapter(
|
|
||||||
|
result_mini_sync?.adapter = ImageAdapter(
|
||||||
R.layout.result_mini_image,
|
R.layout.result_mini_image,
|
||||||
nextFocusDown = R.id.result_sync_set_score,
|
nextFocusDown = R.id.result_sync_set_score,
|
||||||
clickCallback = { action ->
|
clickCallback = { action ->
|
||||||
|
@ -1479,7 +1511,6 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
result_mini_sync?.adapter = imgAdapter
|
|
||||||
|
|
||||||
observe(syncModel.synced) { list ->
|
observe(syncModel.synced) { list ->
|
||||||
result_sync_names?.text =
|
result_sync_names?.text =
|
||||||
|
@ -1638,7 +1669,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
?.let {
|
?.let {
|
||||||
result_play_movie?.text = it
|
result_play_movie?.text = it
|
||||||
}
|
}
|
||||||
println("startAction = $startAction")
|
//println("startAction = $startAction")
|
||||||
|
|
||||||
when (startAction) {
|
when (startAction) {
|
||||||
START_ACTION_RESUME_LATEST -> {
|
START_ACTION_RESUME_LATEST -> {
|
||||||
|
@ -1738,7 +1769,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result_cast_items?.setOnFocusChangeListener { v, hasFocus ->
|
result_cast_items?.setOnFocusChangeListener { _, hasFocus ->
|
||||||
// Always escape focus
|
// Always escape focus
|
||||||
if (hasFocus) result_bookmark_button?.requestFocus()
|
if (hasFocus) result_bookmark_button?.requestFocus()
|
||||||
}
|
}
|
||||||
|
@ -1992,6 +2023,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
result_movie_progress_downloaded_holder?.isVisible = hasDownloadSupport
|
result_movie_progress_downloaded_holder?.isVisible = hasDownloadSupport
|
||||||
if (hasDownloadSupport) {
|
if (hasDownloadSupport) {
|
||||||
val localId = d.getId()
|
val localId = d.getId()
|
||||||
|
|
||||||
val file =
|
val file =
|
||||||
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
|
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
|
@ -2018,42 +2050,9 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
d.rating,
|
d.rating,
|
||||||
d.plot,
|
d.plot,
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
|
),
|
||||||
|
::handleDownloadButton
|
||||||
)
|
)
|
||||||
) { downloadClickEvent ->
|
|
||||||
if (downloadClickEvent.action == DOWNLOAD_ACTION_DOWNLOAD) {
|
|
||||||
currentEpisodes?.firstOrNull()?.let { episode ->
|
|
||||||
handleAction(
|
|
||||||
EpisodeClickEvent(
|
|
||||||
ACTION_DOWNLOAD_EPISODE,
|
|
||||||
ResultEpisode(
|
|
||||||
d.name,
|
|
||||||
d.name,
|
|
||||||
null,
|
|
||||||
0,
|
|
||||||
null,
|
|
||||||
episode.data,
|
|
||||||
d.apiName,
|
|
||||||
localId,
|
|
||||||
0,
|
|
||||||
0L,
|
|
||||||
0L,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
d.type,
|
|
||||||
localId,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
handleDownloadClick(
|
|
||||||
activity,
|
|
||||||
currentHeaderName,
|
|
||||||
downloadClickEvent
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result_download_movie?.setOnLongClickListener {
|
result_download_movie?.setOnLongClickListener {
|
||||||
val card =
|
val card =
|
||||||
|
@ -2158,16 +2157,14 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val recAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? = activity?.let {
|
result_recommendations?.adapter =
|
||||||
SearchAdapter(
|
SearchAdapter(
|
||||||
ArrayList(),
|
ArrayList(),
|
||||||
result_recommendations,
|
result_recommendations,
|
||||||
) { callback ->
|
) { callback ->
|
||||||
SearchHelper.handleSearchClickCallback(activity, callback)
|
SearchHelper.handleSearchClickCallback(activity, callback)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
result_recommendations?.adapter = recAdapter
|
|
||||||
|
|
||||||
context?.let { ctx ->
|
context?.let { ctx ->
|
||||||
result_bookmark_button?.isVisible = ctx.isTvSettings()
|
result_bookmark_button?.isVisible = ctx.isTvSettings()
|
||||||
|
|
|
@ -129,11 +129,15 @@ object UIHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Activity?.navigate(@IdRes navigation: Int, arguments: Bundle? = null) {
|
fun Activity?.navigate(@IdRes navigation: Int, arguments: Bundle? = null) {
|
||||||
|
try {
|
||||||
if (this is FragmentActivity) {
|
if (this is FragmentActivity) {
|
||||||
(supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as? NavHostFragment?)?.navController?.navigate(
|
(supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as? NavHostFragment?)?.navController?.navigate(
|
||||||
navigation, arguments
|
navigation, arguments
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} catch (e : Exception) {
|
||||||
|
logError(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ColorInt
|
@ColorInt
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
-->
|
-->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/download_storage_appbar"
|
android:id="@+id/download_storage_appbar"
|
||||||
|
tools:visibility="visible"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:layout_margin="10dp"
|
android:layout_margin="10dp"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
|
|
@ -360,14 +360,15 @@
|
||||||
tools:text="121min" />
|
tools:text="121min" />
|
||||||
</com.lagradost.cloudstream3.widget.FlowLayout>
|
</com.lagradost.cloudstream3.widget.FlowLayout>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
This has half margin and half padding to make TV focus on description look better.
|
This has half margin and half padding to make TV focus on description look better.
|
||||||
The focus outline now settles between the poster and text.
|
The focus outline now settles between the poster and text.
|
||||||
-->
|
-->
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_marginHorizontal="5dp"
|
android:layout_marginHorizontal="5dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:maxLength="1000"
|
android:maxLength="1000"
|
||||||
|
@ -848,9 +849,10 @@ The focus outline now settles between the poster and text.
|
||||||
android:textColor="?attr/grayTextColor"
|
android:textColor="?attr/grayTextColor"
|
||||||
android:textSize="17sp"
|
android:textSize="17sp"
|
||||||
android:textStyle="normal"
|
android:textStyle="normal"
|
||||||
android:text="Episode 1022 will be released in" />
|
tools:text="Episode 1022 will be released in" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:paddingEnd="5dp"
|
||||||
android:paddingStart="5dp"
|
android:paddingStart="5dp"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:id="@+id/result_next_airing_time"
|
android:id="@+id/result_next_airing_time"
|
||||||
|
@ -903,6 +905,7 @@ The focus outline now settles between the poster and text.
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="0dp"
|
android:layout_marginTop="0dp"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
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" />
|
||||||
|
|
Loading…
Reference in a new issue