cleanup
This commit is contained in:
parent
0a327ccbda
commit
77294dc68e
|
@ -1122,23 +1122,25 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
if (isTvSettings()) {
|
if (isTvSettings()) {
|
||||||
val newLocalBinding = ActivityMainTvBinding.inflate(layoutInflater, null, false)
|
val newLocalBinding = ActivityMainTvBinding.inflate(layoutInflater, null, false)
|
||||||
setContentView(newLocalBinding.root)
|
setContentView(newLocalBinding.root)
|
||||||
TvFocus.focusOutline = WeakReference(newLocalBinding.focusOutline)
|
|
||||||
newLocalBinding.root.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus ->
|
if(isTrueTvSettings()) {
|
||||||
// println("refocus $oldFocus -> $newFocus")
|
TvFocus.focusOutline = WeakReference(newLocalBinding.focusOutline)
|
||||||
try {
|
newLocalBinding.root.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus ->
|
||||||
val r = Rect(0, 0, 0, 0)
|
// println("refocus $oldFocus -> $newFocus")
|
||||||
newFocus.getDrawingRect(r)
|
try {
|
||||||
val x = r.centerX()
|
val r = Rect(0, 0, 0, 0)
|
||||||
val y = r.centerY()
|
newFocus.getDrawingRect(r)
|
||||||
val dx = 0 //screenWidth / 2
|
val x = r.centerX()
|
||||||
val dy = screenHeight / 2
|
val y = r.centerY()
|
||||||
val r2 = Rect(x - dx, y - dy, x + dx, y + dy)
|
val dx = 0 //screenWidth / 2
|
||||||
newFocus.requestRectangleOnScreen(r2, false)
|
val dy = screenHeight / 2
|
||||||
// TvFocus.current =TvFocus.current.copy(y=y.toFloat())
|
val r2 = Rect(x - dx, y - dy, x + dx, y + dy)
|
||||||
} catch (_: Throwable) {
|
newFocus.requestRectangleOnScreen(r2, false)
|
||||||
}
|
// TvFocus.current =TvFocus.current.copy(y=y.toFloat())
|
||||||
TvFocus.updateFocusView(newFocus)
|
} catch (_: Throwable) {
|
||||||
/*var focus = newFocus
|
}
|
||||||
|
TvFocus.updateFocusView(newFocus)
|
||||||
|
/*var focus = newFocus
|
||||||
|
|
||||||
while(focus != null) {
|
while(focus != null) {
|
||||||
if(focus is ScrollingView && focus.canScrollVertically()) {
|
if(focus is ScrollingView && focus.canScrollVertically()) {
|
||||||
|
@ -1149,7 +1151,11 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
else -> break
|
else -> break
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newLocalBinding.focusOutline.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
newLocalBinding.root.viewTreeObserver.addOnScrollChangedListener {
|
newLocalBinding.root.viewTreeObserver.addOnScrollChangedListener {
|
||||||
TvFocus.updateFocusView(TvFocus.lastFocus.get(), same = true)
|
TvFocus.updateFocusView(TvFocus.lastFocus.get(), same = true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import android.content.DialogInterface
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -23,18 +22,12 @@ import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.button.MaterialButton
|
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import com.google.android.material.chip.ChipGroup
|
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.APIHolder.apis
|
import com.lagradost.cloudstream3.APIHolder.apis
|
||||||
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
|
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
|
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
|
||||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||||
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
|
|
||||||
import com.lagradost.cloudstream3.MainActivity.Companion.bookmarksUpdatedEvent
|
|
||||||
import com.lagradost.cloudstream3.MainActivity.Companion.mainPluginsLoadedEvent
|
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentHomeBinding
|
import com.lagradost.cloudstream3.databinding.FragmentHomeBinding
|
||||||
import com.lagradost.cloudstream3.databinding.HomeEpisodesExpandedBinding
|
import com.lagradost.cloudstream3.databinding.HomeEpisodesExpandedBinding
|
||||||
import com.lagradost.cloudstream3.databinding.HomeSelectMainpageBinding
|
import com.lagradost.cloudstream3.databinding.HomeSelectMainpageBinding
|
||||||
|
@ -45,37 +38,26 @@ import com.lagradost.cloudstream3.mvvm.observe
|
||||||
import com.lagradost.cloudstream3.mvvm.observeNullable
|
import com.lagradost.cloudstream3.mvvm.observeNullable
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
|
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi
|
import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi
|
||||||
import com.lagradost.cloudstream3.ui.WatchType
|
|
||||||
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
|
||||||
import com.lagradost.cloudstream3.ui.result.txt
|
import com.lagradost.cloudstream3.ui.result.txt
|
||||||
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
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.addProgramsToContinueWatching
|
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.isRecyclerScrollable
|
import com.lagradost.cloudstream3.utils.AppUtils.isRecyclerScrollable
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
|
import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.ownHide
|
import com.lagradost.cloudstream3.utils.AppUtils.ownHide
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.ownShow
|
import com.lagradost.cloudstream3.utils.AppUtils.ownShow
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.setDefaultFocus
|
import com.lagradost.cloudstream3.utils.AppUtils.setDefaultFocus
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||||
import com.lagradost.cloudstream3.utils.Event
|
import com.lagradost.cloudstream3.utils.Event
|
||||||
import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso
|
import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
|
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
||||||
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
const val HOME_BOOKMARK_VALUE_LIST = "home_bookmarked_last_list"
|
|
||||||
const val HOME_PREF_HOMEPAGE = "home_pref_homepage"
|
|
||||||
|
|
||||||
class HomeFragment : Fragment() {
|
class HomeFragment : Fragment() {
|
||||||
companion object {
|
companion object {
|
||||||
val configEvent = Event<Int>()
|
val configEvent = Event<Int>()
|
||||||
|
@ -377,10 +359,7 @@ class HomeFragment : Fragment() {
|
||||||
var currentApiName = selectedApiName
|
var currentApiName = selectedApiName
|
||||||
|
|
||||||
var currentValidApis: MutableList<MainAPI> = mutableListOf()
|
var currentValidApis: MutableList<MainAPI> = mutableListOf()
|
||||||
val preSelectedTypes = this.getKey<List<String>>("${DataStoreHelper.currentAccount}/$HOME_PREF_HOMEPAGE")
|
val preSelectedTypes = DataStoreHelper.homePreference.toMutableList()
|
||||||
?.mapNotNull { listName -> TvType.values().firstOrNull { it.name == listName } }
|
|
||||||
?.toMutableList()
|
|
||||||
?: mutableListOf(TvType.Movie, TvType.TvSeries)
|
|
||||||
|
|
||||||
binding.cancelBtt.setOnClickListener {
|
binding.cancelBtt.setOnClickListener {
|
||||||
dialog.dismissSafe()
|
dialog.dismissSafe()
|
||||||
|
@ -408,7 +387,7 @@ class HomeFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateList() {
|
fun updateList() {
|
||||||
this.setKey("${DataStoreHelper.currentAccount}/$HOME_PREF_HOMEPAGE", preSelectedTypes)
|
DataStoreHelper.homePreference = preSelectedTypes
|
||||||
|
|
||||||
arrayAdapter.clear()
|
arrayAdapter.clear()
|
||||||
currentValidApis = validAPIs.filter { api ->
|
currentValidApis = validAPIs.filter { api ->
|
||||||
|
|
|
@ -12,7 +12,6 @@ import com.lagradost.cloudstream3.APIHolder.filterSearchResultByFilmQuality
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.context
|
import com.lagradost.cloudstream3.AcraApplication.Companion.context
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
|
||||||
import com.lagradost.cloudstream3.CommonActivity.activity
|
import com.lagradost.cloudstream3.CommonActivity.activity
|
||||||
import com.lagradost.cloudstream3.HomePageList
|
import com.lagradost.cloudstream3.HomePageList
|
||||||
import com.lagradost.cloudstream3.LoadResponse
|
import com.lagradost.cloudstream3.LoadResponse
|
||||||
|
@ -170,10 +169,7 @@ class HomeViewModel : ViewModel() {
|
||||||
currentWatchTypes.remove(WatchType.NONE)
|
currentWatchTypes.remove(WatchType.NONE)
|
||||||
|
|
||||||
if (currentWatchTypes.size <= 0) {
|
if (currentWatchTypes.size <= 0) {
|
||||||
setKey(
|
DataStoreHelper.homeBookmarkedList = intArrayOf()
|
||||||
"${DataStoreHelper.currentAccount}/$HOME_BOOKMARK_VALUE_LIST",
|
|
||||||
intArrayOf()
|
|
||||||
)
|
|
||||||
_availableWatchStatusTypes.postValue(setOf<WatchType>() to setOf())
|
_availableWatchStatusTypes.postValue(setOf<WatchType>() to setOf())
|
||||||
_bookmarks.postValue(Pair(false, ArrayList()))
|
_bookmarks.postValue(Pair(false, ArrayList()))
|
||||||
return@launchSafe
|
return@launchSafe
|
||||||
|
@ -181,16 +177,14 @@ class HomeViewModel : ViewModel() {
|
||||||
|
|
||||||
val watchPrefNotNull = preferredWatchStatus ?: EnumSet.of(currentWatchTypes.first())
|
val watchPrefNotNull = preferredWatchStatus ?: EnumSet.of(currentWatchTypes.first())
|
||||||
//if (currentWatchTypes.any { watchPrefNotNull.contains(it) }) watchPrefNotNull else listOf(currentWatchTypes.first())
|
//if (currentWatchTypes.any { watchPrefNotNull.contains(it) }) watchPrefNotNull else listOf(currentWatchTypes.first())
|
||||||
setKey(
|
|
||||||
"${DataStoreHelper.currentAccount}/$HOME_BOOKMARK_VALUE_LIST",
|
DataStoreHelper.homeBookmarkedList = watchPrefNotNull.map { it.internalId }.toIntArray()
|
||||||
watchPrefNotNull.map { it.internalId }.toIntArray()
|
|
||||||
)
|
|
||||||
_availableWatchStatusTypes.postValue(
|
_availableWatchStatusTypes.postValue(
|
||||||
Pair(
|
|
||||||
watchPrefNotNull,
|
watchPrefNotNull to
|
||||||
currentWatchTypes,
|
currentWatchTypes,
|
||||||
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
val list = withContext(Dispatchers.IO) {
|
val list = withContext(Dispatchers.IO) {
|
||||||
watchStatusIds.filter { watchPrefNotNull.contains(it.second) }
|
watchStatusIds.filter { watchPrefNotNull.contains(it.second) }
|
||||||
|
@ -463,7 +457,7 @@ class HomeViewModel : ViewModel() {
|
||||||
|
|
||||||
fun loadStoredData() {
|
fun loadStoredData() {
|
||||||
val list = EnumSet.noneOf(WatchType::class.java)
|
val list = EnumSet.noneOf(WatchType::class.java)
|
||||||
getKey<IntArray>("${DataStoreHelper.currentAccount}/$HOME_BOOKMARK_VALUE_LIST")?.map { WatchType.fromInternalId(it) }?.let {
|
DataStoreHelper.homeBookmarkedList.map { WatchType.fromInternalId(it) }.let {
|
||||||
list.addAll(it)
|
list.addAll(it)
|
||||||
}
|
}
|
||||||
loadStoredData(list)
|
loadStoredData(list)
|
||||||
|
|
|
@ -33,8 +33,6 @@ import androidx.preference.PreferenceManager
|
||||||
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
||||||
import com.github.rubensousa.previewseekbar.PreviewBar
|
import com.github.rubensousa.previewseekbar.PreviewBar
|
||||||
import com.github.rubensousa.previewseekbar.media3.PreviewTimeBar
|
import com.github.rubensousa.previewseekbar.media3.PreviewTimeBar
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
|
||||||
import com.lagradost.cloudstream3.CommonActivity.canEnterPipMode
|
import com.lagradost.cloudstream3.CommonActivity.canEnterPipMode
|
||||||
import com.lagradost.cloudstream3.CommonActivity.isInPIPMode
|
import com.lagradost.cloudstream3.CommonActivity.isInPIPMode
|
||||||
import com.lagradost.cloudstream3.CommonActivity.keyEventListener
|
import com.lagradost.cloudstream3.CommonActivity.keyEventListener
|
||||||
|
@ -48,7 +46,7 @@ import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle
|
||||||
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
|
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils
|
import com.lagradost.cloudstream3.utils.AppUtils
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.requestLocalAudioFocus
|
import com.lagradost.cloudstream3.utils.AppUtils.requestLocalAudioFocus
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.currentAccount
|
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||||
import com.lagradost.cloudstream3.utils.EpisodeSkip
|
import com.lagradost.cloudstream3.utils.EpisodeSkip
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper
|
import com.lagradost.cloudstream3.utils.UIHelper
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI
|
import com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI
|
||||||
|
@ -443,7 +441,7 @@ abstract class AbstractPlayerFragment(
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n", "UnsafeOptInUsageError")
|
@SuppressLint("SetTextI18n", "UnsafeOptInUsageError")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
resizeMode = getKey("$currentAccount/$RESIZE_MODE_KEY") ?: 0
|
resizeMode = DataStoreHelper.resizeMode
|
||||||
resize(resizeMode, false)
|
resize(resizeMode, false)
|
||||||
|
|
||||||
player.releaseCallbacks()
|
player.releaseCallbacks()
|
||||||
|
@ -466,7 +464,8 @@ abstract class AbstractPlayerFragment(
|
||||||
var resume = false
|
var resume = false
|
||||||
progressBar.addOnScrubListener(object : PreviewBar.OnScrubListener {
|
progressBar.addOnScrubListener(object : PreviewBar.OnScrubListener {
|
||||||
override fun onScrubStart(previewBar: PreviewBar?) {
|
override fun onScrubStart(previewBar: PreviewBar?) {
|
||||||
progressBar.isPreviewEnabled = player.hasPreview()
|
val hasPreview = player.hasPreview()
|
||||||
|
progressBar.isPreviewEnabled = hasPreview
|
||||||
resume = player.getIsPlaying()
|
resume = player.getIsPlaying()
|
||||||
if (resume) player.handleEvent(
|
if (resume) player.handleEvent(
|
||||||
CSPlayerEvent.Pause,
|
CSPlayerEvent.Pause,
|
||||||
|
@ -574,7 +573,7 @@ abstract class AbstractPlayerFragment(
|
||||||
|
|
||||||
@SuppressLint("UnsafeOptInUsageError")
|
@SuppressLint("UnsafeOptInUsageError")
|
||||||
fun resize(resize: PlayerResize, showToast: Boolean) {
|
fun resize(resize: PlayerResize, showToast: Boolean) {
|
||||||
setKey("$currentAccount/$RESIZE_MODE_KEY", resize.ordinal)
|
DataStoreHelper.resizeMode = resize.ordinal
|
||||||
val type = when (resize) {
|
val type = when (resize) {
|
||||||
PlayerResize.Fill -> AspectRatioFrameLayout.RESIZE_MODE_FILL
|
PlayerResize.Fill -> AspectRatioFrameLayout.RESIZE_MODE_FILL
|
||||||
PlayerResize.Fit -> AspectRatioFrameLayout.RESIZE_MODE_FIT
|
PlayerResize.Fit -> AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||||
|
|
|
@ -49,7 +49,7 @@ import com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper
|
||||||
import com.lagradost.cloudstream3.ui.result.setText
|
import com.lagradost.cloudstream3.ui.result.setText
|
||||||
import com.lagradost.cloudstream3.ui.result.txt
|
import com.lagradost.cloudstream3.ui.result.txt
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.isUsingMobileData
|
import com.lagradost.cloudstream3.utils.AppUtils.isUsingMobileData
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.currentAccount
|
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
|
@ -357,7 +357,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
|
|
||||||
private fun setPlayBackSpeed(speed: Float) {
|
private fun setPlayBackSpeed(speed: Float) {
|
||||||
try {
|
try {
|
||||||
setKey("$currentAccount/$PLAYBACK_SPEED_KEY", speed)
|
DataStoreHelper.playBackSpeed = speed
|
||||||
playerBinding?.playerSpeedBtt?.text =
|
playerBinding?.playerSpeedBtt?.text =
|
||||||
getString(R.string.player_speed_text_format).format(speed)
|
getString(R.string.player_speed_text_format).format(speed)
|
||||||
.replace(".0x", "x")
|
.replace(".0x", "x")
|
||||||
|
@ -1195,7 +1195,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
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("$currentAccount/$PLAYBACK_SPEED_KEY") ?: 1.0f)
|
setPlayBackSpeed(DataStoreHelper.playBackSpeed)
|
||||||
savedInstanceState?.getLong(SUBTITLE_DELAY_BUNDLE_KEY)?.let {
|
savedInstanceState?.getLong(SUBTITLE_DELAY_BUNDLE_KEY)?.let {
|
||||||
subtitleDelay = it
|
subtitleDelay = it
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,17 +199,8 @@ data class CurrentTracks(
|
||||||
class InvalidFileException(msg: String) : Exception(msg)
|
class InvalidFileException(msg: String) : Exception(msg)
|
||||||
|
|
||||||
//http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4
|
//http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4
|
||||||
const val STATE_RESUME_WINDOW = "resumeWindow"
|
|
||||||
const val STATE_RESUME_POSITION = "resumePosition"
|
|
||||||
const val STATE_PLAYER_FULLSCREEN = "playerFullscreen"
|
|
||||||
const val STATE_PLAYER_PLAYING = "playerOnPlay"
|
|
||||||
const val ACTION_MEDIA_CONTROL = "media_control"
|
const val ACTION_MEDIA_CONTROL = "media_control"
|
||||||
const val EXTRA_CONTROL_TYPE = "control_type"
|
const val EXTRA_CONTROL_TYPE = "control_type"
|
||||||
const val PLAYBACK_SPEED = "playback_speed"
|
|
||||||
const val RESIZE_MODE_KEY = "resize_mode" // Last used resize mode
|
|
||||||
const val PLAYBACK_SPEED_KEY = "playback_speed" // Last used playback speed
|
|
||||||
const val PREFERRED_SUBS_KEY = "preferred_subtitles" // Last used resize mode
|
|
||||||
//const val PLAYBACK_FASTFORWARD = "playback_fastforward" // Last used resize mode
|
|
||||||
|
|
||||||
/** Abstract Exoplayer logic, can be expanded to other players */
|
/** Abstract Exoplayer logic, can be expanded to other players */
|
||||||
interface IPlayer {
|
interface IPlayer {
|
||||||
|
|
|
@ -28,86 +28,122 @@ const val MIN_LOD = 3
|
||||||
interface IPreviewGenerator {
|
interface IPreviewGenerator {
|
||||||
fun hasPreview(): Boolean
|
fun hasPreview(): Boolean
|
||||||
fun getPreviewImage(fraction: Float): Bitmap?
|
fun getPreviewImage(fraction: Float): Bitmap?
|
||||||
fun clear(keepCache: Boolean = false)
|
|
||||||
fun release()
|
fun release()
|
||||||
|
|
||||||
|
var durationMs: Long
|
||||||
|
var loadedImages: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** PreviewGenerator that hides the implementation details of the sub generators that is used, used for source switch cache */
|
||||||
class PreviewGenerator : IPreviewGenerator {
|
class PreviewGenerator : IPreviewGenerator {
|
||||||
|
/** the most up to date generator, will always mirror the actual source in the player */
|
||||||
private var currentGenerator: IPreviewGenerator = NoPreviewGenerator()
|
private var currentGenerator: IPreviewGenerator = NoPreviewGenerator()
|
||||||
|
/** the longest generated preview of the same episode */
|
||||||
|
private var lastGenerator: IPreviewGenerator = NoPreviewGenerator()
|
||||||
|
/** always NoPreviewGenerator, used as a cache for nothing */
|
||||||
|
private val dummy: IPreviewGenerator = NoPreviewGenerator()
|
||||||
|
|
||||||
|
/** if the current generator is the same as the last by checking time */
|
||||||
|
private fun isSameLength(): Boolean =
|
||||||
|
currentGenerator.durationMs.minus(lastGenerator.durationMs).absoluteValue < 10_000L
|
||||||
|
|
||||||
|
/** use the backup if the current generator is init or if they have the same length */
|
||||||
|
private val backupGenerator: IPreviewGenerator
|
||||||
|
get() {
|
||||||
|
if (currentGenerator.durationMs == 0L || isSameLength()) {
|
||||||
|
return lastGenerator
|
||||||
|
}
|
||||||
|
return dummy
|
||||||
|
}
|
||||||
|
|
||||||
override fun hasPreview(): Boolean {
|
override fun hasPreview(): Boolean {
|
||||||
return currentGenerator.hasPreview()
|
return currentGenerator.hasPreview() || backupGenerator.hasPreview()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPreviewImage(fraction: Float): Bitmap? {
|
override fun getPreviewImage(fraction: Float): Bitmap? {
|
||||||
return try {
|
return try {
|
||||||
currentGenerator.getPreviewImage(fraction)
|
currentGenerator.getPreviewImage(fraction) ?: backupGenerator.getPreviewImage(fraction)
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
logError(t)
|
logError(t)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clear(keepCache: Boolean) {
|
override fun release() {
|
||||||
currentGenerator.clear(keepCache)
|
lastGenerator.release()
|
||||||
|
currentGenerator.release()
|
||||||
|
lastGenerator = NoPreviewGenerator()
|
||||||
|
currentGenerator = NoPreviewGenerator()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun release() {
|
override var durationMs: Long
|
||||||
currentGenerator.release()
|
get() = currentGenerator.durationMs
|
||||||
|
set(_) {}
|
||||||
|
override var loadedImages: Int
|
||||||
|
get() = currentGenerator.loadedImages
|
||||||
|
set(_) {}
|
||||||
|
|
||||||
|
fun clear(keepCache: Boolean) {
|
||||||
|
if (keepCache) {
|
||||||
|
if (!isSameLength() || currentGenerator.loadedImages >= lastGenerator.loadedImages || lastGenerator.durationMs == 0L) {
|
||||||
|
// the current generator is better than the last generator, therefore keep the current
|
||||||
|
// or the lengths are not the same, therefore favoring the more recent selection
|
||||||
|
|
||||||
|
// if they are the same we favor the current generator
|
||||||
|
lastGenerator.release()
|
||||||
|
lastGenerator = currentGenerator
|
||||||
|
} else {
|
||||||
|
// otherwise just keep the last generator and throw away the current generator
|
||||||
|
currentGenerator.release()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we switched the episode, therefore keep nothing
|
||||||
|
lastGenerator.release()
|
||||||
|
lastGenerator = NoPreviewGenerator()
|
||||||
|
currentGenerator.release()
|
||||||
|
// we assume that we set currentGenerator right after this, so currentGenerator != NoPreviewGenerator
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun load(link: ExtractorLink, keepCache: Boolean) {
|
fun load(link: ExtractorLink, keepCache: Boolean) {
|
||||||
val gen = currentGenerator
|
clear(keepCache)
|
||||||
|
|
||||||
when (link.type) {
|
when (link.type) {
|
||||||
ExtractorLinkType.M3U8 -> {
|
ExtractorLinkType.M3U8 -> {
|
||||||
if (gen is M3u8PreviewGenerator) {
|
currentGenerator = M3u8PreviewGenerator().apply {
|
||||||
gen.load(keepCache = keepCache, url = link.url, headers = link.getAllHeaders())
|
load(url = link.url, headers = link.getAllHeaders())
|
||||||
} else {
|
|
||||||
currentGenerator.release()
|
|
||||||
currentGenerator = M3u8PreviewGenerator().apply {
|
|
||||||
load(keepCache = keepCache, url = link.url, headers = link.getAllHeaders())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtractorLinkType.VIDEO -> {
|
ExtractorLinkType.VIDEO -> {
|
||||||
if (gen is Mp4PreviewGenerator) {
|
currentGenerator = Mp4PreviewGenerator().apply {
|
||||||
gen.load(keepCache = keepCache, url = link.url, headers = link.getAllHeaders())
|
load(url = link.url, headers = link.getAllHeaders())
|
||||||
} else {
|
|
||||||
currentGenerator.release()
|
|
||||||
currentGenerator = Mp4PreviewGenerator().apply {
|
|
||||||
load(keepCache = keepCache, url = link.url, headers = link.getAllHeaders())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
Log.i("PreviewImg", "unsupported format for $link")
|
Log.i("PreviewImg", "unsupported format for $link")
|
||||||
currentGenerator.clear(keepCache)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun load(context: Context, link: ExtractorUri, keepCache: Boolean) {
|
fun load(context: Context, link: ExtractorUri, keepCache: Boolean) {
|
||||||
val gen = currentGenerator
|
clear(keepCache)
|
||||||
if (gen is Mp4PreviewGenerator) {
|
currentGenerator = Mp4PreviewGenerator().apply {
|
||||||
gen.load(keepCache = keepCache, context = context, uri = link.uri)
|
load(keepCache = keepCache, context = context, uri = link.uri)
|
||||||
} else {
|
|
||||||
currentGenerator.release()
|
|
||||||
currentGenerator = Mp4PreviewGenerator().apply {
|
|
||||||
load(keepCache = keepCache, context = context, uri = link.uri)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NoPreviewGenerator : IPreviewGenerator {
|
private class NoPreviewGenerator : IPreviewGenerator {
|
||||||
override fun hasPreview(): Boolean = false
|
override fun hasPreview(): Boolean = false
|
||||||
override fun getPreviewImage(fraction: Float): Bitmap? = null
|
override fun getPreviewImage(fraction: Float): Bitmap? = null
|
||||||
override fun clear(keepCache: Boolean) = Unit
|
|
||||||
override fun release() = Unit
|
override fun release() = Unit
|
||||||
|
override var durationMs: Long = 0L
|
||||||
|
override var loadedImages: Int = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
class M3u8PreviewGenerator : IPreviewGenerator {
|
private class M3u8PreviewGenerator : IPreviewGenerator {
|
||||||
// generated images 1:1 to idx of hsl
|
// generated images 1:1 to idx of hsl
|
||||||
private var images: Array<Bitmap?> = arrayOf()
|
private var images: Array<Bitmap?> = arrayOf()
|
||||||
|
|
||||||
|
@ -118,7 +154,7 @@ class M3u8PreviewGenerator : IPreviewGenerator {
|
||||||
private var prefixSum: Array<Double> = arrayOf()
|
private var prefixSum: Array<Double> = arrayOf()
|
||||||
|
|
||||||
// how many images has been generated
|
// how many images has been generated
|
||||||
private var loadedImages: Int = 0
|
override var loadedImages: Int = 0
|
||||||
|
|
||||||
// how many images we can generate in total, == hsl.size ?: 0
|
// how many images we can generate in total, == hsl.size ?: 0
|
||||||
private var totalImages: Int = 0
|
private var totalImages: Int = 0
|
||||||
|
@ -155,7 +191,7 @@ class M3u8PreviewGenerator : IPreviewGenerator {
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clear(keepCache: Boolean) {
|
private fun clear() {
|
||||||
synchronized(images) {
|
synchronized(images) {
|
||||||
currentJob?.cancel()
|
currentJob?.cancel()
|
||||||
images = arrayOf()
|
images = arrayOf()
|
||||||
|
@ -170,9 +206,11 @@ class M3u8PreviewGenerator : IPreviewGenerator {
|
||||||
images = arrayOf()
|
images = arrayOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override var durationMs: Long = 0L
|
||||||
|
|
||||||
private var currentJob: Job? = null
|
private var currentJob: Job? = null
|
||||||
fun load(keepCache: Boolean, url: String, headers: Map<String, String>) {
|
fun load(url: String, headers: Map<String, String>) {
|
||||||
clear(keepCache)
|
clear()
|
||||||
currentJob?.cancel()
|
currentJob?.cancel()
|
||||||
currentJob = ioSafe {
|
currentJob = ioSafe {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
|
@ -201,6 +239,7 @@ class M3u8PreviewGenerator : IPreviewGenerator {
|
||||||
|
|
||||||
// total duration of the entire m3u8 in seconds
|
// total duration of the entire m3u8 in seconds
|
||||||
val duration = hsl.allTsLinks.sumOf { it.time ?: 0.0 }
|
val duration = hsl.allTsLinks.sumOf { it.time ?: 0.0 }
|
||||||
|
durationMs = (duration * 1000.0).toLong()
|
||||||
val durationInv = 1.0 / duration
|
val durationInv = 1.0 / duration
|
||||||
|
|
||||||
// if the total duration is less then 10s then something is very wrong or
|
// if the total duration is less then 10s then something is very wrong or
|
||||||
|
@ -245,7 +284,7 @@ class M3u8PreviewGenerator : IPreviewGenerator {
|
||||||
if (!isActive) {
|
if (!isActive) {
|
||||||
return@withContext
|
return@withContext
|
||||||
}
|
}
|
||||||
if(img == null || img.width <= 1 || img.height <= 1) continue
|
if (img == null || img.width <= 1 || img.height <= 1) continue
|
||||||
synchronized(images) {
|
synchronized(images) {
|
||||||
images[index] = img
|
images[index] = img
|
||||||
loadedImages += 1
|
loadedImages += 1
|
||||||
|
@ -269,11 +308,11 @@ class M3u8PreviewGenerator : IPreviewGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Mp4PreviewGenerator : IPreviewGenerator {
|
private class Mp4PreviewGenerator : IPreviewGenerator {
|
||||||
// lod = level of detail where the number indicates how many ones there is
|
// lod = level of detail where the number indicates how many ones there is
|
||||||
// 2^(lod-1) = images
|
// 2^(lod-1) = images
|
||||||
private var loadedLod = 0
|
private var loadedLod = 0
|
||||||
private var loadedImages = 0
|
override var loadedImages = 0
|
||||||
private var images = Array<Bitmap?>((1 shl MAX_LOD) - 1) {
|
private var images = Array<Bitmap?>((1 shl MAX_LOD) - 1) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@ -305,7 +344,7 @@ class Mp4PreviewGenerator : IPreviewGenerator {
|
||||||
if (idx > loadedImages) {
|
if (idx > loadedImages) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if(images[idx] == null) {
|
if (images[idx] == null) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val currentFraction =
|
val currentFraction =
|
||||||
|
@ -325,7 +364,7 @@ class Mp4PreviewGenerator : IPreviewGenerator {
|
||||||
// also check out https://github.com/wseemann/FFmpegMediaMetadataRetriever
|
// also check out https://github.com/wseemann/FFmpegMediaMetadataRetriever
|
||||||
private val retriever: MediaMetadataRetriever = MediaMetadataRetriever()
|
private val retriever: MediaMetadataRetriever = MediaMetadataRetriever()
|
||||||
|
|
||||||
override fun clear(keepCache: Boolean) {
|
private fun clear(keepCache: Boolean) {
|
||||||
if (keepCache) return
|
if (keepCache) return
|
||||||
synchronized(images) {
|
synchronized(images) {
|
||||||
loadedLod = 0
|
loadedLod = 0
|
||||||
|
@ -335,11 +374,11 @@ class Mp4PreviewGenerator : IPreviewGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private var currentJob: Job? = null
|
private var currentJob: Job? = null
|
||||||
fun load(keepCache: Boolean, url: String, headers: Map<String, String>) {
|
fun load(url: String, headers: Map<String, String>) {
|
||||||
currentJob?.cancel()
|
currentJob?.cancel()
|
||||||
currentJob = ioSafe {
|
currentJob = ioSafe {
|
||||||
Log.i(TAG, "Loading with url = $url headers = $headers")
|
Log.i(TAG, "Loading with url = $url headers = $headers")
|
||||||
clear(keepCache)
|
clear(true)
|
||||||
retriever.setDataSource(url, headers)
|
retriever.setDataSource(url, headers)
|
||||||
start(this)
|
start(this)
|
||||||
}
|
}
|
||||||
|
@ -360,6 +399,8 @@ class Mp4PreviewGenerator : IPreviewGenerator {
|
||||||
clear(false)
|
clear(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override var durationMs: Long = 0L
|
||||||
|
|
||||||
@Throws
|
@Throws
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
private fun start(scope: CoroutineScope) {
|
private fun start(scope: CoroutineScope) {
|
||||||
|
@ -368,6 +409,7 @@ class Mp4PreviewGenerator : IPreviewGenerator {
|
||||||
val durationMs =
|
val durationMs =
|
||||||
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong()
|
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong()
|
||||||
?: throw IllegalArgumentException("Bad video duration")
|
?: throw IllegalArgumentException("Bad video duration")
|
||||||
|
this.durationMs = durationMs
|
||||||
val durationUs = (durationMs * 1000L).toFloat()
|
val durationUs = (durationMs * 1000L).toFloat()
|
||||||
//val width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toInt() ?: throw IllegalArgumentException("Bad video width")
|
//val width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toInt() ?: throw IllegalArgumentException("Bad video width")
|
||||||
//val height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toInt() ?: throw IllegalArgumentException("Bad video height")
|
//val height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toInt() ?: throw IllegalArgumentException("Bad video height")
|
||||||
|
@ -388,7 +430,7 @@ class Mp4PreviewGenerator : IPreviewGenerator {
|
||||||
MediaMetadataRetriever.OPTION_CLOSEST_SYNC
|
MediaMetadataRetriever.OPTION_CLOSEST_SYNC
|
||||||
)
|
)
|
||||||
if (!scope.isActive) return
|
if (!scope.isActive) return
|
||||||
if(img == null || img.width <= 1 || img.height <= 1) continue
|
if (img == null || img.width <= 1 || img.height <= 1) continue
|
||||||
synchronized(images) {
|
synchronized(images) {
|
||||||
images[idx] = img
|
images[idx] = img
|
||||||
loadedImages = maxOf(loadedImages, idx)
|
loadedImages = maxOf(loadedImages, idx)
|
||||||
|
|
|
@ -22,17 +22,22 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.lagradost.cloudstream3.*
|
|
||||||
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
|
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
|
||||||
import com.lagradost.cloudstream3.APIHolder.filterSearchResultByFilmQuality
|
import com.lagradost.cloudstream3.APIHolder.filterSearchResultByFilmQuality
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
|
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiSettings
|
import com.lagradost.cloudstream3.APIHolder.getApiSettings
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKeys
|
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKeys
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
import com.lagradost.cloudstream3.AllLanguagesName
|
||||||
|
import com.lagradost.cloudstream3.AnimeSearchResponse
|
||||||
|
import com.lagradost.cloudstream3.HomePageList
|
||||||
|
import com.lagradost.cloudstream3.MainAPI
|
||||||
|
import com.lagradost.cloudstream3.MainActivity
|
||||||
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
|
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
|
||||||
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.SearchResponse
|
||||||
|
import com.lagradost.cloudstream3.TvType
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentSearchBinding
|
import com.lagradost.cloudstream3.databinding.FragmentSearchBinding
|
||||||
import com.lagradost.cloudstream3.databinding.HomeSelectMainpageBinding
|
import com.lagradost.cloudstream3.databinding.HomeSelectMainpageBinding
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
|
@ -53,8 +58,7 @@ import com.lagradost.cloudstream3.utils.AppUtils.ownHide
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.ownShow
|
import com.lagradost.cloudstream3.utils.AppUtils.ownShow
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.setDefaultFocus
|
import com.lagradost.cloudstream3.utils.AppUtils.setDefaultFocus
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.currentAccount
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.currentAccount
|
||||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
|
@ -63,9 +67,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
|
|
||||||
const val SEARCH_PREF_TAGS = "search_pref_tags"
|
|
||||||
const val SEARCH_PREF_PROVIDERS = "search_pref_providers"
|
|
||||||
|
|
||||||
class SearchFragment : Fragment() {
|
class SearchFragment : Fragment() {
|
||||||
companion object {
|
companion object {
|
||||||
fun List<SearchResponse>.filterSearchResponse(): List<SearchResponse> {
|
fun List<SearchResponse>.filterSearchResponse(): List<SearchResponse> {
|
||||||
|
@ -194,7 +195,7 @@ class SearchFragment : Fragment() {
|
||||||
validAPIs.flatMap { api -> api.supportedTypes }.distinct()
|
validAPIs.flatMap { api -> api.supportedTypes }.distinct()
|
||||||
) { list ->
|
) { list ->
|
||||||
if (selectedSearchTypes.toSet() != list.toSet()) {
|
if (selectedSearchTypes.toSet() != list.toSet()) {
|
||||||
setKey("$currentAccount/$SEARCH_PREF_TAGS", selectedSearchTypes)
|
DataStoreHelper.searchPreferenceTags = list
|
||||||
selectedSearchTypes.clear()
|
selectedSearchTypes.clear()
|
||||||
selectedSearchTypes.addAll(list)
|
selectedSearchTypes.addAll(list)
|
||||||
search(binding?.mainSearch?.query?.toString())
|
search(binding?.mainSearch?.query?.toString())
|
||||||
|
@ -233,13 +234,7 @@ class SearchFragment : Fragment() {
|
||||||
//searchMagIcon.scaleX = 0.65f
|
//searchMagIcon.scaleX = 0.65f
|
||||||
//searchMagIcon.scaleY = 0.65f
|
//searchMagIcon.scaleY = 0.65f
|
||||||
|
|
||||||
context?.let { ctx ->
|
selectedApis = DataStoreHelper.searchPreferenceProviders.toMutableSet()
|
||||||
val validAPIs = ctx.filterProviderByPreferredMedia()
|
|
||||||
selectedApis = ctx.getKey(
|
|
||||||
"$currentAccount/$SEARCH_PREF_PROVIDERS",
|
|
||||||
defVal = validAPIs.map { it.name }
|
|
||||||
)!!.toMutableSet()
|
|
||||||
}
|
|
||||||
|
|
||||||
binding?.searchFilter?.setOnClickListener { searchView ->
|
binding?.searchFilter?.setOnClickListener { searchView ->
|
||||||
searchView?.context?.let { ctx ->
|
searchView?.context?.let { ctx ->
|
||||||
|
@ -287,7 +282,7 @@ class SearchFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateList(types: List<TvType>) {
|
fun updateList(types: List<TvType>) {
|
||||||
setKey("$currentAccount/$SEARCH_PREF_TAGS", types.map { it.name })
|
DataStoreHelper.searchPreferenceTags = types
|
||||||
|
|
||||||
arrayAdapter.clear()
|
arrayAdapter.clear()
|
||||||
currentValidApis = validAPIs.filter { api ->
|
currentValidApis = validAPIs.filter { api ->
|
||||||
|
@ -312,12 +307,7 @@ class SearchFragment : Fragment() {
|
||||||
arrayAdapter.notifyDataSetChanged()
|
arrayAdapter.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
val selectedSearchTypes = getKey<List<String>>("$currentAccount/$SEARCH_PREF_TAGS")
|
val selectedSearchTypes = DataStoreHelper.searchPreferenceTags
|
||||||
?.mapNotNull { listName ->
|
|
||||||
TvType.values().firstOrNull { it.name == listName }
|
|
||||||
}
|
|
||||||
?.toMutableList()
|
|
||||||
?: mutableListOf(TvType.Movie, TvType.TvSeries)
|
|
||||||
|
|
||||||
bindChips(
|
bindChips(
|
||||||
binding.tvtypesChipsScroll.tvtypesChips,
|
binding.tvtypesChipsScroll.tvtypesChips,
|
||||||
|
@ -343,7 +333,7 @@ class SearchFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.setOnDismissListener {
|
dialog.setOnDismissListener {
|
||||||
context?.setKey("$currentAccount/$SEARCH_PREF_PROVIDERS", currentSelectedApis.toList())
|
DataStoreHelper.searchPreferenceProviders = currentSelectedApis.toList()
|
||||||
selectedApis = currentSelectedApis
|
selectedApis = currentSelectedApis
|
||||||
}
|
}
|
||||||
updateList(selectedSearchTypes.toList())
|
updateList(selectedSearchTypes.toList())
|
||||||
|
@ -354,10 +344,7 @@ class SearchFragment : Fragment() {
|
||||||
val settingsManager = context?.let { PreferenceManager.getDefaultSharedPreferences(it) }
|
val settingsManager = context?.let { PreferenceManager.getDefaultSharedPreferences(it) }
|
||||||
val isAdvancedSearch = settingsManager?.getBoolean("advanced_search", true) ?: true
|
val isAdvancedSearch = settingsManager?.getBoolean("advanced_search", true) ?: true
|
||||||
|
|
||||||
selectedSearchTypes = context?.getKey<List<String>>("$currentAccount/$SEARCH_PREF_TAGS")
|
selectedSearchTypes = DataStoreHelper.searchPreferenceTags.toMutableList()
|
||||||
?.mapNotNull { listName -> TvType.values().firstOrNull { it.name == listName } }
|
|
||||||
?.toMutableList()
|
|
||||||
?: mutableListOf(TvType.Movie, TvType.TvSeries)
|
|
||||||
|
|
||||||
if (isTrueTvSettings()) {
|
if (isTrueTvSettings()) {
|
||||||
binding?.searchFilter?.isFocusable = true
|
binding?.searchFilter?.isFocusable = true
|
||||||
|
|
|
@ -10,7 +10,9 @@ import androidx.core.widget.doOnTextChanged
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
|
||||||
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
|
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
|
||||||
|
import com.lagradost.cloudstream3.AcraApplication.Companion.context
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKeys
|
import com.lagradost.cloudstream3.AcraApplication.Companion.getKeys
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
||||||
|
@ -31,6 +33,8 @@ import com.lagradost.cloudstream3.ui.result.setImage
|
||||||
import com.lagradost.cloudstream3.ui.result.setLinearListLayout
|
import com.lagradost.cloudstream3.ui.result.setLinearListLayout
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.setDefaultFocus
|
import com.lagradost.cloudstream3.utils.AppUtils.setDefaultFocus
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
const val VIDEO_POS_DUR = "video_pos_dur"
|
const val VIDEO_POS_DUR = "video_pos_dur"
|
||||||
const val VIDEO_WATCH_STATE = "video_watch_state"
|
const val VIDEO_WATCH_STATE = "video_watch_state"
|
||||||
|
@ -44,6 +48,28 @@ const val RESULT_EPISODE = "result_episode"
|
||||||
const val RESULT_SEASON = "result_season"
|
const val RESULT_SEASON = "result_season"
|
||||||
const val RESULT_DUB = "result_dub"
|
const val RESULT_DUB = "result_dub"
|
||||||
|
|
||||||
|
|
||||||
|
class UserPreferenceDelegate<T : Any>(
|
||||||
|
private val key: String, private val default: T //, private val klass: KClass<T>
|
||||||
|
) {
|
||||||
|
private val klass: KClass<out T> = default::class
|
||||||
|
private val realKey get() = "${DataStoreHelper.currentAccount}/$key"
|
||||||
|
operator fun getValue(self: Any?, property: KProperty<*>) =
|
||||||
|
AcraApplication.getKeyClass(realKey, klass.java) ?: default
|
||||||
|
|
||||||
|
operator fun setValue(
|
||||||
|
self: Any?,
|
||||||
|
property: KProperty<*>,
|
||||||
|
t: T?
|
||||||
|
) {
|
||||||
|
if (t == null) {
|
||||||
|
removeKey(realKey)
|
||||||
|
} else {
|
||||||
|
AcraApplication.setKeyClass(realKey, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object DataStoreHelper {
|
object DataStoreHelper {
|
||||||
// be aware, don't change the index of these as Account uses the index for the art
|
// be aware, don't change the index of these as Account uses the index for the art
|
||||||
private val profileImages = arrayOf(
|
private val profileImages = arrayOf(
|
||||||
|
@ -56,6 +82,48 @@ object DataStoreHelper {
|
||||||
R.drawable.profile_bg_teal
|
R.drawable.profile_bg_teal
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private var searchPreferenceProvidersStrings : List<String> by UserPreferenceDelegate(
|
||||||
|
/** java moment right here, as listOf()::class.java != List(0) { "" }::class.java */
|
||||||
|
"search_pref_providers", List(0) { "" }
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun serializeTv(data : List<TvType>) : List<String> = data.map { it.name }
|
||||||
|
|
||||||
|
private fun deserializeTv(data : List<String>) : List<TvType> {
|
||||||
|
return data.mapNotNull { listName ->
|
||||||
|
TvType.values().firstOrNull { it.name == listName }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var searchPreferenceProviders : List<String>
|
||||||
|
get() {
|
||||||
|
val ret = searchPreferenceProvidersStrings
|
||||||
|
return ret.ifEmpty {
|
||||||
|
context?.filterProviderByPreferredMedia()?.map { it.name } ?: emptyList()
|
||||||
|
}
|
||||||
|
} set(value) {
|
||||||
|
searchPreferenceProvidersStrings = value
|
||||||
|
}
|
||||||
|
|
||||||
|
private var searchPreferenceTagsStrings : List<String> by UserPreferenceDelegate("search_pref_tags", listOf(TvType.Movie, TvType.TvSeries).map { it.name })
|
||||||
|
var searchPreferenceTags : List<TvType>
|
||||||
|
get() = deserializeTv(searchPreferenceTagsStrings)
|
||||||
|
set(value) {
|
||||||
|
searchPreferenceTagsStrings = serializeTv(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private var homePreferenceStrings : List<String> by UserPreferenceDelegate("home_pref_homepage", listOf(TvType.Movie, TvType.TvSeries).map { it.name })
|
||||||
|
var homePreference : List<TvType>
|
||||||
|
get() = deserializeTv(homePreferenceStrings)
|
||||||
|
set(value) {
|
||||||
|
homePreferenceStrings = serializeTv(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
var homeBookmarkedList : IntArray by UserPreferenceDelegate("home_bookmarked_last_list", IntArray(0))
|
||||||
|
var playBackSpeed : Float by UserPreferenceDelegate("playback_speed", 1.0f)
|
||||||
|
var resizeMode : Int by UserPreferenceDelegate("resize_mode", 0)
|
||||||
|
|
||||||
data class Account(
|
data class Account(
|
||||||
@JsonProperty("keyIndex")
|
@JsonProperty("keyIndex")
|
||||||
val keyIndex: Int,
|
val keyIndex: Int,
|
||||||
|
|
|
@ -349,14 +349,15 @@
|
||||||
android:layout_width="150dp"
|
android:layout_width="150dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:layout_marginEnd="100dp"
|
android:layout_marginEnd="100dp"
|
||||||
|
android:layout_marginTop="60dp"
|
||||||
android:backgroundTint="@color/skipOpTransparent"
|
android:backgroundTint="@color/skipOpTransparent"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:padding="10dp"
|
android:padding="10dp"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:cornerRadius="@dimen/rounded_button_radius"
|
app:cornerRadius="@dimen/rounded_button_radius"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/bottom_player_bar"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/player_top_holder"
|
||||||
app:strokeColor="@color/white"
|
app:strokeColor="@color/white"
|
||||||
app:strokeWidth="1dp"
|
app:strokeWidth="1dp"
|
||||||
tools:text="Skip Opening"
|
tools:text="Skip Opening"
|
||||||
|
@ -435,6 +436,7 @@
|
||||||
android:id="@+id/player_video_bar"
|
android:id="@+id/player_video_bar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
tools:visibility="visible"
|
||||||
android:layoutDirection="ltr"
|
android:layoutDirection="ltr"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue