mirror of
https://github.com/owenlejeune/TVTime.git
synced 2025-11-08 04:32:43 -05:00
various changes
This commit is contained in:
@@ -93,6 +93,8 @@ dependencies {
|
||||
implementation "androidx.paging:paging-compose:$compose_paging"
|
||||
implementation "androidx.constraintlayout:constraintlayout-compose:$compose_constraint_layout"
|
||||
implementation "com.google.accompanist:accompanist-webview:$compose_accompanist"
|
||||
implementation "androidx.biometric:biometric-ktx:1.2.0-alpha05"
|
||||
|
||||
|
||||
// material you
|
||||
def monet_compat = "0.4.1"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.api
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
@@ -12,7 +11,6 @@ import androidx.paging.PagingData
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import androidx.paging.cachedIn
|
||||
import com.owenlejeune.tvtime.R
|
||||
import com.owenlejeune.tvtime.ui.viewmodel.ViewModelConstants
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.koin.core.component.KoinComponent
|
||||
|
||||
@@ -40,6 +40,7 @@ class AppPreferences(context: Context) {
|
||||
private val FLOATING_BOTTOM_BAR = "floating_bottom_bar"
|
||||
private val RECENT_SEARCHES = "recent_searches"
|
||||
private val SHOW_GOT_QUOTES = "show_got_quotes"
|
||||
private val USE_ACCOUNT_BIOMETRICS = "use_account_biometrics"
|
||||
}
|
||||
|
||||
private val preferences: SharedPreferences = context.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE)
|
||||
@@ -81,6 +82,11 @@ class AppPreferences(context: Context) {
|
||||
get() = preferences.getInt(SELECTED_COLOR, selectedColorDefault)
|
||||
set(value) { preferences.put(SELECTED_COLOR, value) }
|
||||
|
||||
val accountBiometricsDefault: Boolean = false
|
||||
var accountBiometrics: Boolean
|
||||
get() = preferences.getBoolean(USE_ACCOUNT_BIOMETRICS, accountBiometricsDefault)
|
||||
set(value) { preferences.put(USE_ACCOUNT_BIOMETRICS, value) }
|
||||
|
||||
/******* Session Tokens ********/
|
||||
var authorizedSessionValues: SessionManager.AuthorizedSessionValues?
|
||||
get() = preferences.getString(AUTHORIZED_SESSION_VALUES, null)?.let {
|
||||
|
||||
@@ -13,10 +13,12 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
@@ -34,6 +36,7 @@ import com.owenlejeune.tvtime.api.tmdb.api.v4.model.RatedTv
|
||||
import com.owenlejeune.tvtime.extensions.getCalendarYear
|
||||
import com.owenlejeune.tvtime.extensions.lazyPagingItems
|
||||
import com.owenlejeune.tvtime.extensions.unlessEmpty
|
||||
import com.owenlejeune.tvtime.preferences.AppPreferences
|
||||
import com.owenlejeune.tvtime.ui.components.AccountIcon
|
||||
import com.owenlejeune.tvtime.ui.components.BackButton
|
||||
import com.owenlejeune.tvtime.ui.components.MediaResultCard
|
||||
@@ -44,16 +47,38 @@ import com.owenlejeune.tvtime.ui.navigation.AppNavItem
|
||||
import com.owenlejeune.tvtime.ui.screens.tabs.AccountTabNavItem
|
||||
import com.owenlejeune.tvtime.ui.viewmodel.AccountViewModel
|
||||
import com.owenlejeune.tvtime.ui.viewmodel.ApplicationViewModel
|
||||
import com.owenlejeune.tvtime.utils.BiometricUtils
|
||||
import com.owenlejeune.tvtime.utils.SessionManager
|
||||
import com.owenlejeune.tvtime.utils.TmdbUtils
|
||||
import com.owenlejeune.tvtime.utils.types.MediaViewType
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.java.KoinJavaComponent.get
|
||||
import java.util.Date
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AccountScreen(
|
||||
appNavController: NavHostController,
|
||||
doSignInPartTwo: Boolean = false,
|
||||
appPreferences: AppPreferences = get(AppPreferences::class.java)
|
||||
) {
|
||||
var proceed by remember { mutableStateOf(!appPreferences.accountBiometrics) }
|
||||
if (!proceed) {
|
||||
val activity = LocalContext.current as FragmentActivity
|
||||
BiometricUtils.showBiometricPrompt(
|
||||
activity,
|
||||
onFailed = { appNavController.popBackStack() },
|
||||
onError = { appNavController.popBackStack() },
|
||||
onSuccess = { proceed = true }
|
||||
)
|
||||
} else {
|
||||
AccountView(appNavController = appNavController, doSignInPartTwo = doSignInPartTwo)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AccountView(
|
||||
appNavController: NavHostController,
|
||||
doSignInPartTwo: Boolean = false
|
||||
) {
|
||||
|
||||
@@ -1115,7 +1115,7 @@ private fun ReviewsCard(
|
||||
if (isExpanded) {
|
||||
reviews
|
||||
} else {
|
||||
reviews.subList(0, 3)
|
||||
reviews.subList(0, minOf(reviews.size, 3))
|
||||
}
|
||||
} ?: emptyList()
|
||||
Column(
|
||||
|
||||
@@ -60,6 +60,7 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
@@ -85,7 +86,9 @@ import com.owenlejeune.tvtime.ui.viewmodel.ApplicationViewModel
|
||||
import com.owenlejeune.tvtime.ui.viewmodel.SettingsViewModel
|
||||
import com.owenlejeune.tvtime.ui.views.HomeTabRecyclerAdapter
|
||||
import com.owenlejeune.tvtime.ui.views.ItemMoveCallback
|
||||
import com.owenlejeune.tvtime.utils.BiometricUtils
|
||||
import com.owenlejeune.tvtime.utils.SessionManager
|
||||
import com.owenlejeune.tvtime.utils.canShowBiometricsPrompt
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.java.KoinJavaComponent.get
|
||||
|
||||
@@ -237,7 +240,7 @@ fun DesignPreferences(
|
||||
settingsNavController: NavController,
|
||||
) {
|
||||
val settingsViewModel = viewModel<SettingsViewModel>()
|
||||
val activity = LocalContext.current as Activity
|
||||
val activity = LocalContext.current as FragmentActivity
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -315,6 +318,24 @@ fun DesignPreferences(
|
||||
if (showWallpaperPicker.value) {
|
||||
WallpaperPicker(showPopup = showWallpaperPicker)
|
||||
}
|
||||
|
||||
if (canShowBiometricsPrompt()) {
|
||||
SwitchPreference(
|
||||
titleText = "Biometrics",
|
||||
subtitleText = "###",
|
||||
checkState = settingsViewModel.useAccountBiometrics.collectAsState(),
|
||||
onCheckedChange = {
|
||||
settingsViewModel.toggleUseAccountBiometrics()
|
||||
if (it) {
|
||||
BiometricUtils.showBiometricPrompt(
|
||||
activity,
|
||||
onFailed = { settingsViewModel.setUseAccountBiometrics(false) },
|
||||
onError = { settingsViewModel.setUseAccountBiometrics(false) }
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ class SettingsViewModel: ViewModel() {
|
||||
private val _showBackdropGallery = MutableStateFlow(preferences.showBackdropGallery)
|
||||
private val _showNextMcuProduction = MutableStateFlow(preferences.showNextMcuProduction)
|
||||
private val _showGotQuotes = MutableStateFlow(preferences.showGotQuotes)
|
||||
private val _useAccountBiometrics = MutableStateFlow(preferences.accountBiometrics)
|
||||
}
|
||||
|
||||
val showSearchBar = _showSearchBar.asStateFlow()
|
||||
@@ -42,6 +43,7 @@ class SettingsViewModel: ViewModel() {
|
||||
val showBackdropGallery = _showBackdropGallery.asStateFlow()
|
||||
val showNextMcuProduction = _showNextMcuProduction.asStateFlow()
|
||||
val showGotQuotes = _showGotQuotes.asStateFlow()
|
||||
val useAccountBiometrics = _useAccountBiometrics.asStateFlow()
|
||||
|
||||
fun toggleShowSearchBar() {
|
||||
_showSearchBar.value = _showSearchBar.value.not()
|
||||
@@ -168,4 +170,14 @@ class SettingsViewModel: ViewModel() {
|
||||
preferences.showGotQuotes = value
|
||||
}
|
||||
|
||||
fun toggleUseAccountBiometrics() {
|
||||
_useAccountBiometrics.value = _useAccountBiometrics.value.not()
|
||||
preferences.accountBiometrics = _useAccountBiometrics.value
|
||||
}
|
||||
|
||||
fun setUseAccountBiometrics(value: Boolean) {
|
||||
_useAccountBiometrics.value = value
|
||||
preferences.accountBiometrics = value
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.owenlejeune.tvtime.utils
|
||||
|
||||
import androidx.biometric.BiometricManager
|
||||
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG
|
||||
import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
|
||||
import androidx.biometric.BiometricPrompt
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
|
||||
object BiometricUtils {
|
||||
|
||||
fun showBiometricPrompt(activity: FragmentActivity, onError: () -> Unit = {}, onFailed: () -> Unit = {}, onSuccess: () -> Unit = {}) {
|
||||
val executor = ContextCompat.getMainExecutor(activity)
|
||||
val biometricPrompt = BiometricPrompt(activity, executor, object: BiometricPrompt.AuthenticationCallback() {
|
||||
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||
super.onAuthenticationError(errorCode, errString)
|
||||
onError()
|
||||
}
|
||||
|
||||
override fun onAuthenticationFailed() {
|
||||
super.onAuthenticationFailed()
|
||||
onFailed()
|
||||
}
|
||||
|
||||
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
||||
super.onAuthenticationSucceeded(result)
|
||||
onSuccess()
|
||||
}
|
||||
})
|
||||
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle("Title")
|
||||
.setSubtitle("Subtitle")
|
||||
.setNegativeButtonText("Cancel")
|
||||
.build()
|
||||
biometricPrompt.authenticate(promptInfo)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun canShowBiometricsPrompt(): Boolean {
|
||||
val context = LocalContext.current
|
||||
val biometricManager = BiometricManager.from(context)
|
||||
return biometricManager.canAuthenticate(BIOMETRIC_STRONG or DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS
|
||||
}
|
||||
Reference in New Issue
Block a user