Show loading indicator while connecting, delay error display

Display a CircularProgressIndicator with "Connecting..." text during
initial connection attempts. Only show the connection error message
after 10 seconds of failed attempts to improve user experience.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
vesp 2025-11-21 17:01:10 +01:00
parent 581487a29d
commit 89c291e11e
2 changed files with 49 additions and 2 deletions

View File

@ -93,6 +93,8 @@ fun MainScreen(
) { ) {
if (uiState.serverAddress.isBlank()) { if (uiState.serverAddress.isBlank()) {
NoServerConfigured(onNavigateToSettings) NoServerConfigured(onNavigateToSettings)
} else if (!uiState.isConnected && uiState.isConnecting) {
ConnectingIndicator()
} else if (!uiState.isConnected) { } else if (!uiState.isConnected) {
ConnectionError( ConnectionError(
errorMessage = uiState.errorMessage, errorMessage = uiState.errorMessage,
@ -159,6 +161,26 @@ private fun NoServerConfigured(onNavigateToSettings: () -> Unit) {
} }
} }
@Composable
private fun ConnectingIndicator() {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
CircularProgressIndicator(
modifier = Modifier.size(64.dp),
color = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "Connecting...",
style = MaterialTheme.typography.headlineSmall,
fontWeight = FontWeight.Bold
)
}
}
@Composable @Composable
private fun ConnectionError( private fun ConnectionError(
errorMessage: String?, errorMessage: String?,

View File

@ -22,6 +22,7 @@ import javax.inject.Inject
data class MainUiState( data class MainUiState(
val isLoading: Boolean = false, val isLoading: Boolean = false,
val isConnected: Boolean = false, val isConnected: Boolean = false,
val isConnecting: Boolean = true, // Show loading while waiting for connection
val errorMessage: String? = null, val errorMessage: String? = null,
val serverAddress: String = "", val serverAddress: String = "",
val karadioStatus: KaradioStatus = KaradioStatus(), val karadioStatus: KaradioStatus = KaradioStatus(),
@ -43,16 +44,24 @@ class MainViewModel @Inject constructor(
private var pollingJob: Job? = null private var pollingJob: Job? = null
private var lastStationName: String? = null private var lastStationName: String? = null
private var connectionFailedSince: Long? = null
companion object {
private const val ERROR_DISPLAY_DELAY_MS = 10_000L // 10 seconds
}
init { init {
viewModelScope.launch { viewModelScope.launch {
settingsRepository.settings.collect { settings -> settingsRepository.settings.collect { settings ->
_uiState.update { it.copy(serverAddress = settings.serverAddress) } _uiState.update { it.copy(serverAddress = settings.serverAddress) }
if (settings.serverAddress.isNotBlank()) { if (settings.serverAddress.isNotBlank()) {
// Reset failure tracking when server address changes
connectionFailedSince = null
_uiState.update { it.copy(isConnecting = true, errorMessage = null) }
startPolling() startPolling()
} else { } else {
stopPolling() stopPolling()
_uiState.update { it.copy(isConnected = false) } _uiState.update { it.copy(isConnected = false, isConnecting = false) }
} }
} }
} }
@ -80,9 +89,12 @@ class MainViewModel @Inject constructor(
karadioRepository.getStatus(serverAddress) karadioRepository.getStatus(serverAddress)
.onSuccess { status -> .onSuccess { status ->
// Connection successful - reset failure tracking
connectionFailedSince = null
_uiState.update { _uiState.update {
it.copy( it.copy(
isConnected = true, isConnected = true,
isConnecting = false,
errorMessage = null, errorMessage = null,
karadioStatus = status karadioStatus = status
) )
@ -95,10 +107,23 @@ class MainViewModel @Inject constructor(
} }
} }
.onFailure { error -> .onFailure { error ->
val now = System.currentTimeMillis()
// Start tracking failure time if this is the first failure
if (connectionFailedSince == null) {
connectionFailedSince = now
}
val failureDuration = now - (connectionFailedSince ?: now)
val shouldShowError = failureDuration >= ERROR_DISPLAY_DELAY_MS
_uiState.update { _uiState.update {
it.copy( it.copy(
isConnected = false, isConnected = false,
errorMessage = "Connection failed: ${error.localizedMessage}" isConnecting = !shouldShowError,
errorMessage = if (shouldShowError) {
"Connection failed: ${error.localizedMessage}"
} else null
) )
} }
} }