diff --git a/CHANGELOG.md b/CHANGELOG.md index 938c89d2..687c0952 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/virtusize/src/main/java/com/virtusize/android/Virtusize.kt b/virtusize/src/main/java/com/virtusize/android/Virtusize.kt index d15a7596..ba9efb27 100644 --- a/virtusize/src/main/java/com/virtusize/android/Virtusize.kt +++ b/virtusize/src/main/java/com/virtusize/android/Virtusize.kt @@ -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. diff --git a/virtusize/src/main/java/com/virtusize/android/VirtusizeImpl.kt b/virtusize/src/main/java/com/virtusize/android/VirtusizeImpl.kt index d32802c4..2054834b 100644 --- a/virtusize/src/main/java/com/virtusize/android/VirtusizeImpl.kt +++ b/virtusize/src/main/java/com/virtusize/android/VirtusizeImpl.kt @@ -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 @@ -47,6 +48,12 @@ internal class VirtusizeImpl( // Registered message handlers private val messageHandlers = mutableListOf() + // 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 { @@ -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() } } @@ -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) + } } /** @@ -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) } } diff --git a/virtusize/src/main/java/com/virtusize/android/VirtusizeRepository.kt b/virtusize/src/main/java/com/virtusize/android/VirtusizeRepository.kt index 6f57479e..8fad4316 100644 --- a/virtusize/src/main/java/com/virtusize/android/VirtusizeRepository.kt +++ b/virtusize/src/main/java/com/virtusize/android/VirtusizeRepository.kt @@ -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 @@ -48,7 +49,7 @@ class VirtusizeRepository internal constructor( private var userProducts: List? = 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? = null @@ -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) { @@ -383,7 +386,7 @@ class VirtusizeRepository internal constructor( externalProductId = productId, userProductRecommendedSize = null, userBodyRecommendedSize = userBodyRecommendedSize, - userBodyWillFit = userBodyWillFit, + userBodyWillFit = userBodyProfileRecommendedSize?.willFit, ) } @@ -392,7 +395,7 @@ class VirtusizeRepository internal constructor( externalProductId = productId, userProductRecommendedSize = userProductRecommendedSize, userBodyRecommendedSize = userBodyRecommendedSize, - userBodyWillFit = userBodyWillFit, + userBodyWillFit = userBodyProfileRecommendedSize?.willFit, ) } } @@ -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?, - ): String? { + ): BodyProfileRecommendedSize? { if (storeProduct == null || productTypes == null || storeProduct.isAccessory()) { - userBodyWillFit = null return null } val userBodyProfileResponse = virtusizeAPIService.getUserBodyProfile() @@ -436,8 +438,7 @@ class VirtusizeRepository internal constructor( storeProduct, userBodyProfileResponse.successData!!, ) - userBodyWillFit = bodyProfileRecommendedSizeResponse.successData?.willFit - return bodyProfileRecommendedSizeResponse.successData?.sizeName + return bodyProfileRecommendedSizeResponse.successData } else { val bodyProfileRecommendedSizeResponse = virtusizeAPIService.getBodyProfileRecommendedItemSize( @@ -445,15 +446,13 @@ class VirtusizeRepository internal constructor( 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 }