Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
### 2.12.3
- Fix: Align mobile SDK size recommendation API requests with web implementation

### 2.12.2
- Fix: Display proper size recommendation text

Expand Down
4 changes: 2 additions & 2 deletions README-COMPOSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,15 @@ In your app `build.gradle` file, add the following dependencies:

```groovy
dependencies {
implementation 'com.virtusize.android:virtusize:2.12.2'
implementation 'com.virtusize.android:virtusize:2.12.3'
}
```

- Kotlin (build.gradle.kts)

```kotlin
dependencies {
implementation("com.virtusize.android:virtusize:2.12.2")
implementation("com.virtusize.android:virtusize:2.12.3")
}
```

Expand Down
4 changes: 2 additions & 2 deletions README-JP.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,15 @@ appの`build.gradle`ファイルに下記のdependencyを追加

```groovy
dependencies {
implementation 'com.virtusize.android:virtusize:2.12.2'
implementation 'com.virtusize.android:virtusize:2.12.3'
}
```

- Kotlin (build.gradle.kts)

```kotlin
dependencies {
implementation("com.virtusize.android:virtusize:2.12.2")
implementation("com.virtusize.android:virtusize:2.12.3")
}
```

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ In your app `build.gradle` file, add the following dependencies:

```groovy
dependencies {
implementation 'com.virtusize.android:virtusize:2.12.2'
implementation 'com.virtusize.android:virtusize:2.12.3'
}
```

- Kotlin (build.gradle.kts)

