Spårning: fixa fasbytet (stale state) + loggvisaren till inställningarna
All checks were successful
release / build-release (push) Successful in 4m12s

- onLocationChanged skrev tillbaka ett gammalt state-snapshot och nollade
  SEARCHING→ACTIVE-övergången — klockan stod kvar på 00:00 trots fix
  (syntes som dubbla 'aktiverad'-rader i loggen). Nu utgår slutskrivningen
  från aktuellt state.
- Teknisk spårningslogg är nu en switch under Inställningar → Felsökning,
  av som standard. Version 0.8.2.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C2GA94E1f3cmrvdQLQhYdg
This commit is contained in:
2026-08-25 09:44:54 +02:00
parent dcb91f587d
commit edbd16464d
5 changed files with 50 additions and 6 deletions

View File

@@ -32,6 +32,8 @@ data class AppSettings(
val birthYear: Int? = null,
/** null = inte satt, false = man, true = kvinna */
val isFemale: Boolean? = null,
/** Visa teknisk logg på spårskärmen (felsökning) */
val trackLogEnabled: Boolean = false,
)
class SettingsStore(private val context: Context) {
@@ -58,9 +60,14 @@ class SettingsStore(private val context: Context) {
heightCm = prefs[KEY_HEIGHT_CM]?.toDoubleOrNull(),
birthYear = prefs[KEY_BIRTH_YEAR],
isFemale = prefs[KEY_IS_FEMALE]?.toBooleanStrictOrNull(),
trackLogEnabled = prefs[KEY_TRACK_LOG]?.toBooleanStrictOrNull() ?: false,
)
}
suspend fun setTrackLogEnabled(value: Boolean) {
context.settingsDataStore.edit { it[KEY_TRACK_LOG] = value.toString() }
}
suspend fun setScale(address: String?, name: String?, driver: String?) {
context.settingsDataStore.edit { prefs ->
if (address == null) {
@@ -132,5 +139,6 @@ class SettingsStore(private val context: Context) {
private val KEY_HEIGHT_CM = stringPreferencesKey("height_cm")
private val KEY_BIRTH_YEAR = intPreferencesKey("birth_year")
private val KEY_IS_FEMALE = stringPreferencesKey("is_female")
private val KEY_TRACK_LOG = stringPreferencesKey("track_log_enabled")
}
}

View File

@@ -251,10 +251,13 @@ class TrackingService : Service(), LocationListener {
}
lastLocation = location
_state.value = s.copy(
// Utgå från AKTUELLT state (inte snapshotet från funktionens start) —
// annars skrivs t.ex. fasbytet till ACTIVE över och klockan står still.
val cur = _state.value
_state.value = cur.copy(
distanceMeters = distance,
elevationGainMeters = elevGain,
points = s.points + (location.latitude to location.longitude),
points = cur.points + (location.latitude to location.longitude),
currentSpeedKmh = if (location.hasSpeed()) location.speed * 3.6 else null,
gpsFix = true,
)

View File

@@ -71,6 +71,8 @@ class SettingsViewModel(
fun addCustomBar(value: Double) = viewModelScope.launch { store.addCustomBarWeight(value) }
fun removeCustomBar(value: Double) = viewModelScope.launch { store.removeCustomBarWeight(value) }
fun setTrackLog(value: Boolean) = viewModelScope.launch { store.setTrackLogEnabled(value) }
fun setAutoRelogin(value: Boolean) = viewModelScope.launch {
store.setAutoRelogin(value)
// Stängs funktionen av slängs de sparade uppgifterna direkt.
@@ -145,6 +147,28 @@ fun SettingsScreen(
}
}
SettingsCard(title = "Felsökning") {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 6.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Column(modifier = Modifier.weight(1f)) {
Text("Teknisk spårningslogg", style = MaterialTheme.typography.bodyLarge)
Text(
"Visar GPS-loggen på aktivitetsskärmen (för felsökning).",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
androidx.compose.material3.Switch(
checked = settings.trackLogEnabled,
onCheckedChange = viewModel::setTrackLog,
)
}
}
SettingsCard(title = "Vilotimerns utseende") {
RadioRow(
label = "Helskärm",

View File

@@ -67,6 +67,7 @@ import eu.brassepc.fitnessdroid.ui.appContainer
import eu.brassepc.fitnessdroid.ui.common.compact
import eu.brassepc.fitnessdroid.ui.common.openAppSettings
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.osmdroid.config.Configuration
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
@@ -79,8 +80,11 @@ import java.time.Instant
class TrackViewModel(
private val gymApi: GymApi,
private val repo: GymRepository,
settingsStore: eu.brassepc.fitnessdroid.data.SettingsStore,
) : ViewModel() {
val tracking = TrackingService.state
/** Teknisk logg visas bara om den slagits på i inställningarna. */
val logEnabled = settingsStore.settings.map { it.trackLogEnabled }
val message = MutableStateFlow<String?>(null)
val saved = MutableStateFlow(false)
/** Sammanfattningen som visas efter stopp (null = spårning pågår/ej startad) */
@@ -168,7 +172,7 @@ class TrackViewModel(
val Factory: ViewModelProvider.Factory = viewModelFactory {
initializer {
val c = appContainer()
TrackViewModel(c.gymApi, c.gymRepository)
TrackViewModel(c.gymApi, c.gymRepository, c.settingsStore)
}
}
}
@@ -186,6 +190,7 @@ fun TrackScreen(
val summary by viewModel.summary.collectAsStateWithLifecycle()
val saved by viewModel.saved.collectAsStateWithLifecycle()
val message by viewModel.message.collectAsStateWithLifecycle()
val logEnabled by viewModel.logEnabled.collectAsStateWithLifecycle(false)
val pendingType by viewModel.pendingType.collectAsStateWithLifecycle()
val typeLoadError by viewModel.typeLoadError.collectAsStateWithLifecycle()
@@ -276,6 +281,7 @@ fun TrackScreen(
message = message,
onSave = { rpe, overrideId -> viewModel.save(rpe, overrideId) },
onDone = onBack,
showLog = logEnabled,
)
permissionDenied -> Column(
modifier = Modifier.padding(16.dp),
@@ -323,6 +329,7 @@ fun TrackScreen(
tracking = tracking,
onStop = { viewModel.stop(context) },
onStartAnyway = { TrackingService.startNow(context) },
showLog = logEnabled,
)
}
}
@@ -334,6 +341,7 @@ private fun LiveContent(
tracking: TrackingState,
onStop: () -> Unit,
onStartAnyway: () -> Unit,
showLog: Boolean,
) {
Column(modifier = Modifier.fillMaxSize()) {
if (tracking.isDistanceBased) {
@@ -424,7 +432,7 @@ private fun LiveContent(
Icon(Icons.Default.Stop, contentDescription = null)
Text("Avsluta aktiviteten", modifier = Modifier.padding(start = 6.dp))
}
TechLogSection()
if (showLog) TechLogSection()
}
}
}
@@ -561,6 +569,7 @@ private fun SummaryContent(
message: String?,
onSave: (Double?, Int?) -> Unit,
onDone: () -> Unit,
showLog: Boolean,
) {
var rpe by remember { mutableStateOf(5f) }
@@ -635,7 +644,7 @@ private fun SummaryContent(
message?.let { Text(it, color = MaterialTheme.colorScheme.error) }
TechLogSection()
if (showLog) TechLogSection()
if (saved) {
Text(