Initial commit - StepMates Sync Android v1.1
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user