```kotlin
dependencies {
implementation("com.virtusize.android:virtusize:2.12.2")
implementation("com.virtusize.android:virtusize:2.12.3")
}
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ object Constants {
const val TARGET_SDK = 34

// Update versionName when publishing a new release
const val VERSION_NAME = "2.12.2"
const val VERSION_NAME = "2.12.3"
const val GROUP_ID = "com.virtusize.android"
}
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ material = "1.12.0"
nextPublish = "1.1.0"
robolectric = "4.13"
truth = "1.4.4"
virtusize = "2.12.2"
virtusize = "2.12.3"
virtusizeAuth = "1.1.1"
browser = "1.8.0"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ internal data class BodyProfileRecommendedSizeParams(
*/
fun paramsToMap(): Map<String, Any> {
return emptyMap<String, Any>()
.plus(
mapOf("app_origin" to APP_ORIGIN_ANDROID),
)
.plus(
mapOf(PARAM_BODY_DATA to createBodyDataParams()),
)
Expand All @@ -47,8 +50,40 @@ internal data class BodyProfileRecommendedSizeParams(
)
}

private fun createItemsParams(): Map<String, Any?> {
return emptyMap<String, Any?>()
fun paramsToMapShoe(): Map<String, Any> {
return emptyMap<String, Any>()
.plus(
mapOf(PARAM_BODY_DATA to createBodyDataParams()),
)
.plus(
mapOf(PARAM_USER_GENDER to userBodyProfile.gender),
)
.plus(
mapOf(PARAM_USER_HEIGHT to userBodyProfile.height),
)
.plus(
userBodyProfile.weight.toFloatOrNull()?.let { mapOf(PARAM_USER_WEIGHT to it) }
.orEmpty(),
)
.plus(
mapOf(PARAM_USER_AGE to userBodyProfile.age),
)
.plus(
createItemsParams(),
)
.plus(
mapOf(PARAM_FOOTWEAR_DATA to userBodyProfile.footwearData),
)
.plus(
mapOf(PARAM_ADDITIONAL_INFO to createAdditionalInfoParams()),
)
.plus(
mapOf(PARAM_PRODUCT_NAME to storeProduct.name),
)
}

private fun createItemsParams(): Map<String, Any> {
return emptyMap<String, Any>()
.plus(
mapOf(PARAM_ITEM_SIZES to createItemSizesParams()),
)
Expand Down Expand Up @@ -80,6 +115,10 @@ internal data class BodyProfileRecommendedSizeParams(
measurement.name to measurement.millimeter
}
}
val modelInfo =
storeProduct.storeProductMeta?.additionalInfo?.modelInfo
?.mapKeys { (key, _) -> toSnakeCase(key) } ?: JSONObject.NULL

return emptyMap<String, Any?>()
.plus(
mapOf(PARAM_BRAND to (brand ?: "")),
Expand All @@ -93,13 +132,10 @@ internal data class BodyProfileRecommendedSizeParams(
mapOf(PARAM_SIZES to (sizeHashMap ?: mutableMapOf())),
)
.plus(
mapOf(
PARAM_MODEL_INFO to
(storeProduct.storeProductMeta?.additionalInfo?.modelInfo ?: JSONObject.NULL),
),
mapOf(PARAM_MODEL_INFO to modelInfo),
)
.plus(
mapOf(PARAM_GENDER to userBodyProfile.gender),
mapOf(PARAM_GENDER to (storeProduct.storeProductMeta?.additionalInfo?.gender ?: "male")),
)
.plus(
mapOf(
Expand Down Expand Up @@ -137,6 +173,8 @@ internal data class BodyProfileRecommendedSizeParams(
)
}.orEmpty(),
)
// Convert all keys in the map to snake_case
.mapKeys { (key, _) -> toSnakeCase(key) }
}

/**
Expand All @@ -155,27 +193,40 @@ internal data class BodyProfileRecommendedSizeParams(
}

private companion object {
const val PARAM_ADDITIONAL_INFO = "additionalInfo"
const val PARAM_BODY_DATA = "bodyData"
const val PARAM_ITEM_SIZES = "itemSizesOrig"
const val PARAM_ADDITIONAL_INFO = "additional_info"
const val PARAM_BODY_DATA = "body_data"
const val PARAM_ITEM_SIZES = "item_sizes_orig"
const val PARAM_ITEMS = "items"
const val PARAM_PRODUCT_TYPE = "productType"
const val PARAM_USER_GENDER = "userGender"
const val PARAM_USER_HEIGHT = "userHeight"
const val PARAM_USER_WEIGHT = "userWeight"
const val PARAM_USER_AGE = "userAge"
const val PARAM_EXTERNAL_PRODUCT_ID = "extProductId"
const val PARAM_PRODUCT_TYPE = "product_type"
const val PARAM_USER_GENDER = "user_gender"
const val PARAM_USER_HEIGHT = "user_height"
const val PARAM_USER_WEIGHT = "user_weight"
const val PARAM_USER_AGE = "user_age"
const val PARAM_EXTERNAL_PRODUCT_ID = "ext_product_id"
const val PARAM_FOOTWEAR_DATA = "footwear_data"
const val PARAM_PRODUCT_NAME = "product_name"

const val PARAM_BRAND = "brand"
const val PARAM_FIT = "fit"
const val PARAM_SIZES = "sizes"
const val PARAM_MODEL_INFO = "modelInfo"
const val PARAM_MODEL_INFO = "model_info"
const val PARAM_GENDER = "gender"
const val PARAM_STYLE = "style"

const val PARAM_BODY_MEASUREMENT_VALUE = "value"
const val PARAM_BODY_MEASUREMENT_PREDICTED = "predicted"
const val PARAM_BODY_BUST = "bust"
const val PARAM_BODY_CHEST = "chest"

const val APP_ORIGIN_ANDROID = 2
}

/**
* Converts a camelCase or PascalCase string to snake_case
*/
private fun toSnakeCase(input: String): String {
return input.replace(Regex("([a-z])([A-Z])"), "$1_$2")
.replace(Regex("([A-Z])([A-Z][a-z])"), "$1_$2")
.lowercase()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@ class UserBodyProfileJsonParser : VirtusizeJsonParser<UserBodyProfile> {
val height = json.optInt(FIELD_HEIGHT)
val weight = json.optString(FIELD_WEIGHT)
var bodyData = setOf<Measurement>()
var footwearData = mapOf<String, Any>()
json.optJSONObject(FIELD_BODY_DATA)?.let { bodyDataJsonObject ->
bodyData = JsonUtils.jsonObjectToMeasurements(bodyDataJsonObject)
}
json.optJSONObject(FIELD_FOOTWEAR_DATA)?.let { footwearDataJsonObject ->
footwearData = JsonUtils.jsonObjectToMap(footwearDataJsonObject)
}
if (age == 0 || height == 0 || weight.isBlank() || bodyData.isEmpty()) {
return null
}
return UserBodyProfile(gender, age, height, weight, bodyData)
return UserBodyProfile(gender, age, height, weight, bodyData, footwearData)
}

companion object {
Expand All @@ -26,5 +30,6 @@ class UserBodyProfileJsonParser : VirtusizeJsonParser<UserBodyProfile> {
private const val FIELD_HEIGHT = "height"
private const val FIELD_WEIGHT = "weight"
private const val FIELD_BODY_DATA = "bodyData"
private const val FIELD_FOOTWEAR_DATA = "footwearData"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,11 @@ data class Product(
fun isAccessory(): Boolean {
return productType == 18 || productType == 19 || productType == 25 || productType == 26
}

/**
* Checks if the product is a shoe
*/
fun isShoe(): Boolean {
return productType == 17
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ data class UserBodyProfile(
val height: Int,
val weight: String,
val bodyData: Set<Measurement>,
val footwearData: Map<String, Any>,
)
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ object VirtusizeApi {
* @param userBodyProfile [UserBodyProfile]
* @see ApiRequest
*/
fun getSize(
fun getItemSizeRecommendationRequest(
productTypes: List<ProductType>,
storeProduct: Product,
userBodyProfile: UserBodyProfile,
Expand All @@ -428,4 +428,26 @@ object VirtusizeApi {
.toString()
return ApiRequest(url, HttpMethod.POST, bodyProfileRecommendedSizeParams.paramsToMap())
}

/**
* Gets a API request for getting the recommended shoe size based on the user's body profile
* @param productTypes the list of available [ProductType]
* @param storeProduct [Product]
* @param userBodyProfile [UserBodyProfile]
* @see ApiRequest
*/
fun getShoeSizeRecommendationRequest(
productTypes: List<ProductType>,
storeProduct: Product,
userBodyProfile: UserBodyProfile,
): ApiRequest {
val bodyProfileRecommendedSizeParams =
BodyProfileRecommendedSizeParams(productTypes, storeProduct, userBodyProfile)
val url =
Uri.parse("${environment.sizeRecommendationApiBaseUrl()}${VirtusizeEndpoint.GetShoeSize.path}")
.buildUpon()
.build()
.toString()
return ApiRequest(url, HttpMethod.POST, bodyProfileRecommendedSizeParams.paramsToMapShoe())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ sealed interface VirtusizeEndpoint {
override val path: String = "/item"
}

data object GetShoeSize : VirtusizeEndpoint {
override val path: String = "/shoe"
}

data object LatestAoyamaVersion : VirtusizeEndpoint {
override val path: String = "/a/aoyama/latest.txt"
}
Expand Down
Loading