GPS-filter mot jitter: fartgrind (Doppler), stillastående-filter, baslinje-reset
All checks were successful
release / build-release (push) Successful in 4m19s
All checks were successful
release / build-release (push) Successful in 4m19s
Användarens idé i sensorriktig variant: GPS:ens egen Doppler-fartmätning (stabilare än positionerna) används som referens — - Fartgrind: positionshopp som kräver > faktor × Doppler-fart förkastas (t.ex. 100 m-hopp vid gångfart). Efter 4 förkastade i rad sätts ny baslinje (tunnel/underfart) utan att distans räknas. - Stillastående-filter: vandring < max(2 m, halva noggrannheten) räknas varken som distans eller spårpunkt — ingen fejkdistans när man står still. - Allt loggas i tekniska loggen (hopp, tillåten fart, förkastanden). Justerbart i Inställningar → GPS-spårning: noggrannhetsgräns (35 m), fartfaktor (2,0×), fartgolv (12 km/h). Version 0.8.3. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C2GA94E1f3cmrvdQLQhYdg
This commit is contained in:
@@ -29,7 +29,7 @@ android {
|
|||||||
minSdk = 31
|
minSdk = 31
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = ciRunNumber ?: 1
|
versionCode = ciRunNumber ?: 1
|
||||||
versionName = "0.8.2" + (ciRunNumber?.let { "+build.$it" } ?: "-dev")
|
versionName = "0.8.3" + (ciRunNumber?.let { "+build.$it" } ?: "-dev")
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ data class AppSettings(
|
|||||||
val isFemale: Boolean? = null,
|
val isFemale: Boolean? = null,
|
||||||
/** Visa teknisk logg på spårskärmen (felsökning) */
|
/** Visa teknisk logg på spårskärmen (felsökning) */
|
||||||
val trackLogEnabled: Boolean = false,
|
val trackLogEnabled: Boolean = false,
|
||||||
|
/** GPS-filter: förkasta fixar med sämre noggrannhet än detta (meter) */
|
||||||
|
val gpsAccuracyLimitM: Int = 35,
|
||||||
|
/** GPS-filter: max tillåten positionsfart som multipel av Doppler-farten */
|
||||||
|
val gpsSpeedFactor: Double = 2.0,
|
||||||
|
/** GPS-filter: fartgolv (km/h) när Doppler-fart saknas/är noll */
|
||||||
|
val gpsSpeedFloorKmh: Int = 12,
|
||||||
)
|
)
|
||||||
|
|
||||||
class SettingsStore(private val context: Context) {
|
class SettingsStore(private val context: Context) {
|
||||||
@@ -61,9 +67,24 @@ class SettingsStore(private val context: Context) {
|
|||||||
birthYear = prefs[KEY_BIRTH_YEAR],
|
birthYear = prefs[KEY_BIRTH_YEAR],
|
||||||
isFemale = prefs[KEY_IS_FEMALE]?.toBooleanStrictOrNull(),
|
isFemale = prefs[KEY_IS_FEMALE]?.toBooleanStrictOrNull(),
|
||||||
trackLogEnabled = prefs[KEY_TRACK_LOG]?.toBooleanStrictOrNull() ?: false,
|
trackLogEnabled = prefs[KEY_TRACK_LOG]?.toBooleanStrictOrNull() ?: false,
|
||||||
|
gpsAccuracyLimitM = prefs[KEY_GPS_ACC] ?: 35,
|
||||||
|
gpsSpeedFactor = prefs[KEY_GPS_FACTOR]?.toDoubleOrNull() ?: 2.0,
|
||||||
|
gpsSpeedFloorKmh = prefs[KEY_GPS_FLOOR] ?: 12,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun setGpsAccuracyLimit(value: Int) {
|
||||||
|
context.settingsDataStore.edit { it[KEY_GPS_ACC] = value.coerceIn(10, 100) }
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun setGpsSpeedFactor(value: Double) {
|
||||||
|
context.settingsDataStore.edit { it[KEY_GPS_FACTOR] = value.coerceIn(1.2, 5.0).toString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun setGpsSpeedFloor(value: Int) {
|
||||||
|
context.settingsDataStore.edit { it[KEY_GPS_FLOOR] = value.coerceIn(4, 40) }
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun setTrackLogEnabled(value: Boolean) {
|
suspend fun setTrackLogEnabled(value: Boolean) {
|
||||||
context.settingsDataStore.edit { it[KEY_TRACK_LOG] = value.toString() }
|
context.settingsDataStore.edit { it[KEY_TRACK_LOG] = value.toString() }
|
||||||
}
|
}
|
||||||
@@ -140,5 +161,8 @@ class SettingsStore(private val context: Context) {
|
|||||||
private val KEY_BIRTH_YEAR = intPreferencesKey("birth_year")
|
private val KEY_BIRTH_YEAR = intPreferencesKey("birth_year")
|
||||||
private val KEY_IS_FEMALE = stringPreferencesKey("is_female")
|
private val KEY_IS_FEMALE = stringPreferencesKey("is_female")
|
||||||
private val KEY_TRACK_LOG = stringPreferencesKey("track_log_enabled")
|
private val KEY_TRACK_LOG = stringPreferencesKey("track_log_enabled")
|
||||||
|
private val KEY_GPS_ACC = intPreferencesKey("gps_accuracy_limit_m")
|
||||||
|
private val KEY_GPS_FACTOR = stringPreferencesKey("gps_speed_factor")
|
||||||
|
private val KEY_GPS_FLOOR = intPreferencesKey("gps_speed_floor_kmh")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,13 @@ class TrackingService : Service(), LocationListener {
|
|||||||
private var weightKg: Double? = null
|
private var weightKg: Double? = null
|
||||||
private var activeSinceElapsed = 0L
|
private var activeSinceElapsed = 0L
|
||||||
private var lastLocation: Location? = null
|
private var lastLocation: Location? = null
|
||||||
|
// GPS-filter (justerbara i inställningarna, skickas med vid start)
|
||||||
|
private var accuracyLimitM = 35f
|
||||||
|
private var speedFactor = 2.0
|
||||||
|
private var speedFloorMs = 12.0 / 3.6
|
||||||
|
// Glidande Doppler-fart (m/s) — GPS:ens egen fartmätning, stabilare än positionerna
|
||||||
|
private var dopplerEmaMs = 0.0
|
||||||
|
private var rejectStreak = 0
|
||||||
// Glidande medel av höjd för att filtrera GPS-brus innan höjdmeter summeras
|
// Glidande medel av höjd för att filtrera GPS-brus innan höjdmeter summeras
|
||||||
private val altitudeWindow = ArrayDeque<Double>()
|
private val altitudeWindow = ArrayDeque<Double>()
|
||||||
private var smoothedAltitude: Double? = null
|
private var smoothedAltitude: Double? = null
|
||||||
@@ -99,6 +106,11 @@ class TrackingService : Service(), LocationListener {
|
|||||||
private fun startTracking(intent: Intent) {
|
private fun startTracking(intent: Intent) {
|
||||||
val distanceBased = intent.getBooleanExtra(EXTRA_DISTANCE_BASED, false)
|
val distanceBased = intent.getBooleanExtra(EXTRA_DISTANCE_BASED, false)
|
||||||
weightKg = intent.getDoubleExtra(EXTRA_WEIGHT_KG, -1.0).takeIf { it > 0 }
|
weightKg = intent.getDoubleExtra(EXTRA_WEIGHT_KG, -1.0).takeIf { it > 0 }
|
||||||
|
accuracyLimitM = intent.getIntExtra(EXTRA_GPS_ACC_LIMIT, 35).toFloat()
|
||||||
|
speedFactor = intent.getDoubleExtra(EXTRA_GPS_SPEED_FACTOR, 2.0)
|
||||||
|
speedFloorMs = intent.getIntExtra(EXTRA_GPS_SPEED_FLOOR, 12) / 3.6
|
||||||
|
dopplerEmaMs = 0.0
|
||||||
|
rejectStreak = 0
|
||||||
|
|
||||||
_state.value = TrackingState(
|
_state.value = TrackingState(
|
||||||
isActive = true,
|
isActive = true,
|
||||||
@@ -116,6 +128,12 @@ class TrackingService : Service(), LocationListener {
|
|||||||
"start: ${_state.value.typeName} (distans=$distanceBased, vikt=${weightKg ?: "?"} kg)" +
|
"start: ${_state.value.typeName} (distans=$distanceBased, vikt=${weightKg ?: "?"} kg)" +
|
||||||
if (distanceBased) " — väntar på GPS-fix" else ""
|
if (distanceBased) " — väntar på GPS-fix" else ""
|
||||||
)
|
)
|
||||||
|
if (distanceBased) {
|
||||||
|
TrackLog.log(
|
||||||
|
"filter: acc≤${accuracyLimitM.toInt()} m, fartgrind ${speedFactor}× Doppler " +
|
||||||
|
"(golv ${"%.0f".format(speedFloorMs * 3.6)} km/h)"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val type = if (distanceBased) {
|
val type = if (distanceBased) {
|
||||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION
|
ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION
|
||||||
@@ -217,11 +235,45 @@ class TrackingService : Service(), LocationListener {
|
|||||||
// Position för kartan uppdateras alltid, oavsett kvalitet
|
// Position för kartan uppdateras alltid, oavsett kvalitet
|
||||||
_state.value = _state.value.copy(currentPosition = location.latitude to location.longitude)
|
_state.value = _state.value.copy(currentPosition = location.latitude to location.longitude)
|
||||||
|
|
||||||
// Spårpunkter kräver hygglig noggrannhet
|
// Grind 1: spårpunkter kräver hygglig noggrannhet
|
||||||
if (location.hasAccuracy() && location.accuracy > 35f) {
|
if (location.hasAccuracy() && location.accuracy > accuracyLimitM) {
|
||||||
TrackLog.log("${location.provider}: förkastad för spåret, acc=${"%.0f".format(acc)} m (>35)")
|
TrackLog.log("${location.provider}: förkastad, acc=${"%.0f".format(acc)} m (>${accuracyLimitM.toInt()})")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Uppdatera glidande Doppler-fart (GPS:ens fartmätning via frekvensskift)
|
||||||
|
if (location.hasSpeed()) {
|
||||||
|
dopplerEmaMs = if (dopplerEmaMs == 0.0) location.speed.toDouble()
|
||||||
|
else 0.7 * dopplerEmaMs + 0.3 * location.speed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grind 2 (fartgrinden): en ny position som skulle kräva högre fart än
|
||||||
|
// speedFactor × Doppler-farten är orimlig — GPS-hopp, inte förflyttning.
|
||||||
|
lastLocation?.let { prev ->
|
||||||
|
val dtSec = (location.elapsedRealtimeNanos - prev.elapsedRealtimeNanos) / 1e9
|
||||||
|
if (dtSec > 0.3) {
|
||||||
|
val jump = prev.distanceTo(location).toDouble()
|
||||||
|
val impliedMs = jump / dtSec
|
||||||
|
val allowedMs = maxOf(speedFloorMs, dopplerEmaMs * speedFactor)
|
||||||
|
if (impliedMs > allowedMs) {
|
||||||
|
rejectStreak++
|
||||||
|
TrackLog.log(
|
||||||
|
"${location.provider}: fartgrind — hopp ${"%.0f".format(jump)} m på ${"%.1f".format(dtSec)} s " +
|
||||||
|
"= ${"%.1f".format(impliedMs * 3.6)} km/h (tillåtet ${"%.1f".format(allowedMs * 3.6)}), förkastad ($rejectStreak)"
|
||||||
|
)
|
||||||
|
// Många orimliga i rad = det är NYA positionen som är sann
|
||||||
|
// (t.ex. efter tunnel) — sätt ny baslinje utan att räkna distans.
|
||||||
|
if (rejectStreak >= 4) {
|
||||||
|
TrackLog.log("fartgrind: ny baslinje efter $rejectStreak förkastade")
|
||||||
|
lastLocation = location
|
||||||
|
rejectStreak = 0
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rejectStreak = 0
|
||||||
|
|
||||||
TrackLog.log(
|
TrackLog.log(
|
||||||
"${location.provider}: fix acc=${"%.0f".format(acc)} m" +
|
"${location.provider}: fix acc=${"%.0f".format(acc)} m" +
|
||||||
" alt=${if (location.hasAltitude()) "%.0f".format(location.altitude) else "?"}" +
|
" alt=${if (location.hasAltitude()) "%.0f".format(location.altitude) else "?"}" +
|
||||||
@@ -232,10 +284,13 @@ class TrackingService : Service(), LocationListener {
|
|||||||
var distance = s.distanceMeters
|
var distance = s.distanceMeters
|
||||||
var elevGain = s.elevationGainMeters
|
var elevGain = s.elevationGainMeters
|
||||||
|
|
||||||
|
var acceptedAsMovement = true
|
||||||
lastLocation?.let { prev ->
|
lastLocation?.let { prev ->
|
||||||
val d = prev.distanceTo(location).toDouble()
|
val d = prev.distanceTo(location).toDouble()
|
||||||
// Ignorera mikrobrus när man står stilla
|
// Grind 3 (stillastående): vandring mindre än halva noggrannheten
|
||||||
if (d >= 2.0) distance += d
|
// är brus, inte förflyttning — räkna varken distans eller spårpunkt.
|
||||||
|
val minMove = maxOf(2.0, (if (location.hasAccuracy()) location.accuracy else 5f) * 0.5)
|
||||||
|
if (d >= minMove) distance += d else acceptedAsMovement = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (location.hasAltitude()) {
|
if (location.hasAltitude()) {
|
||||||
@@ -257,7 +312,9 @@ class TrackingService : Service(), LocationListener {
|
|||||||
_state.value = cur.copy(
|
_state.value = cur.copy(
|
||||||
distanceMeters = distance,
|
distanceMeters = distance,
|
||||||
elevationGainMeters = elevGain,
|
elevationGainMeters = elevGain,
|
||||||
points = cur.points + (location.latitude to location.longitude),
|
points = if (acceptedAsMovement || cur.points.isEmpty()) {
|
||||||
|
cur.points + (location.latitude to location.longitude)
|
||||||
|
} else cur.points,
|
||||||
currentSpeedKmh = if (location.hasSpeed()) location.speed * 3.6 else null,
|
currentSpeedKmh = if (location.hasSpeed()) location.speed * 3.6 else null,
|
||||||
gpsFix = true,
|
gpsFix = true,
|
||||||
)
|
)
|
||||||
@@ -333,12 +390,22 @@ class TrackingService : Service(), LocationListener {
|
|||||||
const val EXTRA_MET = "met"
|
const val EXTRA_MET = "met"
|
||||||
const val EXTRA_DISTANCE_BASED = "distanceBased"
|
const val EXTRA_DISTANCE_BASED = "distanceBased"
|
||||||
const val EXTRA_WEIGHT_KG = "weightKg"
|
const val EXTRA_WEIGHT_KG = "weightKg"
|
||||||
|
const val EXTRA_GPS_ACC_LIMIT = "gpsAccLimit"
|
||||||
|
const val EXTRA_GPS_SPEED_FACTOR = "gpsSpeedFactor"
|
||||||
|
const val EXTRA_GPS_SPEED_FLOOR = "gpsSpeedFloor"
|
||||||
|
|
||||||
private val _state = MutableStateFlow(TrackingState())
|
private val _state = MutableStateFlow(TrackingState())
|
||||||
/** Läses av UI:t — servicen äger sanningen. */
|
/** Läses av UI:t — servicen äger sanningen. */
|
||||||
val state: StateFlow<TrackingState> = _state.asStateFlow()
|
val state: StateFlow<TrackingState> = _state.asStateFlow()
|
||||||
|
|
||||||
fun start(context: Context, type: ActivityType, weightKg: Double?) {
|
fun start(
|
||||||
|
context: Context,
|
||||||
|
type: ActivityType,
|
||||||
|
weightKg: Double?,
|
||||||
|
gpsAccuracyLimitM: Int = 35,
|
||||||
|
gpsSpeedFactor: Double = 2.0,
|
||||||
|
gpsSpeedFloorKmh: Int = 12,
|
||||||
|
) {
|
||||||
val intent = Intent(context, TrackingService::class.java).apply {
|
val intent = Intent(context, TrackingService::class.java).apply {
|
||||||
putExtra(EXTRA_TYPE_ID, type.id)
|
putExtra(EXTRA_TYPE_ID, type.id)
|
||||||
putExtra(EXTRA_TYPE_KEY, type.key)
|
putExtra(EXTRA_TYPE_KEY, type.key)
|
||||||
@@ -347,6 +414,9 @@ class TrackingService : Service(), LocationListener {
|
|||||||
putExtra(EXTRA_MET, type.met)
|
putExtra(EXTRA_MET, type.met)
|
||||||
putExtra(EXTRA_DISTANCE_BASED, type.isDistanceBased)
|
putExtra(EXTRA_DISTANCE_BASED, type.isDistanceBased)
|
||||||
weightKg?.let { putExtra(EXTRA_WEIGHT_KG, it) }
|
weightKg?.let { putExtra(EXTRA_WEIGHT_KG, it) }
|
||||||
|
putExtra(EXTRA_GPS_ACC_LIMIT, gpsAccuracyLimitM)
|
||||||
|
putExtra(EXTRA_GPS_SPEED_FACTOR, gpsSpeedFactor)
|
||||||
|
putExtra(EXTRA_GPS_SPEED_FLOOR, gpsSpeedFloorKmh)
|
||||||
}
|
}
|
||||||
context.startForegroundService(intent)
|
context.startForegroundService(intent)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,16 @@ class SettingsViewModel(
|
|||||||
|
|
||||||
fun setTrackLog(value: Boolean) = viewModelScope.launch { store.setTrackLogEnabled(value) }
|
fun setTrackLog(value: Boolean) = viewModelScope.launch { store.setTrackLogEnabled(value) }
|
||||||
|
|
||||||
|
fun adjustGpsAccuracy(delta: Int) = viewModelScope.launch {
|
||||||
|
store.setGpsAccuracyLimit(settings.value.gpsAccuracyLimitM + delta)
|
||||||
|
}
|
||||||
|
fun adjustGpsSpeedFactor(delta: Double) = viewModelScope.launch {
|
||||||
|
store.setGpsSpeedFactor(settings.value.gpsSpeedFactor + delta)
|
||||||
|
}
|
||||||
|
fun adjustGpsSpeedFloor(delta: Int) = viewModelScope.launch {
|
||||||
|
store.setGpsSpeedFloor(settings.value.gpsSpeedFloorKmh + delta)
|
||||||
|
}
|
||||||
|
|
||||||
fun setAutoRelogin(value: Boolean) = viewModelScope.launch {
|
fun setAutoRelogin(value: Boolean) = viewModelScope.launch {
|
||||||
store.setAutoRelogin(value)
|
store.setAutoRelogin(value)
|
||||||
// Stängs funktionen av slängs de sparade uppgifterna direkt.
|
// Stängs funktionen av slängs de sparade uppgifterna direkt.
|
||||||
@@ -147,6 +157,41 @@ fun SettingsScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsCard(title = "GPS-spårning") {
|
||||||
|
Text(
|
||||||
|
"Filter mot GPS-brus i aktivitetsspårningen. Fartgrinden förkastar " +
|
||||||
|
"positionshopp som skulle kräva högre fart än faktorn × GPS:ens " +
|
||||||
|
"egen fartmätning (Doppler).",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp),
|
||||||
|
)
|
||||||
|
StepperRow(
|
||||||
|
label = "Noggrannhetsgräns",
|
||||||
|
value = "${settings.gpsAccuracyLimitM} m",
|
||||||
|
onMinus = { viewModel.adjustGpsAccuracy(-5) },
|
||||||
|
onPlus = { viewModel.adjustGpsAccuracy(5) },
|
||||||
|
)
|
||||||
|
StepperRow(
|
||||||
|
label = "Fartgrind (× uppmätt fart)",
|
||||||
|
value = "${settings.gpsSpeedFactor}×",
|
||||||
|
onMinus = { viewModel.adjustGpsSpeedFactor(-0.5) },
|
||||||
|
onPlus = { viewModel.adjustGpsSpeedFactor(0.5) },
|
||||||
|
)
|
||||||
|
StepperRow(
|
||||||
|
label = "Fartgolv",
|
||||||
|
value = "${settings.gpsSpeedFloorKmh} km/h",
|
||||||
|
onMinus = { viewModel.adjustGpsSpeedFloor(-2) },
|
||||||
|
onPlus = { viewModel.adjustGpsSpeedFloor(2) },
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
"Gäller från nästa startade aktivitet. Standard: 35 m / 2,0× / 12 km/h.",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
SettingsCard(title = "Felsökning") {
|
SettingsCard(title = "Felsökning") {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -378,6 +423,30 @@ private fun SettingsCard(title: String, content: @Composable () -> Unit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun StepperRow(
|
||||||
|
label: String,
|
||||||
|
value: String,
|
||||||
|
onMinus: () -> Unit,
|
||||||
|
onPlus: () -> Unit,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 2.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Text(label, modifier = Modifier.weight(1f), style = MaterialTheme.typography.bodyLarge)
|
||||||
|
FilledTonalButton(onClick = onMinus) { Text("−") }
|
||||||
|
Text(
|
||||||
|
value,
|
||||||
|
modifier = Modifier.padding(horizontal = 10.dp),
|
||||||
|
style = MaterialTheme.typography.titleSmall,
|
||||||
|
)
|
||||||
|
FilledTonalButton(onClick = onPlus) { Text("+") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun RadioRow(label: String, description: String, selected: Boolean, onClick: () -> Unit) {
|
private fun RadioRow(label: String, description: String, selected: Boolean, onClick: () -> Unit) {
|
||||||
Row(
|
Row(
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ import eu.brassepc.fitnessdroid.ui.appContainer
|
|||||||
import eu.brassepc.fitnessdroid.ui.common.compact
|
import eu.brassepc.fitnessdroid.ui.common.compact
|
||||||
import eu.brassepc.fitnessdroid.ui.common.openAppSettings
|
import eu.brassepc.fitnessdroid.ui.common.openAppSettings
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.osmdroid.config.Configuration
|
import org.osmdroid.config.Configuration
|
||||||
@@ -80,7 +81,7 @@ import java.time.Instant
|
|||||||
class TrackViewModel(
|
class TrackViewModel(
|
||||||
private val gymApi: GymApi,
|
private val gymApi: GymApi,
|
||||||
private val repo: GymRepository,
|
private val repo: GymRepository,
|
||||||
settingsStore: eu.brassepc.fitnessdroid.data.SettingsStore,
|
private val settingsStore: eu.brassepc.fitnessdroid.data.SettingsStore,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
val tracking = TrackingService.state
|
val tracking = TrackingService.state
|
||||||
/** Teknisk logg visas bara om den slagits på i inställningarna. */
|
/** Teknisk logg visas bara om den slagits på i inställningarna. */
|
||||||
@@ -110,7 +111,13 @@ class TrackViewModel(
|
|||||||
fun start(context: android.content.Context) {
|
fun start(context: android.content.Context) {
|
||||||
val type = pendingType.value ?: return
|
val type = pendingType.value ?: return
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
TrackingService.start(context, type, repo.bodyWeightKg())
|
val cfg = settingsStore.settings.first()
|
||||||
|
TrackingService.start(
|
||||||
|
context, type, repo.bodyWeightKg(),
|
||||||
|
gpsAccuracyLimitM = cfg.gpsAccuracyLimitM,
|
||||||
|
gpsSpeedFactor = cfg.gpsSpeedFactor,
|
||||||
|
gpsSpeedFloorKmh = cfg.gpsSpeedFloorKmh,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user