Skip to content
Open
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### Changes:
- Fix: Align iOS and Android willFit parameter for recommended text
- Fix: Reload recommended size on change store

### 2.12.21
- Fix: Compose VirtusizeInPageMini VirtusizeInPageStandard update fix

Expand Down
14 changes: 6 additions & 8 deletions virtusize/src/main/java/com/virtusize/android/Virtusize.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,14 @@ interface Virtusize {
fun setUserId(userId: String)

/**
* Use this function to set up the apiKey in the app when the user changes country
* Use this function to switch the store when the user changes country
* @param apiKey unique store Api Key
* @param env the [VirtusizeEnvironment] for the new store
*/
fun setApiKey(newApiKey: String)

/**
* Use this function to change API environment
* @param env unique API environment
*/
fun setEnvironment(env: VirtusizeEnvironment)
fun changeStore(
apiKey: String,
env: VirtusizeEnvironment,
)

/**
* Registers a message handler.
Expand Down
43 changes: 30 additions & 13 deletions virtusize/src/main/java/com/virtusize/android/VirtusizeImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import com.virtusize.android.util.trimI18nText
import com.virtusize.android.util.valueOf
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
Expand All @@ -47,6 +48,12 @@ internal class VirtusizeImpl(
// Registered message handlers
private val messageHandlers = mutableListOf<VirtusizeMessageHandler>()

// Job to track and cancel the previous load operation
private var loadJob: Job? = null

// Tracks the last product loaded to detect product changes and allow re-loading on config changes
private var lastLoadedProduct: VirtusizeProduct? = null

// The Virtusize message handler passes received errors and events to registered message handlers
val messageHandler =
object : VirtusizeMessageHandler {
Expand Down Expand Up @@ -150,13 +157,19 @@ internal class VirtusizeImpl(

is VirtusizeEvent.UserUpdatedBodyMeasurements -> {
invalidateCurrentProduct()
// Updates the body recommendation size and switches the view to the body comparison
// Updates the body recommendation size and switches the view to the body comparison,
// then re-fetches the body profile and updates the recommendation again
val sizeRecName = event.data?.optString("sizeRecName")
scope.launch {
virtusizeRepository.updateUserBodyRecommendedSize(sizeRecName)
virtusizeRepository.updateInPageRecommendation(
type = SizeRecommendationType.Body,
)
virtusizeRepository.fetchDataForInPageRecommendation(
shouldUpdateUserProducts = false,
shouldUpdateBodyProfile = true,
)
virtusizeRepository.updateInPageRecommendation()
}
}

Expand Down Expand Up @@ -320,23 +333,22 @@ internal class VirtusizeImpl(
}

/**
* @see Virtusize.setApiKey
* @see Virtusize.changeStore
*/
override fun setApiKey(apiKey: String) {
override fun changeStore(
apiKey: String,
env: VirtusizeEnvironment,
) {
VirtusizeApi.setApiKey(apiKey)
virtusizeViews.forEach { virtusizeView ->
virtusizeView.virtusizeParams.apiKey = apiKey
}
}

/**
* @see Virtusize.setEnvironment
*/
override fun setEnvironment(env: VirtusizeEnvironment) {
VirtusizeApi.setEnvironment(env)
virtusizeViews.forEach { virtusizeView ->
virtusizeView.virtusizeParams.apiKey = apiKey
virtusizeView.virtusizeParams.environment = env
}
lastLoadedProduct?.let { product ->
invalidateCurrentProduct()
load(product)
}
}

/**
Expand All @@ -357,7 +369,12 @@ internal class VirtusizeImpl(
* @see Virtusize.load
*/
override fun load(virtusizeProduct: VirtusizeProduct) {
scope.launch {
if (lastLoadedProduct?.externalId != virtusizeProduct.externalId) {
invalidateCurrentProduct()
}
lastLoadedProduct = virtusizeProduct
loadJob?.cancel()
loadJob = scope.launch {
productCheck(virtusizeProduct)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import com.virtusize.android.data.local.throwError
import com.virtusize.android.data.local.virtusizeError
import com.virtusize.android.data.parsers.I18nLocalizationJsonParser
import com.virtusize.android.data.parsers.UserAuthDataJsonParser
import com.virtusize.android.data.remote.BodyProfileRecommendedSize
import com.virtusize.android.data.remote.I18nLocalization
import com.virtusize.android.data.remote.Product
import com.virtusize.android.data.remote.ProductCheckData
Expand Down Expand Up @@ -48,7 +49,7 @@ class VirtusizeRepository internal constructor(
private var userProducts: List<Product>? = null
private var userProductRecommendedSize: SizeComparisonRecommendedSize? = null
private var userBodyRecommendedSize: String? = null
private var userBodyWillFit: Boolean? = null
private var userBodyProfileRecommendedSize: BodyProfileRecommendedSize? = null

// This variable holds the list of product types from the Virtusize API
private var productTypes: List<ProductType>? = null
Expand Down Expand Up @@ -311,7 +312,9 @@ class VirtusizeRepository internal constructor(
// set `userBodyRecommendedSize` only when update is requested
if (shouldUpdateBodyProfile) {
// reset userBodyRecommendedSize if update is requested but hasSessionBodyMeasurement is false
userBodyRecommendedSize = recommendedSizeDeferred?.await()
val bodyProfileResult = recommendedSizeDeferred?.await()
userBodyProfileRecommendedSize = bodyProfileResult
userBodyRecommendedSize = bodyProfileResult?.sizeName
}

if (userProductsResponse != null) {
Expand Down Expand Up @@ -383,7 +386,7 @@ class VirtusizeRepository internal constructor(
externalProductId = productId,
userProductRecommendedSize = null,
userBodyRecommendedSize = userBodyRecommendedSize,
userBodyWillFit = userBodyWillFit,
userBodyWillFit = userBodyProfileRecommendedSize?.willFit,
)
}

Expand All @@ -392,7 +395,7 @@ class VirtusizeRepository internal constructor(
externalProductId = productId,
userProductRecommendedSize = userProductRecommendedSize,
userBodyRecommendedSize = userBodyRecommendedSize,
userBodyWillFit = userBodyWillFit,
userBodyWillFit = userBodyProfileRecommendedSize?.willFit,
)
}
}
Expand All @@ -410,21 +413,20 @@ class VirtusizeRepository internal constructor(
userProducts = null
userProductRecommendedSize = null
userBodyRecommendedSize = null
userBodyWillFit = null
userBodyProfileRecommendedSize = null
}

/**
* Gets size recommendation for a store product that would best fit a user's body.
* @param storeProduct the store product
* @param productTypes a list of product types
* @return recommended size name. If it's not available, return null
* @return [BodyProfileRecommendedSize] containing the size name and willFit flag, or null if not available
*/
private suspend fun getUserBodyRecommendedSize(
storeProduct: Product?,
productTypes: List<ProductType>?,
): String? {
): BodyProfileRecommendedSize? {
if (storeProduct == null || productTypes == null || storeProduct.isAccessory()) {
userBodyWillFit = null
return null
}
val userBodyProfileResponse = virtusizeAPIService.getUserBodyProfile()
Expand All @@ -436,24 +438,21 @@ class VirtusizeRepository internal constructor(
storeProduct,
userBodyProfileResponse.successData!!,
)
userBodyWillFit = bodyProfileRecommendedSizeResponse.successData?.willFit
return bodyProfileRecommendedSizeResponse.successData?.sizeName
return bodyProfileRecommendedSizeResponse.successData
} else {
val bodyProfileRecommendedSizeResponse =
virtusizeAPIService.getBodyProfileRecommendedItemSize(
productTypes,
storeProduct,
userBodyProfileResponse.successData!!,
)
userBodyWillFit = bodyProfileRecommendedSizeResponse.successData?.get(0)?.willFit
return bodyProfileRecommendedSizeResponse.successData?.get(0)?.sizeName
return bodyProfileRecommendedSizeResponse.successData?.get(0)
}
} else if (userBodyProfileResponse.failureData?.code != HttpURLConnection.HTTP_NOT_FOUND) {
userBodyProfileResponse.failureData?.let {
messageHandler.onError(it)
}
}
userBodyWillFit = null
return null
}

Expand Down
Loading