Biometric authentication implemented and integrated in dashboard
This commit is contained in:
@@ -4,39 +4,24 @@ import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.calculateEndPadding
|
||||
import androidx.compose.foundation.layout.calculateStartPadding
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.safeDrawing
|
||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.List
|
||||
import androidx.compose.material.icons.automirrored.filled.Logout
|
||||
import androidx.compose.material.icons.filled.Home
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme.colorScheme
|
||||
import androidx.compose.material3.MaterialTheme.typography
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -48,20 +33,16 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.modifier.modifierLocalConsumer
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import io.github.jan.supabase.auth.auth
|
||||
import io.github.jan.supabase.auth.status.SessionStatus
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import net.tinsae.clocked.biometric.GlobalAuthenticator
|
||||
import net.tinsae.clocked.components.ShowLoadingScreen
|
||||
import net.tinsae.clocked.dashboard.DashboardScreen
|
||||
import net.tinsae.clocked.data.Locale
|
||||
@@ -71,11 +52,10 @@ import net.tinsae.clocked.history.HistoryScreen
|
||||
import net.tinsae.clocked.settings.SettingsScreen
|
||||
import net.tinsae.clocked.settings.SettingsViewModel
|
||||
import net.tinsae.clocked.ui.theme.ClockedTheme
|
||||
import net.tinsae.clocked.util.SupabaseClient
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
private val settingsViewModel: SettingsViewModel by viewModels()
|
||||
private val authViewModel: AuthViewModel by viewModels()
|
||||
@@ -120,6 +100,7 @@ class MainActivity : ComponentActivity() {
|
||||
setContent {
|
||||
// The single ViewModel instances from the Activity are passed down.
|
||||
AppEntry(settingsViewModel, authViewModel)
|
||||
GlobalAuthenticator()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,19 +109,7 @@ class MainActivity : ComponentActivity() {
|
||||
fun AppEntry(settingsViewModel: SettingsViewModel, authViewModel: AuthViewModel) {
|
||||
val settingsState by settingsViewModel.uiState.collectAsState()
|
||||
val sessionStatus by authViewModel.sessionStatus.collectAsState()
|
||||
|
||||
|
||||
/*LaunchedEffect(Unit) {
|
||||
SupabaseClient.client.auth.sessionStatus.collect { status ->
|
||||
if (status is SessionStatus.Authenticated &&
|
||||
SupabaseClient.client.auth.currentSessionOrNull() != null
|
||||
) {
|
||||
LogRepository.fetchLogs()
|
||||
} else {
|
||||
return@collect
|
||||
}
|
||||
}
|
||||
}*/
|
||||
// Trigger fetching of logs when the session status changes.
|
||||
LaunchedEffect(sessionStatus) {
|
||||
if (sessionStatus is SessionStatus.Authenticated){
|
||||
LogRepository.fetchLogs()
|
||||
@@ -169,11 +138,9 @@ fun AppEntry(settingsViewModel: SettingsViewModel, authViewModel: AuthViewModel)
|
||||
ClockedApp(settingsViewModel, authViewModel)
|
||||
}
|
||||
|
||||
is SessionStatus.NotAuthenticated -> {
|
||||
else -> {
|
||||
LoginScreen(authViewModel)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,12 +161,16 @@ fun ClockedApp(settingsViewModel: SettingsViewModel, authViewModel: AuthViewMode
|
||||
|
||||
|
||||
NavigationSuiteScaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
navigationSuiteItems = {
|
||||
AppDestinations.entries.forEach { destination ->
|
||||
item(
|
||||
icon = { Icon(
|
||||
imageVector = destination.icon,
|
||||
contentDescription = stringResource(destination.label))
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = destination.icon,
|
||||
contentDescription = stringResource(destination.label),
|
||||
modifier = Modifier.padding(1.dp).size(24.dp)
|
||||
)
|
||||
},
|
||||
alwaysShowLabel = false,
|
||||
label = { Text(stringResource(destination.label)) },
|
||||
@@ -211,52 +182,40 @@ fun ClockedApp(settingsViewModel: SettingsViewModel, authViewModel: AuthViewMode
|
||||
) {
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
/*topBar = {
|
||||
TopBar(
|
||||
appName = stringResource(id = R.string.app_name, currentDestination.label),
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
isForContainer = true,
|
||||
actions = {
|
||||
IconButton(
|
||||
onClick = { authViewModel.logout() }, modifier = Modifier.padding(10.dp),
|
||||
|
||||
topBar = {
|
||||
Surface(
|
||||
color = colorScheme.surfaceContainer,
|
||||
shadowElevation = 2.dp, // Adds a subtle shadow to lift the bar
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
// No padding needed here on the Surface itself
|
||||
) {
|
||||
Row(
|
||||
// Apply safe area padding to the Row to push content down
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(WindowInsets.safeDrawing.only(WindowInsetsSides.Top).asPaddingValues()),
|
||||
verticalAlignment = androidx.compose.ui.Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 16.dp), // Vertical padding is handled by Row's alignment
|
||||
text = stringResource(R.string.app_name),
|
||||
style = typography.titleLarge,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
IconButton(onClick = { authViewModel.logout() }, modifier = Modifier.padding(10.dp)) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.Logout,
|
||||
contentDescription = "Logout" // Use string resource
|
||||
)
|
||||
) {
|
||||
Icon(imageVector = Icons.AutoMirrored.Filled.Logout, contentDescription = stringResource(R.string.logout))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
) { innerPadding ->
|
||||
val modifier = Modifier.fillMaxWidth().padding(innerPadding)
|
||||
|
||||
when (currentDestination) {
|
||||
AppDestinations.HOME -> DashboardScreen( modifier = modifier)
|
||||
AppDestinations.HISTORY -> HistoryScreen(modifier = modifier)
|
||||
AppDestinations.SETTING -> SettingsScreen(
|
||||
modifier = Modifier,
|
||||
viewModel = settingsViewModel,
|
||||
authViewModel = authViewModel
|
||||
)
|
||||
}*/
|
||||
|
||||
) { innerPadding ->
|
||||
val modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(innerPadding)
|
||||
|
||||
when (currentDestination) {
|
||||
AppDestinations.HOME -> DashboardScreen(modifier = modifier)
|
||||
AppDestinations.HISTORY -> HistoryScreen(modifier = modifier)
|
||||
AppDestinations.SETTING -> SettingsScreen(
|
||||
modifier = modifier,
|
||||
viewModel = settingsViewModel
|
||||
)
|
||||
|
||||
AppDestinations.LOGOUT -> {
|
||||
authViewModel.logout()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,12 +226,5 @@ enum class AppDestinations(
|
||||
HOME(R.string.nav_home, Icons.Default.Home),
|
||||
HISTORY(R.string.nav_history, Icons.AutoMirrored.Filled.List),
|
||||
SETTING(R.string.nav_settings, Icons.Default.Settings),
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun AppEntryPreview() {
|
||||
ClockedTheme {
|
||||
AppEntry(SettingsViewModel(), AuthViewModel())
|
||||
}
|
||||
LOGOUT(R.string.logout, Icons.AutoMirrored.Filled.Logout)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user