mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
+ Fixed ephemeral scroll
+ Fixed Unable to remove Subs + Fixed download 1 frame visual glitch + Maybe fixed worker + Updated layout API + Bump
This commit is contained in:
parent
638cc4fee9
commit
ad67b9ddab
46 changed files with 665 additions and 451 deletions
|
@ -60,7 +60,7 @@ android {
|
|||
targetSdk = 33 /* Android 14 is Fu*ked
|
||||
^ https://developer.android.com/about/versions/14/behavior-changes-14#safer-dynamic-code-loading*/
|
||||
versionCode = 63
|
||||
versionName = "4.3.1"
|
||||
versionName = "4.3.2"
|
||||
|
||||
resValue("string", "app_version", "${defaultConfig.versionName}${versionNameSuffix ?: ""}")
|
||||
resValue("string", "commit_hash", "git rev-parse --short HEAD".execute() ?: "")
|
||||
|
@ -163,10 +163,10 @@ dependencies {
|
|||
// Android Core & Lifecycle
|
||||
implementation("androidx.core:core-ktx:1.12.0")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("androidx.navigation:navigation-ui-ktx:2.7.6")
|
||||
implementation("androidx.navigation:navigation-ui-ktx:2.7.7")
|
||||
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
|
||||
implementation("androidx.navigation:navigation-fragment-ktx:2.7.6")
|
||||
implementation("androidx.navigation:navigation-fragment-ktx:2.7.7")
|
||||
|
||||
// Design & UI
|
||||
implementation("jp.wasabeef:glide-transformations:4.3.0")
|
||||
|
|
|
@ -11,7 +11,9 @@ import androidx.fragment.app.FragmentActivity
|
|||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
|
||||
import com.lagradost.cloudstream3.plugins.PluginManager
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread
|
||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||
|
@ -31,7 +33,6 @@ import org.acra.sender.ReportSenderFactory
|
|||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.PrintStream
|
||||
import java.lang.Exception
|
||||
import java.lang.ref.WeakReference
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.system.exitProcess
|
||||
|
@ -211,7 +212,7 @@ class AcraApplication : Application() {
|
|||
fun openBrowser(url: String, activity: FragmentActivity?) {
|
||||
openBrowser(
|
||||
url,
|
||||
isTvSettings(),
|
||||
isLayout(TV or EMULATOR),
|
||||
activity?.supportFragmentManager?.fragments?.lastOrNull()
|
||||
)
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ import com.lagradost.cloudstream3.mvvm.logError
|
|||
import com.lagradost.cloudstream3.ui.player.PlayerEventType
|
||||
import com.lagradost.cloudstream3.ui.result.ResultFragment
|
||||
import com.lagradost.cloudstream3.ui.result.UiText
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.updateTv
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.updateTv
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.isRtl
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
import com.lagradost.cloudstream3.utils.Event
|
||||
|
|
|
@ -18,6 +18,7 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.simklAp
|
|||
import com.lagradost.cloudstream3.syncproviders.SyncIdName
|
||||
import com.lagradost.cloudstream3.syncproviders.providers.SimklApi
|
||||
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
||||
import com.lagradost.cloudstream3.ui.result.ResultViewModel2
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.mainWork
|
||||
|
@ -119,7 +120,8 @@ object APIHolder {
|
|||
}
|
||||
|
||||
fun LoadResponse.getId(): Int {
|
||||
return getLoadResponseIdFromUrl(url, apiName)
|
||||
// this fixes an issue with outdated api as getLoadResponseIdFromUrl might be fucked
|
||||
return (if (this is ResultViewModel2.LoadResponseFromSearch) this.id else null) ?: getLoadResponseIdFromUrl(url, apiName)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -86,6 +86,7 @@ import com.lagradost.cloudstream3.plugins.PluginManager
|
|||
import com.lagradost.cloudstream3.plugins.PluginManager.loadAllOnlinePlugins
|
||||
import com.lagradost.cloudstream3.plugins.PluginManager.loadSinglePlugin
|
||||
import com.lagradost.cloudstream3.receivers.VideoDownloadRestartReceiver
|
||||
import com.lagradost.cloudstream3.services.SubscriptionWorkManager
|
||||
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.OAuth2Apis
|
||||
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.accountManagers
|
||||
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appString
|
||||
|
@ -112,11 +113,11 @@ import com.lagradost.cloudstream3.ui.result.setText
|
|||
import com.lagradost.cloudstream3.ui.result.txt
|
||||
import com.lagradost.cloudstream3.ui.search.SearchFragment
|
||||
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTruePhone
|
||||
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.updateTv
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.PHONE
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.updateTv
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsGeneral
|
||||
import com.lagradost.cloudstream3.ui.setup.HAS_DONE_SETUP_KEY
|
||||
import com.lagradost.cloudstream3.ui.setup.SetupFragmentExtensions
|
||||
|
@ -290,7 +291,8 @@ var app = Requests(responseParser = object : ResponseParser {
|
|||
defaultHeaders = mapOf("user-agent" to USER_AGENT)
|
||||
}
|
||||
|
||||
class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAuthenticator.BiometricAuthCallback {
|
||||
class MainActivity : AppCompatActivity(), ColorPickerDialogListener,
|
||||
BiometricAuthenticator.BiometricAuthCallback {
|
||||
companion object {
|
||||
const val TAG = "MAINACT"
|
||||
const val ANIMATED_OUTLINE: Boolean = false
|
||||
|
@ -336,10 +338,12 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
|
||||
// kinda shitty solution, but cant com main->home otherwise for popups
|
||||
val bookmarksUpdatedEvent = Event<Boolean>()
|
||||
|
||||
/**
|
||||
* Used by DataStoreHelper to fully reload home when switching accounts
|
||||
*/
|
||||
val reloadHomeEvent = Event<Boolean>()
|
||||
|
||||
/**
|
||||
* Used by DataStoreHelper to fully reload library when switching accounts
|
||||
*/
|
||||
|
@ -467,7 +471,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
}
|
||||
|
||||
var lastPopup: SearchResponse? = null
|
||||
fun loadPopup(result: SearchResponse, load : Boolean = true) {
|
||||
fun loadPopup(result: SearchResponse, load: Boolean = true) {
|
||||
lastPopup = result
|
||||
val syncName = syncViewModel.syncName(result.apiName)
|
||||
|
||||
|
@ -488,8 +492,8 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
.contains(DubStatus.Dubbed)
|
||||
) DubStatus.Dubbed else DubStatus.Subbed, null
|
||||
)
|
||||
}else {
|
||||
viewModel.loadSmall(this,result)
|
||||
} else {
|
||||
viewModel.loadSmall(this, result)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,7 +558,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
binding?.navHostFragment?.apply {
|
||||
val params = layoutParams as ConstraintLayout.LayoutParams
|
||||
val push =
|
||||
if (!dontPush && isTvSettings()) resources.getDimensionPixelSize(R.dimen.navbar_width) else 0
|
||||
if (!dontPush && isLayout(TV or EMULATOR)) resources.getDimensionPixelSize(R.dimen.navbar_width) else 0
|
||||
|
||||
if (!this.isLtr()) {
|
||||
params.setMargins(
|
||||
|
@ -581,7 +585,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
}
|
||||
|
||||
Configuration.ORIENTATION_PORTRAIT -> {
|
||||
isTvSettings()
|
||||
isLayout(TV or EMULATOR)
|
||||
}
|
||||
|
||||
else -> {
|
||||
|
@ -787,9 +791,10 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
}
|
||||
|
||||
lateinit var viewModel: ResultViewModel2
|
||||
lateinit var syncViewModel : SyncViewModel
|
||||
lateinit var syncViewModel: SyncViewModel
|
||||
|
||||
/** kinda dirty, however it signals that we should use the watch status as sync or not*/
|
||||
var isLocalList : Boolean = false
|
||||
var isLocalList: Boolean = false
|
||||
override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
|
||||
viewModel =
|
||||
ViewModelProvider(this)[ResultViewModel2::class.java]
|
||||
|
@ -1105,8 +1110,8 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
}
|
||||
}
|
||||
|
||||
private fun centerView(view : View?) {
|
||||
if(view == null) return
|
||||
private fun centerView(view: View?) {
|
||||
if (view == null) return
|
||||
try {
|
||||
Log.v(TAG, "centerView: $view")
|
||||
val r = Rect(0, 0, 0, 0)
|
||||
|
@ -1172,11 +1177,11 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
|
||||
// just in case, MAIN SHOULD *NEVER* BOOT LOOP CRASH
|
||||
binding = try {
|
||||
if (isTvSettings()) {
|
||||
if (isLayout(TV or EMULATOR)) {
|
||||
val newLocalBinding = ActivityMainTvBinding.inflate(layoutInflater, null, false)
|
||||
setContentView(newLocalBinding.root)
|
||||
|
||||
if (isTrueTvSettings() && ANIMATED_OUTLINE) {
|
||||
if (isLayout(TV) && ANIMATED_OUTLINE) {
|
||||
TvFocus.focusOutline = WeakReference(newLocalBinding.focusOutline)
|
||||
newLocalBinding.root.viewTreeObserver.addOnScrollChangedListener {
|
||||
TvFocus.updateFocusView(TvFocus.lastFocus.get(), same = true)
|
||||
|
@ -1188,7 +1193,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
newLocalBinding.focusOutline.isVisible = false
|
||||
}
|
||||
|
||||
if(isTrueTvSettings()) {
|
||||
if (isLayout(TV)) {
|
||||
// Put here any button you don't want focusing it to center the view
|
||||
val exceptionButtons = listOf(
|
||||
R.id.home_preview_play_btt,
|
||||
|
@ -1205,7 +1210,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
R.id.result_search_Button,
|
||||
R.id.result_episodes_show_button,
|
||||
)
|
||||
|
||||
|
||||
newLocalBinding.root.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus ->
|
||||
if (exceptionButtons.contains(newFocus?.id)) return@addOnGlobalFocusChangeListener
|
||||
centerView(newFocus)
|
||||
|
@ -1223,18 +1228,21 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
null
|
||||
}
|
||||
|
||||
changeStatusBarState(isEmulatorSettings())
|
||||
changeStatusBarState(isLayout(EMULATOR))
|
||||
|
||||
/** Biometric stuff for users without accounts **/
|
||||
val authEnabled = settingsManager.getBoolean(getString(R.string.biometric_key), false)
|
||||
val noAccounts = settingsManager.getBoolean(getString(R.string.skip_startup_account_select_key), false) || accounts.count() <= 1
|
||||
val noAccounts = settingsManager.getBoolean(
|
||||
getString(R.string.skip_startup_account_select_key),
|
||||
false
|
||||
) || accounts.count() <= 1
|
||||
|
||||
if (isTruePhone() && authEnabled && noAccounts) {
|
||||
if (isLayout(PHONE) && authEnabled && noAccounts) {
|
||||
if (deviceHasPasswordPinLock(this)) {
|
||||
startBiometricAuthentication(this, R.string.biometric_authentication_title, false)
|
||||
|
||||
BiometricAuthenticator.promptInfo?.let {
|
||||
BiometricAuthenticator.biometricPrompt?.authenticate(it)
|
||||
BiometricAuthenticator.promptInfo?.let { promt ->
|
||||
BiometricAuthenticator.biometricPrompt?.authenticate(promt)
|
||||
}
|
||||
|
||||
// hide background while authenticating, Sorry moms & dads 🙏
|
||||
|
@ -1326,7 +1334,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
}
|
||||
|
||||
|
||||
fun setUserData(status : Resource<SyncAPI.AbstractSyncStatus>?) {
|
||||
fun setUserData(status: Resource<SyncAPI.AbstractSyncStatus>?) {
|
||||
if (isLocalList) return
|
||||
bottomPreviewBinding?.apply {
|
||||
when (status) {
|
||||
|
@ -1351,7 +1359,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
}
|
||||
}
|
||||
|
||||
fun setWatchStatus(state : WatchType?) {
|
||||
fun setWatchStatus(state: WatchType?) {
|
||||
if (!isLocalList || state == null) return
|
||||
|
||||
bottomPreviewBinding?.resultviewPreviewBookmark?.apply {
|
||||
|
@ -1360,13 +1368,42 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
}
|
||||
}
|
||||
|
||||
observe(viewModel.watchStatus) { state ->
|
||||
setWatchStatus(state)
|
||||
}
|
||||
observe(syncViewModel.userData) { status ->
|
||||
setUserData(status)
|
||||
fun setSubscribeStatus(state: Boolean?) {
|
||||
bottomPreviewBinding?.resultviewPreviewSubscribe?.apply {
|
||||
if (state != null) {
|
||||
val drawable = if (state) {
|
||||
R.drawable.ic_baseline_notifications_active_24
|
||||
} else {
|
||||
R.drawable.baseline_notifications_none_24
|
||||
}
|
||||
setImageResource(drawable)
|
||||
}
|
||||
isVisible = state != null
|
||||
|
||||
setOnClickListener {
|
||||
viewModel.toggleSubscriptionStatus(context) { newStatus: Boolean? ->
|
||||
if (newStatus == null) return@toggleSubscriptionStatus
|
||||
|
||||
val message = if (newStatus) {
|
||||
// Kinda icky to have this here, but it works.
|
||||
SubscriptionWorkManager.enqueuePeriodicWork(context)
|
||||
R.string.subscription_new
|
||||
} else {
|
||||
R.string.subscription_deleted
|
||||
}
|
||||
|
||||
val name = (viewModel.page.value as? Resource.Success)?.value?.title
|
||||
?: txt(R.string.no_data).asStringNull(context) ?: ""
|
||||
showToast(txt(message, name), Toast.LENGTH_SHORT)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
observe(viewModel.watchStatus,::setWatchStatus)
|
||||
observe(syncViewModel.userData, ::setUserData)
|
||||
observeNullable(viewModel.subscribeStatus, ::setSubscribeStatus)
|
||||
|
||||
observeNullable(viewModel.page) { resource ->
|
||||
if (resource == null) {
|
||||
hidePreviewPopupDialog()
|
||||
|
@ -1408,6 +1445,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
|
||||
setUserData(syncViewModel.userData.value)
|
||||
setWatchStatus(viewModel.watchStatus.value)
|
||||
setSubscribeStatus(viewModel.subscribeStatus.value)
|
||||
|
||||
resultviewPreviewBookmark.setOnClickListener {
|
||||
//viewModel.updateWatchStatus(WatchType.PLANTOWATCH)
|
||||
|
@ -1426,7 +1464,9 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
)
|
||||
}
|
||||
} else {
|
||||
val value = (syncViewModel.userData.value as? Resource.Success)?.value?.status ?: SyncWatchType.NONE
|
||||
val value =
|
||||
(syncViewModel.userData.value as? Resource.Success)?.value?.status
|
||||
?: SyncWatchType.NONE
|
||||
|
||||
this@MainActivity.showBottomDialog(
|
||||
SyncWatchType.values().map { getString(it.stringRes) }.toList(),
|
||||
|
@ -1453,7 +1493,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
resultviewPreviewFavorite.setImageResource(drawable)
|
||||
}
|
||||
|
||||
resultviewPreviewFavorite.setOnClickListener{
|
||||
resultviewPreviewFavorite.setOnClickListener {
|
||||
viewModel.toggleFavoriteStatus(this@MainActivity) { newStatus: Boolean? ->
|
||||
if (newStatus == null) return@toggleFavoriteStatus
|
||||
|
||||
|
@ -1469,7 +1509,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
}
|
||||
}
|
||||
|
||||
if (!isTvSettings()) // dont want this clickable on tv layout
|
||||
if (isLayout(PHONE)) // dont want this clickable on tv layout
|
||||
resultviewPreviewDescription.setOnClickListener { view ->
|
||||
view.context?.let { ctx ->
|
||||
val builder: AlertDialog.Builder =
|
||||
|
@ -1544,7 +1584,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
}
|
||||
}
|
||||
|
||||
if (isTvSettings()) {
|
||||
if (isLayout(TV or EMULATOR)) {
|
||||
if (navDestination.matchDestination(R.id.navigation_home)) {
|
||||
attachBackPressedCallback()
|
||||
} else detachBackPressedCallback()
|
||||
|
@ -1580,7 +1620,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
|
|||
itemRippleColor = rippleColor
|
||||
itemActiveIndicatorColor = rippleColor
|
||||
setupWithNavController(navController)
|
||||
if (isTvSettings()) {
|
||||
if (isLayout(TV or EMULATOR)) {
|
||||
background?.alpha = 200
|
||||
} else {
|
||||
background?.alpha = 255
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.lagradost.cloudstream3.services
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
|
@ -12,7 +13,7 @@ import com.lagradost.cloudstream3.*
|
|||
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
||||
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.plugins.PluginManager
|
||||
import com.lagradost.cloudstream3.ui.result.txt
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.createNotificationChannel
|
||||
|
@ -97,128 +98,138 @@ class SubscriptionWorkManager(val context: Context, workerParams: WorkerParamete
|
|||
)
|
||||
}
|
||||
|
||||
@SuppressLint("UnspecifiedImmutableFlag")
|
||||
override suspend fun doWork(): Result {
|
||||
try {
|
||||
// println("Update subscriptions!")
|
||||
context.createNotificationChannel(
|
||||
SUBSCRIPTION_CHANNEL_ID,
|
||||
SUBSCRIPTION_CHANNEL_NAME,
|
||||
SUBSCRIPTION_CHANNEL_DESCRIPTION
|
||||
)
|
||||
|
||||
setForeground(
|
||||
ForegroundInfo(
|
||||
SUBSCRIPTION_NOTIFICATION_ID,
|
||||
progressNotificationBuilder.build()
|
||||
context.createNotificationChannel(
|
||||
SUBSCRIPTION_CHANNEL_ID,
|
||||
SUBSCRIPTION_CHANNEL_NAME,
|
||||
SUBSCRIPTION_CHANNEL_DESCRIPTION
|
||||
)
|
||||
)
|
||||
|
||||
val subscriptions = getAllSubscriptions()
|
||||
setForeground(
|
||||
ForegroundInfo(
|
||||
SUBSCRIPTION_NOTIFICATION_ID,
|
||||
progressNotificationBuilder.build()
|
||||
)
|
||||
)
|
||||
|
||||
if (subscriptions.isEmpty()) {
|
||||
WorkManager.getInstance(context).cancelWorkById(this.id)
|
||||
val subscriptions = getAllSubscriptions()
|
||||
|
||||
if (subscriptions.isEmpty()) {
|
||||
WorkManager.getInstance(context).cancelWorkById(this.id)
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
val max = subscriptions.size
|
||||
var progress = 0
|
||||
|
||||
updateProgress(max, progress, true)
|
||||
|
||||
// We need all plugins loaded.
|
||||
PluginManager.loadAllOnlinePlugins(context)
|
||||
PluginManager.loadAllLocalPlugins(context, false)
|
||||
|
||||
subscriptions.apmap { savedData ->
|
||||
try {
|
||||
val id = savedData.id ?: return@apmap null
|
||||
val api = getApiFromNameNull(savedData.apiName) ?: return@apmap null
|
||||
|
||||
// Reasonable timeout to prevent having this worker run forever.
|
||||
val response = withTimeoutOrNull(60_000) {
|
||||
api.load(savedData.url) as? EpisodeResponse
|
||||
} ?: return@apmap null
|
||||
|
||||
val dubPreference =
|
||||
getDub(id) ?: if (
|
||||
context.getApiDubstatusSettings().contains(DubStatus.Dubbed)
|
||||
) {
|
||||
DubStatus.Dubbed
|
||||
} else {
|
||||
DubStatus.Subbed
|
||||
}
|
||||
|
||||
val latestEpisodes = response.getLatestEpisodes()
|
||||
val latestPreferredEpisode = latestEpisodes[dubPreference]
|
||||
|
||||
val (shouldUpdate, latestEpisode) = if (latestPreferredEpisode != null) {
|
||||
val latestSeenEpisode =
|
||||
savedData.lastSeenEpisodeCount[dubPreference] ?: Int.MIN_VALUE
|
||||
val shouldUpdate = latestPreferredEpisode > latestSeenEpisode
|
||||
shouldUpdate to latestPreferredEpisode
|
||||
} else {
|
||||
val latestEpisode = latestEpisodes[DubStatus.None] ?: Int.MIN_VALUE
|
||||
val latestSeenEpisode =
|
||||
savedData.lastSeenEpisodeCount[DubStatus.None] ?: Int.MIN_VALUE
|
||||
val shouldUpdate = latestEpisode > latestSeenEpisode
|
||||
shouldUpdate to latestEpisode
|
||||
}
|
||||
|
||||
DataStoreHelper.updateSubscribedData(
|
||||
id,
|
||||
savedData,
|
||||
response
|
||||
)
|
||||
|
||||
if (shouldUpdate) {
|
||||
val updateHeader = savedData.name
|
||||
val updateDescription = txt(
|
||||
R.string.subscription_episode_released,
|
||||
latestEpisode,
|
||||
savedData.name
|
||||
).asString(context)
|
||||
|
||||
val intent = Intent(context, MainActivity::class.java).apply {
|
||||
data = savedData.url.toUri()
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
}
|
||||
|
||||
val pendingIntent =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
PendingIntent.getActivity(
|
||||
context,
|
||||
0,
|
||||
intent,
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
} else {
|
||||
PendingIntent.getActivity(context, 0, intent, 0)
|
||||
}
|
||||
|
||||
val poster = ioWork {
|
||||
savedData.posterUrl?.let { url ->
|
||||
context.getImageBitmapFromUrl(
|
||||
url,
|
||||
savedData.posterHeaders
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val updateNotification =
|
||||
updateNotificationBuilder.setContentTitle(updateHeader)
|
||||
.setContentText(updateDescription)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setLargeIcon(poster)
|
||||
.build()
|
||||
|
||||
notificationManager.notify(id, updateNotification)
|
||||
}
|
||||
|
||||
// You can probably get some issues here since this is async but it does not matter much.
|
||||
updateProgress(max, ++progress, false)
|
||||
} catch (t: Throwable) {
|
||||
logError(t)
|
||||
}
|
||||
}
|
||||
|
||||
return Result.success()
|
||||
} catch (t: Throwable) {
|
||||
logError(t)
|
||||
// ye, while this is not correct, but because gods know why android just crashes
|
||||
// and this causes major battery usage as it retries it inf times. This is better, just
|
||||
// in case android decides to be android and fuck us
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
val max = subscriptions.size
|
||||
var progress = 0
|
||||
|
||||
updateProgress(max, progress, true)
|
||||
|
||||
// We need all plugins loaded.
|
||||
PluginManager.loadAllOnlinePlugins(context)
|
||||
PluginManager.loadAllLocalPlugins(context, false)
|
||||
|
||||
subscriptions.apmap { savedData ->
|
||||
try {
|
||||
val id = savedData.id ?: return@apmap null
|
||||
val api = getApiFromNameNull(savedData.apiName) ?: return@apmap null
|
||||
|
||||
// Reasonable timeout to prevent having this worker run forever.
|
||||
val response = withTimeoutOrNull(60_000) {
|
||||
api.load(savedData.url) as? EpisodeResponse
|
||||
} ?: return@apmap null
|
||||
|
||||
val dubPreference =
|
||||
getDub(id) ?: if (
|
||||
context.getApiDubstatusSettings().contains(DubStatus.Dubbed)
|
||||
) {
|
||||
DubStatus.Dubbed
|
||||
} else {
|
||||
DubStatus.Subbed
|
||||
}
|
||||
|
||||
val latestEpisodes = response.getLatestEpisodes()
|
||||
val latestPreferredEpisode = latestEpisodes[dubPreference]
|
||||
|
||||
val (shouldUpdate, latestEpisode) = if (latestPreferredEpisode != null) {
|
||||
val latestSeenEpisode =
|
||||
savedData.lastSeenEpisodeCount[dubPreference] ?: Int.MIN_VALUE
|
||||
val shouldUpdate = latestPreferredEpisode > latestSeenEpisode
|
||||
shouldUpdate to latestPreferredEpisode
|
||||
} else {
|
||||
val latestEpisode = latestEpisodes[DubStatus.None] ?: Int.MIN_VALUE
|
||||
val latestSeenEpisode =
|
||||
savedData.lastSeenEpisodeCount[DubStatus.None] ?: Int.MIN_VALUE
|
||||
val shouldUpdate = latestEpisode > latestSeenEpisode
|
||||
shouldUpdate to latestEpisode
|
||||
}
|
||||
|
||||
DataStoreHelper.updateSubscribedData(
|
||||
id,
|
||||
savedData,
|
||||
response
|
||||
)
|
||||
|
||||
if (shouldUpdate) {
|
||||
val updateHeader = savedData.name
|
||||
val updateDescription = txt(
|
||||
R.string.subscription_episode_released,
|
||||
latestEpisode,
|
||||
savedData.name
|
||||
).asString(context)
|
||||
|
||||
val intent = Intent(context, MainActivity::class.java).apply {
|
||||
data = savedData.url.toUri()
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
}
|
||||
|
||||
val pendingIntent =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
PendingIntent.getActivity(
|
||||
context,
|
||||
0,
|
||||
intent,
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
} else {
|
||||
PendingIntent.getActivity(context, 0, intent, 0)
|
||||
}
|
||||
|
||||
val poster = ioWork {
|
||||
savedData.posterUrl?.let { url ->
|
||||
context.getImageBitmapFromUrl(
|
||||
url,
|
||||
savedData.posterHeaders
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val updateNotification =
|
||||
updateNotificationBuilder.setContentTitle(updateHeader)
|
||||
.setContentText(updateDescription)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setLargeIcon(poster)
|
||||
.build()
|
||||
|
||||
notificationManager.notify(id, updateNotification)
|
||||
}
|
||||
|
||||
// You can probably get some issues here since this is async but it does not matter much.
|
||||
updateProgress(max, ++progress, false)
|
||||
} catch (_: Throwable) {
|
||||
}
|
||||
}
|
||||
|
||||
return Result.success()
|
||||
}
|
||||
}
|
|
@ -8,7 +8,8 @@ import com.lagradost.cloudstream3.syncproviders.SyncIdName
|
|||
import com.lagradost.cloudstream3.ui.WatchType
|
||||
import com.lagradost.cloudstream3.ui.library.ListSorting
|
||||
import com.lagradost.cloudstream3.ui.result.txt
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.ioWork
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllFavorites
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllSubscriptions
|
||||
|
@ -71,9 +72,9 @@ class LocalList : SyncAPI {
|
|||
}?.distinctBy { it.first } ?: return null
|
||||
|
||||
val list = ioWork {
|
||||
val isTrueTv = isTrueTvSettings()
|
||||
val isTrueTv = isLayout(TV)
|
||||
|
||||
val baseMap = WatchType.values().filter { it != WatchType.NONE }.associate {
|
||||
val baseMap = WatchType.entries.filter { it != WatchType.NONE }.associate {
|
||||
// None is not something to display
|
||||
it.stringRes to emptyList<SyncAPI.LibraryItem>()
|
||||
} + mapOf(
|
||||
|
|
|
@ -12,7 +12,9 @@ import com.lagradost.cloudstream3.databinding.AccountListItemBinding
|
|||
import com.lagradost.cloudstream3.databinding.AccountListItemEditBinding
|
||||
import com.lagradost.cloudstream3.ui.account.AccountHelper.showAccountEditDialog
|
||||
import com.lagradost.cloudstream3.ui.result.setImage
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
|
||||
|
@ -38,7 +40,7 @@ class AccountAdapter(
|
|||
is AccountListItemBinding -> binding.apply {
|
||||
if (account == null) return@apply
|
||||
|
||||
val isTv = isTvSettings() || !root.isInTouchMode
|
||||
val isTv = isLayout(TV or EMULATOR) || !root.isInTouchMode
|
||||
|
||||
val isLastUsedAccount = account.keyIndex == DataStoreHelper.selectedKeyIndex
|
||||
|
||||
|
@ -80,7 +82,7 @@ class AccountAdapter(
|
|||
is AccountListItemEditBinding -> binding.apply {
|
||||
if (account == null) return@apply
|
||||
|
||||
val isTv = isTvSettings() || !root.isInTouchMode
|
||||
val isTv = isLayout(TV or EMULATOR) || !root.isInTouchMode
|
||||
|
||||
val isLastUsedAccount = account.keyIndex == DataStoreHelper.selectedKeyIndex
|
||||
|
||||
|
|
|
@ -18,8 +18,10 @@ import com.lagradost.cloudstream3.mvvm.observe
|
|||
import com.lagradost.cloudstream3.ui.AutofitRecyclerView
|
||||
import com.lagradost.cloudstream3.ui.account.AccountAdapter.Companion.VIEW_TYPE_EDIT_ACCOUNT
|
||||
import com.lagradost.cloudstream3.ui.account.AccountAdapter.Companion.VIEW_TYPE_SELECT_ACCOUNT
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTruePhone
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.PHONE
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.BiometricAuthenticator
|
||||
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.deviceHasPasswordPinLock
|
||||
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.startBiometricAuthentication
|
||||
|
@ -54,7 +56,7 @@ class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.Biomet
|
|||
|
||||
fun askBiometricAuth() {
|
||||
|
||||
if (isTruePhone() && authEnabled) {
|
||||
if (isLayout(PHONE) && authEnabled) {
|
||||
if (deviceHasPasswordPinLock(this)) {
|
||||
startBiometricAuthentication(
|
||||
this,
|
||||
|
@ -62,8 +64,8 @@ class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.Biomet
|
|||
false
|
||||
)
|
||||
|
||||
BiometricAuthenticator.promptInfo?.let {
|
||||
BiometricAuthenticator.biometricPrompt?.authenticate(it)
|
||||
BiometricAuthenticator.promptInfo?.let { promt ->
|
||||
BiometricAuthenticator.biometricPrompt?.authenticate(promt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +129,7 @@ class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.Biomet
|
|||
|
||||
recyclerView.adapter = adapter
|
||||
|
||||
if (isTvSettings()) {
|
||||
if (isLayout(TV or EMULATOR)) {
|
||||
binding.editAccountButton.setBackgroundResource(
|
||||
R.drawable.player_button_tv_attr_no_bg
|
||||
)
|
||||
|
@ -168,7 +170,7 @@ class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.Biomet
|
|||
viewModel.toggleIsEditing()
|
||||
}
|
||||
|
||||
if (isTvSettings()) {
|
||||
if (isLayout(TV or EMULATOR)) {
|
||||
recyclerView.spanCount = if (liveAccounts.count() + 1 <= 6) {
|
||||
liveAccounts.count() + 1
|
||||
} else 6
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.content.ClipboardManager
|
|||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.format.Formatter.formatShortFileSize
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -13,17 +14,25 @@ import android.widget.Toast
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.FragmentDownloadsBinding
|
||||
import com.lagradost.cloudstream3.databinding.StreamInputBinding
|
||||
import com.lagradost.cloudstream3.isMovieType
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
||||
import com.lagradost.cloudstream3.ui.player.BasicLink
|
||||
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
||||
import com.lagradost.cloudstream3.ui.player.LinkGenerator
|
||||
import com.lagradost.cloudstream3.ui.result.FOCUS_SELF
|
||||
import com.lagradost.cloudstream3.ui.result.setLinearListLayout
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE
|
||||
|
@ -34,15 +43,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
|||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||
import android.text.format.Formatter.formatShortFileSize
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import com.lagradost.cloudstream3.databinding.FragmentDownloadsBinding
|
||||
import com.lagradost.cloudstream3.databinding.StreamInputBinding
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.ui.player.BasicLink
|
||||
import com.lagradost.cloudstream3.ui.result.FOCUS_SELF
|
||||
import com.lagradost.cloudstream3.ui.result.setLinearListLayout
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import java.net.URI
|
||||
|
||||
|
||||
|
@ -200,7 +200,7 @@ class DownloadFragment : Fragment() {
|
|||
}
|
||||
|
||||
// Should be visible in emulator layout
|
||||
binding?.downloadStreamButton?.isGone = isTrueTvSettings()
|
||||
binding?.downloadStreamButton?.isGone = isLayout(TV)
|
||||
binding?.downloadStreamButton?.setOnClickListener {
|
||||
val dialog =
|
||||
Dialog(it.context ?: return@setOnClickListener, R.style.AlertDialogCustom)
|
||||
|
|
|
@ -2,16 +2,19 @@ package com.lagradost.cloudstream3.ui.download.button
|
|||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Looper
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DELETE_FILE
|
||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_LONG_CLICK
|
||||
|
@ -241,40 +244,54 @@ open class PieFetchButton(context: Context, attributeSet: AttributeSet) :
|
|||
}
|
||||
}*/
|
||||
|
||||
@MainThread
|
||||
private fun setStatusInternal(status : DownloadStatusTell?) {
|
||||
val isPreActive = isZeroBytes && status == DownloadStatusTell.IsDownloading
|
||||
if (animateWaiting && (status == DownloadStatusTell.IsPending || isPreActive)) {
|
||||
val animation = AnimationUtils.loadAnimation(context, waitingAnimation)
|
||||
progressBarBackground.startAnimation(animation)
|
||||
} else {
|
||||
progressBarBackground.clearAnimation()
|
||||
}
|
||||
|
||||
val progressDrawable =
|
||||
if (status == DownloadStatusTell.IsDownloading && !isPreActive) activeOutline else nonActiveOutline
|
||||
|
||||
progressBarBackground.background =
|
||||
ContextCompat.getDrawable(context, progressDrawable)
|
||||
|
||||
val drawable = getDrawableFromStatus(status)
|
||||
statusView.setImageDrawable(drawable)
|
||||
val isDrawable = drawable != null
|
||||
|
||||
statusView.isVisible = isDrawable
|
||||
val hide = hideWhenIcon && isDrawable
|
||||
if (hide) {
|
||||
progressBar.clearAnimation()
|
||||
progressBarBackground.clearAnimation()
|
||||
}
|
||||
progressBarBackground.isGone = hide
|
||||
progressBar.isGone = hide
|
||||
}
|
||||
|
||||
/** Also sets currentStatus */
|
||||
override fun setStatus(status: DownloadStatusTell?) {
|
||||
currentStatus = status
|
||||
|
||||
//progressBar.isVisible =
|
||||
// status != null && status != DownloadStatusTell.Complete && status != DownloadStatusTell.Error
|
||||
//progressBarBackground.isVisible = status != null && status != DownloadStatusTell.Complete
|
||||
progressBarBackground.post {
|
||||
val isPreActive = isZeroBytes && status == DownloadStatusTell.IsDownloading
|
||||
if (animateWaiting && (status == DownloadStatusTell.IsPending || isPreActive)) {
|
||||
val animation = AnimationUtils.loadAnimation(context, waitingAnimation)
|
||||
progressBarBackground.startAnimation(animation)
|
||||
} else {
|
||||
progressBarBackground.clearAnimation()
|
||||
// runs on the main thread, but also instant if it already is
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
try {
|
||||
setStatusInternal(status)
|
||||
} catch (t : Throwable) {
|
||||
logError(t) // just in case setStatusInternal throws because thread
|
||||
progressBarBackground.post {
|
||||
setStatusInternal(status)
|
||||
}
|
||||
}
|
||||
|
||||
val progressDrawable =
|
||||
if (status == DownloadStatusTell.IsDownloading && !isPreActive) activeOutline else nonActiveOutline
|
||||
|
||||
progressBarBackground.background =
|
||||
ContextCompat.getDrawable(context, progressDrawable)
|
||||
|
||||
val drawable = getDrawableFromStatus(status)
|
||||
statusView.setImageDrawable(drawable)
|
||||
val isDrawable = drawable != null
|
||||
|
||||
statusView.isVisible = isDrawable
|
||||
val hide = hideWhenIcon && isDrawable
|
||||
if (hide) {
|
||||
progressBar.clearAnimation()
|
||||
progressBarBackground.clearAnimation()
|
||||
} else {
|
||||
progressBarBackground.post {
|
||||
setStatusInternal(status)
|
||||
}
|
||||
progressBarBackground.isGone = hide
|
||||
progressBar.isGone = hide
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,8 +42,10 @@ import com.lagradost.cloudstream3.ui.account.AccountHelper.showAccountSelectLine
|
|||
import com.lagradost.cloudstream3.ui.result.txt
|
||||
import com.lagradost.cloudstream3.ui.search.*
|
||||
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.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.PHONE
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.isRecyclerScrollable
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.ownHide
|
||||
|
@ -311,7 +313,7 @@ class HomeFragment : Fragment() {
|
|||
button?.isVisible = isValid
|
||||
button?.isChecked = isValid && selectedTypes.any { types.contains(it) }
|
||||
button?.isFocusable = true
|
||||
if (isTrueTvSettings()) {
|
||||
if (isLayout(TV)) {
|
||||
button?.isFocusableInTouchMode = true
|
||||
}
|
||||
|
||||
|
@ -435,7 +437,7 @@ class HomeFragment : Fragment() {
|
|||
|
||||
bottomSheetDialog?.ownShow()
|
||||
val layout =
|
||||
if (isTvSettings()) R.layout.fragment_home_tv else R.layout.fragment_home
|
||||
if (isLayout(TV or EMULATOR)) R.layout.fragment_home_tv else R.layout.fragment_home
|
||||
val root = inflater.inflate(layout, container, false)
|
||||
binding = try {
|
||||
FragmentHomeBinding.bind(root)
|
||||
|
@ -449,6 +451,11 @@ class HomeFragment : Fragment() {
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
homeMasterAdapter?.onSaveInstanceState(
|
||||
instanceState,
|
||||
binding?.homeMasterRecycler
|
||||
)
|
||||
|
||||
bottomSheetDialog?.ownHide()
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
|
@ -485,6 +492,10 @@ class HomeFragment : Fragment() {
|
|||
|
||||
private var bottomSheetDialog: BottomSheetDialog? = null
|
||||
|
||||
// https://github.com/vivchar/RendererRecyclerViewAdapter/blob/185251ee9d94fb6eb3e063b00d646b745186c365/example/src/main/java/com/github/vivchar/example/pages/github/GithubFragment.kt#L32
|
||||
// cry about it, but this is android we are talking about, we cant do the most simple shit without making a global variable
|
||||
private var instanceState: Bundle = Bundle()
|
||||
private var homeMasterAdapter: HomeParentItemAdapterPreview? = null
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
@ -505,15 +516,16 @@ class HomeFragment : Fragment() {
|
|||
activity.loadSearchResult(listHomepageItems.random())
|
||||
}
|
||||
}
|
||||
|
||||
homeMasterRecycler.adapter =
|
||||
HomeParentItemAdapterPreview(
|
||||
mutableListOf(),
|
||||
homeViewModel
|
||||
)
|
||||
homeMasterAdapter = HomeParentItemAdapterPreview(
|
||||
mutableListOf(),
|
||||
homeViewModel,
|
||||
).apply {
|
||||
onRestoreInstanceState(instanceState)
|
||||
}
|
||||
homeMasterRecycler.adapter = homeMasterAdapter
|
||||
//fixPaddingStatusbar(homeLoadingStatusbar)
|
||||
|
||||
homeApiFab.isVisible = !isTvSettings()
|
||||
homeApiFab.isVisible = isLayout(PHONE)
|
||||
|
||||
homeMasterRecycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
|
@ -521,7 +533,7 @@ class HomeFragment : Fragment() {
|
|||
homeApiFab.shrink() // hide
|
||||
homeRandom.shrink()
|
||||
} else if (dy < -5) {
|
||||
if (!isTvSettings()) {
|
||||
if (isLayout(PHONE)) {
|
||||
homeApiFab.extend() // show
|
||||
homeRandom.extend()
|
||||
}
|
||||
|
@ -540,7 +552,7 @@ class HomeFragment : Fragment() {
|
|||
settingsManager.getBoolean(
|
||||
getString(R.string.random_button_key),
|
||||
false
|
||||
) && !isTvSettings()
|
||||
) && isLayout(PHONE)
|
||||
binding?.homeRandom?.visibility = View.GONE
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.lagradost.cloudstream3.ui.home
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -7,16 +9,20 @@ import android.widget.TextView
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListUpdateCallback
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.lagradost.cloudstream3.HomePageList
|
||||
import com.lagradost.cloudstream3.LoadResponse
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.HomepageParentBinding
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.ui.result.FOCUS_SELF
|
||||
import com.lagradost.cloudstream3.ui.result.setLinearListLayout
|
||||
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
||||
import com.lagradost.cloudstream3.ui.search.SearchFragment.Companion.filterSearchResponse
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.PHONE
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.isRecyclerScrollable
|
||||
|
||||
class LoadClickCallback(
|
||||
|
@ -32,18 +38,90 @@ open class ParentItemAdapter(
|
|||
private val clickCallback: (SearchClickCallback) -> Unit,
|
||||
private val moreInfoClickCallback: (HomeViewModel.ExpandableHomepageList) -> Unit,
|
||||
private val expandCallback: ((String) -> Unit)? = null,
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
) : RecyclerView.Adapter<ViewHolder>() {
|
||||
// Ok, this is fucked, but there is a reason for this as we want to resume 1. when scrolling up and down
|
||||
// and 2. when doing into a thing and coming back. 1 is always active, but 2 requires doing it in the fragment
|
||||
// as OnCreateView is called and this adapter is recreated losing the internal state to the GC
|
||||
//
|
||||
// 1. This works by having the adapter having a internal state "scrollStates" that keeps track of the states
|
||||
// when a view recycles, it looks up this internal state
|
||||
// 2. To solve the the coming back shit we have to save "scrollStates" to a Bundle inside the
|
||||
// fragment via onSaveInstanceState, because this cant be easy for some reason as the adapter does
|
||||
// not have a state but the layout-manager for no reason, then it is resumed via onRestoreInstanceState
|
||||
//
|
||||
// Even when looking at a real example they do this :skull:
|
||||
// https://github.com/vivchar/RendererRecyclerViewAdapter/blob/185251ee9d94fb6eb3e063b00d646b745186c365/example/src/main/java/com/github/vivchar/example/pages/github/GithubFragment.kt#L32
|
||||
private val scrollStates = mutableMapOf<Int, Parcelable?>()
|
||||
|
||||
companion object {
|
||||
private const val SCROLL_KEY: String = "ParentItemAdapter::scrollStates.keys"
|
||||
private const val SCROLL_VALUE: String = "ParentItemAdapter::scrollStates.values"
|
||||
}
|
||||
|
||||
open fun onRestoreInstanceState(savedInstanceState: Bundle?) {
|
||||
try {
|
||||
val keys = savedInstanceState?.getIntArray(SCROLL_KEY) ?: intArrayOf()
|
||||
val values = savedInstanceState?.getParcelableArray(SCROLL_VALUE) ?: arrayOf()
|
||||
for ((k, v) in keys.zip(values)) {
|
||||
this.scrollStates[k] = v
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
logError(t)
|
||||
}
|
||||
}
|
||||
|
||||
open fun onSaveInstanceState(outState: Bundle, recyclerView: RecyclerView? = null) {
|
||||
if (recyclerView != null) {
|
||||
for (position in items.indices) {
|
||||
val holder = recyclerView.findViewHolderForAdapterPosition(position) ?: continue
|
||||
saveHolder(holder)
|
||||
}
|
||||
}
|
||||
|
||||
outState.putIntArray(SCROLL_KEY, scrollStates.keys.toIntArray())
|
||||
outState.putParcelableArray(SCROLL_VALUE, scrollStates.values.toTypedArray())
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is ParentViewHolder -> {
|
||||
holder.bind(items[position])
|
||||
scrollStates[holder.absoluteAdapterPosition]?.let {
|
||||
holder.binding.homeChildRecyclerview.layoutManager?.onRestoreInstanceState(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveHolder(holder : ViewHolder) {
|
||||
when (holder) {
|
||||
is ParentViewHolder -> {
|
||||
scrollStates[holder.absoluteAdapterPosition] =
|
||||
holder.binding.homeChildRecyclerview.layoutManager?.onSaveInstanceState()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewRecycled(holder: ViewHolder) {
|
||||
saveHolder(holder)
|
||||
super.onViewRecycled(holder)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val layoutResId = when {
|
||||
isTrueTvSettings() -> R.layout.homepage_parent_tv
|
||||
parent.context.isEmulatorSettings() -> R.layout.homepage_parent_emulator
|
||||
isLayout(TV) -> R.layout.homepage_parent_tv
|
||||
isLayout(EMULATOR) -> R.layout.homepage_parent_emulator
|
||||
else -> R.layout.homepage_parent
|
||||
}
|
||||
|
||||
val root = LayoutInflater.from(parent.context).inflate(layoutResId, parent, false)
|
||||
|
||||
val binding = HomepageParentBinding.bind(root)
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val binding = try {
|
||||
HomepageParentBinding.bind(inflater.inflate(layoutResId, parent, false))
|
||||
} catch (t : Throwable) {
|
||||
logError(t)
|
||||
// just in case someone forgot we don't want to crash
|
||||
HomepageParentBinding.inflate(inflater)
|
||||
}
|
||||
|
||||
return ParentViewHolder(
|
||||
binding,
|
||||
|
@ -53,14 +131,6 @@ open class ParentItemAdapter(
|
|||
)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is ParentViewHolder -> {
|
||||
holder.bind(items[position])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return items.size
|
||||
}
|
||||
|
@ -116,7 +186,6 @@ open class ParentItemAdapter(
|
|||
}
|
||||
|
||||
override fun onChanged(_position: Int, count: Int, payload: Any?) {
|
||||
|
||||
val position = _position + delta
|
||||
|
||||
// I know kinda messy, what this does is using the update or bind instead of onCreateViewHolder -> bind
|
||||
|
@ -155,15 +224,15 @@ open class ParentItemAdapter(
|
|||
//diffResult.dispatchUpdatesTo(this)
|
||||
}
|
||||
|
||||
class ParentViewHolder
|
||||
constructor(
|
||||
|
||||
class ParentViewHolder(
|
||||
val binding: HomepageParentBinding,
|
||||
// val viewModel: HomeViewModel,
|
||||
private val clickCallback: (SearchClickCallback) -> Unit,
|
||||
private val moreInfoClickCallback: (HomeViewModel.ExpandableHomepageList) -> Unit,
|
||||
private val expandCallback: ((String) -> Unit)? = null,
|
||||
) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
ViewHolder(binding.root) {
|
||||
val title: TextView = binding.homeChildMoreInfo
|
||||
private val recyclerView: RecyclerView = binding.homeChildRecyclerview
|
||||
private val startFocus = R.id.nav_rail_view
|
||||
|
@ -237,7 +306,7 @@ open class ParentItemAdapter(
|
|||
})
|
||||
|
||||
//(recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged()
|
||||
if (!isTrueTvSettings()) {
|
||||
if (isLayout(PHONE)) {
|
||||
title.setOnClickListener {
|
||||
moreInfoClickCallback.invoke(expand)
|
||||
}
|
||||
|
|
|
@ -36,8 +36,9 @@ import com.lagradost.cloudstream3.ui.result.setLinearListLayout
|
|||
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD
|
||||
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_SHOW_METADATA
|
||||
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showOptionSelectStringRes
|
||||
|
@ -48,7 +49,8 @@ import com.lagradost.cloudstream3.utils.UIHelper.populateChips
|
|||
class HomeParentItemAdapterPreview(
|
||||
items: MutableList<HomeViewModel.ExpandableHomepageList>,
|
||||
private val viewModel: HomeViewModel,
|
||||
) : ParentItemAdapter(items, clickCallback = {
|
||||
) : ParentItemAdapter(items,
|
||||
clickCallback = {
|
||||
viewModel.click(it)
|
||||
}, moreInfoClickCallback = {
|
||||
viewModel.popup(it)
|
||||
|
@ -78,13 +80,13 @@ class HomeParentItemAdapterPreview(
|
|||
return when (viewType) {
|
||||
VIEW_TYPE_HEADER -> {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val binding = if (isTvSettings()) FragmentHomeHeadTvBinding.inflate(
|
||||
val binding = if (isLayout(TV or EMULATOR)) FragmentHomeHeadTvBinding.inflate(
|
||||
inflater,
|
||||
parent,
|
||||
false
|
||||
) else FragmentHomeHeadBinding.inflate(inflater, parent, false)
|
||||
|
||||
if (binding is FragmentHomeHeadTvBinding && parent.context.isEmulatorSettings()) {
|
||||
if (binding is FragmentHomeHeadTvBinding && isLayout(EMULATOR)) {
|
||||
binding.homeBookmarkParentItemMoreInfo.isVisible = true
|
||||
|
||||
val marginInDp = 50
|
||||
|
@ -598,7 +600,7 @@ class HomeParentItemAdapterPreview(
|
|||
if (
|
||||
binding is FragmentHomeHeadBinding ||
|
||||
binding is FragmentHomeHeadTvBinding &&
|
||||
binding.root.context.isEmulatorSettings()
|
||||
isLayout(EMULATOR)
|
||||
) {
|
||||
val title = (binding as? FragmentHomeHeadBinding)?.homeWatchParentItemTitle
|
||||
?: (binding as? FragmentHomeHeadTvBinding)?.homeWatchParentItemTitle
|
||||
|
@ -628,7 +630,7 @@ class HomeParentItemAdapterPreview(
|
|||
if (
|
||||
binding is FragmentHomeHeadBinding ||
|
||||
binding is FragmentHomeHeadTvBinding &&
|
||||
binding.root.context.isEmulatorSettings()
|
||||
isLayout(EMULATOR)
|
||||
) {
|
||||
val title = (binding as? FragmentHomeHeadBinding)?.homeBookmarkParentItemTitle
|
||||
?: (binding as? FragmentHomeHeadTvBinding)?.homeBookmarkParentItemTitle
|
||||
|
|
|
@ -10,7 +10,9 @@ import androidx.viewbinding.ViewBinding
|
|||
import com.lagradost.cloudstream3.LoadResponse
|
||||
import com.lagradost.cloudstream3.databinding.HomeScrollViewBinding
|
||||
import com.lagradost.cloudstream3.databinding.HomeScrollViewTvBinding
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
|
||||
class HomeScrollAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
@ -40,7 +42,7 @@ class HomeScrollAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val binding = if (isTvSettings()) {
|
||||
val binding = if (isLayout(TV or EMULATOR)) {
|
||||
HomeScrollViewTvBinding.inflate(inflater, parent, false)
|
||||
} else {
|
||||
HomeScrollViewBinding.inflate(inflater, parent, false)
|
||||
|
|
|
@ -34,7 +34,8 @@ import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
|||
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_FOCUSED
|
||||
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.addProgramsToContinueWatching
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||
|
@ -132,7 +133,7 @@ class HomeViewModel : ViewModel() {
|
|||
|
||||
private fun loadResumeWatching() = viewModelScope.launchSafe {
|
||||
val resumeWatchingResult = getResumeWatching()
|
||||
if (isTrueTvSettings() && resumeWatchingResult != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
if (isLayout(TV) && resumeWatchingResult != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
ioSafe {
|
||||
// this WILL crash on non tvs, so keep this inside a try catch
|
||||
activity?.addProgramsToContinueWatching(resumeWatchingResult)
|
||||
|
|
|
@ -49,6 +49,11 @@ import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
|||
import com.lagradost.cloudstream3.ui.result.txt
|
||||
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD
|
||||
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_SHOW_METADATA
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.PHONE
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
|
||||
|
@ -101,7 +106,7 @@ class LibraryFragment : Fragment() {
|
|||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View {
|
||||
val layout =
|
||||
if (SettingsFragment.isTvSettings()) R.layout.fragment_library_tv else R.layout.fragment_library
|
||||
if (isLayout(TV or EMULATOR)) R.layout.fragment_library_tv else R.layout.fragment_library
|
||||
val root = inflater.inflate(layout, container, false)
|
||||
binding = try {
|
||||
FragmentLibraryBinding.bind(root)
|
||||
|
@ -220,7 +225,7 @@ class LibraryFragment : Fragment() {
|
|||
settingsManager.getBoolean(
|
||||
getString(R.string.random_button_key),
|
||||
false
|
||||
) && !SettingsFragment.isTvSettings()
|
||||
) && isLayout(PHONE)
|
||||
binding?.libraryRandom?.visibility = View.GONE
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.lagradost.cloudstream3.ui.library
|
||||
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.doOnAttach
|
||||
|
@ -12,7 +11,9 @@ import com.lagradost.cloudstream3.R
|
|||
import com.lagradost.cloudstream3.databinding.LibraryViewpagerPageBinding
|
||||
import com.lagradost.cloudstream3.syncproviders.SyncAPI
|
||||
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
|
||||
|
||||
class ViewpagerAdapter(
|
||||
|
@ -73,7 +74,7 @@ class ViewpagerAdapter(
|
|||
val diff = scrollY - oldScrollY
|
||||
|
||||
//Expand the top Appbar based on scroll direction up/down, simulate phone behavior
|
||||
if (SettingsFragment.isTvSettings()) {
|
||||
if (isLayout(TV or EMULATOR)) {
|
||||
binding.root.rootView.findViewById<AppBarLayout>(R.id.search_bar)
|
||||
.apply {
|
||||
if (diff <= 0)
|
||||
|
|
|
@ -46,6 +46,7 @@ import com.lagradost.cloudstream3.ui.player.GeneratorPlayer.Companion.subsProvid
|
|||
import com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper
|
||||
import com.lagradost.cloudstream3.ui.result.setText
|
||||
import com.lagradost.cloudstream3.ui.result.txt
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.isUsingMobileData
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
|
@ -1514,7 +1515,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
|||
}
|
||||
}
|
||||
// cs3 is peak media center
|
||||
setRemainingTimeCounter(durationMode || SettingsFragment.isTrueTvSettings())
|
||||
setRemainingTimeCounter(durationMode || Globals.isLayout(Globals.TV))
|
||||
playerBinding?.exoPosition?.doOnTextChanged { _, _, _, _ ->
|
||||
updateRemainingTime()
|
||||
}
|
||||
|
|
|
@ -39,7 +39,10 @@ import com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSub
|
|||
import com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper
|
||||
import com.lagradost.cloudstream3.ui.player.source_priority.QualityProfileDialog
|
||||
import com.lagradost.cloudstream3.ui.result.*
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.ui.subtitles.SUBTITLE_AUTO_SELECT_KEY
|
||||
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment.Companion.getAutoSelectLanguageISO639_1
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
|
@ -1275,8 +1278,7 @@ class GeneratorPlayer : FullScreenPlayer() {
|
|||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View? {
|
||||
// this is used instead of layout-television to follow the settings and some TV devices are not classified as TV for some reason
|
||||
isTv = isTvSettings()
|
||||
layout = if (isTv) R.layout.fragment_player_tv else R.layout.fragment_player
|
||||
layout = if (isLayout(TV or EMULATOR)) R.layout.fragment_player_tv else R.layout.fragment_player
|
||||
|
||||
viewModel = ViewModelProvider(this)[PlayerGeneratorViewModel::class.java]
|
||||
sync = ViewModelProvider(this)[SyncViewModel::class.java]
|
||||
|
|
|
@ -9,6 +9,9 @@ import android.util.Log
|
|||
import androidx.annotation.WorkerThread
|
||||
import androidx.core.graphics.scale
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
|
@ -63,7 +66,7 @@ interface IPreviewGenerator {
|
|||
companion object {
|
||||
fun new(): IPreviewGenerator {
|
||||
/** because TV has low ram + not show we disable this for now */
|
||||
return if (SettingsFragment.isTrueTvSettings()) {
|
||||
return if (isLayout(TV)) {
|
||||
empty()
|
||||
} else {
|
||||
PreviewGenerator()
|
||||
|
|
|
@ -34,7 +34,8 @@ import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
|||
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||
import com.lagradost.cloudstream3.ui.search.SearchViewModel
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.ownShow
|
||||
import com.lagradost.cloudstream3.utils.UIHelper
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||
|
@ -277,7 +278,7 @@ class QuickSearchFragment : Fragment() {
|
|||
activity?.popCurrentPage()
|
||||
}
|
||||
|
||||
if (isTrueTvSettings()) {
|
||||
if (isLayout(TV)) {
|
||||
binding?.quickSearch?.requestFocus()
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,10 @@ import com.lagradost.cloudstream3.databinding.ResultEpisodeLargeBinding
|
|||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_LONG_CLICK
|
||||
import com.lagradost.cloudstream3.ui.download.DownloadClickEvent
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.PHONE
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.html
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
||||
|
@ -172,15 +174,13 @@ class EpisodeAdapter(
|
|||
@SuppressLint("SetTextI18n")
|
||||
fun bind(card: ResultEpisode) {
|
||||
localCard = card
|
||||
|
||||
val setWidth =
|
||||
if (isTvSettings()) TV_EP_SIZE_LARGE.toPx else ViewGroup.LayoutParams.MATCH_PARENT
|
||||
if (isLayout(TV or EMULATOR)) TV_EP_SIZE_LARGE.toPx else ViewGroup.LayoutParams.MATCH_PARENT
|
||||
|
||||
binding.episodeLinHolder.layoutParams.width = setWidth
|
||||
binding.episodeHolderLarge.layoutParams.width = setWidth
|
||||
binding.episodeHolder.layoutParams.width = setWidth
|
||||
|
||||
val isTrueTv = isTrueTvSettings()
|
||||
|
||||
binding.apply {
|
||||
downloadButton.isVisible = hasDownloadSupport
|
||||
|
@ -249,7 +249,7 @@ class EpisodeAdapter(
|
|||
|
||||
var isExpanded = false
|
||||
setOnClickListener {
|
||||
if (isTrueTv) {
|
||||
if (isLayout(TV)) {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_DESCRIPTION, card))
|
||||
} else {
|
||||
isExpanded = !isExpanded
|
||||
|
@ -260,7 +260,7 @@ class EpisodeAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
if (!isTrueTv) {
|
||||
if (isLayout(EMULATOR or PHONE)) {
|
||||
episodePoster.setOnClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card))
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ class EpisodeAdapter(
|
|||
clickCallback.invoke(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card))
|
||||
}
|
||||
|
||||
if (isTrueTv) {
|
||||
if (isLayout(TV)) {
|
||||
itemView.isFocusable = true
|
||||
itemView.isFocusableInTouchMode = true
|
||||
//itemView.touchscreenBlocksFocus = false
|
||||
|
@ -300,11 +300,9 @@ class EpisodeAdapter(
|
|||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun bind(card: ResultEpisode) {
|
||||
val isTrueTv = isTrueTvSettings()
|
||||
|
||||
binding.episodeHolder.layoutParams.apply {
|
||||
width =
|
||||
if (isTvSettings()) TV_EP_SIZE_SMALL.toPx else ViewGroup.LayoutParams.MATCH_PARENT
|
||||
if (isLayout(TV or EMULATOR)) TV_EP_SIZE_SMALL.toPx else ViewGroup.LayoutParams.MATCH_PARENT
|
||||
}
|
||||
|
||||
binding.apply {
|
||||
|
@ -361,7 +359,7 @@ class EpisodeAdapter(
|
|||
clickCallback.invoke(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card))
|
||||
}
|
||||
|
||||
if (isTrueTv) {
|
||||
if (isLayout(TV)) {
|
||||
itemView.isFocusable = true
|
||||
itemView.isFocusableInTouchMode = true
|
||||
//itemView.touchscreenBlocksFocus = false
|
||||
|
|
|
@ -5,7 +5,8 @@ import android.view.ViewGroup
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lagradost.cloudstream3.databinding.ResultMiniImageBinding
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
|
||||
/*
|
||||
class ImageAdapter(context: Context, val resource: Int) : ArrayAdapter<Int>(context, resource) {
|
||||
|
@ -83,7 +84,7 @@ class ImageAdapter(
|
|||
this.nextFocusUpId = nextFocusUp
|
||||
}
|
||||
if (clickCallback != null) {
|
||||
if (isTrueTvSettings()) {
|
||||
if (isLayout(TV)) {
|
||||
isClickable = true
|
||||
isLongClickable = true
|
||||
isFocusable = true
|
||||
|
|
|
@ -39,8 +39,10 @@ import com.lagradost.cloudstream3.ui.result.ResultFragment.updateUIEvent
|
|||
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_FOCUSED
|
||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.html
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.isRtl
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
|
||||
|
@ -598,7 +600,7 @@ class ResultFragmentTv : Fragment() {
|
|||
}
|
||||
|
||||
observeNullable(viewModel.subscribeStatus) { isSubscribed ->
|
||||
binding?.resultSubscribe?.isVisible = isSubscribed != null && requireContext().isEmulatorSettings()
|
||||
binding?.resultSubscribe?.isVisible = isSubscribed != null && isLayout(EMULATOR)
|
||||
binding?.resultSubscribeButton?.apply {
|
||||
|
||||
if (isSubscribed == null) return@observeNullable
|
||||
|
@ -752,7 +754,7 @@ class ResultFragmentTv : Fragment() {
|
|||
setRecommendations(recommendations, null)
|
||||
}
|
||||
|
||||
if (isTrueTvSettings()) {
|
||||
if (isLayout(TV)) {
|
||||
observe(viewModel.episodeSynopsis) { description ->
|
||||
view.context?.let { ctx ->
|
||||
val builder: AlertDialog.Builder =
|
||||
|
@ -878,7 +880,7 @@ class ResultFragmentTv : Fragment() {
|
|||
resultDescription.apply {
|
||||
setTextHtml(d.plotText)
|
||||
setOnClickListener {
|
||||
if (context.isEmulatorSettings()) {
|
||||
if (isLayout(EMULATOR)) {
|
||||
isExpanded = !isExpanded
|
||||
maxLines = if (isExpanded) {
|
||||
Integer.MAX_VALUE
|
||||
|
|
|
@ -928,15 +928,20 @@ class ResultViewModel2 : ViewModel() {
|
|||
) {
|
||||
val isSubscribed = _subscribeStatus.value ?: return
|
||||
val response = currentResponse ?: return
|
||||
if (response !is EpisodeResponse) return
|
||||
|
||||
val currentId = currentId ?: return
|
||||
|
||||
// This might be a bit confusing, but even if the loadresponse is not a EpisodeResponse
|
||||
// _subscribeStatus might be true.
|
||||
|
||||
if (isSubscribed) {
|
||||
removeSubscribedData(currentId)
|
||||
statusChangedCallback?.invoke(false)
|
||||
_subscribeStatus.postValue(false)
|
||||
_subscribeStatus.postValue(if (response is EpisodeResponse) false else null)
|
||||
MainActivity.reloadLibraryEvent(true)
|
||||
} else {
|
||||
if (response !is EpisodeResponse) {
|
||||
return
|
||||
}
|
||||
checkAndWarnDuplicates(
|
||||
context,
|
||||
LibraryListType.SUBSCRIPTIONS,
|
||||
|
@ -981,8 +986,8 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
|
||||
_subscribeStatus.postValue(true)
|
||||
|
||||
statusChangedCallback?.invoke(true)
|
||||
MainActivity.reloadLibraryEvent(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2046,12 +2051,15 @@ class ResultViewModel2 : ViewModel() {
|
|||
}
|
||||
|
||||
private fun postSubscription(loadResponse: LoadResponse) {
|
||||
val id = loadResponse.getId()
|
||||
val data = getSubscribedData(id)
|
||||
if (loadResponse.isEpisodeBased()) {
|
||||
val id = loadResponse.getId()
|
||||
val data = getSubscribedData(id)
|
||||
updateSubscribedData(id, data, loadResponse as? EpisodeResponse)
|
||||
val isSubscribed = data != null
|
||||
_subscribeStatus.postValue(isSubscribed)
|
||||
_subscribeStatus.postValue(data != null)
|
||||
}
|
||||
// lets say that we have subscribed, then we must be able to unsubscribe no matter what
|
||||
else if (data != null) {
|
||||
_subscribeStatus.postValue(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2585,6 +2593,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
override var posterHeaders: Map<String, String>? = null,
|
||||
override var backgroundPosterUrl: String? = null,
|
||||
override var contentRating: String? = null,
|
||||
val id : Int?,
|
||||
) : LoadResponse
|
||||
|
||||
fun loadSmall(activity: Activity?, searchResponse : SearchResponse) = ioSafe {
|
||||
|
@ -2594,7 +2603,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
val api = APIHolder.getApiFromNameNull(searchResponse.apiName) ?: APIHolder.getApiFromUrlNull(searchResponse.url) ?: APIRepository.noneApi
|
||||
val repo = APIRepository(api)
|
||||
val response = LoadResponseFromSearch(name = searchResponse.name, url = searchResponse.url, apiName = api.name, type = searchResponse.type ?: TvType.Others,
|
||||
posterUrl = searchResponse.posterUrl).apply {
|
||||
posterUrl = searchResponse.posterUrl, id = searchResponse.id).apply {
|
||||
if (searchResponse is SyncAPI.LibraryItem) {
|
||||
this.plot = searchResponse.plot
|
||||
this.rating = searchResponse.personalRating?.times(100) ?: searchResponse.rating
|
||||
|
@ -2606,12 +2615,14 @@ class ResultViewModel2 : ViewModel() {
|
|||
this.tags = searchResponse.tags
|
||||
}
|
||||
}
|
||||
val mainId = searchResponse.id ?: response.getId()
|
||||
val mainId = response.getId()
|
||||
|
||||
postSuccessful(
|
||||
loadResponse = response,
|
||||
mainId = mainId,
|
||||
apiRepository = repo, updateEpisodes = false, updateFillers = false)
|
||||
apiRepository = repo,
|
||||
updateEpisodes = false,
|
||||
updateFillers = false)
|
||||
}
|
||||
|
||||
fun load(
|
||||
|
|
|
@ -6,7 +6,8 @@ import androidx.recyclerview.widget.DiffUtil
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.lagradost.cloudstream3.databinding.ResultSelectionBinding
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
|
||||
typealias SelectData = Pair<UiText?, Any>
|
||||
|
||||
|
@ -72,8 +73,7 @@ class SelectAdaptor(val callback: (Any) -> Unit) : RecyclerView.Adapter<Recycler
|
|||
fun bind(
|
||||
data: SelectData, isSelected: Boolean, callback: (Any) -> Unit
|
||||
) {
|
||||
val isTrueTv = isTrueTvSettings()
|
||||
if (isTrueTv) {
|
||||
if (isLayout(TV)) {
|
||||
item.isFocusable = true
|
||||
item.isFocusableInTouchMode = true
|
||||
}
|
||||
|
|
|
@ -54,8 +54,9 @@ import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.updateChips
|
|||
import com.lagradost.cloudstream3.ui.home.ParentItemAdapter
|
||||
import com.lagradost.cloudstream3.ui.result.FOCUS_SELF
|
||||
import com.lagradost.cloudstream3.ui.result.setLinearListLayout
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.ownHide
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.ownShow
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.setDefaultFocus
|
||||
|
@ -107,13 +108,16 @@ class SearchFragment : Fragment() {
|
|||
)
|
||||
bottomSheetDialog?.ownShow()
|
||||
|
||||
val layout = if (isTvSettings()) R.layout.fragment_search_tv else R.layout.fragment_search
|
||||
|
||||
val root = inflater.inflate(layout, container, false)
|
||||
// TODO TRYCATCH
|
||||
binding = FragmentSearchBinding.bind(root)
|
||||
binding = try {
|
||||
val layout = if (isLayout(TV or EMULATOR)) R.layout.fragment_search_tv else R.layout.fragment_search
|
||||
val root = inflater.inflate(layout, container, false)
|
||||
FragmentSearchBinding.bind(root)
|
||||
} catch (t : Throwable) {
|
||||
FragmentSearchBinding.inflate(inflater)
|
||||
}
|
||||
|
||||
return root
|
||||
return binding?.root
|
||||
}
|
||||
|
||||
private fun fixGrid() {
|
||||
|
@ -369,7 +373,7 @@ class SearchFragment : Fragment() {
|
|||
|
||||
selectedSearchTypes = DataStoreHelper.searchPreferenceTags.toMutableList()
|
||||
|
||||
if (isTrueTvSettings()) {
|
||||
if (isLayout(TV)) {
|
||||
binding?.searchFilter?.isFocusable = true
|
||||
binding?.searchFilter?.isFocusableInTouchMode = true
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.lagradost.cloudstream3.ui.search
|
||||
|
||||
import android.app.Activity
|
||||
import android.widget.Toast
|
||||
import com.lagradost.cloudstream3.CommonActivity.activity
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
|
@ -10,7 +9,8 @@ import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_PLAY_FILE
|
|||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
||||
import com.lagradost.cloudstream3.ui.download.DownloadClickEvent
|
||||
import com.lagradost.cloudstream3.ui.result.START_ACTION_LOAD_EP
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.PHONE
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
|
@ -56,7 +56,7 @@ object SearchHelper {
|
|||
}
|
||||
}
|
||||
SEARCH_ACTION_SHOW_METADATA -> {
|
||||
if(!isTvSettings()) { // we only want this on phone as UI is not done yet on tv
|
||||
if(isLayout(PHONE)) { // we only want this on phone as UI is not done yet on tv
|
||||
(activity as? MainActivity?)?.apply {
|
||||
loadPopup(callback.card)
|
||||
} ?: kotlin.run {
|
||||
|
|
|
@ -17,7 +17,8 @@ import com.lagradost.cloudstream3.SearchQuality
|
|||
import com.lagradost.cloudstream3.SearchResponse
|
||||
import com.lagradost.cloudstream3.isMovieType
|
||||
import com.lagradost.cloudstream3.syncproviders.SyncAPI
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual
|
||||
|
@ -164,7 +165,7 @@ object SearchResultBuilder {
|
|||
|
||||
bg.isFocusable = false
|
||||
bg.isFocusableInTouchMode = false
|
||||
if(!isTrueTvSettings()) {
|
||||
if(!isLayout(TV)) {
|
||||
bg.setOnClickListener {
|
||||
click(it)
|
||||
}
|
||||
|
@ -207,7 +208,7 @@ object SearchResultBuilder {
|
|||
|
||||
*/
|
||||
|
||||
if (isTrueTvSettings()) {
|
||||
if (isLayout(TV)) {
|
||||
// bg.isFocusable = true
|
||||
// bg.isFocusableInTouchMode = true
|
||||
// bg.touchscreenBlocksFocus = false
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package com.lagradost.cloudstream3.ui.settings
|
||||
|
||||
import android.app.UiModeManager
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.lagradost.cloudstream3.R
|
||||
|
||||
object Globals {
|
||||
var beneneCount = 0
|
||||
|
||||
const val PHONE : Int = 0b001
|
||||
const val TV : Int = 0b010
|
||||
const val EMULATOR : Int = 0b100
|
||||
private const val INVALID = -1
|
||||
private var layoutId = INVALID
|
||||
|
||||
private fun Context.getLayoutInt(): Int {
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
return settingsManager.getInt(this.getString(R.string.app_layout_key), -1)
|
||||
}
|
||||
|
||||
private fun Context.isAutoTv(): Boolean {
|
||||
val uiModeManager = getSystemService(Context.UI_MODE_SERVICE) as UiModeManager?
|
||||
// AFT = Fire TV
|
||||
val model = Build.MODEL.lowercase()
|
||||
return uiModeManager?.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION || Build.MODEL.contains(
|
||||
"AFT"
|
||||
) || model.contains("firestick") || model.contains("fire tv") || model.contains("chromecast")
|
||||
}
|
||||
|
||||
private fun Context.layoutIntCorrected(): Int {
|
||||
return when(getLayoutInt()) {
|
||||
-1 -> if (isAutoTv()) TV else PHONE
|
||||
0 -> PHONE
|
||||
1 -> TV
|
||||
2 -> EMULATOR
|
||||
else -> PHONE
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.updateTv() {
|
||||
layoutId = layoutIntCorrected()
|
||||
}
|
||||
|
||||
/** Returns true if the layout is any of the flags,
|
||||
* so isLayout(TV or EMULATOR) is a valid statement for checking if the layout is in the emulator
|
||||
* or tv. Auto will become the "TV" or the "PHONE" layout.
|
||||
*
|
||||
* Valid flags are: PHONE, TV, EMULATOR
|
||||
* */
|
||||
fun isLayout(flags: Int) : Boolean {
|
||||
return (layoutId and flags) != 0
|
||||
}
|
||||
}
|
|
@ -29,8 +29,10 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.simklAp
|
|||
import com.lagradost.cloudstream3.syncproviders.AuthAPI
|
||||
import com.lagradost.cloudstream3.syncproviders.InAppAuthAPI
|
||||
import com.lagradost.cloudstream3.syncproviders.OAuth2API
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
|
||||
|
@ -76,7 +78,7 @@ class SettingsAccount : PreferenceFragmentCompat() {
|
|||
showAccountSwitch(activity, api)
|
||||
}
|
||||
|
||||
if (isTvSettings()) {
|
||||
if (isLayout(TV or EMULATOR)) {
|
||||
binding.accountSwitchAccount.requestFocus()
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +142,7 @@ class SettingsAccount : PreferenceFragmentCompat() {
|
|||
binding.loginUsernameInput to api.requiresUsername
|
||||
)
|
||||
|
||||
if (isTvSettings()) {
|
||||
if (isLayout(TV or EMULATOR)) {
|
||||
visibilityMap.forEach { (input, isVisible) ->
|
||||
input.isVisible = isVisible
|
||||
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
package com.lagradost.cloudstream3.ui.settings
|
||||
|
||||
import android.app.UiModeManager
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -16,18 +12,19 @@ import androidx.core.view.updateLayoutParams
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.context
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.MainSettingsBinding
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.accountManagers
|
||||
import com.lagradost.cloudstream3.ui.home.HomeFragment
|
||||
import com.lagradost.cloudstream3.ui.result.txt
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.UIHelper
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.clipboardHelper
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
||||
|
@ -35,10 +32,6 @@ import java.io.File
|
|||
|
||||
class SettingsFragment : Fragment() {
|
||||
companion object {
|
||||
var beneneCount = 0
|
||||
|
||||
private var isTv: Boolean = false
|
||||
private var isTrueTv: Boolean = false
|
||||
|
||||
fun PreferenceFragmentCompat?.getPref(id: Int): Preference? {
|
||||
if (this == null) return null
|
||||
|
@ -55,12 +48,12 @@ class SettingsFragment : Fragment() {
|
|||
* On TV you cannot properly scroll to the bottom of settings, this fixes that.
|
||||
* */
|
||||
fun PreferenceFragmentCompat.setPaddingBottom() {
|
||||
if (isTvSettings()) {
|
||||
if (isLayout(TV or EMULATOR)) {
|
||||
listView?.setPadding(0, 0, 0, 100.toPx)
|
||||
}
|
||||
}
|
||||
fun PreferenceFragmentCompat.setToolBarScrollFlags() {
|
||||
if (isTvSettings()) {
|
||||
if (isLayout(TV or EMULATOR)) {
|
||||
val settingsAppbar = view?.findViewById<MaterialToolbar>(R.id.settings_toolbar)
|
||||
|
||||
settingsAppbar?.updateLayoutParams<AppBarLayout.LayoutParams> {
|
||||
|
@ -69,7 +62,7 @@ class SettingsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
fun Fragment?.setToolBarScrollFlags() {
|
||||
if (isTvSettings()) {
|
||||
if (isLayout(TV or EMULATOR)) {
|
||||
val settingsAppbar = this?.view?.findViewById<MaterialToolbar>(R.id.settings_toolbar)
|
||||
|
||||
settingsAppbar?.updateLayoutParams<AppBarLayout.LayoutParams> {
|
||||
|
@ -88,7 +81,7 @@ class SettingsFragment : Fragment() {
|
|||
activity?.onBackPressedDispatcher?.onBackPressed()
|
||||
}
|
||||
}
|
||||
fixPaddingStatusbar(settingsToolbar)
|
||||
UIHelper.fixPaddingStatusbar(settingsToolbar)
|
||||
}
|
||||
|
||||
fun Fragment?.setUpToolbar(@StringRes title: Int) {
|
||||
|
@ -103,7 +96,7 @@ class SettingsFragment : Fragment() {
|
|||
activity?.onBackPressedDispatcher?.onBackPressed()
|
||||
}
|
||||
}
|
||||
fixPaddingStatusbar(settingsToolbar)
|
||||
UIHelper.fixPaddingStatusbar(settingsToolbar)
|
||||
}
|
||||
|
||||
fun getFolderSize(dir: File): Long {
|
||||
|
@ -119,60 +112,7 @@ class SettingsFragment : Fragment() {
|
|||
|
||||
return size
|
||||
}
|
||||
|
||||
private fun Context.getLayoutInt(): Int {
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
return settingsManager.getInt(this.getString(R.string.app_layout_key), -1)
|
||||
}
|
||||
|
||||
private fun Context.isTvSettings(): Boolean {
|
||||
var value = getLayoutInt()
|
||||
if (value == -1) {
|
||||
value = if (isAutoTv()) 1 else 0
|
||||
}
|
||||
return value == 1 || value == 2
|
||||
}
|
||||
|
||||
private fun Context.isTrueTvSettings(): Boolean {
|
||||
var value = getLayoutInt()
|
||||
if (value == -1) {
|
||||
value = if (isAutoTv()) 1 else 0
|
||||
}
|
||||
return value == 1
|
||||
}
|
||||
|
||||
fun Context.updateTv() {
|
||||
isTrueTv = isTrueTvSettings()
|
||||
isTv = isTvSettings()
|
||||
}
|
||||
|
||||
fun isTrueTvSettings(): Boolean {
|
||||
return isTrueTv
|
||||
}
|
||||
|
||||
fun isTvSettings(): Boolean {
|
||||
return isTv
|
||||
}
|
||||
|
||||
fun Context.isEmulatorSettings(): Boolean {
|
||||
return getLayoutInt() == 2
|
||||
}
|
||||
|
||||
// phone exclusive
|
||||
fun isTruePhone(): Boolean {
|
||||
return !isTrueTvSettings() && !isTvSettings() && context?.isEmulatorSettings() != true
|
||||
}
|
||||
|
||||
private fun Context.isAutoTv(): Boolean {
|
||||
val uiModeManager = getSystemService(Context.UI_MODE_SERVICE) as UiModeManager?
|
||||
// AFT = Fire TV
|
||||
val model = Build.MODEL.lowercase()
|
||||
return uiModeManager?.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION || Build.MODEL.contains(
|
||||
"AFT"
|
||||
) || model.contains("firestick") || model.contains("fire tv") || model.contains("chromecast")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
|
@ -197,8 +137,6 @@ class SettingsFragment : Fragment() {
|
|||
|
||||
// used to debug leaks showToast(activity,"${VideoDownloadManager.downloadStatusEvent.size} : ${VideoDownloadManager.downloadProgressEvent.size}")
|
||||
|
||||
val isTrueTv = isTrueTvSettings()
|
||||
|
||||
for (syncApi in accountManagers) {
|
||||
val login = syncApi.loginInfo()
|
||||
val pic = login?.profilePicture ?: continue
|
||||
|
@ -226,7 +164,7 @@ class SettingsFragment : Fragment() {
|
|||
setOnClickListener {
|
||||
navigate(navigationId)
|
||||
}
|
||||
if (isTrueTv) {
|
||||
if (isLayout(TV)) {
|
||||
isFocusable = true
|
||||
isFocusableInTouchMode = true
|
||||
}
|
||||
|
@ -234,7 +172,7 @@ class SettingsFragment : Fragment() {
|
|||
}
|
||||
|
||||
// Default focus on TV
|
||||
if (isTrueTv) {
|
||||
if (isLayout(TV)) {
|
||||
settingsGeneral.requestFocus()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import com.lagradost.cloudstream3.mvvm.logError
|
|||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.network.initClient
|
||||
import com.lagradost.cloudstream3.ui.EasterEggMonke
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.beneneCount
|
||||
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.setToolBarScrollFlags
|
||||
|
@ -378,30 +379,30 @@ class SettingsGeneral : PreferenceFragmentCompat() {
|
|||
}
|
||||
|
||||
try {
|
||||
SettingsFragment.beneneCount =
|
||||
beneneCount =
|
||||
settingsManager.getInt(getString(R.string.benene_count), 0)
|
||||
getPref(R.string.benene_count)?.let { pref ->
|
||||
pref.summary =
|
||||
if (SettingsFragment.beneneCount <= 0) getString(R.string.benene_count_text_none) else getString(
|
||||
if (beneneCount <= 0) getString(R.string.benene_count_text_none) else getString(
|
||||
R.string.benene_count_text
|
||||
).format(
|
||||
SettingsFragment.beneneCount
|
||||
beneneCount
|
||||
)
|
||||
|
||||
pref.setOnPreferenceClickListener {
|
||||
try {
|
||||
SettingsFragment.beneneCount++
|
||||
if (SettingsFragment.beneneCount%20 == 0) {
|
||||
beneneCount++
|
||||
if (beneneCount%20 == 0) {
|
||||
val intent = Intent(context, EasterEggMonke::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
settingsManager.edit().putInt(
|
||||
getString(R.string.benene_count),
|
||||
SettingsFragment.beneneCount
|
||||
beneneCount
|
||||
)
|
||||
.apply()
|
||||
it.summary =
|
||||
getString(R.string.benene_count_text).format(SettingsFragment.beneneCount)
|
||||
getString(R.string.benene_count_text).format(beneneCount)
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ import com.lagradost.cloudstream3.R
|
|||
import com.lagradost.cloudstream3.SearchQuality
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.updateTv
|
||||
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.setToolBarScrollFlags
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.updateTv
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog
|
||||
|
|
|
@ -29,7 +29,8 @@ import com.lagradost.cloudstream3.plugins.RepositoryManager
|
|||
import com.lagradost.cloudstream3.ui.result.FOCUS_SELF
|
||||
import com.lagradost.cloudstream3.ui.result.setLinearListLayout
|
||||
import com.lagradost.cloudstream3.ui.result.setText
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.downloadAllPluginsDialog
|
||||
|
@ -97,7 +98,7 @@ class ExtensionsFragment : Fragment() {
|
|||
nextLeft = R.id.nav_rail_view
|
||||
)
|
||||
|
||||
if (!isTrueTvSettings())
|
||||
if (!isLayout(TV))
|
||||
binding?.addRepoButton?.let { button ->
|
||||
button.post {
|
||||
setPadding(
|
||||
|
@ -286,7 +287,7 @@ class ExtensionsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
val isTv = isTrueTvSettings()
|
||||
val isTv = isLayout(TV)
|
||||
binding?.apply {
|
||||
addRepoButton.isGone = isTv
|
||||
addRepoButtonImageviewHolder.isVisible = isTv
|
||||
|
|
|
@ -17,7 +17,8 @@ import com.lagradost.cloudstream3.plugins.PluginManager
|
|||
import com.lagradost.cloudstream3.plugins.VotingApi.getVotes
|
||||
import com.lagradost.cloudstream3.ui.result.setText
|
||||
import com.lagradost.cloudstream3.ui.result.txt
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.html
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
|
@ -44,7 +45,7 @@ class PluginAdapter(
|
|||
private val plugins: MutableList<PluginViewData> = mutableListOf()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val layout = if(isTrueTvSettings()) R.layout.repository_item_tv else R.layout.repository_item
|
||||
val layout = if(isLayout(TV)) R.layout.repository_item_tv else R.layout.repository_item
|
||||
val inflated = LayoutInflater.from(parent.context).inflate(layout, parent, false)
|
||||
|
||||
return PluginViewHolder(
|
||||
|
|
|
@ -17,7 +17,9 @@ import com.lagradost.cloudstream3.mvvm.observe
|
|||
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.bindChips
|
||||
import com.lagradost.cloudstream3.ui.result.FOCUS_SELF
|
||||
import com.lagradost.cloudstream3.ui.result.setLinearListLayout
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
|
||||
import com.lagradost.cloudstream3.ui.settings.appLanguages
|
||||
|
@ -155,7 +157,7 @@ class PluginsFragment : Fragment() {
|
|||
pluginViewModel.handlePluginAction(activity, url, it, isLocal)
|
||||
}
|
||||
|
||||
if (isTvSettings()) {
|
||||
if (isLayout(TV or EMULATOR)) {
|
||||
// Scrolling down does not reveal the whole RecyclerView on TV, add to bypass that.
|
||||
binding?.pluginRecyclerView?.setPadding(0, 0, 0, 200.toPx)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,8 @@ import com.lagradost.cloudstream3.databinding.RepositoryItemBinding
|
|||
import com.lagradost.cloudstream3.databinding.RepositoryItemTvBinding
|
||||
import com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES
|
||||
import com.lagradost.cloudstream3.ui.result.txt
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.clipboardHelper
|
||||
|
||||
class RepoAdapter(
|
||||
|
@ -23,7 +24,7 @@ class RepoAdapter(
|
|||
private val repositories: MutableList<RepositoryData> = mutableListOf()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val layout = if (isTrueTvSettings()) RepositoryItemTvBinding.inflate(
|
||||
val layout = if (isLayout(TV)) RepositoryItemTvBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
|
|
|
@ -11,7 +11,8 @@ import com.lagradost.cloudstream3.databinding.FragmentTestingBinding
|
|||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.mvvm.observeNullable
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
|
||||
|
||||
|
@ -62,7 +63,7 @@ class TestFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
if (isTrueTvSettings()) {
|
||||
if (isLayout(TV)) {
|
||||
providerTest.playPauseButton?.isFocusableInTouchMode = true
|
||||
providerTest.playPauseButton?.requestFocus()
|
||||
}
|
||||
|
@ -75,7 +76,7 @@ class TestFragment : Fragment() {
|
|||
|
||||
fun focusRecyclerView() {
|
||||
// Hack to make it possible to focus the recyclerview.
|
||||
if (isTrueTvSettings()) {
|
||||
if (isLayout(TV)) {
|
||||
providerTestRecyclerView.requestFocus()
|
||||
providerTestAppbar.setExpanded(false, true)
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@ import android.view.ViewGroup
|
|||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import androidx.media3.common.text.Cue
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.google.android.gms.cast.TextTrackStyle
|
||||
import com.google.android.gms.cast.TextTrackStyle.*
|
||||
import com.jaredrummler.android.colorpicker.ColorPickerDialog
|
||||
|
@ -24,7 +24,9 @@ import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
|
|||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.ChromecastSubtitleSettingsBinding
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
||||
import com.lagradost.cloudstream3.utils.Event
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
||||
|
@ -173,7 +175,7 @@ class ChromecastSubtitlesFragment : Fragment() {
|
|||
state = getCurrentSavedStyle()
|
||||
context?.updateState()
|
||||
|
||||
val isTvSettings = isTvSettings()
|
||||
val isTvSettings = isLayout(TV or EMULATOR)
|
||||
|
||||
fun View.setFocusableInTv() {
|
||||
this.isFocusableInTouchMode = isTvSettings
|
||||
|
|
|
@ -28,7 +28,9 @@ import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
|
|||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.SubtitleSettingsBinding
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
||||
import com.lagradost.cloudstream3.utils.Event
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
||||
|
@ -252,7 +254,7 @@ class SubtitlesFragment : Fragment() {
|
|||
state = getCurrentSavedStyle()
|
||||
context?.updateState()
|
||||
|
||||
val isTvTrueSettings = isTrueTvSettings()
|
||||
val isTvTrueSettings = isLayout(TV)
|
||||
|
||||
fun View.setFocusableInTv() {
|
||||
this.isFocusableInTouchMode = isTvTrueSettings
|
||||
|
|
|
@ -61,8 +61,7 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appStri
|
|||
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
|
||||
import com.lagradost.cloudstream3.ui.WebviewFragment
|
||||
import com.lagradost.cloudstream3.ui.result.ResultFragment
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals
|
||||
import com.lagradost.cloudstream3.ui.settings.extensions.PluginsViewModel.Companion.downloadAll
|
||||
import com.lagradost.cloudstream3.ui.settings.extensions.RepositoryData
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||
|
@ -78,7 +77,6 @@ import okhttp3.Cache
|
|||
import java.io.*
|
||||
import java.net.URL
|
||||
import java.net.URLDecoder
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
object AppUtils {
|
||||
fun RecyclerView.setMaxViewPoolSize(maxViewTypeId: Int, maxPoolSize: Int) {
|
||||
|
@ -583,7 +581,7 @@ object AppUtils {
|
|||
//private val viewModel: ResultViewModel by activityViewModels()
|
||||
|
||||
private fun getResultsId(): Int {
|
||||
return if (isTvSettings()) {
|
||||
return if (Globals.isLayout(Globals.TV or Globals.EMULATOR)) {
|
||||
R.id.global_to_navigation_results_tv
|
||||
} else {
|
||||
R.id.global_to_navigation_results_phone
|
||||
|
@ -707,7 +705,7 @@ object AppUtils {
|
|||
* Sets the focus to the negative button when in TV and Emulator layout.
|
||||
**/
|
||||
fun AlertDialog.setDefaultFocus(buttonFocus: Int = DialogInterface.BUTTON_NEGATIVE) {
|
||||
if (!isTvSettings()) return
|
||||
if (!Globals.isLayout(Globals.TV or Globals.EMULATOR)) return
|
||||
this.getButton(buttonFocus).run {
|
||||
isFocusableInTouchMode = true
|
||||
requestFocus()
|
||||
|
|
|
@ -21,7 +21,9 @@ import com.lagradost.cloudstream3.databinding.BottomInputDialogBinding
|
|||
import com.lagradost.cloudstream3.databinding.BottomSelectionDialogBinding
|
||||
import com.lagradost.cloudstream3.databinding.BottomTextDialogBinding
|
||||
import com.lagradost.cloudstream3.databinding.OptionsPopupTvBinding
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
|
@ -54,7 +56,7 @@ object SingleSelectionHelper {
|
|||
) {
|
||||
if (this == null) return
|
||||
|
||||
if (isTvSettings()) {
|
||||
if (isLayout(TV or EMULATOR)) {
|
||||
val binding = OptionsPopupTvBinding.inflate(layoutInflater)
|
||||
val dialog = AlertDialog.Builder(this, R.style.AlertDialogCustom)
|
||||
.setView(binding.root)
|
||||
|
|
|
@ -69,8 +69,9 @@ import com.lagradost.cloudstream3.mvvm.logError
|
|||
import com.lagradost.cloudstream3.ui.result.UiImage
|
||||
import com.lagradost.cloudstream3.ui.result.UiText
|
||||
import com.lagradost.cloudstream3.ui.result.txt
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import jp.wasabeef.glide.transformations.BlurTransformation
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
@ -468,7 +469,7 @@ object UIHelper {
|
|||
}
|
||||
|
||||
fun Context.getStatusBarHeight(): Int {
|
||||
if (isTvSettings()) {
|
||||
if (isLayout(Globals.TV or EMULATOR)) {
|
||||
return 0
|
||||
}
|
||||
|
||||
|
@ -570,7 +571,7 @@ object UIHelper {
|
|||
(View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
|
||||
//}
|
||||
|
||||
changeStatusBarState(isEmulatorSettings())
|
||||
changeStatusBarState(isLayout(EMULATOR))
|
||||
}
|
||||
|
||||
fun Context.shouldShowPIPMode(isInPlayer: Boolean): Boolean {
|
||||
|
|
|
@ -41,22 +41,34 @@
|
|||
android:layout_marginStart="10dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<FrameLayout
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/resultview_preview_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:textColor="?attr/textColor"
|
||||
android:textSize="16sp"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginEnd="25dp"
|
||||
tools:text="The Perfect Run">
|
||||
tools:text="The Perfect Run" />
|
||||
|
||||
</TextView>
|
||||
<ImageView
|
||||
android:id="@+id/resultview_preview_subscribe"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
|
||||
android:layout_margin="5dp"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/subscribe_tooltip"
|
||||
android:elevation="10dp"
|
||||
android:nextFocusDown="@id/resultview_preview_bookmark"
|
||||
android:src="@drawable/baseline_notifications_none_24"
|
||||
app:tint="?attr/textColor" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/resultview_preview_favorite"
|
||||
|
@ -66,11 +78,13 @@
|
|||
|
||||
android:layout_margin="5dp"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/favorite"
|
||||
android:elevation="10dp"
|
||||
android:nextFocusDown="@id/resultview_preview_bookmark"
|
||||
android:src="@drawable/ic_baseline_favorite_border_24"
|
||||
app:tint="?attr/textColor" />
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.lagradost.cloudstream3.widget.FlowLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -134,38 +148,38 @@
|
|||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:padding="7dp"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="7dp">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/resultview_preview_bookmark"
|
||||
style="@style/BlackButton"
|
||||
android:layout_width="50dp"
|
||||
android:layout_weight="1"
|
||||
android:nextFocusUp="@id/resultview_preview_favorite"
|
||||
|
||||
android:nextFocusRight="@id/resultview_preview_more_info"
|
||||
|
||||
tools:visibility="visible"
|
||||
|
||||
android:nextFocusUp="@id/resultview_preview_favorite"
|
||||
app:icon="@drawable/ic_baseline_bookmark_24"
|
||||
tools:text="Bookmark"
|
||||
style="@style/BlackButton"
|
||||
|
||||
android:layout_width="50dp" />
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/resultview_preview_more_info"
|
||||
style="@style/WhiteButton"
|
||||
android:layout_width="50dp"
|
||||
android:layout_weight="1"
|
||||
android:nextFocusUp="@id/resultview_preview_favorite"
|
||||
|
||||
android:nextFocusLeft="@id/resultview_preview_bookmark"
|
||||
|
||||
tools:visibility="visible"
|
||||
|
||||
app:icon="@drawable/ic_baseline_open_in_new_24"
|
||||
android:nextFocusUp="@id/resultview_preview_favorite"
|
||||
android:text="@string/home_more_info"
|
||||
style="@style/WhiteButton"
|
||||
app:icon="@drawable/ic_baseline_open_in_new_24"
|
||||
|
||||
android:layout_width="50dp" />
|
||||
tools:visibility="visible" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
|
Loading…
Reference in a new issue