Skip to content

Commit

Permalink
Added the logic to pop-up biometric sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
aritra-tech committed Jan 29, 2025
1 parent 0913e54 commit 645cd41
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 4 deletions.
11 changes: 11 additions & 0 deletions .idea/other.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 36 additions & 1 deletion app/src/main/java/com/aritradas/uncrack/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,15 @@ import androidx.annotation.RequiresApi
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.core.view.WindowCompat
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.aritradas.uncrack.navigation.Navigation
import com.aritradas.uncrack.presentation.settings.SettingsViewModel
import com.aritradas.uncrack.sharedViewModel.SharedViewModel
import com.aritradas.uncrack.ui.theme.UnCrackTheme
import com.aritradas.uncrack.util.AppBioMetricManager
import com.aritradas.uncrack.util.NetworkConnectivityObserver
import com.google.android.gms.tasks.Task
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
Expand All @@ -25,11 +31,18 @@ import com.google.android.play.core.appupdate.AppUpdateOptions
import com.google.android.play.core.install.model.AppUpdateType
import com.google.android.play.core.install.model.UpdateAvailability
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import javax.inject.Inject

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
class MainActivity : FragmentActivity() {

private val settingsViewModel: SettingsViewModel by viewModels()
private val viewModel: SharedViewModel by viewModels()

@Inject
lateinit var appBioMetricManager: AppBioMetricManager

private val activityResultLauncher = registerForActivityResult(
ActivityResultContracts.StartIntentSenderForResult()
Expand Down Expand Up @@ -75,6 +88,28 @@ class MainActivity : ComponentActivity() {
Navigation(this, connectivityObserver)
}
}

setObserver()
}

private fun setObserver() {
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.initAuth.collect { value ->
if (value && viewModel.loading.value) {
viewModel.showBiometricPrompt(this@MainActivity)
}
}
}
}

lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.finishActivity.collect { value ->
if (value) finish()
}
}
}
}

private fun checkForAppUpdate() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.aritradas.uncrack.presentation.settings

interface BiometricAuthListener {
fun onBiometricAuthSuccess()
fun onUserCancelled()
fun onErrorOccurred()
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,20 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import com.aritradas.uncrack.MainActivity
import com.aritradas.uncrack.R
import com.aritradas.uncrack.components.SettingsItemGroup
import com.aritradas.uncrack.components.ThemeDialog
Expand All @@ -51,9 +54,11 @@ fun SettingsScreen(
modifier: Modifier = Modifier
) {

val context = LocalContext.current
val isScreenshotEnabled by settingsViewModel.isScreenshotEnabled.observeAsState(false)
val onLogOutComplete by settingsViewModel.onLogOutComplete.observeAsState(false)
val onDeleteAccountComplete by settingsViewModel.onDeleteAccountComplete.observeAsState(false)
val biometricAuthState by settingsViewModel.biometricAuthState.collectAsState()
var openThemeDialog by remember { mutableStateOf(false) }
var openLogoutDialog by remember { mutableStateOf(false) }
var openDeleteAccountDialog by remember { mutableStateOf(false) }
Expand Down Expand Up @@ -228,8 +233,10 @@ fun SettingsScreen(

UCSwitchCard(
itemName = stringResource(R.string.unlock_with_biometric),
isChecked = false,
onChecked = {}
isChecked = biometricAuthState,
onChecked = {
settingsViewModel.showBiometricPrompt(context as MainActivity)
}
)

HorizontalDivider(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
package com.aritradas.uncrack.presentation.settings

import androidx.datastore.preferences.core.edit
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.aritradas.uncrack.MainActivity
import com.aritradas.uncrack.data.datastore.DataStoreUtil
import com.aritradas.uncrack.domain.repository.AccountRepository
import com.aritradas.uncrack.domain.repository.KeyRepository
import com.aritradas.uncrack.util.AppBioMetricManager
import com.aritradas.uncrack.util.runIO
import com.google.firebase.Firebase
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.auth
import com.google.firebase.firestore.FirebaseFirestore
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class SettingsViewModel @Inject constructor(
private val keyRepository: KeyRepository,
private val accountRepository: AccountRepository
private val accountRepository: AccountRepository,
private val appBioMetricManager: AppBioMetricManager,
dataStoreUtil: DataStoreUtil
): ViewModel() {

private val auth = Firebase.auth
Expand All @@ -26,6 +38,41 @@ class SettingsViewModel @Inject constructor(
val isScreenshotEnabled: LiveData<Boolean> get() = _isScreenshotEnabled
private val user = auth.currentUser
private val userDB = FirebaseFirestore.getInstance()
private val dataStore = dataStoreUtil.dataStore
private val _biometricAuthState = MutableStateFlow(false)
val biometricAuthState: StateFlow<Boolean> = _biometricAuthState

init {
viewModelScope.launch(Dispatchers.IO) {
dataStore.data.map { preferences ->
preferences[DataStoreUtil.IS_BIOMETRIC_AUTH_SET_KEY] ?: false
}.collect {
_biometricAuthState.value = it
}
}
}

fun showBiometricPrompt(activity: MainActivity) {
appBioMetricManager.initBiometricPrompt(
activity = activity,
listener = object : BiometricAuthListener {
override fun onBiometricAuthSuccess() {
viewModelScope.launch {
dataStore.edit { preferences ->
preferences[DataStoreUtil.IS_BIOMETRIC_AUTH_SET_KEY] =
!_biometricAuthState.value
}
}
}

override fun onUserCancelled() {
}

override fun onErrorOccurred() {
}
}
)
}

fun setScreenshotEnabled(enabled: Boolean) {
_isScreenshotEnabled.value = enabled
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.aritradas.uncrack.sharedViewModel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.aritradas.uncrack.MainActivity
import com.aritradas.uncrack.data.datastore.DataStoreUtil
import com.aritradas.uncrack.presentation.settings.BiometricAuthListener
import com.aritradas.uncrack.util.AppBioMetricManager
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class SharedViewModel @Inject constructor(
private val appBioMetricManager: AppBioMetricManager,
dataStoreUtil: DataStoreUtil,
) : ViewModel() {

private val dataStore = dataStoreUtil.dataStore

private val _loading = MutableStateFlow(true)
val loading: StateFlow<Boolean> = _loading.asStateFlow()

private val _initAuth = MutableStateFlow(false)
val initAuth: StateFlow<Boolean> = _initAuth.asStateFlow()

private val _finishActivity = MutableStateFlow(false)
val finishActivity: StateFlow<Boolean> = _finishActivity.asStateFlow()

init {
viewModelScope.launch(Dispatchers.IO) {
dataStore.data.map { preferences ->
preferences[DataStoreUtil.IS_BIOMETRIC_AUTH_SET_KEY] ?: false
}.collect { biometricAuthState ->
if (biometricAuthState && appBioMetricManager.canAuthenticate()) {
_initAuth.emit(true)
} else {
delay(1_000L)
_loading.emit(false)
}
}
}
}

fun showBiometricPrompt(mainActivity: MainActivity) {
appBioMetricManager.initBiometricPrompt(
activity = mainActivity,
listener = object : BiometricAuthListener {
override fun onBiometricAuthSuccess() {
viewModelScope.launch {
_loading.emit(false)
}
}

override fun onUserCancelled() {
finishActivity()
}

override fun onErrorOccurred() {
finishActivity()
}
}
)
}

private fun finishActivity() {
viewModelScope.launch {
_finishActivity.emit(true)
}
}
}

0 comments on commit 645cd41

Please sign in to comment.