diff --git a/app/src/main/java/cz/bugsy/karemote/ui/screens/main/MainScreen.kt b/app/src/main/java/cz/bugsy/karemote/ui/screens/main/MainScreen.kt index 9eb60cb..5aa1cb6 100644 --- a/app/src/main/java/cz/bugsy/karemote/ui/screens/main/MainScreen.kt +++ b/app/src/main/java/cz/bugsy/karemote/ui/screens/main/MainScreen.kt @@ -93,6 +93,8 @@ fun MainScreen( ) { if (uiState.serverAddress.isBlank()) { NoServerConfigured(onNavigateToSettings) + } else if (!uiState.isConnected && uiState.isConnecting) { + ConnectingIndicator() } else if (!uiState.isConnected) { ConnectionError( 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 private fun ConnectionError( errorMessage: String?, diff --git a/app/src/main/java/cz/bugsy/karemote/ui/screens/main/MainViewModel.kt b/app/src/main/java/cz/bugsy/karemote/ui/screens/main/MainViewModel.kt index 4bb3ed3..fa89a81 100644 --- a/app/src/main/java/cz/bugsy/karemote/ui/screens/main/MainViewModel.kt +++ b/app/src/main/java/cz/bugsy/karemote/ui/screens/main/MainViewModel.kt @@ -22,6 +22,7 @@ import javax.inject.Inject data class MainUiState( val isLoading: Boolean = false, val isConnected: Boolean = false, + val isConnecting: Boolean = true, // Show loading while waiting for connection val errorMessage: String? = null, val serverAddress: String = "", val karadioStatus: KaradioStatus = KaradioStatus(), @@ -43,16 +44,24 @@ class MainViewModel @Inject constructor( private var pollingJob: Job? = 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 { viewModelScope.launch { settingsRepository.settings.collect { settings -> _uiState.update { it.copy(serverAddress = settings.serverAddress) } if (settings.serverAddress.isNotBlank()) { + // Reset failure tracking when server address changes + connectionFailedSince = null + _uiState.update { it.copy(isConnecting = true, errorMessage = null) } startPolling() } else { 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) .onSuccess { status -> + // Connection successful - reset failure tracking + connectionFailedSince = null _uiState.update { it.copy( isConnected = true, + isConnecting = false, errorMessage = null, karadioStatus = status ) @@ -95,10 +107,23 @@ class MainViewModel @Inject constructor( } } .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 { it.copy( isConnected = false, - errorMessage = "Connection failed: ${error.localizedMessage}" + isConnecting = !shouldShowError, + errorMessage = if (shouldShowError) { + "Connection failed: ${error.localizedMessage}" + } else null ) } }