Skip to content

Commit daecdbd

Browse files
committed
Merge branch 'trunk' into feature/new_privacy_screen
2 parents 2a17991 + 93f3222 commit daecdbd

21 files changed

+360
-52
lines changed

WooCommerce/src/main/kotlin/com/woocommerce/android/model/Notification.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ data class Notification(
2222
val noteMessage: String?,
2323
val noteType: WooNotificationType,
2424
val channelType: NotificationChannelType,
25-
val tag: String? = null
25+
val tag: String? = null,
26+
val data: String? = null
2627
) : Parcelable {
2728
@IgnoredOnParcel
2829
val isOrderNotification = noteType == WooNotificationType.NEW_ORDER

WooCommerce/src/main/kotlin/com/woocommerce/android/notifications/local/LocalNotification.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ sealed class LocalNotification(
1717
abstract fun getTitleString(resourceProvider: ResourceProvider): String
1818
abstract fun getDescriptionString(resourceProvider: ResourceProvider): String
1919

20+
open val data: String? = null
21+
2022
data class StoreCreationFinishedNotification(
2123
val name: String
2224
) : LocalNotification(
@@ -34,4 +36,22 @@ sealed class LocalNotification(
3436
return resourceProvider.getString(description, name)
3537
}
3638
}
39+
40+
data class StoreCreationIncompleteNotification(val name: String, val storeName: String) : LocalNotification(
41+
title = R.string.local_notification_without_free_trial_title,
42+
description = R.string.local_notification_without_free_trial_description,
43+
type = LocalNotificationType.STORE_CREATION_INCOMPLETE,
44+
delay = 24,
45+
delayUnit = TimeUnit.HOURS
46+
) {
47+
override fun getTitleString(resourceProvider: ResourceProvider): String {
48+
return resourceProvider.getString(title)
49+
}
50+
51+
override fun getDescriptionString(resourceProvider: ResourceProvider): String {
52+
return resourceProvider.getString(description, name, storeName)
53+
}
54+
55+
override val data: String = storeName
56+
}
3757
}

WooCommerce/src/main/kotlin/com/woocommerce/android/notifications/local/LocalNotificationScheduler.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class LocalNotificationScheduler @Inject constructor(
2222
const val LOCAL_NOTIFICATION_ID = "local_notification_id"
2323
const val LOCAL_NOTIFICATION_TITLE = "local_notification_title"
2424
const val LOCAL_NOTIFICATION_DESC = "local_notification_description"
25+
const val LOCAL_NOTIFICATION_DATA = "local_notification_data"
2526
}
2627

2728
private val workManager = WorkManager.getInstance(appContext)
@@ -54,7 +55,8 @@ class LocalNotificationScheduler @Inject constructor(
5455
LOCAL_NOTIFICATION_TYPE to notification.type.value,
5556
LOCAL_NOTIFICATION_ID to notification.id,
5657
LOCAL_NOTIFICATION_TITLE to notification.getTitleString(resourceProvider),
57-
LOCAL_NOTIFICATION_DESC to notification.getDescriptionString(resourceProvider)
58+
LOCAL_NOTIFICATION_DESC to notification.getDescriptionString(resourceProvider),
59+
LOCAL_NOTIFICATION_DATA to notification.data
5860
)
5961
return OneTimeWorkRequestBuilder<LocalNotificationWorker>()
6062
.addTag(notification.type.value)

WooCommerce/src/main/kotlin/com/woocommerce/android/notifications/local/LocalNotificationWorker.kt

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import com.woocommerce.android.model.Notification
1212
import com.woocommerce.android.notifications.NotificationChannelType.OTHER
1313
import com.woocommerce.android.notifications.WooNotificationBuilder
1414
import com.woocommerce.android.notifications.WooNotificationType.LOCAL_REMINDER
15+
import com.woocommerce.android.notifications.local.LocalNotificationScheduler.Companion.LOCAL_NOTIFICATION_DATA
1516
import com.woocommerce.android.notifications.local.LocalNotificationScheduler.Companion.LOCAL_NOTIFICATION_DESC
1617
import com.woocommerce.android.notifications.local.LocalNotificationScheduler.Companion.LOCAL_NOTIFICATION_ID
1718
import com.woocommerce.android.notifications.local.LocalNotificationScheduler.Companion.LOCAL_NOTIFICATION_TITLE
@@ -35,13 +36,14 @@ class LocalNotificationWorker @AssistedInject constructor(
3536
val id = inputData.getInt(LOCAL_NOTIFICATION_ID, -1)
3637
val title = inputData.getString(LOCAL_NOTIFICATION_TITLE)
3738
val description = inputData.getString(LOCAL_NOTIFICATION_DESC)
39+
val data = inputData.getString(LOCAL_NOTIFICATION_DATA)
3840

3941
if (type != null && id != -1 && title != null && description != null) {
40-
val notification = buildNotification(id, type, title, description)
42+
val notification = buildNotification(id, type, title, description, data)
4143
wooNotificationBuilder.buildAndDisplayLocalNotification(
4244
appContext.getString(R.string.notification_channel_general_id),
4345
notification,
44-
getIntent(appContext, notification),
46+
getIntent(notification),
4547
)
4648

4749
AnalyticsTracker.track(
@@ -54,14 +56,20 @@ class LocalNotificationWorker @AssistedInject constructor(
5456
return Result.success()
5557
}
5658

57-
private fun getIntent(context: Context, notification: Notification): Intent {
58-
return Intent(context, MainActivity::class.java).apply {
59+
private fun getIntent(notification: Notification): Intent {
60+
return Intent(appContext, MainActivity::class.java).apply {
5961
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
6062
putExtra(MainActivity.FIELD_LOCAL_NOTIFICATION, notification)
6163
}
6264
}
6365

64-
private fun buildNotification(id: Int, type: String, title: String, description: String) = Notification(
66+
private fun buildNotification(
67+
id: Int,
68+
type: String,
69+
title: String,
70+
description: String,
71+
data: String?
72+
) = Notification(
6573
noteId = id,
6674
tag = type,
6775
uniqueId = 0,
@@ -71,6 +79,7 @@ class LocalNotificationWorker @AssistedInject constructor(
7179
noteTitle = title,
7280
noteMessage = description,
7381
noteType = LOCAL_REMINDER,
74-
channelType = OTHER
82+
channelType = OTHER,
83+
data = data
7584
)
7685
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/iap/CheckIapEligibilityFragment.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import androidx.compose.ui.platform.ComposeView
88
import androidx.compose.ui.platform.ViewCompositionStrategy
99
import androidx.fragment.app.viewModels
1010
import androidx.navigation.fragment.findNavController
11+
import androidx.navigation.fragment.navArgs
1112
import com.woocommerce.android.extensions.navigateSafely
1213
import com.woocommerce.android.extensions.navigateToHelpScreen
1314
import com.woocommerce.android.ui.base.BaseFragment
@@ -26,6 +27,8 @@ class CheckIapEligibilityFragment : BaseFragment() {
2627
override val activityAppBarStatus: AppBarStatus
2728
get() = AppBarStatus.Hidden
2829

30+
private val navArgs by navArgs<CheckIapEligibilityFragmentArgs>()
31+
2932
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
3033
return ComposeView(requireContext()).apply {
3134
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
@@ -68,7 +71,8 @@ class CheckIapEligibilityFragment : BaseFragment() {
6871
private fun navigateToStoreCreationNative() {
6972
findNavController()
7073
.navigateSafely(
71-
CheckIapEligibilityFragmentDirections.actionCheckIapEligibilityFragmentToStoreNamePickerFragment(),
74+
CheckIapEligibilityFragmentDirections
75+
.actionCheckIapEligibilityFragmentToStoreNamePickerFragment(navArgs.storeName),
7276
skipThrottling = true
7377
)
7478
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/name/StoreNamePickerViewModel.kt

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,36 @@ import com.woocommerce.android.AppPrefsWrapper
1111
import com.woocommerce.android.analytics.AnalyticsEvent
1212
import com.woocommerce.android.analytics.AnalyticsTracker
1313
import com.woocommerce.android.analytics.AnalyticsTrackerWrapper
14+
import com.woocommerce.android.extensions.isNotNullOrEmpty
15+
import com.woocommerce.android.notifications.local.LocalNotification.StoreCreationIncompleteNotification
16+
import com.woocommerce.android.notifications.local.LocalNotificationScheduler
1417
import com.woocommerce.android.support.help.HelpOrigin.STORE_CREATION
1518
import com.woocommerce.android.ui.login.storecreation.NewStore
1619
import com.woocommerce.android.util.FeatureFlag
20+
import com.woocommerce.android.util.IsRemoteFeatureFlagEnabled
21+
import com.woocommerce.android.util.RemoteFeatureFlag.LOCAL_NOTIFICATION_NUDGE_FREE_TRIAL_AFTER_1D
1722
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event
1823
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit
1924
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.NavigateToHelpScreen
2025
import com.woocommerce.android.viewmodel.ScopedViewModel
2126
import com.woocommerce.android.viewmodel.SingleLiveEvent
2227
import com.woocommerce.android.viewmodel.getStateFlow
28+
import com.woocommerce.android.viewmodel.navArgs
2329
import dagger.hilt.android.lifecycle.HiltViewModel
2430
import kotlinx.coroutines.flow.update
2531
import kotlinx.parcelize.Parcelize
32+
import org.wordpress.android.fluxc.store.AccountStore
2633
import javax.inject.Inject
2734

2835
@HiltViewModel
2936
class StoreNamePickerViewModel @Inject constructor(
3037
savedStateHandle: SavedStateHandle,
3138
private val newStore: NewStore,
3239
private val analyticsTrackerWrapper: AnalyticsTrackerWrapper,
33-
private val prefsWrapper: AppPrefsWrapper
40+
private val prefsWrapper: AppPrefsWrapper,
41+
private val localNotificationScheduler: LocalNotificationScheduler,
42+
private val isRemoteFeatureFlagEnabled: IsRemoteFeatureFlagEnabled,
43+
private val accountStore: AccountStore
3444
) : ScopedViewModel(savedStateHandle) {
3545
override val _event = SingleLiveEvent<Event>()
3646
override val event: LiveData<Event> = _event
@@ -45,6 +55,8 @@ class StoreNamePickerViewModel @Inject constructor(
4555
get() = FeatureFlag.FREE_TRIAL_M2.isEnabled() &&
4656
FeatureFlag.STORE_CREATION_PROFILER.isEnabled().not()
4757

58+
private val navArgs: StoreNamePickerFragmentArgs by savedStateHandle.navArgs()
59+
4860
init {
4961
analyticsTrackerWrapper.track(
5062
AnalyticsEvent.SITE_CREATION_STEP,
@@ -54,6 +66,10 @@ class StoreNamePickerViewModel @Inject constructor(
5466
)
5567

5668
triggerEvent(CheckNotificationsPermission(::onCheckNotificationsPermissionResult))
69+
70+
if (navArgs.storeName != null) {
71+
onStoreNameChanged(navArgs.storeName!!)
72+
}
5773
}
5874

5975
fun onCancelPressed() {
@@ -88,6 +104,9 @@ class StoreNamePickerViewModel @Inject constructor(
88104

89105
fun onContinueClicked() {
90106
newStore.update(name = _viewState.value.storeName)
107+
108+
scheduleDeferredNotification()
109+
91110
if (canCreateFreeTrialStore) {
92111
triggerEvent(NavigateToSummary)
93112
} else if (FeatureFlag.STORE_CREATION_PROFILER.isEnabled()) {
@@ -97,6 +116,22 @@ class StoreNamePickerViewModel @Inject constructor(
97116
}
98117
}
99118

119+
private fun scheduleDeferredNotification() {
120+
if (isRemoteFeatureFlagEnabled(LOCAL_NOTIFICATION_NUDGE_FREE_TRIAL_AFTER_1D)) {
121+
val name = if (accountStore.account.firstName.isNotNullOrEmpty())
122+
accountStore.account.firstName
123+
else
124+
accountStore.account.userName
125+
126+
localNotificationScheduler.scheduleNotification(
127+
StoreCreationIncompleteNotification(
128+
name,
129+
_viewState.value.storeName
130+
)
131+
)
132+
}
133+
}
134+
100135
fun onPermissionRationaleDismissed() {
101136
setPermissionRationaleVisible(false)
102137

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/summary/StoreCreationSummaryViewModel.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import com.woocommerce.android.analytics.AnalyticsTrackerWrapper
88
import com.woocommerce.android.extensions.isNotNullOrEmpty
99
import com.woocommerce.android.notifications.local.LocalNotification.StoreCreationFinishedNotification
1010
import com.woocommerce.android.notifications.local.LocalNotificationScheduler
11+
import com.woocommerce.android.notifications.local.LocalNotificationType.STORE_CREATION_INCOMPLETE
1112
import com.woocommerce.android.ui.login.storecreation.CreateFreeTrialStore
1213
import com.woocommerce.android.ui.login.storecreation.CreateFreeTrialStore.StoreCreationState.Failed
1314
import com.woocommerce.android.ui.login.storecreation.CreateFreeTrialStore.StoreCreationState.Finished
@@ -92,6 +93,9 @@ class StoreCreationSummaryViewModel @Inject constructor(
9293
accountStore.account.userName
9394
localNotificationScheduler.scheduleNotification(StoreCreationFinishedNotification(name))
9495
}
96+
97+
// No need to display a notification to complete store creation anymore
98+
localNotificationScheduler.cancelScheduledNotification(STORE_CREATION_INCOMPLETE)
9599
}
96100

97101
object OnCancelPressed : MultiLiveEvent.Event()

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import androidx.navigation.NavController
3535
import androidx.navigation.NavDestination
3636
import androidx.navigation.fragment.FragmentNavigatorExtras
3737
import androidx.navigation.fragment.NavHostFragment
38+
import androidx.navigation.navOptions
3839
import com.automattic.android.tracks.crashlogging.CrashLogging
3940
import com.google.android.material.appbar.AppBarLayout
4041
import com.woocommerce.android.AppPrefs
@@ -77,6 +78,7 @@ import com.woocommerce.android.ui.main.MainActivityViewModel.RestartActivityForA
7778
import com.woocommerce.android.ui.main.MainActivityViewModel.RestartActivityForNotification
7879
import com.woocommerce.android.ui.main.MainActivityViewModel.ShortcutOpenOrderCreation
7980
import com.woocommerce.android.ui.main.MainActivityViewModel.ShortcutOpenPayments
81+
import com.woocommerce.android.ui.main.MainActivityViewModel.ShortcutOpenStoreCreation
8082
import com.woocommerce.android.ui.main.MainActivityViewModel.ShowFeatureAnnouncement
8183
import com.woocommerce.android.ui.main.MainActivityViewModel.ViewMyStoreStats
8284
import com.woocommerce.android.ui.main.MainActivityViewModel.ViewOrderDetail
@@ -98,6 +100,7 @@ import com.woocommerce.android.ui.plans.trial.DetermineTrialStatusBarState.Trial
98100
import com.woocommerce.android.ui.prefs.AppSettingsActivity
99101
import com.woocommerce.android.ui.products.ProductListFragmentDirections
100102
import com.woocommerce.android.ui.reviews.ReviewListFragmentDirections
103+
import com.woocommerce.android.ui.sitepicker.SitePickerFragmentDirections
101104
import com.woocommerce.android.util.ChromeCustomTabUtils
102105
import com.woocommerce.android.util.WooAnimUtils.Duration
103106
import com.woocommerce.android.util.WooAnimUtils.animateBottomBar
@@ -718,6 +721,7 @@ class MainActivity :
718721
viewModel.handleIncomingNotification(localPushId, notification)
719722
} else if (localNotification != null) {
720723
viewModel.onLocalNotificationTapped(localNotification)
724+
intent.removeExtra(FIELD_LOCAL_NOTIFICATION)
721725
}
722726
}
723727
// endregion
@@ -737,6 +741,7 @@ class MainActivity :
737741
is ShowFeatureAnnouncement -> navigateToFeatureAnnouncement(event)
738742
is ViewUrlInWebView -> navigateToWebView(event)
739743
is RequestNotificationsPermission -> requestNotificationsPermission()
744+
is ShortcutOpenStoreCreation -> shortcutOpenStoreCreation(event.storeName)
740745
ViewPayments -> showPayments()
741746
ViewTapToPay -> showTapToPaySummary()
742747
ShortcutOpenPayments -> shortcutShowPayments()
@@ -758,6 +763,22 @@ class MainActivity :
758763
observeBottomBarState()
759764
}
760765

766+
private fun shortcutOpenStoreCreation(storeName: String?) {
767+
navController.apply {
768+
navigate(
769+
NavGraphMainDirections.actionGlobalLoginToSitePickerFragment(
770+
openedFromLogin = AppPrefs.getStoreCreationSource() != AnalyticsTracker.VALUE_SWITCHING_STORE
771+
)
772+
)
773+
navigate(
774+
SitePickerFragmentDirections.actionSitePickerFragmentToStoreCreationNativeFlow(storeName),
775+
navOptions {
776+
popUpTo(R.id.sitePickerFragment) { inclusive = true }
777+
}
778+
)
779+
}
780+
}
781+
761782
private fun observeNotificationsPermissionBarVisibility() {
762783
viewModel.isNotificationsPermissionCardVisible.observe(this) { isVisible ->
763784
if (isVisible) {

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivityViewModel.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import com.woocommerce.android.model.FeatureAnnouncement
1616
import com.woocommerce.android.model.Notification
1717
import com.woocommerce.android.notifications.NotificationChannelType
1818
import com.woocommerce.android.notifications.UnseenReviewsCountHandler
19+
import com.woocommerce.android.notifications.local.LocalNotificationType
1920
import com.woocommerce.android.notifications.push.NotificationMessageHandler
2021
import com.woocommerce.android.tools.SelectedSite
2122
import com.woocommerce.android.tools.SiteConnectionType.Jetpack
@@ -251,6 +252,10 @@ class MainActivityViewModel @Inject constructor(
251252
AnalyticsEvent.LOCAL_NOTIFICATION_TAPPED,
252253
mapOf(AnalyticsTracker.KEY_TYPE to notification.tag)
253254
)
255+
256+
if (notification.tag == LocalNotificationType.STORE_CREATION_INCOMPLETE.value) {
257+
triggerEvent(ShortcutOpenStoreCreation(storeName = notification.data))
258+
}
254259
}
255260

256261
fun onPrivacyPreferenceUpdateFailed(analyticsEnabled: Boolean) {
@@ -280,6 +285,7 @@ class MainActivityViewModel @Inject constructor(
280285
data class ViewUrlInWebView(val url: String) : Event()
281286
object ShortcutOpenPayments : Event()
282287
object ShortcutOpenOrderCreation : Event()
288+
data class ShortcutOpenStoreCreation(val storeName: String?) : Event()
283289
data class RestartActivityForNotification(val pushId: Int, val notification: Notification) : Event()
284290
data class RestartActivityForAppLink(val data: Uri) : Event()
285291
data class ShowFeatureAnnouncement(val announcement: FeatureAnnouncement) : Event()

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ class OrderDetailViewModel @Inject constructor(
108108
private val shippingLabelOnboardingRepository: ShippingLabelOnboardingRepository,
109109
private val orderDetailsTransactionLauncher: OrderDetailsTransactionLauncher,
110110
private val getOrderSubscriptions: GetOrderSubscriptions,
111-
private val giftCardRepository: GiftCardRepository
111+
private val giftCardRepository: GiftCardRepository,
112+
private val orderProductMapper: OrderProductMapper
112113
) : ScopedViewModel(savedState), OnProductFetchedListener {
113114
private val navArgs: OrderDetailFragmentArgs by savedState.navArgs()
114115

@@ -607,7 +608,7 @@ class OrderDetailViewModel @Inject constructor(
607608
): ListInfo<OrderProduct> {
608609
val products = refunds.list.getNonRefundedProducts(order.items)
609610
checkAddonAvailability(products)
610-
val orderProducts = products.toOrderProducts()
611+
val orderProducts = orderProductMapper.toOrderProducts(_productList.value ?: emptyList(), products)
611612
return ListInfo(isVisible = orderProducts.isNotEmpty(), list = orderProducts)
612613
}
613614
private fun checkAddonAvailability(products: List<Order.Item>) {

0 commit comments

Comments
 (0)