Compare commits
4 Commits
05e14147d9
...
cbe363066c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbe363066c | ||
|
|
974c529830 | ||
|
|
b45d4ab473 | ||
|
|
2f64d509d0 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -10,3 +10,5 @@
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
keystore.properties
|
||||
*.jks
|
||||
|
||||
@ -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
|
||||
|
||||
# Build release APK
|
||||
JAVA_HOME=/path/to/jdk-17 ./gradlew assembleRelease
|
||||
JAVA_HOME=/home/pavelb/Stažené/jdk-17.0.15+6 ./gradlew assembleRelease
|
||||
|
||||
# Run unit tests
|
||||
./gradlew test
|
||||
|
||||
@ -7,16 +7,33 @@ plugins {
|
||||
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 {
|
||||
namespace = "cz.bugsy.karemote"
|
||||
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 {
|
||||
applicationId = "cz.bugsy.karemote"
|
||||
minSdk = 33
|
||||
targetSdk = 36
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
versionCode = 2
|
||||
versionName = "1.1"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
@ -31,6 +48,7 @@ android {
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
@ -42,6 +60,7 @@ android {
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
buildConfig = true
|
||||
}
|
||||
packaging {
|
||||
resources {
|
||||
|
||||
@ -65,6 +65,7 @@ class MainViewModel @Inject constructor(
|
||||
private var pollingJob: Job? = null
|
||||
private var lastStationName: String? = null
|
||||
private var connectionFailedSince: Long? = null
|
||||
private var consecutiveFailures: Int = 0
|
||||
private var volumeJob: Job? = null
|
||||
private var lastVolumeSentTime: Long = 0
|
||||
private var pendingVolume: Int? = null
|
||||
@ -72,6 +73,7 @@ class MainViewModel @Inject constructor(
|
||||
companion object {
|
||||
private const val ERROR_DISPLAY_DELAY_MS = 10_000L // 10 seconds
|
||||
private const val VOLUME_THROTTLE_MS = 300L // Throttle volume commands
|
||||
private const val DISCONNECT_THRESHOLD = 3 // Consecutive failures before marking disconnected
|
||||
}
|
||||
|
||||
init {
|
||||
@ -81,6 +83,7 @@ class MainViewModel @Inject constructor(
|
||||
if (settings.serverAddress.isNotBlank()) {
|
||||
// Reset failure tracking when server address changes
|
||||
connectionFailedSince = null
|
||||
consecutiveFailures = 0
|
||||
_uiState.update { it.copy(isConnecting = true, errorMessage = null) }
|
||||
startPolling()
|
||||
} else {
|
||||
@ -115,6 +118,7 @@ class MainViewModel @Inject constructor(
|
||||
.onSuccess { status ->
|
||||
// Connection successful - reset failure tracking
|
||||
connectionFailedSince = null
|
||||
consecutiveFailures = 0
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isConnected = true,
|
||||
@ -131,6 +135,7 @@ class MainViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
.onFailure { error ->
|
||||
consecutiveFailures++
|
||||
val now = System.currentTimeMillis()
|
||||
|
||||
// Start tracking failure time if this is the first failure
|
||||
@ -141,6 +146,9 @@ class MainViewModel @Inject constructor(
|
||||
val failureDuration = now - (connectionFailedSince ?: now)
|
||||
val shouldShowError = failureDuration >= ERROR_DISPLAY_DELAY_MS
|
||||
|
||||
// Only mark as disconnected after multiple consecutive failures
|
||||
// to avoid flapping when ESP32 has intermittent errors
|
||||
if (consecutiveFailures >= DISCONNECT_THRESHOLD) {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isConnected = false,
|
||||
@ -153,6 +161,7 @@ class MainViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchRadioBrowserInfo(stationName: String) {
|
||||
viewModelScope.launch {
|
||||
|
||||
@ -206,7 +206,7 @@ fun SettingsScreen(
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = "Version 1.0",
|
||||
text = "Version ${cz.bugsy.karemote.BuildConfig.VERSION_NAME}",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user