mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Merge remote-tracking branch 'origin/master' into bread_toast
This commit is contained in:
commit
7dfd9c454c
38 changed files with 1004 additions and 623 deletions
|
@ -212,6 +212,7 @@ dependencies {
|
|||
implementation("androidx.palette:palette-ktx:1.0.0") // Palette For Images -> Colors
|
||||
implementation("androidx.tvprovider:tvprovider:1.0.0")
|
||||
implementation("com.github.discord:OverlappingPanels:0.1.5") // Gestures
|
||||
implementation ("androidx.biometric:biometric:1.2.0-alpha05") // Fingerprint Authentication
|
||||
implementation("com.github.rubensousa:previewseekbar-media3:1.1.1.0") // SeekBar Preview
|
||||
|
||||
// Extensions & Other Libs
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /> <!-- Used for Android TV watch next -->
|
||||
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION" /> <!-- Used for updates without prompt -->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- Used for update service -->
|
||||
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||
|
||||
<!-- Required for getting arbitrary Aniyomi packages -->
|
||||
|
|
|
@ -308,6 +308,7 @@ object CommonActivity {
|
|||
"Banana" -> R.style.OverlayPrimaryColorBanana
|
||||
"Party" -> R.style.OverlayPrimaryColorParty
|
||||
"Pink" -> R.style.OverlayPrimaryColorPink
|
||||
"Lavender" -> R.style.OverlayPrimaryColorLavender
|
||||
"Monet" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||
R.style.OverlayPrimaryColorMonet else R.style.OverlayPrimaryColorNormal
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.marginStart
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
|
@ -112,6 +113,7 @@ 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
|
||||
|
@ -131,11 +133,15 @@ import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
|
|||
import com.lagradost.cloudstream3.utils.AppUtils.setDefaultFocus
|
||||
import com.lagradost.cloudstream3.utils.BackupUtils.backup
|
||||
import com.lagradost.cloudstream3.utils.BackupUtils.setUpBackup
|
||||
import com.lagradost.cloudstream3.utils.BiometricAuthenticator
|
||||
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.deviceHasPasswordPinLock
|
||||
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.startBiometricAuthentication
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.accounts
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching
|
||||
import com.lagradost.cloudstream3.utils.Event
|
||||
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
|
||||
|
@ -166,7 +172,6 @@ import kotlin.math.absoluteValue
|
|||
import kotlin.reflect.KClass
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
|
||||
//https://github.com/videolan/vlc-android/blob/3706c4be2da6800b3d26344fc04fab03ffa4b860/application/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.kt#L1898
|
||||
//https://wiki.videolan.org/Android_Player_Intents/
|
||||
|
||||
|
@ -285,7 +290,7 @@ var app = Requests(responseParser = object : ResponseParser {
|
|||
defaultHeaders = mapOf("user-agent" to USER_AGENT)
|
||||
}
|
||||
|
||||
class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||
class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAuthenticator.BiometricAuthCallback {
|
||||
companion object {
|
||||
const val TAG = "MAINACT"
|
||||
const val ANIMATED_OUTLINE: Boolean = false
|
||||
|
@ -1184,13 +1189,29 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
}
|
||||
|
||||
if(isTrueTvSettings()) {
|
||||
// Put here any button you don't want focusing it to center the view
|
||||
val exceptionButtons = listOf(
|
||||
R.id.home_preview_play_btt,
|
||||
R.id.home_preview_info_btt,
|
||||
R.id.home_preview_hidden_next_focus,
|
||||
R.id.home_preview_hidden_prev_focus,
|
||||
R.id.result_play_movie_button,
|
||||
R.id.result_play_series_button,
|
||||
R.id.result_resume_series_button,
|
||||
R.id.result_play_trailer_button,
|
||||
R.id.result_bookmark_Button,
|
||||
R.id.result_favorite_Button,
|
||||
R.id.result_subscribe_Button,
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ActivityMainBinding.bind(newLocalBinding.root) // this may crash
|
||||
} else {
|
||||
val newLocalBinding = ActivityMainBinding.inflate(layoutInflater, null, false)
|
||||
|
@ -1204,6 +1225,23 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
|
||||
changeStatusBarState(isEmulatorSettings())
|
||||
|
||||
/** 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
|
||||
|
||||
if (isTruePhone() && authEnabled && noAccounts) {
|
||||
if (deviceHasPasswordPinLock(this)) {
|
||||
startBiometricAuthentication(this, R.string.biometric_authentication_title, false)
|
||||
|
||||
BiometricAuthenticator.promptInfo?.let {
|
||||
BiometricAuthenticator.biometricPrompt?.authenticate(it)
|
||||
}
|
||||
|
||||
// hide background while authenticating, Sorry moms & dads 🙏
|
||||
binding?.navHostFragment?.isInvisible = true
|
||||
}
|
||||
}
|
||||
|
||||
// Automatically enable jsdelivr if cant connect to raw.githubusercontent.com
|
||||
if (this.getKey<Boolean>(getString(R.string.jsdelivr_proxy_key)) == null && isNetworkAvailable()) {
|
||||
main {
|
||||
|
@ -1743,6 +1781,12 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
)
|
||||
}
|
||||
|
||||
/** Biometric stuff **/
|
||||
override fun onAuthenticationSuccess() {
|
||||
// make background (nav host fragment) visible again
|
||||
binding?.navHostFragment?.isInvisible = false
|
||||
}
|
||||
|
||||
private var backPressedCallback: OnBackPressedCallback? = null
|
||||
|
||||
private fun attachBackPressedCallback() {
|
||||
|
|
|
@ -49,11 +49,15 @@ inline fun debugWarning(assert: () -> Boolean, message: () -> String) {
|
|||
}
|
||||
}
|
||||
|
||||
/** NOTE: Only one observer at a time per value */
|
||||
fun <T> LifecycleOwner.observe(liveData: LiveData<T>, action: (t: T) -> Unit) {
|
||||
liveData.removeObservers(this)
|
||||
liveData.observe(this) { it?.let { t -> action(t) } }
|
||||
}
|
||||
|
||||
/** NOTE: Only one observer at a time per value */
|
||||
fun <T> LifecycleOwner.observeNullable(liveData: LiveData<T>, action: (t: T) -> Unit) {
|
||||
liveData.removeObservers(this)
|
||||
liveData.observe(this) { action(it) }
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.ui.account
|
|||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.preference.PreferenceManager
|
||||
|
@ -17,13 +18,17 @@ 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.utils.BiometricAuthenticator
|
||||
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.deviceHasPasswordPinLock
|
||||
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.startBiometricAuthentication
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.accounts
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.selectedKeyIndex
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.setAccount
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
||||
|
||||
class AccountSelectActivity : AppCompatActivity() {
|
||||
class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.BiometricAuthCallback {
|
||||
|
||||
lateinit var viewModel: AccountViewModel
|
||||
|
||||
|
@ -41,13 +46,36 @@ class AccountSelectActivity : AppCompatActivity() {
|
|||
)
|
||||
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
val skipStartup = settingsManager.getBoolean(
|
||||
getString(R.string.skip_startup_account_select_key),
|
||||
false
|
||||
val authEnabled = settingsManager.getBoolean(getString(R.string.biometric_key), false)
|
||||
val skipStartup = settingsManager.getBoolean(getString(R.string.skip_startup_account_select_key), false
|
||||
) || accounts.count() <= 1
|
||||
|
||||
viewModel = ViewModelProvider(this)[AccountViewModel::class.java]
|
||||
|
||||
fun askBiometricAuth() {
|
||||
|
||||
if (isTruePhone() && authEnabled) {
|
||||
if (deviceHasPasswordPinLock(this)) {
|
||||
startBiometricAuthentication(
|
||||
this,
|
||||
R.string.biometric_authentication_title,
|
||||
false
|
||||
)
|
||||
|
||||
BiometricAuthenticator.promptInfo?.let {
|
||||
BiometricAuthenticator.biometricPrompt?.authenticate(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
observe(viewModel.isAllowedLogin) { isAllowedLogin ->
|
||||
if (isAllowedLogin) {
|
||||
// We are allowed to continue to MainActivity
|
||||
navigateToMainActivity()
|
||||
}
|
||||
}
|
||||
|
||||
// Don't show account selection if there is only
|
||||
// one account that exists
|
||||
if (!isEditingFromMainActivity && skipStartup) {
|
||||
|
@ -55,12 +83,6 @@ class AccountSelectActivity : AppCompatActivity() {
|
|||
if (currentAccount?.lockPin != null) {
|
||||
CommonActivity.init(this)
|
||||
viewModel.handleAccountSelect(currentAccount, this, true)
|
||||
observe(viewModel.isAllowedLogin) { isAllowedLogin ->
|
||||
if (isAllowedLogin) {
|
||||
// We are allowed to continue to MainActivity
|
||||
navigateToMainActivity()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (accounts.count() > 1) {
|
||||
showToast(this, getString(
|
||||
|
@ -88,12 +110,6 @@ class AccountSelectActivity : AppCompatActivity() {
|
|||
// Handle the selected account
|
||||
accountSelectCallback = {
|
||||
viewModel.handleAccountSelect(it, this)
|
||||
observe(viewModel.isAllowedLogin) { isAllowedLogin ->
|
||||
if (isAllowedLogin) {
|
||||
// We are allowed to continue to MainActivity
|
||||
navigateToMainActivity()
|
||||
}
|
||||
}
|
||||
},
|
||||
accountCreateCallback = { viewModel.handleAccountUpdate(it, this) },
|
||||
accountEditCallback = {
|
||||
|
@ -158,6 +174,8 @@ class AccountSelectActivity : AppCompatActivity() {
|
|||
} else 6
|
||||
}
|
||||
}
|
||||
|
||||
askBiometricAuth()
|
||||
}
|
||||
|
||||
private fun navigateToMainActivity() {
|
||||
|
@ -165,4 +183,8 @@ class AccountSelectActivity : AppCompatActivity() {
|
|||
startActivity(mainIntent)
|
||||
finish() // Finish the account selection activity
|
||||
}
|
||||
|
||||
override fun onAuthenticationSuccess() {
|
||||
Log.i(BiometricAuthenticator.TAG,"Authentication successful in AccountSelectActivity")
|
||||
}
|
||||
}
|
|
@ -529,6 +529,7 @@ class HomeFragment : Fragment() {
|
|||
super.onScrolled(recyclerView, dx, dy)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -131,6 +131,18 @@ class LibraryFragment : Fragment() {
|
|||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
private fun updateRandom() {
|
||||
val position = libraryViewModel.currentPage.value ?: 0
|
||||
val pages = (libraryViewModel.pages.value as? Resource.Success)?.value ?: return
|
||||
if (toggleRandomButton) {
|
||||
listLibraryItems.clear()
|
||||
listLibraryItems.addAll(pages[position].items)
|
||||
binding?.libraryRandom?.isVisible = listLibraryItems.isNotEmpty()
|
||||
} else {
|
||||
binding?.libraryRandom?.isGone = true
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ResourceType", "CutPasteId")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -395,15 +407,7 @@ class LibraryFragment : Fragment() {
|
|||
binding?.viewpager?.setCurrentItem(page, false)
|
||||
}
|
||||
|
||||
observe(libraryViewModel.currentPage){
|
||||
if (toggleRandomButton) {
|
||||
listLibraryItems.clear()
|
||||
listLibraryItems.addAll(pages[it].items)
|
||||
libraryRandom.isVisible = listLibraryItems.isNotEmpty()
|
||||
} else {
|
||||
libraryRandom.isGone = true
|
||||
}
|
||||
}
|
||||
updateRandom()
|
||||
|
||||
// Only stop loading after 300ms to hide the fade effect the viewpager produces when updating
|
||||
// Without this there would be a flashing effect:
|
||||
|
@ -481,6 +485,7 @@ class LibraryFragment : Fragment() {
|
|||
}
|
||||
|
||||
observe(libraryViewModel.currentPage) { position ->
|
||||
updateRandom()
|
||||
val all = binding?.viewpager?.allViews?.toList()
|
||||
?.filterIsInstance<AutofitRecyclerView>()
|
||||
|
||||
|
|
|
@ -33,13 +33,13 @@ import com.lagradost.cloudstream3.ui.WatchType
|
|||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup
|
||||
import com.lagradost.cloudstream3.ui.player.ExtractorLinkGenerator
|
||||
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
||||
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
||||
import com.lagradost.cloudstream3.ui.result.ResultFragment.getStoredData
|
||||
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.utils.AppUtils.getNameFull
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.html
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.isRtl
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
|
||||
|
@ -129,9 +129,9 @@ class ResultFragmentTv : Fragment() {
|
|||
* Note that this will steal any focus if the episode loading is too slow (unlikely).
|
||||
*/
|
||||
private fun focusPlayButton() {
|
||||
binding?.resultPlayMovie?.requestFocus()
|
||||
binding?.resultPlaySeries?.requestFocus()
|
||||
binding?.resultResumeSeries?.requestFocus()
|
||||
binding?.resultPlayMovieButton?.requestFocus()
|
||||
binding?.resultPlaySeriesButton?.requestFocus()
|
||||
binding?.resultResumeSeriesButton?.requestFocus()
|
||||
}
|
||||
|
||||
private fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||
|
@ -246,37 +246,15 @@ class ResultFragmentTv : Fragment() {
|
|||
storedData.start
|
||||
)
|
||||
// ===== ===== =====
|
||||
var comingSoon = false
|
||||
|
||||
binding?.apply {
|
||||
//episodesShadow.rotationX = 180.0f//if(episodesShadow.isRtl()) 180.0f else 0.0f
|
||||
|
||||
val leftListener: View.OnFocusChangeListener =
|
||||
View.OnFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) return@OnFocusChangeListener
|
||||
toggleEpisodes(false)
|
||||
}
|
||||
|
||||
val rightListener: View.OnFocusChangeListener =
|
||||
View.OnFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) return@OnFocusChangeListener
|
||||
toggleEpisodes(true)
|
||||
}
|
||||
|
||||
resultPlayMovie.onFocusChangeListener = leftListener
|
||||
resultPlaySeries.onFocusChangeListener = leftListener
|
||||
resultResumeSeries.onFocusChangeListener = leftListener
|
||||
resultPlayTrailer.onFocusChangeListener = leftListener
|
||||
resultEpisodesShow.onFocusChangeListener = rightListener
|
||||
resultDescription.onFocusChangeListener = leftListener
|
||||
resultBookmarkButton.onFocusChangeListener = leftListener
|
||||
resultFavoriteButton.onFocusChangeListener = leftListener
|
||||
resultEpisodesShow.setOnClickListener {
|
||||
// toggle, to make it more touch accessable just in case someone thinks that a
|
||||
// tv layout is better but is using a touch device
|
||||
toggleEpisodes(!episodeHolderTv.isVisible)
|
||||
}
|
||||
|
||||
// resultEpisodes.onFocusChangeListener = leftListener
|
||||
// parallax on background
|
||||
resultFinishLoading.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { view, _, scrollY, _, oldScrollY ->
|
||||
backgroundPosterHolder.translationY = -scrollY.toFloat() * 0.8f
|
||||
})
|
||||
|
||||
redirectToPlay.setOnFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) return@setOnFocusChangeListener
|
||||
|
@ -284,13 +262,14 @@ class ResultFragmentTv : Fragment() {
|
|||
|
||||
binding?.apply {
|
||||
val views = listOf(
|
||||
resultPlayMovie,
|
||||
resultPlaySeries,
|
||||
resultResumeSeries,
|
||||
resultPlayTrailer,
|
||||
resultPlayMovieButton,
|
||||
resultPlaySeriesButton,
|
||||
resultResumeSeriesButton,
|
||||
resultPlayTrailerButton,
|
||||
resultBookmarkButton,
|
||||
resultFavoriteButton,
|
||||
resultSubscribeButton
|
||||
resultSubscribeButton,
|
||||
resultSearchButton
|
||||
)
|
||||
for (requestView in views) {
|
||||
if (!requestView.isVisible) continue
|
||||
|
@ -299,11 +278,6 @@ class ResultFragmentTv : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
// parallax on background
|
||||
resultFinishLoading.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||
backgroundPosterHolder.translationY = -scrollY.toFloat() * 0.8f
|
||||
})
|
||||
|
||||
redirectToEpisodes.setOnFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) return@setOnFocusChangeListener
|
||||
toggleEpisodes(true)
|
||||
|
@ -313,7 +287,7 @@ class ResultFragmentTv : Fragment() {
|
|||
resultSeasonSelection,
|
||||
resultRangeSelection,
|
||||
resultEpisodes,
|
||||
resultPlayTrailer,
|
||||
resultPlayTrailerButton,
|
||||
)
|
||||
for (requestView in views) {
|
||||
if (!requestView.isShown) continue
|
||||
|
@ -322,6 +296,45 @@ class ResultFragmentTv : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
mapOf(
|
||||
resultPlayMovieButton to resultPlayMovieText,
|
||||
resultPlaySeriesButton to resultPlaySeriesText,
|
||||
resultResumeSeriesButton to resultResumeSeriesText,
|
||||
resultPlayTrailerButton to resultPlayTrailerText,
|
||||
resultBookmarkButton to resultBookmarkText,
|
||||
resultFavoriteButton to resultFavoriteText,
|
||||
resultSubscribeButton to resultSubscribeText,
|
||||
resultSearchButton to resultSearchText,
|
||||
resultEpisodesShowButton to resultEpisodesShowText
|
||||
).forEach { (button , text) ->
|
||||
|
||||
button.setOnFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) {
|
||||
text.isSelected = false
|
||||
return@setOnFocusChangeListener
|
||||
}
|
||||
|
||||
text.isSelected = true
|
||||
if (button.tag == context?.getString(R.string.tv_no_focus_tag)){
|
||||
resultFinishLoading.scrollTo(0,0)
|
||||
}
|
||||
when (button.id) {
|
||||
R.id.result_episodes_show_button -> {
|
||||
toggleEpisodes(true)
|
||||
}
|
||||
else -> {
|
||||
toggleEpisodes(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resultEpisodesShowButton.setOnClickListener {
|
||||
// toggle, to make it more touch accessible just in case someone thinks that a
|
||||
// tv layout is better but is using a touch device
|
||||
toggleEpisodes(!episodeHolderTv.isVisible)
|
||||
}
|
||||
|
||||
resultEpisodes.setLinearListLayout(
|
||||
isHorizontal = false,
|
||||
nextUp = FOCUS_SELF,
|
||||
|
@ -430,9 +443,9 @@ class ResultFragmentTv : Fragment() {
|
|||
|
||||
val aboveCast = listOf(
|
||||
binding?.resultEpisodesShow,
|
||||
binding?.resultBookmarkButton,
|
||||
binding?.resultFavoriteButton,
|
||||
binding?.resultSubscribeButton,
|
||||
binding?.resultBookmark,
|
||||
binding?.resultFavorite,
|
||||
binding?.resultSubscribe,
|
||||
).firstOrNull {
|
||||
it?.isVisible == true
|
||||
}
|
||||
|
@ -443,8 +456,15 @@ class ResultFragmentTv : Fragment() {
|
|||
|
||||
observeNullable(viewModel.resumeWatching) { resume ->
|
||||
binding?.apply {
|
||||
|
||||
// > resultResumeSeries is visible when not null
|
||||
if (resume == null) {
|
||||
resultResumeSeries.isVisible = false
|
||||
return@observeNullable
|
||||
}
|
||||
|
||||
// show progress no matter if series or movie
|
||||
resume?.progress?.let { progress ->
|
||||
resume.progress?.let { progress ->
|
||||
resultResumeSeriesProgressText.setText(progress.progressLeft)
|
||||
resultResumeSeriesProgress.apply {
|
||||
isVisible = true
|
||||
|
@ -456,37 +476,24 @@ class ResultFragmentTv : Fragment() {
|
|||
resultResumeProgressHolder.isVisible = false
|
||||
}
|
||||
|
||||
// if movie then hide both as movie button is
|
||||
// always visible on movies, this is done in movie observe
|
||||
|
||||
if (resume?.isMovie == true) {
|
||||
resultPlaySeries.isVisible = false
|
||||
resultResumeSeries.isVisible = false
|
||||
return@observeNullable
|
||||
}
|
||||
|
||||
// if series then
|
||||
// > resultPlaySeries is visible when null
|
||||
// > resultResumeSeries is visible when not null
|
||||
if (resume == null) {
|
||||
resultPlaySeries.isVisible = true
|
||||
resultResumeSeries.isVisible = false
|
||||
return@observeNullable
|
||||
}
|
||||
|
||||
resultPlayMovie.isVisible = false
|
||||
resultPlaySeries.isVisible = false
|
||||
resultResumeSeries.isVisible = true
|
||||
|
||||
focusPlayButton()
|
||||
// Stops last button right focus if it is a movie
|
||||
if (resume.isMovie)
|
||||
resultSearchButton.nextFocusRightId = R.id.result_search_Button
|
||||
|
||||
resultResumeSeries.text =
|
||||
if (resume.isMovie) context?.getString(R.string.play_movie_button) else context?.getNameFull(
|
||||
null, // resume.result.name, we don't want episode title
|
||||
resume.result.episode,
|
||||
resume.result.season
|
||||
)
|
||||
resultResumeSeriesText.text =
|
||||
when {
|
||||
resume.isMovie -> context?.getString(R.string.resume)
|
||||
resume.result.season != null ->
|
||||
"${getString(R.string.season_short)}${resume.result.season}:${getString(R.string.episode_short)}${resume.result.episode}"
|
||||
else -> "${getString(R.string.episode)}${resume.result.episode}"
|
||||
}
|
||||
|
||||
resultResumeSeries.setOnClickListener {
|
||||
resultResumeSeriesButton.setOnClickListener {
|
||||
viewModel.handleAction(
|
||||
EpisodeClickEvent(
|
||||
storedData.playerAction, //?: ACTION_PLAY_EPISODE_IN_PLAYER,
|
||||
|
@ -495,7 +502,7 @@ class ResultFragmentTv : Fragment() {
|
|||
)
|
||||
}
|
||||
|
||||
resultResumeSeries.setOnLongClickListener {
|
||||
resultResumeSeriesButton.setOnLongClickListener {
|
||||
viewModel.handleAction(
|
||||
EpisodeClickEvent(ACTION_SHOW_OPTIONS, resume.result)
|
||||
)
|
||||
|
@ -509,9 +516,9 @@ class ResultFragmentTv : Fragment() {
|
|||
context?.updateHasTrailers()
|
||||
if (!LoadResponse.isTrailersEnabled) return@observe
|
||||
val trailers = trailersLinks.flatMap { it.mirros }
|
||||
binding?.resultPlayTrailer?.apply {
|
||||
isGone = trailers.isEmpty()
|
||||
setOnClickListener {
|
||||
binding?.apply {
|
||||
resultPlayTrailer.isGone = trailers.isEmpty()
|
||||
resultPlayTrailerButton.setOnClickListener {
|
||||
if (trailers.isEmpty()) return@setOnClickListener
|
||||
activity.navigate(
|
||||
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
|
||||
|
@ -526,24 +533,38 @@ class ResultFragmentTv : Fragment() {
|
|||
}
|
||||
|
||||
observe(viewModel.watchStatus) { watchType ->
|
||||
binding?.resultBookmarkButton?.apply {
|
||||
setText(watchType.stringRes)
|
||||
binding?.apply {
|
||||
resultBookmarkText.setText(watchType.stringRes)
|
||||
|
||||
resultBookmarkButton.apply {
|
||||
|
||||
val drawable = if (watchType.stringRes == R.string.type_none) {
|
||||
R.drawable.outline_bookmark_add_24
|
||||
} else {
|
||||
R.drawable.ic_baseline_bookmark_24
|
||||
}
|
||||
setIconResource(drawable)
|
||||
|
||||
setOnClickListener { view ->
|
||||
activity?.showBottomDialog(
|
||||
WatchType.values().map { view.context.getString(it.stringRes) }.toList(),
|
||||
WatchType.entries.map { view.context.getString(it.stringRes) }.toList(),
|
||||
watchType.ordinal,
|
||||
view.context.getString(R.string.action_add_to_bookmarks),
|
||||
showApply = false,
|
||||
{}) {
|
||||
viewModel.updateWatchStatus(WatchType.values()[it], context)
|
||||
viewModel.updateWatchStatus(WatchType.entries[it], context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
observeNullable(viewModel.favoriteStatus) { isFavorite ->
|
||||
|
||||
binding?.resultFavorite?.isVisible = isFavorite != null
|
||||
|
||||
binding?.resultFavoriteButton?.apply {
|
||||
isVisible = isFavorite != null
|
||||
|
||||
if (isFavorite == null) return@observeNullable
|
||||
|
||||
val drawable = if (isFavorite) {
|
||||
|
@ -552,14 +573,8 @@ class ResultFragmentTv : Fragment() {
|
|||
R.drawable.ic_baseline_favorite_border_24
|
||||
}
|
||||
|
||||
val text = if (isFavorite) {
|
||||
R.string.action_remove_from_favorites
|
||||
} else {
|
||||
R.string.action_add_to_favorites
|
||||
}
|
||||
|
||||
setIconResource(drawable)
|
||||
setText(text)
|
||||
|
||||
setOnClickListener {
|
||||
viewModel.toggleFavoriteStatus(context) { newStatus: Boolean? ->
|
||||
if (newStatus == null) return@toggleFavoriteStatus
|
||||
|
@ -576,11 +591,21 @@ class ResultFragmentTv : Fragment() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding?.resultFavoriteText?.apply {
|
||||
val text = if (isFavorite == true) {
|
||||
R.string.unfavorite
|
||||
} else {
|
||||
R.string.favorite
|
||||
}
|
||||
setText(text)
|
||||
}
|
||||
}
|
||||
|
||||
observeNullable(viewModel.subscribeStatus) { isSubscribed ->
|
||||
binding?.resultSubscribe?.isVisible = isSubscribed != null && requireContext().isEmulatorSettings()
|
||||
binding?.resultSubscribeButton?.apply {
|
||||
isVisible = isSubscribed != null && context.isEmulatorSettings()
|
||||
|
||||
if (isSubscribed == null) return@observeNullable
|
||||
|
||||
val drawable = if (isSubscribed) {
|
||||
|
@ -589,14 +614,8 @@ class ResultFragmentTv : Fragment() {
|
|||
R.drawable.baseline_notifications_none_24
|
||||
}
|
||||
|
||||
val text = if (isSubscribed) {
|
||||
R.string.action_unsubscribe
|
||||
} else {
|
||||
R.string.action_subscribe
|
||||
}
|
||||
|
||||
setIconResource(drawable)
|
||||
setText(text)
|
||||
|
||||
setOnClickListener {
|
||||
viewModel.toggleSubscriptionStatus(context) { newStatus: Boolean? ->
|
||||
if (newStatus == null) return@toggleSubscriptionStatus
|
||||
|
@ -614,32 +633,47 @@ class ResultFragmentTv : Fragment() {
|
|||
CommonActivity.showToast(txt(message, name), Toast.LENGTH_SHORT)
|
||||
}
|
||||
}
|
||||
|
||||
binding?.resultSubscribeText?.apply {
|
||||
val text = if (isSubscribed) {
|
||||
R.string.action_unsubscribe
|
||||
} else {
|
||||
R.string.action_subscribe
|
||||
}
|
||||
setText(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
observeNullable(viewModel.movie) { data ->
|
||||
if (data == null) return@observeNullable
|
||||
|
||||
binding?.apply {
|
||||
resultPlayMovie.isVisible = data is Resource.Success
|
||||
resultPlaySeries.isVisible = data == null
|
||||
seriesHolder.isVisible = data == null
|
||||
resultEpisodesShow.isVisible = data == null
|
||||
resultPlayMovie.isVisible = (data is Resource.Success) && !comingSoon
|
||||
resultPlaySeries.isVisible = false
|
||||
resultEpisodesShow.isVisible = false
|
||||
|
||||
(data as? Resource.Success)?.value?.let { (text, ep) ->
|
||||
resultPlayMovie.setText(text)
|
||||
resultPlayMovie.setOnClickListener {
|
||||
//resultPlayMovieText.setText(text)
|
||||
resultPlayMovieButton.setOnClickListener {
|
||||
viewModel.handleAction(
|
||||
EpisodeClickEvent(ACTION_CLICK_DEFAULT, ep)
|
||||
)
|
||||
}
|
||||
resultPlayMovie.setOnLongClickListener {
|
||||
resultPlayMovieButton.setOnLongClickListener {
|
||||
viewModel.handleAction(
|
||||
EpisodeClickEvent(ACTION_SHOW_OPTIONS, ep)
|
||||
)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
focusPlayButton()
|
||||
//focusPlayButton()
|
||||
resultPlayMovieButton.requestFocus()
|
||||
|
||||
// Stops last button right focus
|
||||
resultSearchButton.nextFocusRightId = R.id.result_search_Button
|
||||
}
|
||||
}
|
||||
//focusPlayButton()
|
||||
}
|
||||
|
||||
observeNullable(viewModel.selectPopup) { popup ->
|
||||
|
@ -736,19 +770,26 @@ class ResultFragmentTv : Fragment() {
|
|||
// Used to request focus the first time the episodes are loaded.
|
||||
var hasLoadedEpisodesOnce = false
|
||||
observeNullable(viewModel.episodes) { episodes ->
|
||||
if (episodes == null) return@observeNullable
|
||||
|
||||
binding?.apply {
|
||||
resultEpisodes.isVisible = episodes is Resource.Success
|
||||
|
||||
resultPlayMovie.isVisible = false
|
||||
resultPlaySeries.isVisible = true && !comingSoon
|
||||
resultEpisodes.isVisible = true && !comingSoon
|
||||
resultEpisodesShow.isVisible = true && !comingSoon
|
||||
|
||||
// resultEpisodeLoading.isVisible = episodes is Resource.Loading
|
||||
if (episodes is Resource.Success) {
|
||||
val first = episodes.value.firstOrNull()
|
||||
if (first != null) {
|
||||
resultPlaySeries.text = context?.getNameFull(
|
||||
null, // resume.result.name, we don't want episode title
|
||||
first.episode,
|
||||
first.season
|
||||
)
|
||||
|
||||
resultPlaySeries.setOnClickListener {
|
||||
resultPlaySeriesText.text = //"${getString(R.string.season_short)}${first.season}:${getString(R.string.episode_short)}${first.episode}"
|
||||
when {
|
||||
first.season != null ->
|
||||
"${getString(R.string.season_short)}${first.season}:${getString(R.string.episode_short)}${first.episode}"
|
||||
else -> "${getString(R.string.episode)} ${first.episode}"
|
||||
}
|
||||
resultPlaySeriesButton.setOnClickListener {
|
||||
viewModel.handleAction(
|
||||
EpisodeClickEvent(
|
||||
ACTION_CLICK_DEFAULT,
|
||||
|
@ -756,7 +797,7 @@ class ResultFragmentTv : Fragment() {
|
|||
)
|
||||
)
|
||||
}
|
||||
resultPlaySeries.setOnLongClickListener {
|
||||
resultPlaySeriesButton.setOnLongClickListener {
|
||||
viewModel.handleAction(
|
||||
EpisodeClickEvent(ACTION_SHOW_OPTIONS, first)
|
||||
)
|
||||
|
@ -765,6 +806,7 @@ class ResultFragmentTv : Fragment() {
|
|||
if (!hasLoadedEpisodesOnce) {
|
||||
hasLoadedEpisodesOnce = true
|
||||
focusPlayButton()
|
||||
resultPlaySeries.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -826,6 +868,7 @@ class ResultFragmentTv : Fragment() {
|
|||
resultMetaYear.setText(d.yearText)
|
||||
resultMetaDuration.setText(d.durationText)
|
||||
resultMetaRating.setText(d.ratingText)
|
||||
resultMetaStatus.setText(d.onGoingText)
|
||||
resultMetaContentRating.setText(d.contentRatingText)
|
||||
resultCastText.setText(d.actorsText)
|
||||
resultNextAiring.setText(d.nextAiringEpisode)
|
||||
|
@ -859,8 +902,12 @@ class ResultFragmentTv : Fragment() {
|
|||
radius = 0,
|
||||
errorImageDrawable = error
|
||||
)
|
||||
resultComingSoon.isVisible = d.comingSoon
|
||||
comingSoon = d.comingSoon
|
||||
resultTvComingSoon.isVisible = d.comingSoon
|
||||
resultPlayMovie.isGone = d.comingSoon
|
||||
resultPlaySeries.isGone = d.comingSoon
|
||||
resultDataHolder.isGone = d.comingSoon
|
||||
|
||||
UIHelper.populateChips(resultTag, d.tags)
|
||||
resultCastItems.isGone = d.actors.isNullOrEmpty()
|
||||
(resultCastItems.adapter as? ActorAdaptor)?.updateList(
|
||||
|
@ -871,6 +918,10 @@ class ResultFragmentTv : Fragment() {
|
|||
// If there is no rating to display, we don't want an empty gap
|
||||
resultMetaContentRating.width = 0
|
||||
}
|
||||
|
||||
resultSearchButton.setOnClickListener {
|
||||
QuickSearchFragment.pushSearch(activity, d.title)
|
||||
}
|
||||
}
|
||||
|
||||
is Resource.Loading -> {
|
||||
|
|
|
@ -20,6 +20,7 @@ import com.lagradost.cloudstream3.APIHolder.apis
|
|||
import com.lagradost.cloudstream3.APIHolder.getId
|
||||
import com.lagradost.cloudstream3.APIHolder.unixTime
|
||||
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.context
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||
import com.lagradost.cloudstream3.CommonActivity.activity
|
||||
import com.lagradost.cloudstream3.CommonActivity.getCastSession
|
||||
|
@ -31,6 +32,7 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.isMovie
|
|||
import com.lagradost.cloudstream3.metaproviders.SyncRedirector
|
||||
import com.lagradost.cloudstream3.mvvm.*
|
||||
import com.lagradost.cloudstream3.syncproviders.AccountManager
|
||||
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.secondsToReadable
|
||||
import com.lagradost.cloudstream3.syncproviders.SyncAPI
|
||||
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
|
||||
import com.lagradost.cloudstream3.syncproviders.providers.SimklApi
|
||||
|
@ -261,8 +263,7 @@ fun LoadResponse.toResultData(repo: APIRepository): ResultData {
|
|||
metaText =
|
||||
if (repo.providerType == ProviderType.MetaProvider) txt(R.string.provider_info_meta) else null,
|
||||
durationText = if (dur == null || dur <= 0) null else txt(
|
||||
R.string.duration_format,
|
||||
dur
|
||||
secondsToReadable(dur * 60, "0 mins")
|
||||
),
|
||||
onGoingText = if (this is EpisodeResponse) {
|
||||
txt(
|
||||
|
@ -2464,7 +2465,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
ResumeProgress(
|
||||
progress = (viewPos.position / 1000).toInt(),
|
||||
maxProgress = (viewPos.duration / 1000).toInt(),
|
||||
txt(R.string.resume_time_left, (viewPos.duration - viewPos.position) / (60_000))
|
||||
txt(R.string.resume_remaining, secondsToReadable(((viewPos.duration - viewPos.position) / 1_000).toInt(), "0 mins"))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,10 @@ import androidx.core.view.isGone
|
|||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser
|
||||
import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.AccountManagmentBinding
|
||||
|
@ -32,7 +34,10 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSet
|
|||
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.utils.AppUtils.html
|
||||
import com.lagradost.cloudstream3.utils.BackupUtils
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogText
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
|
@ -256,6 +261,24 @@ class SettingsAccount : PreferenceFragmentCompat() {
|
|||
hideKeyboard()
|
||||
setPreferencesFromResource(R.xml.settings_account, rootKey)
|
||||
|
||||
getPref(R.string.biometric_key)?.setOnPreferenceClickListener {
|
||||
val authEnabled = PreferenceManager.getDefaultSharedPreferences(
|
||||
context ?: return@setOnPreferenceClickListener false
|
||||
)
|
||||
.getBoolean(getString(R.string.biometric_key), false)
|
||||
|
||||
if (authEnabled) {
|
||||
BackupUtils.backup(activity)
|
||||
val title = activity?.getString(R.string.biometric_setting)
|
||||
val warning = activity?.getString(R.string.biometric_warning)
|
||||
activity?.showBottomDialogText(
|
||||
title as String,
|
||||
warning.html()
|
||||
) { onDialogDismissedEvent }
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
val syncApis =
|
||||
listOf(
|
||||
R.string.mal_key to malApi,
|
||||
|
|
|
@ -19,6 +19,7 @@ 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
|
||||
|
@ -155,6 +156,11 @@ class SettingsFragment : Fragment() {
|
|||
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
|
||||
|
|
|
@ -65,12 +65,16 @@ object BackupUtils {
|
|||
PLUGINS_KEY_LOCAL,
|
||||
|
||||
OPEN_SUBTITLES_USER_KEY,
|
||||
"nginx_user", // Nginx user key
|
||||
|
||||
DOWNLOAD_EPISODE_CACHE,
|
||||
|
||||
"biometric_key", // can lock down users if backup is shared on a incompatible device
|
||||
"nginx_user" // Nginx user key
|
||||
)
|
||||
|
||||
/** false if blacklisted key */
|
||||
/** false if key should not be contained in backup */
|
||||
private fun String.isTransferable(): Boolean {
|
||||
return !nonTransferableKeys.contains(this)
|
||||
return !nonTransferableKeys.any { this.contains(it) }
|
||||
}
|
||||
|
||||
private var restoreFileSelector: ActivityResultLauncher<Array<String>>? = null
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
package com.lagradost.cloudstream3.utils
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.KeyguardManager
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.biometric.BiometricManager
|
||||
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG
|
||||
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK
|
||||
import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
|
||||
import androidx.biometric.BiometricPrompt
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.R
|
||||
|
||||
object BiometricAuthenticator {
|
||||
|
||||
private const val MAX_FAILED_ATTEMPTS = 3
|
||||
private var failedAttempts = 0
|
||||
const val TAG = "cs3Auth"
|
||||
|
||||
private var biometricManager: BiometricManager? = null
|
||||
var biometricPrompt: BiometricPrompt? = null
|
||||
var promptInfo: BiometricPrompt.PromptInfo? = null
|
||||
|
||||
var authCallback: BiometricAuthCallback? = null // listen to authentication success
|
||||
|
||||
private fun initializeBiometrics(activity: Activity) {
|
||||
val executor = ContextCompat.getMainExecutor(activity)
|
||||
|
||||
biometricManager = BiometricManager.from(activity)
|
||||
|
||||
biometricPrompt = BiometricPrompt(
|
||||
activity as FragmentActivity,
|
||||
executor,
|
||||
object : BiometricPrompt.AuthenticationCallback() {
|
||||
|
||||
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||
super.onAuthenticationError(errorCode, errString)
|
||||
showToast("$errString")
|
||||
Log.e(TAG, "$errorCode")
|
||||
failedAttempts++
|
||||
|
||||
if (failedAttempts >= MAX_FAILED_ATTEMPTS) {
|
||||
failedAttempts = 0
|
||||
activity.finish()
|
||||
} else {
|
||||
failedAttempts = 0
|
||||
activity.finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
||||
super.onAuthenticationSucceeded(result)
|
||||
failedAttempts = 0
|
||||
authCallback?.onAuthenticationSuccess()
|
||||
}
|
||||
|
||||
override fun onAuthenticationFailed() {
|
||||
super.onAuthenticationFailed()
|
||||
failedAttempts++
|
||||
if (failedAttempts >= MAX_FAILED_ATTEMPTS) {
|
||||
failedAttempts = 0
|
||||
activity.finish()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
// authentication dialog prompt builder
|
||||
private fun authenticationDialog(
|
||||
activity: Activity,
|
||||
title: Int,
|
||||
setDeviceCred: Boolean,
|
||||
) {
|
||||
val description = activity.getString(R.string.biometric_prompt_description)
|
||||
|
||||
if (setDeviceCred) {
|
||||
// For API level > 30, Newer API setAllowedAuthenticators is used
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
|
||||
val authFlag = DEVICE_CREDENTIAL or BIOMETRIC_WEAK or BIOMETRIC_STRONG
|
||||
promptInfo = BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(activity.getString(title))
|
||||
.setDescription(description)
|
||||
.setAllowedAuthenticators(authFlag)
|
||||
.build()
|
||||
|
||||
} else {
|
||||
// for apis < 30
|
||||
promptInfo = BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(activity.getString(title))
|
||||
.setDescription(description)
|
||||
.setDeviceCredentialAllowed(true)
|
||||
.build()
|
||||
}
|
||||
|
||||
} else {
|
||||
// fallback for A12+ when both fingerprint & Face unlock is absent but PIN is set
|
||||
promptInfo = BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(activity.getString(title))
|
||||
.setDescription(description)
|
||||
.setDeviceCredentialAllowed(true)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isBiometricHardWareAvailable(): Boolean {
|
||||
// authentication occurs only when this is true and device is truly capable
|
||||
var result = false
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
|
||||
when (biometricManager?.canAuthenticate(
|
||||
DEVICE_CREDENTIAL or BIOMETRIC_STRONG or BIOMETRIC_WEAK
|
||||
)) {
|
||||
BiometricManager.BIOMETRIC_SUCCESS -> result = true
|
||||
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> result = false
|
||||
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> result = false
|
||||
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> result = false
|
||||
BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> result = true
|
||||
BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> result = true
|
||||
BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> result = false
|
||||
}
|
||||
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
when (biometricManager?.canAuthenticate()) {
|
||||
BiometricManager.BIOMETRIC_SUCCESS -> result = true
|
||||
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> result = false
|
||||
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> result = false
|
||||
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> result = false
|
||||
BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> result = true
|
||||
BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> result = true
|
||||
BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> result = false
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// checks if device is secured i.e has at least some type of lock
|
||||
fun deviceHasPasswordPinLock(context: Context?): Boolean {
|
||||
val keyMgr =
|
||||
context?.getSystemService(AppCompatActivity.KEYGUARD_SERVICE) as? KeyguardManager
|
||||
return keyMgr?.isKeyguardSecure ?: false
|
||||
}
|
||||
|
||||
// function to start authentication in any fragment or activity
|
||||
fun startBiometricAuthentication(activity: Activity, title: Int, setDeviceCred: Boolean) {
|
||||
initializeBiometrics(activity)
|
||||
|
||||
if (isBiometricHardWareAvailable()) {
|
||||
authCallback = activity as? BiometricAuthCallback
|
||||
authenticationDialog(activity, title, setDeviceCred)
|
||||
promptInfo?.let { biometricPrompt?.authenticate(it) }
|
||||
|
||||
} else {
|
||||
if (deviceHasPasswordPinLock(activity)) {
|
||||
authCallback = activity as? BiometricAuthCallback
|
||||
authenticationDialog(activity, R.string.password_pin_authentication_title, true)
|
||||
promptInfo?.let { biometricPrompt?.authenticate(it) }
|
||||
|
||||
} else {
|
||||
showToast(R.string.biometric_unsupported)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface BiometricAuthCallback {
|
||||
fun onAuthenticationSuccess()
|
||||
}
|
||||
}
|
|
@ -532,7 +532,6 @@ object UIHelper {
|
|||
WindowInsetsControllerCompat(window, View(this)).show(WindowInsetsCompat.Type.systemBars())
|
||||
|
||||
} else {*/ /** WINDOW COMPAT IS BUGGY DUE TO FU*KED UP PLAYER AND TRAILERS **/
|
||||
Suppress("DEPRECATION")
|
||||
window.decorView.systemUiVisibility =
|
||||
(View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
|
||||
//}
|
||||
|
|
10
app/src/main/res/drawable/ic_baseline_film_roll_24.xml
Normal file
10
app/src/main/res/drawable/ic_baseline_film_roll_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M240,760L240,800Q240,817 228.5,828.5Q217,840 200,840Q183,840 171.5,828.5Q160,817 160,800L160,160Q160,143 171.5,131.5Q183,120 200,120Q217,120 228.5,131.5Q240,143 240,160L240,200L320,200L320,160Q320,143 331.5,131.5Q343,120 360,120L600,120Q617,120 628.5,131.5Q640,143 640,160L640,200L720,200L720,160Q720,143 731.5,131.5Q743,120 760,120Q777,120 788.5,131.5Q800,143 800,160L800,800Q800,817 788.5,828.5Q777,840 760,840Q743,840 731.5,828.5Q720,817 720,800L720,760L640,760L640,800Q640,817 628.5,828.5Q617,840 600,840L360,840Q343,840 331.5,828.5Q320,817 320,800L320,760L240,760ZM240,680L320,680L320,600L240,600L240,680ZM240,520L320,520L320,440L240,440L240,520ZM240,360L320,360L320,280L240,280L240,360ZM640,680L720,680L720,600L640,600L640,680ZM640,520L720,520L720,440L640,440L640,520ZM640,360L720,360L720,280L640,280L640,360Z"/>
|
||||
</vector>
|
11
app/src/main/res/drawable/ic_baseline_resume_arrow.xml
Normal file
11
app/src/main/res/drawable/ic_baseline_resume_arrow.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="m8.46,5l0,14l11,-7l-11,-7z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="0.006"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
12
app/src/main/res/drawable/ic_baseline_resume_arrow2.xml
Normal file
12
app/src/main/res/drawable/ic_baseline_resume_arrow2.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="m8.46,5l0,14l11,-7l-11,-7z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M4.92,5.04h2.31v13.98h-2.31z"/>
|
||||
</vector>
|
11
app/src/main/res/drawable/ic_fingerprint.xml
Normal file
11
app/src/main/res/drawable/ic_fingerprint.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/white"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24"
|
||||
android:width="24dp">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M17.81,4.47c-0.08,0 -0.16,-0.02 -0.23,-0.06C15.66,3.42 14,3 12.01,3c-1.98,0 -3.86,0.47 -5.57,1.41 -0.24,0.13 -0.54,0.04 -0.68,-0.2 -0.13,-0.24 -0.04,-0.55 0.2,-0.68C7.82,2.52 9.86,2 12.01,2c2.13,0 3.99,0.47 6.03,1.52 0.25,0.13 0.34,0.43 0.21,0.67 -0.09,0.18 -0.26,0.28 -0.44,0.28zM3.5,9.72c-0.1,0 -0.2,-0.03 -0.29,-0.09 -0.23,-0.16 -0.28,-0.47 -0.12,-0.7 0.99,-1.4 2.25,-2.5 3.75,-3.27C9.98,4.04 14,4.03 17.15,5.65c1.5,0.77 2.76,1.86 3.75,3.25 0.16,0.22 0.11,0.54 -0.12,0.7 -0.23,0.16 -0.54,0.11 -0.7,-0.12 -0.9,-1.26 -2.04,-2.25 -3.39,-2.94 -2.87,-1.47 -6.54,-1.47 -9.4,0.01 -1.36,0.7 -2.5,1.7 -3.4,2.96 -0.08,0.14 -0.23,0.21 -0.39,0.21zM9.75,21.79c-0.13,0 -0.26,-0.05 -0.35,-0.15 -0.87,-0.87 -1.34,-1.43 -2.01,-2.64 -0.69,-1.23 -1.05,-2.73 -1.05,-4.34 0,-2.97 2.54,-5.39 5.66,-5.39s5.66,2.42 5.66,5.39c0,0.28 -0.22,0.5 -0.5,0.5s-0.5,-0.22 -0.5,-0.5c0,-2.42 -2.09,-4.39 -4.66,-4.39s-4.66,1.97 -4.66,4.39c0,1.44 0.32,2.77 0.93,3.85 0.64,1.15 1.08,1.64 1.85,2.42 0.19,0.2 0.19,0.51 0,0.71 -0.11,0.1 -0.24,0.15 -0.37,0.15zM16.92,19.94c-1.19,0 -2.24,-0.3 -3.1,-0.89 -1.49,-1.01 -2.38,-2.65 -2.38,-4.39 0,-0.28 0.22,-0.5 0.5,-0.5s0.5,0.22 0.5,0.5c0,1.41 0.72,2.74 1.94,3.56 0.71,0.48 1.54,0.71 2.54,0.71 0.24,0 0.64,-0.03 1.04,-0.1 0.27,-0.05 0.53,0.13 0.58,0.41 0.05,0.27 -0.13,0.53 -0.41,0.58 -0.57,0.11 -1.07,0.12 -1.21,0.12zM14.91,22c-0.04,0 -0.09,-0.01 -0.13,-0.02 -1.59,-0.44 -2.63,-1.03 -3.72,-2.1 -1.4,-1.39 -2.17,-3.24 -2.17,-5.22 0,-1.62 1.38,-2.94 3.08,-2.94s3.08,1.32 3.08,2.94c0,1.07 0.93,1.94 2.08,1.94s2.08,-0.87 2.08,-1.94c0,-3.77 -3.25,-6.83 -7.25,-6.83 -2.84,0 -5.44,1.58 -6.61,4.03 -0.39,0.81 -0.59,1.76 -0.59,2.8 0,0.78 0.07,2.01 0.67,3.61 0.1,0.26 -0.03,0.55 -0.29,0.64 -0.26,0.1 -0.55,-0.04 -0.64,-0.29 -0.49,-1.31 -0.73,-2.61 -0.73,-3.96 0,-1.2 0.23,-2.29 0.68,-3.24 1.33,-2.79 4.28,-4.6 7.51,-4.6 4.55,0 8.25,3.51 8.25,7.83 0,1.62 -1.38,2.94 -3.08,2.94s-3.08,-1.32 -3.08,-2.94c0,-1.07 -0.93,-1.94 -2.08,-1.94s-2.08,0.87 -2.08,1.94c0,1.71 0.66,3.31 1.87,4.51 0.95,0.94 1.86,1.46 3.27,1.85 0.27,0.07 0.42,0.35 0.35,0.61 -0.05,0.23 -0.26,0.38 -0.47,0.38z"/>
|
||||
</vector>
|
10
app/src/main/res/drawable/library_icon.xml
Normal file
10
app/src/main/res/drawable/library_icon.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/white">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160L400,160L480,240L800,240Q833,240 856.5,263.5Q880,287 880,320L447,320L367,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720L256,400L940,400L837,743Q829,769 807.5,784.5Q786,800 760,800L160,800ZM244,720L760,720L832,480L316,480L244,720ZM244,720L316,480L316,480L244,720L244,720ZM160,320L160,240Q160,240 160,240Q160,240 160,240L160,240L160,320L160,320Z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/outline_bookmark_add_24.xml
Normal file
5
app/src/main/res/drawable/outline_bookmark_add_24.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M17,11v6.97l-5,-2.14l-5,2.14V5h6V3H7C5.9,3 5,3.9 5,5v16l7,-3l7,3V11H17zM21,7h-2v2h-2V7h-2V5h2V3h2v2h2V7z"/>
|
||||
</vector>
|
|
@ -3,13 +3,13 @@
|
|||
<item android:state_focused="true">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="?attr/white" />
|
||||
<corners android:radius="3dp"/>
|
||||
<corners android:radius="@dimen/rounded_image_radius"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/white_attr_20" />
|
||||
<corners android:radius="3dp"/>
|
||||
<corners android:radius="@dimen/rounded_image_radius"/>
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
|
@ -3,7 +3,7 @@
|
|||
<item android:state_focused="true">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="?attr/white" />
|
||||
<corners android:radius="3dp"/>
|
||||
<corners android:radius="@dimen/rounded_image_radius"/>
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
|
@ -17,7 +17,6 @@
|
|||
android:layout_width="100dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:focusable="true"
|
||||
android:padding="5dp">
|
||||
<!--app:cardCornerRadius="@dimen/roundedImageRadius"-->
|
||||
<FrameLayout
|
||||
|
|
|
@ -157,6 +157,7 @@
|
|||
android:id="@+id/home_preview_hidden_prev_focus"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="1dp"
|
||||
android:tag="@string/tv_no_focus_tag"
|
||||
android:focusable="false" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
|
@ -189,6 +190,7 @@
|
|||
android:id="@+id/home_preview_hidden_next_focus"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="1dp"
|
||||
android:tag="@string/tv_no_focus_tag"
|
||||
android:focusable="false" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -412,7 +412,7 @@
|
|||
android:foreground="@drawable/outline_drawable"
|
||||
android:maxLength="1000"
|
||||
android:nextFocusUp="@id/result_back"
|
||||
android:nextFocusDown="@id/result_bookmark_button"
|
||||
android:nextFocusDown="@id/result_bookmark_Button"
|
||||
android:paddingTop="5dp"
|
||||
android:textColor="?attr/textColor"
|
||||
android:textSize="15sp"
|
||||
|
@ -474,7 +474,7 @@
|
|||
android:fadingEdge="horizontal"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
android:nextFocusUp="@id/result_bookmark_button"
|
||||
android:nextFocusUp="@id/result_bookmark_Button"
|
||||
android:nextFocusDown="@id/result_play_movie"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="5dp"
|
||||
|
@ -580,7 +580,7 @@
|
|||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:nextFocusUp="@id/result_bookmark_button"
|
||||
android:nextFocusUp="@id/result_bookmark_Button"
|
||||
android:nextFocusDown="@id/result_download_movie"
|
||||
android:text="@string/play_movie_button"
|
||||
android:visibility="visible"
|
||||
|
@ -658,7 +658,7 @@
|
|||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:nextFocusUp="@id/result_bookmark_button"
|
||||
android:nextFocusUp="@id/result_bookmark_Button"
|
||||
android:nextFocusDown="@id/result_download_movie"
|
||||
android:text="@string/resume"
|
||||
android:visibility="visible"
|
||||
|
@ -674,7 +674,7 @@
|
|||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:nextFocusUp="@id/result_bookmark_button"
|
||||
android:nextFocusUp="@id/result_bookmark_Button"
|
||||
android:nextFocusDown="@id/result_download_movie"
|
||||
android:text="@string/next_episode"
|
||||
android:visibility="gone"
|
||||
|
|
|
@ -78,6 +78,30 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
</LinearLayout>
|
||||
</com.facebook.shimmer.ShimmerFrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/background_poster_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="275dp"
|
||||
android:visibility="visible">
|
||||
|
||||
<com.lagradost.cloudstream3.utils.PercentageCropImageView
|
||||
android:id="@+id/background_poster"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="275dp"
|
||||
android:layout_gravity="center"
|
||||
android:alpha="0.8"
|
||||
android:scaleType="matrix"
|
||||
tools:src="@drawable/profile_bg_dark_blue" >
|
||||
</com.lagradost.cloudstream3.utils.PercentageCropImageView>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="120dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:src="@drawable/background_shadow">
|
||||
</ImageView>
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_loading_error"
|
||||
|
||||
|
@ -124,31 +148,6 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
android:textColor="?attr/textColor" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/background_poster_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="250dp"
|
||||
android:visibility="visible">
|
||||
|
||||
<com.lagradost.cloudstream3.utils.PercentageCropImageView
|
||||
android:id="@+id/background_poster"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="275dp"
|
||||
android:layout_gravity="center"
|
||||
android:alpha="0.8"
|
||||
android:scaleType="matrix"
|
||||
tools:src="@drawable/profile_bg_dark_blue" >
|
||||
</com.lagradost.cloudstream3.utils.PercentageCropImageView>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="120dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:src="@drawable/background_shadow">
|
||||
</ImageView>
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/result_finish_loading"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -165,7 +164,7 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="175dp">
|
||||
android:layout_marginTop="225dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_title"
|
||||
|
@ -175,7 +174,7 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
android:gravity="center_vertical"
|
||||
android:singleLine="true"
|
||||
android:textColor="?attr/textColor"
|
||||
android:textSize="20sp"
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="The Perfect Run The Perfect Run" />
|
||||
|
||||
|
@ -221,157 +220,289 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
android:textStyle="normal"
|
||||
tools:text="5d 3h 30m" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_resume_progress_holder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:id="@+id/result_resume_series_progress"
|
||||
app:trackCornerRadius="50dp"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:indeterminate="false"
|
||||
android:max="100"
|
||||
android:paddingEnd="10dp"
|
||||
android:progress="0"
|
||||
android:progressBackgroundTint="?attr/colorPrimary"
|
||||
tools:progress="50"
|
||||
tools:visibility="visible"
|
||||
tools:ignore="RtlSymmetry" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_resume_series_progress_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:textColor="?attr/grayTextColor"
|
||||
tools:ignore="RtlSymmetry"
|
||||
tools:text="69m remaining" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_play_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:descendantFocusability="afterDescendants"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:id="@+id/result_play_movie"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_play_movie_button"
|
||||
android:focusable="true"
|
||||
style="@style/ResultSmallButtonTV"
|
||||
app:iconPadding="0dp"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24"
|
||||
android:nextFocusUp="@id/result_play_movie_button"
|
||||
android:nextFocusDown="@id/result_description"
|
||||
android:tag="@string/tv_no_focus_tag">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_play_movie_text"
|
||||
style="@style/ResultMarqueeButtonText"
|
||||
android:text="@string/movies_singular" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:id="@+id/result_play_series"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_play_series_button"
|
||||
android:focusable="true"
|
||||
style="@style/ResultSmallButtonTV"
|
||||
app:iconPadding="0dp"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24"
|
||||
android:nextFocusUp="@id/result_play_series_button"
|
||||
android:nextFocusDown="@id/result_description"
|
||||
android:tag="@string/tv_no_focus_tag">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_play_series_text"
|
||||
style="@style/ResultMarqueeButtonText"
|
||||
android:text="@string/episode" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_resume_series"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_resume_series_button"
|
||||
android:focusable="true"
|
||||
style="@style/ResultSmallButtonTV"
|
||||
app:iconPadding="0dp"
|
||||
app:icon="@drawable/ic_baseline_resume_arrow2"
|
||||
android:nextFocusUp="@id/result_resume_series_button"
|
||||
android:nextFocusDown="@id/result_description"
|
||||
android:tag="@string/tv_no_focus_tag">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_resume_series_text"
|
||||
style="@style/ResultMarqueeButtonText"
|
||||
android:text="@string/resume" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_play_trailer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_play_trailer_button"
|
||||
android:focusable="true"
|
||||
style="@style/ResultSmallButtonTV"
|
||||
app:iconPadding="0dp"
|
||||
app:icon="@drawable/ic_baseline_film_roll_24"
|
||||
android:nextFocusUp="@id/result_play_trailer_button"
|
||||
android:nextFocusDown="@id/result_description"
|
||||
android:tag="@string/tv_no_focus_tag">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_play_trailer_text"
|
||||
style="@style/ResultMarqueeButtonText"
|
||||
android:text="@string/play_trailer_button" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_bookmark"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_bookmark_Button"
|
||||
android:focusable="true"
|
||||
style="@style/ResultSmallButtonTV"
|
||||
app:iconPadding="0dp"
|
||||
app:icon="@drawable/outline_bookmark_add_24"
|
||||
android:nextFocusUp="@id/result_bookmark_Button"
|
||||
android:nextFocusDown="@id/result_description"
|
||||
android:tag="@string/tv_no_focus_tag">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_bookmark_text"
|
||||
style="@style/ResultMarqueeButtonText"
|
||||
android:text="@string/type_none" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_favorite"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_favorite_Button"
|
||||
android:focusable="true"
|
||||
style="@style/ResultSmallButtonTV"
|
||||
app:iconPadding="0dp"
|
||||
app:icon="@drawable/ic_baseline_favorite_border_24"
|
||||
android:nextFocusUp="@id/result_favorite_Button"
|
||||
android:nextFocusDown="@id/result_description"
|
||||
android:tag="@string/tv_no_focus_tag">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_favorite_Text"
|
||||
style="@style/ResultMarqueeButtonText"
|
||||
android:text="@string/favorite" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:id="@+id/result_subscribe"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_subscribe_Button"
|
||||
android:focusable="true"
|
||||
style="@style/ResultSmallButtonTV"
|
||||
app:iconPadding="0dp"
|
||||
app:icon="@drawable/baseline_notifications_none_24"
|
||||
android:nextFocusUp="@id/result_subscribe_Button"
|
||||
android:nextFocusDown="@id/result_description"
|
||||
android:tag="@string/tv_no_focus_tag">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_subscribe_text"
|
||||
style="@style/ResultMarqueeButtonText"
|
||||
android:text="@string/action_subscribe" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:id="@+id/result_search"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_search_Button"
|
||||
android:focusable="true"
|
||||
style="@style/ResultSmallButtonTV"
|
||||
app:iconPadding="0dp"
|
||||
app:icon="@drawable/search_icon"
|
||||
android:nextFocusUp="@id/result_search_Button"
|
||||
android:nextFocusDown="@id/result_description"
|
||||
android:tag="@string/tv_no_focus_tag">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_search_text"
|
||||
style="@style/ResultMarqueeButtonText"
|
||||
android:text="@string/title_search" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:id="@+id/result_episodes_show"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_episodes_show_button"
|
||||
android:focusable="true"
|
||||
style="@style/ResultSmallButtonTV"
|
||||
app:iconPadding="0dp"
|
||||
app:icon="@drawable/ic_baseline_sort_24"
|
||||
android:nextFocusUp="@id/result_episodes_show_button"
|
||||
android:nextFocusRight="@id/redirect_to_episodes"
|
||||
android:nextFocusDown="@id/result_description"
|
||||
android:tag="@string/tv_no_focus_tag">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_episodes_show_text"
|
||||
style="@style/ResultMarqueeButtonText"
|
||||
android:text="@string/episodes" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="10dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_weight="0"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_movie_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical"
|
||||
tools:visibility="visible">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_play_movie"
|
||||
style="@style/ResultButtonTV"
|
||||
|
||||
android:nextFocusRight="@id/result_description"
|
||||
android:nextFocusUp="@id/result_play_movie"
|
||||
android:nextFocusDown="@id/result_play_series"
|
||||
android:text="@string/play_movie_button"
|
||||
android:visibility="visible"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/series_holder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_play_series"
|
||||
style="@style/ResultButtonTV"
|
||||
|
||||
android:nextFocusRight="@id/result_description"
|
||||
android:nextFocusUp="@id/result_play_movie"
|
||||
android:nextFocusDown="@id/result_resume_series"
|
||||
android:text="@string/play_episode"
|
||||
android:visibility="visible"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_resume_series"
|
||||
style="@style/ResultButtonTV"
|
||||
|
||||
android:nextFocusRight="@id/result_description"
|
||||
android:nextFocusUp="@id/result_play_series"
|
||||
android:nextFocusDown="@id/result_play_trailer"
|
||||
android:text="@string/resume"
|
||||
android:visibility="visible"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_play_trailer"
|
||||
style="@style/ResultButtonTV"
|
||||
|
||||
android:nextFocusRight="@id/result_description"
|
||||
android:nextFocusUp="@id/result_resume_series"
|
||||
android:nextFocusDown="@id/result_bookmark_button"
|
||||
android:text="@string/play_trailer_button"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
||||
<!-- <com.lagradost.cloudstream3.ui.download.button.DownloadButton
|
||||
android:visibility="gone"
|
||||
android:id="@+id/download_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minWidth="250dp"
|
||||
app:download_layout="@layout/download_button_layout" />
|
||||
-->
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_bookmark_button"
|
||||
style="@style/ResultButtonTV"
|
||||
android:nextFocusRight="@id/result_description"
|
||||
android:nextFocusUp="@id/result_play_trailer"
|
||||
android:nextFocusDown="@id/result_favorite_button"
|
||||
|
||||
android:text="@string/type_none"
|
||||
android:visibility="visible"
|
||||
app:icon="@drawable/ic_baseline_bookmark_24" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_favorite_button"
|
||||
style="@style/ResultButtonTV"
|
||||
android:nextFocusRight="@id/result_description"
|
||||
android:nextFocusUp="@id/result_bookmark_button"
|
||||
android:nextFocusDown="@id/result_subscribe_button"
|
||||
|
||||
android:text="@string/action_add_to_favorites"
|
||||
android:visibility="visible"
|
||||
app:icon="@drawable/ic_baseline_favorite_border_24" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_subscribe_button"
|
||||
style="@style/ResultButtonTV"
|
||||
android:nextFocusRight="@id/result_description"
|
||||
android:nextFocusUp="@id/result_favorite_button"
|
||||
android:nextFocusDown="@id/result_episodes_show"
|
||||
|
||||
android:text="@string/action_subscribe"
|
||||
android:visibility="visible"
|
||||
app:icon="@drawable/ic_baseline_favorite_border_24" />
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_episodes_show"
|
||||
style="@style/ResultButtonTV"
|
||||
|
||||
android:nextFocusRight="@id/redirect_to_episodes"
|
||||
android:nextFocusUp="@id/result_subscribe_button"
|
||||
android:nextFocusDown="@id/result_cast_items"
|
||||
|
||||
android:text="@string/episodes"
|
||||
android:visibility="visible"
|
||||
app:icon="@drawable/ic_baseline_sort_24"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<View
|
||||
android:id="@+id/redirect_to_episodes"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="1dp"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true" />
|
||||
|
||||
|
||||
<View
|
||||
android:id="@+id/redirect_to_play"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="1dp"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
android:layout_marginTop="10dp"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/right_layout"
|
||||
|
@ -382,7 +513,8 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/linearLayout2"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="UselessParent">
|
||||
|
||||
<com.lagradost.cloudstream3.widget.FlowLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -439,8 +571,8 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
android:foreground="@drawable/outline_drawable"
|
||||
android:maxLines="7"
|
||||
android:focusable="true"
|
||||
android:nextFocusUp="@id/result_back"
|
||||
android:nextFocusDown="@id/result_bookmark_button"
|
||||
android:nextFocusUp="@id/result_play_parent"
|
||||
android:nextFocusDown="@id/result_cast_items"
|
||||
android:padding="5dp"
|
||||
android:requiresFadingEdge="vertical"
|
||||
android:textColor="?attr/textColor"
|
||||
|
@ -450,59 +582,8 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/result_tag"
|
||||
style="@style/ChipParent"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_resume_progress_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:id="@+id/result_resume_series_progress"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:indeterminate="false"
|
||||
android:max="100"
|
||||
|
||||
android:paddingEnd="10dp"
|
||||
android:progress="0"
|
||||
android:progressBackgroundTint="?attr/colorPrimary"
|
||||
android:visibility="gone"
|
||||
tools:progress="50"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_resume_series_progress_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="0"
|
||||
android:gravity="center"
|
||||
android:maxLines="1"
|
||||
android:paddingEnd="5dp"
|
||||
android:textColor="?attr/grayTextColor"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlSymmetry"
|
||||
tools:text="69m remaining" />
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -513,10 +594,8 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
android:descendantFocusability="afterDescendants"
|
||||
|
||||
android:fadingEdge="horizontal"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
android:nextFocusUp="@id/result_episodes_show"
|
||||
android:nextFocusDown="@id/result_recommendations_filter_selection"
|
||||
android:nextFocusUp="@id/result_description"
|
||||
android:nextFocusDown="@id/result_recommendations_list"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="5dp"
|
||||
android:requiresFadingEdge="horizontal"
|
||||
|
@ -525,8 +604,23 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
tools:listitem="@layout/cast_item"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_tv_coming_soon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:paddingTop="50dp"
|
||||
android:text="@string/coming_soon"
|
||||
android:textColor="?attr/textColor"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
tools:visibility="visible"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_recommendations_holder"
|
||||
android:descendantFocusability="afterDescendants"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
|
@ -540,7 +634,7 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
android:layout_marginEnd="10dp"
|
||||
android:nextFocusUp="@id/result_cast_items"
|
||||
android:nextFocusDown="@id/result_recommendations_list"
|
||||
|
||||
android:descendantFocusability="afterDescendants"
|
||||
android:orientation="horizontal"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:itemCount="2"
|
||||
|
@ -563,7 +657,7 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:descendantFocusability="afterDescendants"
|
||||
android:nextFocusUp="@id/result_recommendations_filter_selection"
|
||||
android:nextFocusUp="@id/result_cast_items"
|
||||
android:orientation="vertical"
|
||||
app:spanCount="8"
|
||||
tools:listitem="@layout/search_result_grid" />
|
||||
|
@ -576,7 +670,7 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
tools:visibility="invisible">
|
||||
|
||||
|
||||
<!--
|
||||
|
@ -765,152 +859,7 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<!--
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_movie_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical"
|
||||
tools:visibility="visible">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_play_movie"
|
||||
style="@style/RegularButtonTV"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_weight="1"
|
||||
android:minWidth="250dp"
|
||||
android:nextFocusUp="@id/result_back"
|
||||
android:nextFocusDown="@id/result_play_series"
|
||||
android:text="@string/play_movie_button"
|
||||
android:visibility="visible"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24">
|
||||
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/series_holder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_play_series"
|
||||
style="@style/RegularButtonTV"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginStart="0dp"
|
||||
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_weight="1"
|
||||
android:minWidth="250dp"
|
||||
android:nextFocusUp="@id/result_play_movie"
|
||||
android:nextFocusDown="@id/result_resume_series"
|
||||
android:text="@string/play_episode"
|
||||
android:visibility="visible"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_resume_series"
|
||||
style="@style/RegularButtonTV"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginStart="0dp"
|
||||
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_weight="1"
|
||||
android:minWidth="250dp"
|
||||
android:nextFocusUp="@id/result_play_series"
|
||||
android:nextFocusDown="@id/result_play_trailer"
|
||||
android:text="@string/resume"
|
||||
android:visibility="visible"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24"
|
||||
tools:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_play_trailer"
|
||||
style="@style/RegularButtonTV"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_weight="1"
|
||||
android:minWidth="250dp"
|
||||
android:nextFocusUp="@id/result_resume_series"
|
||||
android:nextFocusDown="@id/result_bookmark_button"
|
||||
android:text="@string/play_trailer_button"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24"
|
||||
tools:visibility="visible">
|
||||
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_bookmark_button"
|
||||
style="@style/RegularButtonTV"
|
||||
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_weight="1"
|
||||
android:minWidth="250dp"
|
||||
android:nextFocusUp="@id/result_play_trailer"
|
||||
android:nextFocusDown="@id/result_resume_series_button"
|
||||
android:text="@string/type_none"
|
||||
android:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_resume_progress_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:id="@+id/result_resume_series_progress"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:indeterminate="false"
|
||||
android:max="100"
|
||||
android:paddingEnd="10dp"
|
||||
android:progress="0"
|
||||
android:progressBackgroundTint="?attr/colorPrimary"
|
||||
android:visibility="visible"
|
||||
tools:progress="50"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_resume_series_progress_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="0"
|
||||
android:gravity="center"
|
||||
android:maxLines="1"
|
||||
android:paddingEnd="5dp"
|
||||
android:textColor="?attr/grayTextColor"
|
||||
tools:ignore="RtlSymmetry"
|
||||
tools:text="69m remaining" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
-->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/result_poster_holder"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -1067,70 +1016,47 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_baseline_add_24" />
|
||||
|
||||
|
||||
<!--<LinearLayout
|
||||
|
||||
android:id="@+id/result_resume_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="gone">
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/result_next_series_button"
|
||||
style="@style/WhiteButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:nextFocusUp="@id/result_bookmark_button"
|
||||
android:nextFocusDown="@id/result_download_movie"
|
||||
android:text="@string/next_episode"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/cast_ic_mini_controller_skip_next" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_weight="0"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_movie_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
android:layout_gravity="start"
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/result_resume_series_button"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
|
||||
android:layout_gravity="center"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/download"
|
||||
|
||||
android:nextFocusUp="@id/result_play_movie"
|
||||
android:nextFocusDown="@id/result_season_selection"
|
||||
android:src="@drawable/ic_baseline_play_arrow_24"
|
||||
android:visibility="visible"
|
||||
app:tint="?attr/white" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_resume_series_title"
|
||||
<LinearLayout
|
||||
android:id="@+id/series_holder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:textColor="?attr/textColor"
|
||||
android:textSize="17sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="S1E1 Episode 1" />
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:id="@+id/redirect_to_episodes"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="1dp"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true" />
|
||||
|
||||
<View
|
||||
android:id="@+id/redirect_to_play"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="1dp"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>-->
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</FrameLayout>
|
|
@ -533,18 +533,14 @@
|
|||
android:id="@id/exo_position"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="20dp"
|
||||
android:gravity="end|center_vertical"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:minWidth="50dp"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingRight="4dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="normal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/player_pause_play"
|
||||
app:layout_constraintStart_toEndOf="@id/player_pause_play"
|
||||
tools:text="15:30" />
|
||||
|
||||
<FrameLayout
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
android:title="@string/title_search" />
|
||||
<item
|
||||
android:id="@+id/navigation_library"
|
||||
android:icon="@drawable/ic_outline_account_circle_24"
|
||||
android:icon="@drawable/library_icon"
|
||||
android:title="@string/library" />
|
||||
<item
|
||||
android:id="@+id/navigation_downloads"
|
||||
|
|
|
@ -212,6 +212,7 @@
|
|||
<item>Banana</item>
|
||||
<item>Fiesta</item>
|
||||
<item>Dolor rosa</item>
|
||||
<item>Lavanda</item>
|
||||
<item>Material You</item>
|
||||
<item>Material You (Secondary)</item>
|
||||
</string-array>
|
||||
|
@ -235,6 +236,7 @@
|
|||
<item>Banana</item>
|
||||
<item>Party</item>
|
||||
<item>Pink</item>
|
||||
<item>Lavender</item>
|
||||
<item>Monet</item>
|
||||
<item>Monet2</item>
|
||||
</string-array>
|
||||
|
|
|
@ -221,6 +221,7 @@
|
|||
<item>Bananowy</item>
|
||||
<item>Łososiowy</item>
|
||||
<item>Świnko peppowy</item>
|
||||
<item>Lawenda</item>
|
||||
<item>Material You</item>
|
||||
<item>Material You (drugorzędny)</item>
|
||||
</string-array>
|
||||
|
@ -244,6 +245,7 @@
|
|||
<item>Banana</item>
|
||||
<item>Party</item>
|
||||
<item>Pink</item>
|
||||
<item>Lavender</item>
|
||||
<item>Monet</item>
|
||||
<item>Monet2</item>
|
||||
</string-array>
|
||||
|
|
|
@ -247,6 +247,7 @@
|
|||
<item>Muz</item>
|
||||
<item>Parti</item>
|
||||
<item>Pembe</item>
|
||||
<item>Lavanta</item>
|
||||
<item>Material You</item>
|
||||
<item>Material You (İkincil)</item>
|
||||
</string-array>
|
||||
|
@ -270,6 +271,7 @@
|
|||
<item>Banana</item>
|
||||
<item>Party</item>
|
||||
<item>Pink</item>
|
||||
<item>Lavender</item>
|
||||
<item>Monet</item>
|
||||
<item>Monet2</item>
|
||||
</string-array>
|
||||
|
|
|
@ -213,6 +213,7 @@
|
|||
<item>Vàng</item>
|
||||
<item>Hồng</item>
|
||||
<item>Hồng đậm</item>
|
||||
<item>Hoa oải hương</item>
|
||||
<item>Material You</item>
|
||||
<item>Material You (Secondary)</item>
|
||||
</string-array>
|
||||
|
@ -236,6 +237,7 @@
|
|||
<item>Banana</item>
|
||||
<item>Party</item>
|
||||
<item>Pink</item>
|
||||
<item>Lavender</item>
|
||||
<item>Monet</item>
|
||||
<item>Monet2</item>
|
||||
</string-array>
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
<item>Banana</item>
|
||||
<item>Party</item>
|
||||
<item>Pink Pain</item>
|
||||
<item>Lavender</item>
|
||||
<item>Material You</item>
|
||||
<item>Material You (Secondary)</item>
|
||||
</string-array>
|
||||
|
@ -307,6 +308,7 @@
|
|||
<item>Banana</item>
|
||||
<item>Party</item>
|
||||
<item>Pink</item>
|
||||
<item>Lavender</item>
|
||||
<item>Monet</item>
|
||||
<item>Monet2</item>
|
||||
</string-array>
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
<color name="colorPrimaryOrange">#CE8500</color>
|
||||
<color name="colorPrimaryDandelionYellow">#F5BB00</color>
|
||||
<color name="colorPrimaryCoolBlue">#408cac</color>
|
||||
<color name="colorPrimaryLavender">#6F55AF</color>
|
||||
|
||||
<color name="colorTestPass">#48E484</color>
|
||||
<color name="colorTestFail">#ea596e</color>
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
<string name="enable_skip_op_from_database" translatable="false">enable_skip_op_from_database</string>
|
||||
<string name="rotate_video_key" translatable="false">rotate_video_key</string>
|
||||
<string name="auto_rotate_video_key" translatable="false">auto_rotate_video_key</string>
|
||||
<string name="biometric_key" translatable="false">biometric_key</string>
|
||||
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
|
||||
<string name="extra_info_format" formatted="true" translatable="false">%d %s | %s</string>
|
||||
<string name="storage_size_format" formatted="true" translatable="false">%s • %s</string>
|
||||
|
@ -247,7 +248,7 @@
|
|||
<string name="backup_failed_error_format">Error backing up %s</string>
|
||||
<string name="search">Search</string>
|
||||
<string name="library">Library</string>
|
||||
<string name="category_account">Accounts</string>
|
||||
<string name="category_account">Accounts and Security</string>
|
||||
<string name="category_updates">Updates and backup</string>
|
||||
<string name="settings_info">Info</string>
|
||||
<string name="advanced_search">Advanced Search</string>
|
||||
|
@ -306,6 +307,7 @@
|
|||
<string name="go_forward_30">+30</string>
|
||||
<string name="delete_message" formatted="true">This will permanently delete %s\nAre you sure?</string>
|
||||
<string name="resume_time_left" formatted="true">%dm\nremaining</string>
|
||||
<string name="resume_remaining" formatted="true">%s\nremaining</string>
|
||||
<string name="status_ongoing">Ongoing</string>
|
||||
<string name="status_completed">Completed</string>
|
||||
<string name="status">Status</string>
|
||||
|
@ -745,4 +747,17 @@
|
|||
<string name="rotate_video_desc">Display a toggle button for screen orientation</string>
|
||||
<string name="auto_rotate_video_desc">Enable automatic switching of screen orientation based on video orientation</string>
|
||||
<string name="auto_rotate_video">Auto rotate</string>
|
||||
<string name="favorite">Favorite</string>
|
||||
<string name="unfavorite">Unfavorite</string>
|
||||
<!-- For Biometrics -->
|
||||
<string name="biometric_authentication_title">Unlock CloudStream</string>
|
||||
<string name="biometric_setting">Lock with Biometrics</string>
|
||||
<string name="password_pin_authentication_title">Password/PIN Authentication</string>
|
||||
<string name="biometric_unsupported">Biometric authentication is not supported on this device</string>
|
||||
<string name="biometric_setting_summary">Unlock the app with Fingerprint, Face ID, PIN, Pattern and Password.</string>
|
||||
<string name="biometric_prompt_description">This window will close after few failed attempts. You\'ll have to restart the App.</string>
|
||||
<string name="biometric_warning">Your CloudStream data has been backed up now, although probability of this rare case is very low but all
|
||||
devices behave differently, in case you get locked down from accessing the app in worst case scenario,
|
||||
Clear the app data wholly and restore the backup. Any inconvenience if arrived is deeply regretted.</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -383,6 +383,16 @@
|
|||
<item name="android:colorAccent">@color/colorPrimaryCoolBlue</item>
|
||||
</style>
|
||||
|
||||
<style name="OverlayPrimaryColorLavender">
|
||||
<item name="colorPrimary">@color/colorPrimaryLavender</item>
|
||||
<item name="android:colorPrimary">@color/colorPrimaryLavender</item>
|
||||
<item name="colorPrimaryDark">#6B51AB</item>
|
||||
<item name="colorAccent">#7961B4</item>
|
||||
<item name="colorOnPrimary">@color/whiteText</item>
|
||||
<!-- Needed for leanback fuckery -->
|
||||
<item name="android:colorAccent">@color/colorPrimaryLavender</item>
|
||||
</style>
|
||||
|
||||
<style name="customRatingBar" parent="@style/Widget.AppCompat.RatingBar">
|
||||
|
||||
<item name="android:progressDrawable">@drawable/abc_ratingbar_indicator_material</item>
|
||||
|
@ -804,6 +814,35 @@
|
|||
<item name="android:insetTop">0dp</item>
|
||||
</style>
|
||||
|
||||
<style name="ResultSmallButtonTV">
|
||||
<item name="android:tag">@string/tv_no_focus_tag</item>
|
||||
<item name="android:stateListAnimator">@null</item>
|
||||
<item name="strokeColor">@color/transparent</item>
|
||||
<item name="backgroundTint">@null</item>
|
||||
<item name="android:background">@drawable/player_button_tv_attr</item>
|
||||
<item name="rippleColor">@color/white</item>
|
||||
<item name="android:shadowColor">@color/transparent</item>
|
||||
<item name="iconTint">@color/player_on_button_tv_attr</item>
|
||||
<item name="iconGravity">textStart</item>
|
||||
<item name="android:layout_width">60dp</item>
|
||||
<item name="android:layout_height">40dp</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:layout_gravity">center</item>
|
||||
<item name="android:layout_marginStart">4dp</item>
|
||||
<item name="android:layout_marginEnd">4dp</item>
|
||||
<item name="android:layout_marginBottom">4dp</item>
|
||||
</style>
|
||||
|
||||
<style name="ResultMarqueeButtonText">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:gravity">top|center_horizontal</item>
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:scrollHorizontally">true</item>
|
||||
<item name="android:marqueeRepeatLimit">marquee_forever</item>
|
||||
<item name="android:ellipsize">marquee</item>
|
||||
</style>
|
||||
|
||||
<style name="VideoButtonTV">
|
||||
<item name="android:tag">@string/tv_no_focus_tag</item>
|
||||
<item name="android:stateListAnimator">@null</item>
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:icon="@drawable/ic_outline_account_circle_24"
|
||||
android:key="@string/skip_startup_account_select_key"
|
||||
android:title="@string/skip_startup_account_select_pref" />
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/mal_logo"
|
||||
|
@ -22,17 +16,18 @@
|
|||
<Preference
|
||||
android:icon="@drawable/open_subtitles_icon"
|
||||
android:key="@string/opensubtitles_key" />
|
||||
<!-- <Preference-->
|
||||
<!-- android:key="@string/nginx_key"-->
|
||||
<!-- android:icon="@drawable/nginx" />-->
|
||||
|
||||
<!-- <Preference-->
|
||||
<!-- android:title="@string/nginx_info_title"-->
|
||||
<!-- android:icon="@drawable/nginx_question"-->
|
||||
<!-- android:summary="@string/nginx_info_summary">-->
|
||||
<!-- <intent-->
|
||||
<!-- android:action="android.intent.action.VIEW"-->
|
||||
<!-- android:data="https://www.sarlays.com/use-nginx-with-cloudstream/" />-->
|
||||
<!-- </Preference>-->
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:icon="@drawable/ic_outline_account_circle_24"
|
||||
android:key="@string/skip_startup_account_select_key"
|
||||
android:title="@string/skip_startup_account_select_pref" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="@string/biometric_key"
|
||||
android:defaultValue="false"
|
||||
android:summary="@string/biometric_setting_summary"
|
||||
android:icon="@drawable/ic_fingerprint"
|
||||
android:title="@string/biometric_setting" />
|
||||
|
||||
</PreferenceScreen>
|
Loading…
Add table
Add a link
Reference in a new issue