From 9e0101642a2678bf5f75bdcfa9ca552bbb1c1341 Mon Sep 17 00:00:00 2001 From: "Maurice L." Date: Sat, 21 Feb 2026 00:20:40 +0100 Subject: [PATCH] Extended Login and UI The login process has been expanded to include fields for Server URL, Username, and Password, replacing the previous User ID-only login. The UI now utilizes `navigationBarsPadding` to prevent overlap with system navigation elements on the Login, Account Selection, and generic screens. The `Account` entity has been updated to include a `serverUrl`. --- .../shap_planner/activities/MainActivity.kt | 53 ++++++++++++++----- .../shap_planner/entities/Account.kt | 3 +- .../shap_planner/viewmodels/LoginViewModel.kt | 10 +++- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/de/miaurizius/shap_planner/activities/MainActivity.kt b/app/src/main/java/de/miaurizius/shap_planner/activities/MainActivity.kt index b65f60d..31f772f 100644 --- a/app/src/main/java/de/miaurizius/shap_planner/activities/MainActivity.kt +++ b/app/src/main/java/de/miaurizius/shap_planner/activities/MainActivity.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBarsPadding @@ -65,11 +66,7 @@ class MainActivity : ComponentActivity() { when { !isLoggedIn || accountList.isEmpty() -> { - LoginScreen { userId -> - val acc = Account(userId, "MiauRizius", "Pfadi-WG") //TODO: get data from backend - mainViewModel.addAccount(acc) - loginViewModel.login(acc.id.toString()) - } + LoginScreen { serverUrl, username, password -> loginViewModel.login(serverUrl, username, password, mainViewModel) } } selectedAccount != null -> { @@ -99,7 +96,11 @@ class MainActivity : ComponentActivity() { @Composable fun AccountSelectionScreen(accounts: List, onAccountClick: (Account) -> Unit, onAddAccountClick: () -> Unit) { LazyColumn( - modifier = Modifier.fillMaxSize().padding(16.dp).statusBarsPadding(), + modifier = Modifier + .fillMaxSize() + .padding(16.dp) + .statusBarsPadding() + .navigationBarsPadding(), verticalArrangement = Arrangement.spacedBy(12.dp) ) { item { @@ -131,19 +132,44 @@ fun AccountSelectionScreen(accounts: List, onAccountClick: (Account) -> } @Composable -fun LoginScreen(onLogin: (UUID) -> Unit) { - var userId by remember { mutableStateOf("") } +fun LoginScreen(onLogin: (String, String, String) -> Unit) { + var serverUrl by remember { mutableStateOf("") } + var username by remember { mutableStateOf("") } + var password by remember { mutableStateOf("") } - Column(modifier = Modifier.padding(16.dp).statusBarsPadding()) { + Column(modifier = Modifier.padding(16.dp).statusBarsPadding().navigationBarsPadding()) { Text("Bitte anmelden") Spacer(modifier = Modifier.height(8.dp)) + + //Home-Server TextField( - value = userId, - onValueChange = { userId = it }, - label = { Text("User ID") } + value = serverUrl, + onValueChange = { serverUrl = it }, + label = { Text("Server-URL") } ) Spacer(modifier = Modifier.height(8.dp)) - Button(onClick = { if(userId.isNotEmpty()) onLogin(UUID.fromString(userId)) }) { + + //Username + TextField( + value = username, + onValueChange = { username = it }, + label = { Text("Nutzername") } + ) + Spacer(modifier = Modifier.height(8.dp)) + + //Password + TextField( + value = password, + onValueChange = { password = it }, + label = { Text("Passwort") } + ) + Spacer(modifier = Modifier.height(8.dp)) + + Button(onClick = { if(serverUrl.isNotEmpty() && username.isNotEmpty() && password.isNotEmpty()) onLogin( + serverUrl, + username, + password + ) }) { Text("Login") } } @@ -156,6 +182,7 @@ fun DashboardScreen(account: Account, onBack: () -> Unit) { .fillMaxSize() .padding(16.dp) .statusBarsPadding() + .navigationBarsPadding() ) { Row( modifier = Modifier.fillMaxWidth(), diff --git a/app/src/main/java/de/miaurizius/shap_planner/entities/Account.kt b/app/src/main/java/de/miaurizius/shap_planner/entities/Account.kt index 415566c..02dcaf6 100644 --- a/app/src/main/java/de/miaurizius/shap_planner/entities/Account.kt +++ b/app/src/main/java/de/miaurizius/shap_planner/entities/Account.kt @@ -15,7 +15,8 @@ data class Account ( @PrimaryKey val id: UUID, val name: String, val wgName: String, - val avatarUrl: String? = null + val avatarUrl: String? = null, + val serverUrl: String, ) @Dao diff --git a/app/src/main/java/de/miaurizius/shap_planner/viewmodels/LoginViewModel.kt b/app/src/main/java/de/miaurizius/shap_planner/viewmodels/LoginViewModel.kt index e1ed193..dd376b5 100644 --- a/app/src/main/java/de/miaurizius/shap_planner/viewmodels/LoginViewModel.kt +++ b/app/src/main/java/de/miaurizius/shap_planner/viewmodels/LoginViewModel.kt @@ -3,17 +3,23 @@ package de.miaurizius.shap_planner.viewmodels import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import de.miaurizius.shap_planner.UserPreferences +import de.miaurizius.shap_planner.entities.Account import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import java.util.UUID class LoginViewModel(private val prefs: UserPreferences) : ViewModel() { val isLoggedIn = prefs.isLoggedInFlow.stateIn(viewModelScope, SharingStarted.Lazily, false) val lastUserId = prefs.lastUserLoginFlow.stateIn(viewModelScope, SharingStarted.Lazily, null) - fun login(userId: String) { - viewModelScope.launch { prefs.saveLogin(userId) } + fun login(serverUrl: String, username: String, password: String, viewModel: MainViewModel) { + val uuid = UUID.randomUUID(); + val acc = Account(uuid, username, "Pfadi-WG", null, serverUrl) //TODO: get data from backend + viewModel.addAccount(acc) + println("Logged in as ${username} in ${serverUrl}") + viewModelScope.launch { prefs.saveLogin(uuid.toString()) } } fun logout() {