Etapp 1: kroppsdata synkas mot servern + BMR + dagens kcal-mätare på Hem
All checks were successful
release / build-release (push) Successful in 5m54s

- Profile/myProfile med heightCm/birthYear/sex (fallback mot äldre server),
  updateProfile-mutation i GymApi
- Kroppsdata sparas lokalt och synkas: serverns värden vinner, lokala pushas
  upp om servern är tom (migrerar vågens lokala data)
- Mifflin–St Jeor-BMR (data/Bmr.kt)
- Hemskärm: Dagens kalorier-kort — aktivt loggat (dagens pass), telefonen
  (platshållare för etapp 5) och passivt (BMR-andel av dygnet, tickar per
  minut). Uppmaning om kroppsdata saknas.
- Version 0.5.0

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C2GA94E1f3cmrvdQLQhYdg
This commit is contained in:
2026-08-23 17:20:39 +02:00
parent 9784b749aa
commit 06b2f0ec86
7 changed files with 261 additions and 6 deletions

View File

@@ -1,8 +1,10 @@
package eu.brassepc.fitnessdroid.data
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.put
@Serializable
data class Profile(
@@ -10,6 +12,10 @@ data class Profile(
val displayName: String? = null,
val email: String? = null,
val bodyWeightKg: Double? = null,
val heightCm: Double? = null,
val birthYear: Int? = null,
/** "male"/"female" — serverns konvention */
val sex: String? = null,
)
/** Autentiserade anrop mot gym-API:t. Query-strängarna speglar gymTrackerApi.js. */
@@ -18,14 +24,37 @@ class GymApi(
private val auth: AuthRepository,
) {
suspend fun myProfile(): Profile {
val data = client.execute(MY_PROFILE, token = auth.bearerToken())
// Fallback till gamla fältuppsättningen mot en äldre server.
val data = try {
client.execute(MY_PROFILE, token = auth.bearerToken())
} catch (e: GraphQlException) {
client.execute(MY_PROFILE_LEGACY, token = auth.bearerToken())
}
val profile = data["myProfile"]?.jsonObject
?: throw GraphQlException(listOf("Kunde inte hämta profilen"))
return client.json.decodeFromJsonElement(profile)
}
/** Kroppsdata till servern. null = rör ej, -1/"" = rensa (serverns konvention). */
suspend fun updateProfile(heightCm: Double?, birthYear: Int?, sex: String?): Profile {
val data = client.execute(
"mutation(\$h: Float,\$y: Int,\$s: String){updateProfile(heightCm:\$h,birthYear:\$y,sex:\$s){username displayName email bodyWeightKg heightCm birthYear sex}}",
buildJsonObject {
heightCm?.let { put("h", it) }
birthYear?.let { put("y", it) }
sex?.let { put("s", it) }
},
auth.bearerToken(),
)
val profile = data["updateProfile"]?.jsonObject
?: throw GraphQlException(listOf("Kunde inte spara kroppsdata"))
return client.json.decodeFromJsonElement(profile)
}
companion object {
private const val MY_PROFILE =
"query{myProfile{username displayName email bodyWeightKg heightCm birthYear sex}}"
private const val MY_PROFILE_LEGACY =
"query{myProfile{username displayName email bodyWeightKg}}"
}
}