From bbd0b6e6a50618bc90e8c68f8944236c4259363a Mon Sep 17 00:00:00 2001 From: Alejo Date: Sun, 15 Sep 2024 23:46:04 -0600 Subject: [PATCH 001/162] check for plugin version --- .../details/ShippingLabelOnboardingRepository.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt index 908e68e3b6a..0de2e07d89c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt @@ -16,6 +16,7 @@ class ShippingLabelOnboardingRepository @Inject constructor( companion object { // The required version to support shipping label creation const val SUPPORTED_WCS_VERSION = "1.25.11" + const val SUPPORTED_WC_SHIPPING_VERSION = "1.0.6" const val SUPPORTED_WCS_CURRENCY = "USD" const val SUPPORTED_WCS_COUNTRY = "US" } @@ -53,8 +54,13 @@ class ShippingLabelOnboardingRepository @Inject constructor( }?.let { return true } orderDetailRepository.getWooShippingPluginInfo() - .takeIf { it.isPluginReady() && FeatureFlag.NEW_SHIPPING_SUPPORT.isEnabled() } - ?.let { return true } + .takeIf { + val pluginVersion = it.version ?: "0.0.0" + + it.isPluginReady() + && FeatureFlag.REVAMP_WOO_SHIPPING.isEnabled() + && pluginVersion.semverCompareTo(SUPPORTED_WC_SHIPPING_VERSION) >= 0 + }?.let { return true } return false } From e58467dd07da1827b47c5222603b5d0a8a528a4f Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Fri, 27 Sep 2024 16:46:53 +0100 Subject: [PATCH 002/162] Remove unused code --- .../LoginSiteCredentialsScreen.kt | 245 ++++++------------ .../LoginSiteCredentialsViewModel.kt | 143 +++------- .../LoginSiteCredentialsViewModelTest.kt | 33 --- 3 files changed, 113 insertions(+), 308 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsScreen.kt index 7040debd012..cdebf0ab85e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsScreen.kt @@ -17,7 +17,6 @@ import androidx.compose.material.Scaffold import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.Clear import androidx.compose.runtime.Composable import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment @@ -36,7 +35,6 @@ import com.woocommerce.android.ui.compose.component.WCOutlinedTextField import com.woocommerce.android.ui.compose.component.WCPasswordField import com.woocommerce.android.ui.compose.component.WCTextButton import com.woocommerce.android.ui.compose.component.getText -import com.woocommerce.android.ui.compose.component.web.WCWebView import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground @Composable @@ -50,8 +48,7 @@ fun LoginSiteCredentialsScreen(viewModel: LoginSiteCredentialsViewModel) { onResetPasswordClick = viewModel::onResetPasswordClick, onBackClick = viewModel::onBackClick, onHelpButtonClick = viewModel::onHelpButtonClick, - onErrorDialogDismissed = viewModel::onErrorDialogDismissed, - onWebAuthorizationUrlLoaded = viewModel::onWebAuthorizationUrlLoaded + onErrorDialogDismissed = viewModel::onErrorDialogDismissed ) } } @@ -66,7 +63,6 @@ fun LoginSiteCredentialsScreen( onBackClick: () -> Unit, onHelpButtonClick: () -> Unit, onErrorDialogDismissed: () -> Unit, - onWebAuthorizationUrlLoaded: (String) -> Unit ) { Scaffold( topBar = { @@ -74,204 +70,128 @@ fun LoginSiteCredentialsScreen( title = stringResource(id = R.string.log_in), onNavigationButtonClick = onBackClick, onHelpButtonClick = onHelpButtonClick, - navigationIcon = if (viewState is LoginSiteCredentialsViewModel.ViewState.WebAuthorizationViewState) { - Icons.Filled.Clear - } else { - Icons.AutoMirrored.Filled.ArrowBack - } + navigationIcon = Icons.AutoMirrored.Filled.ArrowBack ) } ) { paddingValues -> - when (viewState) { - is LoginSiteCredentialsViewModel.ViewState.NativeLoginViewState -> NativeLoginForm( - viewState = viewState, - onUsernameChanged = onUsernameChanged, - onPasswordChanged = onPasswordChanged, - onContinueClick = onContinueClick, - onResetPasswordClick = onResetPasswordClick, - onErrorDialogDismissed = onErrorDialogDismissed, - onHelpButtonClick = onHelpButtonClick, - modifier = Modifier.padding(paddingValues) - ) - - is LoginSiteCredentialsViewModel.ViewState.WebAuthorizationViewState -> WebAuthorizationScreen( - viewState = viewState, - onPageFinished = onWebAuthorizationUrlLoaded, - onErrorDialogDismissed = { - onErrorDialogDismissed() - onBackClick() - }, - modifier = Modifier.padding(paddingValues) - ) - } - } -} - -@Composable -private fun NativeLoginForm( - viewState: LoginSiteCredentialsViewModel.ViewState.NativeLoginViewState, - onUsernameChanged: (String) -> Unit, - onPasswordChanged: (String) -> Unit, - onContinueClick: () -> Unit, - onResetPasswordClick: () -> Unit, - onErrorDialogDismissed: () -> Unit, - onHelpButtonClick: () -> Unit, - modifier: Modifier = Modifier, -) { - Column( - modifier = modifier - .background(MaterialTheme.colors.surface) - .fillMaxSize(), - ) { Column( modifier = Modifier - .weight(1f) - .fillMaxWidth() - .verticalScroll(rememberScrollState()) - .padding(dimensionResource(id = R.dimen.major_100)), + .padding(paddingValues) + .background(MaterialTheme.colors.surface) + .fillMaxSize(), ) { - Text( - text = stringResource(id = R.string.enter_credentials_for_site, viewState.siteUrl), - style = MaterialTheme.typography.body2 - ) - Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_100))) - WCOutlinedTextField( - value = viewState.username, - onValueChange = onUsernameChanged, - label = stringResource(id = R.string.username), - singleLine = true, - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next) - ) - WCPasswordField( - value = viewState.password, - onValueChange = onPasswordChanged, - label = stringResource(id = R.string.password), - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), - keyboardActions = KeyboardActions( - onDone = { onContinueClick() } + Column( + modifier = Modifier + .weight(1f) + .fillMaxWidth() + .verticalScroll(rememberScrollState()) + .padding(dimensionResource(id = R.dimen.major_100)), + ) { + Text( + text = stringResource(id = R.string.enter_credentials_for_site, viewState.siteUrl), + style = MaterialTheme.typography.body2 ) - ) - WCTextButton(onClick = onResetPasswordClick) { - Text(text = stringResource(id = R.string.reset_your_password)) - } - } - - WCColoredButton( - onClick = onContinueClick, - enabled = viewState.isValid, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = dimensionResource(id = R.dimen.major_100)) - ) { - Text( - text = stringResource(id = R.string.continue_button) - ) - } - Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_100))) - } - - if (viewState.errorDialogMessage != null) { - AlertDialog( - text = { - Text(text = viewState.errorDialogMessage.getText()) - }, - onDismissRequest = onErrorDialogDismissed, - buttons = { - Column( - horizontalAlignment = Alignment.End, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = dimensionResource(id = R.dimen.major_100)) - ) { - WCTextButton( - onClick = { - onErrorDialogDismissed() - onHelpButtonClick() - } - ) { - Text(text = stringResource(id = R.string.login_site_address_more_help)) - } - WCTextButton( - onClick = onErrorDialogDismissed - ) { - Text( - text = stringResource(id = R.string.cancel), - textAlign = TextAlign.End - ) - } + Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_100))) + WCOutlinedTextField( + value = viewState.username, + onValueChange = onUsernameChanged, + label = stringResource(id = R.string.username), + singleLine = true, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next) + ) + WCPasswordField( + value = viewState.password, + onValueChange = onPasswordChanged, + label = stringResource(id = R.string.password), + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), + keyboardActions = KeyboardActions( + onDone = { onContinueClick() } + ) + ) + WCTextButton(onClick = onResetPasswordClick) { + Text(text = stringResource(id = R.string.reset_your_password)) } } - ) - } - - if (viewState.loadingMessage != null) { - ProgressDialog(title = "", subtitle = stringResource(id = viewState.loadingMessage)) - } -} -@Composable -private fun WebAuthorizationScreen( - viewState: LoginSiteCredentialsViewModel.ViewState.WebAuthorizationViewState, - onPageFinished: (String) -> Unit, - onErrorDialogDismissed: () -> Unit, - modifier: Modifier = Modifier, -) { - when { - viewState.loadingMessage != null -> { - ProgressDialog(title = "", subtitle = stringResource(id = viewState.loadingMessage)) + WCColoredButton( + onClick = onContinueClick, + enabled = viewState.isValid, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = dimensionResource(id = R.dimen.major_100)) + ) { + Text( + text = stringResource(id = R.string.continue_button) + ) + } + Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_100))) } - viewState.errorDialogMessage != null -> { + if (viewState.errorDialogMessage != null) { AlertDialog( text = { Text(text = viewState.errorDialogMessage.getText()) }, onDismissRequest = onErrorDialogDismissed, - confirmButton = { - WCTextButton( - onClick = onErrorDialogDismissed + buttons = { + Column( + horizontalAlignment = Alignment.End, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = dimensionResource(id = R.dimen.major_100)) ) { - Text(text = stringResource(id = android.R.string.ok)) + WCTextButton( + onClick = { + onErrorDialogDismissed() + onHelpButtonClick() + } + ) { + Text(text = stringResource(id = R.string.login_site_address_more_help)) + } + WCTextButton( + onClick = onErrorDialogDismissed + ) { + Text( + text = stringResource(id = R.string.cancel), + textAlign = TextAlign.End + ) + } } } ) } - viewState.authorizationUrl != null -> { - WCWebView( - url = viewState.authorizationUrl, - userAgent = viewState.userAgent, - onPageFinished = onPageFinished, - modifier = modifier - ) + if (viewState.loadingMessage != null) { + ProgressDialog(title = "", subtitle = stringResource(id = viewState.loadingMessage)) } } } @Preview @Composable -private fun NativeLoginFormPreview() { +private fun LoginSiteCredentialsScreenPreview() { WooThemeWithBackground { - NativeLoginForm( - viewState = LoginSiteCredentialsViewModel.ViewState.NativeLoginViewState( + LoginSiteCredentialsScreen( + viewState = LoginSiteCredentialsViewModel.ViewState( siteUrl = "https://wordpress.com" ), onUsernameChanged = {}, onPasswordChanged = {}, onContinueClick = {}, onResetPasswordClick = {}, - onErrorDialogDismissed = {}, - onHelpButtonClick = {} + onBackClick = {}, + onHelpButtonClick = {}, + onErrorDialogDismissed = {} ) } } @Preview @Composable -private fun NativeLoginFormWithErrorDialogPreview() { +private fun LoginSiteCredentialsScreenWithErrorPreview() { WooThemeWithBackground { - NativeLoginForm( - viewState = LoginSiteCredentialsViewModel.ViewState.NativeLoginViewState( + LoginSiteCredentialsScreen( + viewState = LoginSiteCredentialsViewModel.ViewState( siteUrl = "https://wordpress.com", errorDialogMessage = UiString.UiStringRes(R.string.login_site_credentials_fetching_site_failed) ), @@ -279,8 +199,9 @@ private fun NativeLoginFormWithErrorDialogPreview() { onPasswordChanged = {}, onContinueClick = {}, onResetPasswordClick = {}, - onErrorDialogDismissed = {}, - onHelpButtonClick = {} + onBackClick = {}, + onHelpButtonClick = {}, + onErrorDialogDismissed = {} ) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt index cfe241dae71..ade378f9e43 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt @@ -30,10 +30,7 @@ import com.woocommerce.android.viewmodel.ScopedViewModel import com.woocommerce.android.viewmodel.getNullableStateFlow import com.woocommerce.android.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map @@ -75,7 +72,6 @@ class LoginSiteCredentialsViewModel @Inject constructor( private val siteAddress: String = savedStateHandle[SITE_ADDRESS_KEY]!! - private val state = savedStateHandle.getStateFlow(viewModelScope, State.NativeLogin) private val errorDialogMessage = savedStateHandle.getNullableStateFlow( scope = viewModelScope, initialValue = null, @@ -90,17 +86,20 @@ class LoginSiteCredentialsViewModel @Inject constructor( get() = this?.applicationPasswordsAuthorizeUrl ?.let { url -> "$url?app_name=$applicationPasswordsClientId&success_url=$REDIRECTION_URL" } - @OptIn(ExperimentalCoroutinesApi::class) - val viewState = state.flatMapLatest { - // Reset loading and error state when the state changes - loadingMessage.value = 0 - errorDialogMessage.value = null - - when (it) { - State.NativeLogin -> prepareNativeLoginViewState() - State.WebAuthorization -> prepareWebAuthorizationViewState() - State.RetryWebAuthorization -> prepareWebAuthorizationViewState() - } + val viewState = combine( + flowOf(siteAddress.removeSchemeAndSuffix()), + savedStateHandle.getStateFlow(USERNAME_KEY, ""), + savedStateHandle.getStateFlow(PASSWORD_KEY, ""), + loadingMessage.map { message -> message.takeIf { it != 0 } }, + errorDialogMessage + ) { siteAddress, username, password, loadingMessage, errorDialog -> + ViewState( + siteUrl = siteAddress, + username = username, + password = password, + loadingMessage = loadingMessage, + errorDialogMessage = errorDialog + ) }.asLiveData() init { @@ -150,30 +149,15 @@ class LoginSiteCredentialsViewModel @Inject constructor( } fun onBackClick() { - if (state.value == State.WebAuthorization) { - fetchedSiteId.value = -1 - state.value = State.NativeLogin - } else { - triggerEvent(Exit) - } + triggerEvent(Exit) } fun onHelpButtonClick() { viewState.value?.let { - triggerEvent(ShowHelpScreen(siteAddress, (it as? ViewState.NativeLoginViewState)?.username.orEmpty())) + triggerEvent(ShowHelpScreen(siteAddress, it.username)) } } - /** - * This is currently a unreachable event due to the current usage of the application passwords feature - * available in the [ShowApplicationPasswordTutorialScreen] event, but it's kept here for future reference - * in case we need to start the Authorization from here back again. - */ - fun onStartWebAuthorizationClick() { - state.value = State.WebAuthorization - analyticsTracker.track(AnalyticsEvent.APPLICATION_PASSWORDS_AUTHORIZATION_WEB_VIEW_SHOWN) - } - fun onWebAuthorizationUrlLoaded(url: String) { if (url.startsWith(REDIRECTION_URL)) { launch { @@ -185,7 +169,6 @@ class LoginSiteCredentialsViewModel @Inject constructor( val isSuccess = params[SUCCESS_PARAMETER]?.toBoolean() ?: true if (!isSuccess) { fetchedSiteId.value = -1 - state.value = State.NativeLogin analyticsTracker.track(AnalyticsEvent.APPLICATION_PASSWORDS_AUTHORIZATION_REJECTED) triggerEvent(ShowSnackbar(R.string.login_site_credentials_web_authorization_connection_rejected)) @@ -208,53 +191,11 @@ class LoginSiteCredentialsViewModel @Inject constructor( } fun retryApplicationPasswordsCheck() = launch { - if (state.value == State.NativeLogin) { - // When using native login, retry fetching user info - fetchUserInfo() - } else { - // When using web authorization, retry fetching the site - fetchSite() - state.value = State.RetryWebAuthorization - } - } - - private fun prepareNativeLoginViewState(): Flow = combine( - flowOf(siteAddress.removeSchemeAndSuffix()), - savedStateHandle.getStateFlow(USERNAME_KEY, ""), - savedStateHandle.getStateFlow(PASSWORD_KEY, ""), - loadingMessage.map { message -> message.takeIf { it != 0 } }, - errorDialogMessage - ) { siteAddress, username, password, loadingMessage, errorDialog -> - ViewState.NativeLoginViewState( - siteUrl = siteAddress, - username = username, - password = password, - loadingMessage = loadingMessage, - errorDialogMessage = errorDialog - ) - } - - private fun prepareWebAuthorizationViewState(): Flow { - if (fetchedSiteId.value == -1) { - launch { fetchSite() } - } - - return combine( - loadingMessage.map { message -> message.takeIf { it != 0 } }, - errorDialogMessage, - fetchedSiteId.map { if (it == -1) null else wpApiSiteRepository.getSiteByLocalId(it) } - ) { loadingMessage, errorDialogMessage, site -> - ViewState.WebAuthorizationViewState( - authorizationUrl = site?.fullAuthorizationUrl, - userAgent = userAgent, - loadingMessage = loadingMessage, - errorDialogMessage = errorDialogMessage - ) - } + fetchUserInfo() } private suspend fun login() { - val state = requireNotNull(this@LoginSiteCredentialsViewModel.viewState.value as ViewState.NativeLoginViewState) + val state = requireNotNull(this@LoginSiteCredentialsViewModel.viewState.value) loadingMessage.value = R.string.logging_in wpApiSiteRepository.login( url = siteAddress, @@ -333,27 +274,16 @@ class LoginSiteCredentialsViewModel @Inject constructor( private suspend fun fetchSite() { val viewState = viewState.value - loadingMessage.value = if (state.value == State.WebAuthorization) { - R.string.login_site_credentials_fetching_site - } else { - R.string.logging_in - } + loadingMessage.value = R.string.logging_in wpApiSiteRepository.fetchSite( url = siteAddress, - username = (viewState as? ViewState.NativeLoginViewState)?.username, - password = (viewState as? ViewState.NativeLoginViewState)?.password + username = viewState?.username, + password = viewState?.password ).fold( onSuccess = { site -> if (site.hasWooCommerce) { fetchedSiteId.value = site.id - // In case of the native login, then continue with the login flow - // Otherwise, the web authorization flow will handle the login - if (state.value == State.NativeLogin) { - fetchUserInfo() - } else if (site.applicationPasswordsAuthorizeUrl.isNullOrEmpty()) { - analyticsTracker.track(AnalyticsEvent.APPLICATION_PASSWORDS_AUTHORIZATION_URL_NOT_AVAILABLE) - triggerEvent(ShowApplicationPasswordsUnavailableScreen(siteAddress, site.isJetpackConnected)) - } + fetchUserInfo() } else { triggerEvent(ShowNonWooErrorScreen(siteAddress)) } @@ -450,27 +380,14 @@ class LoginSiteCredentialsViewModel @Inject constructor( is UiStringText -> text } - private enum class State { - NativeLogin, WebAuthorization, RetryWebAuthorization - } - - sealed interface ViewState { - data class NativeLoginViewState( - val siteUrl: String, - val username: String = "", - val password: String = "", - @StringRes val loadingMessage: Int? = null, - val errorDialogMessage: UiString? = null - ) : ViewState { - val isValid = username.isNotBlank() && password.isNotBlank() - } - - data class WebAuthorizationViewState( - val authorizationUrl: String?, - val userAgent: UserAgent, - @StringRes val loadingMessage: Int? = null, - val errorDialogMessage: UiString? = null - ) : ViewState + data class ViewState( + val siteUrl: String, + val username: String = "", + val password: String = "", + @StringRes val loadingMessage: Int? = null, + val errorDialogMessage: UiString? = null + ) { + val isValid = username.isNotBlank() && password.isNotBlank() } @VisibleForTesting diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModelTest.kt index 03961ae494a..19b4f38b630 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModelTest.kt @@ -120,26 +120,6 @@ class LoginSiteCredentialsViewModelTest : BaseUnitTest() { ) } - @Test - fun `given shown login error dialog, when user chooses wp-admin login, then show login webview`() = testBlocking { - setup { - whenever(wpApiSiteRepository.getSiteByLocalId(testSite.id)).thenReturn( - testSite.apply { applicationPasswordsAuthorizeUrl = urlAuthBase } - ) - } - - val state = viewModel.viewState.runAndCaptureValues { - viewModel.onStartWebAuthorizationClick() - }.last() - - assertThat(state).isEqualTo( - LoginSiteCredentialsViewModel.ViewState.WebAuthorizationViewState( - authorizationUrl = urlAuthFull, - userAgent = userAgent - ) - ) - } - @Test fun `when changing username, then update state`() = testBlocking { setup() @@ -331,19 +311,6 @@ class LoginSiteCredentialsViewModelTest : BaseUnitTest() { .isEqualTo(ShowApplicationPasswordsUnavailableScreen(siteAddress, isJetpackConnected)) } - @Test - fun `given application pwd disabled and wp-login-php inaccessible, when choosing webview login, then show error`() = testBlocking { - setup() - - viewModel.viewState.observeForTesting { - viewModel.onStartWebAuthorizationClick() - applicationPasswordsUnavailableEvents.tryEmit(mock()) - } - - assertThat(viewModel.event.value) - .isEqualTo(ShowApplicationPasswordsUnavailableScreen(siteAddress, isJetpackConnected)) - } - @Test fun `give user role fetch fails, when submitting login, then show a snackbar`() = testBlocking { setup { From d51512b8e6c9981d0c38b9e1fd09c3b17402e713 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Fri, 27 Sep 2024 16:48:07 +0100 Subject: [PATCH 003/162] Retry the complete login after app passwords error screen --- .../ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt index ade378f9e43..62977a91471 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt @@ -191,7 +191,7 @@ class LoginSiteCredentialsViewModel @Inject constructor( } fun retryApplicationPasswordsCheck() = launch { - fetchUserInfo() + login() } private suspend fun login() { From 9b112904817ebb6e504b396d9a5e7b1553aafc23 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 3 Oct 2024 10:15:46 +0100 Subject: [PATCH 004/162] Remove unused property --- .../ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt index 62977a91471..eab7d103b07 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt @@ -38,7 +38,6 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.module.ApplicationPasswordsClientId -import org.wordpress.android.fluxc.network.UserAgent import org.wordpress.android.fluxc.network.rest.wpapi.Nonce.CookieNonceErrorType.INVALID_CREDENTIALS import org.wordpress.android.fluxc.store.SiteStore.SiteError import org.wordpress.android.login.LoginAnalyticsListener @@ -55,7 +54,6 @@ class LoginSiteCredentialsViewModel @Inject constructor( applicationPasswordsNotifier: ApplicationPasswordsNotifier, private val analyticsTracker: AnalyticsTrackerWrapper, private val appPrefs: AppPrefsWrapper, - private val userAgent: UserAgent, private val resourceProvider: ResourceProvider, @ApplicationPasswordsClientId private val applicationPasswordsClientId: String ) : ScopedViewModel(savedStateHandle) { From 3527a512ba8cf66b1ec691f7fd71d19de10ea6b6 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 3 Oct 2024 12:26:10 +0100 Subject: [PATCH 005/162] Fix unit tests --- .../LoginSiteCredentialsViewModelTest.kt | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModelTest.kt index 19b4f38b630..8376c4cbfcf 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModelTest.kt @@ -37,7 +37,6 @@ import org.mockito.kotlin.whenever import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.network.BaseRequest.BaseNetworkError import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType -import org.wordpress.android.fluxc.network.UserAgent import org.wordpress.android.fluxc.network.rest.wpapi.Nonce import org.wordpress.android.fluxc.network.rest.wpapi.WPAPINetworkError import org.wordpress.android.login.LoginAnalyticsListener @@ -74,7 +73,6 @@ class LoginSiteCredentialsViewModelTest : BaseUnitTest() { private val loginAnalyticsListener: LoginAnalyticsListener = mock() private val analyticsTracker: AnalyticsTrackerWrapper = mock() private val appPrefs: AppPrefsWrapper = mock() - private val userAgent: UserAgent = mock() private val resourceProvider: ResourceProvider = mock { on { getString(any()) } doAnswer { it.arguments[0].toString() } } @@ -97,7 +95,6 @@ class LoginSiteCredentialsViewModelTest : BaseUnitTest() { applicationPasswordsNotifier = applicationPasswordsNotifier, analyticsTracker = analyticsTracker, appPrefs = appPrefs, - userAgent = userAgent, applicationPasswordsClientId = clientId, resourceProvider = resourceProvider ) @@ -112,7 +109,7 @@ class LoginSiteCredentialsViewModelTest : BaseUnitTest() { }.last() assertThat(state).isEqualTo( - LoginSiteCredentialsViewModel.ViewState.NativeLoginViewState( + LoginSiteCredentialsViewModel.ViewState( siteUrl = siteAddressWithoutSchemeAndSuffix, username = "", password = "" @@ -126,7 +123,7 @@ class LoginSiteCredentialsViewModelTest : BaseUnitTest() { val state = viewModel.viewState.runAndCaptureValues { viewModel.onUsernameChanged(testUsername) - }.last() as LoginSiteCredentialsViewModel.ViewState.NativeLoginViewState + }.last() assertThat(state.username).isEqualTo(testUsername) } @@ -137,7 +134,7 @@ class LoginSiteCredentialsViewModelTest : BaseUnitTest() { val state = viewModel.viewState.runAndCaptureValues { viewModel.onUsernameChanged(testPassword) - }.last() as LoginSiteCredentialsViewModel.ViewState.NativeLoginViewState + }.last() assertThat(state.username).isEqualTo(testPassword) } @@ -148,7 +145,7 @@ class LoginSiteCredentialsViewModelTest : BaseUnitTest() { val state = viewModel.viewState.runAndCaptureValues { viewModel.onUsernameChanged("") - }.last() as LoginSiteCredentialsViewModel.ViewState.NativeLoginViewState + }.last() assertThat(state.isValid).isFalse() } @@ -159,7 +156,7 @@ class LoginSiteCredentialsViewModelTest : BaseUnitTest() { val state = viewModel.viewState.runAndCaptureValues { viewModel.onPasswordChanged("") - }.last() as LoginSiteCredentialsViewModel.ViewState.NativeLoginViewState + }.last() assertThat(state.isValid).isFalse() } @@ -224,7 +221,7 @@ class LoginSiteCredentialsViewModelTest : BaseUnitTest() { viewModel.onUsernameChanged(testUsername) viewModel.onPasswordChanged(testPassword) viewModel.onContinueClick() - }.last() as LoginSiteCredentialsViewModel.ViewState.NativeLoginViewState + }.last() assertThat(state.errorDialogMessage).isEqualTo(expectedError.errorMessage) verify(analyticsTracker).track( @@ -295,7 +292,7 @@ class LoginSiteCredentialsViewModelTest : BaseUnitTest() { } @Test - fun `given application pwd disabled and wp-login-php accessible, when submitting native login, then show error screen`() = testBlocking { + fun `given application pwd disabled and wp-login-php accessible, when submitting login, then show error screen`() = testBlocking { setup { whenever(wpApiSiteRepository.checkIfUserIsEligible(testSite)).thenReturn(Result.failure(Exception())) } From 9d0f1ebd524a12ed786a0785573c285361f52e1f Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 3 Oct 2024 13:28:58 +0100 Subject: [PATCH 006/162] Handle back button on site credentials webview authorization --- .../applicationpassword/ApplicationPasswordTutorialScreen.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/applicationpassword/ApplicationPasswordTutorialScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/applicationpassword/ApplicationPasswordTutorialScreen.kt index d072961f9ea..7b3a42ea372 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/applicationpassword/ApplicationPasswordTutorialScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/applicationpassword/ApplicationPasswordTutorialScreen.kt @@ -1,5 +1,6 @@ package com.woocommerce.android.ui.login.sitecredentials.applicationpassword +import androidx.activity.compose.BackHandler import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -38,6 +39,8 @@ import org.wordpress.android.fluxc.network.UserAgent @Composable fun ApplicationPasswordTutorialScreen(viewModel: ApplicationPasswordTutorialViewModel) { + BackHandler { viewModel.onNavigationButtonClicked() } + val viewState = viewModel.viewState.observeAsState() ApplicationPasswordTutorialScreen( authorizationStarted = viewState.value?.authorizationStarted ?: false, From 899afd177008b87e5e438b41433cac17bd3abaf3 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 3 Oct 2024 17:51:18 +0100 Subject: [PATCH 007/162] Force refetching the site when retrying application password check --- .../ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt index eab7d103b07..ec5f9d1809e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt @@ -189,6 +189,7 @@ class LoginSiteCredentialsViewModel @Inject constructor( } fun retryApplicationPasswordsCheck() = launch { + fetchedSiteId.value = -1 login() } From d16b6b4f2af27d78317cf28c38f98458651f6b38 Mon Sep 17 00:00:00 2001 From: Alejo Date: Thu, 3 Oct 2024 12:21:31 -0600 Subject: [PATCH 008/162] using the is operational function --- .../orders/details/ShippingLabelOnboardingRepository.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt index 0de2e07d89c..9d2884813f3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt @@ -50,20 +50,16 @@ class ShippingLabelOnboardingRepository @Inject constructor( orderDetailRepository.getWooServicesPluginInfo() .takeIf { val pluginVersion = it.version ?: "0.0.0" - it.isPluginReady() && pluginVersion.semverCompareTo(SUPPORTED_WCS_VERSION) >= 0 + it.isOperational && pluginVersion.semverCompareTo(SUPPORTED_WCS_VERSION) >= 0 }?.let { return true } orderDetailRepository.getWooShippingPluginInfo() .takeIf { val pluginVersion = it.version ?: "0.0.0" - - it.isPluginReady() - && FeatureFlag.REVAMP_WOO_SHIPPING.isEnabled() + it.isOperational && pluginVersion.semverCompareTo(SUPPORTED_WC_SHIPPING_VERSION) >= 0 }?.let { return true } return false } - - private fun WooPlugin.isPluginReady() = isInstalled && isActive } From e8b9fad84beaeacd2516e72351f3fb13e6ae3d4a Mon Sep 17 00:00:00 2001 From: Alejo Date: Thu, 3 Oct 2024 17:08:37 -0600 Subject: [PATCH 009/162] refactor add ShippingLabelSupport --- .../ui/orders/details/OrderDetailViewModel.kt | 8 +++--- .../ShippingLabelOnboardingRepository.kt | 27 ++++++++++++++----- .../ui/orders/OrderDetailViewModelTest.kt | 27 ++++++++++++------- .../ShippingLabelOnboardingRepositoryTest.kt | 6 ++--- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt index 848f5814ad2..2d808788d75 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt @@ -93,7 +93,7 @@ import org.wordpress.android.fluxc.store.WooCommerceStore import javax.inject.Inject @HiltViewModel -@Suppress("LargeClass") +@Suppress("LargeClass, LongParameterList") class OrderDetailViewModel @Inject constructor( savedState: SavedStateHandle, private val appPrefs: AppPrefs, @@ -770,7 +770,7 @@ class OrderDetailViewModel @Inject constructor( } private fun fetchSLCreationEligibilityAsync() = async { - if (shippingLabelOnboardingRepository.isShippingPluginReady) { + if (shippingLabelOnboardingRepository.shippingPluginSupport.isSupported()) { orderDetailRepository.fetchSLCreationEligibility(navArgs.orderId) } orderDetailsTransactionLauncher.onPackageCreationEligibleFetched() @@ -802,7 +802,7 @@ class OrderDetailViewModel @Inject constructor( } private fun fetchOrderShippingLabelsAsync() = async { - if (shippingLabelOnboardingRepository.isShippingPluginReady) { + if (shippingLabelOnboardingRepository.shippingPluginSupport.isSupported()) { orderDetailRepository.fetchOrderShippingLabels(navArgs.orderId) } orderDetailsTransactionLauncher.onShippingLabelFetchingCompleted() @@ -874,7 +874,7 @@ class OrderDetailViewModel @Inject constructor( val orderEligibleForInPersonPayments = viewState.orderInfo?.isPaymentCollectableWithCardReader == true - val isOrderEligibleForSLCreation = shippingLabelOnboardingRepository.isShippingPluginReady && + val isOrderEligibleForSLCreation = shippingLabelOnboardingRepository.shippingPluginSupport.isSupported() && orderDetailRepository.isOrderEligibleForSLCreation(order.id) && !orderEligibleForInPersonPayments diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt index 9d2884813f3..4febd93e858 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt @@ -3,7 +3,6 @@ package com.woocommerce.android.ui.orders.details import com.woocommerce.android.AppPrefsWrapper import com.woocommerce.android.extensions.semverCompareTo import com.woocommerce.android.model.Order -import com.woocommerce.android.model.WooPlugin import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.util.FeatureFlag import javax.inject.Inject @@ -21,10 +20,10 @@ class ShippingLabelOnboardingRepository @Inject constructor( const val SUPPORTED_WCS_COUNTRY = "US" } - val isShippingPluginReady: Boolean by lazy { isShippingLabelSupported() } + val shippingPluginSupport: ShippingLabelSupport by lazy { getShippingLabelSupport() } fun shouldShowWcShippingBanner(order: Order, eligibleForIpp: Boolean): Boolean = - !isShippingPluginReady && + !shippingPluginSupport.isSupported() && orderDetailRepository.getStoreCountryCode() == SUPPORTED_WCS_COUNTRY && order.currency == SUPPORTED_WCS_CURRENCY && !order.isCashPayment && @@ -46,20 +45,34 @@ class ShippingLabelOnboardingRepository @Inject constructor( } @Suppress("ReturnCount") - private fun isShippingLabelSupported(): Boolean { + private fun getShippingLabelSupport(): ShippingLabelSupport { orderDetailRepository.getWooServicesPluginInfo() .takeIf { val pluginVersion = it.version ?: "0.0.0" it.isOperational && pluginVersion.semverCompareTo(SUPPORTED_WCS_VERSION) >= 0 - }?.let { return true } + }?.let { return ShippingLabelSupport.WCS_SUPPORTED } orderDetailRepository.getWooShippingPluginInfo() .takeIf { val pluginVersion = it.version ?: "0.0.0" it.isOperational && pluginVersion.semverCompareTo(SUPPORTED_WC_SHIPPING_VERSION) >= 0 - }?.let { return true } + }?.let { + return if (FeatureFlag.REVAMP_WOO_SHIPPING.isEnabled()) { + ShippingLabelSupport.WC_SHIPPING_SUPPORTED + } else { + ShippingLabelSupport.WCS_SUPPORTED + } + } - return false + return ShippingLabelSupport.NOT_SUPPORTED + } + + enum class ShippingLabelSupport { + NOT_SUPPORTED, + WC_SHIPPING_SUPPORTED, + WCS_SUPPORTED; + + fun isSupported() = this == WCS_SUPPORTED || this == WC_SHIPPING_SUPPORTED } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/OrderDetailViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/OrderDetailViewModelTest.kt index 1182b58a429..30e849ca369 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/OrderDetailViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/OrderDetailViewModelTest.kt @@ -41,6 +41,7 @@ import com.woocommerce.android.ui.orders.details.OrderDetailsTransactionLauncher import com.woocommerce.android.ui.orders.details.OrderProduct import com.woocommerce.android.ui.orders.details.OrderProductMapper import com.woocommerce.android.ui.orders.details.ShippingLabelOnboardingRepository +import com.woocommerce.android.ui.orders.details.ShippingLabelOnboardingRepository.ShippingLabelSupport import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper import com.woocommerce.android.ui.payments.tracking.PaymentsFlowTracker @@ -120,7 +121,7 @@ class OrderDetailViewModelTest : BaseUnitTest() { } private val paymentCollectibilityChecker: CardReaderPaymentCollectibilityChecker = mock() private val shippingLabelOnboardingRepository: ShippingLabelOnboardingRepository = mock { - doReturn(true).whenever(it).isShippingPluginReady + doReturn(ShippingLabelSupport.WCS_SUPPORTED).whenever(it).shippingPluginSupport } private val savedState = OrderDetailFragmentArgs( @@ -643,7 +644,8 @@ class OrderDetailViewModelTest : BaseUnitTest() { doReturn(Unit).whenever(orderDetailRepository).fetchSLCreationEligibility(order.id) doReturn(true).whenever(orderDetailRepository).isOrderEligibleForSLCreation(order.id) - doReturn(true).whenever(shippingLabelOnboardingRepository).isShippingPluginReady + doReturn(ShippingLabelSupport.WCS_SUPPORTED) + .whenever(shippingLabelOnboardingRepository).shippingPluginSupport val shippingLabels = ArrayList() viewModel.shippingLabels.observeForever { @@ -684,7 +686,8 @@ class OrderDetailViewModelTest : BaseUnitTest() { doReturn(Unit).whenever(orderDetailRepository).fetchSLCreationEligibility(order.id) doReturn(true).whenever(orderDetailRepository).isOrderEligibleForSLCreation(order.id) - doReturn(true).whenever(shippingLabelOnboardingRepository).isShippingPluginReady + doReturn(ShippingLabelSupport.WCS_SUPPORTED) + .whenever(shippingLabelOnboardingRepository).shippingPluginSupport val shippingLabels = ArrayList() viewModel.shippingLabels.observeForever { @@ -997,7 +1000,8 @@ class OrderDetailViewModelTest : BaseUnitTest() { doReturn(emptyList()).whenever(orderDetailRepository).fetchOrderRefunds(any()) doReturn(emptyList()).whenever(orderDetailRepository).fetchProductsByRemoteIds(any()) doReturn(false).whenever(addonsRepository).containsAddonsFrom(any()) - doReturn(true).whenever(shippingLabelOnboardingRepository).isShippingPluginReady + doReturn(ShippingLabelSupport.WCS_SUPPORTED) + .whenever(shippingLabelOnboardingRepository).shippingPluginSupport var isCreateShippingLabelButtonVisible: Boolean? = null viewModel.viewStateData.observeForever { _, new -> @@ -1014,7 +1018,8 @@ class OrderDetailViewModelTest : BaseUnitTest() { testBlocking { doReturn(order).whenever(orderDetailRepository).getOrderById(any()) doReturn(order).whenever(orderDetailRepository).fetchOrderById(any()) - doReturn(false).whenever(shippingLabelOnboardingRepository).isShippingPluginReady + doReturn(ShippingLabelSupport.NOT_SUPPORTED) + .whenever(shippingLabelOnboardingRepository).shippingPluginSupport doReturn(true).whenever(orderDetailRepository).fetchOrderNotes(any()) doReturn(RequestResult.SUCCESS).whenever(orderDetailRepository).fetchOrderShipmentTrackingList(any()) doReturn(emptyList()).whenever(orderDetailRepository).fetchOrderRefunds(any()) @@ -1059,7 +1064,8 @@ class OrderDetailViewModelTest : BaseUnitTest() { @Test fun `hide shipping label creation if wcs plugin is not installed`() = testBlocking { - doReturn(false).whenever(shippingLabelOnboardingRepository).isShippingPluginReady + doReturn(ShippingLabelSupport.NOT_SUPPORTED) + .whenever(shippingLabelOnboardingRepository).shippingPluginSupport doReturn(order).whenever(orderDetailRepository).getOrderById(any()) doReturn(order).whenever(orderDetailRepository).fetchOrderById(any()) doReturn(true).whenever(orderDetailRepository).fetchOrderNotes(any()) @@ -1689,7 +1695,8 @@ class OrderDetailViewModelTest : BaseUnitTest() { @Test fun `when service plugin is installed and active, then fetch plugin data`() = testBlocking { - doReturn(true).whenever(shippingLabelOnboardingRepository).isShippingPluginReady + doReturn(ShippingLabelSupport.WCS_SUPPORTED) + .whenever(shippingLabelOnboardingRepository).shippingPluginSupport doReturn(order).whenever(orderDetailRepository).getOrderById(any()) doReturn(true).whenever(orderDetailRepository).fetchOrderNotes(any()) doReturn(true).whenever(addonsRepository).containsAddonsFrom(any()) @@ -1703,7 +1710,7 @@ class OrderDetailViewModelTest : BaseUnitTest() { @Test fun `when service plugin is NOT active, then DON'T fetch plugin data`() = testBlocking { - doReturn(false).whenever(shippingLabelOnboardingRepository).isShippingPluginReady + doReturn(ShippingLabelSupport.NOT_SUPPORTED).whenever(shippingLabelOnboardingRepository).shippingPluginSupport doReturn(order).whenever(orderDetailRepository).getOrderById(any()) doReturn(true).whenever(orderDetailRepository).fetchOrderNotes(any()) doReturn(true).whenever(addonsRepository).containsAddonsFrom(any()) @@ -1717,7 +1724,7 @@ class OrderDetailViewModelTest : BaseUnitTest() { @Test fun `when service plugin is NOT installed, then DON'T fetch plugin data`() = testBlocking { - doReturn(false).whenever(shippingLabelOnboardingRepository).isShippingPluginReady + doReturn(ShippingLabelSupport.NOT_SUPPORTED).whenever(shippingLabelOnboardingRepository).shippingPluginSupport doReturn(order).whenever(orderDetailRepository).getOrderById(any()) doReturn(true).whenever(orderDetailRepository).fetchOrderNotes(any()) doReturn(true).whenever(addonsRepository).containsAddonsFrom(any()) @@ -1788,7 +1795,7 @@ class OrderDetailViewModelTest : BaseUnitTest() { @Test fun `when there is no info about the plugins, then optimistically fetch plugin data`() = testBlocking { - doReturn(true).whenever(shippingLabelOnboardingRepository).isShippingPluginReady + doReturn(ShippingLabelSupport.WCS_SUPPORTED).whenever(shippingLabelOnboardingRepository).shippingPluginSupport doReturn(order).whenever(orderDetailRepository).getOrderById(any()) doReturn(true).whenever(orderDetailRepository).fetchOrderNotes(any()) doReturn(true).whenever(addonsRepository).containsAddonsFrom(any()) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepositoryTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepositoryTest.kt index ed5fff2ff84..9627d947a44 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepositoryTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepositoryTest.kt @@ -129,7 +129,7 @@ class ShippingLabelOnboardingRepositoryTest : BaseUnitTest() { givenWCShippingPlugin(installed = false, active = false) // When - val isShippingPluginReady = sut.isShippingPluginReady + val isShippingPluginReady = sut.shippingPluginSupport.isSupported() // Then assertThat(isShippingPluginReady).isTrue @@ -142,7 +142,7 @@ class ShippingLabelOnboardingRepositoryTest : BaseUnitTest() { givenWCShippingPlugin(installed = true, active = true) // When - val isShippingPluginReady = sut.isShippingPluginReady + val isShippingPluginReady = sut.shippingPluginSupport.isSupported() // Then assertThat(isShippingPluginReady).isTrue @@ -155,7 +155,7 @@ class ShippingLabelOnboardingRepositoryTest : BaseUnitTest() { givenWCShippingPlugin(installed = false, active = false) // When - val isShippingPluginReady = sut.isShippingPluginReady + val isShippingPluginReady = sut.shippingPluginSupport.isSupported() // Then assertThat(isShippingPluginReady).isFalse From 20352cc17ecf1e9b39ef6c115301c22f2f9e30d8 Mon Sep 17 00:00:00 2001 From: Alejo Date: Thu, 3 Oct 2024 17:12:15 -0600 Subject: [PATCH 010/162] fix detekt warning --- .../ui/orders/details/ShippingLabelOnboardingRepository.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt index 4febd93e858..85a1383e8f0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt @@ -55,8 +55,8 @@ class ShippingLabelOnboardingRepository @Inject constructor( orderDetailRepository.getWooShippingPluginInfo() .takeIf { val pluginVersion = it.version ?: "0.0.0" - it.isOperational - && pluginVersion.semverCompareTo(SUPPORTED_WC_SHIPPING_VERSION) >= 0 + it.isOperational && + pluginVersion.semverCompareTo(SUPPORTED_WC_SHIPPING_VERSION) >= 0 }?.let { return if (FeatureFlag.REVAMP_WOO_SHIPPING.isEnabled()) { ShippingLabelSupport.WC_SHIPPING_SUPPORTED From b909a095b26361352d8e65aaf1a3093537f064dd Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 27 Sep 2024 15:30:00 +0300 Subject: [PATCH 011/162] Deps: Migrate androidx lifecycle to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 4 ++-- WooCommerce/build.gradle | 6 +++--- build.gradle | 1 - gradle/libs.versions.toml | 8 ++++++++ quicklogin/build.gradle | 2 +- 5 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 gradle/libs.versions.toml diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 9af1466b7fb..a140ae66d51 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -167,8 +167,8 @@ dependencies { // Android Support implementation "androidx.work:work-runtime-ktx:$workManagerVersion" - implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycleVersion" - implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion" + implementation(libs.androidx.lifecycle.viewmodel.savedstate) + implementation(libs.androidx.lifecycle.livedata.ktx) implementation 'androidx.core:core-splashscreen:1.0.1' implementation "androidx.navigation:navigation-compose:2.7.7" implementation 'androidx.activity:activity-compose' diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 53282e4f365..884843298c2 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -409,8 +409,8 @@ dependencies { // ViewModel and LiveData implementation "androidx.fragment:fragment-ktx:1.8.2" implementation "androidx.activity:activity-ktx:1.8.0" - implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycleVersion" - implementation "androidx.lifecycle:lifecycle-process:$lifecycleVersion" + implementation(libs.androidx.lifecycle.viewmodel.savedstate) + implementation(libs.androidx.lifecycle.process) // Coroutines implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" @@ -448,7 +448,7 @@ dependencies { implementation 'androidx.hilt:hilt-navigation-compose:1.1.0' implementation 'androidx.constraintlayout:constraintlayout-compose:1.0.1' - implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2' + implementation(libs.androidx.lifecycle.viewmodel.compose) implementation "io.coil-kt:coil-compose:$coilVersion" implementation "io.coil-kt:coil-svg:$coilVersion" diff --git a/build.gradle b/build.gradle index cf6ae22a421..43704514632 100644 --- a/build.gradle +++ b/build.gradle @@ -109,7 +109,6 @@ ext { googlePlayCoreVersion = '1.10.3' googlePlayWearableVersion = '18.1.0' coroutinesVersion = '1.8.1' - lifecycleVersion = '2.7.0' aztecVersion = 'v2.1.4' flipperVersion = '0.176.1' stateMachineVersion = '0.2.0' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 00000000000..e99bb38f184 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,8 @@ +[versions] +androidx-lifecycle = '2.7.0' + +[libraries] +androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } +androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidx-lifecycle" } +androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } +androidx-lifecycle-viewmodel-savedstate = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-savedstate", version.ref = "androidx-lifecycle" } diff --git a/quicklogin/build.gradle b/quicklogin/build.gradle index d650e446700..52418400a3e 100644 --- a/quicklogin/build.gradle +++ b/quicklogin/build.gradle @@ -78,7 +78,7 @@ android { } dependencies { - implementation "androidx.lifecycle:lifecycle-process:$lifecycleVersion" + implementation(libs.androidx.lifecycle.process) implementation "androidx.test.uiautomator:uiautomator:2.2.0" implementation "junit:junit:$jUnitVersion" From 74382711e98bf280eeb988748210866da2001d41 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 15:55:40 +0300 Subject: [PATCH 012/162] Deps: Migrate androidx test uiautomator to version catalogs on all mods --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ quicklogin/build.gradle | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 884843298c2..f73029ae984 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -373,7 +373,7 @@ dependencies { } androidTestImplementation "com.google.dagger:hilt-android-testing:$gradle.ext.daggerVersion" kspAndroidTest "com.google.dagger:hilt-android-compiler:$gradle.ext.daggerVersion" - androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' + androidTestImplementation(libs.androidx.test.uiautomator) // Dependencies for screenshots androidTestImplementation 'tools.fastlane:screengrab:2.1.1' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e99bb38f184..99ba8b5d578 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,8 +1,10 @@ [versions] androidx-lifecycle = '2.7.0' +androidx-test-uiautomator = '2.2.0' [libraries] androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-savedstate = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-savedstate", version.ref = "androidx-lifecycle" } +androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidx-test-uiautomator" } diff --git a/quicklogin/build.gradle b/quicklogin/build.gradle index 52418400a3e..9abd0157617 100644 --- a/quicklogin/build.gradle +++ b/quicklogin/build.gradle @@ -80,7 +80,7 @@ android { dependencies { implementation(libs.androidx.lifecycle.process) - implementation "androidx.test.uiautomator:uiautomator:2.2.0" + implementation(libs.androidx.test.uiautomator) implementation "junit:junit:$jUnitVersion" implementation "androidx.test.ext:junit:$jUnitExtVersion" implementation "androidx.test:runner:$androidxTestCoreVersion" From ca33ceff035ed7a4f9d67e7ba95536515649f20e Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 15:57:18 +0300 Subject: [PATCH 013/162] Deps: Migrate junit to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ libs/iap/build.gradle | 2 +- quicklogin/build.gradle | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index a140ae66d51..bc12c2fcdd9 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -195,7 +195,7 @@ dependencies { ksp "com.google.dagger:dagger-android-processor:$gradle.ext.daggerVersion" // Testing - testImplementation "junit:junit:$jUnitVersion" + testImplementation(libs.junit) testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" testImplementation "org.mockito:mockito-inline:$mockitoVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index f73029ae984..ca1a6831151 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -352,7 +352,7 @@ dependencies { } // Dependencies for local unit tests - testImplementation "junit:junit:$jUnitVersion" + testImplementation(libs.junit) testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" testImplementation "org.mockito:mockito-inline:$mockitoVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" diff --git a/build.gradle b/build.gradle index 43704514632..b1fdc7b0015 100644 --- a/build.gradle +++ b/build.gradle @@ -146,7 +146,6 @@ ext { wearComposeVersion = "1.3.1" // Testing - jUnitVersion = '4.13.2' jUnitExtVersion = '1.1.5' androidxTestCoreVersion = '1.4.0' assertjVersion = '3.24.1' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 99ba8b5d578..79d9b716a59 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,7 @@ [versions] androidx-lifecycle = '2.7.0' androidx-test-uiautomator = '2.2.0' +junit = '4.13.2' [libraries] androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } @@ -8,3 +9,4 @@ androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-p androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-savedstate = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-savedstate", version.ref = "androidx-lifecycle" } androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidx-test-uiautomator" } +junit = { group = "junit", name = "junit", version.ref = "junit" } diff --git a/libs/iap/build.gradle b/libs/iap/build.gradle index 54032e4795a..81ec7fe6919 100644 --- a/libs/iap/build.gradle +++ b/libs/iap/build.gradle @@ -32,7 +32,7 @@ dependencies { implementation("com.android.billingclient:billing-ktx:$billingVersion") implementation "androidx.appcompat:appcompat:$appCompatVersion" - testImplementation "junit:junit:$jUnitVersion" + testImplementation(libs.junit) testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" testImplementation "org.mockito:mockito-inline:$mockitoVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" diff --git a/quicklogin/build.gradle b/quicklogin/build.gradle index 9abd0157617..0c8818cbaf7 100644 --- a/quicklogin/build.gradle +++ b/quicklogin/build.gradle @@ -81,7 +81,7 @@ dependencies { implementation(libs.androidx.lifecycle.process) implementation(libs.androidx.test.uiautomator) - implementation "junit:junit:$jUnitVersion" + implementation(libs.junit) implementation "androidx.test.ext:junit:$jUnitExtVersion" implementation "androidx.test:runner:$androidxTestCoreVersion" implementation "androidx.test:rules:$androidxTestCoreVersion" From b62244b4e806fdd6a2dd6e83234c97633b181e18 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 15:59:25 +0300 Subject: [PATCH 014/162] Deps: Migrate androidx test ext to version catalogs on all modules --- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ quicklogin/build.gradle | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index ca1a6831151..c2e0c31abf4 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -364,7 +364,7 @@ dependencies { }) // Dependencies for Espresso UI tests - androidTestImplementation "androidx.test.ext:junit:$jUnitExtVersion" + androidTestImplementation(libs.androidx.test.ext.junit) androidTestImplementation "androidx.test:rules:$androidxTestCoreVersion" androidTestImplementation "org.assertj:assertj-core:$assertjVersion" androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion" diff --git a/build.gradle b/build.gradle index b1fdc7b0015..befa80c4c38 100644 --- a/build.gradle +++ b/build.gradle @@ -146,7 +146,6 @@ ext { wearComposeVersion = "1.3.1" // Testing - jUnitExtVersion = '1.1.5' androidxTestCoreVersion = '1.4.0' assertjVersion = '3.24.1' espressoVersion = '3.4.0' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 79d9b716a59..f599407f03d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,6 @@ [versions] androidx-lifecycle = '2.7.0' +androidx-test-ext = '1.1.5' androidx-test-uiautomator = '2.2.0' junit = '4.13.2' @@ -8,5 +9,6 @@ androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecy androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-savedstate = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-savedstate", version.ref = "androidx-lifecycle" } +androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext" } androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidx-test-uiautomator" } junit = { group = "junit", name = "junit", version.ref = "junit" } diff --git a/quicklogin/build.gradle b/quicklogin/build.gradle index 0c8818cbaf7..a7be0537114 100644 --- a/quicklogin/build.gradle +++ b/quicklogin/build.gradle @@ -82,7 +82,7 @@ dependencies { implementation(libs.androidx.test.uiautomator) implementation(libs.junit) - implementation "androidx.test.ext:junit:$jUnitExtVersion" + implementation(libs.androidx.test.ext.junit) implementation "androidx.test:runner:$androidxTestCoreVersion" implementation "androidx.test:rules:$androidxTestCoreVersion" implementation "androidx.test:core:$androidxTestCoreVersion" From 7719a7d65347cde2e5b2dbaad9737ce664a9f7d5 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 16:01:32 +0300 Subject: [PATCH 015/162] Deps: Migrate androidx test main to version catalogs on all modules --- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 4 ++++ quicklogin/build.gradle | 6 +++--- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index c2e0c31abf4..742e405010f 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -365,7 +365,7 @@ dependencies { // Dependencies for Espresso UI tests androidTestImplementation(libs.androidx.test.ext.junit) - androidTestImplementation "androidx.test:rules:$androidxTestCoreVersion" + androidTestImplementation(libs.androidx.test.main.rules) androidTestImplementation "org.assertj:assertj-core:$assertjVersion" androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion" androidTestImplementation("androidx.test.espresso:espresso-contrib:$espressoVersion") { diff --git a/build.gradle b/build.gradle index befa80c4c38..f2ae3c55f3c 100644 --- a/build.gradle +++ b/build.gradle @@ -146,7 +146,6 @@ ext { wearComposeVersion = "1.3.1" // Testing - androidxTestCoreVersion = '1.4.0' assertjVersion = '3.24.1' espressoVersion = '3.4.0' mockitoKotlinVersion = '4.0.0' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f599407f03d..463a94039ff 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,7 @@ [versions] androidx-lifecycle = '2.7.0' androidx-test-ext = '1.1.5' +androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' junit = '4.13.2' @@ -10,5 +11,8 @@ androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-p androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-savedstate = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-savedstate", version.ref = "androidx-lifecycle" } androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext" } +androidx-test-main-core = { group = "androidx.test", name = "core", version.ref = "androidx-test-main" } +androidx-test-main-rules = { group = "androidx.test", name = "rules", version.ref = "androidx-test-main" } +androidx-test-main-runner = { group = "androidx.test", name = "runner", version.ref = "androidx-test-main" } androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidx-test-uiautomator" } junit = { group = "junit", name = "junit", version.ref = "junit" } diff --git a/quicklogin/build.gradle b/quicklogin/build.gradle index a7be0537114..9c87d9faad6 100644 --- a/quicklogin/build.gradle +++ b/quicklogin/build.gradle @@ -83,9 +83,9 @@ dependencies { implementation(libs.androidx.test.uiautomator) implementation(libs.junit) implementation(libs.androidx.test.ext.junit) - implementation "androidx.test:runner:$androidxTestCoreVersion" - implementation "androidx.test:rules:$androidxTestCoreVersion" - implementation "androidx.test:core:$androidxTestCoreVersion" + implementation(libs.androidx.test.main.runner) + implementation(libs.androidx.test.main.rules) + implementation(libs.androidx.test.main.core) } if (project.hasProperty("debugStoreFile")) { From 831ff5cd0c04b69e1e8c371d194e6fb7078eb087 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 16:04:03 +0300 Subject: [PATCH 016/162] Deps: Migrate stripe terminal to version catalogs on cardreader --- build.gradle | 1 - gradle/libs.versions.toml | 3 +++ libs/cardreader/build.gradle | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index f2ae3c55f3c..c402a2e52c3 100644 --- a/build.gradle +++ b/build.gradle @@ -124,7 +124,6 @@ ext { automatticTracksVersion = '5.0.0' workManagerVersion = '2.7.1' billingVersion = '5.0.0' - stripeTerminalVersion = '3.7.1' mlkitBarcodeScanningVersion = '17.2.0' mlkitTextRecognitionVersion = '16.0.0' androidxCameraVersion = '1.2.3' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 463a94039ff..b73ec84a01d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,6 +4,7 @@ androidx-test-ext = '1.1.5' androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' junit = '4.13.2' +stripe-terminal = '3.7.1' [libraries] androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } @@ -16,3 +17,5 @@ androidx-test-main-rules = { group = "androidx.test", name = "rules", version.re androidx-test-main-runner = { group = "androidx.test", name = "runner", version.ref = "androidx-test-main" } androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidx-test-uiautomator" } junit = { group = "junit", name = "junit", version.ref = "junit" } +stripe-terminal-localmobile = { group = "com.stripe", name = "stripeterminal-localmobile", version.ref = "stripe-terminal" } +stripe-terminal-core = { group = "com.stripe", name = "stripeterminal-core", version.ref = "stripe-terminal" } diff --git a/libs/cardreader/build.gradle b/libs/cardreader/build.gradle index e727516d5f3..63dff5d2dcb 100644 --- a/libs/cardreader/build.gradle +++ b/libs/cardreader/build.gradle @@ -27,8 +27,8 @@ android { } dependencies { - implementation "com.stripe:stripeterminal-localmobile:$stripeTerminalVersion" - implementation "com.stripe:stripeterminal-core:$stripeTerminalVersion" + implementation(libs.stripe.terminal.localmobile) + implementation(libs.stripe.terminal.core) // Coroutines implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" From ca0acb4ac2438cf110000a2fc11762cf7ebc3b60 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 16:11:22 +0300 Subject: [PATCH 017/162] Deps: Migrate kotlinx coroutines to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 8 ++++---- WooCommerce/build.gradle | 8 ++++---- build.gradle | 1 - gradle/libs.versions.toml | 5 +++++ libs/cardreader/build.gradle | 6 +++--- libs/iap/build.gradle | 6 +++--- 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index bc12c2fcdd9..42ad89d85e8 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -178,10 +178,10 @@ dependencies { implementation 'com.google.code.gson:gson:2.10.1' // Coroutines - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutinesVersion" - testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion" + implementation(libs.kotlinx.coroutines.core) + implementation(libs.kotlinx.coroutines.android) + implementation(libs.kotlinx.coroutines.play.services) + testImplementation(libs.kotlinx.coroutines.test) // Dagger & Hilt implementation "com.google.dagger:hilt-android:$gradle.ext.daggerVersion" diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 742e405010f..ece6a038826 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -413,10 +413,10 @@ dependencies { implementation(libs.androidx.lifecycle.process) // Coroutines - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutinesVersion" - testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion" + implementation(libs.kotlinx.coroutines.core) + implementation(libs.kotlinx.coroutines.android) + implementation(libs.kotlinx.coroutines.play.services) + testImplementation(libs.kotlinx.coroutines.test) testImplementation 'app.cash.turbine:turbine:1.0.0' diff --git a/build.gradle b/build.gradle index c402a2e52c3..777a099f5f7 100644 --- a/build.gradle +++ b/build.gradle @@ -108,7 +108,6 @@ ext { eventBusVersion = '3.3.1' googlePlayCoreVersion = '1.10.3' googlePlayWearableVersion = '18.1.0' - coroutinesVersion = '1.8.1' aztecVersion = 'v2.1.4' flipperVersion = '0.176.1' stateMachineVersion = '0.2.0' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b73ec84a01d..70e58081405 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,6 +4,7 @@ androidx-test-ext = '1.1.5' androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' junit = '4.13.2' +kotlinx-coroutines = '1.8.1' stripe-terminal = '3.7.1' [libraries] @@ -17,5 +18,9 @@ androidx-test-main-rules = { group = "androidx.test", name = "rules", version.re androidx-test-main-runner = { group = "androidx.test", name = "runner", version.ref = "androidx-test-main" } androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidx-test-uiautomator" } junit = { group = "junit", name = "junit", version.ref = "junit" } +kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } +kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } +kotlinx-coroutines-play-services = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-play-services", version.ref = "kotlinx-coroutines" } +kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } stripe-terminal-localmobile = { group = "com.stripe", name = "stripeterminal-localmobile", version.ref = "stripe-terminal" } stripe-terminal-core = { group = "com.stripe", name = "stripeterminal-core", version.ref = "stripe-terminal" } diff --git a/libs/cardreader/build.gradle b/libs/cardreader/build.gradle index 63dff5d2dcb..17ff82347ae 100644 --- a/libs/cardreader/build.gradle +++ b/libs/cardreader/build.gradle @@ -31,12 +31,12 @@ dependencies { implementation(libs.stripe.terminal.core) // Coroutines - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion" + implementation(libs.kotlinx.coroutines.core) + implementation(libs.kotlinx.coroutines.android) testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" testImplementation "org.mockito:mockito-inline:$mockitoVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" testImplementation "org.assertj:assertj-core:$assertjVersion" - testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion" + testImplementation(libs.kotlinx.coroutines.test) } diff --git a/libs/iap/build.gradle b/libs/iap/build.gradle index 81ec7fe6919..13c4e60617d 100644 --- a/libs/iap/build.gradle +++ b/libs/iap/build.gradle @@ -26,8 +26,8 @@ android { } dependencies { - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion" + implementation(libs.kotlinx.coroutines.core) + implementation(libs.kotlinx.coroutines.android) implementation("com.android.billingclient:billing-ktx:$billingVersion") implementation "androidx.appcompat:appcompat:$appCompatVersion" @@ -37,5 +37,5 @@ dependencies { testImplementation "org.mockito:mockito-inline:$mockitoVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" testImplementation "org.assertj:assertj-core:$assertjVersion" - testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion" + testImplementation(libs.kotlinx.coroutines.test) } From 43ac3f6d5d664c7fa9a65f0156b1897a9f8bde0a Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 16:21:48 +0300 Subject: [PATCH 018/162] Deps: Migrate mockito kotlin to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ libs/cardreader/build.gradle | 2 +- libs/iap/build.gradle | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 42ad89d85e8..5ce491157cf 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -196,7 +196,7 @@ dependencies { // Testing testImplementation(libs.junit) - testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" + testImplementation(libs.mockito.kotlin) testImplementation "org.mockito:mockito-inline:$mockitoVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" testImplementation "org.assertj:assertj-core:$assertjVersion" diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index ece6a038826..17f5667c393 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -353,7 +353,7 @@ dependencies { // Dependencies for local unit tests testImplementation(libs.junit) - testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" + testImplementation(libs.mockito.kotlin) testImplementation "org.mockito:mockito-inline:$mockitoVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" testImplementation "org.assertj:assertj-core:$assertjVersion" diff --git a/build.gradle b/build.gradle index 777a099f5f7..05d55b4da13 100644 --- a/build.gradle +++ b/build.gradle @@ -146,7 +146,6 @@ ext { // Testing assertjVersion = '3.24.1' espressoVersion = '3.4.0' - mockitoKotlinVersion = '4.0.0' mockitoVersion = '4.6.1' } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 70e58081405..538f7819de7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,6 +5,7 @@ androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' junit = '4.13.2' kotlinx-coroutines = '1.8.1' +mockito-kotlin = '4.0.0' stripe-terminal = '3.7.1' [libraries] @@ -22,5 +23,6 @@ kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx- kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-play-services = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-play-services", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } +mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockito-kotlin" } stripe-terminal-localmobile = { group = "com.stripe", name = "stripeterminal-localmobile", version.ref = "stripe-terminal" } stripe-terminal-core = { group = "com.stripe", name = "stripeterminal-core", version.ref = "stripe-terminal" } diff --git a/libs/cardreader/build.gradle b/libs/cardreader/build.gradle index 17ff82347ae..99d6e5eb18a 100644 --- a/libs/cardreader/build.gradle +++ b/libs/cardreader/build.gradle @@ -34,7 +34,7 @@ dependencies { implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.coroutines.android) - testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" + testImplementation(libs.mockito.kotlin) testImplementation "org.mockito:mockito-inline:$mockitoVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" testImplementation "org.assertj:assertj-core:$assertjVersion" diff --git a/libs/iap/build.gradle b/libs/iap/build.gradle index 13c4e60617d..a857a69ea3a 100644 --- a/libs/iap/build.gradle +++ b/libs/iap/build.gradle @@ -33,7 +33,7 @@ dependencies { implementation "androidx.appcompat:appcompat:$appCompatVersion" testImplementation(libs.junit) - testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" + testImplementation(libs.mockito.kotlin) testImplementation "org.mockito:mockito-inline:$mockitoVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" testImplementation "org.assertj:assertj-core:$assertjVersion" From f65ee2193342ff1ab3c7e2ad55712af721fec7f3 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 16:23:14 +0300 Subject: [PATCH 019/162] Deps: Migrate mockito inline to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ libs/cardreader/build.gradle | 2 +- libs/iap/build.gradle | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 5ce491157cf..f6a716c919d 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -197,7 +197,7 @@ dependencies { // Testing testImplementation(libs.junit) testImplementation(libs.mockito.kotlin) - testImplementation "org.mockito:mockito-inline:$mockitoVersion" + testImplementation(libs.mockito.inline) testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" testImplementation "org.assertj:assertj-core:$assertjVersion" testImplementation("androidx.arch.core:core-testing:2.1.0", { diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 17f5667c393..076d93ed71f 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -354,7 +354,7 @@ dependencies { // Dependencies for local unit tests testImplementation(libs.junit) testImplementation(libs.mockito.kotlin) - testImplementation "org.mockito:mockito-inline:$mockitoVersion" + testImplementation(libs.mockito.inline) testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" testImplementation "org.assertj:assertj-core:$assertjVersion" testImplementation("androidx.arch.core:core-testing:2.1.0", { diff --git a/build.gradle b/build.gradle index 05d55b4da13..73218234245 100644 --- a/build.gradle +++ b/build.gradle @@ -146,7 +146,6 @@ ext { // Testing assertjVersion = '3.24.1' espressoVersion = '3.4.0' - mockitoVersion = '4.6.1' } // Onboarding and dev env setup tasks diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 538f7819de7..12ca46d17aa 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,6 +5,7 @@ androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' junit = '4.13.2' kotlinx-coroutines = '1.8.1' +mockito-inline = '4.6.1' mockito-kotlin = '4.0.0' stripe-terminal = '3.7.1' @@ -23,6 +24,7 @@ kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx- kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-play-services = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-play-services", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } +mockito-inline = { group = "org.mockito", name = "mockito-inline", version.ref = "mockito-inline" } mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockito-kotlin" } stripe-terminal-localmobile = { group = "com.stripe", name = "stripeterminal-localmobile", version.ref = "stripe-terminal" } stripe-terminal-core = { group = "com.stripe", name = "stripeterminal-core", version.ref = "stripe-terminal" } diff --git a/libs/cardreader/build.gradle b/libs/cardreader/build.gradle index 99d6e5eb18a..685efa42fdb 100644 --- a/libs/cardreader/build.gradle +++ b/libs/cardreader/build.gradle @@ -35,7 +35,7 @@ dependencies { implementation(libs.kotlinx.coroutines.android) testImplementation(libs.mockito.kotlin) - testImplementation "org.mockito:mockito-inline:$mockitoVersion" + testImplementation(libs.mockito.inline) testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" testImplementation "org.assertj:assertj-core:$assertjVersion" testImplementation(libs.kotlinx.coroutines.test) diff --git a/libs/iap/build.gradle b/libs/iap/build.gradle index a857a69ea3a..50b8a9c3875 100644 --- a/libs/iap/build.gradle +++ b/libs/iap/build.gradle @@ -34,7 +34,7 @@ dependencies { testImplementation(libs.junit) testImplementation(libs.mockito.kotlin) - testImplementation "org.mockito:mockito-inline:$mockitoVersion" + testImplementation(libs.mockito.inline) testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" testImplementation "org.assertj:assertj-core:$assertjVersion" testImplementation(libs.kotlinx.coroutines.test) From 2255b40171fbe17e0a673e756584abff2dd50513 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 16:25:36 +0300 Subject: [PATCH 020/162] Deps: Migrate assertj to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 4 ++-- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ libs/cardreader/build.gradle | 2 +- libs/iap/build.gradle | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index f6a716c919d..6667e049cb5 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -199,7 +199,7 @@ dependencies { testImplementation(libs.mockito.kotlin) testImplementation(libs.mockito.inline) testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" - testImplementation "org.assertj:assertj-core:$assertjVersion" + testImplementation(libs.assertj.core) testImplementation("androidx.arch.core:core-testing:2.1.0", { exclude group: 'com.android.support', module: 'support-compat' exclude group: 'com.android.support', module: 'support-annotations' diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 076d93ed71f..1492d3e35cc 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -356,7 +356,7 @@ dependencies { testImplementation(libs.mockito.kotlin) testImplementation(libs.mockito.inline) testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" - testImplementation "org.assertj:assertj-core:$assertjVersion" + testImplementation(libs.assertj.core) testImplementation("androidx.arch.core:core-testing:2.1.0", { exclude group: 'com.android.support', module: 'support-compat' exclude group: 'com.android.support', module: 'support-annotations' @@ -366,7 +366,7 @@ dependencies { // Dependencies for Espresso UI tests androidTestImplementation(libs.androidx.test.ext.junit) androidTestImplementation(libs.androidx.test.main.rules) - androidTestImplementation "org.assertj:assertj-core:$assertjVersion" + androidTestImplementation(libs.assertj.core) androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion" androidTestImplementation("androidx.test.espresso:espresso-contrib:$espressoVersion") { exclude group: "com.google.protobuf", module: "protobuf-lite" diff --git a/build.gradle b/build.gradle index 73218234245..34353168135 100644 --- a/build.gradle +++ b/build.gradle @@ -144,7 +144,6 @@ ext { wearComposeVersion = "1.3.1" // Testing - assertjVersion = '3.24.1' espressoVersion = '3.4.0' } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 12ca46d17aa..cc7bc756494 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,6 +3,7 @@ androidx-lifecycle = '2.7.0' androidx-test-ext = '1.1.5' androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' +assertj = '3.24.1' junit = '4.13.2' kotlinx-coroutines = '1.8.1' mockito-inline = '4.6.1' @@ -19,6 +20,7 @@ androidx-test-main-core = { group = "androidx.test", name = "core", version.ref androidx-test-main-rules = { group = "androidx.test", name = "rules", version.ref = "androidx-test-main" } androidx-test-main-runner = { group = "androidx.test", name = "runner", version.ref = "androidx-test-main" } androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidx-test-uiautomator" } +assertj-core = { group = "org.assertj", name = "assertj-core", version.ref = "assertj" } junit = { group = "junit", name = "junit", version.ref = "junit" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } diff --git a/libs/cardreader/build.gradle b/libs/cardreader/build.gradle index 685efa42fdb..56d00f6cec5 100644 --- a/libs/cardreader/build.gradle +++ b/libs/cardreader/build.gradle @@ -37,6 +37,6 @@ dependencies { testImplementation(libs.mockito.kotlin) testImplementation(libs.mockito.inline) testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" - testImplementation "org.assertj:assertj-core:$assertjVersion" + testImplementation(libs.assertj.core) testImplementation(libs.kotlinx.coroutines.test) } diff --git a/libs/iap/build.gradle b/libs/iap/build.gradle index 50b8a9c3875..de3a8b4e4ee 100644 --- a/libs/iap/build.gradle +++ b/libs/iap/build.gradle @@ -36,6 +36,6 @@ dependencies { testImplementation(libs.mockito.kotlin) testImplementation(libs.mockito.inline) testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" - testImplementation "org.assertj:assertj-core:$assertjVersion" + testImplementation(libs.assertj.core) testImplementation(libs.kotlinx.coroutines.test) } From 03bd87556b20f2a565087c89496c6b69cd52d8b0 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 16:26:57 +0300 Subject: [PATCH 021/162] Deps: Migrate android billingclient to version catalogs on iap --- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ libs/iap/build.gradle | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 34353168135..384ebf6d6de 100644 --- a/build.gradle +++ b/build.gradle @@ -122,7 +122,6 @@ ext { aboutAutomatticVersion = '0.0.6' automatticTracksVersion = '5.0.0' workManagerVersion = '2.7.1' - billingVersion = '5.0.0' mlkitBarcodeScanningVersion = '17.2.0' mlkitTextRecognitionVersion = '16.0.0' androidxCameraVersion = '1.2.3' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cc7bc756494..fd3b1f4e230 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,4 +1,5 @@ [versions] +android-billingclient = '5.0.0' androidx-lifecycle = '2.7.0' androidx-test-ext = '1.1.5' androidx-test-main = '1.4.0' @@ -11,6 +12,7 @@ mockito-kotlin = '4.0.0' stripe-terminal = '3.7.1' [libraries] +android-billingclient-ktx = { group = "com.android.billingclient", name = "billing-ktx", version.ref = "android-billingclient" } androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } diff --git a/libs/iap/build.gradle b/libs/iap/build.gradle index de3a8b4e4ee..46c9f746a67 100644 --- a/libs/iap/build.gradle +++ b/libs/iap/build.gradle @@ -29,7 +29,7 @@ dependencies { implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.coroutines.android) - implementation("com.android.billingclient:billing-ktx:$billingVersion") + implementation(libs.android.billingclient.ktx) implementation "androidx.appcompat:appcompat:$appCompatVersion" testImplementation(libs.junit) From 98b1d702428777834eda04020a7ca1f40c162f4d Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 16:29:13 +0300 Subject: [PATCH 022/162] Deps: Migrate androidx appcompat to version catalogs on all modules --- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ libs/iap/build.gradle | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 1492d3e35cc..875ca23302a 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -238,7 +238,7 @@ dependencies { implementation "androidx.constraintlayout:constraintlayout:2.1.4" implementation "androidx.recyclerview:recyclerview:1.3.2" implementation "androidx.recyclerview:recyclerview-selection:1.1.0" - implementation "androidx.appcompat:appcompat:$appCompatVersion" + implementation(libs.androidx.appcompat) implementation "com.google.android.material:material:$materialVersion" implementation "androidx.transition:transition:$transitionVersion" implementation "androidx.cardview:cardview:1.0.0" diff --git a/build.gradle b/build.gradle index 384ebf6d6de..708cf328841 100644 --- a/build.gradle +++ b/build.gradle @@ -112,7 +112,6 @@ ext { flipperVersion = '0.176.1' stateMachineVersion = '0.2.0' coreKtxVersion = '1.13.1' - appCompatVersion = '1.4.2' materialVersion = '1.12.0' transitionVersion = '1.5.1' hiltJetpackVersion = '1.1.0' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fd3b1f4e230..4419c6cf882 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,6 @@ [versions] android-billingclient = '5.0.0' +androidx-appcompat = '1.4.2' androidx-lifecycle = '2.7.0' androidx-test-ext = '1.1.5' androidx-test-main = '1.4.0' @@ -13,6 +14,7 @@ stripe-terminal = '3.7.1' [libraries] android-billingclient-ktx = { group = "com.android.billingclient", name = "billing-ktx", version.ref = "android-billingclient" } +androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } diff --git a/libs/iap/build.gradle b/libs/iap/build.gradle index 46c9f746a67..6f24abc5dfb 100644 --- a/libs/iap/build.gradle +++ b/libs/iap/build.gradle @@ -30,7 +30,7 @@ dependencies { implementation(libs.kotlinx.coroutines.android) implementation(libs.android.billingclient.ktx) - implementation "androidx.appcompat:appcompat:$appCompatVersion" + implementation(libs.androidx.appcompat) testImplementation(libs.junit) testImplementation(libs.mockito.kotlin) From 4c7fcd564fe6105334394eab6f60d94ce7075b6d Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 16:30:44 +0300 Subject: [PATCH 023/162] Deps: Migrate wordpress libaddressinput to version catalogs on wc --- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 875ca23302a..e64b1b41ebf 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -221,7 +221,7 @@ android { } dependencies { - implementation("org.wordpress:libaddressinput.common:$libaddressinputVersion") { + implementation(libs.wordpress.libaddressinput.common) { exclude group: "org.json", module: "json" exclude group: "com.google.guava", module: "guava" } diff --git a/build.gradle b/build.gradle index 708cf328841..d4438f7a455 100644 --- a/build.gradle +++ b/build.gradle @@ -104,7 +104,6 @@ ext { glideVersion = '4.16.0' coilVersion = '2.1.0' constraintLayoutVersion = '1.2.0' - libaddressinputVersion = '0.0.2' eventBusVersion = '3.3.1' googlePlayCoreVersion = '1.10.3' googlePlayWearableVersion = '18.1.0' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4419c6cf882..b7bdaaaab8e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,6 +11,7 @@ kotlinx-coroutines = '1.8.1' mockito-inline = '4.6.1' mockito-kotlin = '4.0.0' stripe-terminal = '3.7.1' +wordpress-libaddressinput = '0.0.2' [libraries] android-billingclient-ktx = { group = "com.android.billingclient", name = "billing-ktx", version.ref = "android-billingclient" } @@ -34,3 +35,4 @@ mockito-inline = { group = "org.mockito", name = "mockito-inline", version.ref = mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockito-kotlin" } stripe-terminal-localmobile = { group = "com.stripe", name = "stripeterminal-localmobile", version.ref = "stripe-terminal" } stripe-terminal-core = { group = "com.stripe", name = "stripeterminal-core", version.ref = "stripe-terminal" } +wordpress-libaddressinput-common = { group = "org.wordpress", name = "libaddressinput.common", version.ref = "wordpress-libaddressinput" } From ffd32093f33f7df5879657e509621cea2ccbda0e Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 16:32:47 +0300 Subject: [PATCH 024/162] Deps: Migrate google firebase to version catalogs on woocommerce --- WooCommerce/build.gradle | 8 ++++---- gradle/libs.versions.toml | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index e64b1b41ebf..8f460b57f84 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -226,10 +226,10 @@ dependencies { exclude group: "com.google.guava", module: "guava" } - implementation platform('com.google.firebase:firebase-bom:32.7.1') - implementation 'com.google.firebase:firebase-messaging' - implementation 'com.google.firebase:firebase-config' - implementation 'com.google.firebase:firebase-analytics' + implementation(platform(libs.google.firebase.bom)) + implementation(libs.google.firebase.messaging) + implementation(libs.google.firebase.config) + implementation(libs.google.firebase.analytics) implementation 'com.google.android.gms:play-services-auth:20.2.0' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b7bdaaaab8e..f72e280ab36 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,6 +6,7 @@ androidx-test-ext = '1.1.5' androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' assertj = '3.24.1' +google-firebase-bom = '32.7.1' junit = '4.13.2' kotlinx-coroutines = '1.8.1' mockito-inline = '4.6.1' @@ -26,6 +27,10 @@ androidx-test-main-rules = { group = "androidx.test", name = "rules", version.re androidx-test-main-runner = { group = "androidx.test", name = "runner", version.ref = "androidx-test-main" } androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidx-test-uiautomator" } assertj-core = { group = "org.assertj", name = "assertj-core", version.ref = "assertj" } +google-firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics" } +google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } +google-firebase-config = { group = "com.google.firebase", name = "firebase-config" } +google-firebase-messaging = { group = "com.google.firebase", name = "firebase-messaging" } junit = { group = "junit", name = "junit", version.ref = "junit" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } From 9838d5d0e070f255675f803b66070e51732dbf56 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 16:35:11 +0300 Subject: [PATCH 025/162] Deps: Migrate google play services to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 6 +++--- build.gradle | 1 - gradle/libs.versions.toml | 6 ++++++ 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 6667e049cb5..b812cf6b8ab 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -143,7 +143,7 @@ dependencies { implementation "com.automattic.tracks:crashlogging:$automatticTracksVersion" // WearOS - implementation "com.google.android.gms:play-services-wearable:$googlePlayWearableVersion" + implementation(libs.google.play.services.wearable) implementation 'androidx.wear.tiles:tiles' implementation 'androidx.wear.tiles:tiles-material' implementation "com.google.android.horologist:horologist-compose-tools:$wearHorologistVersion" diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 8f460b57f84..d1a64287b53 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -231,7 +231,7 @@ dependencies { implementation(libs.google.firebase.config) implementation(libs.google.firebase.analytics) - implementation 'com.google.android.gms:play-services-auth:20.2.0' + implementation(libs.google.play.services.auth) // Support library implementation "androidx.core:core-ktx:$coreKtxVersion" @@ -325,7 +325,7 @@ dependencies { implementation 'com.google.android.play:app-update:2.1.0' implementation 'com.google.android.play:review:2.0.1' - implementation 'com.google.android.gms:play-services-code-scanner:16.1.0' + implementation(libs.google.play.services.code.scanner) implementation "com.google.mlkit:text-recognition:$mlkitTextRecognitionVersion" implementation "com.google.android.gms:play-services-mlkit-text-recognition-japanese:$mlkitTextRecognitionVersion" @@ -335,7 +335,7 @@ dependencies { implementation "com.google.mlkit:barcode-scanning:$mlkitBarcodeScanningVersion" implementation "com.google.zxing:core:3.5.3" - implementation "com.google.android.gms:play-services-wearable:$googlePlayWearableVersion" + implementation(libs.google.play.services.wearable) // Debug dependencies debugImplementation "com.facebook.flipper:flipper:$flipperVersion" diff --git a/build.gradle b/build.gradle index d4438f7a455..33e6be61f87 100644 --- a/build.gradle +++ b/build.gradle @@ -106,7 +106,6 @@ ext { constraintLayoutVersion = '1.2.0' eventBusVersion = '3.3.1' googlePlayCoreVersion = '1.10.3' - googlePlayWearableVersion = '18.1.0' aztecVersion = 'v2.1.4' flipperVersion = '0.176.1' stateMachineVersion = '0.2.0' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f72e280ab36..991044019c1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,6 +7,9 @@ androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' assertj = '3.24.1' google-firebase-bom = '32.7.1' +google-play-services-auth = '20.2.0' +google-play-services-code-scanner = '16.1.0' +google-play-services-wearable = '18.1.0' junit = '4.13.2' kotlinx-coroutines = '1.8.1' mockito-inline = '4.6.1' @@ -31,6 +34,9 @@ google-firebase-analytics = { group = "com.google.firebase", name = "firebase-an google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } google-firebase-config = { group = "com.google.firebase", name = "firebase-config" } google-firebase-messaging = { group = "com.google.firebase", name = "firebase-messaging" } +google-play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "google-play-services-auth" } +google-play-services-code-scanner = { group = "com.google.android.gms", name = "play-services-code-scanner", version.ref = "google-play-services-code-scanner" } +google-play-services-wearable = { group = "com.google.android.gms", name = "play-services-wearable", version.ref = "google-play-services-wearable" } junit = { group = "junit", name = "junit", version.ref = "junit" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } From 9df67a762b1613143c35af6bcf6583189a333cd2 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 16:40:25 +0300 Subject: [PATCH 026/162] Deps: Migrate google mlkit to version catalogs on woocommerce FYI: Notice that the Japanese, Chinese and Korea 'Text Recognition' related dependencies are not 'Google MLKit' related but actually 'Google Play Services' related. However, to keep things simple and since the version is coming from 'Google MLKit' and it main 'Text Recognition' dependency the overall version catalog is pointing to 'Google MLKit' and not 'Google Play Services'. --- WooCommerce/build.gradle | 10 +++++----- build.gradle | 2 -- gradle/libs.versions.toml | 7 +++++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index d1a64287b53..8bd63997cce 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -327,12 +327,12 @@ dependencies { implementation(libs.google.play.services.code.scanner) - implementation "com.google.mlkit:text-recognition:$mlkitTextRecognitionVersion" - implementation "com.google.android.gms:play-services-mlkit-text-recognition-japanese:$mlkitTextRecognitionVersion" - implementation "com.google.android.gms:play-services-mlkit-text-recognition-chinese:$mlkitTextRecognitionVersion" - implementation "com.google.android.gms:play-services-mlkit-text-recognition-korean:$mlkitTextRecognitionVersion" + implementation(libs.google.mlkit.text.recognition.main) + implementation(libs.google.mlkit.text.recognition.japanese) + implementation(libs.google.mlkit.text.recognition.chinese) + implementation(libs.google.mlkit.text.recognition.korean) - implementation "com.google.mlkit:barcode-scanning:$mlkitBarcodeScanningVersion" + implementation(libs.google.mlkit.barcode.scanning) implementation "com.google.zxing:core:3.5.3" implementation(libs.google.play.services.wearable) diff --git a/build.gradle b/build.gradle index 33e6be61f87..3b879e1f01c 100644 --- a/build.gradle +++ b/build.gradle @@ -119,8 +119,6 @@ ext { aboutAutomatticVersion = '0.0.6' automatticTracksVersion = '5.0.0' workManagerVersion = '2.7.1' - mlkitBarcodeScanningVersion = '17.2.0' - mlkitTextRecognitionVersion = '16.0.0' androidxCameraVersion = '1.2.3' guavaVersion = '33.1.0-android' protobufVersion = '3.25.3' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 991044019c1..07821b663cc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,6 +7,8 @@ androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' assertj = '3.24.1' google-firebase-bom = '32.7.1' +google-mlkit-barcode-scanning = '17.2.0' +google-mlkit-text-recognition = '16.0.0' google-play-services-auth = '20.2.0' google-play-services-code-scanner = '16.1.0' google-play-services-wearable = '18.1.0' @@ -34,6 +36,11 @@ google-firebase-analytics = { group = "com.google.firebase", name = "firebase-an google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } google-firebase-config = { group = "com.google.firebase", name = "firebase-config" } google-firebase-messaging = { group = "com.google.firebase", name = "firebase-messaging" } +google-mlkit-barcode-scanning = { group = "com.google.mlkit", name = "barcode-scanning", version.ref = "google-mlkit-barcode-scanning" } +google-mlkit-text-recognition-main = { group = "com.google.mlkit", name = "text-recognition", version.ref = "google-mlkit-text-recognition" } +google-mlkit-text-recognition-japanese = { group = "com.google.android.gms", name = "play-services-mlkit-text-recognition-japanese", version.ref = "google-mlkit-text-recognition" } +google-mlkit-text-recognition-chinese = { group = "com.google.android.gms", name = "play-services-mlkit-text-recognition-chinese", version.ref = "google-mlkit-text-recognition" } +google-mlkit-text-recognition-korean = { group = "com.google.android.gms", name = "play-services-mlkit-text-recognition-korean", version.ref = "google-mlkit-text-recognition" } google-play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "google-play-services-auth" } google-play-services-code-scanner = { group = "com.google.android.gms", name = "play-services-code-scanner", version.ref = "google-play-services-code-scanner" } google-play-services-wearable = { group = "com.google.android.gms", name = "play-services-wearable", version.ref = "google-play-services-wearable" } From d967e755d837f837b3a693b4610ded7729f1fb89 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Wed, 2 Oct 2024 16:42:33 +0300 Subject: [PATCH 027/162] Deps: Migrate androidx core to version catalogs on all modules FYI: Notice that the 'AndroidX Core Splashscreen' version on the 'WooCommerce' module is pointing to '1.0.0', while on the 'WooCommerce-Wear' module it is pointing to '1.0.1'. This change also updates the 'WooCommerce' version to point to '1.0.1' as well, it being just a batch update that includes a single bugfix and no more. Release Notes: https://developer.android.com/jetpack/androidx/releases/ core#core-splashscreen-1.0.1 --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 4 ++-- build.gradle | 1 - gradle/libs.versions.toml | 4 ++++ 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index b812cf6b8ab..26dbd39247a 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -169,7 +169,7 @@ dependencies { implementation "androidx.work:work-runtime-ktx:$workManagerVersion" implementation(libs.androidx.lifecycle.viewmodel.savedstate) implementation(libs.androidx.lifecycle.livedata.ktx) - implementation 'androidx.core:core-splashscreen:1.0.1' + implementation(libs.androidx.core.splashscreen) implementation "androidx.navigation:navigation-compose:2.7.7" implementation 'androidx.activity:activity-compose' implementation "androidx.preference:preference-ktx:1.2.1" diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 8bd63997cce..97b43a5f40f 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -234,7 +234,7 @@ dependencies { implementation(libs.google.play.services.auth) // Support library - implementation "androidx.core:core-ktx:$coreKtxVersion" + implementation(libs.androidx.core.ktx) implementation "androidx.constraintlayout:constraintlayout:2.1.4" implementation "androidx.recyclerview:recyclerview:1.3.2" implementation "androidx.recyclerview:recyclerview-selection:1.1.0" @@ -256,7 +256,7 @@ dependencies { implementation "androidx.work:work-runtime-ktx:$workManagerVersion" - implementation 'androidx.core:core-splashscreen:1.0.0' + implementation(libs.androidx.core.splashscreen) implementation("org.wordpress:utils:$wordPressUtilsVersion") { exclude group: "com.mcxiaoke.volley" diff --git a/build.gradle b/build.gradle index 3b879e1f01c..265ccd198e1 100644 --- a/build.gradle +++ b/build.gradle @@ -109,7 +109,6 @@ ext { aztecVersion = 'v2.1.4' flipperVersion = '0.176.1' stateMachineVersion = '0.2.0' - coreKtxVersion = '1.13.1' materialVersion = '1.12.0' transitionVersion = '1.5.1' hiltJetpackVersion = '1.1.0' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 07821b663cc..383f0f3a846 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,8 @@ [versions] android-billingclient = '5.0.0' androidx-appcompat = '1.4.2' +androidx-core-main = '1.13.1' +androidx-core-splashscreen = '1.0.1' androidx-lifecycle = '2.7.0' androidx-test-ext = '1.1.5' androidx-test-main = '1.4.0' @@ -22,6 +24,8 @@ wordpress-libaddressinput = '0.0.2' [libraries] android-billingclient-ktx = { group = "com.android.billingclient", name = "billing-ktx", version.ref = "android-billingclient" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-main" } +androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidx-core-splashscreen" } androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } From e7c49359739369775d631ddf277b7048f856d825 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 3 Oct 2024 16:33:01 +0300 Subject: [PATCH 028/162] Deps: Migrate androidx constraintlayout to version catalogs on wc --- WooCommerce/build.gradle | 4 ++-- gradle/libs.versions.toml | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 97b43a5f40f..562cabc1956 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -235,7 +235,7 @@ dependencies { // Support library implementation(libs.androidx.core.ktx) - implementation "androidx.constraintlayout:constraintlayout:2.1.4" + implementation(libs.androidx.constraintlayout.main) implementation "androidx.recyclerview:recyclerview:1.3.2" implementation "androidx.recyclerview:recyclerview-selection:1.1.0" implementation(libs.androidx.appcompat) @@ -447,7 +447,7 @@ dependencies { implementation 'androidx.navigation:navigation-compose' implementation 'androidx.hilt:hilt-navigation-compose:1.1.0' - implementation 'androidx.constraintlayout:constraintlayout-compose:1.0.1' + implementation(libs.androidx.constraintlayout.compose) implementation(libs.androidx.lifecycle.viewmodel.compose) implementation "io.coil-kt:coil-compose:$coilVersion" implementation "io.coil-kt:coil-svg:$coilVersion" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 383f0f3a846..208e6c2301b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,8 @@ [versions] android-billingclient = '5.0.0' androidx-appcompat = '1.4.2' +androidx-constraintlayout-compose = '1.0.1' +androidx-constraintlayout-main = '2.1.4' androidx-core-main = '1.13.1' androidx-core-splashscreen = '1.0.1' androidx-lifecycle = '2.7.0' @@ -24,6 +26,8 @@ wordpress-libaddressinput = '0.0.2' [libraries] android-billingclient-ktx = { group = "com.android.billingclient", name = "billing-ktx", version.ref = "android-billingclient" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } +androidx-constraintlayout-compose = { group = "androidx.constraintlayout", name = "constraintlayout-compose", version.ref = "androidx-constraintlayout-compose" } +androidx-constraintlayout-main = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout-main" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-main" } androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidx-core-splashscreen" } androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } From 62cbe386ad8ad998fa1d5ac3ca987a9e0bf0f171 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 3 Oct 2024 16:40:58 +0300 Subject: [PATCH 029/162] Deps: Migrate androidx recyclerview to version catalogs on woocommerce --- WooCommerce/build.gradle | 4 ++-- gradle/libs.versions.toml | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 562cabc1956..0abe775b08f 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -236,8 +236,8 @@ dependencies { // Support library implementation(libs.androidx.core.ktx) implementation(libs.androidx.constraintlayout.main) - implementation "androidx.recyclerview:recyclerview:1.3.2" - implementation "androidx.recyclerview:recyclerview-selection:1.1.0" + implementation(libs.androidx.recyclerview.main) + implementation(libs.androidx.recyclerview.selection) implementation(libs.androidx.appcompat) implementation "com.google.android.material:material:$materialVersion" implementation "androidx.transition:transition:$transitionVersion" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 208e6c2301b..5e4d70bb86d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,6 +6,8 @@ androidx-constraintlayout-main = '2.1.4' androidx-core-main = '1.13.1' androidx-core-splashscreen = '1.0.1' androidx-lifecycle = '2.7.0' +androidx-recyclerview-main = '1.3.2' +androidx-recyclerview-selection = '1.1.0' androidx-test-ext = '1.1.5' androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' @@ -34,6 +36,8 @@ androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecy androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-savedstate = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-savedstate", version.ref = "androidx-lifecycle" } +androidx-recyclerview-main = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "androidx-recyclerview-main" } +androidx-recyclerview-selection = { group = "androidx.recyclerview", name = "recyclerview-selection", version.ref = "androidx-recyclerview-selection" } androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext" } androidx-test-main-core = { group = "androidx.test", name = "core", version.ref = "androidx-test-main" } androidx-test-main-rules = { group = "androidx.test", name = "rules", version.ref = "androidx-test-main" } From 27a9195380873fcefd7f6292f7dc7b6108f58069 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 3 Oct 2024 16:42:09 +0300 Subject: [PATCH 030/162] Deps: Migrate google material to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 0abe775b08f..206617093b1 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -239,7 +239,7 @@ dependencies { implementation(libs.androidx.recyclerview.main) implementation(libs.androidx.recyclerview.selection) implementation(libs.androidx.appcompat) - implementation "com.google.android.material:material:$materialVersion" + implementation(libs.google.material) implementation "androidx.transition:transition:$transitionVersion" implementation "androidx.cardview:cardview:1.0.0" implementation("androidx.browser:browser:1.5.0") { diff --git a/build.gradle b/build.gradle index 265ccd198e1..d3e6b5674d6 100644 --- a/build.gradle +++ b/build.gradle @@ -109,7 +109,6 @@ ext { aztecVersion = 'v2.1.4' flipperVersion = '0.176.1' stateMachineVersion = '0.2.0' - materialVersion = '1.12.0' transitionVersion = '1.5.1' hiltJetpackVersion = '1.1.0' wordPressUtilsVersion = '3.5.0' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5e4d70bb86d..428751e0060 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,6 +13,7 @@ androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' assertj = '3.24.1' google-firebase-bom = '32.7.1' +google-material = '1.12.0' google-mlkit-barcode-scanning = '17.2.0' google-mlkit-text-recognition = '16.0.0' google-play-services-auth = '20.2.0' @@ -48,6 +49,7 @@ google-firebase-analytics = { group = "com.google.firebase", name = "firebase-an google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } google-firebase-config = { group = "com.google.firebase", name = "firebase-config" } google-firebase-messaging = { group = "com.google.firebase", name = "firebase-messaging" } +google-material = { group = "com.google.android.material", name = "material", version.ref = "google-material" } google-mlkit-barcode-scanning = { group = "com.google.mlkit", name = "barcode-scanning", version.ref = "google-mlkit-barcode-scanning" } google-mlkit-text-recognition-main = { group = "com.google.mlkit", name = "text-recognition", version.ref = "google-mlkit-text-recognition" } google-mlkit-text-recognition-japanese = { group = "com.google.android.gms", name = "play-services-mlkit-text-recognition-japanese", version.ref = "google-mlkit-text-recognition" } From 2ddfadc9ac8aad708444e431bd004379d0dcf039 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 3 Oct 2024 16:44:02 +0300 Subject: [PATCH 031/162] Deps: Migrate androidx transition to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 206617093b1..4aec4bd8477 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -240,7 +240,7 @@ dependencies { implementation(libs.androidx.recyclerview.selection) implementation(libs.androidx.appcompat) implementation(libs.google.material) - implementation "androidx.transition:transition:$transitionVersion" + implementation(libs.androidx.transition) implementation "androidx.cardview:cardview:1.0.0" implementation("androidx.browser:browser:1.5.0") { exclude group: 'com.google.guava', module: 'listenablefuture' diff --git a/build.gradle b/build.gradle index d3e6b5674d6..658af21e3ea 100644 --- a/build.gradle +++ b/build.gradle @@ -109,7 +109,6 @@ ext { aztecVersion = 'v2.1.4' flipperVersion = '0.176.1' stateMachineVersion = '0.2.0' - transitionVersion = '1.5.1' hiltJetpackVersion = '1.1.0' wordPressUtilsVersion = '3.5.0' mediapickerVersion = '0.3.1' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 428751e0060..09fb7801045 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,6 +11,7 @@ androidx-recyclerview-selection = '1.1.0' androidx-test-ext = '1.1.5' androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' +androidx-transition = '1.5.1' assertj = '3.24.1' google-firebase-bom = '32.7.1' google-material = '1.12.0' @@ -44,6 +45,7 @@ androidx-test-main-core = { group = "androidx.test", name = "core", version.ref androidx-test-main-rules = { group = "androidx.test", name = "rules", version.ref = "androidx-test-main" } androidx-test-main-runner = { group = "androidx.test", name = "runner", version.ref = "androidx-test-main" } androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidx-test-uiautomator" } +androidx-transition = { group = "androidx.transition", name = "transition", version.ref = "androidx-transition" } assertj-core = { group = "org.assertj", name = "assertj-core", version.ref = "assertj" } google-firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics" } google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } From 2a8bd49eb4f7eafaea7379b13bd3826deed2b7ab Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 3 Oct 2024 16:45:50 +0300 Subject: [PATCH 032/162] Deps: Migrate androidx cardview to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 4aec4bd8477..eb9ba8c415f 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -241,7 +241,7 @@ dependencies { implementation(libs.androidx.appcompat) implementation(libs.google.material) implementation(libs.androidx.transition) - implementation "androidx.cardview:cardview:1.0.0" + implementation(libs.androidx.cardview) implementation("androidx.browser:browser:1.5.0") { exclude group: 'com.google.guava', module: 'listenablefuture' } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 09fb7801045..c1fb5dae7e7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,7 @@ [versions] android-billingclient = '5.0.0' androidx-appcompat = '1.4.2' +androidx-cardview = '1.0.0' androidx-constraintlayout-compose = '1.0.1' androidx-constraintlayout-main = '2.1.4' androidx-core-main = '1.13.1' @@ -30,6 +31,7 @@ wordpress-libaddressinput = '0.0.2' [libraries] android-billingclient-ktx = { group = "com.android.billingclient", name = "billing-ktx", version.ref = "android-billingclient" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } +androidx-cardview = { group = "androidx.cardview", name = "cardview", version.ref = "androidx-cardview" } androidx-constraintlayout-compose = { group = "androidx.constraintlayout", name = "constraintlayout-compose", version.ref = "androidx-constraintlayout-compose" } androidx-constraintlayout-main = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout-main" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-main" } From c77fff9f217867d4dad3234f31a533c97f8db77e Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 3 Oct 2024 16:47:28 +0300 Subject: [PATCH 033/162] Deps: Migrate androidx browser to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index eb9ba8c415f..4293debd95c 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -242,7 +242,7 @@ dependencies { implementation(libs.google.material) implementation(libs.androidx.transition) implementation(libs.androidx.cardview) - implementation("androidx.browser:browser:1.5.0") { + implementation(libs.androidx.browser) { exclude group: 'com.google.guava', module: 'listenablefuture' } implementation "androidx.preference:preference:1.2.0" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c1fb5dae7e7..2dcbcd920c8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,7 @@ [versions] android-billingclient = '5.0.0' androidx-appcompat = '1.4.2' +androidx-browser = '1.5.0' androidx-cardview = '1.0.0' androidx-constraintlayout-compose = '1.0.1' androidx-constraintlayout-main = '2.1.4' @@ -31,6 +32,7 @@ wordpress-libaddressinput = '0.0.2' [libraries] android-billingclient-ktx = { group = "com.android.billingclient", name = "billing-ktx", version.ref = "android-billingclient" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } +androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "androidx-browser" } androidx-cardview = { group = "androidx.cardview", name = "cardview", version.ref = "androidx-cardview" } androidx-constraintlayout-compose = { group = "androidx.constraintlayout", name = "constraintlayout-compose", version.ref = "androidx-constraintlayout-compose" } androidx-constraintlayout-main = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout-main" } From 42b9e11bb64b24bf48a1d86380030a7b55877298 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 3 Oct 2024 16:51:20 +0300 Subject: [PATCH 034/162] Deps: Migrate androidx preference to version catalogs on all modules FYI: Notice that the 'AndroidX Preference KTX' version on the 'WooCommerce' module is pointing to '1.2.0', while on the 'WooCommerce-Wear' module it is pointing to '1.2.1'. This change also updates the 'WooCommerce' version to point to '1.2.1' as well, it being just a batch update that includes a few bugfixes and no more. Release Notes: https://developer.android.com/jetpack/androidx/releases/ preference#1.2.1 --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 26dbd39247a..e2948f38d1e 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -172,7 +172,7 @@ dependencies { implementation(libs.androidx.core.splashscreen) implementation "androidx.navigation:navigation-compose:2.7.7" implementation 'androidx.activity:activity-compose' - implementation "androidx.preference:preference-ktx:1.2.1" + implementation(libs.androidx.preference.ktx) implementation "androidx.datastore:datastore-preferences:1.1.0" implementation "androidx.datastore:datastore:1.1.0" implementation 'com.google.code.gson:gson:2.10.1' diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 4293debd95c..bb889ef7db9 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -245,7 +245,7 @@ dependencies { implementation(libs.androidx.browser) { exclude group: 'com.google.guava', module: 'listenablefuture' } - implementation "androidx.preference:preference:1.2.0" + implementation(libs.androidx.preference.main) implementation "androidx.datastore:datastore-preferences:1.0.0" implementation "androidx.datastore:datastore:1.0.0" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2dcbcd920c8..ebdc1f1e8bd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,6 +8,7 @@ androidx-constraintlayout-main = '2.1.4' androidx-core-main = '1.13.1' androidx-core-splashscreen = '1.0.1' androidx-lifecycle = '2.7.0' +androidx-preference = '1.2.1' androidx-recyclerview-main = '1.3.2' androidx-recyclerview-selection = '1.1.0' androidx-test-ext = '1.1.5' @@ -42,6 +43,8 @@ androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecy androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-savedstate = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-savedstate", version.ref = "androidx-lifecycle" } +androidx-preference-main = { group = "androidx.preference", name = "preference", version.ref = "androidx-preference" } +androidx-preference-ktx = { group = "androidx.preference", name = "preference-ktx", version.ref = "androidx-preference" } androidx-recyclerview-main = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "androidx-recyclerview-main" } androidx-recyclerview-selection = { group = "androidx.recyclerview", name = "recyclerview-selection", version.ref = "androidx-recyclerview-selection" } androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext" } From 7f69b0c4c5eb37a934724aa87ae158ab68097b57 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 3 Oct 2024 16:58:10 +0300 Subject: [PATCH 035/162] Deps: Migrate androidx datastore to version catalogs on all modules FYI: Notice that the 'AndroidX Datastore' versions on the 'WooCommerce' module are pointing to '1.0.0', while on the 'WooCommerce-Wear' module they are pointing to '1.1.0'. This change also updates the 'WooCommerce' versions to point to '1.1.0' as well, it having only additional features on top of '1.0.0' but no breaking changes. Release Notes: https://developer.android.com/jetpack/androidx/releases/ datastore#1.1.0 --- WooCommerce-Wear/build.gradle | 4 ++-- WooCommerce/build.gradle | 4 ++-- gradle/libs.versions.toml | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index e2948f38d1e..a031c79de6c 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -173,8 +173,8 @@ dependencies { implementation "androidx.navigation:navigation-compose:2.7.7" implementation 'androidx.activity:activity-compose' implementation(libs.androidx.preference.ktx) - implementation "androidx.datastore:datastore-preferences:1.1.0" - implementation "androidx.datastore:datastore:1.1.0" + implementation(libs.androidx.datastore.preferences) + implementation(libs.androidx.datastore.main) implementation 'com.google.code.gson:gson:2.10.1' // Coroutines diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index bb889ef7db9..ab5463014d1 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -246,8 +246,8 @@ dependencies { exclude group: 'com.google.guava', module: 'listenablefuture' } implementation(libs.androidx.preference.main) - implementation "androidx.datastore:datastore-preferences:1.0.0" - implementation "androidx.datastore:datastore:1.0.0" + implementation(libs.androidx.datastore.preferences) + implementation(libs.androidx.datastore.main) implementation "androidx.navigation:navigation-common:$gradle.ext.navigationVersion" implementation "androidx.navigation:navigation-fragment:$gradle.ext.navigationVersion" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ebdc1f1e8bd..8b4a4ea2d22 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,6 +7,7 @@ androidx-constraintlayout-compose = '1.0.1' androidx-constraintlayout-main = '2.1.4' androidx-core-main = '1.13.1' androidx-core-splashscreen = '1.0.1' +androidx-datastore = '1.1.0' androidx-lifecycle = '2.7.0' androidx-preference = '1.2.1' androidx-recyclerview-main = '1.3.2' @@ -39,6 +40,8 @@ androidx-constraintlayout-compose = { group = "androidx.constraintlayout", name androidx-constraintlayout-main = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout-main" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-main" } androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidx-core-splashscreen" } +androidx-datastore-main = { group = "androidx.datastore", name = "datastore", version.ref = "androidx-datastore" } +androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "androidx-datastore" } androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } From d3d12af808ce59206761154ade4bbc44699ffc6a Mon Sep 17 00:00:00 2001 From: Alejo Date: Fri, 4 Oct 2024 08:27:01 -0600 Subject: [PATCH 036/162] fix detekt warning --- .../android/ui/orders/details/OrderDetailViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt index 2d808788d75..cd960b9d536 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt @@ -93,7 +93,7 @@ import org.wordpress.android.fluxc.store.WooCommerceStore import javax.inject.Inject @HiltViewModel -@Suppress("LargeClass, LongParameterList") +@Suppress("LargeClass", "LongParameterList", "TooManyFunctions") class OrderDetailViewModel @Inject constructor( savedState: SavedStateHandle, private val appPrefs: AppPrefs, From d1b1763998aad8c3f90dbf4ed9a61915a9f36d22 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Fri, 4 Oct 2024 16:49:09 +0200 Subject: [PATCH 037/162] Fix navigation issue when triggering blaze from product detail When triggering Blaze from product detail the Blaze intro view was always shown, even when the user had plenty of campaigns created already. --- .../BlazeCampaignCreationDispatcher.kt | 22 +++++--- .../BlazeCampaignCreationIntroFragment.kt | 54 ++++++++----------- .../nav_graph_blaze_campaign_creation.xml | 42 +-------------- .../main/res/navigation/nav_graph_main.xml | 45 ++++++++++++++++ 4 files changed, 82 insertions(+), 81 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcher.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcher.kt index 817dc891260..6b1fe50ff90 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcher.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcher.kt @@ -14,6 +14,7 @@ import com.woocommerce.android.extensions.navigateSafely import com.woocommerce.android.ui.base.BaseFragment import com.woocommerce.android.ui.blaze.BlazeRepository import com.woocommerce.android.ui.blaze.BlazeUrlsHelper.BlazeFlowSource +import com.woocommerce.android.ui.blaze.BlazeUrlsHelper.BlazeFlowSource.INTRO_VIEW import com.woocommerce.android.ui.blaze.creation.intro.BlazeCampaignCreationIntroFragmentArgs import com.woocommerce.android.ui.blaze.creation.preview.BlazeCampaignCreationPreviewFragmentArgs import com.woocommerce.android.ui.blaze.notification.AbandonedCampaignReminder @@ -58,7 +59,7 @@ class BlazeCampaignCreationDispatcher @Inject constructor( handler: (BlazeCampaignCreationDispatcherEvent) -> Unit = ::handleEvent ) { when { - blazeRepository.getMostRecentCampaign() == null -> handler( + blazeRepository.getMostRecentCampaign() == null && source != INTRO_VIEW -> handler( BlazeCampaignCreationDispatcherEvent.ShowBlazeCampaignCreationIntro(productId, source) ) @@ -127,12 +128,20 @@ class BlazeCampaignCreationDispatcher @Inject constructor( } private fun BaseFragment.showIntro(productId: Long?, blazeSource: BlazeFlowSource) { - findNavController().navigateToBlazeGraph( - startDestination = R.id.blazeCampaignCreationIntroFragment, - bundle = BlazeCampaignCreationIntroFragmentArgs( + findNavController().navigate( + resId = R.id.blazeCampaignCreationIntroFragment, + args = BlazeCampaignCreationIntroFragmentArgs( productId = productId ?: -1L, source = blazeSource - ).toBundle() + ).toBundle(), + navOptions = navOptions { + anim { + enter = R.anim.default_enter_anim + exit = R.anim.default_exit_anim + popEnter = R.anim.default_pop_enter_anim + popExit = R.anim.default_pop_exit_anim + } + } ) } @@ -147,9 +156,6 @@ class BlazeCampaignCreationDispatcher @Inject constructor( } private fun BaseFragment.showProductSelector() { - val navGraph = findNavController().graph.findNode(R.id.nav_graph_blaze_campaign_creation) as NavGraph - navGraph.setStartDestination(R.id.nav_graph_product_selector) - findNavController().navigateToBlazeGraph( startDestination = R.id.nav_graph_product_selector, bundle = ProductSelectorFragmentArgs( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/intro/BlazeCampaignCreationIntroFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/intro/BlazeCampaignCreationIntroFragment.kt index 746889b3af1..24ebc0f4772 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/intro/BlazeCampaignCreationIntroFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/intro/BlazeCampaignCreationIntroFragment.kt @@ -5,24 +5,28 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController -import androidx.navigation.navOptions -import com.woocommerce.android.R import com.woocommerce.android.extensions.handleResult -import com.woocommerce.android.extensions.navigateSafely import com.woocommerce.android.ui.base.BaseFragment +import com.woocommerce.android.ui.blaze.BlazeUrlsHelper.BlazeFlowSource +import com.woocommerce.android.ui.blaze.creation.BlazeCampaignCreationDispatcher import com.woocommerce.android.ui.compose.composeView import com.woocommerce.android.ui.main.AppBarStatus import com.woocommerce.android.ui.products.selector.ProductSelectorFragment -import com.woocommerce.android.ui.products.selector.ProductSelectorViewModel import com.woocommerce.android.ui.products.selector.ProductSelectorViewModel.SelectedItem import com.woocommerce.android.viewmodel.MultiLiveEvent import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import javax.inject.Inject @AndroidEntryPoint class BlazeCampaignCreationIntroFragment : BaseFragment() { private val viewModel: BlazeCampaignCreationIntroViewModel by viewModels() + @Inject + lateinit var blazeCampaignCreationDispatcher: BlazeCampaignCreationDispatcher + override val activityAppBarStatus: AppBarStatus get() = AppBarStatus.Hidden @@ -33,6 +37,7 @@ class BlazeCampaignCreationIntroFragment : BaseFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + blazeCampaignCreationDispatcher.attachFragment(this, BlazeFlowSource.INTRO_VIEW) handleEvents() handleResults() } @@ -40,44 +45,29 @@ class BlazeCampaignCreationIntroFragment : BaseFragment() { private fun handleEvents() { viewModel.event.observe(viewLifecycleOwner) { event -> when (event) { - is BlazeCampaignCreationIntroViewModel.ShowCampaignCreationForm -> { - findNavController().navigateSafely( - directions = BlazeCampaignCreationIntroFragmentDirections - .actionBlazeCampaignCreationIntroFragmentToBlazeCampaignCreationPreviewFragment( - productId = event.productId, - source = event.source - ), - navOptions = navOptions { - popUpTo(R.id.blazeCampaignCreationIntroFragment) { inclusive = true } - } - ) - } + is BlazeCampaignCreationIntroViewModel.ShowCampaignCreationForm -> + startBlazeCampaignCreationFlow(event.source, event.productId) - is BlazeCampaignCreationIntroViewModel.ShowProductSelector -> { - navigateToProductSelectorScreen() - } + is BlazeCampaignCreationIntroViewModel.ShowProductSelector -> + startBlazeCampaignCreationFlow(BlazeFlowSource.INTRO_VIEW) is MultiLiveEvent.Event.Exit -> findNavController().navigateUp() } } } + private fun startBlazeCampaignCreationFlow(source: BlazeFlowSource, productId: Long? = null) { + lifecycleScope.launch { + blazeCampaignCreationDispatcher.startCampaignCreation( + productId = productId, + source = source + ) + } + } + private fun handleResults() { handleResult>(ProductSelectorFragment.PRODUCT_SELECTOR_RESULT) { viewModel.onProductSelected(it.first().id) } } - - private fun navigateToProductSelectorScreen() { - findNavController().navigateSafely( - BlazeCampaignCreationIntroFragmentDirections - .actionBlazeCampaignCreationIntroFragmentToNavGraphProductSelector( - selectionMode = ProductSelectorViewModel.SelectionMode.SINGLE, - selectionHandling = ProductSelectorViewModel.SelectionHandling.SIMPLE, - screenTitleOverride = getString(R.string.blaze_campaign_creation_product_selector_title), - ctaButtonTextOverride = getString(R.string.blaze_campaign_creation_product_selector_cta_button), - productSelectorFlow = ProductSelectorViewModel.ProductSelectorFlow.Undefined - ) - ) - } } diff --git a/WooCommerce/src/main/res/navigation/nav_graph_blaze_campaign_creation.xml b/WooCommerce/src/main/res/navigation/nav_graph_blaze_campaign_creation.xml index b89e972fc52..978eee4bd5b 100644 --- a/WooCommerce/src/main/res/navigation/nav_graph_blaze_campaign_creation.xml +++ b/WooCommerce/src/main/res/navigation/nav_graph_blaze_campaign_creation.xml @@ -2,50 +2,10 @@ + app:startDestination="@id/blazeCampaignCreationPreviewFragment"> - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + From 2cb87df269928553189eaa1cae19b7fbfc6505e9 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 3 Oct 2024 17:15:52 +0300 Subject: [PATCH 038/162] Deps: Migrate androidx work to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index a031c79de6c..e9f611ef0c3 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -166,7 +166,7 @@ dependencies { implementation 'androidx.compose.ui:ui-text-google-fonts' // Android Support - implementation "androidx.work:work-runtime-ktx:$workManagerVersion" + implementation(libs.androidx.work.runtime.ktx) implementation(libs.androidx.lifecycle.viewmodel.savedstate) implementation(libs.androidx.lifecycle.livedata.ktx) implementation(libs.androidx.core.splashscreen) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index ab5463014d1..8541338a553 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -254,7 +254,7 @@ dependencies { implementation "androidx.navigation:navigation-runtime:$gradle.ext.navigationVersion" implementation "androidx.navigation:navigation-ui:$gradle.ext.navigationVersion" - implementation "androidx.work:work-runtime-ktx:$workManagerVersion" + implementation(libs.androidx.work.runtime.ktx) implementation(libs.androidx.core.splashscreen) diff --git a/build.gradle b/build.gradle index 658af21e3ea..469c5c972b3 100644 --- a/build.gradle +++ b/build.gradle @@ -115,7 +115,6 @@ ext { wordPressLoginVersion = '1.18.0' aboutAutomatticVersion = '0.0.6' automatticTracksVersion = '5.0.0' - workManagerVersion = '2.7.1' androidxCameraVersion = '1.2.3' guavaVersion = '33.1.0-android' protobufVersion = '3.25.3' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8b4a4ea2d22..d45053cd38a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,6 +16,7 @@ androidx-test-ext = '1.1.5' androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' androidx-transition = '1.5.1' +androidx-work = '2.7.1' assertj = '3.24.1' google-firebase-bom = '32.7.1' google-material = '1.12.0' @@ -56,6 +57,7 @@ androidx-test-main-rules = { group = "androidx.test", name = "rules", version.re androidx-test-main-runner = { group = "androidx.test", name = "runner", version.ref = "androidx-test-main" } androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidx-test-uiautomator" } androidx-transition = { group = "androidx.transition", name = "transition", version.ref = "androidx-transition" } +androidx-work-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "androidx-work" } assertj-core = { group = "org.assertj", name = "assertj-core", version.ref = "assertj" } google-firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics" } google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } From 7a2bf6ef29d61d5dc41064e8f180d9a90d4c8a7e Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 3 Oct 2024 17:19:37 +0300 Subject: [PATCH 039/162] Deps: Migrate wordpress utils to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index e9f611ef0c3..dae7d1c01ae 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -135,7 +135,7 @@ dependencies { exclude group: "com.android.support" exclude group: "org.wordpress", module: "utils" } - implementation("org.wordpress:utils:$wordPressUtilsVersion") { + implementation(libs.wordpress.utils) { exclude group: "com.mcxiaoke.volley" exclude group: "com.android.support" } diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 8541338a553..40ee4836769 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -258,7 +258,7 @@ dependencies { implementation(libs.androidx.core.splashscreen) - implementation("org.wordpress:utils:$wordPressUtilsVersion") { + implementation(libs.wordpress.utils) { exclude group: "com.mcxiaoke.volley" exclude group: "com.android.support" } diff --git a/build.gradle b/build.gradle index 469c5c972b3..5d8b07e656a 100644 --- a/build.gradle +++ b/build.gradle @@ -110,7 +110,6 @@ ext { flipperVersion = '0.176.1' stateMachineVersion = '0.2.0' hiltJetpackVersion = '1.1.0' - wordPressUtilsVersion = '3.5.0' mediapickerVersion = '0.3.1' wordPressLoginVersion = '1.18.0' aboutAutomatticVersion = '0.0.6' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d45053cd38a..c509e9e37f3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,6 +31,7 @@ mockito-inline = '4.6.1' mockito-kotlin = '4.0.0' stripe-terminal = '3.7.1' wordpress-libaddressinput = '0.0.2' +wordpress-utils = '3.5.0' [libraries] android-billingclient-ktx = { group = "com.android.billingclient", name = "billing-ktx", version.ref = "android-billingclient" } @@ -82,3 +83,4 @@ mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", versio stripe-terminal-localmobile = { group = "com.stripe", name = "stripeterminal-localmobile", version.ref = "stripe-terminal" } stripe-terminal-core = { group = "com.stripe", name = "stripeterminal-core", version.ref = "stripe-terminal" } wordpress-libaddressinput-common = { group = "org.wordpress", name = "libaddressinput.common", version.ref = "wordpress-libaddressinput" } +wordpress-utils = { group = "org.wordpress", name = "utils", version.ref = "wordpress-utils" } From c323595404fe71e371b35c36874ed9ef1398d35b Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 3 Oct 2024 17:22:53 +0300 Subject: [PATCH 040/162] Deps: Migrate automattic tracks to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 4 ++-- WooCommerce/build.gradle | 6 +++--- build.gradle | 1 - gradle/libs.versions.toml | 4 ++++ 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index dae7d1c01ae..3e7e3625b6f 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -139,8 +139,8 @@ dependencies { exclude group: "com.mcxiaoke.volley" exclude group: "com.android.support" } - implementation "com.automattic:Automattic-Tracks-Android:$automatticTracksVersion" - implementation "com.automattic.tracks:crashlogging:$automatticTracksVersion" + implementation(libs.automattic.tracks.android) + implementation(libs.automattic.tracks.crashlogging) // WearOS implementation(libs.google.play.services.wearable) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 40ee4836769..f8a49a1bf5f 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -263,11 +263,11 @@ dependencies { exclude group: "com.android.support" } - implementation("com.automattic.tracks:experimentation:$automatticTracksVersion") { + implementation(libs.automattic.tracks.experimentation) { exclude group: "org.wordpress", module: "fluxc" } - implementation "com.automattic:Automattic-Tracks-Android:$automatticTracksVersion" - implementation "com.automattic.tracks:crashlogging:$automatticTracksVersion" + implementation(libs.automattic.tracks.android) + implementation(libs.automattic.tracks.crashlogging) implementation("${gradle.ext.fluxCBinaryPath}:$fluxCVersion") { exclude group: "com.android.support" diff --git a/build.gradle b/build.gradle index 5d8b07e656a..bb0c02139b1 100644 --- a/build.gradle +++ b/build.gradle @@ -113,7 +113,6 @@ ext { mediapickerVersion = '0.3.1' wordPressLoginVersion = '1.18.0' aboutAutomatticVersion = '0.0.6' - automatticTracksVersion = '5.0.0' androidxCameraVersion = '1.2.3' guavaVersion = '33.1.0-android' protobufVersion = '3.25.3' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c509e9e37f3..14db2072f2e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,6 +17,7 @@ androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' androidx-transition = '1.5.1' androidx-work = '2.7.1' +automattic-tracks = '5.0.0' assertj = '3.24.1' google-firebase-bom = '32.7.1' google-material = '1.12.0' @@ -60,6 +61,9 @@ androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiaut androidx-transition = { group = "androidx.transition", name = "transition", version.ref = "androidx-transition" } androidx-work-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "androidx-work" } assertj-core = { group = "org.assertj", name = "assertj-core", version.ref = "assertj" } +automattic-tracks-android = { group = "com.automattic", name = "Automattic-Tracks-Android", version.ref = "automattic-tracks" } +automattic-tracks-experimentation = { group = "com.automattic.tracks", name = "experimentation", version.ref = "automattic-tracks" } +automattic-tracks-crashlogging = { group = "com.automattic.tracks", name = "crashlogging", version.ref = "automattic-tracks" } google-firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics" } google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } google-firebase-config = { group = "com.google.firebase", name = "firebase-config" } From fd72fd6f3f9156c236b968f161b42667eb692124 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 15:28:58 +0300 Subject: [PATCH 041/162] Deps: Migrate wordpress fluxc to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 4 ++-- WooCommerce/build.gradle | 4 ++-- build.gradle | 1 - gradle/libs.versions.toml | 1 + 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 3e7e3625b6f..2023db2981d 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -127,11 +127,11 @@ android { dependencies { // Project implementation project(":libs:commons") - implementation("${gradle.ext.fluxCBinaryPath}:$fluxCVersion") { + implementation("${gradle.ext.fluxCBinaryPath}:${libs.versions.wordpress.fluxc.get()}") { exclude group: "com.android.support" exclude group: "org.wordpress", module: "utils" } - implementation("${gradle.ext.fluxCWooCommercePluginBinaryPath}:$fluxCVersion") { + implementation("${gradle.ext.fluxCWooCommercePluginBinaryPath}:${libs.versions.wordpress.fluxc.get()}") { exclude group: "com.android.support" exclude group: "org.wordpress", module: "utils" } diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index f8a49a1bf5f..d46695c8ccb 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -269,11 +269,11 @@ dependencies { implementation(libs.automattic.tracks.android) implementation(libs.automattic.tracks.crashlogging) - implementation("${gradle.ext.fluxCBinaryPath}:$fluxCVersion") { + implementation("${gradle.ext.fluxCBinaryPath}:${libs.versions.wordpress.fluxc.get()}") { exclude group: "com.android.support" exclude group: "org.wordpress", module: "utils" } - implementation("${gradle.ext.fluxCWooCommercePluginBinaryPath}:$fluxCVersion") { + implementation("${gradle.ext.fluxCWooCommercePluginBinaryPath}:${libs.versions.wordpress.fluxc.get()}") { exclude group: "com.android.support" exclude group: "org.wordpress", module: "utils" } diff --git a/build.gradle b/build.gradle index bb0c02139b1..1ec4d3379f6 100644 --- a/build.gradle +++ b/build.gradle @@ -100,7 +100,6 @@ tasks.register("installGitHooks", Copy) { } ext { - fluxCVersion = 'trunk-7ad6ce4c250ba435d8d8c7feb898bceb259fb007' glideVersion = '4.16.0' coilVersion = '2.1.0' constraintLayoutVersion = '1.2.0' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 14db2072f2e..e9223902b5d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,6 +31,7 @@ kotlinx-coroutines = '1.8.1' mockito-inline = '4.6.1' mockito-kotlin = '4.0.0' stripe-terminal = '3.7.1' +wordpress-fluxc = 'trunk-7ad6ce4c250ba435d8d8c7feb898bceb259fb007' wordpress-libaddressinput = '0.0.2' wordpress-utils = '3.5.0' From be402c0a0dd09ed6838916e9e9a2edb4ac69ceda Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 15:40:11 +0300 Subject: [PATCH 042/162] Deps: Migrate wordpress login to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index d46695c8ccb..0c86dd479eb 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -278,7 +278,7 @@ dependencies { exclude group: "org.wordpress", module: "utils" } - implementation("$gradle.ext.loginFlowBinaryPath:$wordPressLoginVersion") { + implementation("$gradle.ext.loginFlowBinaryPath:${libs.versions.wordpress.login.get()}") { exclude group: "org.wordpress", module: "utils" exclude group: "org.wordpress", module: "fluxc" } diff --git a/build.gradle b/build.gradle index 1ec4d3379f6..7bc62963f13 100644 --- a/build.gradle +++ b/build.gradle @@ -110,7 +110,6 @@ ext { stateMachineVersion = '0.2.0' hiltJetpackVersion = '1.1.0' mediapickerVersion = '0.3.1' - wordPressLoginVersion = '1.18.0' aboutAutomatticVersion = '0.0.6' androidxCameraVersion = '1.2.3' guavaVersion = '33.1.0-android' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e9223902b5d..ce1cacaa21a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,6 +32,7 @@ mockito-inline = '4.6.1' mockito-kotlin = '4.0.0' stripe-terminal = '3.7.1' wordpress-fluxc = 'trunk-7ad6ce4c250ba435d8d8c7feb898bceb259fb007' +wordpress-login = '1.18.0' wordpress-libaddressinput = '0.0.2' wordpress-utils = '3.5.0' From 8034f12e0cee7e3dd19e04aa96a431d35935566c Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 15:48:52 +0300 Subject: [PATCH 043/162] Deps: Migrate wordpress aztec to version catalogs on woocommerce --- WooCommerce/build.gradle | 4 ++-- build.gradle | 1 - gradle/libs.versions.toml | 3 +++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 0c86dd479eb..d0e638ea343 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -283,13 +283,13 @@ dependencies { exclude group: "org.wordpress", module: "fluxc" } - implementation("org.wordpress:aztec:$aztecVersion") { + implementation(libs.wordpress.aztec.main) { exclude group: "com.android.volley" exclude group: "com.android.support" exclude group: "org.wordpress", module: "utils" } - implementation("org.wordpress.aztec:glide-loader:$aztecVersion") { + implementation(libs.wordpress.aztec.glide.loader) { exclude group: "com.android.volley" exclude group: "com.android.support" exclude group: "org.wordpress", module: "utils" diff --git a/build.gradle b/build.gradle index 7bc62963f13..cfc7e113f63 100644 --- a/build.gradle +++ b/build.gradle @@ -105,7 +105,6 @@ ext { constraintLayoutVersion = '1.2.0' eventBusVersion = '3.3.1' googlePlayCoreVersion = '1.10.3' - aztecVersion = 'v2.1.4' flipperVersion = '0.176.1' stateMachineVersion = '0.2.0' hiltJetpackVersion = '1.1.0' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ce1cacaa21a..f69806b8aa6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,6 +31,7 @@ kotlinx-coroutines = '1.8.1' mockito-inline = '4.6.1' mockito-kotlin = '4.0.0' stripe-terminal = '3.7.1' +wordpress-aztec = 'v2.1.4' wordpress-fluxc = 'trunk-7ad6ce4c250ba435d8d8c7feb898bceb259fb007' wordpress-login = '1.18.0' wordpress-libaddressinput = '0.0.2' @@ -89,4 +90,6 @@ mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", versio stripe-terminal-localmobile = { group = "com.stripe", name = "stripeterminal-localmobile", version.ref = "stripe-terminal" } stripe-terminal-core = { group = "com.stripe", name = "stripeterminal-core", version.ref = "stripe-terminal" } wordpress-libaddressinput-common = { group = "org.wordpress", name = "libaddressinput.common", version.ref = "wordpress-libaddressinput" } +wordpress-aztec-main = { group = "org.wordpress", name = "aztec", version.ref = "wordpress-aztec" } +wordpress-aztec-glide-loader = { group = "org.wordpress.aztec", name = "glide-loader", version.ref = "wordpress-aztec" } wordpress-utils = { group = "org.wordpress", name = "utils", version.ref = "wordpress-utils" } From 3270c2a0ee3f5ed0021668b086171aff5f749822 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 15:50:41 +0300 Subject: [PATCH 044/162] Deps: Migrate gravatar to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index d0e638ea343..cb75b971dfd 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -295,7 +295,7 @@ dependencies { exclude group: "org.wordpress", module: "utils" } - implementation("com.gravatar:gravatar:$gravatarVersion") + implementation(libs.gravatar) implementation project(":libs:commons") implementation project(":libs:cardreader") diff --git a/build.gradle b/build.gradle index cfc7e113f63..1e93617d406 100644 --- a/build.gradle +++ b/build.gradle @@ -113,7 +113,6 @@ ext { androidxCameraVersion = '1.2.3' guavaVersion = '33.1.0-android' protobufVersion = '3.25.3' - gravatarVersion = '0.2.0' wearHorologistVersion = '0.6.10' securityLintVersion = '1.0.1' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f69806b8aa6..da6a5a9bc57 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,6 +26,7 @@ google-mlkit-text-recognition = '16.0.0' google-play-services-auth = '20.2.0' google-play-services-code-scanner = '16.1.0' google-play-services-wearable = '18.1.0' +gravatar = '0.2.0' junit = '4.13.2' kotlinx-coroutines = '1.8.1' mockito-inline = '4.6.1' @@ -80,6 +81,7 @@ google-mlkit-text-recognition-korean = { group = "com.google.android.gms", name google-play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "google-play-services-auth" } google-play-services-code-scanner = { group = "com.google.android.gms", name = "play-services-code-scanner", version.ref = "google-play-services-code-scanner" } google-play-services-wearable = { group = "com.google.android.gms", name = "play-services-wearable", version.ref = "google-play-services-wearable" } +gravatar = { group = "com.gravatar", name = "gravatar", version.ref = "gravatar" } junit = { group = "junit", name = "junit", version.ref = "junit" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } From 043f001b9a1be026a54783f92c4c28fba1593ac1 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 15:52:48 +0300 Subject: [PATCH 045/162] Deps: Migrate facebook shimmer to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index cb75b971dfd..b802f1c24a3 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -301,7 +301,7 @@ dependencies { implementation project(":libs:cardreader") debugImplementation project(":libs:iap") - implementation 'com.facebook.shimmer:shimmer:0.5.0' + implementation(libs.facebook.shimmer) implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation "com.automattic:about:$aboutAutomatticVersion" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index da6a5a9bc57..cb8a68fe98d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,6 +19,7 @@ androidx-transition = '1.5.1' androidx-work = '2.7.1' automattic-tracks = '5.0.0' assertj = '3.24.1' +facebook-shimmer = '0.5.0' google-firebase-bom = '32.7.1' google-material = '1.12.0' google-mlkit-barcode-scanning = '17.2.0' @@ -68,6 +69,7 @@ assertj-core = { group = "org.assertj", name = "assertj-core", version.ref = "as automattic-tracks-android = { group = "com.automattic", name = "Automattic-Tracks-Android", version.ref = "automattic-tracks" } automattic-tracks-experimentation = { group = "com.automattic.tracks", name = "experimentation", version.ref = "automattic-tracks" } automattic-tracks-crashlogging = { group = "com.automattic.tracks", name = "crashlogging", version.ref = "automattic-tracks" } +facebook-shimmer = { group = "com.facebook.shimmer", name = "shimmer", version.ref = "facebook-shimmer" } google-firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics" } google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } google-firebase-config = { group = "com.google.firebase", name = "firebase-config" } From cc32b51b9d33aef74d551968b0504d1d33b8d880 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 15:54:29 +0300 Subject: [PATCH 046/162] Deps: Migrate photoview to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index b802f1c24a3..fc41c8a4a4f 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -302,7 +302,7 @@ dependencies { debugImplementation project(":libs:iap") implementation(libs.facebook.shimmer) - implementation 'com.github.chrisbanes:PhotoView:2.3.0' + implementation(libs.photoview) implementation "com.automattic:about:$aboutAutomatticVersion" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cb8a68fe98d..952cf992761 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,6 +32,7 @@ junit = '4.13.2' kotlinx-coroutines = '1.8.1' mockito-inline = '4.6.1' mockito-kotlin = '4.0.0' +photoview = '2.3.0' stripe-terminal = '3.7.1' wordpress-aztec = 'v2.1.4' wordpress-fluxc = 'trunk-7ad6ce4c250ba435d8d8c7feb898bceb259fb007' @@ -91,6 +92,7 @@ kotlinx-coroutines-play-services = { group = "org.jetbrains.kotlinx", name = "ko kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } mockito-inline = { group = "org.mockito", name = "mockito-inline", version.ref = "mockito-inline" } mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockito-kotlin" } +photoview = { group = "com.github.chrisbanes", name = "PhotoView", version.ref = "photoview" } stripe-terminal-localmobile = { group = "com.stripe", name = "stripeterminal-localmobile", version.ref = "stripe-terminal" } stripe-terminal-core = { group = "com.stripe", name = "stripeterminal-core", version.ref = "stripe-terminal" } wordpress-libaddressinput-common = { group = "org.wordpress", name = "libaddressinput.common", version.ref = "wordpress-libaddressinput" } From 794dc7dff8c360996e0e6b471138c07378dcc27c Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:04:11 +0300 Subject: [PATCH 047/162] Deps: Migrate automattic about to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index fc41c8a4a4f..080210c09ea 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -304,7 +304,7 @@ dependencies { implementation(libs.facebook.shimmer) implementation(libs.photoview) - implementation "com.automattic:about:$aboutAutomatticVersion" + implementation(libs.automattic.about) // Dagger implementation "com.google.dagger:hilt-android:$gradle.ext.daggerVersion" diff --git a/build.gradle b/build.gradle index 1e93617d406..09442554187 100644 --- a/build.gradle +++ b/build.gradle @@ -109,7 +109,6 @@ ext { stateMachineVersion = '0.2.0' hiltJetpackVersion = '1.1.0' mediapickerVersion = '0.3.1' - aboutAutomatticVersion = '0.0.6' androidxCameraVersion = '1.2.3' guavaVersion = '33.1.0-android' protobufVersion = '3.25.3' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 952cf992761..24ab5a02aca 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,6 +17,7 @@ androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' androidx-transition = '1.5.1' androidx-work = '2.7.1' +automattic-about = '0.0.6' automattic-tracks = '5.0.0' assertj = '3.24.1' facebook-shimmer = '0.5.0' @@ -67,6 +68,7 @@ androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiaut androidx-transition = { group = "androidx.transition", name = "transition", version.ref = "androidx-transition" } androidx-work-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "androidx-work" } assertj-core = { group = "org.assertj", name = "assertj-core", version.ref = "assertj" } +automattic-about = { group = "com.automattic", name = "about", version.ref = "automattic-about" } automattic-tracks-android = { group = "com.automattic", name = "Automattic-Tracks-Android", version.ref = "automattic-tracks" } automattic-tracks-experimentation = { group = "com.automattic.tracks", name = "experimentation", version.ref = "automattic-tracks" } automattic-tracks-crashlogging = { group = "com.automattic.tracks", name = "crashlogging", version.ref = "automattic-tracks" } From e810a1f21d4d22566fe3eefdf066fd5d72bec316 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:12:36 +0300 Subject: [PATCH 048/162] Deps: Migrate androidx hilt to version catalogs on all modules FYI: Notice that the 'AndroidX Hilt Compose' version on the 'WooCommerce-Wear' module is pointing to '1.2.0', while on the 'WooCommerce' module it is pointing to '1.1.0', as well as all other 'AndroidX Hilt' dependencies on 'WooCommerce-Wear' too, which too are pointing to '1.1.0'. This change downgrades the 'WooCommerce-Wear' version of only 'AndroidX Hilt Compose' to point to '1.1.0' as well, '1.2.0' has only one important change on top of '1.1.0' but no breaking changes. Release Notes: https://developer.android.com/jetpack/androidx/releases/ hilt#hilt_version_12_2 --- WooCommerce-Wear/build.gradle | 10 +++++----- WooCommerce/build.gradle | 10 +++++----- build.gradle | 1 - gradle/libs.versions.toml | 6 ++++++ 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 2023db2981d..20bb5fb0d23 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -185,11 +185,11 @@ dependencies { // Dagger & Hilt implementation "com.google.dagger:hilt-android:$gradle.ext.daggerVersion" - implementation "androidx.hilt:hilt-navigation-fragment:$hiltJetpackVersion" - implementation "androidx.hilt:hilt-common:$hiltJetpackVersion" - implementation "androidx.hilt:hilt-work:$hiltJetpackVersion" - implementation "androidx.hilt:hilt-navigation-compose:1.2.0" - ksp "androidx.hilt:hilt-compiler:$hiltJetpackVersion" + implementation(libs.androidx.hilt.navigation.fragment) + implementation(libs.androidx.hilt.common) + implementation(libs.androidx.hilt.work) + implementation(libs.androidx.hilt.navigation.compose) + ksp(libs.androidx.hilt.compiler) ksp "com.google.dagger:hilt-compiler:$gradle.ext.daggerVersion" implementation "com.google.dagger:dagger-android-support:$gradle.ext.daggerVersion" ksp "com.google.dagger:dagger-android-processor:$gradle.ext.daggerVersion" diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 080210c09ea..a8ad6f4ca75 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -308,11 +308,11 @@ dependencies { // Dagger implementation "com.google.dagger:hilt-android:$gradle.ext.daggerVersion" - implementation "androidx.hilt:hilt-navigation-fragment:$hiltJetpackVersion" - implementation "androidx.hilt:hilt-common:$hiltJetpackVersion" - implementation "androidx.hilt:hilt-work:$hiltJetpackVersion" + implementation(libs.androidx.hilt.navigation.fragment) + implementation(libs.androidx.hilt.common) + implementation(libs.androidx.hilt.work) - ksp "androidx.hilt:hilt-compiler:$hiltJetpackVersion" + ksp(libs.androidx.hilt.compiler) ksp "com.google.dagger:hilt-compiler:$gradle.ext.daggerVersion" implementation "com.google.dagger:dagger-android-support:$gradle.ext.daggerVersion" ksp "com.google.dagger:dagger-android-processor:$gradle.ext.daggerVersion" @@ -446,7 +446,7 @@ dependencies { implementation 'androidx.compose.ui:ui-text-google-fonts' implementation 'androidx.navigation:navigation-compose' - implementation 'androidx.hilt:hilt-navigation-compose:1.1.0' + implementation(libs.androidx.hilt.navigation.compose) implementation(libs.androidx.constraintlayout.compose) implementation(libs.androidx.lifecycle.viewmodel.compose) implementation "io.coil-kt:coil-compose:$coilVersion" diff --git a/build.gradle b/build.gradle index 09442554187..b0680ff5f4b 100644 --- a/build.gradle +++ b/build.gradle @@ -107,7 +107,6 @@ ext { googlePlayCoreVersion = '1.10.3' flipperVersion = '0.176.1' stateMachineVersion = '0.2.0' - hiltJetpackVersion = '1.1.0' mediapickerVersion = '0.3.1' androidxCameraVersion = '1.2.3' guavaVersion = '33.1.0-android' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 24ab5a02aca..1344f4e7374 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,6 +8,7 @@ androidx-constraintlayout-main = '2.1.4' androidx-core-main = '1.13.1' androidx-core-splashscreen = '1.0.1' androidx-datastore = '1.1.0' +androidx-hilt = '1.1.0' androidx-lifecycle = '2.7.0' androidx-preference = '1.2.1' androidx-recyclerview-main = '1.3.2' @@ -52,6 +53,11 @@ androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidx-core-splashscreen" } androidx-datastore-main = { group = "androidx.datastore", name = "datastore", version.ref = "androidx-datastore" } androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "androidx-datastore" } +androidx-hilt-common = { group = "androidx.hilt", name = "hilt-common", version.ref = "androidx-hilt" } +androidx-hilt-compiler = { group = "androidx.hilt", name = "hilt-compiler", version.ref = "androidx-hilt" } +androidx-hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "androidx-hilt" } +androidx-hilt-navigation-fragment = { group = "androidx.hilt", name = "hilt-navigation-fragment", version.ref = "androidx-hilt" } +androidx-hilt-work = { group = "androidx.hilt", name = "hilt-work", version.ref = "androidx-hilt" } androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } From a0eb3625b412db5dacff537ea30a24f5b9e042fb Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:15:22 +0300 Subject: [PATCH 049/162] Deps: Migrate mpandroidchart to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index a8ad6f4ca75..d93d3dfa278 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -317,7 +317,7 @@ dependencies { implementation "com.google.dagger:dagger-android-support:$gradle.ext.daggerVersion" ksp "com.google.dagger:dagger-android-processor:$gradle.ext.daggerVersion" - implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0' + implementation(libs.mpandroidchart) implementation "com.github.bumptech.glide:glide:$glideVersion" ksp "com.github.bumptech.glide:compiler:$glideVersion" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1344f4e7374..24af28fa8c8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -34,6 +34,7 @@ junit = '4.13.2' kotlinx-coroutines = '1.8.1' mockito-inline = '4.6.1' mockito-kotlin = '4.0.0' +mpandroidchart = 'v3.1.0' photoview = '2.3.0' stripe-terminal = '3.7.1' wordpress-aztec = 'v2.1.4' @@ -100,6 +101,7 @@ kotlinx-coroutines-play-services = { group = "org.jetbrains.kotlinx", name = "ko kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } mockito-inline = { group = "org.mockito", name = "mockito-inline", version.ref = "mockito-inline" } mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockito-kotlin" } +mpandroidchart = { group = "com.github.PhilJay", name = "MPAndroidChart", version.ref = "mpandroidchart" } photoview = { group = "com.github.chrisbanes", name = "PhotoView", version.ref = "photoview" } stripe-terminal-localmobile = { group = "com.stripe", name = "stripeterminal-localmobile", version.ref = "stripe-terminal" } stripe-terminal-core = { group = "com.stripe", name = "stripeterminal-core", version.ref = "stripe-terminal" } From 8893f9ac15c293bfe8206b672af1d23c46ab8359 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:21:23 +0300 Subject: [PATCH 050/162] Deps: Migrate bumptech glide to version catalogs on woocommerce FYI: This change also drops the '@aar' suffix requirement, as the per the 'Glide v4 Volley' documentation. PS: The only difference between having the '@aar' suffix and not having it, is the fact that not having it also bring in transitive dependencies related to that 'volley-integration' dependency. --- WooCommerce/build.gradle | 6 +++--- build.gradle | 1 - gradle/libs.versions.toml | 4 ++++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index d93d3dfa278..f4ecd1e7106 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -319,9 +319,9 @@ dependencies { implementation(libs.mpandroidchart) - implementation "com.github.bumptech.glide:glide:$glideVersion" - ksp "com.github.bumptech.glide:compiler:$glideVersion" - implementation "com.github.bumptech.glide:volley-integration:$glideVersion@aar" + implementation(libs.bumptech.glide.main) + ksp(libs.bumptech.glide.compiler) + implementation(libs.bumptech.glide.volley.integration) implementation 'com.google.android.play:app-update:2.1.0' implementation 'com.google.android.play:review:2.0.1' diff --git a/build.gradle b/build.gradle index b0680ff5f4b..e89ab400436 100644 --- a/build.gradle +++ b/build.gradle @@ -100,7 +100,6 @@ tasks.register("installGitHooks", Copy) { } ext { - glideVersion = '4.16.0' coilVersion = '2.1.0' constraintLayoutVersion = '1.2.0' eventBusVersion = '3.3.1' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 24af28fa8c8..af5128aa332 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -21,6 +21,7 @@ androidx-work = '2.7.1' automattic-about = '0.0.6' automattic-tracks = '5.0.0' assertj = '3.24.1' +bumptech-glide = '4.16.0' facebook-shimmer = '0.5.0' google-firebase-bom = '32.7.1' google-material = '1.12.0' @@ -79,6 +80,9 @@ automattic-about = { group = "com.automattic", name = "about", version.ref = "au automattic-tracks-android = { group = "com.automattic", name = "Automattic-Tracks-Android", version.ref = "automattic-tracks" } automattic-tracks-experimentation = { group = "com.automattic.tracks", name = "experimentation", version.ref = "automattic-tracks" } automattic-tracks-crashlogging = { group = "com.automattic.tracks", name = "crashlogging", version.ref = "automattic-tracks" } +bumptech-glide-main = { group = "com.github.bumptech.glide", name = "glide", version.ref = "bumptech-glide" } +bumptech-glide-compiler = { group = "com.github.bumptech.glide", name = "compiler", version.ref = "bumptech-glide" } +bumptech-glide-volley-integration = { group = "com.github.bumptech.glide", name = "volley-integration", version.ref = "bumptech-glide" } facebook-shimmer = { group = "com.facebook.shimmer", name = "shimmer", version.ref = "facebook-shimmer" } google-firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics" } google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } From 74c7aa97387db31b166aacbb3917719fbd5238a1 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:30:13 +0300 Subject: [PATCH 051/162] Deps: Migrate google play to version catalogs on woocommerce --- WooCommerce/build.gradle | 4 ++-- gradle/libs.versions.toml | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index f4ecd1e7106..f4cbd5e0f4e 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -322,8 +322,8 @@ dependencies { implementation(libs.bumptech.glide.main) ksp(libs.bumptech.glide.compiler) implementation(libs.bumptech.glide.volley.integration) - implementation 'com.google.android.play:app-update:2.1.0' - implementation 'com.google.android.play:review:2.0.1' + implementation(libs.google.play.app.update) + implementation(libs.google.play.review) implementation(libs.google.play.services.code.scanner) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index af5128aa332..93014707c5c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -27,6 +27,8 @@ google-firebase-bom = '32.7.1' google-material = '1.12.0' google-mlkit-barcode-scanning = '17.2.0' google-mlkit-text-recognition = '16.0.0' +google-play-app-update = '2.1.0' +google-play-review = '2.0.1' google-play-services-auth = '20.2.0' google-play-services-code-scanner = '16.1.0' google-play-services-wearable = '18.1.0' @@ -94,6 +96,8 @@ google-mlkit-text-recognition-main = { group = "com.google.mlkit", name = "text- google-mlkit-text-recognition-japanese = { group = "com.google.android.gms", name = "play-services-mlkit-text-recognition-japanese", version.ref = "google-mlkit-text-recognition" } google-mlkit-text-recognition-chinese = { group = "com.google.android.gms", name = "play-services-mlkit-text-recognition-chinese", version.ref = "google-mlkit-text-recognition" } google-mlkit-text-recognition-korean = { group = "com.google.android.gms", name = "play-services-mlkit-text-recognition-korean", version.ref = "google-mlkit-text-recognition" } +google-play-app-update = { group = "com.google.android.play", name = "app-update", version.ref = "google-play-app-update" } +google-play-review = { group = "com.google.android.play", name = "review", version.ref = "google-play-review" } google-play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "google-play-services-auth" } google-play-services-code-scanner = { group = "com.google.android.gms", name = "play-services-code-scanner", version.ref = "google-play-services-code-scanner" } google-play-services-wearable = { group = "com.google.android.gms", name = "play-services-wearable", version.ref = "google-play-services-wearable" } From 627041c0417ccc8dd21ba264c3175635b8516375 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:32:35 +0300 Subject: [PATCH 052/162] Deps: Migrate google zxing to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index f4cbd5e0f4e..1ed79afbb32 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -334,7 +334,7 @@ dependencies { implementation(libs.google.mlkit.barcode.scanning) - implementation "com.google.zxing:core:3.5.3" + implementation(libs.google.zxing.core) implementation(libs.google.play.services.wearable) // Debug dependencies diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 93014707c5c..1f5b380718e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,6 +32,7 @@ google-play-review = '2.0.1' google-play-services-auth = '20.2.0' google-play-services-code-scanner = '16.1.0' google-play-services-wearable = '18.1.0' +google-zxing = '3.5.3' gravatar = '0.2.0' junit = '4.13.2' kotlinx-coroutines = '1.8.1' @@ -101,6 +102,7 @@ google-play-review = { group = "com.google.android.play", name = "review", versi google-play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "google-play-services-auth" } google-play-services-code-scanner = { group = "com.google.android.gms", name = "play-services-code-scanner", version.ref = "google-play-services-code-scanner" } google-play-services-wearable = { group = "com.google.android.gms", name = "play-services-wearable", version.ref = "google-play-services-wearable" } +google-zxing-core = { group = "com.google.zxing", name = "core", version.ref = "google-zxing" } gravatar = { group = "com.gravatar", name = "gravatar", version.ref = "gravatar" } junit = { group = "junit", name = "junit", version.ref = "junit" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } From 9a6e4627e36ab19b377e652a3b6c28b6be5b095e Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:35:45 +0300 Subject: [PATCH 053/162] Deps: Migrate facebook flipper to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 4 ++-- WooCommerce/build.gradle | 4 ++-- build.gradle | 1 - gradle/libs.versions.toml | 3 +++ 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 20bb5fb0d23..70260271bd3 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -207,9 +207,9 @@ dependencies { }) // Debug dependencies - debugImplementation "com.facebook.flipper:flipper:$flipperVersion" + debugImplementation(libs.facebook.flipper.main) debugImplementation "com.facebook.soloader:soloader:0.10.4" - debugImplementation("com.facebook.flipper:flipper-network-plugin:$flipperVersion") { + debugImplementation(libs.facebook.flipper.network.plugin) { // Force Flipper to use the okhttp version defined in the fluxc module // okhttp versions higher than 3.9.0 break handling for self-signed SSL sites // See https://github.com/wordpress-mobile/WordPress-FluxC-Android/issues/919 diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 1ed79afbb32..a89a298fa6d 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -338,9 +338,9 @@ dependencies { implementation(libs.google.play.services.wearable) // Debug dependencies - debugImplementation "com.facebook.flipper:flipper:$flipperVersion" + debugImplementation(libs.facebook.flipper.main) debugImplementation "com.facebook.soloader:soloader:0.10.4" - debugImplementation("com.facebook.flipper:flipper-network-plugin:$flipperVersion") { + debugImplementation(libs.facebook.flipper.network.plugin) { // Force Flipper to use the okhttp version defined in the fluxc module // okhttp versions higher than 3.9.0 break handling for self-signed SSL sites // See https://github.com/wordpress-mobile/WordPress-FluxC-Android/issues/919 diff --git a/build.gradle b/build.gradle index e89ab400436..1c324ac52dc 100644 --- a/build.gradle +++ b/build.gradle @@ -104,7 +104,6 @@ ext { constraintLayoutVersion = '1.2.0' eventBusVersion = '3.3.1' googlePlayCoreVersion = '1.10.3' - flipperVersion = '0.176.1' stateMachineVersion = '0.2.0' mediapickerVersion = '0.3.1' androidxCameraVersion = '1.2.3' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1f5b380718e..380af895b86 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,6 +22,7 @@ automattic-about = '0.0.6' automattic-tracks = '5.0.0' assertj = '3.24.1' bumptech-glide = '4.16.0' +facebook-flipper = '0.176.1' facebook-shimmer = '0.5.0' google-firebase-bom = '32.7.1' google-material = '1.12.0' @@ -86,6 +87,8 @@ automattic-tracks-crashlogging = { group = "com.automattic.tracks", name = "cras bumptech-glide-main = { group = "com.github.bumptech.glide", name = "glide", version.ref = "bumptech-glide" } bumptech-glide-compiler = { group = "com.github.bumptech.glide", name = "compiler", version.ref = "bumptech-glide" } bumptech-glide-volley-integration = { group = "com.github.bumptech.glide", name = "volley-integration", version.ref = "bumptech-glide" } +facebook-flipper-main = { group = "com.facebook.flipper", name = "flipper", version.ref = "facebook-flipper" } +facebook-flipper-network-plugin = { group = "com.facebook.flipper", name = "flipper-network-plugin", version.ref = "facebook-flipper" } facebook-shimmer = { group = "com.facebook.shimmer", name = "shimmer", version.ref = "facebook-shimmer" } google-firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics" } google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } From 24964f463527082820c35bd275422b6c5088d5ae Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:37:53 +0300 Subject: [PATCH 054/162] Deps: Migrate facebook soloader to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 70260271bd3..952bb0e45c9 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -208,7 +208,7 @@ dependencies { // Debug dependencies debugImplementation(libs.facebook.flipper.main) - debugImplementation "com.facebook.soloader:soloader:0.10.4" + debugImplementation(libs.facebook.soloader) debugImplementation(libs.facebook.flipper.network.plugin) { // Force Flipper to use the okhttp version defined in the fluxc module // okhttp versions higher than 3.9.0 break handling for self-signed SSL sites diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index a89a298fa6d..b96ce160c4a 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -339,7 +339,7 @@ dependencies { // Debug dependencies debugImplementation(libs.facebook.flipper.main) - debugImplementation "com.facebook.soloader:soloader:0.10.4" + debugImplementation(libs.facebook.soloader) debugImplementation(libs.facebook.flipper.network.plugin) { // Force Flipper to use the okhttp version defined in the fluxc module // okhttp versions higher than 3.9.0 break handling for self-signed SSL sites diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 380af895b86..3c8d7a3c242 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,6 +24,7 @@ assertj = '3.24.1' bumptech-glide = '4.16.0' facebook-flipper = '0.176.1' facebook-shimmer = '0.5.0' +facebook-soloader = '0.10.4' google-firebase-bom = '32.7.1' google-material = '1.12.0' google-mlkit-barcode-scanning = '17.2.0' @@ -90,6 +91,7 @@ bumptech-glide-volley-integration = { group = "com.github.bumptech.glide", name facebook-flipper-main = { group = "com.facebook.flipper", name = "flipper", version.ref = "facebook-flipper" } facebook-flipper-network-plugin = { group = "com.facebook.flipper", name = "flipper-network-plugin", version.ref = "facebook-flipper" } facebook-shimmer = { group = "com.facebook.shimmer", name = "shimmer", version.ref = "facebook-shimmer" } +facebook-soloader = { group = "com.facebook.soloader", name = "soloader", version.ref = "facebook-soloader" } google-firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics" } google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } google-firebase-config = { group = "com.google.firebase", name = "firebase-config" } From f3479a36a76cf113e553eeee6411350c0fa1d8af Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:40:36 +0300 Subject: [PATCH 055/162] Deps: Migrate squareup leakcanary to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index b96ce160c4a..f53e1186a39 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -348,7 +348,7 @@ dependencies { } if (isLeakCanaryEnabled()) { - debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14' + debugImplementation(libs.squareup.leakcanary.android) } // Dependencies for local unit tests diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3c8d7a3c242..5bfc90ddd24 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -42,6 +42,7 @@ mockito-inline = '4.6.1' mockito-kotlin = '4.0.0' mpandroidchart = 'v3.1.0' photoview = '2.3.0' +squareup-leakcanary = '2.14' stripe-terminal = '3.7.1' wordpress-aztec = 'v2.1.4' wordpress-fluxc = 'trunk-7ad6ce4c250ba435d8d8c7feb898bceb259fb007' @@ -118,6 +119,7 @@ mockito-inline = { group = "org.mockito", name = "mockito-inline", version.ref = mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockito-kotlin" } mpandroidchart = { group = "com.github.PhilJay", name = "MPAndroidChart", version.ref = "mpandroidchart" } photoview = { group = "com.github.chrisbanes", name = "PhotoView", version.ref = "photoview" } +squareup-leakcanary-android = { group = "com.squareup.leakcanary", name = "leakcanary-android", version.ref = "squareup-leakcanary" } stripe-terminal-localmobile = { group = "com.stripe", name = "stripeterminal-localmobile", version.ref = "stripe-terminal" } stripe-terminal-core = { group = "com.stripe", name = "stripeterminal-core", version.ref = "stripe-terminal" } wordpress-libaddressinput-common = { group = "org.wordpress", name = "libaddressinput.common", version.ref = "wordpress-libaddressinput" } From 7fe947b3eae77d189a0cf526ff4305ae62c0cce5 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:44:08 +0300 Subject: [PATCH 056/162] Deps: Migrate androidx arch core to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 4 ++-- WooCommerce/build.gradle | 4 ++-- gradle/libs.versions.toml | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 952bb0e45c9..07125b98495 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -200,11 +200,11 @@ dependencies { testImplementation(libs.mockito.inline) testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" testImplementation(libs.assertj.core) - testImplementation("androidx.arch.core:core-testing:2.1.0", { + testImplementation(libs.androidx.arch.core.testing) { exclude group: 'com.android.support', module: 'support-compat' exclude group: 'com.android.support', module: 'support-annotations' exclude group: 'com.android.support', module: 'support-core-utils' - }) + } // Debug dependencies debugImplementation(libs.facebook.flipper.main) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index f53e1186a39..1c4d9116437 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -357,11 +357,11 @@ dependencies { testImplementation(libs.mockito.inline) testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" testImplementation(libs.assertj.core) - testImplementation("androidx.arch.core:core-testing:2.1.0", { + testImplementation(libs.androidx.arch.core.testing) { exclude group: 'com.android.support', module: 'support-compat' exclude group: 'com.android.support', module: 'support-annotations' exclude group: 'com.android.support', module: 'support-core-utils' - }) + } // Dependencies for Espresso UI tests androidTestImplementation(libs.androidx.test.ext.junit) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5bfc90ddd24..cdd2ad45c36 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,7 @@ [versions] android-billingclient = '5.0.0' androidx-appcompat = '1.4.2' +androidx-arch-core = '2.1.0' androidx-browser = '1.5.0' androidx-cardview = '1.0.0' androidx-constraintlayout-compose = '1.0.1' @@ -53,6 +54,7 @@ wordpress-utils = '3.5.0' [libraries] android-billingclient-ktx = { group = "com.android.billingclient", name = "billing-ktx", version.ref = "android-billingclient" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } +androidx-arch-core-testing = { group = "androidx.arch.core", name = "core-testing", version.ref = "androidx-arch-core" } androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "androidx-browser" } androidx-cardview = { group = "androidx.cardview", name = "cardview", version.ref = "androidx-cardview" } androidx-constraintlayout-compose = { group = "androidx.constraintlayout", name = "constraintlayout-compose", version.ref = "androidx-constraintlayout-compose" } From 50cfbcae8381cb4f39c1bf4f507432c9a314bf51 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:46:32 +0300 Subject: [PATCH 057/162] Deps: Migrate androidx test espresso to version catalogs on woocommerce --- WooCommerce/build.gradle | 4 ++-- build.gradle | 3 --- gradle/libs.versions.toml | 3 +++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 1c4d9116437..92654b57db9 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -367,8 +367,8 @@ dependencies { androidTestImplementation(libs.androidx.test.ext.junit) androidTestImplementation(libs.androidx.test.main.rules) androidTestImplementation(libs.assertj.core) - androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion" - androidTestImplementation("androidx.test.espresso:espresso-contrib:$espressoVersion") { + androidTestImplementation(libs.androidx.test.espresso.core) + androidTestImplementation(libs.androidx.test.espresso.contrib) { exclude group: "com.google.protobuf", module: "protobuf-lite" } androidTestImplementation "com.google.dagger:hilt-android-testing:$gradle.ext.daggerVersion" diff --git a/build.gradle b/build.gradle index 1c324ac52dc..49d9ba0ed91 100644 --- a/build.gradle +++ b/build.gradle @@ -122,9 +122,6 @@ ext { composeCompilerVersion = "1.5.9" composeAccompanistVersion = "0.32.0" wearComposeVersion = "1.3.1" - - // Testing - espressoVersion = '3.4.0' } // Onboarding and dev env setup tasks diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cdd2ad45c36..197002ceb87 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,6 +14,7 @@ androidx-lifecycle = '2.7.0' androidx-preference = '1.2.1' androidx-recyclerview-main = '1.3.2' androidx-recyclerview-selection = '1.1.0' +androidx-test-espresso = '3.4.0' androidx-test-ext = '1.1.5' androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' @@ -76,6 +77,8 @@ androidx-preference-main = { group = "androidx.preference", name = "preference", androidx-preference-ktx = { group = "androidx.preference", name = "preference-ktx", version.ref = "androidx-preference" } androidx-recyclerview-main = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "androidx-recyclerview-main" } androidx-recyclerview-selection = { group = "androidx.recyclerview", name = "recyclerview-selection", version.ref = "androidx-recyclerview-selection" } +androidx-test-espresso-contrib = { group = "androidx.test.espresso", name = "espresso-contrib", version.ref = "androidx-test-espresso" } +androidx-test-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "androidx-test-espresso" } androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext" } androidx-test-main-core = { group = "androidx.test", name = "core", version.ref = "androidx-test-main" } androidx-test-main-rules = { group = "androidx.test", name = "rules", version.ref = "androidx-test-main" } From c9951d34b4037b4778d12d265430b08a1f431f60 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:49:07 +0300 Subject: [PATCH 058/162] Deps: Migrate fastlane screengrab to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 92654b57db9..3140fb16acf 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -376,7 +376,7 @@ dependencies { androidTestImplementation(libs.androidx.test.uiautomator) // Dependencies for screenshots - androidTestImplementation 'tools.fastlane:screengrab:2.1.1' + androidTestImplementation(libs.fastlane.screengrab) androidTestImplementation('com.github.tomakehurst:wiremock') { exclude group: 'org.apache.httpcomponents', module: 'httpclient' exclude group: 'org.apache.commons', module: 'commons-lang3' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 197002ceb87..b147d54d417 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -27,6 +27,7 @@ bumptech-glide = '4.16.0' facebook-flipper = '0.176.1' facebook-shimmer = '0.5.0' facebook-soloader = '0.10.4' +fastlane-screengrab = '2.1.1' google-firebase-bom = '32.7.1' google-material = '1.12.0' google-mlkit-barcode-scanning = '17.2.0' @@ -98,6 +99,7 @@ facebook-flipper-main = { group = "com.facebook.flipper", name = "flipper", vers facebook-flipper-network-plugin = { group = "com.facebook.flipper", name = "flipper-network-plugin", version.ref = "facebook-flipper" } facebook-shimmer = { group = "com.facebook.shimmer", name = "shimmer", version.ref = "facebook-shimmer" } facebook-soloader = { group = "com.facebook.soloader", name = "soloader", version.ref = "facebook-soloader" } +fastlane-screengrab = { group = "tools.fastlane", name = "screengrab", version.ref = "fastlane-screengrab" } google-firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics" } google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } google-firebase-config = { group = "com.google.firebase", name = "firebase-config" } From 3b4cff793f86b551b13c7425e82a8152f120cedb Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:51:39 +0300 Subject: [PATCH 059/162] Deps: Migrate wiremock to version catalogs on woocommerce --- WooCommerce/build.gradle | 4 ++-- gradle/libs.versions.toml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 3140fb16acf..9b2868eb00b 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -377,14 +377,14 @@ dependencies { // Dependencies for screenshots androidTestImplementation(libs.fastlane.screengrab) - androidTestImplementation('com.github.tomakehurst:wiremock') { + androidTestImplementation(libs.wiremock.get().module.toString()) { exclude group: 'org.apache.httpcomponents', module: 'httpclient' exclude group: 'org.apache.commons', module: 'commons-lang3' exclude group: 'asm', module: 'asm' exclude group: 'org.json', module: 'json' } constraints { - androidTestImplementation("com.github.tomakehurst:wiremock:2.26.3") { + androidTestImplementation(libs.wiremock) { because("newer versions of WireMock use Java APIs not available on Android") } androidTestImplementation('org.eclipse.jetty:jetty-webapp:9.4.51.v20230217') { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b147d54d417..636a10c053c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -47,6 +47,7 @@ mpandroidchart = 'v3.1.0' photoview = '2.3.0' squareup-leakcanary = '2.14' stripe-terminal = '3.7.1' +wiremock = '2.26.3' wordpress-aztec = 'v2.1.4' wordpress-fluxc = 'trunk-7ad6ce4c250ba435d8d8c7feb898bceb259fb007' wordpress-login = '1.18.0' @@ -129,6 +130,7 @@ photoview = { group = "com.github.chrisbanes", name = "PhotoView", version.ref = squareup-leakcanary-android = { group = "com.squareup.leakcanary", name = "leakcanary-android", version.ref = "squareup-leakcanary" } stripe-terminal-localmobile = { group = "com.stripe", name = "stripeterminal-localmobile", version.ref = "stripe-terminal" } stripe-terminal-core = { group = "com.stripe", name = "stripeterminal-core", version.ref = "stripe-terminal" } +wiremock = { group = "com.github.tomakehurst", name = "wiremock", version.ref = "wiremock" } wordpress-libaddressinput-common = { group = "org.wordpress", name = "libaddressinput.common", version.ref = "wordpress-libaddressinput" } wordpress-aztec-main = { group = "org.wordpress", name = "aztec", version.ref = "wordpress-aztec" } wordpress-aztec-glide-loader = { group = "org.wordpress.aztec", name = "glide-loader", version.ref = "wordpress-aztec" } From bf0a57687f96453692c8d848d81cf004a1289e80 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:53:38 +0300 Subject: [PATCH 060/162] Deps: Migrate jetty webapp to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 9b2868eb00b..e0c6be88b12 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -387,7 +387,7 @@ dependencies { androidTestImplementation(libs.wiremock) { because("newer versions of WireMock use Java APIs not available on Android") } - androidTestImplementation('org.eclipse.jetty:jetty-webapp:9.4.51.v20230217') { + androidTestImplementation(libs.jetty.webapp) { because("version shipped with WireMock 2.26.3 contains security vulnerabilities") } androidTestImplementation('com.fasterxml.jackson.core:jackson-databind:2.12.7.1') { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 636a10c053c..6644a2ef564 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,6 +39,7 @@ google-play-services-code-scanner = '16.1.0' google-play-services-wearable = '18.1.0' google-zxing = '3.5.3' gravatar = '0.2.0' +jetty-webapp = '9.4.51.v20230217' junit = '4.13.2' kotlinx-coroutines = '1.8.1' mockito-inline = '4.6.1' @@ -118,6 +119,7 @@ google-play-services-code-scanner = { group = "com.google.android.gms", name = " google-play-services-wearable = { group = "com.google.android.gms", name = "play-services-wearable", version.ref = "google-play-services-wearable" } google-zxing-core = { group = "com.google.zxing", name = "core", version.ref = "google-zxing" } gravatar = { group = "com.gravatar", name = "gravatar", version.ref = "gravatar" } +jetty-webapp = { group = "org.eclipse.jetty", name = "jetty-webapp", version.ref = "jetty-webapp" } junit = { group = "junit", name = "junit", version.ref = "junit" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } From dd02fae4841ec9d65dde77059bda96b8d3d18b18 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:55:13 +0300 Subject: [PATCH 061/162] Deps: Migrate jackson databind to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index e0c6be88b12..52a44e731c4 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -390,7 +390,7 @@ dependencies { androidTestImplementation(libs.jetty.webapp) { because("version shipped with WireMock 2.26.3 contains security vulnerabilities") } - androidTestImplementation('com.fasterxml.jackson.core:jackson-databind:2.12.7.1') { + androidTestImplementation(libs.jackson.databind) { because("version shipped with WireMock 2.26.3 contains security vulnerabilities") } androidTestImplementation('com.jayway.jsonpath:json-path:2.9.0') { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6644a2ef564..186a64abfd1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,6 +39,7 @@ google-play-services-code-scanner = '16.1.0' google-play-services-wearable = '18.1.0' google-zxing = '3.5.3' gravatar = '0.2.0' +jackson-databind = '2.12.7.1' jetty-webapp = '9.4.51.v20230217' junit = '4.13.2' kotlinx-coroutines = '1.8.1' @@ -119,6 +120,7 @@ google-play-services-code-scanner = { group = "com.google.android.gms", name = " google-play-services-wearable = { group = "com.google.android.gms", name = "play-services-wearable", version.ref = "google-play-services-wearable" } google-zxing-core = { group = "com.google.zxing", name = "core", version.ref = "google-zxing" } gravatar = { group = "com.gravatar", name = "gravatar", version.ref = "gravatar" } +jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson-databind" } jetty-webapp = { group = "org.eclipse.jetty", name = "jetty-webapp", version.ref = "jetty-webapp" } junit = { group = "junit", name = "junit", version.ref = "junit" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } From 2d4f674c626a7ec2bbf513323849aa756f23d5f4 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:56:22 +0300 Subject: [PATCH 062/162] Deps: Migrate json path to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 52a44e731c4..cb4b207b0b0 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -393,7 +393,7 @@ dependencies { androidTestImplementation(libs.jackson.databind) { because("version shipped with WireMock 2.26.3 contains security vulnerabilities") } - androidTestImplementation('com.jayway.jsonpath:json-path:2.9.0') { + androidTestImplementation(libs.json.path) { because("version shipped with WireMock 2.26.3 contains security vulnerabilities") } androidTestImplementation('commons-fileupload:commons-fileupload:1.5') { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 186a64abfd1..b1632643226 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -41,6 +41,7 @@ google-zxing = '3.5.3' gravatar = '0.2.0' jackson-databind = '2.12.7.1' jetty-webapp = '9.4.51.v20230217' +json-path = '2.9.0' junit = '4.13.2' kotlinx-coroutines = '1.8.1' mockito-inline = '4.6.1' @@ -122,6 +123,7 @@ google-zxing-core = { group = "com.google.zxing", name = "core", version.ref = " gravatar = { group = "com.gravatar", name = "gravatar", version.ref = "gravatar" } jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson-databind" } jetty-webapp = { group = "org.eclipse.jetty", name = "jetty-webapp", version.ref = "jetty-webapp" } +json-path = { group = "com.jayway.jsonpath", name = "json-path", version.ref = "json-path" } junit = { group = "junit", name = "junit", version.ref = "junit" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } From 1334fecd1d5a2af247594672e0edfd768b573706 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:57:37 +0300 Subject: [PATCH 063/162] Deps: Migrate commons fileupload to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index cb4b207b0b0..0c0d568b3bb 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -396,7 +396,7 @@ dependencies { androidTestImplementation(libs.json.path) { because("version shipped with WireMock 2.26.3 contains security vulnerabilities") } - androidTestImplementation('commons-fileupload:commons-fileupload:1.5') { + androidTestImplementation(libs.commons.fileupload) { because("version shipped with WireMock 2.26.3 contains security vulnerabilities") } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b1632643226..e79cf32f3f1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,6 +24,7 @@ automattic-about = '0.0.6' automattic-tracks = '5.0.0' assertj = '3.24.1' bumptech-glide = '4.16.0' +commons-fileupload = '1.5' facebook-flipper = '0.176.1' facebook-shimmer = '0.5.0' facebook-soloader = '0.10.4' @@ -99,6 +100,7 @@ automattic-tracks-crashlogging = { group = "com.automattic.tracks", name = "cras bumptech-glide-main = { group = "com.github.bumptech.glide", name = "glide", version.ref = "bumptech-glide" } bumptech-glide-compiler = { group = "com.github.bumptech.glide", name = "compiler", version.ref = "bumptech-glide" } bumptech-glide-volley-integration = { group = "com.github.bumptech.glide", name = "volley-integration", version.ref = "bumptech-glide" } +commons-fileupload = { group = "commons-fileupload", name = "commons-fileupload", version.ref = "commons-fileupload" } facebook-flipper-main = { group = "com.facebook.flipper", name = "flipper", version.ref = "facebook-flipper" } facebook-flipper-network-plugin = { group = "com.facebook.flipper", name = "flipper-network-plugin", version.ref = "facebook-flipper" } facebook-shimmer = { group = "com.facebook.shimmer", name = "shimmer", version.ref = "facebook-shimmer" } From be21407f54664b404e93b84f6ff686b6c9b50d7a Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 16:59:32 +0300 Subject: [PATCH 064/162] Deps: Migrate apache http client android to version catalogs on wc --- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 0c0d568b3bb..0de03571106 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -400,7 +400,7 @@ dependencies { because("version shipped with WireMock 2.26.3 contains security vulnerabilities") } } - androidTestImplementation "org.apache.httpcomponents:httpclient-android:$httpClientAndroidVersion" + androidTestImplementation(libs.apache.http.client.android) implementation("com.zendesk:support:5.0.8") { exclude group: 'com.android.support', module: 'support-annotations' diff --git a/build.gradle b/build.gradle index 49d9ba0ed91..50c9a043e78 100644 --- a/build.gradle +++ b/build.gradle @@ -115,7 +115,6 @@ ext { // Apache commonsText = '1.10.0' commonsIO = '2.11.0' - httpClientAndroidVersion = '4.3.5.1' // Compose and its module versions need to be consistent with each other (for example 'compose-theme-adapter') composeBOMVersion = "2024.04.00" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e79cf32f3f1..e12de9c3c5b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,6 +20,7 @@ androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' androidx-transition = '1.5.1' androidx-work = '2.7.1' +apache-http-client-android = '4.3.5.1' automattic-about = '0.0.6' automattic-tracks = '5.0.0' assertj = '3.24.1' @@ -92,6 +93,7 @@ androidx-test-main-runner = { group = "androidx.test", name = "runner", version. androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidx-test-uiautomator" } androidx-transition = { group = "androidx.transition", name = "transition", version.ref = "androidx-transition" } androidx-work-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "androidx-work" } +apache-http-client-android = { group = "org.apache.httpcomponents", name = "httpclient-android", version.ref = "apache-http-client-android" } assertj-core = { group = "org.assertj", name = "assertj-core", version.ref = "assertj" } automattic-about = { group = "com.automattic", name = "about", version.ref = "automattic-about" } automattic-tracks-android = { group = "com.automattic", name = "Automattic-Tracks-Android", version.ref = "automattic-tracks" } From 9631da3e02f32a35cd2ea91eed0d728d5e35456f Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 17:01:26 +0300 Subject: [PATCH 065/162] Deps: Migrate zendesk to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 0de03571106..8f4038cdcf4 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -402,7 +402,7 @@ dependencies { } androidTestImplementation(libs.apache.http.client.android) - implementation("com.zendesk:support:5.0.8") { + implementation(libs.zendesk.support) { exclude group: 'com.android.support', module: 'support-annotations' } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e12de9c3c5b..8ff3ef0d32c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -58,6 +58,7 @@ wordpress-fluxc = 'trunk-7ad6ce4c250ba435d8d8c7feb898bceb259fb007' wordpress-login = '1.18.0' wordpress-libaddressinput = '0.0.2' wordpress-utils = '3.5.0' +zendesk = '5.0.8' [libraries] android-billingclient-ktx = { group = "com.android.billingclient", name = "billing-ktx", version.ref = "android-billingclient" } @@ -145,3 +146,4 @@ wordpress-libaddressinput-common = { group = "org.wordpress", name = "libaddress wordpress-aztec-main = { group = "org.wordpress", name = "aztec", version.ref = "wordpress-aztec" } wordpress-aztec-glide-loader = { group = "org.wordpress.aztec", name = "glide-loader", version.ref = "wordpress-aztec" } wordpress-utils = { group = "org.wordpress", name = "utils", version.ref = "wordpress-utils" } +zendesk-support = { group = "com.zendesk", name = "support", version.ref = "zendesk" } From 5be0d0f4d79f777cff3622373ca55767624493ff Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 17:03:55 +0300 Subject: [PATCH 066/162] Deps: Migrate androidx fragment to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 8f4038cdcf4..1fcce347642 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -407,7 +407,7 @@ dependencies { } // ViewModel and LiveData - implementation "androidx.fragment:fragment-ktx:1.8.2" + implementation(libs.androidx.fragment.ktx) implementation "androidx.activity:activity-ktx:1.8.0" implementation(libs.androidx.lifecycle.viewmodel.savedstate) implementation(libs.androidx.lifecycle.process) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8ff3ef0d32c..19ca6069c9f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,7 @@ androidx-constraintlayout-main = '2.1.4' androidx-core-main = '1.13.1' androidx-core-splashscreen = '1.0.1' androidx-datastore = '1.1.0' +androidx-fragment = '1.8.2' androidx-hilt = '1.1.0' androidx-lifecycle = '2.7.0' androidx-preference = '1.2.1' @@ -72,6 +73,7 @@ androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidx-core-splashscreen" } androidx-datastore-main = { group = "androidx.datastore", name = "datastore", version.ref = "androidx-datastore" } androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "androidx-datastore" } +androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "androidx-fragment" } androidx-hilt-common = { group = "androidx.hilt", name = "hilt-common", version.ref = "androidx-hilt" } androidx-hilt-compiler = { group = "androidx.hilt", name = "hilt-compiler", version.ref = "androidx-hilt" } androidx-hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "androidx-hilt" } From 00004566190250be7501cdc2f164fd6f94eb67f7 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Fri, 4 Oct 2024 17:42:23 +0200 Subject: [PATCH 067/162] Add extra test case --- .../BlazeCampaignCreationDispatcherTests.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcherTests.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcherTests.kt index eab49ee32fe..975e2b96933 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcherTests.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcherTests.kt @@ -123,4 +123,25 @@ class BlazeCampaignCreationDispatcherTests : BaseUnitTest() { ) ) } + + @Test + fun `given no campaign yet, when starting the flow from intro screen, then start flow without intro`() = + testBlocking { + setup { + whenever(blazeRepository.getMostRecentCampaign()).thenReturn(null) + } + + var event: BlazeCampaignCreationDispatcherEvent? = null + dispatcher.startCampaignCreation( + source = BlazeFlowSource.INTRO_VIEW, + productId = 1L + ) { event = it } + + assertThat(event).isEqualTo( + BlazeCampaignCreationDispatcherEvent.ShowBlazeCampaignCreationForm( + productId = 1L, + blazeSource = BlazeFlowSource.INTRO_VIEW + ) + ) + } } From 4ecc1502971775da12c828f6801386749b17bb2c Mon Sep 17 00:00:00 2001 From: Alejo Date: Fri, 4 Oct 2024 11:35:37 -0600 Subject: [PATCH 068/162] add new fragment --- .../WooShippingLabelCreationFragment.kt | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationFragment.kt diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationFragment.kt new file mode 100644 index 00000000000..783949d31de --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationFragment.kt @@ -0,0 +1,39 @@ +package com.woocommerce.android.ui.orders.wooshippinglabels + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import com.woocommerce.android.R +import com.woocommerce.android.ui.base.BaseFragment +import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground + +class WooShippingLabelCreationFragment : BaseFragment() { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + WooThemeWithBackground { + Surface { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Text(text = "This is the new shipping label flow") + } + } + } + } + } + } + + override fun getFragmentTitle() = getString(R.string.orderdetail_shipping_label_create_shipping_label) +} From 73e880a0b61ed3ed393c90e31e2b4154818cb23d Mon Sep 17 00:00:00 2001 From: Alejo Date: Fri, 4 Oct 2024 11:36:04 -0600 Subject: [PATCH 069/162] check for new plugin --- .../ui/orders/details/ShippingLabelOnboardingRepository.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt index 85a1383e8f0..a08234948ef 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/ShippingLabelOnboardingRepository.kt @@ -74,5 +74,6 @@ class ShippingLabelOnboardingRepository @Inject constructor( WCS_SUPPORTED; fun isSupported() = this == WCS_SUPPORTED || this == WC_SHIPPING_SUPPORTED + fun isWooShippingSupported() = this == WC_SHIPPING_SUPPORTED } } From 3279d33be5dc0d02d412b34048e24696f0b54c38 Mon Sep 17 00:00:00 2001 From: Alejo Date: Fri, 4 Oct 2024 11:36:44 -0600 Subject: [PATCH 070/162] navigation to woo shipping flow --- .../android/ui/orders/OrderNavigationTarget.kt | 1 + .../woocommerce/android/ui/orders/OrderNavigator.kt | 7 +++++++ .../src/main/res/navigation/nav_graph_orders.xml | 11 +++++++++++ 3 files changed, 19 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderNavigationTarget.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderNavigationTarget.kt index ff7794a59ba..681467cdf22 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderNavigationTarget.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderNavigationTarget.kt @@ -53,6 +53,7 @@ sealed class OrderNavigationTarget : Event() { object ViewShippingLabelFormatOptions : OrderNavigationTarget() data class ViewPrintCustomsForm(val invoices: List, val isReprint: Boolean) : OrderNavigationTarget() data class StartShippingLabelCreationFlow(val orderId: Long) : OrderNavigationTarget() + data class StartWooShippingLabelCreationFlow(val orderId: Long) : OrderNavigationTarget() data class StartPaymentFlow( val orderId: Long, val paymentTypeFlow: CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderNavigator.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderNavigator.kt index 30e58230cf0..a20b87fba7b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderNavigator.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderNavigator.kt @@ -17,6 +17,7 @@ import com.woocommerce.android.ui.orders.OrderNavigationTarget.PrintShippingLabe import com.woocommerce.android.ui.orders.OrderNavigationTarget.RefundShippingLabel import com.woocommerce.android.ui.orders.OrderNavigationTarget.StartPaymentFlow import com.woocommerce.android.ui.orders.OrderNavigationTarget.StartShippingLabelCreationFlow +import com.woocommerce.android.ui.orders.OrderNavigationTarget.StartWooShippingLabelCreationFlow import com.woocommerce.android.ui.orders.OrderNavigationTarget.ViewCreateShippingLabelInfo import com.woocommerce.android.ui.orders.OrderNavigationTarget.ViewCustomFields import com.woocommerce.android.ui.orders.OrderNavigationTarget.ViewOrderFulfillInfo @@ -227,6 +228,12 @@ class OrderNavigator @Inject constructor() { ) fragment.findNavController().navigateSafely(action) } + + is StartWooShippingLabelCreationFlow -> { + val action = OrderDetailFragmentDirections + .actionOrderDetailFragmentToWooShippingLabelCreationFragment(target.orderId) + fragment.findNavController().navigateSafely(action) + } } } } diff --git a/WooCommerce/src/main/res/navigation/nav_graph_orders.xml b/WooCommerce/src/main/res/navigation/nav_graph_orders.xml index a7efab48b9c..3c51d403aa8 100644 --- a/WooCommerce/src/main/res/navigation/nav_graph_orders.xml +++ b/WooCommerce/src/main/res/navigation/nav_graph_orders.xml @@ -309,6 +309,9 @@ app:argType="org.wordpress.android.fluxc.model.metadata.MetaDataParentItemType" android:defaultValue="ORDER" /> + + + + From 904dd820727f0fc01e698b1a9efd9dd72fcd81d7 Mon Sep 17 00:00:00 2001 From: Alejo Date: Fri, 4 Oct 2024 11:37:11 -0600 Subject: [PATCH 071/162] navigate to new flow --- .../android/ui/orders/details/OrderDetailViewModel.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt index cd960b9d536..29c4c43cc75 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt @@ -44,6 +44,7 @@ import com.woocommerce.android.ui.orders.OrderNavigationTarget.PrintShippingLabe import com.woocommerce.android.ui.orders.OrderNavigationTarget.RefundShippingLabel import com.woocommerce.android.ui.orders.OrderNavigationTarget.StartPaymentFlow import com.woocommerce.android.ui.orders.OrderNavigationTarget.StartShippingLabelCreationFlow +import com.woocommerce.android.ui.orders.OrderNavigationTarget.StartWooShippingLabelCreationFlow import com.woocommerce.android.ui.orders.OrderNavigationTarget.ViewCreateShippingLabelInfo import com.woocommerce.android.ui.orders.OrderNavigationTarget.ViewOrderFulfillInfo import com.woocommerce.android.ui.orders.OrderNavigationTarget.ViewOrderStatusSelector @@ -656,7 +657,14 @@ class OrderDetailViewModel @Inject constructor( fun onCreateShippingLabelButtonTapped() { tracker.trackShippinhLabelTapped() - triggerEvent(StartShippingLabelCreationFlow(order.id)) + if ( + FeatureFlag.REVAMP_WOO_SHIPPING.isEnabled() && + shippingLabelOnboardingRepository.shippingPluginSupport.isWooShippingSupported() + ) { + triggerEvent(StartWooShippingLabelCreationFlow(order.id)) + } else { + triggerEvent(StartShippingLabelCreationFlow(order.id)) + } } fun onMarkOrderCompleteButtonTapped() { From 13af208d2e8f0b4597e1bf311a93f542c8e80bd1 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 17:08:28 +0300 Subject: [PATCH 072/162] Deps: Migrate androidx activity to version catalogs on woocommerce FYI: The 'androidx-activity-compose' dependency has no associated 'androidx-activity' version on it as it seems to be taking this version from 'androidx-compose-bom' instead. --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 4 ++-- gradle/libs.versions.toml | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 07125b98495..a0a0491dba7 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -171,7 +171,7 @@ dependencies { implementation(libs.androidx.lifecycle.livedata.ktx) implementation(libs.androidx.core.splashscreen) implementation "androidx.navigation:navigation-compose:2.7.7" - implementation 'androidx.activity:activity-compose' + implementation(libs.androidx.activity.compose) implementation(libs.androidx.preference.ktx) implementation(libs.androidx.datastore.preferences) implementation(libs.androidx.datastore.main) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 1fcce347642..9bfad8da82c 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -408,7 +408,7 @@ dependencies { // ViewModel and LiveData implementation(libs.androidx.fragment.ktx) - implementation "androidx.activity:activity-ktx:1.8.0" + implementation(libs.androidx.activity.ktx) implementation(libs.androidx.lifecycle.viewmodel.savedstate) implementation(libs.androidx.lifecycle.process) @@ -437,7 +437,7 @@ dependencies { // Jetpack Compose implementation platform("androidx.compose:compose-bom:$composeBOMVersion") // Dependencies managed by BOM - implementation 'androidx.activity:activity-compose' + implementation(libs.androidx.activity.compose) implementation 'androidx.compose.material:material' implementation 'androidx.compose.animation:animation' implementation 'androidx.compose.ui:ui-tooling' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 19ca6069c9f..4bd264f850f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,6 @@ [versions] android-billingclient = '5.0.0' +androidx-activity = '1.8.0' androidx-appcompat = '1.4.2' androidx-arch-core = '2.1.0' androidx-browser = '1.5.0' @@ -63,6 +64,8 @@ zendesk = '5.0.8' [libraries] android-billingclient-ktx = { group = "com.android.billingclient", name = "billing-ktx", version.ref = "android-billingclient" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose" } +androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "androidx-activity" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } androidx-arch-core-testing = { group = "androidx.arch.core", name = "core-testing", version.ref = "androidx-arch-core" } androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "androidx-browser" } From a9cb94ba85c0ec5975d83f4fd13bbe41b5f7cd67 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 17:12:05 +0300 Subject: [PATCH 073/162] Deps: Migrate cashapp turbine to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 9bfad8da82c..f3744720b7e 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -418,7 +418,7 @@ dependencies { implementation(libs.kotlinx.coroutines.play.services) testImplementation(libs.kotlinx.coroutines.test) - testImplementation 'app.cash.turbine:turbine:1.0.0' + testImplementation(libs.cashapp.turbine) implementation "org.apache.commons:commons-text:$commonsText" implementation "commons-io:commons-io:$commonsIO" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4bd264f850f..c78199a191e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -27,6 +27,7 @@ automattic-about = '0.0.6' automattic-tracks = '5.0.0' assertj = '3.24.1' bumptech-glide = '4.16.0' +cashapp-turbine = '1.0.0' commons-fileupload = '1.5' facebook-flipper = '0.176.1' facebook-shimmer = '0.5.0' @@ -108,6 +109,7 @@ automattic-tracks-crashlogging = { group = "com.automattic.tracks", name = "cras bumptech-glide-main = { group = "com.github.bumptech.glide", name = "glide", version.ref = "bumptech-glide" } bumptech-glide-compiler = { group = "com.github.bumptech.glide", name = "compiler", version.ref = "bumptech-glide" } bumptech-glide-volley-integration = { group = "com.github.bumptech.glide", name = "volley-integration", version.ref = "bumptech-glide" } +cashapp-turbine = { group = "app.cash.turbine", name = "turbine", version.ref = "cashapp-turbine" } commons-fileupload = { group = "commons-fileupload", name = "commons-fileupload", version.ref = "commons-fileupload" } facebook-flipper-main = { group = "com.facebook.flipper", name = "flipper", version.ref = "facebook-flipper" } facebook-flipper-network-plugin = { group = "com.facebook.flipper", name = "flipper-network-plugin", version.ref = "facebook-flipper" } From ed5addcf3ee8bd9c0e47b14fd9f999df8734645d Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 17:14:21 +0300 Subject: [PATCH 074/162] Deps: Migrate apache commons text to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index f3744720b7e..a048fea081c 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -420,7 +420,7 @@ dependencies { testImplementation(libs.cashapp.turbine) - implementation "org.apache.commons:commons-text:$commonsText" + implementation(libs.apache.commons.text) implementation "commons-io:commons-io:$commonsIO" implementation "com.tinder.statemachine:statemachine:$stateMachineVersion" diff --git a/build.gradle b/build.gradle index 50c9a043e78..491759c0a92 100644 --- a/build.gradle +++ b/build.gradle @@ -113,7 +113,6 @@ ext { securityLintVersion = '1.0.1' // Apache - commonsText = '1.10.0' commonsIO = '2.11.0' // Compose and its module versions need to be consistent with each other (for example 'compose-theme-adapter') diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c78199a191e..82374747aa2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,6 +22,7 @@ androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' androidx-transition = '1.5.1' androidx-work = '2.7.1' +apache-commons-text = '1.10.0' apache-http-client-android = '4.3.5.1' automattic-about = '0.0.6' automattic-tracks = '5.0.0' @@ -100,6 +101,7 @@ androidx-test-main-runner = { group = "androidx.test", name = "runner", version. androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidx-test-uiautomator" } androidx-transition = { group = "androidx.transition", name = "transition", version.ref = "androidx-transition" } androidx-work-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "androidx-work" } +apache-commons-text = { group = "org.apache.commons", name = "commons-text", version.ref = "apache-commons-text" } apache-http-client-android = { group = "org.apache.httpcomponents", name = "httpclient-android", version.ref = "apache-http-client-android" } assertj-core = { group = "org.assertj", name = "assertj-core", version.ref = "assertj" } automattic-about = { group = "com.automattic", name = "about", version.ref = "automattic-about" } From a4807cbe48d6c88b9af8931b9560447eaa9ba8bb Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 17:16:50 +0300 Subject: [PATCH 075/162] Deps: Migrate commons io to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- build.gradle | 3 --- gradle/libs.versions.toml | 2 ++ 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index a048fea081c..58cec283ed8 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -421,7 +421,7 @@ dependencies { testImplementation(libs.cashapp.turbine) implementation(libs.apache.commons.text) - implementation "commons-io:commons-io:$commonsIO" + implementation(libs.commons.io) implementation "com.tinder.statemachine:statemachine:$stateMachineVersion" diff --git a/build.gradle b/build.gradle index 491759c0a92..7925fdaf942 100644 --- a/build.gradle +++ b/build.gradle @@ -112,9 +112,6 @@ ext { wearHorologistVersion = '0.6.10' securityLintVersion = '1.0.1' - // Apache - commonsIO = '2.11.0' - // Compose and its module versions need to be consistent with each other (for example 'compose-theme-adapter') composeBOMVersion = "2024.04.00" composeCompilerVersion = "1.5.9" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 82374747aa2..82be9f817d7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,6 +30,7 @@ assertj = '3.24.1' bumptech-glide = '4.16.0' cashapp-turbine = '1.0.0' commons-fileupload = '1.5' +commons-io = '2.11.0' facebook-flipper = '0.176.1' facebook-shimmer = '0.5.0' facebook-soloader = '0.10.4' @@ -113,6 +114,7 @@ bumptech-glide-compiler = { group = "com.github.bumptech.glide", name = "compile bumptech-glide-volley-integration = { group = "com.github.bumptech.glide", name = "volley-integration", version.ref = "bumptech-glide" } cashapp-turbine = { group = "app.cash.turbine", name = "turbine", version.ref = "cashapp-turbine" } commons-fileupload = { group = "commons-fileupload", name = "commons-fileupload", version.ref = "commons-fileupload" } +commons-io = { group = "commons-io", name = "commons-io", version.ref = "commons-io" } facebook-flipper-main = { group = "com.facebook.flipper", name = "flipper", version.ref = "facebook-flipper" } facebook-flipper-network-plugin = { group = "com.facebook.flipper", name = "flipper-network-plugin", version.ref = "facebook-flipper" } facebook-shimmer = { group = "com.facebook.shimmer", name = "shimmer", version.ref = "facebook-shimmer" } From cc73979dc2666aca619a86da4192feebe08097be Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 17:19:12 +0300 Subject: [PATCH 076/162] Deps: Migrate tinder statemachine to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 58cec283ed8..8cc88a5f656 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -423,7 +423,7 @@ dependencies { implementation(libs.apache.commons.text) implementation(libs.commons.io) - implementation "com.tinder.statemachine:statemachine:$stateMachineVersion" + implementation(libs.tinder.statemachine) implementation("${gradle.ext.mediaPickerBinaryPath}:$mediapickerVersion") { exclude group: "org.wordpress", module: "utils" diff --git a/build.gradle b/build.gradle index 7925fdaf942..22aff4eada8 100644 --- a/build.gradle +++ b/build.gradle @@ -104,7 +104,6 @@ ext { constraintLayoutVersion = '1.2.0' eventBusVersion = '3.3.1' googlePlayCoreVersion = '1.10.3' - stateMachineVersion = '0.2.0' mediapickerVersion = '0.3.1' androidxCameraVersion = '1.2.3' guavaVersion = '33.1.0-android' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 82be9f817d7..7be099ac58f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -57,6 +57,7 @@ mpandroidchart = 'v3.1.0' photoview = '2.3.0' squareup-leakcanary = '2.14' stripe-terminal = '3.7.1' +tinder-statemachine = '0.2.0' wiremock = '2.26.3' wordpress-aztec = 'v2.1.4' wordpress-fluxc = 'trunk-7ad6ce4c250ba435d8d8c7feb898bceb259fb007' @@ -152,6 +153,7 @@ photoview = { group = "com.github.chrisbanes", name = "PhotoView", version.ref = squareup-leakcanary-android = { group = "com.squareup.leakcanary", name = "leakcanary-android", version.ref = "squareup-leakcanary" } stripe-terminal-localmobile = { group = "com.stripe", name = "stripeterminal-localmobile", version.ref = "stripe-terminal" } stripe-terminal-core = { group = "com.stripe", name = "stripeterminal-core", version.ref = "stripe-terminal" } +tinder-statemachine = { group = "com.tinder.statemachine", name = "statemachine", version.ref = "tinder-statemachine" } wiremock = { group = "com.github.tomakehurst", name = "wiremock", version.ref = "wiremock" } wordpress-libaddressinput-common = { group = "org.wordpress", name = "libaddressinput.common", version.ref = "wordpress-libaddressinput" } wordpress-aztec-main = { group = "org.wordpress", name = "aztec", version.ref = "wordpress-aztec" } From 8da5ec165a1eb76fc5856c618df0d7ba92f11a64 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 17:33:25 +0300 Subject: [PATCH 077/162] Deps: Migrate wordpress mediapicker to version catalogs on woocommerce --- WooCommerce/build.gradle | 6 +++--- build.gradle | 1 - gradle/libs.versions.toml | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 8cc88a5f656..5b599c83bf2 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -425,11 +425,11 @@ dependencies { implementation(libs.tinder.statemachine) - implementation("${gradle.ext.mediaPickerBinaryPath}:$mediapickerVersion") { + implementation("${gradle.ext.mediaPickerBinaryPath}:${libs.versions.wordpress.mediapicker.get()}") { exclude group: "org.wordpress", module: "utils" } - implementation("${gradle.ext.mediaPickerSourceCameraBinaryPath}:$mediapickerVersion") - implementation("${gradle.ext.mediaPickerSourceWordPressBinaryPath}:$mediapickerVersion") { + implementation("${gradle.ext.mediaPickerSourceCameraBinaryPath}:${libs.versions.wordpress.mediapicker.get()}") + implementation("${gradle.ext.mediaPickerSourceWordPressBinaryPath}:${libs.versions.wordpress.mediapicker.get()}") { exclude group: "org.wordpress", module: "utils" exclude group: "org.wordpress", module: "fluxc" } diff --git a/build.gradle b/build.gradle index 22aff4eada8..4628a27a0b8 100644 --- a/build.gradle +++ b/build.gradle @@ -104,7 +104,6 @@ ext { constraintLayoutVersion = '1.2.0' eventBusVersion = '3.3.1' googlePlayCoreVersion = '1.10.3' - mediapickerVersion = '0.3.1' androidxCameraVersion = '1.2.3' guavaVersion = '33.1.0-android' protobufVersion = '3.25.3' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7be099ac58f..64ed3e69d24 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -63,6 +63,7 @@ wordpress-aztec = 'v2.1.4' wordpress-fluxc = 'trunk-7ad6ce4c250ba435d8d8c7feb898bceb259fb007' wordpress-login = '1.18.0' wordpress-libaddressinput = '0.0.2' +wordpress-mediapicker = '0.3.1' wordpress-utils = '3.5.0' zendesk = '5.0.8' From 02b3d26bf70602efa6a9e01a6c472271d79c8b8d Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 17:34:31 +0300 Subject: [PATCH 078/162] Cleanup: Remove local woocommerce shared path leftover This is a leftover from this 298efad766dac076a7414fcad34afb978268bf4c commit that wasn't removed as part of it. --- local-builds.gradle-example | 1 - 1 file changed, 1 deletion(-) diff --git a/local-builds.gradle-example b/local-builds.gradle-example index b77bf9bb268..8a58586e77a 100644 --- a/local-builds.gradle-example +++ b/local-builds.gradle-example @@ -17,5 +17,4 @@ ext { //localFluxCPath = "../WordPress-FluxC-Android" //localLoginFlowPath = "../WordPress-Login-Flow-Android" //localMediaPickerPath = "../WordPress-MediaPicker-Android" - //localWooCommerceSharedPath = "../WooCommerce-Shared/libraries/android" } From 9e129c0d92f79c5a0e610d4319d2c3d1a2333366 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 18:00:42 +0300 Subject: [PATCH 079/162] Deps: Migrate androidx compose to version catalogs on all modules FYI: The 'androidx.compose.ui:ui-test-junit4' version is not being dependant on the 'androidx.compose.bom' version, via this newly added 'androidTestImplementation(platform(libs.androidx.compose.bom))' configuration, and not hardcoded to the specific '1.3.2' version of this library. --- WooCommerce-Wear/build.gradle | 20 ++++++++++---------- WooCommerce/build.gradle | 21 +++++++++++---------- build.gradle | 2 -- gradle/libs.versions.toml | 13 +++++++++++++ 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index a0a0491dba7..221ba8d5ba8 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -88,7 +88,7 @@ android { compose true } composeOptions { - kotlinCompilerExtensionVersion composeCompilerVersion + kotlinCompilerExtensionVersion libs.versions.androidx.compose.compiler.get() } packaging { resources { @@ -155,15 +155,15 @@ dependencies { implementation 'androidx.wear:wear-tooling-preview:1.0.0' // Compose - implementation platform("androidx.compose:compose-bom:$composeBOMVersion") - implementation 'androidx.compose.ui:ui' - implementation 'androidx.compose.ui:ui-tooling-preview' - implementation 'androidx.compose.material:material' - implementation 'androidx.compose.animation:animation' - implementation 'androidx.compose.ui:ui-tooling' - implementation 'androidx.compose.runtime:runtime-livedata' - implementation "androidx.compose.material:material-icons-extended" - implementation 'androidx.compose.ui:ui-text-google-fonts' + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui.main) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material.main) + implementation(libs.androidx.compose.animation.main) + implementation(libs.androidx.compose.ui.tooling.main) + implementation(libs.androidx.compose.runtime.livedata) + implementation(libs.androidx.compose.material.icons.extended) + implementation(libs.androidx.compose.ui.text.google.fonts) // Android Support implementation(libs.androidx.work.runtime.ktx) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 5b599c83bf2..0173bf904a3 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -151,7 +151,7 @@ android { } composeOptions { - kotlinCompilerExtensionVersion composeCompilerVersion + kotlinCompilerExtensionVersion libs.versions.androidx.compose.compiler.get() } flavorDimensions "buildType" @@ -435,15 +435,16 @@ dependencies { } // Jetpack Compose - implementation platform("androidx.compose:compose-bom:$composeBOMVersion") + implementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(platform(libs.androidx.compose.bom)) // Dependencies managed by BOM implementation(libs.androidx.activity.compose) - implementation 'androidx.compose.material:material' - implementation 'androidx.compose.animation:animation' - implementation 'androidx.compose.ui:ui-tooling' - implementation 'androidx.compose.runtime:runtime-livedata' - implementation "androidx.compose.material:material-icons-extended" - implementation 'androidx.compose.ui:ui-text-google-fonts' + implementation(libs.androidx.compose.material.main) + implementation(libs.androidx.compose.animation.main) + implementation(libs.androidx.compose.ui.tooling.main) + implementation(libs.androidx.compose.runtime.livedata) + implementation(libs.androidx.compose.material.icons.extended) + implementation(libs.androidx.compose.ui.text.google.fonts) implementation 'androidx.navigation:navigation-compose' implementation(libs.androidx.hilt.navigation.compose) @@ -452,8 +453,8 @@ dependencies { implementation "io.coil-kt:coil-compose:$coilVersion" implementation "io.coil-kt:coil-svg:$coilVersion" - androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.3.2' - debugImplementation 'androidx.compose.ui:ui-test-manifest' + androidTestImplementation(libs.androidx.compose.ui.test.junit4) + debugImplementation(libs.androidx.compose.ui.test.manifest) coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' diff --git a/build.gradle b/build.gradle index 4628a27a0b8..c147d7e18bc 100644 --- a/build.gradle +++ b/build.gradle @@ -111,8 +111,6 @@ ext { securityLintVersion = '1.0.1' // Compose and its module versions need to be consistent with each other (for example 'compose-theme-adapter') - composeBOMVersion = "2024.04.00" - composeCompilerVersion = "1.5.9" composeAccompanistVersion = "0.32.0" wearComposeVersion = "1.3.1" } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 64ed3e69d24..4ca95c3a025 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,6 +5,8 @@ androidx-appcompat = '1.4.2' androidx-arch-core = '2.1.0' androidx-browser = '1.5.0' androidx-cardview = '1.0.0' +androidx-compose-bom = '2024.04.00' +androidx-compose-compiler = '1.5.9' androidx-constraintlayout-compose = '1.0.1' androidx-constraintlayout-main = '2.1.4' androidx-core-main = '1.13.1' @@ -75,6 +77,17 @@ androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version androidx-arch-core-testing = { group = "androidx.arch.core", name = "core-testing", version.ref = "androidx-arch-core" } androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "androidx-browser" } androidx-cardview = { group = "androidx.cardview", name = "cardview", version.ref = "androidx-cardview" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "androidx-compose-bom" } +androidx-compose-animation-main = { group = "androidx.compose.animation", name = "animation" } +androidx-compose-material-main = { group = "androidx.compose.material", name = "material" } +androidx-compose-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended" } +androidx-compose-runtime-livedata = { group = "androidx.compose.runtime", name = "runtime-livedata" } +androidx-compose-ui-main = { group = "androidx.compose.ui", name = "ui" } +androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } +androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-compose-ui-text-google-fonts = { group = "androidx.compose.ui", name = "ui-text-google-fonts" } +androidx-compose-ui-tooling-main = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } androidx-constraintlayout-compose = { group = "androidx.constraintlayout", name = "constraintlayout-compose", version.ref = "androidx-constraintlayout-compose" } androidx-constraintlayout-main = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout-main" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-main" } From 0ee51cc515e115b3c11ca6bfa3c5d491c56b4e49 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 18:04:15 +0300 Subject: [PATCH 080/162] Deps: Migrate coil to version catalogs on woocommerce --- WooCommerce/build.gradle | 4 ++-- build.gradle | 1 - gradle/libs.versions.toml | 3 +++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 0173bf904a3..e4f8d4a7502 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -450,8 +450,8 @@ dependencies { implementation(libs.androidx.hilt.navigation.compose) implementation(libs.androidx.constraintlayout.compose) implementation(libs.androidx.lifecycle.viewmodel.compose) - implementation "io.coil-kt:coil-compose:$coilVersion" - implementation "io.coil-kt:coil-svg:$coilVersion" + implementation(libs.coil.compose) + implementation(libs.coil.svg) androidTestImplementation(libs.androidx.compose.ui.test.junit4) debugImplementation(libs.androidx.compose.ui.test.manifest) diff --git a/build.gradle b/build.gradle index c147d7e18bc..50c79d25eca 100644 --- a/build.gradle +++ b/build.gradle @@ -100,7 +100,6 @@ tasks.register("installGitHooks", Copy) { } ext { - coilVersion = '2.1.0' constraintLayoutVersion = '1.2.0' eventBusVersion = '3.3.1' googlePlayCoreVersion = '1.10.3' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4ca95c3a025..2f4772d109d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,6 +31,7 @@ automattic-tracks = '5.0.0' assertj = '3.24.1' bumptech-glide = '4.16.0' cashapp-turbine = '1.0.0' +coil = '2.1.0' commons-fileupload = '1.5' commons-io = '2.11.0' facebook-flipper = '0.176.1' @@ -128,6 +129,8 @@ bumptech-glide-main = { group = "com.github.bumptech.glide", name = "glide", ver bumptech-glide-compiler = { group = "com.github.bumptech.glide", name = "compiler", version.ref = "bumptech-glide" } bumptech-glide-volley-integration = { group = "com.github.bumptech.glide", name = "volley-integration", version.ref = "bumptech-glide" } cashapp-turbine = { group = "app.cash.turbine", name = "turbine", version.ref = "cashapp-turbine" } +coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" } +coil-svg = { group = "io.coil-kt", name = "coil-svg", version.ref = "coil" } commons-fileupload = { group = "commons-fileupload", name = "commons-fileupload", version.ref = "commons-fileupload" } commons-io = { group = "commons-io", name = "commons-io", version.ref = "commons-io" } facebook-flipper-main = { group = "com.facebook.flipper", name = "flipper", version.ref = "facebook-flipper" } From bb3a1f67a642c93134c37569393b5ce3ee655eaf Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 18:05:49 +0300 Subject: [PATCH 081/162] Deps: Migrate android desugar to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index e4f8d4a7502..37a7e0f27a0 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -456,7 +456,7 @@ dependencies { androidTestImplementation(libs.androidx.compose.ui.test.junit4) debugImplementation(libs.androidx.compose.ui.test.manifest) - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' + coreLibraryDesugaring(libs.android.desugar) // CameraX implementation "androidx.camera:camera-camera2:$androidxCameraVersion" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2f4772d109d..9669c8b9f7c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,6 @@ [versions] android-billingclient = '5.0.0' +android-desugar = '2.0.4' androidx-activity = '1.8.0' androidx-appcompat = '1.4.2' androidx-arch-core = '2.1.0' @@ -72,6 +73,7 @@ zendesk = '5.0.8' [libraries] android-billingclient-ktx = { group = "com.android.billingclient", name = "billing-ktx", version.ref = "android-billingclient" } +android-desugar = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "android-desugar" } androidx-activity-compose = { group = "androidx.activity", name = "activity-compose" } androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "androidx-activity" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } From fff1ef82571324b653f249ecab2a1972b4bd7e53 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 18:07:58 +0300 Subject: [PATCH 082/162] Deps: Migrate androidx camera to version catalogs on woocommerce --- WooCommerce/build.gradle | 6 +++--- build.gradle | 1 - gradle/libs.versions.toml | 4 ++++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 37a7e0f27a0..433e9a1ad45 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -459,9 +459,9 @@ dependencies { coreLibraryDesugaring(libs.android.desugar) // CameraX - implementation "androidx.camera:camera-camera2:$androidxCameraVersion" - implementation "androidx.camera:camera-lifecycle:$androidxCameraVersion" - implementation "androidx.camera:camera-view:$androidxCameraVersion" + implementation(libs.androidx.camera.camera2) + implementation(libs.androidx.camera.lifecycle) + implementation(libs.androidx.camera.view) implementation "com.google.guava:guava:$guavaVersion" diff --git a/build.gradle b/build.gradle index 50c79d25eca..6b398accc77 100644 --- a/build.gradle +++ b/build.gradle @@ -103,7 +103,6 @@ ext { constraintLayoutVersion = '1.2.0' eventBusVersion = '3.3.1' googlePlayCoreVersion = '1.10.3' - androidxCameraVersion = '1.2.3' guavaVersion = '33.1.0-android' protobufVersion = '3.25.3' wearHorologistVersion = '0.6.10' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9669c8b9f7c..70dee8abf66 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,6 +5,7 @@ androidx-activity = '1.8.0' androidx-appcompat = '1.4.2' androidx-arch-core = '2.1.0' androidx-browser = '1.5.0' +androidx-camera = '1.2.3' androidx-cardview = '1.0.0' androidx-compose-bom = '2024.04.00' androidx-compose-compiler = '1.5.9' @@ -79,6 +80,9 @@ androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", ve androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } androidx-arch-core-testing = { group = "androidx.arch.core", name = "core-testing", version.ref = "androidx-arch-core" } androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "androidx-browser" } +androidx-camera-camera2 = { group = "androidx.camera", name = "camera-camera2", version.ref = "androidx-camera" } +androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "androidx-camera" } +androidx-camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "androidx-camera" } androidx-cardview = { group = "androidx.cardview", name = "cardview", version.ref = "androidx-cardview" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "androidx-compose-bom" } androidx-compose-animation-main = { group = "androidx.compose.animation", name = "animation" } From 033983c47c36ae42047d9b88cae215d95a90898d Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 18:18:22 +0300 Subject: [PATCH 083/162] Deps: Migrate google guava to version catalogs on woocommerce --- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 433e9a1ad45..c9931e51dab 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -463,7 +463,7 @@ dependencies { implementation(libs.androidx.camera.lifecycle) implementation(libs.androidx.camera.view) - implementation "com.google.guava:guava:$guavaVersion" + implementation(libs.google.guava) implementation "com.google.protobuf:protobuf-javalite:$protobufVersion" diff --git a/build.gradle b/build.gradle index 6b398accc77..642d3bb1669 100644 --- a/build.gradle +++ b/build.gradle @@ -103,7 +103,6 @@ ext { constraintLayoutVersion = '1.2.0' eventBusVersion = '3.3.1' googlePlayCoreVersion = '1.10.3' - guavaVersion = '33.1.0-android' protobufVersion = '3.25.3' wearHorologistVersion = '0.6.10' securityLintVersion = '1.0.1' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 70dee8abf66..2b2c2e23372 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -41,6 +41,7 @@ facebook-shimmer = '0.5.0' facebook-soloader = '0.10.4' fastlane-screengrab = '2.1.1' google-firebase-bom = '32.7.1' +google-guava = '33.1.0-android' google-material = '1.12.0' google-mlkit-barcode-scanning = '17.2.0' google-mlkit-text-recognition = '16.0.0' @@ -148,6 +149,7 @@ google-firebase-analytics = { group = "com.google.firebase", name = "firebase-an google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } google-firebase-config = { group = "com.google.firebase", name = "firebase-config" } google-firebase-messaging = { group = "com.google.firebase", name = "firebase-messaging" } +google-guava = { group = "com.google.guava", name = "guava", version.ref = "google-guava" } google-material = { group = "com.google.android.material", name = "material", version.ref = "google-material" } google-mlkit-barcode-scanning = { group = "com.google.mlkit", name = "barcode-scanning", version.ref = "google-mlkit-barcode-scanning" } google-mlkit-text-recognition-main = { group = "com.google.mlkit", name = "text-recognition", version.ref = "google-mlkit-text-recognition" } From cb1d91e38a28df36a8d5bd2fa1887d998f935539 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 18:23:12 +0300 Subject: [PATCH 084/162] Deps: Migrate android security lint to version catalogs on all modules --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 2 +- build.gradle | 1 - gradle/libs.versions.toml | 2 ++ 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 221ba8d5ba8..7c6b011d50b 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -215,7 +215,7 @@ dependencies { // See https://github.com/wordpress-mobile/WordPress-FluxC-Android/issues/919 exclude group: 'com.squareup.okhttp3' } - lintChecks "com.android.security.lint:lint:$securityLintVersion" + lintChecks(libs.android.security.lint) } def checkGradlePropertiesFile() { diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index c9931e51dab..ddf3a34d2cb 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -467,7 +467,7 @@ dependencies { implementation "com.google.protobuf:protobuf-javalite:$protobufVersion" - lintChecks "com.android.security.lint:lint:$securityLintVersion" + lintChecks(libs.android.security.lint) } protobuf { diff --git a/build.gradle b/build.gradle index 642d3bb1669..a9164524f35 100644 --- a/build.gradle +++ b/build.gradle @@ -105,7 +105,6 @@ ext { googlePlayCoreVersion = '1.10.3' protobufVersion = '3.25.3' wearHorologistVersion = '0.6.10' - securityLintVersion = '1.0.1' // Compose and its module versions need to be consistent with each other (for example 'compose-theme-adapter') composeAccompanistVersion = "0.32.0" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2b2c2e23372..30a45c703ee 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,7 @@ [versions] android-billingclient = '5.0.0' android-desugar = '2.0.4' +android-security-lint = '1.0.1' androidx-activity = '1.8.0' androidx-appcompat = '1.4.2' androidx-arch-core = '2.1.0' @@ -76,6 +77,7 @@ zendesk = '5.0.8' [libraries] android-billingclient-ktx = { group = "com.android.billingclient", name = "billing-ktx", version.ref = "android-billingclient" } android-desugar = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "android-desugar" } +android-security-lint = { group = "com.android.security.lint", name = "lint", version.ref = "android-security-lint" } androidx-activity-compose = { group = "androidx.activity", name = "activity-compose" } androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "androidx-activity" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } From c27691161b777412240b6afb86a614072a472dc1 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 18:36:57 +0300 Subject: [PATCH 085/162] Deps: Migrate androidx wear to version catalogs on woocommerce wear FYI: The 'androidx-wear-tiles' dependencies have no associated 'androidx-wear-tiles' version on them as it seems that they are not to be taking any version from anywhere. --- WooCommerce-Wear/build.gradle | 12 ++++++------ build.gradle | 1 - gradle/libs.versions.toml | 9 +++++++++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 7c6b011d50b..86a3bc2bc91 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -144,15 +144,15 @@ dependencies { // WearOS implementation(libs.google.play.services.wearable) - implementation 'androidx.wear.tiles:tiles' - implementation 'androidx.wear.tiles:tiles-material' + implementation(libs.androidx.wear.tiles.main) + implementation(libs.androidx.wear.tiles.material) implementation "com.google.android.horologist:horologist-compose-tools:$wearHorologistVersion" implementation "com.google.android.horologist:horologist-tiles:$wearHorologistVersion" implementation "com.google.android.horologist:horologist-compose-layout:$wearHorologistVersion" - implementation 'androidx.wear.watchface:watchface-complications-data-source-ktx:1.2.1' - implementation "androidx.wear.compose:compose-material:$wearComposeVersion" - implementation "androidx.wear.compose:compose-foundation:$wearComposeVersion" - implementation 'androidx.wear:wear-tooling-preview:1.0.0' + implementation(libs.androidx.wear.watchface.complications.data.source.ktx) + implementation(libs.androidx.wear.compose.material) + implementation(libs.androidx.wear.compose.foundation) + implementation(libs.androidx.wear.tooling.preview) // Compose implementation(platform(libs.androidx.compose.bom)) diff --git a/build.gradle b/build.gradle index a9164524f35..c4aaa6fc06e 100644 --- a/build.gradle +++ b/build.gradle @@ -108,7 +108,6 @@ ext { // Compose and its module versions need to be consistent with each other (for example 'compose-theme-adapter') composeAccompanistVersion = "0.32.0" - wearComposeVersion = "1.3.1" } // Onboarding and dev env setup tasks diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 30a45c703ee..4067f8437ff 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,6 +26,9 @@ androidx-test-ext = '1.1.5' androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' androidx-transition = '1.5.1' +androidx-wear-compose = '1.3.1' +androidx-wear-tooling = '1.0.0' +androidx-wear-watchface = '1.2.1' androidx-work = '2.7.1' apache-commons-text = '1.10.0' apache-http-client-android = '4.3.5.1' @@ -126,6 +129,12 @@ androidx-test-main-rules = { group = "androidx.test", name = "rules", version.re androidx-test-main-runner = { group = "androidx.test", name = "runner", version.ref = "androidx-test-main" } androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidx-test-uiautomator" } androidx-transition = { group = "androidx.transition", name = "transition", version.ref = "androidx-transition" } +androidx-wear-compose-material = { group = "androidx.wear.compose", name = "compose-material", version.ref = "androidx-wear-compose" } +androidx-wear-compose-foundation = { group = "androidx.wear.compose", name = "compose-foundation", version.ref = "androidx-wear-compose" } +androidx-wear-tiles-main = { group = "androidx.wear.tiles", name = "tiles" } +androidx-wear-tiles-material = { group = "androidx.wear.tiles", name = "tiles-material" } +androidx-wear-tooling-preview = { group = "androidx.wear", name = "wear-tooling-preview", version.ref = "androidx-wear-tooling" } +androidx-wear-watchface-complications-data-source-ktx = { group = "androidx.wear.watchface", name = "watchface-complications-data-source-ktx", version.ref = "androidx-wear-watchface" } androidx-work-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "androidx-work" } apache-commons-text = { group = "org.apache.commons", name = "commons-text", version.ref = "apache-commons-text" } apache-http-client-android = { group = "org.apache.httpcomponents", name = "httpclient-android", version.ref = "apache-http-client-android" } From 4b31eefe716db98357579fa73a79298106ed4508 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 18:44:49 +0300 Subject: [PATCH 086/162] Deps: Migrate google horologist to version catalogs on woocommerce wear --- WooCommerce-Wear/build.gradle | 6 +++--- build.gradle | 1 - gradle/libs.versions.toml | 4 ++++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 86a3bc2bc91..3076729a51c 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -146,9 +146,9 @@ dependencies { implementation(libs.google.play.services.wearable) implementation(libs.androidx.wear.tiles.main) implementation(libs.androidx.wear.tiles.material) - implementation "com.google.android.horologist:horologist-compose-tools:$wearHorologistVersion" - implementation "com.google.android.horologist:horologist-tiles:$wearHorologistVersion" - implementation "com.google.android.horologist:horologist-compose-layout:$wearHorologistVersion" + implementation(libs.google.horologist.compose.tools) + implementation(libs.google.horologist.tiles) + implementation(libs.google.horologist.compose.layout) implementation(libs.androidx.wear.watchface.complications.data.source.ktx) implementation(libs.androidx.wear.compose.material) implementation(libs.androidx.wear.compose.foundation) diff --git a/build.gradle b/build.gradle index c4aaa6fc06e..256e7568b0b 100644 --- a/build.gradle +++ b/build.gradle @@ -104,7 +104,6 @@ ext { eventBusVersion = '3.3.1' googlePlayCoreVersion = '1.10.3' protobufVersion = '3.25.3' - wearHorologistVersion = '0.6.10' // Compose and its module versions need to be consistent with each other (for example 'compose-theme-adapter') composeAccompanistVersion = "0.32.0" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4067f8437ff..b341667f51a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -46,6 +46,7 @@ facebook-soloader = '0.10.4' fastlane-screengrab = '2.1.1' google-firebase-bom = '32.7.1' google-guava = '33.1.0-android' +google-horologist = '0.6.10' google-material = '1.12.0' google-mlkit-barcode-scanning = '17.2.0' google-mlkit-text-recognition = '16.0.0' @@ -161,6 +162,9 @@ google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", ve google-firebase-config = { group = "com.google.firebase", name = "firebase-config" } google-firebase-messaging = { group = "com.google.firebase", name = "firebase-messaging" } google-guava = { group = "com.google.guava", name = "guava", version.ref = "google-guava" } +google-horologist-compose-layout = { group = "com.google.android.horologist", name = "horologist-compose-layout", version.ref = "google-horologist" } +google-horologist-compose-tools = { group = "com.google.android.horologist", name = "horologist-compose-tools", version.ref = "google-horologist" } +google-horologist-tiles = { group = "com.google.android.horologist", name = "horologist-tiles", version.ref = "google-horologist" } google-material = { group = "com.google.android.material", name = "material", version.ref = "google-material" } google-mlkit-barcode-scanning = { group = "com.google.mlkit", name = "barcode-scanning", version.ref = "google-mlkit-barcode-scanning" } google-mlkit-text-recognition-main = { group = "com.google.mlkit", name = "text-recognition", version.ref = "google-mlkit-text-recognition" } From eff7cde9ce79877b0921c4b8115b42493b9eca83 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 18:47:45 +0300 Subject: [PATCH 087/162] Deps: Migrate google gson to version catalogs on woocommerce wear --- WooCommerce-Wear/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 3076729a51c..4612f216764 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -175,7 +175,7 @@ dependencies { implementation(libs.androidx.preference.ktx) implementation(libs.androidx.datastore.preferences) implementation(libs.androidx.datastore.main) - implementation 'com.google.code.gson:gson:2.10.1' + implementation(libs.google.gson) // Coroutines implementation(libs.kotlinx.coroutines.core) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b341667f51a..1881b62f2a1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -45,6 +45,7 @@ facebook-shimmer = '0.5.0' facebook-soloader = '0.10.4' fastlane-screengrab = '2.1.1' google-firebase-bom = '32.7.1' +google-gson = '2.10.1' google-guava = '33.1.0-android' google-horologist = '0.6.10' google-material = '1.12.0' @@ -161,6 +162,7 @@ google-firebase-analytics = { group = "com.google.firebase", name = "firebase-an google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } google-firebase-config = { group = "com.google.firebase", name = "firebase-config" } google-firebase-messaging = { group = "com.google.firebase", name = "firebase-messaging" } +google-gson = { group = "com.google.code.gson", name = "gson", version.ref = "google-gson" } google-guava = { group = "com.google.guava", name = "guava", version.ref = "google-guava" } google-horologist-compose-layout = { group = "com.google.android.horologist", name = "horologist-compose-layout", version.ref = "google-horologist" } google-horologist-compose-tools = { group = "com.google.android.horologist", name = "horologist-compose-tools", version.ref = "google-horologist" } From 3080940330fa18e183ae69ae716c15b4dbefd770 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 18:48:01 +0300 Subject: [PATCH 088/162] Cleanup: Remove unused dependency versions from root build gradle file --- build.gradle | 6 ------ 1 file changed, 6 deletions(-) diff --git a/build.gradle b/build.gradle index 256e7568b0b..55820a0d657 100644 --- a/build.gradle +++ b/build.gradle @@ -100,13 +100,7 @@ tasks.register("installGitHooks", Copy) { } ext { - constraintLayoutVersion = '1.2.0' - eventBusVersion = '3.3.1' - googlePlayCoreVersion = '1.10.3' protobufVersion = '3.25.3' - - // Compose and its module versions need to be consistent with each other (for example 'compose-theme-adapter') - composeAccompanistVersion = "0.32.0" } // Onboarding and dev env setup tasks From 03fee7550c1ed2751171f2f750496045331950cb Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 19:19:45 +0300 Subject: [PATCH 089/162] Deps: Migrate agp plugin to version catalogs --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 2 +- build.gradle | 4 +++- gradle/libs.versions.toml | 6 ++++++ libs/cardreader/build.gradle | 2 +- libs/commons/build.gradle | 2 +- libs/iap/build.gradle | 2 +- quicklogin/build.gradle | 2 +- settings.gradle | 3 --- 9 files changed, 15 insertions(+), 10 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 4612f216764..8f961e9b789 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -1,7 +1,7 @@ import io.sentry.android.gradle.extensions.InstrumentationFeature plugins { - id 'com.android.application' + alias(libs.plugins.android.application) id 'org.jetbrains.kotlin.android' id 'org.jetbrains.kotlin.plugin.parcelize' id 'com.google.dagger.hilt.android' diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index ddf3a34d2cb..b2f93216042 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -1,7 +1,7 @@ import io.sentry.android.gradle.extensions.InstrumentationFeature plugins { - id 'com.android.application' + alias(libs.plugins.android.application) id 'org.jetbrains.kotlin.android' id 'org.jetbrains.kotlin.plugin.parcelize' id 'com.google.dagger.hilt.android' diff --git a/build.gradle b/build.gradle index 55820a0d657..216f1981107 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,9 @@ plugins { id 'io.gitlab.arturbosch.detekt' id 'com.automattic.android.measure-builds' id "com.autonomousapps.dependency-analysis" - id 'com.android.application' apply false + alias(libs.plugins.android.application).apply(false) + alias(libs.plugins.android.library).apply(false) + alias(libs.plugins.android.test).apply(false) id 'org.jetbrains.kotlin.android' apply false id 'com.google.dagger.hilt.android' apply false id 'androidx.navigation.safeargs.kotlin' apply false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1881b62f2a1..842948479ff 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,4 +1,5 @@ [versions] +agp = '8.5.1' android-billingclient = '5.0.0' android-desugar = '2.0.4' android-security-lint = '1.0.1' @@ -202,3 +203,8 @@ wordpress-aztec-main = { group = "org.wordpress", name = "aztec", version.ref = wordpress-aztec-glide-loader = { group = "org.wordpress.aztec", name = "glide-loader", version.ref = "wordpress-aztec" } wordpress-utils = { group = "org.wordpress", name = "utils", version.ref = "wordpress-utils" } zendesk-support = { group = "com.zendesk", name = "support", version.ref = "zendesk" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +android-library = { id = "com.android.library", version.ref = "agp" } +android-test = { id = "com.android.test", version.ref = "agp" } diff --git a/libs/cardreader/build.gradle b/libs/cardreader/build.gradle index 56d00f6cec5..1a99bdea1ff 100644 --- a/libs/cardreader/build.gradle +++ b/libs/cardreader/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.android.library' + alias(libs.plugins.android.library) id 'org.jetbrains.kotlin.android' id 'org.jetbrains.kotlin.plugin.parcelize' } diff --git a/libs/commons/build.gradle b/libs/commons/build.gradle index b52e2241fd6..163cd0e9d31 100644 --- a/libs/commons/build.gradle +++ b/libs/commons/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.android.library' + alias(libs.plugins.android.library) id 'org.jetbrains.kotlin.android' } diff --git a/libs/iap/build.gradle b/libs/iap/build.gradle index 6f24abc5dfb..dafe75e7fa0 100644 --- a/libs/iap/build.gradle +++ b/libs/iap/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.android.library' + alias(libs.plugins.android.library) id 'org.jetbrains.kotlin.android' } diff --git a/quicklogin/build.gradle b/quicklogin/build.gradle index 9c87d9faad6..b44264121de 100644 --- a/quicklogin/build.gradle +++ b/quicklogin/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.android.test' + alias(libs.plugins.android.test) id 'org.jetbrains.kotlin.android' } diff --git a/settings.gradle b/settings.gradle index 0e819471080..e9f34b292a6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,4 @@ pluginManagement { - gradle.ext.agpVersion = '8.5.1' gradle.ext.googleServicesVersion = '4.4.0' gradle.ext.daggerVersion = '2.50' gradle.ext.detektVersion = '1.23.5' @@ -30,8 +29,6 @@ pluginManagement { plugins { id 'androidx.navigation.safeargs.kotlin' version gradle.ext.navigationVersion - id 'com.android.application' version gradle.ext.agpVersion - id 'com.android.library' version gradle.ext.agpVersion id 'com.automattic.android.measure-builds' version gradle.ext.measureBuildsVersion id 'com.google.gms.google-services' version gradle.ext.googleServicesVersion id 'io.gitlab.arturbosch.detekt' version gradle.ext.detektVersion From 64d34641f92358868330d7545ed8278bf72778c1 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 19:33:33 +0300 Subject: [PATCH 090/162] Deps: Migrate google services plugin to version catalogs --- WooCommerce/build.gradle | 2 +- build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ settings.gradle | 2 -- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index b2f93216042..be10a3b0244 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -7,7 +7,7 @@ plugins { id 'com.google.dagger.hilt.android' id 'io.sentry.android.gradle' id 'androidx.navigation.safeargs.kotlin' - id 'com.google.gms.google-services' + alias(libs.plugins.google.services) id 'com.google.devtools.ksp' id "com.google.protobuf" id "com.osacky.fladle" diff --git a/build.gradle b/build.gradle index 216f1981107..8006912729c 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ plugins { id 'org.jetbrains.kotlin.android' apply false id 'com.google.dagger.hilt.android' apply false id 'androidx.navigation.safeargs.kotlin' apply false - id 'com.google.gms.google-services' apply false + alias(libs.plugins.google.services).apply(false) id 'com.google.devtools.ksp' apply false } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 842948479ff..a054dc0440c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -57,6 +57,7 @@ google-play-review = '2.0.1' google-play-services-auth = '20.2.0' google-play-services-code-scanner = '16.1.0' google-play-services-wearable = '18.1.0' +google-services = '4.4.0' google-zxing = '3.5.3' gravatar = '0.2.0' jackson-databind = '2.12.7.1' @@ -208,3 +209,4 @@ zendesk-support = { group = "com.zendesk", name = "support", version.ref = "zend android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } android-test = { id = "com.android.test", version.ref = "agp" } +google-services = { id = "com.google.gms.google-services", version.ref = "google-services" } diff --git a/settings.gradle b/settings.gradle index e9f34b292a6..b9f5883a600 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,4 @@ pluginManagement { - gradle.ext.googleServicesVersion = '4.4.0' gradle.ext.daggerVersion = '2.50' gradle.ext.detektVersion = '1.23.5' gradle.ext.kotlinVersion = '1.9.22' @@ -30,7 +29,6 @@ pluginManagement { plugins { id 'androidx.navigation.safeargs.kotlin' version gradle.ext.navigationVersion id 'com.automattic.android.measure-builds' version gradle.ext.measureBuildsVersion - id 'com.google.gms.google-services' version gradle.ext.googleServicesVersion id 'io.gitlab.arturbosch.detekt' version gradle.ext.detektVersion id 'io.sentry.android.gradle' version gradle.ext.sentryVersion id 'org.jetbrains.kotlin.android' version gradle.ext.kotlinVersion From 62b500c05634caab92d45c30132bdca89e721454 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 19:55:51 +0300 Subject: [PATCH 091/162] Deps: Migrate google dagger plugin to version catalogs --- WooCommerce-Wear/build.gradle | 10 +++++----- WooCommerce/build.gradle | 14 +++++++------- build.gradle | 2 +- gradle/libs.versions.toml | 8 ++++++++ settings.gradle | 2 -- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 8f961e9b789..e7446ac4a97 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -4,7 +4,7 @@ plugins { alias(libs.plugins.android.application) id 'org.jetbrains.kotlin.android' id 'org.jetbrains.kotlin.plugin.parcelize' - id 'com.google.dagger.hilt.android' + alias(libs.plugins.google.dagger.hilt) id 'com.google.devtools.ksp' id 'io.sentry.android.gradle' } @@ -184,15 +184,15 @@ dependencies { testImplementation(libs.kotlinx.coroutines.test) // Dagger & Hilt - implementation "com.google.dagger:hilt-android:$gradle.ext.daggerVersion" + implementation(libs.google.dagger.hilt.android.main) implementation(libs.androidx.hilt.navigation.fragment) implementation(libs.androidx.hilt.common) implementation(libs.androidx.hilt.work) implementation(libs.androidx.hilt.navigation.compose) ksp(libs.androidx.hilt.compiler) - ksp "com.google.dagger:hilt-compiler:$gradle.ext.daggerVersion" - implementation "com.google.dagger:dagger-android-support:$gradle.ext.daggerVersion" - ksp "com.google.dagger:dagger-android-processor:$gradle.ext.daggerVersion" + ksp(libs.google.dagger.hilt.compiler) + implementation(libs.google.dagger.android.support) + ksp(libs.google.dagger.android.processor) // Testing testImplementation(libs.junit) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index be10a3b0244..3e696399b76 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -4,7 +4,7 @@ plugins { alias(libs.plugins.android.application) id 'org.jetbrains.kotlin.android' id 'org.jetbrains.kotlin.plugin.parcelize' - id 'com.google.dagger.hilt.android' + alias(libs.plugins.google.dagger.hilt) id 'io.sentry.android.gradle' id 'androidx.navigation.safeargs.kotlin' alias(libs.plugins.google.services) @@ -307,15 +307,15 @@ dependencies { implementation(libs.automattic.about) // Dagger - implementation "com.google.dagger:hilt-android:$gradle.ext.daggerVersion" + implementation(libs.google.dagger.hilt.android.main) implementation(libs.androidx.hilt.navigation.fragment) implementation(libs.androidx.hilt.common) implementation(libs.androidx.hilt.work) ksp(libs.androidx.hilt.compiler) - ksp "com.google.dagger:hilt-compiler:$gradle.ext.daggerVersion" - implementation "com.google.dagger:dagger-android-support:$gradle.ext.daggerVersion" - ksp "com.google.dagger:dagger-android-processor:$gradle.ext.daggerVersion" + ksp(libs.google.dagger.hilt.compiler) + implementation(libs.google.dagger.android.support) + ksp(libs.google.dagger.android.processor) implementation(libs.mpandroidchart) @@ -371,8 +371,8 @@ dependencies { androidTestImplementation(libs.androidx.test.espresso.contrib) { exclude group: "com.google.protobuf", module: "protobuf-lite" } - androidTestImplementation "com.google.dagger:hilt-android-testing:$gradle.ext.daggerVersion" - kspAndroidTest "com.google.dagger:hilt-android-compiler:$gradle.ext.daggerVersion" + androidTestImplementation(libs.google.dagger.hilt.android.testing) + kspAndroidTest(libs.google.dagger.hilt.android.compiler) androidTestImplementation(libs.androidx.test.uiautomator) // Dependencies for screenshots diff --git a/build.gradle b/build.gradle index 8006912729c..16e3559814a 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ plugins { alias(libs.plugins.android.library).apply(false) alias(libs.plugins.android.test).apply(false) id 'org.jetbrains.kotlin.android' apply false - id 'com.google.dagger.hilt.android' apply false + alias(libs.plugins.google.dagger.hilt).apply(false) id 'androidx.navigation.safeargs.kotlin' apply false alias(libs.plugins.google.services).apply(false) id 'com.google.devtools.ksp' apply false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a054dc0440c..a1ae381c054 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -45,6 +45,7 @@ facebook-flipper = '0.176.1' facebook-shimmer = '0.5.0' facebook-soloader = '0.10.4' fastlane-screengrab = '2.1.1' +google-dagger = "2.50" google-firebase-bom = '32.7.1' google-gson = '2.10.1' google-guava = '33.1.0-android' @@ -160,6 +161,12 @@ facebook-flipper-network-plugin = { group = "com.facebook.flipper", name = "flip facebook-shimmer = { group = "com.facebook.shimmer", name = "shimmer", version.ref = "facebook-shimmer" } facebook-soloader = { group = "com.facebook.soloader", name = "soloader", version.ref = "facebook-soloader" } fastlane-screengrab = { group = "tools.fastlane", name = "screengrab", version.ref = "fastlane-screengrab" } +google-dagger-android-processor = { group = "com.google.dagger", name = "dagger-android-processor", version.ref = "google-dagger" } +google-dagger-android-support = { group = "com.google.dagger", name = "dagger-android-support", version.ref = "google-dagger" } +google-dagger-hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "google-dagger" } +google-dagger-hilt-android-main = { group = "com.google.dagger", name = "hilt-android", version.ref = "google-dagger" } +google-dagger-hilt-android-testing = { group = "com.google.dagger", name = "hilt-android-testing", version.ref = "google-dagger" } +google-dagger-hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "google-dagger" } google-firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics" } google-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "google-firebase-bom" } google-firebase-config = { group = "com.google.firebase", name = "firebase-config" } @@ -209,4 +216,5 @@ zendesk-support = { group = "com.zendesk", name = "support", version.ref = "zend android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } android-test = { id = "com.android.test", version.ref = "agp" } +google-dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "google-dagger" } google-services = { id = "com.google.gms.google-services", version.ref = "google-services" } diff --git a/settings.gradle b/settings.gradle index b9f5883a600..3c4562ca379 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,4 @@ pluginManagement { - gradle.ext.daggerVersion = '2.50' gradle.ext.detektVersion = '1.23.5' gradle.ext.kotlinVersion = '1.9.22' gradle.ext.kspVersion = '1.9.22-1.0.17' @@ -34,7 +33,6 @@ pluginManagement { id 'org.jetbrains.kotlin.android' version gradle.ext.kotlinVersion id 'org.jetbrains.kotlin.jvm' version gradle.ext.kotlinVersion id 'org.jetbrains.kotlin.plugin.parcelize' version gradle.ext.kotlinVersion - id 'com.google.dagger.hilt.android' version gradle.ext.daggerVersion id 'com.google.devtools.ksp' version gradle.ext.kspVersion id "com.google.protobuf" version gradle.ext.protobufVersion id "com.autonomousapps.dependency-analysis" version gradle.ext.dependencyAnalysisVersion From 64ebe6ebf0405f92528320d181c25a6a86f2e10b Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 19:59:59 +0300 Subject: [PATCH 092/162] Deps: Migrate detekt plugin to version catalogs --- build.gradle | 6 +++--- gradle/libs.versions.toml | 3 +++ settings.gradle | 2 -- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 16e3559814a..37e62e4d29f 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ import io.gitlab.arturbosch.detekt.Detekt import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - id 'io.gitlab.arturbosch.detekt' + alias(libs.plugins.detekt) id 'com.automattic.android.measure-builds' id "com.autonomousapps.dependency-analysis" alias(libs.plugins.android.application).apply(false) @@ -24,7 +24,7 @@ measureBuilds { } allprojects { - apply plugin: 'io.gitlab.arturbosch.detekt' + apply plugin: libs.plugins.detekt.get().pluginId repositories { google() @@ -83,7 +83,7 @@ detektAll.configure { } dependencies { - detektPlugins "io.gitlab.arturbosch.detekt:detekt-formatting:$gradle.ext.detektVersion" + detektPlugins(libs.detekt.formatting) } task clean(type: Delete) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a1ae381c054..66dc50837f4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -41,6 +41,7 @@ cashapp-turbine = '1.0.0' coil = '2.1.0' commons-fileupload = '1.5' commons-io = '2.11.0' +detekt = '1.23.5' facebook-flipper = '0.176.1' facebook-shimmer = '0.5.0' facebook-soloader = '0.10.4' @@ -156,6 +157,7 @@ coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coi coil-svg = { group = "io.coil-kt", name = "coil-svg", version.ref = "coil" } commons-fileupload = { group = "commons-fileupload", name = "commons-fileupload", version.ref = "commons-fileupload" } commons-io = { group = "commons-io", name = "commons-io", version.ref = "commons-io" } +detekt-formatting = { group = "io.gitlab.arturbosch.detekt", name = "detekt-formatting", version.ref = "detekt" } facebook-flipper-main = { group = "com.facebook.flipper", name = "flipper", version.ref = "facebook-flipper" } facebook-flipper-network-plugin = { group = "com.facebook.flipper", name = "flipper-network-plugin", version.ref = "facebook-flipper" } facebook-shimmer = { group = "com.facebook.shimmer", name = "shimmer", version.ref = "facebook-shimmer" } @@ -216,5 +218,6 @@ zendesk-support = { group = "com.zendesk", name = "support", version.ref = "zend android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } android-test = { id = "com.android.test", version.ref = "agp" } +detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } google-dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "google-dagger" } google-services = { id = "com.google.gms.google-services", version.ref = "google-services" } diff --git a/settings.gradle b/settings.gradle index 3c4562ca379..8c67e853b2a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,4 @@ pluginManagement { - gradle.ext.detektVersion = '1.23.5' gradle.ext.kotlinVersion = '1.9.22' gradle.ext.kspVersion = '1.9.22-1.0.17' gradle.ext.measureBuildsVersion = '2.1.2' @@ -28,7 +27,6 @@ pluginManagement { plugins { id 'androidx.navigation.safeargs.kotlin' version gradle.ext.navigationVersion id 'com.automattic.android.measure-builds' version gradle.ext.measureBuildsVersion - id 'io.gitlab.arturbosch.detekt' version gradle.ext.detektVersion id 'io.sentry.android.gradle' version gradle.ext.sentryVersion id 'org.jetbrains.kotlin.android' version gradle.ext.kotlinVersion id 'org.jetbrains.kotlin.jvm' version gradle.ext.kotlinVersion From 73e832f724c4aeb94e7e587c2f0196a7075008ee Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 20:12:42 +0300 Subject: [PATCH 093/162] Deps: Migrate kotlin plugin to version catalogs FYI: The 'org.jetbrains.kotlin.jvm' plugin got completely removed as it is not being used anywhere. --- WooCommerce-Wear/build.gradle | 6 +++--- WooCommerce/build.gradle | 6 +++--- build.gradle | 3 ++- gradle/libs.versions.toml | 4 ++++ libs/cardreader/build.gradle | 6 +++--- libs/commons/build.gradle | 2 +- libs/iap/build.gradle | 4 ++-- quicklogin/build.gradle | 2 +- settings.gradle | 4 ---- 9 files changed, 19 insertions(+), 18 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index e7446ac4a97..6426fc277fa 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -2,8 +2,8 @@ import io.sentry.android.gradle.extensions.InstrumentationFeature plugins { alias(libs.plugins.android.application) - id 'org.jetbrains.kotlin.android' - id 'org.jetbrains.kotlin.plugin.parcelize' + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.parcelize) alias(libs.plugins.google.dagger.hilt) id 'com.google.devtools.ksp' id 'io.sentry.android.gradle' @@ -198,7 +198,7 @@ dependencies { testImplementation(libs.junit) testImplementation(libs.mockito.kotlin) testImplementation(libs.mockito.inline) - testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" + testImplementation(libs.kotlin.test.junit) testImplementation(libs.assertj.core) testImplementation(libs.androidx.arch.core.testing) { exclude group: 'com.android.support', module: 'support-compat' diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 3e696399b76..3ea2012f9be 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -2,8 +2,8 @@ import io.sentry.android.gradle.extensions.InstrumentationFeature plugins { alias(libs.plugins.android.application) - id 'org.jetbrains.kotlin.android' - id 'org.jetbrains.kotlin.plugin.parcelize' + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.parcelize) alias(libs.plugins.google.dagger.hilt) id 'io.sentry.android.gradle' id 'androidx.navigation.safeargs.kotlin' @@ -355,7 +355,7 @@ dependencies { testImplementation(libs.junit) testImplementation(libs.mockito.kotlin) testImplementation(libs.mockito.inline) - testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" + testImplementation(libs.kotlin.test.junit) testImplementation(libs.assertj.core) testImplementation(libs.androidx.arch.core.testing) { exclude group: 'com.android.support', module: 'support-compat' diff --git a/build.gradle b/build.gradle index 37e62e4d29f..b4104af8a0c 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,8 @@ plugins { alias(libs.plugins.android.application).apply(false) alias(libs.plugins.android.library).apply(false) alias(libs.plugins.android.test).apply(false) - id 'org.jetbrains.kotlin.android' apply false + alias(libs.plugins.kotlin.android).apply(false) + alias(libs.plugins.kotlin.parcelize).apply(false) alias(libs.plugins.google.dagger.hilt).apply(false) id 'androidx.navigation.safeargs.kotlin' apply false alias(libs.plugins.google.services).apply(false) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 66dc50837f4..cfd06eeb5ac 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -66,6 +66,7 @@ jackson-databind = '2.12.7.1' jetty-webapp = '9.4.51.v20230217' json-path = '2.9.0' junit = '4.13.2' +kotlin = '1.9.22' kotlinx-coroutines = '1.8.1' mockito-inline = '4.6.1' mockito-kotlin = '4.0.0' @@ -195,6 +196,7 @@ jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-datab jetty-webapp = { group = "org.eclipse.jetty", name = "jetty-webapp", version.ref = "jetty-webapp" } json-path = { group = "com.jayway.jsonpath", name = "json-path", version.ref = "json-path" } junit = { group = "junit", name = "junit", version.ref = "junit" } +kotlin-test-junit = { group = "org.jetbrains.kotlin", name = "kotlin-test-junit", version.ref = "kotlin" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-play-services = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-play-services", version.ref = "kotlinx-coroutines" } @@ -221,3 +223,5 @@ android-test = { id = "com.android.test", version.ref = "agp" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } google-dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "google-dagger" } google-services = { id = "com.google.gms.google-services", version.ref = "google-services" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } diff --git a/libs/cardreader/build.gradle b/libs/cardreader/build.gradle index 1a99bdea1ff..6a1203bf7e9 100644 --- a/libs/cardreader/build.gradle +++ b/libs/cardreader/build.gradle @@ -1,7 +1,7 @@ plugins { alias(libs.plugins.android.library) - id 'org.jetbrains.kotlin.android' - id 'org.jetbrains.kotlin.plugin.parcelize' + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.parcelize) } android { @@ -36,7 +36,7 @@ dependencies { testImplementation(libs.mockito.kotlin) testImplementation(libs.mockito.inline) - testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" + testImplementation(libs.kotlin.test.junit) testImplementation(libs.assertj.core) testImplementation(libs.kotlinx.coroutines.test) } diff --git a/libs/commons/build.gradle b/libs/commons/build.gradle index 163cd0e9d31..a0d38063d6a 100644 --- a/libs/commons/build.gradle +++ b/libs/commons/build.gradle @@ -1,6 +1,6 @@ plugins { alias(libs.plugins.android.library) - id 'org.jetbrains.kotlin.android' + alias(libs.plugins.kotlin.android) } android { diff --git a/libs/iap/build.gradle b/libs/iap/build.gradle index dafe75e7fa0..0fcddd4cc9c 100644 --- a/libs/iap/build.gradle +++ b/libs/iap/build.gradle @@ -1,6 +1,6 @@ plugins { alias(libs.plugins.android.library) - id 'org.jetbrains.kotlin.android' + alias(libs.plugins.kotlin.android) } android { @@ -35,7 +35,7 @@ dependencies { testImplementation(libs.junit) testImplementation(libs.mockito.kotlin) testImplementation(libs.mockito.inline) - testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$gradle.ext.kotlinVersion" + testImplementation(libs.kotlin.test.junit) testImplementation(libs.assertj.core) testImplementation(libs.kotlinx.coroutines.test) } diff --git a/quicklogin/build.gradle b/quicklogin/build.gradle index b44264121de..c2d921eba06 100644 --- a/quicklogin/build.gradle +++ b/quicklogin/build.gradle @@ -1,6 +1,6 @@ plugins { alias(libs.plugins.android.test) - id 'org.jetbrains.kotlin.android' + alias(libs.plugins.kotlin.android) } repositories { diff --git a/settings.gradle b/settings.gradle index 8c67e853b2a..78d24c574a0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,4 @@ pluginManagement { - gradle.ext.kotlinVersion = '1.9.22' gradle.ext.kspVersion = '1.9.22-1.0.17' gradle.ext.measureBuildsVersion = '2.1.2' gradle.ext.navigationVersion = '2.7.7' @@ -28,9 +27,6 @@ pluginManagement { id 'androidx.navigation.safeargs.kotlin' version gradle.ext.navigationVersion id 'com.automattic.android.measure-builds' version gradle.ext.measureBuildsVersion id 'io.sentry.android.gradle' version gradle.ext.sentryVersion - id 'org.jetbrains.kotlin.android' version gradle.ext.kotlinVersion - id 'org.jetbrains.kotlin.jvm' version gradle.ext.kotlinVersion - id 'org.jetbrains.kotlin.plugin.parcelize' version gradle.ext.kotlinVersion id 'com.google.devtools.ksp' version gradle.ext.kspVersion id "com.google.protobuf" version gradle.ext.protobufVersion id "com.autonomousapps.dependency-analysis" version gradle.ext.dependencyAnalysisVersion From b89ee504cd1cf1d18c5b796d680447d6729e4714 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 20:54:04 +0300 Subject: [PATCH 094/162] Deps: Migrate ksp plugin to version catalogs --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 2 +- build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ settings.gradle | 2 -- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 6426fc277fa..11998365123 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -5,7 +5,7 @@ plugins { alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.parcelize) alias(libs.plugins.google.dagger.hilt) - id 'com.google.devtools.ksp' + alias(libs.plugins.ksp) id 'io.sentry.android.gradle' } diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 3ea2012f9be..e023c091e73 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -8,7 +8,7 @@ plugins { id 'io.sentry.android.gradle' id 'androidx.navigation.safeargs.kotlin' alias(libs.plugins.google.services) - id 'com.google.devtools.ksp' + alias(libs.plugins.ksp) id "com.google.protobuf" id "com.osacky.fladle" } diff --git a/build.gradle b/build.gradle index b4104af8a0c..145d4709e23 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ plugins { alias(libs.plugins.google.dagger.hilt).apply(false) id 'androidx.navigation.safeargs.kotlin' apply false alias(libs.plugins.google.services).apply(false) - id 'com.google.devtools.ksp' apply false + alias(libs.plugins.ksp).apply(false) } measureBuilds { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cfd06eeb5ac..de6bd68e899 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -68,6 +68,7 @@ json-path = '2.9.0' junit = '4.13.2' kotlin = '1.9.22' kotlinx-coroutines = '1.8.1' +ksp = '1.9.22-1.0.17' mockito-inline = '4.6.1' mockito-kotlin = '4.0.0' mpandroidchart = 'v3.1.0' @@ -225,3 +226,4 @@ google-dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "goo google-services = { id = "com.google.gms.google-services", version.ref = "google-services" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } diff --git a/settings.gradle b/settings.gradle index 78d24c574a0..aff5e661b25 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,4 @@ pluginManagement { - gradle.ext.kspVersion = '1.9.22-1.0.17' gradle.ext.measureBuildsVersion = '2.1.2' gradle.ext.navigationVersion = '2.7.7' gradle.ext.sentryVersion = '4.10.0' @@ -27,7 +26,6 @@ pluginManagement { id 'androidx.navigation.safeargs.kotlin' version gradle.ext.navigationVersion id 'com.automattic.android.measure-builds' version gradle.ext.measureBuildsVersion id 'io.sentry.android.gradle' version gradle.ext.sentryVersion - id 'com.google.devtools.ksp' version gradle.ext.kspVersion id "com.google.protobuf" version gradle.ext.protobufVersion id "com.autonomousapps.dependency-analysis" version gradle.ext.dependencyAnalysisVersion id "com.osacky.fladle" version gradle.ext.fladleVersion From 48db59bb0cb7f9df08f5e4ad0b9e33b2a19ec528 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 20:56:12 +0300 Subject: [PATCH 095/162] Deps: Migrate automattic measure builds plugin to version catalogs --- build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ settings.gradle | 2 -- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 145d4709e23..e569dc38b9b 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { alias(libs.plugins.detekt) - id 'com.automattic.android.measure-builds' + alias(libs.plugins.automattic.measure.builds) id "com.autonomousapps.dependency-analysis" alias(libs.plugins.android.application).apply(false) alias(libs.plugins.android.library).apply(false) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index de6bd68e899..79757e9ffb0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -34,6 +34,7 @@ androidx-work = '2.7.1' apache-commons-text = '1.10.0' apache-http-client-android = '4.3.5.1' automattic-about = '0.0.6' +automattic-measure-builds = '2.1.2' automattic-tracks = '5.0.0' assertj = '3.24.1' bumptech-glide = '4.16.0' @@ -221,6 +222,7 @@ zendesk-support = { group = "com.zendesk", name = "support", version.ref = "zend android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } android-test = { id = "com.android.test", version.ref = "agp" } +automattic-measure-builds = { id = "com.automattic.android.measure-builds", version.ref = "automattic-measure-builds" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } google-dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "google-dagger" } google-services = { id = "com.google.gms.google-services", version.ref = "google-services" } diff --git a/settings.gradle b/settings.gradle index aff5e661b25..78364b95535 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,4 @@ pluginManagement { - gradle.ext.measureBuildsVersion = '2.1.2' gradle.ext.navigationVersion = '2.7.7' gradle.ext.sentryVersion = '4.10.0' gradle.ext.protobufVersion = '0.9.4' @@ -24,7 +23,6 @@ pluginManagement { plugins { id 'androidx.navigation.safeargs.kotlin' version gradle.ext.navigationVersion - id 'com.automattic.android.measure-builds' version gradle.ext.measureBuildsVersion id 'io.sentry.android.gradle' version gradle.ext.sentryVersion id "com.google.protobuf" version gradle.ext.protobufVersion id "com.autonomousapps.dependency-analysis" version gradle.ext.dependencyAnalysisVersion From 5f790e890f9e76ea004a8fe7be305d1b424dc062 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 21:05:55 +0300 Subject: [PATCH 096/162] Deps: Migrate androidx navigation plugin to version catalogs FYI: The 'androidx-navigation-compose' dependency on the 'WooCommerce' module had no associated version on it, and was most probably taking this version from 'androidx-compose-bom' instead. However, the same dependency on the 'WooCommerce-Wear' module did have one. This change, applies the same version on the 'WooCommerce' module to keep things consistent. --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 12 ++++++------ build.gradle | 2 +- gradle/libs.versions.toml | 7 +++++++ settings.gradle | 2 -- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 11998365123..26de70a3113 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -170,7 +170,7 @@ dependencies { implementation(libs.androidx.lifecycle.viewmodel.savedstate) implementation(libs.androidx.lifecycle.livedata.ktx) implementation(libs.androidx.core.splashscreen) - implementation "androidx.navigation:navigation-compose:2.7.7" + implementation(libs.androidx.navigation.compose) implementation(libs.androidx.activity.compose) implementation(libs.androidx.preference.ktx) implementation(libs.androidx.datastore.preferences) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index e023c091e73..9392a8c342b 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -6,7 +6,7 @@ plugins { alias(libs.plugins.kotlin.parcelize) alias(libs.plugins.google.dagger.hilt) id 'io.sentry.android.gradle' - id 'androidx.navigation.safeargs.kotlin' + alias(libs.plugins.androidx.navigation.safeargs) alias(libs.plugins.google.services) alias(libs.plugins.ksp) id "com.google.protobuf" @@ -249,10 +249,10 @@ dependencies { implementation(libs.androidx.datastore.preferences) implementation(libs.androidx.datastore.main) - implementation "androidx.navigation:navigation-common:$gradle.ext.navigationVersion" - implementation "androidx.navigation:navigation-fragment:$gradle.ext.navigationVersion" - implementation "androidx.navigation:navigation-runtime:$gradle.ext.navigationVersion" - implementation "androidx.navigation:navigation-ui:$gradle.ext.navigationVersion" + implementation(libs.androidx.navigation.common) + implementation(libs.androidx.navigation.fragment) + implementation(libs.androidx.navigation.runtime) + implementation(libs.androidx.navigation.ui) implementation(libs.androidx.work.runtime.ktx) @@ -445,7 +445,7 @@ dependencies { implementation(libs.androidx.compose.runtime.livedata) implementation(libs.androidx.compose.material.icons.extended) implementation(libs.androidx.compose.ui.text.google.fonts) - implementation 'androidx.navigation:navigation-compose' + implementation(libs.androidx.navigation.compose) implementation(libs.androidx.hilt.navigation.compose) implementation(libs.androidx.constraintlayout.compose) diff --git a/build.gradle b/build.gradle index e569dc38b9b..8870f536d37 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ plugins { alias(libs.plugins.kotlin.android).apply(false) alias(libs.plugins.kotlin.parcelize).apply(false) alias(libs.plugins.google.dagger.hilt).apply(false) - id 'androidx.navigation.safeargs.kotlin' apply false + alias(libs.plugins.androidx.navigation.safeargs).apply(false) alias(libs.plugins.google.services).apply(false) alias(libs.plugins.ksp).apply(false) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 79757e9ffb0..b37fc43b498 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,6 +19,7 @@ androidx-datastore = '1.1.0' androidx-fragment = '1.8.2' androidx-hilt = '1.1.0' androidx-lifecycle = '2.7.0' +androidx-navigation = '2.7.7' androidx-preference = '1.2.1' androidx-recyclerview-main = '1.3.2' androidx-recyclerview-selection = '1.1.0' @@ -126,6 +127,11 @@ androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecy androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel-savedstate = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-savedstate", version.ref = "androidx-lifecycle" } +androidx-navigation-common = { group = "androidx.navigation", name = "navigation-common", version.ref = "androidx-navigation" } +androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "androidx-navigation" } +androidx-navigation-fragment = { group = "androidx.navigation", name = "navigation-fragment", version.ref = "androidx-navigation" } +androidx-navigation-runtime = { group = "androidx.navigation", name = "navigation-runtime", version.ref = "androidx-navigation" } +androidx-navigation-ui = { group = "androidx.navigation", name = "navigation-ui", version.ref = "androidx-navigation" } androidx-preference-main = { group = "androidx.preference", name = "preference", version.ref = "androidx-preference" } androidx-preference-ktx = { group = "androidx.preference", name = "preference-ktx", version.ref = "androidx-preference" } androidx-recyclerview-main = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "androidx-recyclerview-main" } @@ -222,6 +228,7 @@ zendesk-support = { group = "com.zendesk", name = "support", version.ref = "zend android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } android-test = { id = "com.android.test", version.ref = "agp" } +androidx-navigation-safeargs = { id = "androidx.navigation.safeargs.kotlin", version.ref = "androidx-navigation" } automattic-measure-builds = { id = "com.automattic.android.measure-builds", version.ref = "automattic-measure-builds" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } google-dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "google-dagger" } diff --git a/settings.gradle b/settings.gradle index 78364b95535..666870987c3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,4 @@ pluginManagement { - gradle.ext.navigationVersion = '2.7.7' gradle.ext.sentryVersion = '4.10.0' gradle.ext.protobufVersion = '0.9.4' gradle.ext.dependencyAnalysisVersion = '1.28.0' @@ -22,7 +21,6 @@ pluginManagement { } plugins { - id 'androidx.navigation.safeargs.kotlin' version gradle.ext.navigationVersion id 'io.sentry.android.gradle' version gradle.ext.sentryVersion id "com.google.protobuf" version gradle.ext.protobufVersion id "com.autonomousapps.dependency-analysis" version gradle.ext.dependencyAnalysisVersion From 90579d487435249969a45d4441762420a54e34da Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 21:13:01 +0300 Subject: [PATCH 097/162] Deps: Migrate sentry plugin to version catalogs --- WooCommerce-Wear/build.gradle | 2 +- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ settings.gradle | 2 -- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 26de70a3113..b82c097ea5a 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -6,7 +6,7 @@ plugins { alias(libs.plugins.kotlin.parcelize) alias(libs.plugins.google.dagger.hilt) alias(libs.plugins.ksp) - id 'io.sentry.android.gradle' + alias(libs.plugins.sentry) } repositories { diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 9392a8c342b..b7aaea5bf2a 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -5,7 +5,7 @@ plugins { alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.parcelize) alias(libs.plugins.google.dagger.hilt) - id 'io.sentry.android.gradle' + alias(libs.plugins.sentry) alias(libs.plugins.androidx.navigation.safeargs) alias(libs.plugins.google.services) alias(libs.plugins.ksp) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b37fc43b498..9b3e4f2c2b3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -75,6 +75,7 @@ mockito-inline = '4.6.1' mockito-kotlin = '4.0.0' mpandroidchart = 'v3.1.0' photoview = '2.3.0' +sentry = '4.10.0' squareup-leakcanary = '2.14' stripe-terminal = '3.7.1' tinder-statemachine = '0.2.0' @@ -236,3 +237,4 @@ google-services = { id = "com.google.gms.google-services", version.ref = "google kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +sentry = { id = "io.sentry.android.gradle", version.ref = "sentry" } diff --git a/settings.gradle b/settings.gradle index 666870987c3..9e111d88ba6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,4 @@ pluginManagement { - gradle.ext.sentryVersion = '4.10.0' gradle.ext.protobufVersion = '0.9.4' gradle.ext.dependencyAnalysisVersion = '1.28.0' gradle.ext.fladleVersion = '0.17.5' @@ -21,7 +20,6 @@ pluginManagement { } plugins { - id 'io.sentry.android.gradle' version gradle.ext.sentryVersion id "com.google.protobuf" version gradle.ext.protobufVersion id "com.autonomousapps.dependency-analysis" version gradle.ext.dependencyAnalysisVersion id "com.osacky.fladle" version gradle.ext.fladleVersion From 715e0cbf2204396fb89ff96e1f04fd621481e61b Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 21:29:46 +0300 Subject: [PATCH 098/162] Deps: Migrate google protobuf plugin to version catalogs --- WooCommerce/build.gradle | 6 +++--- build.gradle | 4 ---- gradle/libs.versions.toml | 5 +++++ settings.gradle | 2 -- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index b7aaea5bf2a..adc135f5719 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -9,7 +9,7 @@ plugins { alias(libs.plugins.androidx.navigation.safeargs) alias(libs.plugins.google.services) alias(libs.plugins.ksp) - id "com.google.protobuf" + alias(libs.plugins.google.protobuf) id "com.osacky.fladle" } @@ -465,14 +465,14 @@ dependencies { implementation(libs.google.guava) - implementation "com.google.protobuf:protobuf-javalite:$protobufVersion" + implementation(libs.google.protobuf.javalite) lintChecks(libs.android.security.lint) } protobuf { protoc { - artifact = "com.google.protobuf:protoc:$protobufVersion" + artifact = libs.google.protobuf.protoc.get().toString() } // Generates the java Protobuf-lite code for the Protobufs in this project. See diff --git a/build.gradle b/build.gradle index 8870f536d37..6f841522b9e 100644 --- a/build.gradle +++ b/build.gradle @@ -102,10 +102,6 @@ tasks.register("installGitHooks", Copy) { fileMode 0777 } -ext { - protobufVersion = '3.25.3' -} - // Onboarding and dev env setup tasks task checkBundler(type: Exec) { doFirst { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9b3e4f2c2b3..45c1eb36dba 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -61,6 +61,8 @@ google-play-review = '2.0.1' google-play-services-auth = '20.2.0' google-play-services-code-scanner = '16.1.0' google-play-services-wearable = '18.1.0' +google-protobuf-plugin = '0.9.4' +google-protobuf-library = '3.25.3' google-services = '4.4.0' google-zxing = '3.5.3' gravatar = '0.2.0' @@ -199,6 +201,8 @@ google-play-review = { group = "com.google.android.play", name = "review", versi google-play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "google-play-services-auth" } google-play-services-code-scanner = { group = "com.google.android.gms", name = "play-services-code-scanner", version.ref = "google-play-services-code-scanner" } google-play-services-wearable = { group = "com.google.android.gms", name = "play-services-wearable", version.ref = "google-play-services-wearable" } +google-protobuf-javalite = { group = "com.google.protobuf", name = "protobuf-javalite", version.ref = "google-protobuf-library" } +google-protobuf-protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "google-protobuf-library" } google-zxing-core = { group = "com.google.zxing", name = "core", version.ref = "google-zxing" } gravatar = { group = "com.gravatar", name = "gravatar", version.ref = "gravatar" } jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson-databind" } @@ -233,6 +237,7 @@ androidx-navigation-safeargs = { id = "androidx.navigation.safeargs.kotlin", ver automattic-measure-builds = { id = "com.automattic.android.measure-builds", version.ref = "automattic-measure-builds" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } google-dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "google-dagger" } +google-protobuf = { id = "com.google.protobuf", version.ref = "google-protobuf-plugin" } google-services = { id = "com.google.gms.google-services", version.ref = "google-services" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } diff --git a/settings.gradle b/settings.gradle index 9e111d88ba6..6f56bb1abda 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,4 @@ pluginManagement { - gradle.ext.protobufVersion = '0.9.4' gradle.ext.dependencyAnalysisVersion = '1.28.0' gradle.ext.fladleVersion = '0.17.5' @@ -20,7 +19,6 @@ pluginManagement { } plugins { - id "com.google.protobuf" version gradle.ext.protobufVersion id "com.autonomousapps.dependency-analysis" version gradle.ext.dependencyAnalysisVersion id "com.osacky.fladle" version gradle.ext.fladleVersion } From 845f909f4a93a894508453c7511afb1604dda375 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 21:43:28 +0300 Subject: [PATCH 099/162] Deps: Migrate dependency analysis plugin to version catalogs --- build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ settings.gradle | 2 -- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 6f841522b9e..e87e12c2135 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { alias(libs.plugins.detekt) alias(libs.plugins.automattic.measure.builds) - id "com.autonomousapps.dependency-analysis" + alias(libs.plugins.dependency.analysis) alias(libs.plugins.android.application).apply(false) alias(libs.plugins.android.library).apply(false) alias(libs.plugins.android.test).apply(false) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 45c1eb36dba..db4899d28e1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -43,6 +43,7 @@ cashapp-turbine = '1.0.0' coil = '2.1.0' commons-fileupload = '1.5' commons-io = '2.11.0' +dependency-analysis = '1.28.0' detekt = '1.23.5' facebook-flipper = '0.176.1' facebook-shimmer = '0.5.0' @@ -235,6 +236,7 @@ android-library = { id = "com.android.library", version.ref = "agp" } android-test = { id = "com.android.test", version.ref = "agp" } androidx-navigation-safeargs = { id = "androidx.navigation.safeargs.kotlin", version.ref = "androidx-navigation" } automattic-measure-builds = { id = "com.automattic.android.measure-builds", version.ref = "automattic-measure-builds" } +dependency-analysis = { id = "com.autonomousapps.dependency-analysis", version.ref = "dependency-analysis" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } google-dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "google-dagger" } google-protobuf = { id = "com.google.protobuf", version.ref = "google-protobuf-plugin" } diff --git a/settings.gradle b/settings.gradle index 6f56bb1abda..baf77d0073e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,4 @@ pluginManagement { - gradle.ext.dependencyAnalysisVersion = '1.28.0' gradle.ext.fladleVersion = '0.17.5' repositories { @@ -19,7 +18,6 @@ pluginManagement { } plugins { - id "com.autonomousapps.dependency-analysis" version gradle.ext.dependencyAnalysisVersion id "com.osacky.fladle" version gradle.ext.fladleVersion } } From 13a9d591cb11cead208f4f2de0b04f9fa53ba786 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 4 Oct 2024 21:45:32 +0300 Subject: [PATCH 100/162] Deps: Migrate fladle plugin to version catalogs --- WooCommerce/build.gradle | 2 +- gradle/libs.versions.toml | 2 ++ settings.gradle | 6 ------ 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index adc135f5719..2018e455434 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -10,7 +10,7 @@ plugins { alias(libs.plugins.google.services) alias(libs.plugins.ksp) alias(libs.plugins.google.protobuf) - id "com.osacky.fladle" + alias(libs.plugins.fladle) } fladle { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index db4899d28e1..e3a3929387c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -49,6 +49,7 @@ facebook-flipper = '0.176.1' facebook-shimmer = '0.5.0' facebook-soloader = '0.10.4' fastlane-screengrab = '2.1.1' +fladle = '0.17.5' google-dagger = "2.50" google-firebase-bom = '32.7.1' google-gson = '2.10.1' @@ -238,6 +239,7 @@ androidx-navigation-safeargs = { id = "androidx.navigation.safeargs.kotlin", ver automattic-measure-builds = { id = "com.automattic.android.measure-builds", version.ref = "automattic-measure-builds" } dependency-analysis = { id = "com.autonomousapps.dependency-analysis", version.ref = "dependency-analysis" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } +fladle = { id = "com.osacky.fladle", version.ref = "fladle" } google-dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "google-dagger" } google-protobuf = { id = "com.google.protobuf", version.ref = "google-protobuf-plugin" } google-services = { id = "com.google.gms.google-services", version.ref = "google-services" } diff --git a/settings.gradle b/settings.gradle index baf77d0073e..794b7eb05e3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,4 @@ pluginManagement { - gradle.ext.fladleVersion = '0.17.5' - repositories { google() exclusiveContent { @@ -16,10 +14,6 @@ pluginManagement { } gradlePluginPortal() } - - plugins { - id "com.osacky.fladle" version gradle.ext.fladleVersion - } } plugins { From d66f2b3bb4719752c7cc8f82f2103e15f601943f Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Mon, 7 Oct 2024 17:59:35 +0100 Subject: [PATCH 101/162] Add tests for the subscription date sync parsing --- .../products/SubscriptionDetailsMapperTest.kt | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/SubscriptionDetailsMapperTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/SubscriptionDetailsMapperTest.kt index fb50393fb38..4afa07daed4 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/SubscriptionDetailsMapperTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/SubscriptionDetailsMapperTest.kt @@ -1,11 +1,13 @@ package com.woocommerce.android.ui.products import com.woocommerce.android.model.SubscriptionDetailsMapper +import com.woocommerce.android.model.SubscriptionPaymentSyncDate import com.woocommerce.android.model.SubscriptionPeriod import com.woocommerce.android.viewmodel.BaseUnitTest import kotlinx.coroutines.ExperimentalCoroutinesApi import org.assertj.core.api.Assertions.assertThat import org.junit.Test +import org.wordpress.android.fluxc.model.WCProductModel import java.math.BigDecimal @OptIn(ExperimentalCoroutinesApi::class) @@ -49,6 +51,57 @@ class SubscriptionDetailsMapperTest : BaseUnitTest() { } } + @Test + fun `when sync date contains both a day and month, then parse it successfully`() { + val metadata = """ [ { + "id": 5182, + "key": ${WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_PAYMENT_SYNC_DATE}, + "value": { + "day": 1, + "month": 9 + } + }] + """ + val result = SubscriptionDetailsMapper.toAppModel(metadata) + assertThat(result).isNotNull + assertThat(result!!.paymentsSyncDate).isEqualTo( + SubscriptionPaymentSyncDate.MonthDay(month = 9, day = 1) + ) + } + + @Test + fun `when sync data day is 0, then parse it successfully`() { + val metadata = """ [ { + "id": 5182, + "key": ${WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_PAYMENT_SYNC_DATE}, + "value": { + "day": 0, + "month": 0 + } + }] + """ + val result = SubscriptionDetailsMapper.toAppModel(metadata) + assertThat(result).isNotNull + assertThat(result!!.paymentsSyncDate).isEqualTo( + SubscriptionPaymentSyncDate.None + ) + } + + @Test + fun `when sync date contains only a day, then parse it successfully`() { + val metadata = """ [ { + "id": 5182, + "key": ${WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_PAYMENT_SYNC_DATE}, + "value": 1 + }] + """ + val result = SubscriptionDetailsMapper.toAppModel(metadata) + assertThat(result).isNotNull + assertThat(result!!.paymentsSyncDate).isEqualTo( + SubscriptionPaymentSyncDate.Day(1) + ) + } + /** * price = 60, * period = month, From 470a4c6af6f9205666580bc6f1f1b2032599f23c Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Mon, 7 Oct 2024 18:20:29 +0100 Subject: [PATCH 102/162] Fix parsing bug --- .../com/woocommerce/android/model/SubscriptionDetailsMapper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetailsMapper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetailsMapper.kt index fc976af7b4c..8253ebbc68d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetailsMapper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetailsMapper.kt @@ -75,7 +75,7 @@ object SubscriptionDetailsMapper { if (day == 0) { SubscriptionPaymentSyncDate.None } else { - SubscriptionPaymentSyncDate.MonthDay(day, month) + SubscriptionPaymentSyncDate.MonthDay(month = month, day = day) } } From 874b636bc8b4438f3909c15f7d64a81710771421 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Mon, 7 Oct 2024 15:13:30 +0100 Subject: [PATCH 103/162] Introduce ProductAggregate class --- .../android/model/ProductAggregate.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductAggregate.kt diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductAggregate.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductAggregate.kt new file mode 100644 index 00000000000..885ccc213c9 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductAggregate.kt @@ -0,0 +1,25 @@ +package com.woocommerce.android.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +/** + * Container class for product and any additional details that are stored as product metadata. + * + * For now, the additional details include subscription details only. + * + * @param product The product. + * @param subscription The subscription details. + */ +@Parcelize +data class ProductAggregate( + val product: Product, + val subscription: SubscriptionDetails? +) : Parcelable { + val hasShipping: Boolean + get() = product.hasShipping || subscription?.oneTimeShipping == true + + fun isSame(other: ProductAggregate): Boolean { + return product.isSameProduct(other.product) && subscription == other.subscription + } +} From d2023373cf3dc3280b6ed0d81fcbea6c494e60b6 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Mon, 7 Oct 2024 16:19:18 +0100 Subject: [PATCH 104/162] First pass at updating product detail screen to use ProductAggregate --- .../ProductDetailBottomSheetBuilder.kt | 83 ++-- .../details/ProductDetailCardBuilder.kt | 401 +++++++++--------- .../details/ProductDetailViewModel.kt | 122 +++--- 3 files changed, 315 insertions(+), 291 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailBottomSheetBuilder.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailBottomSheetBuilder.kt index a7b3785f3b6..ee9c9e4d100 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailBottomSheetBuilder.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailBottomSheetBuilder.kt @@ -4,6 +4,7 @@ import androidx.annotation.StringRes import com.woocommerce.android.R.string import com.woocommerce.android.analytics.AnalyticsEvent import com.woocommerce.android.model.Product +import com.woocommerce.android.model.ProductAggregate import com.woocommerce.android.model.SubscriptionProductVariation import com.woocommerce.android.ui.customfields.CustomFieldsRepository import com.woocommerce.android.ui.products.ProductNavigationTarget @@ -49,84 +50,84 @@ class ProductDetailBottomSheetBuilder( ) @Suppress("LongMethod") - suspend fun buildBottomSheetList(product: Product): List { - return when (product.productType) { + suspend fun buildBottomSheetList(productAggregate: ProductAggregate): List { + return when (productAggregate.product.productType) { SIMPLE, SUBSCRIPTION -> { listOfNotNull( - product.getShipping(), - product.getCategories(), - product.getTags(), - product.getShortDescription(), - product.getLinkedProducts(), - product.getDownloadableFiles(), - product.getCustomFields() + productAggregate.getShipping(), + productAggregate.product.getCategories(), + productAggregate.product.getTags(), + productAggregate.product.getShortDescription(), + productAggregate.product.getLinkedProducts(), + productAggregate.product.getDownloadableFiles(), + productAggregate.product.getCustomFields() ) } EXTERNAL -> { listOfNotNull( - product.getCategories(), - product.getTags(), - product.getShortDescription(), - product.getLinkedProducts(), - product.getCustomFields() + productAggregate.product.getCategories(), + productAggregate.product.getTags(), + productAggregate.product.getShortDescription(), + productAggregate.product.getLinkedProducts(), + productAggregate.product.getCustomFields() ) } GROUPED -> { listOfNotNull( - product.getCategories(), - product.getTags(), - product.getShortDescription(), - product.getLinkedProducts(), - product.getCustomFields() + productAggregate.product.getCategories(), + productAggregate.product.getTags(), + productAggregate.product.getShortDescription(), + productAggregate.product.getLinkedProducts(), + productAggregate.product.getCustomFields() ) } VARIABLE, VARIABLE_SUBSCRIPTION -> { listOfNotNull( - product.getShipping(), - product.getCategories(), - product.getTags(), - product.getShortDescription(), - product.getLinkedProducts(), - product.getCustomFields() + productAggregate.getShipping(), + productAggregate.product.getCategories(), + productAggregate.product.getTags(), + productAggregate.product.getShortDescription(), + productAggregate.product.getLinkedProducts(), + productAggregate.product.getCustomFields() ) } else -> { listOfNotNull( - product.getCategories(), - product.getTags(), - product.getShortDescription(), - product.getCustomFields() + productAggregate.product.getCategories(), + productAggregate.product.getTags(), + productAggregate.product.getShortDescription(), + productAggregate.product.getCustomFields() ) } } } - private fun Product.getShipping(): ProductDetailBottomSheetUiItem? { - return if (!isVirtual && !hasShipping) { + private fun ProductAggregate.getShipping(): ProductDetailBottomSheetUiItem? { + return if (!product.isVirtual && !hasShipping) { ProductDetailBottomSheetUiItem( ProductDetailBottomSheetType.PRODUCT_SHIPPING, ViewProductShipping( ShippingData( - weight = weight, - length = length, - width = width, - height = height, - shippingClassSlug = shippingClass, - shippingClassId = shippingClassId, - subscriptionShippingData = if (productType == SUBSCRIPTION || - this.productType == VARIABLE_SUBSCRIPTION + weight = product.weight, + length = product.length, + width = product.width, + height = product.height, + shippingClassSlug = product.shippingClass, + shippingClassId = product.shippingClassId, + subscriptionShippingData = if (product.productType == SUBSCRIPTION || + product.productType == VARIABLE_SUBSCRIPTION ) { ShippingData.SubscriptionShippingData( oneTimeShipping = subscription?.oneTimeShipping ?: false, - canEnableOneTimeShipping = if (productType == SUBSCRIPTION) { + canEnableOneTimeShipping = if (product.productType == SUBSCRIPTION) { subscription?.supportsOneTimeShipping ?: false } else { // For variable subscription products, we need to check against the variations - variationRepository.getProductVariationList(remoteId).all { + variationRepository.getProductVariationList(product.remoteId).all { (it as? SubscriptionProductVariation)?.subscriptionDetails ?.supportsOneTimeShipping ?: false } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailCardBuilder.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailCardBuilder.kt index 171a2433cb3..151446aaada 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailCardBuilder.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailCardBuilder.kt @@ -19,6 +19,8 @@ import com.woocommerce.android.extensions.filterNotEmpty import com.woocommerce.android.extensions.isEligibleForAI import com.woocommerce.android.extensions.isSet import com.woocommerce.android.model.Product +import com.woocommerce.android.model.ProductAggregate +import com.woocommerce.android.model.SubscriptionDetails import com.woocommerce.android.model.SubscriptionProductVariation import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.blaze.BlazeUrlsHelper.BlazeFlowSource @@ -110,38 +112,41 @@ class ProductDetailCardBuilder( private val onTooltipDismiss = { appPrefsWrapper.isAIProductDescriptionTooltipDismissed = true } - suspend fun buildPropertyCards(product: Product, originalSku: String): List { + suspend fun buildPropertyCards( + productAggregate: ProductAggregate, + originalSku: String + ): List { this.originalSku = originalSku val cards = mutableListOf() - cards.addIfNotEmpty(getPrimaryCard(product)) - - cards.addIfNotEmpty(getBlazeCard(product)) - - when (product.productType) { - SIMPLE -> cards.addIfNotEmpty(getSimpleProductCard(product)) - VARIABLE -> cards.addIfNotEmpty(getVariableProductCard(product)) - GROUPED -> cards.addIfNotEmpty(getGroupedProductCard(product)) - EXTERNAL -> cards.addIfNotEmpty(getExternalProductCard(product)) - SUBSCRIPTION -> cards.addIfNotEmpty(getSubscriptionProductCard(product)) - VARIABLE_SUBSCRIPTION -> cards.addIfNotEmpty(getVariableSubscriptionProductCard(product)) - BUNDLE -> cards.addIfNotEmpty(getBundleProductsCard(product)) - COMPOSITE -> cards.addIfNotEmpty(getCompositeProductsCard(product)) - else -> cards.addIfNotEmpty(getOtherProductCard(product)) + cards.addIfNotEmpty(getPrimaryCard(productAggregate)) + + cards.addIfNotEmpty(getBlazeCard(productAggregate)) + + when (productAggregate.product.productType) { + SIMPLE -> cards.addIfNotEmpty(getSimpleProductCard(productAggregate)) + VARIABLE -> cards.addIfNotEmpty(getVariableProductCard(productAggregate)) + GROUPED -> cards.addIfNotEmpty(getGroupedProductCard(productAggregate)) + EXTERNAL -> cards.addIfNotEmpty(getExternalProductCard(productAggregate)) + SUBSCRIPTION -> cards.addIfNotEmpty(getSubscriptionProductCard(productAggregate)) + VARIABLE_SUBSCRIPTION -> cards.addIfNotEmpty(getVariableSubscriptionProductCard(productAggregate)) + BUNDLE -> cards.addIfNotEmpty(getBundleProductsCard(productAggregate)) + COMPOSITE -> cards.addIfNotEmpty(getCompositeProductsCard(productAggregate)) + else -> cards.addIfNotEmpty(getOtherProductCard(productAggregate)) } return cards } - private fun getPrimaryCard(product: Product): ProductPropertyCard { - val showTooltip = product.description.isEmpty() && + private fun getPrimaryCard(productAggregate: ProductAggregate): ProductPropertyCard { + val showTooltip = productAggregate.product.description.isEmpty() && !appPrefsWrapper.isAIProductDescriptionTooltipDismissed && appPrefsWrapper.getAIDescriptionTooltipShownNumber() <= MAXIMUM_TIMES_TO_SHOW_TOOLTIP return ProductPropertyCard( type = PRIMARY, properties = ( - listOf(product.title()) + - product.description( + listOf(productAggregate.product.title()) + + productAggregate.product.description( showAIButton = selectedSite.get().isEligibleForAI, showTooltip = showTooltip, onWriteWithAIClicked = viewModel::onWriteWithAIClicked, @@ -151,15 +156,15 @@ class ProductDetailCardBuilder( ) } - private suspend fun getBlazeCard(product: Product): ProductPropertyCard? { - val isProductPublic = product.status == ProductStatus.PUBLISH && + private suspend fun getBlazeCard(productAggregate: ProductAggregate): ProductPropertyCard? { + val isProductPublic = productAggregate.product.status == ProductStatus.PUBLISH && viewModel.getProductVisibility() == ProductVisibility.PUBLIC @Suppress("ComplexCondition") if (!isBlazeEnabled() || !isProductPublic || viewModel.isProductUnderCreation || - isProductCurrentlyPromoted(product.remoteId.toString()) + isProductCurrentlyPromoted(productAggregate.product.remoteId.toString()) ) { return null } @@ -186,169 +191,169 @@ class ProductDetailCardBuilder( ) } - private suspend fun getSimpleProductCard(product: Product): ProductPropertyCard { + private suspend fun getSimpleProductCard(productAggregate: ProductAggregate): ProductPropertyCard { return ProductPropertyCard( type = SECONDARY, properties = listOf( - product.price(), - if (viewModel.isProductUnderCreation) null else product.productReviews(), - product.inventory(SIMPLE), - product.addons(), - product.quantityRules(), - product.shipping(), - product.categories(), - product.tags(), - product.shortDescription(), - product.linkedProducts(), - product.downloads(), - product.customFields(), - product.productType() + productAggregate.price(), + if (viewModel.isProductUnderCreation) null else productAggregate.product.productReviews(), + productAggregate.product.inventory(SIMPLE), + productAggregate.product.addons(), + productAggregate.product.quantityRules(), + productAggregate.shipping(), + productAggregate.product.categories(), + productAggregate.product.tags(), + productAggregate.product.shortDescription(), + productAggregate.product.linkedProducts(), + productAggregate.product.downloads(), + productAggregate.product.customFields(), + productAggregate.product.productType() ).filterNotEmpty() ) } - private suspend fun getGroupedProductCard(product: Product): ProductPropertyCard { + private suspend fun getGroupedProductCard(productAggregate: ProductAggregate): ProductPropertyCard { return ProductPropertyCard( type = SECONDARY, properties = listOf( - product.groupedProducts(), - if (viewModel.isProductUnderCreation) null else product.productReviews(), - product.inventory(GROUPED), - product.addons(), - product.quantityRules(), - product.categories(), - product.tags(), - product.shortDescription(), - product.linkedProducts(), - product.customFields(), - product.productType() + productAggregate.product.groupedProducts(), + if (viewModel.isProductUnderCreation) null else productAggregate.product.productReviews(), + productAggregate.product.inventory(GROUPED), + productAggregate.product.addons(), + productAggregate.product.quantityRules(), + productAggregate.product.categories(), + productAggregate.product.tags(), + productAggregate.product.shortDescription(), + productAggregate.product.linkedProducts(), + productAggregate.product.customFields(), + productAggregate.product.productType() ).filterNotEmpty() ) } - private suspend fun getExternalProductCard(product: Product): ProductPropertyCard { + private suspend fun getExternalProductCard(productAggregate: ProductAggregate): ProductPropertyCard { return ProductPropertyCard( type = SECONDARY, properties = listOf( - product.price(), - if (viewModel.isProductUnderCreation) null else product.productReviews(), - product.externalLink(), - product.inventory(EXTERNAL), - product.addons(), - product.quantityRules(), - product.categories(), - product.tags(), - product.shortDescription(), - product.linkedProducts(), - product.customFields(), - product.productType() + productAggregate.price(), + if (viewModel.isProductUnderCreation) null else productAggregate.product.productReviews(), + productAggregate.product.externalLink(), + productAggregate.product.inventory(EXTERNAL), + productAggregate.product.addons(), + productAggregate.product.quantityRules(), + productAggregate.product.categories(), + productAggregate.product.tags(), + productAggregate.product.shortDescription(), + productAggregate.product.linkedProducts(), + productAggregate.product.customFields(), + productAggregate.product.productType() ).filterNotEmpty() ) } - private suspend fun getVariableProductCard(product: Product): ProductPropertyCard { + private suspend fun getVariableProductCard(productAggregate: ProductAggregate): ProductPropertyCard { return ProductPropertyCard( type = SECONDARY, properties = listOf( - product.warning(), - product.variations(), - product.variationAttributes(), - if (viewModel.isProductUnderCreation) null else product.productReviews(), - product.inventory(VARIABLE), - product.addons(), - product.quantityRules(), - product.shipping(), - product.categories(), - product.tags(), - product.shortDescription(), - product.linkedProducts(), - product.customFields(), - product.productType() + productAggregate.product.warning(), + productAggregate.product.variations(), + productAggregate.product.variationAttributes(), + if (viewModel.isProductUnderCreation) null else productAggregate.product.productReviews(), + productAggregate.product.inventory(VARIABLE), + productAggregate.product.addons(), + productAggregate.product.quantityRules(), + productAggregate.shipping(), + productAggregate.product.categories(), + productAggregate.product.tags(), + productAggregate.product.shortDescription(), + productAggregate.product.linkedProducts(), + productAggregate.product.customFields(), + productAggregate.product.productType() ).filterNotEmpty() ) } - private suspend fun getSubscriptionProductCard(product: Product): ProductPropertyCard { + private suspend fun getSubscriptionProductCard(productAggregate: ProductAggregate): ProductPropertyCard { return ProductPropertyCard( type = SECONDARY, properties = listOf( - product.price(), - product.subscriptionExpirationDate(), - product.subscriptionTrial(), - if (viewModel.isProductUnderCreation) null else product.productReviews(), - product.inventory(SIMPLE), - product.addons(), - product.quantityRules(), - product.shipping(), - product.categories(), - product.tags(), - product.shortDescription(), - product.linkedProducts(), - product.downloads(), - product.customFields(), - product.productType() + productAggregate.price(), + productAggregate.subscription?.subscriptionExpirationDate(), + productAggregate.subscription?.subscriptionTrial(), + if (viewModel.isProductUnderCreation) null else productAggregate.product.productReviews(), + productAggregate.product.inventory(SIMPLE), + productAggregate.product.addons(), + productAggregate.product.quantityRules(), + productAggregate.shipping(), + productAggregate.product.categories(), + productAggregate.product.tags(), + productAggregate.product.shortDescription(), + productAggregate.product.linkedProducts(), + productAggregate.product.downloads(), + productAggregate.product.customFields(), + productAggregate.product.productType() ).filterNotEmpty() ) } - private suspend fun getVariableSubscriptionProductCard(product: Product): ProductPropertyCard { + private suspend fun getVariableSubscriptionProductCard(productAggregate: ProductAggregate): ProductPropertyCard { return ProductPropertyCard( type = SECONDARY, properties = listOf( - product.warning(), - product.variations(), - product.variationAttributes(), - if (viewModel.isProductUnderCreation) null else product.productReviews(), - product.inventory(VARIABLE), - product.addons(), - product.quantityRules(), - product.shipping(), - product.categories(), - product.tags(), - product.shortDescription(), - product.linkedProducts(), - product.customFields(), - product.productType() + productAggregate.product.warning(), + productAggregate.product.variations(), + productAggregate.product.variationAttributes(), + if (viewModel.isProductUnderCreation) null else productAggregate.product.productReviews(), + productAggregate.product.inventory(VARIABLE), + productAggregate.product.addons(), + productAggregate.product.quantityRules(), + productAggregate.shipping(), + productAggregate.product.categories(), + productAggregate.product.tags(), + productAggregate.product.shortDescription(), + productAggregate.product.linkedProducts(), + productAggregate.product.customFields(), + productAggregate.product.productType() ).filterNotEmpty() ) } - private suspend fun getBundleProductsCard(product: Product): ProductPropertyCard { + private suspend fun getBundleProductsCard(productAggregate: ProductAggregate): ProductPropertyCard { return ProductPropertyCard( type = SECONDARY, properties = listOf( - product.bundleProducts(), - product.price(), - if (viewModel.isProductUnderCreation) null else product.productReviews(), - product.inventory(SIMPLE), - product.addons(), - product.quantityRules(), - product.categories(), - product.tags(), - product.shortDescription(), - product.linkedProducts(), - product.customFields(), - product.productType() + productAggregate.product.bundleProducts(), + productAggregate.price(), + if (viewModel.isProductUnderCreation) null else productAggregate.product.productReviews(), + productAggregate.product.inventory(SIMPLE), + productAggregate.product.addons(), + productAggregate.product.quantityRules(), + productAggregate.product.categories(), + productAggregate.product.tags(), + productAggregate.product.shortDescription(), + productAggregate.product.linkedProducts(), + productAggregate.product.customFields(), + productAggregate.product.productType() ).filterNotEmpty() ) } - private suspend fun getCompositeProductsCard(product: Product): ProductPropertyCard { + private suspend fun getCompositeProductsCard(productAggregate: ProductAggregate): ProductPropertyCard { return ProductPropertyCard( type = SECONDARY, properties = listOf( - product.componentProducts(), - product.price(), - if (viewModel.isProductUnderCreation) null else product.productReviews(), - product.inventory(SIMPLE), - product.addons(), - product.quantityRules(), - product.categories(), - product.tags(), - product.shortDescription(), - product.linkedProducts(), - product.customFields(), - product.productType() + productAggregate.product.componentProducts(), + productAggregate.price(), + if (viewModel.isProductUnderCreation) null else productAggregate.product.productReviews(), + productAggregate.product.inventory(SIMPLE), + productAggregate.product.addons(), + productAggregate.product.quantityRules(), + productAggregate.product.categories(), + productAggregate.product.tags(), + productAggregate.product.shortDescription(), + productAggregate.product.linkedProducts(), + productAggregate.product.customFields(), + productAggregate.product.productType() ).filterNotEmpty() ) } @@ -357,19 +362,19 @@ class ProductDetailCardBuilder( * Used for product types the app doesn't support yet (ex: subscriptions), uses a subset * of properties since we can't be sure pricing, shipping, etc., are applicable */ - private suspend fun getOtherProductCard(product: Product): ProductPropertyCard { + private suspend fun getOtherProductCard(productAggregate: ProductAggregate): ProductPropertyCard { return ProductPropertyCard( type = SECONDARY, properties = listOf( - if (viewModel.isProductUnderCreation) null else product.productReviews(), - product.addons(), - product.quantityRules(), - product.categories(), - product.tags(), - product.shortDescription(), - product.linkedProducts(), - product.customFields(), - product.productType() + if (viewModel.isProductUnderCreation) null else productAggregate.product.productReviews(), + productAggregate.product.addons(), + productAggregate.product.quantityRules(), + productAggregate.product.categories(), + productAggregate.product.tags(), + productAggregate.product.shortDescription(), + productAggregate.product.linkedProducts(), + productAggregate.product.customFields(), + productAggregate.product.productType() ).filterNotEmpty() ) } @@ -463,16 +468,16 @@ class ProductDetailCardBuilder( } } - private fun Product.shipping(): ProductProperty? { - return if (!this.isVirtual && hasShipping) { - val weightWithUnits = this.getWeightWithUnits(parameters.weightUnit) - val sizeWithUnits = this.getSizeWithUnits(parameters.dimensionUnit) + private fun ProductAggregate.shipping(): ProductProperty? { + return if (!this.product.isVirtual && hasShipping) { + val weightWithUnits = product.getWeightWithUnits(parameters.weightUnit) + val sizeWithUnits = product.getSizeWithUnits(parameters.dimensionUnit) val shippingGroup = mapOf( Pair(resources.getString(string.product_weight), weightWithUnits), Pair(resources.getString(string.product_dimensions), sizeWithUnits), Pair( resources.getString(string.product_shipping_class), - viewModel.getShippingClassByRemoteShippingClassId(this.shippingClassId) + viewModel.getShippingClassByRemoteShippingClassId(this.product.shippingClassId) ), Pair( resources.getString(string.subscription_one_time_shipping), @@ -492,22 +497,22 @@ class ProductDetailCardBuilder( viewModel.onEditProductCardClicked( ViewProductShipping( ShippingData( - weight = weight, - length = length, - width = width, - height = height, - shippingClassSlug = shippingClass, - shippingClassId = shippingClassId, - subscriptionShippingData = if (productType == SUBSCRIPTION || - this.productType == VARIABLE_SUBSCRIPTION + weight = product.weight, + length = product.length, + width = product.width, + height = product.height, + shippingClassSlug = product.shippingClass, + shippingClassId = product.shippingClassId, + subscriptionShippingData = if (product.productType == SUBSCRIPTION || + product.productType == VARIABLE_SUBSCRIPTION ) { ShippingData.SubscriptionShippingData( oneTimeShipping = subscription?.oneTimeShipping ?: false, - canEnableOneTimeShipping = if (productType == SUBSCRIPTION) { + canEnableOneTimeShipping = if (product.productType == SUBSCRIPTION) { subscription?.supportsOneTimeShipping ?: false } else { // For variable subscription products, we need to check against the variations - variationRepository.getProductVariationList(remoteId).all { + variationRepository.getProductVariationList(product.remoteId).all { (it as? SubscriptionProductVariation)?.subscriptionDetails ?.supportsOneTimeShipping ?: false } @@ -552,16 +557,16 @@ class ProductDetailCardBuilder( } } - private fun Product.price(): ProductProperty { + private fun ProductAggregate.price(): ProductProperty { val pricingData = PricingData( - taxClass = taxClass, - taxStatus = taxStatus, - isSaleScheduled = isSaleScheduled, - saleStartDate = saleStartDateGmt, - saleEndDate = saleEndDateGmt, - regularPrice = regularPrice, - salePrice = salePrice, - isSubscription = this.productType == SUBSCRIPTION, + taxClass = product.taxClass, + taxStatus = product.taxStatus, + isSaleScheduled = product.isSaleScheduled, + saleStartDate = product.saleStartDateGmt, + saleEndDate = product.saleEndDateGmt, + regularPrice = product.regularPrice, + salePrice = product.salePrice, + isSubscription = product.productType == SUBSCRIPTION, subscriptionPeriod = subscription?.period, subscriptionInterval = subscription?.periodInterval, subscriptionSignUpFee = subscription?.signUpFee, @@ -578,7 +583,7 @@ class ProductDetailCardBuilder( string.product_price, pricingGroup, drawable.ic_gridicons_money, - showTitle = this.regularPrice.isSet() + showTitle = product.regularPrice.isSet() ) { viewModel.onEditProductCardClicked( ViewProductPricing(pricingData), @@ -894,43 +899,37 @@ class ProductDetailCardBuilder( ) } - private fun Product.subscriptionExpirationDate(): ProductProperty? = - this.subscription?.let { subscription -> - PropertyGroup( - title = string.product_subscription_expiration_title, - icon = drawable.ic_calendar_expiration, - properties = mapOf( - resources.getString(string.subscription_expire) to subscription.expirationDisplayValue( - resources - ) - ), - showTitle = true, - onClick = { - viewModel.onEditProductCardClicked( - ViewProductSubscriptionExpiration(subscription), - AnalyticsEvent.PRODUCT_DETAILS_VIEW_SUBSCRIPTION_EXPIRATION_TAPPED - ) - } + private fun SubscriptionDetails.subscriptionExpirationDate(): ProductProperty = PropertyGroup( + title = string.product_subscription_expiration_title, + icon = drawable.ic_calendar_expiration, + properties = mapOf( + resources.getString(string.subscription_expire) to expirationDisplayValue( + resources + ) + ), + showTitle = true, + onClick = { + viewModel.onEditProductCardClicked( + ViewProductSubscriptionExpiration(this), + AnalyticsEvent.PRODUCT_DETAILS_VIEW_SUBSCRIPTION_EXPIRATION_TAPPED ) } - - private fun Product.subscriptionTrial(): ProductProperty? = - this.subscription?.let { subscription -> - PropertyGroup( - title = string.product_subscription_free_trial_title, - icon = drawable.ic_hourglass_empty, - properties = mapOf( - resources.getString(string.subscription_free_trial) to subscription.trialDisplayValue(resources) - ), - showTitle = true, - onClick = { - viewModel.onEditProductCardClicked( - ViewProductSubscriptionFreeTrial(subscription), - AnalyticsEvent.PRODUCT_DETAILS_VIEW_SUBSCRIPTION_FREE_TRIAL_TAPPED - ) - } + ) + + private fun SubscriptionDetails.subscriptionTrial(): ProductProperty = PropertyGroup( + title = string.product_subscription_free_trial_title, + icon = drawable.ic_hourglass_empty, + properties = mapOf( + resources.getString(string.subscription_free_trial) to trialDisplayValue(resources) + ), + showTitle = true, + onClick = { + viewModel.onEditProductCardClicked( + ViewProductSubscriptionFreeTrial(this), + AnalyticsEvent.PRODUCT_DETAILS_VIEW_SUBSCRIPTION_FREE_TRIAL_TAPPED ) } + ) private fun Product.warning(): ProductProperty? { val variations = variationRepository.getProductVariationList(this.remoteId) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt index 6fa960ddbc3..7e97d85f9f6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt @@ -33,12 +33,14 @@ import com.woocommerce.android.media.MediaFilesRepository import com.woocommerce.android.media.MediaFilesRepository.UploadResult import com.woocommerce.android.model.Component import com.woocommerce.android.model.Product +import com.woocommerce.android.model.ProductAggregate import com.woocommerce.android.model.ProductAttribute import com.woocommerce.android.model.ProductCategory import com.woocommerce.android.model.ProductFile import com.woocommerce.android.model.ProductGlobalAttribute import com.woocommerce.android.model.ProductTag import com.woocommerce.android.model.RequestResult +import com.woocommerce.android.model.SubscriptionDetails import com.woocommerce.android.model.SubscriptionPeriod import com.woocommerce.android.model.addTags import com.woocommerce.android.model.sortCategories @@ -187,8 +189,8 @@ class ProductDetailViewModel @Inject constructor( savedState = savedState, initialValue = ProductDetailViewState(areImagesAvailable = !selectedSite.get().isPrivate) ) { old, new -> - if (old?.productDraft != new.productDraft) { - new.productDraft?.let { + if (old?.productAggregateDraft != new.productAggregateDraft) { + new.productAggregateDraft?.let { updateCards(it) draftChanges.value = it } @@ -200,9 +202,9 @@ class ProductDetailViewModel @Inject constructor( * The goal of this is to allow composition of reactive streams using the product draft changes, * we need a separate stream because [LiveDataDelegate] supports a single observer. */ - private val draftChanges = MutableStateFlow(null) + private val draftChanges = MutableStateFlow(null) - private val storedProduct = MutableStateFlow(null) + private val storedProduct = MutableStateFlow(null) /** * Saving more data than necessary into the SavedState has associated risks which were not known at the time this @@ -300,7 +302,7 @@ class ProductDetailViewModel @Inject constructor( private val _hasChanges = storedProduct .combine(draftChanges) { storedProduct, productDraft -> - storedProduct?.let { product -> productDraft?.isSameProduct(product) == false } ?: false + storedProduct?.let { product -> productDraft?.isSame(product) == false } ?: false }.stateIn(viewModelScope, SharingStarted.Eagerly, false) val hasChanges = _hasChanges.asLiveData() @@ -318,8 +320,8 @@ class ProductDetailViewModel @Inject constructor( val menuButtonsState = draftChanges .filterNotNull() - .combine(_hasChanges) { productDraft, hasChanges -> - Pair(productDraft, hasChanges) + .combine(_hasChanges) { draft, hasChanges -> + Pair(draft.product, hasChanges) }.map { (productDraft, hasChanges) -> val canBeSavedAsDraft = this.isAddNewProductFlow && !isProductStoredAtSite && @@ -456,15 +458,18 @@ class ProductDetailViewModel @Inject constructor( } private fun initializeStoredProductAfterRestoration() { + // TODO: fetch subscription details launch { if (isAddNewProductFlow && !isProductStoredAtSite) { - storedProduct.value = createDefaultProductForAddFlow() + storedProduct.value = ProductAggregate(createDefaultProductForAddFlow(), null) } else { when (val mode = navArgs.mode) { is ProductDetailFragment.Mode.ShowProduct -> { - storedProduct.value = productRepository.getProductAsync( + productRepository.getProductAsync( viewState.productDraft?.remoteId ?: mode.remoteProductId - ) + )?.let { + storedProduct.value = ProductAggregate(it, null) + } } ProductDetailFragment.Mode.Loading -> { @@ -711,15 +716,15 @@ class ProductDetailViewModel @Inject constructor( attributeListViewState = attributeListViewState.copy(progressDialogState = ProgressDialogState.Hidden) } - fun hasCategoryChanges() = storedProduct.value?.hasCategoryChanges(viewState.productDraft) ?: false + fun hasCategoryChanges() = storedProduct.value?.product?.hasCategoryChanges(viewState.productDraft) ?: false - fun hasTagChanges() = storedProduct.value?.hasTagChanges(viewState.productDraft) ?: false + fun hasTagChanges() = storedProduct.value?.product?.hasTagChanges(viewState.productDraft) ?: false fun hasSettingsChanges(): Boolean { - return if (storedProduct.value?.hasSettingsChanges(viewState.productDraft) == true) { + return if (storedProduct.value?.product?.hasSettingsChanges(viewState.productDraft) == true) { true } else { - storedProduct.value?.password != viewState.draftPassword + storedProduct.value?.product?.password != viewState.draftPassword } } @@ -847,7 +852,7 @@ class ProductDetailViewModel @Inject constructor( ) } - fun hasExternalLinkChanges() = storedProduct.value?.hasExternalLinkChanges(viewState.productDraft) ?: false + fun hasExternalLinkChanges() = storedProduct.value?.product?.hasExternalLinkChanges(viewState.productDraft) ?: false /** * Called when the back= button is clicked in a product sub detail screen @@ -1138,7 +1143,7 @@ class ProductDetailViewModel @Inject constructor( storedProduct.value?.let { tracker.track( event, - mapOf(AnalyticsTracker.KEY_PRODUCT_ID to it.remoteId) + mapOf(AnalyticsTracker.KEY_PRODUCT_ID to it.product.remoteId) ) } } @@ -1175,7 +1180,7 @@ class ProductDetailViewModel @Inject constructor( */ fun onSettingsVisibilityButtonClicked() { val visibility = getProductVisibility() - val password = viewState.draftPassword ?: storedProduct.value?.password + val password = viewState.draftPassword ?: storedProduct.value?.product?.password triggerEvent( ProductNavigationTarget.ViewProductVisibility( selectedSite.connectionType == SiteConnectionType.ApplicationPasswords, @@ -1222,12 +1227,12 @@ class ProductDetailViewModel @Inject constructor( ) { updateProductDraft(type = productType.value, isVirtual = isVirtual) - viewState.productDraft?.let { productDraft -> - if (productType == ProductType.SUBSCRIPTION && productDraft.subscription == null) { + viewState.productAggregateDraft?.let { productAggregateDraft -> + if (productType == ProductType.SUBSCRIPTION && productAggregateDraft.subscription == null) { viewState = viewState.copy( - productDraft = productDraft.copy( + productAggregateDraft = productAggregateDraft.copy( subscription = ProductHelper.getDefaultSubscriptionDetails().copy( - price = productDraft.regularPrice + price = productAggregateDraft.product.regularPrice ) ) ) @@ -1331,12 +1336,12 @@ class ProductDetailViewModel @Inject constructor( saleEndDateGmt = if (productHasSale(isSaleScheduled, product)) { saleEndDate } else { - storedProduct.value?.saleEndDateGmt + storedProduct.value?.product?.saleEndDateGmt }, saleStartDateGmt = if (productHasSale(isSaleScheduled, product)) { saleStartDate ?: product.saleStartDateGmt } else { - storedProduct.value?.saleStartDateGmt + storedProduct.value?.product?.saleStartDateGmt }, downloads = downloads ?: product.downloads, downloadLimit = downloadLimit ?: product.downloadLimit, @@ -1353,17 +1358,16 @@ class ProductDetailViewModel @Inject constructor( } fun updateProductSubscription( - price: BigDecimal? = viewState.productDraft?.subscription?.price, + price: BigDecimal? = viewState.productAggregateDraft?.subscription?.price, period: SubscriptionPeriod? = null, periodInterval: Int? = null, - signUpFee: BigDecimal? = viewState.productDraft?.subscription?.signUpFee, + signUpFee: BigDecimal? = viewState.productAggregateDraft?.subscription?.signUpFee, length: Int? = null, trialLength: Int? = null, trialPeriod: SubscriptionPeriod? = null, oneTimeShipping: Boolean? = null ) { - viewState.productDraft?.let { product -> - val subscription = product.subscription ?: return + viewState.productAggregateDraft?.subscription?.let { subscription -> // The length ranges depend on the subscription period (days,weeks,months,years) and interval. If these // change we need to reset the length to "Never expire". This replicates web behavior val updatedLength = subscription.resetSubscriptionLengthIfThePeriodOrIntervalChanged( @@ -1381,7 +1385,7 @@ class ProductDetailViewModel @Inject constructor( trialPeriod = trialPeriod ?: subscription.trialPeriod, oneTimeShipping = oneTimeShipping ?: subscription.oneTimeShipping ) - viewState = viewState.copy(productDraft = product.copy(subscription = updatedSubscription)) + viewState = viewState.copy(subscriptionDraft = updatedSubscription) } } @@ -1402,10 +1406,13 @@ class ProductDetailViewModel @Inject constructor( } } - private fun updateCards(product: Product) { + private fun updateCards(productAggregate: ProductAggregate) { launch(dispatchers.io) { mutex.withLock { - val cards = cardBuilder.buildPropertyCards(product, storedProduct.value?.sku ?: "") + val cards = cardBuilder.buildPropertyCards( + productAggregate = productAggregate, + originalSku = storedProduct.value?.product?.sku ?: "" + ) withContext(dispatchers.main) { _productDetailCards.value = cards } @@ -1415,7 +1422,7 @@ class ProductDetailViewModel @Inject constructor( } private fun fetchBottomSheetList() { - viewState.productDraft?.let { + viewState.productAggregateDraft?.let { launch(dispatchers.computation) { val detailList = productDetailBottomSheetBuilder.buildBottomSheetList(it) withContext(dispatchers.main) { @@ -1477,7 +1484,7 @@ class ProductDetailViewModel @Inject constructor( */ private fun trackProductDetailLoaded() { if (hasTrackedProductDetailLoaded.not()) { - storedProduct.value?.let { product -> + storedProduct.value?.product?.let { product -> launch { val properties = mapOf( AnalyticsTracker.KEY_HAS_LINKED_PRODUCTS to product.hasLinkedProducts(), @@ -1506,7 +1513,9 @@ class ProductDetailViewModel @Inject constructor( */ fun updateProductVisibility(visibility: ProductVisibility, password: String?) { viewState = viewState.copy( - productDraft = viewState.productDraft?.copy(password = password) + productAggregateDraft = viewState.productAggregateDraft?.copy( + product = viewState.productDraft!!.copy(password = password) + ) ) when (visibility) { @@ -1531,8 +1540,8 @@ class ProductDetailViewModel @Inject constructor( * then the visibility is `PRIVATE`, otherwise it's `PUBLIC`. */ fun getProductVisibility(): ProductVisibility { - val status = viewState.productDraft?.status ?: storedProduct.value?.status - val password = viewState.draftPassword ?: storedProduct.value?.password + val status = viewState.productDraft?.status ?: storedProduct.value?.product?.status + val password = viewState.draftPassword ?: storedProduct.value?.product?.password return when { password?.isNotEmpty() == true -> { ProductVisibility.PASSWORD_PROTECTED @@ -1555,13 +1564,15 @@ class ProductDetailViewModel @Inject constructor( val productPasswordApi = determineProductPasswordApi() val password = when (productPasswordApi) { ProductPasswordApi.WPCOM -> productRepository.fetchProductPassword(remoteProductId) - ProductPasswordApi.CORE -> storedProduct.value?.password + ProductPasswordApi.CORE -> storedProduct.value?.product?.password ProductPasswordApi.UNSUPPORTED -> return } - storedProduct.update { it?.copy(password = password) } + storedProduct.update { it?.copy(product = it.product.copy(password = password)) } viewState = viewState.copy( - productDraft = viewState.productDraft?.copy(password = viewState.draftPassword ?: password) + productAggregateDraft = viewState.productAggregateDraft?.copy( + product = viewState.productDraft!!.copy(password = viewState.draftPassword ?: password) + ) ) } @@ -1853,7 +1864,7 @@ class ProductDetailViewModel @Inject constructor( triggerEvent(ProductNavigationTarget.RenameProductAttribute(attributeName)) } - fun hasAttributeChanges() = storedProduct.value?.hasAttributeChanges(viewState.productDraft) ?: false + fun hasAttributeChanges() = storedProduct.value?.product?.hasAttributeChanges(viewState.productDraft) ?: false /** * Used by the add attribute screen to fetch the list of store-wide product attributes @@ -1955,12 +1966,12 @@ class ProductDetailViewModel @Inject constructor( val result = productRepository.updateProduct(product.copy(password = viewState.draftPassword)) if (result.first) { val successMsg = pickProductUpdateSuccessText(isPublish) - val isPasswordChanged = storedProduct.value?.password != viewState.draftPassword + val isPasswordChanged = storedProduct.value?.product?.password != viewState.draftPassword if (isPasswordChanged && determineProductPasswordApi() == ProductPasswordApi.WPCOM) { // Update the product password using WordPress.com API val password = viewState.productDraft?.password if (productRepository.updateProductPassword(product.remoteId, password)) { - storedProduct.update { it?.copy(password = password) } + storedProduct.update { it?.copy(product = it.product.copy(password = password)) } triggerEvent(ShowSnackbar(successMsg)) } else { triggerEvent(ShowSnackbar(R.string.product_detail_update_product_password_error)) @@ -2063,7 +2074,7 @@ class ProductDetailViewModel @Inject constructor( private fun updateProductState(productToUpdateFrom: Product) { val updatedDraft = viewState.productDraft?.let { currentDraft -> - if (storedProduct.value?.isSameProduct(currentDraft) == true) { + if (storedProduct.value?.product?.isSameProduct(currentDraft) == true) { productToUpdateFrom } else { productToUpdateFrom.mergeProduct(currentDraft) @@ -2072,11 +2083,9 @@ class ProductDetailViewModel @Inject constructor( loadProductTaxAndShippingClassDependencies(updatedDraft) - viewState = viewState.copy( - productDraft = updatedDraft, - auxiliaryState = ProductDetailViewState.AuxiliaryState.None - ) - storedProduct.value = productToUpdateFrom + viewState = viewState.copy(productDraft = updatedDraft) + .copy(auxiliaryState = ProductDetailViewState.AuxiliaryState.None) + storedProduct.update { it?.copy(product = updatedDraft) } } private fun loadProductTaxAndShippingClassDependencies(product: Product) { @@ -2097,6 +2106,7 @@ class ProductDetailViewModel @Inject constructor( imageUploadsJob?.cancel() imageUploadsJob = launch { draftChanges + .map { it?.product } .distinctUntilChanged { old, new -> old?.remoteId == new?.remoteId } .map { getRemoteProductId() } .filter { productId -> productId != DEFAULT_ADD_NEW_PRODUCT_ID || isAddNewProductFlow } @@ -2578,7 +2588,7 @@ class ProductDetailViewModel @Inject constructor( } private fun hasSubscriptionExpirationChanges(): Boolean { - return storedProduct.value?.subscription?.length != viewState.productDraft?.subscription?.length + return storedProduct.value?.subscription?.length != viewState.subscriptionDraft?.length } fun onProductCategorySearchQueryChanged(query: String) { @@ -2696,7 +2706,7 @@ class ProductDetailViewModel @Inject constructor( */ @Parcelize data class ProductDetailViewState( - val productDraft: Product? = null, + val productAggregateDraft: ProductAggregate? = null, val auxiliaryState: AuxiliaryState = AuxiliaryState.None, val uploadingImageUris: List? = null, val isProgressDialogShown: Boolean? = null, @@ -2706,9 +2716,23 @@ class ProductDetailViewModel @Inject constructor( val isVariationListEmpty: Boolean? = null, val areImagesAvailable: Boolean ) : Parcelable { + val productDraft + get() = productAggregateDraft?.product + val subscriptionDraft + get() = productAggregateDraft?.subscription val draftPassword get() = productDraft?.password + fun copy(productDraft: Product?) = copy( + productAggregateDraft = productDraft?.let { + productAggregateDraft?.copy(product = it) + } + ) + + fun copy(subscriptionDraft: SubscriptionDetails) = copy( + productAggregateDraft = productAggregateDraft?.copy(subscription = subscriptionDraft) + ) + @Parcelize sealed class AuxiliaryState : Parcelable { @Parcelize From 4bef2535b516cf70062d081174e51f8f14ea16c4 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Tue, 8 Oct 2024 11:30:51 +0100 Subject: [PATCH 105/162] Few fixes to ensure the logic is still the same --- .../android/model/ProductAggregate.kt | 2 +- .../details/ProductDetailViewModel.kt | 60 +++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductAggregate.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductAggregate.kt index 885ccc213c9..a1fb491cb4f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductAggregate.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductAggregate.kt @@ -14,7 +14,7 @@ import kotlinx.parcelize.Parcelize @Parcelize data class ProductAggregate( val product: Product, - val subscription: SubscriptionDetails? + val subscription: SubscriptionDetails? = null ) : Parcelable { val hasShipping: Boolean get() = product.hasShipping || subscription?.oneTimeShipping == true diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt index 7e97d85f9f6..e537d9e6175 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt @@ -204,7 +204,7 @@ class ProductDetailViewModel @Inject constructor( */ private val draftChanges = MutableStateFlow(null) - private val storedProduct = MutableStateFlow(null) + private val storedProductAggregate = MutableStateFlow(null) /** * Saving more data than necessary into the SavedState has associated risks which were not known at the time this @@ -300,9 +300,9 @@ class ProductDetailViewModel @Inject constructor( ProductDetailBottomSheetBuilder(resources, variationRepository, customFieldsRepository) } - private val _hasChanges = storedProduct - .combine(draftChanges) { storedProduct, productDraft -> - storedProduct?.let { product -> productDraft?.isSame(product) == false } ?: false + private val _hasChanges = storedProductAggregate + .combine(draftChanges) { storedProductAggregate, productAggregateDraft -> + storedProductAggregate?.let { product -> productAggregateDraft?.isSame(product) == false } ?: false }.stateIn(viewModelScope, SharingStarted.Eagerly, false) val hasChanges = _hasChanges.asLiveData() @@ -461,14 +461,14 @@ class ProductDetailViewModel @Inject constructor( // TODO: fetch subscription details launch { if (isAddNewProductFlow && !isProductStoredAtSite) { - storedProduct.value = ProductAggregate(createDefaultProductForAddFlow(), null) + storedProductAggregate.value = ProductAggregate(createDefaultProductForAddFlow(), null) } else { when (val mode = navArgs.mode) { is ProductDetailFragment.Mode.ShowProduct -> { productRepository.getProductAsync( viewState.productDraft?.remoteId ?: mode.remoteProductId )?.let { - storedProduct.value = ProductAggregate(it, null) + storedProductAggregate.value = ProductAggregate(it, null) } } @@ -716,15 +716,15 @@ class ProductDetailViewModel @Inject constructor( attributeListViewState = attributeListViewState.copy(progressDialogState = ProgressDialogState.Hidden) } - fun hasCategoryChanges() = storedProduct.value?.product?.hasCategoryChanges(viewState.productDraft) ?: false + fun hasCategoryChanges() = storedProductAggregate.value?.product?.hasCategoryChanges(viewState.productDraft) ?: false - fun hasTagChanges() = storedProduct.value?.product?.hasTagChanges(viewState.productDraft) ?: false + fun hasTagChanges() = storedProductAggregate.value?.product?.hasTagChanges(viewState.productDraft) ?: false fun hasSettingsChanges(): Boolean { - return if (storedProduct.value?.product?.hasSettingsChanges(viewState.productDraft) == true) { + return if (storedProductAggregate.value?.product?.hasSettingsChanges(viewState.productDraft) == true) { true } else { - storedProduct.value?.product?.password != viewState.draftPassword + storedProductAggregate.value?.product?.password != viewState.draftPassword } } @@ -852,7 +852,7 @@ class ProductDetailViewModel @Inject constructor( ) } - fun hasExternalLinkChanges() = storedProduct.value?.product?.hasExternalLinkChanges(viewState.productDraft) ?: false + fun hasExternalLinkChanges() = storedProductAggregate.value?.product?.hasExternalLinkChanges(viewState.productDraft) ?: false /** * Called when the back= button is clicked in a product sub detail screen @@ -1140,7 +1140,7 @@ class ProductDetailViewModel @Inject constructor( } private fun trackWithProductId(event: AnalyticsEvent) { - storedProduct.value?.let { + storedProductAggregate.value?.let { tracker.track( event, mapOf(AnalyticsTracker.KEY_PRODUCT_ID to it.product.remoteId) @@ -1180,7 +1180,7 @@ class ProductDetailViewModel @Inject constructor( */ fun onSettingsVisibilityButtonClicked() { val visibility = getProductVisibility() - val password = viewState.draftPassword ?: storedProduct.value?.product?.password + val password = viewState.draftPassword ?: storedProductAggregate.value?.product?.password triggerEvent( ProductNavigationTarget.ViewProductVisibility( selectedSite.connectionType == SiteConnectionType.ApplicationPasswords, @@ -1336,12 +1336,12 @@ class ProductDetailViewModel @Inject constructor( saleEndDateGmt = if (productHasSale(isSaleScheduled, product)) { saleEndDate } else { - storedProduct.value?.product?.saleEndDateGmt + storedProductAggregate.value?.product?.saleEndDateGmt }, saleStartDateGmt = if (productHasSale(isSaleScheduled, product)) { saleStartDate ?: product.saleStartDateGmt } else { - storedProduct.value?.product?.saleStartDateGmt + storedProductAggregate.value?.product?.saleStartDateGmt }, downloads = downloads ?: product.downloads, downloadLimit = downloadLimit ?: product.downloadLimit, @@ -1411,7 +1411,7 @@ class ProductDetailViewModel @Inject constructor( mutex.withLock { val cards = cardBuilder.buildPropertyCards( productAggregate = productAggregate, - originalSku = storedProduct.value?.product?.sku ?: "" + originalSku = storedProductAggregate.value?.product?.sku ?: "" ) withContext(dispatchers.main) { _productDetailCards.value = cards @@ -1484,7 +1484,7 @@ class ProductDetailViewModel @Inject constructor( */ private fun trackProductDetailLoaded() { if (hasTrackedProductDetailLoaded.not()) { - storedProduct.value?.product?.let { product -> + storedProductAggregate.value?.product?.let { product -> launch { val properties = mapOf( AnalyticsTracker.KEY_HAS_LINKED_PRODUCTS to product.hasLinkedProducts(), @@ -1540,8 +1540,8 @@ class ProductDetailViewModel @Inject constructor( * then the visibility is `PRIVATE`, otherwise it's `PUBLIC`. */ fun getProductVisibility(): ProductVisibility { - val status = viewState.productDraft?.status ?: storedProduct.value?.product?.status - val password = viewState.draftPassword ?: storedProduct.value?.product?.password + val status = viewState.productDraft?.status ?: storedProductAggregate.value?.product?.status + val password = viewState.draftPassword ?: storedProductAggregate.value?.product?.password return when { password?.isNotEmpty() == true -> { ProductVisibility.PASSWORD_PROTECTED @@ -1564,11 +1564,11 @@ class ProductDetailViewModel @Inject constructor( val productPasswordApi = determineProductPasswordApi() val password = when (productPasswordApi) { ProductPasswordApi.WPCOM -> productRepository.fetchProductPassword(remoteProductId) - ProductPasswordApi.CORE -> storedProduct.value?.product?.password + ProductPasswordApi.CORE -> storedProductAggregate.value?.product?.password ProductPasswordApi.UNSUPPORTED -> return } - storedProduct.update { it?.copy(product = it.product.copy(password = password)) } + storedProductAggregate.update { it?.copy(product = it.product.copy(password = password)) } viewState = viewState.copy( productAggregateDraft = viewState.productAggregateDraft?.copy( product = viewState.productDraft!!.copy(password = viewState.draftPassword ?: password) @@ -1864,7 +1864,7 @@ class ProductDetailViewModel @Inject constructor( triggerEvent(ProductNavigationTarget.RenameProductAttribute(attributeName)) } - fun hasAttributeChanges() = storedProduct.value?.product?.hasAttributeChanges(viewState.productDraft) ?: false + fun hasAttributeChanges() = storedProductAggregate.value?.product?.hasAttributeChanges(viewState.productDraft) ?: false /** * Used by the add attribute screen to fetch the list of store-wide product attributes @@ -1966,12 +1966,12 @@ class ProductDetailViewModel @Inject constructor( val result = productRepository.updateProduct(product.copy(password = viewState.draftPassword)) if (result.first) { val successMsg = pickProductUpdateSuccessText(isPublish) - val isPasswordChanged = storedProduct.value?.product?.password != viewState.draftPassword + val isPasswordChanged = storedProductAggregate.value?.product?.password != viewState.draftPassword if (isPasswordChanged && determineProductPasswordApi() == ProductPasswordApi.WPCOM) { // Update the product password using WordPress.com API val password = viewState.productDraft?.password if (productRepository.updateProductPassword(product.remoteId, password)) { - storedProduct.update { it?.copy(product = it.product.copy(password = password)) } + storedProductAggregate.update { it?.copy(product = it.product.copy(password = password)) } triggerEvent(ShowSnackbar(successMsg)) } else { triggerEvent(ShowSnackbar(R.string.product_detail_update_product_password_error)) @@ -2074,7 +2074,7 @@ class ProductDetailViewModel @Inject constructor( private fun updateProductState(productToUpdateFrom: Product) { val updatedDraft = viewState.productDraft?.let { currentDraft -> - if (storedProduct.value?.product?.isSameProduct(currentDraft) == true) { + if (storedProductAggregate.value?.product?.isSameProduct(currentDraft) == true) { productToUpdateFrom } else { productToUpdateFrom.mergeProduct(currentDraft) @@ -2085,7 +2085,7 @@ class ProductDetailViewModel @Inject constructor( viewState = viewState.copy(productDraft = updatedDraft) .copy(auxiliaryState = ProductDetailViewState.AuxiliaryState.None) - storedProduct.update { it?.copy(product = updatedDraft) } + storedProductAggregate.update { it?.copy(product = updatedDraft) ?: ProductAggregate(updatedDraft) } } private fun loadProductTaxAndShippingClassDependencies(product: Product) { @@ -2588,7 +2588,7 @@ class ProductDetailViewModel @Inject constructor( } private fun hasSubscriptionExpirationChanges(): Boolean { - return storedProduct.value?.subscription?.length != viewState.subscriptionDraft?.length + return storedProductAggregate.value?.subscription?.length != viewState.subscriptionDraft?.length } fun onProductCategorySearchQueryChanged(query: String) { @@ -2695,12 +2695,12 @@ class ProductDetailViewModel @Inject constructor( /** * [productDraft] is used for the UI. Any updates to the fields in the UI would update this model. - * [storedProduct.value] is the [Product] model that is fetched from the API and available in the local db. + * [storedProductAggregate.value] is the [Product] model that is fetched from the API and available in the local db. * This is read only and is not updated in any way. It is used in the product detail screen, to check * if we need to display the UPDATE menu button (which is only displayed if there are changes made to * any of the product fields). * - * When the user first enters the product detail screen, the [productDraft] and [storedProduct.value] are the same. + * When the user first enters the product detail screen, the [productDraft] and [storedProductAggregate.value] are the same. * When a change is made to the product in the UI, the [productDraft] model is updated with whatever change * has been made in the UI. */ @@ -2725,7 +2725,7 @@ class ProductDetailViewModel @Inject constructor( fun copy(productDraft: Product?) = copy( productAggregateDraft = productDraft?.let { - productAggregateDraft?.copy(product = it) + productAggregateDraft?.copy(product = it) ?: ProductAggregate(product = it) } ) From 9fa672a21d03945f68c6faddaf5bb7b032a57100 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Tue, 8 Oct 2024 11:31:05 +0100 Subject: [PATCH 106/162] Introduce an overload to the subscription details mapper --- .../model/SubscriptionDetailsMapper.kt | 122 +++++++++--------- 1 file changed, 59 insertions(+), 63 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetailsMapper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetailsMapper.kt index 8253ebbc68d..28aa2a340ca 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetailsMapper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetailsMapper.kt @@ -1,77 +1,73 @@ package com.woocommerce.android.model import com.google.gson.Gson -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonObject +import com.google.gson.JsonParser import org.wordpress.android.fluxc.model.WCProductModel.SubscriptionMetadataKeys import org.wordpress.android.fluxc.model.metadata.WCMetaData +import org.wordpress.android.fluxc.model.metadata.get object SubscriptionDetailsMapper { private val gson by lazy { Gson() } - fun toAppModel(metadata: String): SubscriptionDetails? { - val jsonArray = gson.fromJson(metadata, JsonArray::class.java) ?: return null + fun toAppModel(metadata: List): SubscriptionDetails? { + if (metadata.none { it.key in SubscriptionMetadataKeys.ALL_KEYS }) { + return null + } - val subscriptionInformation = jsonArray - .mapNotNull { it as? JsonObject } - .filter { jsonObject -> jsonObject[WCMetaData.KEY].asString in SubscriptionMetadataKeys.ALL_KEYS } - .associate { jsonObject -> - jsonObject[WCMetaData.KEY].asString to jsonObject[WCMetaData.VALUE] - } + val price = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_PRICE]?.valueAsString?.toBigDecimalOrNull() - return if (subscriptionInformation.isNotEmpty()) { - val price = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_PRICE]?.asString - ?.toBigDecimalOrNull() - - val periodString = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD]?.asString ?: "" - val period = SubscriptionPeriod.fromValue(periodString) - - val periodIntervalString = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD_INTERVAL] - ?.asString ?: "" - val periodInterval = periodIntervalString.toIntOrNull() ?: 0 - - val lengthInt = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_LENGTH]?.asString - ?.toIntOrNull() - val length = if (lengthInt != null && lengthInt > 0) lengthInt else null - - val signUpFee = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_SIGN_UP_FEE]?.asString - ?.toBigDecimalOrNull() - - val trialPeriodString = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_PERIOD] - ?.asString - val trialPeriod = trialPeriodString?.let { SubscriptionPeriod.fromValue(trialPeriodString) } - - val trialLengthInt = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_LENGTH] - ?.asString?.toIntOrNull() - val trialLength = if (trialLengthInt != null && trialLengthInt > 0) trialLengthInt else null - - val oneTimeShipping = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_ONE_TIME_SHIPPING] - ?.asString == "yes" - - val paymentsSyncDate = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_PAYMENT_SYNC_DATE] - ?.extractPaymentsSyncDate() - - SubscriptionDetails( - price = price, - period = period, - periodInterval = periodInterval, - length = length, - signUpFee = signUpFee, - trialPeriod = trialPeriod, - trialLength = trialLength, - oneTimeShipping = oneTimeShipping, - paymentsSyncDate = paymentsSyncDate - ) - } else { - null - } + val periodString = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD]?.valueAsString ?: "" + val period = SubscriptionPeriod.fromValue(periodString) + + val periodIntervalString = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD_INTERVAL] + ?.valueAsString ?: "" + val periodInterval = periodIntervalString.toIntOrNull() ?: 0 + + val lengthInt = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_LENGTH]?.valueAsString + ?.toIntOrNull() + val length = if (lengthInt != null && lengthInt > 0) lengthInt else null + + val signUpFee = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_SIGN_UP_FEE]?.valueAsString + ?.toBigDecimalOrNull() + + val trialPeriodString = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_PERIOD] + ?.valueAsString + val trialPeriod = trialPeriodString?.let { SubscriptionPeriod.fromValue(trialPeriodString) } + + val trialLengthInt = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_LENGTH] + ?.valueAsString?.toIntOrNull() + val trialLength = if (trialLengthInt != null && trialLengthInt > 0) trialLengthInt else null + + val oneTimeShipping = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_ONE_TIME_SHIPPING] + ?.valueAsString == "yes" + + val paymentsSyncDate = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_PAYMENT_SYNC_DATE] + ?.extractPaymentsSyncDate() + + return SubscriptionDetails( + price = price, + period = period, + periodInterval = periodInterval, + length = length, + signUpFee = signUpFee, + trialPeriod = trialPeriod, + trialLength = trialLength, + oneTimeShipping = oneTimeShipping, + paymentsSyncDate = paymentsSyncDate + ) + } + + fun toAppModel(metadata: String): SubscriptionDetails? { + val metadataList = gson.fromJson(metadata, Array::class.java)?.toList() ?: return null + + return toAppModel(metadataList) } - private fun JsonElement.extractPaymentsSyncDate(): SubscriptionPaymentSyncDate? { - return when { - isJsonObject -> asJsonObject.let { - val day = it["day"].asInt - val month = it["month"].asInt + private fun WCMetaData.extractPaymentsSyncDate(): SubscriptionPaymentSyncDate? { + return when(isJson) { + true -> value.stringValue.let { + val jsonObject = JsonParser.parseString(it).asJsonObject + val day = jsonObject["day"].asInt + val month = jsonObject["month"].asInt if (day == 0) { SubscriptionPaymentSyncDate.None } else { @@ -79,7 +75,7 @@ object SubscriptionDetailsMapper { } } - else -> asString?.toIntOrNull()?.let { day -> + false -> valueAsString.toIntOrNull()?.let { day -> if (day == 0) { SubscriptionPaymentSyncDate.None } else { From a830f55dfba810cb20eb1dd201b42815b407a6d9 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Tue, 8 Oct 2024 12:22:08 +0100 Subject: [PATCH 107/162] Update logic to fetch and use ProductAggregate --- .../android/model/ProductAggregate.kt | 10 +++++ .../details/ProductDetailRepository.kt | 19 ++++++++ .../details/ProductDetailViewModel.kt | 45 ++++++++++--------- 3 files changed, 52 insertions(+), 22 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductAggregate.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductAggregate.kt index a1fb491cb4f..96721b7b980 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductAggregate.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductAggregate.kt @@ -16,10 +16,20 @@ data class ProductAggregate( val product: Product, val subscription: SubscriptionDetails? = null ) : Parcelable { + val remoteId: Long + get() = product.remoteId + val hasShipping: Boolean get() = product.hasShipping || subscription?.oneTimeShipping == true fun isSame(other: ProductAggregate): Boolean { return product.isSameProduct(other.product) && subscription == other.subscription } + + fun merge(other: ProductAggregate): ProductAggregate { + return copy( + product = product.mergeProduct(other.product), + subscription = other.subscription + ) + } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailRepository.kt index 8605bebf736..d0b38a1dee9 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailRepository.kt @@ -5,11 +5,13 @@ import com.woocommerce.android.analytics.AnalyticsEvent.PRODUCT_DETAIL_UPDATE_ER import com.woocommerce.android.analytics.AnalyticsEvent.PRODUCT_DETAIL_UPDATE_SUCCESS import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.model.Product +import com.woocommerce.android.model.ProductAggregate import com.woocommerce.android.model.ProductAttribute import com.woocommerce.android.model.ProductAttributeTerm import com.woocommerce.android.model.ProductGlobalAttribute import com.woocommerce.android.model.RequestResult import com.woocommerce.android.model.ShippingClass +import com.woocommerce.android.model.SubscriptionDetailsMapper import com.woocommerce.android.model.TaxClass import com.woocommerce.android.model.toAppModel import com.woocommerce.android.model.toDataModel @@ -90,6 +92,17 @@ class ProductDetailRepository @Inject constructor( return getProduct(remoteProductId) } + suspend fun fetchAndGetProductAggregate(remoteProductId: Long): ProductAggregate? { + val payload = WCProductStore.FetchSingleProductPayload(selectedSite.get(), remoteProductId) + val result = productStore.fetchSingleProduct(payload) + + if (result.isError) { + lastFetchProductErrorType = result.error.type + } + + return getProductAggregate(remoteProductId) + } + suspend fun fetchProductPassword(remoteProductId: Long): String? { this.remoteProductId = remoteProductId val result = continuationFetchProductPassword.callAndWaitUntilTimeout(AppConstants.REQUEST_TIMEOUT) { @@ -276,6 +289,12 @@ class ProductDetailRepository @Inject constructor( getCachedWCProductModel(remoteProductId)?.toAppModel() } + suspend fun getProductAggregate(remoteProductId: Long): ProductAggregate? { + val product = getProduct(remoteProductId) ?: return null + val subscriptionDetails = SubscriptionDetailsMapper.toAppModel(getProductMetadata(remoteProductId)) + return ProductAggregate(product, subscriptionDetails) + } + fun isSkuAvailableLocally(sku: String) = !productStore.geProductExistsBySku(selectedSite.get(), sku) fun getCachedVariationCount(remoteProductId: Long) = diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt index e537d9e6175..75cd3198e1c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt @@ -444,31 +444,30 @@ class ProductDetailViewModel @Inject constructor( private fun startAddNewProduct() { val defaultProduct = createDefaultProductForAddFlow() viewState = viewState.copy( - productDraft = defaultProduct + productAggregateDraft = defaultProduct ) updateProductState(defaultProduct) trackProductDetailLoaded() } - private fun createDefaultProductForAddFlow(): Product { + private fun createDefaultProductForAddFlow(): ProductAggregate { val preferredSavedType = appPrefsWrapper.getSelectedProductType() val defaultProductType = ProductType.fromString(preferredSavedType) val isProductVirtual = appPrefsWrapper.isSelectedProductVirtual() - return ProductHelper.getDefaultNewProduct(defaultProductType, isProductVirtual) + return ProductAggregate(ProductHelper.getDefaultNewProduct(defaultProductType, isProductVirtual)) } private fun initializeStoredProductAfterRestoration() { - // TODO: fetch subscription details launch { if (isAddNewProductFlow && !isProductStoredAtSite) { - storedProductAggregate.value = ProductAggregate(createDefaultProductForAddFlow(), null) + storedProductAggregate.value = createDefaultProductForAddFlow() } else { when (val mode = navArgs.mode) { is ProductDetailFragment.Mode.ShowProduct -> { - productRepository.getProductAsync( + productRepository.getProductAggregate( viewState.productDraft?.remoteId ?: mode.remoteProductId )?.let { - storedProductAggregate.value = ProductAggregate(it, null) + storedProductAggregate.value = it } } @@ -686,7 +685,7 @@ class ProductDetailViewModel @Inject constructor( when (variationRepository.bulkCreateVariations(remoteProductId, variationCandidates)) { RequestResult.SUCCESS -> { tracker.track(AnalyticsEvent.PRODUCT_VARIATION_GENERATION_SUCCESS) - productRepository.fetchAndGetProduct(remoteProductId) + productRepository.fetchAndGetProductAggregate(remoteProductId) ?.also { updateProductState(productToUpdateFrom = it) } triggerEvent(ProductExitEvent.ExitAttributesAdded) } @@ -709,7 +708,7 @@ class ProductDetailViewModel @Inject constructor( ) variationRepository.createEmptyVariation(draft) ?.let { - productRepository.fetchAndGetProduct(draft.remoteId) + productRepository.fetchAndGetProductAggregate(draft.remoteId) ?.also { updateProductState(productToUpdateFrom = it) } } }.also { @@ -1461,13 +1460,13 @@ class ProductDetailViewModel @Inject constructor( launch { // fetch product - val productInDb = productRepository.getProductAsync(remoteProductId) - if (productInDb != null) { + val productAggregateInDb = productRepository.getProductAggregate(remoteProductId) + if (productAggregateInDb != null) { val shouldFetch = remoteProductId != getRemoteProductId() - updateProductState(productInDb) + updateProductState(productAggregateInDb) val cachedVariationCount = productRepository.getCachedVariationCount(remoteProductId) - if (shouldFetch || cachedVariationCount != productInDb.numVariations) { + if (shouldFetch || cachedVariationCount != productAggregateInDb.product.numVariations) { fetchProduct(remoteProductId) fetchProductPassword(remoteProductId) } @@ -1578,7 +1577,7 @@ class ProductDetailViewModel @Inject constructor( private suspend fun fetchProduct(remoteProductId: Long) { if (checkConnection()) { - val fetchedProduct = productRepository.fetchAndGetProduct(remoteProductId) + val fetchedProduct = productRepository.fetchAndGetProductAggregate(remoteProductId) if (fetchedProduct != null) { updateProductState(fetchedProduct) } else { @@ -2072,20 +2071,22 @@ class ProductDetailViewModel @Inject constructor( productRepository.getProductShippingClassByRemoteId(remoteShippingClassId)?.name ?: viewState.productDraft?.shippingClass ?: "" - private fun updateProductState(productToUpdateFrom: Product) { - val updatedDraft = viewState.productDraft?.let { currentDraft -> - if (storedProductAggregate.value?.product?.isSameProduct(currentDraft) == true) { + private fun updateProductState(productToUpdateFrom: ProductAggregate) { + val updatedDraft = viewState.productAggregateDraft?.let { currentDraft -> + if (storedProductAggregate.value?.isSame(currentDraft) == true) { productToUpdateFrom } else { - productToUpdateFrom.mergeProduct(currentDraft) + productToUpdateFrom.merge(currentDraft) } } ?: productToUpdateFrom - loadProductTaxAndShippingClassDependencies(updatedDraft) + loadProductTaxAndShippingClassDependencies(updatedDraft.product) - viewState = viewState.copy(productDraft = updatedDraft) - .copy(auxiliaryState = ProductDetailViewState.AuxiliaryState.None) - storedProductAggregate.update { it?.copy(product = updatedDraft) ?: ProductAggregate(updatedDraft) } + viewState = viewState.copy( + productAggregateDraft = updatedDraft, + auxiliaryState = ProductDetailViewState.AuxiliaryState.None + ) + storedProductAggregate.value = productToUpdateFrom } private fun loadProductTaxAndShippingClassDependencies(product: Product) { From 0335cf279bdfa182a2e94856763f1954bb239db2 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Tue, 8 Oct 2024 12:34:27 +0100 Subject: [PATCH 108/162] Add logic for creating the default product aggregate --- .../android/ui/products/ProductHelper.kt | 22 ++++++++++++------- .../details/ProductDetailViewModel.kt | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductHelper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductHelper.kt index e11a2a84264..592ad2f4b6f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductHelper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductHelper.kt @@ -1,14 +1,13 @@ package com.woocommerce.android.ui.products import com.woocommerce.android.model.Product +import com.woocommerce.android.model.ProductAggregate import com.woocommerce.android.model.SubscriptionDetails import com.woocommerce.android.model.SubscriptionPeriod import com.woocommerce.android.ui.products.ProductBackorderStatus.NotAvailable import com.woocommerce.android.ui.products.ProductStatus.DRAFT import com.woocommerce.android.ui.products.ProductStatus.PUBLISH import com.woocommerce.android.ui.products.ProductStockStatus.InStock -import com.woocommerce.android.ui.products.ProductType.SUBSCRIPTION -import com.woocommerce.android.ui.products.ProductType.VARIABLE_SUBSCRIPTION import com.woocommerce.android.ui.products.settings.ProductCatalogVisibility.VISIBLE import java.math.BigDecimal import java.util.Date @@ -93,12 +92,6 @@ object ProductHelper { variationIds = listOf(), downloads = listOf(), isPurchasable = false, - subscription = - if (productType == SUBSCRIPTION || productType == VARIABLE_SUBSCRIPTION) { - getDefaultSubscriptionDetails() - } else { - null - }, isSampleProduct = false, parentId = 0, minAllowedQuantity = null, @@ -111,6 +104,19 @@ object ProductHelper { ) } + fun getDefaultProductAggregate(productType: ProductType, isVirtual: Boolean): ProductAggregate { + return ProductAggregate( + product = getDefaultNewProduct(productType, isVirtual), + subscription = if (productType == ProductType.SUBSCRIPTION || + productType == ProductType.VARIABLE_SUBSCRIPTION + ) { + getDefaultSubscriptionDetails() + } else { + null + } + ) + } + fun getDefaultSubscriptionDetails(): SubscriptionDetails = SubscriptionDetails( price = null, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt index 75cd3198e1c..4e7171ff566 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt @@ -454,7 +454,7 @@ class ProductDetailViewModel @Inject constructor( val preferredSavedType = appPrefsWrapper.getSelectedProductType() val defaultProductType = ProductType.fromString(preferredSavedType) val isProductVirtual = appPrefsWrapper.isSelectedProductVirtual() - return ProductAggregate(ProductHelper.getDefaultNewProduct(defaultProductType, isProductVirtual)) + return ProductHelper.getDefaultProductAggregate(defaultProductType, isProductVirtual) } private fun initializeStoredProductAfterRestoration() { From 5b5137447321c85cfb682180dbbabb8f31036133 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Tue, 8 Oct 2024 12:42:01 +0100 Subject: [PATCH 109/162] Remove the subscription property of the Product model --- .../com/woocommerce/android/model/Product.kt | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Product.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Product.kt index c27fc2aac06..3fb096e1335 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Product.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Product.kt @@ -83,7 +83,6 @@ data class Product( override val width: Float, override val height: Float, override val weight: Float, - val subscription: SubscriptionDetails?, val isSampleProduct: Boolean, val specialStockStatus: ProductStockStatus? = null, val isConfigurable: Boolean = false, @@ -153,7 +152,6 @@ data class Product( downloadExpiry == product.downloadExpiry && isDownloadable == product.isDownloadable && attributes == product.attributes && - subscription == product.subscription && specialStockStatus == product.specialStockStatus && minAllowedQuantity == product.minAllowedQuantity && maxAllowedQuantity == product.maxAllowedQuantity && @@ -169,8 +167,7 @@ data class Product( get() { return weight > 0 || length > 0 || width > 0 || height > 0 || - shippingClass.isNotEmpty() || - subscription?.oneTimeShipping == true + shippingClass.isNotEmpty() } val productType get() = ProductType.fromString(type) val variationEnabledAttributes @@ -334,7 +331,6 @@ data class Product( downloads = updatedProduct.downloads, downloadLimit = updatedProduct.downloadLimit, downloadExpiry = updatedProduct.downloadExpiry, - subscription = updatedProduct.subscription, specialStockStatus = specialStockStatus, minAllowedQuantity = updatedProduct.minAllowedQuantity, maxAllowedQuantity = updatedProduct.maxAllowedQuantity, @@ -482,20 +478,10 @@ fun Product.toDataModel(storedProductModel: WCProductModel? = null): WCProductMo it.groupOfQuantity = groupOfQuantity ?: -1 it.combineVariationQuantities = combineVariationQuantities ?: false it.password = password - // Subscription details are currently the only editable metadata fields from the app. - it.metadata = subscription?.toMetadataJson().toString() } } fun WCProductModel.toAppModel(): Product { - val productType = ProductType.fromString(type) - val subscription = if ( - productType == ProductType.SUBSCRIPTION || productType == ProductType.VARIABLE_SUBSCRIPTION - ) { - SubscriptionDetailsMapper.toAppModel(this.metadata) - } else { - null - } return Product( remoteId = this.remoteProductId, parentId = this.parentId, @@ -580,7 +566,6 @@ fun WCProductModel.toAppModel(): Product { upsellProductIds = this.getUpsellProductIdList(), variationIds = this.getVariationIdList(), isPurchasable = this.purchasable, - subscription = subscription, isSampleProduct = isSampleProduct, specialStockStatus = if (this.specialStockStatus.isNotNullOrEmpty()) { ProductStockStatus.fromString(this.specialStockStatus) From b210d2ba9a36bda94606211c271dc9a38410b85c Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Tue, 8 Oct 2024 15:36:41 +0100 Subject: [PATCH 110/162] Bump fluxc --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cf6ae22a421..9726defb013 100644 --- a/build.gradle +++ b/build.gradle @@ -100,7 +100,7 @@ tasks.register("installGitHooks", Copy) { } ext { - fluxCVersion = 'trunk-7ad6ce4c250ba435d8d8c7feb898bceb259fb007' + fluxCVersion = '3106-5dd2a279d69ec6dbf4fd6d29c924383d809ad5ed' glideVersion = '4.16.0' coilVersion = '2.1.0' constraintLayoutVersion = '1.2.0' From 34cb39a2f84f1474f5dab37c01511b99a8f1d029 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Tue, 8 Oct 2024 15:36:53 +0100 Subject: [PATCH 111/162] Fix unit tests --- .../products/SubscriptionDetailsMapperTest.kt | 176 ++++---- .../ProductDetailBottomSheetBuilderTest.kt | 7 +- .../details/ProductDetailCardBuilderTest.kt | 13 +- ...etailViewModelGenerateVariationFlowTest.kt | 3 +- .../details/ProductDetailViewModelTest.kt | 388 +++++++++--------- .../ProductDetailViewModel_AddFlowTest.kt | 13 +- 6 files changed, 305 insertions(+), 295 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/SubscriptionDetailsMapperTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/SubscriptionDetailsMapperTest.kt index 4afa07daed4..5639c0606df 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/SubscriptionDetailsMapperTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/SubscriptionDetailsMapperTest.kt @@ -8,11 +8,11 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import org.assertj.core.api.Assertions.assertThat import org.junit.Test import org.wordpress.android.fluxc.model.WCProductModel +import org.wordpress.android.fluxc.model.metadata.WCMetaData import java.math.BigDecimal @OptIn(ExperimentalCoroutinesApi::class) class SubscriptionDetailsMapperTest : BaseUnitTest() { - @Test fun `when metadata is valid then a SubscriptionDetails is returned`() { val result = SubscriptionDetailsMapper.toAppModel(successMetadata) @@ -112,77 +112,74 @@ class SubscriptionDetailsMapperTest : BaseUnitTest() { * trialLength = 2, * oneTimeShipping = yes */ - private val successMetadata = """ [ { - "id": 5182, - "key": "_subscription_payment_sync_date", - "value": "0" - }, - { - "id": 5183, - "key": "_subscription_price", - "value": "60" - }, - { - "id": 5187, - "key": "_subscription_trial_length", - "value": "2" - }, - { - "id": 5188, - "key": "_subscription_sign_up_fee", - "value": "5" - }, - { - "id": 5189, - "key": "_subscription_period", - "value": "month" - }, - { - "id": 5190, - "key": "_subscription_period_interval", - "value": "1" - }, - { - "id": 5191, - "key": "_subscription_length", - "value": "0" - }, - { - "id": 5192, - "key": "_subscription_trial_period", - "value": "day" - }, - { - "id": 5193, - "key": "_subscription_limit", - "value": "no" - }, - { - "id": 5194, - "key": "_subscription_one_time_shipping", - "value": "yes" - } ] - """ + private val successMetadata = listOf( + WCMetaData( + id = 5182, + key = WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_PAYMENT_SYNC_DATE, + value = "0" + ), + WCMetaData( + id = 5183, + key = WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_PRICE, + value = "60" + ), + WCMetaData( + id = 5187, + key = WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_LENGTH, + value = "2" + ), + WCMetaData( + id = 5188, + key = WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_SIGN_UP_FEE, + value = "5" + ), + WCMetaData( + id = 5189, + key = WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD, + value = "month" + ), + WCMetaData( + id = 5190, + key = WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD_INTERVAL, + value = "1" + ), + WCMetaData( + id = 5191, + key = WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_LENGTH, + value = "0" + ), + WCMetaData( + id = 5192, + key = WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_PERIOD, + value = "day" + ), + WCMetaData( + id = 5194, + key = WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_ONE_TIME_SHIPPING, + value = "yes" + ) + ) /** * Metadata with no subscription key */ - private val noSubscriptionKeysMetadata = """ [ { - "id": 5182, - "key": "sync_date", - "value": "0" - }, - { - "id": 5183, - "key": "price", - "value": "60" - }, - { - "id": 5187, - "key": "trial_length", - "value": "2" - }] - """ + private val noSubscriptionKeysMetadata = listOf( + WCMetaData( + id = 5182, + key = "sync_date", + value = "0" + ), + WCMetaData( + id = 5183, + key = "price", + value = "60" + ), + WCMetaData( + id = 5187, + key = "trial_length", + value = "2" + ) + ) /** * price = 60, @@ -194,25 +191,26 @@ class SubscriptionDetailsMapperTest : BaseUnitTest() { * trialLength = 2, * oneTimeShipping = */ - private val successMetadataPartial = """ [ { - "id": 5182, - "key": "_subscription_payment_sync_date", - "value": "0" - }, - { - "id": 5183, - "key": "_subscription_price", - "value": "60" - }, - { - "id": 5187, - "key": "_subscription_trial_length", - "value": "2" - }, - { - "id": 5188, - "key": "_subscription_sign_up_fee", - "value": "5" - }] - """ + private val successMetadataPartial = listOf( + WCMetaData( + id = 5182, + key = WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_PAYMENT_SYNC_DATE, + value = "0" + ), + WCMetaData( + id = 5183, + key = WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_PRICE, + value = "60" + ), + WCMetaData( + id = 5187, + key = WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_LENGTH, + value = "2" + ), + WCMetaData( + id = 5188, + key = WCProductModel.SubscriptionMetadataKeys.SUBSCRIPTION_SIGN_UP_FEE, + value = "5" + ) + ) } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailBottomSheetBuilderTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailBottomSheetBuilderTest.kt index 4486a5316cc..ebcf167f9dc 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailBottomSheetBuilderTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailBottomSheetBuilderTest.kt @@ -1,5 +1,6 @@ package com.woocommerce.android.ui.products.details +import com.woocommerce.android.model.ProductAggregate import com.woocommerce.android.ui.customfields.CustomFieldsRepository import com.woocommerce.android.ui.products.ProductNavigationTarget import com.woocommerce.android.ui.products.ProductTestUtils @@ -39,7 +40,7 @@ class ProductDetailBottomSheetBuilderTest : BaseUnitTest() { whenever(customFieldsRepository.hasDisplayableCustomFields(any())).thenReturn(true) val product = ProductTestUtils.generateProduct(productId = 1L) - val result = sut.buildBottomSheetList(product) + val result = sut.buildBottomSheetList(ProductAggregate(product)) assertThat(result).noneMatch { it.type == ProductDetailBottomSheetBuilder.ProductDetailBottomSheetType.CUSTOM_FIELDS @@ -51,7 +52,7 @@ class ProductDetailBottomSheetBuilderTest : BaseUnitTest() { whenever(customFieldsRepository.hasDisplayableCustomFields(any())).thenReturn(false) val product = ProductTestUtils.generateProduct(productId = 1L) - val result = sut.buildBottomSheetList(product) + val result = sut.buildBottomSheetList(ProductAggregate(product)) val customFieldsItem = result.single { it.type == ProductDetailBottomSheetBuilder.ProductDetailBottomSheetType.CUSTOM_FIELDS @@ -62,7 +63,7 @@ class ProductDetailBottomSheetBuilderTest : BaseUnitTest() { @Test fun `when product is not saved in server, then hide the custom fields item`() = testBlocking { val product = ProductTestUtils.generateProduct(productId = ProductDetailViewModel.DEFAULT_ADD_NEW_PRODUCT_ID) - val result = sut.buildBottomSheetList(product) + val result = sut.buildBottomSheetList(ProductAggregate(product)) assertThat(result).noneMatch { it.type == ProductDetailBottomSheetBuilder.ProductDetailBottomSheetType.CUSTOM_FIELDS diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailCardBuilderTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailCardBuilderTest.kt index 68a7b2e49ac..fd46cdc4549 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailCardBuilderTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailCardBuilderTest.kt @@ -2,6 +2,7 @@ package com.woocommerce.android.ui.products.details import com.woocommerce.android.R import com.woocommerce.android.model.Product +import com.woocommerce.android.model.ProductAggregate import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.blaze.IsBlazeEnabled import com.woocommerce.android.ui.customfields.CustomFieldsRepository @@ -83,7 +84,7 @@ class ProductDetailCardBuilderTest : BaseUnitTest() { height = 0F ) - val cards = sut.buildPropertyCards(productStub, "") + val cards = sut.buildPropertyCards(ProductAggregate(productStub), "") Assertions.assertThat(cards).isNotEmpty cards.find { it.type == ProductPropertyCard.Type.SECONDARY } @@ -110,7 +111,7 @@ class ProductDetailCardBuilderTest : BaseUnitTest() { ) var foundAttributesCard = false - val cards = sut.buildPropertyCards(productStub, "") + val cards = sut.buildPropertyCards(ProductAggregate(productStub), "") Assertions.assertThat(cards).isNotEmpty cards.find { it.type == ProductPropertyCard.Type.SECONDARY } @@ -134,7 +135,7 @@ class ProductDetailCardBuilderTest : BaseUnitTest() { ) var foundQuantityRulesCard = false - val cards = sut.buildPropertyCards(productStub, "") + val cards = sut.buildPropertyCards(ProductAggregate(productStub), "") Assertions.assertThat(cards).isNotEmpty cards.find { it.type == ProductPropertyCard.Type.SECONDARY } @@ -156,7 +157,7 @@ class ProductDetailCardBuilderTest : BaseUnitTest() { whenever(customFieldsRepository.hasDisplayableCustomFields(any())) doReturn false productStub = ProductTestUtils.generateProduct(productId = 1L) - val cards = sut.buildPropertyCards(productStub, "") + val cards = sut.buildPropertyCards(ProductAggregate(productStub), "") val properties = cards.first { it.type == ProductPropertyCard.Type.SECONDARY }.properties val customFieldsCard = properties.find { @@ -171,7 +172,7 @@ class ProductDetailCardBuilderTest : BaseUnitTest() { whenever(customFieldsRepository.hasDisplayableCustomFields(any())) doReturn true productStub = ProductTestUtils.generateProduct(productId = 1L) - val cards = sut.buildPropertyCards(productStub, "") + val cards = sut.buildPropertyCards(ProductAggregate(productStub), "") val properties = cards.first { it.type == ProductPropertyCard.Type.SECONDARY }.properties val customFieldsCard = properties.find { @@ -184,7 +185,7 @@ class ProductDetailCardBuilderTest : BaseUnitTest() { @Test fun `when a new is not saved on the server, then hide the custom fields card`() = testBlocking { productStub = ProductTestUtils.generateProduct(productId = ProductDetailViewModel.DEFAULT_ADD_NEW_PRODUCT_ID) - val cards = sut.buildPropertyCards(productStub, "") + val cards = sut.buildPropertyCards(ProductAggregate(productStub), "") val properties = cards.first { it.type == ProductPropertyCard.Type.SECONDARY }.properties val customFieldsCard = properties.find { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModelGenerateVariationFlowTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModelGenerateVariationFlowTest.kt index c2917f0d18a..72e062fef57 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModelGenerateVariationFlowTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModelGenerateVariationFlowTest.kt @@ -7,6 +7,7 @@ import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.media.MediaFilesRepository import com.woocommerce.android.media.ProductImagesServiceWrapper +import com.woocommerce.android.model.ProductAggregate import com.woocommerce.android.model.RequestResult import com.woocommerce.android.model.VariantOption import com.woocommerce.android.tools.NetworkStatus @@ -92,7 +93,7 @@ class ProductDetailViewModelGenerateVariationFlowTest : BaseUnitTest() { doReturn(true).whenever(networkStatus).isConnected() productRepository = mock { - onBlocking { fetchAndGetProduct(PRODUCT_REMOTE_ID) } doReturn product + onBlocking { fetchAndGetProductAggregate(PRODUCT_REMOTE_ID) } doReturn ProductAggregate(product) } variationRepository = mock { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModelTest.kt index 259f9869833..2439f10ef1a 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModelTest.kt @@ -8,6 +8,7 @@ import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.extensions.takeIfNotEqualTo import com.woocommerce.android.media.MediaFilesRepository import com.woocommerce.android.media.ProductImagesServiceWrapper +import com.woocommerce.android.model.ProductAggregate import com.woocommerce.android.model.ProductAttribute import com.woocommerce.android.model.ProductVariation import com.woocommerce.android.tools.NetworkStatus @@ -124,7 +125,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { private val prefsWrapper: AppPrefsWrapper = mock() private val productUtils = ProductUtils() - private val product = ProductTestUtils.generateProduct(PRODUCT_REMOTE_ID) + private val productAggregate = ProductAggregate(ProductTestUtils.generateProduct(PRODUCT_REMOTE_ID)) private val productWithTagsAndCategories = ProductTestUtils.generateProductWithTagsAndCategories(PRODUCT_REMOTE_ID) private val offlineProduct = ProductTestUtils.generateProduct(OFFLINE_PRODUCT_REMOTE_ID) private val productCategories = ProductTestUtils.generateProductCategories() @@ -141,7 +142,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { } private val productWithParameters = ProductDetailViewModel.ProductDetailViewState( - productDraft = product, + productAggregateDraft = productAggregate, auxiliaryState = ProductDetailViewModel.ProductDetailViewState.AuxiliaryState.None, uploadingImageUris = emptyList(), showBottomSheetButton = true, @@ -152,8 +153,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { ProductPropertyCard( type = ProductPropertyCard.Type.PRIMARY, properties = listOf( - ProductProperty.Editable(R.string.product_detail_title_hint, product.name), - ProductProperty.ComplexProperty(R.string.product_description, product.description) + ProductProperty.Editable(R.string.product_detail_title_hint, productAggregate.product.name), + ProductProperty.ComplexProperty(R.string.product_description, productAggregate.product.description) ) ), ProductPropertyCard( @@ -181,8 +182,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { ), ProductProperty.RatingBar( R.string.product_reviews, - resources.getString(R.string.product_ratings_count, product.ratingCount), - product.averageRating, + resources.getString(R.string.product_ratings_count, productAggregate.product.ratingCount), + productAggregate.product.averageRating, R.drawable.ic_reviews ), ProductProperty.PropertyGroup( @@ -227,7 +228,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { ), ProductProperty.ComplexProperty( R.string.product_short_description, - product.shortDescription, + productAggregate.product.shortDescription, R.drawable.ic_gridicons_align_left ), ProductProperty.ComplexProperty( @@ -296,7 +297,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Displays the product detail properties correctly`() = testBlocking { doReturn(true).whenever(networkStatus).isConnected() - doReturn(productWithTagsAndCategories).whenever(productRepository).getProductAsync(any()) + doReturn(ProductAggregate(productWithTagsAndCategories)).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } @@ -312,8 +313,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Displays the product detail view correctly`() = testBlocking { - doReturn(product).whenever(productRepository).getProductAsync(any()) - doReturn(product).whenever(productRepository).fetchAndGetProduct(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) + doReturn(productAggregate).whenever(productRepository).fetchAndGetProductAggregate(any()) var productData: ProductDetailViewModel.ProductDetailViewState? = null viewModel.productDetailViewStateData.observeForever { _, new -> productData = new } @@ -325,12 +326,12 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `given nothing returned from repo, when view model started, the error status emitted`() = testBlocking { - whenever(productRepository.fetchAndGetProduct(PRODUCT_REMOTE_ID)).thenReturn(null) - whenever(productRepository.getProductAsync(PRODUCT_REMOTE_ID)).thenReturn(null) + whenever(productRepository.fetchAndGetProductAggregate(PRODUCT_REMOTE_ID)).thenReturn(null) + whenever(productRepository.getProductAggregate(PRODUCT_REMOTE_ID)).thenReturn(null) viewModel.start() - verify(productRepository, times(1)).fetchAndGetProduct(PRODUCT_REMOTE_ID) + verify(productRepository, times(1)).fetchAndGetProductAggregate(PRODUCT_REMOTE_ID) Assertions.assertThat(viewModel.getProduct().productDraft).isNull() Assertions.assertThat(viewModel.getProduct().auxiliaryState).isEqualTo( @@ -343,15 +344,15 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `given nothing returned from repo with INVALID_PRODUCT_ID error, when view model started, the error status emitted with invalid id text`() = testBlocking { - whenever(productRepository.fetchAndGetProduct(PRODUCT_REMOTE_ID)).thenReturn(null) - whenever(productRepository.getProductAsync(PRODUCT_REMOTE_ID)).thenReturn(null) + whenever(productRepository.fetchAndGetProductAggregate(PRODUCT_REMOTE_ID)).thenReturn(null) + whenever(productRepository.getProductAggregate(PRODUCT_REMOTE_ID)).thenReturn(null) whenever(productRepository.lastFetchProductErrorType).thenReturn( WCProductStore.ProductErrorType.INVALID_PRODUCT_ID ) viewModel.start() - verify(productRepository, times(1)).fetchAndGetProduct(PRODUCT_REMOTE_ID) + verify(productRepository, times(1)).fetchAndGetProductAggregate(PRODUCT_REMOTE_ID) Assertions.assertThat(viewModel.getProduct().productDraft).isNull() Assertions.assertThat(viewModel.getProduct().auxiliaryState).isEqualTo( @@ -363,7 +364,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Do not fetch product from api when not connected`() = testBlocking { - doReturn(offlineProduct).whenever(productRepository).getProductAsync(any()) + doReturn(ProductAggregate(offlineProduct)).whenever(productRepository).getProductAggregate(any()) doReturn(false).whenever(networkStatus).isConnected() var snackbar: MultiLiveEvent.Event.ShowSnackbar? = null @@ -373,16 +374,16 @@ class ProductDetailViewModelTest : BaseUnitTest() { viewModel.start() - verify(productRepository, times(1)).getProductAsync(PRODUCT_REMOTE_ID) - verify(productRepository, times(0)).fetchAndGetProduct(any()) + verify(productRepository, times(1)).getProductAggregate(PRODUCT_REMOTE_ID) + verify(productRepository, times(0)).fetchAndGetProductAggregate(any()) Assertions.assertThat(snackbar).isEqualTo(MultiLiveEvent.Event.ShowSnackbar(R.string.offline_error)) } @Test fun `Shows and hides product detail skeleton correctly`() = testBlocking { - doReturn(null).whenever(productRepository).getProductAsync(any()) - doReturn(product).whenever(productRepository).fetchAndGetProduct(any()) + doReturn(null).whenever(productRepository).getProductAggregate(any()) + doReturn(productAggregate).whenever(productRepository).fetchAndGetProductAggregate(any()) val auxiliaryStates = ArrayList() viewModel.productDetailViewStateData.observeForever { old, new -> @@ -402,8 +403,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Displays the updated product detail view correctly`() = testBlocking { - doReturn(product).whenever(productRepository).getProductAsync(any()) - doReturn(product).whenever(productRepository).fetchAndGetProduct(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) + doReturn(productAggregate).whenever(productRepository).fetchAndGetProductAggregate(any()) var productData: ProductDetailViewModel.ProductDetailViewState? = null viewModel.productDetailViewStateData.observeForever { _, new -> productData = new } @@ -420,8 +421,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `When update product price is null, product detail view displayed correctly`() = testBlocking { - doReturn(product).whenever(productRepository).getProductAsync(any()) - doReturn(product).whenever(productRepository).fetchAndGetProduct(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) + doReturn(productAggregate).whenever(productRepository).fetchAndGetProductAggregate(any()) var productData: ProductDetailViewModel.ProductDetailViewState? = null viewModel.productDetailViewStateData.observeForever { _, new -> productData = new } @@ -443,8 +444,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `When update product price is zero, product detail view displayed correctly`() = testBlocking { - doReturn(product).whenever(productRepository).getProductAsync(any()) - doReturn(product).whenever(productRepository).fetchAndGetProduct(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) + doReturn(productAggregate).whenever(productRepository).fetchAndGetProductAggregate(any()) var productData: ProductDetailViewModel.ProductDetailViewState? = null viewModel.productDetailViewStateData.observeForever { _, new -> productData = new } @@ -466,7 +467,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Displays update menu action if product is edited`() = testBlocking { - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } viewModel.productDetailViewStateData.observeForever { _, _ -> } @@ -485,7 +486,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Displays progress dialog when product is edited`() = testBlocking { - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) doReturn(Pair(false, null)).whenever(productRepository).updateProduct(any()) val isProgressDialogShown = ArrayList() @@ -504,7 +505,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Do not update product when not connected`() = testBlocking { - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) doReturn(false).whenever(networkStatus).isConnected() var snackbar: MultiLiveEvent.Event.ShowSnackbar? = null @@ -526,7 +527,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Display error message on generic update product error`() = testBlocking { - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) doReturn(Pair(false, WCProductStore.ProductError())).whenever(productRepository).updateProduct(any()) var snackbar: MultiLiveEvent.Event.ShowSnackbar? = null @@ -550,7 +551,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Display error message on min-max quantities update product error`() = testBlocking { val displayErrorMessage = "This is an error message" - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) doReturn( Pair( false, @@ -582,7 +583,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Display success message on update product success`() = testBlocking { - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) doReturn(Pair(true, null)).whenever(productRepository).updateProduct(any()) var successSnackbarShown = false @@ -603,19 +604,19 @@ class ProductDetailViewModelTest : BaseUnitTest() { viewModel.onSaveButtonClicked() verify(productRepository, times(1)).updateProduct(any()) - verify(productRepository, times(2)).getProductAsync(PRODUCT_REMOTE_ID) + verify(productRepository, times(2)).getProductAggregate(PRODUCT_REMOTE_ID) Assertions.assertThat(successSnackbarShown).isTrue() Assertions.assertThat(productData?.isProgressDialogShown).isFalse Assertions.assertThat(hasChanges).isFalse() - Assertions.assertThat(productData?.productDraft).isEqualTo(product) + Assertions.assertThat(productData?.productAggregateDraft).isEqualTo(productAggregate) } @Test fun `Correctly sorts the Product Categories By their Parent Ids and by name`() { testBlocking { val sortedByNameAndParent = viewModel.sortAndStyleProductCategories( - product, + productAggregate.product, productCategories ).toList() Assertions.assertThat(sortedByNameAndParent[0].category).isEqualTo(productCategories[0]) @@ -680,7 +681,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Should update view state with not null sale end date when sale is scheduled`() = testBlocking { viewModel.productDetailViewStateData.observeForever { _, _ -> } - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) viewModel.start() viewModel.updateProductDraft(saleEndDate = SALE_END_DATE, isSaleScheduled = true) @@ -691,20 +692,22 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Should update with stored product sale end date when sale is not scheduled`() = testBlocking { viewModel.productDetailViewStateData.observeForever { _, _ -> } - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) viewModel.start() viewModel.updateProductDraft(saleEndDate = SALE_END_DATE, isSaleScheduled = false) - Assertions.assertThat(productsDraft?.saleEndDateGmt).isEqualTo(product.saleEndDateGmt) + Assertions.assertThat(productsDraft?.saleEndDateGmt).isEqualTo(productAggregate.product.saleEndDateGmt) } @Test fun `Should update sale end date when sale schedule is unknown but stored product sale is scheduled`() = testBlocking { viewModel.productDetailViewStateData.observeForever { _, _ -> } - val storedProduct = product.copy(isSaleScheduled = true) - doReturn(storedProduct).whenever(productRepository).getProductAsync(any()) + val storedProductAggregate = productAggregate.copy( + product = productAggregate.product.copy(isSaleScheduled = true) + ) + doReturn(storedProductAggregate).whenever(productRepository).getProductAggregate(any()) viewModel.start() viewModel.updateProductDraft(saleEndDate = SALE_END_DATE, isSaleScheduled = null) @@ -715,11 +718,13 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Should update with null sale end date and stored product has scheduled sale`() = testBlocking { viewModel.productDetailViewStateData.observeForever { _, _ -> } - val storedProduct = product.copy( - saleEndDateGmt = SALE_END_DATE, - isSaleScheduled = true + val storedProductAggregate = productAggregate.copy( + product = productAggregate.product.copy( + saleEndDateGmt = SALE_END_DATE, + isSaleScheduled = true + ) ) - doReturn(storedProduct).whenever(productRepository).getProductAsync(any()) + doReturn(storedProductAggregate).whenever(productRepository).getProductAggregate(any()) viewModel.start() viewModel.updateProductDraft(saleEndDate = null) @@ -730,12 +735,14 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Re-ordering attribute terms is saved correctly`() = testBlocking { viewModel.productDetailViewStateData.observeForever { _, _ -> } - val storedProduct = product.copy( - attributes = ProductTestUtils.generateProductAttributeList() + val storedProductAggregate = productAggregate.copy( + product = productAggregate.product.copy( + attributes = ProductTestUtils.generateProductAttributeList() + ) ) - doReturn(storedProduct).whenever(productRepository).getProductAsync(any()) + doReturn(storedProductAggregate).whenever(productRepository).getProductAggregate(any()) - val attribute = storedProduct.attributes[0] + val attribute = storedProductAggregate.product.attributes[0] val firstTerm = attribute.terms[0] val secondTerm = attribute.terms[1] @@ -772,10 +779,10 @@ class ProductDetailViewModelTest : BaseUnitTest() { ) ) - val storedProduct = product.copy( - attributes = attributes + val storedProductAggregate = productAggregate.copy( + product = productAggregate.product.copy(attributes = attributes) ) - doReturn(storedProduct).whenever(productRepository).getProductAsync(any()) + doReturn(storedProductAggregate).whenever(productRepository).getProductAggregate(any()) viewModel.start() viewModel.renameAttributeInDraft(1, attributeName, newName) @@ -787,7 +794,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { /** * Protection for a race condition bug in Variations. * - * We're requiring [ProductDetailRepository.fetchAndGetProduct] to be called right after + * We're requiring [ProductDetailRepository.fetchAndGetProductAggregate] to be called right after * [VariationRepository.createEmptyVariation] to fix a race condition problem in the Product Details page. The * bug can be reproduced inconsistently by following these steps: * @@ -811,7 +818,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { fun `When generating a variation, the latest Product should be fetched from the site`() = testBlocking { // Given - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) var productData: ProductDetailViewModel.ProductDetailViewState? = null viewModel.productDetailViewStateData.observeForever { _, new -> productData = new } @@ -824,16 +831,16 @@ class ProductDetailViewModelTest : BaseUnitTest() { Assertions.assertThat(productData?.productDraft?.numVariations).isZero() doReturn(mock()).whenever(variationRepository).createEmptyVariation(any()) - doReturn(product.copy(numVariations = 1_914)).whenever(productRepository) - .fetchAndGetProduct(eq(product.remoteId)) + doReturn(productAggregate.copy(product = productAggregate.product.copy(numVariations = 1_914))) + .whenever(productRepository).fetchAndGetProductAggregate(eq(productAggregate.product.remoteId)) // When viewModel.onGenerateVariationClicked() // Then - verify(variationRepository, times(1)).createEmptyVariation(eq(product)) + verify(variationRepository, times(1)).createEmptyVariation(eq(productAggregate.product)) // Prove that we fetched from the API. - verify(productRepository, times(1)).fetchAndGetProduct(eq(product.remoteId)) + verify(productRepository, times(1)).fetchAndGetProductAggregate(eq(productAggregate.remoteId)) // The VM state should have been updated with the _fetched_ product's numVariations Assertions.assertThat(productData?.productDraft?.numVariations).isEqualTo(1_914) @@ -843,8 +850,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { fun `when there image upload errors, then show a snackbar`() = testBlocking { val errorEvents = MutableSharedFlow>() doReturn(errorEvents).whenever(mediaFileUploadHandler).observeCurrentUploadErrors(PRODUCT_REMOTE_ID) - doReturn(product).whenever(productRepository).fetchAndGetProduct(any()) - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).fetchAndGetProductAggregate(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) val errorMessage = "message" doReturn(errorMessage).whenever(resources).getString(any(), anyVararg()) @@ -871,8 +878,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { fun `when image uploads gets cleared, then auto-dismiss the snackbar`() = testBlocking { val errorEvents = MutableSharedFlow>() doReturn(errorEvents).whenever(mediaFileUploadHandler).observeCurrentUploadErrors(PRODUCT_REMOTE_ID) - doReturn(product).whenever(productRepository).fetchAndGetProduct(any()) - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).fetchAndGetProductAggregate(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) viewModel.start() errorEvents.emit(emptyList()) @@ -882,7 +889,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Publish option not shown when product is published except addProduct flow`() = testBlocking { - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } var menuButtonsState: ProductDetailViewModel.MenuButtonsState? = null viewModel.menuButtonsState.observeForever { menuButtonsState = it } @@ -894,7 +901,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Publish option not shown when product is published privately except addProduct flow`() = testBlocking { - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } var menuButtonsState: ProductDetailViewModel.MenuButtonsState? = null viewModel.menuButtonsState.observeForever { menuButtonsState = it } @@ -906,7 +913,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Publish option shown when product is Draft`() = testBlocking { - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } var menuButtonsState: ProductDetailViewModel.MenuButtonsState? = null @@ -919,7 +926,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Publish option shown when product is Pending Review`() = testBlocking { - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } var menuButtonsState: ProductDetailViewModel.MenuButtonsState? = null @@ -933,7 +940,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Save option shown when product has changes except add product flow irrespective of product statuses`() = testBlocking { - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } var menuButtonsState: ProductDetailViewModel.MenuButtonsState? = null @@ -941,7 +948,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { viewModel.start() // Trigger changes - viewModel.updateProductDraft(title = product.name + "2") + viewModel.updateProductDraft(title = productAggregate.product.name + "2") Assertions.assertThat(menuButtonsState?.saveOption).isTrue() } @@ -949,7 +956,11 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `when restoring saved state, then re-fetch stored product to correctly calculate hasChanges`() = testBlocking { // Make sure draft product has different data than draft product - doReturn(product.copy(name = product.name + "test")).whenever(productRepository).getProductAsync(any()) + doReturn( + productAggregate.copy( + product = productAggregate.product.copy(name = productAggregate.product.name + "test") + ) + ).whenever(productRepository).getProductAggregate(any()) savedState.set(ProductDetailViewModel.ProductDetailViewState::class.java.name, productWithParameters) viewModel.productDetailViewStateData.observeForever { _, _ -> } @@ -964,10 +975,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `given regular price set, when updating inventory, then price remains unchanged`() = testBlocking { doReturn( - product.copy( - regularPrice = BigDecimal(99) - ) - ).whenever(productRepository).getProductAsync(any()) + productAggregate.copy(product = productAggregate.product.copy(regularPrice = BigDecimal(99))) + ).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } viewModel.start() @@ -979,10 +988,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `given sale price set, when updating attributes, then price remains unchanged`() = testBlocking { doReturn( - product.copy( - salePrice = BigDecimal(99) - ) - ).whenever(productRepository).getProductAsync(any()) + productAggregate.copy(product = productAggregate.product.copy(salePrice = BigDecimal(99))) + ).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } viewModel.start() @@ -994,10 +1001,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `given regular price greater than 0, when setting price to 0, then price is set to zero`() = testBlocking { doReturn( - product.copy( - regularPrice = BigDecimal(99) - ) - ).whenever(productRepository).getProductAsync(any()) + productAggregate.copy(product = productAggregate.product.copy(regularPrice = BigDecimal(99))) + ).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } viewModel.start() @@ -1009,10 +1014,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `given sale price greater than 0, when setting price to 0, then price is set to zero`() = testBlocking { doReturn( - product.copy( - regularPrice = BigDecimal(99) - ) - ).whenever(productRepository).getProductAsync(any()) + productAggregate.copy(product = productAggregate.product.copy(regularPrice = BigDecimal(99))) + ).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } viewModel.start() @@ -1024,10 +1027,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `given regular price greater than 0, when setting price to null, then price is set to null`() = testBlocking { doReturn( - product.copy( - regularPrice = BigDecimal(99) - ) - ).whenever(productRepository).getProductAsync(any()) + productAggregate.copy(product = productAggregate.product.copy(regularPrice = BigDecimal(99))) + ).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } viewModel.start() @@ -1039,10 +1040,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `given sale price greater than 0, when setting price to null, then price is set to null`() = testBlocking { doReturn( - product.copy( - regularPrice = BigDecimal(99) - ) - ).whenever(productRepository).getProductAsync(any()) + productAggregate.copy(product = productAggregate.product.copy(regularPrice = BigDecimal(99))) + ).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } viewModel.start() @@ -1059,7 +1058,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { images = uris ).toSavedStateHandle() - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) mediaFileUploadHandler = mock { on { it.observeCurrentUploadErrors(any()) } doReturn emptyFlow() @@ -1095,66 +1094,70 @@ class ProductDetailViewModelTest : BaseUnitTest() { } @Test - fun `given tablet, when loaded remote products, then PRODUCT_DETAIL_LOADED tracked with regular horizontal class`() = testBlocking { - // GIVEN - whenever(isWindowClassLargeThanCompact()).thenReturn(true) + fun `given tablet, when loaded remote products, then PRODUCT_DETAIL_LOADED tracked with regular horizontal class`() = + testBlocking { + // GIVEN + whenever(isWindowClassLargeThanCompact()).thenReturn(true) - // WHEN - setup() + // WHEN + setup() - // THEN - verify(tracker).track( - eq(AnalyticsEvent.PRODUCT_DETAIL_LOADED), - eq(mapOf("horizontal_size_class" to "regular")) - ) - } + // THEN + verify(tracker).track( + eq(AnalyticsEvent.PRODUCT_DETAIL_LOADED), + eq(mapOf("horizontal_size_class" to "regular")) + ) + } @Test - fun `given not tablet, when loaded remote products, then PRODUCT_DETAIL_LOADED tracked with compact horizontal class`() = testBlocking { - // GIVEN - whenever(isWindowClassLargeThanCompact()).thenReturn(false) + fun `given not tablet, when loaded remote products, then PRODUCT_DETAIL_LOADED tracked with compact horizontal class`() = + testBlocking { + // GIVEN + whenever(isWindowClassLargeThanCompact()).thenReturn(false) - // WHEN - setup() + // WHEN + setup() - // THEN - verify(tracker, times(2)).track( - eq(AnalyticsEvent.PRODUCT_DETAIL_LOADED), - eq(mapOf("horizontal_size_class" to "compact")) - ) - } + // THEN + verify(tracker, times(2)).track( + eq(AnalyticsEvent.PRODUCT_DETAIL_LOADED), + eq(mapOf("horizontal_size_class" to "compact")) + ) + } @Test - fun `given product updated successfuly, when onPublishButtonClicked, then ProductUpdated event emitted`() = testBlocking { - // GIVEN - whenever(productRepository.getProductAsync(any())).thenReturn(product) - whenever(productRepository.updateProduct(any())).thenReturn(Pair(true, null)) - viewModel.start() + fun `given product updated successfuly, when onPublishButtonClicked, then ProductUpdated event emitted`() = + testBlocking { + // GIVEN + whenever(productRepository.getProductAggregate(any())).thenReturn(productAggregate) + whenever(productRepository.updateProduct(any())).thenReturn(Pair(true, null)) + viewModel.start() - // WHEN - viewModel.onPublishButtonClicked() + // WHEN + viewModel.onPublishButtonClicked() - // THEN - Assertions.assertThat(viewModel.event.value).isEqualTo(ProductDetailViewModel.ProductUpdated) - } + // THEN + Assertions.assertThat(viewModel.event.value).isEqualTo(ProductDetailViewModel.ProductUpdated) + } @Test - fun `given selected site is private, when product detail is opened, then images are not available`() = testBlocking { - // GIVEN - whenever(selectedSite.get()).thenReturn(SiteModel().apply { setIsPrivate(true) }) - savedState = ProductDetailFragmentArgs(ProductDetailFragment.Mode.ShowProduct(PRODUCT_REMOTE_ID)) - .toSavedStateHandle() + fun `given selected site is private, when product detail is opened, then images are not available`() = + testBlocking { + // GIVEN + whenever(selectedSite.get()).thenReturn(SiteModel().apply { setIsPrivate(true) }) + savedState = ProductDetailFragmentArgs(ProductDetailFragment.Mode.ShowProduct(PRODUCT_REMOTE_ID)) + .toSavedStateHandle() - setup() - viewModel.start() + setup() + viewModel.start() - // WHEN - var productData: ProductDetailViewModel.ProductDetailViewState? = null - viewModel.productDetailViewStateData.observeForever { _, new -> productData = new } + // WHEN + var productData: ProductDetailViewModel.ProductDetailViewState? = null + viewModel.productDetailViewStateData.observeForever { _, new -> productData = new } - // THEN - Assertions.assertThat(productData?.areImagesAvailable).isFalse() - } + // THEN + Assertions.assertThat(productData?.areImagesAvailable).isFalse() + } @Test fun `given selected site is public, when product detail is opened, then images are available`() = testBlocking { @@ -1170,70 +1173,75 @@ class ProductDetailViewModelTest : BaseUnitTest() { } @Test - fun `given product password API uses CORE, when product details are fetched, then use password from the model`() = testBlocking { - // GIVEN - val password = "password" - whenever(determineProductPasswordApi.invoke()).thenReturn(ProductPasswordApi.CORE) - whenever(productRepository.getProductAsync(any())).thenReturn(product.copy(password = password)) + fun `given product password API uses CORE, when product details are fetched, then use password from the model`() = + testBlocking { + // GIVEN + val password = "password" + whenever(determineProductPasswordApi.invoke()).thenReturn(ProductPasswordApi.CORE) + whenever(productRepository.getProductAggregate(any())) + .thenReturn(productAggregate.copy(product = productAggregate.product.copy(password = password))) - // WHEN - viewModel.start() - val viewState = viewModel.productDetailViewStateData.liveData.getOrAwaitValue() + // WHEN + viewModel.start() + val viewState = viewModel.productDetailViewStateData.liveData.getOrAwaitValue() - // THEN - Assertions.assertThat(viewState.draftPassword).isEqualTo(password) - verify(productRepository, never()).fetchProductPassword(any()) - } + // THEN + Assertions.assertThat(viewState.draftPassword).isEqualTo(password) + verify(productRepository, never()).fetchProductPassword(any()) + } @Test - fun `given product password API uses WPCOM, when product details are fetched, then fetch password from the API`() = testBlocking { - // GIVEN - val password = "password" - whenever(determineProductPasswordApi.invoke()).thenReturn(ProductPasswordApi.WPCOM) - whenever(productRepository.getProductAsync(any())).thenReturn(product) - whenever(productRepository.fetchProductPassword(any())).thenReturn(password) + fun `given product password API uses WPCOM, when product details are fetched, then fetch password from the API`() = + testBlocking { + // GIVEN + val password = "password" + whenever(determineProductPasswordApi.invoke()).thenReturn(ProductPasswordApi.WPCOM) + whenever(productRepository.getProductAggregate(any())).thenReturn(productAggregate) + whenever(productRepository.fetchProductPassword(any())).thenReturn(password) - // WHEN - viewModel.start() - val viewState = viewModel.productDetailViewStateData.liveData.getOrAwaitValue() + // WHEN + viewModel.start() + val viewState = viewModel.productDetailViewStateData.liveData.getOrAwaitValue() - // THEN - Assertions.assertThat(viewState.draftPassword).isEqualTo(password) - verify(productRepository).fetchProductPassword(any()) - } + // THEN + Assertions.assertThat(viewState.draftPassword).isEqualTo(password) + verify(productRepository).fetchProductPassword(any()) + } @Test - fun `given product password API uses WPCOM, when product is saved, then update password using WPCOM API`() = testBlocking { - // GIVEN - val password = "password" - whenever(determineProductPasswordApi.invoke()).thenReturn(ProductPasswordApi.WPCOM) - whenever(productRepository.getProductAsync(any())).thenReturn(product) - whenever(productRepository.fetchProductPassword(any())).thenReturn(password) - whenever(productRepository.updateProduct(any())).thenReturn(Pair(true, null)) - - // WHEN - viewModel.start() - viewModel.updateProductVisibility(ProductVisibility.PASSWORD_PROTECTED, "newPassword") - viewModel.onSaveButtonClicked() + fun `given product password API uses WPCOM, when product is saved, then update password using WPCOM API`() = + testBlocking { + // GIVEN + val password = "password" + whenever(determineProductPasswordApi.invoke()).thenReturn(ProductPasswordApi.WPCOM) + whenever(productRepository.getProductAggregate(any())).thenReturn(productAggregate) + whenever(productRepository.fetchProductPassword(any())).thenReturn(password) + whenever(productRepository.updateProduct(any())).thenReturn(Pair(true, null)) + + // WHEN + viewModel.start() + viewModel.updateProductVisibility(ProductVisibility.PASSWORD_PROTECTED, "newPassword") + viewModel.onSaveButtonClicked() - // THEN - verify(productRepository).updateProductPassword(eq(product.remoteId), eq("newPassword")) - } + // THEN + verify(productRepository).updateProductPassword(eq(productAggregate.remoteId), eq("newPassword")) + } @Test - fun `given product password API is not supported, when product details are fetched, then password is empty`() = testBlocking { - // GIVEN - whenever(determineProductPasswordApi.invoke()).thenReturn(ProductPasswordApi.UNSUPPORTED) - whenever(productRepository.getProductAsync(any())).thenReturn(product) + fun `given product password API is not supported, when product details are fetched, then password is empty`() = + testBlocking { + // GIVEN + whenever(determineProductPasswordApi.invoke()).thenReturn(ProductPasswordApi.UNSUPPORTED) + whenever(productRepository.getProductAggregate(any())).thenReturn(productAggregate) - // WHEN - viewModel.start() - val viewState = viewModel.productDetailViewStateData.liveData.getOrAwaitValue() + // WHEN + viewModel.start() + val viewState = viewModel.productDetailViewStateData.liveData.getOrAwaitValue() - // THEN - Assertions.assertThat(viewState.draftPassword).isNull() - verify(productRepository, never()).fetchProductPassword(any()) - } + // THEN + Assertions.assertThat(viewState.draftPassword).isNull() + verify(productRepository, never()).fetchProductPassword(any()) + } private val productsDraft get() = viewModel.productDetailViewStateData.liveData.value?.productDraft diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel_AddFlowTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel_AddFlowTest.kt index 6658f9f3187..b4180796084 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel_AddFlowTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel_AddFlowTest.kt @@ -7,6 +7,7 @@ import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.media.MediaFilesRepository import com.woocommerce.android.media.ProductImagesServiceWrapper import com.woocommerce.android.model.Product +import com.woocommerce.android.model.ProductAggregate import com.woocommerce.android.tools.NetworkStatus import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.blaze.IsBlazeEnabled @@ -222,7 +223,7 @@ class ProductDetailViewModel_AddFlowTest : BaseUnitTest() { @Test fun `Display success message on add product success`() = testBlocking { // given - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(ProductAggregate(product)).whenever(productRepository).getProductAggregate(any()) doReturn(Pair(true, 1L)).whenever(productRepository).addProduct(any()) var successSnackbarShown = false @@ -244,7 +245,7 @@ class ProductDetailViewModel_AddFlowTest : BaseUnitTest() { viewModel.onPublishButtonClicked() // then - verify(productRepository, times(1)).getProductAsync(1L) + verify(productRepository, times(1)).getProductAggregate(1L) Assertions.assertThat(successSnackbarShown).isTrue() Assertions.assertThat(productData?.isProgressDialogShown).isFalse() @@ -308,7 +309,7 @@ class ProductDetailViewModel_AddFlowTest : BaseUnitTest() { fun `Display correct message on updating a freshly added product`() = testBlocking { // given - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(ProductAggregate(product)).whenever(productRepository).getProductAggregate(any()) doReturn(Pair(true, 1L)).whenever(productRepository).addProduct(any()) var successSnackbarShown = false @@ -330,7 +331,7 @@ class ProductDetailViewModel_AddFlowTest : BaseUnitTest() { viewModel.onPublishButtonClicked() // then - verify(productRepository, times(1)).getProductAsync(1L) + verify(productRepository, times(1)).getProductAggregate(1L) Assertions.assertThat(successSnackbarShown).isTrue() Assertions.assertThat(productData?.isProgressDialogShown).isFalse() @@ -399,7 +400,7 @@ class ProductDetailViewModel_AddFlowTest : BaseUnitTest() { @Test fun `when a new product is saved, then assign the new id to ongoing image uploads`() = testBlocking { doReturn(Pair(true, PRODUCT_REMOTE_ID)).whenever(productRepository).addProduct(any()) - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(product).whenever(productRepository).getProductAggregate(any()) savedState = ProductDetailFragmentArgs( mode = ProductDetailFragment.Mode.AddNewProduct ).toSavedStateHandle() @@ -454,7 +455,7 @@ class ProductDetailViewModel_AddFlowTest : BaseUnitTest() { fun `given a product is under creation, when clicking on save product, then assign uploads to the new id`() = testBlocking { doReturn(Pair(true, PRODUCT_REMOTE_ID)).whenever(productRepository).addProduct(any()) - doReturn(product).whenever(productRepository).getProductAsync(any()) + doReturn(product).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } viewModel.start() From e537a29c560eae9021fb6b8fab3f8ce9589e16d4 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Tue, 8 Oct 2024 15:39:44 +0100 Subject: [PATCH 112/162] Fix detekt --- .../android/model/SubscriptionDetailsMapper.kt | 2 +- .../ui/products/details/ProductDetailCardBuilder.kt | 1 + .../ui/products/details/ProductDetailViewModel.kt | 9 ++++++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetailsMapper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetailsMapper.kt index 28aa2a340ca..44e7f39361d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetailsMapper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetailsMapper.kt @@ -63,7 +63,7 @@ object SubscriptionDetailsMapper { } private fun WCMetaData.extractPaymentsSyncDate(): SubscriptionPaymentSyncDate? { - return when(isJson) { + return when (isJson) { true -> value.stringValue.let { val jsonObject = JsonParser.parseString(it).asJsonObject val day = jsonObject["day"].asInt diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailCardBuilder.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailCardBuilder.kt index 151446aaada..13ed2ca0cf2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailCardBuilder.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailCardBuilder.kt @@ -468,6 +468,7 @@ class ProductDetailCardBuilder( } } + @Suppress("LongMethod") private fun ProductAggregate.shipping(): ProductProperty? { return if (!this.product.isVirtual && hasShipping) { val weightWithUnits = product.getWeightWithUnits(parameters.weightUnit) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt index 4e7171ff566..11f9669e56f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt @@ -715,7 +715,8 @@ class ProductDetailViewModel @Inject constructor( attributeListViewState = attributeListViewState.copy(progressDialogState = ProgressDialogState.Hidden) } - fun hasCategoryChanges() = storedProductAggregate.value?.product?.hasCategoryChanges(viewState.productDraft) ?: false + fun hasCategoryChanges() = storedProductAggregate.value + ?.product?.hasCategoryChanges(viewState.productDraft) ?: false fun hasTagChanges() = storedProductAggregate.value?.product?.hasTagChanges(viewState.productDraft) ?: false @@ -851,7 +852,8 @@ class ProductDetailViewModel @Inject constructor( ) } - fun hasExternalLinkChanges() = storedProductAggregate.value?.product?.hasExternalLinkChanges(viewState.productDraft) ?: false + fun hasExternalLinkChanges() = storedProductAggregate.value + ?.product?.hasExternalLinkChanges(viewState.productDraft) ?: false /** * Called when the back= button is clicked in a product sub detail screen @@ -1863,7 +1865,8 @@ class ProductDetailViewModel @Inject constructor( triggerEvent(ProductNavigationTarget.RenameProductAttribute(attributeName)) } - fun hasAttributeChanges() = storedProductAggregate.value?.product?.hasAttributeChanges(viewState.productDraft) ?: false + fun hasAttributeChanges() = storedProductAggregate.value + ?.product?.hasAttributeChanges(viewState.productDraft) ?: false /** * Used by the add attribute screen to fetch the list of store-wide product attributes From d5c34755b86ac41cc132346f89e54a58ae63cf85 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Wed, 9 Oct 2024 12:40:03 +0100 Subject: [PATCH 113/162] Fix unit tests --- .../android/ui/customfields/list/CustomFieldsViewModelTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/customfields/list/CustomFieldsViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/customfields/list/CustomFieldsViewModelTest.kt index c4f19fd831a..d83c920593d 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/customfields/list/CustomFieldsViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/customfields/list/CustomFieldsViewModelTest.kt @@ -491,7 +491,7 @@ class CustomFieldsViewModelTest : BaseUnitTest() { val customField = CustomField( id = 1, key = "key", - value = WCMetaDataValue.fromRawString("{\"key\": \"value\"}") + value = WCMetaDataValue("{\"key\": \"value\"}") ) setup { whenever(repository.observeDisplayableCustomFields(PARENT_ITEM_ID)).thenReturn(flowOf(listOf(customField))) @@ -514,7 +514,7 @@ class CustomFieldsViewModelTest : BaseUnitTest() { val customField = CustomField( id = 1, key = "key", - value = WCMetaDataValue.fromRawString("{\"key\": \"value\"}") + value = WCMetaDataValue("{\"key\": \"value\"}") ) setup { whenever(repository.observeDisplayableCustomFields(PARENT_ITEM_ID)).thenReturn(flowOf(listOf(customField))) From 104b53419e32dfb7b15f0819592ff8cb22559345 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Wed, 9 Oct 2024 10:38:12 +0100 Subject: [PATCH 114/162] Handle updating metadata when updating a product --- .../android/model/SubscriptionDetails.kt | 43 +++++++++++++++++++ .../details/ProductDetailRepository.kt | 28 ++++++++++-- .../details/ProductDetailViewModel.kt | 14 +++--- .../media/ProductImagesUploadWorkerTest.kt | 7 +-- .../details/ProductDetailViewModelTest.kt | 21 ++++----- .../ProductDetailViewModel_AddFlowTest.kt | 4 +- .../ScanToUpdateInventoryViewModelTest.kt | 7 +-- 7 files changed, 96 insertions(+), 28 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetails.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetails.kt index 93417854e08..eb595ddf24e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetails.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetails.kt @@ -50,3 +50,46 @@ fun SubscriptionDetails.toMetadataJson(): JsonArray { } return jsonArray } + +fun SubscriptionDetails.toMetaData() = listOf( + WCMetaData( + id = 0, + key = SubscriptionMetadataKeys.SUBSCRIPTION_PRICE, + value = price?.toString().orEmpty() + ), + WCMetaData( + id = 0, + key = SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD, + value = period.value + ), + WCMetaData( + id = 0, + key = SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD_INTERVAL, + value = periodInterval.toString() + ), + WCMetaData( + id = 0, + key = SubscriptionMetadataKeys.SUBSCRIPTION_LENGTH, + value = length?.toString().orEmpty() + ), + WCMetaData( + id = 0, + key = SubscriptionMetadataKeys.SUBSCRIPTION_SIGN_UP_FEE, + value = signUpFee?.toString().orEmpty() + ), + WCMetaData( + id = 0, + key = SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_PERIOD, + value = (trialPeriod ?: SubscriptionPeriod.Day).value + ), + WCMetaData( + id = 0, + key = SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_LENGTH, + value = (trialLength ?: 0).toString() + ), + WCMetaData( + id = 0, + key = SubscriptionMetadataKeys.SUBSCRIPTION_ONE_TIME_SHIPPING, + value = if (oneTimeShipping) "yes" else "no" + ) +) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailRepository.kt index d0b38a1dee9..8a9de0366f4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailRepository.kt @@ -15,6 +15,7 @@ import com.woocommerce.android.model.SubscriptionDetailsMapper import com.woocommerce.android.model.TaxClass import com.woocommerce.android.model.toAppModel import com.woocommerce.android.model.toDataModel +import com.woocommerce.android.model.toMetaData import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.products.models.QuantityRules import com.woocommerce.android.util.ContinuationWrapper @@ -37,6 +38,7 @@ import org.wordpress.android.fluxc.action.WCProductAction.FETCH_SINGLE_PRODUCT_S import org.wordpress.android.fluxc.action.WCProductAction.UPDATED_PRODUCT import org.wordpress.android.fluxc.action.WCProductAction.UPDATE_PRODUCT_PASSWORD import org.wordpress.android.fluxc.generated.WCProductActionBuilder +import org.wordpress.android.fluxc.model.metadata.MetadataChanges import org.wordpress.android.fluxc.model.metadata.WCMetaData import org.wordpress.android.fluxc.store.WCGlobalAttributeStore import org.wordpress.android.fluxc.store.WCProductStore @@ -120,14 +122,23 @@ class ProductDetailRepository @Inject constructor( * * @return the result of the action as a [Boolean] */ - suspend fun updateProduct(updatedProduct: Product): Pair { + suspend fun updateProduct(updatedProductAggregate: ProductAggregate): Pair { return try { suspendCoroutineWithTimeout>(AppConstants.REQUEST_TIMEOUT) { continuationUpdateProduct = it - val cachedProduct = getCachedWCProductModel(updatedProduct.remoteId) - val product = updatedProduct.toDataModel(cachedProduct) - val payload = WCProductStore.UpdateProductPayload(selectedSite.get(), product) + val cachedProduct = getCachedWCProductModel(updatedProductAggregate.remoteId) + val product = updatedProductAggregate.product.toDataModel(cachedProduct) + val metadataChanges = MetadataChanges( + // Even though the subscription keys are passed as new metadata here, the server will replace any + // existing keys with the new ones. + insertedMetadata = updatedProductAggregate.subscription?.toMetaData() ?: emptyList() + ) + val payload = WCProductStore.UpdateProductPayload( + site = selectedSite.get(), + product = product, + metadataChanges = metadataChanges + ) dispatcher.dispatch(WCProductActionBuilder.newUpdateProductAction(payload)) } ?: Pair(false, null) // request timed out } catch (e: CancellationException) { @@ -136,6 +147,15 @@ class ProductDetailRepository @Inject constructor( } } + /** + * Fires the request to update the product + * + * @return the result of the action as a [Boolean] + */ + suspend fun updateProduct(updatedProduct: Product): Pair { + return updateProduct(ProductAggregate(updatedProduct, null)) + } + /** * Fires the request to add a product * diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt index 11f9669e56f..a0a28da272d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt @@ -1035,8 +1035,8 @@ class ProductDetailViewModel @Inject constructor( stat = AnalyticsEvent.PRODUCT_DETAIL_UPDATE_BUTTON_TAPPED, properties = mapOf(AnalyticsTracker.KEY_IS_AI_CONTENT to navArgs.isAIContent) ) - viewState.productDraft?.let { - val product = if (isPublish) it.copy(status = ProductStatus.PUBLISH) else it + viewState.productAggregateDraft?.let { + val product = if (isPublish) it.copy(product = it.product.copy(status = ProductStatus.PUBLISH)) else it viewState = viewState.copy(isProgressDialogShown = true) launch { updateProduct(isPublish, product) } } @@ -1960,19 +1960,21 @@ class ProductDetailViewModel @Inject constructor( * Updates the product to the backend only if network is connected. * Otherwise, an offline snackbar is displayed. */ - private suspend fun updateProduct(isPublish: Boolean, product: Product) { + private suspend fun updateProduct(isPublish: Boolean, productAggregate: ProductAggregate) { if (!checkConnection()) { viewState = viewState.copy(isProgressDialogShown = false) return } - val result = productRepository.updateProduct(product.copy(password = viewState.draftPassword)) + val result = productRepository.updateProduct( + productAggregate.copy(product = productAggregate.product.copy(password = viewState.draftPassword)) + ) if (result.first) { val successMsg = pickProductUpdateSuccessText(isPublish) val isPasswordChanged = storedProductAggregate.value?.product?.password != viewState.draftPassword if (isPasswordChanged && determineProductPasswordApi() == ProductPasswordApi.WPCOM) { // Update the product password using WordPress.com API val password = viewState.productDraft?.password - if (productRepository.updateProductPassword(product.remoteId, password)) { + if (productRepository.updateProductPassword(productAggregate.remoteId, password)) { storedProductAggregate.update { it?.copy(product = it.product.copy(password = password)) } triggerEvent(ShowSnackbar(successMsg)) } else { @@ -1988,7 +1990,7 @@ class ProductDetailViewModel @Inject constructor( productDraft = null ) triggerEvent(ProductUpdated) - loadRemoteProduct(product.remoteId) + loadRemoteProduct(productAggregate.remoteId) } else { result.second?.let { if (it.canDisplayMessage) { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/media/ProductImagesUploadWorkerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/media/ProductImagesUploadWorkerTest.kt index e765c7bd877..e4af37273e3 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/media/ProductImagesUploadWorkerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/media/ProductImagesUploadWorkerTest.kt @@ -13,6 +13,7 @@ import com.woocommerce.android.media.ProductImagesUploadWorker.Event.ProductUpda import com.woocommerce.android.media.ProductImagesUploadWorker.Event.ProductUpdateEvent.ProductUpdateSucceeded import com.woocommerce.android.media.ProductImagesUploadWorker.Event.ProductUploadsCompleted import com.woocommerce.android.media.ProductImagesUploadWorker.Work +import com.woocommerce.android.model.Product import com.woocommerce.android.model.toAppModel import com.woocommerce.android.ui.products.ProductTestUtils import com.woocommerce.android.ui.products.details.ProductDetailRepository @@ -222,7 +223,7 @@ class ProductImagesUploadWorkerTest : BaseUnitTest() { fun `when update product succeeds, then send an event`() = testBlocking { val product = ProductTestUtils.generateProduct(REMOTE_PRODUCT_ID) whenever(productDetailRepository.fetchAndGetProduct(REMOTE_PRODUCT_ID)).thenReturn(product) - whenever(productDetailRepository.updateProduct(any())).thenReturn(Pair(true, null)) + whenever(productDetailRepository.updateProduct(any())).thenReturn(Pair(true, null)) val eventsList = mutableListOf() val job = launch { @@ -239,7 +240,7 @@ class ProductImagesUploadWorkerTest : BaseUnitTest() { fun `when update product fails, then retry three times`() = testBlocking { val product = ProductTestUtils.generateProduct(REMOTE_PRODUCT_ID) whenever(productDetailRepository.fetchAndGetProduct(REMOTE_PRODUCT_ID)).thenReturn(product) - whenever(productDetailRepository.updateProduct(any())).thenReturn(Pair(false, null)) + whenever(productDetailRepository.updateProduct(any())).thenReturn(Pair(false, null)) worker.enqueueWork(Work.UpdateProduct(REMOTE_PRODUCT_ID, listOf(UPLOADED_MEDIA))) @@ -252,7 +253,7 @@ class ProductImagesUploadWorkerTest : BaseUnitTest() { fun `when update product fails, then send an event`() = testBlocking { val product = ProductTestUtils.generateProduct(REMOTE_PRODUCT_ID) whenever(productDetailRepository.fetchAndGetProduct(REMOTE_PRODUCT_ID)).thenReturn(product) - whenever(productDetailRepository.updateProduct(any())).thenReturn(Pair(false, null)) + whenever(productDetailRepository.updateProduct(any())).thenReturn(Pair(false, null)) val eventsList = mutableListOf() val job = launch { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModelTest.kt index 2439f10ef1a..b846c22e2cd 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModelTest.kt @@ -487,7 +487,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Displays progress dialog when product is edited`() = testBlocking { doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) - doReturn(Pair(false, null)).whenever(productRepository).updateProduct(any()) + doReturn(Pair(false, null)).whenever(productRepository).updateProduct(any()) val isProgressDialogShown = ArrayList() viewModel.productDetailViewStateData.observeForever { old, new -> @@ -520,7 +520,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { viewModel.onSaveButtonClicked() - verify(productRepository, times(0)).updateProduct(any()) + verify(productRepository, times(0)).updateProduct(any()) Assertions.assertThat(snackbar).isEqualTo(MultiLiveEvent.Event.ShowSnackbar(R.string.offline_error)) Assertions.assertThat(productData?.isProgressDialogShown).isFalse() } @@ -528,7 +528,8 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Display error message on generic update product error`() = testBlocking { doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) - doReturn(Pair(false, WCProductStore.ProductError())).whenever(productRepository).updateProduct(any()) + doReturn(Pair(false, WCProductStore.ProductError())).whenever(productRepository) + .updateProduct(any()) var snackbar: MultiLiveEvent.Event.ShowSnackbar? = null viewModel.event.observeForever { @@ -542,7 +543,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { viewModel.onSaveButtonClicked() - verify(productRepository, times(1)).updateProduct(any()) + verify(productRepository, times(1)).updateProduct(any()) Assertions.assertThat(snackbar) .isEqualTo(MultiLiveEvent.Event.ShowSnackbar(R.string.product_detail_update_product_error)) Assertions.assertThat(productData?.isProgressDialogShown).isFalse() @@ -561,7 +562,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { ) ) ) - .whenever(productRepository).updateProduct(any()) + .whenever(productRepository).updateProduct(any()) var showUpdateProductError: ProductDetailViewModel.ShowUpdateProductError? = null viewModel.event.observeForever { @@ -575,7 +576,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { viewModel.onSaveButtonClicked() - verify(productRepository, times(1)).updateProduct(any()) + verify(productRepository, times(1)).updateProduct(any()) Assertions.assertThat(showUpdateProductError) .isEqualTo(ProductDetailViewModel.ShowUpdateProductError(displayErrorMessage)) Assertions.assertThat(productData?.isProgressDialogShown).isFalse() @@ -584,7 +585,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { @Test fun `Display success message on update product success`() = testBlocking { doReturn(productAggregate).whenever(productRepository).getProductAggregate(any()) - doReturn(Pair(true, null)).whenever(productRepository).updateProduct(any()) + doReturn(Pair(true, null)).whenever(productRepository).updateProduct(any()) var successSnackbarShown = false viewModel.event.observeForever { @@ -603,7 +604,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { viewModel.onSaveButtonClicked() - verify(productRepository, times(1)).updateProduct(any()) + verify(productRepository, times(1)).updateProduct(any()) verify(productRepository, times(2)).getProductAggregate(PRODUCT_REMOTE_ID) Assertions.assertThat(successSnackbarShown).isTrue() @@ -1130,7 +1131,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { testBlocking { // GIVEN whenever(productRepository.getProductAggregate(any())).thenReturn(productAggregate) - whenever(productRepository.updateProduct(any())).thenReturn(Pair(true, null)) + whenever(productRepository.updateProduct(any())).thenReturn(Pair(true, null)) viewModel.start() // WHEN @@ -1216,7 +1217,7 @@ class ProductDetailViewModelTest : BaseUnitTest() { whenever(determineProductPasswordApi.invoke()).thenReturn(ProductPasswordApi.WPCOM) whenever(productRepository.getProductAggregate(any())).thenReturn(productAggregate) whenever(productRepository.fetchProductPassword(any())).thenReturn(password) - whenever(productRepository.updateProduct(any())).thenReturn(Pair(true, null)) + whenever(productRepository.updateProduct(any())).thenReturn(Pair(true, null)) // WHEN viewModel.start() diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel_AddFlowTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel_AddFlowTest.kt index b4180796084..2711cfa4834 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel_AddFlowTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel_AddFlowTest.kt @@ -339,10 +339,10 @@ class ProductDetailViewModel_AddFlowTest : BaseUnitTest() { Assertions.assertThat(productData?.productDraft).isEqualTo(product) // when - doReturn(Pair(true, null)).whenever(productRepository).updateProduct(any()) + doReturn(Pair(true, null)).whenever(productRepository).updateProduct(any()) viewModel.onPublishButtonClicked() - verify(productRepository, times(1)).updateProduct(any()) + verify(productRepository, times(1)).updateProduct(any()) viewModel.event.observeForever { if (it is ShowSnackbar && it.message == R.string.product_detail_save_product_success) { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/inventory/ScanToUpdateInventoryViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/inventory/ScanToUpdateInventoryViewModelTest.kt index 2f6f0fa4445..e414ae85f6a 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/inventory/ScanToUpdateInventoryViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/inventory/ScanToUpdateInventoryViewModelTest.kt @@ -6,6 +6,7 @@ import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsEvent import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.analytics.AnalyticsTrackerWrapper +import com.woocommerce.android.model.Product import com.woocommerce.android.model.ProductVariation import com.woocommerce.android.model.UiString import com.woocommerce.android.ui.orders.creation.CodeScannerStatus @@ -214,7 +215,7 @@ class ScanToUpdateInventoryViewModelTest : BaseUnitTest() { GoogleBarcodeFormatMapper.BarcodeFormat.FormatEAN8 ) ) - whenever(productRepo.updateProduct(any())).thenReturn(Pair(true, null)) + whenever(productRepo.updateProduct(any())).thenReturn(Pair(true, null)) whenever( resourceProvider.getString( R.string.scan_to_update_inventory_success_snackbar, @@ -248,7 +249,7 @@ class ScanToUpdateInventoryViewModelTest : BaseUnitTest() { GoogleBarcodeFormatMapper.BarcodeFormat.FormatEAN8 ) ) - whenever(productRepo.updateProduct(any())).thenReturn(Pair(true, null)) + whenever(productRepo.updateProduct(any())).thenReturn(Pair(true, null)) whenever( resourceProvider.getString( R.string.scan_to_update_inventory_success_snackbar, @@ -280,7 +281,7 @@ class ScanToUpdateInventoryViewModelTest : BaseUnitTest() { whenever(fetchProductBySKU(any(), any())).thenReturn(Result.success(product)) whenever(productRepo.getProduct(productId)).thenReturn(product) - whenever(productRepo.updateProduct(any())).thenReturn(Pair(true, null)) + whenever(productRepo.updateProduct(any())).thenReturn(Pair(true, null)) whenever( resourceProvider.getString( eq(R.string.scan_to_update_inventory_success_snackbar), From 5eb0385c6a9ba72c6b2d88b22305fcead08ef36b Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Wed, 9 Oct 2024 12:40:39 +0100 Subject: [PATCH 115/162] Handle passing product metadata when adding a new product --- .../android/model/SubscriptionDetails.kt | 52 ++++--------------- .../android/ui/products/DuplicateProduct.kt | 22 +++++--- .../details/ProductDetailRepository.kt | 21 ++++++-- .../details/ProductDetailViewModel.kt | 28 +++++----- 4 files changed, 56 insertions(+), 67 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetails.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetails.kt index eb595ddf24e..b7ce2250183 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetails.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/SubscriptionDetails.kt @@ -6,6 +6,7 @@ import com.google.gson.JsonObject import kotlinx.parcelize.Parcelize import org.wordpress.android.fluxc.model.WCProductModel.SubscriptionMetadataKeys import org.wordpress.android.fluxc.model.metadata.WCMetaData +import org.wordpress.android.fluxc.model.metadata.WCMetaDataValue import java.math.BigDecimal @Parcelize @@ -51,45 +52,14 @@ fun SubscriptionDetails.toMetadataJson(): JsonArray { return jsonArray } -fun SubscriptionDetails.toMetaData() = listOf( - WCMetaData( - id = 0, - key = SubscriptionMetadataKeys.SUBSCRIPTION_PRICE, - value = price?.toString().orEmpty() - ), - WCMetaData( - id = 0, - key = SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD, - value = period.value - ), - WCMetaData( - id = 0, - key = SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD_INTERVAL, - value = periodInterval.toString() - ), - WCMetaData( - id = 0, - key = SubscriptionMetadataKeys.SUBSCRIPTION_LENGTH, - value = length?.toString().orEmpty() - ), - WCMetaData( - id = 0, - key = SubscriptionMetadataKeys.SUBSCRIPTION_SIGN_UP_FEE, - value = signUpFee?.toString().orEmpty() - ), - WCMetaData( - id = 0, - key = SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_PERIOD, - value = (trialPeriod ?: SubscriptionPeriod.Day).value - ), - WCMetaData( - id = 0, - key = SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_LENGTH, - value = (trialLength ?: 0).toString() - ), - WCMetaData( - id = 0, - key = SubscriptionMetadataKeys.SUBSCRIPTION_ONE_TIME_SHIPPING, - value = if (oneTimeShipping) "yes" else "no" - ) +fun SubscriptionDetails.toMetaData() = mapOf( + SubscriptionMetadataKeys.SUBSCRIPTION_PRICE to WCMetaDataValue(price?.toString().orEmpty()), + SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD to WCMetaDataValue(period.value), + SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD_INTERVAL to WCMetaDataValue(periodInterval), + SubscriptionMetadataKeys.SUBSCRIPTION_LENGTH to WCMetaDataValue(length?.toString().orEmpty()), + SubscriptionMetadataKeys.SUBSCRIPTION_SIGN_UP_FEE to WCMetaDataValue(signUpFee?.toString().orEmpty()), + SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_PERIOD to + WCMetaDataValue((trialPeriod ?: SubscriptionPeriod.Day).value), + SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_LENGTH to WCMetaDataValue(trialLength?.toString().orEmpty()), + SubscriptionMetadataKeys.SUBSCRIPTION_ONE_TIME_SHIPPING to WCMetaDataValue(if (oneTimeShipping) "yes" else "no"), ) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/DuplicateProduct.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/DuplicateProduct.kt index 9e408d178f9..9c60ac6f78b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/DuplicateProduct.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/DuplicateProduct.kt @@ -3,6 +3,7 @@ package com.woocommerce.android.ui.products import com.woocommerce.android.R import com.woocommerce.android.WooException import com.woocommerce.android.model.Product +import com.woocommerce.android.model.ProductAggregate import com.woocommerce.android.ui.products.details.ProductDetailRepository import com.woocommerce.android.ui.products.variations.VariationRepository import com.woocommerce.android.util.WooLog @@ -18,19 +19,24 @@ class DuplicateProduct @Inject constructor( private val resourceProvider: ResourceProvider, ) { - suspend operator fun invoke(product: Product): Result { - val newProduct = product.copy( - remoteId = 0, - name = resourceProvider.getString(R.string.product_duplicate_copied_product_name, product.name), - sku = "", - status = ProductStatus.DRAFT + suspend operator fun invoke(productAggregate: ProductAggregate): Result { + val newProduct = productAggregate.copy( + product = productAggregate.product.copy( + remoteId = 0, + name = resourceProvider.getString( + R.string.product_duplicate_copied_product_name, + productAggregate.product.name + ), + sku = "", + status = ProductStatus.DRAFT + ) ) val (duplicateProductSuccess, duplicatedProductRemoteId) = productDetailRepository.addProduct(newProduct) return if (duplicateProductSuccess) { - if (product.numVariations > 0) { - duplicateVariations(product, duplicatedProductRemoteId) + if (productAggregate.product.numVariations > 0) { + duplicateVariations(productAggregate.product, duplicatedProductRemoteId) } else { Result.success(duplicatedProductRemoteId) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailRepository.kt index 8a9de0366f4..265e4a146c3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailRepository.kt @@ -132,7 +132,9 @@ class ProductDetailRepository @Inject constructor( val metadataChanges = MetadataChanges( // Even though the subscription keys are passed as new metadata here, the server will replace any // existing keys with the new ones. - insertedMetadata = updatedProductAggregate.subscription?.toMetaData() ?: emptyList() + insertedMetadata = updatedProductAggregate.subscription?.toMetaData()?.map { (key, value) -> + WCMetaData(id = 0L, key = key, value = value) + } ?: emptyList() ) val payload = WCProductStore.UpdateProductPayload( site = selectedSite.get(), @@ -161,12 +163,16 @@ class ProductDetailRepository @Inject constructor( * * @return the result of the action as a [Boolean] */ - suspend fun addProduct(product: Product): Pair { + suspend fun addProduct(productAggregate: ProductAggregate): Pair { return try { suspendCoroutineWithTimeout>(AppConstants.REQUEST_TIMEOUT) { continuationAddProduct = it - val model = product.toDataModel(null) - val payload = WCProductStore.AddProductPayload(selectedSite.get(), model) + val model = productAggregate.product.toDataModel(null) + val payload = WCProductStore.AddProductPayload( + site = selectedSite.get(), + product = model, + metadata = productAggregate.subscription?.toMetaData() + ) dispatcher.dispatch(WCProductActionBuilder.newAddProductAction(payload)) } ?: Pair(false, 0L) // request timed out } catch (e: CancellationException) { @@ -175,6 +181,13 @@ class ProductDetailRepository @Inject constructor( } } + /** + * Fires the request to add a product + * + * @return the result of the action as a [Boolean] + */ + suspend fun addProduct(product: Product): Pair = addProduct(ProductAggregate(product, null)) + /** * Fires the request to update the product password * diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt index a0a28da272d..60b6f59fffb 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt @@ -1017,11 +1017,11 @@ class ProductDetailViewModel @Inject constructor( * 3. is a Draft */ fun saveAsDraftIfNewVariableProduct() = launch { - viewState.productDraft + viewState.productAggregateDraft ?.takeIf { isProductStoredAtSite.not() and - it.productType.isVariableProduct() and - (it.status == DRAFT) + it.product.productType.isVariableProduct() and + (it.product.status == DRAFT) } ?.takeIf { addProduct(it).first } ?.let { @@ -1043,14 +1043,14 @@ class ProductDetailViewModel @Inject constructor( } private fun startPublishProduct(productStatus: ProductStatus, exitWhenDone: Boolean = false) { - viewState.productDraft?.let { - val product = it.copy(status = productStatus) - trackPublishing(product) + viewState.productAggregateDraft?.let { + val productAggregate = it.copy(product = it.product.copy(status = productStatus)) + trackPublishing(productAggregate.product) viewState = viewState.copy(isProgressDialogShown = true) launch { - val (isSuccess, newProductId) = addProduct(product) + val (isSuccess, newProductId) = addProduct(productAggregate) viewState = viewState.copy(isProgressDialogShown = false) val snackbarMessage = pickAddProductRequestSnackbarText(isSuccess, productStatus) triggerEvent(ShowSnackbar(snackbarMessage)) @@ -1058,8 +1058,8 @@ class ProductDetailViewModel @Inject constructor( if (isPublishingFirstProduct()) { triggerEvent( ProductNavigationTarget.ViewFirstProductCelebration( - productName = product.name, - permalink = product.permalink + productName = productAggregate.product.name, + permalink = productAggregate.product.permalink ) ) } @@ -1070,13 +1070,13 @@ class ProductDetailViewModel @Inject constructor( ) } tracker.track(AnalyticsEvent.ADD_PRODUCT_SUCCESS) - if (product.remoteId != newProductId) { + if (productAggregate.remoteId != newProductId) { // Assign the current uploads to the new product id mediaFileUploadHandler.assignUploadsToCreatedProduct(newProductId) } if (exitWhenDone) { triggerEvent(ProductNavigationTarget.ExitProduct) - } else if (product.remoteId != newProductId) { + } else if (productAggregate.remoteId != newProductId) { // Restart observing image uploads using the new product id observeImageUploadEvents() } @@ -2009,10 +2009,10 @@ class ProductDetailViewModel @Inject constructor( * Otherwise, an offline snackbar is displayed. Returns true only * if product successfully added */ - private suspend fun addProduct(product: Product): Pair { + private suspend fun addProduct(productAggregate: ProductAggregate): Pair { if (!checkConnection()) return Pair(false, 0L) - val result = productRepository.addProduct(product) + val result = productRepository.addProduct(productAggregate) val (isSuccess, newProductRemoteId) = result if (isSuccess) { checkLinkedProductPromo() @@ -2520,7 +2520,7 @@ class ProductDetailViewModel @Inject constructor( fun onDuplicateProduct() { launch { tracker.track(AnalyticsEvent.PRODUCT_DETAIL_DUPLICATE_BUTTON_TAPPED) - viewState.productDraft?.let { product -> + viewState.productAggregateDraft?.let { product -> triggerEvent(ShowDuplicateProductInProgress) val result = duplicateProduct(product) From 89676819cfab95ddd744b13ec27d0490927711a6 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Wed, 9 Oct 2024 19:04:12 +0100 Subject: [PATCH 116/162] Use && instead of and and doesn't do any short-circuiting, so it's less performant. --- .../android/ui/products/details/ProductDetailViewModel.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt index 60b6f59fffb..9b8b527ae82 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt @@ -376,7 +376,7 @@ class ProductDetailViewModel @Inject constructor( * Validates if the view model was started for the **add** flow AND there is an already valid product to modify. */ val isProductUnderCreation: Boolean - get() = isAddNewProductFlow and isProductStoredAtSite.not() + get() = isAddNewProductFlow && isProductStoredAtSite.not() /** * Returns boolean value of [navArgs.isTrashEnabled] to determine if the detail fragment should enable @@ -1019,8 +1019,8 @@ class ProductDetailViewModel @Inject constructor( fun saveAsDraftIfNewVariableProduct() = launch { viewState.productAggregateDraft ?.takeIf { - isProductStoredAtSite.not() and - it.product.productType.isVariableProduct() and + isProductStoredAtSite.not() && + it.product.productType.isVariableProduct() && (it.product.status == DRAFT) } ?.takeIf { addProduct(it).first } From 185a1ad98d1ff2dbe2489f30276154029d14c6b1 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 10 Oct 2024 10:41:01 +0100 Subject: [PATCH 117/162] Simplify expression --- .../ui/products/details/ProductDetailViewModel.kt | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt index 11f9669e56f..c00153a4c9f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel.kt @@ -1231,10 +1231,8 @@ class ProductDetailViewModel @Inject constructor( viewState.productAggregateDraft?.let { productAggregateDraft -> if (productType == ProductType.SUBSCRIPTION && productAggregateDraft.subscription == null) { viewState = viewState.copy( - productAggregateDraft = productAggregateDraft.copy( - subscription = ProductHelper.getDefaultSubscriptionDetails().copy( - price = productAggregateDraft.product.regularPrice - ) + subscriptionDraft = ProductHelper.getDefaultSubscriptionDetails().copy( + price = productAggregateDraft.product.regularPrice ) ) } @@ -1514,9 +1512,7 @@ class ProductDetailViewModel @Inject constructor( */ fun updateProductVisibility(visibility: ProductVisibility, password: String?) { viewState = viewState.copy( - productAggregateDraft = viewState.productAggregateDraft?.copy( - product = viewState.productDraft!!.copy(password = password) - ) + productDraft = viewState.productDraft?.copy(password = password) ) when (visibility) { @@ -1571,9 +1567,7 @@ class ProductDetailViewModel @Inject constructor( storedProductAggregate.update { it?.copy(product = it.product.copy(password = password)) } viewState = viewState.copy( - productAggregateDraft = viewState.productAggregateDraft?.copy( - product = viewState.productDraft!!.copy(password = viewState.draftPassword ?: password) - ) + productDraft = viewState.productDraft?.copy(password = viewState.draftPassword ?: password) ) } From f7e6c34560dadd276b1a76054f231e73ece3a63e Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Wed, 9 Oct 2024 19:52:53 +0100 Subject: [PATCH 118/162] Fix unit tests --- .../android/ui/products/DuplicateProductTest.kt | 17 +++++++++-------- .../ProductDetailViewModel_AddFlowTest.kt | 12 ++++++------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/DuplicateProductTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/DuplicateProductTest.kt index 62728b9a521..b1e61288b4b 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/DuplicateProductTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/DuplicateProductTest.kt @@ -1,6 +1,6 @@ package com.woocommerce.android.ui.products -import com.woocommerce.android.model.Product +import com.woocommerce.android.model.ProductAggregate import com.woocommerce.android.model.ProductVariation import com.woocommerce.android.ui.products.details.ProductDetailRepository import com.woocommerce.android.ui.products.variations.VariationRepository @@ -41,24 +41,25 @@ class DuplicateProductTest : BaseUnitTest() { @Test fun `should duplicate a product and set expected properties`() = testBlocking { // given - val productToDuplicate = ProductTestUtils.generateProduct().copy(sku = "not an empty value") + val productToDuplicate = ProductAggregate(ProductTestUtils.generateProduct().copy(sku = "not an empty value")) productDetailRepository.stub { - onBlocking { addProduct(any()) } doReturn Pair(true, 123) + onBlocking { addProduct(any()) } doReturn Pair(true, 123) } // when sut.invoke(productToDuplicate) // then - val duplicationRequestCapture = argumentCaptor() + val duplicationRequestCapture = argumentCaptor() verify(productDetailRepository).addProduct(duplicationRequestCapture.capture()) assertThat(duplicationRequestCapture.firstValue) .matches { - it.remoteId == 0L && it.name == "copied name" && it.sku == "" && it.status == ProductStatus.DRAFT + it.remoteId == 0L && it.product.name == "copied name" && + it.product.sku == "" && it.product.status == ProductStatus.DRAFT } .usingRecursiveComparison() - .ignoringFields("remoteId", "name", "sku", "status") + .ignoringFields("product.remoteId", "product.name", "product.sku", "product.status") .isEqualTo(productToDuplicate) } @@ -66,10 +67,10 @@ class DuplicateProductTest : BaseUnitTest() { fun `should duplicate a variable product and keep all properties of variations except sku and remoteProductId`() = testBlocking { // given - val productToDuplicate = ProductTestUtils.generateProduct().copy(numVariations = 15) + val productToDuplicate = ProductAggregate(ProductTestUtils.generateProduct().copy(numVariations = 15)) val duplicatedProductId = 456L productDetailRepository.stub { - onBlocking { addProduct(any()) } doReturn Pair(true, duplicatedProductId) + onBlocking { addProduct(any()) } doReturn Pair(true, duplicatedProductId) } val variationsOfProductToDuplicate = diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel_AddFlowTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel_AddFlowTest.kt index 2711cfa4834..cec29d45126 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel_AddFlowTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/details/ProductDetailViewModel_AddFlowTest.kt @@ -224,7 +224,7 @@ class ProductDetailViewModel_AddFlowTest : BaseUnitTest() { fun `Display success message on add product success`() = testBlocking { // given doReturn(ProductAggregate(product)).whenever(productRepository).getProductAggregate(any()) - doReturn(Pair(true, 1L)).whenever(productRepository).addProduct(any()) + doReturn(Pair(true, 1L)).whenever(productRepository).addProduct(any()) var successSnackbarShown = false viewModel.event.observeForever { @@ -256,7 +256,7 @@ class ProductDetailViewModel_AddFlowTest : BaseUnitTest() { @Test fun `Display error message on add product failed`() = testBlocking { // given - doReturn(Pair(false, 0L)).whenever(productRepository).addProduct(any()) + doReturn(Pair(false, 0L)).whenever(productRepository).addProduct(any()) var successSnackbarShown = false viewModel.event.observeForever { @@ -310,7 +310,7 @@ class ProductDetailViewModel_AddFlowTest : BaseUnitTest() { testBlocking { // given doReturn(ProductAggregate(product)).whenever(productRepository).getProductAggregate(any()) - doReturn(Pair(true, 1L)).whenever(productRepository).addProduct(any()) + doReturn(Pair(true, 1L)).whenever(productRepository).addProduct(any()) var successSnackbarShown = false viewModel.event.observeForever { @@ -399,7 +399,7 @@ class ProductDetailViewModel_AddFlowTest : BaseUnitTest() { @Test fun `when a new product is saved, then assign the new id to ongoing image uploads`() = testBlocking { - doReturn(Pair(true, PRODUCT_REMOTE_ID)).whenever(productRepository).addProduct(any()) + doReturn(Pair(true, PRODUCT_REMOTE_ID)).whenever(productRepository).addProduct(any()) doReturn(product).whenever(productRepository).getProductAggregate(any()) savedState = ProductDetailFragmentArgs( mode = ProductDetailFragment.Mode.AddNewProduct @@ -454,7 +454,7 @@ class ProductDetailViewModel_AddFlowTest : BaseUnitTest() { @Test fun `given a product is under creation, when clicking on save product, then assign uploads to the new id`() = testBlocking { - doReturn(Pair(true, PRODUCT_REMOTE_ID)).whenever(productRepository).addProduct(any()) + doReturn(Pair(true, PRODUCT_REMOTE_ID)).whenever(productRepository).addProduct(any()) doReturn(product).whenever(productRepository).getProductAggregate(any()) viewModel.productDetailViewStateData.observeForever { _, _ -> } @@ -494,7 +494,7 @@ class ProductDetailViewModel_AddFlowTest : BaseUnitTest() { @Test fun `given product status is draft, when save is clicked, then save product with correct status`() = testBlocking { - whenever(productRepository.addProduct(any())).thenAnswer { it.arguments.first() as Product } + whenever(productRepository.addProduct(any())).thenAnswer { it.arguments.first() as Product } var viewState: ProductDetailViewModel.ProductDetailViewState? = null viewModel.productDetailViewStateData.observeForever { _, new -> viewState = new } From c99a54c816cca9aa01f09b445b4b1f8d126bab7b Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 10 Oct 2024 13:31:41 +0100 Subject: [PATCH 119/162] Add a test for confirming that local image is not re-uploaded on retries --- .../preview/AiProductPreviewViewModelTest.kt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModelTest.kt index df762f4ee72..ed27c617e20 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModelTest.kt @@ -23,6 +23,7 @@ import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.doAnswer import org.mockito.kotlin.doSuspendableAnswer import org.mockito.kotlin.mock +import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import java.util.Date @@ -274,6 +275,28 @@ class AiProductPreviewViewModelTest : BaseUnitTest() { } } + @Test + fun `given a local image uploaded successfully, when retrying after an error, then don't reupload the image`() = testBlocking { + setup( + args = AiProductPreviewFragmentArgs( + productFeatures = PRODUCT_FEATURES, + image = Image.LocalImage("path") + ) + ) { + whenever(uploadImage.invoke(any())) + .thenReturn(Result.success(Product.Image(1, "url", "url", Date()))) + whenever(saveAiGeneratedProduct.invoke(any(), anyOrNull())) + .thenReturn(Result.failure(Exception())) + } + + advanceUntilIdle() + viewModel.onSaveProductAsDraft() + advanceUntilIdle() + viewModel.onSaveProductAsDraft() + + verify(uploadImage, times(1)).invoke(Image.LocalImage("path")) + } + @Test fun `when product is saved successfully, then navigate to the product details`() = testBlocking { setup() From 795e3589dd171bc663c4308489d15147bb4bdf88 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 10 Oct 2024 13:07:36 +0100 Subject: [PATCH 120/162] Move the upload image logic to the save product usecase --- .../ui/products/ai/SaveAiGeneratedProduct.kt | 15 +++++++-- .../ai/preview/AiProductPreviewViewModel.kt | 31 +++++-------------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/SaveAiGeneratedProduct.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/SaveAiGeneratedProduct.kt index ed660c9ede7..9a09531213e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/SaveAiGeneratedProduct.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/SaveAiGeneratedProduct.kt @@ -1,7 +1,9 @@ package com.woocommerce.android.ui.products.ai +import com.woocommerce.android.model.Image import com.woocommerce.android.model.Product import com.woocommerce.android.ui.products.ProductStatus +import com.woocommerce.android.ui.products.ai.preview.UploadImage import com.woocommerce.android.ui.products.categories.ProductCategoriesRepository import com.woocommerce.android.ui.products.details.ProductDetailRepository import com.woocommerce.android.ui.products.tags.ProductTagsRepository @@ -11,13 +13,20 @@ import javax.inject.Inject class SaveAiGeneratedProduct @Inject constructor( private val productCategoriesRepository: ProductCategoriesRepository, private val productTagsRepository: ProductTagsRepository, - private val productDetailRepository: ProductDetailRepository + private val productDetailRepository: ProductDetailRepository, + private val uploadImage: UploadImage ) { @Suppress("ReturnCount") suspend operator fun invoke( product: Product, - selectedImage: Product.Image? + selectedImage: Image? ): Result { + // upload the selected image + val image = selectedImage?.let { uploadImage(it) }?.getOrElse { + WooLog.e(WooLog.T.PRODUCTS, "Failed to upload the selected image", it) + return Result.failure(it) + } + // Create missing categories val missingCategories = product.categories.filter { it.remoteCategoryId == 0L } val createdCategories = missingCategories @@ -55,7 +64,7 @@ class SaveAiGeneratedProduct @Inject constructor( val updatedProduct = product.copy( categories = product.categories - missingCategories.toSet() + createdCategories.orEmpty(), tags = product.tags - missingTags.toSet() + createdTags.orEmpty(), - images = listOfNotNull(selectedImage), + images = listOfNotNull(image), status = ProductStatus.DRAFT ) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModel.kt index ee8e637d81e..e0da0944d28 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModel.kt @@ -11,9 +11,8 @@ import com.woocommerce.android.analytics.AnalyticsEvent import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.extensions.combine +import com.woocommerce.android.media.MediaFilesRepository import com.woocommerce.android.model.Image -import com.woocommerce.android.model.Image.WPMediaLibraryImage -import com.woocommerce.android.model.Product import com.woocommerce.android.ui.products.ai.AIProductModel import com.woocommerce.android.ui.products.ai.BuildProductPreviewProperties import com.woocommerce.android.ui.products.ai.ProductPropertyCard @@ -42,7 +41,6 @@ class AiProductPreviewViewModel @Inject constructor( savedStateHandle: SavedStateHandle, private val buildProductPreviewProperties: BuildProductPreviewProperties, private val generateProductWithAI: GenerateProductWithAI, - private val uploadImage: UploadImage, private val analyticsTracker: AnalyticsTrackerWrapper, private val saveAiGeneratedProduct: SaveAiGeneratedProduct, private val resourceProvider: ResourceProvider @@ -229,9 +227,7 @@ class AiProductPreviewViewModel @Inject constructor( val product = generatedProduct.value?.getOrNull()?.toProduct(selectedVariant.value) ?: return savingProductState.value = SavingProductState.Loading viewModelScope.launch { - val image = uploadSelectedImage().onFailure { - return@launch - }.getOrNull() + val image = imageState.value.image val editedFields = userEditedFields.value saveAiGeneratedProduct( @@ -249,8 +245,12 @@ class AiProductPreviewViewModel @Inject constructor( analyticsTracker.track(AnalyticsEvent.PRODUCT_CREATION_AI_SAVE_AS_DRAFT_SUCCESS) }, onFailure = { + val messageRes = when (it) { + is MediaFilesRepository.MediaUploadException -> R.string.ai_product_creation_error_media_upload + else -> R.string.error_generic + } savingProductState.value = SavingProductState.Error( - messageRes = R.string.error_generic, + messageRes = messageRes, onRetryClick = ::onSaveProductAsDraft, onDismissClick = { savingProductState.value = SavingProductState.Idle } ) @@ -260,23 +260,6 @@ class AiProductPreviewViewModel @Inject constructor( } } - private suspend fun uploadSelectedImage(): Result { - val image = imageState.value.image ?: return Result.success(null) - return uploadImage(image) - .onSuccess { - imageState.value = imageState.value.copy( - image = WPMediaLibraryImage(content = it) - ) - } - .onFailure { - savingProductState.value = SavingProductState.Error( - messageRes = R.string.ai_product_creation_error_media_upload, - onRetryClick = ::onSaveProductAsDraft, - onDismissClick = { savingProductState.value = SavingProductState.Idle } - ) - } - } - private fun trackUndoEditClick(field: String) { analyticsTracker.track( AnalyticsEvent.PRODUCT_CREATION_AI_UNDO_EDIT_TAPPED, From cc6a05028b533994cf8a8475ca00eecb360c08e4 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 10 Oct 2024 13:18:37 +0100 Subject: [PATCH 121/162] Refactor logic to allow keeping track of the uploaded image --- .../ui/products/ai/SaveAiGeneratedProduct.kt | 22 +++-- .../ai/preview/AiProductPreviewViewModel.kt | 31 ++++--- .../preview/AiProductPreviewViewModelTest.kt | 82 +++++++------------ 3 files changed, 67 insertions(+), 68 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/SaveAiGeneratedProduct.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/SaveAiGeneratedProduct.kt index 9a09531213e..47c0e3e7368 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/SaveAiGeneratedProduct.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/SaveAiGeneratedProduct.kt @@ -20,11 +20,11 @@ class SaveAiGeneratedProduct @Inject constructor( suspend operator fun invoke( product: Product, selectedImage: Image? - ): Result { + ): AiProductSaveResult { // upload the selected image val image = selectedImage?.let { uploadImage(it) }?.getOrElse { WooLog.e(WooLog.T.PRODUCTS, "Failed to upload the selected image", it) - return Result.failure(it) + return AiProductSaveResult.Failure.UploadImageFailure } // Create missing categories @@ -40,7 +40,7 @@ class SaveAiGeneratedProduct @Inject constructor( onSuccess = { it }, onFailure = { WooLog.e(WooLog.T.PRODUCTS, "Failed to add product categories", it) - return Result.failure(it) + return AiProductSaveResult.Failure.Generic(image?.asWPMediaLibraryImage()) } ) @@ -57,7 +57,7 @@ class SaveAiGeneratedProduct @Inject constructor( onSuccess = { it }, onFailure = { WooLog.e(WooLog.T.PRODUCTS, "Failed to add product tags", it) - return Result.failure(it) + return AiProductSaveResult.Failure.Generic(image?.asWPMediaLibraryImage()) } ) @@ -70,10 +70,20 @@ class SaveAiGeneratedProduct @Inject constructor( return productDetailRepository.addProduct(updatedProduct).let { (success, productId) -> if (success) { - Result.success(productId) + AiProductSaveResult.Success(productId) } else { - Result.failure(Exception("Failed to save the AI generated product")) + AiProductSaveResult.Failure.Generic(image?.asWPMediaLibraryImage()) } } } + + private fun Product.Image.asWPMediaLibraryImage() = Image.WPMediaLibraryImage(this) +} + +sealed interface AiProductSaveResult { + data class Success(val productId: Long) : AiProductSaveResult + sealed interface Failure : AiProductSaveResult { + data object UploadImageFailure : Failure + data class Generic(val uploadedImage: Image.WPMediaLibraryImage? = null) : Failure + } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModel.kt index e0da0944d28..93de74cbd64 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModel.kt @@ -11,9 +11,9 @@ import com.woocommerce.android.analytics.AnalyticsEvent import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.extensions.combine -import com.woocommerce.android.media.MediaFilesRepository import com.woocommerce.android.model.Image import com.woocommerce.android.ui.products.ai.AIProductModel +import com.woocommerce.android.ui.products.ai.AiProductSaveResult import com.woocommerce.android.ui.products.ai.BuildProductPreviewProperties import com.woocommerce.android.ui.products.ai.ProductPropertyCard import com.woocommerce.android.ui.products.ai.SaveAiGeneratedProduct @@ -230,7 +230,7 @@ class AiProductPreviewViewModel @Inject constructor( val image = imageState.value.image val editedFields = userEditedFields.value - saveAiGeneratedProduct( + val result = saveAiGeneratedProduct( product.copy( name = editedFields.names[selectedVariant.value] ?: product.name, description = editedFields.descriptions[selectedVariant.value] ?: product.description, @@ -238,17 +238,28 @@ class AiProductPreviewViewModel @Inject constructor( ?: product.shortDescription ), image - ).fold( - onSuccess = { productId -> + ) + + when (result) { + is AiProductSaveResult.Success -> { savingProductState.value = SavingProductState.Success - triggerEvent(NavigateToProductDetailScreen(productId)) + triggerEvent(NavigateToProductDetailScreen(result.productId)) analyticsTracker.track(AnalyticsEvent.PRODUCT_CREATION_AI_SAVE_AS_DRAFT_SUCCESS) - }, - onFailure = { - val messageRes = when (it) { - is MediaFilesRepository.MediaUploadException -> R.string.ai_product_creation_error_media_upload + } + + is AiProductSaveResult.Failure -> { + // Keep track of the uploaded image to avoid re-uploading it on retry + (result as? AiProductSaveResult.Failure.Generic)?.uploadedImage?.let { + imageState.value = imageState.value.copy(image = it) + } + + val messageRes = when (result) { + is AiProductSaveResult.Failure.UploadImageFailure -> + R.string.ai_product_creation_error_media_upload + else -> R.string.error_generic } + savingProductState.value = SavingProductState.Error( messageRes = messageRes, onRetryClick = ::onSaveProductAsDraft, @@ -256,7 +267,7 @@ class AiProductPreviewViewModel @Inject constructor( ) analyticsTracker.track(AnalyticsEvent.PRODUCT_CREATION_AI_SAVE_AS_DRAFT_FAILED) } - ) + } } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModelTest.kt index ed27c617e20..1e4b9c965c4 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/ai/preview/AiProductPreviewViewModelTest.kt @@ -5,6 +5,7 @@ import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.model.Image import com.woocommerce.android.model.Product import com.woocommerce.android.ui.products.ai.AIProductModel +import com.woocommerce.android.ui.products.ai.AiProductSaveResult import com.woocommerce.android.ui.products.ai.BuildProductPreviewProperties import com.woocommerce.android.ui.products.ai.SaveAiGeneratedProduct import com.woocommerce.android.ui.products.ai.components.ImageAction @@ -20,6 +21,7 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.Test import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.argThat import org.mockito.kotlin.doAnswer import org.mockito.kotlin.doSuspendableAnswer import org.mockito.kotlin.mock @@ -43,16 +45,10 @@ class AiProductPreviewViewModelTest : BaseUnitTest() { Result.success(SAMPLE_PRODUCT) } } - private val uploadImage: UploadImage = mock { - onBlocking { invoke(any()) } doSuspendableAnswer { - delay(100) - Result.success(SAMPLE_UPLOADED_IMAGE) - } - } private val saveAiGeneratedProduct: SaveAiGeneratedProduct = mock { onBlocking { invoke(any(), anyOrNull()) } doSuspendableAnswer { delay(100) - Result.success(1L) + AiProductSaveResult.Success(1L) } } private val analyticsTracker: AnalyticsTrackerWrapper = mock() @@ -74,7 +70,6 @@ class AiProductPreviewViewModelTest : BaseUnitTest() { savedStateHandle = args.toSavedStateHandle(), buildProductPreviewProperties = buildProductPreviewProperties, generateProductWithAI = generateProductWithAI, - uploadImage = uploadImage, analyticsTracker = analyticsTracker, saveAiGeneratedProduct = saveAiGeneratedProduct, resourceProvider = resourceProvider, @@ -227,30 +222,6 @@ class AiProductPreviewViewModelTest : BaseUnitTest() { assertThat(event).isInstanceOf(MultiLiveEvent.Event.ShowUndoSnackbar::class.java) } - @Test - fun `given a local image, when the user taps on save, then upload the image`() = testBlocking { - setup( - args = AiProductPreviewFragmentArgs( - productFeatures = PRODUCT_FEATURES, - image = Image.LocalImage("path") - ) - ) - - val viewState = viewModel.state.runAndCaptureValues { - advanceUntilIdle() - viewModel.onSaveProductAsDraft() - advanceUntilIdle() - }.last() - - verify(uploadImage).invoke(Image.LocalImage("path")) - val successState = viewState as AiProductPreviewViewModel.State.Success - assertThat(successState.imageState).isEqualTo( - AiProductPreviewViewModel.ImageState( - image = Image.WPMediaLibraryImage(SAMPLE_UPLOADED_IMAGE) - ) - ) - } - @Test fun `given a local image, when the image upload fails, then show an error`() = testBlocking { setup( @@ -259,7 +230,8 @@ class AiProductPreviewViewModelTest : BaseUnitTest() { image = Image.LocalImage("path") ) ) { - whenever(uploadImage.invoke(any())).thenReturn(Result.failure(Exception())) + whenever(saveAiGeneratedProduct.invoke(any(), any())) + .thenReturn(AiProductSaveResult.Failure.UploadImageFailure) } val viewState = viewModel.state.runAndCaptureValues { @@ -276,26 +248,27 @@ class AiProductPreviewViewModelTest : BaseUnitTest() { } @Test - fun `given a local image uploaded successfully, when retrying after an error, then don't reupload the image`() = testBlocking { - setup( - args = AiProductPreviewFragmentArgs( - productFeatures = PRODUCT_FEATURES, - image = Image.LocalImage("path") - ) - ) { - whenever(uploadImage.invoke(any())) - .thenReturn(Result.success(Product.Image(1, "url", "url", Date()))) - whenever(saveAiGeneratedProduct.invoke(any(), anyOrNull())) - .thenReturn(Result.failure(Exception())) - } + fun `given a local image uploaded successfully, when retrying after an error, then don't reupload the image`() = + testBlocking { + setup( + args = AiProductPreviewFragmentArgs( + productFeatures = PRODUCT_FEATURES, + image = Image.LocalImage("path") + ) + ) { + whenever(saveAiGeneratedProduct.invoke(any(), anyOrNull())) + .thenReturn(AiProductSaveResult.Failure.Generic(Image.WPMediaLibraryImage(SAMPLE_UPLOADED_IMAGE))) + .thenReturn(AiProductSaveResult.Success(1L)) + } - advanceUntilIdle() - viewModel.onSaveProductAsDraft() - advanceUntilIdle() - viewModel.onSaveProductAsDraft() + advanceUntilIdle() + viewModel.onSaveProductAsDraft() + advanceUntilIdle() + viewModel.onSaveProductAsDraft() - verify(uploadImage, times(1)).invoke(Image.LocalImage("path")) - } + verify(saveAiGeneratedProduct, times(1)).invoke(any(), argThat { this is Image.LocalImage }) + verify(saveAiGeneratedProduct, times(1)).invoke(any(), argThat { this is Image.WPMediaLibraryImage }) + } @Test fun `when product is saved successfully, then navigate to the product details`() = testBlocking { @@ -313,7 +286,12 @@ class AiProductPreviewViewModelTest : BaseUnitTest() { @Test fun `when product saving fails, then show an error`() = testBlocking { setup { - whenever(saveAiGeneratedProduct.invoke(any(), anyOrNull())).thenReturn(Result.failure(Exception())) + whenever( + saveAiGeneratedProduct.invoke( + any(), + anyOrNull() + ) + ).thenReturn(AiProductSaveResult.Failure.Generic()) } val viewState = viewModel.state.runAndCaptureValues { From cec2abb1ea555dbe5e27234da14ac815e8450e3c Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 10 Oct 2024 17:50:37 +0100 Subject: [PATCH 122/162] Update logic of saving to handle the preparation requests in parallel --- .../ui/products/ai/SaveAiGeneratedProduct.kt | 101 +++++++++++------- 1 file changed, 63 insertions(+), 38 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/SaveAiGeneratedProduct.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/SaveAiGeneratedProduct.kt index 47c0e3e7368..e3b3c7c70d8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/SaveAiGeneratedProduct.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/SaveAiGeneratedProduct.kt @@ -2,12 +2,17 @@ package com.woocommerce.android.ui.products.ai import com.woocommerce.android.model.Image import com.woocommerce.android.model.Product +import com.woocommerce.android.model.ProductCategory +import com.woocommerce.android.model.ProductTag import com.woocommerce.android.ui.products.ProductStatus import com.woocommerce.android.ui.products.ai.preview.UploadImage import com.woocommerce.android.ui.products.categories.ProductCategoriesRepository import com.woocommerce.android.ui.products.details.ProductDetailRepository import com.woocommerce.android.ui.products.tags.ProductTagsRepository import com.woocommerce.android.util.WooLog +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope import javax.inject.Inject class SaveAiGeneratedProduct @Inject constructor( @@ -16,50 +21,37 @@ class SaveAiGeneratedProduct @Inject constructor( private val productDetailRepository: ProductDetailRepository, private val uploadImage: UploadImage ) { - @Suppress("ReturnCount") suspend operator fun invoke( product: Product, selectedImage: Image? - ): AiProductSaveResult { - // upload the selected image - val image = selectedImage?.let { uploadImage(it) }?.getOrElse { - WooLog.e(WooLog.T.PRODUCTS, "Failed to upload the selected image", it) - return AiProductSaveResult.Failure.UploadImageFailure - } + ): AiProductSaveResult = coroutineScope { + // Start uploading the selected image + val imageTask = selectedImage?.let { selectedImage -> startUploadingImage(selectedImage) } - // Create missing categories val missingCategories = product.categories.filter { it.remoteCategoryId == 0L } - val createdCategories = missingCategories - .takeIf { it.isNotEmpty() }?.let { productCategories -> - WooLog.d( - tag = WooLog.T.PRODUCTS, - message = "Create the missing product categories ${productCategories.map { it.name }}" - ) - productCategoriesRepository.addProductCategories(productCategories) - }?.fold( - onSuccess = { it }, - onFailure = { - WooLog.e(WooLog.T.PRODUCTS, "Failed to add product categories", it) - return AiProductSaveResult.Failure.Generic(image?.asWPMediaLibraryImage()) - } - ) + // Start create missing categories + val categoriesTask = missingCategories + .takeIf { it.isNotEmpty() } + ?.let { productCategories -> startCreatingCategories(productCategories) } - // Create missing tags + // Start Create missing tags val missingTags = product.tags.filter { it.remoteTagId == 0L } - val createdTags = missingTags - .takeIf { it.isNotEmpty() }?.let { productTags -> - WooLog.d( - tag = WooLog.T.PRODUCTS, - message = "Create the missing product tags ${productTags.map { it.name }}" - ) - productTagsRepository.addProductTags(productTags.map { it.name }) - }?.fold( - onSuccess = { it }, - onFailure = { - WooLog.e(WooLog.T.PRODUCTS, "Failed to add product tags", it) - return AiProductSaveResult.Failure.Generic(image?.asWPMediaLibraryImage()) - } - ) + val tagsTask = missingTags + .takeIf { it.isNotEmpty() } + ?.let { productTags -> startCreatingTags(productTags) } + + // Wait for the image to be uploaded + val image = imageTask?.await()?.getOrElse { + return@coroutineScope AiProductSaveResult.Failure.UploadImageFailure + } + + // Wait for the created categories and tags + val createdCategories = categoriesTask?.await()?.getOrElse { + return@coroutineScope AiProductSaveResult.Failure.Generic(image?.asWPMediaLibraryImage()) + } + val createdTags = tagsTask?.await()?.getOrElse { + return@coroutineScope AiProductSaveResult.Failure.Generic(image?.asWPMediaLibraryImage()) + } val updatedProduct = product.copy( categories = product.categories - missingCategories.toSet() + createdCategories.orEmpty(), @@ -68,15 +60,48 @@ class SaveAiGeneratedProduct @Inject constructor( status = ProductStatus.DRAFT ) - return productDetailRepository.addProduct(updatedProduct).let { (success, productId) -> + productDetailRepository.addProduct(updatedProduct).let { (success, productId) -> if (success) { + WooLog.d( + tag = WooLog.T.PRODUCTS, + message = "Successfully saved the AI generated product as draft with id $productId" + ) AiProductSaveResult.Success(productId) } else { + WooLog.e(WooLog.T.PRODUCTS, "Failed to save the AI generated product as draft") AiProductSaveResult.Failure.Generic(image?.asWPMediaLibraryImage()) } } } + private fun CoroutineScope.startUploadingImage(image: Image) = async { + uploadImage(image).onFailure { + WooLog.e(WooLog.T.PRODUCTS, "Failed to upload the selected image", it) + } + } + + private fun CoroutineScope.startCreatingCategories(categories: List) = async { + WooLog.d( + tag = WooLog.T.PRODUCTS, + message = "Create the missing product categories ${categories.map { it.name }}" + ) + productCategoriesRepository.addProductCategories(categories) + .onFailure { + WooLog.e(WooLog.T.PRODUCTS, "Failed to add product categories", it) + } + } + + private fun CoroutineScope.startCreatingTags(tags: List) = async { + WooLog.d( + tag = WooLog.T.PRODUCTS, + message = "Create the missing product tags ${tags.map { it.name }}" + ) + productTagsRepository.addProductTags(tags.map { it.name }) + .onFailure { + WooLog.e(WooLog.T.PRODUCTS, "Failed to add product tags", it) + } + } + private fun Product.Image.asWPMediaLibraryImage() = Image.WPMediaLibraryImage(this) } From 4fd66b2387d87edf2b5a4dc21d609708929c5bbd Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 14 Oct 2024 18:30:00 +0300 Subject: [PATCH 123/162] Deps: Update fluxc to 2.99.0 Release Notes: https://github.com/wordpress-mobile/ WordPress-FluxC-Android/releases/tag/2.99.0 The actual update was done as part of 55313270f6245ce94cada95f2f14773fc47ecaa9, but after merging this branch with 'trunk', to fully resolved this one conflict, the FluxC update needs to be redone, this time within 'libs.versions.toml'. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e3a3929387c..5b1ce5c95bc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -85,7 +85,7 @@ stripe-terminal = '3.7.1' tinder-statemachine = '0.2.0' wiremock = '2.26.3' wordpress-aztec = 'v2.1.4' -wordpress-fluxc = 'trunk-7ad6ce4c250ba435d8d8c7feb898bceb259fb007' +wordpress-fluxc = '2.99.0' wordpress-login = '1.18.0' wordpress-libaddressinput = '0.0.2' wordpress-mediapicker = '0.3.1' From c11e208823a59ab731900c450ab09cc27ccc475a Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 14 Oct 2024 18:39:02 +0300 Subject: [PATCH 124/162] Deps: Add an explicit version to androidx wear tiles dependencies As per the c27691161b777412240b6afb86a614072a472dc1 commit, these two 'androidx-wear-tiles' dependencies had no associated version on them. This could be problematic, non deterministic and could cause trouble moving forward. As such, and as per the PR comment suggestion below, this commit adds the most appropriate '1.3.0' version, which is also the one currently being implicitly set transitively by the 'horologist' dependencies themselves. PR Comment: https://github.com/woocommerce/woocommerce-android/pull/ 12765#discussion_r1795224428 --- gradle/libs.versions.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5b1ce5c95bc..6afe89f4323 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,6 +29,7 @@ androidx-test-main = '1.4.0' androidx-test-uiautomator = '2.2.0' androidx-transition = '1.5.1' androidx-wear-compose = '1.3.1' +androidx-wear-tiles = '1.3.0' androidx-wear-tooling = '1.0.0' androidx-wear-watchface = '1.2.1' androidx-work = '2.7.1' @@ -151,8 +152,8 @@ androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiaut androidx-transition = { group = "androidx.transition", name = "transition", version.ref = "androidx-transition" } androidx-wear-compose-material = { group = "androidx.wear.compose", name = "compose-material", version.ref = "androidx-wear-compose" } androidx-wear-compose-foundation = { group = "androidx.wear.compose", name = "compose-foundation", version.ref = "androidx-wear-compose" } -androidx-wear-tiles-main = { group = "androidx.wear.tiles", name = "tiles" } -androidx-wear-tiles-material = { group = "androidx.wear.tiles", name = "tiles-material" } +androidx-wear-tiles-main = { group = "androidx.wear.tiles", name = "tiles", version.ref = "androidx-wear-tiles" } +androidx-wear-tiles-material = { group = "androidx.wear.tiles", name = "tiles-material", version.ref = "androidx-wear-tiles" } androidx-wear-tooling-preview = { group = "androidx.wear", name = "wear-tooling-preview", version.ref = "androidx-wear-tooling" } androidx-wear-watchface-complications-data-source-ktx = { group = "androidx.wear.watchface", name = "watchface-complications-data-source-ktx", version.ref = "androidx-wear-watchface" } androidx-work-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "androidx-work" } From 970ec5a4257e9dc2e07bdc5bc348f6bef3d54abf Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 14 Oct 2024 18:54:39 +0300 Subject: [PATCH 125/162] Refactor: Revert to previous simpler syntax of alias plugin apply false PR Comment: https://github.com/woocommerce/woocommerce-android/pull/ 12765#discussion_r1795251645 --- build.gradle | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index e87e12c2135..b5df01ef33e 100644 --- a/build.gradle +++ b/build.gradle @@ -6,15 +6,15 @@ plugins { alias(libs.plugins.detekt) alias(libs.plugins.automattic.measure.builds) alias(libs.plugins.dependency.analysis) - alias(libs.plugins.android.application).apply(false) - alias(libs.plugins.android.library).apply(false) - alias(libs.plugins.android.test).apply(false) - alias(libs.plugins.kotlin.android).apply(false) - alias(libs.plugins.kotlin.parcelize).apply(false) - alias(libs.plugins.google.dagger.hilt).apply(false) - alias(libs.plugins.androidx.navigation.safeargs).apply(false) - alias(libs.plugins.google.services).apply(false) - alias(libs.plugins.ksp).apply(false) + alias(libs.plugins.android.application) apply false + alias(libs.plugins.android.library) apply false + alias(libs.plugins.android.test) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlin.parcelize) apply false + alias(libs.plugins.google.dagger.hilt) apply false + alias(libs.plugins.androidx.navigation.safeargs) apply false + alias(libs.plugins.google.services) apply false + alias(libs.plugins.ksp) apply false } measureBuilds { From fb6ac9ef616ad6fd977dfe4e94b55c6b8480d97d Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Mon, 14 Oct 2024 20:03:13 +0200 Subject: [PATCH 126/162] Revert "Fix navigation issue when triggering blaze from product detail" This reverts commit d1b1763998aad8c3f90dbf4ed9a61915a9f36d22. --- .../BlazeCampaignCreationDispatcher.kt | 22 +++----- .../BlazeCampaignCreationIntroFragment.kt | 54 +++++++++++-------- .../nav_graph_blaze_campaign_creation.xml | 42 ++++++++++++++- .../main/res/navigation/nav_graph_main.xml | 45 ---------------- 4 files changed, 81 insertions(+), 82 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcher.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcher.kt index 6b1fe50ff90..817dc891260 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcher.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcher.kt @@ -14,7 +14,6 @@ import com.woocommerce.android.extensions.navigateSafely import com.woocommerce.android.ui.base.BaseFragment import com.woocommerce.android.ui.blaze.BlazeRepository import com.woocommerce.android.ui.blaze.BlazeUrlsHelper.BlazeFlowSource -import com.woocommerce.android.ui.blaze.BlazeUrlsHelper.BlazeFlowSource.INTRO_VIEW import com.woocommerce.android.ui.blaze.creation.intro.BlazeCampaignCreationIntroFragmentArgs import com.woocommerce.android.ui.blaze.creation.preview.BlazeCampaignCreationPreviewFragmentArgs import com.woocommerce.android.ui.blaze.notification.AbandonedCampaignReminder @@ -59,7 +58,7 @@ class BlazeCampaignCreationDispatcher @Inject constructor( handler: (BlazeCampaignCreationDispatcherEvent) -> Unit = ::handleEvent ) { when { - blazeRepository.getMostRecentCampaign() == null && source != INTRO_VIEW -> handler( + blazeRepository.getMostRecentCampaign() == null -> handler( BlazeCampaignCreationDispatcherEvent.ShowBlazeCampaignCreationIntro(productId, source) ) @@ -128,20 +127,12 @@ class BlazeCampaignCreationDispatcher @Inject constructor( } private fun BaseFragment.showIntro(productId: Long?, blazeSource: BlazeFlowSource) { - findNavController().navigate( - resId = R.id.blazeCampaignCreationIntroFragment, - args = BlazeCampaignCreationIntroFragmentArgs( + findNavController().navigateToBlazeGraph( + startDestination = R.id.blazeCampaignCreationIntroFragment, + bundle = BlazeCampaignCreationIntroFragmentArgs( productId = productId ?: -1L, source = blazeSource - ).toBundle(), - navOptions = navOptions { - anim { - enter = R.anim.default_enter_anim - exit = R.anim.default_exit_anim - popEnter = R.anim.default_pop_enter_anim - popExit = R.anim.default_pop_exit_anim - } - } + ).toBundle() ) } @@ -156,6 +147,9 @@ class BlazeCampaignCreationDispatcher @Inject constructor( } private fun BaseFragment.showProductSelector() { + val navGraph = findNavController().graph.findNode(R.id.nav_graph_blaze_campaign_creation) as NavGraph + navGraph.setStartDestination(R.id.nav_graph_product_selector) + findNavController().navigateToBlazeGraph( startDestination = R.id.nav_graph_product_selector, bundle = ProductSelectorFragmentArgs( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/intro/BlazeCampaignCreationIntroFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/intro/BlazeCampaignCreationIntroFragment.kt index 24ebc0f4772..746889b3af1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/intro/BlazeCampaignCreationIntroFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/intro/BlazeCampaignCreationIntroFragment.kt @@ -5,28 +5,24 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.viewModels -import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController +import androidx.navigation.navOptions +import com.woocommerce.android.R import com.woocommerce.android.extensions.handleResult +import com.woocommerce.android.extensions.navigateSafely import com.woocommerce.android.ui.base.BaseFragment -import com.woocommerce.android.ui.blaze.BlazeUrlsHelper.BlazeFlowSource -import com.woocommerce.android.ui.blaze.creation.BlazeCampaignCreationDispatcher import com.woocommerce.android.ui.compose.composeView import com.woocommerce.android.ui.main.AppBarStatus import com.woocommerce.android.ui.products.selector.ProductSelectorFragment +import com.woocommerce.android.ui.products.selector.ProductSelectorViewModel import com.woocommerce.android.ui.products.selector.ProductSelectorViewModel.SelectedItem import com.woocommerce.android.viewmodel.MultiLiveEvent import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch -import javax.inject.Inject @AndroidEntryPoint class BlazeCampaignCreationIntroFragment : BaseFragment() { private val viewModel: BlazeCampaignCreationIntroViewModel by viewModels() - @Inject - lateinit var blazeCampaignCreationDispatcher: BlazeCampaignCreationDispatcher - override val activityAppBarStatus: AppBarStatus get() = AppBarStatus.Hidden @@ -37,7 +33,6 @@ class BlazeCampaignCreationIntroFragment : BaseFragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - blazeCampaignCreationDispatcher.attachFragment(this, BlazeFlowSource.INTRO_VIEW) handleEvents() handleResults() } @@ -45,29 +40,44 @@ class BlazeCampaignCreationIntroFragment : BaseFragment() { private fun handleEvents() { viewModel.event.observe(viewLifecycleOwner) { event -> when (event) { - is BlazeCampaignCreationIntroViewModel.ShowCampaignCreationForm -> - startBlazeCampaignCreationFlow(event.source, event.productId) + is BlazeCampaignCreationIntroViewModel.ShowCampaignCreationForm -> { + findNavController().navigateSafely( + directions = BlazeCampaignCreationIntroFragmentDirections + .actionBlazeCampaignCreationIntroFragmentToBlazeCampaignCreationPreviewFragment( + productId = event.productId, + source = event.source + ), + navOptions = navOptions { + popUpTo(R.id.blazeCampaignCreationIntroFragment) { inclusive = true } + } + ) + } - is BlazeCampaignCreationIntroViewModel.ShowProductSelector -> - startBlazeCampaignCreationFlow(BlazeFlowSource.INTRO_VIEW) + is BlazeCampaignCreationIntroViewModel.ShowProductSelector -> { + navigateToProductSelectorScreen() + } is MultiLiveEvent.Event.Exit -> findNavController().navigateUp() } } } - private fun startBlazeCampaignCreationFlow(source: BlazeFlowSource, productId: Long? = null) { - lifecycleScope.launch { - blazeCampaignCreationDispatcher.startCampaignCreation( - productId = productId, - source = source - ) - } - } - private fun handleResults() { handleResult>(ProductSelectorFragment.PRODUCT_SELECTOR_RESULT) { viewModel.onProductSelected(it.first().id) } } + + private fun navigateToProductSelectorScreen() { + findNavController().navigateSafely( + BlazeCampaignCreationIntroFragmentDirections + .actionBlazeCampaignCreationIntroFragmentToNavGraphProductSelector( + selectionMode = ProductSelectorViewModel.SelectionMode.SINGLE, + selectionHandling = ProductSelectorViewModel.SelectionHandling.SIMPLE, + screenTitleOverride = getString(R.string.blaze_campaign_creation_product_selector_title), + ctaButtonTextOverride = getString(R.string.blaze_campaign_creation_product_selector_cta_button), + productSelectorFlow = ProductSelectorViewModel.ProductSelectorFlow.Undefined + ) + ) + } } diff --git a/WooCommerce/src/main/res/navigation/nav_graph_blaze_campaign_creation.xml b/WooCommerce/src/main/res/navigation/nav_graph_blaze_campaign_creation.xml index 978eee4bd5b..b89e972fc52 100644 --- a/WooCommerce/src/main/res/navigation/nav_graph_blaze_campaign_creation.xml +++ b/WooCommerce/src/main/res/navigation/nav_graph_blaze_campaign_creation.xml @@ -2,10 +2,50 @@ + app:startDestination="@id/blazeCampaignCreationIntroFragment"> + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - From 235e70eeed3757764e946020f82b8c1b6533f472 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Mon, 14 Oct 2024 20:33:54 +0200 Subject: [PATCH 127/162] Fix navigation issue when triggering Blaze from product detail --- .../ui/blaze/creation/BlazeCampaignCreationDispatcher.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcher.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcher.kt index 817dc891260..6de3b8ec9aa 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcher.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcher.kt @@ -147,9 +147,6 @@ class BlazeCampaignCreationDispatcher @Inject constructor( } private fun BaseFragment.showProductSelector() { - val navGraph = findNavController().graph.findNode(R.id.nav_graph_blaze_campaign_creation) as NavGraph - navGraph.setStartDestination(R.id.nav_graph_product_selector) - findNavController().navigateToBlazeGraph( startDestination = R.id.nav_graph_product_selector, bundle = ProductSelectorFragmentArgs( @@ -166,7 +163,10 @@ class BlazeCampaignCreationDispatcher @Inject constructor( startDestination: Int, bundle: android.os.Bundle? = null, ) { - val navGraph = graph.findNode(R.id.nav_graph_blaze_campaign_creation) as NavGraph + // Retrieve the parent navgraph. + // currentDestination should never be null, but we're being cautious here by falling back to the main graph. + val parentGraph = currentDestination?.parent ?: graph + val navGraph = parentGraph.findNode(R.id.nav_graph_blaze_campaign_creation) as NavGraph navGraph.setStartDestination(startDestination) navigateSafely( From babceceebaa71d119668b6562ca4b78918286abd Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Mon, 14 Oct 2024 21:20:57 +0200 Subject: [PATCH 128/162] Remove unnecessary test --- .../BlazeCampaignCreationDispatcherTests.kt | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcherTests.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcherTests.kt index 975e2b96933..eab49ee32fe 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcherTests.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/BlazeCampaignCreationDispatcherTests.kt @@ -123,25 +123,4 @@ class BlazeCampaignCreationDispatcherTests : BaseUnitTest() { ) ) } - - @Test - fun `given no campaign yet, when starting the flow from intro screen, then start flow without intro`() = - testBlocking { - setup { - whenever(blazeRepository.getMostRecentCampaign()).thenReturn(null) - } - - var event: BlazeCampaignCreationDispatcherEvent? = null - dispatcher.startCampaignCreation( - source = BlazeFlowSource.INTRO_VIEW, - productId = 1L - ) { event = it } - - assertThat(event).isEqualTo( - BlazeCampaignCreationDispatcherEvent.ShowBlazeCampaignCreationForm( - productId = 1L, - blazeSource = BlazeFlowSource.INTRO_VIEW - ) - ) - } } From f97e1f60d934e251fca7aec428144f9d5e18df28 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Tue, 15 Oct 2024 14:56:47 +0300 Subject: [PATCH 129/162] Add ObjectiveViewState to BlazeCampaignObjectiveViewModel --- .../objective/BlazeCampaignObjectiveViewModel.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveViewModel.kt index 2d617ba22c9..c4a7f3c0822 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveViewModel.kt @@ -13,4 +13,20 @@ class BlazeCampaignObjectiveViewModel @Inject constructor( fun onDismissClick() { triggerEvent(Exit) } + + data class ObjectiveViewState( + val items: List, + val selectedItemId: String? = null, + val isStoreSelectionButtonToggled: Boolean = false, + ) { + val isSaveButtonEnabled: Boolean + get() = selectedItemId != null + } + + data class ObjectiveItem( + val id: String, + val title: String, + val description: String, + val suitableForDescription: String, + ) } From 2d7b2688cb0d060aeaa76f5dbbdad9d9570abbe6 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Tue, 15 Oct 2024 14:59:12 +0300 Subject: [PATCH 130/162] Add BlazeCampaignObjectiveScreen --- .../BlazeCampaignObjectiveFragment.kt | 3 +- .../objective/BlazeCampaignObjectiveScreen.kt | 225 ++++++++++++++++++ .../BlazeCampaignObjectiveViewModel.kt | 39 ++- .../src/main/res/values-night/colors_base.xml | 1 + .../src/main/res/values/colors_base.xml | 1 + WooCommerce/src/main/res/values/strings.xml | 2 + 6 files changed, 268 insertions(+), 3 deletions(-) create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveScreen.kt diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveFragment.kt index f5224873a8a..8ce626df446 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.compose.material.Text import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import com.woocommerce.android.ui.base.BaseFragment @@ -22,7 +21,7 @@ class BlazeCampaignObjectiveFragment : BaseFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return composeView { - Text(text = "Select Campaign Objective") + BlazeCampaignObjectiveScreen(viewModel) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveScreen.kt new file mode 100644 index 00000000000..8a78c721821 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveScreen.kt @@ -0,0 +1,225 @@ +package com.woocommerce.android.ui.blaze.creation.objective + +import androidx.compose.animation.Crossfade +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.runtime.Composable +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.text.font.FontWeight +import com.woocommerce.android.R +import com.woocommerce.android.ui.blaze.creation.objective.BlazeCampaignObjectiveViewModel.ObjectiveItem +import com.woocommerce.android.ui.blaze.creation.objective.BlazeCampaignObjectiveViewModel.ObjectiveViewState +import com.woocommerce.android.ui.compose.annotatedStringRes +import com.woocommerce.android.ui.compose.component.Toolbar +import com.woocommerce.android.ui.compose.component.WCTextButton +import com.woocommerce.android.ui.compose.preview.LightDarkThemePreviews + +@Composable +fun BlazeCampaignObjectiveScreen(viewModel: BlazeCampaignObjectiveViewModel) { + viewModel.viewState.observeAsState().value?.let { state -> + ObjectiveScreen( + state = state, + onBackPressed = viewModel::onBackPressed, + onSaveTapped = viewModel::onSaveTapped, + onObjectiveTapped = viewModel::onItemToggled + ) + } +} + +@Composable +private fun ObjectiveScreen( + state: ObjectiveViewState, + onBackPressed: () -> Unit, + onSaveTapped: () -> Unit, + onObjectiveTapped: (ObjectiveItem) -> Unit, +) { + Scaffold( + topBar = { + Toolbar( + title = stringResource(id = R.string.blaze_campaign_preview_details_objective), + onNavigationButtonClick = onBackPressed, + navigationIcon = Icons.AutoMirrored.Filled.ArrowBack, + actions = { + WCTextButton( + onClick = onSaveTapped, + enabled = state.isSaveButtonEnabled, + text = stringResource(R.string.save) + ) + } + ) + }, + modifier = Modifier.background(MaterialTheme.colors.surface) + ) { paddingValues -> + Column( + modifier = Modifier + .background(MaterialTheme.colors.surface) + .padding(paddingValues) + .fillMaxSize() + ) { + LazyColumn( + modifier = Modifier.padding(vertical = dimensionResource(id = R.dimen.minor_50)) + ) { + items(state.items) { + ObjectiveListItem( + it.title, + it.description, + it.suitableForDescription, + onClickLabel = stringResource( + id = R.string.blaze_campaign_objective_select_objective_label, + it.title + ), + isSelected = it.id == state.selectedItemId, + ) { + onObjectiveTapped(it) + } + } + } + } + } +} + +@Composable +fun ObjectiveListItem( + title: String, + description: String, + suitableForDescription: String, + isSelected: Boolean, + onClickLabel: String?, + onItemClick: () -> Unit, +) { + val roundedShape = RoundedCornerShape(dimensionResource(id = R.dimen.minor_100)) + val borderSize = if (isSelected) R.dimen.minor_25 else R.dimen.minor_10 + val borderColor = if (isSelected) R.color.woo_purple_60 else R.color.woo_gray_5 + val modifier = Modifier + .fillMaxWidth() + .padding( + horizontal = dimensionResource(id = R.dimen.major_100), + vertical = dimensionResource(id = R.dimen.minor_50) + ) + .clip(roundedShape) + .clickable( + role = Role.Button, + onClick = { onItemClick() }, + onClickLabel = onClickLabel + ) + .border( + width = dimensionResource(id = borderSize), + color = colorResource(id = borderColor), + shape = roundedShape + ) + + Row( + modifier = if (isSelected) { + modifier.then(Modifier.background(colorResource(id = R.color.blaze_campaign_objective_item_background))) + } else { + modifier + }.padding(dimensionResource(id = R.dimen.major_100)), + horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.major_100)) + ) { + val selectionDrawable = if (isSelected) { + R.drawable.ic_rounded_chcekbox_checked + } else { + R.drawable.ic_rounded_chcekbox_unchecked + } + Crossfade( + targetState = selectionDrawable, + label = "itemSelection" + ) { icon -> + Image( + painter = painterResource(id = icon), + contentDescription = null + ) + } + + Column( + modifier = Modifier.animateContentSize(), + verticalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.minor_100)) + ) { + Text( + text = title, + style = MaterialTheme.typography.subtitle1, + fontWeight = FontWeight.W600, + color = MaterialTheme.colors.onSurface, + ) + Text( + text = description, + style = MaterialTheme.typography.subtitle1, + color = MaterialTheme.colors.onSurface, + ) + if (isSelected) { + Text( + text = annotatedStringRes( + stringResId = R.string.blaze_campaign_objective_good_for, + suitableForDescription + ), + style = MaterialTheme.typography.subtitle1, + color = MaterialTheme.colors.onSurface, + ) + } + } + } +} + +@LightDarkThemePreviews +@Composable +fun PreviewObjectiveScreen() { + ObjectiveScreen( + state = ObjectiveViewState( + items = listOf( + ObjectiveItem( + id = "traffic", + title = "Traffic", + description = "Aims to drive more visitors and increase page views.", + suitableForDescription = "E-commerce sites, content-driven websites, startups." + ), + ObjectiveItem( + id = "sales", + title = "Sales", + description = "Converts potential customers into buyers by encouraging purchase.", + suitableForDescription = "E-commerce, retailers, subscription services." + ), + ObjectiveItem( + id = "awareness", + title = "Awareness", + description = "Focuses on increasing brand recognition and visibility.", + suitableForDescription = "New businesses, brands launching new products." + ), + ObjectiveItem( + id = "engagement", + title = "Engagement", + description = "Encourages your audience to interact and connect with your brand.", + suitableForDescription = "Influencers and community builders looking for followers of the same" + + "interest." + ), + ), + selectedItemId = null + ), + onBackPressed = { }, + onSaveTapped = { }, + onObjectiveTapped = { }, + ) +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveViewModel.kt index c4a7f3c0822..b12aa18469b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/objective/BlazeCampaignObjectiveViewModel.kt @@ -1,19 +1,56 @@ package com.woocommerce.android.ui.blaze.creation.objective +import android.os.Parcelable import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.asLiveData +import androidx.lifecycle.viewModelScope +import com.woocommerce.android.ui.blaze.BlazeRepository import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit import com.woocommerce.android.viewmodel.ScopedViewModel +import com.woocommerce.android.viewmodel.getNullableStateFlow +import com.woocommerce.android.viewmodel.navArgs import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.update import javax.inject.Inject @HiltViewModel class BlazeCampaignObjectiveViewModel @Inject constructor( + blazeRepository: BlazeRepository, savedStateHandle: SavedStateHandle ) : ScopedViewModel(savedStateHandle) { - fun onDismissClick() { + private val navArgs: BlazeCampaignObjectiveFragmentArgs by savedStateHandle.navArgs() + + private val selectedId = savedStateHandle.getNullableStateFlow( + scope = viewModelScope, + initialValue = navArgs.selectedId, + clazz = String::class.java + ) + + private val items: Flow> = + blazeRepository.observeObjectives().map { objectives -> + objectives.map { objective -> + ObjectiveItem(objective.id, objective.title, objective.description, objective.suitableForDescription) + } + } + + val viewState = combine(items, selectedId) { items, selectedId -> + ObjectiveViewState(items = items, selectedItemId = selectedId) + }.asLiveData() + + fun onItemToggled(item: ObjectiveItem) { + selectedId.update { item.id } + } + + fun onBackPressed() { triggerEvent(Exit) } + fun onSaveTapped() { + } + data class ObjectiveViewState( val items: List, val selectedItemId: String? = null, diff --git a/WooCommerce/src/main/res/values-night/colors_base.xml b/WooCommerce/src/main/res/values-night/colors_base.xml index 452dae09fa7..fe5d437c0ae 100644 --- a/WooCommerce/src/main/res/values-night/colors_base.xml +++ b/WooCommerce/src/main/res/values-night/colors_base.xml @@ -231,5 +231,6 @@ --> @color/woo_black_90_alpha_038 @color/woo_white_alpha_012 + @color/woo_purple_90 diff --git a/WooCommerce/src/main/res/values/colors_base.xml b/WooCommerce/src/main/res/values/colors_base.xml index 8589722e4fe..a19755ca585 100644 --- a/WooCommerce/src/main/res/values/colors_base.xml +++ b/WooCommerce/src/main/res/values/colors_base.xml @@ -301,6 +301,7 @@ @color/woo_gray_6 @color/woo_gray_0 @color/woo_gray_0 + @color/woo_purple_0 + Select objective %s + Good for: %s]]> + Save my selection for future campaigns + @@ -3992,8 +4000,6 @@ Start typing country, state or city to see available options No location found.\nPlease try again. Searching failed.\nPlease try again - Select objective %s - Good for: %s]]>