Implemented LoginScreen
This commit is contained in:
parent
6e6449e956
commit
4697119c58
Binary file not shown.
After Width: | Height: | Size: 5.0 KiB |
|
@ -9,6 +9,8 @@ import androidx.compose.ui.unit.sp
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import net.codinux.banking.ui.config.Colors
|
import net.codinux.banking.ui.config.Colors
|
||||||
import net.codinux.banking.ui.config.DI
|
import net.codinux.banking.ui.config.DI
|
||||||
|
import net.codinux.banking.ui.model.settings.AppAuthenticationMethod
|
||||||
|
import net.codinux.banking.ui.screens.LoginScreen
|
||||||
import net.codinux.banking.ui.screens.MainScreen
|
import net.codinux.banking.ui.screens.MainScreen
|
||||||
import net.codinux.log.LoggerFactory
|
import net.codinux.log.LoggerFactory
|
||||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
@ -25,14 +27,24 @@ fun App() {
|
||||||
val colors = MaterialTheme.colors.copy(primary = Colors.Primary, primaryVariant = Colors.PrimaryDark, onPrimary = Color.White,
|
val colors = MaterialTheme.colors.copy(primary = Colors.Primary, primaryVariant = Colors.PrimaryDark, onPrimary = Color.White,
|
||||||
secondary = Colors.Accent, secondaryVariant = Colors.Accent, onSecondary = Color.White)
|
secondary = Colors.Accent, secondaryVariant = Colors.Accent, onSecondary = Color.White)
|
||||||
|
|
||||||
|
val appSettings = DI.uiState.appSettings.collectAsState().value
|
||||||
|
|
||||||
|
var isLoggedIn by remember(appSettings.authenticationMethod) { mutableStateOf(appSettings.authenticationMethod == AppAuthenticationMethod.None) }
|
||||||
|
|
||||||
var isInitialized by remember { mutableStateOf(false) }
|
var isInitialized by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
|
||||||
MaterialTheme(colors = colors, typography = typography) {
|
MaterialTheme(colors = colors, typography = typography) {
|
||||||
|
if (isLoggedIn == false) {
|
||||||
|
LoginScreen(appSettings) {
|
||||||
|
isLoggedIn = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
MainScreen()
|
MainScreen()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
LaunchedEffect(isInitialized) {
|
LaunchedEffect(isInitialized) {
|
||||||
|
|
|
@ -43,6 +43,10 @@ object DI {
|
||||||
|
|
||||||
fun setRepository(repository: BankingRepository) {
|
fun setRepository(repository: BankingRepository) {
|
||||||
this.bankingRepository = repository
|
this.bankingRepository = repository
|
||||||
|
|
||||||
|
repository.getAppSettings()?.let { // otherwise it's the first app start, BankingService will take care of this case
|
||||||
|
uiState.appSettings.value = it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,16 @@ import androidx.compose.ui.text.input.VisualTransformation
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
@Composable // try BasicSecureTextField
|
@Composable // try BasicSecureTextField
|
||||||
fun PasswordTextField(password: String = "", label: String = "Passwort", modifier: Modifier = Modifier, keyboardOptions: KeyboardOptions? = null, forceHidePassword: Boolean? = null, onEnterPressed: (() -> Unit)? = null, onChange: (String) -> Unit) {
|
fun PasswordTextField(
|
||||||
|
password: String = "",
|
||||||
|
label: String = "Passwort",
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
keyboardOptions: KeyboardOptions? = null,
|
||||||
|
isError: Boolean = false,
|
||||||
|
forceHidePassword: Boolean? = null,
|
||||||
|
onEnterPressed: (() -> Unit)? = null,
|
||||||
|
onChange: (String) -> Unit
|
||||||
|
) {
|
||||||
|
|
||||||
var passwordVisible by remember { mutableStateOf(false) }
|
var passwordVisible by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
@ -30,6 +39,7 @@ fun PasswordTextField(password: String = "", label: String = "Passwort", modifie
|
||||||
onValueChange = { onChange(it) },
|
onValueChange = { onChange(it) },
|
||||||
label = { Text(label) },
|
label = { Text(label) },
|
||||||
modifier = modifier.fillMaxWidth(),
|
modifier = modifier.fillMaxWidth(),
|
||||||
|
isError = isError,
|
||||||
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
val visibilityIcon = if (passwordVisible) {
|
val visibilityIcon = if (passwordVisible) {
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package net.codinux.banking.ui.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
import androidx.compose.material.Button
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import bankmeister.composeapp.generated.resources.*
|
||||||
|
import bankmeister.composeapp.generated.resources.Res
|
||||||
|
import net.codinux.banking.ui.forms.PasswordTextField
|
||||||
|
import net.codinux.banking.ui.model.settings.AppAuthenticationMethod
|
||||||
|
import net.codinux.banking.ui.model.settings.AppSettings
|
||||||
|
import net.codinux.banking.ui.service.PasswordService
|
||||||
|
import org.jetbrains.compose.resources.imageResource
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LoginScreen(appSettings: AppSettings, onLoginSuccess: () -> Unit) {
|
||||||
|
|
||||||
|
var password by remember { mutableStateOf("") }
|
||||||
|
|
||||||
|
var showError by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
|
||||||
|
fun checkPassword() {
|
||||||
|
if (appSettings.hashedPassword != null && PasswordService.checkPassword(password, appSettings.hashedPassword!!)) {
|
||||||
|
onLoginSuccess()
|
||||||
|
} else {
|
||||||
|
showError = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(16.dp),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
Image(imageResource(Res.drawable.AppIcon_round), "Bankmeister's app icon", Modifier.size(144.dp).padding(bottom = 32.dp))
|
||||||
|
|
||||||
|
if (appSettings.authenticationMethod == AppAuthenticationMethod.Password) {
|
||||||
|
Text("Bitte geben Sie Ihr Passwort ein um die App zu entsperren", style = MaterialTheme.typography.h5, textAlign = TextAlign.Center)
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
||||||
|
PasswordTextField(
|
||||||
|
password = password,
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
|
onEnterPressed = { checkPassword() },
|
||||||
|
isError = showError
|
||||||
|
) {
|
||||||
|
password = it
|
||||||
|
showError = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showError) {
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
Text("Passwort ist falsch", color = MaterialTheme.colors.error, fontSize = 18.sp)
|
||||||
|
}
|
||||||
|
|
||||||
|
Button(modifier = Modifier.padding(top = 24.dp).width(300.dp).height(50.dp), onClick = { checkPassword() }) {
|
||||||
|
Text("Login", color = Color.White)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue