Extended Login and UI</div>

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`.
This commit is contained in:
2026-02-21 00:20:40 +01:00
parent 885d95991e
commit 9e0101642a
3 changed files with 50 additions and 16 deletions

View File

@@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
@@ -65,11 +66,7 @@ class MainActivity : ComponentActivity() {
when { when {
!isLoggedIn || accountList.isEmpty() -> { !isLoggedIn || accountList.isEmpty() -> {
LoginScreen { userId -> LoginScreen { serverUrl, username, password -> loginViewModel.login(serverUrl, username, password, mainViewModel) }
val acc = Account(userId, "MiauRizius", "Pfadi-WG") //TODO: get data from backend
mainViewModel.addAccount(acc)
loginViewModel.login(acc.id.toString())
}
} }
selectedAccount != null -> { selectedAccount != null -> {
@@ -99,7 +96,11 @@ class MainActivity : ComponentActivity() {
@Composable @Composable
fun AccountSelectionScreen(accounts: List<Account>, onAccountClick: (Account) -> Unit, onAddAccountClick: () -> Unit) { fun AccountSelectionScreen(accounts: List<Account>, onAccountClick: (Account) -> Unit, onAddAccountClick: () -> Unit) {
LazyColumn( LazyColumn(
modifier = Modifier.fillMaxSize().padding(16.dp).statusBarsPadding(), modifier = Modifier
.fillMaxSize()
.padding(16.dp)
.statusBarsPadding()
.navigationBarsPadding(),
verticalArrangement = Arrangement.spacedBy(12.dp) verticalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
item { item {
@@ -131,19 +132,44 @@ fun AccountSelectionScreen(accounts: List<Account>, onAccountClick: (Account) ->
} }
@Composable @Composable
fun LoginScreen(onLogin: (UUID) -> Unit) { fun LoginScreen(onLogin: (String, String, String) -> Unit) {
var userId by remember { mutableStateOf("") } 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") Text("Bitte anmelden")
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
//Home-Server
TextField( TextField(
value = userId, value = serverUrl,
onValueChange = { userId = it }, onValueChange = { serverUrl = it },
label = { Text("User ID") } label = { Text("Server-URL") }
) )
Spacer(modifier = Modifier.height(8.dp)) 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") Text("Login")
} }
} }
@@ -156,6 +182,7 @@ fun DashboardScreen(account: Account, onBack: () -> Unit) {
.fillMaxSize() .fillMaxSize()
.padding(16.dp) .padding(16.dp)
.statusBarsPadding() .statusBarsPadding()
.navigationBarsPadding()
) { ) {
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),

View File

@@ -15,7 +15,8 @@ data class Account (
@PrimaryKey val id: UUID, @PrimaryKey val id: UUID,
val name: String, val name: String,
val wgName: String, val wgName: String,
val avatarUrl: String? = null val avatarUrl: String? = null,
val serverUrl: String,
) )
@Dao @Dao

View File

@@ -3,17 +3,23 @@ package de.miaurizius.shap_planner.viewmodels
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.miaurizius.shap_planner.UserPreferences import de.miaurizius.shap_planner.UserPreferences
import de.miaurizius.shap_planner.entities.Account
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.util.UUID
class LoginViewModel(private val prefs: UserPreferences) : ViewModel() { class LoginViewModel(private val prefs: UserPreferences) : ViewModel() {
val isLoggedIn = prefs.isLoggedInFlow.stateIn(viewModelScope, SharingStarted.Lazily, false) val isLoggedIn = prefs.isLoggedInFlow.stateIn(viewModelScope, SharingStarted.Lazily, false)
val lastUserId = prefs.lastUserLoginFlow.stateIn(viewModelScope, SharingStarted.Lazily, null) val lastUserId = prefs.lastUserLoginFlow.stateIn(viewModelScope, SharingStarted.Lazily, null)
fun login(userId: String) { fun login(serverUrl: String, username: String, password: String, viewModel: MainViewModel) {
viewModelScope.launch { prefs.saveLogin(userId) } 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() { fun logout() {