From 0c379e6ec40e5281cc647793dc2f02bc3fb4d7b9 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Fri, 8 Nov 2024 16:04:09 +0100 Subject: [PATCH 01/18] Add new text input field to enter ad cta text --- .../android/ui/blaze/BlazeRepository.kt | 1 + .../ad/BlazeCampaignCreationEditAdScreen.kt | 186 ++++++++++++------ .../BlazeCampaignCreationEditAdViewModel.kt | 31 ++- WooCommerce/src/main/res/values/strings.xml | 1 + 4 files changed, 156 insertions(+), 63 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt index ea5ddd86748c..832b0f750a03 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt @@ -446,6 +446,7 @@ class BlazeRepository @Inject constructor( data class AiSuggestionForAd( val tagLine: String, val description: String, + val ctaText: String = "" ) : Parcelable @Parcelize diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdScreen.kt index f880be2d77ad..1999b0340647 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdScreen.kt @@ -71,7 +71,8 @@ fun BlazeCampaignCreationPreviewScreen(viewModel: BlazeCampaignCreationEditAdVie onMediaPickerDialogDismissed = viewModel::onMediaPickerDialogDismissed, onProductImagesRequested = viewModel::onProductImagesRequested, onMediaLibraryRequested = viewModel::onMediaLibraryRequested, - onSaveTapped = viewModel::onSaveTapped + onSaveTapped = viewModel::onSaveTapped, + onCtaTextChanged = viewModel::onCtaTextChanged ) } } @@ -88,7 +89,8 @@ private fun BlazeCampaignCreationEditAdScreen( onMediaPickerDialogDismissed: () -> Unit, onProductImagesRequested: () -> Unit, onMediaLibraryRequested: (DataSource) -> Unit, - onSaveTapped: () -> Unit + onSaveTapped: () -> Unit, + onCtaTextChanged: (String) -> Unit ) { if (viewState.isMediaPickerDialogVisible) { MediaPickerDialog( @@ -123,7 +125,8 @@ private fun BlazeCampaignCreationEditAdScreen( onDescriptionChanged, onChangeImageTapped, onPreviousSuggestionTapped, - onNextSuggestionTapped + onNextSuggestionTapped, + onCtaTextChanged ) } } @@ -137,6 +140,7 @@ fun CampaignEditAdContent( onChangeImageTapped: () -> Unit, onPreviousSuggestionTapped: () -> Unit, onNextSuggestionTapped: () -> Unit, + onCtaTextChanged: (String) -> Unit ) { Column( modifier = Modifier @@ -156,7 +160,8 @@ fun CampaignEditAdContent( onTagLineChanged = onTagLineChanged, onDescriptionChanged = onDescriptionChanged, onPreviousSuggestionTapped = onPreviousSuggestionTapped, - onNextSuggestionTapped = onNextSuggestionTapped + onNextSuggestionTapped = onNextSuggestionTapped, + onCtaTextChanged = onCtaTextChanged ) } } @@ -167,7 +172,8 @@ private fun AdDataSection( onTagLineChanged: (String) -> Unit, onDescriptionChanged: (String) -> Unit, onPreviousSuggestionTapped: () -> Unit, - onNextSuggestionTapped: () -> Unit + onNextSuggestionTapped: () -> Unit, + onCtaTextChanged: (String) -> Unit ) { Column( modifier = Modifier @@ -175,62 +181,16 @@ private fun AdDataSection( .fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { - Box { - WCOutlinedTextField( - value = viewState.tagLine, - onValueChange = onTagLineChanged, - label = stringResource(id = string.blaze_campaign_edit_ad_change_tagline_title), - singleLine = true, - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next) - ) - - CornerCharacterWarning( - charsLeft = viewState.taglineCharactersRemaining, - modifier = Modifier.align(Alignment.TopEnd) - ) - } - - Text( - text = stringResource( - id = string.blaze_campaign_edit_ad_characters_remaining, - viewState.taglineCharactersRemaining - ), - style = MaterialTheme.typography.caption, - color = colorResource(id = color.color_on_surface_disabled), - modifier = Modifier - .padding(top = dimensionResource(id = dimen.minor_100)) - .fillMaxWidth() + TaglineInputText(viewState, onTagLineChanged) + DescriptionInputText( + viewState, + onDescriptionChanged, + modifier = Modifier.padding(top = dimensionResource(id = dimen.major_150)) ) - - Box( - modifier = Modifier - .padding(top = dimensionResource(id = dimen.major_150)) - ) { - WCOutlinedTextField( - value = viewState.description, - onValueChange = onDescriptionChanged, - label = stringResource(id = string.blaze_campaign_edit_ad_change_description_title), - maxLines = 3, - minLines = 3, - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next) - ) - - CornerCharacterWarning( - charsLeft = viewState.descriptionCharactersRemaining, - modifier = Modifier.align(Alignment.TopEnd) - ) - } - - Text( - text = stringResource( - id = string.blaze_campaign_edit_ad_characters_remaining, - viewState.descriptionCharactersRemaining - ), - style = MaterialTheme.typography.caption, - color = colorResource(id = color.color_on_surface_disabled), - modifier = Modifier - .padding(top = dimensionResource(id = dimen.minor_100)) - .fillMaxWidth() + CallToActionInputText( + viewState, + onCtaTextChanged, + modifier = Modifier.padding(top = dimensionResource(id = dimen.major_150)) ) if (viewState.suggestions.size > 1) { @@ -271,6 +231,109 @@ private fun AdDataSection( } } +@Composable +private fun DescriptionInputText( + viewState: ViewState, + onDescriptionChanged: (String) -> Unit, + modifier: Modifier = Modifier +) { + Box(modifier = modifier) { + WCOutlinedTextField( + value = viewState.description, + onValueChange = onDescriptionChanged, + label = stringResource(id = string.blaze_campaign_edit_ad_change_description_title), + maxLines = 3, + minLines = 3, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next) + ) + + CornerCharacterWarning( + charsLeft = viewState.descriptionCharactersRemaining, + modifier = Modifier.align(Alignment.TopEnd) + ) + } + + Text( + text = stringResource( + id = string.blaze_campaign_edit_ad_characters_remaining, + viewState.descriptionCharactersRemaining + ), + style = MaterialTheme.typography.caption, + color = colorResource(id = color.color_on_surface_disabled), + modifier = Modifier + .padding(top = dimensionResource(id = dimen.minor_100)) + .fillMaxWidth() + ) +} + +@Composable +private fun TaglineInputText( + viewState: ViewState, + onTagLineChanged: (String) -> Unit, + modifier: Modifier = Modifier +) { + Box(modifier = modifier) { + WCOutlinedTextField( + value = viewState.tagLine, + onValueChange = onTagLineChanged, + label = stringResource(id = string.blaze_campaign_edit_ad_change_tagline_title), + singleLine = true, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next) + ) + + CornerCharacterWarning( + charsLeft = viewState.taglineCharactersRemaining, + modifier = Modifier.align(Alignment.TopEnd) + ) + } + + Text( + text = stringResource( + id = string.blaze_campaign_edit_ad_characters_remaining, + viewState.taglineCharactersRemaining + ), + style = MaterialTheme.typography.caption, + color = colorResource(id = color.color_on_surface_disabled), + modifier = Modifier + .padding(top = dimensionResource(id = dimen.minor_100)) + .fillMaxWidth() + ) +} + +@Composable +private fun CallToActionInputText( + viewState: ViewState, + onCtaTextChanged: (String) -> Unit, + modifier: Modifier = Modifier +) { + Box(modifier = modifier) { + WCOutlinedTextField( + value = viewState.ctaText, + onValueChange = onCtaTextChanged, + label = stringResource(id = string.blaze_campaign_edit_ad_change_cta_text_title), + singleLine = true, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next) + ) + + CornerCharacterWarning( + charsLeft = viewState.ctaTextCharactersRemaining, + modifier = Modifier.align(Alignment.TopEnd) + ) + } + + Text( + text = stringResource( + id = string.blaze_campaign_edit_ad_characters_remaining, + viewState.ctaTextCharactersRemaining + ), + style = MaterialTheme.typography.caption, + color = colorResource(id = color.color_on_surface_disabled), + modifier = Modifier + .padding(top = dimensionResource(id = dimen.minor_100)) + .fillMaxWidth() + ) +} + @Composable private fun CornerCharacterWarning(charsLeft: Int, modifier: Modifier = Modifier) { if (charsLeft < 10) { @@ -380,7 +443,8 @@ fun PreviewCampaignEditAdContent() { onDescriptionChanged = { }, onChangeImageTapped = { }, onPreviousSuggestionTapped = { }, - onNextSuggestionTapped = { } + onNextSuggestionTapped = { }, + onCtaTextChanged = { }, ) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt index ca7fcfe6396f..d8ce4b785f88 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt @@ -33,6 +33,7 @@ class BlazeCampaignCreationEditAdViewModel @Inject constructor( companion object { private const val TAGLINE_MAX_LENGTH = 32 private const val DESCRIPTION_MAX_LENGTH = 140 + private const val CTA_TEST_MAX_LENGTH = 26 } private val navArgs: BlazeCampaignCreationEditAdFragmentArgs by savedStateHandle.navArgs() @@ -107,11 +108,23 @@ class BlazeCampaignCreationEditAdViewModel @Inject constructor( } fun onTagLineChanged(tagLine: String) { - updateSuggestion(AiSuggestionForAd(tagLine.take(TAGLINE_MAX_LENGTH), _viewState.value.description)) + updateSuggestion( + AiSuggestionForAd( + tagLine.take(TAGLINE_MAX_LENGTH), + _viewState.value.description, + _viewState.value.ctaText + ) + ) } fun onDescriptionChanged(description: String) { - updateSuggestion(AiSuggestionForAd(_viewState.value.tagLine, description.take(DESCRIPTION_MAX_LENGTH))) + updateSuggestion( + AiSuggestionForAd( + _viewState.value.tagLine, + description.take(DESCRIPTION_MAX_LENGTH), + _viewState.value.ctaText + ) + ) } fun onLocalImageSelected(uri: String) { @@ -175,6 +188,16 @@ class BlazeCampaignCreationEditAdViewModel @Inject constructor( setMediaPickerDialogVisibility(false) } + fun onCtaTextChanged(ctaText: String) { + updateSuggestion( + AiSuggestionForAd( + _viewState.value.tagLine, + _viewState.value.description, + ctaText.take(CTA_TEST_MAX_LENGTH) + ) + ) + } + data class ShowMediaLibrary(val source: MediaPickerSetup.DataSource) : Event() data class ShowProductImagePicker(val productId: Long) : Event() @@ -189,10 +212,14 @@ class BlazeCampaignCreationEditAdViewModel @Inject constructor( get() = suggestions.getOrNull(suggestionIndex)?.tagLine ?: "" val description: String get() = suggestions.getOrNull(suggestionIndex)?.description ?: "" + val ctaText: String + get() = suggestions.getOrNull(suggestionIndex)?.ctaText ?: "" val taglineCharactersRemaining: Int get() = TAGLINE_MAX_LENGTH - (suggestions.getOrNull(suggestionIndex)?.tagLine?.length ?: 0) val descriptionCharactersRemaining: Int get() = DESCRIPTION_MAX_LENGTH - (suggestions.getOrNull(suggestionIndex)?.description?.length ?: 0) + val ctaTextCharactersRemaining: Int + get() = CTA_TEST_MAX_LENGTH - (suggestions.getOrNull(suggestionIndex)?.ctaText?.length ?: 0) val isPreviousSuggestionButtonEnabled: Boolean get() = suggestionIndex > 0 val isNextSuggestionButtonEnabled: Boolean diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index 9d831fdb4310..b155d08aa7da 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -3988,6 +3988,7 @@ --> Change image Tagline + Call to action Description %d characters remaining Suggested by AI From 5041aa7f8de34110fface2838161aefd13eb6c61 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Fri, 8 Nov 2024 16:09:19 +0100 Subject: [PATCH 02/18] Save entered cta text between screen navigation --- .../woocommerce/android/ui/blaze/BlazeRepository.kt | 4 +++- .../ad/BlazeCampaignCreationEditAdViewModel.kt | 6 ++++-- .../preview/BlazeCampaignCreationPreviewFragment.kt | 2 +- .../preview/BlazeCampaignCreationPreviewViewModel.kt | 12 ++++++++---- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt index 832b0f750a03..caca9247fe0a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt @@ -194,7 +194,8 @@ class BlazeRepository @Inject constructor( targetUrl = product.permalink, parameters = emptyMap() ), - objectiveId = appPrefsWrapper.blazeCampaignSelectedObjective + objectiveId = appPrefsWrapper.blazeCampaignSelectedObjective, + ctaText = "TODO" ) } @@ -394,6 +395,7 @@ class BlazeRepository @Inject constructor( val productId: Long, val tagLine: String, val description: String, + val ctaText: String, val campaignImage: BlazeCampaignImage, val budget: Budget, val targetingParameters: TargetingParameters, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt index d8ce4b785f88..177d3247e6d4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt @@ -84,7 +84,8 @@ class BlazeCampaignCreationEditAdViewModel @Inject constructor( EditAdResult( tagline = _viewState.value.tagLine, description = _viewState.value.description, - campaignImage = _viewState.value.adImage + campaignImage = _viewState.value.adImage, + ctaText = _viewState.value.ctaText ) ) ) @@ -230,6 +231,7 @@ class BlazeCampaignCreationEditAdViewModel @Inject constructor( data class EditAdResult( val tagline: String, val description: String, - val campaignImage: BlazeRepository.BlazeCampaignImage + val campaignImage: BlazeRepository.BlazeCampaignImage, + val ctaText: String ) : Parcelable } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewFragment.kt index 29b55aad0717..1395fea4e9b7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewFragment.kt @@ -120,7 +120,7 @@ class BlazeCampaignCreationPreviewFragment : BaseFragment() { private fun handleResults() { handleResult(BlazeCampaignCreationEditAdFragment.EDIT_AD_RESULT) { - viewModel.onAdUpdated(it.tagline, it.description, it.campaignImage) + viewModel.onAdUpdated(it) } handleResult(BlazeCampaignObjectiveFragment.BLAZE_OBJECTIVE_SELECTION_RESULT) { viewModel.onObjectiveUpdated(it.objectiveId) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt index 70530bcceb05..cb3c195ffe4b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt @@ -18,6 +18,7 @@ import com.woocommerce.android.ui.blaze.BlazeRepository.AiSuggestionForAd import com.woocommerce.android.ui.blaze.BlazeRepository.CampaignDetails import com.woocommerce.android.ui.blaze.BlazeRepository.Objective import com.woocommerce.android.ui.blaze.Location +import com.woocommerce.android.ui.blaze.creation.ad.BlazeCampaignCreationEditAdViewModel.EditAdResult import com.woocommerce.android.ui.blaze.creation.targets.BlazeTargetType import com.woocommerce.android.ui.blaze.creation.targets.BlazeTargetType.DEVICE import com.woocommerce.android.ui.blaze.creation.targets.BlazeTargetType.INTEREST @@ -108,6 +109,7 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( productId = navArgs.productId, tagLine = it.tagLine, description = it.description, + ctaText = it.ctaText, campaignImage = it.campaignImage, aiSuggestions = aiSuggestions ) @@ -115,12 +117,13 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( } } - fun onAdUpdated(tagline: String, description: String, campaignImage: BlazeRepository.BlazeCampaignImage) { + fun onAdUpdated(updatedAd: EditAdResult) { campaignDetails.update { it?.copy( - tagLine = tagline, - description = description, - campaignImage = campaignImage + tagLine = updatedAd.tagline, + description = updatedAd.description, + campaignImage = updatedAd.campaignImage, + ctaText = updatedAd.ctaText ) } } @@ -442,6 +445,7 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( val productId: Long, val tagLine: String, val description: String, + val ctaText: String, val campaignImage: BlazeRepository.BlazeCampaignImage, val aiSuggestions: List ) : MultiLiveEvent.Event() From 022e01b97f89cedad2d0b2dff460cf38a4395e6c Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Fri, 8 Nov 2024 17:46:38 +0100 Subject: [PATCH 03/18] Show updated cta text in ad preview --- .../creation/preview/BlazeCampaignCreationPreviewScreen.kt | 3 ++- .../creation/preview/BlazeCampaignCreationPreviewViewModel.kt | 2 ++ WooCommerce/src/main/res/values/strings.xml | 1 - 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewScreen.kt index 217ae3f7218d..495a68aa221d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewScreen.kt @@ -264,7 +264,7 @@ fun CampaignHeader( fontWeight = FontWeight.Bold, ) WCColoredButton( - text = stringResource(id = R.string.blaze_campaign_preview_shop_now_button), + text = adDetails.ctaText, modifier = Modifier .padding(start = 16.dp), colors = ButtonDefaults.buttonColors( @@ -418,6 +418,7 @@ fun CampaignScreenPreview() { productId = 123, description = "Get the latest white t-shirts", tagLine = "From 45.00 USD", + ctaText = "Shop Now", campaignImageUrl = "https://rb.gy/gmjuwb", isContentSuggestedByAi = true ), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt index cb3c195ffe4b..9ed98d88d2cc 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt @@ -76,6 +76,7 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( productId = navArgs.productId, description = campaignDetails.description, tagLine = campaignDetails.tagLine, + ctaText = campaignDetails.ctaText, campaignImageUrl = campaignDetails.campaignImage.uri, isContentSuggestedByAi = isAdContentGeneratedByAi(campaignDetails) ) @@ -403,6 +404,7 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( val productId: Long, val description: String, val tagLine: String, + val ctaText: String, val campaignImageUrl: String?, val isContentSuggestedByAi: Boolean, ) : AdDetailsUi diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index b155d08aa7da..39960a10c9f2 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -3922,7 +3922,6 @@ --> Preview Edit ad - Shop now Details Audience Budget From 60cac222b1a4e07888383cbe9e7cd556617151fc Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Fri, 8 Nov 2024 18:13:20 +0100 Subject: [PATCH 04/18] Add missing ctaText navarg --- .../blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt | 2 +- .../main/res/navigation/nav_graph_blaze_campaign_creation.xml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt index 177d3247e6d4..46b05d7d3a8e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt @@ -50,7 +50,7 @@ class BlazeCampaignCreationEditAdViewModel @Inject constructor( private fun loadSuggestions() { viewModelScope.launch { - val passedDetails = AiSuggestionForAd(navArgs.tagline, navArgs.description) + val passedDetails = AiSuggestionForAd(navArgs.tagline, navArgs.description, navArgs.ctaText) val suggestions = navArgs.aiSuggestionsForAd.toList() _viewState.update { it.copy( 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 616f16d53c6b..49044c7d8ba4 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 @@ -95,6 +95,10 @@ android:name="description" android:defaultValue="" app:argType="string" /> + From 81621734ff1ab94b39339f0857987c9d3856dfff Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Fri, 8 Nov 2024 18:13:40 +0100 Subject: [PATCH 05/18] Add ctaText to campaign creation details --- .../com/woocommerce/android/ui/blaze/BlazeRepository.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt index caca9247fe0a..e6cd703361f1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt @@ -149,7 +149,7 @@ class BlazeRepository @Inject constructor( suspend fun fetchAdSuggestions(productId: Long): Result> { fun List.mapToUiModel(): List { - return map { AiSuggestionForAd(it.tagLine, it.description) } + return map { AiSuggestionForAd(it.tagLine, it.description, it.ctaText) } } val result = blazeCampaignsStore.fetchBlazeAdSuggestions(selectedSite.get(), productId) @@ -298,6 +298,7 @@ class BlazeRepository @Inject constructor( targetResourceId = campaignDetails.productId, tagLine = campaignDetails.tagLine, description = campaignDetails.description, + ctaText = campaignDetails.ctaText, startDate = campaignDetails.budget.startDate, endDate = campaignDetails.budget.endDate, budget = BlazeCampaignCreationRequestBudget( @@ -448,7 +449,7 @@ class BlazeRepository @Inject constructor( data class AiSuggestionForAd( val tagLine: String, val description: String, - val ctaText: String = "" + val ctaText: String ) : Parcelable @Parcelize From c29b0d9e71e7f2e8aae03e68afb164fd98a8d2b8 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Fri, 8 Nov 2024 18:26:31 +0100 Subject: [PATCH 06/18] Fix minor UI issues to display the correct ctaText suggestion --- .../creation/preview/BlazeCampaignCreationPreviewFragment.kt | 1 + .../creation/preview/BlazeCampaignCreationPreviewViewModel.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewFragment.kt index 1395fea4e9b7..e806d405725b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewFragment.kt @@ -75,6 +75,7 @@ class BlazeCampaignCreationPreviewFragment : BaseFragment() { productId = event.productId, tagline = event.tagLine, description = event.description, + ctaText = event.ctaText, adImage = event.campaignImage, aiSuggestionsForAd = event.aiSuggestions.toTypedArray() ) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt index 9ed98d88d2cc..049ea48e6cd2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt @@ -265,6 +265,7 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( it?.copy( tagLine = suggestions?.firstOrNull()?.tagLine.orEmpty(), description = suggestions?.firstOrNull()?.description.orEmpty(), + ctaText = suggestions?.firstOrNull()?.ctaText.orEmpty() ) } } From b231f772b96bce887583363ed07e1716016bd246 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Mon, 11 Nov 2024 10:58:51 +0100 Subject: [PATCH 07/18] Suppress detekt long method warning --- .../kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt index e6cd703361f1..5711b528ba26 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt @@ -274,6 +274,7 @@ class BlazeRepository @Inject constructor( ) } + @Suppress("LongMethod") suspend fun createCampaign( campaignDetails: CampaignDetails, paymentMethodId: String From 49c711c135414bbce45ddcb3c98509be49f4e56f Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Mon, 11 Nov 2024 11:32:20 +0100 Subject: [PATCH 08/18] Update FluxC version --- 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 8b68c77a7a9f..cad67236079b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -86,7 +86,7 @@ stripe-terminal = '3.7.1' tinder-statemachine = '0.2.0' wiremock = '2.26.3' wordpress-aztec = 'v2.1.4' -wordpress-fluxc = '2.99.1' +wordpress-fluxc = '3108-0209c40e7ac3806c11f2c96c2c691061d0a773e8' wordpress-login = '1.19.0' wordpress-libaddressinput = '0.0.2' wordpress-mediapicker = '0.3.1' From fd752816a57eb1e8b4ca5bacd73047f8726acdc3 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Mon, 11 Nov 2024 12:21:54 +0100 Subject: [PATCH 09/18] Update preview to show the ad cta with the same style as Blaze dsp --- .../BlazeCampaignCreationPreviewScreen.kt | 42 ++++++++++++++++--- .../src/main/res/values/colors_base.xml | 2 +- .../src/main/res/values/wc_colors_base.xml | 4 +- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewScreen.kt index 495a68aa221d..1872cdcab067 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewScreen.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -27,6 +28,7 @@ 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.automirrored.filled.ArrowForwardIos import androidx.compose.runtime.Composable import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment @@ -193,7 +195,7 @@ fun AdDetailsHeader( onEditAdClicked: () -> Unit, modifier: Modifier = Modifier, ) { - CampaignHeader( + AdPreview( adDetails = adDetails, onEditAdClicked = onEditAdClicked, modifier = modifier @@ -205,7 +207,7 @@ fun AdDetailsHeader( } @Composable -fun CampaignHeader( +fun AdPreview( adDetails: AdDetails, onEditAdClicked: () -> Unit, modifier: Modifier = Modifier @@ -263,13 +265,21 @@ fun CampaignHeader( style = MaterialTheme.typography.subtitle1, fontWeight = FontWeight.Bold, ) + if (adDetails.ctaText.isEmpty()) { + DefaultBlazeButton( + modifier = Modifier + .padding(start = 16.dp) + .align(Alignment.Top) + ) + } + } + if (adDetails.ctaText.isNotEmpty()) { WCColoredButton( + modifier = Modifier.padding(top = 8.dp), text = adDetails.ctaText, - modifier = Modifier - .padding(start = 16.dp), colors = ButtonDefaults.buttonColors( - contentColor = colorResource(id = R.color.color_on_secondary), - backgroundColor = colorResource(id = R.color.blaze_campaign_preview_shop_now_button), + contentColor = colorResource(id = R.color.color_on_primary_surface), + backgroundColor = colorResource(id = R.color.blaze_ad_cta_background), ), onClick = { /*TODO*/ }, ) @@ -365,6 +375,26 @@ private fun CampaignPropertyGroupItem( } } +@Composable +private fun DefaultBlazeButton(modifier: Modifier = Modifier) { + Box( + modifier = modifier + .size(40.dp) + .clip(RoundedCornerShape(16.dp)) + .background(color = colorResource(id = R.color.blaze_ad_cta_background)) + ) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowForwardIos, + contentDescription = null, + tint = colorResource(id = R.color.color_on_primary_surface), + modifier = Modifier + .align(Alignment.Center) + .size(32.dp) + .padding(6.dp) + ) + } +} + @Composable private fun CampaignPropertyItem( item: CampaignDetailItemUi, diff --git a/WooCommerce/src/main/res/values/colors_base.xml b/WooCommerce/src/main/res/values/colors_base.xml index a19755ca5858..15a64417c572 100644 --- a/WooCommerce/src/main/res/values/colors_base.xml +++ b/WooCommerce/src/main/res/values/colors_base.xml @@ -300,8 +300,8 @@ @color/white @color/woo_gray_6 @color/woo_gray_0 - @color/woo_gray_0 @color/woo_purple_0 + @color/blaze_blue Change image Tagline + Tagline cannot be empty Call to action Description + Description cannot be empty %d characters remaining Suggested by AI Invalid image From 3480f0777ddabe1ccf6220fceadfa84f536fa1cf Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Mon, 11 Nov 2024 16:32:28 +0100 Subject: [PATCH 13/18] Fix code indentation issue --- .../com/woocommerce/android/ui/blaze/BlazeRepositoryTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/BlazeRepositoryTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/BlazeRepositoryTest.kt index 4a72a756b95c..73257ddd62e9 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/BlazeRepositoryTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/BlazeRepositoryTest.kt @@ -133,7 +133,7 @@ class BlazeRepositoryTest : BaseUnitTest() { budget = DEFAULT_BUDGET, targetingParameters = EMPTY_TARGETING_PARAMETERS, destinationParameters = EMPTY_DESTINATION_PARAMETERS, - objectiveId = "sales", + objectiveId = "sales", ) private val ENDLESS_CAMPAIGN_DETAILS = DEFAULT_CAMPAIGN_DETAILS.copy( budget = DEFAULT_BUDGET.copy(isEndlessCampaign = true) From 0778bf4d824652d38d26d6051b0ce98e3ea7c375 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Wed, 13 Nov 2024 22:02:32 +0100 Subject: [PATCH 14/18] Remove leftover TODO --- .../kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt index 5711b528ba26..930d1f6569dd 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt @@ -195,7 +195,7 @@ class BlazeRepository @Inject constructor( parameters = emptyMap() ), objectiveId = appPrefsWrapper.blazeCampaignSelectedObjective, - ctaText = "TODO" + ctaText = "" ) } From 1f9d78f8d4f7e0988e1f265a21132ccf0cfa13dd Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Wed, 13 Nov 2024 22:12:07 +0100 Subject: [PATCH 15/18] Check if cta text changes when updating isAdContentGeneratedByAi status --- .../creation/preview/BlazeCampaignCreationPreviewViewModel.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt index 049ea48e6cd2..5b8f2d4a4187 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt @@ -245,7 +245,8 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( private fun isAdContentGeneratedByAi(campaignDetails: CampaignDetails?): Boolean = aiSuggestions.any { it.tagLine == campaignDetails?.tagLine && - it.description == campaignDetails.description + it.description == campaignDetails.description && + it.ctaText == campaignDetails.ctaText } private fun loadData() { From 7a9af96c66e9d889d2376db231c64ec92a708605 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Wed, 13 Nov 2024 22:18:37 +0100 Subject: [PATCH 16/18] Updates FluxC changeset to latest trunk --- 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 cad67236079b..80c219995b46 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -86,7 +86,7 @@ stripe-terminal = '3.7.1' tinder-statemachine = '0.2.0' wiremock = '2.26.3' wordpress-aztec = 'v2.1.4' -wordpress-fluxc = '3108-0209c40e7ac3806c11f2c96c2c691061d0a773e8' +wordpress-fluxc = 'trunk-cc17141a0e910d5b808ba6bbfb4b7d393d3517a0' wordpress-login = '1.19.0' wordpress-libaddressinput = '0.0.2' wordpress-mediapicker = '0.3.1' From f1670b21d58a9db87a04e53fe7493dca000f873b Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Thu, 14 Nov 2024 08:58:17 +0100 Subject: [PATCH 17/18] Fix wrong indentation --- .../preview/BlazeCampaignCreationPreviewViewModel.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt index 7350e8b8bdc6..6aa553b39729 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt @@ -268,10 +268,10 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( it?.copy( tagLine = suggestions.firstOrNull()?.tagLine.orEmpty(), description = suggestions.firstOrNull()?.description.orEmpty(), - ctaText = suggestions?.firstOrNull()?.ctaText.orEmpty() - ) - } - }, + ctaText = suggestions?.firstOrNull()?.ctaText.orEmpty() + ) + } + }, onFailure = { error -> analyticsTrackerWrapper.track( stat = AnalyticsEvent.BLAZE_SUGGESTIONS_LOADING_FAILED, From 819562f6ad6118f4b4e29bfbae5876c6b5beba2b Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Thu, 14 Nov 2024 08:59:23 +0100 Subject: [PATCH 18/18] Remove unnecessary safe call to a non-null receiver --- .../creation/preview/BlazeCampaignCreationPreviewViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt index 6aa553b39729..e2fc24307b68 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt @@ -268,7 +268,7 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( it?.copy( tagLine = suggestions.firstOrNull()?.tagLine.orEmpty(), description = suggestions.firstOrNull()?.description.orEmpty(), - ctaText = suggestions?.firstOrNull()?.ctaText.orEmpty() + ctaText = suggestions.firstOrNull()?.ctaText.orEmpty() ) } },