mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
bff9727f96
12 changed files with 261 additions and 142 deletions
|
@ -128,6 +128,7 @@ import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
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.DataStore.getKey
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching
|
||||||
import com.lagradost.cloudstream3.utils.Event
|
import com.lagradost.cloudstream3.utils.Event
|
||||||
import com.lagradost.cloudstream3.utils.IOnBackPressed
|
import com.lagradost.cloudstream3.utils.IOnBackPressed
|
||||||
|
@ -305,6 +306,10 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
|
|
||||||
// kinda shitty solution, but cant com main->home otherwise for popups
|
// kinda shitty solution, but cant com main->home otherwise for popups
|
||||||
val bookmarksUpdatedEvent = Event<Boolean>()
|
val bookmarksUpdatedEvent = Event<Boolean>()
|
||||||
|
/**
|
||||||
|
* Used by data store helper to fully reload home when switching accounts
|
||||||
|
*/
|
||||||
|
val reloadHomeEvent = Event<Boolean>()
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -539,6 +544,10 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
val isTrueTv = isTrueTvSettings()
|
val isTrueTv = isTrueTvSettings()
|
||||||
navView.menu.findItem(R.id.navigation_library)?.isVisible = !isTrueTv
|
navView.menu.findItem(R.id.navigation_library)?.isVisible = !isTrueTv
|
||||||
navRailView.menu.findItem(R.id.navigation_library)?.isVisible = !isTrueTv
|
navRailView.menu.findItem(R.id.navigation_library)?.isVisible = !isTrueTv
|
||||||
|
|
||||||
|
// Hide downloads on TV
|
||||||
|
navView.menu.findItem(R.id.navigation_downloads)?.isVisible = !isTrueTv
|
||||||
|
navRailView.menu.findItem(R.id.navigation_downloads)?.isVisible = !isTrueTv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1092,15 +1101,19 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
updateTv()
|
updateTv()
|
||||||
|
|
||||||
// backup when we update the app, I don't trust myself to not boot lock users, might want to make this a setting?
|
// backup when we update the app, I don't trust myself to not boot lock users, might want to make this a setting?
|
||||||
try {
|
normalSafeApiCall {
|
||||||
val appVer = BuildConfig.VERSION_NAME
|
val appVer = BuildConfig.VERSION_NAME
|
||||||
val lastAppAutoBackup: String = getKey("VERSION_NAME") ?: ""
|
val lastAppAutoBackup: String = getKey("VERSION_NAME") ?: ""
|
||||||
if (appVer != lastAppAutoBackup) {
|
if (appVer != lastAppAutoBackup) {
|
||||||
setKey("VERSION_NAME", BuildConfig.VERSION_NAME)
|
setKey("VERSION_NAME", BuildConfig.VERSION_NAME)
|
||||||
backup()
|
normalSafeApiCall {
|
||||||
|
backup()
|
||||||
|
}
|
||||||
|
normalSafeApiCall {
|
||||||
|
// Recompile oat on new version
|
||||||
|
PluginManager.deleteAllOatFiles(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (t: Throwable) {
|
|
||||||
logError(t)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// just in case, MAIN SHOULD *NEVER* BOOT LOOP CRASH
|
// just in case, MAIN SHOULD *NEVER* BOOT LOOP CRASH
|
||||||
|
@ -1112,16 +1125,17 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
newLocalBinding.root.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus ->
|
newLocalBinding.root.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus ->
|
||||||
// println("refocus $oldFocus -> $newFocus")
|
// println("refocus $oldFocus -> $newFocus")
|
||||||
try {
|
try {
|
||||||
val r = Rect(0,0,0,0)
|
val r = Rect(0, 0, 0, 0)
|
||||||
newFocus.getDrawingRect(r)
|
newFocus.getDrawingRect(r)
|
||||||
val x = r.centerX()
|
val x = r.centerX()
|
||||||
val y = r.centerY()
|
val y = r.centerY()
|
||||||
val dx = 0 //screenWidth / 2
|
val dx = 0 //screenWidth / 2
|
||||||
val dy = screenHeight / 2
|
val dy = screenHeight / 2
|
||||||
val r2 = Rect(x-dx,y-dy,x+dx,y+dy)
|
val r2 = Rect(x - dx, y - dy, x + dx, y + dy)
|
||||||
newFocus.requestRectangleOnScreen(r2, false)
|
newFocus.requestRectangleOnScreen(r2, false)
|
||||||
// TvFocus.current =TvFocus.current.copy(y=y.toFloat())
|
// TvFocus.current =TvFocus.current.copy(y=y.toFloat())
|
||||||
} catch (_ : Throwable) { }
|
} catch (_: Throwable) {
|
||||||
|
}
|
||||||
TvFocus.updateFocusView(newFocus)
|
TvFocus.updateFocusView(newFocus)
|
||||||
/*var focus = newFocus
|
/*var focus = newFocus
|
||||||
|
|
||||||
|
@ -1182,7 +1196,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
}
|
}
|
||||||
} else if (lastError == null) {
|
} else if (lastError == null) {
|
||||||
ioSafe {
|
ioSafe {
|
||||||
getKey<String>(USER_SELECTED_HOMEPAGE_API)?.let { homeApi ->
|
DataStoreHelper.currentHomePage?.let { homeApi ->
|
||||||
mainPluginsLoadedEvent.invoke(loadSinglePlugin(this@MainActivity, homeApi))
|
mainPluginsLoadedEvent.invoke(loadSinglePlugin(this@MainActivity, homeApi))
|
||||||
} ?: run {
|
} ?: run {
|
||||||
mainPluginsLoadedEvent.invoke(false)
|
mainPluginsLoadedEvent.invoke(false)
|
||||||
|
@ -1543,6 +1557,11 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
migrateResumeWatching()
|
migrateResumeWatching()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getKey<String>(USER_SELECTED_HOMEPAGE_API)?.let { homepage ->
|
||||||
|
DataStoreHelper.currentHomePage = homepage
|
||||||
|
removeKey(USER_SELECTED_HOMEPAGE_API)
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (getKey(HAS_DONE_SETUP_KEY, false) != true) {
|
if (getKey(HAS_DONE_SETUP_KEY, false) != true) {
|
||||||
navController.navigate(R.id.navigation_setup_language)
|
navController.navigate(R.id.navigation_setup_language)
|
||||||
|
|
|
@ -137,6 +137,20 @@ object PluginManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all generated oat files which will force Android to recompile the dex extensions.
|
||||||
|
* This might fix unrecoverable SIGSEGV exceptions when old oat files are loaded in a new app update.
|
||||||
|
*/
|
||||||
|
fun deleteAllOatFiles(context: Context) {
|
||||||
|
File("${context.filesDir}/${ONLINE_PLUGINS_FOLDER}").listFiles()?.forEach { repo ->
|
||||||
|
repo.listFiles { file -> file.name == "oat" && file.isDirectory }?.forEach { file ->
|
||||||
|
val success = file.deleteRecursively()
|
||||||
|
Log.i(TAG, "Deleted oat directory: ${file.absolutePath} Success=$success")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun getPluginsOnline(): Array<PluginData> {
|
fun getPluginsOnline(): Array<PluginData> {
|
||||||
return getKey(PLUGINS_KEY) ?: emptyArray()
|
return getKey(PLUGINS_KEY) ?: emptyArray()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.ui
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.core.view.children
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
@ -70,8 +71,8 @@ class GrdLayoutManager(val context: Context, _spanCount: Int) :
|
||||||
val orientation = this.orientation
|
val orientation = this.orientation
|
||||||
|
|
||||||
// fixes arabic by inverting left and right layout focus
|
// fixes arabic by inverting left and right layout focus
|
||||||
val correctDirection = if(this.isLayoutRTL) {
|
val correctDirection = if (this.isLayoutRTL) {
|
||||||
when(direction) {
|
when (direction) {
|
||||||
View.FOCUS_RIGHT -> View.FOCUS_LEFT
|
View.FOCUS_RIGHT -> View.FOCUS_LEFT
|
||||||
View.FOCUS_LEFT -> View.FOCUS_RIGHT
|
View.FOCUS_LEFT -> View.FOCUS_RIGHT
|
||||||
else -> direction
|
else -> direction
|
||||||
|
@ -83,12 +84,15 @@ class GrdLayoutManager(val context: Context, _spanCount: Int) :
|
||||||
View.FOCUS_DOWN -> {
|
View.FOCUS_DOWN -> {
|
||||||
return spanCount
|
return spanCount
|
||||||
}
|
}
|
||||||
|
|
||||||
View.FOCUS_UP -> {
|
View.FOCUS_UP -> {
|
||||||
return -spanCount
|
return -spanCount
|
||||||
}
|
}
|
||||||
|
|
||||||
View.FOCUS_RIGHT -> {
|
View.FOCUS_RIGHT -> {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
View.FOCUS_LEFT -> {
|
View.FOCUS_LEFT -> {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
@ -98,12 +102,15 @@ class GrdLayoutManager(val context: Context, _spanCount: Int) :
|
||||||
View.FOCUS_DOWN -> {
|
View.FOCUS_DOWN -> {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
View.FOCUS_UP -> {
|
View.FOCUS_UP -> {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
View.FOCUS_RIGHT -> {
|
View.FOCUS_RIGHT -> {
|
||||||
return spanCount
|
return spanCount
|
||||||
}
|
}
|
||||||
|
|
||||||
View.FOCUS_LEFT -> {
|
View.FOCUS_LEFT -> {
|
||||||
return -spanCount
|
return -spanCount
|
||||||
}
|
}
|
||||||
|
@ -156,3 +163,31 @@ class AutofitRecyclerView @JvmOverloads constructor(context: Context, attrs: Att
|
||||||
layoutManager = manager
|
layoutManager = manager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recyclerview wherein the max item width or height is set by the biggest view to prevent inconsistent view sizes.
|
||||||
|
*/
|
||||||
|
class MaxRecyclerView(ctx: Context, attrs: AttributeSet) : RecyclerView(ctx, attrs) {
|
||||||
|
private var biggestObserved: Int = 0
|
||||||
|
private val orientation = LayoutManager.getProperties(context, attrs, 0, 0).orientation
|
||||||
|
private val isHorizontal = orientation == HORIZONTAL
|
||||||
|
private fun View.updateMaxSize() {
|
||||||
|
if (isHorizontal) {
|
||||||
|
this.minimumHeight = biggestObserved
|
||||||
|
} else {
|
||||||
|
this.minimumWidth = biggestObserved
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onChildAttachedToWindow(child: View) {
|
||||||
|
child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
|
||||||
|
val observed = if (isHorizontal) child.measuredHeight else child.measuredWidth
|
||||||
|
if (observed > biggestObserved) {
|
||||||
|
biggestObserved = observed
|
||||||
|
children.forEach { it.updateMaxSize() }
|
||||||
|
} else {
|
||||||
|
child.updateMaxSize()
|
||||||
|
}
|
||||||
|
super.onChildAttachedToWindow(child)
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,7 +69,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
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 com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
|
|
||||||
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
@ -669,7 +668,7 @@ class HomeFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
homeViewModel.reloadStored()
|
homeViewModel.reloadStored()
|
||||||
homeViewModel.loadAndCancel(getKey(USER_SELECTED_HOMEPAGE_API), false)
|
homeViewModel.loadAndCancel(DataStoreHelper.currentHomePage, false)
|
||||||
//loadHomePage(false)
|
//loadHomePage(false)
|
||||||
|
|
||||||
// nice profile pic on homepage
|
// nice profile pic on homepage
|
||||||
|
|
|
@ -49,7 +49,6 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getLastWatched
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getLastWatched
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultWatchState
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultWatchState
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
||||||
import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
|
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
@ -426,23 +425,29 @@ class HomeViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun afterPluginsLoaded(forceReload: Boolean) {
|
private fun afterPluginsLoaded(forceReload: Boolean) {
|
||||||
loadAndCancel(getKey(USER_SELECTED_HOMEPAGE_API), forceReload)
|
loadAndCancel(DataStoreHelper.currentHomePage, forceReload)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun afterMainPluginsLoaded(unused: Boolean = false) {
|
private fun afterMainPluginsLoaded(unused: Boolean = false) {
|
||||||
loadAndCancel(getKey(USER_SELECTED_HOMEPAGE_API), false)
|
loadAndCancel(DataStoreHelper.currentHomePage, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reloadHome(unused: Boolean = false) {
|
||||||
|
loadAndCancel(DataStoreHelper.currentHomePage, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
MainActivity.bookmarksUpdatedEvent += ::bookmarksUpdated
|
MainActivity.bookmarksUpdatedEvent += ::bookmarksUpdated
|
||||||
MainActivity.afterPluginsLoadedEvent += ::afterPluginsLoaded
|
MainActivity.afterPluginsLoadedEvent += ::afterPluginsLoaded
|
||||||
MainActivity.mainPluginsLoadedEvent += ::afterMainPluginsLoaded
|
MainActivity.mainPluginsLoadedEvent += ::afterMainPluginsLoaded
|
||||||
|
MainActivity.reloadHomeEvent += ::reloadHome
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
MainActivity.bookmarksUpdatedEvent -= ::bookmarksUpdated
|
MainActivity.bookmarksUpdatedEvent -= ::bookmarksUpdated
|
||||||
MainActivity.afterPluginsLoadedEvent -= ::afterPluginsLoaded
|
MainActivity.afterPluginsLoadedEvent -= ::afterPluginsLoaded
|
||||||
MainActivity.mainPluginsLoadedEvent -= ::afterMainPluginsLoaded
|
MainActivity.mainPluginsLoadedEvent -= ::afterMainPluginsLoaded
|
||||||
|
MainActivity.reloadHomeEvent -= ::reloadHome
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,7 +500,7 @@ class HomeViewModel : ViewModel() {
|
||||||
val api = getApiFromNameNull(preferredApiName)
|
val api = getApiFromNameNull(preferredApiName)
|
||||||
if (preferredApiName == noneApi.name) {
|
if (preferredApiName == noneApi.name) {
|
||||||
// just set to random
|
// just set to random
|
||||||
if (fromUI) setKey(USER_SELECTED_HOMEPAGE_API, noneApi.name)
|
if (fromUI) DataStoreHelper.currentHomePage = noneApi.name
|
||||||
loadAndCancel(noneApi)
|
loadAndCancel(noneApi)
|
||||||
} else if (preferredApiName == randomApi.name) {
|
} else if (preferredApiName == randomApi.name) {
|
||||||
// randomize the api, if none exist like if not loaded or not installed
|
// randomize the api, if none exist like if not loaded or not installed
|
||||||
|
@ -506,7 +511,7 @@ class HomeViewModel : ViewModel() {
|
||||||
} else {
|
} else {
|
||||||
val apiRandom = validAPIs.random()
|
val apiRandom = validAPIs.random()
|
||||||
loadAndCancel(apiRandom)
|
loadAndCancel(apiRandom)
|
||||||
if (fromUI) setKey(USER_SELECTED_HOMEPAGE_API, apiRandom.name)
|
if (fromUI) DataStoreHelper.currentHomePage = apiRandom.name
|
||||||
}
|
}
|
||||||
} else if (api == null) {
|
} else if (api == null) {
|
||||||
// API is not found aka not loaded or removed, post the loading
|
// API is not found aka not loaded or removed, post the loading
|
||||||
|
@ -520,7 +525,7 @@ class HomeViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if the api is found, then set it to it and save key
|
// if the api is found, then set it to it and save key
|
||||||
if (fromUI) setKey(USER_SELECTED_HOMEPAGE_API, api.name)
|
if (fromUI) DataStoreHelper.currentHomePage = api.name
|
||||||
loadAndCancel(api)
|
loadAndCancel(api)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,7 +177,7 @@ class ResultFragmentTv : Fragment() {
|
||||||
isVisible = true
|
isVisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
this.animate().alpha(if (turnVisible) 1.0f else 0.0f).apply {
|
this.animate().alpha(if (turnVisible) 0.97f else 0.0f).apply {
|
||||||
duration = 200
|
duration = 200
|
||||||
interpolator = DecelerateInterpolator()
|
interpolator = DecelerateInterpolator()
|
||||||
setListener(object : Animator.AnimatorListener {
|
setListener(object : Animator.AnimatorListener {
|
||||||
|
@ -294,9 +294,9 @@ class ResultFragmentTv : Fragment() {
|
||||||
toggleEpisodes(true)
|
toggleEpisodes(true)
|
||||||
binding?.apply {
|
binding?.apply {
|
||||||
val views = listOf(
|
val views = listOf(
|
||||||
|
resultDubSelection,
|
||||||
resultSeasonSelection,
|
resultSeasonSelection,
|
||||||
resultRangeSelection,
|
resultRangeSelection,
|
||||||
resultDubSelection,
|
|
||||||
resultEpisodes,
|
resultEpisodes,
|
||||||
resultPlayTrailer,
|
resultPlayTrailer,
|
||||||
)
|
)
|
||||||
|
|
|
@ -518,7 +518,8 @@ class ResultViewModel2 : ViewModel() {
|
||||||
val episodeNumber = episodes[currentIndex].episode
|
val episodeNumber = episodes[currentIndex].episode
|
||||||
if (episodeNumber < currentMin) {
|
if (episodeNumber < currentMin) {
|
||||||
currentMin = episodeNumber
|
currentMin = episodeNumber
|
||||||
} else if (episodeNumber > currentMax) {
|
}
|
||||||
|
if (episodeNumber > currentMax) {
|
||||||
currentMax = episodeNumber
|
currentMax = episodeNumber
|
||||||
}
|
}
|
||||||
++currentIndex
|
++currentIndex
|
||||||
|
|
|
@ -14,7 +14,7 @@ import com.lagradost.cloudstream3.ui.APIRepository
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
|
||||||
import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
|
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog
|
||||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
||||||
|
@ -96,7 +96,7 @@ class SettingsProviders : PreferenceFragmentCompat() {
|
||||||
this.getString(R.string.prefer_media_type_key),
|
this.getString(R.string.prefer_media_type_key),
|
||||||
selectedList.map { it.toString() }.toMutableSet()
|
selectedList.map { it.toString() }.toMutableSet()
|
||||||
).apply()
|
).apply()
|
||||||
removeKey(USER_SELECTED_HOMEPAGE_API)
|
DataStoreHelper.currentHomePage = null
|
||||||
//(context ?: AcraApplication.context)?.let { ctx -> app.initClient(ctx) }
|
//(context ?: AcraApplication.context)?.let { ctx -> app.initClient(ctx) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.TvType
|
import com.lagradost.cloudstream3.TvType
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentSetupMediaBinding
|
import com.lagradost.cloudstream3.databinding.FragmentSetupMediaBinding
|
||||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||||
import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
|
|
||||||
|
|
||||||
|
|
||||||
class SetupFragmentMedia : Fragment() {
|
class SetupFragmentMedia : Fragment() {
|
||||||
|
@ -77,7 +77,7 @@ class SetupFragmentMedia : Fragment() {
|
||||||
.apply()
|
.apply()
|
||||||
|
|
||||||
// Regenerate set homepage
|
// Regenerate set homepage
|
||||||
removeKey(USER_SELECTED_HOMEPAGE_API)
|
DataStoreHelper.currentHomePage = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,10 +77,28 @@ object DataStoreHelper {
|
||||||
var selectedKeyIndex by PreferenceDelegate("$TAG/account_key_index", 0)
|
var selectedKeyIndex by PreferenceDelegate("$TAG/account_key_index", 0)
|
||||||
val currentAccount: String get() = selectedKeyIndex.toString()
|
val currentAccount: String get() = selectedKeyIndex.toString()
|
||||||
|
|
||||||
private fun setAccount(account: Account) {
|
/**
|
||||||
|
* Get or set the current account homepage.
|
||||||
|
* Setting this does not automatically reload the homepage.
|
||||||
|
*/
|
||||||
|
var currentHomePage: String?
|
||||||
|
get() = getKey("$currentAccount/$USER_SELECTED_HOMEPAGE_API")
|
||||||
|
set(value) {
|
||||||
|
val key = "$currentAccount/$USER_SELECTED_HOMEPAGE_API"
|
||||||
|
if (value == null) {
|
||||||
|
removeKey(key)
|
||||||
|
} else {
|
||||||
|
setKey(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setAccount(account: Account, refreshHomePage: Boolean) {
|
||||||
selectedKeyIndex = account.keyIndex
|
selectedKeyIndex = account.keyIndex
|
||||||
showToast(account.name)
|
showToast(account.name)
|
||||||
MainActivity.bookmarksUpdatedEvent(true)
|
MainActivity.bookmarksUpdatedEvent(true)
|
||||||
|
if (refreshHomePage) {
|
||||||
|
MainActivity.reloadHomeEvent(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun editAccount(context: Context, account: Account, isNewAccount: Boolean) {
|
private fun editAccount(context: Context, account: Account, isNewAccount: Boolean) {
|
||||||
|
@ -112,7 +130,7 @@ object DataStoreHelper {
|
||||||
accounts = currentAccounts.toTypedArray()
|
accounts = currentAccounts.toTypedArray()
|
||||||
|
|
||||||
// update UI
|
// update UI
|
||||||
setAccount(getDefaultAccount(context))
|
setAccount(getDefaultAccount(context), true)
|
||||||
MainActivity.bookmarksUpdatedEvent(true)
|
MainActivity.bookmarksUpdatedEvent(true)
|
||||||
dialog?.dismissSafe()
|
dialog?.dismissSafe()
|
||||||
}
|
}
|
||||||
|
@ -161,8 +179,13 @@ object DataStoreHelper {
|
||||||
currentAccounts.add(currentEditAccount)
|
currentAccounts.add(currentEditAccount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save the current homepage for new accounts
|
||||||
|
val currentHomePage = DataStoreHelper.currentHomePage
|
||||||
|
|
||||||
// set the new default account as well as add the key for the new account
|
// set the new default account as well as add the key for the new account
|
||||||
setAccount(currentEditAccount)
|
setAccount(currentEditAccount, false)
|
||||||
|
DataStoreHelper.currentHomePage = currentHomePage
|
||||||
|
|
||||||
accounts = currentAccounts.toTypedArray()
|
accounts = currentAccounts.toTypedArray()
|
||||||
|
|
||||||
dialog.dismissSafe()
|
dialog.dismissSafe()
|
||||||
|
@ -204,7 +227,7 @@ object DataStoreHelper {
|
||||||
)
|
)
|
||||||
binding.profilesRecyclerview.adapter = WhoIsWatchingAdapter(
|
binding.profilesRecyclerview.adapter = WhoIsWatchingAdapter(
|
||||||
selectCallBack = { account ->
|
selectCallBack = { account ->
|
||||||
setAccount(account)
|
setAccount(account, true)
|
||||||
builder.dismissSafe()
|
builder.dismissSafe()
|
||||||
},
|
},
|
||||||
addAccountCallback = {
|
addAccountCallback = {
|
||||||
|
@ -353,7 +376,7 @@ object DataStoreHelper {
|
||||||
removeKeys(folder2)
|
removeKeys(folder2)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteBookmarkedData(id : Int?) {
|
fun deleteBookmarkedData(id: Int?) {
|
||||||
if (id == null) return
|
if (id == null) return
|
||||||
removeKey("$currentAccount/$RESULT_WATCH_STATE", id.toString())
|
removeKey("$currentAccount/$RESULT_WATCH_STATE", id.toString())
|
||||||
removeKey("$currentAccount/$RESULT_WATCH_STATE_DATA", id.toString())
|
removeKey("$currentAccount/$RESULT_WATCH_STATE_DATA", id.toString())
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<gradient
|
<gradient
|
||||||
android:startColor="@color/transparent"
|
android:centerColor="?attr/primaryBlackBackground"
|
||||||
android:endColor="?attr/primaryBlackBackground"/>
|
android:centerX="0.2"
|
||||||
|
android:endColor="?attr/primaryBlackBackground"
|
||||||
|
android:startColor="@color/transparent" />
|
||||||
</shape>
|
</shape>
|
|
@ -535,129 +535,150 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
<FrameLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible"
|
|
||||||
android:id="@+id/episodes_shadow"
|
android:id="@+id/episodes_shadow"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
<ImageView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:clickable="false"
|
|
||||||
android:focusable="false"
|
|
||||||
android:focusableInTouchMode="false"
|
|
||||||
android:importantForAccessibility="no"
|
|
||||||
android:src="@drawable/episodes_shadow"/>
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:clickable="false"
|
|
||||||
android:focusable="false"
|
|
||||||
android:focusableInTouchMode="false"
|
|
||||||
android:importantForAccessibility="no"
|
|
||||||
android:src="@drawable/episodes_shadow"/>
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/episode_holder_tv"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
|
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="end"
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingStart="@dimen/result_padding"
|
|
||||||
android:paddingEnd="@dimen/result_padding"
|
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
tools:visibility="visible">
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:ignore="RtlHardcoded"
|
|
||||||
tools:visibility="gone">
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/result_season_selection"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
|
|
||||||
android:descendantFocusability="afterDescendants"
|
|
||||||
android:nextFocusLeft="@id/result_episodes_show"
|
|
||||||
android:nextFocusRight="@id/result_range_selection"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingVertical="@dimen/result_padding"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
|
||||||
tools:listitem="@layout/result_selection" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/result_range_selection"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
android:descendantFocusability="afterDescendants"
|
|
||||||
|
|
||||||
android:nextFocusLeft="@id/result_season_selection"
|
|
||||||
android:nextFocusRight="@id/result_dub_selection"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingVertical="@dimen/result_padding"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
|
||||||
tools:listitem="@layout/result_selection"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/result_dub_selection"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
|
|
||||||
android:descendantFocusability="afterDescendants"
|
|
||||||
android:nextFocusLeft="@id/result_range_selection"
|
|
||||||
android:nextFocusRight="@id/result_episodes"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingVertical="@dimen/result_padding"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
|
||||||
tools:listitem="@layout/result_selection" />
|
|
||||||
|
|
||||||
|
|
||||||
<!--<androidx.core.widget.ContentLoadingProgressBar
|
<!--
|
||||||
android:id="@+id/result_episode_loading"
|
These two shadow spaces are used to create a view which always x% bigger
|
||||||
|
than the episode_holder_tv. This is required for creating a consistent shadow.
|
||||||
|
-->
|
||||||
|
<Space
|
||||||
|
android:id="@+id/shadow_space_1"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/episode_holder_tv"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/episode_holder_tv" />
|
||||||
|
|
||||||
style="@style/Widget.AppCompat.ProgressBar"
|
<!--
|
||||||
android:layout_gravity="center"
|
The dimension ratio should and episodes_shadow centerX should add up to
|
||||||
android:layout_width="50dp"
|
100% for the best results. For example (100:80 + 0.2) or (100:70 + 0.3).
|
||||||
android:layout_height="50dp" />-->
|
Bigger centerX => Larger fade distance.
|
||||||
|
-->
|
||||||
|
<Space
|
||||||
|
android:id="@+id/shadow_space_2"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="100:80"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/shadow_space_1" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<ImageView
|
||||||
android:id="@+id/result_episodes"
|
android:layout_width="0dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_gravity="end"
|
||||||
android:clipToPadding="false"
|
android:clickable="false"
|
||||||
android:descendantFocusability="afterDescendants"
|
|
||||||
android:nextFocusLeft="@id/result_dub_selection"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingVertical="@dimen/result_padding"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
|
||||||
tools:listitem="@layout/result_episode" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/temporary_no_focus"
|
|
||||||
android:layout_width="1dp"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:nextFocusLeft="@id/temporary_no_focus"
|
android:focusableInTouchMode="false"
|
||||||
android:nextFocusRight="@id/temporary_no_focus"
|
android:importantForAccessibility="no"
|
||||||
android:nextFocusUp="@id/temporary_no_focus"
|
android:src="@drawable/episodes_shadow"
|
||||||
android:nextFocusDown="@id/temporary_no_focus" />
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
</LinearLayout>
|
app:layout_constraintStart_toStartOf="@+id/shadow_space_2"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/episode_holder_tv"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="@dimen/result_padding"
|
||||||
|
android:paddingEnd="@dimen/result_padding"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<com.lagradost.cloudstream3.ui.MaxRecyclerView
|
||||||
|
android:id="@+id/result_dub_selection"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:descendantFocusability="afterDescendants"
|
||||||
|
android:nextFocusLeft="@id/result_episodes_show"
|
||||||
|
android:nextFocusRight="@id/result_season_selection"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingVertical="@dimen/result_padding"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/result_selection"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
|
||||||
|
<com.lagradost.cloudstream3.ui.MaxRecyclerView
|
||||||
|
android:id="@+id/result_season_selection"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:descendantFocusability="afterDescendants"
|
||||||
|
android:nextFocusLeft="@id/result_dub_selection"
|
||||||
|
android:nextFocusRight="@id/result_range_selection"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingVertical="@dimen/result_padding"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/result_selection"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
|
||||||
|
<com.lagradost.cloudstream3.ui.MaxRecyclerView
|
||||||
|
android:id="@+id/result_range_selection"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:descendantFocusability="afterDescendants"
|
||||||
|
android:nextFocusLeft="@id/result_season_selection"
|
||||||
|
android:nextFocusRight="@id/result_episodes"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingVertical="@dimen/result_padding"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/result_selection"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
|
||||||
|
<!--<androidx.core.widget.ContentLoadingProgressBar
|
||||||
|
android:id="@+id/result_episode_loading"
|
||||||
|
|
||||||
|
style="@style/Widget.AppCompat.ProgressBar"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp" />-->
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/result_episodes"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:descendantFocusability="afterDescendants"
|
||||||
|
android:nextFocusLeft="@id/result_range_selection"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingVertical="@dimen/result_padding"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/result_episode" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/temporary_no_focus"
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:focusable="false"
|
||||||
|
android:nextFocusLeft="@id/temporary_no_focus"
|
||||||
|
android:nextFocusRight="@id/temporary_no_focus"
|
||||||
|
android:nextFocusUp="@id/temporary_no_focus"
|
||||||
|
android:nextFocusDown="@id/temporary_no_focus" />
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|
Loading…
Reference in a new issue