fix(wear): improve client initialization, consolidate health callbacks, and reset workout state
This commit is contained in:
@@ -9,15 +9,28 @@ import androidx.health.services.client.data.DataType
|
||||
import androidx.health.services.client.data.ExerciseUpdate
|
||||
import androidx.health.services.client.data.ExerciseState
|
||||
import androidx.health.services.client.data.DataPointAvailability
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import kotlinx.coroutines.tasks.await
|
||||
|
||||
class HealthServicesManager(context: Context) {
|
||||
private val healthClient = HealthServices.getClient(context)
|
||||
private val exerciseClient: ExerciseClient = healthClient.exerciseClient
|
||||
|
||||
private val hrChannel = Channel<Double>(Channel.CONFLATED)
|
||||
private val calChannel = Channel<Double>(Channel.CONFLATED)
|
||||
private var callbackRegistered = false
|
||||
|
||||
private val combinedCallback = object : androidx.health.services.client.ExerciseUpdateCallback {
|
||||
override fun onNewUpdate(update: ExerciseUpdate) {
|
||||
update.getData(DataType.HEART_RATE_BPM)?.toDouble()?.let { hrChannel.trySend(it) }
|
||||
update.getData(DataType.CALORIES)?.toDouble()?.let { calChannel.trySend(it) }
|
||||
}
|
||||
|
||||
override fun onAvailabilityChanged(dataType: DataType, availability: DataPointAvailability) {}
|
||||
}
|
||||
|
||||
suspend fun hasSwimmingCapability(): Boolean {
|
||||
return try {
|
||||
val capabilities = exerciseClient.getCapabilitiesAsync().await()
|
||||
@@ -50,38 +63,21 @@ class HealthServicesManager(context: Context) {
|
||||
exerciseClient.endExerciseAsync().await()
|
||||
}
|
||||
|
||||
fun heartRateFlow(): Flow<Double> = callbackFlow {
|
||||
val callback = object : androidx.health.services.client.ExerciseUpdateCallback {
|
||||
override fun onNewUpdate(update: ExerciseUpdate) {
|
||||
update.getData(DataType.HEART_RATE_BPM)?.let { data ->
|
||||
trySend(data.toDouble())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAvailabilityChanged(dataType: DataType, availability: DataPointAvailability) {
|
||||
// Not used
|
||||
}
|
||||
}
|
||||
|
||||
exerciseClient.setUpdateCallback(callback)
|
||||
awaitClose { exerciseClient.clearUpdateCallbackAsync() }
|
||||
fun heartRateFlow(): Flow<Double> {
|
||||
ensureCallbackRegistered()
|
||||
return hrChannel.receiveAsFlow()
|
||||
}
|
||||
|
||||
fun caloriesFlow(): Flow<Double> = callbackFlow {
|
||||
val callback = object : androidx.health.services.client.ExerciseUpdateCallback {
|
||||
override fun onNewUpdate(update: ExerciseUpdate) {
|
||||
update.getData(DataType.CALORIES)?.let { data ->
|
||||
trySend(data.toDouble())
|
||||
}
|
||||
}
|
||||
fun caloriesFlow(): Flow<Double> {
|
||||
ensureCallbackRegistered()
|
||||
return calChannel.receiveAsFlow()
|
||||
}
|
||||
|
||||
override fun onAvailabilityChanged(dataType: DataType, availability: DataPointAvailability) {
|
||||
// Not used
|
||||
}
|
||||
private fun ensureCallbackRegistered() {
|
||||
if (!callbackRegistered) {
|
||||
exerciseClient.setUpdateCallback(combinedCallback)
|
||||
callbackRegistered = true
|
||||
}
|
||||
|
||||
exerciseClient.setUpdateCallback(callback)
|
||||
awaitClose { exerciseClient.clearUpdateCallbackAsync() }
|
||||
}
|
||||
|
||||
fun isActive(): Boolean {
|
||||
|
||||
@@ -187,6 +187,7 @@ class WorkoutViewModel(application: Application) : AndroidViewModel(application)
|
||||
}
|
||||
|
||||
fun completeLap() {
|
||||
if (!_isWorkoutActive.value || _isResting.value) return
|
||||
val workout = _selectedWorkout.value ?: return
|
||||
val currentSet = workout.sets.getOrNull(_currentSetIndex.value) ?: return
|
||||
|
||||
@@ -245,6 +246,9 @@ class WorkoutViewModel(application: Application) : AndroidViewModel(application)
|
||||
viewModelScope.launch {
|
||||
healthManager.endWorkout()
|
||||
_isWorkoutActive.value = false
|
||||
_currentSetIndex.value = 0
|
||||
_currentRep.value = 0
|
||||
_elapsedSeconds.value = 0f
|
||||
|
||||
HapticFeedback.play(appContext, HapticFeedback.Type.SUCCESS)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user