feat(settings): server-sync UI aufräumen (#108)
- Login-Status + Logout auf eigene ElevatedCard - Logout-Button als OutlinedButton (Material-Button statt TextLink) - Letzte Sync direkt unter Verbindungsstatus ohne Divider - Refresh-IconButton neben Serverstatus entfernt - Server-URL Reset nur sichtbar wenn nicht-default Adresse - Manuelle Sync-Buttons entfernt (vollautomatisch)
This commit is contained in:
parent
bdd8cb4b11
commit
887cdbd3f7
1 changed files with 55 additions and 81 deletions
|
|
@ -21,7 +21,6 @@ import androidx.compose.foundation.rememberScrollState
|
|||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Refresh
|
||||
import androidx.compose.material.icons.filled.SystemUpdate
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
|
|
@ -31,7 +30,6 @@ import androidx.compose.material3.ElevatedCard
|
|||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
|
|
@ -290,31 +288,32 @@ internal fun SettingsScreen(
|
|||
singleLine = true,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
IconButton(onClick = viewModel::resetServerUrl) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Refresh,
|
||||
contentDescription = "Standard-Server wiederherstellen"
|
||||
)
|
||||
val isNonDefaultUrl = uiState.serverUrl != de.bollwerk.app.domain.model.SettingsKey.DEFAULT_SERVER_URL
|
||||
if (isNonDefaultUrl) {
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
TextButton(onClick = viewModel::resetServerUrl) {
|
||||
Text("Reset")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
if (uiState.isLoggedIn) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Text(
|
||||
text = "Angemeldet als: ${uiState.loggedInUsername}",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
TextButton(onClick = viewModel::logout) {
|
||||
Text("Abmelden")
|
||||
ElevatedCard(modifier = Modifier.fillMaxWidth()) {
|
||||
Column(modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp)) {
|
||||
Text(
|
||||
text = "Angemeldet als: ${uiState.loggedInUsername}",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
OutlinedButton(
|
||||
onClick = viewModel::logout,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text("Abmelden")
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -367,15 +366,7 @@ internal fun SettingsScreen(
|
|||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
val isSyncEnabled = uiState.isLoggedIn &&
|
||||
uiState.serverUrl.isNotBlank() &&
|
||||
!uiState.isSyncing
|
||||
|
||||
SyncStatusCard(
|
||||
uiState = uiState,
|
||||
isSyncEnabled = isSyncEnabled,
|
||||
onSyncClick = viewModel::pullSync
|
||||
)
|
||||
SyncStatusCard(uiState = uiState)
|
||||
|
||||
if (de.bollwerk.app.BuildConfig.FEATURE_CAMERA_ENABLED) {
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
|
|
@ -549,65 +540,56 @@ internal fun SettingsScreen(
|
|||
|
||||
@Composable
|
||||
private fun SyncStatusCard(
|
||||
uiState: SettingsUiState,
|
||||
isSyncEnabled: Boolean,
|
||||
onSyncClick: () -> Unit
|
||||
uiState: SettingsUiState
|
||||
) {
|
||||
ElevatedCard(modifier = Modifier.fillMaxWidth()) {
|
||||
Column(modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp)) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp)
|
||||
) {
|
||||
val (dotColor, statusText) = when (uiState.connectionState) {
|
||||
is ConnectionState.Connected -> Color(0xFF4CAF50) to "Verbunden"
|
||||
is ConnectionState.Connecting -> Color(0xFFFFC107) to "Verbinde…"
|
||||
is ConnectionState.Disconnected -> Color(0xFFF44336) to "Keine Verbindung"
|
||||
is ConnectionState.NotConfigured -> Color.Gray to "Nicht angemeldet"
|
||||
}
|
||||
val disconnectedSeconds =
|
||||
(uiState.connectionState as? ConnectionState.Disconnected)?.reconnectInSeconds
|
||||
val (dotColor, statusText) = when (uiState.connectionState) {
|
||||
is ConnectionState.Connected -> Color(0xFF4CAF50) to "Verbunden"
|
||||
is ConnectionState.Connecting -> Color(0xFFFFC107) to "Verbinde…"
|
||||
is ConnectionState.Disconnected -> Color(0xFFF44336) to "Keine Verbindung"
|
||||
is ConnectionState.NotConfigured -> Color.Gray to "Nicht angemeldet"
|
||||
}
|
||||
val disconnectedSeconds =
|
||||
(uiState.connectionState as? ConnectionState.Disconnected)?.reconnectInSeconds
|
||||
Text(
|
||||
text = "●",
|
||||
color = dotColor,
|
||||
style = MaterialTheme.typography.bodyLarge
|
||||
)
|
||||
Column {
|
||||
Text(
|
||||
text = "●",
|
||||
color = dotColor,
|
||||
style = MaterialTheme.typography.bodyLarge
|
||||
text = statusText,
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
Column {
|
||||
if (disconnectedSeconds != null) {
|
||||
Text(
|
||||
text = statusText,
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
text = "Nächster Versuch in $disconnectedSeconds Sek.",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
if (disconnectedSeconds != null) {
|
||||
Text(
|
||||
text = "Nächster Versuch in $disconnectedSeconds Sek.",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uiState.isSyncing) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(24.dp),
|
||||
strokeWidth = 2.dp
|
||||
)
|
||||
} else {
|
||||
IconButton(
|
||||
onClick = onSyncClick,
|
||||
enabled = isSyncEnabled
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Refresh,
|
||||
contentDescription = "Jetzt synchronisieren"
|
||||
if (uiState.lastSyncTime != null) {
|
||||
Text(
|
||||
text = "Letzte Sync: ${uiState.lastSyncTime}",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uiState.isSyncing) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(24.dp),
|
||||
strokeWidth = 2.dp
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = uiState.syncActivity != null,
|
||||
enter = fadeIn(),
|
||||
|
|
@ -623,14 +605,6 @@ private fun SyncStatusCard(
|
|||
)
|
||||
}
|
||||
}
|
||||
if (uiState.lastSyncTime != null) {
|
||||
HorizontalDivider(modifier = Modifier.padding(top = 12.dp, bottom = 8.dp))
|
||||
Text(
|
||||
text = "Letzte Synchronisierung: ${uiState.lastSyncTime}",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue