@sency/react-native-smkit-ui 2.0.4 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ AI-powered fitness assessments, custom workouts, and workout programs with real-
|
|
|
25
25
|
- **Multiple Assessment Types** - Fitness, Body360, Strength, Cardio, and custom assessments
|
|
26
26
|
- **Cross-Platform** - Native support for iOS and Android
|
|
27
27
|
- **Configurable Workouts** - Customize by body zone, difficulty, and duration
|
|
28
|
+
- **Intelligent Model Selection** (Android) - Automatically selects the best pose estimation model based on device capabilities for optimal performance
|
|
28
29
|
|
|
29
30
|
---
|
|
30
31
|
|
|
@@ -152,6 +153,15 @@ android {
|
|
|
152
153
|
}
|
|
153
154
|
```
|
|
154
155
|
|
|
156
|
+
3. **Pose Estimation Model Selection** (v2.0.5+)
|
|
157
|
+
|
|
158
|
+
The SMKit SDK automatically selects the best pose estimation model based on device capabilities:
|
|
159
|
+
- **Pro Model** - High-end devices for maximum accuracy and detailed pose detection
|
|
160
|
+
- **Lite Model** - Mid-range devices for balanced performance and accuracy
|
|
161
|
+
- **UltraLite Model** - Lower-end devices for smooth real-time performance
|
|
162
|
+
|
|
163
|
+
This automatic selection ensures optimal performance and accuracy across a wide range of Android devices without requiring manual configuration.
|
|
164
|
+
|
|
155
165
|
---
|
|
156
166
|
|
|
157
167
|
## Getting Started
|
package/android/build.gradle
CHANGED
|
@@ -95,7 +95,7 @@ dependencies {
|
|
|
95
95
|
implementation "com.facebook.react:react-android"
|
|
96
96
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
97
97
|
|
|
98
|
-
implementation("com.sency.smkitui:smkitui:1.4.
|
|
98
|
+
implementation("com.sency.smkitui:smkitui:1.4.7") {
|
|
99
99
|
exclude group: 'com.facebook.fbjni', module: 'fbjni-java-only'
|
|
100
100
|
// // Don't exclude native libraries
|
|
101
101
|
// exclude group: 'com.facebook.react', module: 'react-native'
|
|
@@ -111,4 +111,3 @@ dependencies {
|
|
|
111
111
|
implementation "com.squareup.moshi:moshi-kotlin:$moshi"
|
|
112
112
|
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi"
|
|
113
113
|
}
|
|
114
|
-
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
package com.smkituilibrary
|
|
2
2
|
|
|
3
|
+
import android.os.Handler
|
|
4
|
+
import android.os.Looper
|
|
3
5
|
import android.util.Log
|
|
4
6
|
import com.facebook.react.bridge.Arguments
|
|
5
7
|
import com.facebook.react.bridge.Promise
|
|
@@ -30,6 +32,7 @@ import com.sency.smkitui.model.workoutConfig.EndExercisePreference
|
|
|
30
32
|
import com.sency.smkitui.model.workoutConfig.SMLanguage
|
|
31
33
|
import com.sency.smkitui.model.workoutConfig.WorkoutConfigModel
|
|
32
34
|
import com.smkituilibrary.mapper.toSMWorkout
|
|
35
|
+
import com.smkituilibrary.mapper.toSMWorkoutWithoutScoringParams
|
|
33
36
|
import com.smkituilibrary.mapper.toWFPSummary
|
|
34
37
|
import com.smkituilibrary.mapper.toWorkoutConfig
|
|
35
38
|
import com.smkituilibrary.model.SMKitWorkout
|
|
@@ -91,6 +94,14 @@ class SmkitUiLibraryModule(reactContext: ReactApplicationContext) :
|
|
|
91
94
|
}
|
|
92
95
|
resultPromise?.resolve(result)
|
|
93
96
|
sendEvent(reactApplicationContext, "workoutDidFinish", params)
|
|
97
|
+
// Dismiss the SDK UI on the main thread
|
|
98
|
+
Handler(Looper.getMainLooper()).post {
|
|
99
|
+
try {
|
|
100
|
+
smKitUI?.exitSDK()
|
|
101
|
+
} catch (e: Exception) {
|
|
102
|
+
Log.e(TAG, "Error exiting SDK: ${e.message}", e)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
94
105
|
}
|
|
95
106
|
|
|
96
107
|
override fun didExitWorkout(summary: WorkoutSummaryData) {
|
|
@@ -113,6 +124,14 @@ class SmkitUiLibraryModule(reactContext: ReactApplicationContext) :
|
|
|
113
124
|
}
|
|
114
125
|
resultPromise?.resolve(result)
|
|
115
126
|
sendEvent(reactApplicationContext, "didExitWorkout", params)
|
|
127
|
+
// Dismiss the SDK UI on the main thread
|
|
128
|
+
Handler(Looper.getMainLooper()).post {
|
|
129
|
+
try {
|
|
130
|
+
smKitUI?.exitSDK()
|
|
131
|
+
} catch (e: Exception) {
|
|
132
|
+
Log.e(TAG, "Error exiting SDK: ${e.message}", e)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
116
135
|
}
|
|
117
136
|
|
|
118
137
|
|
|
@@ -265,7 +284,16 @@ class SmkitUiLibraryModule(reactContext: ReactApplicationContext) :
|
|
|
265
284
|
val assessmentType = when (type) {
|
|
266
285
|
"fitness" -> Fitness
|
|
267
286
|
"body360" -> Body360
|
|
268
|
-
else ->
|
|
287
|
+
else -> {
|
|
288
|
+
// Validate customAssessmentId is not empty for custom assessments
|
|
289
|
+
if (customAssessmentId.isNullOrBlank()) {
|
|
290
|
+
Log.e(TAG, "Custom assessment ID is empty or blank")
|
|
291
|
+
promise.reject("Starting Assessment Failed", "Custom assessment ID is required for custom assessment type")
|
|
292
|
+
return
|
|
293
|
+
}
|
|
294
|
+
Log.d(TAG, "Creating Custom assessment with ID: $customAssessmentId")
|
|
295
|
+
Custom(customAssessmentId)
|
|
296
|
+
}
|
|
269
297
|
}
|
|
270
298
|
val user = if(userData == null) null else if (forceShowUserDataScreen) null else {
|
|
271
299
|
serializeUserData(userData)
|
|
@@ -294,12 +322,20 @@ class SmkitUiLibraryModule(reactContext: ReactApplicationContext) :
|
|
|
294
322
|
try {
|
|
295
323
|
Log.d(TAG, "startCustomWorkout called with modifications: $modifications")
|
|
296
324
|
resultPromise = promise
|
|
297
|
-
|
|
325
|
+
// Use mapper without scoring params for workouts
|
|
326
|
+
val workout = serializeWorkoutWithoutScoringParams(jsonArguments)
|
|
298
327
|
if (workout == null) {
|
|
299
328
|
Log.e(TAG, "Failed to serialize workout from JSON")
|
|
300
329
|
promise.reject("Starting Custom Workout Failed", "Failed to parse workout JSON")
|
|
301
330
|
return
|
|
302
331
|
}
|
|
332
|
+
// Verify no scoring params exist in the workout
|
|
333
|
+
val hasScoringParams = workout.exercises.any { it.scoringParams != null }
|
|
334
|
+
if (hasScoringParams) {
|
|
335
|
+
Log.w(TAG, "Warning: Workout still contains scoring params after removal attempt")
|
|
336
|
+
} else {
|
|
337
|
+
Log.d(TAG, "Verified: Workout has no scoring params")
|
|
338
|
+
}
|
|
303
339
|
val (finalModifications, showPhoneCalibration) = processModifications(modifications)
|
|
304
340
|
smKitUI?.startCustomizedWorkout(
|
|
305
341
|
workout = workout,
|
|
@@ -354,6 +390,44 @@ class SmkitUiLibraryModule(reactContext: ReactApplicationContext) :
|
|
|
354
390
|
|
|
355
391
|
private fun serializeWorkout(jsonArguments: String) =
|
|
356
392
|
moshi.adapter(SMKitWorkout::class.java).fromJson(jsonArguments)?.toSMWorkout()
|
|
393
|
+
|
|
394
|
+
private fun serializeWorkoutWithoutScoringParams(jsonArguments: String): com.sency.smkitui.model.SMWorkout? {
|
|
395
|
+
// Remove scoring params from JSON before deserializing to ensure they're completely excluded
|
|
396
|
+
val jsonWithoutScoringParams = removeScoringParamsFromJson(jsonArguments)
|
|
397
|
+
return moshi.adapter(SMKitWorkout::class.java).fromJson(jsonWithoutScoringParams)?.toSMWorkoutWithoutScoringParams()
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
private fun removeScoringParamsFromJson(json: String): String {
|
|
401
|
+
return try {
|
|
402
|
+
val jsonObject = gson.fromJson(json, Map::class.java) as? Map<*, *> ?: return json
|
|
403
|
+
val mutableMap = jsonObject.toMutableMap()
|
|
404
|
+
|
|
405
|
+
// Get exercises array
|
|
406
|
+
val exercises = mutableMap["exercises"] as? List<*> ?: return json
|
|
407
|
+
val updatedExercises = exercises.mapIndexed { index, exercise ->
|
|
408
|
+
if (exercise is Map<*, *>) {
|
|
409
|
+
val exerciseMap = exercise.toMutableMap()
|
|
410
|
+
// Remove scoringParams field (check both camelCase and snake_case variants)
|
|
411
|
+
val removed = exerciseMap.remove("scoringParams")
|
|
412
|
+
exerciseMap.remove("scoring_params")
|
|
413
|
+
if (removed != null) {
|
|
414
|
+
Log.d(TAG, "Removed scoringParams from exercise at index $index")
|
|
415
|
+
}
|
|
416
|
+
exerciseMap
|
|
417
|
+
} else {
|
|
418
|
+
exercise
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
mutableMap["exercises"] = updatedExercises
|
|
423
|
+
val result = gson.toJson(mutableMap)
|
|
424
|
+
Log.d(TAG, "Removed scoring params from workout JSON")
|
|
425
|
+
result
|
|
426
|
+
} catch (e: Exception) {
|
|
427
|
+
Log.e(TAG, "Error removing scoring params from JSON: ${e.message}", e)
|
|
428
|
+
json // Return original JSON if parsing fails
|
|
429
|
+
}
|
|
430
|
+
}
|
|
357
431
|
|
|
358
432
|
private fun serializeUserData(jsonArguments: String) =
|
|
359
433
|
moshi.adapter(SMUserData::class.java).fromJson(jsonArguments)?.toUserData()
|
|
@@ -40,6 +40,17 @@ internal fun SMKitWorkout.toSMWorkout(): SMWorkout = SMWorkout(
|
|
|
40
40
|
bodycalFinished = bodycalFinished ?: ""
|
|
41
41
|
)
|
|
42
42
|
|
|
43
|
+
internal fun SMKitWorkout.toSMWorkoutWithoutScoringParams(): SMWorkout = SMWorkout(
|
|
44
|
+
id = id ?: "",
|
|
45
|
+
name = name ?: "",
|
|
46
|
+
workoutIntro = workoutIntro ?: "",
|
|
47
|
+
soundtrack = soundtrack ?: "",
|
|
48
|
+
exercises = exercises.map(SMKitExercise::toSMExerciseWithoutScoringParams),
|
|
49
|
+
workoutClosure = workoutClosure ?: "",
|
|
50
|
+
getInFrame = getInFrame ?: "",
|
|
51
|
+
bodycalFinished = bodycalFinished ?: ""
|
|
52
|
+
)
|
|
53
|
+
|
|
43
54
|
private fun SMKitExercise.toSMExercise(): SMExercise = SMExercise(
|
|
44
55
|
prettyName = prettyName ?: "",
|
|
45
56
|
exerciseIntro = exerciseIntro ?: "",
|
|
@@ -57,6 +68,23 @@ private fun SMKitExercise.toSMExercise(): SMExercise = SMExercise(
|
|
|
57
68
|
side = side
|
|
58
69
|
)
|
|
59
70
|
|
|
71
|
+
private fun SMKitExercise.toSMExerciseWithoutScoringParams(): SMExercise = SMExercise(
|
|
72
|
+
prettyName = prettyName ?: "",
|
|
73
|
+
exerciseIntro = exerciseIntro ?: "",
|
|
74
|
+
totalSeconds = totalSeconds ?: 0,
|
|
75
|
+
videoInstruction = videoInstruction ?: "",
|
|
76
|
+
uiElements = uiElements ?: emptySet(),
|
|
77
|
+
detector = detector ?: "",
|
|
78
|
+
exerciseClosure = exerciseClosure ?: "",
|
|
79
|
+
closureFailedSound = closureFailedSound ?: "",
|
|
80
|
+
scoringParams = null, // Exclude scoring params for workouts
|
|
81
|
+
summaryTitle = summaryTitle ?: "",
|
|
82
|
+
summarySubTitle = summarySubTitle ?: "",
|
|
83
|
+
summaryMainMetricTitle = summaryTitleMainMetric ?: "",
|
|
84
|
+
summarySubTitleMainMetric = summarySubTitleMainMetric ?: "",
|
|
85
|
+
side = side
|
|
86
|
+
)
|
|
87
|
+
|
|
60
88
|
private fun SMKitScoringParams.toParams(): ScoringParams {
|
|
61
89
|
return ScoringParams(
|
|
62
90
|
type = type ?: "",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sency/react-native-smkit-ui",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "React Native library for SMKit UI - Advanced fitness assessments and workout programs with AI-powered motion detection and real-time performance tracking",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|