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.text.KeyboardOptions
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Refresh
|
|
||||||
import androidx.compose.material.icons.filled.SystemUpdate
|
import androidx.compose.material.icons.filled.SystemUpdate
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
|
|
@ -31,7 +30,6 @@ import androidx.compose.material3.ElevatedCard
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LinearProgressIndicator
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedButton
|
import androidx.compose.material3.OutlinedButton
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
|
@ -290,31 +288,32 @@ internal fun SettingsScreen(
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
val isNonDefaultUrl = uiState.serverUrl != de.bollwerk.app.domain.model.SettingsKey.DEFAULT_SERVER_URL
|
||||||
IconButton(onClick = viewModel::resetServerUrl) {
|
if (isNonDefaultUrl) {
|
||||||
Icon(
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
imageVector = Icons.Default.Refresh,
|
TextButton(onClick = viewModel::resetServerUrl) {
|
||||||
contentDescription = "Standard-Server wiederherstellen"
|
Text("Reset")
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
|
||||||
if (uiState.isLoggedIn) {
|
if (uiState.isLoggedIn) {
|
||||||
Row(
|
ElevatedCard(modifier = Modifier.fillMaxWidth()) {
|
||||||
modifier = Modifier.fillMaxWidth(),
|
Column(modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp)) {
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
Text(
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
text = "Angemeldet als: ${uiState.loggedInUsername}",
|
||||||
) {
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
Text(
|
color = MaterialTheme.colorScheme.primary
|
||||||
text = "Angemeldet als: ${uiState.loggedInUsername}",
|
)
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
color = MaterialTheme.colorScheme.primary,
|
OutlinedButton(
|
||||||
modifier = Modifier.weight(1f)
|
onClick = viewModel::logout,
|
||||||
)
|
modifier = Modifier.fillMaxWidth()
|
||||||
TextButton(onClick = viewModel::logout) {
|
) {
|
||||||
Text("Abmelden")
|
Text("Abmelden")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -367,15 +366,7 @@ internal fun SettingsScreen(
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
val isSyncEnabled = uiState.isLoggedIn &&
|
SyncStatusCard(uiState = uiState)
|
||||||
uiState.serverUrl.isNotBlank() &&
|
|
||||||
!uiState.isSyncing
|
|
||||||
|
|
||||||
SyncStatusCard(
|
|
||||||
uiState = uiState,
|
|
||||||
isSyncEnabled = isSyncEnabled,
|
|
||||||
onSyncClick = viewModel::pullSync
|
|
||||||
)
|
|
||||||
|
|
||||||
if (de.bollwerk.app.BuildConfig.FEATURE_CAMERA_ENABLED) {
|
if (de.bollwerk.app.BuildConfig.FEATURE_CAMERA_ENABLED) {
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
|
@ -549,65 +540,56 @@ internal fun SettingsScreen(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SyncStatusCard(
|
private fun SyncStatusCard(
|
||||||
uiState: SettingsUiState,
|
uiState: SettingsUiState
|
||||||
isSyncEnabled: Boolean,
|
|
||||||
onSyncClick: () -> Unit
|
|
||||||
) {
|
) {
|
||||||
ElevatedCard(modifier = Modifier.fillMaxWidth()) {
|
ElevatedCard(modifier = Modifier.fillMaxWidth()) {
|
||||||
Column(modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp)) {
|
Column(modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp)) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
horizontalArrangement = Arrangement.spacedBy(10.dp)
|
||||||
) {
|
) {
|
||||||
Row(
|
val (dotColor, statusText) = when (uiState.connectionState) {
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
is ConnectionState.Connected -> Color(0xFF4CAF50) to "Verbunden"
|
||||||
horizontalArrangement = Arrangement.spacedBy(10.dp)
|
is ConnectionState.Connecting -> Color(0xFFFFC107) to "Verbinde…"
|
||||||
) {
|
is ConnectionState.Disconnected -> Color(0xFFF44336) to "Keine Verbindung"
|
||||||
val (dotColor, statusText) = when (uiState.connectionState) {
|
is ConnectionState.NotConfigured -> Color.Gray to "Nicht angemeldet"
|
||||||
is ConnectionState.Connected -> Color(0xFF4CAF50) to "Verbunden"
|
}
|
||||||
is ConnectionState.Connecting -> Color(0xFFFFC107) to "Verbinde…"
|
val disconnectedSeconds =
|
||||||
is ConnectionState.Disconnected -> Color(0xFFF44336) to "Keine Verbindung"
|
(uiState.connectionState as? ConnectionState.Disconnected)?.reconnectInSeconds
|
||||||
is ConnectionState.NotConfigured -> Color.Gray to "Nicht angemeldet"
|
Text(
|
||||||
}
|
text = "●",
|
||||||
val disconnectedSeconds =
|
color = dotColor,
|
||||||
(uiState.connectionState as? ConnectionState.Disconnected)?.reconnectInSeconds
|
style = MaterialTheme.typography.bodyLarge
|
||||||
|
)
|
||||||
|
Column {
|
||||||
Text(
|
Text(
|
||||||
text = "●",
|
text = statusText,
|
||||||
color = dotColor,
|
style = MaterialTheme.typography.bodyMedium
|
||||||
style = MaterialTheme.typography.bodyLarge
|
|
||||||
)
|
)
|
||||||
Column {
|
if (disconnectedSeconds != null) {
|
||||||
Text(
|
Text(
|
||||||
text = statusText,
|
text = "Nächster Versuch in $disconnectedSeconds Sek.",
|
||||||
style = MaterialTheme.typography.bodyMedium
|
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.lastSyncTime != null) {
|
||||||
if (uiState.isSyncing) {
|
Text(
|
||||||
CircularProgressIndicator(
|
text = "Letzte Sync: ${uiState.lastSyncTime}",
|
||||||
modifier = Modifier.size(24.dp),
|
style = MaterialTheme.typography.bodySmall,
|
||||||
strokeWidth = 2.dp
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
)
|
|
||||||
} else {
|
|
||||||
IconButton(
|
|
||||||
onClick = onSyncClick,
|
|
||||||
enabled = isSyncEnabled
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Refresh,
|
|
||||||
contentDescription = "Jetzt synchronisieren"
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (uiState.isSyncing) {
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
CircularProgressIndicator(
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
strokeWidth = 2.dp
|
||||||
|
)
|
||||||
|
}
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = uiState.syncActivity != null,
|
visible = uiState.syncActivity != null,
|
||||||
enter = fadeIn(),
|
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