feat(wearos): track swimming stroke count during workouts
This commit is contained in:
@@ -20,12 +20,14 @@ class HealthServicesManager(context: Context) {
|
||||
|
||||
private val hrChannel = Channel<Double>(Channel.CONFLATED)
|
||||
private val calChannel = Channel<Double>(Channel.CONFLATED)
|
||||
private val strokeCountChannel = Channel<Long>(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) }
|
||||
update.getData(DataType.SWIMMING_STROKES)?.let { strokeCountChannel.trySend(it) }
|
||||
}
|
||||
|
||||
override fun onAvailabilityChanged(dataType: DataType, availability: DataPointAvailability) {}
|
||||
@@ -46,6 +48,7 @@ class HealthServicesManager(context: Context) {
|
||||
|
||||
val config = ExerciseConfig.builder(ExerciseType.SWIMMING_POOL)
|
||||
.setDataTypes(poolCapabilities.supportedDataTypes)
|
||||
.setSwimmingPoolLengthMeters(poolLengthMeters)
|
||||
.build()
|
||||
|
||||
exerciseClient.startExerciseAsync(config).await()
|
||||
@@ -73,6 +76,11 @@ class HealthServicesManager(context: Context) {
|
||||
return calChannel.receiveAsFlow()
|
||||
}
|
||||
|
||||
fun strokeCountFlow(): Flow<Long> {
|
||||
ensureCallbackRegistered()
|
||||
return strokeCountChannel.receiveAsFlow()
|
||||
}
|
||||
|
||||
private fun ensureCallbackRegistered() {
|
||||
if (!callbackRegistered) {
|
||||
exerciseClient.setUpdateCallback(combinedCallback)
|
||||
|
||||
@@ -70,6 +70,7 @@ class WorkoutViewModel(application: Application) : AndroidViewModel(application)
|
||||
private var startTime = 0L
|
||||
private var lapStartTime = 0L
|
||||
private var lapDetector: LapDetector? = null
|
||||
private var currentStrokeCount = 0L
|
||||
|
||||
private val workoutReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
@@ -141,10 +142,12 @@ class WorkoutViewModel(application: Application) : AndroidViewModel(application)
|
||||
_currentSetIndex.value = 0
|
||||
_currentRep.value = 0
|
||||
_completedLaps.value = emptyList()
|
||||
currentStrokeCount = 0L
|
||||
|
||||
startElapsedTimeTracking()
|
||||
startHeartRateTracking()
|
||||
startCaloriesTracking()
|
||||
startStrokeCountTracking()
|
||||
startLapDetection()
|
||||
}
|
||||
}
|
||||
@@ -186,6 +189,14 @@ class WorkoutViewModel(application: Application) : AndroidViewModel(application)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startStrokeCountTracking() {
|
||||
viewModelScope.launch {
|
||||
healthManager.strokeCountFlow().collect { delta ->
|
||||
currentStrokeCount += delta
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun completeLap() {
|
||||
if (!_isWorkoutActive.value || _isResting.value) return
|
||||
val workout = _selectedWorkout.value ?: return
|
||||
@@ -202,10 +213,12 @@ class WorkoutViewModel(application: Application) : AndroidViewModel(application)
|
||||
repNumber = _currentRep.value + 1,
|
||||
distance = currentSet.distancePerRep,
|
||||
duration = lapDuration,
|
||||
heartRate = _heartRate.value
|
||||
heartRate = _heartRate.value,
|
||||
strokeCount = currentStrokeCount.toInt()
|
||||
)
|
||||
|
||||
_completedLaps.value = _completedLaps.value + lap
|
||||
currentStrokeCount = 0L
|
||||
|
||||
if (_currentRep.value < currentSet.repCount - 1) {
|
||||
_currentRep.value++
|
||||
|
||||
@@ -21,7 +21,8 @@ data class CompletedLap(
|
||||
val repNumber: Int,
|
||||
val distance: Int,
|
||||
val duration: Float,
|
||||
val heartRate: Int?
|
||||
val heartRate: Int?,
|
||||
val strokeCount: Int? = null
|
||||
)
|
||||
|
||||
data class WorkoutSummary(
|
||||
|
||||
Reference in New Issue
Block a user