Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/trunk' into issue/12444-entry-po…
Browse files Browse the repository at this point in the history
…int-new-sl-flow
  • Loading branch information
Alejo committed Oct 1, 2024
2 parents dd12347 + 14b24c0 commit 581aa36
Show file tree
Hide file tree
Showing 60 changed files with 486 additions and 459 deletions.
3 changes: 3 additions & 0 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
20.7
-----
- [**] Improve barcode scanner reading accuracy [https://github.com/woocommerce/woocommerce-android/pull/12673]
- [Internal] AI product creation banner is removed [https://github.com/woocommerce/woocommerce-android/pull/12705]
- [*] [Login] Fix an issue where the app doesn't show the correct error screen when application passwords are disabled [https://github.com/woocommerce/woocommerce-android/pull/12717]
- [**] Fixed bug with coupons disappearing from the order creation screen unexpectedly [https://github.com/woocommerce/woocommerce-android/pull/12724]
- [Internal] Fixes crash [https://github.com/woocommerce/woocommerce-android/issues/12715]
- [*] Fixed incorrect instructions on "What is Tap to Pay" screen in the Payments section [https://github.com/woocommerce/woocommerce-android/pull/12709]

20.6
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,6 @@ open class Screen {
private fun initializeAppPrefs() {
AppPrefs.init(getInstrumentation().targetContext.applicationContext)

// hide the promo dialog because it breaks the tests
AppPrefs.wasAIProductDescriptionPromoDialogShown = true

// also hide AI description tooltip to make test more simple
AppPrefs.isAIProductDescriptionTooltipDismissed = true

Expand Down
27 changes: 5 additions & 22 deletions WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,10 @@ object AppPrefs {
NOTIFICATIONS_PERMISSION_BAR,
IS_EU_SHIPPING_NOTICE_DISMISSED,
HAS_SAVED_PRIVACY_SETTINGS,
WAS_AI_DESCRIPTION_PROMO_DIALOG_SHOWN,
IS_AI_DESCRIPTION_TOOLTIP_DISMISSED,
NUMBER_OF_TIMES_AI_DESCRIPTION_TOOLTIP_SHOWN,
STORE_CREATION_PROFILER_ANSWERS,
AI_CONTENT_GENERATION_TONE,
AI_PRODUCT_CREATION_IS_FIRST_ATTEMPT,
BLAZE_FIRST_TIME_WITHOUT_CAMPAIGN,
BLAZE_CAMPAIGN_CREATED,
BLAZE_CELEBRATION_SCREEN_SHOWN,
Expand All @@ -129,6 +127,7 @@ object AppPrefs {
TIMES_AI_PRODUCT_CREATION_SURVEY_DISPLAYED,
AI_PRODUCT_CREATION_SURVEY_DISMISSED,
CUSTOM_FIELDS_TOP_BANNER_DISMISSED,
BLAZE_CAMPAIGN_SELECTED_OBJECTIVE
}

/**
Expand Down Expand Up @@ -274,6 +273,10 @@ object AppPrefs {
get() = getBoolean(DeletablePrefKey.CUSTOM_FIELDS_TOP_BANNER_DISMISSED, false)
set(value) = setBoolean(DeletablePrefKey.CUSTOM_FIELDS_TOP_BANNER_DISMISSED, value)

var blazeCampaignSelectedObjective: String
get() = getString(DeletablePrefKey.BLAZE_CAMPAIGN_SELECTED_OBJECTIVE, "")
set(value) = setString(DeletablePrefKey.BLAZE_CAMPAIGN_SELECTED_OBJECTIVE, value)

fun getProductSortingChoice(currentSiteId: Int) = getString(getProductSortingKey(currentSiteId)).orNullIfEmpty()

fun setProductSortingChoice(currentSiteId: Int, value: String) {
Expand Down Expand Up @@ -976,16 +979,6 @@ object AppPrefs {
value = value
)

var wasAIProductDescriptionPromoDialogShown: Boolean
get() = getBoolean(
key = DeletablePrefKey.WAS_AI_DESCRIPTION_PROMO_DIALOG_SHOWN,
default = false
)
set(value) = setBoolean(
key = DeletablePrefKey.WAS_AI_DESCRIPTION_PROMO_DIALOG_SHOWN,
value = value
)

var isAIProductDescriptionTooltipDismissed: Boolean
get() = getBoolean(
key = DeletablePrefKey.IS_AI_DESCRIPTION_TOOLTIP_DISMISSED,
Expand Down Expand Up @@ -1013,16 +1006,6 @@ object AppPrefs {
value = value.slug
)

var aiProductCreationIsFirstAttempt: Boolean
get() = getBoolean(
key = DeletablePrefKey.AI_PRODUCT_CREATION_IS_FIRST_ATTEMPT,
default = true
)
set(value) = setBoolean(
key = DeletablePrefKey.AI_PRODUCT_CREATION_IS_FIRST_ATTEMPT,
value = value
)

var isBlazeCelebrationScreenShown: Boolean
get() = getBoolean(
key = DeletablePrefKey.BLAZE_CELEBRATION_SCREEN_SHOWN,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,10 @@ import javax.inject.Inject
class AppPrefsWrapper @Inject constructor() {
var savedPrivacyBannerSettings by AppPrefs::savedPrivacySettings

var wasAIProductDescriptionPromoDialogShown by AppPrefs::wasAIProductDescriptionPromoDialogShown

var isAIProductDescriptionTooltipDismissed by AppPrefs::isAIProductDescriptionTooltipDismissed

var aiContentGenerationTone by AppPrefs::aiContentGenerationTone

var aiProductCreationIsFirstAttempt by AppPrefs::aiProductCreationIsFirstAttempt

var isBlazeCelebrationScreenShown by AppPrefs::isBlazeCelebrationScreenShown

var blazeFirstTimeWithoutCampaign by AppPrefs::blazeFirstTimeWithoutCampaign
Expand All @@ -40,6 +36,8 @@ class AppPrefsWrapper @Inject constructor() {

var isCustomFieldsTopBannerDismissed by AppPrefs::isCustomFieldsTopBannerDismissed

var blazeCampaignSelectedObjective by AppPrefs::blazeCampaignSelectedObjective

fun getAppInstallationDate() = AppPrefs.installationDate

fun getReceiptUrl(localSiteId: Int, remoteSiteId: Long, selfHostedSiteId: Long, orderId: Long) =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.woocommerce.android.ui.blaze

import android.os.Parcelable
import com.woocommerce.android.AppPrefsWrapper
import com.woocommerce.android.AppUrls.FETCH_PAYMENT_METHOD_URL_PATH
import com.woocommerce.android.AppUrls.WPCOM_ADD_PAYMENT_METHOD
import com.woocommerce.android.BuildConfig
Expand Down Expand Up @@ -36,7 +37,8 @@ class BlazeRepository @Inject constructor(
private val selectedSite: SelectedSite,
private val blazeCampaignsStore: BlazeCampaignsStore,
private val productDetailRepository: ProductDetailRepository,
private val mediaFilesRepository: MediaFilesRepository
private val mediaFilesRepository: MediaFilesRepository,
private val appPrefsWrapper: AppPrefsWrapper
) {
companion object {
private const val BLAZE_CAMPAIGN_CREATION_ORIGIN = "wc-android"
Expand Down Expand Up @@ -191,7 +193,8 @@ class BlazeRepository @Inject constructor(
destinationParameters = DestinationParameters(
targetUrl = product.permalink,
parameters = emptyMap()
)
),
objectiveId = appPrefsWrapper.blazeCampaignSelectedObjective
)
}

Expand Down Expand Up @@ -318,7 +321,8 @@ class BlazeRepository @Inject constructor(
topics = it.interests.map { interest -> interest.id }
)
},
isEndlessCampaign = campaignDetails.budget.isEndlessCampaign
isEndlessCampaign = campaignDetails.budget.isEndlessCampaign,
objectiveId = campaignDetails.objectiveId
)
)

Expand Down Expand Up @@ -384,6 +388,7 @@ class BlazeRepository @Inject constructor(
val budget: Budget,
val targetingParameters: TargetingParameters,
val destinationParameters: DestinationParameters,
val objectiveId: String
) : Parcelable

sealed interface BlazeCampaignImage : Parcelable {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.woocommerce.android.ui.blaze.creation.objective

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
import com.woocommerce.android.ui.compose.composeView
import com.woocommerce.android.ui.main.AppBarStatus
import com.woocommerce.android.viewmodel.MultiLiveEvent
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class BlazeCampaignObjectiveFragment : BaseFragment() {
override val activityAppBarStatus: AppBarStatus
get() = AppBarStatus.Hidden

val viewModel: BlazeCampaignObjectiveViewModel by viewModels()

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return composeView {
Text(text = "Select Campaign Objective")
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
handleEvents()
}

private fun handleEvents() {
viewModel.event.observe(viewLifecycleOwner) { event ->
when (event) {
is MultiLiveEvent.Event.Exit -> findNavController().navigateUp()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.woocommerce.android.ui.blaze.creation.objective

import androidx.lifecycle.SavedStateHandle
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit
import com.woocommerce.android.viewmodel.ScopedViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@HiltViewModel
class BlazeCampaignObjectiveViewModel @Inject constructor(
savedStateHandle: SavedStateHandle
) : ScopedViewModel(savedStateHandle) {
fun onDismissClick() {
triggerEvent(Exit)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import com.woocommerce.android.ui.blaze.creation.destination.BlazeCampaignCreati
import com.woocommerce.android.ui.blaze.creation.preview.BlazeCampaignCreationPreviewViewModel.NavigateToAdDestinationScreen
import com.woocommerce.android.ui.blaze.creation.preview.BlazeCampaignCreationPreviewViewModel.NavigateToBudgetScreen
import com.woocommerce.android.ui.blaze.creation.preview.BlazeCampaignCreationPreviewViewModel.NavigateToEditAdScreen
import com.woocommerce.android.ui.blaze.creation.preview.BlazeCampaignCreationPreviewViewModel.NavigateToObjectiveSelectionScreen
import com.woocommerce.android.ui.blaze.creation.preview.BlazeCampaignCreationPreviewViewModel.NavigateToPaymentSummary
import com.woocommerce.android.ui.blaze.creation.preview.BlazeCampaignCreationPreviewViewModel.NavigateToTargetLocationSelectionScreen
import com.woocommerce.android.ui.blaze.creation.preview.BlazeCampaignCreationPreviewViewModel.NavigateToTargetSelectionScreen
Expand Down Expand Up @@ -99,12 +100,18 @@ class BlazeCampaignCreationPreviewFragment : BaseFragment() {
event.destinationParameters
)
)

is NavigateToPaymentSummary -> findNavController().navigateSafely(
BlazeCampaignCreationPreviewFragmentDirections
.actionBlazeCampaignCreationPreviewFragmentToBlazeCampaignPaymentSummaryFragment(
event.campaignDetails
)
)

is NavigateToObjectiveSelectionScreen -> findNavController().navigateSafely(
BlazeCampaignCreationPreviewFragmentDirections
.actionBlazeCampaignCreationPreviewFragmentToBlazeCampaignObjectiveFragment()
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ fun CampaignDetails(
style = MaterialTheme.typography.body2
)
// Budget
CampaignPropertyGroupItem(items = listOf(campaignDetails.budget))
CampaignPropertyGroupItem(items = listOf(campaignDetails.selectedObjective, campaignDetails.budget))
Spacer(modifier = Modifier.height(16.dp))

// Ad Audience
Expand Down Expand Up @@ -449,7 +449,12 @@ fun CampaignScreenPreview() {
displayValue = "https://www.myer.com.au/p/white-t-shirt-797334760-797334760",
onItemSelected = {},
maxLinesValue = 1,
)
),
selectedObjective = CampaignDetailItemUi(
displayTitle = stringResource(R.string.blaze_campaign_preview_details_objective),
displayValue = "Sales",
onItemSelected = {},
),
)
),
onBackPressed = { },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.woocommerce.android.support.help.HelpOrigin
import com.woocommerce.android.ui.blaze.BlazeRepository
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.targets.BlazeTargetType
import com.woocommerce.android.ui.blaze.creation.targets.BlazeTargetType.DEVICE
Expand Down Expand Up @@ -43,7 +44,7 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor(
private val blazeRepository: BlazeRepository,
private val resourceProvider: ResourceProvider,
private val currencyFormatter: CurrencyFormatter,
private val analyticsTrackerWrapper: AnalyticsTrackerWrapper,
private val analyticsTrackerWrapper: AnalyticsTrackerWrapper
) : ScopedViewModel(savedStateHandle) {
private val navArgs: BlazeCampaignCreationPreviewFragmentArgs by savedStateHandle.navArgs()
private val campaignDetails = savedStateHandle.getNullableStateFlow(
Expand All @@ -53,15 +54,18 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor(
clazz = CampaignDetails::class.java
)
private var aiSuggestions: List<AiSuggestionForAd> = emptyList()
private var campaignObjectives: List<Objective> = emptyList()

private val adDetailsState = savedStateHandle.getStateFlow(viewModelScope, AdDetailsUiState.LOADING)
private val dialogState = MutableStateFlow<DialogState?>(null)

val viewState = combine(
campaignDetails.filterNotNull(),
adDetailsState,
dialogState
) { campaignDetails, adDetailsState, dialogState ->
dialogState,
blazeRepository.observeObjectives()
) { campaignDetails, adDetailsState, dialogState, objectives ->
campaignObjectives = objectives
CampaignPreviewUiState(
adDetails = when (adDetailsState) {
AdDetailsUiState.LOADING -> AdDetailsUi.Loading
Expand Down Expand Up @@ -234,6 +238,7 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor(
)
}
}
blazeRepository.fetchObjectives()
}
}

Expand All @@ -245,9 +250,22 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor(
getTargetLocationsDetails(),
getTargetInterestsDetails(),
),
destinationUrl = getTargetDestinationDetails()
destinationUrl = getTargetDestinationDetails(),
selectedObjective = getSelectedObjective(campaignObjectives)
)

private fun getSelectedObjective(objectives: List<Objective>): CampaignDetailItemUi {
val selectedObjectiveDisplayValue = objectives
.find { it.id == campaignDetails.value?.objectiveId }
?.title
?: resourceProvider.getString(R.string.blaze_campaign_preview_details_choose_objective)
return CampaignDetailItemUi(
displayTitle = resourceProvider.getString(R.string.blaze_campaign_preview_details_objective),
displayValue = selectedObjectiveDisplayValue,
onItemSelected = { triggerEvent(NavigateToObjectiveSelectionScreen) }
)
}

private fun CampaignDetails.getBudgetDetails() =
CampaignDetailItemUi(
displayTitle = resourceProvider.getString(R.string.blaze_campaign_preview_details_budget),
Expand Down Expand Up @@ -365,6 +383,7 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor(
val budget: CampaignDetailItemUi,
val targetDetails: List<CampaignDetailItemUi>,
val destinationUrl: CampaignDetailItemUi,
val selectedObjective: CampaignDetailItemUi
)

data class CampaignDetailItemUi(
Expand Down Expand Up @@ -404,4 +423,6 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor(
data class NavigateToPaymentSummary(
val campaignDetails: CampaignDetails
) : MultiLiveEvent.Event()

data object NavigateToObjectiveSelectionScreen : MultiLiveEvent.Event()
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,32 @@ data class CustomFieldUiModel(
val key: String,
val value: String,
val id: Long? = null,
val isJson: Boolean = false
) : Parcelable {
constructor(customField: CustomField) : this(customField.key, customField.valueAsString, customField.id)
constructor(customField: CustomField) : this(
key = customField.key,
value = customField.valueAsString,
id = customField.id,
isJson = customField.isJson
)

val valueStrippedHtml: String
get() = HtmlUtils.fastStripHtml(value)

@IgnoredOnParcel
val contentType: CustomFieldContentType = CustomFieldContentType.fromMetadataValue(value)

fun toDomainModel() = CustomField(
id = id ?: 0, // Use 0 for new custom fields
key = key,
value = WCMetaDataValue.StringValue(value) // Treat all updates as string values
)
fun toDomainModel(): CustomField {
require(!isJson) {
"Editing JSON custom fields is not supported, this shouldn't be called for JSON custom fields"
}

return CustomField(
id = id ?: 0, // Use 0 for new custom fields
key = key,
value = WCMetaDataValue.StringValue(value) // Treat all updates as string values
)
}
}

enum class CustomFieldContentType {
Expand Down
Loading

0 comments on commit 581aa36

Please sign in to comment.