Files
stepmates-sync/app/src/main/java/com/stepmates/sync/StepSyncWorker.kt
T

91 lines
3.7 KiB
Kotlin

package com.stepmates.sync
import android.content.Context
import androidx.health.connect.client.HealthConnectClient
import androidx.health.connect.client.permission.HealthPermission
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.request.ReadRecordsRequest
import androidx.health.connect.client.time.TimeRangeFilter
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONArray
import org.json.JSONObject
import java.text.SimpleDateFormat
import java.time.Instant
import java.time.LocalDate
import java.time.ZoneId
import java.util.Date
import java.util.Locale
class StepSyncWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
private val httpClient = OkHttpClient()
override suspend fun doWork(): Result {
val prefs = applicationContext.getSharedPreferences("stepmates", Context.MODE_PRIVATE)
val webhookUrl = prefs.getString("webhook_url", null) ?: return Result.failure()
val availabilityStatus = HealthConnectClient.getSdkStatus(applicationContext)
if (availabilityStatus != HealthConnectClient.SDK_AVAILABLE) return Result.failure()
val client = HealthConnectClient.getOrCreate(applicationContext)
val granted = client.permissionController.getGrantedPermissions()
if (!granted.contains(HealthPermission.getReadPermission(StepsRecord::class))) return Result.failure()
return try {
val today = LocalDate.now(ZoneId.systemDefault())
val stepsByDate = mutableMapOf<String, Long>()
for (i in 0..6) {
val date = today.minusDays(i.toLong())
val startTime = date.atStartOfDay(ZoneId.systemDefault()).toInstant()
val endTime = if (i == 0) Instant.now() else date.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant()
val response = client.readRecords(ReadRecordsRequest(StepsRecord::class, timeRangeFilter = TimeRangeFilter.between(startTime, endTime)))
val total = response.records.sumOf { it.count }
if (total > 0) {
val dateKey = "${date.year}-${date.monthValue.toString().padStart(2,'0')}-${date.dayOfMonth.toString().padStart(2,'0')}"
stepsByDate[dateKey] = total
}
}
if (stepsByDate.isEmpty()) return Result.success()
val metricsArray = JSONArray()
val stepsMetric = JSONObject()
stepsMetric.put("name", "steps")
val dataArray = JSONArray()
for ((dateStr, count) in stepsByDate) {
val entry = JSONObject()
entry.put("date", dateStr)
entry.put("qty", count)
dataArray.put(entry)
}
stepsMetric.put("data", dataArray)
metricsArray.put(stepsMetric)
val payload = JSONObject()
val dataObj = JSONObject()
dataObj.put("metrics", metricsArray)
payload.put("data", dataObj)
val body = payload.toString().toRequestBody("application/json".toMediaType())
val request = Request.Builder().url(webhookUrl).post(body).build()
val httpResponse = httpClient.newCall(request).execute()
if (httpResponse.isSuccessful) {
val now = System.currentTimeMillis()
prefs.edit().putLong("last_sync", now).apply()
Result.success()
} else {
Result.retry()
}
} catch (e: Exception) {
Result.retry()
}
}
}