Compare commits

..

No commits in common. "cbe363066cbe6f14f4e02c3a9014f5aabe7ac447" and "05e14147d927a3d8972630fbbaadcad008f4308e" have entirely different histories.

5 changed files with 12 additions and 42 deletions

2
.gitignore vendored
View File

@ -10,5 +10,3 @@
.externalNativeBuild .externalNativeBuild
.cxx .cxx
local.properties local.properties
keystore.properties
*.jks

View File

@ -9,7 +9,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
JAVA_HOME=/path/to/jdk-17 ./gradlew assembleDebug JAVA_HOME=/path/to/jdk-17 ./gradlew assembleDebug
# Build release APK # Build release APK
JAVA_HOME=/home/pavelb/Stažené/jdk-17.0.15+6 ./gradlew assembleRelease JAVA_HOME=/path/to/jdk-17 ./gradlew assembleRelease
# Run unit tests # Run unit tests
./gradlew test ./gradlew test

View File

@ -7,33 +7,16 @@ plugins {
alias(libs.plugins.ksp) alias(libs.plugins.ksp)
} }
import java.util.Properties
val keystorePropertiesFile = rootProject.file("keystore.properties")
val keystoreProperties = Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(keystorePropertiesFile.inputStream())
}
android { android {
namespace = "cz.bugsy.karemote" namespace = "cz.bugsy.karemote"
compileSdk = 36 compileSdk = 36
signingConfigs {
create("release") {
storeFile = rootProject.file(keystoreProperties["storeFile"] as String)
storePassword = keystoreProperties["storePassword"] as String?
keyAlias = keystoreProperties["keyAlias"] as String?
keyPassword = keystoreProperties["keyPassword"] as String?
}
}
defaultConfig { defaultConfig {
applicationId = "cz.bugsy.karemote" applicationId = "cz.bugsy.karemote"
minSdk = 33 minSdk = 33
targetSdk = 36 targetSdk = 36
versionCode = 2 versionCode = 1
versionName = "1.1" versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables { vectorDrawables {
@ -48,7 +31,6 @@ android {
getDefaultProguardFile("proguard-android-optimize.txt"), getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro" "proguard-rules.pro"
) )
signingConfig = signingConfigs.getByName("release")
} }
} }
compileOptions { compileOptions {
@ -60,7 +42,6 @@ android {
} }
buildFeatures { buildFeatures {
compose = true compose = true
buildConfig = true
} }
packaging { packaging {
resources { resources {

View File

@ -65,7 +65,6 @@ 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 private var connectionFailedSince: Long? = null
private var consecutiveFailures: Int = 0
private var volumeJob: Job? = null private var volumeJob: Job? = null
private var lastVolumeSentTime: Long = 0 private var lastVolumeSentTime: Long = 0
private var pendingVolume: Int? = null private var pendingVolume: Int? = null
@ -73,7 +72,6 @@ class MainViewModel @Inject constructor(
companion object { companion object {
private const val ERROR_DISPLAY_DELAY_MS = 10_000L // 10 seconds private const val ERROR_DISPLAY_DELAY_MS = 10_000L // 10 seconds
private const val VOLUME_THROTTLE_MS = 300L // Throttle volume commands private const val VOLUME_THROTTLE_MS = 300L // Throttle volume commands
private const val DISCONNECT_THRESHOLD = 3 // Consecutive failures before marking disconnected
} }
init { init {
@ -83,7 +81,6 @@ class MainViewModel @Inject constructor(
if (settings.serverAddress.isNotBlank()) { if (settings.serverAddress.isNotBlank()) {
// Reset failure tracking when server address changes // Reset failure tracking when server address changes
connectionFailedSince = null connectionFailedSince = null
consecutiveFailures = 0
_uiState.update { it.copy(isConnecting = true, errorMessage = null) } _uiState.update { it.copy(isConnecting = true, errorMessage = null) }
startPolling() startPolling()
} else { } else {
@ -118,7 +115,6 @@ class MainViewModel @Inject constructor(
.onSuccess { status -> .onSuccess { status ->
// Connection successful - reset failure tracking // Connection successful - reset failure tracking
connectionFailedSince = null connectionFailedSince = null
consecutiveFailures = 0
_uiState.update { _uiState.update {
it.copy( it.copy(
isConnected = true, isConnected = true,
@ -135,7 +131,6 @@ class MainViewModel @Inject constructor(
} }
} }
.onFailure { error -> .onFailure { error ->
consecutiveFailures++
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
// Start tracking failure time if this is the first failure // Start tracking failure time if this is the first failure
@ -146,18 +141,14 @@ class MainViewModel @Inject constructor(
val failureDuration = now - (connectionFailedSince ?: now) val failureDuration = now - (connectionFailedSince ?: now)
val shouldShowError = failureDuration >= ERROR_DISPLAY_DELAY_MS val shouldShowError = failureDuration >= ERROR_DISPLAY_DELAY_MS
// Only mark as disconnected after multiple consecutive failures _uiState.update {
// to avoid flapping when ESP32 has intermittent errors it.copy(
if (consecutiveFailures >= DISCONNECT_THRESHOLD) { isConnected = false,
_uiState.update { isConnecting = !shouldShowError,
it.copy( errorMessage = if (shouldShowError) {
isConnected = false, "Connection failed: ${error.localizedMessage}"
isConnecting = !shouldShowError, } else null
errorMessage = if (shouldShowError) { )
"Connection failed: ${error.localizedMessage}"
} else null
)
}
} }
} }
} }

View File

@ -206,7 +206,7 @@ fun SettingsScreen(
) )
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
Text( Text(
text = "Version ${cz.bugsy.karemote.BuildConfig.VERSION_NAME}", text = "Version 1.0",
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )