From 2fefc7a6498c1e490e788f7267bb078c8912666c Mon Sep 17 00:00:00 2001 From: samiuelson Date: Thu, 1 Aug 2024 13:31:45 +0200 Subject: [PATCH 001/196] Save and restore view state using SavedStateHandle --- .../android/ui/woopos/home/WooPosHomeState.kt | 30 +++++++++++++++---- .../ui/woopos/home/WooPosHomeViewModel.kt | 10 +++++-- .../home/products/WooPosProductsViewModel.kt | 12 ++++++-- .../home/products/WooPosProductsViewState.kt | 13 ++++---- 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeState.kt index f06d7d46341..bf244d2034b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeState.kt @@ -1,30 +1,44 @@ package com.woocommerce.android.ui.woopos.home import androidx.annotation.StringRes +import android.os.Parcelable import com.woocommerce.android.R +import kotlinx.parcelize.IgnoredOnParcel +import kotlinx.parcelize.Parcelize +@Parcelize data class WooPosHomeState( val screenPositionState: ScreenPositionState, val productsInfoDialog: ProductsInfoDialog, val exitConfirmationDialog: WooPosExitConfirmationDialog? = null, -) { - sealed class ScreenPositionState { +) : Parcelable { + @Parcelize + sealed class ScreenPositionState : Parcelable { + @Parcelize sealed class Cart : ScreenPositionState() { + @Parcelize sealed class Visible : Cart() { + @Parcelize data object Empty : Cart() + @Parcelize data object NotEmpty : Cart() } + @Parcelize data object Hidden : Cart() } + @Parcelize sealed class Checkout : ScreenPositionState() { + @Parcelize data object NotPaid : Checkout() + @Parcelize data object Paid : Checkout() } } - sealed class ProductsInfoDialog { + @Parcelize + sealed class ProductsInfoDialog: Parcelable { data object Hidden : ProductsInfoDialog() data class Visible( @@ -33,16 +47,22 @@ data class WooPosHomeState( @StringRes val secondaryMessage: Int, val primaryButton: PrimaryButton, ) : ProductsInfoDialog() { + @Parcelize data class PrimaryButton( @StringRes val label: Int, - ) + ): Parcelable } } } -data object WooPosExitConfirmationDialog { +@Parcelize +data object WooPosExitConfirmationDialog: Parcelable { + @IgnoredOnParcel val title: Int = R.string.woopos_exit_confirmation_title + @IgnoredOnParcel val message: Int = R.string.woopos_exit_confirmation_message + @IgnoredOnParcel val confirmButton: Int = R.string.woopos_exit_confirmation_confirm_button + @IgnoredOnParcel val dismissButton: Int = R.string.woopos_exit_confirmation_dismiss_button } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt index 476fa77da3e..8de2f8c98ea 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt @@ -1,10 +1,11 @@ package com.woocommerce.android.ui.woopos.home +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.woocommerce.android.viewmodel.getStateFlow import com.woocommerce.android.R import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import javax.inject.Inject @@ -13,9 +14,12 @@ import javax.inject.Inject class WooPosHomeViewModel @Inject constructor( private val childrenToParentEventReceiver: WooPosChildrenToParentEventReceiver, private val parentToChildrenEventSender: WooPosParentToChildrenEventSender, + savedStateHandle: SavedStateHandle, ) : ViewModel() { - private val _state = MutableStateFlow( - WooPosHomeState( + private val _state = savedStateHandle.getStateFlow( + scope = viewModelScope, + key = "home_state", + initialValue = WooPosHomeState( screenPositionState = WooPosHomeState.ScreenPositionState.Cart.Hidden, productsInfoDialog = WooPosHomeState.ProductsInfoDialog.Hidden, exitConfirmationDialog = null diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt index bfd0356f52e..2b87f2f1fa5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt @@ -1,5 +1,6 @@ package com.woocommerce.android.ui.woopos.home.products +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.woocommerce.android.R @@ -9,6 +10,7 @@ import com.woocommerce.android.ui.woopos.home.WooPosChildrenToParentEventSender import com.woocommerce.android.ui.woopos.util.datastore.WooPosPreferencesRepository import com.woocommerce.android.ui.woopos.util.format.WooPosFormatPrice import com.woocommerce.android.util.WooLog +import com.woocommerce.android.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow @@ -25,11 +27,17 @@ class WooPosProductsViewModel @Inject constructor( private val productsDataSource: WooPosProductsDataSource, private val fromChildToParentEventSender: WooPosChildrenToParentEventSender, private val priceFormat: WooPosFormatPrice, - private val preferencesRepository: WooPosPreferencesRepository + private val preferencesRepository: WooPosPreferencesRepository, + savedStateHandle: SavedStateHandle, ) : ViewModel() { private var loadMoreProductsJob: Job? = null - private val _viewState = MutableStateFlow(WooPosProductsViewState.Loading()) + private val _viewState: MutableStateFlow = savedStateHandle.getStateFlow( + scope = viewModelScope, + key = "productsViewState", + initialValue = + WooPosProductsViewState.Loading() + ) val viewState: StateFlow = _viewState .onEach { notifyParentAboutStatusChange(it) } .stateIn( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt index 6a147bfdeb0..e672e565bce 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt @@ -5,29 +5,32 @@ import androidx.annotation.DrawableRes import androidx.annotation.StringRes import kotlinx.parcelize.Parcelize +@Parcelize sealed class WooPosProductsViewState( open val reloadingProductsWithPullToRefresh: Boolean, -) { +): Parcelable { + @Parcelize data class Content( val products: List, val loadingMore: Boolean, val bannerState: BannerState, override val reloadingProductsWithPullToRefresh: Boolean = false, ) : WooPosProductsViewState(reloadingProductsWithPullToRefresh) { + @Parcelize data class BannerState( val isBannerHiddenByUser: Boolean, @StringRes val title: Int, @StringRes val message: Int, @DrawableRes val icon: Int, - ) + ): Parcelable } - + @Parcelize data class Loading(override val reloadingProductsWithPullToRefresh: Boolean = false) : WooPosProductsViewState(reloadingProductsWithPullToRefresh) - + @Parcelize data class Error(override val reloadingProductsWithPullToRefresh: Boolean = false) : WooPosProductsViewState(reloadingProductsWithPullToRefresh) - + @Parcelize data class Empty(override val reloadingProductsWithPullToRefresh: Boolean = false) : WooPosProductsViewState(reloadingProductsWithPullToRefresh) } From 197d03c4b6ce79239ac788883a8c0c486849a06c Mon Sep 17 00:00:00 2001 From: samiuelson Date: Thu, 1 Aug 2024 13:32:38 +0200 Subject: [PATCH 002/196] Don't recompute checkout state when products state changes --- .../woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt index 8de2f8c98ea..303cbefa21f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt @@ -133,6 +133,7 @@ class WooPosHomeViewModel @Inject constructor( } private fun handleProductsStatusChanged(event: ChildToParentEvent.ProductsStatusChanged) { + if (state.value.screenPositionState is WooPosHomeState.ScreenPositionState.Checkout) return val newScreenPositionState = when (event) { ChildToParentEvent.ProductsStatusChanged.FullScreen -> WooPosHomeState.ScreenPositionState.Cart.Hidden ChildToParentEvent.ProductsStatusChanged.WithCart -> { From 41042d01f8c56806faf941d4675701c465a6a2f5 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Thu, 1 Aug 2024 15:16:16 +0200 Subject: [PATCH 003/196] Fix detekt's complaints --- .../android/ui/woopos/home/WooPosHomeState.kt | 13 +++++++++---- .../android/ui/woopos/home/WooPosHomeViewModel.kt | 2 +- .../woopos/home/products/WooPosProductsViewState.kt | 7 +++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeState.kt index bf244d2034b..977cf3e94a5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeState.kt @@ -1,7 +1,7 @@ package com.woocommerce.android.ui.woopos.home -import androidx.annotation.StringRes import android.os.Parcelable +import androidx.annotation.StringRes import com.woocommerce.android.R import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize @@ -20,6 +20,7 @@ data class WooPosHomeState( sealed class Visible : Cart() { @Parcelize data object Empty : Cart() + @Parcelize data object NotEmpty : Cart() } @@ -32,13 +33,14 @@ data class WooPosHomeState( sealed class Checkout : ScreenPositionState() { @Parcelize data object NotPaid : Checkout() + @Parcelize data object Paid : Checkout() } } @Parcelize - sealed class ProductsInfoDialog: Parcelable { + sealed class ProductsInfoDialog : Parcelable { data object Hidden : ProductsInfoDialog() data class Visible( @@ -50,19 +52,22 @@ data class WooPosHomeState( @Parcelize data class PrimaryButton( @StringRes val label: Int, - ): Parcelable + ) : Parcelable } } } @Parcelize -data object WooPosExitConfirmationDialog: Parcelable { +data object WooPosExitConfirmationDialog : Parcelable { @IgnoredOnParcel val title: Int = R.string.woopos_exit_confirmation_title + @IgnoredOnParcel val message: Int = R.string.woopos_exit_confirmation_message + @IgnoredOnParcel val confirmButton: Int = R.string.woopos_exit_confirmation_confirm_button + @IgnoredOnParcel val dismissButton: Int = R.string.woopos_exit_confirmation_dismiss_button } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt index 303cbefa21f..6eefec8401b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt @@ -3,8 +3,8 @@ package com.woocommerce.android.ui.woopos.home import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.woocommerce.android.viewmodel.getStateFlow import com.woocommerce.android.R +import com.woocommerce.android.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt index e672e565bce..603712af5fa 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt @@ -8,7 +8,7 @@ import kotlinx.parcelize.Parcelize @Parcelize sealed class WooPosProductsViewState( open val reloadingProductsWithPullToRefresh: Boolean, -): Parcelable { +) : Parcelable { @Parcelize data class Content( val products: List, @@ -22,14 +22,17 @@ sealed class WooPosProductsViewState( @StringRes val title: Int, @StringRes val message: Int, @DrawableRes val icon: Int, - ): Parcelable + ) : Parcelable } + @Parcelize data class Loading(override val reloadingProductsWithPullToRefresh: Boolean = false) : WooPosProductsViewState(reloadingProductsWithPullToRefresh) + @Parcelize data class Error(override val reloadingProductsWithPullToRefresh: Boolean = false) : WooPosProductsViewState(reloadingProductsWithPullToRefresh) + @Parcelize data class Empty(override val reloadingProductsWithPullToRefresh: Boolean = false) : WooPosProductsViewState(reloadingProductsWithPullToRefresh) From f3aa5b06dc8788669f8974f498159dc0d5ab0f74 Mon Sep 17 00:00:00 2001 From: Rooney Date: Thu, 1 Aug 2024 10:36:07 -0400 Subject: [PATCH 004/196] Should read "Taxes" --- WooCommerce/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index 99d6d6a6b52..37c25eea8f6 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -4219,7 +4219,7 @@ Payment successful New transaction Subtotal - Tax + Taxes Total Collect Card Payment No products From f6a38c8bda0f6ce649971252519ecdadad3e618b Mon Sep 17 00:00:00 2001 From: samiuelson Date: Thu, 1 Aug 2024 16:42:01 +0200 Subject: [PATCH 005/196] Update unit tests --- .../android/ui/woopos/home/WooPosHomeViewModelTest.kt | 9 ++++++++- .../woopos/home/products/WooPosProductsViewModelTest.kt | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModelTest.kt index 1463ef5abc1..539d472ffc7 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModelTest.kt @@ -1,5 +1,7 @@ package com.woocommerce.android.ui.woopos.home +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.lifecycle.SavedStateHandle import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.util.WooPosCoroutineTestRule import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -21,6 +23,10 @@ class WooPosHomeViewModelTest { @JvmField val coroutinesTestRule = WooPosCoroutineTestRule() + @Rule + @JvmField + val rule = InstantTaskExecutorRule() + private val childrenToParentEventReceiver: WooPosChildrenToParentEventReceiver = mock() private val parentToChildrenEventSender: WooPosParentToChildrenEventSender = mock() @@ -226,6 +232,7 @@ class WooPosHomeViewModelTest { private fun createViewModel() = WooPosHomeViewModel( childrenToParentEventReceiver, - parentToChildrenEventSender + parentToChildrenEventSender, + SavedStateHandle() ) } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt index b0acf7d6756..3474befe18b 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt @@ -1,5 +1,7 @@ package com.woocommerce.android.ui.woopos.home.products +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.lifecycle.SavedStateHandle import app.cash.turbine.test import com.woocommerce.android.R import com.woocommerce.android.ui.products.ProductTestUtils @@ -30,6 +32,10 @@ class WooPosProductsViewModelTest { @JvmField val coroutinesTestRule = WooPosCoroutineTestRule() + @Rule + @JvmField + val rule = InstantTaskExecutorRule() + private val productsDataSource: WooPosProductsDataSource = mock() private val fromChildToParentEventSender: WooPosChildrenToParentEventSender = mock() private val posPreferencesRepository: WooPosPreferencesRepository = mock() @@ -789,6 +795,7 @@ class WooPosProductsViewModelTest { productsDataSource, fromChildToParentEventSender, priceFormat, - posPreferencesRepository + posPreferencesRepository, + SavedStateHandle() ) } From fe5b44c73f9ed44b4a781234e8246f0a64f4f7b1 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Fri, 2 Aug 2024 14:17:56 +0200 Subject: [PATCH 006/196] Revert storing Products pane state in Bundle --- .../woopos/home/products/WooPosProductsViewModel.kt | 11 ++--------- .../home/products/WooPosProductsViewModelTest.kt | 7 ------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt index 2b87f2f1fa5..4e14cc9be11 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt @@ -1,6 +1,5 @@ package com.woocommerce.android.ui.woopos.home.products -import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.woocommerce.android.R @@ -10,7 +9,6 @@ import com.woocommerce.android.ui.woopos.home.WooPosChildrenToParentEventSender import com.woocommerce.android.ui.woopos.util.datastore.WooPosPreferencesRepository import com.woocommerce.android.ui.woopos.util.format.WooPosFormatPrice import com.woocommerce.android.util.WooLog -import com.woocommerce.android.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow @@ -28,16 +26,11 @@ class WooPosProductsViewModel @Inject constructor( private val fromChildToParentEventSender: WooPosChildrenToParentEventSender, private val priceFormat: WooPosFormatPrice, private val preferencesRepository: WooPosPreferencesRepository, - savedStateHandle: SavedStateHandle, ) : ViewModel() { private var loadMoreProductsJob: Job? = null - private val _viewState: MutableStateFlow = savedStateHandle.getStateFlow( - scope = viewModelScope, - key = "productsViewState", - initialValue = - WooPosProductsViewState.Loading() - ) + private val _viewState = + MutableStateFlow(WooPosProductsViewState.Loading()) val viewState: StateFlow = _viewState .onEach { notifyParentAboutStatusChange(it) } .stateIn( diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt index 3474befe18b..6f1bc0e18a7 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt @@ -1,7 +1,5 @@ package com.woocommerce.android.ui.woopos.home.products -import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import androidx.lifecycle.SavedStateHandle import app.cash.turbine.test import com.woocommerce.android.R import com.woocommerce.android.ui.products.ProductTestUtils @@ -32,10 +30,6 @@ class WooPosProductsViewModelTest { @JvmField val coroutinesTestRule = WooPosCoroutineTestRule() - @Rule - @JvmField - val rule = InstantTaskExecutorRule() - private val productsDataSource: WooPosProductsDataSource = mock() private val fromChildToParentEventSender: WooPosChildrenToParentEventSender = mock() private val posPreferencesRepository: WooPosPreferencesRepository = mock() @@ -796,6 +790,5 @@ class WooPosProductsViewModelTest { fromChildToParentEventSender, priceFormat, posPreferencesRepository, - SavedStateHandle() ) } From 80d918104d27d30918bfd21814b8973d404fb709 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Fri, 2 Aug 2024 14:35:05 +0200 Subject: [PATCH 007/196] Revert parcelization of `WooPosProductsViewState` --- .../home/products/WooPosProductsViewState.kt | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt index 603712af5fa..20f56fdccf7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt @@ -1,47 +1,38 @@ package com.woocommerce.android.ui.woopos.home.products -import android.os.Parcelable import androidx.annotation.DrawableRes import androidx.annotation.StringRes -import kotlinx.parcelize.Parcelize -@Parcelize sealed class WooPosProductsViewState( open val reloadingProductsWithPullToRefresh: Boolean, -) : Parcelable { - @Parcelize +) { data class Content( val products: List, val loadingMore: Boolean, val bannerState: BannerState, override val reloadingProductsWithPullToRefresh: Boolean = false, ) : WooPosProductsViewState(reloadingProductsWithPullToRefresh) { - @Parcelize data class BannerState( val isBannerHiddenByUser: Boolean, @StringRes val title: Int, @StringRes val message: Int, @DrawableRes val icon: Int, - ) : Parcelable + ) } - @Parcelize data class Loading(override val reloadingProductsWithPullToRefresh: Boolean = false) : WooPosProductsViewState(reloadingProductsWithPullToRefresh) - @Parcelize data class Error(override val reloadingProductsWithPullToRefresh: Boolean = false) : WooPosProductsViewState(reloadingProductsWithPullToRefresh) - @Parcelize data class Empty(override val reloadingProductsWithPullToRefresh: Boolean = false) : WooPosProductsViewState(reloadingProductsWithPullToRefresh) } -@Parcelize data class WooPosProductsListItem( val id: Long, val name: String, val price: String, val imageUrl: String?, -) : Parcelable +) From ac96b95989c28c51a15124352aa5e09f13a5a2b3 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Fri, 2 Aug 2024 20:51:48 +0300 Subject: [PATCH 008/196] Remove retaining the version 480 --- fastlane/Fastfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index df46979ffbb..368d2557009 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -634,9 +634,7 @@ platform :android do skip_upload_changelogs: false, skip_upload_images: true, skip_upload_screenshots: true, - json_key: UPLOAD_TO_PLAY_STORE_JSON_KEY, - # We're retaining version 16.4 - 480 because 16.5 increases the minSDKVersion from Android 7 to Android 8 - version_codes_to_retain: app == WEAR_APP ? nil : [480] + json_key: UPLOAD_TO_PLAY_STORE_JSON_KEY ) create_gh_release(app: app, version: version) if options[:create_release] From 165429a598aa41516d9aa15b9a39087b09ac89af Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Mon, 5 Aug 2024 09:44:13 +0530 Subject: [PATCH 009/196] Debounce connect to card reader click action --- .../home/toolbar/WooPosToolbarViewModel.kt | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModel.kt index 73782fcd6d1..877fb4bad99 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModel.kt @@ -15,6 +15,8 @@ import com.woocommerce.android.ui.woopos.home.toolbar.WooPosToolbarUIEvent.MenuI import com.woocommerce.android.ui.woopos.home.toolbar.WooPosToolbarUIEvent.OnOutsideOfToolbarMenuClicked import com.woocommerce.android.ui.woopos.home.toolbar.WooPosToolbarUIEvent.OnToolbarMenuClicked import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch @@ -33,6 +35,8 @@ class WooPosToolbarViewModel @Inject constructor( ) val state: StateFlow = _state + private var debounceJob: Job? = null + init { viewModelScope.launch { cardReaderFacade.readerStatus.collect { @@ -85,7 +89,9 @@ class WooPosToolbarViewModel @Inject constructor( private fun handleConnectToReaderButtonClicked() { if (_state.value.cardReaderStatus != WooPosToolbarState.WooPosCardReaderStatus.Connected) { - cardReaderFacade.connectToReader() + debounce { + cardReaderFacade.connectToReader() + } } } @@ -96,6 +102,16 @@ class WooPosToolbarViewModel @Inject constructor( } } + private fun debounce(block: () -> Unit) { + if (debounceJob?.isActive == true) { + return + } + debounceJob = viewModelScope.launch { + block() + delay(DEBOUNCE_TIME_MS) + } + } + private companion object { val toolbarMenuItems = listOf( WooPosToolbarState.Menu.MenuItem( @@ -107,5 +123,12 @@ class WooPosToolbarViewModel @Inject constructor( icon = R.drawable.woopos_ic_exit_pos, ), ) + + private const val DEBOUNCE_TIME_MS = 800L + } + + override fun onCleared() { + super.onCleared() + debounceJob?.cancel() } } From 81036b34aafae4711cda9ab06e79a519cb9f65bb Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Mon, 5 Aug 2024 09:45:05 +0530 Subject: [PATCH 010/196] Add test to verify that multiple successive clicks to connect card reader is handled properly --- .../home/toolbar/WooPosToolbarViewModelTest.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModelTest.kt index 3c3fbc7cc2f..4d506ec25b1 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModelTest.kt @@ -8,11 +8,13 @@ import com.woocommerce.android.ui.woopos.home.WooPosChildrenToParentEventSender import com.woocommerce.android.ui.woopos.util.WooPosCoroutineTestRule import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat import org.junit.Rule import org.junit.Test import org.mockito.kotlin.mock +import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @@ -129,6 +131,22 @@ class WooPosToolbarViewModelTest { assertThat(viewModel.state.value.menu).isEqualTo(WooPosToolbarState.Menu.Hidden) } + @Test + fun `when connect to card reader clicked multiple times, then debounce prevents multiple clicks`() = runTest { + // GIVEN + whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(CardReaderStatus.NotConnected())) + val viewModel = createViewModel() + + // WHEN + viewModel.onUiEvent(WooPosToolbarUIEvent.ConnectToAReaderClicked) + viewModel.onUiEvent(WooPosToolbarUIEvent.ConnectToAReaderClicked) + viewModel.onUiEvent(WooPosToolbarUIEvent.ConnectToAReaderClicked) + advanceUntilIdle() + + // THEN + verify(cardReaderFacade, times(1)).connectToReader() + } + private fun createViewModel() = WooPosToolbarViewModel( cardReaderFacade, childrenToParentEventSender From ab8707e477dadca31a823cb1fc10cc249bac062c Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Mon, 5 Aug 2024 09:45:44 +0530 Subject: [PATCH 011/196] Add test to verify that multiple successive clicks after delay to connect card reader is handled properly (all clicks should be received) --- .../home/toolbar/WooPosToolbarViewModelTest.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModelTest.kt index 4d506ec25b1..2942c4cbad9 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModelTest.kt @@ -147,6 +147,24 @@ class WooPosToolbarViewModelTest { verify(cardReaderFacade, times(1)).connectToReader() } + @Test + fun `when connect to card reader clicked multiple times after delay, then debounce handles all clicks`() = runTest { + // GIVEN + whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(CardReaderStatus.NotConnected())) + val viewModel = createViewModel() + + // WHEN + viewModel.onUiEvent(WooPosToolbarUIEvent.ConnectToAReaderClicked) + advanceUntilIdle() + viewModel.onUiEvent(WooPosToolbarUIEvent.ConnectToAReaderClicked) + advanceUntilIdle() + viewModel.onUiEvent(WooPosToolbarUIEvent.ConnectToAReaderClicked) + advanceUntilIdle() + + // THEN + verify(cardReaderFacade, times(3)).connectToReader() + } + private fun createViewModel() = WooPosToolbarViewModel( cardReaderFacade, childrenToParentEventSender From c688862def272f1aedb02621e9992ddfdafb4ae1 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 5 Aug 2024 15:49:46 +0200 Subject: [PATCH 012/196] Paddings as on the design --- .../WooPosTotalsPaymentSuccessScreen.kt | 60 ++++++++----------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt index 8736a02005a..8528501c862 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -39,48 +38,39 @@ fun WooPosPaymentSuccessScreen( ) { Column( modifier = Modifier + .padding(24.dp.toAdaptivePadding()) .fillMaxSize() + .verticalScroll(rememberScrollState()) .background(Color(0xFF98F179)), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Column( - modifier = Modifier - .padding(24.dp.toAdaptivePadding()) - .weight(1f) - .fillMaxWidth() - .verticalScroll(rememberScrollState()), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - ) { - Spacer(modifier = Modifier.weight(1f)) + Spacer(modifier = Modifier.weight(1f)) - Icon( - painter = painterResource(id = R.drawable.woo_pos_ic_payment_success), - tint = Color.Unspecified, - contentDescription = null, - ) - Spacer(modifier = Modifier.height(16.dp.toAdaptivePadding())) - Text( - text = stringResource(R.string.woopos_payment_successful_label), - style = MaterialTheme.typography.h4, - fontWeight = FontWeight.Bold, - textAlign = TextAlign.Center, - color = MaterialTheme.colors.onSurface - ) + Icon( + painter = painterResource(id = R.drawable.woo_pos_ic_payment_success), + tint = Color.Unspecified, + contentDescription = null, + ) + Spacer(modifier = Modifier.height(56.dp.toAdaptivePadding())) + Text( + text = stringResource(R.string.woopos_payment_successful_label), + style = MaterialTheme.typography.h4, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center, + color = MaterialTheme.colors.onSurface + ) - Text( - text = stringResource(R.string.woopos_success_screen_total, state.orderTotalText), - style = MaterialTheme.typography.subtitle1, - textAlign = TextAlign.Center, - color = MaterialTheme.colors.onSurface, - modifier = Modifier.padding(24.dp.toAdaptivePadding()) - ) + Spacer(modifier = Modifier.height(16.dp.toAdaptivePadding())) - Spacer(modifier = Modifier.weight(1f)) - } + Text( + text = stringResource(R.string.woopos_success_screen_total, state.orderTotalText), + style = MaterialTheme.typography.subtitle1, + textAlign = TextAlign.Center, + color = MaterialTheme.colors.onSurface, + ) - Spacer(modifier = Modifier.height(24.dp.toAdaptivePadding())) + Spacer(modifier = Modifier.height(80.dp.toAdaptivePadding())) OutlinedButton( modifier = Modifier @@ -106,6 +96,8 @@ fun WooPosPaymentSuccessScreen( textAlign = TextAlign.Center ) } + + Spacer(modifier = Modifier.weight(1f)) } } From fd9ebd7e5c20b493f13cc0524dce52c1758f1d83 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 5 Aug 2024 16:06:15 +0200 Subject: [PATCH 013/196] CheckMarkIcon --- .../WooPosTotalsPaymentSuccessScreen.kt | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt index 8528501c862..dcc51802f5e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt @@ -2,6 +2,7 @@ package com.woocommerce.android.ui.woopos.home.totals.payment.success import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -10,15 +11,19 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.ButtonDefaults import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.OutlinedButton import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -47,12 +52,10 @@ fun WooPosPaymentSuccessScreen( ) { Spacer(modifier = Modifier.weight(1f)) - Icon( - painter = painterResource(id = R.drawable.woo_pos_ic_payment_success), - tint = Color.Unspecified, - contentDescription = null, - ) + CheckMarkIcon() + Spacer(modifier = Modifier.height(56.dp.toAdaptivePadding())) + Text( text = stringResource(R.string.woopos_payment_successful_label), style = MaterialTheme.typography.h4, @@ -101,6 +104,26 @@ fun WooPosPaymentSuccessScreen( } } +@Composable +private fun CheckMarkIcon() { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .size(156.dp) + .shadow(8.dp, CircleShape) + .background( + MaterialTheme.colors.background, CircleShape + ) + ) { + Icon( + imageVector = Icons.Default.Check, + tint = WooPosTheme.colors.success, + contentDescription = null, + modifier = Modifier.size(72.dp) + ) + } +} + @WooPosPreview @Composable fun WooPosPaymentSuccessScreenPreview() { From 6b04faaaabb233356e1cba984581a74d94c4a6d8 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 5 Aug 2024 16:07:06 +0200 Subject: [PATCH 014/196] contentDescription for the icon --- .../totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt index dcc51802f5e..3d120e2d0bd 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt @@ -118,7 +118,7 @@ private fun CheckMarkIcon() { Icon( imageVector = Icons.Default.Check, tint = WooPosTheme.colors.success, - contentDescription = null, + contentDescription = stringResource(id = R.string.woopos_payment_successful_label), modifier = Modifier.size(72.dp) ) } From da57c62c9e17895d9221ef758e05a59578f33704 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 5 Aug 2024 16:08:34 +0200 Subject: [PATCH 015/196] paymentSuccessBackground color --- .../android/ui/woopos/common/composeui/WooPosTheme.kt | 3 +++ .../totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/WooPosTheme.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/WooPosTheme.kt index 3a095053997..276424a7c86 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/WooPosTheme.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/WooPosTheme.kt @@ -18,6 +18,7 @@ data class CustomColors( val border: Color, val success: Color, val error: Color, + val paymentSuccessBackground: Color, ) private val DarkColorPalette = darkColors( @@ -49,6 +50,7 @@ private val DarkCustomColors = CustomColors( border = Color(0xFF8D8D8D), success = Color(0xFF06B166), error = Color(0xFFBE4400), + paymentSuccessBackground = Color(0xFF74C758), ) private val LightCustomColors = CustomColors( @@ -56,6 +58,7 @@ private val LightCustomColors = CustomColors( border = Color(0xFFC6C6C8), success = Color(0xFF03D479), error = Color(0xFFF16618), + paymentSuccessBackground = Color(0xFF98F179), ) private val LocalCustomColors = staticCompositionLocalOf { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt index 3d120e2d0bd..edee4d01980 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt @@ -24,7 +24,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow -import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -46,7 +45,7 @@ fun WooPosPaymentSuccessScreen( .padding(24.dp.toAdaptivePadding()) .fillMaxSize() .verticalScroll(rememberScrollState()) - .background(Color(0xFF98F179)), + .background(WooPosTheme.colors.paymentSuccessBackground), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { From 4bc9a8692f66d1f86679c031d846d5f94a1ee664 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 5 Aug 2024 16:21:48 +0200 Subject: [PATCH 016/196] Fixed naming of WooPosHomeProductInfoDialog --- .../{ProductInfoDialog.kt => WooPosHomeProductInfoDialog.kt} | 4 ++-- .../woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/{ProductInfoDialog.kt => WooPosHomeProductInfoDialog.kt} (99%) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/ProductInfoDialog.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeProductInfoDialog.kt similarity index 99% rename from WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/ProductInfoDialog.kt rename to WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeProductInfoDialog.kt index 657052fa686..27793f791b6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/ProductInfoDialog.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeProductInfoDialog.kt @@ -47,7 +47,7 @@ import com.woocommerce.android.ui.woopos.common.composeui.WooPosTheme import com.woocommerce.android.ui.woopos.common.composeui.toAdaptivePadding @Composable -fun ProductInfoDialog( +fun WooPosProductInfoDialog( state: WooPosHomeState.ProductsInfoDialog.Visible, onDismissRequest: () -> Unit, ) { @@ -214,7 +214,7 @@ fun ProductInfoDialogPreview() { modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { - ProductInfoDialog( + WooPosProductInfoDialog( state = WooPosHomeState.ProductsInfoDialog.Visible( header = R.string.woopos_dialog_products_info_heading, primaryMessage = R.string.woopos_dialog_products_info_primary_message, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt index 0e8756c33da..b6e20f3441d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt @@ -236,7 +236,7 @@ private fun HandleProductsInfoDialog( BoxOverlay(state = currentState) { // no op } - ProductInfoDialog( + WooPosProductInfoDialog( state = currentState, onDismissRequest = { isDialogVisible = false From 852373bc3d38d2796a63aa1a8f5974a272a54efd Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 5 Aug 2024 16:23:05 +0200 Subject: [PATCH 017/196] Fixed sizes of the button --- .../success/WooPosTotalsPaymentSuccessScreen.kt | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt index edee4d01980..cf665749103 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt @@ -13,7 +13,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.verticalScroll -import androidx.compose.material.ButtonDefaults import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.OutlinedButton @@ -77,22 +76,20 @@ fun WooPosPaymentSuccessScreen( OutlinedButton( modifier = Modifier .padding(24.dp.toAdaptivePadding()) - .height(80.dp.toAdaptivePadding()) - .width(600.dp.toAdaptivePadding()), - colors = ButtonDefaults.outlinedButtonColors( - contentColor = MaterialTheme.colors.onSurface - ), + .height(80.dp) + .width(604.dp), onClick = onNewTransactionClicked ) { Icon( - modifier = Modifier.size(20.dp.toAdaptivePadding()), + modifier = Modifier.size(24.dp), painter = painterResource(id = R.drawable.woo_pos_ic_return_home), - contentDescription = null + tint = MaterialTheme.colors.onSurface, + contentDescription = stringResource(id = R.string.woopos_new_order_button) ) - Spacer(modifier = Modifier.width(8.dp.toAdaptivePadding())) + Spacer(modifier = Modifier.width(12.dp.toAdaptivePadding())) Text( text = stringResource(R.string.woopos_new_order_button), - style = MaterialTheme.typography.h6, + style = MaterialTheme.typography.h5, fontWeight = FontWeight.SemiBold, color = MaterialTheme.colors.onSurface, textAlign = TextAlign.Center From 99d14ab43c607f4f3a12bb854c726e59d49037f1 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 5 Aug 2024 16:26:54 +0200 Subject: [PATCH 018/196] Fixed color text --- .../android/ui/woopos/common/composeui/WooPosTheme.kt | 3 +++ .../totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/WooPosTheme.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/WooPosTheme.kt index 276424a7c86..4dad524cca5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/WooPosTheme.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/WooPosTheme.kt @@ -19,6 +19,7 @@ data class CustomColors( val success: Color, val error: Color, val paymentSuccessBackground: Color, + val paymentSuccessText: Color, ) private val DarkColorPalette = darkColors( @@ -51,6 +52,7 @@ private val DarkCustomColors = CustomColors( success = Color(0xFF06B166), error = Color(0xFFBE4400), paymentSuccessBackground = Color(0xFF74C758), + paymentSuccessText = Color(0xFFF2EBFF), ) private val LightCustomColors = CustomColors( @@ -59,6 +61,7 @@ private val LightCustomColors = CustomColors( success = Color(0xFF03D479), error = Color(0xFFF16618), paymentSuccessBackground = Color(0xFF98F179), + paymentSuccessText = Color(0xFF271B3D), ) private val LocalCustomColors = staticCompositionLocalOf { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt index cf665749103..dce01ec043c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt @@ -91,7 +91,7 @@ fun WooPosPaymentSuccessScreen( text = stringResource(R.string.woopos_new_order_button), style = MaterialTheme.typography.h5, fontWeight = FontWeight.SemiBold, - color = MaterialTheme.colors.onSurface, + color = WooPosTheme.colors.paymentSuccessText, textAlign = TextAlign.Center ) } From e7f17729417931f71034c9230f2b67cf8142834e Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 5 Aug 2024 16:32:33 +0200 Subject: [PATCH 019/196] Button as per design --- .../success/WooPosTotalsPaymentSuccessScreen.kt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt index dce01ec043c..79651141824 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt @@ -1,5 +1,6 @@ package com.woocommerce.android.ui.woopos.home.totals.payment.success +import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -12,7 +13,9 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll +import androidx.compose.material.ButtonDefaults import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.OutlinedButton @@ -23,6 +26,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -66,8 +70,9 @@ fun WooPosPaymentSuccessScreen( Text( text = stringResource(R.string.woopos_success_screen_total, state.orderTotalText), - style = MaterialTheme.typography.subtitle1, + style = MaterialTheme.typography.h6, textAlign = TextAlign.Center, + fontWeight = FontWeight.Normal, color = MaterialTheme.colors.onSurface, ) @@ -75,10 +80,15 @@ fun WooPosPaymentSuccessScreen( OutlinedButton( modifier = Modifier - .padding(24.dp.toAdaptivePadding()) .height(80.dp) .width(604.dp), - onClick = onNewTransactionClicked + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.Transparent, + contentColor = Color.Transparent, + ), + onClick = onNewTransactionClicked, + border = BorderStroke(1.dp, MaterialTheme.colors.onSurface), + shape = RoundedCornerShape(8.dp), ) { Icon( modifier = Modifier.size(24.dp), From 32d51dbb50caca17bcb834ce40c27b3277540dd6 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 5 Aug 2024 16:35:01 +0200 Subject: [PATCH 020/196] Fixed formatting --- .../payment/success/WooPosTotalsPaymentSuccessScreen.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt index 79651141824..2a1a45633a3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt @@ -117,9 +117,7 @@ private fun CheckMarkIcon() { modifier = Modifier .size(156.dp) .shadow(8.dp, CircleShape) - .background( - MaterialTheme.colors.background, CircleShape - ) + .background(MaterialTheme.colors.background, CircleShape) ) { Icon( imageVector = Icons.Default.Check, From f35717937b14f2c07464ddb9b6e732bb94da4bb9 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 5 Aug 2024 16:44:34 +0200 Subject: [PATCH 021/196] Removed redundant padding --- .../totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt index 2a1a45633a3..8045cdcf823 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState @@ -45,7 +44,6 @@ fun WooPosPaymentSuccessScreen( ) { Column( modifier = Modifier - .padding(24.dp.toAdaptivePadding()) .fillMaxSize() .verticalScroll(rememberScrollState()) .background(WooPosTheme.colors.paymentSuccessBackground), From 8a39437ee87c75027587a2c08fbb852ae091daab Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Tue, 6 Aug 2024 08:18:52 +0530 Subject: [PATCH 022/196] Change cross icon color --- .../com/woocommerce/android/ui/woopos/home/ProductInfoDialog.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/ProductInfoDialog.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/ProductInfoDialog.kt index 657052fa686..336923915d1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/ProductInfoDialog.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/ProductInfoDialog.kt @@ -131,7 +131,7 @@ fun ProductInfoDialog( Icon( modifier = Modifier.size(35.dp), imageVector = Icons.Default.Close, - tint = MaterialTheme.colors.secondaryVariant.copy(alpha = 0.30f), + tint = MaterialTheme.colors.onSurface, contentDescription = stringResource( id = R.string.woopos_banner_simple_products_close_content_description ), From 00866f58a233ed55ac1d9b53570c0055f880455f Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 6 Aug 2024 11:24:58 +0200 Subject: [PATCH 023/196] Add an animation --- .../WooPosTotalsPaymentSuccessScreen.kt | 197 ++++++++++++------ 1 file changed, 137 insertions(+), 60 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt index 8045cdcf823..cdd1075a6a6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt @@ -1,19 +1,18 @@ package com.woocommerce.android.ui.woopos.home.totals.payment.success +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.animation.core.spring import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll import androidx.compose.material.ButtonDefaults import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme @@ -22,6 +21,11 @@ import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow @@ -31,89 +35,159 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import androidx.constraintlayout.compose.ConstraintLayout import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview import com.woocommerce.android.ui.woopos.common.composeui.WooPosTheme import com.woocommerce.android.ui.woopos.common.composeui.toAdaptivePadding import com.woocommerce.android.ui.woopos.home.totals.WooPosTotalsViewState +import kotlinx.coroutines.delay @Composable fun WooPosPaymentSuccessScreen( state: WooPosTotalsViewState.PaymentSuccess, onNewTransactionClicked: () -> Unit, ) { - Column( + var bottomAnimationStarted by remember { mutableStateOf(false) } + var iconAnimationStarted by remember { mutableStateOf(false) } + + LaunchedEffect(Unit) { + delay(300) + bottomAnimationStarted = true + delay(300) + iconAnimationStarted = true + } + + WooPosPaymentSuccessScreen( + state = state, + iconAnimationStarted = iconAnimationStarted, + bottomAnimationStarted = bottomAnimationStarted, + onNewTransactionClicked = onNewTransactionClicked, + ) +} + +@Composable +fun WooPosPaymentSuccessScreen( + state: WooPosTotalsViewState.PaymentSuccess, + iconAnimationStarted: Boolean, + bottomAnimationStarted: Boolean, + onNewTransactionClicked: () -> Unit, +) { + Box( modifier = Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()) .background(WooPosTheme.colors.paymentSuccessBackground), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, + contentAlignment = Alignment.Center ) { - Spacer(modifier = Modifier.weight(1f)) - - CheckMarkIcon() - - Spacer(modifier = Modifier.height(56.dp.toAdaptivePadding())) - - Text( - text = stringResource(R.string.woopos_payment_successful_label), - style = MaterialTheme.typography.h4, - fontWeight = FontWeight.Bold, - textAlign = TextAlign.Center, - color = MaterialTheme.colors.onSurface - ) - - Spacer(modifier = Modifier.height(16.dp.toAdaptivePadding())) - - Text( - text = stringResource(R.string.woopos_success_screen_total, state.orderTotalText), - style = MaterialTheme.typography.h6, - textAlign = TextAlign.Center, - fontWeight = FontWeight.Normal, - color = MaterialTheme.colors.onSurface, + val marginBetweenButtonAndText by animateDpAsState( + targetValue = if (bottomAnimationStarted) 80.dp else 16.dp, + label = "Check mark size" ) + ConstraintLayout { + val (icon, title, message, button) = createRefs() - Spacer(modifier = Modifier.height(80.dp.toAdaptivePadding())) + val checkMarkIconMargin = 56.dp.toAdaptivePadding() + CheckMarkIcon( + animationStarted = iconAnimationStarted, + modifier = Modifier.constrainAs(icon) { + start.linkTo(parent.start) + end.linkTo(parent.end) + bottom.linkTo(title.top, margin = checkMarkIconMargin) + } + ) - OutlinedButton( - modifier = Modifier - .height(80.dp) - .width(604.dp), - colors = ButtonDefaults.buttonColors( - backgroundColor = Color.Transparent, - contentColor = Color.Transparent, - ), - onClick = onNewTransactionClicked, - border = BorderStroke(1.dp, MaterialTheme.colors.onSurface), - shape = RoundedCornerShape(8.dp), - ) { - Icon( - modifier = Modifier.size(24.dp), - painter = painterResource(id = R.drawable.woo_pos_ic_return_home), - tint = MaterialTheme.colors.onSurface, - contentDescription = stringResource(id = R.string.woopos_new_order_button) + val textsMargin = 16.dp.toAdaptivePadding() + Text( + text = stringResource(R.string.woopos_payment_successful_label), + style = MaterialTheme.typography.h4, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center, + color = MaterialTheme.colors.onSurface, + modifier = Modifier.constrainAs(title) { + start.linkTo(parent.start) + end.linkTo(parent.end) + bottom.linkTo(message.top, margin = textsMargin) + } ) - Spacer(modifier = Modifier.width(12.dp.toAdaptivePadding())) + + val marginBetweenButtonAndTextAdaptive = marginBetweenButtonAndText.toAdaptivePadding() Text( - text = stringResource(R.string.woopos_new_order_button), - style = MaterialTheme.typography.h5, - fontWeight = FontWeight.SemiBold, - color = WooPosTheme.colors.paymentSuccessText, - textAlign = TextAlign.Center + text = stringResource(R.string.woopos_success_screen_total, state.orderTotalText), + style = MaterialTheme.typography.h6, + textAlign = TextAlign.Center, + fontWeight = FontWeight.Normal, + color = MaterialTheme.colors.onSurface, + modifier = Modifier.constrainAs(message) { + start.linkTo(parent.start) + end.linkTo(parent.end) + bottom.linkTo(button.top, margin = marginBetweenButtonAndTextAdaptive) + } ) - } - Spacer(modifier = Modifier.weight(1f)) + OutlinedButton( + modifier = Modifier + .constrainAs(button) { + bottom.linkTo(parent.bottom) + start.linkTo(parent.start) + end.linkTo(parent.end) + } + .height(80.dp) + .width(604.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.Transparent, + contentColor = Color.Transparent, + ), + onClick = onNewTransactionClicked, + border = BorderStroke(1.dp, MaterialTheme.colors.onSurface), + shape = RoundedCornerShape(8.dp), + ) { + Icon( + modifier = Modifier.size(24.dp), + painter = painterResource(id = R.drawable.woo_pos_ic_return_home), + tint = MaterialTheme.colors.onSurface, + contentDescription = stringResource(id = R.string.woopos_new_order_button) + ) + Spacer(modifier = Modifier.width(12.dp.toAdaptivePadding())) + Text( + text = stringResource(R.string.woopos_new_order_button), + style = MaterialTheme.typography.h5, + fontWeight = FontWeight.SemiBold, + color = WooPosTheme.colors.paymentSuccessText, + textAlign = TextAlign.Center + ) + } + } } } @Composable -private fun CheckMarkIcon() { +private fun CheckMarkIcon( + animationStarted: Boolean, + modifier: Modifier = Modifier, +) { + val size by animateDpAsState( + targetValue = if (animationStarted) 156.dp else 0.dp, + label = "Check mark size" + ) + + var iconAnimationStarted by remember { mutableStateOf(false) } + val iconSize by animateDpAsState( + targetValue = if (iconAnimationStarted) 72.dp else 0.dp, + animationSpec = spring(dampingRatio = Spring.DampingRatioMediumBouncy), + label = "Icon Size" + ) + + LaunchedEffect(animationStarted) { + if (animationStarted) { + delay(300) + iconAnimationStarted = true + } + } + Box( contentAlignment = Alignment.Center, - modifier = Modifier - .size(156.dp) + modifier = modifier + .size(size) .shadow(8.dp, CircleShape) .background(MaterialTheme.colors.background, CircleShape) ) { @@ -121,7 +195,8 @@ private fun CheckMarkIcon() { imageVector = Icons.Default.Check, tint = WooPosTheme.colors.success, contentDescription = stringResource(id = R.string.woopos_payment_successful_label), - modifier = Modifier.size(72.dp) + modifier = Modifier + .size(iconSize) ) } } @@ -136,6 +211,8 @@ fun WooPosPaymentSuccessScreenPreview() { orderTotalText = "$13.18", orderTaxText = "$1.20" ), + bottomAnimationStarted = true, + iconAnimationStarted = true, onNewTransactionClicked = {} ) } From 535e122703e1fd7d0317e8066f6c71d4547d763f Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 6 Aug 2024 11:26:33 +0200 Subject: [PATCH 024/196] Supressed detekt complain about Destructuring --- .../totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt index cdd1075a6a6..e2aeb5e679f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt @@ -83,6 +83,7 @@ fun WooPosPaymentSuccessScreen( targetValue = if (bottomAnimationStarted) 80.dp else 16.dp, label = "Check mark size" ) + @Suppress("DestructuringDeclarationWithTooManyEntries") ConstraintLayout { val (icon, title, message, button) = createRefs() From 517a8860353a77057bc88bc78b1fdce010a94559 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 6 Aug 2024 11:36:31 +0200 Subject: [PATCH 025/196] Fixed typo in Retry --- WooCommerce/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index f4d3c4b9092..16ba52d1172 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -4237,7 +4237,7 @@ Error loading products Give it another go? Error indication icon - Rerty + Retry Couldn\'t create order A payment of %1$s was successfully made From 70a7915c7511b5ef7f2af7ab486df875f7fcf932 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 6 Aug 2024 12:15:36 +0200 Subject: [PATCH 026/196] Use in memory cache --- .../home/products/WooPosProductsDataSource.kt | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSource.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSource.kt index 82f8a49e9ef..b29b9790024 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSource.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSource.kt @@ -1,7 +1,6 @@ package com.woocommerce.android.ui.woopos.home.products import com.woocommerce.android.model.Product -import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.products.ProductType import com.woocommerce.android.ui.products.selector.ProductListHandler import com.woocommerce.android.util.WooLog @@ -17,37 +16,31 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class WooPosProductsDataSource @Inject constructor( - private val handler: ProductListHandler, - private val productStore: WCProductStore, - private val site: SelectedSite, -) { +class WooPosProductsDataSource @Inject constructor(private val handler: ProductListHandler) { + private val productCache = mutableListOf() + val hasMorePages: Boolean get() = handler.canLoadMore.get() fun loadSimpleProducts(forceRefreshProducts: Boolean): Flow = flow { if (forceRefreshProducts) { - productStore.deleteProductsForSite(site.get()) + productCache.clear() } + emit(ProductsResult.Cached(productCache)) + val result = handler.loadFromCacheAndFetch( searchType = ProductListHandler.SearchType.DEFAULT, filters = mapOf(WCProductStore.ProductFilterOption.TYPE to ProductType.SIMPLE.value) ) - emit( - ProductsResult.Cached( - handler.productsFlow.first().filter { product -> product.price != null } - ) - ) - if (result.isSuccess) { val remoteProducts = handler.productsFlow.first().filter { it.price != null } + productCache.clear() + productCache.addAll(remoteProducts) emit(ProductsResult.Remote(Result.success(remoteProducts))) } else { - val error = result.exceptionOrNull() - val errorMessage = error?.message ?: "Unknown error" - WooLog.e(WooLog.T.POS, "Loading simple products failed - $errorMessage", error) + result.logFailure() emit(ProductsResult.Remote(Result.failure(result.exceptionOrNull()!!))) } }.flowOn(Dispatchers.IO).take(2) @@ -55,15 +48,21 @@ class WooPosProductsDataSource @Inject constructor( suspend fun loadMore(): Result> = withContext(Dispatchers.IO) { val result = handler.loadMore() if (result.isSuccess) { - Result.success(handler.productsFlow.first().filter { it.price != null }) + val moreProducts = handler.productsFlow.first().filter { it.price != null } + productCache.addAll(moreProducts) + Result.success(moreProducts) } else { - val error = result.exceptionOrNull() - val errorMessage = error?.message ?: "Unknown error" - WooLog.e(WooLog.T.POS, "Loading more products failed - $errorMessage", error) - Result.failure(error!!) + result.logFailure() + Result.failure(result.exceptionOrNull()!!) } } + private fun Result.logFailure() { + val error = exceptionOrNull() + val errorMessage = error?.message ?: "Unknown error" + WooLog.e(WooLog.T.POS, "Loading products failed - $errorMessage", error) + } + sealed class ProductsResult { data class Cached(val products: List) : ProductsResult() data class Remote(val productsResult: Result>) : ProductsResult() From 237b1072fc2e1c07197dc14da090fd5fa7789573 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 6 Aug 2024 12:30:29 +0200 Subject: [PATCH 027/196] Removed redundant logging --- .../ui/woopos/home/products/WooPosProductsViewModel.kt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt index bfd0356f52e..3dc995a2db9 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt @@ -8,7 +8,6 @@ import com.woocommerce.android.ui.woopos.home.ChildToParentEvent import com.woocommerce.android.ui.woopos.home.WooPosChildrenToParentEventSender import com.woocommerce.android.ui.woopos.util.datastore.WooPosPreferencesRepository import com.woocommerce.android.ui.woopos.util.format.WooPosFormatPrice -import com.woocommerce.android.util.WooLog import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow @@ -134,12 +133,7 @@ class WooPosProductsViewModel @Inject constructor( } } - else -> { - val error = result.productsResult.exceptionOrNull() - val errorMessage = error?.message ?: "Unknown error" - WooLog.e(WooLog.T.POS, "Loading simple products failed - $errorMessage", error) - WooPosProductsViewState.Error() - } + else -> WooPosProductsViewState.Error() } } } From a08fdcb952d649005c32443a86d80a6b76be9079 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 6 Aug 2024 12:53:10 +0200 Subject: [PATCH 028/196] Fixed tests --- .../products/WooPosProductsDataSourceTest.kt | 74 ++++++++++--------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSourceTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSourceTest.kt index 4852346a1f8..21cb00f7772 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSourceTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSourceTest.kt @@ -1,7 +1,6 @@ package com.woocommerce.android.ui.woopos.home.products import com.woocommerce.android.model.Product -import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.products.selector.ProductListHandler import com.woocommerce.android.ui.woopos.util.WooPosCoroutineTestRule import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -12,12 +11,8 @@ import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat import org.junit.Rule import org.mockito.kotlin.any -import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.mock -import org.mockito.kotlin.verify import org.mockito.kotlin.whenever -import org.wordpress.android.fluxc.model.SiteModel -import org.wordpress.android.fluxc.store.WCProductStore import java.math.BigDecimal import java.util.concurrent.atomic.AtomicBoolean import kotlin.test.Test @@ -35,34 +30,36 @@ class WooPosProductsDataSourceTest { ) private val handler: ProductListHandler = mock() - private val productStore: WCProductStore = mock() - private val site: SelectedSite = mock { - on { getOrNull() }.thenReturn(SiteModel()) - } @Test - fun `given force refresh, when loadSimpleProducts called, then should wipe products table`() = runTest { + fun `given force refresh, when loadSimpleProducts called, then should clear cache`() = runTest { // GIVEN whenever(handler.canLoadMore).thenReturn(AtomicBoolean(true)) - whenever(site.getOrNull()).thenReturn(SiteModel()) whenever(handler.productsFlow).thenReturn(flowOf(sampleProducts)) - val sut = WooPosProductsDataSource(handler, productStore, site) + val sut = WooPosProductsDataSource(handler) + + // Pre-populate the cache + sut.loadSimpleProducts(forceRefreshProducts = false).first() + assertThat(sut.loadSimpleProducts(forceRefreshProducts = false).first()).isInstanceOf(WooPosProductsDataSource.ProductsResult.Cached::class.java) // WHEN sut.loadSimpleProducts(forceRefreshProducts = true).first() // THEN - verify(productStore).deleteProductsForSite(anyOrNull()) + // Ensure the cache is cleared (by checking that the cache was reloaded) + val result = sut.loadSimpleProducts(forceRefreshProducts = false).first() + assertThat(result).isInstanceOf(WooPosProductsDataSource.ProductsResult.Cached::class.java) + val cachedResult = result as WooPosProductsDataSource.ProductsResult.Cached + assertThat(cachedResult.products).containsExactlyElementsOf(sampleProducts) } @Test fun `given cached products, when loadSimpleProducts called, then should emit cached products first`() = runTest { // GIVEN whenever(handler.canLoadMore).thenReturn(AtomicBoolean(true)) - whenever(site.getOrNull()).thenReturn(SiteModel()) whenever(handler.productsFlow).thenReturn(flowOf(sampleProducts)) whenever(handler.loadFromCacheAndFetch(any(), any(), any())).thenReturn(Result.success(Unit)) - val sut = WooPosProductsDataSource(handler, productStore, site) + val sut = WooPosProductsDataSource(handler) // WHEN val result = sut.loadSimpleProducts(forceRefreshProducts = false).first() @@ -74,34 +71,39 @@ class WooPosProductsDataSourceTest { } @Test - fun `given cached and remote products, when loadSimpleProducts called, then should emit remote products after cached products`() = - runTest { - // GIVEN - whenever(handler.canLoadMore).thenReturn(AtomicBoolean(true)) - whenever(handler.productsFlow).thenReturn(flowOf(sampleProducts)) - whenever(handler.loadFromCacheAndFetch(any(), any(), any())).thenReturn(Result.success(Unit)) - val sut = WooPosProductsDataSource(handler, productStore, site) - - // WHEN - val flow = sut.loadSimpleProducts(forceRefreshProducts = false).toList() - - // THEN - val cachedResult = flow[0] as WooPosProductsDataSource.ProductsResult.Cached - val remoteResult = flow[1] as WooPosProductsDataSource.ProductsResult.Remote - - assertThat(cachedResult.products).containsExactlyElementsOf(sampleProducts) - assertThat(remoteResult.productsResult.isSuccess).isTrue() - assertThat(remoteResult.productsResult.getOrNull()).containsExactlyElementsOf(sampleProducts) - } + fun `given cached and remote products, when loadSimpleProducts called, then should emit remote products after cached products`() = runTest { + // GIVEN + whenever(handler.canLoadMore).thenReturn(AtomicBoolean(true)) + whenever(handler.productsFlow).thenReturn(flowOf(sampleProducts)) + whenever(handler.loadFromCacheAndFetch(any(), any(), any())).thenReturn(Result.success(Unit)) + val sut = WooPosProductsDataSource(handler) + + // WHEN + val flow = sut.loadSimpleProducts(forceRefreshProducts = false).toList() + + // THEN + val cachedResult = flow[0] as WooPosProductsDataSource.ProductsResult.Cached + val remoteResult = flow[1] as WooPosProductsDataSource.ProductsResult.Remote + + assertThat(cachedResult.products).containsExactlyElementsOf(sampleProducts) + assertThat(remoteResult.productsResult.isSuccess).isTrue() + assertThat(remoteResult.productsResult.getOrNull()).containsExactlyElementsOf(sampleProducts) + } @Test - fun `given remote load fails, when loadSimpleProducts called, then should emit error`() = runTest { + fun `given remote load fails, when loadSimpleProducts called, then should emit cached products and then error`() = runTest { // GIVEN whenever(handler.canLoadMore).thenReturn(AtomicBoolean(true)) whenever(handler.productsFlow).thenReturn(flowOf(sampleProducts)) val exception = Exception("Remote load failed") + whenever(handler.loadFromCacheAndFetch(any(), any(), any())).thenReturn(Result.success(Unit)) + + val sut = WooPosProductsDataSource(handler) + + // Prepopulate the cache by calling loadSimpleProducts once + sut.loadSimpleProducts(forceRefreshProducts = false).first() + whenever(handler.loadFromCacheAndFetch(any(), any(), any())).thenReturn(Result.failure(exception)) - val sut = WooPosProductsDataSource(handler, productStore, site) // WHEN val flow = sut.loadSimpleProducts(forceRefreshProducts = false).toList() From 40c10a5ffa63dbfcbb82ee1f1153073578e13611 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 6 Aug 2024 12:54:09 +0200 Subject: [PATCH 029/196] Tests on loadMore functionality --- .../products/WooPosProductsDataSourceTest.kt | 135 +++++++++++++----- 1 file changed, 98 insertions(+), 37 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSourceTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSourceTest.kt index 21cb00f7772..76a9627d1f3 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSourceTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSourceTest.kt @@ -29,6 +29,11 @@ class WooPosProductsDataSourceTest { mock { on { price }.thenReturn(BigDecimal(3)) }, ) + private val additionalProducts = listOf( + mock { on { price }.thenReturn(BigDecimal(4)) }, + mock { on { price }.thenReturn(BigDecimal(5)) } + ) + private val handler: ProductListHandler = mock() @Test @@ -40,7 +45,9 @@ class WooPosProductsDataSourceTest { // Pre-populate the cache sut.loadSimpleProducts(forceRefreshProducts = false).first() - assertThat(sut.loadSimpleProducts(forceRefreshProducts = false).first()).isInstanceOf(WooPosProductsDataSource.ProductsResult.Cached::class.java) + assertThat( + sut.loadSimpleProducts(forceRefreshProducts = false).first() + ).isInstanceOf(WooPosProductsDataSource.ProductsResult.Cached::class.java) // WHEN sut.loadSimpleProducts(forceRefreshProducts = true).first() @@ -71,49 +78,103 @@ class WooPosProductsDataSourceTest { } @Test - fun `given cached and remote products, when loadSimpleProducts called, then should emit remote products after cached products`() = runTest { - // GIVEN - whenever(handler.canLoadMore).thenReturn(AtomicBoolean(true)) - whenever(handler.productsFlow).thenReturn(flowOf(sampleProducts)) - whenever(handler.loadFromCacheAndFetch(any(), any(), any())).thenReturn(Result.success(Unit)) - val sut = WooPosProductsDataSource(handler) + fun `given cached and remote products, when loadSimpleProducts called, then should emit remote products after cached products`() = + runTest { + // GIVEN + whenever(handler.canLoadMore).thenReturn(AtomicBoolean(true)) + whenever(handler.productsFlow).thenReturn(flowOf(sampleProducts)) + whenever(handler.loadFromCacheAndFetch(any(), any(), any())).thenReturn(Result.success(Unit)) + val sut = WooPosProductsDataSource(handler) + + // WHEN + val flow = sut.loadSimpleProducts(forceRefreshProducts = false).toList() + + // THEN + val cachedResult = flow[0] as WooPosProductsDataSource.ProductsResult.Cached + val remoteResult = flow[1] as WooPosProductsDataSource.ProductsResult.Remote + + assertThat(cachedResult.products).containsExactlyElementsOf(sampleProducts) + assertThat(remoteResult.productsResult.isSuccess).isTrue() + assertThat(remoteResult.productsResult.getOrNull()).containsExactlyElementsOf(sampleProducts) + } - // WHEN - val flow = sut.loadSimpleProducts(forceRefreshProducts = false).toList() - - // THEN - val cachedResult = flow[0] as WooPosProductsDataSource.ProductsResult.Cached - val remoteResult = flow[1] as WooPosProductsDataSource.ProductsResult.Remote + @Test + fun `given remote load fails, when loadSimpleProducts called, then should emit cached products and then error`() = + runTest { + // GIVEN + whenever(handler.canLoadMore).thenReturn(AtomicBoolean(true)) + whenever(handler.productsFlow).thenReturn(flowOf(sampleProducts)) + val exception = Exception("Remote load failed") + whenever(handler.loadFromCacheAndFetch(any(), any(), any())).thenReturn(Result.success(Unit)) - assertThat(cachedResult.products).containsExactlyElementsOf(sampleProducts) - assertThat(remoteResult.productsResult.isSuccess).isTrue() - assertThat(remoteResult.productsResult.getOrNull()).containsExactlyElementsOf(sampleProducts) - } + val sut = WooPosProductsDataSource(handler) - @Test - fun `given remote load fails, when loadSimpleProducts called, then should emit cached products and then error`() = runTest { - // GIVEN - whenever(handler.canLoadMore).thenReturn(AtomicBoolean(true)) - whenever(handler.productsFlow).thenReturn(flowOf(sampleProducts)) - val exception = Exception("Remote load failed") - whenever(handler.loadFromCacheAndFetch(any(), any(), any())).thenReturn(Result.success(Unit)) + // Prepopulate the cache by calling loadSimpleProducts once + sut.loadSimpleProducts(forceRefreshProducts = false).first() - val sut = WooPosProductsDataSource(handler) + whenever(handler.loadFromCacheAndFetch(any(), any(), any())).thenReturn(Result.failure(exception)) - // Prepopulate the cache by calling loadSimpleProducts once - sut.loadSimpleProducts(forceRefreshProducts = false).first() + // WHEN + val flow = sut.loadSimpleProducts(forceRefreshProducts = false).toList() - whenever(handler.loadFromCacheAndFetch(any(), any(), any())).thenReturn(Result.failure(exception)) + // THEN + val cachedResult = flow[0] as WooPosProductsDataSource.ProductsResult.Cached + val remoteResult = flow[1] as WooPosProductsDataSource.ProductsResult.Remote - // WHEN - val flow = sut.loadSimpleProducts(forceRefreshProducts = false).toList() + assertThat(cachedResult.products).containsExactlyElementsOf(sampleProducts) + assertThat(remoteResult.productsResult.isFailure).isTrue() + assertThat(remoteResult.productsResult.exceptionOrNull()).isEqualTo(exception) + } - // THEN - val cachedResult = flow[0] as WooPosProductsDataSource.ProductsResult.Cached - val remoteResult = flow[1] as WooPosProductsDataSource.ProductsResult.Remote + @Test + fun `given successful loadMore, when loadMore called, then should add products to cache and return them`() = + runTest { + // GIVEN + whenever(handler.canLoadMore).thenReturn(AtomicBoolean(true)) + whenever(handler.productsFlow).thenReturn( + flowOf(sampleProducts), + flowOf(sampleProducts + additionalProducts) + ) + whenever(handler.loadMore()).thenReturn(Result.success(Unit)) + val sut = WooPosProductsDataSource(handler) + + sut.loadSimpleProducts(forceRefreshProducts = false).first() + + // WHEN + val result = sut.loadMore() + + // THEN + assertThat(result.isSuccess).isTrue() + assertThat(result.getOrNull()).containsExactlyElementsOf(sampleProducts + additionalProducts) + + val cachedResult = sut.loadSimpleProducts(forceRefreshProducts = false).first() + assertThat(cachedResult).isInstanceOf(WooPosProductsDataSource.ProductsResult.Cached::class.java) + val cachedProducts = (cachedResult as WooPosProductsDataSource.ProductsResult.Cached).products + assertThat(cachedProducts).containsExactlyElementsOf(sampleProducts + additionalProducts) + } - assertThat(cachedResult.products).containsExactlyElementsOf(sampleProducts) - assertThat(remoteResult.productsResult.isFailure).isTrue() - assertThat(remoteResult.productsResult.exceptionOrNull()).isEqualTo(exception) - } + @Test + fun `given failed loadMore, when loadMore called, then should return error and cache remains unchanged`() = + runTest { + // GIVEN + whenever(handler.canLoadMore).thenReturn(AtomicBoolean(true)) + whenever(handler.productsFlow).thenReturn(flowOf(sampleProducts)) + val exception = Exception("Load more failed") + whenever(handler.loadMore()).thenReturn(Result.failure(exception)) + val sut = WooPosProductsDataSource(handler) + + sut.loadSimpleProducts(forceRefreshProducts = false).first() + + // WHEN + val result = sut.loadMore() + + // THEN + assertThat(result.isFailure).isTrue() + assertThat(result.exceptionOrNull()).isEqualTo(exception) + + val cachedResult = sut.loadSimpleProducts(forceRefreshProducts = false).first() + assertThat(cachedResult).isInstanceOf(WooPosProductsDataSource.ProductsResult.Cached::class.java) + val cachedProducts = (cachedResult as WooPosProductsDataSource.ProductsResult.Cached).products + assertThat(cachedProducts).containsExactlyElementsOf(sampleProducts) + } } From 75872e6a24c6d23936f2b300cd28c65890516067 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 6 Aug 2024 13:28:20 +0200 Subject: [PATCH 030/196] Fixed potential NPE --- .../woopos/home/products/WooPosProductsDataSource.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSource.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSource.kt index b29b9790024..d8708222a49 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSource.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsDataSource.kt @@ -41,7 +41,13 @@ class WooPosProductsDataSource @Inject constructor(private val handler: ProductL emit(ProductsResult.Remote(Result.success(remoteProducts))) } else { result.logFailure() - emit(ProductsResult.Remote(Result.failure(result.exceptionOrNull()!!))) + emit( + ProductsResult.Remote( + Result.failure( + result.exceptionOrNull() ?: Exception("Unknown error") + ) + ) + ) } }.flowOn(Dispatchers.IO).take(2) @@ -53,7 +59,7 @@ class WooPosProductsDataSource @Inject constructor(private val handler: ProductL Result.success(moreProducts) } else { result.logFailure() - Result.failure(result.exceptionOrNull()!!) + Result.failure(result.exceptionOrNull() ?: Exception("Unknown error")) } } From ffd17b6ee3f79c66b0e7d2351ea8e8bd014cfced Mon Sep 17 00:00:00 2001 From: samiuelson Date: Tue, 6 Aug 2024 16:15:01 +0200 Subject: [PATCH 031/196] Improve the code style --- .../android/ui/woopos/home/WooPosHomeViewModel.kt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt index 6eefec8401b..783eb1cbef5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt @@ -133,18 +133,23 @@ class WooPosHomeViewModel @Inject constructor( } private fun handleProductsStatusChanged(event: ChildToParentEvent.ProductsStatusChanged) { - if (state.value.screenPositionState is WooPosHomeState.ScreenPositionState.Checkout) return + val screenPosition = _state.value.screenPositionState val newScreenPositionState = when (event) { - ChildToParentEvent.ProductsStatusChanged.FullScreen -> WooPosHomeState.ScreenPositionState.Cart.Hidden + ChildToParentEvent.ProductsStatusChanged.FullScreen -> { + when (screenPosition) { + is WooPosHomeState.ScreenPositionState.Cart -> WooPosHomeState.ScreenPositionState.Cart.Hidden + is WooPosHomeState.ScreenPositionState.Checkout -> screenPosition + } + } ChildToParentEvent.ProductsStatusChanged.WithCart -> { - when (val value = _state.value.screenPositionState) { + when (screenPosition) { WooPosHomeState.ScreenPositionState.Cart.Hidden -> WooPosHomeState.ScreenPositionState.Cart.Visible.Empty WooPosHomeState.ScreenPositionState.Cart.Visible.Empty, WooPosHomeState.ScreenPositionState.Cart.Visible.NotEmpty, WooPosHomeState.ScreenPositionState.Checkout.NotPaid, - WooPosHomeState.ScreenPositionState.Checkout.Paid -> value + WooPosHomeState.ScreenPositionState.Checkout.Paid -> screenPosition } } } From 44b8c7934cf1b962f0c652726af55a99d41fb9ed Mon Sep 17 00:00:00 2001 From: samiuelson Date: Tue, 6 Aug 2024 16:15:36 +0200 Subject: [PATCH 032/196] Add test for activity death scenario --- .../ui/woopos/home/WooPosHomeViewModelTest.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModelTest.kt index 539d472ffc7..e9f64753480 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModelTest.kt @@ -230,6 +230,19 @@ class WooPosHomeViewModelTest { assertFalse((viewModel.state.value.productsInfoDialog is WooPosHomeState.ProductsInfoDialog.Visible)) } + @Test + fun `given home screen is at checkout, when products are updated, then should not modify screen position`() { + whenever(childrenToParentEventReceiver.events).thenReturn( + flowOf( + ChildToParentEvent.CheckoutClicked(listOf(1)), + ChildToParentEvent.ProductsStatusChanged.FullScreen + ) + ) + val viewModel = createViewModel() + + assertTrue(viewModel.state.value.screenPositionState is WooPosHomeState.ScreenPositionState.Checkout) + } + private fun createViewModel() = WooPosHomeViewModel( childrenToParentEventReceiver, parentToChildrenEventSender, From 38e25e742faa89519039fe8ba8cd5bf27f66d41e Mon Sep 17 00:00:00 2001 From: malinajirka Date: Tue, 6 Aug 2024 18:15:41 +0200 Subject: [PATCH 033/196] Update android-lifecycle from 2.6.2 to 2.7.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8bbfbd37a7d..e3385fb35db 100644 --- a/build.gradle +++ b/build.gradle @@ -108,7 +108,7 @@ ext { googlePlayCoreVersion = '1.10.3' googlePlayWearableVersion = '18.1.0' coroutinesVersion = '1.8.1' - lifecycleVersion = '2.6.2' + lifecycleVersion = '2.7.0' aztecVersion = 'v1.3.45' flipperVersion = '0.176.1' stateMachineVersion = '0.2.0' From 325953f4be723e40794f4b4b241be269e079430a Mon Sep 17 00:00:00 2001 From: malinajirka Date: Tue, 6 Aug 2024 18:23:56 +0200 Subject: [PATCH 034/196] Update release notes --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index d367b2ae48f..c78a892270a 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -5,6 +5,7 @@ ----- - [*] [Internal] Update Android material from 1.9.0 to 1.10.0 [https://github.com/woocommerce/woocommerce-android/pull/12186] - [*] [Internal] Update Android-core from 1.12.0 to 1.13.1 [https://github.com/woocommerce/woocommerce-android/pull/12229] +- [*] [Internal] Update Android-lifecycle from 2.6.2 to 2.7.0 [https://github.com/woocommerce/woocommerce-android/pull/12230] 19.8 ----- From 1406f7f6bc42520366a5991ae8b78fa5a61b6cc4 Mon Sep 17 00:00:00 2001 From: malinajirka Date: Tue, 6 Aug 2024 18:50:42 +0200 Subject: [PATCH 035/196] Update androidx-fragment from 1.6.2 to 1.8.2 --- WooCommerce/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index b022c27933f..e44b5628a90 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -400,7 +400,7 @@ dependencies { } // ViewModel and LiveData - implementation "androidx.fragment:fragment-ktx:1.6.1" + 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-livedata-ktx:$lifecycleVersion" From 931181a655ffdc086a5bef17a7903878c4941dda Mon Sep 17 00:00:00 2001 From: malinajirka Date: Tue, 6 Aug 2024 18:55:42 +0200 Subject: [PATCH 036/196] Update release notes --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index c78a892270a..44fcbc0eea4 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -6,6 +6,7 @@ - [*] [Internal] Update Android material from 1.9.0 to 1.10.0 [https://github.com/woocommerce/woocommerce-android/pull/12186] - [*] [Internal] Update Android-core from 1.12.0 to 1.13.1 [https://github.com/woocommerce/woocommerce-android/pull/12229] - [*] [Internal] Update Android-lifecycle from 2.6.2 to 2.7.0 [https://github.com/woocommerce/woocommerce-android/pull/12230] +- [*] [Internal] Update Androidx-fragment from 1.6.2 to 1.8.2 [https://github.com/woocommerce/woocommerce-android/pull/12231] 19.8 ----- From 81d9beaf4c6b740e025d6c453c52a5b3efa8f9cb Mon Sep 17 00:00:00 2001 From: samiuelson Date: Tue, 6 Aug 2024 19:19:27 +0200 Subject: [PATCH 037/196] Return to POS right after payment success --- .../payment/CardReaderPaymentViewModel.kt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt index b0ca3b3662b..2df6fc8f136 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt @@ -464,9 +464,17 @@ class CardReaderPaymentViewModel ) { paymentReceiptHelper.storeReceiptUrl(orderId, paymentStatus.receiptUrl) appPrefs.setCardReaderSuccessfulPaymentTime() - triggerEvent(PlayChaChing) - showPaymentSuccessfulState() - reFetchOrder() + val flowParam: CardReaderFlowParam.PaymentOrRefund = arguments.paymentOrRefund + if (flowParam is CardReaderFlowParam.PaymentOrRefund.Payment && + flowParam.paymentType == CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.WOO_POS + ) { + reFetchOrder() + onCancelPaymentFlow() + } else { + triggerEvent(PlayChaChing) + showPaymentSuccessfulState() + reFetchOrder() + } } @VisibleForTesting From df46510f690ae136b548cb5ae895c2582f5a1298 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 6 Aug 2024 18:06:35 -0300 Subject: [PATCH 038/196] Introduce CrashLoggings initial structure in the commons lib --- libs/commons/build.gradle | 4 ++++ .../commons/crashlogging/WCCrashLoggingDataProvider.kt | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 libs/commons/src/main/java/com/woocommerce/commons/crashlogging/WCCrashLoggingDataProvider.kt diff --git a/libs/commons/build.gradle b/libs/commons/build.gradle index b52e2241fd6..769205c0b31 100644 --- a/libs/commons/build.gradle +++ b/libs/commons/build.gradle @@ -20,3 +20,7 @@ android { jvmTarget = '1.8' } } + +dependencies { + implementation "com.automattic.tracks:crashlogging:$automatticTracksVersion" +} diff --git a/libs/commons/src/main/java/com/woocommerce/commons/crashlogging/WCCrashLoggingDataProvider.kt b/libs/commons/src/main/java/com/woocommerce/commons/crashlogging/WCCrashLoggingDataProvider.kt new file mode 100644 index 00000000000..4f217bccb2b --- /dev/null +++ b/libs/commons/src/main/java/com/woocommerce/commons/crashlogging/WCCrashLoggingDataProvider.kt @@ -0,0 +1,4 @@ +package com.woocommerce.commons.crashlogging + +class WCCrashLoggingDataProvider { +} From 0b7916c529f049694d1345bbbf40927b9c181dc3 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 6 Aug 2024 18:24:33 -0300 Subject: [PATCH 039/196] Fix missing repositories for Automattic tracks --- libs/commons/build.gradle | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libs/commons/build.gradle b/libs/commons/build.gradle index 769205c0b31..41ff440fc1f 100644 --- a/libs/commons/build.gradle +++ b/libs/commons/build.gradle @@ -3,6 +3,16 @@ plugins { id 'org.jetbrains.kotlin.android' } +repositories { + maven { + url 'https://a8c-libs.s3.amazonaws.com/android' + content { + includeGroup "com.automattic" + includeGroup "com.automattic.tracks" + } + } +} + android { namespace 'com.woocommerce.commons' compileSdk gradle.ext.compileSdkVersion @@ -22,5 +32,7 @@ android { } dependencies { + implementation "com.automattic:Automattic-Tracks-Android:$automatticTracksVersion" implementation "com.automattic.tracks:crashlogging:$automatticTracksVersion" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" } From 688b0442f73cfcd0ef3dcb42ab4f26f1870862ac Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 6 Aug 2024 18:24:42 -0300 Subject: [PATCH 040/196] Introduce WCCrashLoggingDataProvider scaffold --- .../WCCrashLoggingDataProvider.kt | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/libs/commons/src/main/java/com/woocommerce/commons/crashlogging/WCCrashLoggingDataProvider.kt b/libs/commons/src/main/java/com/woocommerce/commons/crashlogging/WCCrashLoggingDataProvider.kt index 4f217bccb2b..0d332d51907 100644 --- a/libs/commons/src/main/java/com/woocommerce/commons/crashlogging/WCCrashLoggingDataProvider.kt +++ b/libs/commons/src/main/java/com/woocommerce/commons/crashlogging/WCCrashLoggingDataProvider.kt @@ -1,4 +1,48 @@ package com.woocommerce.commons.crashlogging -class WCCrashLoggingDataProvider { +import com.automattic.android.tracks.crashlogging.CrashLoggingDataProvider +import com.automattic.android.tracks.crashlogging.CrashLoggingUser +import com.automattic.android.tracks.crashlogging.EventLevel +import com.automattic.android.tracks.crashlogging.ExtraKnownKey +import com.automattic.android.tracks.crashlogging.PerformanceMonitoringConfig +import com.automattic.android.tracks.crashlogging.ReleaseName +import java.util.Locale +import kotlinx.coroutines.flow.Flow + +class WCCrashLoggingDataProvider: CrashLoggingDataProvider { + override val applicationContextProvider: Flow> + get() = TODO("Not yet implemented") + override val buildType: String + get() = TODO("Not yet implemented") + override val enableCrashLoggingLogs: Boolean + get() = TODO("Not yet implemented") + override val locale: Locale? + get() = TODO("Not yet implemented") + override val performanceMonitoringConfig: PerformanceMonitoringConfig + get() = TODO("Not yet implemented") + override val releaseName: ReleaseName + get() = TODO("Not yet implemented") + override val sentryDSN: String + get() = TODO("Not yet implemented") + override val user: Flow + get() = TODO("Not yet implemented") + + override fun crashLoggingEnabled(): Boolean { + TODO("Not yet implemented") + } + + override fun extraKnownKeys(): List { + TODO("Not yet implemented") + } + + override fun provideExtrasForEvent( + currentExtras: Map, + eventLevel: EventLevel + ): Map { + TODO("Not yet implemented") + } + + override fun shouldDropWrappingException(module: String, type: String, value: String): Boolean { + TODO("Not yet implemented") + } } From 11b4dc37fbadc04518263347137f04881655422a Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Wed, 7 Aug 2024 00:24:53 +0300 Subject: [PATCH 041/196] Add subtotal and taxes lines to refund product list item --- .../res/layout/refunds_product_list_item.xml | 63 +++++++++++++++---- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/WooCommerce/src/main/res/layout/refunds_product_list_item.xml b/WooCommerce/src/main/res/layout/refunds_product_list_item.xml index 02d3c534125..eb856bff857 100644 --- a/WooCommerce/src/main/res/layout/refunds_product_list_item.xml +++ b/WooCommerce/src/main/res/layout/refunds_product_list_item.xml @@ -4,7 +4,8 @@ xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:paddingBottom="@dimen/major_75"> + app:layout_constraintBottom_toBottomOf="@id/refundItem_description" + app:layout_constraintTop_toTopOf="@id/refundItem_productName"> @@ -46,11 +46,9 @@ style="@style/Woo.ListItem.Body" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/major_75" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toStartOf="@+id/refundItem_quantity" - app:layout_constraintStart_toEndOf="@+id/refundItem_iconFrame" - app:layout_constraintTop_toBottomOf="@+id/refundItem_productName" + app:layout_constraintEnd_toStartOf="@id/refundItem_quantity" + app:layout_constraintStart_toEndOf="@id/refundItem_iconFrame" + app:layout_constraintTop_toBottomOf="@id/refundItem_productName" tools:text="2 x $15.00 each" /> + + + + + + + From c935557ed7c59b0c3bc5444c34eb86219111e553 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 6 Aug 2024 18:27:21 -0300 Subject: [PATCH 042/196] Add Sentry initial configuration in commons build.gradle --- libs/commons/build.gradle | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/libs/commons/build.gradle b/libs/commons/build.gradle index 41ff440fc1f..a0247629eeb 100644 --- a/libs/commons/build.gradle +++ b/libs/commons/build.gradle @@ -1,6 +1,9 @@ +import io.sentry.android.gradle.extensions.InstrumentationFeature + plugins { id 'com.android.library' id 'org.jetbrains.kotlin.android' + id 'io.sentry.android.gradle' } repositories { @@ -13,6 +16,34 @@ repositories { } } +sentry { + includeSourceContext = true + autoUploadSourceContext = true + tracingInstrumentation { + enabled = true + features = [InstrumentationFeature.DATABASE] + logcat { + enabled = false + } + } + autoInstallation { + enabled = false + } + includeDependenciesReport = false + /* Sentry won't send source context or add performance instrumentations for debug builds + so we can save build times. Sending events will still work in debug builds + (if enabled in WCCrashLoggingDataProvider). + */ + ignoredBuildTypes = ["debug"] + + /* Additional source directories to be included in the source context. For now, manually: + https://github.com/getsentry/sentry-android-gradle-plugin/issues/685 + */ + additionalSourceDirsForSourceContext = [ + '../libs/cardreader/src/main/java', + ] +} + android { namespace 'com.woocommerce.commons' compileSdk gradle.ext.compileSdkVersion From 8a1392e06cff7aa73e35ccdbfb7ddbd6307bff4a Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Wed, 7 Aug 2024 00:41:37 +0300 Subject: [PATCH 043/196] Hide common subtotal and taxes lines for products from refund screen --- .../payments/refunds/RefundByItemsFragment.kt | 8 ++---- .../res/layout/refund_by_items_products.xml | 25 +++++++++++-------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/RefundByItemsFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/RefundByItemsFragment.kt index 72d62a64a63..9aeecc037a1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/RefundByItemsFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/RefundByItemsFragment.kt @@ -151,12 +151,6 @@ class RefundByItemsFragment : new.feesTaxes?.takeIfNotEqualTo(old?.feesTaxes) { feeLinesBinding.issueRefundFeesTax.text = it } - new.taxes?.takeIfNotEqualTo(old?.taxes) { - productsBinding.issueRefundTaxesTotal.text = it - } - new.subtotal?.takeIfNotEqualTo(old?.subtotal) { - productsBinding.issueRefundSubtotal.text = it - } new.selectedItemsHeader?.takeIfNotEqualTo(old?.selectedItemsHeader) { binding.issueRefundSelectedItems.text = it } @@ -202,8 +196,10 @@ class RefundByItemsFragment : new.isRefundNoticeVisible.takeIfNotEqualTo(old?.isRefundNoticeVisible) { isVisible -> if (isVisible) { productsBinding.issueRefundRefundNotice.show() + productsBinding.issueRefundDividerBelowList.show() } else { productsBinding.issueRefundRefundNotice.hide() + productsBinding.issueRefundDividerBelowList.hide() } } new.refundNotice.takeIfNotEqualTo(old?.refundNotice) { notice -> diff --git a/WooCommerce/src/main/res/layout/refund_by_items_products.xml b/WooCommerce/src/main/res/layout/refund_by_items_products.xml index 13cc361410c..0c69fbe9f7a 100644 --- a/WooCommerce/src/main/res/layout/refund_by_items_products.xml +++ b/WooCommerce/src/main/res/layout/refund_by_items_products.xml @@ -24,7 +24,7 @@ android:layout_marginEnd="@dimen/minor_00" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/issueRefund_products" - app:layout_constraintBottom_toTopOf="@+id/issueRefund_lblSubtotal"/> + app:layout_constraintBottom_toTopOf="@id/issueRefund_lblSubtotal"/> @@ -72,15 +72,12 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="@dimen/major_100" - android:layout_marginStart="@dimen/minor_00" - android:layout_marginEnd="@dimen/minor_00" android:drawableStart="@drawable/ic_deprecated_info_outline_24dp" android:drawablePadding="@dimen/major_100" - tools:text="@string/order_refunds_shipping_refund_variable_notice" - android:visibility="visible" - app:layout_constraintEnd_toEndOf="@+id/issueRefund_taxesTotal" - app:layout_constraintStart_toStartOf="@+id/issueRefund_lblTaxes" - app:layout_constraintTop_toBottomOf="@id/issueRefund_taxesTotal" /> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/issueRefund_taxesTotal" + tools:text="@string/order_refunds_shipping_refund_variable_notice" /> @@ -102,7 +99,7 @@ android:layout_marginBottom="@dimen/major_75" android:text="@string/order_refunds_products_refund" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toStartOf="@+id/issueRefund_productsTotal" + app:layout_constraintEnd_toStartOf="@id/issueRefund_productsTotal" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/issueRefund_dividerBelowTaxes" /> @@ -124,4 +121,10 @@ android:layout_height="wrap_content" app:constraint_referenced_ids="issueRefund_refundNotice,issueRefund_dividerBelowList,issueRefund_dividerBelowTaxes,issueRefund_taxesTotal,issueRefund_subtotal,issueRefund_productsTotal,issueRefund_lblProductsTotal,issueRefund_lblTaxes,issueRefund_lblSubtotal" /> + From 1294f0fea98cbab9aefacfdfa90a33b1d06f3f71 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Wed, 7 Aug 2024 00:42:58 +0300 Subject: [PATCH 044/196] Add ProductRefundListItem.calculateTotal() and use in calculateTotals --- .../android/extensions/RefundsExt.kt | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/RefundsExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/RefundsExt.kt index b0365501d22..66d4696947d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/RefundsExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/RefundsExt.kt @@ -8,15 +8,18 @@ fun List.calculateTotals(): Pair var taxes = BigDecimal.ZERO var subtotal = BigDecimal.ZERO this.forEach { item -> - val quantity = item.quantity.toBigDecimal() - subtotal += quantity.times(item.orderItem.price) - - val singleItemTax = item.orderItem.totalTax.divide( - item.orderItem.quantity.toBigDecimal(), - 2, - HALF_UP - ) - taxes += quantity.times(singleItemTax) + val (itemSubtotal, itemTaxes) = item.calculateTotal() + subtotal += itemSubtotal + taxes += itemTaxes } return Pair(subtotal, taxes) } + +fun ProductRefundListItem.calculateTotal(): Pair { + val quantity = quantity.toBigDecimal() + val subtotal = quantity.times(orderItem.price) + + val singleItemTax = orderItem.totalTax.divide(orderItem.quantity.toBigDecimal(), 2, HALF_UP) + val taxes = quantity.times(singleItemTax) + return Pair(subtotal, taxes) +} From 8684ac01f5f927fa3ec0456d845867aea324cb1e Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Wed, 7 Aug 2024 00:47:11 +0300 Subject: [PATCH 045/196] Fill subtotal, taxes fields in the refund list item --- .../payments/refunds/IssueRefundViewModel.kt | 23 +++++++++++++------ .../refunds/RefundProductListAdapter.kt | 10 +++++++- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/IssueRefundViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/IssueRefundViewModel.kt index 352a93535bd..3ead2becf0d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/IssueRefundViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/IssueRefundViewModel.kt @@ -18,6 +18,7 @@ import com.woocommerce.android.analytics.AnalyticsEvent.REFUND_CREATE_SUCCESS import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.extensions.adminUrlOrDefault +import com.woocommerce.android.extensions.calculateTotal import com.woocommerce.android.extensions.calculateTotals import com.woocommerce.android.extensions.isCashPayment import com.woocommerce.android.extensions.isEqualTo @@ -285,7 +286,13 @@ class IssueRefundViewModel @Inject constructor( val items = order.items.map { val maxQuantity = maxQuantities[it.itemId] ?: 0f val selectedQuantity = min(selectedQuantities[it.itemId] ?: 0, maxQuantity.toInt()) - ProductRefundListItem(it, maxQuantity, selectedQuantity) + ProductRefundListItem( + it, + maxQuantity, + selectedQuantity, + formatCurrency(BigDecimal.ZERO), + formatCurrency(BigDecimal.ZERO) + ) } updateRefundItems(items) @@ -649,12 +656,14 @@ class IssueRefundViewModel @Inject constructor( val newItems = mutableListOf() _refundItems.value?.forEach { if (it.orderItem.itemId == uniqueId) { - newItems.add( - it.copy( - quantity = newQuantity, - maxQuantity = maxQuantities[uniqueId] ?: 0f - ) - ) + // Update the quantity + var newItem = it.copy(quantity = newQuantity, maxQuantity = maxQuantities[uniqueId] ?: 0f) + + // Update the subtotal and taxes based on the new quantity + val (subtotal, taxes) = newItem.calculateTotal() + newItem = newItem.copy(subtotal = formatCurrency(subtotal), taxes = formatCurrency(taxes)) + + newItems.add(newItem) } else { newItems.add(it) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/RefundProductListAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/RefundProductListAdapter.kt index 9bb2d32b5f4..0ce0e28f1fb 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/RefundProductListAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/RefundProductListAdapter.kt @@ -140,6 +140,8 @@ class RefundProductListAdapter( private val descriptionTextView: TextView = itemView.findViewById(R.id.refundItem_description) private val quantityTextView: TextView = itemView.findViewById(R.id.refundItem_quantity) private val productImageView: ImageView = itemView.findViewById(R.id.refundItem_icon) + private val subtotalTextView: TextView = itemView.findViewById(R.id.refundItemSubtotal) + private val taxesTextView: TextView = itemView.findViewById(R.id.refundItemTaxes) @SuppressLint("SetTextI18n") override fun bind(item: ProductRefundListItem) { @@ -166,6 +168,10 @@ class RefundProductListAdapter( .placeholder(R.drawable.ic_product) .into(productImageView) } ?: productImageView.setImageResource(R.drawable.ic_product) + + subtotalTextView.text = item.subtotal + + taxesTextView.text = item.taxes } } @@ -173,7 +179,9 @@ class RefundProductListAdapter( data class ProductRefundListItem( val orderItem: Order.Item, val maxQuantity: Float = 0f, - val quantity: Int = 0 + val quantity: Int = 0, + val subtotal: String? = null, + val taxes: String? = null ) : Parcelable { @IgnoredOnParcel val availableRefundQuantity From 0e3d3f150c3c16aea35bb6e4972a3ebc9e3a1cda Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Wed, 7 Aug 2024 01:20:38 +0300 Subject: [PATCH 046/196] Update RELEASE-NOTES.txt --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 8db33e31ccf..6af0d7f6238 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -4,6 +4,7 @@ 19.9 ----- - [*] [Internal] Update Android material from 1.9.0 to 1.10.0 [https://github.com/woocommerce/woocommerce-android/pull/12186] +- [*] Added subtotal and taxes fields to each refund item on the refund screen. [https://github.com/woocommerce/woocommerce-android/pull/12235] 19.8 ----- From cf99eb617f8a24baadb8d59636b0d4338822fefb Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 07:10:13 +0200 Subject: [PATCH 047/196] Update Android Transition from 1.4.0 to 1.5.0 --- WooCommerce/build.gradle | 1 + build.gradle | 1 + 2 files changed, 2 insertions(+) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index e44b5628a90..29a5e00a18e 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -240,6 +240,7 @@ dependencies { implementation "androidx.recyclerview:recyclerview-selection:1.1.0" implementation "androidx.appcompat:appcompat:$appCompatVersion" implementation "com.google.android.material:material:$materialVersion" + implementation "androidx.transition:transition:$transitionVersion" 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 e3385fb35db..a52f34f5567 100644 --- a/build.gradle +++ b/build.gradle @@ -115,6 +115,7 @@ ext { coreKtxVersion = '1.13.1' appCompatVersion = '1.4.2' materialVersion = '1.10.0' + transitionVersion = '1.5.0' hiltJetpackVersion = '1.1.0' wordPressUtilsVersion = '3.5.0' mediapickerVersion = '0.3.1' From 5dc879037808b3dbe65ca97db8f18f66c15c4c67 Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 07:10:36 +0200 Subject: [PATCH 048/196] Update Android Material from 1.10.0 to 1.12.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a52f34f5567..fdf1809022d 100644 --- a/build.gradle +++ b/build.gradle @@ -114,7 +114,7 @@ ext { stateMachineVersion = '0.2.0' coreKtxVersion = '1.13.1' appCompatVersion = '1.4.2' - materialVersion = '1.10.0' + materialVersion = '1.12.0' transitionVersion = '1.5.0' hiltJetpackVersion = '1.1.0' wordPressUtilsVersion = '3.5.0' From f998372573e348cefda5c2fdacb78db99673bccc Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 07:17:40 +0200 Subject: [PATCH 049/196] Use ktx version of androidx transition --- WooCommerce/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 29a5e00a18e..0f2b0bc9487 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -240,7 +240,7 @@ dependencies { implementation "androidx.recyclerview:recyclerview-selection:1.1.0" implementation "androidx.appcompat:appcompat:$appCompatVersion" implementation "com.google.android.material:material:$materialVersion" - implementation "androidx.transition:transition:$transitionVersion" + implementation "androidx.transition:transition-ktx:$transitionVersion" implementation "androidx.cardview:cardview:1.0.0" implementation("androidx.browser:browser:1.5.0") { exclude group: 'com.google.guava', module: 'listenablefuture' From 5a3186cd83d493159ee894ce4a3e9ffbcb130e6d Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 07:17:58 +0200 Subject: [PATCH 050/196] Update androidx transition to 1.5.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index fdf1809022d..06508ed2575 100644 --- a/build.gradle +++ b/build.gradle @@ -115,7 +115,7 @@ ext { coreKtxVersion = '1.13.1' appCompatVersion = '1.4.2' materialVersion = '1.12.0' - transitionVersion = '1.5.0' + transitionVersion = '1.5.1' hiltJetpackVersion = '1.1.0' wordPressUtilsVersion = '3.5.0' mediapickerVersion = '0.3.1' From 356bc3f53eaef9eea44cc87159bd939d404d54a3 Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 07:20:27 +0200 Subject: [PATCH 051/196] Update release notes --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 44fcbc0eea4..a14ca016124 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -7,6 +7,7 @@ - [*] [Internal] Update Android-core from 1.12.0 to 1.13.1 [https://github.com/woocommerce/woocommerce-android/pull/12229] - [*] [Internal] Update Android-lifecycle from 2.6.2 to 2.7.0 [https://github.com/woocommerce/woocommerce-android/pull/12230] - [*] [Internal] Update Androidx-fragment from 1.6.2 to 1.8.2 [https://github.com/woocommerce/woocommerce-android/pull/12231] +- [*] [Internal] Update Material to 1.12.0 and Transition to 1.5.1 [https://github.com/woocommerce/woocommerce-android/pull/12237] 19.8 ----- From ede2bf235a3fa52e88605f280a969de7ede73add Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 08:37:38 +0200 Subject: [PATCH 052/196] Revert "Revert explicit specification of service type" This reverts commit c5d5bee87b573adbfb24b0b0b492858b8d3df1d5. --- WooCommerce/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/AndroidManifest.xml b/WooCommerce/src/main/AndroidManifest.xml index d08db657360..281612f6271 100644 --- a/WooCommerce/src/main/AndroidManifest.xml +++ b/WooCommerce/src/main/AndroidManifest.xml @@ -199,6 +199,7 @@ Date: Wed, 7 Aug 2024 08:37:39 +0200 Subject: [PATCH 053/196] Revert "Downgrade targetSdkVersion back to 33" This reverts commit ba70d60195aebbc7047e6240c5d67354ffa31316. --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 48c9f36156e..a5bdc1b2553 100644 --- a/settings.gradle +++ b/settings.gradle @@ -73,7 +73,7 @@ gradle.ext.mediaPickerSourceWordPressBinaryPath = "org.wordpress.mediapicker:sou gradle.ext { compileSdkVersion = 34 - targetSdkVersion = 33 + targetSdkVersion = 34 minSdkVersion = 26 } From 92c0107fd0c485a940cab7c0f8a110678d2c9598 Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 08:59:12 +0200 Subject: [PATCH 054/196] Update Stripe Terminal Sdk from 3.1.1 to 3.7.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 06508ed2575..0ac3bcf5a57 100644 --- a/build.gradle +++ b/build.gradle @@ -124,7 +124,7 @@ ext { automatticTracksVersion = '5.0.0' workManagerVersion = '2.7.1' billingVersion = '5.0.0' - stripeTerminalVersion = '3.1.1' + stripeTerminalVersion = '3.7.1' mlkitBarcodeScanningVersion = '17.2.0' mlkitTextRecognitionVersion = '16.0.0' androidxCameraVersion = '1.2.3' From 4da88f6d3659f2c825a7932eb3827074b6ca8a33 Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 08:59:40 +0200 Subject: [PATCH 055/196] Update RefundParams to use new constructor for id --- .../woocommerce/android/cardreader/payments/RefundParams.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/cardreader/src/main/java/com/woocommerce/android/cardreader/payments/RefundParams.kt b/libs/cardreader/src/main/java/com/woocommerce/android/cardreader/payments/RefundParams.kt index 8525f9f5404..6c9c6864dd7 100644 --- a/libs/cardreader/src/main/java/com/woocommerce/android/cardreader/payments/RefundParams.kt +++ b/libs/cardreader/src/main/java/com/woocommerce/android/cardreader/payments/RefundParams.kt @@ -1,6 +1,7 @@ package com.woocommerce.android.cardreader.payments import com.stripe.stripeterminal.external.models.RefundParameters +import com.stripe.stripeterminal.external.models.RefundParameters.Id import com.woocommerce.android.cardreader.internal.payments.PaymentUtils import java.math.BigDecimal @@ -12,7 +13,7 @@ data class RefundParams( internal fun RefundParams.toStripeRefundParameters(paymentUtils: PaymentUtils): RefundParameters { return RefundParameters.Builder( - chargeId = this.chargeId, + Id.Charge(id = this.chargeId), amount = paymentUtils.convertToSmallestCurrencyUnit(this.amount, this.currency), currency = this.currency ).build() From 6e7cf7f81bba8e2ddd5d30e2b64436496ae767d0 Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 09:12:29 +0200 Subject: [PATCH 056/196] Update release notes --- RELEASE-NOTES.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index a14ca016124..b344f9e8b44 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -3,11 +3,12 @@ *** For entries which are touching the Android Wear app's, start entry with `[WEAR]` too. 19.9 ----- -- [*] [Internal] Update Android material from 1.9.0 to 1.10.0 [https://github.com/woocommerce/woocommerce-android/pull/12186] -- [*] [Internal] Update Android-core from 1.12.0 to 1.13.1 [https://github.com/woocommerce/woocommerce-android/pull/12229] -- [*] [Internal] Update Android-lifecycle from 2.6.2 to 2.7.0 [https://github.com/woocommerce/woocommerce-android/pull/12230] -- [*] [Internal] Update Androidx-fragment from 1.6.2 to 1.8.2 [https://github.com/woocommerce/woocommerce-android/pull/12231] -- [*] [Internal] Update Material to 1.12.0 and Transition to 1.5.1 [https://github.com/woocommerce/woocommerce-android/pull/12237] +- [*****] [Internal] Update Android material from 1.9.0 to 1.10.0 [https://github.com/woocommerce/woocommerce-android/pull/12186] +- [*****] [Internal] Update Android-core from 1.12.0 to 1.13.1 [https://github.com/woocommerce/woocommerce-android/pull/12229] +- [*****] [Internal] Update Android-lifecycle from 2.6.2 to 2.7.0 [https://github.com/woocommerce/woocommerce-android/pull/12230] +- [*****] [Internal] Update Androidx-fragment from 1.6.2 to 1.8.2 [https://github.com/woocommerce/woocommerce-android/pull/12231] +- [*****] [Internal] Update Material to 1.12.0 and Transition to 1.5.1 [https://github.com/woocommerce/woocommerce-android/pull/12237] +- [*****] [Internal] Update Stripe Terminal SDK from 3.1.1 to 3.7.1 [https://github.com/woocommerce/woocommerce-android/pull/12239] 19.8 ----- From 9370d2a88badcb797f6e0461212153cf642bf834 Mon Sep 17 00:00:00 2001 From: malinajirka Date: Mon, 5 Aug 2024 15:52:09 +0200 Subject: [PATCH 057/196] Hide TTP on Android 10 as it is no longer supported --- .../android/ui/payments/taptopay/TapToPayAvailabilityStatus.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/taptopay/TapToPayAvailabilityStatus.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/taptopay/TapToPayAvailabilityStatus.kt index cadf34a04af..d899424a39a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/taptopay/TapToPayAvailabilityStatus.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/taptopay/TapToPayAvailabilityStatus.kt @@ -19,7 +19,7 @@ class TapToPayAvailabilityStatus @Inject constructor( ) { operator fun invoke() = when { - !systemVersionUtilsWrapper.isAtLeastQ() -> Result.NotAvailable.SystemVersionNotSupported + !systemVersionUtilsWrapper.isAtLeastR() -> Result.NotAvailable.SystemVersionNotSupported !deviceFeatures.isGooglePlayServicesAvailable() -> Result.NotAvailable.GooglePlayServicesNotAvailable !deviceFeatures.isNFCAvailable() -> Result.NotAvailable.NfcNotAvailable !isTppSupportedInCountry() -> Result.NotAvailable.CountryNotSupported From 8f89955df55a1a39c66318c105e4889c3c8e9395 Mon Sep 17 00:00:00 2001 From: malinajirka Date: Mon, 5 Aug 2024 15:53:26 +0200 Subject: [PATCH 058/196] Update unit tests for TTP supported OS versions --- .../ui/payments/taptopay/TapToPayAvailabilityStatusTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/taptopay/TapToPayAvailabilityStatusTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/taptopay/TapToPayAvailabilityStatusTest.kt index 8b2b2dcbc72..067f4d23a5d 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/taptopay/TapToPayAvailabilityStatusTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/taptopay/TapToPayAvailabilityStatusTest.kt @@ -64,10 +64,10 @@ class TapToPayAvailabilityStatusTest { } @Test - fun `given device has os less than Android 9, when invoking, then system is not supported returned`() { + fun `given device has os less than Android 10, when invoking, then system is not supported returned`() { whenever(deviceFeatures.isNFCAvailable()).thenReturn(true) whenever(deviceFeatures.isGooglePlayServicesAvailable()).thenReturn(true) - whenever(systemVersionUtilsWrapper.isAtLeastQ()).thenReturn(false) + whenever(systemVersionUtilsWrapper.isAtLeastR()).thenReturn(false) val result = availabilityStatus.invoke() From 512c0dcadd4e51782ebf7efa44a0a64180bdb713 Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 09:51:57 +0200 Subject: [PATCH 059/196] Update name of TTP process definition --- .../src/main/kotlin/com/woocommerce/android/WooCommerce.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt index ed601d1cc1a..3c0036d3f30 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt @@ -55,6 +55,6 @@ open class WooCommerce : Application(), HasAndroidInjector, Configuration.Provid override fun androidInjector(): AndroidInjector = androidInjector companion object { - private const val TAP_TO_PAY_STRIPE_PROCESS_NAME = "com.stripe.cots.aidlservice" + private const val TAP_TO_PAY_STRIPE_PROCESS_NAME = "com.woocommerce.android:stripelocalmobile" } } From 54b3dccc1ba8e57bd0bd67f2dabf723c551ae24c Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 10:06:54 +0200 Subject: [PATCH 060/196] Update TTP process name on debug builds --- .../src/main/kotlin/com/woocommerce/android/WooCommerce.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt index 3c0036d3f30..136977f66e0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt @@ -30,7 +30,7 @@ open class WooCommerce : Application(), HasAndroidInjector, Configuration.Provid // > Caused by: java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process // > com.stripe.cots.aidlservice. Make sure to call FirebaseApp.initializeApp(Context) first. // In this case we don't want to initialize any Firebase (or any at all) features of the app in their process. - if (getCurrentProcessName() == TAP_TO_PAY_STRIPE_PROCESS_NAME) return + if (getCurrentProcessName() == "$packageName:$TAP_TO_PAY_STRIPE_PROCESS_NAME_SUFFIX") return // Disables Volley debug logging on release build and prevents the "Marker added to finished log" crash // https://github.com/woocommerce/woocommerce-android/issues/817 @@ -55,6 +55,6 @@ open class WooCommerce : Application(), HasAndroidInjector, Configuration.Provid override fun androidInjector(): AndroidInjector = androidInjector companion object { - private const val TAP_TO_PAY_STRIPE_PROCESS_NAME = "com.woocommerce.android:stripelocalmobile" + private const val TAP_TO_PAY_STRIPE_PROCESS_NAME_SUFFIX = "stripelocalmobile" } } From 47d53c338d194d6491c613b34da6300c8bdc0868 Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 10:11:27 +0200 Subject: [PATCH 061/196] Update comment --- .../src/main/kotlin/com/woocommerce/android/WooCommerce.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt index 136977f66e0..58859aed1b2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt @@ -28,7 +28,7 @@ open class WooCommerce : Application(), HasAndroidInjector, Configuration.Provid // Stripe Tap to Pay library starts it's own process. That causes the crash: // > Caused by: java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process - // > com.stripe.cots.aidlservice. Make sure to call FirebaseApp.initializeApp(Context) first. + // > com.woocommerce.android:stripelocalmobile Make sure to call FirebaseApp.initializeApp(Context) first. // In this case we don't want to initialize any Firebase (or any at all) features of the app in their process. if (getCurrentProcessName() == "$packageName:$TAP_TO_PAY_STRIPE_PROCESS_NAME_SUFFIX") return From 590cd660c3e7ab03a8c76e277434dde6ad243cc5 Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 10:13:56 +0200 Subject: [PATCH 062/196] Replace packageName with Application ID --- .../src/main/kotlin/com/woocommerce/android/WooCommerce.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt index 58859aed1b2..f7226a6e3aa 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/WooCommerce.kt @@ -30,7 +30,7 @@ open class WooCommerce : Application(), HasAndroidInjector, Configuration.Provid // > Caused by: java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process // > com.woocommerce.android:stripelocalmobile Make sure to call FirebaseApp.initializeApp(Context) first. // In this case we don't want to initialize any Firebase (or any at all) features of the app in their process. - if (getCurrentProcessName() == "$packageName:$TAP_TO_PAY_STRIPE_PROCESS_NAME_SUFFIX") return + if (getCurrentProcessName() == "${BuildConfig.APPLICATION_ID}:$TAP_TO_PAY_STRIPE_PROCESS_NAME_SUFFIX") return // Disables Volley debug logging on release build and prevents the "Marker added to finished log" crash // https://github.com/woocommerce/woocommerce-android/issues/817 From ba426a45d1ef23615f5792f6999e7912bad73900 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 7 Aug 2024 12:13:57 +0200 Subject: [PATCH 063/196] Improve code style --- .../cardreader/payment/CardReaderPaymentViewModel.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt index 2df6fc8f136..49e307370b7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt @@ -464,10 +464,7 @@ class CardReaderPaymentViewModel ) { paymentReceiptHelper.storeReceiptUrl(orderId, paymentStatus.receiptUrl) appPrefs.setCardReaderSuccessfulPaymentTime() - val flowParam: CardReaderFlowParam.PaymentOrRefund = arguments.paymentOrRefund - if (flowParam is CardReaderFlowParam.PaymentOrRefund.Payment && - flowParam.paymentType == CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.WOO_POS - ) { + if (arguments.paymentOrRefund.isPOS()) { reFetchOrder() onCancelPaymentFlow() } else { @@ -477,6 +474,11 @@ class CardReaderPaymentViewModel } } + private fun CardReaderFlowParam.PaymentOrRefund.isPOS(): Boolean { + return this is CardReaderFlowParam.PaymentOrRefund.Payment && + this.paymentType == CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.WOO_POS + } + @VisibleForTesting fun reFetchOrder() { refetchOrderJob = launch { From bbc844a3a4d1bffa4366eea54a81745d960aceba Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 7 Aug 2024 14:30:35 +0200 Subject: [PATCH 064/196] Add unit tests --- .../CardReaderPaymentViewModelTest.kt | 58 ++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index b8b05c6c7d0..dcab52ca408 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -4427,6 +4427,58 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { verify(cardReaderManager, never()).collectPayment(any()) } + @Test + fun `given point of sale, when payment captured, then should not show success state`() { + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + initViewModel( + readerType = EXTERNAL, + cardReaderFlowParam = CardReaderFlowParam.PaymentOrRefund.Payment( + orderId = ORDER_ID, + paymentType = CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.WOO_POS + ) + ) + + viewModel.start() + + assertThat(viewModel.viewStateData.value).isNotInstanceOfAny( + BuiltInReaderPaymentSuccessfulState::class.java, + ExternalReaderPaymentSuccessfulState::class.java, + ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState::class.java, + BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState::class.java, + ) + } + } + + @Test + fun `given point of sale, when payment captured, then should exit`() { + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + initViewModel( + readerType = EXTERNAL, + cardReaderFlowParam = CardReaderFlowParam.PaymentOrRefund.Payment( + orderId = ORDER_ID, + paymentType = CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.WOO_POS + ) + ) + + val events = mutableListOf() + viewModel.event.observeForever { + events.add(it) + } + + viewModel.start() + + assertThat(events[0]).isInstanceOf(Exit::class.java) + } + } + private suspend fun simulateFetchOrderJobState(inProgress: Boolean) { if (inProgress) { whenever(orderRepository.fetchOrderById(any())).doSuspendableAnswer { @@ -4466,11 +4518,13 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { private fun initViewModel( readerType: CardReaderType, - savedStateValue: Pair? = null + savedStateValue: Pair? = null, + cardReaderFlowParam: CardReaderFlowParam.PaymentOrRefund = + CardReaderFlowParam.PaymentOrRefund.Payment(ORDER_ID, ORDER), ) { viewModel = CardReaderPaymentViewModel( CardReaderPaymentDialogFragmentArgs( - CardReaderFlowParam.PaymentOrRefund.Payment(ORDER_ID, ORDER), + cardReaderFlowParam, readerType, ).toSavedStateHandle().also { if (savedStateValue != null) it[savedStateValue.first] = savedStateValue.second From c698207574f3971e08d424420a69c025f11e738b Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 7 Aug 2024 14:37:00 +0200 Subject: [PATCH 065/196] Atempt to emulate shadow manually --- .../composeui/component/WooPosLazyColumn.kt | 119 ++++++++++++++++++ .../home/products/WooPosProductsScreen.kt | 3 +- 2 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosLazyColumn.kt diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosLazyColumn.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosLazyColumn.kt new file mode 100644 index 00000000000..89353041fc7 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosLazyColumn.kt @@ -0,0 +1,119 @@ +package com.woocommerce.android.ui.woopos.common.composeui.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material.Card +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview +import com.woocommerce.android.ui.woopos.common.composeui.WooPosTheme +import com.woocommerce.android.ui.woopos.common.composeui.toAdaptivePadding + +@Composable +fun WooPosLazyColumn( + modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(0.dp), + verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(8.dp), + state: LazyListState = rememberLazyListState(), + content: LazyListScope.() -> Unit +) { + Box { + LazyColumn( + modifier = modifier, + contentPadding = contentPadding, + verticalArrangement = verticalArrangement, + state = state, + content = content + ) + + val showShadow = remember { + derivedStateOf { + state.firstVisibleItemIndex > 0 || state.firstVisibleItemScrollOffset > 0 + } + } + + if (showShadow.value) { + val height = 16.dp.toAdaptivePadding() + Box( + modifier = Modifier + .fillMaxWidth() + .height(height) + .align(Alignment.TopCenter) + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(height) + .background( + brush = Brush.horizontalGradient( + colors = listOf( + Color.Transparent, + MaterialTheme.colors.onSurface.copy(alpha = .03f), + MaterialTheme.colors.onSurface.copy(alpha = .03f), + MaterialTheme.colors.onSurface.copy(alpha = .03f), + MaterialTheme.colors.onSurface.copy(alpha = .03f), + Color.Transparent, + ), + startX = 0f, + endX = Float.POSITIVE_INFINITY + ) + ) + ) + Box( + modifier = Modifier + .fillMaxWidth() + .height(height) + .background( + brush = Brush.verticalGradient( + colors = listOf( + MaterialTheme.colors.onSurface.copy(alpha = .1f), + Color.Transparent, + ), + startY = 0f, + endY = height.value + ) + ) + ) + } + } + } +} + +@WooPosPreview +@Composable +fun WooPosLazyColumnPreview() { + WooPosTheme + WooPosLazyColumn { + items(10) { i -> + Card( + modifier = Modifier.fillMaxWidth(), + elevation = 4.dp, + ) { + Text( + "Item $i", + modifier = Modifier + .height(64.dp) + .fillMaxWidth(), + style = MaterialTheme.typography.h6, + color = MaterialTheme.colors.onSurface, + ) + } + } + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt index cd635efd947..ec1e91ddfe1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt @@ -64,6 +64,7 @@ import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview import com.woocommerce.android.ui.woopos.common.composeui.WooPosTheme import com.woocommerce.android.ui.woopos.common.composeui.component.Button import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosErrorState +import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosLazyColumn import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosShimmerBox import com.woocommerce.android.ui.woopos.common.composeui.toAdaptivePadding import com.woocommerce.android.ui.woopos.home.products.WooPosProductsUIEvent.EndOfProductListReached @@ -244,7 +245,7 @@ private fun ProductsList( onEndOfProductsListReached: () -> Unit, ) { val listState = rememberLazyListState() - LazyColumn( + WooPosLazyColumn( verticalArrangement = Arrangement.spacedBy(8.dp), contentPadding = PaddingValues(2.dp), state = listState, From 110f745997f806624ef783fac6eaa6f1ac8aa573 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 7 Aug 2024 15:17:28 +0200 Subject: [PATCH 066/196] Use card for better shadow --- .../composeui/component/WooPosLazyColumn.kt | 51 +++---------------- 1 file changed, 8 insertions(+), 43 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosLazyColumn.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosLazyColumn.kt index 89353041fc7..0e46155434c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosLazyColumn.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosLazyColumn.kt @@ -1,11 +1,11 @@ package com.woocommerce.android.ui.woopos.common.composeui.component -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListState @@ -18,8 +18,6 @@ import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview import com.woocommerce.android.ui.woopos.common.composeui.WooPosTheme @@ -49,48 +47,15 @@ fun WooPosLazyColumn( } if (showShadow.value) { - val height = 16.dp.toAdaptivePadding() - Box( + Card( modifier = Modifier .fillMaxWidth() - .height(height) - .align(Alignment.TopCenter) - ) { - Box( - modifier = Modifier - .fillMaxWidth() - .height(height) - .background( - brush = Brush.horizontalGradient( - colors = listOf( - Color.Transparent, - MaterialTheme.colors.onSurface.copy(alpha = .03f), - MaterialTheme.colors.onSurface.copy(alpha = .03f), - MaterialTheme.colors.onSurface.copy(alpha = .03f), - MaterialTheme.colors.onSurface.copy(alpha = .03f), - Color.Transparent, - ), - startX = 0f, - endX = Float.POSITIVE_INFINITY - ) - ) - ) - Box( - modifier = Modifier - .fillMaxWidth() - .height(height) - .background( - brush = Brush.verticalGradient( - colors = listOf( - MaterialTheme.colors.onSurface.copy(alpha = .1f), - Color.Transparent, - ), - startY = 0f, - endY = height.value - ) - ) - ) - } + .height(0.5.dp) + .padding(horizontal = .5.dp) + .align(Alignment.TopCenter), + elevation = 4.dp.toAdaptivePadding(), + backgroundColor = MaterialTheme.colors.onBackground.copy(alpha = 0.1f) + ) {} } } } From ee28af5c272a4a9eaceb290d6863a1b9ad12f35d Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 7 Aug 2024 15:33:39 +0200 Subject: [PATCH 067/196] Use WooPosLazyColumn for the rest of the lists --- .../woopos/common/composeui/component/WooPosLazyColumn.kt | 6 +++--- .../android/ui/woopos/home/cart/WooPosCartScreen.kt | 6 +++--- .../android/ui/woopos/home/products/WooPosProductsScreen.kt | 3 +-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosLazyColumn.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosLazyColumn.kt index 0e46155434c..6defe09c0f8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosLazyColumn.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosLazyColumn.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListState @@ -28,6 +27,7 @@ fun WooPosLazyColumn( modifier: Modifier = Modifier, contentPadding: PaddingValues = PaddingValues(0.dp), verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(8.dp), + horizontalAlignment: Alignment.Horizontal = Alignment.Start, state: LazyListState = rememberLazyListState(), content: LazyListScope.() -> Unit ) { @@ -36,6 +36,7 @@ fun WooPosLazyColumn( modifier = modifier, contentPadding = contentPadding, verticalArrangement = verticalArrangement, + horizontalAlignment = horizontalAlignment, state = state, content = content ) @@ -48,10 +49,9 @@ fun WooPosLazyColumn( if (showShadow.value) { Card( - modifier = Modifier + modifier = modifier .fillMaxWidth() .height(0.5.dp) - .padding(horizontal = .5.dp) .align(Alignment.TopCenter), elevation = 4.dp.toAdaptivePadding(), backgroundColor = MaterialTheme.colors.onBackground.copy(alpha = 0.1f) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartScreen.kt index 69bb3b2d8b4..11cf2638ee2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartScreen.kt @@ -19,7 +19,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState @@ -57,6 +56,7 @@ import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview import com.woocommerce.android.ui.woopos.common.composeui.WooPosTheme import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosButton +import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosLazyColumn import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosOutlinedButton import com.woocommerce.android.ui.woopos.common.composeui.toAdaptivePadding @@ -81,6 +81,7 @@ private fun WooPosCartScreen( top = 40.dp.toAdaptivePadding(), bottom = 16.dp.toAdaptivePadding() ) + .fillMaxSize() .background(MaterialTheme.colors.surface) ) { Column { @@ -151,9 +152,8 @@ private fun CartBodyWithItems( val listState = rememberLazyListState() ScrollToBottomHandler(items, listState) - LazyColumn( + WooPosLazyColumn( modifier = Modifier - .fillMaxSize() .padding(horizontal = 16.dp.toAdaptivePadding()), state = listState, verticalArrangement = Arrangement.spacedBy(8.dp.toAdaptivePadding()), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt index ec1e91ddfe1..69309063a3a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt @@ -19,7 +19,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState @@ -277,7 +276,7 @@ private fun ProductsList( @Composable fun ProductsLoadingIndicator() { - LazyColumn( + WooPosLazyColumn( verticalArrangement = Arrangement.spacedBy(8.dp), contentPadding = PaddingValues(2.dp), ) { From cbd0f76cceff96bdfa347f3e23538a65726c5dff Mon Sep 17 00:00:00 2001 From: Alejo Date: Wed, 7 Aug 2024 07:56:19 -0600 Subject: [PATCH 068/196] update last update on background sync --- .../UpdateAnalyticsDataByRangeSelection.kt | 57 ++++++++++++++++--- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/background/UpdateAnalyticsDataByRangeSelection.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/background/UpdateAnalyticsDataByRangeSelection.kt index 6ff43402c7f..70a93d51412 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/background/UpdateAnalyticsDataByRangeSelection.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/background/UpdateAnalyticsDataByRangeSelection.kt @@ -3,6 +3,7 @@ package com.woocommerce.android.background import com.woocommerce.android.model.AnalyticsCards import com.woocommerce.android.ui.analytics.hub.ObserveAnalyticsCardsConfiguration import com.woocommerce.android.ui.analytics.hub.sync.AnalyticsRepository +import com.woocommerce.android.ui.analytics.hub.sync.AnalyticsUpdateDataStore import com.woocommerce.android.ui.analytics.ranges.StatsTimeRangeSelection import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll @@ -12,7 +13,8 @@ import javax.inject.Inject class UpdateAnalyticsDataByRangeSelection @Inject constructor( private val analyticsCardsConfiguration: ObserveAnalyticsCardsConfiguration, - private val analyticsRepository: AnalyticsRepository + private val analyticsRepository: AnalyticsRepository, + private val analyticsUpdateDataStore: AnalyticsUpdateDataStore ) { @Suppress("LongMethod") suspend operator fun invoke( @@ -34,49 +36,90 @@ class UpdateAnalyticsDataByRangeSelection @Inject constructor( selectedRange, AnalyticsRepository.FetchStrategy.ForceNew ) - result is AnalyticsRepository.RevenueResult.RevenueData + if (result is AnalyticsRepository.RevenueResult.RevenueData) { + analyticsUpdateDataStore.storeLastAnalyticsUpdate( + selectedRange, + AnalyticsUpdateDataStore.AnalyticData.REVENUE + ) + true + } else { + false + } } } + AnalyticsCards.Orders -> { async { val result = analyticsRepository.fetchOrdersData( selectedRange, AnalyticsRepository.FetchStrategy.ForceNew ) - result is AnalyticsRepository.OrdersResult.OrdersData + if (result is AnalyticsRepository.OrdersResult.OrdersData) { + analyticsUpdateDataStore.storeLastAnalyticsUpdate( + selectedRange, + AnalyticsUpdateDataStore.AnalyticData.ORDERS + ) + true + } else { + false + } } } + AnalyticsCards.Products -> { async { val result = analyticsRepository.fetchProductsData( selectedRange, AnalyticsRepository.FetchStrategy.ForceNew ) - result is AnalyticsRepository.ProductsResult.ProductsData + if (result is AnalyticsRepository.ProductsResult.ProductsData) { + analyticsUpdateDataStore.storeLastAnalyticsUpdate( + selectedRange, + AnalyticsUpdateDataStore.AnalyticData.TOP_PERFORMERS + ) + true + } else { + false + } } } + AnalyticsCards.Session -> { async { val result = analyticsRepository.fetchVisitorsData( selectedRange, AnalyticsRepository.FetchStrategy.ForceNew ) - result is AnalyticsRepository.VisitorsResult.VisitorsData || - result is AnalyticsRepository.VisitorsResult.VisitorsNotSupported + when (result) { + is AnalyticsRepository.VisitorsResult.VisitorsData -> { + analyticsUpdateDataStore.storeLastAnalyticsUpdate( + selectedRange, + AnalyticsUpdateDataStore.AnalyticData.VISITORS + ) + true + } + is AnalyticsRepository.VisitorsResult.VisitorsNotSupported -> true + else -> { + false + } + } } } + AnalyticsCards.Bundles -> { async { val result = analyticsRepository.fetchProductBundlesStats(selectedRange) result is AnalyticsRepository.BundlesResult.BundlesData } } + AnalyticsCards.GiftCards -> { async { val result = analyticsRepository.fetchGiftCardsStats(selectedRange) result is AnalyticsRepository.GiftCardResult.GiftCardData } } + AnalyticsCards.GoogleAds -> { async { val result = analyticsRepository.fetchGoogleAdsStats(selectedRange) @@ -85,7 +128,7 @@ class UpdateAnalyticsDataByRangeSelection @Inject constructor( } } } - asyncCalls.awaitAll().all { succeed -> succeed } + asyncCalls.awaitAll().all { it } } } } From a7160446cf952e346f6ad5393f9eee1a97645507 Mon Sep 17 00:00:00 2001 From: Alejo Date: Wed, 7 Aug 2024 09:41:45 -0600 Subject: [PATCH 069/196] add unit test --- ...UpdateAnalyticsDataByRangeSelectionTest.kt | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/background/UpdateAnalyticsDataByRangeSelectionTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/background/UpdateAnalyticsDataByRangeSelectionTest.kt index 9a0c0211aa2..7c7ed3f6e02 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/background/UpdateAnalyticsDataByRangeSelectionTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/background/UpdateAnalyticsDataByRangeSelectionTest.kt @@ -4,6 +4,7 @@ import com.woocommerce.android.model.AnalyticCardConfiguration import com.woocommerce.android.model.AnalyticsCards import com.woocommerce.android.ui.analytics.hub.ObserveAnalyticsCardsConfiguration import com.woocommerce.android.ui.analytics.hub.sync.AnalyticsRepository +import com.woocommerce.android.ui.analytics.hub.sync.AnalyticsUpdateDataStore import com.woocommerce.android.ui.analytics.ranges.StatsTimeRangeSelection import com.woocommerce.android.viewmodel.BaseUnitTest import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -26,6 +27,7 @@ class UpdateAnalyticsDataByRangeSelectionTest : BaseUnitTest() { private val analyticsCardsConfiguration: ObserveAnalyticsCardsConfiguration = mock() private val analyticsRepository: AnalyticsRepository = mock() + private val analyticsUpdateDataStore: AnalyticsUpdateDataStore = mock() private val defaultVisibleCards = listOf( AnalyticCardConfiguration( @@ -62,7 +64,8 @@ class UpdateAnalyticsDataByRangeSelectionTest : BaseUnitTest() { private val sut = UpdateAnalyticsDataByRangeSelection( analyticsCardsConfiguration = analyticsCardsConfiguration, - analyticsRepository = analyticsRepository + analyticsRepository = analyticsRepository, + analyticsUpdateDataStore = analyticsUpdateDataStore ) private val defaultRangeSelection = StatsTimeRangeSelection.SelectionType.TODAY.generateSelectionData( @@ -214,4 +217,48 @@ class UpdateAnalyticsDataByRangeSelectionTest : BaseUnitTest() { assertTrue(result) } + + @Test + fun `save last update only for success requests`() = runTest { + whenever(analyticsCardsConfiguration.invoke()).doReturn(flowOf(defaultVisibleCards)) + whenever( + analyticsRepository.fetchRevenueData( + defaultRangeSelection, + AnalyticsRepository.FetchStrategy.ForceNew + ) + ).doReturn(AnalyticsRepository.RevenueResult.RevenueData(mock())) + whenever(analyticsRepository.fetchGiftCardsStats(defaultRangeSelection)) + .doReturn(AnalyticsRepository.GiftCardResult.GiftCardData(mock())) + whenever(analyticsRepository.fetchProductBundlesStats(defaultRangeSelection)) + .doReturn(AnalyticsRepository.BundlesResult.BundlesData(mock())) + whenever( + analyticsRepository.fetchOrdersData( + defaultRangeSelection, + AnalyticsRepository.FetchStrategy.ForceNew + ) + ).doReturn(AnalyticsRepository.OrdersResult.OrdersError) + whenever( + analyticsRepository.fetchProductsData( + defaultRangeSelection, + AnalyticsRepository.FetchStrategy.ForceNew + ) + ).doReturn(AnalyticsRepository.ProductsResult.ProductsData(mock())) + + val result = sut.invoke(defaultRangeSelection, listOf(AnalyticsCards.Products)) + + assertFalse(result) + + verify(analyticsUpdateDataStore).storeLastAnalyticsUpdate( + defaultRangeSelection, + AnalyticsUpdateDataStore.AnalyticData.REVENUE + ) + verify(analyticsUpdateDataStore).storeLastAnalyticsUpdate( + defaultRangeSelection, + AnalyticsUpdateDataStore.AnalyticData.TOP_PERFORMERS + ) + verify(analyticsUpdateDataStore, never()).storeLastAnalyticsUpdate( + defaultRangeSelection, + AnalyticsUpdateDataStore.AnalyticData.ORDERS + ) + } } From 58c1a9d6a2504a09aa3ea918e9b39c6ff6172513 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 7 Aug 2024 18:11:23 +0200 Subject: [PATCH 070/196] Clean up the code --- .../payment/CardReaderPaymentViewModel.kt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt index 49e307370b7..854b829715f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt @@ -146,6 +146,10 @@ class CardReaderPaymentViewModel private var refetchOrderJob: Job? = null + private val CardReaderFlowParam.PaymentOrRefund.isPOS: Boolean + get() = this is CardReaderFlowParam.PaymentOrRefund.Payment && + this.paymentType == CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.WOO_POS + fun start() { if (cardReaderManager.readerStatus.value is CardReaderStatus.Connected) { startFlowWhenReaderConnected() @@ -464,9 +468,11 @@ class CardReaderPaymentViewModel ) { paymentReceiptHelper.storeReceiptUrl(orderId, paymentStatus.receiptUrl) appPrefs.setCardReaderSuccessfulPaymentTime() - if (arguments.paymentOrRefund.isPOS()) { - reFetchOrder() - onCancelPaymentFlow() + if (arguments.paymentOrRefund.isPOS) { + launch { + orderRepository.fetchOrderById(orderId) + triggerEvent(Exit) + } } else { triggerEvent(PlayChaChing) showPaymentSuccessfulState() @@ -474,11 +480,6 @@ class CardReaderPaymentViewModel } } - private fun CardReaderFlowParam.PaymentOrRefund.isPOS(): Boolean { - return this is CardReaderFlowParam.PaymentOrRefund.Payment && - this.paymentType == CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.WOO_POS - } - @VisibleForTesting fun reFetchOrder() { refetchOrderJob = launch { From 0e35ada75c278b065744b5ebdcf4f3fa1d63ae4f Mon Sep 17 00:00:00 2001 From: Alejo Date: Wed, 7 Aug 2024 10:32:49 -0600 Subject: [PATCH 071/196] refactor sync data result --- .../UpdateAnalyticsDataByRangeSelection.kt | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/background/UpdateAnalyticsDataByRangeSelection.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/background/UpdateAnalyticsDataByRangeSelection.kt index 70a93d51412..4044cca5002 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/background/UpdateAnalyticsDataByRangeSelection.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/background/UpdateAnalyticsDataByRangeSelection.kt @@ -36,15 +36,14 @@ class UpdateAnalyticsDataByRangeSelection @Inject constructor( selectedRange, AnalyticsRepository.FetchStrategy.ForceNew ) - if (result is AnalyticsRepository.RevenueResult.RevenueData) { + val isSuccess = result is AnalyticsRepository.RevenueResult.RevenueData + if (isSuccess) { analyticsUpdateDataStore.storeLastAnalyticsUpdate( selectedRange, AnalyticsUpdateDataStore.AnalyticData.REVENUE ) - true - } else { - false } + isSuccess } } @@ -54,15 +53,14 @@ class UpdateAnalyticsDataByRangeSelection @Inject constructor( selectedRange, AnalyticsRepository.FetchStrategy.ForceNew ) - if (result is AnalyticsRepository.OrdersResult.OrdersData) { + val isSuccess = result is AnalyticsRepository.OrdersResult.OrdersData + if (isSuccess) { analyticsUpdateDataStore.storeLastAnalyticsUpdate( selectedRange, AnalyticsUpdateDataStore.AnalyticData.ORDERS ) - true - } else { - false } + isSuccess } } @@ -72,15 +70,14 @@ class UpdateAnalyticsDataByRangeSelection @Inject constructor( selectedRange, AnalyticsRepository.FetchStrategy.ForceNew ) - if (result is AnalyticsRepository.ProductsResult.ProductsData) { + val isSuccess = result is AnalyticsRepository.ProductsResult.ProductsData + if (isSuccess) { analyticsUpdateDataStore.storeLastAnalyticsUpdate( selectedRange, AnalyticsUpdateDataStore.AnalyticData.TOP_PERFORMERS ) - true - } else { - false } + isSuccess } } From eb68724d9d62240989e3ce2950e6565fb8ee7ff6 Mon Sep 17 00:00:00 2001 From: Spencer Transier Date: Wed, 7 Aug 2024 11:20:41 -0700 Subject: [PATCH 072/196] Update Ruby Gems --- Gemfile.lock | 68 +++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2da0446bb68..f31f3a70516 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -15,26 +15,26 @@ GEM minitest (>= 5.1) mutex_m tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) artifactory (3.0.17) ast (2.4.2) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.942.0) - aws-sdk-core (3.197.0) + aws-partitions (1.962.0) + aws-sdk-core (3.201.3) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.83.0) - aws-sdk-core (~> 3, >= 3.197.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.152.1) - aws-sdk-core (~> 3, >= 3.197.0) + aws-sdk-kms (1.88.0) + aws-sdk-core (~> 3, >= 3.201.0) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.157.0) + aws-sdk-core (~> 3, >= 3.201.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.8) - aws-sigv4 (1.8.0) + aws-sigv4 (~> 1.5) + aws-sigv4 (1.9.1) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) base64 (0.2.0) @@ -55,7 +55,7 @@ GEM connection_pool (2.4.1) cork (0.3.0) colored2 (~> 3.1) - danger (9.4.3) + danger (9.5.0) claide (~> 1.0) claide-plugins (>= 0.9.2) colored2 (~> 3.1) @@ -65,10 +65,9 @@ GEM git (~> 1.13) kramdown (~> 2.3) kramdown-parser-gfm (~> 1.0) - no_proxy_fix octokit (>= 4.0) terminal-table (>= 1, < 4) - danger-dangermattic (1.1.1) + danger-dangermattic (1.1.2) danger (~> 9.4) danger-plugin-api (~> 1.0) danger-rubocop (~> 0.13) @@ -86,7 +85,7 @@ GEM dotenv (2.8.1) drb (2.2.1) emoji_regex (3.2.3) - excon (0.110.0) + excon (0.111.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -110,7 +109,7 @@ GEM faraday-httpclient (1.0.1) faraday-multipart (1.0.4) multipart-post (~> 2) - faraday-net_http (1.0.1) + faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) @@ -118,7 +117,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.3.1) - fastlane (2.220.0) + fastlane (2.222.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -159,7 +158,7 @@ GEM xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) - fastlane-plugin-wpmreleasetoolkit (11.0.2) + fastlane-plugin-wpmreleasetoolkit (11.1.0) activesupport (>= 6.1.7.1) buildkit (~> 1.5) chroma (= 0.2.0) @@ -196,7 +195,7 @@ GEM google-apis-core (>= 0.11.0, < 2.a) google-apis-storage_v1 (0.31.0) google-apis-core (>= 0.11.0, < 2.a) - google-cloud-core (1.7.0) + google-cloud-core (1.7.1) google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) @@ -225,17 +224,17 @@ GEM java-properties (0.3.0) jmespath (1.6.2) json (2.7.2) - jwt (2.8.1) + jwt (2.8.2) base64 kramdown (2.4.0) rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) language_server-protocol (3.17.0.3) - mini_magick (4.12.0) + mini_magick (4.13.2) mini_mime (1.1.5) mini_portile2 (2.8.7) - minitest (5.23.1) + minitest (5.24.1) multi_json (1.15.0) multipart-post (2.4.1) mutex_m (0.2.0) @@ -243,8 +242,7 @@ GEM nap (1.1.0) naturally (2.2.1) nkf (0.2.0) - no_proxy_fix (0.1.2) - nokogiri (1.16.6) + nokogiri (1.16.7) mini_portile2 (~> 2.8.2) racc (~> 1.4) octokit (6.1.1) @@ -255,43 +253,43 @@ GEM optparse (0.5.0) os (1.1.4) parallel (1.25.1) - parser (3.3.0.5) + parser (3.3.4.1) ast (~> 2.4.1) racc plist (3.7.1) progress_bar (1.3.4) highline (>= 1.6) options (~> 2.3.0) - public_suffix (5.0.5) - racc (1.8.0) + public_suffix (6.0.1) + racc (1.8.1) rainbow (3.1.1) rake (13.2.1) rake-compiler (1.2.7) rake rchardet (1.8.0) - regexp_parser (2.9.0) + regexp_parser (2.9.2) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.9) + rexml (3.3.4) strscan rmagick (4.3.0) rouge (2.0.7) - rubocop (1.63.5) + rubocop (1.65.1) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) + regexp_parser (>= 2.4, < 3.0) rexml (>= 3.2.5, < 4.0) rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.31.2) - parser (>= 3.3.0.4) + rubocop-ast (1.32.0) + parser (>= 3.3.1.0) ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) rubyzip (2.3.2) @@ -321,13 +319,13 @@ GEM uber (0.1.0) unicode-display_width (2.5.0) word_wrap (1.0.0) - xcodeproj (1.24.0) + xcodeproj (1.25.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) - rexml (~> 3.2.4) + rexml (>= 3.3.2, < 4.0) xcpretty (0.3.0) rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.1) From 605d2c2757fb7d31af00a7b47ae6bc43e9a80995 Mon Sep 17 00:00:00 2001 From: Alejo Date: Wed, 7 Aug 2024 13:25:01 -0600 Subject: [PATCH 073/196] add shouldAllCardsBePresent param to last update filter --- .../analytics/hub/sync/AnalyticsUpdateDataStore.kt | 14 ++++++++++---- .../ui/dashboard/domain/ObserveLastUpdate.kt | 6 ++++-- .../ui/dashboard/stats/DashboardStatsViewModel.kt | 3 ++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/sync/AnalyticsUpdateDataStore.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/sync/AnalyticsUpdateDataStore.kt index 051e83b0d28..a43507e010a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/sync/AnalyticsUpdateDataStore.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/sync/AnalyticsUpdateDataStore.kt @@ -98,22 +98,28 @@ class AnalyticsUpdateDataStore @Inject constructor( */ fun observeLastUpdate( rangeSelection: StatsTimeRangeSelection, - analyticData: List + analyticData: List, + shouldAllCardsBePresent: Boolean = true ): Flow { val timestampKeys = analyticData.map { data -> getTimeStampKey(rangeSelection.identifier, data) } - return observeLastUpdate(timestampKeys) + return observeLastUpdate(timestampKeys, shouldAllCardsBePresent) } private fun observeLastUpdate( - timestampKeys: List + timestampKeys: List, + shouldAllCardsBePresent: Boolean ): Flow { val flows = timestampKeys.map { timestampKey -> dataStore.data.map { prefs -> prefs[longPreferencesKey(timestampKey)] } } return combine(flows) { lastUpdateMillisArray -> lastUpdateMillisArray.filterNotNull() } - .filter { notNullValues -> notNullValues.size == timestampKeys.size } + .filter { notNullValues -> + if (shouldAllCardsBePresent) { + notNullValues.size == timestampKeys.size + } else true + } .map { lastUpdateValues -> lastUpdateValues.min() } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/domain/ObserveLastUpdate.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/domain/ObserveLastUpdate.kt index dcb45c6c439..7b091e3d924 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/domain/ObserveLastUpdate.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/domain/ObserveLastUpdate.kt @@ -10,11 +10,13 @@ class ObserveLastUpdate @Inject constructor( ) { operator fun invoke( selectedRange: StatsTimeRangeSelection, - analyticDataList: List + analyticDataList: List, + shouldAllCardsBePresent: Boolean = true ): Flow { return analyticsUpdateDataStore.observeLastUpdate( rangeSelection = selectedRange, - analyticData = analyticDataList + analyticData = analyticDataList, + shouldAllCardsBePresent = shouldAllCardsBePresent ) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/stats/DashboardStatsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/stats/DashboardStatsViewModel.kt index 5707febe953..047d02d821e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/stats/DashboardStatsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/stats/DashboardStatsViewModel.kt @@ -261,7 +261,8 @@ class DashboardStatsViewModel @AssistedInject constructor( listOf( AnalyticsUpdateDataStore.AnalyticData.REVENUE, AnalyticsUpdateDataStore.AnalyticData.VISITORS - ) + ), + false ).collect { lastUpdateMillis -> _lastUpdateStats.value = lastUpdateMillis } } } From e63c14fab0856cee91c2d0e0da6a2c17c8d94e12 Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 22:24:37 +0200 Subject: [PATCH 074/196] Ensure InstantTaskExecutorRule is evaluated before VM creation --- .../editing/address/AddressViewModelTest.kt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/editing/address/AddressViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/editing/address/AddressViewModelTest.kt index 684f319280f..305c1fb6da0 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/editing/address/AddressViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/editing/address/AddressViewModelTest.kt @@ -56,12 +56,8 @@ class AddressViewModelTest : BaseUnitTest() { on { getStates(newCountry.code) } doReturn listOf(newState) } - private val addressViewModel = AddressViewModel( - savedStateHandle, - selectedSite, - dataStore, - GetLocations(dataStore) - ) + private lateinit var addressViewModel: AddressViewModel + private val viewStateObserver: Observer = mock() private val shippingAddress = CreateShippingLabelTestUtils.generateAddress().copy( country = testCountry, @@ -70,6 +66,12 @@ class AddressViewModelTest : BaseUnitTest() { @Before fun setup() { + addressViewModel = AddressViewModel( + savedStateHandle, + selectedSite, + dataStore, + GetLocations(dataStore) + ) addressViewModel.viewStateData.liveData.observeForever(viewStateObserver) addressViewModel.shouldEnableDoneButton.observeForever(mock()) } From f366de06c3366515abf14c54f8b718426c9b9f97 Mon Sep 17 00:00:00 2001 From: Alejo Date: Wed, 7 Aug 2024 14:32:33 -0600 Subject: [PATCH 075/196] refactor shouldAllCardsBePresent -> shouldAllDataBePresent --- .../analytics/hub/sync/AnalyticsUpdateDataStore.kt | 12 +++++++----- .../android/ui/dashboard/domain/ObserveLastUpdate.kt | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/sync/AnalyticsUpdateDataStore.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/sync/AnalyticsUpdateDataStore.kt index a43507e010a..dd835112d22 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/sync/AnalyticsUpdateDataStore.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/sync/AnalyticsUpdateDataStore.kt @@ -99,26 +99,28 @@ class AnalyticsUpdateDataStore @Inject constructor( fun observeLastUpdate( rangeSelection: StatsTimeRangeSelection, analyticData: List, - shouldAllCardsBePresent: Boolean = true + shouldAllDataBePresent: Boolean = true ): Flow { val timestampKeys = analyticData.map { data -> getTimeStampKey(rangeSelection.identifier, data) } - return observeLastUpdate(timestampKeys, shouldAllCardsBePresent) + return observeLastUpdate(timestampKeys, shouldAllDataBePresent) } private fun observeLastUpdate( timestampKeys: List, - shouldAllCardsBePresent: Boolean + shouldAllDataBePresent: Boolean ): Flow { val flows = timestampKeys.map { timestampKey -> dataStore.data.map { prefs -> prefs[longPreferencesKey(timestampKey)] } } return combine(flows) { lastUpdateMillisArray -> lastUpdateMillisArray.filterNotNull() } .filter { notNullValues -> - if (shouldAllCardsBePresent) { + if (shouldAllDataBePresent) { notNullValues.size == timestampKeys.size - } else true + } else { + true + } } .map { lastUpdateValues -> lastUpdateValues.min() } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/domain/ObserveLastUpdate.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/domain/ObserveLastUpdate.kt index 7b091e3d924..4b284bbfaa4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/domain/ObserveLastUpdate.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/domain/ObserveLastUpdate.kt @@ -11,12 +11,12 @@ class ObserveLastUpdate @Inject constructor( operator fun invoke( selectedRange: StatsTimeRangeSelection, analyticDataList: List, - shouldAllCardsBePresent: Boolean = true + shouldAllDataBePresent: Boolean = true ): Flow { return analyticsUpdateDataStore.observeLastUpdate( rangeSelection = selectedRange, analyticData = analyticDataList, - shouldAllCardsBePresent = shouldAllCardsBePresent + shouldAllDataBePresent = shouldAllDataBePresent ) } From ac11bc6cb672c52e97edfe51b72ed0b7d9590e19 Mon Sep 17 00:00:00 2001 From: Alejo Date: Wed, 7 Aug 2024 14:32:51 -0600 Subject: [PATCH 076/196] add unit tests --- .../hub/sync/AnalyticsUpdateDataStoreTest.kt | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/hub/sync/AnalyticsUpdateDataStoreTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/hub/sync/AnalyticsUpdateDataStoreTest.kt index 3fe4d9ace4a..0b94fee7ff2 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/hub/sync/AnalyticsUpdateDataStoreTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/hub/sync/AnalyticsUpdateDataStoreTest.kt @@ -3,6 +3,7 @@ package com.woocommerce.android.ui.analytics.hub.sync import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.longPreferencesKey import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.analytics.ranges.StatsTimeRangeSelection.SelectionType import com.woocommerce.android.ui.analytics.ranges.StatsTimeRangeSelection.SelectionType.LAST_MONTH @@ -172,6 +173,127 @@ class AnalyticsUpdateDataStoreTest : BaseUnitTest() { assertThat(timestampUpdate).isEqualTo(2000) } + @Test + fun `given observe should emit last update for all data sources, when a data source is missing then return null`() = testBlocking { + // Given + val selectedSiteId = 1 + val lastUpdateTimestamp = 2000L + val rangeId = defaultSelectionData.selectionType.identifier + val presentKey = + "${selectedSiteId}${AnalyticsUpdateDataStore.AnalyticData.REVENUE}$rangeId" + + val analyticsPreferences = mock { + on { get(longPreferencesKey(presentKey)) } doReturn lastUpdateTimestamp + } + + createAnalyticsUpdateScenarioWith(analyticsPreferences, selectedSiteId) + + // When + var timestampUpdate: Long? = null + sut.observeLastUpdate( + rangeSelection = defaultSelectionData, + analyticData = listOf( + AnalyticsUpdateDataStore.AnalyticData.REVENUE, + AnalyticsUpdateDataStore.AnalyticData.VISITORS + ) + ).onEach { + timestampUpdate = it + }.launchIn(this) + + // Then + assertThat(timestampUpdate).isNull() + } + + @Test + fun `given observe should emit last update for all data sources, when all data source are present then return the oldest timestamp`() = testBlocking { + // Given + val selectedSiteId = 1 + val oldLastUpdateTimestamp = 2000L + val newLastUpdateTimestamp = 2500L + val rangeId = defaultSelectionData.selectionType.identifier + val keyRevenue = + "${selectedSiteId}${AnalyticsUpdateDataStore.AnalyticData.REVENUE}$rangeId" + val keyVisitors = + "${selectedSiteId}${AnalyticsUpdateDataStore.AnalyticData.VISITORS}$rangeId" + + val analyticsPreferences = mock { + on { get(longPreferencesKey(keyRevenue)) } doReturn newLastUpdateTimestamp + on { get(longPreferencesKey(keyVisitors)) } doReturn oldLastUpdateTimestamp + } + + createAnalyticsUpdateScenarioWith(analyticsPreferences, selectedSiteId) + + // When + var timestampUpdate: Long? = null + sut.observeLastUpdate( + rangeSelection = defaultSelectionData, + analyticData = listOf( + AnalyticsUpdateDataStore.AnalyticData.REVENUE, + AnalyticsUpdateDataStore.AnalyticData.VISITORS + ) + ).onEach { + timestampUpdate = it + }.launchIn(this) + + // Then + assertThat(timestampUpdate).isNotNull() + assertThat(timestampUpdate).isEqualTo(oldLastUpdateTimestamp) + } + + @Test + fun `given observe should emit last update, when all data sources are not required, if a data source is missing then return the available last update`() = testBlocking { + // Given + val selectedSiteId = 1 + val lastUpdateTimestamp = 2000L + val rangeId = defaultSelectionData.selectionType.identifier + val presentKey = + "${selectedSiteId}${AnalyticsUpdateDataStore.AnalyticData.REVENUE}$rangeId" + + val analyticsPreferences = mock { + on { get(longPreferencesKey(presentKey)) } doReturn lastUpdateTimestamp + } + + createAnalyticsUpdateScenarioWith(analyticsPreferences, selectedSiteId) + + // When + var timestampUpdate: Long? = null + sut.observeLastUpdate( + rangeSelection = defaultSelectionData, + analyticData = listOf( + AnalyticsUpdateDataStore.AnalyticData.REVENUE, + AnalyticsUpdateDataStore.AnalyticData.VISITORS + ), + shouldAllDataBePresent = false + ).onEach { + timestampUpdate = it + }.launchIn(this) + + // Then + assertThat(timestampUpdate).isNotNull() + assertThat(timestampUpdate).isEqualTo(lastUpdateTimestamp) + } + + private fun createAnalyticsUpdateScenarioWith( + analyticsPreferences: Preferences, + selectedSiteId: Int + ) { + dataStore = mock { + on { data } doReturn flowOf(analyticsPreferences) + } + + currentTimeProvider = mock() + + val selectedSite: SelectedSite = mock { + on { getSelectedSiteId() } doReturn selectedSiteId + } + + sut = AnalyticsUpdateDataStore( + dataStore = dataStore, + currentTimeProvider = currentTimeProvider, + selectedSite = selectedSite + ) + } + private fun createAnalyticsUpdateScenarioWith( lastUpdateTimestamp: Long?, currentTimestamp: Long From e51bb4141cf0493a0a589c4b4056db437ceff368 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 7 Aug 2024 17:38:05 -0300 Subject: [PATCH 077/196] Adjust analytics_call_to_action_view.xml margins --- .../src/main/res/layout/analytics_call_to_action_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/res/layout/analytics_call_to_action_view.xml b/WooCommerce/src/main/res/layout/analytics_call_to_action_view.xml index 09a5fbc704a..89ab4013827 100644 --- a/WooCommerce/src/main/res/layout/analytics_call_to_action_view.xml +++ b/WooCommerce/src/main/res/layout/analytics_call_to_action_view.xml @@ -9,7 +9,7 @@ android:id="@+id/analyticsCallToActionCard" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_margin="@dimen/major_75" + android:layout_marginTop="@dimen/major_75" android:orientation="vertical"> Date: Wed, 7 Aug 2024 17:41:25 -0300 Subject: [PATCH 078/196] Remove CTA from AnalyticsHub main view --- .../android/ui/analytics/hub/AnalyticsHubFragment.kt | 1 - .../android/ui/analytics/hub/AnalyticsHubViewModel.kt | 5 +---- .../android/ui/analytics/hub/AnalyticsHubViewState.kt | 1 - WooCommerce/src/main/res/layout/fragment_analytics.xml | 9 --------- 4 files changed, 1 insertion(+), 15 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubFragment.kt index 46cda4682fb..b5d8451394c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubFragment.kt @@ -162,7 +162,6 @@ class AnalyticsHubFragment : BaseFragment(R.layout.fragment_analytics) { binding.analyticsDateSelectorCard.updatePreviousRange(viewState.analyticsDateRangeSelectorState.previousRange) binding.analyticsDateSelectorCard.updateCurrentRange(viewState.analyticsDateRangeSelectorState.currentRange) binding.analyticsDateSelectorCard.updateLastUpdateTimestamp(viewState.lastUpdateTimestamp) - binding.analyticsCallToActionCard.updateInformation(viewState.ctaState) binding.analyticsRefreshLayout.isRefreshing = viewState.refreshIndicator == ShowIndicator displayFeedbackBanner(viewState.showFeedBackBanner) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt index b64f354a36a..3e3eda3fced 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt @@ -118,7 +118,6 @@ class AnalyticsHubViewModel @Inject constructor( refreshIndicator = NotShowIndicator, analyticsDateRangeSelectorState = AnalyticsHubDateRangeSelectorViewState.EMPTY, cards = AnalyticsHubCardViewState.LoadingCardsConfiguration, - ctaState = AnalyticsHubUserCallToActionViewState.EMPTY, showFeedBackBanner = false, lastUpdateTimestamp = "" ) @@ -830,9 +829,7 @@ class AnalyticsHubViewModel @Inject constructor( callToActionText = resourceProvider.getString(R.string.analytics_google_ads_cta_action), isVisible = isVisible, onCallToActionClickListener = { onGoogleAdsCTAClicked() } - ).let { newState -> - mutableState.update { it.copy(ctaState = newState) } - } + ) if (isVisible) { tracker.track( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewState.kt index 3a48da178c5..6c42bc19c4f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewState.kt @@ -7,7 +7,6 @@ data class AnalyticsViewState( val refreshIndicator: RefreshIndicator, val analyticsDateRangeSelectorState: AnalyticsHubDateRangeSelectorViewState, val cards: AnalyticsHubCardViewState, - val ctaState: AnalyticsHubUserCallToActionViewState, val showFeedBackBanner: Boolean, val lastUpdateTimestamp: String ) diff --git a/WooCommerce/src/main/res/layout/fragment_analytics.xml b/WooCommerce/src/main/res/layout/fragment_analytics.xml index cf01e402aca..edaaca58333 100644 --- a/WooCommerce/src/main/res/layout/fragment_analytics.xml +++ b/WooCommerce/src/main/res/layout/fragment_analytics.xml @@ -50,15 +50,6 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/divider" /> - - Date: Wed, 7 Aug 2024 17:47:27 -0300 Subject: [PATCH 079/196] Update AnalyticsHubCustomSelectionCardView states to work with the CTA visibility --- .../ui/analytics/hub/AnalyticsHubCardState.kt | 9 ++++- .../ui/analytics/hub/AnalyticsHubViewModel.kt | 40 ++++++++----------- .../AnalyticsHubCustomSelectionCardView.kt | 4 +- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubCardState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubCardState.kt index fa1783068cd..c6ee4ff4d59 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubCardState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubCardState.kt @@ -85,8 +85,13 @@ sealed class AnalyticsHubCustomSelectionListViewState : AnalyticsCardViewState { } } - data class HiddenState( - override val card: AnalyticsCards + data class ShowCTAState( + override val card: AnalyticsCards, + val title: String, + val description: String, + val callToActionText: String, + val isVisible: Boolean, + val onCallToActionClickListener: () -> Unit ) : AnalyticsHubCustomSelectionListViewState() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt index 3e3eda3fced..2d59bd8948b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt @@ -28,7 +28,7 @@ import com.woocommerce.android.model.SessionStat import com.woocommerce.android.model.StatType import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.CustomListViewState -import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.HiddenState +import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.ShowCTAState import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.LoadingAdsViewState import com.woocommerce.android.ui.analytics.hub.AnalyticsHubInformationViewState.DataViewState import com.woocommerce.android.ui.analytics.hub.AnalyticsHubInformationViewState.LoadingViewState @@ -485,16 +485,27 @@ class AnalyticsHubViewModel @Inject constructor( private fun observeGoogleAdsChanges() { googleAdsObservationJob = updateStats.googleAdsState.onEach { state -> - updateGoogleAdsCTAVisibility(isVisible = false) - when (state) { is GoogleAdsState.Available -> { updateCardStatus(AnalyticsCards.GoogleAds, buildGoogleAdsDataViewState(state.googleAdsStat)) } is GoogleAdsState.Empty -> { - updateGoogleAdsCTAVisibility(isVisible = true) - updateCardStatus(AnalyticsCards.GoogleAds, HiddenState(AnalyticsCards.GoogleAds)) + tracker.track( + stat = AnalyticsEvent.GOOGLEADS_ENTRY_POINT_DISPLAYED, + properties = mapOf( + KEY_GOOGLEADS_SOURCE to VALUE_GOOGLEADS_ENTRY_POINT_TYPE_ANALYTICS_HUB + ) + ) + val ctaState = ShowCTAState( + card = AnalyticsCards.GoogleAds, + title = resourceProvider.getString(R.string.analytics_google_ads_cta_title), + description = resourceProvider.getString(R.string.analytics_google_ads_cta_description), + callToActionText = resourceProvider.getString(R.string.analytics_google_ads_cta_action), + isVisible = true, + onCallToActionClickListener = { onGoogleAdsCTAClicked() } + ) + updateCardStatus(AnalyticsCards.GoogleAds, ctaState) } is GoogleAdsState.Error -> { @@ -822,25 +833,6 @@ class AnalyticsHubViewModel @Inject constructor( giftCardsObservationJob?.cancel() } - private fun updateGoogleAdsCTAVisibility(isVisible: Boolean) { - AnalyticsHubUserCallToActionViewState( - title = resourceProvider.getString(R.string.analytics_google_ads_cta_title), - description = resourceProvider.getString(R.string.analytics_google_ads_cta_description), - callToActionText = resourceProvider.getString(R.string.analytics_google_ads_cta_action), - isVisible = isVisible, - onCallToActionClickListener = { onGoogleAdsCTAClicked() } - ) - - if (isVisible) { - tracker.track( - stat = AnalyticsEvent.GOOGLEADS_ENTRY_POINT_DISPLAYED, - properties = mapOf( - KEY_GOOGLEADS_SOURCE to VALUE_GOOGLEADS_ENTRY_POINT_TYPE_ANALYTICS_HUB - ) - ) - } - } - private fun onGoogleAdsCTAClicked() { selectedSite.getOrNull()?.let { it.adminUrlOrDefault + GOOGLE_ADMIN_CAMPAIGN_CREATION_SUFFIX diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/customlistcard/AnalyticsHubCustomSelectionCardView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/customlistcard/AnalyticsHubCustomSelectionCardView.kt index e563419f94c..2a2e0f736be 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/customlistcard/AnalyticsHubCustomSelectionCardView.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/customlistcard/AnalyticsHubCustomSelectionCardView.kt @@ -13,7 +13,7 @@ import com.woocommerce.android.R import com.woocommerce.android.databinding.AnalyticsCustomSelectionCardViewBinding import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.CustomListViewState -import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.HiddenState +import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.ShowCTAState import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.LoadingAdsViewState import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.NoAdsState import com.woocommerce.android.ui.analytics.hub.informationcard.SeeReportClickListener @@ -37,7 +37,7 @@ class AnalyticsHubCustomSelectionCardView @JvmOverloads constructor( is LoadingAdsViewState -> setSkeleton() is NoAdsState -> setNoAdsViewState(viewState) is CustomListViewState -> setDataViewState(viewState) - is HiddenState -> setHiddenState() + is ShowCTAState -> setHiddenState() } } From d062a86f89298532aadcf0baf2d9a8c73cfc041f Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 7 Aug 2024 18:01:27 -0300 Subject: [PATCH 080/196] Introduce the AnalyticsHubCustomSelectionCardView to analytics_custom_selection_card_view.xml --- .../res/layout/analytics_custom_selection_card_view.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/WooCommerce/src/main/res/layout/analytics_custom_selection_card_view.xml b/WooCommerce/src/main/res/layout/analytics_custom_selection_card_view.xml index 1addd6c5bd2..87e4df11cab 100644 --- a/WooCommerce/src/main/res/layout/analytics_custom_selection_card_view.xml +++ b/WooCommerce/src/main/res/layout/analytics_custom_selection_card_view.xml @@ -6,6 +6,12 @@ android:layout_height="wrap_content" tools:context=".ui.analytics.hub.customlistcard.AnalyticsHubCustomSelectionCardView"> + + Date: Wed, 7 Aug 2024 18:01:46 -0300 Subject: [PATCH 081/196] Handle CTAState inside the AnalyticsHubCustomSelectionCardView --- .../android/ui/analytics/hub/AnalyticsHubCardState.kt | 11 ++++++++++- .../AnalyticsHubCustomSelectionCardView.kt | 9 +++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubCardState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubCardState.kt index c6ee4ff4d59..57361a584ac 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubCardState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubCardState.kt @@ -92,7 +92,16 @@ sealed class AnalyticsHubCustomSelectionListViewState : AnalyticsCardViewState { val callToActionText: String, val isVisible: Boolean, val onCallToActionClickListener: () -> Unit - ) : AnalyticsHubCustomSelectionListViewState() + ) : AnalyticsHubCustomSelectionListViewState() { + val asAnalyticsHubUserCallToActionViewState + get() = AnalyticsHubUserCallToActionViewState( + title = title, + description = description, + callToActionText = callToActionText, + isVisible = isVisible, + onCallToActionClickListener = onCallToActionClickListener + ) + } } data class AnalyticsHubUserCallToActionViewState( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/customlistcard/AnalyticsHubCustomSelectionCardView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/customlistcard/AnalyticsHubCustomSelectionCardView.kt index 2a2e0f736be..848b3774e4e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/customlistcard/AnalyticsHubCustomSelectionCardView.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/customlistcard/AnalyticsHubCustomSelectionCardView.kt @@ -37,13 +37,15 @@ class AnalyticsHubCustomSelectionCardView @JvmOverloads constructor( is LoadingAdsViewState -> setSkeleton() is NoAdsState -> setNoAdsViewState(viewState) is CustomListViewState -> setDataViewState(viewState) - is ShowCTAState -> setHiddenState() + is ShowCTAState -> setCtaState(viewState) } } - private fun setHiddenState() { + private fun setCtaState(state: ShowCTAState) { skeletonView.hide() binding.analyticsCustomCardListContainer.visibility = GONE + binding.analyticsCallToActionCard.visibility = VISIBLE + binding.analyticsCallToActionCard.updateInformation(state.asAnalyticsHubUserCallToActionViewState) } private fun setDataViewState(viewState: CustomListViewState) { @@ -78,6 +80,7 @@ class AnalyticsHubCustomSelectionCardView @JvmOverloads constructor( binding.analyticsListLeftHeader.visibility = VISIBLE binding.analyticsListRightHeader.visibility = VISIBLE binding.noDataText.visibility = GONE + binding.analyticsCallToActionCard.visibility = GONE viewState.reportUrl?.let { binding.reportGroup.visibility = VISIBLE @@ -121,6 +124,7 @@ class AnalyticsHubCustomSelectionCardView @JvmOverloads constructor( binding.analyticsListRightHeader.visibility = GONE binding.analyticsItemsTag.visibility = GONE binding.analyticsFilterButton.visibility = GONE + binding.analyticsCallToActionCard.visibility = GONE binding.noDataText.visibility = VISIBLE binding.noDataText.text = viewState.message } @@ -140,6 +144,7 @@ class AnalyticsHubCustomSelectionCardView @JvmOverloads constructor( binding.analyticsItemsTag.visibility = GONE binding.noDataText.visibility = GONE binding.analyticsFilterButton.visibility = GONE + binding.analyticsCallToActionCard.visibility = GONE } private fun getDeltaTagText(viewState: CustomListViewState) = From fdf5f9471455bd3b120bbbf04d705a39c832178a Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 7 Aug 2024 18:08:34 -0300 Subject: [PATCH 082/196] Fix incorrect constraints in fragment_analytics.xml --- WooCommerce/src/main/res/layout/fragment_analytics.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/res/layout/fragment_analytics.xml b/WooCommerce/src/main/res/layout/fragment_analytics.xml index edaaca58333..09b8f3aaca2 100644 --- a/WooCommerce/src/main/res/layout/fragment_analytics.xml +++ b/WooCommerce/src/main/res/layout/fragment_analytics.xml @@ -57,7 +57,7 @@ android:layout_marginTop="@dimen/major_100" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/analyticsCallToActionCard" /> + app:layout_constraintTop_toBottomOf="@+id/analyticsDateSelectorCard" /> From 2b54be0a38645f79e0db41066d5eee3416cea265 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 7 Aug 2024 18:13:19 -0300 Subject: [PATCH 083/196] Update CTA margins in analytics_custom_selection_card_view.xml --- .../src/main/res/layout/analytics_call_to_action_view.xml | 2 +- .../main/res/layout/analytics_custom_selection_card_view.xml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/res/layout/analytics_call_to_action_view.xml b/WooCommerce/src/main/res/layout/analytics_call_to_action_view.xml index 89ab4013827..87c6bb01364 100644 --- a/WooCommerce/src/main/res/layout/analytics_call_to_action_view.xml +++ b/WooCommerce/src/main/res/layout/analytics_call_to_action_view.xml @@ -9,7 +9,7 @@ android:id="@+id/analyticsCallToActionCard" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/major_75" + android:layout_marginVertical="@dimen/major_75" android:orientation="vertical"> + android:layout_height="wrap_content" /> Date: Wed, 7 Aug 2024 18:15:39 -0300 Subject: [PATCH 084/196] Fix lint issues --- .../android/ui/analytics/hub/AnalyticsHubViewModel.kt | 2 +- .../hub/customlistcard/AnalyticsHubCustomSelectionCardView.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt index 2d59bd8948b..7f18b1f9f49 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt @@ -28,8 +28,8 @@ import com.woocommerce.android.model.SessionStat import com.woocommerce.android.model.StatType import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.CustomListViewState -import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.ShowCTAState import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.LoadingAdsViewState +import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.ShowCTAState import com.woocommerce.android.ui.analytics.hub.AnalyticsHubInformationViewState.DataViewState import com.woocommerce.android.ui.analytics.hub.AnalyticsHubInformationViewState.LoadingViewState import com.woocommerce.android.ui.analytics.hub.AnalyticsHubInformationViewState.NoDataState diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/customlistcard/AnalyticsHubCustomSelectionCardView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/customlistcard/AnalyticsHubCustomSelectionCardView.kt index 848b3774e4e..e3a7786f695 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/customlistcard/AnalyticsHubCustomSelectionCardView.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/customlistcard/AnalyticsHubCustomSelectionCardView.kt @@ -13,9 +13,9 @@ import com.woocommerce.android.R import com.woocommerce.android.databinding.AnalyticsCustomSelectionCardViewBinding import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.CustomListViewState -import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.ShowCTAState import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.LoadingAdsViewState import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.NoAdsState +import com.woocommerce.android.ui.analytics.hub.AnalyticsHubCustomSelectionListViewState.ShowCTAState import com.woocommerce.android.ui.analytics.hub.informationcard.SeeReportClickListener import com.woocommerce.android.ui.analytics.hub.listcard.AnalyticsHubListAdapter import com.woocommerce.android.ui.analytics.hub.listcard.AnalyticsHubListCardView From b300df22e3d8a8faafd7a7a9b3632e2fae5c2c0e Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 7 Aug 2024 18:18:52 -0300 Subject: [PATCH 085/196] Refactor GoogleAds CTA state creation --- .../ui/analytics/hub/AnalyticsHubViewModel.kt | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt index 7f18b1f9f49..c905effc0bf 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt @@ -497,15 +497,7 @@ class AnalyticsHubViewModel @Inject constructor( KEY_GOOGLEADS_SOURCE to VALUE_GOOGLEADS_ENTRY_POINT_TYPE_ANALYTICS_HUB ) ) - val ctaState = ShowCTAState( - card = AnalyticsCards.GoogleAds, - title = resourceProvider.getString(R.string.analytics_google_ads_cta_title), - description = resourceProvider.getString(R.string.analytics_google_ads_cta_description), - callToActionText = resourceProvider.getString(R.string.analytics_google_ads_cta_action), - isVisible = true, - onCallToActionClickListener = { onGoogleAdsCTAClicked() } - ) - updateCardStatus(AnalyticsCards.GoogleAds, ctaState) + updateCardStatus(AnalyticsCards.GoogleAds, buildGoogleAdsCTAViewState()) } is GoogleAdsState.Error -> { @@ -752,6 +744,17 @@ class AnalyticsHubViewModel @Inject constructor( ) } + private fun buildGoogleAdsCTAViewState(): ShowCTAState { + return ShowCTAState( + card = AnalyticsCards.GoogleAds, + title = resourceProvider.getString(R.string.analytics_google_ads_cta_title), + description = resourceProvider.getString(R.string.analytics_google_ads_cta_description), + callToActionText = resourceProvider.getString(R.string.analytics_google_ads_cta_action), + isVisible = true, + onCallToActionClickListener = { onGoogleAdsCTAClicked() } + ) + } + private fun onGoogleCampaignFilterSelected( googleAdsStats: GoogleAdsStat, selectedFilterName: String From 18bb28150eeef513c8b97aa7058876025348c7c1 Mon Sep 17 00:00:00 2001 From: malinajirka Date: Wed, 7 Aug 2024 23:25:36 +0200 Subject: [PATCH 086/196] Fix unit tests after TTP min OS version update --- .../taptopay/TapToPayAvailabilityStatusTest.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/taptopay/TapToPayAvailabilityStatusTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/taptopay/TapToPayAvailabilityStatusTest.kt index 067f4d23a5d..e564abf575f 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/taptopay/TapToPayAvailabilityStatusTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/taptopay/TapToPayAvailabilityStatusTest.kt @@ -16,7 +16,7 @@ import org.wordpress.android.fluxc.store.WooCommerceStore class TapToPayAvailabilityStatusTest { private val systemVersionUtilsWrapper = mock { - on { isAtLeastQ() }.thenReturn(true) + on { isAtLeastR() }.thenReturn(true) } private val cardReaderCountryConfigProvider: CardReaderCountryConfigProvider = mock { on { provideCountryConfigFor("US") }.thenReturn(CardReaderConfigForUSA) @@ -45,7 +45,7 @@ class TapToPayAvailabilityStatusTest { fun `given device has no NFC, when invoking, then nfc disabled returned`() { whenever(deviceFeatures.isNFCAvailable()).thenReturn(false) whenever(deviceFeatures.isGooglePlayServicesAvailable()).thenReturn(true) - whenever(systemVersionUtilsWrapper.isAtLeastQ()).thenReturn(true) + whenever(systemVersionUtilsWrapper.isAtLeastR()).thenReturn(true) val result = availabilityStatus.invoke() @@ -56,7 +56,7 @@ class TapToPayAvailabilityStatusTest { fun `given device has no Google Play Services, when invoking, then GPS not available`() { whenever(deviceFeatures.isNFCAvailable()).thenReturn(true) whenever(deviceFeatures.isGooglePlayServicesAvailable()).thenReturn(false) - whenever(systemVersionUtilsWrapper.isAtLeastQ()).thenReturn(true) + whenever(systemVersionUtilsWrapper.isAtLeastR()).thenReturn(true) val result = availabilityStatus.invoke() @@ -78,7 +78,7 @@ class TapToPayAvailabilityStatusTest { fun `given country other than US, when invoking, then country is not supported returned`() { whenever(deviceFeatures.isNFCAvailable()).thenReturn(true) whenever(deviceFeatures.isGooglePlayServicesAvailable()).thenReturn(true) - whenever(systemVersionUtilsWrapper.isAtLeastQ()).thenReturn(true) + whenever(systemVersionUtilsWrapper.isAtLeastR()).thenReturn(true) whenever(wooStore.getStoreCountryCode(siteModel)).thenReturn("RU") val result = availabilityStatus.invoke() @@ -90,7 +90,7 @@ class TapToPayAvailabilityStatusTest { fun `given device satisfies all the requirements, when invoking, then tpp available returned`() { whenever(deviceFeatures.isNFCAvailable()).thenReturn(true) whenever(deviceFeatures.isGooglePlayServicesAvailable()).thenReturn(true) - whenever(systemVersionUtilsWrapper.isAtLeastQ()).thenReturn(true) + whenever(systemVersionUtilsWrapper.isAtLeastR()).thenReturn(true) val result = availabilityStatus.invoke() From bd7ff16dce52e78f9643adcf3efab0d8f04be5e4 Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Thu, 8 Aug 2024 09:46:34 +0530 Subject: [PATCH 087/196] Fix pagination when pull to refreshed on products screen --- .../android/ui/woopos/home/products/WooPosProductsScreen.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt index cd635efd947..d41dcb0f513 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt @@ -205,6 +205,7 @@ private fun ProductsToolbar( } } } + else -> { // no op } @@ -269,7 +270,7 @@ private fun ProductsList( Spacer(modifier = Modifier.height(104.dp)) } } - InfiniteListHandler(listState) { + InfiniteListHandler(listState, state) { onEndOfProductsListReached() } } @@ -447,6 +448,7 @@ fun ProductsError(onRetryClicked: () -> Unit) { @Composable private fun InfiniteListHandler( listState: LazyListState, + state: WooPosProductsViewState.Content, onEndOfProductsListReached: () -> Unit ) { val buffer = 5 @@ -460,7 +462,7 @@ private fun InfiniteListHandler( } } - LaunchedEffect(loadMore) { + LaunchedEffect(state.reloadingProductsWithPullToRefresh) { snapshotFlow { loadMore.value } .distinctUntilChanged() .filter { it } From 719e688d8fbf194c34d97291ad9dda2a224b6685 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Thu, 8 Aug 2024 09:40:39 +0200 Subject: [PATCH 088/196] Fix detekt's complaints --- .../payments/cardreader/payment/CardReaderPaymentViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt index 854b829715f..eca9b2789c5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt @@ -148,7 +148,7 @@ class CardReaderPaymentViewModel private val CardReaderFlowParam.PaymentOrRefund.isPOS: Boolean get() = this is CardReaderFlowParam.PaymentOrRefund.Payment && - this.paymentType == CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.WOO_POS + this.paymentType == CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.WOO_POS fun start() { if (cardReaderManager.readerStatus.value is CardReaderStatus.Connected) { From 792fce41eae044e93d543f3796e0d6f4df26e471 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 8 Aug 2024 10:22:11 +0200 Subject: [PATCH 089/196] Changed size of the check mark --- .../totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt index e2aeb5e679f..4e486fa669f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt @@ -167,7 +167,7 @@ private fun CheckMarkIcon( modifier: Modifier = Modifier, ) { val size by animateDpAsState( - targetValue = if (animationStarted) 156.dp else 0.dp, + targetValue = if (animationStarted) 164.dp else 0.dp, label = "Check mark size" ) From ab16fefc7a97b0d9583507de4f679268d207d18a Mon Sep 17 00:00:00 2001 From: samiuelson Date: Thu, 8 Aug 2024 12:29:35 +0200 Subject: [PATCH 090/196] Clean up the code --- .../cardreader/payment/CardReaderPaymentViewModel.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt index eca9b2789c5..617c78d01a3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/CardReaderPaymentViewModel.kt @@ -470,7 +470,7 @@ class CardReaderPaymentViewModel appPrefs.setCardReaderSuccessfulPaymentTime() if (arguments.paymentOrRefund.isPOS) { launch { - orderRepository.fetchOrderById(orderId) + syncOrderStatus(orderId) triggerEvent(Exit) } } else { @@ -480,6 +480,10 @@ class CardReaderPaymentViewModel } } + private suspend fun syncOrderStatus(orderId: Long) { + orderRepository.fetchOrderById(orderId) + } + @VisibleForTesting fun reFetchOrder() { refetchOrderJob = launch { From 3795ca614fb9e5e076d00c2cdc827c04159ed2d2 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Thu, 8 Aug 2024 14:40:52 +0300 Subject: [PATCH 091/196] Add names to call arguments of ProductRefundListItem --- .../ui/payments/refunds/IssueRefundViewModel.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/IssueRefundViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/IssueRefundViewModel.kt index 3ead2becf0d..ee3fdc5d19c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/IssueRefundViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/IssueRefundViewModel.kt @@ -287,11 +287,11 @@ class IssueRefundViewModel @Inject constructor( val maxQuantity = maxQuantities[it.itemId] ?: 0f val selectedQuantity = min(selectedQuantities[it.itemId] ?: 0, maxQuantity.toInt()) ProductRefundListItem( - it, - maxQuantity, - selectedQuantity, - formatCurrency(BigDecimal.ZERO), - formatCurrency(BigDecimal.ZERO) + orderItem = it, + maxQuantity = maxQuantity, + quantity = selectedQuantity, + subtotal = formatCurrency(BigDecimal.ZERO), + taxes = formatCurrency(BigDecimal.ZERO) ) } updateRefundItems(items) From d5ba73732401fe0a924f034767939743da5eb1c7 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Thu, 8 Aug 2024 15:04:22 +0300 Subject: [PATCH 092/196] Split ProductRefundListItem.calculateTotal() into two functions --- .../woocommerce/android/extensions/RefundsExt.kt | 16 +++++++++------- .../ui/payments/refunds/IssueRefundViewModel.kt | 8 +++++--- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/RefundsExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/RefundsExt.kt index 66d4696947d..f7a32524773 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/RefundsExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/RefundsExt.kt @@ -8,18 +8,20 @@ fun List.calculateTotals(): Pair var taxes = BigDecimal.ZERO var subtotal = BigDecimal.ZERO this.forEach { item -> - val (itemSubtotal, itemTaxes) = item.calculateTotal() - subtotal += itemSubtotal - taxes += itemTaxes + subtotal += item.calculateTotalSubtotal() + taxes += item.calculateTotalTaxes() } return Pair(subtotal, taxes) } -fun ProductRefundListItem.calculateTotal(): Pair { +fun ProductRefundListItem.calculateTotalSubtotal(): BigDecimal { + val quantity = quantity.toBigDecimal() + return quantity.times(orderItem.price) +} + +fun ProductRefundListItem.calculateTotalTaxes(): BigDecimal { val quantity = quantity.toBigDecimal() - val subtotal = quantity.times(orderItem.price) val singleItemTax = orderItem.totalTax.divide(orderItem.quantity.toBigDecimal(), 2, HALF_UP) - val taxes = quantity.times(singleItemTax) - return Pair(subtotal, taxes) + return quantity.times(singleItemTax) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/IssueRefundViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/IssueRefundViewModel.kt index ee3fdc5d19c..9f0be15d165 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/IssueRefundViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/refunds/IssueRefundViewModel.kt @@ -18,7 +18,8 @@ import com.woocommerce.android.analytics.AnalyticsEvent.REFUND_CREATE_SUCCESS import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.extensions.adminUrlOrDefault -import com.woocommerce.android.extensions.calculateTotal +import com.woocommerce.android.extensions.calculateTotalSubtotal +import com.woocommerce.android.extensions.calculateTotalTaxes import com.woocommerce.android.extensions.calculateTotals import com.woocommerce.android.extensions.isCashPayment import com.woocommerce.android.extensions.isEqualTo @@ -660,8 +661,9 @@ class IssueRefundViewModel @Inject constructor( var newItem = it.copy(quantity = newQuantity, maxQuantity = maxQuantities[uniqueId] ?: 0f) // Update the subtotal and taxes based on the new quantity - val (subtotal, taxes) = newItem.calculateTotal() - newItem = newItem.copy(subtotal = formatCurrency(subtotal), taxes = formatCurrency(taxes)) + val subtotal = formatCurrency(newItem.calculateTotalSubtotal()) + val taxes = formatCurrency(newItem.calculateTotalTaxes()) + newItem = newItem.copy(subtotal = subtotal, taxes = taxes) newItems.add(newItem) } else { From d723cf6d18c681c6ecf7478a4964043b4a6ef4dc Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 8 Aug 2024 10:57:39 -0300 Subject: [PATCH 093/196] Add Sentry config to the Wear module --- WooCommerce-Wear/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index 42da8d5881a..ea556ed45ff 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -4,6 +4,7 @@ plugins { id 'org.jetbrains.kotlin.plugin.parcelize' id 'com.google.dagger.hilt.android' id 'com.google.devtools.ksp' + id 'io.sentry.android.gradle' } repositories { @@ -14,6 +15,8 @@ repositories { includeGroup "org.wordpress.fluxc" includeGroup "org.wordpress.fluxc.plugins" includeGroup "org.wordpress.wellsql" + includeGroup "com.automattic" + includeGroup "com.automattic.tracks" } } mavenCentral() @@ -113,6 +116,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" // WearOS implementation "com.google.android.gms:play-services-wearable:$googlePlayWearableVersion" From d544b8a0f52fec050fe51e85e949540ae9118fea Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 8 Aug 2024 10:58:20 -0300 Subject: [PATCH 094/196] Apply gradle config options to Sentry in the Wear module --- WooCommerce-Wear/build.gradle | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index ea556ed45ff..36487a44c3b 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -1,3 +1,5 @@ +import io.sentry.android.gradle.extensions.InstrumentationFeature + plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' @@ -28,6 +30,34 @@ repositories { } } +sentry { + includeSourceContext = true + autoUploadSourceContext = true + tracingInstrumentation { + enabled = true + features = [InstrumentationFeature.DATABASE] + logcat { + enabled = false + } + } + autoInstallation { + enabled = false + } + includeDependenciesReport = false + /* Sentry won't send source context or add performance instrumentations for debug builds + so we can save build times. Sending events will still work in debug builds + (if enabled in WCCrashLoggingDataProvider). + */ + ignoredBuildTypes = ["debug"] + + /* Additional source directories to be included in the source context. For now, manually: + https://github.com/getsentry/sentry-android-gradle-plugin/issues/685 + */ + additionalSourceDirsForSourceContext = [ + '../libs/cardreader/src/main/java', + ] +} + def versionProperties = loadPropertiesFromFile(file("${rootDir}/version.properties")) def versionCodeDifferenceBetweenAppAndWear = 50000 From f6f0a4f864a21e46128d8a1bf0240e5b85ec5e94 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 8 Aug 2024 11:21:00 -0300 Subject: [PATCH 095/196] Remove Sentry from the commons Library --- libs/commons/build.gradle | 47 ------------------ .../WCCrashLoggingDataProvider.kt | 48 ------------------- 2 files changed, 95 deletions(-) delete mode 100644 libs/commons/src/main/java/com/woocommerce/commons/crashlogging/WCCrashLoggingDataProvider.kt diff --git a/libs/commons/build.gradle b/libs/commons/build.gradle index a0247629eeb..b52e2241fd6 100644 --- a/libs/commons/build.gradle +++ b/libs/commons/build.gradle @@ -1,47 +1,6 @@ -import io.sentry.android.gradle.extensions.InstrumentationFeature - plugins { id 'com.android.library' id 'org.jetbrains.kotlin.android' - id 'io.sentry.android.gradle' -} - -repositories { - maven { - url 'https://a8c-libs.s3.amazonaws.com/android' - content { - includeGroup "com.automattic" - includeGroup "com.automattic.tracks" - } - } -} - -sentry { - includeSourceContext = true - autoUploadSourceContext = true - tracingInstrumentation { - enabled = true - features = [InstrumentationFeature.DATABASE] - logcat { - enabled = false - } - } - autoInstallation { - enabled = false - } - includeDependenciesReport = false - /* Sentry won't send source context or add performance instrumentations for debug builds - so we can save build times. Sending events will still work in debug builds - (if enabled in WCCrashLoggingDataProvider). - */ - ignoredBuildTypes = ["debug"] - - /* Additional source directories to be included in the source context. For now, manually: - https://github.com/getsentry/sentry-android-gradle-plugin/issues/685 - */ - additionalSourceDirsForSourceContext = [ - '../libs/cardreader/src/main/java', - ] } android { @@ -61,9 +20,3 @@ android { jvmTarget = '1.8' } } - -dependencies { - implementation "com.automattic:Automattic-Tracks-Android:$automatticTracksVersion" - implementation "com.automattic.tracks:crashlogging:$automatticTracksVersion" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" -} diff --git a/libs/commons/src/main/java/com/woocommerce/commons/crashlogging/WCCrashLoggingDataProvider.kt b/libs/commons/src/main/java/com/woocommerce/commons/crashlogging/WCCrashLoggingDataProvider.kt deleted file mode 100644 index 0d332d51907..00000000000 --- a/libs/commons/src/main/java/com/woocommerce/commons/crashlogging/WCCrashLoggingDataProvider.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.woocommerce.commons.crashlogging - -import com.automattic.android.tracks.crashlogging.CrashLoggingDataProvider -import com.automattic.android.tracks.crashlogging.CrashLoggingUser -import com.automattic.android.tracks.crashlogging.EventLevel -import com.automattic.android.tracks.crashlogging.ExtraKnownKey -import com.automattic.android.tracks.crashlogging.PerformanceMonitoringConfig -import com.automattic.android.tracks.crashlogging.ReleaseName -import java.util.Locale -import kotlinx.coroutines.flow.Flow - -class WCCrashLoggingDataProvider: CrashLoggingDataProvider { - override val applicationContextProvider: Flow> - get() = TODO("Not yet implemented") - override val buildType: String - get() = TODO("Not yet implemented") - override val enableCrashLoggingLogs: Boolean - get() = TODO("Not yet implemented") - override val locale: Locale? - get() = TODO("Not yet implemented") - override val performanceMonitoringConfig: PerformanceMonitoringConfig - get() = TODO("Not yet implemented") - override val releaseName: ReleaseName - get() = TODO("Not yet implemented") - override val sentryDSN: String - get() = TODO("Not yet implemented") - override val user: Flow - get() = TODO("Not yet implemented") - - override fun crashLoggingEnabled(): Boolean { - TODO("Not yet implemented") - } - - override fun extraKnownKeys(): List { - TODO("Not yet implemented") - } - - override fun provideExtrasForEvent( - currentExtras: Map, - eventLevel: EventLevel - ): Map { - TODO("Not yet implemented") - } - - override fun shouldDropWrappingException(module: String, type: String, value: String): Boolean { - TODO("Not yet implemented") - } -} From 328f305361c24cba4963a767fe961f5662e6e24b Mon Sep 17 00:00:00 2001 From: samiuelson Date: Thu, 8 Aug 2024 16:32:50 +0200 Subject: [PATCH 096/196] Fix coupon and discount buttons availability conditions --- .../creation/OrderCreateEditViewModel.kt | 9 +- ...EditFocusedOrderCreateEditViewModelTest.kt | 151 ++++++++++++++++++ 2 files changed, 159 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt index 7fa5b6a3db7..081b90706f8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt @@ -845,9 +845,15 @@ class OrderCreateEditViewModel @Inject constructor( } private fun updateCouponButtonVisibility(order: Order) { - viewState = viewState.copy(isCouponButtonEnabled = order.hasProducts() && order.isEditable) + viewState = viewState.copy( + isCouponButtonEnabled = order.hasProducts() && order.isEditable && !order.containsDiscounts(), + areDiscountButtonsEnabled = order.hasProducts() && order.isEditable && order.couponLines.isEmpty() + ) } + private fun Order.containsDiscounts(): Boolean = items.any { it.discount > BigDecimal.ZERO } + + private fun updateAddShippingButtonVisibility(order: Order) { viewState = viewState.copy(isAddShippingButtonEnabled = order.hasProducts() && order.isEditable) } @@ -2040,6 +2046,7 @@ class OrderCreateEditViewModel @Inject constructor( val isUpdatingOrderDraft: Boolean = false, val showOrderUpdateSnackbar: Boolean = false, val isCouponButtonEnabled: Boolean = false, + val areDiscountButtonsEnabled: Boolean = false, val isAddShippingButtonEnabled: Boolean = false, val isAddGiftCardButtonEnabled: Boolean = false, val shouldDisplayAddGiftCardButton: Boolean = false, diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreateEditViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreateEditViewModelTest.kt index 3f372370364..edbdb510880 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreateEditViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreateEditViewModelTest.kt @@ -336,6 +336,157 @@ class EditFocusedOrderCreateEditViewModelTest : UnifiedOrderEditViewModelTest() assertTrue(lastReceivedState!!.isCouponButtonEnabled) } + @Test + fun `given coupon applied to order, then should disable adding discount to a product`() { + initMocksForAnalyticsWithOrder(defaultOrderValue) + val order = defaultOrderValue.copy( + isEditable = true, + items = listOf( + Order.Item( + 1L, + 1L, + "name", + BigDecimal(1), + "", + 1f, + BigDecimal(1), + BigDecimal(1), + BigDecimal(1), + 1L, + listOf() + ) + ), + couponLines = listOf(Order.CouponLine("code", 1L, "")) + ) + orderDetailRepository.stub { + onBlocking { getOrderById(defaultOrderValue.id) }.doReturn(order) + } + createUpdateOrderUseCase = mock { + onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(order)) + } + createSut() + var orderDraft: Order? = null + sut.orderDraft.observeForever { + orderDraft = it + } + assertTrue(orderDraft!!.couponLines.isNotEmpty()) + var lastReceivedState: OrderCreateEditViewModel.ViewState? = null + sut.viewStateData.liveData.observeForever { + lastReceivedState = it + } + assertFalse(lastReceivedState!!.areDiscountButtonsEnabled) + } + + @Test + fun `given no coupons applied to order, then should enable adding discount to a product`() { + initMocksForAnalyticsWithOrder(defaultOrderValue) + val order = defaultOrderValue.copy( + isEditable = true, + items = listOf( + Order.Item( + 1L, + 1L, + "name", + BigDecimal(1), + "", + 1f, + BigDecimal(1), + BigDecimal(1), + BigDecimal(1), + 1L, + listOf() + ) + ), + ) + orderDetailRepository.stub { + onBlocking { getOrderById(defaultOrderValue.id) }.doReturn(order) + } + createUpdateOrderUseCase = mock { + onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(order)) + } + createSut() + var orderDraft: Order? = null + sut.orderDraft.observeForever { + orderDraft = it + } + assertTrue(orderDraft!!.couponLines.isEmpty()) + var lastReceivedState: OrderCreateEditViewModel.ViewState? = null + sut.viewStateData.liveData.observeForever { + lastReceivedState = it + } + assertTrue(lastReceivedState!!.areDiscountButtonsEnabled) + } + + @Test + fun `given discount applied to at least item, then should disable adding coupon to the order`() { + initMocksForAnalyticsWithOrder(defaultOrderValue) + val item = Order.Item( + itemId = 1L, + productId = 1L, + name = "name", + price = BigDecimal(1), + sku = "", + quantity = 1f, + subtotal = BigDecimal(10), + totalTax = BigDecimal(5), + total = BigDecimal(1), + variationId = 1L, + attributesList = listOf() + ) + val order = defaultOrderValue.copy( + isEditable = true, + items = listOf(item), + ) + orderDetailRepository.stub { + onBlocking { getOrderById(defaultOrderValue.id) }.doReturn(order) + } + createUpdateOrderUseCase = mock { + onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(order)) + } + createSut() + var lastReceivedState: OrderCreateEditViewModel.ViewState? = null + sut.viewStateData.liveData.observeForever { + lastReceivedState = it + } + assertTrue(item.discount > BigDecimal.ZERO) + assertFalse(lastReceivedState!!.isCouponButtonEnabled) + } + + @Test + fun `given no discounts applied to order items, then should disable adding coupon to the order`() { + initMocksForAnalyticsWithOrder(defaultOrderValue) + val item = Order.Item( + itemId = 1L, + productId = 1L, + name = "name", + price = BigDecimal(1), + sku = "", + quantity = 1f, + subtotal = BigDecimal(10), + totalTax = BigDecimal(1), + total = BigDecimal(10), + variationId = 1L, + attributesList = listOf() + ) + val order = defaultOrderValue.copy( + isEditable = true, + items = listOf(item), + ) + orderDetailRepository.stub { + onBlocking { getOrderById(defaultOrderValue.id) }.doReturn(order) + } + createUpdateOrderUseCase = mock { + onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(order)) + } + createSut() + var lastReceivedState: OrderCreateEditViewModel.ViewState? = null + sut.viewStateData.liveData.observeForever { + lastReceivedState = it + } + assertTrue(item.discount == BigDecimal.ZERO) + assertTrue(lastReceivedState!!.isCouponButtonEnabled) + } + @Test fun `given editable order and order paid, then set tax rate button should be disabled`() { testBlocking { From a25423fe7d40de3f7f6b99f78ddb8eea54e2d205 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Thu, 8 Aug 2024 16:34:16 +0200 Subject: [PATCH 097/196] Update `ExtendedProductCardContent` to updated state model --- .../creation/views/ExpandableProductCard.kt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/views/ExpandableProductCard.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/views/ExpandableProductCard.kt index a293769711c..f8639256e95 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/views/ExpandableProductCard.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/views/ExpandableProductCard.kt @@ -307,7 +307,7 @@ fun ExtendedProductCardContent( bottomDivider, orderCount, price, - discountButton, + addDiscountButton, discountAmount, priceAfterDiscountLabel, priceAfterDiscountValue, @@ -322,6 +322,7 @@ fun ExtendedProductCardContent( // The logic to update bundled products quantity is complex so we need to prevent any change while we are // updating the bundle and inner products quantity val isBundledProduct = product.productInfo.productType == ProductType.BUNDLE + val discountButtonsEnabled = state.value?.areDiscountButtonsEnabled == true Divider( modifier = Modifier @@ -399,11 +400,11 @@ fun ExtendedProductCardContent( } if (product.productInfo.hasDiscount) { WCTextButton( - modifier = Modifier.constrainAs(discountButton) { + modifier = Modifier.constrainAs(addDiscountButton) { top.linkTo(price.bottom) }, onClick = onDiscountButtonClicked, - enabled = editableControlsEnabled + enabled = editableControlsEnabled && discountButtonsEnabled ) { Text( text = stringResource(id = R.string.discount), @@ -421,8 +422,8 @@ fun ExtendedProductCardContent( .padding(horizontal = dimensionResource(id = R.dimen.minor_100)) .constrainAs(discountAmount) { end.linkTo(parent.end) - top.linkTo(discountButton.top) - bottom.linkTo(discountButton.bottom) + top.linkTo(addDiscountButton.top) + bottom.linkTo(addDiscountButton.bottom) }, text = "-${product.productInfo.discountAmount}", color = colorResource(id = R.color.woo_green_50) @@ -430,7 +431,7 @@ fun ExtendedProductCardContent( Text( modifier = Modifier .constrainAs(priceAfterDiscountLabel) { - top.linkTo(discountButton.bottom) + top.linkTo(addDiscountButton.bottom) start.linkTo(parent.start) bottom.linkTo(bottomDivider.top) } @@ -451,12 +452,12 @@ fun ExtendedProductCardContent( ) } else { WCTextButton( - modifier = Modifier.constrainAs(discountButton) { + modifier = Modifier.constrainAs(addDiscountButton) { top.linkTo(price.bottom) bottom.linkTo(bottomDivider.top) }, onClick = onDiscountButtonClicked, - enabled = editableControlsEnabled + enabled = editableControlsEnabled && discountButtonsEnabled, ) { Icon( imageVector = ImageVector.vectorResource(R.drawable.ic_add), From 10c42e82bb39d3a832e79960ea92bb14b2b2e5e9 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 8 Aug 2024 11:38:40 -0300 Subject: [PATCH 098/196] Define the WCWearCrashLoggingDataProvider --- .../WCWearCrashLoggingDataProvider.kt | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt new file mode 100644 index 00000000000..22d512d1c35 --- /dev/null +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt @@ -0,0 +1,61 @@ +package com.woocommerce.android.wear.crashlogging + +import com.automattic.android.tracks.crashlogging.CrashLoggingDataProvider +import com.automattic.android.tracks.crashlogging.CrashLoggingUser +import com.automattic.android.tracks.crashlogging.EventLevel +import com.automattic.android.tracks.crashlogging.ExtraKnownKey +import com.automattic.android.tracks.crashlogging.PerformanceMonitoringConfig +import com.automattic.android.tracks.crashlogging.ReleaseName +import com.woocommerce.android.wear.di.AppCoroutineScope +import java.util.Locale +import javax.inject.Inject +import javax.inject.Singleton +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import org.wordpress.android.fluxc.Dispatcher +import org.wordpress.android.fluxc.store.AccountStore +import org.wordpress.android.fluxc.utils.BuildConfigWrapper + +@Singleton +class WCWearCrashLoggingDataProvider @Inject constructor( + private val accountStore: AccountStore, + @AppCoroutineScope private val appScope: CoroutineScope, + buildConfig: BuildConfigWrapper, + dispatcher: Dispatcher, +) : CrashLoggingDataProvider { + override val applicationContextProvider: Flow> + get() = TODO("Not yet implemented") + override val buildType: String + get() = TODO("Not yet implemented") + override val enableCrashLoggingLogs: Boolean + get() = TODO("Not yet implemented") + override val locale: Locale? + get() = TODO("Not yet implemented") + override val performanceMonitoringConfig: PerformanceMonitoringConfig + get() = TODO("Not yet implemented") + override val releaseName: ReleaseName + get() = TODO("Not yet implemented") + override val sentryDSN: String + get() = TODO("Not yet implemented") + override val user: Flow + get() = TODO("Not yet implemented") + + override fun crashLoggingEnabled(): Boolean { + TODO("Not yet implemented") + } + + override fun extraKnownKeys(): List { + TODO("Not yet implemented") + } + + override fun provideExtrasForEvent( + currentExtras: Map, + eventLevel: EventLevel + ): Map { + TODO("Not yet implemented") + } + + override fun shouldDropWrappingException(module: String, type: String, value: String): Boolean { + TODO("Not yet implemented") + } +} From 2c13d71bade40bee473e4449b2412b1440fbc0e5 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Thu, 8 Aug 2024 16:39:31 +0200 Subject: [PATCH 099/196] Rename method --- .../android/ui/orders/creation/OrderCreateEditViewModel.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt index 081b90706f8..bf7e558fbce 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt @@ -467,7 +467,7 @@ class OrderCreateEditViewModel @Inject constructor( isEditable = order.isEditable ) monitorOrderChanges() - updateCouponButtonVisibility(order) + updateCouponAndDiscountButtonsState(order) updateAddShippingButtonVisibility(order) updateAddGiftCardButtonVisibility(order) handleCouponEditResult() @@ -844,7 +844,7 @@ class OrderCreateEditViewModel @Inject constructor( } } - private fun updateCouponButtonVisibility(order: Order) { + private fun updateCouponAndDiscountButtonsState(order: Order) { viewState = viewState.copy( isCouponButtonEnabled = order.hasProducts() && order.isEditable && !order.containsDiscounts(), areDiscountButtonsEnabled = order.hasProducts() && order.isEditable && order.couponLines.isEmpty() @@ -1514,7 +1514,7 @@ class OrderCreateEditViewModel @Inject constructor( updateStatus.order } }.also { - updateCouponButtonVisibility(it) + updateCouponAndDiscountButtonsState(it) updateAddShippingButtonVisibility(it) updateAddGiftCardButtonVisibility(it) } From 5a7060b53accb0e54ef9628b8940abfac0f1a1b9 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Thu, 8 Aug 2024 16:42:42 +0200 Subject: [PATCH 100/196] Fix typo --- .../EditFocusedOrderCreateEditViewModelTest.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreateEditViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreateEditViewModelTest.kt index edbdb510880..073c93cce27 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreateEditViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreateEditViewModelTest.kt @@ -338,6 +338,7 @@ class EditFocusedOrderCreateEditViewModelTest : UnifiedOrderEditViewModelTest() @Test fun `given coupon applied to order, then should disable adding discount to a product`() { + // given initMocksForAnalyticsWithOrder(defaultOrderValue) val order = defaultOrderValue.copy( isEditable = true, @@ -374,11 +375,13 @@ class EditFocusedOrderCreateEditViewModelTest : UnifiedOrderEditViewModelTest() sut.viewStateData.liveData.observeForever { lastReceivedState = it } + // then assertFalse(lastReceivedState!!.areDiscountButtonsEnabled) } @Test fun `given no coupons applied to order, then should enable adding discount to a product`() { + // given initMocksForAnalyticsWithOrder(defaultOrderValue) val order = defaultOrderValue.copy( isEditable = true, @@ -414,11 +417,13 @@ class EditFocusedOrderCreateEditViewModelTest : UnifiedOrderEditViewModelTest() sut.viewStateData.liveData.observeForever { lastReceivedState = it } + // then assertTrue(lastReceivedState!!.areDiscountButtonsEnabled) } @Test - fun `given discount applied to at least item, then should disable adding coupon to the order`() { + fun `given discount applied to at least one item, then should disable adding coupon to the order`() { + // given initMocksForAnalyticsWithOrder(defaultOrderValue) val item = Order.Item( itemId = 1L, @@ -448,12 +453,14 @@ class EditFocusedOrderCreateEditViewModelTest : UnifiedOrderEditViewModelTest() sut.viewStateData.liveData.observeForever { lastReceivedState = it } + // then assertTrue(item.discount > BigDecimal.ZERO) assertFalse(lastReceivedState!!.isCouponButtonEnabled) } @Test fun `given no discounts applied to order items, then should disable adding coupon to the order`() { + // given initMocksForAnalyticsWithOrder(defaultOrderValue) val item = Order.Item( itemId = 1L, @@ -483,6 +490,7 @@ class EditFocusedOrderCreateEditViewModelTest : UnifiedOrderEditViewModelTest() sut.viewStateData.liveData.observeForever { lastReceivedState = it } + // then assertTrue(item.discount == BigDecimal.ZERO) assertTrue(lastReceivedState!!.isCouponButtonEnabled) } From 294fa797c2c0c24cc9e3b34cf38e95bc2aef3b55 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Thu, 8 Aug 2024 16:44:58 +0200 Subject: [PATCH 101/196] Satisfy detekt's complaints --- .../android/ui/orders/creation/OrderCreateEditViewModel.kt | 1 - .../android/ui/orders/creation/views/ExpandableProductCard.kt | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt index bf7e558fbce..3b992477019 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt @@ -853,7 +853,6 @@ class OrderCreateEditViewModel @Inject constructor( private fun Order.containsDiscounts(): Boolean = items.any { it.discount > BigDecimal.ZERO } - private fun updateAddShippingButtonVisibility(order: Order) { viewState = viewState.copy(isAddShippingButtonEnabled = order.hasProducts() && order.isEditable) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/views/ExpandableProductCard.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/views/ExpandableProductCard.kt index f8639256e95..21ed47ac3c8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/views/ExpandableProductCard.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/views/ExpandableProductCard.kt @@ -290,6 +290,7 @@ fun ExpandableProductCard( } } +@Suppress("DestructuringDeclarationWithTooManyEntries") @Composable fun ExtendedProductCardContent( state: State, From fdf81c2f3b96a5ee0fa990bd95e45e5ee37a410d Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 8 Aug 2024 11:48:50 -0300 Subject: [PATCH 102/196] Configure initial implementation of WCWearCrashLoggingDataProvider fields --- .../WCWearCrashLoggingDataProvider.kt | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt index 22d512d1c35..cdcfd5fea97 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt @@ -6,6 +6,7 @@ import com.automattic.android.tracks.crashlogging.EventLevel import com.automattic.android.tracks.crashlogging.ExtraKnownKey import com.automattic.android.tracks.crashlogging.PerformanceMonitoringConfig import com.automattic.android.tracks.crashlogging.ReleaseName +import com.woocommerce.android.BuildConfig import com.woocommerce.android.wear.di.AppCoroutineScope import java.util.Locale import javax.inject.Inject @@ -20,25 +21,33 @@ import org.wordpress.android.fluxc.utils.BuildConfigWrapper class WCWearCrashLoggingDataProvider @Inject constructor( private val accountStore: AccountStore, @AppCoroutineScope private val appScope: CoroutineScope, - buildConfig: BuildConfigWrapper, dispatcher: Dispatcher, ) : CrashLoggingDataProvider { - override val applicationContextProvider: Flow> + override val buildType = BuildConfig.BUILD_TYPE + override val enableCrashLoggingLogs = BuildConfig.DEBUG + override val releaseName: ReleaseName = if (BuildConfig.DEBUG) { + ReleaseName.SetByApplication(DEBUG_RELEASE_NAME) + } else { + ReleaseName.SetByTracksLibrary + } + + override fun provideExtrasForEvent( + currentExtras: Map, + eventLevel: EventLevel + ) = emptyMap() + + override fun shouldDropWrappingException(module: String, type: String, value: String) = false + + override val sentryDSN: String get() = TODO("Not yet implemented") - override val buildType: String + override val user: Flow get() = TODO("Not yet implemented") - override val enableCrashLoggingLogs: Boolean + override val applicationContextProvider: Flow> get() = TODO("Not yet implemented") override val locale: Locale? get() = TODO("Not yet implemented") override val performanceMonitoringConfig: PerformanceMonitoringConfig get() = TODO("Not yet implemented") - override val releaseName: ReleaseName - get() = TODO("Not yet implemented") - override val sentryDSN: String - get() = TODO("Not yet implemented") - override val user: Flow - get() = TODO("Not yet implemented") override fun crashLoggingEnabled(): Boolean { TODO("Not yet implemented") @@ -48,14 +57,7 @@ class WCWearCrashLoggingDataProvider @Inject constructor( TODO("Not yet implemented") } - override fun provideExtrasForEvent( - currentExtras: Map, - eventLevel: EventLevel - ): Map { - TODO("Not yet implemented") - } - - override fun shouldDropWrappingException(module: String, type: String, value: String): Boolean { - TODO("Not yet implemented") + companion object { + const val DEBUG_RELEASE_NAME = "debug" } } From 24fb657543062dc43be1c6cfd2c62b7029bcd3fe Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 8 Aug 2024 11:52:25 -0300 Subject: [PATCH 103/196] Configure the crashlogging user updates --- .../WCWearCrashLoggingDataProvider.kt | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt index cdcfd5fea97..f2a0f9def48 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt @@ -13,9 +13,13 @@ import javax.inject.Inject import javax.inject.Singleton import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.launch +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode import org.wordpress.android.fluxc.Dispatcher +import org.wordpress.android.fluxc.model.AccountModel import org.wordpress.android.fluxc.store.AccountStore -import org.wordpress.android.fluxc.utils.BuildConfigWrapper @Singleton class WCWearCrashLoggingDataProvider @Inject constructor( @@ -23,6 +27,11 @@ class WCWearCrashLoggingDataProvider @Inject constructor( @AppCoroutineScope private val appScope: CoroutineScope, dispatcher: Dispatcher, ) : CrashLoggingDataProvider { + + init { dispatcher.register(this) } + + private val crashLoggingUser = MutableStateFlow(accountStore.account?.toCrashLoggingUser()) + override val buildType = BuildConfig.BUILD_TYPE override val enableCrashLoggingLogs = BuildConfig.DEBUG override val releaseName: ReleaseName = if (BuildConfig.DEBUG) { @@ -31,6 +40,14 @@ class WCWearCrashLoggingDataProvider @Inject constructor( ReleaseName.SetByTracksLibrary } + @Suppress("unused", "unused_parameter") + @Subscribe(threadMode = ThreadMode.MAIN) + fun onAccountChanged(event: AccountStore.OnAccountChanged) { + appScope.launch { + crashLoggingUser.emit(accountStore.account.toCrashLoggingUser()) + } + } + override fun provideExtrasForEvent( currentExtras: Map, eventLevel: EventLevel @@ -57,6 +74,16 @@ class WCWearCrashLoggingDataProvider @Inject constructor( TODO("Not yet implemented") } + private fun AccountModel.toCrashLoggingUser(): CrashLoggingUser? { + if (userId == 0L) return null + + return CrashLoggingUser( + userID = userId.toString(), + email = email, + username = userName + ) + } + companion object { const val DEBUG_RELEASE_NAME = "debug" } From e808af438bfe2fd95362ea005673d8bf823787e5 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Thu, 8 Aug 2024 17:53:54 +0200 Subject: [PATCH 104/196] Update RELEASE-NOTES.txt --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index b344f9e8b44..dcdc59ff5a1 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -9,6 +9,7 @@ - [*****] [Internal] Update Androidx-fragment from 1.6.2 to 1.8.2 [https://github.com/woocommerce/woocommerce-android/pull/12231] - [*****] [Internal] Update Material to 1.12.0 and Transition to 1.5.1 [https://github.com/woocommerce/woocommerce-android/pull/12237] - [*****] [Internal] Update Stripe Terminal SDK from 3.1.1 to 3.7.1 [https://github.com/woocommerce/woocommerce-android/pull/12239] +- [***] Fix logic behind handling enabled/disabled states of "+ Add coupon" and "+ Add discount" buttons in the Order creation/edition flow [https://github.com/woocommerce/woocommerce-android/pull/12263]. 19.8 ----- From bd8b5c9b53e5d6f1d08966c606e2520b457b11f1 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Thu, 8 Aug 2024 18:19:13 +0200 Subject: [PATCH 105/196] Allow adding multiple coupons --- .../creation/OrderCreateEditViewModel.kt | 6 ++- ...EditFocusedOrderCreateEditViewModelTest.kt | 43 +++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt index 3b992477019..833da67d9df 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt @@ -846,12 +846,14 @@ class OrderCreateEditViewModel @Inject constructor( private fun updateCouponAndDiscountButtonsState(order: Order) { viewState = viewState.copy( - isCouponButtonEnabled = order.hasProducts() && order.isEditable && !order.containsDiscounts(), - areDiscountButtonsEnabled = order.hasProducts() && order.isEditable && order.couponLines.isEmpty() + isCouponButtonEnabled = order.hasProducts() && order.isEditable && order.doesNotContainManualDiscounts(), + areDiscountButtonsEnabled = order.hasProducts() && order.isEditable && !order.containsCoupons() ) } private fun Order.containsDiscounts(): Boolean = items.any { it.discount > BigDecimal.ZERO } + private fun Order.containsCoupons(): Boolean = couponLines.isNotEmpty() + private fun Order.doesNotContainManualDiscounts() = (!containsDiscounts() || containsCoupons()) private fun updateAddShippingButtonVisibility(order: Order) { viewState = viewState.copy(isAddShippingButtonEnabled = order.hasProducts() && order.isEditable) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreateEditViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreateEditViewModelTest.kt index 073c93cce27..d0069f1b33d 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreateEditViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreateEditViewModelTest.kt @@ -379,6 +379,49 @@ class EditFocusedOrderCreateEditViewModelTest : UnifiedOrderEditViewModelTest() assertFalse(lastReceivedState!!.areDiscountButtonsEnabled) } + @Test + fun `given a coupon applied to order, then should allow adding another one`() { + // given + initMocksForAnalyticsWithOrder(defaultOrderValue) + val order = defaultOrderValue.copy( + isEditable = true, + items = listOf( + Order.Item( + 1L, + 1L, + "name", + BigDecimal(1), + "", + 1f, + BigDecimal(1), + BigDecimal(1), + BigDecimal(1), + 1L, + listOf() + ) + ), + couponLines = listOf(Order.CouponLine("code", 1L, "")) + ) + orderDetailRepository.stub { + onBlocking { getOrderById(defaultOrderValue.id) }.doReturn(order) + } + createUpdateOrderUseCase = mock { + onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(order)) + } + createSut() + var orderDraft: Order? = null + sut.orderDraft.observeForever { + orderDraft = it + } + assertTrue(orderDraft!!.couponLines.isNotEmpty()) + var lastReceivedState: OrderCreateEditViewModel.ViewState? = null + sut.viewStateData.liveData.observeForever { + lastReceivedState = it + } + // then + assertTrue(lastReceivedState!!.isCouponButtonEnabled) + } + @Test fun `given no coupons applied to order, then should enable adding discount to a product`() { // given From 8344666b60a9dd124bd62b2fd5b5faaca0cdb983 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 8 Aug 2024 19:14:10 -0300 Subject: [PATCH 106/196] Update additional pending sentry data --- .../wear/crashlogging/WCWearCrashLoggingDataProvider.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt index f2a0f9def48..999b618c1df 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt @@ -32,6 +32,8 @@ class WCWearCrashLoggingDataProvider @Inject constructor( private val crashLoggingUser = MutableStateFlow(accountStore.account?.toCrashLoggingUser()) + override val user: Flow = crashLoggingUser + override val sentryDSN: String = BuildConfig.SENTRY_DSN override val buildType = BuildConfig.BUILD_TYPE override val enableCrashLoggingLogs = BuildConfig.DEBUG override val releaseName: ReleaseName = if (BuildConfig.DEBUG) { @@ -55,10 +57,8 @@ class WCWearCrashLoggingDataProvider @Inject constructor( override fun shouldDropWrappingException(module: String, type: String, value: String) = false - override val sentryDSN: String - get() = TODO("Not yet implemented") - override val user: Flow - get() = TODO("Not yet implemented") + + override val applicationContextProvider: Flow> get() = TODO("Not yet implemented") override val locale: Locale? From 65189fd4613249fe35ff8412d6ce6ff24a505f44 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 8 Aug 2024 20:15:27 -0300 Subject: [PATCH 107/196] Add FluxCCrashLoggerImpl to the Wear module --- .../wear/crashlogging/FluxCCrashLoggerImpl.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/FluxCCrashLoggerImpl.kt diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/FluxCCrashLoggerImpl.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/FluxCCrashLoggerImpl.kt new file mode 100644 index 00000000000..38afba19bca --- /dev/null +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/FluxCCrashLoggerImpl.kt @@ -0,0 +1,18 @@ +package com.woocommerce.android.wear.crashlogging + +import com.automattic.android.tracks.crashlogging.CrashLogging +import org.wordpress.android.fluxc.logging.FluxCCrashLogger + +class FluxCCrashLoggerImpl(private val crashLogging: CrashLogging) : FluxCCrashLogger { + override fun recordEvent(message: String, category: String?) { + crashLogging.recordEvent(message, category) + } + + override fun recordException(exception: Throwable, category: String?) { + crashLogging.recordException(exception, category) + } + + override fun sendReport(exception: Throwable?, tags: Map, message: String?) { + crashLogging.sendReport(exception, tags, message) + } +} From cd8db56b3d228d8e249c019fed7e46d516bddc21 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 8 Aug 2024 20:15:38 -0300 Subject: [PATCH 108/196] Define CrashLoggingModule for the Wear app --- .../android/wear/di/CrashLoggingModule.kt | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/CrashLoggingModule.kt diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/CrashLoggingModule.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/CrashLoggingModule.kt new file mode 100644 index 00000000000..4b02769fe5e --- /dev/null +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/CrashLoggingModule.kt @@ -0,0 +1,40 @@ +package com.woocommerce.android.wear.di + +import android.app.Application +import com.automattic.android.tracks.crashlogging.CrashLogging +import com.automattic.android.tracks.crashlogging.CrashLoggingDataProvider +import com.automattic.android.tracks.crashlogging.CrashLoggingProvider +import com.woocommerce.android.wear.crashlogging.FluxCCrashLoggerImpl +import com.woocommerce.android.wear.crashlogging.WCWearCrashLoggingDataProvider +import dagger.Binds +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton +import kotlinx.coroutines.CoroutineScope +import org.wordpress.android.fluxc.logging.FluxCCrashLogger + +@InstallIn(SingletonComponent::class) +@Module +abstract class CrashLoggingModule { + companion object { + @Provides + @Singleton + fun provideCrashLogging( + context: Application, + crashLoggingDataProvider: CrashLoggingDataProvider, + @AppCoroutineScope appScope: CoroutineScope + ): CrashLogging { + return CrashLoggingProvider.createInstance(context, crashLoggingDataProvider, appScope) + } + + @Provides + fun provideFluxCCrashLogger(crashLogging: CrashLogging): FluxCCrashLogger { + return FluxCCrashLoggerImpl(crashLogging) + } + } + + @Binds + abstract fun bindCrashLoggingDataProvider(dataProvider: WCWearCrashLoggingDataProvider): CrashLoggingDataProvider +} From 93f7a7c61d46ad174a8fe956e70fa1c7e1a6f0f7 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 8 Aug 2024 20:21:51 -0300 Subject: [PATCH 109/196] Fix lint issues --- .../wear/crashlogging/WCWearCrashLoggingDataProvider.kt | 8 +++----- .../com/woocommerce/android/wear/di/CrashLoggingModule.kt | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt index 999b618c1df..dd316bd1562 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt @@ -8,9 +8,6 @@ import com.automattic.android.tracks.crashlogging.PerformanceMonitoringConfig import com.automattic.android.tracks.crashlogging.ReleaseName import com.woocommerce.android.BuildConfig import com.woocommerce.android.wear.di.AppCoroutineScope -import java.util.Locale -import javax.inject.Inject -import javax.inject.Singleton import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -20,6 +17,9 @@ import org.greenrobot.eventbus.ThreadMode import org.wordpress.android.fluxc.Dispatcher import org.wordpress.android.fluxc.model.AccountModel import org.wordpress.android.fluxc.store.AccountStore +import java.util.Locale +import javax.inject.Inject +import javax.inject.Singleton @Singleton class WCWearCrashLoggingDataProvider @Inject constructor( @@ -57,8 +57,6 @@ class WCWearCrashLoggingDataProvider @Inject constructor( override fun shouldDropWrappingException(module: String, type: String, value: String) = false - - override val applicationContextProvider: Flow> get() = TODO("Not yet implemented") override val locale: Locale? diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/CrashLoggingModule.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/CrashLoggingModule.kt index 4b02769fe5e..d011c272380 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/CrashLoggingModule.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/CrashLoggingModule.kt @@ -11,9 +11,9 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton import kotlinx.coroutines.CoroutineScope import org.wordpress.android.fluxc.logging.FluxCCrashLogger +import javax.inject.Singleton @InstallIn(SingletonComponent::class) @Module From aed7d66ffd6076b070511dff4156503a31a1f58c Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 9 Aug 2024 10:26:02 +1000 Subject: [PATCH 110/196] Set default `version` directly in block arg for play store lane --- fastlane/Fastfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index df46979ffbb..f41d406f922 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -230,11 +230,9 @@ platform :android do # @example Running the lane # bundle exec fastlane update_play_store_strings version:10.3 # - lane :update_play_store_strings do |version: nil| + lane :update_play_store_strings do |version: release_version_current| ensure_git_status_clean - version ||= release_version_current - app_metadata_source_path = METADATA_SOURCE_DIR_PATH[MOBILE_APP] files = { release_note: METADATA_SOURCE_CHANGELOG_FILE_PATH[MOBILE_APP], From 714033589db9acd439d81ed77631857869c2456b Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 9 Aug 2024 10:28:30 +1000 Subject: [PATCH 111/196] Use named block arguments in `new_beta_release` lane --- fastlane/Fastfile | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index f41d406f922..28d326e9704 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -275,7 +275,7 @@ platform :android do # @param [Boolean] include_wear_app If true, the CI build will also include a job to build the WEAR_APP. Defaults to false. # desc 'Updates a release branch for a new beta release' - lane :new_beta_release do |options| + lane :new_beta_release do |skip_confirm: false, include_wear_app: false| # Verify that there's nothing in progress in the working copy ensure_git_status_clean @@ -293,9 +293,7 @@ platform :android do MESSAGE UI.important(message) - unless options[:skip_confirm] || UI.confirm('Do you want to continue?') - UI.user_error!("Terminating as requested. Don't forget to run the remainder of this automation manually.") - end + UI.user_error!("Terminating as requested. Don't forget to run the remainder of this automation manually.") unless skip_confirm || UI.confirm('Do you want to continue?') # Bump the release version and build code UI.message 'Bumping beta version and build code...' @@ -308,13 +306,10 @@ platform :android do UI.success("Done! New Beta Version: #{version_name_current}. New Build Code: #{build_code_current}") UI.important('Pushing changes to remote and triggering the beta build') - unless options[:skip_confirm] || UI.confirm('Do you want to continue?') - UI.user_error!("Terminating as requested. Don't forget to run the remainder of this automation manually.") - end + UI.user_error!("Terminating as requested. Don't forget to run the remainder of this automation manually.") unless skip_confirm || UI.confirm('Do you want to continue?') push_to_git_remote(tags: false) - include_wear_app = options.fetch(:include_wear_app, false) trigger_release_build(branch_to_build: "release/#{release_version_current}", include_wear_app: include_wear_app) # Create an intermediate branch From 5ebe87e73c625c21c9f8542983630cad12dc93ba Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 9 Aug 2024 10:39:06 +1000 Subject: [PATCH 112/196] Use named block arguments in `new_hotfix_lane` Notice it also removes the need to check the args are given manually, because Ruby does that for us (albeit with a worse failure message) --- fastlane/Fastfile | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 28d326e9704..1662223abfa 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -335,15 +335,12 @@ platform :android do # @param [Boolean] skip_confirm Skip the confirmation prompt if set to true # desc 'Prepare a new hotfix branch cut from the previous tag, and bump the version' - lane :new_hotfix_release do |options| - UI.user_error!('A `version_name` must be provided when calling this lane') if options[:version_name].nil? - UI.user_error!('A `version_code` must be provided when calling this lane') if options[:version_code].nil? - + lane :new_hotfix_release do |version_name:, version_code:, skip_confirm: false| # Verify that there's nothing in progress in the working copy ensure_git_status_clean - new_version = options[:version_name] - version_code_new = options[:version_code] + new_version = version_name + version_code_new = version_code # Parse the provided version into an AppVersion object parsed_version = VERSION_FORMATTER.parse(new_version) previous_version = VERSION_FORMATTER.release_version(VERSION_CALCULATOR.previous_patch_version(version: parsed_version)) @@ -362,9 +359,7 @@ platform :android do MESSAGE UI.important(message) - unless options[:skip_confirm] || UI.confirm('Do you want to continue?') - UI.user_error!("Terminating as requested. Don't forget to run the remainder of this automation manually.") - end + UI.user_error!("Terminating as requested. Don't forget to run the remainder of this automation manually.") unless skip_confirm || UI.confirm('Do you want to continue?') # Check tags UI.user_error!("The version `#{new_version}` tag already exists!") if git_tag_exists(tag: new_version) From 536e53272855bcf5c2636b18b5bfabe240f406d7 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 9 Aug 2024 10:53:50 +1000 Subject: [PATCH 113/196] Derive GlotPress metadata URL from app project URL --- fastlane/Fastfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 1662223abfa..4d6ab2ba346 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -59,7 +59,7 @@ REMOTE_LIBRARIES_STRINGS_PATHS = [ # URL of the GlotPress project containing the app's strings GLOTPRESS_APP_STRINGS_PROJECT_URL = 'https://translate.wordpress.com/projects/woocommerce/woocommerce-android/' # URL of the GlotPress project containing the Play Store metadata (title, keywords, release notes, …) -GLOTPRESS_PLAYSTORE_METADATA_PROJECT_URL = 'https://translate.wordpress.com/projects/woocommerce/woocommerce-android/release-notes/' +GLOTPRESS_PLAYSTORE_METADATA_PROJECT_URL = "#{GLOTPRESS_APP_STRINGS_PROJECT_URL}/release-notes/".freeze APP_PACKAGE_NAME = 'com.woocommerce.android' GOOGLE_FIREBASE_SECRETS_PATH = File.join(PROJECT_ROOT_FOLDER, '.configure-files', 'firebase.secrets.json') From 86983c819c629391e733ce1947e9a9438dfb0b80 Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Fri, 9 Aug 2024 16:51:38 +0530 Subject: [PATCH 114/196] Remove unnecessary code --- .../android/ui/woopos/home/toolbar/WooPosToolbarViewModel.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModel.kt index 877fb4bad99..cdd25daa5f2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModel.kt @@ -128,7 +128,6 @@ class WooPosToolbarViewModel @Inject constructor( } override fun onCleared() { - super.onCleared() debounceJob?.cancel() } } From 7d087739db253d3f212d18a9bf72f2db8e761ab1 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 9 Aug 2024 15:44:45 +0200 Subject: [PATCH 115/196] Do not set InitialState when new transaction clicked to not break the animation --- .../android/ui/woopos/home/totals/WooPosTotalsViewModel.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt index 37b319e31d7..85407c0f913 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt @@ -78,7 +78,6 @@ class WooPosTotalsViewModel @Inject constructor( childrenToParentEventSender.sendToParent( ChildToParentEvent.NewTransactionClicked ) - uiState.value = InitialState } } is WooPosTotalsUIEvent.RetryOrderCreationClicked -> { From e82392d671084f5640499a4df230e7398f6e7885 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 9 Aug 2024 15:49:49 +0200 Subject: [PATCH 116/196] Removed redundant props from PaymentSuccess state --- .../android/ui/woopos/home/totals/WooPosTotalsViewModel.kt | 6 +----- .../android/ui/woopos/home/totals/WooPosTotalsViewState.kt | 6 +----- .../payment/success/WooPosTotalsPaymentSuccessScreen.kt | 6 +----- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt index 85407c0f913..e5e279f9a44 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt @@ -94,11 +94,7 @@ class WooPosTotalsViewModel @Inject constructor( is WooPosCardReaderPaymentResult.Success -> { val state = uiState.value check(state is WooPosTotalsViewState.Totals) - uiState.value = WooPosTotalsViewState.PaymentSuccess( - state.orderSubtotalText, - state.orderTaxText, - state.orderTotalText - ) + uiState.value = WooPosTotalsViewState.PaymentSuccess(orderTotalText = state.orderTotalText) childrenToParentEventSender.sendToParent(ChildToParentEvent.OrderSuccessfullyPaid) } else -> Unit diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewState.kt index 1c8a968ae81..23a78af03d4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewState.kt @@ -13,11 +13,7 @@ sealed class WooPosTotalsViewState : Parcelable { var orderTotalText: String, ) : WooPosTotalsViewState() - data class PaymentSuccess( - var orderSubtotalText: String, - var orderTaxText: String, - var orderTotalText: String - ) : WooPosTotalsViewState() + data class PaymentSuccess(var orderTotalText: String) : WooPosTotalsViewState() data class Error(val message: String) : WooPosTotalsViewState() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt index 4e486fa669f..474754ec7e2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/payment/success/WooPosTotalsPaymentSuccessScreen.kt @@ -207,11 +207,7 @@ private fun CheckMarkIcon( fun WooPosPaymentSuccessScreenPreview() { WooPosTheme { WooPosPaymentSuccessScreen( - state = WooPosTotalsViewState.PaymentSuccess( - orderSubtotalText = "$11.98", - orderTotalText = "$13.18", - orderTaxText = "$1.20" - ), + state = WooPosTotalsViewState.PaymentSuccess(orderTotalText = "$13.18"), bottomAnimationStarted = true, iconAnimationStarted = true, onNewTransactionClicked = {} From 1df1f9c60b5c96dc748873fe0c818e3fbc237d85 Mon Sep 17 00:00:00 2001 From: Automattic Release Bot Date: Fri, 9 Aug 2024 12:16:11 -0400 Subject: [PATCH 117/196] Update translations --- .../src/main/res/values-ar/strings.xml | 20 +- .../src/main/res/values-de/strings.xml | 752 +++++++++--------- .../src/main/res/values-es/strings.xml | 20 +- .../src/main/res/values-fr/strings.xml | 20 +- .../src/main/res/values-he/strings.xml | 20 +- .../src/main/res/values-id/strings.xml | 20 +- .../src/main/res/values-it/strings.xml | 20 +- .../src/main/res/values-ja/strings.xml | 20 +- .../src/main/res/values-ko/strings.xml | 20 +- .../src/main/res/values-nl/strings.xml | 20 +- .../src/main/res/values-pt-rBR/strings.xml | 20 +- .../src/main/res/values-ru/strings.xml | 20 +- .../src/main/res/values-sv/strings.xml | 20 +- .../src/main/res/values-tr/strings.xml | 20 +- .../src/main/res/values-zh-rCN/strings.xml | 20 +- .../src/main/res/values-zh-rTW/strings.xml | 20 +- 16 files changed, 654 insertions(+), 398 deletions(-) diff --git a/WooCommerce/src/main/res/values-ar/strings.xml b/WooCommerce/src/main/res/values-ar/strings.xml index a1c00b27aa9..c0fe85a1841 100644 --- a/WooCommerce/src/main/res/values-ar/strings.xml +++ b/WooCommerce/src/main/res/values-ar/strings.xml @@ -1,11 +1,28 @@ + تم سداد دفعة قدرها ⁦%1$s⁩ بنجاح + طلب جديد + موافق + + إنشاء طلب في إدارة المتجر + لتلقي دفعة مقابل منتج غير بسيط، اخرج من نقطة البيع وأنشئ طلبًا جديدًا من علامة تبويب الطلبات. + لا يمكن استخدام إلا المنتجات المادية البسيطة التي تتضمن نقطة بيع الآن.\nأما أنواع المنتجات الأخرى، مثل: المنتجات المتغيرة والظاهرية، ستتوفر في التحديثات المستقبلية. + لماذا يتعذر علي رؤية منتجاتي؟ + معلومات + إغلاق + معرفة المزيد + تكون المنتجات المادية البسيطة فقط متوافقة مع نقطة بيع الآن. أما أنواع المنتجات الأخرى، مثل: المنتجات المتغيرة والظاهرية، ستصبح متوفرة في التحديثات المستقبلية. + إظهار المنتجات البسيطة فقط + عنوان الموقع + Google for WooCommerce + إضافة حملة مدفوعة + يمكنك زيادة المبيعات وإنشاء مزيد من حركة المرور باستخدام إعلانات غوغل. + حملات غوغل تم تم إنشاء حملتك الجديدة. أوقات مشوقة في انتظار مبيعاتك! كل شيء جاهز الآن! @@ -103,7 +120,6 @@ Language: ar الإجمالي الضريبة الإجمالي الفرعي - معاملة جديدة تمت عملية الدفع بنجاح فشلت عملية الدفع. يرجى المحاولة مجددًا. أيقونة عربة التسوق diff --git a/WooCommerce/src/main/res/values-de/strings.xml b/WooCommerce/src/main/res/values-de/strings.xml index 5c9d7eb0c59..245d4b2f21b 100644 --- a/WooCommerce/src/main/res/values-de/strings.xml +++ b/WooCommerce/src/main/res/values-de/strings.xml @@ -1,39 +1,56 @@ + Eine Zahlung in Höhe von %1$s wurde erfolgreich abgebucht + Neue Bestellung + OK + + Eine Bestellung im Shop-Management erstellen + Um die Zahlung für ein nicht einfaches Produkt entgegenzunehmen, beende POS und erstelle eine neue Bestellung über den Tab „Bestellungen“. + Derzeit können nur einfache physische Produkte mit POS verwendet werden.\nWeitere Produkttypen, wie variable und virtuelle, werden in künftigen Updates bereitgestellt. + Warum werden mir meine Produkte nicht angezeigt? + Info + Schließen + Weitere Informationen + Derzeit sind nur einfache physische Produkte mit POS kompatibel. Weitere Produkttypen, wie variable und virtuelle, werden in künftigen Updates bereitgestellt. + Es werden nur einfache Produkte angezeigt + Website-Adresse + Google für WooCommerce + Gebührenpflichtige Kampagne hinzufügen + Steigere deine Umsätze und generiere mehr Traffic mit Google Ads. + Google-Kampagnen Fertig Deine neue Kampagne wurde erstellt. Gute Aussichten für deine Verkaufszahlen! Fertig! Bestellung konnte nicht erstellt werden Erneut versuchen - Icon für Fehleranzeige Noch einmal versuchen? Fehler beim Laden der Produkte POS unterstützt derzeit nur einfache Produkte + Icon für Fehleranzeige POS unterstützt derzeit nur einfache Produkte – \nerstelle eins, um anzufangen. - Keine unterstützten Produkte gefunden Keine Produkte Zeit, deine Kunden glücklich zu machen - Wird geladen - Erhalte Support - Kartenlesegerät verbinden + Keine unterstützten Produkte gefunden Foto entfernt Bild wird gescannt Fototext zur Startinfo hinzugefügt - Von Foto gescannten Text hinzufügen + Wird geladen + Erhalte Support + Kartenlesegerät verbinden Klicks Aufrufe Konversion Ausgaben Umsatz insgesamt Kennzahl - Umsatz insgesamt: %1$s Ausgaben: %1$s + Von Foto gescannten Text hinzufügen + Umsatz insgesamt: %1$s Filterauswahl Warenkorb ist leer Tippe auf ein Produkt, um \nes dem Warenkorb hinzuzufügen @@ -80,17 +97,17 @@ Language: de Kunden Kundeneinsichten erhalten Kunden + Foto ausgewählt Beim Scannen des Texts auf dem Foto ist ein Fehler aufgetreten. Bitte versuche es erneut Bild wird gescannt - Foto ausgewählt Foto entfernen Foto ersetzen Foto ansehen Name, Zusammenfassung und Beschreibung Du kannst die Produktdetails vor dem Speichern bearbeiten oder neu generieren. Programme - Google-Kampagnen Keine Programme in diesem Zeitraum + Google-Kampagnen Jetzt verbinden Warenkorb Produktdetails erstellen @@ -103,17 +120,16 @@ Language: de Gesamt Steuer Zwischensumme - Neue Transaktion Zahlung erfolgreich Zahlung fehlgeschlagen. Bitte versuche es erneut. Warenkorb-Icon Produkte Produktbild - %d Artikel - Löschen Steigere deine Umsätze und generiere mehr Traffic mit Google Ads Google für WooCommerce Keine Mengenregeln + %d Artikel + Löschen Zielgruppe Abbrechen Beenden @@ -127,8 +143,8 @@ Language: de POS beenden Neue Abschnitte hinzufügen Für den ausgewählten Lagerbestand wurden keine Produkte gefunden - Bestandsberichte für Produkte konnten nicht geladen werden Keine Artikel in den letzten 30 Tagen verkauft + Bestandsberichte für Produkte konnten nicht geladen werden %d Artikel in den letzten 30 Tagen verkauft Nutze die App als Kasse Modus „Verkaufsort“ (POS) @@ -186,28 +202,28 @@ Language: de Vorgeschlagenes Produkt Versuche, diese Karte erneut zu laden. Wenn das Problem weiterhin besteht, <a href=\"support\">wende dich bitte an den Support</a>. Daten konnten nicht geladen werden - %s ausblenden Abgeschlossen Feedback - Achte darauf, dass auf deiner Website die neueste Version von WooCommerce ausgeführt wird und WooCommerce-Analysen aktiviert ist. Wir können die\n Analysen deines Shops nicht anzeigen + %s ausblenden + Achte darauf, dass auf deiner Website die neueste Version von WooCommerce ausgeführt wird und WooCommerce-Analysen aktiviert ist. Alle Aufgaben anzeigen Analysedaten für Sitzungen basieren auf Besucherzahlen, die für individuelle Zeiträume nicht verfügbar sind Sitzungsdaten nicht verfügbar Nicht verfügbar Performance Individuell - Button zum Ändern des Zeitraums Die Bilder sind nicht verfügbar, weil deine Website als privat markiert ist. Du kannst dies ändern, indem du zum Modus „Demnächst verfügbar“ wechselst.\n + Button zum Ändern des Zeitraums Auswahl von Analysekarten Abbrechen Trotzdem beenden Du hast die App-Verbindung anscheinend noch nicht genehmigt. Bist du sicher, dass du den Vorgang beenden möchtest? - Bitte wähle ein Bild aus, das mindestens 400 x 400 Pixel groß ist Ungültiges Bild Der eingegebene Benutzername und das eingegebene Passwort stimmen offenbar nicht überein. Überprüfe deine Anmeldedaten und versuche es noch einmal. Wenn deine Daten immer noch nicht geladen werden, wende dich an unser Support-Team, um Unterstützung zu erhalten. Keine Verbindungsprobleme + Bitte wähle ein Bild aus, das mindestens 400 x 400 Pixel groß ist Zurück zum vorherigen Bildschirm Verbindung erneut versuchen Verbindung mit deiner Website wird hergestellt @@ -231,12 +247,12 @@ Language: de Individuellen Betrag hinzufügen Um einen Zahlungsbetrag festzulegen, füge\ndeiner neuen Bestellung einen individuellen Betrag hinzu. Wir haben die Funktion zum Empfang von Zahlungen mit der\nBestellerstellung kombiniert – für ein zugänglicheres\nund leistungsstärkeres Erlebnis. - Die Funktion zum Empfang von Zahlungen \nwurde verschoben Pakete Verkaufte Pakete Pakete Verkaufte Pakete Blaze-Kampagnen + Die Funktion zum Empfang von Zahlungen \nwurde verschoben Topseller Bist du sicher, dass du die an diesem Produkt vorgenommenen Änderungen verwerfen möchtest? Du bist im Begriff, Änderungen an %s zu verwerfen @@ -261,16 +277,16 @@ Language: de Vorschläge Gib eine Domain ein Wähle eine Domain - Alle Shop-Analysen anzeigen Jährlich Monatlich Wöchentlich Täglich Stündlich - Intervall: %s Weiteren Shop verbinden Erstellst du einen neuen Shop? Shop-Name + Intervall: %s + Alle Shop-Analysen anzeigen Bitte warten … Lagerbestände werden aktualisiert Etwas ist schiefgegangen. Bitte versuche es erneut. @@ -301,17 +317,17 @@ Language: de Fehler beim Verschieben der Bestellung in den Papierkorb Bestellung in den Papierkorb verschoben Anscheinend gibt es ein Problem mit deiner Website.\n\nKontaktiere deinen Hosting-Anbieter, um weitere Unterstützung zu erhalten. + Du bist scheinbar nicht mit dem Internet verbunden.\n\nStelle sicher, dass dein WLAN eingeschaltet ist. Falls du mobile Daten verwendest, solltest du prüfen, ob sie in deinen Geräteeinstellungen aktiviert sind. Anscheinend gibt es ein Problem mit deiner Jetpack-Verbindung.\n\nAber keine Sorge, unser Support-Team wird dich unterstützen. Kontaktiere uns und wir helfen dir gerne weiter. Wir können mit der Antwort deiner Website anscheinend nicht richtig arbeiten.\n\nAber keine Sorge, unser Support-Team wird dich unterstützen. Kontaktiere uns und wir helfen dir gerne weiter. Deine Website braucht anscheinend zu lange, um zu antworten.\n\nKontaktiere deinen Hosting-Anbieter, um weitere Unterstützung zu erhalten. - Du bist scheinbar nicht mit dem Internet verbunden.\n\nStelle sicher, dass dein WLAN eingeschaltet ist. Falls du mobile Daten verwendest, solltest du prüfen, ob sie in deinen Geräteeinstellungen aktiviert sind. - Produkt nicht ausgewählt Weitere Informationen + Internetverbindung + Produkt nicht ausgewählt Support kontaktieren + Statistiken zum angepassten Zeitraum hinzufügen Befehle deiner Website werden abgerufen Verbindung zu den Servern von WordPress.com wird hergestellt - Internetverbindung - Statistiken zum angepassten Zeitraum hinzufügen Kein Ort gefunden.\nBitte versuche es erneut. Seitenaufrufe der Sitzung Gerätetyp @@ -373,22 +389,22 @@ Language: de Ziehpunkt Analysekarten Bericht anzeigen - Die Startseite der Website Die Produkt-URL URL-Parameter Ziel-URL - Manuell eingeben - Suche fehlgeschlagen\nBitte versuche es erneut Beginne mit der Eingabe des Landes, Bundeslandes oder der Stadt, um verfügbare Optionen anzuzeigen + Die Startseite der Website + Manuell eingeben Indem du auf „Kampagne absenden“ klickst, akzeptierst du die <a href=\'termsOfService\'><u>Geschäftsbedingungen</u></a> sowie die <a href=\'advertisingPolicy\'><u>Werberichtlinien</u></a> und erlaubst, dass deine Zahlungsmethode für die von dir gewählte Dauer mit dem von dir gewählten Budget belastet wird. <a href=\'learnMore\'><u>Hier findest du weitere Informationen</u></a> zu Budgets und Zahlungen für beworbene Beiträge. + Suche fehlgeschlagen\nBitte versuche es erneut Kampagne absenden - Fehler beim Laden der Zahlungsmethoden. Versuche es erneut, indem du hier klickst! Zahlungsmethode hinzufügen - Zahlungsmethoden werden geladen Gesamt Blaze-Kampagne Zahlungsübersicht Zahlung + Fehler beim Laden der Zahlungsmethoden. Versuche es erneut, indem du hier klickst! + Zahlungsmethoden werden geladen Orte suchen Beleg konnte nicht gespeichert werden Beleg konnte nicht heruntergeladen werden @@ -403,20 +419,20 @@ Language: de Beginnt %1$s Tage Dauer festlegen - Aufrufe geben die Häufigkeit an, mit der deine Werbung potenziellen Kunden angezeigt wird.\n\n\n Auch wenn aufgrund von schwankendem Internet-Traffic und Nutzerverhalten keine genauen Zahlen garantiert werden können, versuchen wir, die tatsächlichen Aufrufe deiner Werbeanzeige so genau wie möglich mit deiner Zielzahl abzugleichen.\n\n\n Denke daran, dass es bei Aufrufen um die Sichtbarkeit geht und nicht um vom Betrachter ausgeführte Aktionen. Fertig Aufrufe Update Bearbeiten Dauer Geschätzte Anzahl erreichter Personen pro Tag - %1$s täglich für %1$s Tage + Aufrufe geben die Häufigkeit an, mit der deine Werbung potenziellen Kunden angezeigt wird.\n\n\n Auch wenn aufgrund von schwankendem Internet-Traffic und Nutzerverhalten keine genauen Zahlen garantiert werden können, versuchen wir, die tatsächlichen Aufrufe deiner Werbeanzeige so genau wie möglich mit deiner Zielzahl abzugleichen.\n\n\n Denke daran, dass es bei Aufrufen um die Sichtbarkeit geht und nicht um vom Betrachter ausgeführte Aktionen. Gesamtbestellwert Wie viel möchtest du für deine Produkt-Werbekampagne ausgeben? Dein Budget festlegen Alle %1$s Tage seit %2$s + %1$s täglich Nicht erneut anzeigen Später daran erinnern Hast du eine Minute? Hilf uns mit einem kurzen Feedback, unsere KI-gestützten Funktionen zu verbessern. @@ -429,8 +445,8 @@ Language: de Budget Details Jetzt einkaufen - Werbung bearbeiten Vorschau + Werbung bearbeiten Deaktiviert Produktauswahl Produkt %s auswählen @@ -441,12 +457,12 @@ Language: de <b>Auswahl des Produkts:</b> Wähle, was du mit Blaze bewerben möchtest. Bestand verwalten Bestand nicht verwaltet - So funktioniert Blaze Deine Kampagne starten Deine Werbung auf Millionen Websites in den WordPress.com- und Tumblr-Netzwerken. Erziele eine große Reichweite „Unser Tool zeigt dein Produkt dort an, wo es von interessierten Käufern gefunden werden kann.“ Globale Reichweite leicht gemacht + So funktioniert Blaze Veröffentliche Werbung in Minutenschnelle – ohne Erfahrung oder großes Budget – schon ab 5 USD täglich. Schneller Start, große Wirkung Unser Tool ermöglicht es Händlern, Werbekampagnen schnell und einfach einzurichten, um maximalen Traffic zu erzielen. @@ -492,7 +508,6 @@ Language: de Das Produkt mit der SKU %s wird nicht im Lager verwaltet. Bitte versuche es erneut. Das Produkt mit der SKU %s wurde nicht gefunden. Bitte versuche es erneut. Theme konnte nicht aktiviert werden. Bitte versuche es erneut! - Der Benachrichtigungston für Bestellungen wurde deaktiviert. Aktiviere ihn wieder, um bei jedem neuen Verkauf den typischen Ka-tsching-Ton zu hören. Ka-tsching-Ton aktivieren Scanne den Barcode, um den Lagerbestand zu aktualisieren Dies ist nur eine Testbenachrichtigung, um den Ka-tsching-Ton zu überprüfen.\nDu kannst sie einfach wegwischen. @@ -504,9 +519,10 @@ Language: de Aktiviere ihn wieder, um bei jedem neuen Verkauf das Ka-tsching-Geräusch zu hören. Bleibe bei Kundenbestellungen auf dem Laufenden! Ka-tsching-Ton deaktiviert Bestell-Zähler - % 0 Prozentsatz der Gesamtbestellung + Der Benachrichtigungston für Bestellungen wurde deaktiviert. Aktiviere ihn wieder, um bei jedem neuen Verkauf den typischen Ka-tsching-Ton zu hören. + % Fester Betrag Wie möchtest du deinen individuellen Betrag hinzufügen? Prozentsatz der Gesamtbestellung (%1$s) @@ -528,9 +544,9 @@ Language: de Teilen Neu generieren ✨ Die Dankeschön-Nachricht für deine Bestellung wird erstellt … - Dankeschön-Nachricht Hinweis: Wenn diese Einstellung aktiviert werden soll, darf das Abonnement keinen Gratis-Test oder synchronisiertes Verlängerungsdatum haben. Aktiviere diese Option, um die Versandkosten nur einmal bei der ursprünglichen Bestellung zu berechnen. + Dankeschön-Nachricht Aktiviert Einmaliger Versand Dokumente und andere Dateien auf dem Gerät @@ -540,7 +556,6 @@ Language: de Verfügbares Guthaben wird automatisch jeden Tag ausgezahlt. Guthaben, das seit %d Tagen aussteht, wird zur Verfügung gestellt. Variante auswählen - Variante wählen „%1$s“ -> %2$s Bitte wähle eine Variante aus %1$s Artikel ausgewählt @@ -552,6 +567,7 @@ Language: de zwischen %1$s und %2$s Artikeln %d Artikel %d Artikel + Variante wählen Ändere die Produktmenge von %1$.2f zu %2$.2f Konfiguration speichern Konfiguration @@ -586,12 +602,12 @@ Language: de Geschätzt Zusammenfassung der Auszahlungen aus-/einblenden Weitere Informationen zum Erhalt deiner Zahlungen - Verfügbares Guthaben wird automatisch am %s jedes Monats ausgezahlt. - Guthaben, das seit %d Tag aussteht, wird zur Verfügung gestellt. Ausstehendes Guthaben Verfügbares Guthaben Steuern Produkte + Verfügbares Guthaben wird automatisch am %s jedes Monats ausgezahlt. + Guthaben, das seit %d Tag aussteht, wird zur Verfügung gestellt. Zahlungsübersicht E-Mail-Adresse oder Benutzername Bestellung mit individuellem Betrag konnte nicht erstellt werden @@ -615,12 +631,12 @@ Language: de Mit Blaze die Umsätze deines Shops steigern Beim Aktualisieren der Kampagnenliste ist ein Fehler aufgetreten. Bitte versuche es später erneut. Medienquelle auswählen - Beim Generieren von Produktname und -beschreibung ist ein Fehler aufgetreten. Kein Text erkannt. Bitte wähle ein anderes Foto der Verpackung aus oder gib die Produktdetails manuell ein. Produkt hinzufügen Barcode scannen Produktkarte einklappen/aufklappen Produktmenge verringern + Beim Generieren von Produktname und -beschreibung ist ein Fehler aufgetreten. Produktmenge erhöhen Individuellen Betrag hinzufügen Preis mit Rabatt @@ -652,16 +668,16 @@ Language: de 4. Dein Kunde hält seine Karte horizontal oben an dein Mobiltelefon, über das Kontaktlos-Symbol. 3. Zeige deinem Kunden dein Mobiltelefon. 2. Tippe auf „Zahlung empfangen“ und wähle „Tap to Pay“. - 1. Eine Bestellung erstellen So funktioniert es Weitere Informationen zu Kartenlesegeräten Wenn du Zahlungen oberhalb dieses Höchstbetrags akzeptieren möchtest, solltest du möglicherweise ein Kartenlesegerät erwerben, das die Eingabe einer PIN ermöglicht. Die PIN-Eingabe bei Tap to Pay auf Android wird nicht unterstützt. In %1$s erfordern manche Karten eine PIN für kontaklose Transaktionen über %2$s. + 1. Eine Bestellung erstellen Wichtige Informationen Mit Tap to Pay kannst du alle Arten der kontaktlosen Zahlung akzeptieren – beispielsweise physische Debit- und Kreditkarten, oder digitale Wallets –, ohne ein physisches Kartenlesegerät erwerben zu müssen. - Was ist Tap to Pay? Informationen zu Tap to Pay + Was ist Tap to Pay? Negative Rückmeldungen Positive Rückmeldungen Ist das Ergebnis hilfreich? @@ -686,8 +702,8 @@ Language: de Für mich schreiben Erzähle uns mehr von deinem Produkt und was es einzigartig macht! Lasse die KI ansprechende Titel für dich generieren - Produktname Deaktiviere den Filter für ungelesene Produktbewertungen, damit dir alle angezeigt werden + Produktname Keine ungelesenen Produktbewertungen Tonalität ausgewählt Überzeugend @@ -734,8 +750,8 @@ Language: de Steuersatz festlegen Aktivieren Neuen Steuersatz festlegen - WooPayments Einrichten + WooPayments Steuersätze in der Administration bearbeiten Dadurch wird die Adresse des Kunden in den Ort des Steuersatzes geändert, der von dir ausgewählt wurde. Button zum Öffnen des Info-Dialogs zu Steuersätzen @@ -783,16 +799,16 @@ Language: de Gesamtbestellsumme Berechneter Prozentsatz Berechneter Betrag - Name des Shops Wenn du den Namen deines Shops festlegst, kann auch die Suchmaschinenoptimierung für deinen Shop verbessert werden. + Name des Shops Benenne deinen Shop NFC aktivieren Paket, das unter die Regelung für kleine Mengen fällt (Small Quantity Provision Package) (Markierungen erforderlich) - Paket mit begrenzter Menge, das auf dem Landweg versendet wird (LTD QTY Ground Package) – Sprays, Desinfektionssprays, Sprühfarbe, Haarspray, Propan, Butan, Reinigungsprodukte usw. – Duftstoffe, Nagellack, Nagellackentferner, Lösemittel, Händedesinfektionsmittel, Reinigungsalkohol, Ethanol Base-Produkte usw. – Andere Oberflächenmaterialien mit begrenzter Menge (Kosmetika, Reinigungsprodukte, Farben usw.) Paket für Feuerzeuge (Lighters Package) – Autorisierte Feuerzeuge + Paket mit begrenzter Menge, das auf dem Landweg versendet wird (LTD QTY Ground Package) – Sprays, Desinfektionssprays, Sprühfarbe, Haarspray, Propan, Butan, Reinigungsprodukte usw. – Duftstoffe, Nagellack, Nagellackentferner, Lösemittel, Händedesinfektionsmittel, Reinigungsalkohol, Ethanol Base-Produkte usw. – Andere Oberflächenmaterialien mit begrenzter Menge (Kosmetika, Reinigungsprodukte, Farben usw.) + Paket, das unter die Regelung für Ausnahmemengen fällt (Excepted Quantity Provision Package) (z. B. kleine Mengen an entzündbaren Flüssigkeiten, Beizmittel, giftige oder umweltgefährdende Materialien – Markierung erforderlich) ID8000 Paket mit Bedarfsartikeln (ID8000 Consumer Commodity Package) – Für den Lufttransport geeignete ID8000 Bedarfsartikel (Nicht entzündbare Sprays, entzündbare, brennbare Flüssigkeiten, giftige Substanzen, verschiedene Gefahrenstoffe) Gefahrenstoffe, die nur auf dem Landweg versendet werden (Für Gegenstände, die nicht aufgeführt sind, aber nur auf dem Landweg gesendet werden dürfen) - Paket, das unter die Regelung für Ausnahmemengen fällt (Excepted Quantity Provision Package) (z. B. kleine Mengen an entzündbaren Flüssigkeiten, Beizmittel, giftige oder umweltgefährdende Materialien – Markierung erforderlich) Bereich 6.2 – Gefahrenstoffe – Biologische Materialien (Hazardous Materials - Biological Materials) (z. B. Labortestkits, autorisierte Rücksendungen von COVID-Testkits) Bereich 6.1 – Paket mit giftigen Materialien (Toxic Materials Package) (mit einem LD50-Wert von 50 mg/kg oder weniger) – (Pestizide, Unkrautvernichtungsmittel usw.) Bereich 5.2 – Paket mit organischen Peroxiden (Organic Peroxides Package) @@ -812,8 +828,8 @@ Language: de Klasse 4 – Paket (Entzündbare Feststoffe) Klasse 3 – Paket (Händedesinfektionsmittel, Reinigungsalkohol, Ethanol Base-Produkte, entzündbare Flüssigkeiten usw.) Klasse 1 – Paket mit Spielzeugtreibgas/Schmelzsicherung (Toy Propellant/Safety Fuse Package) - Paket mit Ethanol, das auf dem Luftweg versendet werden darf (Air Eligible Ethanol Package) – (Versand von autorisierten Duftstoffen und Händedesinfektionsmittel) OK + Paket mit Ethanol, das auf dem Luftweg versendet werden darf (Air Eligible Ethanol Package) – (Versand von autorisierten Duftstoffen und Händedesinfektionsmittel) Zu den potenziell gefährlichen Materialien zählen u. a. Batterien, Trockeneis, brennbare Flüssigkeiten, Sprühdosen, Munition, Feuerwerkskörper, Nagellack, Parfüm, Farben und Lösemittel. Gefährliche Gegenstände müssen in separaten Paketen versendet werden. Enthält Gefahrstoffe Produkttitel eingeben. @@ -833,7 +849,6 @@ Language: de Festen Rabatt auf Endpreis ausgewählter Produkte erstellen Festen Rabatt auf Endpreis des gesamten Warenkorbs erstellen Prozentualen Rabatt auf ausgewählte Produkte erstellen - Fester Produkt-Rabatt Fester Warenkorb-Rabatt Prozentualer Rabatt Gutscheintyp – festes Produkt @@ -850,6 +865,7 @@ Language: de Testbestellung ausprobieren Führe eine Testbestellung durch, um sicherzugehen, dass die Kunden in deinem WooCommerce-Shop ein reibungsloses Einkauferlebnis genießen Details manuell hinzufügen + Fester Produkt-Rabatt Suche nach Kunden anhand von Sonstiger Grund (bitte angeben) Ich bin Mitglied eines Teams und wir treffen die Entscheidung gemeinsam. @@ -859,9 +875,9 @@ Language: de Hilf uns, deine Abonnemententscheidungen nachzuvollziehen. Dein Feedback ist uns wichtig. Keine E-Mail-Adresse Kein Name - Suche nach bestehendem Kunden oder Letzte Aktualisierung: %s (wird alle 30 Minuten aktualisiert) Letzte Aktualisierung: %s + Suche nach bestehendem Kunden oder <a href=\'\'>Weitere Informationen</a> dazu, wie du Zahlungen über Tap To Pay auf Android empfangen kannst Zahlung empfangen Es können keine Produkte hinzugefügt werden, für die kein Preis angegeben ist @@ -904,10 +920,10 @@ Language: de Problembehandlung Dies könnte mit einem Konflikt mit einem Plugin zusammenhängen. Bitte versuche es später erneut oder kontaktiere uns – wir helfen dir gerne weiter! Deine Daten konnten nicht geladen werden. - Füge mit KI im Handumdrehen Beschreibungen hinzu. Probiere die Funktion noch heute aus! Produktbeschreibung mit KI hinzufügen Verstanden Beachte bitte, dass diese Produktbeschreibung mit unserem KI-gestützten Tool erstellt wurde. Überprüfe und bearbeite den Inhalt entsprechend, damit er deiner Marke und Botschaft entspricht. + Füge mit KI im Handumdrehen Beschreibungen hinzu. Probiere die Funktion noch heute aus! Guter Start! Ist die generierte\nBeschreibung hilfreich? Neu generieren @@ -915,7 +931,6 @@ Language: de Beispiel: eingetopft, Kaktus, Pflanze, dekorativ, pflegeleicht Gib deinen Produktnamen ein Verfasse eine Beschreibung - Zum Scannen des Barcodes ist die Berechtigung zum Zugriff auf deine Kamera erforderlich. Barcode scannen Benutzername Name @@ -923,19 +938,20 @@ Language: de Gutscheine angewendet Weitere Einstellungen Vielleicht später + Zum Scannen des Barcodes ist die Berechtigung zum Zugriff auf deine Kamera erforderlich. Erneut schreiben Ein PIN-Code ist erforderlich, dies wird jedoch von Tap to Pay noch nicht unterstützt. Verwende stattdessen ein externes Kartenlesegerät Kaufe ein Kartenlesegerät Gutschein konnte nicht angewendet werden und wurde aus der Bestellung entfernt - Nachricht zum Teilen kann nicht erstellt werden. Versuche es bitte noch einmal! - Erfahre mehr über unsere KI-Funktion Optionale Nachricht hinzufügen - Schreiben … Mit KI schreiben Produkte mit Blaze bewerben Blaze - KI-Inhaltsgenerator verfügbar Mit Blaze bewerben + Nachricht zum Teilen kann nicht erstellt werden. Versuche es bitte noch einmal! + Erfahre mehr über unsere KI-Funktion + KI-Inhaltsgenerator verfügbar + Schreiben … Produkt teilen Glückwunsch! Du bist einen Schritt weiter auf dem Weg zu deinem neuen Shop. Erstes Produkt erstellt 🎉 @@ -962,7 +978,6 @@ Language: de Datenschutz Weitere Informationen zu den Daten, die wir über deinen Shop erfassen, sowie deinen Optionen zum Kontrollieren dieser Datenfreigabe. Nutzungsaufzeichnung - Es sind weitere Datenschutz-Optionen für woocommerce.com-Benutzer verfügbar. Hier erhältst du weitere Informationen. Web-Optionen Mehr Datenschutz-Optionen Beim Aktualisieren deiner Privatsphäre-Einstellungen ist ein Fehler aufgetreten @@ -971,10 +986,11 @@ Language: de Statistiken Sendungsverfolgung Der Schutz deiner Daten ist uns wichtig. Deine personenbezogenen Daten werden verwendet, um unsere Mobil-Apps zu optimieren, die Sicherheit zu verbessern, Analysen durchzuführen und dein Benutzererlebnis zu verbessern. - Das System hat die Woo-App beendet, die im Hintergrund ausgeführt wurde. Du kannst erneut versuchen, sie zu verwenden. Du kannst variable Produkte nicht direkt hinzufügen. Bitte gib eine bestimmte Variante an Scannen fehlgeschlagen. Bitte versuche es später erneut + Das System hat die Woo-App beendet, die im Hintergrund ausgeführt wurde. Du kannst erneut versuchen, sie zu verwenden. Das Produkt mit der SKU %s wurde nicht gefunden. Hinzufügen zu neuer Bestellung nicht möglich + Es sind weitere Datenschutz-Optionen für woocommerce.com-Benutzer verfügbar. Hier erhältst du weitere Informationen. Scannen fehlgeschlagen. Bitte versuche es später erneut Barcode scannen Beim Versand in Länder, die den Zollvorschriften der Europäischen Union (EU) unterliegen, musst du jeden Artikel ab sofort klar und deutlich beschreiben. Beispiel: Wenn du Bekleidung versendest, musst du die Art der Bekleidung angeben (z. B. Shirts für Männer, Weste für Mädchen, Jacke für Jungen), damit die Beschreibung akzeptiert wird. Ansonsten kann es zu Verzögerungen oder Unterbrechungen von Lieferungen durch den Zoll kommen. @@ -998,9 +1014,9 @@ Language: de Produkte per Scanner hinzufügen Schließen Weitere Informationen - Beim Versand in Länder, die den Zollvorschriften der Europäischen Union unterliegen, musst du eine klare, spezifische Beschreibung aller Artikel angeben. Ansonsten kann es zu Verzögerungen oder Unterbrechungen von Lieferungen durch den Zoll kommen. Bleibe auf dem neuesten Stand und erhöhe die Sicherheit deines Shops. Sieh dir Jetpack jetzt an. Erhalte Bestellbenachrichtigungen und vieles mehr + Beim Versand in Länder, die den Zollvorschriften der Europäischen Union unterliegen, musst du eine klare, spezifische Beschreibung aller Artikel angeben. Ansonsten kann es zu Verzögerungen oder Unterbrechungen von Lieferungen durch den Zoll kommen. Checkliste für die Store-Einrichtung ein- oder ausblenden Checkliste für die Store-Einrichtung Du kannst sie wiederherstellen, falls erforderlich. Gehe dazu zu Menü > Einstellungen > Shop @@ -1018,10 +1034,10 @@ Language: de Standardoption Komponentenoptionen Du kannst Komponenten im Web-Dashboard bearbeiten. - %d Komponenten 1 Komponente Komponenteneinstellungen Komponenten + %d Komponenten Wir benötigen deine Zustimmung, um Push-Benachrichtigungen zu neuen Bestellungen, Bewertungen usw. direkt auf dein Gerät senden zu können. Benachrichtigungen Zusammengesetztes Produkt @@ -1035,7 +1051,6 @@ Language: de Steigere deine Umsätze mit speziellen Angeboten Deinen Shop ansehen Bleibe auf dem Laufenden - Nutze mobile Zahlungen Verwalte mehr als Admin Allgemeines Einstellungen @@ -1047,6 +1062,7 @@ Language: de Kein Maximalbetrag Kein Mindestbetrag Paket + Nutze mobile Zahlungen Gruppe von Höchstmenge Mindestmenge @@ -1079,11 +1095,7 @@ Language: de Aktiv Du kannst Produkt-Abonnements im Web-Dashboard bearbeiten. Kein Testzeitraum - Keine Registrierungsgebühr Nie ablaufend - %1$s alle %2$s %3$s - Alle %1$d %2$s - Jeden/Jedes %1$s Abonnement-Nr. %1$d Abonnement OK @@ -1094,15 +1106,19 @@ Language: de SMS angefordert. Bitte schau in deinen Nachrichten nach dem Code. Abonnement Das Kartenlesegerät akzeptiert Debit- oder Kreditkartenzahlung, die per Auflegen, Chip oder Durchziehen erfolgen. + Keine Registrierungsgebühr + %1$s alle %2$s %3$s + Alle %1$d %2$s + Jeden/Jedes %1$s Akzeptiere kontaktlose Zahlungen sicher und direkt über dein Mobiltelefon. - Nutze dein Mobiltelefon zum Akzeptieren von\nKartenzahlungen. Teste es jetzt. - Feedback teilen Die Anmeldung ist nicht möglich, weil die Erstellung von Anwendungspasswörtern nicht genehmigt wurde. Website wird abgerufen … + Nutze dein Mobiltelefon zum Akzeptieren von\nKartenzahlungen. Teste es jetzt. + Feedback teilen + Lädt… Beim Abrufen der Website ist ein Fehler aufgetreten Versuche es über die WP Admin-Seite erneut Anmelden - Lädt… %s wurde beendet Dein Abonnement wurde beendet. Du hast jetzt nur noch eingeschränkten Zugriff auf alle Funktionen. %1$d Tage @@ -1117,13 +1133,11 @@ Language: de Fehler beim Abrufen der Tarifdetails Du hast %1$s abonniert! Bis zum %2$s kannst du auf alle Funktionen zugreifen. Dein Gratis-Test ist abgelaufen und du hast nun eingeschränkten Zugriff auf alle Funktionen. Abonniere jetzt %1$s. - Du nutzt gerade den %1$d-tägigen Gratis-Test. Der Gratis-Test endet in %2$s. Führe ein Upgrade durch, um von neuen Funktionen zu profitieren und deinen Shop weiterhin zu betreiben. Abonnement-Status Problembehandlung Aktuell: %s Problem mit Abonnement melden Jetzt Upgrade durchführen - Noch %1$s bis zum Ablauf des Testzeitraums. Gratis-Test abgelaufen Dein Gratis-Test ist abgelaufen. Ups, es sind unerwartete Fehler aufgetreten. @@ -1139,6 +1153,8 @@ Language: de Meinen Shop veröffentlichen Bitte aktualisiere deinen Tarif, um deinen Shop zu starten. <u>Upgrade durchführen</u> Domains durchsuchen + Du nutzt gerade den %1$d-tägigen Gratis-Test. Der Gratis-Test endet in %2$s. Führe ein Upgrade durch, um von neuen Funktionen zu profitieren und deinen Shop weiterhin zu betreiben. + Noch %1$s bis zum Ablauf des Testzeitraums. Die Anmeldung ist fehlgeschlagen: Statuscode %1$s Die Anmeldung ist fehlgeschlagen, da die Admin-URL deines Shops nicht ermitteln werden konnte Die Anmeldung ist fehlgeschlagen, da die Anmelde-URL deines Shops nicht ermittelt werden konnte @@ -1166,7 +1182,6 @@ Language: de Nachricht Supportanfrage senden Betreff - Teile uns deine Website-Adresse (URL) mit und gib uns möglichst viele Informationen zu dem Problem. Wir melden uns bei dir. Lass uns das Problem lösen Ich brauche Hilfe bei Supportanfrage @@ -1178,6 +1193,7 @@ Language: de Biete deinen Kunden eine einfache und bequeme Möglichkeit zu bezahlen! Erhalte Zahlungen Wir verwenden die Informationen, damit all deine Einstellungen zu Versand, Steuern und Zahlungen schnell eingerichtet werden können. + Teile uns deine Website-Adresse (URL) mit und gib uns möglichst viele Informationen zu dem Problem. Wir melden uns bei dir. Erzähl uns mehr über deinen Shop Wir haben gerade einen magischen Link an die E-Mail-Adresse deines Kontos gesendet Melde dich an, um fortzufahren @@ -1186,31 +1202,31 @@ Language: de Jetpack-Status wird abgerufen Etwas ist schiefgegangen. Bitte versuche es später erneut. Versuche, eine Zahlung vorzunehmen + Domainname wird registriert … + Land wählen + Bundesstaat auswählen Empfange Kartenzahlungen\nmit deinem Mobiltelefon Tap To Pay AKTIONEN Bei der Domain-Registrierung ist ein Fehler aufgetreten - Bundesstaat auswählen - Land wählen - Domainname wird registriert … - Domain registrieren - Postleitzahl - Status (nicht verfügbar) - Bundesstaat - Ort - Adresse 2 - Adresse - Land - Ländercode Telefon - Organisation (optional) + Ländercode + Land + Adresse + Adresse 2 + Ort + Bundesstaat + Status (nicht verfügbar) + Postleitzahl + Domain registrieren Wir haben bereits deine WordPress.com-\n Kontaktinformationen für dich ausgefüllt. Überprüfe bitte, ob wir die Informationen, die du für diese Domain verwenden möchtest, korrekt eingegeben haben. - Domain-Kontaktdaten - Öffentlich registrieren - Privat mit Datenschutz registrieren - Bitte gib eine gültige %s ein - Mit der Registrierung dieser Domain stimmst du unseren %1$sBestimmungen und Konditionen%2$s zu + Organisation (optional) Domain-Eigentümer müssen ihre Kontaktinformationen in einer öffentlichen Datenbank aller Domains veröffentlichen.\n Durch den Datenschutz veröffentlichen wir unsere eigenen Informationen anstatt deinen und leiten sämtliche Kommunikation vertraulich an dich weiter. + Mit der Registrierung dieser Domain stimmst du unseren %1$sBestimmungen und Konditionen%2$s zu + Bitte gib eine gültige %s ein + Privat mit Datenschutz registrieren + Öffentlich registrieren + Domain-Kontaktdaten Datenschutz Nur Shop-Administratoren haben Zugriff auf die Domain-Einstellungen Oder fahre mit dem magischen Link fort @@ -1218,10 +1234,10 @@ Language: de Gib das Passwort für dein WordPress.com-Konto ein, um dich mit Jetpack zu verbinden Melde dich mit deinem WordPress.com-Konto an, um Jetpack zu installieren Melde dich mit deinem WordPress.com-Konto an, um dich mit Jetpack zu verbinden - Die Domaineinstellungen findest du unter „Einstellungen“ -> „Domains“ Deine Website-Adresse wird eingerichtet. Es kann bis zu 30 Minuten dauern, bis deine Domain funktioniert. Herzlichen Glückwunsch zu deinem Kauf Im ersten Jahr kostenlos + Die Domaineinstellungen findest du unter „Einstellungen“ -> „Domains“ Möchtest du dich wirklich von deinem Konto abmelden? Website-Domains konnten nicht geladen werden %1$d/%2$d abgeschlossen @@ -1236,18 +1252,18 @@ Language: de Dein Gerät wird nicht unterstützt. Bitte wende dich an den Support, um weitere Informationen zu erhalten Die App konnte den Kartenleser nicht aktivieren, da der NFC-Chip deaktiviert ist Die Transaktion wurde abgebrochen - Die erworbene Domain wird Benutzer weiterleiten zu Domain auswählen + Die erworbene Domain wird Benutzer weiterleiten zu Domain hinzufügen Deine Website-Domains - Haupt-Website-Adresse - Erhalte <a href=\'\'><u>weitere Informationen</u></a> über Domains und Aktionen, die du im Zusammenhang mit Domains durchführen kannst. Nach einer Domain suchen - Die erworbene Domain wird Benutzer an deine Hauptadresse weiterleiten. Domain beantragen In deinem Tarif ist eine kostenlose Domain-Registrierung für ein Jahr enthalten. Kostenlose Domain in Anspruch nehmen Deine kostenlose Shop-Adresse + Haupt-Website-Adresse + Erhalte <a href=\'\'><u>weitere Informationen</u></a> über Domains und Aktionen, die du im Zusammenhang mit Domains durchführen kannst. + Die erworbene Domain wird Benutzer an deine Hauptadresse weiterleiten. Domains Nicht erneut anzeigen Später daran erinnern @@ -1260,29 +1276,29 @@ Language: de Gefällt dir die persönliche Zahlung? Teile deine Erfahrung zum Annehmen persönlicher Zahlungen. Wie können wir dir mit persönlichen Verkäufen weiterhelfen? - %1$s kopieren Bitte warte, während wir eine Kopie dieses Produkts in deinem Shop speichern - Dein Produkt wird dupliziert … Produkt kann nicht dupliziert werden Duplizieren + %1$s kopieren + Dein Produkt wird dupliziert … Die Zahlung wird vorbereitet Das geht ganz schnell! + Domain Der integrierte Kartenleser wird vorbereitet … Der integrierte Kartenleser ist bereit - Kartenlesegerät - Tap To Pay - Zielabschlussrate Sitzungen Keine Sitzungen für diesen Zeitraum Verglichen mit - Domain + Tap To Pay + Kartenlesegerät + Zielabschlussrate Was sind Anwendungs-Passwörter? Anscheinend ist die Funktion „Anwendungs-Passwörter“ auf deiner Website %1$s deaktiviert.\n Bitte aktiviere sie, um die WooCommerce-App verwenden zu können. Installationsseite öffnen Der gescannte QR-Code ist kein WooCommerce-Code. - Beim Senden der Antwort ist ein Fehler aufgetreten. - Antwort gesendet! Antworten + Antwort gesendet! + Beim Senden der Antwort ist ein Fehler aufgetreten. Alle auswählen Preis aktualisieren Status aktualisieren @@ -1293,29 +1309,28 @@ Language: de Alle Varianten wurden bereits erstellt. Keine zu erstellenden Varianten Mehrere auswählen - Für diese Suche sind keine Domains verfügbar Varianten erstellen - Dadurch wird eine neue Variante für jede mögliche Kombination von Variantenattributen erstellt (%1$d Varianten). Alle Varianten erstellen? Derzeit können maximal %1$d Varianten erstellt werden. Bei diesem Produkt würden %2$d Varianten erstellt werden. Maximale Anzahl an Varianten überschritten - Erstellt Varianten für alle Kombinationen deiner Attribute. - Alle Varianten erstellen - Erstelle eine neue Variante. Lege manuell fest, welche Attribute zu dem variablen Produkt gehören. Neue Variante hinzufügen Variante hinzufügen + Dadurch wird eine neue Variante für jede mögliche Kombination von Variantenattributen erstellt (%1$d Varianten). + Erstellt Varianten für alle Kombinationen deiner Attribute. + Erstelle eine neue Variante. Lege manuell fest, welche Attribute zu dem variablen Produkt gehören. + Alle Varianten erstellen + Für diese Suche sind keine Domains verfügbar Ohne Verbindung beenden Mit der Verbindung fortfahren - Versuche erneut, eine Verbindung herzustellen, um auf deinen Shop zuzugreifen. Jetpack ist installiert, aber nicht verbunden. Du bist nicht berechtigt, diesen Shop mit Jetpack zu verbinden Wende dich an deinen Shop-Manager oder Administrator, um Hilfe zu erhalten. + Versuche erneut, eine Verbindung herzustellen, um auf deinen Shop zuzugreifen. Installation abbrechen Autorisierung erneut versuchen Aktivierung erneut versuchen Installation erneut versuchen Unterstützung erhalten - Bitte versuche es erneut und wende dich an den Support, falls dieser Fehler weiterhin auftritt. Bei der Kommunikation mit deiner Website ist ein Fehler aufgetreten. Du bist nicht berechtigt, Plugins in diesem Shop zu verwalten Fehler beim Autorisieren der Verbindung mit Jetpack @@ -1339,30 +1354,31 @@ Language: de Jetpack wird installiert Melde dich mit deinen Shop-Anmeldedaten bei <b>%1$s</b> an, um Jetpack zu verbinden. Melde dich mit deinen Shop-Anmeldedaten bei <b>%1$s</b> an, um Jetpack zu installieren. + Bitte versuche es erneut und wende dich an den Support, falls dieser Fehler weiterhin auftritt. Halte deine Shop-Anmeldedaten griffbereit. Bitte verbinde deinen Shop mit Jetpack, um in dieser App darauf zuzugreifen. Bitte installiere das kostenlose Jetpack-Plugin, um in dieser App auf deinen Shop zuzugreifen. Richte einen attraktiven Onlineshop ein und starte mit dem Verkauf – einfach und schnell. Erstelle deinen ersten Shop + Immer Zufällig Nie - Immer Schlüssel des simulierten Lesegeräts aktualisieren Simuliertes Kartenlesegerät aktivieren Jetpack verbinden Shop verbinden - Hier finden dich Personen im Internet. Keine Sorge, du kannst das später noch ändern. Besucher + Hier finden dich Personen im Internet. Keine Sorge, du kannst das später noch ändern. Oder mit Passwort anmelden Zum Anmelden den QR-Code scannen Simuliertes Kartenlesegerät wurde deaktiviert - Schlüssel des simulierten Lesegeräts Aktualisierte Lagerbestandsmenge - Die aktuelle Lagerbestandsmenge ist eine gemischte Zahl Aktuelle Lagerbestandsmenge: %d Lagerbestandsmenge wird aktualisiert Die Lagerbestandsmenge wird für %d Varianten aktualisiert + Schlüssel des simulierten Lesegeräts Lagerbestand + Die aktuelle Lagerbestandsmenge ist eine gemischte Zahl Herausgefilterte Produkte suchen Herausgefilterte Bestellungen suchen Bestehenden Shop verbinden @@ -1381,21 +1397,21 @@ Language: de Keine Bestellungen in diesem Zeitraum Keine Einnahmen in diesem Zeitraum Einnahmen - %1$s – %2$s Wir konnten leider kein Konto für die angegebenen Anmeldedaten erstellen. Versuche es bitte mit einer anderen E-Mail-Adresse. Dein Passwort entspricht nicht unseren Sicherheitsrichtlinien. Bitte versuche es mit einem komplexeren Passwort. Dein Passwort ist zu kurz. Bitte wähle ein Passwort mit mindestens 6 Zeichen. Bitte gib eine gültige E-Mail-Adresse ein. Es ist bereits ein Konto mit dieser E-Mail-Adresse vorhanden. + %1$s – %2$s Andere Adresse versuchen Angepasster Zeitraum Angepasst - Was ist WordPress.com? - Neues Konto wird erstellt Wähle ein Passwort Deine E-Mail-Adresse + Neues Konto wird erstellt Los geht’s \nin Minuten Durch Tippen auf den Button „Jetpack verbinden“ stimmst du unseren <a href=\'terms\'>Geschäftsbedingungen</a> und dem <a href=\'sync\'>Teilen von Daten</a> mit WordPress.com zu. + Was ist WordPress.com? Simuliertes Kartenlesegerät aktivieren Bitte kontaktiere den Website-Betreiber, um eine Einladung zur Website als Shop-Manager oder Administrator zu erhalten und die App verwenden zu können. Mit einer WordPress.com-Website verbinden @@ -1419,8 +1435,8 @@ Language: de Bitte melde dich in der WooCommerce-App an Das Abrufen von Verbindungsdaten ist fehlgeschlagen … Die Jetpack-Verbindung wird überprüft … - Deine Jetpack-Verbindung kann nicht überprüft werden. Bitte versuche es erneut. Für die Website %1$s gilt derzeit ein WordPress.com-Tarif, in dem das Installieren von Plugins nicht möglich ist. Bitte führe ein Tarif-Upgrade durch, um WooCommerce nutzen zu können. + Deine Jetpack-Verbindung kann nicht überprüft werden. Bitte versuche es erneut. Offenbar ist dein Konto nicht mit Jetpack von %1$s verbunden KARTENLESEGERÄTE ZAHLUNGSOPTIONEN @@ -1434,53 +1450,50 @@ Language: de „Persönliche Zahlung“ aktivieren <a href=\'\'>Weitere Informationen</a> zu „Persönliche Zahlungen“ Neu bei WooCommerce - Es ist ein Fehler aufgetreten, kontaktiere bitte den Support Website-Adresse eingeben - Fordere einen Anmeldelink per E-Mail an + Es ist ein Fehler aufgetreten, kontaktiere bitte den Support Hast du dein Passwort vergessen? + Fordere einen Anmeldelink per E-Mail an Wir haben festgestellt, dass du die Einrichtung von Persönliche Zahlungen noch nicht abgeschlossen hast. <a href=\'\'>Mit der Einrichtung fortfahren</a> - Zahlungen - Verstanden! - Jetzt kannst du schnell und einfach auf Persönliche Zahlungen und andere Funktionen zugreifen + WC Admin + Melde dich mit deiner Shop-Adresse an + Andere Websites Zahlungen über den Tab „Menü“ + Jetzt kannst du schnell und einfach auf Persönliche Zahlungen und andere Funktionen zugreifen + Verstanden! + Zahlungen Deine E-Mail-Adresse wird nicht mit einem WordPress.com-Konto verwendet. - Andere Websites - Melde dich mit deiner Shop-Adresse an - WC Admin - Wir haben einen magischen Link an folgende Adresse geschickt: - Überprüfe dein Postfach auf diesem Gerät! - Mit Passwort anmelden - Mit magischem Link anmelden - Wir haben dir gerade einen magischen Link an deine E-Mail-Adresse gesendet. Tippe auf den Link in der E-Mail, um dich anzumelden. Melde dich mit deinen Website-Anmeldedaten an - Füge Upsell- und Cross-Sell-Möglichkeiten hinzu und gib deinen Kunden hilfreiche und relevante Produktempfehlungen - Steigere deine Verkaufszahlen mit verlinkten Produkten - Beginne in weniger als 20 Minuten mit dem persönlichen Verkauf – unser Kartenlesegerät macht es möglich. - Fehler beim Aktualisieren der Bestellnummer%1$d - Bestellnummer %1$d als abgeschlossen markiert - Markieren als\nabgeschlossen - WooCommerce installieren - %1$s ist offenbar keine WooCommerce-Website. - Zwischen mehreren Shops wechseln - Meine Bestellungen verwalten - Meine Produkte erstellen oder aktualisieren - Meine Statistiken überprüfen + Wir haben dir gerade einen magischen Link an deine E-Mail-Adresse gesendet. Tippe auf den Link in der E-Mail, um dich anzumelden. + Mit magischem Link anmelden + Mit Passwort anmelden + Überprüfe dein Postfach auf diesem Gerät! + Wir haben einen magischen Link an folgende Adresse geschickt: + Jetzt einrichten + Tipp Einen Shop einrichten - Mich umschauen + Meine Statistiken überprüfen + Meine Produkte erstellen oder aktualisieren + Meine Bestellungen verwalten + Zwischen mehreren Shops wechseln + %1$s ist offenbar keine WooCommerce-Website. + WooCommerce installieren + Fehler beim Aktualisieren der Bestellnummer%1$d + Steigere deine Verkaufszahlen mit verlinkten Produkten + Füge Upsell- und Cross-Sell-Möglichkeiten hinzu und gib deinen Kunden hilfreiche und relevante Produktempfehlungen Was möchtest du bei WooCommerce tun? - Tipp - Jetzt einrichten + Mich umschauen + Markieren als\nabgeschlossen + Bestellnummer %1$d als abgeschlossen markiert + Beginne in weniger als 20 Minuten mit dem persönlichen Verkauf – unser Kartenlesegerät macht es möglich. Es kann losgehen! Mit WordPress.com anmelden Support kontaktieren - Melde dich in deinem WordPress.com-Konto an - Erhalte Hilfe! Hast du Probleme bei der Anmeldung? Artikelnummer Alle Produkte NICHT ERNEUT ANZEIGEN SPÄTER DARAN ERINNERN - Kein Problem. Du kannst persönliche Zahlungen jederzeit in den Einstellungen aktivieren. Persönliche Zahlungen Kartenlesegerät kaufen Zahlungen problemlos empfangen @@ -1495,6 +1508,9 @@ Language: de Du kannst sie leicht und einfach verwalten Wir wissen, dass dies wichtig für dein Geschäft ist Neu bei WooCommerce + Erhalte Hilfe! + Kein Problem. Du kannst persönliche Zahlungen jederzeit in den Einstellungen aktivieren. + Melde dich in deinem WordPress.com-Konto an Neue Bestellung in Höhe von 50 US-Dollar in deinem WooCommerce-Shop Du hast eine neue Bestellung! 🎉 Details @@ -1503,10 +1519,10 @@ Language: de Bericht zum Systemstatus teilen Bericht zum Systemstatus in die Zwischenablage kopieren Weiter suchen - Persönliche Zahlung für Bestellung #%1$s für %2$s blog_id %3$s. Zahlungsanbieter ändern Rückerstattet: %1$s Warten auf Zahlung + Persönliche Zahlung für Bestellung #%1$s für %2$s blog_id %3$s. Mit Installation fortfahren Was du vor der Installation wissen solltest Erweiterung installieren @@ -1528,8 +1544,8 @@ Language: de gesperrt Um Produkte oder Zahlungsdetails zu bearbeiten, ändere den Status zu „Zahlung ausstehend“. Teile dieser Bestellung können derzeit nicht bearbeitet werden - Nach Kunden suchen Keine Kunden gefunden + Nach Kunden suchen Nicht jetzt Erweiterung zum Shop hinzufügen Was ist WooCommerce Shipping? @@ -1564,8 +1580,6 @@ Language: de Aktuelle Preise sind unterschiedlich Aktueller Preis ist %s Der Preis von %d Varianten wird aktualisiert - Gemischte Zahl - Kein Preis Verkaufspreis Regulärer Preis Preis @@ -1573,6 +1587,8 @@ Language: de Massenupdate OK Massenupdate … + Gemischte Zahl + Kein Preis Varianten werden abgerufen … Die Suche nach Produktkategorien ist fehlgeschlagen Das Laden der Produktkategorien ist fehlgeschlagen @@ -1587,11 +1603,10 @@ Language: de WooCommerce Shipping installieren Drucke Etiketten über dein Mobiltelefon aus – WooCommerce Shipping macht es möglich. Du brauchst ein Versandetikett? - Ändere die Produktmenge von %1$d zu %2$d Regulären Preis aktualisieren Verkaufspreis aktualisieren + Ändere die Produktmenge von %1$d zu %2$d Die WooCommerce Stripe-Erweiterung wird in %1$s nicht unterstützt - Filter Auswahl löschen %d Produkt auswählen %d Produkte auswählen @@ -1603,11 +1618,11 @@ Language: de Aktiviere diese Option, wenn der Gutschein nicht für Produkte gelten soll, die im Angebot sind. Gutscheine pro Produkt/Artikel sind nur einlösbar, wenn das Produkt nicht im Angebot ist. Gutscheine, die Pro-Gesamt-Warenkorb verwendet werden, sind nur einlösbar, wenn der Warenkorb Produkte enthält, die nicht im Angebot sind. Produkte, die im Angebot sind, ausschließen Aktiviere diese Option, wenn der Gutschein nicht zusammen mit anderen Gutscheinen verwendet werden darf. + Filter Nur einzeln anwendbar Nutzungslimit pro Benutzer Nutzung auf X Produkte limitieren Nutzungslimit pro Gutschein - Höchstbestellwert (%1$s) Mindestbestellwert (%1$s) Bitte warten … Gutschein wird gespeichert @@ -1624,6 +1639,7 @@ Language: de Fehler beim Abrufen von Shops Shop zum Verbinden auswählen %s vorrätig + Höchstbestellwert (%1$s) Füge die Beschreibung des Gutscheins hinzu. Beschreibung des Gutscheins Beschreibung bearbeiten @@ -1652,8 +1668,6 @@ Language: de Nur einzeln anwendbar Auf %1$d Artikel im Warenkorb begrenzt Auf %1$d Artikel im Warenkorb begrenzt - Kann %1$d Mal genutzt werden - Kann %1$d Mal genutzt werden %1$d Verwendung pro Benutzer %1$d Verwendungen pro Benutzer Gutschein gelöscht @@ -1664,6 +1678,8 @@ Language: de Alle ignorieren Posteingang Handbücher für Kartenlesegerät + Kann %1$d Mal genutzt werden + Kann %1$d Mal genutzt werden Zum Erstatten tippen oder eingeben Diese Bestellung wird bereits erstattet Rückerstattung storniert @@ -1677,12 +1693,12 @@ Language: de Probiere es mit einer anderen Erstattungsmethode Die Rückerstattung wurde aus einem unbekanntem Grund abgelehnt Leider konnte diese Rückerstattung nicht bearbeitet werden + Kopieren Rückerstattung erfolgreich Rückerstattung wird bearbeitet Zahlung erstatten Rückerstattung fehlgeschlagen Vorbereitung für Zahlungserstattung läuft - Kopieren Gutschein suchen Nachricht zum Teilen des Gutscheincodes kann nicht erstellt werden Fehler beim Teilen des Gutscheincodes. @@ -1693,7 +1709,6 @@ Language: de Gutscheincode Gutscheinübersicht konnte nicht geladen werden Läuft am %1$s ab - %1$s Rabatt auf %2$s Individueller Rabatt (%1$s) Fester Rabatt auf Produkt Fester Warenkorb-Rabatt @@ -1701,24 +1716,16 @@ Language: de Gutschein-Performance konnte nicht geladen werden Gutschein teilen Gutscheincode kopieren + %1$s Rabatt auf %2$s Vielen Dank für dein Feedback! Für Zahlungen mit Kartenleser sind genaue Standortberechtigungen erforderlich Standortzugriff erforderlich Bezahlen – %s Zahlungslink teilen Betrag - Betrag - Rabattierte Bestellungen - Performance - Maximalbestellwert: %s - Mindestbestellwert: %s - Gutscheinübersicht Gutscheinübersicht anzeigen - Wir haben daran gearbeitet, das Anzeigen und Bearbeiten von Gutscheinen von deinem Gerät aus zu ermöglichen! Gutscheine anzeigen und bearbeiten Keine Gutscheine gefunden - %1$s außer %2$s - %1$s und %2$s alles Abgelaufen Aktiv @@ -1734,8 +1741,17 @@ Language: de %d Kategorie \u2022 keine genehmigten Rezensionen \u2022 eine genehmigte Rezension - \u2022 %d genehmigte Rezensionen %1$s (%2$s%%) + \u2022 %d genehmigte Rezensionen + Betrag + Rabattierte Bestellungen + Performance + Mindestbestellwert: %s + Gutscheinübersicht + Maximalbestellwert: %s + Wir haben daran gearbeitet, das Anzeigen und Bearbeiten von Gutscheinen von deinem Gerät aus zu ermöglichen! + %1$s außer %2$s + %1$s und %2$s Wir haben daran gearbeitet, das Erstellen von Bestellungen auf deinem Gerät zu ermöglichen! Du kannst diese Funktion durch Tippen auf den „+“-Button ausprobieren In Kürze bekommst du weitere Tipps und Einsichten zum Ausbau deines Shops Glückwunsch, du hast alles gelesen! @@ -1744,26 +1760,26 @@ Language: de Anzahl: %s Gutscheine Ausblenden - Bei dem Versuch, mit der Website zu kommunizieren, ist ein Problem aufgetreten. Es wurde ein HTTP-Fehlercode 401 zurückgegeben. XML-RPC-Anrufe sind auf dieser Website anscheinend blockiert (Fehlercode 401). Wenn der Anmeldeversuch fehlschlägt, tippe auf das Hilfe-Icon, um die FAQ anzuzeigen. + Bei dem Versuch, mit der Website zu kommunizieren, ist ein Problem aufgetreten. Es wurde ein HTTP-Fehlercode 401 zurückgegeben. Unter dieser URL kann keine WordPress-Website gefunden werden. Tippe auf das Hilfe-Icon, um die FAQ anzuzeigen. Der XML-RPC-Service wurde auf dieser Website deaktiviert. Bitte verwende eine E-Mail-Adresse, die nicht von Automattic ist, um ein Support-Ticket einzureichen Stripe-Konten, die in %1$s registriert sind, werden nicht unterstützt - Die WooCommerce Payments-Erweiterung wird in %1$s nicht unterstützt - Drücke den Einschalt-Button deines Kartenlesegeräts Es wurde ein Beleg an <strong>%s</strong> gesendet Prozentsatz (%) + Drücke den Einschalt-Button deines Kartenlesegeräts + Die WooCommerce Payments-Erweiterung wird in %1$s nicht unterstützt Gebühr aus Bestellung entfernen Versand aus Bestellung entfernen Versand Versand hinzufügen Versand hinzufügen Name - Betrag Gebühren Kundendaten Gebühr hinzufügen + Betrag Kundenanmerkung bearbeiten Kundendaten bearbeiten Bestellstatus bearbeiten @@ -1784,14 +1800,13 @@ Language: de Persönliche Zahlungen funktionieren nur, wenn eines der folgenden Plugins aktiviert ist. Bitte setze dich mit einem Website-Administrator in Verbindung, um eines dieser Plugins zu deaktivieren und fortzufahren: Persönliche Zahlungen funktionieren nur, wenn eines der folgenden Plugins aktiviert ist. Deaktiviere eines der folgenden Plugins, um fortzufahren: In Konflikt stehende Zahlungsplugins entdeckt - Steuern insgesamt oder + Steuern insgesamt Jetpack installieren „Persönliche Zahlungen“ ist derzeit nicht verfügbar Bestellung erstellt Erstellen der Bestellung fehlgeschlagen Bitte warten … - Deine Bestellung wird erstellt Bestellung Gesamtsumme Produkte insgesamt Zahlung @@ -1799,6 +1814,7 @@ Language: de Verkaufte Artikel Conversion Erstellen + Deine Bestellung wird erstellt App-Icon Zurück-Icon Automattic-Logo @@ -1809,7 +1825,6 @@ Language: de Simplenote Pocket Casts Jetpack - Day One Dank an Quelltext Datenschutzhinweis für Kalifornien @@ -1817,6 +1832,7 @@ Language: de Allgemeine Geschäftsbedingungen Von überall aus arbeiten Werde Teil unseres Teams + Day One Automattic-Familie Rechtliches und mehr Twitter @@ -1837,13 +1853,13 @@ Language: de Verbindung Aktivierung Installation - Leider ist während der %s etwas schiefgelaufen Hallo! Hier ist ein Link zum Herunterladen der WooCommerce-App. Mir gefällt sie sehr gut und ich dachte, sie könnte dir auch gefallen. %1$s WooCommerce product_card_detail product_card_%1$s review_card_detail review_card_%1$s + Leider ist während der %s etwas schiefgelaufen Stripe aktualisieren Du hast es fast geschafft! Schließe bitte die Einrichtung von Stripe ab, um Zahlungen mit einer vorgelegten Karte („Card Present Payments“) anzunehmen. Stripe-Einrichtung in deiner Shop-Administration abschließen @@ -1856,9 +1872,7 @@ Language: de Abweichende Versandadresse hinzufügen Vorrätig %s vorrätig - Produkte hinzufügen Produkte - Kundendaten hinzufügen Kunde Als bezahlt markieren Dadurch wird deine Bestellung erstellt und als bezahlt markiert, wenn du eine Zahlung außerhalb von WooCommerce erhalten hast @@ -1866,6 +1880,8 @@ Language: de Deine Zahlungsmethode auswählen Steuern werden anhand deiner Shop-Adresse automatisch berechnet Steuer (%s%%) + Kundendaten hinzufügen + Produkte hinzufügen Zahlung erhalten (%s) Steuern erheben Individueller Betrag @@ -1885,30 +1901,30 @@ Language: de Auf einer Website im Testmodus wurde eine echte Karte verwendet Karten für Systemtests sind für Zahlungen nicht zulässig Eine falsche PIN wurde zu oft eingegeben - Für diese Karte ist ein PIN-Code erforderlich; deshalb kann sie nicht bearbeitet werden Der Zahlungsbetrag ist für die vorliegende Karte nicht zulässig Zahlung wegen unzureichendem Guthaben abgelehnt Die Postleitzahlen der Transaktion und der Karte stimmen nicht überein Die Karte ist abgelaufen Vor Kurzem wurde eine identische Transaktion übermittelt Diese Währung wird von der Karte nicht unterstützt - Diese Art von Kauf wird von der Karte nicht unterstützt Die Karte oder das zugehörige Konto ist ungültig Die Zahlung wurde aus einem nicht näher bezeichneten Grund abgelehnt Versuche es mit einer anderen Zahlungsmethode Versuche es erneut Neue Bestellung Auswahl für Datumsbereich-Filter - im Vergleich zum vorherigen Zeitraum (%1$s) %1$s (%2$s) Bisheriges Jahr Bisheriges Quartal - Bisheriger Monat Bisherige Woche Letztes Jahr Letztes Quartal Letzter Monat Letzte Woche + Für diese Karte ist ein PIN-Code erforderlich; deshalb kann sie nicht bearbeitet werden + Diese Art von Kauf wird von der Karte nicht unterstützt + im Vergleich zum vorherigen Zeitraum (%1$s) + Bisheriger Monat Einfaches Bezahlen Add-ons anzeigen Leider wurden keine Bestellungen gefunden. @@ -1929,29 +1945,27 @@ Language: de Betrag eingeben Zahlung erhalten Einfaches Bezahlen - Erstelle Bestellungen auf deinem Gerät! Statistiken + Erstelle Bestellungen auf deinem Gerät! Erledigt - Dein Store wird verbunden Wird aktiviert - Jetpack wird installiert - Bitte warte, während wir %s mit Jetpack verbinden. - Folgendes wird installiert:\nJetpack deine Website - Installiere das kostenlose Jetpack-Plugin auf <strong>%s</strong>, um auf deinem Mobilgerät die bestmögliche Erfahrung zu haben. Jetpack installieren Fehler beim Abrufen von Produktbewertungen Lesegerät ist nicht verbunden Lesegerät ist verbunden + Dein Store wird verbunden + Jetpack wird installiert + Bitte warte, während wir %s mit Jetpack verbinden. + Folgendes wird installiert:\nJetpack + Installiere das kostenlose Jetpack-Plugin auf <strong>%s</strong>, um auf deinem Mobilgerät die bestmögliche Erfahrung zu haben. Es wird nicht empfohlen, ein laufendes Software-Update abzubrechen. Wenn du abbrichst, wird die Verbindung deines Lesegeräts blockiert. Das Software-Update ist fehlgeschlagen, da der Akkustand deines Lesegeräts zu niedrig ist. Lade den Akku deines Lesegeräts bitte auf über 50 %%, bevor du es erneut versuchst. Das Software-Update ist fehlgeschlagen, da der Akkustand deines Lesegeräts nur %1$s%% beträgt. Lade den Akku deines Lesegeräts bitte auf über 50 %%, bevor du es erneut versuchst. Lade bitte den Akku deines Lesegeräts auf Damit die Software deines Kartenlesegeräts weiter problemlos funktioniert, ist eine Aktualisierung erforderlich - Bitte gib in den Einstellungen deines Stores eine gültige Postleitzahl ein und versuche es erneut Postleitzahl der Store-Adresse ist ungültig Adresse eingeben - Bitte gib die Adresse deines Stores an, um fortzufahren Überprüfe dein Mobilgerät Die Adresse kann nicht mit einer leeren E-Mail aktualisiert werden. Stelle sicher, dass du die neueste Version von WooCommerce ausführst. Letzte 30 Tage @@ -1962,6 +1976,8 @@ Language: de Alle Gefilterte Bestellungen Alle Bestellungen + Bitte gib in den Einstellungen deines Stores eine gültige Postleitzahl ein und versuche es erneut + Bitte gib die Adresse deines Stores an, um fortzufahren Nicht jetzt Jetpack installieren Erlaube mehreren Benutzen, auf WooCommerce Mobile zuzugreifen. @@ -2005,21 +2021,20 @@ Language: de Nachname Vorname Kundenhinweis zu Bestellung bearbeiten - Fehler beim Abrufen des Berichts zum Systemstatus (System Status Report, SSR). Bitte überprüfe WooCommerce -> Status in wp-admin. Bericht zum Systemstatus kann nicht geteilt werden - Fehler beim Kopieren des SSR in die Zwischenablage Bericht zum Systemstatus in die Zwischenablage kopiert Verschiedene Systeminformationen zu deiner Website WooCommerce SSR Bericht zum Systemstatus Herzlichen Glückwunsch, du kannst jetzt Zahlungen mit Kredit- und Debitkarten mit WooCommerce Payments annehmen! Zahlungen mit Kartenleser empfangen - Betrag muss sich mindestens auf %1$s belaufen OK + Fehler beim Abrufen des Berichts zum Systemstatus (System Status Report, SSR). Bitte überprüfe WooCommerce -> Status in wp-admin. + Fehler beim Kopieren des SSR in die Zwischenablage + Betrag muss sich mindestens auf %1$s belaufen Icon-Bild für neue Funktion Shop wechseln Aktualisieren des Produkts %1$s fehlgeschlagen - %1$d Bilder wurden zum Produkt %2$s hinzugefügt Produkt aktualisiert Produkt aktualisieren %1$s Bilder werden im Hintergrund hochgeladen @@ -2027,6 +2042,7 @@ Language: de OK Leider konnte das Add-on für Bestellungen nicht geladen werden Etwas ist schiefgelaufen + %1$d Bilder wurden zum Produkt %2$s hinzugefügt Neu in WooCommerce Add-ons anzeigen Diese Feature-Einstellung konnten wir leider gerade nicht ändern @@ -2045,21 +2061,21 @@ Language: de Ausstehende Bewertung Bitte vergewissere dich, dass das Kartenlesegerät verknüpft ist. Versuche es mit einer anderen Karte erneut - Versuche erneut, kontaktlos zu bezahlen oder die Karte einzufügen. Mehrere Karten erfasst. Versuche es erneut mit einer einzelnen Karte. Karte entfernen Versuche es mit derselben Karte noch einmal. - %d Artikel %d Artikel %d Werktage %d Werktag + Versuche erneut, kontaktlos zu bezahlen oder die Karte einzufügen. + %d Artikel Die Versandadresse konnte nicht automatisch verifiziert werden. %s Die Ursprungsadresse konnte nicht automatisch verifiziert werden. Zeige sie auf Google Maps an, um sicherzugehen, dass die Adresse richtig ist. Wir arbeiten daran, es dir einfacher zu machen, Produkt-Add-ons direkt auf deinem Gerät zu sehen! Im Moment siehst du die Add-ons für deine Bestellung. Du kannst diese Add-ons in deinem Web-Dashboard erstellen und bearbeiten. + Speichern Sieh dir Add-ons über dein Gerät an! Achtung: Wenn du ein Add-on in deinem Web-Dashboard umbenennst, wird es in der App in den vorherigen Bestellungen nicht mehr angezeigt. Add-ons anzeigen - Speichern Lade Details hoch (%d) %d Dateien konnten nicht hochgeladen werden %d Datei konnte nicht hochgeladen werden @@ -2091,27 +2107,22 @@ Language: de „Persönliche Zahlungen“ ist im Testmodus nicht verfügbar. Deaktiviere die Zahlungsmethode, um den Vorgang fortzusetzen. „Persönliche Zahlungen“ ist derzeit nicht verfügbar Dein Konto weist ausstehende Anforderungen auf. Erfülle diese Anforderungen bitte bis %1$s, um weiterhin persönliche Zahlungen zu erhalten. - Dein Konto weist ausstehende Anforderungen auf. - In deinem Konto ist mindestens eine Anforderung überfällig. Erfülle bitte die Anforderung(en), um weiterhin persönliche Zahlungen zu erhalten. „Persönliche Zahlungen“ ist derzeit nicht verfügbar Du kannst persönliche Zahlungen erhalten, sobald wir mit der Prüfung deines Kontos fertig sind. + In deinem Konto ist mindestens eine Anforderung überfällig. Erfülle bitte die Anforderung(en), um weiterhin persönliche Zahlungen zu erhalten. + Dein Konto weist ausstehende Anforderungen auf. „Persönliche Zahlungen“ ist derzeit nicht verfügbar - Leider können wir „Persönliche Zahlungen“ für diesen Store nicht unterstützen. Nach dem Update aktualisieren - In deinem Store ist eine veraltete Version der WooCommerce Payments-Erweiterung installiert. Aktualisiere diese bitte, um persönliche Zahlungen zu erhalten. WooCommerce Payments aktualisieren + Leider können wir „Persönliche Zahlungen“ für diesen Store nicht unterstützen. + In deinem Store ist eine veraltete Version der WooCommerce Payments-Erweiterung installiert. Aktualisiere diese bitte, um persönliche Zahlungen zu erhalten. Du hast es fast geschafft! Schließe bitte die Einrichtung von WooCommerce Payments ab, um persönliche Zahlungen zu erhalten. - Schließe die Einrichtung von WooCommerce Payments in deiner Store-Administration ab Nach der Aktivierung aktualisieren - Die WooCommerce Payments-Erweiterung ist in deinem Store installiert, aber nicht aktiviert. Aktiviere diese bitte, um persönliche Zahlungen zu erhalten. WooCommerce Payments aktivieren Nach der Installation aktualisieren - Um persönliche Zahlungen anzunehmen, musst du in deinem Store die kostenlose WooCommerce Payments-Erweiterung installieren. WooCommerce Payments installieren <a href=\'\'>Weitere Informationen</a> zum Empfang von Zahlungen mit deinem Mobilgerät und zur Bestellung von Kartenlesegeräten Brauchst du Hilfe? <a href=\'\'>Support kontaktieren</a> - Du kannst nach wie vor persönliche Barzahlungen entgegennehmen, indem du in deinem Store die Zahlungsmethode für Barzahlung bei Zustellung aktivierst. - Persönliche Kartenzahlungen werden in %1$s nicht unterstützt Verbindung deines Kontos Persönliche Zahlungen Überprüfe die Verpackungsabmessungen und das Gewicht oder versuche unter „Verpackungsdetails“ eine andere Verpackung zu verwenden. @@ -2119,6 +2130,11 @@ Language: de Alle verfügbaren Pakete wurden aktiviert Paket wird aktiviert Wähle ein Paket aus, das aktiviert werden soll. + Schließe die Einrichtung von WooCommerce Payments in deiner Store-Administration ab + Die WooCommerce Payments-Erweiterung ist in deinem Store installiert, aber nicht aktiviert. Aktiviere diese bitte, um persönliche Zahlungen zu erhalten. + Um persönliche Zahlungen anzunehmen, musst du in deinem Store die kostenlose WooCommerce Payments-Erweiterung installieren. + Du kannst nach wie vor persönliche Barzahlungen entgegennehmen, indem du in deinem Store die Zahlungsmethode für Barzahlung bei Zustellung aktivierst. + Persönliche Kartenzahlungen werden in %1$s nicht unterstützt Pflichtfeld Schließen Variante erstellt @@ -2127,11 +2143,11 @@ Language: de Variante erstellen Nachdem du nun Attribute hinzugefügt hast, kannst du deine erste Variante erstellen! Attribute erstellt - %1$s%% abgeschlossen Es wird nicht empfohlen, ein laufendes Software-Update abzubrechen Leider konnte diese Zahlung nicht bearbeitet werden Keine Verbindung zum Server Keine Internetverbindung + %1$s%% abgeschlossen In Originalverpackung versenden Zu neuem Paket hinzufügen Dieser Artikel befindet sich aktuell in %s. Wohin möchtest du ihn verschieben? @@ -2142,7 +2158,6 @@ Language: de Paketerstellung fehlgeschlagen. Bitte versuch es noch einmal. Paketerstellung fehlgeschlagen: unbekannter API-Fehler. Paketerstellung fehlgeschlagen: %1$s - Bitte warten … Ein neues Paket wird erstellt Ungültiger Wert Dies ist ein Pflichtfeld. @@ -2156,10 +2171,11 @@ Language: de Karton Wähle eine Paketart aus Paketart - Richte das Paket ein, mit dem du deine Produkte versendest. Wir speichern es für zukünftige Bestellungen. Neues Paket hinzufügen Neues Paket erstellen Die Verpackungsabmessungen müssen größer als Null sein. Bitte aktualisiere deine Verpackungsabmessungen im Versandbereich deiner Produktseite, um fortzufahren. + Bitte warten … + Richte das Paket ein, mit dem du deine Produkte versendest. Wir speichern es für zukünftige Bestellungen. Originalverpackung Abmessungen des Artikels Einzeln versendeter Artikel @@ -2172,11 +2188,11 @@ Language: de Update-Überprüfung der Softwareversion fehlgeschlagen <a href=\'\'>Weitere Informationen</a> zum Empfang von Zahlungen per Mobilgerät und zur Bestellung von Kartenlesegeräten Bluetooth aktivieren - Kein Reader verbunden Fehler beim Herstellen einer Verbindung zu deinem Reader Verbinden Mehrere Reader gefunden Diese Bestellung ist bereits bezahlt + Kein Reader verbunden Vielen Dank für deinen Einkauf! Klicke auf den Link unten, um deinen Zahlungsbeleg zu erhalten.\n\n%s Fehler beim Herunterladen des Zollformulars Zollrechnung drucken @@ -2192,12 +2208,11 @@ Language: de Produkt hinzufügen Variantenattribute Aktiviere Bluetooth auf dem Mobilgerät - Fehler beim Abrufen der Bestellung Der Bestellstatus in der App ist eventuell nicht aktuell. Dein Beleg vom %s Bestellung aktualisieren App-Status aktualisieren Dein Kunde hat %1$s ausgewählt - In Zollformularen muss eine zehnstellige Telefonnummer angegeben werden. + Fehler beim Abrufen der Bestellung Der Bestellstatus in der App ist eventuell nicht aktuell. Zollformular ausgefüllt Wenn du Probleme beim Drucken von deinem Gerät aus hast, wende dich an den Kundensupport für deinen Drucker. Wenn die Option „Drucken“ nicht verfügbar ist, kannst du deinen Beleg stattdessen als PDF speichern und ihn per E-Mail an ein anderes Gerät senden, um ihn von dort aus zu drucken. @@ -2210,6 +2225,7 @@ Language: de Um eine Variation zu erstellen, musst du zuerst deren Attribute festlegen (d. h. Farbe, Größe). 1 Variante %1$s Varianten + In Zollformularen muss eine zehnstellige Telefonnummer angegeben werden. USPS-Sendungsverfolgung Die Software deines Kartenlesegeräts wird aktualisiert Software-Update @@ -2269,9 +2285,9 @@ Language: de Weitere Informationen zu Rollen und Berechtigungen Diese App unterstützt nur die Benutzerrollen Administrator und Store-Manager Wenn du deine Rolle upgraden willst, wende dich bitte an deinen Store-Besitzer Neue Produkte von überall aus bearbeiten und hinzufügen + Überspringen Verwalte und bearbeite Bestellungen auch unterwegs Umsätze und erfolgreiche Produkte nachverfolgen - Überspringen Externes Produkt Gruppiertes Produkt Variables Produkt @@ -2280,9 +2296,6 @@ Language: de Einfaches physisches Produkt Einstellungen öffnen Einstellungen öffnen - Bluetooth ist deaktiviert - Standort ist deaktiviert - Erforderliche genaue Standortrechte fehlen Es konnte keine Verbindung zum Reader hergestellt werden. Verbindung zum Reader wird hergestellt Mit Reader verbinden @@ -2290,9 +2303,10 @@ Language: de Suche nach Readern Artikelanzahl Neues Versandetikett erstellen - Einfaches virtuelles Produkt + Bluetooth ist deaktiviert + Standort ist deaktiviert + Erforderliche genaue Standortrechte fehlen Möchtest du diese Variante wirklich löschen? - Variante erstellen Produkt wird gelöscht Beleg senden Beleg drucken @@ -2306,6 +2320,8 @@ Language: de Es kann keine Vorschau des Versandetiketts angezeigt werden. Bitte installiere eine App zum Öffnen von PDF-Dateien und versuche es erneut. An der von dir eingegeben Adresse konnten wir keine WordPress-Website finden. Bitte stelle sicher, dass WordPress installiert ist und du über die aktuelle Version verfügst. mehrere Versandzeilen + Einfaches virtuelles Produkt + Variante erstellen Die Bestellung konnte nicht als vollständig markiert werden. Fehler beim Kauf der Etiketten Bitte warten … @@ -2334,35 +2350,35 @@ Language: de Nur der Website-Betreiber kann die Zahlungsmethoden für Versandetiketten verwalten. Wende dich zur Verwaltung der Zahlungsmethoden bitte an den Website-Betreiber %1$s (%2$s). Varianten hinzufügen Variante hinzufügen - Erste Variante erstellen Insgesamt %s %s Preise ausgewählt + Enthält %s + Unterschrift von einem Erwachsenen erforderlich (%s) + Unterschrift erforderlich (%s) Für kostenlose Signaturanforderung berechtigt Für kostenlose Abholung berechtigt Versicherung (%s) Sendungsverfolgung - Enthält %s - Unterschrift von einem Erwachsenen erforderlich (%s) - Unterschrift erforderlich (%s) Der Kunde hat für den Versand als %1$s den Betrag von %2$s bezahlt - Beim Kauf von Versandetiketten bei WooCommerce erhältst du 5 % bis 40 % Rabatt im Vergleich zu den Preisen bei der Post. + Erste Variante erstellen Was ist der WooCommerce-Dienstleistungsrabatt? Beim Laden der Versandoptionen ist ein Fehler aufgetreten. Versanddienstleister und -tarife Versandetiketten kaufen Markiere diese Bestellung als abgeschlossen und benachrichtige den Kunden. Auftrag insgesamt - Weitere Informationen über WooCommerce-Dienstleistungsrabatte WooCommerce-Dienstleistungsrabatt Zwischensumme Zusammenfassung der Versandetiketten-Bestellung gratis Sonstige + Bezeichnung der Option + Weitere Informationen über WooCommerce-Dienstleistungsrabatte Es ist bereits eine Option mit diesem Namen vorhanden Es ist bereits eine Eigenschaft mit diesem Namen vorhanden Füge jeden Optionsnamen hinzu und drücke die Eingabe-Taste Oder tippe zur Auswahl auf eine bestehende Option - Bezeichnung der Option + Beim Kauf von Versandetiketten bei WooCommerce erhältst du 5 % bis 40 % Rabatt im Vergleich zu den Preisen bei der Post. Fehler beim Speichern deiner Einstellungen Bitte warten … Deine Einstellungen werden gespeichert @@ -2385,18 +2401,15 @@ Language: de Eigenschaft hinzufügen Eigenschaften Attribute bearbeiten - Gesamtgewicht der Pakete: %1$s %2$s %1$d Artikel in %2$d Paketen Gesamtgewicht des Pakets: %1$s %2$s Individuelle Pakete Produkte können nicht abgerufen werden - Bestimmte Pflichtfelder sind leer. Ungültiges Gewicht Ausgewähltes Paket Bitte warten … Pakete werden geladen! Paket %1$d - %d Artikel Paketdefinitionen können nicht geladen werden Enthält Paketgewicht Gesamtgewicht des Pakets: (%1$s) @@ -2409,16 +2422,17 @@ Language: de Wir haben die eingegebene Adresse leicht verändert. Wenn diese korrekt ist, verwende bitte die vorgeschlagene Adresse, um eine Zustellung an den richtigen Empfänger sicherzustellen. Ausgewählte Adresse bearbeiten Ausgewählte Adresse verwenden + Bestimmte Pflichtfelder sind leer. + Gesamtgewicht der Pakete: %1$s %2$s + %d Artikel Adressdaten werden geladen Neue Funktionen verfügbar! - Auf der Karte suchen Kunden kontaktieren Ungültige Straße Hausnummer fehlt Adresse konnte nicht gefunden werden Die Versandadresse konnte nicht automatisch verifiziert werden. Zeige sie auf Google Maps an oder versuche, den Kunden zu kontaktieren, um die Adresse zu überprüfen. Validierung der Adresse fehlgeschlagen - Bitte warten … Validierung der Adresse läuft Adressdaten können nicht geladen werden Adresse wie eingegeben verwenden @@ -2429,6 +2443,8 @@ Language: de Telefon Firma Name + Bitte warten … + Auf der Karte suchen Google Maps-App wurde gefunden Bitte warten … Das Entfernen von Bildern für Produktvarianten wird leider nur in WooCommerce 4.7 oder höher unterstützt. @@ -2444,31 +2460,30 @@ Language: de Verpackungsdetails Versandetikett erstellen Mehr erfahren - Kein Schlangestehen mehr bei der Post! Drucke Versandetiketten zu reduzierten Preisen zu Hause über dein Mobiltelefon aus. Spare durch die Ausführung mit WooCommerce Shipping Zeit und Geld WooCommerce Versand Bestellung als abgeschlossen markieren - Weitere Informationen zum Erstellen von Etiketten mit deinem Mobilgerät Versandetikett erstellen - Mit dem kostenlosen WooCommerce Shipping-Plugin kannst du jetzt Versandetiketten für sämtliche Artikelbestellungen direkt über dein Gerät drucken. Tippe auf „Versandetikett erstellen“ und probiere unsere Beta-Version aus! Erstelle Versandetiketten über dein Gerät! + Mit dem kostenlosen WooCommerce Shipping-Plugin kannst du jetzt Versandetiketten für sämtliche Artikelbestellungen direkt über dein Gerät drucken. Tippe auf „Versandetikett erstellen“ und probiere unsere Beta-Version aus! + Kein Schlangestehen mehr bei der Post! Drucke Versandetiketten zu reduzierten Preisen zu Hause über dein Mobiltelefon aus. + Weitere Informationen zum Erstellen von Etiketten mit deinem Mobilgerät + Bearbeiten Gebühren Nettozahlung Bezahlt Weitere Informationen zum Verbinden von Jetpack - Bearbeiten Bestätigen Nutze Drag-and-Drop zum Umsortieren der Fotos + Löschen Download-Einstellungen Bitte gib einen gültigen Namen ein Gib eine Datei-URL ein - WordPress-Mediathek Überprüfe, ob die eingegebene URL gültig ist Bitte warten … Dateien werden hochgeladen Fehler beim Hochladen der Datei Herunterladbare Datei hinzufügen - Herunterladbare Datei hinzufügen aus Herunterladbare Dateien zu Käufen hinzufügen Abbrechen Ja, ändern @@ -2477,7 +2492,6 @@ Language: de Datei Bist du sicher, dass du diese Datei entfernen möchtest? Herunterladbares Produkt - Löschen Ablauf des Downloads Downloadlimit Gib die Zahl der Tage ein, bevor der Link zum Herunterladen abläuft, oder lasse das Feld frei, wenn er nie abläuft. @@ -2492,11 +2506,13 @@ Language: de Du musst möglicherweise <b>die Funktion zum WLAN-Drucken direkt am Drucker konfigurieren.</b> Stelle sicher, dass die Firmware des Druckers aktualisiert ist. In der Dokumentation zum Drucker findest du eine Anleitung. Du kannst den <b>standardmäßigen Druckdienst</b> deines Gerätes auswählen oder eine <b>App der Druckermarke</b> installieren (dies sollte als empfohlene Option angezeigt werden) Stelle sicher, dass dein Drucker und dein Gerät mit <b>demselben WLAN-Netzwerk</b> verbunden sind. - Teste die neue vereinfachte, verknüpfte und gruppierte Produkterstellung, an der wir gerade arbeiten + WordPress-Mediathek + Herunterladbare Datei hinzufügen aus Erhöhe deine Einnahmen mit Upsell- und Cross-Sell-Möglichkeiten Produkte bearbeiten Produkte hinzufügen Produkte, die im Warenkorb beworben werden, wenn das aktuelle Produkt ausgewählt wird + Teste die neue vereinfachte, verknüpfte und gruppierte Produkterstellung, an der wir gerade arbeiten Cross-Sells (Querverkäufe) Produkte, die anstelle des Produktes beworben werden, das gerade angesehen wird (z. B. rentablere Produkte) Zusatzverkäufe @@ -2504,7 +2520,6 @@ Language: de %1$s%2$s x %3$s Anmeldelink per E-Mail erhalten Hmm, wir können kein WordPress.com-Konto finden, das mit dieser E-Mail-Adresse verknüpft ist. - Teste unsere Add-ons zur Anzeige von Bestellungen, während wir uns auf die Einführung vorbereiten. Produkte erstellen Einstellungen Fehler beim Verschieben des Produkts in den Papierkorb @@ -2516,24 +2531,25 @@ Language: de Das Hinzufügen von Optionen wie Größe und Farbe ist derzeit nur im Web verfügbar. Diese werden als Optionen auf der Produktseite deiner Website angezeigt. Erstelle Produkte mit der App! Produkt nicht gefunden - Wenn beim Drucken von diesem Gerät weiterhin Probleme auftreten, kannst du <b>dein Etikett als PDF speichern</b> und es per E-Mail versenden, um es von einem anderen Gerät zu drucken. - Nach der Auswahl <b>„Versandetikett drucken“</b> musst du möglicherweise einen Drucker auswählen und hinzufügen, wenn du noch nie von diesem Gerät gedruckt hast. Optionen für Etikettenformat - Mit deinem Gerät drucken Etikett (4 x 6 in) Letter (8,5 x 11 in) Legal (8,5 x 14 in) Fehler bei der Vorschau des Versandetiketts - Du weißt nicht, wie du mit deinem Mobilgerät drucken kannst? Siehe Optionen für Etikett-Layout und Papiergröße Versandetikett drucken Papiergröße auswählen Papiergröße - Wenn du das Etikett bereits auf einem Paket verwendet hast, ist das erneute Ausdrucken und Verwenden ein Verstoß gegen unsere Geschäftsbedingungen. Sollte der Ausdruck beim Kauf des Etiketts fehlerhaft sein, kannst du es erneut ausdrucken. - Wir arbeiten daran, es dir einfacher zu machen, Versandetiketten direkt über den Gerät zu drucken! Vorerst haben wir in deiner Shop-Administration mit WooCommerce Shipping Versandetiketten für diese Bestellung erstellt. Du kannst diese hier in deinen Bestelldetails drucken. Drucke Versandetiketten von deinem Gerät! + Mit deinem Gerät drucken + Wenn du das Etikett bereits auf einem Paket verwendet hast, ist das erneute Ausdrucken und Verwenden ein Verstoß gegen unsere Geschäftsbedingungen. + Wenn beim Drucken von diesem Gerät weiterhin Probleme auftreten, kannst du <b>dein Etikett als PDF speichern</b> und es per E-Mail versenden, um es von einem anderen Gerät zu drucken. + Nach der Auswahl <b>„Versandetikett drucken“</b> musst du möglicherweise einen Drucker auswählen und hinzufügen, wenn du noch nie von diesem Gerät gedruckt hast. + Wir arbeiten daran, es dir einfacher zu machen, Versandetiketten direkt über den Gerät zu drucken! Vorerst haben wir in deiner Shop-Administration mit WooCommerce Shipping Versandetiketten für diese Bestellung erstellt. Du kannst diese hier in deinen Bestelldetails drucken. Versandetikett drucken + Teste unsere Add-ons zur Anzeige von Bestellungen, während wir uns auf die Einführung vorbereiten. + Du weißt nicht, wie du mit deinem Mobilgerät drucken kannst? \u0022%1$s\u0022 Produktentwurf gespeichert Fehler beim Speichern des Produktentwurfs @@ -2577,17 +2593,16 @@ Language: de Foto hinzufügen Bild für Variante hinzufügen Installieren und Verbinden von Jetpack - Um diese App für %1$s zu verwenden, muss das Jetpack-Plugin in deinem Shop verbunden sein. Mit einem anderen Konto anmelden - Shop zum Verbinden auswählen Weiter mit WordPress.com - Ein Produkt mit Varianten wie Farbe oder Größe + Um diese App für %1$s zu verwenden, muss das Jetpack-Plugin in deinem Shop verbunden sein. + Shop zum Verbinden auswählen %d Produkt ausgewählt %d Produkte ausgewählt Füge Produkte zur Gruppe hinzu Produkt hinzufügen Passwort eingeben - Zurück zum Shop + Ein Produkt mit Varianten wie Farbe oder Größe Kontaktiere uns hier Bitte beachte, dass dies kein Support-Ticket ist und wir nicht auf jedes individuelle Feedback eingehen können.\n\nBrauchst du Hilfe? %1$s Vielen Dank für dein\n Feedback @@ -2603,7 +2618,6 @@ Language: de Wähle einen Produkttyp aus Feedback senden Einige Varianten weisen keine Preise auf - Varianten ohne Preise werden in deinem Shop nicht angezeigt Variante aktualisiert Das gruppierte Produkt löschen Gruppierte Produkte @@ -2611,8 +2625,10 @@ Language: de Kein Preis festgelegt Aktiviert Du musst den Verkaufspreis festlegen, wenn ein Verkauf geplant ist - Du kannst jetzt gruppierte, externe und variable Produkte bearbeiten, den Produkttyp ändern und Kategorien und Schlagwörter aktualisieren. %1$s hat eine Bewertung hinterlassen + Du kannst jetzt gruppierte, externe und variable Produkte bearbeiten, den Produkttyp ändern und Kategorien und Schlagwörter aktualisieren. + Zurück zum Shop + Varianten ohne Preise werden in deinem Shop nicht angezeigt Ich mag sie Könnte besser sein Gefällt dir die WooCommerce-App? @@ -2621,24 +2637,24 @@ Language: de Beim Hinzufügen von Schlagwörtern ist ein Fehler aufgetreten Schlagwort wird hinzugefügt Deine Rückerstattung wird berarbeitet. Bitte warten … - Rückerstattungsanforderung wurde erfolgreich übermittelt Etikett erstatten (-%1$s) Rückerstattbarer Betrag Kaufdatum - Du kannst für ein Versandetikett, das noch nicht zum Versenden eines Pakets verwendet wurde, eine Rückerstattung anfordern. Die Bearbeitung dauert mindestens 14 Tage. Rückerstattung anfordern Rückerstattungsetikett für Versand + Du kannst für ein Versandetikett, das noch nicht zum Versenden eines Pakets verwendet wurde, eine Rückerstattung anfordern. Die Bearbeitung dauert mindestens 14 Tage. + Rückerstattungsanforderung wurde erfolgreich übermittelt Physisch Ein kurzer Auszug zu deinem Produkt. Erleichtere das Auffinden deiner Produkte mit Schlagwörtern. Ordne deine Produkte in zugehörige Gruppen an. + Deaktiviert Füge Gewicht und Maße hinzu. Weitere Details hinzufügen Organisiere deine Produkte in Schlagwörter. Füge dein erstes Schlagwort hinzu. Schlagwörter Schlagwort hinzufügen - Deaktiviert Virtuelles Produkt Weitere Details hinzufügen %1$s Produkt @@ -2646,9 +2662,7 @@ Language: de %s Produkt Verbleibende Produkte %1$s \u2022 %2$s - %1$s Etikettrückerstattung angefordert Sendung verfolgen - %1$s\n%2$s Sendungsdetails ausblenden Sendungsdetails einblenden Kreditkarte @@ -2658,6 +2672,8 @@ Language: de Versand Versenden von Paket %d + %1$s\n%2$s + %1$s Etikettrückerstattung angefordert SKU: %1$s %1$s (%2$s Optionen) Versandetiketten @@ -2678,8 +2694,8 @@ Language: de Datenschutzhinweis für Benutzer in Kalifornien Änderungen beibehalten Bis %1$s - Wir haben Produkten mehr Bearbeitungsfunktionen hinzugefügt! Du kannst jetzt Bilder aktualisieren, Vorschauen anzeigen und deine Produkte teilen. Neue Bearbeitungsfunktionen verfügbar + Wir haben Produkten mehr Bearbeitungsfunktionen hinzugefügt! Du kannst jetzt Bilder aktualisieren, Vorschauen anzeigen und deine Produkte teilen. Begrenzte Bearbeitungsfunktionen verfügbar Produkte %1$s x %2$s @@ -2773,11 +2789,11 @@ Language: de Breite Länge Erstattete Produkte - %1$s (%2$s x %3$d) %1$s per %2$s Möchtest du wirklich eine Rückerstattung ausstellen? Dies kann nicht rückgängig gemacht werden. Erstattete Produkte Rückerstattungen + %1$s (%2$s x %3$d) Registriere dich bei WordPress.com Leider konnten für „%s“ keine Ergebnisse gefunden werden. Sammle hochwertige Produktbewertungen für deinen Shop. @@ -2798,33 +2814,32 @@ Language: de Inventar hinzufügen Deine Bestellungen werden abgerufen … Text eingeben - Produkttitel eingeben - Produkt gespeichert. Fehler beim Aktualisieren des Produkts Bitte warten … Produkt beschreiben Beschreibung Beschreibung bearbeiten + Produkttitel eingeben + Produkt gespeichert. + Fertig Möchtest du deine Änderungen verwerfen? Aktualisieren - Fertig Die Rückerstattung wird bearbeitet, bitte warten … Rückerstattung für Versand Menge wählen Versandrückerstattung Rückerstattung für Produkt - Je %1$s x %2$s %d Artikel ausgewählt Keine auswählen Alle auswählen Warten auf Bestätigung der Rückerstattung … + Je %1$s x %2$s Passe die Größe von Bildern an und komprimiere sie, um sie schneller hochzuladen. Bildoptimierung Foto aufnehmen Von Gerät auswählen Upload-Methode wählen Uploads - Bilder werden hochgeladen …%1$d von %2$d Bild wird hochgeladen … Auf die Kamera kann nicht zugegriffen werden Möchtest du dieses Bild wirklich entfernen? @@ -2839,6 +2854,7 @@ Language: de Bild hinzufügen Bevorstehend Entfernen + Bilder werden hochgeladen …%1$d von %2$d Leider konnten wir nicht auf deine Website zugreifen. Zum Lösen dieses Problems musst du dich an deinen Host wenden. Aufgrund eines Problems mit dem <b>SSL-Zertifikat</b> konnten wir nicht auf deine Website zugreifen. Zum Lösen dieses Problems musst du dich an deinen Host wenden. Leider konnten wir nicht auf deine Website zugreifen, weil eine <b>HTTP-Authentifizierung</b> erforderlich ist. Zum Lösen dieses Problems musst du dich an deinen Host wenden. @@ -2847,8 +2863,8 @@ Language: de Melde dich mit deinen Website-Anmeldedaten an. Melde dich mit deinen Website-Anmeldedaten für %1$s an. Verifizierungs-E-Mail senden - Teste die neuen Produktbearbeitungsfunktionen, wenn wir sie einführen Produktbearbeitung + Teste die neuen Produktbearbeitungsfunktionen, wenn wir sie einführen Es gab Probleme beim Abrufen deines Kontos. Du kannst es jetzt oder es schließen und später erneut versuchen. Es ist ein Fehler aufgetreten. Melde dich an, umfortzufahren Verbindung mit deiner Website wird hergestellt… @@ -2883,15 +2899,12 @@ Language: de Keine Produkte gefunden Noch keine Produkte %s auf Lager - Auf Lager \u2022 %d Varianten Produktbild %1$s hat eine Bewertung für %2$s hinterlassen Nicht genehmigt Fehler beim Abrufen neuer Produktbewertungen Fehler beim Abrufen von Produktbewertungen - Bei der Rückerstattung ist ein Fehler aufgetreten. Bitte versuche es erneut. - Die Rückerstattung wurde erfolgreich übermittelt. - Deine Rückerstattung für %s wird verarbeitet. Bitte warten … + Auf Lager \u2022 %d Varianten Icon für Rückerstattungsangebot Manuelle Rückerstattung Rückerstattungsdetails @@ -2909,6 +2922,9 @@ Language: de Rückerstattung in Höhe von %s %s zur Rückerstattung verfügbar Rückerstattung ausstellen + Bei der Rückerstattung ist ein Fehler aufgetreten. Bitte versuche es erneut. + Die Rückerstattung wurde erfolgreich übermittelt. + Deine Rückerstattung für %s wird verarbeitet. Bitte warten … %1$s per %2$s Verbesserte Statistiken Betafunktionen @@ -2922,12 +2938,12 @@ Language: de Statistiken von heute Anmelden Du hast Jetpack bereits? %1$s - Es wird versucht, dich mit Jetpack anzumelden … Zum Fortfahren die App aktualisieren - Um diese App für %1$s zu verwenden, muss das Jetpack-Plugin eingerichtet und mit diesem Konto verbunden sein. \n\nAktualisiere nach dem Einrichten die App Es mit einem anderen Shop versuchen Datenbank herabgestuft, Tabellen werden neu erstellt und Shops werden geladen Shops werden geladen + Es wird versucht, dich mit Jetpack anzumelden … + Um diese App für %1$s zu verwenden, muss das Jetpack-Plugin eingerichtet und mit diesem Konto verbunden sein. \n\nAktualisiere nach dem Einrichten die App Keine Versanddienstleister gefunden Bitte gib eine vollständige Website-Adresse wie „example.com“ an. Noch keine Rezensionen vorhanden! @@ -2938,12 +2954,11 @@ Language: de Einstellungen konnten nicht abgerufen werden: Einige APIs sind für diese Kombination aus OAuth-App-ID und Konto nicht verfügbar. Wir stellen weitere Mitarbeiter ein! Sendungsverfolgungsnummer kopieren - WooCommerce wird gesucht … App aktualisieren + WooCommerce wird gesucht … Keine Adresse angegeben Benötigst du Hilfe bei der Suche nach der E-Mail-Adresse, mit der du dich verbunden hast? Die Website mit dieser Adresse ist keine WordPress-Website. Damit wir uns mit ihr verbinden können, muss WordPress auf der Website installiert sein. - Melde dich mit WordPress.com an, um dich mit <b>%1$s</b> zu verbinden Simbabwe Sambia Jemen @@ -3080,6 +3095,7 @@ Language: de Jamaika Elfenbeinküste Italien + Melde dich mit WordPress.com an, um dich mit <b>%1$s</b> zu verbinden Israel Isle of Man Irland @@ -3186,24 +3202,15 @@ Language: de Afghanistan Åland Überprüfen - Individueller Versanddienstleister Individuell - Gib bitte den Namen des Versanddienstleisters ein Gib bitte eine Sendungsverfolgungsnummer ein - Wähle bitte einen Versanddienstleister aus Bist du sicher, dass du diese Sendungsverfolgung verwerfen möchtest? Sendungsverfolgung kann nicht hinzugefügt werden Sendungsverfolgung hinzugefügt - Fehler beim Abrufen der Versanddienstleister - Ausgewählter Versanddienstleister - Versanddienstleister Versanddatum Sendungsverfolgungslink eingeben - Name des Versanddienstleisters eingeben Sendungsverfolgungsnummer eingeben - Versanddienstleister auswählen Sendungsverfolgungslink (optional) - Name des Versanddienstleisters Sendungsverfolgungsnummer Versanddienstleister Verfolgung hinzufügen @@ -3216,19 +3223,25 @@ Language: de Sendung verfolgen In deiner Website-Administration kannst du über das %1$sJetpack-Dashboard%2$s unter %3$sVerbindungen > Kontoverbindung%4$s die E-Mail-Adresse finden, mit der du dich mit WordPress.com verbunden hast. Mit welcher E-Mail-Adresse melde ich mich an? - Benötigst du Hilfe bei der Suche nach der erforderlichen E-Mail-Adresse? Jetpack ist ein kostenloses WordPress-Plugin, das deinen Shop mit den Tools verbindet, die du für ein bestmögliches mobiles Erlebnis benötigst, einschließlich Push-Benachrichtigungen und Statistiken. Was ist Jetpack? Verbundene Shops anzeigen - Offenbar ist %1$s mit einem anderen WordPress.com-Konto verbunden. Weiter bearbeiten + Individueller Versanddienstleister + Gib bitte den Namen des Versanddienstleisters ein + Wähle bitte einen Versanddienstleister aus + Fehler beim Abrufen der Versanddienstleister + Ausgewählter Versanddienstleister + Versanddienstleister + Name des Versanddienstleisters eingeben + Versanddienstleister auswählen + Name des Versanddienstleisters + Offenbar ist %1$s mit einem anderen WordPress.com-Konto verbunden. + Benötigst du Hilfe bei der Suche nach der erforderlichen E-Mail-Adresse? Bitte melde dich mit deinem Benutzernamen und deinem Passwort an. Bitte melde dich mit deinem WordPress.com-Benutzernamen anstelle deiner E-Mail-Adresse an. Die Website mit dieser Adresse ist keine WordPress-Website. Damit wir uns mit ihr verbinden können, muss die Website WordPress verwenden. Hilfe-Center - Virtuell - Gruppiert - Variable Zulassen, aber Kunden benachrichtigen Zulassen Nicht zulassen @@ -3236,6 +3249,9 @@ Language: de Ausverkauft Auf Lager Weitere Informationen + Gruppiert + Variable + Virtuell Bild konnte nicht geladen werden Entwurf Privat @@ -3280,12 +3296,12 @@ Language: de Für diesen Shop wird eine ältere Version von WooCommerce verwendet. Um deinen Shop mit dieser App zu nutzen, musst du ihn auf WooCommerce 3.5 oder höher upgraden. Jetzt ausprobieren Alles klar - Hier tippen, um zwischen Shops zu wechseln - Shop auswählen Abmelden Auftragsstatus ändern Zum Ändern des Auftragsstatus hier klicken Übernehmen + Hier tippen, um zwischen Shops zu wechseln + Shop auswählen Nein, danke Später Jetzt bewerten @@ -3299,33 +3315,33 @@ Language: de Shop auf WooCommerce 3.5 aktualisieren Verbindung zu %s kann nicht hergestellt werden Verwerfen - Fehler beim Markieren aller Bewertungen als gelesen Alle als gelesen markieren Nachricht - Anrufen Anruf oder Nachricht an Kunden + Anrufen + Fehler beim Markieren aller Bewertungen als gelesen Fehler beim Aktualisieren des Produktbewertungsstatus - Fehler beim Laden des Produktbewertungsdetail Papierkorb + Fehler beim Laden des Produktbewertungsdetail Spam Genehmigt Genehmigen Produkt anzeigen Hilfe und Support - Töne, Priorität und Benachrichtigungspunkt Verwalten von Benachrichtigungen Benachrichtigungen Möchtest du dich wirklich vom Konto %s abmelden? - Bewertung als %1$s markiert + Töne, Priorität und Benachrichtigungspunkt Bei Deaktivierung wird der Hinweis privat + Bewertung als %1$s markiert Fehler beim Abrufen der Bestellung Zurück Benachrichtigungen zu Produktbewertungen Benachrichtigungen bei neuer Bestellung An Kunden - Website wird verifiziert … Aktualisierungsanweisungen Suche + Website wird verifiziert … Neu laden und %d weitere. %d neue Benachrichtigungen @@ -3357,9 +3373,9 @@ Language: de Crash Reports Teilen Version %s - HTTP-Passwort - HTTP-Benutzername - Autorisierung erforderlich + Wir haben zu viele Versuche unternommen, einen SMS-Verifizierungscode zu senden – atme kurz durch und fordere in einer Minute einen neuen an. + Kein WordPress.com-Konto stimmt mit diesem Google-Konto überein. + Melde dich bei deinem WordPress.com-Konto an, das du für die Jetpack-Verbindung verwendet hast. Magischer Link gesendet E-Mail-Registrierung Code-Verifizierung @@ -3368,32 +3384,9 @@ Language: de Magischer Link – Login Website-Adresse – Login E-Mail-Adresse – Login - Ein Fehler ist aufgetreten. - Gib bitte einen Authentifizierungscode ein, um den Vorgang fortzusetzen. - Überprüfe bitte dein Passwort, um den Vorgang fortzusetzen. - Anmeldung angehalten - Bitte warten, während Anmeldung erfolgt. - Anmeldung läuft … - Zum Fortfahren tippen. - Angemeldet! - Es ist ein Netzwerkfehler aufgetreten. Bitte überprüfe deine Verbindung und versuche es erneut. - Bitte gib den Namen einer WordPress.com-Website oder einer selbst gehosteten, mit Jetpack verbundenen WordPress-Website ein - Verbindung fehlgeschlagen. Wir haben einen 403-Fehler erhalten, als wir versucht haben, den\n XMLRPC-Endpunkt deiner Website aufzurufen. Die App braucht diesen, um mit deiner Website zu kommunizieren. Kontaktiere deinen Host, um\n dieses Problem zu beheben. - Konnte nicht verbinden. Dein Host blockiert POST-Anforderungen und die App benötigt\n diese, um mit deiner Website zu kommunizieren. Kontaktiere deinen Host, um dieses Problem zu beheben. - Konnte nicht verbinden. Die benötigte XML-RPC Methoden sind nicht auf dem Server vorhanden. - Überprüfe, ob die eingegebene Website-URL gültig ist. - Es ist ein Fehler aufgetreten - Passwort vergessen? - Gib eine gültige E-Mail-Adresse ein - Überprüfe E-Mail-Adresse - Melde dich erneut an, um fortzufahren. - Melde dich bei deinem WordPress.com-Konto an, das du für die Jetpack-Verbindung verwendet hast. - Dein Profil konnte nicht abgerufen werden. - Es wurde eine doppelte Website entdeckt. - Diese Website existiert bereits in der App, du kannst sie nicht hinzufügen. - Der Benutzername oder das Passwort ist falsch - Google hat zu lange gebraucht, um zu antworten. Gegebenenfalls musst du warten, bis du eine stärkere Internetverbindung hast. + Du hast noch kein Konto? %1$sRegistrieren%2$s Anmelden mit Google … + Google hat zu lange gebraucht, um zu antworten. Gegebenenfalls musst du warten, bis du eine stärkere Internetverbindung hast. Mit Google registrieren Mit E-Mail-Adresse registrieren Durch die Registrierung stimmst du unseren %1$sGeschäftsbedingungen%2$s zu. @@ -3403,20 +3396,58 @@ Language: de Es gab Probleme beim Senden dieser E-Mail. Du kannst es jetzt erneut versuchen oder die Seite schließen und es später erneut versuchen. Bitte gib deine E-Mail-Adresse ein, um dein neues WordPress.com-Konto zu erstellen. Es gab Probleme beim Überprüfen der E-Mail-Adresse. - \nVielleicht probierst du es mit einem anderen Konto? + Ein Fehler ist aufgetreten. + Gib bitte einen Authentifizierungscode ein, um den Vorgang fortzusetzen. + Überprüfe bitte dein Passwort, um den Vorgang fortzusetzen. + Anmeldung angehalten + Bitte warten, während Anmeldung erfolgt. + Anmeldung läuft … + Zum Fortfahren tippen. + Angemeldet! Google-Anmeldung konnte nicht gestartet werden. - Wir haben zu viele Versuche unternommen, einen SMS-Verifizierungscode zu senden – atme kurz durch und fordere in einer Minute einen neuen an. + Bitte gib ein Passwort ein + \nVielleicht probierst du es mit einem anderen Konto? Beim Verbinden mit dem Google-Konto ist ein Problem aufgetreten. - Kein WordPress.com-Konto stimmt mit diesem Google-Konto überein. Schließen Mit Google anmelden. + Es ist ein Netzwerkfehler aufgetreten. Bitte überprüfe deine Verbindung und versuche es erneut. Angemeldet als E-Mail-Client-App wird nicht erkannt. - Du hast noch kein Konto? %1$sRegistrieren%2$s Bitte gib einen Verifizierungscode ein. - Bitte gib ein Passwort ein - Bitte gib einen Benutzernamen ein. + Es wurde eine doppelte Website entdeckt. + Diese Website existiert bereits in der App, du kannst sie nicht hinzufügen. + Konnte nicht verbinden. Dein Host blockiert POST-Anforderungen und die App benötigt\n diese, um mit deiner Website zu kommunizieren. Kontaktiere deinen Host, um dieses Problem zu beheben. + Überprüfe E-Mail-Adresse + Konnte nicht verbinden. Die benötigte XML-RPC Methoden sind nicht auf dem Server vorhanden. + Dein Profil konnte nicht abgerufen werden. + Melde dich erneut an, um fortzufahren. + Passwort vergessen? + Der Benutzername oder das Passwort ist falsch + Gib eine gültige E-Mail-Adresse ein + Es ist ein Fehler aufgetreten + Autorisierung erforderlich + Überprüfe, ob die eingegebene Website-URL gültig ist. + HTTP-Passwort + HTTP-Benutzername + Bitte gib den Namen einer WordPress.com-Website oder einer selbst gehosteten, mit Jetpack verbundenen WordPress-Website ein + Verbindung fehlgeschlagen. Wir haben einen 403-Fehler erhalten, als wir versucht haben, den\n XMLRPC-Endpunkt deiner Website aufzurufen. Die App braucht diesen, um mit deiner Website zu kommunizieren. Kontaktiere deinen Host, um\n dieses Problem zu beheben. + Rückgängig + Abbrechen + Heute + Einstellungen + Alternativ: + Allgemein + \@%s + Melde dich mit deinem Benutzernamen an. + Melde dich an, indem du deine Website-Adresse eingibst. + Sende mir stattdessen einen anderen Code per SMS. + Wir haben eine Textnachricht an die Telefonnummer mit den Endziffern %s gesendet. Gib bitte den Verifizierungscode aus der SMS ein. + Bitte melde dich mit dem WordPress.com-Passwort an, um mit diesem Google-Konto fortzufahren. Es wird nur einmal benötigt. Zum Teilen des Inhalts melde dich bei WordPress.com an. + Gib die Adresse der WordPress-Website ein, mit der du den Inhalt teilen möchtest. + Fehler beim Öffnen des Standard-Browsers. Bitte wähle eine andere App: + Link konnte nicht geöffnet werden + Bitte gib einen Benutzernamen ein. Melde dich bei WordPress.com an, um auf diesen Beitrag zuzugreifen. Fehler beim Hinzufügen der Website. Fehlercode: %s Website-Adresse wird überprüft @@ -3425,25 +3456,15 @@ Language: de Wie lautet meine Website-Adresse? Brauchst du Hilfe, um deine Website-Adresse zu finden? Website-Adresse - Gib die Adresse der WordPress-Website ein, mit der du den Inhalt teilen möchtest. \@%s Bereits bei WordPress.com angemeldet Weiter - Website verbinden Andere Website verbinden - Bitte melde dich mit dem WordPress.com-Passwort an, um mit diesem Google-Konto fortzufahren. Es wird nur einmal benötigt. Gib dein WordPress.com-Passwort ein. - Zur Zeit nicht verfügbar. Bitte gib dein Passwort ein Anmelde-E-Mail wird angefordert Dieses Passwort ist anscheinend falsch. Prüfe bitte deine Angaben und versuche es erneut. Verifizierungscode wird per SMS angefordert. - Sende mir stattdessen einen anderen Code per SMS. Stattdessen Code per SMS senden. - Wir haben eine Textnachricht an die Telefonnummer mit den Endziffern %s gesendet. Gib bitte den Verifizierungscode aus der SMS ein. - Fast geschafft! Bitte gib den Verifizierungscode für WordPress.com aus deiner Authenticator-App ein. - Melde dich mit deinem Benutzernamen an. - Melde dich an, indem du deine Website-Adresse eingibst. - Alternativ: E-Mail öffnen Weiter Verwalte deine mit Jetpack betriebene Website unterwegs – du hast WordPress immer dabei. @@ -3451,29 +3472,35 @@ Language: de Du kannst überall und jederzeit deine bevorzugten Websites verfolgen und an der Unterhaltung teilnehmen. Schau zu, wie Leser aus der ganzen Welt deine Website lesen und damit interagieren – in Echtzeit. Veröffentliche deine Beiträge im Park. Blogge im Bus. Kommentiere im Café. WordPress ist immer und überall für dich verfügbar. - Anmelden - Hilfe - Passwort - Benutzername - Gib stattdessen dein Passwort ein + Du bist bereits in einem WordPress.com-Konto angemeldet, du kannst keine WordPress.com-Website hinzufügen, die an ein anderes Konto gebunden ist. + Erneut versuchen + Abmelden Link senden + Zur Zeit nicht verfügbar. Bitte gib dein Passwort ein + Anmeldung läuft + Gib stattdessen dein Passwort ein + E-Mail-Adresse + Details Ungültiger Überprüfungscode Überprüfungscode - E-Mail-Adresse + Hilfe + Verwerfen + Anmelden + Benutzername + Passwort + Unbenannt WooCommerce Android %s-Unterstützung Option nicht aktiviert Option aktiviert Drittanbieter-Erklärung Cookie-Richtlinie Datenschutzerklärung - Von Automattic entwickelt. %1$s Wir verwenden andere Tools zum Tracking, darunter auch solche von Drittanbietern. Hier erhältst du weitere Informationen und Tipps, wie du sie kontrollierst. Datenschutzerklärung lesen Diese Informationen helfen uns dabei, unsere Produkte zu verbessern, Marketing besser auf dich zuzuschneiden, deine Erfahrung mit WooCommerce zu personalisieren und mehr. All das kannst du auch in unserer Datenschutzerklärung nachlesen. Teile Informationen über deine Nutzung von Diensten mit unserem Analysetool, während du in deinem WordPress-Konto angemeldet bist. Informationen erfassen Datenschutzeinstellungen - Einstellungen Bestellstatus Rückerstattet Storniert @@ -3487,7 +3514,6 @@ Language: de Hinzufügen Hinweis per E-Mail an Kunden senden Fehler beim Ändern der Bestellung - Fehler beim Abrufen von Notizen Bestellung als abgeschlossen markiert Bestellung als abgeschlossen markieren Bestellhinweis hinzufügen @@ -3496,7 +3522,6 @@ Language: de Abrechnung einblenden Zahlung gelöscht Bestellhinweise - Privat Bestellhinweis verfassen Kundenprofilbild Vom Kunden angegebener Hinweis @@ -3521,8 +3546,6 @@ Language: de Keine Bestellungen Bestellungen anzeigen Bestellung anzeigen - Keine Aktivitäten in diesem Zeitraum - Bestellungen gesamt: %s Fehlerbild Fehler beim Abrufen der Daten Umsatz @@ -3536,17 +3559,11 @@ Language: de Keine WooCommerce-Shops Dein Profilfoto Verbundener Shop - Lies die %1$sKonfigurationsanleitung%2$s. Für diese App muss Jetpack mit deinem Shop verbunden sein. - \@%s - Gib die Adresse des WooCommerce-Shops ein, den du verbinden möchtest. Melde dich mit der E-Mail-Adresse deines WordPress.com-Kontos an, um deine WooCommerce-Shops zu verwalten. - Du bist bereits in einem WordPress.com-Konto angemeldet, du kannst keine WordPress.com-Website hinzufügen, die an ein anderes Konto gebunden ist. - Link konnte nicht geöffnet werden Es wurde keine SMS-Anwendung gefunden Es wurde keine E-Mail-Anwendung gefunden Es wurde keine Telefonanwendung gefunden - Fehler beim Öffnen des Standard-Browsers. Bitte wähle eine andere App: Der Link konnte nicht geöffnet werden. %1$s um %2$s Älter als einen Monat @@ -3555,22 +3572,15 @@ Language: de Gestern Heute Produkte - Verwerfen Dieses Jahr Diesen Monat Diese Woche - Heute Produkt Dein Netzwerk ist nicht verfügbar. Prüfe deine Daten- oder WLAN-Verbindung. Offline u2014 mit zwischengespeicherten Daten Weitere Informationen - Abbrechen - Unbenannt Weiter - Rückgängig - Erneut versuchen Details ausblenden - Details Rabatt Zwischensumme Steuern @@ -3580,11 +3590,17 @@ Language: de %1$s%2$s Bestellungen Mein Shop - Abmelden - Anmeldung läuft Alle - Allgemein WooCommerce + Von Automattic entwickelt. %1$s + Gib die Adresse des WooCommerce-Shops ein, den du verbinden möchtest. + Privat + Website verbinden + Keine Aktivitäten in diesem Zeitraum + Bestellungen gesamt: %s + Fehler beim Abrufen von Notizen + Lies die %1$sKonfigurationsanleitung%2$s. + Fast geschafft! Bitte gib den Verifizierungscode für WordPress.com aus deiner Authenticator-App ein. \@string/date_timeframe_custom \@string/date_timeframe_today diff --git a/WooCommerce/src/main/res/values-es/strings.xml b/WooCommerce/src/main/res/values-es/strings.xml index b2bcdc34a99..c919b62a558 100644 --- a/WooCommerce/src/main/res/values-es/strings.xml +++ b/WooCommerce/src/main/res/values-es/strings.xml @@ -1,11 +1,28 @@ + Se ha efectuado correctamente un pago de %1$s + Nuevo pedido + Aceptar + + Crear un pedido en la gestión de la tienda + Para aceptar el pago de un producto no sencillo, sal de TPV y crea un nuevo pedido desde la pestaña de pedidos. + En estos momentos, solo se pueden utilizar productos físicos sencillos con TPV.\nOtros tipos de productos, como los variables y los virtuales, estarán disponibles en futuras actualizaciones. + ¿Por qué no puedo ver mis productos? + Información + Cerrar + Más información + En estos momentos, solo los productos físicos sencillos son compatibles con TPV. Otros tipos de productos, como los variables y los virtuales, estarán disponibles en futuras actualizaciones. + Mostrar solo productos sencillos + Dirección del sitio + Google para WooCommerce + Añadir campaña de pago + Dirige las ventas y genera más tráfico con Google Ads. + Campañas de Google Hecho Se ha creado tu nueva campaña. ¡Se avecinan momentos emocionantes para tus ventas! ¡Todo listo! @@ -103,7 +120,6 @@ Language: es Total Impuesto Subtotal - Nueva transacción Pago correcto Error de pago. Inténtalo de nuevo. Icono de carrito diff --git a/WooCommerce/src/main/res/values-fr/strings.xml b/WooCommerce/src/main/res/values-fr/strings.xml index e6485ea75b9..313927bf676 100644 --- a/WooCommerce/src/main/res/values-fr/strings.xml +++ b/WooCommerce/src/main/res/values-fr/strings.xml @@ -1,11 +1,28 @@ + Un paiement de %1$s a été effectué avec succès + Nouvelle commande + OK + + Créer une commande dans la gestion de la boutique + Pour accepter un paiement pour un produit non simple, quittez le PDV et créez une nouvelle commande depuis l’onglet Commandes. + Seuls les produits physiques simples peuvent être utilisés avec le PDV actuellement.\nD’autres types de produits, tels que les produits virtuels et variables, seront disponibles dans les mises à jour à venir. + Pourquoi ne puis-je pas voir mes produits ? + Informations + Fermer + Lire la suite + Seuls les produits physiques simples sont compatibles avec le PDV actuellement. D’autres types de produits, tels que les produits virtuels et variables, seront disponibles dans les mises à jour à venir. + Affichage des produits simples uniquement + Adresse du site + Google pour WooCommerce + Ajouter une campagne payante + Multipliez les ventes et générez plus de trafic avec Google Ads. + Campagnes Google Terminé Votre nouvelle campagne a été créée. L’aventure attend vos ventes ! Tout est prêt ! @@ -103,7 +120,6 @@ Language: fr Total Taxe Sous-total - Nouvelle transaction Paiement réussi Échec du paiement. Veuillez réessayer. Icône du panier diff --git a/WooCommerce/src/main/res/values-he/strings.xml b/WooCommerce/src/main/res/values-he/strings.xml index a67cce72843..80761bcc187 100644 --- a/WooCommerce/src/main/res/values-he/strings.xml +++ b/WooCommerce/src/main/res/values-he/strings.xml @@ -1,11 +1,28 @@ + תשלום של ⁦%1$s⁩ חויב בהצלחה + הזמנה חדשה + אישור + + ליצור הזמנה בניהול החנות + כדי לגבות תשלום במוצר שאינו מוצר פשוט, יש לצאת מ-POS וליצור הזמנה חדשה מלשונית ההזמנות. + נכון לעכשיו, ניתן להשתמש ב-POS רק עבור מוצרים פיזיים פשוטים.\nסוגי מוצרים אחרים, כמו מוצרים עם סוגים או מוצרים וירטואליים, יהיו זמינים בעדכונים בעתיד. + למה המוצרים שלי לא מופיעים? + מידע + לסגור + למידע נוסף + רק מוצרים פיזיים פשוטים תואמים ל-POS כרגע. סוגי מוצרים אחרים, כמו מוצרים עם סוגים או מוצרים וירטואליים, יהיו זמינים בעדכונים בעתיד. + מציג רק מוצרים פשוטים + כתובת האתר + Google ל-WooCommerce + להוסיף קמפיין בתשלום + לעודד מכירות ולהגדיל את התעבורה עם Google Ads. + קמפיינים של Google בוצע הקמפיין החדש שלך נוצר. העתיד של המכירות שלך ורוד! מוכן לפעולה! @@ -103,7 +120,6 @@ Language: he_IL סכום כולל מס סכום ביניים - עסקה חדשה התשלום בוצע בהצלחה התשלום נכשל. יש לנסות שוב. סמל \'עגלת קניות\' diff --git a/WooCommerce/src/main/res/values-id/strings.xml b/WooCommerce/src/main/res/values-id/strings.xml index 8cc75066a3a..2cab8a711d8 100644 --- a/WooCommerce/src/main/res/values-id/strings.xml +++ b/WooCommerce/src/main/res/values-id/strings.xml @@ -1,11 +1,28 @@ + Dana senilai %1$s berhasil dibayarkan + Pesanan baru + Oke + + Buat pesanan di manajemen toko + Untuk memproses pembayaran atas produk non-sederhana, keluar dari POS, kemudian buat pesanan baru dari tab pesanan. + Mengapa produk saya tidak muncul? + Info + Tutup + Baca selengkapnya + Menunjukkan produk sederhana saja + Saat ini, hanya produk fisik sederhana yang dapat menggunakan POS.\nJenis produk lain, seperti variabel dan virtual, akan tersedia dalam pembaruan mendatang. + Saat ini, hanya produk fisik sederhana yang kompatibel dengan POS. Jenis produk lain, seperti variabel dan virtual, akan tersedia dalam pembaruan mendatang. + Alamat Situs + Tambahkan kampanye berbayar + Tingkatkan penjualan dan tarik lebih banyak pengunjung dengan Google Ads. + Kampanye Google + Google for WooCommerce Selesai Kampanye baru sudah dibuat. Bersiaplah, penjualan Anda akan meroket! Semua Siap! @@ -103,7 +120,6 @@ Language: id Total Pajak Subtotal - Transaksi baru Pembayaran berhasil Pembayaran gagal. Coba lagi. Ikon keranjang diff --git a/WooCommerce/src/main/res/values-it/strings.xml b/WooCommerce/src/main/res/values-it/strings.xml index 71695c132a8..e87b6ebb0aa 100644 --- a/WooCommerce/src/main/res/values-it/strings.xml +++ b/WooCommerce/src/main/res/values-it/strings.xml @@ -1,11 +1,28 @@ + Un pagamento di %1$s è stato effettuato correttamente + Nuovo ordine + OK + + Crea un ordine nella gestione del negozio + Per ricevere il pagamento di un prodotto non semplice, esci da POS e crea un nuovo ordire dalla scheda degli ordini. + Al momento solo i prodotti fisici semplici possono essere utilizzati con POS.\nAltri tipi di prodotti, come quelli variabili e quelli virtuali, saranno disponibili in seguito a futuri aggiornamenti. + Perché non riesco a visualizzare i miei prodotti? + Informazioni + Chiudi + Scopri di più + Al momento solo i prodotti fisici semplici sono compatibili con POS. Altri tipi di prodotti, come quelli variabili e quelli virtuali, saranno disponibili in seguito a futuri aggiornamenti. + Visualizzazione dei soli prodotti semplici + Indirizzo del sito + Google per WooCommerce + Aggiungi campagna a pagamento + Aumenta le vendite e genera più traffico con Google Ads. + Campagne Google Fatto La tua nuova campagna è stata creata. Grandi notizie per le tue vendite. Tutto pronto! @@ -103,7 +120,6 @@ Language: it Totale Imposta Subtotale - Nuova transazione Pagamento avvenuto correttamente Pagamento non riuscito. Riprova. Icona della carta diff --git a/WooCommerce/src/main/res/values-ja/strings.xml b/WooCommerce/src/main/res/values-ja/strings.xml index be77554ae35..b8f8d0ffe43 100644 --- a/WooCommerce/src/main/res/values-ja/strings.xml +++ b/WooCommerce/src/main/res/values-ja/strings.xml @@ -1,11 +1,28 @@ + %1$sの支払いが正常に行われました + 新しい注文 + OK + + ストア管理で注文を作成 + シンプルな商品以外の支払いを受け取るには、POS を終了して注文タブから新しい注文を作成します。 + 現在、POS で使用できるのはシンプルな物理的商品のみです。\nバリエーションや仮想などの他の商品タイプは、今後のアップデートで利用可能になります。 + 商品が表示されないのはなぜですか ? + 情報 + 閉じる + さらに詳しく + 現在、POS で対応できるのはシンプルな物理的商品のみです。 バリエーションや仮想などの他の商品タイプは、今後のアップデートで利用可能になります。 + シンプルな商品のみ表示中 + サイトのアドレス + Google for WooCommerce + 有料キャンペーンを追加 + Google 広告で売上を伸ばし、トラフィックを増やしましょう。 + Google キャンペーン 完了 新しいキャンペーンが作成されました。 販売の楽しい時期がやってきます ! 準備完了 ! @@ -103,7 +120,6 @@ Language: ja_JP 合計 小計 - 新規トランザクション 支払いに成功しました 支払いに失敗しました。 もう一度お試しください。 お買い物カゴアイコン diff --git a/WooCommerce/src/main/res/values-ko/strings.xml b/WooCommerce/src/main/res/values-ko/strings.xml index d81d3d8b76c..dab8fa2b88a 100644 --- a/WooCommerce/src/main/res/values-ko/strings.xml +++ b/WooCommerce/src/main/res/values-ko/strings.xml @@ -1,11 +1,28 @@ + %1$s 결제가 완료되었습니다. + 새 주문 + 확인 + + 스토어 관리에서 주문 생성 + 단순 상품이 아닌 상품에 대한 결제를 받으려면 POS를 종료하고 주문 탭에서 새 주문을 생성하세요. + 현재 POS에서는 단순 실물 상품만 사용할 수 있습니다.\n변형 상품, 가상 상품 등의 다른 상품 유형은 향후 업데이트를 통해 지원될 예정입니다. + 왜 내 상품이 보이지 않나요? + 정보 + 닫기 + 더 알아보기 + 현재 POS에는 단순 실물 상품만 호환됩니다. 변형 상품, 가상 상품 등의 다른 상품 유형은 향후 업데이트를 통해 지원될 예정입니다. + 단순 상품만 표시 + 사이트 주소 + 우커머스용 Google + 유료 캠페인 추가 + Google Ads로 매출과 트래픽을 늘리세요. + Google 캠페인 완료 새 캠페인이 생성되었습니다. 판매 시간이 다가오고 있습니다! 모든 준비를 마쳤습니다! @@ -103,7 +120,6 @@ Language: ko_KR 합계 세금 소계 - 새로운 거래 결제 성공 결제에 실패했습니다. 다시 시도해 주세요. 장바구니 아이콘 diff --git a/WooCommerce/src/main/res/values-nl/strings.xml b/WooCommerce/src/main/res/values-nl/strings.xml index d6d6db8cdd8..265c781f839 100644 --- a/WooCommerce/src/main/res/values-nl/strings.xml +++ b/WooCommerce/src/main/res/values-nl/strings.xml @@ -1,11 +1,28 @@ + Een betaling van %1$s is voldaan + Nieuwe bestelling + OK + + Maak een bestelling aan in het winkelbeheer + Verlaat POS en maak een nieuwe bestelling aan vanuit het tabblad Bestellingen om betalingen te ontvangen voor een niet-simpel product. + Alleen simpele fysieke producten zijn momenteel beschikbaar met POS.\nAndere producttypen, zoals variabel en virtueel, worden in toekomstige updates beschikbaar. + Waarom kan ik mijn producten niet zien? + Informatie + Sluiten + Meer informatie + Alleen simpele fysieke producten zijn momenteel compatibel met POS. Andere producttypen, zoals variabel en virtueel, worden in toekomstige updates beschikbaar. + Alleen simpele producten weergeven + Websiteadres + Google voor WooCommerce + Betaalde campagne toevoegen + Stimuleer je verkoop en genereer meer verkeer met Google Ads. + Google-campagnes Gereed Je nieuwe campagne is gemaakt. Er komen geweldige momenten aan voor jouw omzet! Klaar voor de start! @@ -103,7 +120,6 @@ Language: nl Totaal Belasting Subtotaal - Nieuwe transactie Betaling gelukt Betaling mislukt. Probeer het opnieuw. Winkelwagenpictogram diff --git a/WooCommerce/src/main/res/values-pt-rBR/strings.xml b/WooCommerce/src/main/res/values-pt-rBR/strings.xml index 4b61a1a1ee7..2d66af9f959 100644 --- a/WooCommerce/src/main/res/values-pt-rBR/strings.xml +++ b/WooCommerce/src/main/res/values-pt-rBR/strings.xml @@ -1,11 +1,28 @@ + Um pagamento de %1$s foi feito com sucesso + Novo pedido + OK + + Criar um pedido no gerenciamento da loja + Para processar o pagamento de um produto que não é simples, saia do ponto de venda e faça um novo pedido na guia de pedidos. + Agora apenas produtos físicos simples podem ser usados nos pontos de venda.\nOutros tipos de produtos, como variáveis e virtuais, serão disponibilizados em atualizações futuras. + Por que não consigo ver meus produtos? + Informação + Fechar + Saiba mais + Agora apenas produtos físicos simples são compatíveis nos pontos de venda. Outros tipos de produtos, como variáveis e virtuais, serão disponibilizados em atualizações futuras. + Mostrando apenas produtos simples + Endereço do site + Google para WooCommerce + Adicionar campanha paga + Aumente suas vendas e o número de visitas com o Google Ads. + Campanhas do Google Concluído Sua nova campanha foi criada. Bons tempos estão por vir para suas vendas! Tudo pronto! @@ -102,7 +119,6 @@ Language: pt_BR Total Imposto Subtotal - Nova transação Pagamento realizado com êxito Falha no pagamento. Tente novamente. Ícone do carrinho diff --git a/WooCommerce/src/main/res/values-ru/strings.xml b/WooCommerce/src/main/res/values-ru/strings.xml index 497f76e5383..90c0ef0de56 100644 --- a/WooCommerce/src/main/res/values-ru/strings.xml +++ b/WooCommerce/src/main/res/values-ru/strings.xml @@ -1,11 +1,28 @@ + Платёж в сумме %1$s выполнен успешно + Новый заказ + ОК + + Создать заказ в разделе «Управление магазином» + Чтобы принять платёж за товар, не относящийся к простым, выйдите из POS и создайте новый заказ в таблице заказов. + В данный момент POS поддерживает только простые материальные товары.\nДругие типы товаров, в частности виртуальные и вариативные товары, станут доступны в ближайших обновлениях. + Почему я не вижу свои товары? + Информация + Закрыть + Подробнее + В данный момент POS поддерживает только простые материальные товары. Другие типы товаров, в частности виртуальные и вариативные товары, станут доступны в ближайших обновлениях. + Только простые товары + Адрес сайта + Google для WooCommerce + Добавить платную кампанию + Повышайте продажи и привлекайте больше посетителей при помощи Google Ads. + Кампании Google Готово Ваша новая кампания создана. Впереди у вас удачный сезон продаж! Всё готово! @@ -103,7 +120,6 @@ Language: ru Итого Налог Подытог - Новая транзакция Оплата прошла успешно Платёж не выполнен. Повторите попытку. Значок корзины diff --git a/WooCommerce/src/main/res/values-sv/strings.xml b/WooCommerce/src/main/res/values-sv/strings.xml index 9f0d9c91c1e..499c83debf9 100644 --- a/WooCommerce/src/main/res/values-sv/strings.xml +++ b/WooCommerce/src/main/res/values-sv/strings.xml @@ -1,11 +1,28 @@ + En betalning för %1$s återbetalades utan problem. + Ny beställning + OK + + Skapa en beställning i butikshantering + Varför kan jag inte se mina produkter? + Info + Stäng + Lär dig mer + För att ta betalt för en icke-enkel produkt, lämna POS och skapa en ny beställning från fliken Beställningar. + Endast enkla fysiska produkter kan användas med POS just nu.\nAndra produkttyper, till exempel rörliga och virtuella, kommer att bli tillgängliga i framtida uppdateringar. + Endast enkla fysiska produkter är kompatibla med POS just nu. Andra produkttyper, till exempel rörliga och virtuella, kommer att bli tillgängliga i framtida uppdateringar. + Visar endast enkla produkter + Webbplatsadress + Lägg till betald kampanj + Google för WooCommerce + Öka försäljningen och generera mer trafik med Google Ads. + Google-kampanjer Klar Din nya kampanj har skapats. Spännande tider väntar för din försäljning! Kunde inte skapa beställning @@ -102,7 +119,6 @@ Language: sv_SE Totalt Moms Delsumma - Ny transaktion Betalning lyckades Betalning misslyckades. Försök igen. Varukorgsikon diff --git a/WooCommerce/src/main/res/values-tr/strings.xml b/WooCommerce/src/main/res/values-tr/strings.xml index 2dd69a727dc..151019e2f4a 100644 --- a/WooCommerce/src/main/res/values-tr/strings.xml +++ b/WooCommerce/src/main/res/values-tr/strings.xml @@ -1,11 +1,28 @@ + %1$s tutarındaki bir ödeme başarıyla alındı + Yeni sipariş + Tamam + + Mağaza yönetiminde sipariş oluşturun + Temel olmayan bir ürünün ödemesini almak için POS\'tan çıkın ve siparişler sekmesinden yeni sipariş oluşturun. + Şu anda POS ile yalnızca basit fiziksel ürünler kullanılabiliyor.\nDeğişken ve sanal gibi diğer ürün türleri gelecekteki güncellemelerde kullanılabilir olacak. + Ürünlerimi neden göremiyorum? + Bilgi + Kapat + Daha fazla bilgi edinin + Şu anda POS ile yalnızca basit fiziksel ürünler uyumlu. Değişken ve sanal gibi diğer ürün türleri gelecekteki güncellemelerde kullanılabilir olacak. + Yalnızca basit ürünler gösteriliyor + Site Adresi + WooCommerce İçin Google + Ücretli kampanya ekle + Google Ads ile satışları teşvik edin ve trafiği artırın. + Google Kampanyaları Tamam Yeni kampanyanız oluşturuldu. Önümüzdeki günlerde satışlarınızla ilgili harika gelişmeler olacak! Her Şey Hazır! @@ -103,7 +120,6 @@ Language: tr Toplam Vergi Ara Toplam - Yeni işlem Ödeme başarılı Ödeme başarısız. Lütfen tekrar deneyin. Sepet simgesi diff --git a/WooCommerce/src/main/res/values-zh-rCN/strings.xml b/WooCommerce/src/main/res/values-zh-rCN/strings.xml index 6002ac34fb9..3c72c05b683 100644 --- a/WooCommerce/src/main/res/values-zh-rCN/strings.xml +++ b/WooCommerce/src/main/res/values-zh-rCN/strings.xml @@ -1,11 +1,28 @@ + 成功支付 %1$s + 新订单 + 确定 + + 在商店管理中创建订单 + 要接受非简单产品的付款,请退出 POS,然后在订单选项卡中创建新订单。 + POS 目前仅可用于简单实体产品。\n其他产品类型(如可变产品和虚拟产品)将在今后的更新中得到支持。 + 为何看不到我的产品? + 信息 + 关闭 + 了解更多 + POS 目前仅兼容简单实体产品。 其他产品类型(如可变产品和虚拟产品)将在今后的更新中受到支持。 + 仅显示简单产品 + 站点地址 + Google for WooCommerce + 添加付费广告活动 + 通过 Google Ads 推动销售并增加流量。 + Google 广告活动 完成 您的新广告活动已创建。 您的销售工作将迎来激动人心的时刻! 准备就绪! @@ -103,7 +120,6 @@ Language: zh_CN 总计 税费 小计 - 新交易 付款成功 付款失败。 请重试。 购物车图标 diff --git a/WooCommerce/src/main/res/values-zh-rTW/strings.xml b/WooCommerce/src/main/res/values-zh-rTW/strings.xml index 08f88be94a4..9b89fe4d2a1 100644 --- a/WooCommerce/src/main/res/values-zh-rTW/strings.xml +++ b/WooCommerce/src/main/res/values-zh-rTW/strings.xml @@ -1,11 +1,28 @@ + 已成功支付「%1$s」的款項 + 新訂單 + 確定 + + 在商店管理建立訂單 + 若要針對簡單商品以外的品項收款,請將 POS 結束,然後從訂單分頁建立新訂單。 + 目前只有簡單實體商品能使用 POS。\n待未來更新後,將可提供多款式與虛擬商品等其他商品種類的資訊。 + 為什麼我無法查看自己的商品? + 資訊 + 關閉 + 深入了解 + 目前 POS 僅與簡單實體商品相容。 待未來更新後,將可提供多款式與虛擬商品等其他商品種類的資訊。 + 僅顯示簡單商品 + 網站位址 + WooCommerce 的 Google 整合服務 + 新增付費廣告活動 + 運用 Google Ads 刺激銷售額並帶來更多流量。 + Google 廣告活動 完成 已建立你的新行銷活動。 令人興奮的行銷活動即將展開! 準備就緒! @@ -103,7 +120,6 @@ Language: zh_TW 總計 稅金 小計 - 新交易 付款成功 付款失敗。 請再試一次。 購物車圖示 From 8959942df2f87a6ffe7061b703c91b64ca3af19c Mon Sep 17 00:00:00 2001 From: Automattic Release Bot Date: Fri, 9 Aug 2024 12:16:11 -0400 Subject: [PATCH 118/196] Bump version number --- version.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.properties b/version.properties index c2451d17caa..928a69d4ca5 100644 --- a/version.properties +++ b/version.properties @@ -1,2 +1,2 @@ -versionName=19.8-rc-1 -versionCode=586 \ No newline at end of file +versionName=19.8 +versionCode=587 \ No newline at end of file From 6330607127b0eeb0ee4f86bec47a71bdb586252d Mon Sep 17 00:00:00 2001 From: Automattic Release Bot Date: Fri, 9 Aug 2024 12:16:13 -0400 Subject: [PATCH 119/196] Update metadata translations for WooCommerce 19.8 --- fastlane/metadata/android/ar/changelogs/default.txt | 2 ++ fastlane/metadata/android/de-DE/changelogs/default.txt | 2 ++ fastlane/metadata/android/es-ES/changelogs/default.txt | 2 ++ fastlane/metadata/android/fr-FR/changelogs/default.txt | 2 ++ fastlane/metadata/android/id/changelogs/default.txt | 2 ++ fastlane/metadata/android/it-IT/changelogs/default.txt | 2 ++ fastlane/metadata/android/iw-IL/changelogs/default.txt | 2 ++ fastlane/metadata/android/ja-JP/changelogs/default.txt | 2 ++ fastlane/metadata/android/ko-KR/changelogs/default.txt | 2 ++ fastlane/metadata/android/nl-NL/changelogs/default.txt | 2 ++ fastlane/metadata/android/pt-BR/changelogs/default.txt | 2 ++ fastlane/metadata/android/ru-RU/changelogs/default.txt | 2 ++ fastlane/metadata/android/sv-SE/changelogs/default.txt | 2 ++ fastlane/metadata/android/tr-TR/changelogs/default.txt | 2 ++ fastlane/metadata/android/zh-CN/changelogs/default.txt | 2 ++ fastlane/metadata/android/zh-TW/changelogs/default.txt | 2 ++ 16 files changed, 32 insertions(+) create mode 100644 fastlane/metadata/android/ar/changelogs/default.txt create mode 100644 fastlane/metadata/android/de-DE/changelogs/default.txt create mode 100644 fastlane/metadata/android/es-ES/changelogs/default.txt create mode 100644 fastlane/metadata/android/fr-FR/changelogs/default.txt create mode 100644 fastlane/metadata/android/id/changelogs/default.txt create mode 100644 fastlane/metadata/android/it-IT/changelogs/default.txt create mode 100644 fastlane/metadata/android/iw-IL/changelogs/default.txt create mode 100644 fastlane/metadata/android/ja-JP/changelogs/default.txt create mode 100644 fastlane/metadata/android/ko-KR/changelogs/default.txt create mode 100644 fastlane/metadata/android/nl-NL/changelogs/default.txt create mode 100644 fastlane/metadata/android/pt-BR/changelogs/default.txt create mode 100644 fastlane/metadata/android/ru-RU/changelogs/default.txt create mode 100644 fastlane/metadata/android/sv-SE/changelogs/default.txt create mode 100644 fastlane/metadata/android/tr-TR/changelogs/default.txt create mode 100644 fastlane/metadata/android/zh-CN/changelogs/default.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/default.txt diff --git a/fastlane/metadata/android/ar/changelogs/default.txt b/fastlane/metadata/android/ar/changelogs/default.txt new file mode 100644 index 00000000000..58e29aaf360 --- /dev/null +++ b/fastlane/metadata/android/ar/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +في آخر تحديث لدينا، أضفنا زرًا في تحليلات حملة غوغل لتسجيل إنشاء الحملة المدفوعة. يشتمل نموذج دعم الاتصال الآن على حقل عنوان الموقع. استمتع برسوم توضيحية سلسة للمدفوعات الشخصية في الوضع الأفقي، واستفد من التحديثات في الخلفية لقوائم الطلبات وتحليلات لوحة التحكم. diff --git a/fastlane/metadata/android/de-DE/changelogs/default.txt b/fastlane/metadata/android/de-DE/changelogs/default.txt new file mode 100644 index 00000000000..8af9dea82f9 --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +Bei unserem letzten Update haben wir einen Button zu den Analysen für Google-Kampagnen hinzugefügt, um die Erstellung kostenpflichtiger Kampagnen zu erleichtern. Das Formular „Support kontaktieren“ enthält nun ein Feld für die Website-Adresse. Genieße makellose Darstellungen persönlicher Zahlungen im Querformat und profitiere von Hintergrundupdates für Bestelllisten und Dashboard-Analysen. diff --git a/fastlane/metadata/android/es-ES/changelogs/default.txt b/fastlane/metadata/android/es-ES/changelogs/default.txt new file mode 100644 index 00000000000..6e001949f5a --- /dev/null +++ b/fastlane/metadata/android/es-ES/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +En nuestra última actualización, hemos añadido un botón en el análisis de Google Campaigns para facilitar la creación de campañas de pago. El formulario de contacto para asistencia incluye ahora un campo de dirección del sitio. Disfruta de ilustraciones de pagos en persona sin interrupciones en modo horizontal y benefíciate de las actualizaciones en segundo plano de las listas de pedidos y los análisis del escritorio. diff --git a/fastlane/metadata/android/fr-FR/changelogs/default.txt b/fastlane/metadata/android/fr-FR/changelogs/default.txt new file mode 100644 index 00000000000..86bad2be534 --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8 : +Dans notre dernière mise à jour, nous avons ajouté un bouton dans les statistiques de campagnes Google pour une création de campagne payante plus facile. Le formulaire Contacter l’assistance comprend dorénavant un champ Adresse du site. Profitez d’illustrations de paiements en personne fluides en mode paysage et profitez de mises à jour en arrière-plan pour les listes de commandes et les statistiques du tableau de bord. diff --git a/fastlane/metadata/android/id/changelogs/default.txt b/fastlane/metadata/android/id/changelogs/default.txt new file mode 100644 index 00000000000..a247acf49b0 --- /dev/null +++ b/fastlane/metadata/android/id/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +Dalam pembaruan teranyar, kami telah menambahkan tombol pada analitik Google Campaign agar bisa lebih mudah membuat kampanye berbayar. Formulir Dukungan Kontak sekarang menyertakan kolom Alamat Situs. Gunakan ilustrasi pembayaran langsung yang lebih baik dalam mode lanskap, dan manfaatkan pembaruan latar belakang untuk daftar pesanan dan analitik dasbor. diff --git a/fastlane/metadata/android/it-IT/changelogs/default.txt b/fastlane/metadata/android/it-IT/changelogs/default.txt new file mode 100644 index 00000000000..00c28d90e86 --- /dev/null +++ b/fastlane/metadata/android/it-IT/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +Nel nostro ultimo aggiornamento abbiamo aggiunto un pulsante nelle analisi di Google Campaign per una creazione di campagne a pagamento più semplice. Il modulo Contatta il supporto ora include il campo Indirizzo del sito. Goditi perfette illustrazioni dei pagamenti di persona in modalità orizzontale e approfitta degli aggiornamenti in background per gli elenchi degli ordini e le analisi della bacheca. diff --git a/fastlane/metadata/android/iw-IL/changelogs/default.txt b/fastlane/metadata/android/iw-IL/changelogs/default.txt new file mode 100644 index 00000000000..7cc3ef43d72 --- /dev/null +++ b/fastlane/metadata/android/iw-IL/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +בעדכון האחרון, הוספנו כפתור לנתונים אנליטיים בקמפיינים של Google כדי לאפשר יצירה פשוטה יותר של קמפיינים בתשלום. הטופס 'יצירת קשר עם התמיכה' כעת כולל שדה של 'כתובת האתר'. בתהליך התשלומים באופן אישי, אפשר ליהנות מתוכן ברור יותר גם במסך עם תצוגה לרוחב וליהנות מעדכונים ברקע של רשימת הזמנות ונתונים אנליטיים בלוח הבקרה. diff --git a/fastlane/metadata/android/ja-JP/changelogs/default.txt b/fastlane/metadata/android/ja-JP/changelogs/default.txt new file mode 100644 index 00000000000..1a0fee46bdd --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +最新アップデートで Google キャンペーン分析にボタンが追加され、有料キャンペーンの作成が容易になりました。 「サポートに連絡」フォームに「サイトのアドレス」フィールドが追加されました。 ランドスケープモードで、シームレスなオフライン支払いに関するイラストレーションをご活用ください。また、注文リストとダッシュボード分析のバックグラウンド更新をご利用いただけます。 diff --git a/fastlane/metadata/android/ko-KR/changelogs/default.txt b/fastlane/metadata/android/ko-KR/changelogs/default.txt new file mode 100644 index 00000000000..585557a936e --- /dev/null +++ b/fastlane/metadata/android/ko-KR/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +최신 업데이트에서는 더욱 간편하게 유료 캠페인을 만들 수 있는 버튼이 Google 캠페인 분석에 추가되었습니다. 이제 지원팀에 문의 양식에 사이트 주소 필드가 포함됩니다. 가로 모드에서도 대면 결제 일러스트레이션이 이질감 없이 표시되며, 주문 목록 및 알림판 분석이 백그라운드에서 업데이트됩니다. diff --git a/fastlane/metadata/android/nl-NL/changelogs/default.txt b/fastlane/metadata/android/nl-NL/changelogs/default.txt new file mode 100644 index 00000000000..65d401cb9ae --- /dev/null +++ b/fastlane/metadata/android/nl-NL/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +In onze nieuwste update hebben we een knop toegevoegd in de analyse van Google-campagnes om makkelijker betaalde campagnes aan te maken. Het contactformulier van de ondersteuning bevat nu een veld voor het websiteadres. Illustraties voor fysieke betalingen werken nu naadloos in landschapmodus, en je kan je voordeel doen met achtergrondupdates voor bestellijsten en analyses op het dashboard. diff --git a/fastlane/metadata/android/pt-BR/changelogs/default.txt b/fastlane/metadata/android/pt-BR/changelogs/default.txt new file mode 100644 index 00000000000..18e64ab073f --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +Na nossa atualização mais recente, adicionamos um botão nas análises de campanhas do Google para criar campanhas pagas com mais facilidade. O formulário para entrar em contato com o suporte agora inclui um campo de endereço de site. Aproveite as ilustrações de pagamento presencial no modo paisagem e ganhe atualizações em plano de fundo para análises de painéis e listas de pedidos. diff --git a/fastlane/metadata/android/ru-RU/changelogs/default.txt b/fastlane/metadata/android/ru-RU/changelogs/default.txt new file mode 100644 index 00000000000..4b7c26b3ec3 --- /dev/null +++ b/fastlane/metadata/android/ru-RU/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +В этом обновлении мы добавили кнопку в раздел аналитики кампаний Google, чтобы было удобнее создавать платные кампании. В форме «Связаться со службой поддержки» появилось поле «Адрес сайта». Теперь вы можете спокойно рассматривать иллюстрации в альбомной ориентации при совершении очного платежа, а также пользоваться преимуществами обновления списков заказов и аналитики панели мониторинга в фоновом режиме. diff --git a/fastlane/metadata/android/sv-SE/changelogs/default.txt b/fastlane/metadata/android/sv-SE/changelogs/default.txt new file mode 100644 index 00000000000..83cd27f988c --- /dev/null +++ b/fastlane/metadata/android/sv-SE/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +I vår senaste uppdatering har vi lagt till en knapp i Google-kampanjanalysen som gör det enklare att skapa betalkampanjer. Kontakta support-formuläret inkluderar nu ett Webbplatsadress-fält. Ta del av sömlösa illustrationer av personliga betalningar i liggande läge och dra nytta av bakgrundsuppdateringar för beställningslistor och adminpanelsanalyser. diff --git a/fastlane/metadata/android/tr-TR/changelogs/default.txt b/fastlane/metadata/android/tr-TR/changelogs/default.txt new file mode 100644 index 00000000000..2c97e66d80d --- /dev/null +++ b/fastlane/metadata/android/tr-TR/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +En son güncellememizde daha kolay ücretli kampanya oluşturma deneyimi için Google Kampanya analizlerine bir düğme ekledik. Desteğe Ulaşın Formu artık Site Adresi alanı içeriyor. Yatay modda sorunsuz şahsen ödeme illüstrasyonlarının keyfini çıkarın ve sipariş listeleri ve pano analizleri için arkaplan güncellemelerinden yararlanın. diff --git a/fastlane/metadata/android/zh-CN/changelogs/default.txt b/fastlane/metadata/android/zh-CN/changelogs/default.txt new file mode 100644 index 00000000000..22aea23c415 --- /dev/null +++ b/fastlane/metadata/android/zh-CN/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +在最新更新中,我们在 Google 广告活动分析中新增了一个按钮,以便于创建付费广告活动。 联系支持人员表单现在包含站点地址字段。 享受横向模式下的无缝现场付款图示,并受益于后台更新订单列表和仪表盘分析的功能。 diff --git a/fastlane/metadata/android/zh-TW/changelogs/default.txt b/fastlane/metadata/android/zh-TW/changelogs/default.txt new file mode 100644 index 00000000000..e573352f6ab --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/default.txt @@ -0,0 +1,2 @@ +19.8: +在最新版本中,我們已在 Google 廣告活動分析中新增了按鈕,方便更輕鬆地建立付費廣告活動。 「聯絡支援部門」表單現在已包含「網站位址」欄位。 在橫向模式中享有流暢的親自收款插圖,並獲得訂單清單背景更新與儀表板分析的優勢。 From 6f7548dcb64ca0b4469fc03142957aeeea00a59e Mon Sep 17 00:00:00 2001 From: Automattic Release Bot Date: Fri, 9 Aug 2024 14:03:59 -0400 Subject: [PATCH 120/196] Bump version number --- version.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.properties b/version.properties index 928a69d4ca5..8e86f41ea53 100644 --- a/version.properties +++ b/version.properties @@ -1,2 +1,2 @@ -versionName=19.8 -versionCode=587 \ No newline at end of file +versionName=19.9-rc-1 +versionCode=588 \ No newline at end of file From e0732041fd0b43d695ffad7c51ea4c53fff60b35 Mon Sep 17 00:00:00 2001 From: Automattic Release Bot Date: Fri, 9 Aug 2024 14:03:59 -0400 Subject: [PATCH 121/196] Update draft release notes for 19.9. --- fastlane/metadata/android/en-US/changelogs/default.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fastlane/metadata/android/en-US/changelogs/default.txt b/fastlane/metadata/android/en-US/changelogs/default.txt index 45394e60c9a..ed7d0a59a25 100644 --- a/fastlane/metadata/android/en-US/changelogs/default.txt +++ b/fastlane/metadata/android/en-US/changelogs/default.txt @@ -1 +1,8 @@ -In our latest update, we've added a button in Google Campaign analytics for easier paid campaign creation. The Contact Support Form now includes a Site Address field. Enjoy seamless in-person payments illustrations in landscape mode, and benefit from background updates for order lists and dashboard analytics. +- [*] Added subtotal and taxes fields to each refund item on the refund screen. [https://github.com/woocommerce/woocommerce-android/pull/12235] +- [*****] [Internal] Update Android material from 1.9.0 to 1.10.0 [https://github.com/woocommerce/woocommerce-android/pull/12186] +- [*****] [Internal] Update Android-core from 1.12.0 to 1.13.1 [https://github.com/woocommerce/woocommerce-android/pull/12229] +- [*****] [Internal] Update Android-lifecycle from 2.6.2 to 2.7.0 [https://github.com/woocommerce/woocommerce-android/pull/12230] +- [*****] [Internal] Update Androidx-fragment from 1.6.2 to 1.8.2 [https://github.com/woocommerce/woocommerce-android/pull/12231] +- [*****] [Internal] Update Material to 1.12.0 and Transition to 1.5.1 [https://github.com/woocommerce/woocommerce-android/pull/12237] +- [*****] [Internal] Update Stripe Terminal SDK from 3.1.1 to 3.7.1 [https://github.com/woocommerce/woocommerce-android/pull/12239] + From 0b66c1377b52c18ff7db94288e38258a2385ca15 Mon Sep 17 00:00:00 2001 From: Automattic Release Bot Date: Fri, 9 Aug 2024 14:03:59 -0400 Subject: [PATCH 122/196] Release Notes: add new section for next version (20.0) --- RELEASE-NOTES.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index d489fb7c456..d0ef763ceba 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,6 +1,10 @@ *** PLEASE FOLLOW THIS FORMAT: [] [] *** Use [*****] to indicate smoke tests of all critical flows should be run on the final APK before release (e.g. major library or targetSdk updates). *** For entries which are touching the Android Wear app's, start entry with `[WEAR]` too. +20.0 +----- + + 19.9 ----- - [*] Added subtotal and taxes fields to each refund item on the refund screen. [https://github.com/woocommerce/woocommerce-android/pull/12235] From ed73579ba1a9840e14b637694daf9ad85aa934c6 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Fri, 9 Aug 2024 20:15:52 +0200 Subject: [PATCH 123/196] Update image visibility conditions --- .../CardReaderTutorialViewPagerItemFragment.kt | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt index 8b63e77bd2a..f2b0a6cfa2c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt @@ -7,25 +7,22 @@ import androidx.annotation.StringRes import androidx.fragment.app.Fragment import com.woocommerce.android.R import com.woocommerce.android.databinding.FragmentCardReaderTutorialViewpagerItemBinding -import com.woocommerce.android.extensions.hide -import org.wordpress.android.util.DisplayUtils +import com.woocommerce.android.util.UiHelpers /** * Displays a single image and text label in the card reader tutorial view pager */ -class CardReaderTutorialViewPagerItemFragment : Fragment(R.layout.fragment_card_reader_tutorial_viewpager_item) { +class CardReaderTutorialViewPagerItemFragment : + Fragment(R.layout.fragment_card_reader_tutorial_viewpager_item) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { arguments?.let { args -> val binding = FragmentCardReaderTutorialViewpagerItemBinding.bind(view) binding.labelTextView.setText(args.getInt(ARG_LABEL_ID)) binding.detailTextView.setText(args.getInt(ARG_DETAIL_ID)) - - // hide images in landscape - if (DisplayUtils.isLandscape(context)) { - binding.imageView.hide() - } else { - binding.imageView.setImageResource(args.getInt(ARG_DRAWABLE_ID)) - } + UiHelpers.setImageOrHideInLandscapeOnCompactScreenHeightSizeClass( + binding.imageView, + args.getInt(ARG_DRAWABLE_ID) + ) } } From 1cb593cbc7851ffffee78417447c6ff2d271c2c3 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Fri, 9 Aug 2024 20:29:36 +0200 Subject: [PATCH 124/196] Revert "Update image visibility conditions" This reverts commit ed73579ba1a9840e14b637694daf9ad85aa934c6. --- .../CardReaderTutorialViewPagerItemFragment.kt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt index f2b0a6cfa2c..8b63e77bd2a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt @@ -7,22 +7,25 @@ import androidx.annotation.StringRes import androidx.fragment.app.Fragment import com.woocommerce.android.R import com.woocommerce.android.databinding.FragmentCardReaderTutorialViewpagerItemBinding -import com.woocommerce.android.util.UiHelpers +import com.woocommerce.android.extensions.hide +import org.wordpress.android.util.DisplayUtils /** * Displays a single image and text label in the card reader tutorial view pager */ -class CardReaderTutorialViewPagerItemFragment : - Fragment(R.layout.fragment_card_reader_tutorial_viewpager_item) { +class CardReaderTutorialViewPagerItemFragment : Fragment(R.layout.fragment_card_reader_tutorial_viewpager_item) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { arguments?.let { args -> val binding = FragmentCardReaderTutorialViewpagerItemBinding.bind(view) binding.labelTextView.setText(args.getInt(ARG_LABEL_ID)) binding.detailTextView.setText(args.getInt(ARG_DETAIL_ID)) - UiHelpers.setImageOrHideInLandscapeOnCompactScreenHeightSizeClass( - binding.imageView, - args.getInt(ARG_DRAWABLE_ID) - ) + + // hide images in landscape + if (DisplayUtils.isLandscape(context)) { + binding.imageView.hide() + } else { + binding.imageView.setImageResource(args.getInt(ARG_DRAWABLE_ID)) + } } } From 2f368432567e7bcb7531ecd1278f7ec28beccc18 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Fri, 9 Aug 2024 20:32:11 +0200 Subject: [PATCH 125/196] Update image visibility conditions --- .../CardReaderTutorialViewPagerItemFragment.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt index 8b63e77bd2a..f781b70eaa3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt @@ -8,24 +8,25 @@ import androidx.fragment.app.Fragment import com.woocommerce.android.R import com.woocommerce.android.databinding.FragmentCardReaderTutorialViewpagerItemBinding import com.woocommerce.android.extensions.hide +import com.woocommerce.android.util.UiHelpers import org.wordpress.android.util.DisplayUtils /** * Displays a single image and text label in the card reader tutorial view pager */ -class CardReaderTutorialViewPagerItemFragment : Fragment(R.layout.fragment_card_reader_tutorial_viewpager_item) { +class CardReaderTutorialViewPagerItemFragment : + Fragment(R.layout.fragment_card_reader_tutorial_viewpager_item) { + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { arguments?.let { args -> val binding = FragmentCardReaderTutorialViewpagerItemBinding.bind(view) binding.labelTextView.setText(args.getInt(ARG_LABEL_ID)) binding.detailTextView.setText(args.getInt(ARG_DETAIL_ID)) - // hide images in landscape - if (DisplayUtils.isLandscape(context)) { - binding.imageView.hide() - } else { - binding.imageView.setImageResource(args.getInt(ARG_DRAWABLE_ID)) - } + UiHelpers.setImageOrHideInLandscapeOnCompactScreenHeightSizeClass( + binding.imageView, + args.getInt(ARG_DRAWABLE_ID) + ) } } From 3297e5c8d3122f64257d322d1cebdf533b98d8b1 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Fri, 9 Aug 2024 21:35:04 +0200 Subject: [PATCH 126/196] Move responsibility of cart's opacity animating to cart It's the Cart that keeps in its internal state the selected items count or empty state. That's why the Cart should decide about the opacity of its overlay and control the animation. Home is not keeping that state and is not capable of knowing if the Cart is really empty or not. --- .../ui/woopos/home/WooPosHomeScreen.kt | 21 ------------------- .../ui/woopos/home/cart/WooPosCartScreen.kt | 17 +++++++++++++++ 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt index b6e20f3441d..bc5229bb51b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt @@ -117,24 +117,12 @@ private fun WooPosHomeScreen( label = "totalsWidthAnimatedDp" ) - val cartOverlayIntensityAnimated by animateFloatAsState( - when (state.screenPositionState) { - is WooPosHomeState.ScreenPositionState.Cart.Visible.Empty -> .6f - WooPosHomeState.ScreenPositionState.Cart.Visible.NotEmpty, - WooPosHomeState.ScreenPositionState.Checkout.NotPaid, - WooPosHomeState.ScreenPositionState.Checkout.Paid, - WooPosHomeState.ScreenPositionState.Cart.Hidden -> 0f - }, - label = "cartOverlayAnimated" - ) - val scrollState = buildScrollStateForNavigationBetweenState(state.screenPositionState) WooPosHomeScreen( state = state, scrollState = scrollState, productsWidthDp = productsWidthAnimatedDp, cartWidthDp = cartWidthDp, - cartOverlayIntensity = cartOverlayIntensityAnimated, totalsWidthDp = totalsWidthAnimatedDp, onHomeUIEvent, ) @@ -146,7 +134,6 @@ private fun WooPosHomeScreen( scrollState: ScrollState, productsWidthDp: Dp, cartWidthDp: Dp, - cartOverlayIntensity: Float, totalsWidthDp: Dp, onHomeUIEvent: (WooPosHomeUIEvent) -> Unit, ) { @@ -172,14 +159,6 @@ private fun WooPosHomeScreen( modifier = Modifier .width(cartWidthDp) ) - Box( - modifier = Modifier - .width(cartWidthDp) - .fillMaxHeight() - .background( - color = MaterialTheme.colors.background.copy(alpha = cartOverlayIntensity), - ) - ) } } Row( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartScreen.kt index 11cf2638ee2..0498a5610f3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartScreen.kt @@ -3,6 +3,7 @@ package com.woocommerce.android.ui.woopos.home.cart import androidx.compose.animation.core.animateDpAsState +import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image @@ -13,6 +14,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -59,6 +61,7 @@ import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosButton import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosLazyColumn import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosOutlinedButton import com.woocommerce.android.ui.woopos.common.composeui.toAdaptivePadding +import com.woocommerce.android.ui.woopos.home.WooPosHomeState @Composable fun WooPosCartScreen(modifier: Modifier = Modifier) { @@ -116,6 +119,20 @@ private fun WooPosCartScreen( ) } } + val cartOverlayIntensityAnimated by animateFloatAsState( + when (state.body) { + WooPosCartState.Body.Empty -> .6f + is WooPosCartState.Body.WithItems -> 0f + }, + label = "cartOverlayAnimated" + ) + Box( + modifier = Modifier + .fillMaxSize() + .background( + color = MaterialTheme.colors.background.copy(alpha = cartOverlayIntensityAnimated), + ) + ) } @Composable From 7e1e472829c2c58bf3dc4eb8d1b1d52eb58cd8d3 Mon Sep 17 00:00:00 2001 From: Alejo Date: Fri, 9 Aug 2024 13:42:10 -0600 Subject: [PATCH 127/196] Update FluxC version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ecde748ffd9..7447b47f3a4 100644 --- a/build.gradle +++ b/build.gradle @@ -99,7 +99,7 @@ tasks.register("installGitHooks", Copy) { } ext { - fluxCVersion = 'trunk-06355b8e708b8303653a5e1afb751c25d469c40e' + fluxCVersion = '2.92.0' glideVersion = '4.16.0' coilVersion = '2.1.0' constraintLayoutVersion = '1.2.0' From f8a12efe4d3bdc9deda7717645dfffce6cc14ad5 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Fri, 9 Aug 2024 21:44:58 +0200 Subject: [PATCH 128/196] Remove unused imports --- .../com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt | 2 -- .../woocommerce/android/ui/woopos/home/cart/WooPosCartScreen.kt | 2 -- 2 files changed, 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt index bc5229bb51b..50beda10b35 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt @@ -3,7 +3,6 @@ package com.woocommerce.android.ui.woopos.home import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateDpAsState -import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.spring import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut @@ -15,7 +14,6 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartScreen.kt index 0498a5610f3..21a824ad545 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartScreen.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -61,7 +60,6 @@ import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosButton import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosLazyColumn import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosOutlinedButton import com.woocommerce.android.ui.woopos.common.composeui.toAdaptivePadding -import com.woocommerce.android.ui.woopos.home.WooPosHomeState @Composable fun WooPosCartScreen(modifier: Modifier = Modifier) { From c36862b529d71f723eb00cc4cc5c2c60745ec5e4 Mon Sep 17 00:00:00 2001 From: Alejo Date: Fri, 9 Aug 2024 14:08:52 -0600 Subject: [PATCH 129/196] Update FluxC version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ecde748ffd9..7447b47f3a4 100644 --- a/build.gradle +++ b/build.gradle @@ -99,7 +99,7 @@ tasks.register("installGitHooks", Copy) { } ext { - fluxCVersion = 'trunk-06355b8e708b8303653a5e1afb751c25d469c40e' + fluxCVersion = '2.92.0' glideVersion = '4.16.0' coilVersion = '2.1.0' constraintLayoutVersion = '1.2.0' From de20076f00eb813593d84a8ad49be82c79978463 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 9 Aug 2024 17:18:07 -0300 Subject: [PATCH 130/196] Add applicationContext and Locale implementations --- .../WCWearCrashLoggingDataProvider.kt | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt index dd316bd1562..42452e1e4f5 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt @@ -8,6 +8,7 @@ import com.automattic.android.tracks.crashlogging.PerformanceMonitoringConfig import com.automattic.android.tracks.crashlogging.ReleaseName import com.woocommerce.android.BuildConfig import com.woocommerce.android.wear.di.AppCoroutineScope +import com.woocommerce.android.wear.ui.login.LoginRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -20,11 +21,14 @@ import org.wordpress.android.fluxc.store.AccountStore import java.util.Locale import javax.inject.Inject import javax.inject.Singleton +import kotlinx.coroutines.flow.map @Singleton class WCWearCrashLoggingDataProvider @Inject constructor( private val accountStore: AccountStore, @AppCoroutineScope private val appScope: CoroutineScope, + private val providedLocale: Locale, + loginRepository: LoginRepository, dispatcher: Dispatcher, ) : CrashLoggingDataProvider { @@ -41,6 +45,7 @@ class WCWearCrashLoggingDataProvider @Inject constructor( } else { ReleaseName.SetByTracksLibrary } + override val locale: Locale get() = providedLocale @Suppress("unused", "unused_parameter") @Subscribe(threadMode = ThreadMode.MAIN) @@ -57,10 +62,20 @@ class WCWearCrashLoggingDataProvider @Inject constructor( override fun shouldDropWrappingException(module: String, type: String, value: String) = false - override val applicationContextProvider: Flow> - get() = TODO("Not yet implemented") - override val locale: Locale? - get() = TODO("Not yet implemented") + override val applicationContextProvider: Flow> = + loginRepository.selectedSiteFlow + .map { site -> + site?.let { + mutableMapOf( + SITE_URL_KEY to site.url + ).apply { + site.siteId.takeIf { it != 0L }?.toString()?.let { + this[SITE_ID_KEY] = it + } + } + }.orEmpty() + } + override val performanceMonitoringConfig: PerformanceMonitoringConfig get() = TODO("Not yet implemented") @@ -68,9 +83,7 @@ class WCWearCrashLoggingDataProvider @Inject constructor( TODO("Not yet implemented") } - override fun extraKnownKeys(): List { - TODO("Not yet implemented") - } + override fun extraKnownKeys(): List = emptyList() private fun AccountModel.toCrashLoggingUser(): CrashLoggingUser? { if (userId == 0L) return null @@ -83,6 +96,8 @@ class WCWearCrashLoggingDataProvider @Inject constructor( } companion object { + const val SITE_ID_KEY = "site_id" + const val SITE_URL_KEY = "site_url" const val DEBUG_RELEASE_NAME = "debug" } } From fd773496c6d55ebf4368535ce6826714fe3dace1 Mon Sep 17 00:00:00 2001 From: Alejo Date: Fri, 9 Aug 2024 14:23:12 -0600 Subject: [PATCH 131/196] Update changelogs for 19.9 release --- CHANGELOG.md | 3 +++ fastlane/metadata/android/en-US/changelogs/default.txt | 9 +-------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9378afa85b8..b79e9b593e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ +## 19.9 +We've enhanced your refund experience! Now, each refund item on the refund screen includes detailed subtotal and taxes fields, giving you clearer insights into your transactions. Update now to enjoy smoother, more transparent refunds! + ## 19.8 In our latest update, we've added a button in Google Campaign analytics for easier paid campaign creation. The Contact Support Form now includes a Site Address field. Enjoy seamless in-person payments illustrations in landscape mode, and benefit from background updates for order lists and dashboard analytics. diff --git a/fastlane/metadata/android/en-US/changelogs/default.txt b/fastlane/metadata/android/en-US/changelogs/default.txt index ed7d0a59a25..5f67c882148 100644 --- a/fastlane/metadata/android/en-US/changelogs/default.txt +++ b/fastlane/metadata/android/en-US/changelogs/default.txt @@ -1,8 +1 @@ -- [*] Added subtotal and taxes fields to each refund item on the refund screen. [https://github.com/woocommerce/woocommerce-android/pull/12235] -- [*****] [Internal] Update Android material from 1.9.0 to 1.10.0 [https://github.com/woocommerce/woocommerce-android/pull/12186] -- [*****] [Internal] Update Android-core from 1.12.0 to 1.13.1 [https://github.com/woocommerce/woocommerce-android/pull/12229] -- [*****] [Internal] Update Android-lifecycle from 2.6.2 to 2.7.0 [https://github.com/woocommerce/woocommerce-android/pull/12230] -- [*****] [Internal] Update Androidx-fragment from 1.6.2 to 1.8.2 [https://github.com/woocommerce/woocommerce-android/pull/12231] -- [*****] [Internal] Update Material to 1.12.0 and Transition to 1.5.1 [https://github.com/woocommerce/woocommerce-android/pull/12237] -- [*****] [Internal] Update Stripe Terminal SDK from 3.1.1 to 3.7.1 [https://github.com/woocommerce/woocommerce-android/pull/12239] - +We've enhanced your refund experience! Now, each refund item on the refund screen includes detailed subtotal and taxes fields, giving you clearer insights into your transactions. Update now to enjoy smoother, more transparent refunds! From 6a485d033acba259a438ee26681c1962b0584214 Mon Sep 17 00:00:00 2001 From: Automattic Release Bot Date: Fri, 9 Aug 2024 16:43:31 -0400 Subject: [PATCH 132/196] Update `PlayStoreStrings.po` for 19.9 --- fastlane/metadata/PlayStoreStrings.pot | 12 ++++++------ fastlane/metadata/android/ar/changelogs/default.txt | 2 -- .../metadata/android/de-DE/changelogs/default.txt | 2 -- .../metadata/android/es-ES/changelogs/default.txt | 2 -- .../metadata/android/fr-FR/changelogs/default.txt | 2 -- fastlane/metadata/android/id/changelogs/default.txt | 2 -- .../metadata/android/it-IT/changelogs/default.txt | 2 -- .../metadata/android/iw-IL/changelogs/default.txt | 2 -- .../metadata/android/ja-JP/changelogs/default.txt | 2 -- .../metadata/android/ko-KR/changelogs/default.txt | 2 -- .../metadata/android/nl-NL/changelogs/default.txt | 2 -- .../metadata/android/pt-BR/changelogs/default.txt | 2 -- .../metadata/android/ru-RU/changelogs/default.txt | 2 -- .../metadata/android/sv-SE/changelogs/default.txt | 2 -- .../metadata/android/tr-TR/changelogs/default.txt | 2 -- .../metadata/android/zh-CN/changelogs/default.txt | 2 -- .../metadata/android/zh-TW/changelogs/default.txt | 2 -- 17 files changed, 6 insertions(+), 38 deletions(-) delete mode 100644 fastlane/metadata/android/ar/changelogs/default.txt delete mode 100644 fastlane/metadata/android/de-DE/changelogs/default.txt delete mode 100644 fastlane/metadata/android/es-ES/changelogs/default.txt delete mode 100644 fastlane/metadata/android/fr-FR/changelogs/default.txt delete mode 100644 fastlane/metadata/android/id/changelogs/default.txt delete mode 100644 fastlane/metadata/android/it-IT/changelogs/default.txt delete mode 100644 fastlane/metadata/android/iw-IL/changelogs/default.txt delete mode 100644 fastlane/metadata/android/ja-JP/changelogs/default.txt delete mode 100644 fastlane/metadata/android/ko-KR/changelogs/default.txt delete mode 100644 fastlane/metadata/android/nl-NL/changelogs/default.txt delete mode 100644 fastlane/metadata/android/pt-BR/changelogs/default.txt delete mode 100644 fastlane/metadata/android/ru-RU/changelogs/default.txt delete mode 100644 fastlane/metadata/android/sv-SE/changelogs/default.txt delete mode 100644 fastlane/metadata/android/tr-TR/changelogs/default.txt delete mode 100644 fastlane/metadata/android/zh-CN/changelogs/default.txt delete mode 100644 fastlane/metadata/android/zh-TW/changelogs/default.txt diff --git a/fastlane/metadata/PlayStoreStrings.pot b/fastlane/metadata/PlayStoreStrings.pot index 83b17ec5333..2dde86e600a 100644 --- a/fastlane/metadata/PlayStoreStrings.pot +++ b/fastlane/metadata/PlayStoreStrings.pot @@ -16,16 +16,16 @@ msgid "Introduces the new Woo WearOS app featuring instant updates on store data msgstr "" #. translators: Release notes for this version to be displayed in the Play Store. Limit to 500 characters including spaces and commas! -msgctxt "release_note_198" +msgctxt "release_note_199" msgid "" -"19.8:\n" -"In our latest update, we've added a button in Google Campaign analytics for easier paid campaign creation. The Contact Support Form now includes a Site Address field. Enjoy seamless in-person payments illustrations in landscape mode, and benefit from background updates for order lists and dashboard analytics.\n" +"19.9:\n" +"We've enhanced your refund experience! Now, each refund item on the refund screen includes detailed subtotal and taxes fields, giving you clearer insights into your transactions. Update now to enjoy smoother, more transparent refunds!\n" msgstr "" -msgctxt "release_note_197" +msgctxt "release_note_198" msgid "" -"19.7:\n" -"Get ready for a better WooCommerce experience with our latest update! Now, create and manage Google Ads campaigns seamlessly. Enjoy enhanced stability on the order detail screen and get helpful tips with our new AI-powered advice box during product creation. Experience the improvements today!\n" +"19.8:\n" +"In our latest update, we've added a button in Google Campaign analytics for easier paid campaign creation. The Contact Support Form now includes a Site Address field. Enjoy seamless in-person payments illustrations in landscape mode, and benefit from background updates for order lists and dashboard analytics.\n" msgstr "" #. translators: Short description of the app to be displayed in the Play Store. Limit to 80 characters including spaces and commas! diff --git a/fastlane/metadata/android/ar/changelogs/default.txt b/fastlane/metadata/android/ar/changelogs/default.txt deleted file mode 100644 index 58e29aaf360..00000000000 --- a/fastlane/metadata/android/ar/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -في آخر تحديث لدينا، أضفنا زرًا في تحليلات حملة غوغل لتسجيل إنشاء الحملة المدفوعة. يشتمل نموذج دعم الاتصال الآن على حقل عنوان الموقع. استمتع برسوم توضيحية سلسة للمدفوعات الشخصية في الوضع الأفقي، واستفد من التحديثات في الخلفية لقوائم الطلبات وتحليلات لوحة التحكم. diff --git a/fastlane/metadata/android/de-DE/changelogs/default.txt b/fastlane/metadata/android/de-DE/changelogs/default.txt deleted file mode 100644 index 8af9dea82f9..00000000000 --- a/fastlane/metadata/android/de-DE/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -Bei unserem letzten Update haben wir einen Button zu den Analysen für Google-Kampagnen hinzugefügt, um die Erstellung kostenpflichtiger Kampagnen zu erleichtern. Das Formular „Support kontaktieren“ enthält nun ein Feld für die Website-Adresse. Genieße makellose Darstellungen persönlicher Zahlungen im Querformat und profitiere von Hintergrundupdates für Bestelllisten und Dashboard-Analysen. diff --git a/fastlane/metadata/android/es-ES/changelogs/default.txt b/fastlane/metadata/android/es-ES/changelogs/default.txt deleted file mode 100644 index 6e001949f5a..00000000000 --- a/fastlane/metadata/android/es-ES/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -En nuestra última actualización, hemos añadido un botón en el análisis de Google Campaigns para facilitar la creación de campañas de pago. El formulario de contacto para asistencia incluye ahora un campo de dirección del sitio. Disfruta de ilustraciones de pagos en persona sin interrupciones en modo horizontal y benefíciate de las actualizaciones en segundo plano de las listas de pedidos y los análisis del escritorio. diff --git a/fastlane/metadata/android/fr-FR/changelogs/default.txt b/fastlane/metadata/android/fr-FR/changelogs/default.txt deleted file mode 100644 index 86bad2be534..00000000000 --- a/fastlane/metadata/android/fr-FR/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8 : -Dans notre dernière mise à jour, nous avons ajouté un bouton dans les statistiques de campagnes Google pour une création de campagne payante plus facile. Le formulaire Contacter l’assistance comprend dorénavant un champ Adresse du site. Profitez d’illustrations de paiements en personne fluides en mode paysage et profitez de mises à jour en arrière-plan pour les listes de commandes et les statistiques du tableau de bord. diff --git a/fastlane/metadata/android/id/changelogs/default.txt b/fastlane/metadata/android/id/changelogs/default.txt deleted file mode 100644 index a247acf49b0..00000000000 --- a/fastlane/metadata/android/id/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -Dalam pembaruan teranyar, kami telah menambahkan tombol pada analitik Google Campaign agar bisa lebih mudah membuat kampanye berbayar. Formulir Dukungan Kontak sekarang menyertakan kolom Alamat Situs. Gunakan ilustrasi pembayaran langsung yang lebih baik dalam mode lanskap, dan manfaatkan pembaruan latar belakang untuk daftar pesanan dan analitik dasbor. diff --git a/fastlane/metadata/android/it-IT/changelogs/default.txt b/fastlane/metadata/android/it-IT/changelogs/default.txt deleted file mode 100644 index 00c28d90e86..00000000000 --- a/fastlane/metadata/android/it-IT/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -Nel nostro ultimo aggiornamento abbiamo aggiunto un pulsante nelle analisi di Google Campaign per una creazione di campagne a pagamento più semplice. Il modulo Contatta il supporto ora include il campo Indirizzo del sito. Goditi perfette illustrazioni dei pagamenti di persona in modalità orizzontale e approfitta degli aggiornamenti in background per gli elenchi degli ordini e le analisi della bacheca. diff --git a/fastlane/metadata/android/iw-IL/changelogs/default.txt b/fastlane/metadata/android/iw-IL/changelogs/default.txt deleted file mode 100644 index 7cc3ef43d72..00000000000 --- a/fastlane/metadata/android/iw-IL/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -בעדכון האחרון, הוספנו כפתור לנתונים אנליטיים בקמפיינים של Google כדי לאפשר יצירה פשוטה יותר של קמפיינים בתשלום. הטופס 'יצירת קשר עם התמיכה' כעת כולל שדה של 'כתובת האתר'. בתהליך התשלומים באופן אישי, אפשר ליהנות מתוכן ברור יותר גם במסך עם תצוגה לרוחב וליהנות מעדכונים ברקע של רשימת הזמנות ונתונים אנליטיים בלוח הבקרה. diff --git a/fastlane/metadata/android/ja-JP/changelogs/default.txt b/fastlane/metadata/android/ja-JP/changelogs/default.txt deleted file mode 100644 index 1a0fee46bdd..00000000000 --- a/fastlane/metadata/android/ja-JP/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -最新アップデートで Google キャンペーン分析にボタンが追加され、有料キャンペーンの作成が容易になりました。 「サポートに連絡」フォームに「サイトのアドレス」フィールドが追加されました。 ランドスケープモードで、シームレスなオフライン支払いに関するイラストレーションをご活用ください。また、注文リストとダッシュボード分析のバックグラウンド更新をご利用いただけます。 diff --git a/fastlane/metadata/android/ko-KR/changelogs/default.txt b/fastlane/metadata/android/ko-KR/changelogs/default.txt deleted file mode 100644 index 585557a936e..00000000000 --- a/fastlane/metadata/android/ko-KR/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -최신 업데이트에서는 더욱 간편하게 유료 캠페인을 만들 수 있는 버튼이 Google 캠페인 분석에 추가되었습니다. 이제 지원팀에 문의 양식에 사이트 주소 필드가 포함됩니다. 가로 모드에서도 대면 결제 일러스트레이션이 이질감 없이 표시되며, 주문 목록 및 알림판 분석이 백그라운드에서 업데이트됩니다. diff --git a/fastlane/metadata/android/nl-NL/changelogs/default.txt b/fastlane/metadata/android/nl-NL/changelogs/default.txt deleted file mode 100644 index 65d401cb9ae..00000000000 --- a/fastlane/metadata/android/nl-NL/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -In onze nieuwste update hebben we een knop toegevoegd in de analyse van Google-campagnes om makkelijker betaalde campagnes aan te maken. Het contactformulier van de ondersteuning bevat nu een veld voor het websiteadres. Illustraties voor fysieke betalingen werken nu naadloos in landschapmodus, en je kan je voordeel doen met achtergrondupdates voor bestellijsten en analyses op het dashboard. diff --git a/fastlane/metadata/android/pt-BR/changelogs/default.txt b/fastlane/metadata/android/pt-BR/changelogs/default.txt deleted file mode 100644 index 18e64ab073f..00000000000 --- a/fastlane/metadata/android/pt-BR/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -Na nossa atualização mais recente, adicionamos um botão nas análises de campanhas do Google para criar campanhas pagas com mais facilidade. O formulário para entrar em contato com o suporte agora inclui um campo de endereço de site. Aproveite as ilustrações de pagamento presencial no modo paisagem e ganhe atualizações em plano de fundo para análises de painéis e listas de pedidos. diff --git a/fastlane/metadata/android/ru-RU/changelogs/default.txt b/fastlane/metadata/android/ru-RU/changelogs/default.txt deleted file mode 100644 index 4b7c26b3ec3..00000000000 --- a/fastlane/metadata/android/ru-RU/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -В этом обновлении мы добавили кнопку в раздел аналитики кампаний Google, чтобы было удобнее создавать платные кампании. В форме «Связаться со службой поддержки» появилось поле «Адрес сайта». Теперь вы можете спокойно рассматривать иллюстрации в альбомной ориентации при совершении очного платежа, а также пользоваться преимуществами обновления списков заказов и аналитики панели мониторинга в фоновом режиме. diff --git a/fastlane/metadata/android/sv-SE/changelogs/default.txt b/fastlane/metadata/android/sv-SE/changelogs/default.txt deleted file mode 100644 index 83cd27f988c..00000000000 --- a/fastlane/metadata/android/sv-SE/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -I vår senaste uppdatering har vi lagt till en knapp i Google-kampanjanalysen som gör det enklare att skapa betalkampanjer. Kontakta support-formuläret inkluderar nu ett Webbplatsadress-fält. Ta del av sömlösa illustrationer av personliga betalningar i liggande läge och dra nytta av bakgrundsuppdateringar för beställningslistor och adminpanelsanalyser. diff --git a/fastlane/metadata/android/tr-TR/changelogs/default.txt b/fastlane/metadata/android/tr-TR/changelogs/default.txt deleted file mode 100644 index 2c97e66d80d..00000000000 --- a/fastlane/metadata/android/tr-TR/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -En son güncellememizde daha kolay ücretli kampanya oluşturma deneyimi için Google Kampanya analizlerine bir düğme ekledik. Desteğe Ulaşın Formu artık Site Adresi alanı içeriyor. Yatay modda sorunsuz şahsen ödeme illüstrasyonlarının keyfini çıkarın ve sipariş listeleri ve pano analizleri için arkaplan güncellemelerinden yararlanın. diff --git a/fastlane/metadata/android/zh-CN/changelogs/default.txt b/fastlane/metadata/android/zh-CN/changelogs/default.txt deleted file mode 100644 index 22aea23c415..00000000000 --- a/fastlane/metadata/android/zh-CN/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -在最新更新中,我们在 Google 广告活动分析中新增了一个按钮,以便于创建付费广告活动。 联系支持人员表单现在包含站点地址字段。 享受横向模式下的无缝现场付款图示,并受益于后台更新订单列表和仪表盘分析的功能。 diff --git a/fastlane/metadata/android/zh-TW/changelogs/default.txt b/fastlane/metadata/android/zh-TW/changelogs/default.txt deleted file mode 100644 index e573352f6ab..00000000000 --- a/fastlane/metadata/android/zh-TW/changelogs/default.txt +++ /dev/null @@ -1,2 +0,0 @@ -19.8: -在最新版本中,我們已在 Google 廣告活動分析中新增了按鈕,方便更輕鬆地建立付費廣告活動。 「聯絡支援部門」表單現在已包含「網站位址」欄位。 在橫向模式中享有流暢的親自收款插圖,並獲得訂單清單背景更新與儀表板分析的優勢。 From 74dbc933f5e41744da678ee31857b43b14eb7bce Mon Sep 17 00:00:00 2001 From: Automattic Release Bot Date: Fri, 9 Aug 2024 16:43:33 -0400 Subject: [PATCH 133/196] Freeze strings for translation --- fastlane/resources/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/resources/values/strings.xml b/fastlane/resources/values/strings.xml index f4d3c4b9092..16ba52d1172 100644 --- a/fastlane/resources/values/strings.xml +++ b/fastlane/resources/values/strings.xml @@ -4237,7 +4237,7 @@ Error loading products Give it another go? Error indication icon - Rerty + Retry Couldn\'t create order A payment of %1$s was successfully made From 98091b32a503c6130cb9db0912a43f0d9a460236 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 9 Aug 2024 17:47:42 -0300 Subject: [PATCH 134/196] Introduce Settings DataStore qualifiers and injection --- .../android/wear/datastore/DataStoreType.kt | 3 ++- .../woocommerce/android/wear/di/DataStoreModule.kt | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/datastore/DataStoreType.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/datastore/DataStoreType.kt index 059e726a6bd..d89ab4e0327 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/datastore/DataStoreType.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/datastore/DataStoreType.kt @@ -3,5 +3,6 @@ package com.woocommerce.android.wear.datastore enum class DataStoreType(val typeName: String) { LOGIN("login"), STATS("stats"), - ORDERS("orders") + ORDERS("orders"), + SETTINGS("settings") } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/DataStoreModule.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/DataStoreModule.kt index a7725fd11e1..39783349bf7 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/DataStoreModule.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/DataStoreModule.kt @@ -8,6 +8,7 @@ import androidx.datastore.preferences.preferencesDataStoreFile import com.woocommerce.android.wear.datastore.DataStoreQualifier import com.woocommerce.android.wear.datastore.DataStoreType.LOGIN import com.woocommerce.android.wear.datastore.DataStoreType.ORDERS +import com.woocommerce.android.wear.datastore.DataStoreType.SETTINGS import com.woocommerce.android.wear.datastore.DataStoreType.STATS import dagger.Module import dagger.Provides @@ -52,4 +53,15 @@ class DataStoreModule { produceFile = { appContext.preferencesDataStoreFile(ORDERS.typeName) }, scope = CoroutineScope(appCoroutineScope.coroutineContext + Dispatchers.IO) ) + + @Provides + @Singleton + @DataStoreQualifier(SETTINGS) + fun providePrefsDataStore( + appContext: Context, + @AppCoroutineScope appCoroutineScope: CoroutineScope + ): DataStore = PreferenceDataStoreFactory.create( + produceFile = { appContext.preferencesDataStoreFile(SETTINGS.typeName) }, + scope = CoroutineScope(appCoroutineScope.coroutineContext + Dispatchers.IO) + ) } From e3e86496f156757275f94226aa8dd7d74725bb41 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 9 Aug 2024 17:58:05 -0300 Subject: [PATCH 135/196] Define SettingsKey for better value control --- .../android/wear/prefs/AppSettingsType.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/AppSettingsType.kt diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/AppSettingsType.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/AppSettingsType.kt new file mode 100644 index 00000000000..19e3a469ae6 --- /dev/null +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/AppSettingsType.kt @@ -0,0 +1,12 @@ +package com.woocommerce.android.wear.prefs + +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.booleanPreferencesKey + +sealed class SettingsKey( + open val prefsKey: Preferences.Key +) { + data object CrashReportEnabled : SettingsKey( + prefsKey = booleanPreferencesKey("crash_report_enabled") + ) +} From 2d56afe6889c32d325d69858244fb0ec8fa3fd58 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 9 Aug 2024 18:04:54 -0300 Subject: [PATCH 136/196] Introduce SettingsRepository --- .../android/wear/prefs/SettingsRepository.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt new file mode 100644 index 00000000000..dc5912dbfe0 --- /dev/null +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt @@ -0,0 +1,21 @@ +package com.woocommerce.android.wear.prefs + +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit +import com.woocommerce.android.wear.datastore.DataStoreQualifier +import com.woocommerce.android.wear.datastore.DataStoreType +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.mapNotNull + +class SettingsRepository @Inject constructor( + @DataStoreQualifier(DataStoreType.SETTINGS) private val settingsDataStore: DataStore +) { + suspend fun storeSettingsKey(key: SettingsKey, value: T) { + settingsDataStore.edit { it[key.prefsKey] = value } + } + + fun fetchSettingsValue(key: SettingsKey): Flow = + settingsDataStore.data.mapNotNull { it[key.prefsKey] } +} From c559a484be73cdf368410e468fcd79aacefa3c6f Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 9 Aug 2024 18:14:24 -0300 Subject: [PATCH 137/196] Introduce WearAppSettings and respective Path --- libs/commons/src/main/java/com/woocommerce/commons/Paths.kt | 5 ++++- .../main/java/com/woocommerce/commons/WearSharedModels.kt | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/libs/commons/src/main/java/com/woocommerce/commons/Paths.kt b/libs/commons/src/main/java/com/woocommerce/commons/Paths.kt index c9f258b34c0..de22d940ad9 100644 --- a/libs/commons/src/main/java/com/woocommerce/commons/Paths.kt +++ b/libs/commons/src/main/java/com/woocommerce/commons/Paths.kt @@ -39,5 +39,8 @@ enum class DataParameters(val value: String) { // Analytics data ANALYTICS_TRACK("analytics-track"), - ANALYTICS_PARAMETERS("analytics-parameters") + ANALYTICS_PARAMETERS("analytics-parameters"), + + // App Settings + APP_SETTINGS("app_settings") } diff --git a/libs/commons/src/main/java/com/woocommerce/commons/WearSharedModels.kt b/libs/commons/src/main/java/com/woocommerce/commons/WearSharedModels.kt index d27a33fae6f..82cd26571ea 100644 --- a/libs/commons/src/main/java/com/woocommerce/commons/WearSharedModels.kt +++ b/libs/commons/src/main/java/com/woocommerce/commons/WearSharedModels.kt @@ -32,3 +32,7 @@ data class WearOrderAddress( val country: String, val phone: String ) + +data class WearAppSettings( + val crashReportEnabled: Boolean +) From b891e18ea5f3b91500516fb18218750e57d48366 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 9 Aug 2024 18:28:49 -0300 Subject: [PATCH 138/196] Configure App Settings message and data channels --- .../wear/WearableConnectionRepository.kt | 17 +++++++++++++++++ .../android/wear/WearableConnectionService.kt | 2 ++ .../main/java/com/woocommerce/commons/Paths.kt | 6 ++++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt index 342b2fda202..0642d322e8c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt @@ -6,12 +6,14 @@ import com.google.android.gms.wearable.MessageEvent import com.google.android.gms.wearable.PutDataMapRequest import com.google.gson.Gson import com.google.gson.reflect.TypeToken +import com.woocommerce.android.AppPrefs import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.analytics.toAnalyticsEvent import com.woocommerce.android.extensions.convertedFrom import com.woocommerce.android.tools.SelectedSite import com.woocommerce.commons.DataParameters.ANALYTICS_PARAMETERS import com.woocommerce.commons.DataParameters.ANALYTICS_TRACK +import com.woocommerce.commons.DataParameters.APP_SETTINGS import com.woocommerce.commons.DataParameters.CONVERSION_RATE import com.woocommerce.commons.DataParameters.ORDERS_COUNT import com.woocommerce.commons.DataParameters.ORDERS_JSON @@ -24,11 +26,13 @@ import com.woocommerce.commons.DataParameters.TOKEN import com.woocommerce.commons.DataParameters.TOTAL_REVENUE import com.woocommerce.commons.DataParameters.VISITORS_TOTAL import com.woocommerce.commons.DataPath +import com.woocommerce.commons.DataPath.APP_SETTINGS_DATA import com.woocommerce.commons.DataPath.ORDERS_DATA import com.woocommerce.commons.DataPath.ORDER_PRODUCTS_DATA import com.woocommerce.commons.DataPath.SITE_DATA import com.woocommerce.commons.DataPath.STATS_DATA import com.woocommerce.commons.WearAnalyticsEvent +import com.woocommerce.commons.WearAppSettings import com.woocommerce.commons.WearOrder import com.woocommerce.commons.WearOrderAddress import kotlinx.coroutines.CoroutineScope @@ -156,6 +160,19 @@ class WearableConnectionRepository @Inject constructor( ) } + fun sendAppSettingsData() = coroutineScope.launch { + val settingsJson = WearAppSettings( + crashReportEnabled = AppPrefs.isCrashReportingEnabled() + ).let { gson.toJson(it) } + + sendData( + APP_SETTINGS_DATA, + DataMap().apply { + putString(APP_SETTINGS.value, settingsJson) + } + ) + } + fun receiveAnalyticsFromWear(dataMap: DataMap) { val typeToken = object : TypeToken>() {}.type val parameters: Map = dataMap.getString(ANALYTICS_PARAMETERS.value) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionService.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionService.kt index ccccc5b7a04..82cf5be94f7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionService.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionService.kt @@ -6,6 +6,7 @@ import com.google.android.gms.wearable.DataMapItem import com.google.android.gms.wearable.MessageEvent import com.google.android.gms.wearable.WearableListenerService import com.woocommerce.commons.DataPath.ANALYTICS_DATA +import com.woocommerce.commons.MessagePath.REQUEST_APP_SETTINGS import com.woocommerce.commons.MessagePath.REQUEST_ORDERS import com.woocommerce.commons.MessagePath.REQUEST_ORDER_PRODUCTS import com.woocommerce.commons.MessagePath.REQUEST_SITE @@ -26,6 +27,7 @@ class WearableConnectionService : WearableListenerService() { REQUEST_STATS.value -> wearableConnectionRepository.sendStatsData() REQUEST_ORDERS.value -> wearableConnectionRepository.sendOrdersData() REQUEST_ORDER_PRODUCTS.value -> wearableConnectionRepository.sendOrderProductsData(message) + REQUEST_APP_SETTINGS.value -> wearableConnectionRepository.sendAppSettingsData() } } diff --git a/libs/commons/src/main/java/com/woocommerce/commons/Paths.kt b/libs/commons/src/main/java/com/woocommerce/commons/Paths.kt index de22d940ad9..ac5254669d5 100644 --- a/libs/commons/src/main/java/com/woocommerce/commons/Paths.kt +++ b/libs/commons/src/main/java/com/woocommerce/commons/Paths.kt @@ -4,7 +4,8 @@ enum class MessagePath(val value: String) { REQUEST_SITE("/request-site"), REQUEST_STATS("/request-stats"), REQUEST_ORDERS("/request-orders"), - REQUEST_ORDER_PRODUCTS("/request-order-products") + REQUEST_ORDER_PRODUCTS("/request-order-products"), + REQUEST_APP_SETTINGS("/request-app-settings") } enum class DataPath(val value: String) { @@ -12,7 +13,8 @@ enum class DataPath(val value: String) { STATS_DATA("/stats-data"), ORDERS_DATA("/orders-data"), ORDER_PRODUCTS_DATA("/order-products-data"), - ANALYTICS_DATA("/analytics-data") + ANALYTICS_DATA("/analytics-data"), + APP_SETTINGS_DATA("/app-settings-data") } enum class DataParameters(val value: String) { From 2a7e43175edfaf42bc48c7b4a0b2765daa447226 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 9 Aug 2024 18:47:05 -0300 Subject: [PATCH 139/196] Handle app settings data response from Phone --- .../wear/phone/PhoneConnectionRepository.kt | 4 ++++ .../android/wear/prefs/SettingsRepository.kt | 22 +++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/phone/PhoneConnectionRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/phone/PhoneConnectionRepository.kt index becaa3e8a38..9cb79d786b3 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/phone/PhoneConnectionRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/phone/PhoneConnectionRepository.kt @@ -8,11 +8,13 @@ import com.google.android.gms.wearable.DataMap import com.google.android.gms.wearable.DataMapItem import com.google.android.gms.wearable.MessageClient import com.google.android.gms.wearable.PutDataMapRequest +import com.woocommerce.android.wear.prefs.SettingsRepository import com.woocommerce.android.wear.ui.login.LoginRepository import com.woocommerce.android.wear.ui.orders.OrdersRepository import com.woocommerce.android.wear.ui.stats.datasource.StatsRepository import com.woocommerce.commons.DataParameters import com.woocommerce.commons.DataPath +import com.woocommerce.commons.DataPath.APP_SETTINGS_DATA import com.woocommerce.commons.DataPath.ORDERS_DATA import com.woocommerce.commons.DataPath.ORDER_PRODUCTS_DATA import com.woocommerce.commons.DataPath.SITE_DATA @@ -30,6 +32,7 @@ class PhoneConnectionRepository @Inject constructor( private val loginRepository: LoginRepository, private val statsRepository: StatsRepository, private val ordersRepository: OrdersRepository, + private val settingsRepository: SettingsRepository, private val capabilityClient: CapabilityClient, private val dataClient: DataClient, private val messageClient: MessageClient, @@ -47,6 +50,7 @@ class PhoneConnectionRepository @Inject constructor( STATS_DATA.value -> statsRepository.receiveStatsDataFromPhone(dataMap) ORDERS_DATA.value -> ordersRepository.receiveOrdersDataFromPhone(dataMap) ORDER_PRODUCTS_DATA.value -> ordersRepository.receiveOrderProductsDataFromPhone(dataMap) + APP_SETTINGS_DATA.value -> settingsRepository.receiveAppSettingsDataFromPhone(dataMap) else -> Log.d(TAG, "Unknown path data received") } } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt index dc5912dbfe0..9a3e227bc14 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt @@ -3,8 +3,12 @@ package com.woocommerce.android.wear.prefs import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit +import com.google.android.gms.wearable.DataMap +import com.google.gson.Gson import com.woocommerce.android.wear.datastore.DataStoreQualifier import com.woocommerce.android.wear.datastore.DataStoreType +import com.woocommerce.commons.DataParameters.APP_SETTINGS +import com.woocommerce.commons.WearAppSettings import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.mapNotNull @@ -12,10 +16,24 @@ import kotlinx.coroutines.flow.mapNotNull class SettingsRepository @Inject constructor( @DataStoreQualifier(DataStoreType.SETTINGS) private val settingsDataStore: DataStore ) { - suspend fun storeSettingsKey(key: SettingsKey, value: T) { - settingsDataStore.edit { it[key.prefsKey] = value } + private val gson by lazy { Gson() } + + suspend fun receiveAppSettingsDataFromPhone(data: DataMap) { + val settings = data.getString(APP_SETTINGS.value, "") + .takeIf { it.isNotEmpty() } + ?.let { gson.fromJson(it, WearAppSettings::class.java) } + ?: return + + storeSettingsKey( + key = SettingsKey.CrashReportEnabled, + value = settings.crashReportEnabled + ) } fun fetchSettingsValue(key: SettingsKey): Flow = settingsDataStore.data.mapNotNull { it[key.prefsKey] } + + private suspend fun storeSettingsKey(key: SettingsKey, value: T) { + settingsDataStore.edit { it[key.prefsKey] = value } + } } From 55a309c8084b2f2062452f17491511ac16870017 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 9 Aug 2024 19:04:52 -0300 Subject: [PATCH 140/196] Rename SettingsKey to SettingsType --- .../woocommerce/android/wear/prefs/AppSettingsType.kt | 4 ++-- .../android/wear/prefs/SettingsRepository.kt | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/AppSettingsType.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/AppSettingsType.kt index 19e3a469ae6..be5f4126517 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/AppSettingsType.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/AppSettingsType.kt @@ -3,10 +3,10 @@ package com.woocommerce.android.wear.prefs import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.booleanPreferencesKey -sealed class SettingsKey( +sealed class SettingsType( open val prefsKey: Preferences.Key ) { - data object CrashReportEnabled : SettingsKey( + data object CrashReportEnabled : SettingsType( prefsKey = booleanPreferencesKey("crash_report_enabled") ) } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt index 9a3e227bc14..b228a62c5a2 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt @@ -10,7 +10,7 @@ import com.woocommerce.android.wear.datastore.DataStoreType import com.woocommerce.commons.DataParameters.APP_SETTINGS import com.woocommerce.commons.WearAppSettings import javax.inject.Inject -import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.mapNotNull class SettingsRepository @Inject constructor( @@ -25,15 +25,15 @@ class SettingsRepository @Inject constructor( ?: return storeSettingsKey( - key = SettingsKey.CrashReportEnabled, + key = SettingsType.CrashReportEnabled, value = settings.crashReportEnabled ) } - fun fetchSettingsValue(key: SettingsKey): Flow = - settingsDataStore.data.mapNotNull { it[key.prefsKey] } + suspend fun fetchSettingsValue(key: SettingsType): T = + settingsDataStore.data.mapNotNull { it[key.prefsKey] }.first() - private suspend fun storeSettingsKey(key: SettingsKey, value: T) { + private suspend fun storeSettingsKey(key: SettingsType, value: T) { settingsDataStore.edit { it[key.prefsKey] = value } } } From 607635b0d31fb36b88a12388ee90322d17eb226b Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 9 Aug 2024 19:35:46 -0300 Subject: [PATCH 141/196] Move PreferenceUtils to the commons library --- WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefs.kt | 2 +- .../main/java/com/woocommerce/commons/prefs}/PreferenceUtils.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename {WooCommerce/src/main/kotlin/com/woocommerce/android/util => libs/commons/src/main/java/com/woocommerce/commons/prefs}/PreferenceUtils.kt (97%) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefs.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefs.kt index 37f5fd13f1b..48d18f64d9c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefs.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefs.kt @@ -43,9 +43,9 @@ import com.woocommerce.android.ui.prefs.domain.DomainFlowSource import com.woocommerce.android.ui.products.ProductType import com.woocommerce.android.ui.products.ai.AiTone import com.woocommerce.android.ui.promobanner.PromoBannerType -import com.woocommerce.android.util.PreferenceUtils import com.woocommerce.android.util.ThemeOption import com.woocommerce.android.util.ThemeOption.DEFAULT +import com.woocommerce.commons.prefs.PreferenceUtils import java.util.Calendar import java.util.Date diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PreferenceUtils.kt b/libs/commons/src/main/java/com/woocommerce/commons/prefs/PreferenceUtils.kt similarity index 97% rename from WooCommerce/src/main/kotlin/com/woocommerce/android/util/PreferenceUtils.kt rename to libs/commons/src/main/java/com/woocommerce/commons/prefs/PreferenceUtils.kt index 50c22ab24eb..b04c027bb1c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PreferenceUtils.kt +++ b/libs/commons/src/main/java/com/woocommerce/commons/prefs/PreferenceUtils.kt @@ -1,4 +1,4 @@ -package com.woocommerce.android.util +package com.woocommerce.commons.prefs import android.content.SharedPreferences From 5a88dc4e3966f0649bf669c6718838e91f0bc8c2 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 9 Aug 2024 19:36:04 -0300 Subject: [PATCH 142/196] Refactor the AppSettings to use SharedPreferences --- .../android/wear/prefs/AppSettingsType.kt | 12 ----------- .../android/wear/settings/AppSettingsType.kt | 21 +++++++++++++++++++ 2 files changed, 21 insertions(+), 12 deletions(-) delete mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/AppSettingsType.kt create mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/AppSettingsType.kt diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/AppSettingsType.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/AppSettingsType.kt deleted file mode 100644 index be5f4126517..00000000000 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/AppSettingsType.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.woocommerce.android.wear.prefs - -import androidx.datastore.preferences.core.Preferences -import androidx.datastore.preferences.core.booleanPreferencesKey - -sealed class SettingsType( - open val prefsKey: Preferences.Key -) { - data object CrashReportEnabled : SettingsType( - prefsKey = booleanPreferencesKey("crash_report_enabled") - ) -} diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/AppSettingsType.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/AppSettingsType.kt new file mode 100644 index 00000000000..2fde51610fd --- /dev/null +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/AppSettingsType.kt @@ -0,0 +1,21 @@ +package com.woocommerce.android.wear.settings + +import android.content.SharedPreferences +import com.woocommerce.commons.prefs.PreferenceUtils + +sealed class AppSettings( + private val preferences: SharedPreferences +) { + abstract var value: T + abstract val key: String + + data class CrashReportEnabled( + private val preferences: SharedPreferences + ) : AppSettings(preferences) { + override val key = this::class.simpleName.orEmpty() + + override var value: Boolean + get() = PreferenceUtils.getBoolean(preferences, key, false) + set(value) = PreferenceUtils.setBoolean(preferences, key, value) + } +} From 13063a68b88fd5b547e0f42e0b5fa7382147fe03 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 9 Aug 2024 19:37:57 -0300 Subject: [PATCH 143/196] Fix import issues --- .../src/main/kotlin/com/woocommerce/android/FeedbackPrefs.kt | 2 +- .../main/kotlin/com/woocommerce/android/tools/SelectedSite.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/FeedbackPrefs.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/FeedbackPrefs.kt index 47215b447c7..afde148324e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/FeedbackPrefs.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/FeedbackPrefs.kt @@ -10,7 +10,7 @@ import com.woocommerce.android.FeedbackPrefs.FeedbackPrefKey.LAST_FEEDBACK_DATE import com.woocommerce.android.extensions.greaterThan import com.woocommerce.android.extensions.pastTimeDeltaFromNowInDays import com.woocommerce.android.model.FeatureFeedbackSettings -import com.woocommerce.android.util.PreferenceUtils +import com.woocommerce.commons.prefs.PreferenceUtils import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/tools/SelectedSite.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/tools/SelectedSite.kt index fa9a3473021..de63701c0a0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/tools/SelectedSite.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/tools/SelectedSite.kt @@ -4,7 +4,7 @@ import android.content.Context import androidx.preference.PreferenceManager import com.woocommerce.android.di.SiteComponent import com.woocommerce.android.di.SiteComponent.Builder -import com.woocommerce.android.util.PreferenceUtils +import com.woocommerce.commons.prefs.PreferenceUtils import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob From f29e6e46aa0220733c825d8b9e1fba83614b9095 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 9 Aug 2024 19:38:39 -0300 Subject: [PATCH 144/196] Remove all Settings DataStore usage --- .../android/wear/datastore/DataStoreType.kt | 3 +- .../android/wear/di/DataStoreModule.kt | 12 ------ .../wear/phone/PhoneConnectionRepository.kt | 2 +- .../android/wear/prefs/SettingsRepository.kt | 39 ------------------- .../wear/settings/SettingsRepository.kt | 27 +++++++++++++ 5 files changed, 29 insertions(+), 54 deletions(-) delete mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt create mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/datastore/DataStoreType.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/datastore/DataStoreType.kt index d89ab4e0327..059e726a6bd 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/datastore/DataStoreType.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/datastore/DataStoreType.kt @@ -3,6 +3,5 @@ package com.woocommerce.android.wear.datastore enum class DataStoreType(val typeName: String) { LOGIN("login"), STATS("stats"), - ORDERS("orders"), - SETTINGS("settings") + ORDERS("orders") } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/DataStoreModule.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/DataStoreModule.kt index 39783349bf7..a7725fd11e1 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/DataStoreModule.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/di/DataStoreModule.kt @@ -8,7 +8,6 @@ import androidx.datastore.preferences.preferencesDataStoreFile import com.woocommerce.android.wear.datastore.DataStoreQualifier import com.woocommerce.android.wear.datastore.DataStoreType.LOGIN import com.woocommerce.android.wear.datastore.DataStoreType.ORDERS -import com.woocommerce.android.wear.datastore.DataStoreType.SETTINGS import com.woocommerce.android.wear.datastore.DataStoreType.STATS import dagger.Module import dagger.Provides @@ -53,15 +52,4 @@ class DataStoreModule { produceFile = { appContext.preferencesDataStoreFile(ORDERS.typeName) }, scope = CoroutineScope(appCoroutineScope.coroutineContext + Dispatchers.IO) ) - - @Provides - @Singleton - @DataStoreQualifier(SETTINGS) - fun providePrefsDataStore( - appContext: Context, - @AppCoroutineScope appCoroutineScope: CoroutineScope - ): DataStore = PreferenceDataStoreFactory.create( - produceFile = { appContext.preferencesDataStoreFile(SETTINGS.typeName) }, - scope = CoroutineScope(appCoroutineScope.coroutineContext + Dispatchers.IO) - ) } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/phone/PhoneConnectionRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/phone/PhoneConnectionRepository.kt index 9cb79d786b3..80422fdad23 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/phone/PhoneConnectionRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/phone/PhoneConnectionRepository.kt @@ -8,7 +8,7 @@ import com.google.android.gms.wearable.DataMap import com.google.android.gms.wearable.DataMapItem import com.google.android.gms.wearable.MessageClient import com.google.android.gms.wearable.PutDataMapRequest -import com.woocommerce.android.wear.prefs.SettingsRepository +import com.woocommerce.android.wear.settings.SettingsRepository import com.woocommerce.android.wear.ui.login.LoginRepository import com.woocommerce.android.wear.ui.orders.OrdersRepository import com.woocommerce.android.wear.ui.stats.datasource.StatsRepository diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt deleted file mode 100644 index b228a62c5a2..00000000000 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/prefs/SettingsRepository.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.woocommerce.android.wear.prefs - -import androidx.datastore.core.DataStore -import androidx.datastore.preferences.core.Preferences -import androidx.datastore.preferences.core.edit -import com.google.android.gms.wearable.DataMap -import com.google.gson.Gson -import com.woocommerce.android.wear.datastore.DataStoreQualifier -import com.woocommerce.android.wear.datastore.DataStoreType -import com.woocommerce.commons.DataParameters.APP_SETTINGS -import com.woocommerce.commons.WearAppSettings -import javax.inject.Inject -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.mapNotNull - -class SettingsRepository @Inject constructor( - @DataStoreQualifier(DataStoreType.SETTINGS) private val settingsDataStore: DataStore -) { - private val gson by lazy { Gson() } - - suspend fun receiveAppSettingsDataFromPhone(data: DataMap) { - val settings = data.getString(APP_SETTINGS.value, "") - .takeIf { it.isNotEmpty() } - ?.let { gson.fromJson(it, WearAppSettings::class.java) } - ?: return - - storeSettingsKey( - key = SettingsType.CrashReportEnabled, - value = settings.crashReportEnabled - ) - } - - suspend fun fetchSettingsValue(key: SettingsType): T = - settingsDataStore.data.mapNotNull { it[key.prefsKey] }.first() - - private suspend fun storeSettingsKey(key: SettingsType, value: T) { - settingsDataStore.edit { it[key.prefsKey] = value } - } -} diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt new file mode 100644 index 00000000000..128e8f17144 --- /dev/null +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt @@ -0,0 +1,27 @@ +package com.woocommerce.android.wear.settings + +import android.content.Context +import androidx.preference.PreferenceManager +import com.google.android.gms.wearable.DataMap +import com.google.gson.Gson +import com.woocommerce.commons.DataParameters.APP_SETTINGS +import com.woocommerce.commons.WearAppSettings +import javax.inject.Inject + +class SettingsRepository @Inject constructor( + private val appContext: Context +) { + private val preferences + get() = PreferenceManager.getDefaultSharedPreferences(appContext) + + private val gson by lazy { Gson() } + + fun receiveAppSettingsDataFromPhone(data: DataMap) { + val settings = data.getString(APP_SETTINGS.value, "") + .takeIf { it.isNotEmpty() } + ?.let { gson.fromJson(it, WearAppSettings::class.java) } + ?: return + + AppSettings.CrashReportEnabled(preferences).value = settings.crashReportEnabled + } +} From 7807af3bf58f937279ee3cbec6d7442c6b4ecb2d Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 9 Aug 2024 19:44:18 -0300 Subject: [PATCH 145/196] Set the crashLoggingEnabled value in WCWearCrashLoggingDataProvider --- .../wear/crashlogging/WCWearCrashLoggingDataProvider.kt | 9 +++++++-- .../woocommerce/android/wear/settings/AppSettingsType.kt | 6 ++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt index 42452e1e4f5..dc8cdd91a39 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt @@ -1,5 +1,7 @@ package com.woocommerce.android.wear.crashlogging +import android.content.Context +import androidx.preference.PreferenceManager import com.automattic.android.tracks.crashlogging.CrashLoggingDataProvider import com.automattic.android.tracks.crashlogging.CrashLoggingUser import com.automattic.android.tracks.crashlogging.EventLevel @@ -8,6 +10,7 @@ import com.automattic.android.tracks.crashlogging.PerformanceMonitoringConfig import com.automattic.android.tracks.crashlogging.ReleaseName import com.woocommerce.android.BuildConfig import com.woocommerce.android.wear.di.AppCoroutineScope +import com.woocommerce.android.wear.settings.AppSettings import com.woocommerce.android.wear.ui.login.LoginRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow @@ -25,8 +28,9 @@ import kotlinx.coroutines.flow.map @Singleton class WCWearCrashLoggingDataProvider @Inject constructor( - private val accountStore: AccountStore, @AppCoroutineScope private val appScope: CoroutineScope, + private val appContext: Context, + private val accountStore: AccountStore, private val providedLocale: Locale, loginRepository: LoginRepository, dispatcher: Dispatcher, @@ -80,7 +84,8 @@ class WCWearCrashLoggingDataProvider @Inject constructor( get() = TODO("Not yet implemented") override fun crashLoggingEnabled(): Boolean { - TODO("Not yet implemented") + val preferences = PreferenceManager.getDefaultSharedPreferences(appContext) + return AppSettings.CrashReportEnabled(preferences).value } override fun extraKnownKeys(): List = emptyList() diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/AppSettingsType.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/AppSettingsType.kt index 2fde51610fd..e00e7d61a6d 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/AppSettingsType.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/AppSettingsType.kt @@ -3,15 +3,13 @@ package com.woocommerce.android.wear.settings import android.content.SharedPreferences import com.woocommerce.commons.prefs.PreferenceUtils -sealed class AppSettings( - private val preferences: SharedPreferences -) { +sealed class AppSettings() { abstract var value: T abstract val key: String data class CrashReportEnabled( private val preferences: SharedPreferences - ) : AppSettings(preferences) { + ) : AppSettings() { override val key = this::class.simpleName.orEmpty() override var value: Boolean From 40386271aa1b6c30f2bb34eb1961b2ab5b4c3e3b Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Mon, 12 Aug 2024 09:56:16 +1000 Subject: [PATCH 146/196] Remove redundant lane arg re-assignment Co-authored-by: Olivier Halligon --- fastlane/Fastfile | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 4d6ab2ba346..665e99e0c78 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -339,20 +339,18 @@ platform :android do # Verify that there's nothing in progress in the working copy ensure_git_status_clean - new_version = version_name - version_code_new = version_code # Parse the provided version into an AppVersion object - parsed_version = VERSION_FORMATTER.parse(new_version) + parsed_version = VERSION_FORMATTER.parse(version_name) previous_version = VERSION_FORMATTER.release_version(VERSION_CALCULATOR.previous_patch_version(version: parsed_version)) # Check versions message = <<-MESSAGE Current release version: #{release_version_current} - New hotfix version: #{new_version} + New hotfix version: #{version_name} Current build code: #{build_code_current} - New build code: #{version_code_new} + New build code: #{version_code} Branching from tag: #{previous_version} @@ -362,19 +360,19 @@ platform :android do UI.user_error!("Terminating as requested. Don't forget to run the remainder of this automation manually.") unless skip_confirm || UI.confirm('Do you want to continue?') # Check tags - UI.user_error!("The version `#{new_version}` tag already exists!") if git_tag_exists(tag: new_version) + UI.user_error!("The version `#{version_name}` tag already exists!") if git_tag_exists(tag: version_name) UI.user_error!("Version #{previous_version} is not tagged! A hotfix branch cannot be created.") unless git_tag_exists(tag: previous_version) # Create the hotfix branch UI.message('Creating hotfix branch...') - Fastlane::Helper::GitHelper.create_branch("release/#{new_version}", from: previous_version) + Fastlane::Helper::GitHelper.create_branch("release/#{version_name}", from: previous_version) UI.success("Done! New hotfix branch is: #{git_branch}") # Bump the hotfix version and build code and write it to the `version.properties` file UI.message('Bumping hotfix version and build code...') VERSION_FILE.write_version( - version_name: new_version, - version_code: version_code_new + version_name: version_name, + version_code: version_code ) commit_version_bump UI.success("Done! New Release Version: #{release_version_current}. New Build Code: #{build_code_current}") From 36e8a16c11683097a7ad76a87d15d891659f759a Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Mon, 12 Aug 2024 07:14:44 +0200 Subject: [PATCH 147/196] Bring back Buildkite annotations for instrumented tests --- fastlane/Fastfile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 2d67d530b96..f904c10b3ae 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -950,7 +950,16 @@ platform :android do lane :build_and_instrumented_test do gradle(tasks: %w[assembleVanillaDebug assembleVanillaDebugAndroidTest]) - gradle(task: 'runFlank') + annotation_ctx = 'firebase-test-woocommerce-vanilla-debug' + begin + gradle(task: 'runFlank') + sh("buildkite-agent annotation remove --context '#{annotation_ctx}' || true") if is_ci? + rescue StandardError + details_url = sh('jq', '.[].webLink', '../build/instrumented-tests/matrix_ids.json', '-r') + message = "Firebase Tests failed. Failure details can be seen [here in Firebase Console](#{details_url})" + sh('buildkite-agent', 'annotate', message, '--style', 'error', '--context', annotation_ctx) if is_ci? + UI.test_failure!(message) + end end ##################################################################################### From c3b2e7ad9604ece29e27eedea570f7379f25880a Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Mon, 12 Aug 2024 07:15:20 +0200 Subject: [PATCH 148/196] temp: break instrumentation tests to test Buildkite annotations --- .../androidTest/kotlin/com/woocommerce/android/AppPrefsTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/AppPrefsTest.kt b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/AppPrefsTest.kt index 5d17090b4bc..f73e188fa34 100644 --- a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/AppPrefsTest.kt +++ b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/AppPrefsTest.kt @@ -489,7 +489,7 @@ class AppPrefsTest { remoteSiteId = 0L, selfHostedSiteId = 0L, ) - ).isFalse + ).isTrue() } @Test From 73b99a3c661437d0461373ff299392afbf9f97b0 Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Mon, 12 Aug 2024 08:28:05 +0200 Subject: [PATCH 149/196] Revert "temp: break instrumentation tests" This reverts commit c3b2e7ad9604ece29e27eedea570f7379f25880a. --- .../androidTest/kotlin/com/woocommerce/android/AppPrefsTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/AppPrefsTest.kt b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/AppPrefsTest.kt index f73e188fa34..5d17090b4bc 100644 --- a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/AppPrefsTest.kt +++ b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/AppPrefsTest.kt @@ -489,7 +489,7 @@ class AppPrefsTest { remoteSiteId = 0L, selfHostedSiteId = 0L, ) - ).isTrue() + ).isFalse } @Test From 0693733f633d66dc2611439d0d5dde4baa4c1b40 Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Mon, 12 Aug 2024 09:55:46 +0200 Subject: [PATCH 150/196] Use `merge_junit_reports` script This script is provided by ci toolkit --- .buildkite/commands/run-unit-tests.sh | 2 +- merge_junit.sh | 40 --------------------------- 2 files changed, 1 insertion(+), 41 deletions(-) delete mode 100755 merge_junit.sh diff --git a/.buildkite/commands/run-unit-tests.sh b/.buildkite/commands/run-unit-tests.sh index 248b21a23cb..528101ceb8e 100755 --- a/.buildkite/commands/run-unit-tests.sh +++ b/.buildkite/commands/run-unit-tests.sh @@ -18,7 +18,7 @@ echo "--- 🚦 Report Tests Status" results_file="WooCommerce/build/test-results/merged-test-results.xml" # Merge JUnit results into a single file (for performance reasons with reporting) # See https://github.com/woocommerce/woocommerce-android/pull/12064 -./merge_junit.sh -d WooCommerce/build/test-results/testJalapenoDebugUnitTest -o $results_file +merge_junit_reports -d WooCommerce/build/test-results/testJalapenoDebugUnitTest -o $results_file if [[ $BUILDKITE_BRANCH == trunk ]] || [[ $BUILDKITE_BRANCH == release/* ]]; then annotate_test_failures "$results_file" --slack "build-and-ship" diff --git a/merge_junit.sh b/merge_junit.sh deleted file mode 100755 index b4935373939..00000000000 --- a/merge_junit.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - -# Initialize variables -reports_dir="" -output_file="" - -# Function to show usage -usage() { - echo "Usage: $0 -d -o " - exit 1 -} - -# Parse command-line options -while getopts "d:o:" opt; do - case $opt in - d) reports_dir=$OPTARG ;; - o) output_file=$OPTARG ;; - ?) usage ;; - esac -done - -# Check if both arguments were provided -if [ -z "$reports_dir" ] || [ -z "$output_file" ]; then - usage -fi - -# Write XML header to the output file -echo '' > "$output_file" -echo '' >> "$output_file" - -# Merge the content of all input JUnit files in the directory. -# (Note that in the case of Unit Tests, the JUnit XML files produced by Gradle -# don't have a parent `` root tag, so there's no need to try and remove it) -sed '/<\?xml .*\?>/d' "$reports_dir"/*.xml >> "$output_file" - -# Close the testsuites tag -echo '' >> "$output_file" - -# Print the result -echo "Merged XML reports into $output_file" From 3ffcfb943769f3dc565c352d0d27599ab6380e25 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 12 Aug 2024 09:56:45 +0200 Subject: [PATCH 151/196] Update RELEASE-NOTES.txt --- RELEASE-NOTES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index d0ef763ceba..2d2c2b71a49 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -3,7 +3,7 @@ *** For entries which are touching the Android Wear app's, start entry with `[WEAR]` too. 20.0 ----- - +- [*] Fixed missing pictures in card reader tutorial on tablets [https://github.com/woocommerce/woocommerce-android/pull/12274] 19.9 ----- From ff4556961c02f62a3994284fe2f20d3e65cb9993 Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Mon, 12 Aug 2024 09:57:57 +0200 Subject: [PATCH 152/196] Specify `result_file` as the file for test collector It's more readable this way --- .buildkite/commands/run-unit-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.buildkite/commands/run-unit-tests.sh b/.buildkite/commands/run-unit-tests.sh index 528101ceb8e..bf5f14c056f 100755 --- a/.buildkite/commands/run-unit-tests.sh +++ b/.buildkite/commands/run-unit-tests.sh @@ -31,6 +31,6 @@ echo "--- ⚒️ Generating and uploading code coverage" .buildkite/commands/upload-code-coverage.sh echo "--- 🧪 Copying test logs for test collector" -mkdir WooCommerce/build/buildkite-test-analytics && cp WooCommerce/build/test-results/*.xml WooCommerce/build/buildkite-test-analytics +mkdir WooCommerce/build/buildkite-test-analytics && cp $results_file WooCommerce/build/buildkite-test-analytics exit $TESTS_EXIT_STATUS From 8ff2eceab485dfa2fcff0e87ee0c1d7100d6a455 Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Mon, 12 Aug 2024 09:59:59 +0200 Subject: [PATCH 153/196] Specify merged JUnit report file as the only artifact of unit tests job --- .buildkite/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 34b7c6896e7..2a015a8a3bf 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -87,7 +87,7 @@ steps: <<: *test_collector_common_params api-token-env-name: "BUILDKITE_ANALYTICS_TOKEN_UNIT_TESTS" artifact_paths: - - "**/build/test-results/*/*.xml" + - "**/build/test-results/merged-test-results.xml" - label: "Instrumented tests" command: .buildkite/commands/run-instrumented-tests.sh From d48756f8dfc1b7eb63cb15803e7dfd861d3a321b Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 12 Aug 2024 10:22:47 +0200 Subject: [PATCH 154/196] Remove unused imports --- .../tutorial/CardReaderTutorialViewPagerItemFragment.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt index f781b70eaa3..b205bdd05ee 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/tutorial/CardReaderTutorialViewPagerItemFragment.kt @@ -7,9 +7,7 @@ import androidx.annotation.StringRes import androidx.fragment.app.Fragment import com.woocommerce.android.R import com.woocommerce.android.databinding.FragmentCardReaderTutorialViewpagerItemBinding -import com.woocommerce.android.extensions.hide import com.woocommerce.android.util.UiHelpers -import org.wordpress.android.util.DisplayUtils /** * Displays a single image and text label in the card reader tutorial view pager From 0263e51a9ca1be9a3f3d8afdaaca34aeecd552a3 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 12 Aug 2024 11:04:45 +0200 Subject: [PATCH 155/196] Set bottom padding to 0 when gesture navigation used, so we follow the design --- .../android/ui/woopos/root/WooPosActivity.kt | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosActivity.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosActivity.kt index 620d9a2e187..8cabc07d01b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosActivity.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosActivity.kt @@ -1,20 +1,18 @@ package com.woocommerce.android.ui.woopos.root -import android.R import android.content.pm.ActivityInfo import android.os.Bundle import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.asPaddingValues -import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding -import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.unit.dp import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsCompat import com.woocommerce.android.ui.woopos.cardreader.WooPosCardReaderFacade import com.woocommerce.android.ui.woopos.common.composeui.WooPosTheme import dagger.hilt.android.AndroidEntryPoint @@ -37,8 +35,7 @@ class WooPosActivity : AppCompatActivity() { SystemBars() WooPosRootScreen( - modifier = Modifier - .padding(bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()) + modifier = Modifier.gesturesOrButtonsNavigationPadding() ) } } @@ -46,11 +43,31 @@ class WooPosActivity : AppCompatActivity() { @Composable private fun SystemBars() { - val colors = MaterialTheme.colors - SideEffect { - window.statusBarColor = getColor(R.color.transparent) - window.navigationBarColor = colors.background.toArgb() + window.statusBarColor = getColor(android.R.color.transparent) + window.navigationBarColor = getColor(android.R.color.transparent) } } } + +@Composable +private fun Modifier.gesturesOrButtonsNavigationPadding(): Modifier { + val view = LocalView.current + val insets = WindowInsetsCompat.toWindowInsetsCompat(view.rootWindowInsets) + val isGestureNavigation = insets.isGestureNavigation() + + return if (isGestureNavigation) { + this.padding(bottom = 0.dp) + } else { + this.navigationBarsPadding() + } +} + +private fun WindowInsetsCompat.isGestureNavigation(): Boolean { + val bottomInset = getInsets(WindowInsetsCompat.Type.navigationBars()).bottom + + // That seems to be different on different devices, but 48dp is a common upper value + val gestureNavigationBarHeight = 48 + return bottomInset <= gestureNavigationBarHeight +} + From 128f901f0e950e8a19411bb77aa9c22d2847f44c Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 12 Aug 2024 11:09:17 +0200 Subject: [PATCH 156/196] Fixed detekt complains --- .../woocommerce/android/ui/woopos/root/WooPosActivity.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosActivity.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosActivity.kt index 8cabc07d01b..5a8f7838c76 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosActivity.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosActivity.kt @@ -63,11 +63,10 @@ private fun Modifier.gesturesOrButtonsNavigationPadding(): Modifier { } } +// That seems to be different on different devices, but 48dp is a common upper value +private const val GESTURE_NAVIGATION_BAR_HEIGHT = 48 private fun WindowInsetsCompat.isGestureNavigation(): Boolean { val bottomInset = getInsets(WindowInsetsCompat.Type.navigationBars()).bottom - // That seems to be different on different devices, but 48dp is a common upper value - val gestureNavigationBarHeight = 48 - return bottomInset <= gestureNavigationBarHeight + return bottomInset <= GESTURE_NAVIGATION_BAR_HEIGHT } - From 5c026df11d775afd10ebad55a8786e332d22fa2d Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Mon, 12 Aug 2024 11:20:55 +0200 Subject: [PATCH 157/196] temp: break unit test To assert Buildkite annotation logic works as expected --- .../ui/orders/details/editing/address/AddressViewModelTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/editing/address/AddressViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/editing/address/AddressViewModelTest.kt index 305c1fb6da0..74c7d7ce936 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/editing/address/AddressViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/editing/address/AddressViewModelTest.kt @@ -112,7 +112,7 @@ class AddressViewModelTest : BaseUnitTest() { addressViewModel.start( mapOf(SHIPPING to shippingAddress) ) - verify(dataStore, times(2)).fetchCountriesAndStates(selectedSite.get()) + verify(dataStore, times(0)).fetchCountriesAndStates(selectedSite.get()) } } From 196488c3c2f03e6bcd28ebeadaa593140a63efbd Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Mon, 12 Aug 2024 11:54:15 +0200 Subject: [PATCH 158/196] Revert "temp: break unit test" This reverts commit 5c026df11d775afd10ebad55a8786e332d22fa2d. --- .../ui/orders/details/editing/address/AddressViewModelTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/editing/address/AddressViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/editing/address/AddressViewModelTest.kt index 74c7d7ce936..305c1fb6da0 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/editing/address/AddressViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/details/editing/address/AddressViewModelTest.kt @@ -112,7 +112,7 @@ class AddressViewModelTest : BaseUnitTest() { addressViewModel.start( mapOf(SHIPPING to shippingAddress) ) - verify(dataStore, times(0)).fetchCountriesAndStates(selectedSite.get()) + verify(dataStore, times(2)).fetchCountriesAndStates(selectedSite.get()) } } From d1ae29417d34c47dccdcf91413d707ffc2affdbe Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Mon, 12 Aug 2024 13:33:52 +0200 Subject: [PATCH 159/196] Remove Qr code scanner CTA from login with magic link flow --- .../android/analytics/AnalyticsEvent.kt | 1 - .../android/ui/login/LoginActivity.kt | 38 +------------------ .../LoginMagicLinkSentImprovedFragment.kt | 7 +--- .../ui/login/qrcode/QrCodeLoginListener.kt | 5 --- ...ragment_login_magic_link_sent_improved.xml | 9 ----- WooCommerce/src/main/res/values/strings.xml | 1 - 6 files changed, 2 insertions(+), 59 deletions(-) delete mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/qrcode/QrCodeLoginListener.kt diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt index 05dd427fe97..0cb0aa640fc 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt @@ -108,7 +108,6 @@ enum class AnalyticsEvent(override val siteless: Boolean = false) : IAnalyticsEv LOGIN_JETPACK_CONNECT_COMPLETED(siteless = true), LOGIN_JETPACK_CONNECT_DISMISSED(siteless = true), LOGIN_JETPACK_CONNECTION_VERIFICATION_FAILED(siteless = true), - LOGIN_WITH_QR_CODE_BUTTON_TAPPED(siteless = true), LOGIN_WITH_QR_CODE_SCANNED(siteless = true), LOGIN_PROLOGUE_STARTING_A_NEW_STORE_TAPPED(siteless = true), LOGIN_MALFORMED_APP_LOGIN_LINK(siteless = true), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginActivity.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginActivity.kt index 18b34b7b014..76744d57469 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginActivity.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginActivity.kt @@ -6,14 +6,12 @@ import android.net.Uri import android.os.Bundle import android.os.Parcelable import android.view.MenuItem -import android.widget.Toast import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.lifecycle.withStarted -import com.google.mlkit.vision.codescanner.GmsBarcodeScanning import com.woocommerce.android.AppPrefsWrapper import com.woocommerce.android.AppUrls import com.woocommerce.android.AppUrls.LOGIN_WITH_EMAIL_WHAT_IS_WORDPRESS_COM_ACCOUNT @@ -24,7 +22,6 @@ import com.woocommerce.android.analytics.AnalyticsTracker.Companion.KEY_FLOW import com.woocommerce.android.analytics.AnalyticsTracker.Companion.KEY_SOURCE import com.woocommerce.android.analytics.AnalyticsTracker.Companion.KEY_URL import com.woocommerce.android.analytics.AnalyticsTracker.Companion.VALUE_JETPACK_INSTALLATION_SOURCE_WEB -import com.woocommerce.android.analytics.AnalyticsTracker.Companion.VALUE_LOGIN_WITH_WORDPRESS_COM import com.woocommerce.android.analytics.AnalyticsTracker.Companion.VALUE_NO_WP_COM import com.woocommerce.android.analytics.AnalyticsTracker.Companion.VALUE_WP_COM import com.woocommerce.android.analytics.ExperimentTracker @@ -50,8 +47,6 @@ import com.woocommerce.android.ui.login.error.LoginNotWPDialogFragment import com.woocommerce.android.ui.login.overrides.WooLoginEmailFragment import com.woocommerce.android.ui.login.overrides.WooLoginEmailPasswordFragment import com.woocommerce.android.ui.login.overrides.WooLoginSiteAddressFragment -import com.woocommerce.android.ui.login.qrcode.QrCodeLoginListener -import com.woocommerce.android.ui.login.qrcode.ValidateScannedValue import com.woocommerce.android.ui.login.sitecredentials.LoginSiteCredentialsFragment import com.woocommerce.android.ui.login.sitecredentials.applicationpassword.ApplicationPasswordTutorialFragment import com.woocommerce.android.ui.main.MainActivity @@ -105,8 +100,7 @@ class LoginActivity : LoginNoJetpackListener, LoginEmailHelpDialogFragment.Listener, WooLoginEmailFragment.Listener, - LoginSiteCredentialsFragment.Listener, - QrCodeLoginListener { + LoginSiteCredentialsFragment.Listener { companion object { private const val FORGOT_PASSWORD_URL_SUFFIX = "wp-login.php?action=lostpassword" private const val JETPACK_CONNECT_URL = "https://wordpress.com/jetpack/connect" @@ -948,17 +942,6 @@ class LoginActivity : } } - override fun onScanQrCodeClicked(source: String) { - AnalyticsTracker.track( - stat = AnalyticsEvent.LOGIN_WITH_QR_CODE_BUTTON_TAPPED, - properties = mapOf( - KEY_FLOW to VALUE_LOGIN_WITH_WORDPRESS_COM, - KEY_SOURCE to source - ) - ) - openQrCodeScannerFragment() - } - private fun clearCachedSites() { // Clear all sites from the DB to avoid any conflicts with the new login // Sometimes, the same website could be fetched from different APIs (WPCom or WPApi), and if cached twice @@ -1005,25 +988,6 @@ class LoginActivity : } } - private fun openQrCodeScannerFragment() { - GmsBarcodeScanning.getClient(this).startScan() - .addOnSuccessListener { rawValue -> - if (ValidateScannedValue.validate(rawValue.rawValue)) { - AnalyticsTracker.track(stat = AnalyticsEvent.LOGIN_WITH_QR_CODE_SCANNED) - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(rawValue.rawValue)) - intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK or - Intent.FLAG_ACTIVITY_CLEAR_TASK - startActivity(intent) - } else { - Toast.makeText( - this, - resources.getText(R.string.not_a_valid_qr_code), - Toast.LENGTH_LONG - ).show() - } - } - } - /** * Show a DialogFragment using the current Fragment's childFragmentManager. * This is useful to make sure the dialog's lifecycle is linked to the Fragment that invokes it and that it would diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginMagicLinkSentImprovedFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginMagicLinkSentImprovedFragment.kt index 2ab6e4d8f9b..525443979e6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginMagicLinkSentImprovedFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginMagicLinkSentImprovedFragment.kt @@ -12,7 +12,6 @@ import androidx.core.view.MenuProvider import androidx.fragment.app.Fragment import com.woocommerce.android.R import com.woocommerce.android.databinding.FragmentLoginMagicLinkSentImprovedBinding -import com.woocommerce.android.ui.login.qrcode.QrCodeLoginListener import dagger.hilt.android.AndroidEntryPoint import org.wordpress.android.login.LoginAnalyticsListener import org.wordpress.android.login.LoginListener @@ -36,7 +35,6 @@ class LoginMagicLinkSentImprovedFragment : Fragment(R.layout.fragment_login_magi } private var mLoginListener: LoginListener? = null - private lateinit var qrCodeLoginListener: QrCodeLoginListener private var mEmail: String? = null private var mAllowPassword = false @@ -56,9 +54,6 @@ class LoginMagicLinkSentImprovedFragment : Fragment(R.layout.fragment_login_magi override fun onAttach(context: Context) { super.onAttach(context) - if (activity is QrCodeLoginListener) { - qrCodeLoginListener = activity as QrCodeLoginListener - } if (activity is LoginListener) { mLoginListener = activity as LoginListener } @@ -82,7 +77,6 @@ class LoginMagicLinkSentImprovedFragment : Fragment(R.layout.fragment_login_magi } } binding.email.text = mEmail - binding.magicLinkSentScanQrCode.setOnClickListener { qrCodeLoginListener.onScanQrCodeClicked(TAG) } } override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { @@ -97,6 +91,7 @@ class LoginMagicLinkSentImprovedFragment : Fragment(R.layout.fragment_login_magi mLoginListener?.helpMagicLinkSent(mEmail) true } + else -> false } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/qrcode/QrCodeLoginListener.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/qrcode/QrCodeLoginListener.kt deleted file mode 100644 index 7d8ec8e0c13..00000000000 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/qrcode/QrCodeLoginListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.woocommerce.android.ui.login.qrcode - -interface QrCodeLoginListener { - fun onScanQrCodeClicked(source: String) -} diff --git a/WooCommerce/src/main/res/layout/fragment_login_magic_link_sent_improved.xml b/WooCommerce/src/main/res/layout/fragment_login_magic_link_sent_improved.xml index e0412396162..a21857c3181 100644 --- a/WooCommerce/src/main/res/layout/fragment_login_magic_link_sent_improved.xml +++ b/WooCommerce/src/main/res/layout/fragment_login_magic_link_sent_improved.xml @@ -77,15 +77,6 @@ android:layout_marginEnd="@dimen/margin_extra_large" android:text="@string/open_mail" /> - - We just sent a magic link to We just sent a magic link to your account\'s email address Try another address - Scan QR code to log in Or log in with password Exit POS - Reader Connected + Reader connected Connect your reader Checkout Reader Status Unknown From 823c852e55701bfd567246d88645f52cbd72872b Mon Sep 17 00:00:00 2001 From: Rooney Date: Mon, 12 Aug 2024 16:17:07 -0400 Subject: [PATCH 168/196] Sentence case --- WooCommerce/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index 5892769997c..7a1d0416af4 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -4222,7 +4222,7 @@ Subtotal Taxes Total - Collect Card Payment + Collect card payment No products Connect now Couldn\'t load totals From 9d62b82525a88fc068581798c07d4cd651beb664 Mon Sep 17 00:00:00 2001 From: Rooney Date: Mon, 12 Aug 2024 16:18:29 -0400 Subject: [PATCH 169/196] Sentence case --- WooCommerce/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index 7a1d0416af4..f6aa153d7e6 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -4188,7 +4188,7 @@ Reader connected Connect your reader Checkout - Reader Status Unknown + Reader status unknown Check out Remove item from cart Cart From 81bb05b33a6487e756a140179b41cd80f0782c08 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Mon, 12 Aug 2024 23:58:15 +0300 Subject: [PATCH 170/196] Use a resizable bottom sheet for the AI button in product description --- .../description/AIProductDescriptionBottomSheetFragment.kt | 6 ++++++ WooCommerce/src/main/res/values/styles_base.xml | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/description/AIProductDescriptionBottomSheetFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/description/AIProductDescriptionBottomSheetFragment.kt index d85be13ff10..76ec87dcaee 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/description/AIProductDescriptionBottomSheetFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/description/AIProductDescriptionBottomSheetFragment.kt @@ -6,6 +6,7 @@ import android.view.View import android.view.ViewGroup import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.fragment.app.DialogFragment import androidx.fragment.app.viewModels import com.woocommerce.android.R import com.woocommerce.android.extensions.copyToClipboard @@ -26,6 +27,11 @@ class AIProductDescriptionBottomSheetFragment : WCBottomSheetDialogFragment() { private val viewModel: AIProductDescriptionViewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(DialogFragment.STYLE_NORMAL, R.style.Woo_Theme_BottomSheetDialog_Resizeable) + } + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return ComposeView(requireContext()).apply { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) diff --git a/WooCommerce/src/main/res/values/styles_base.xml b/WooCommerce/src/main/res/values/styles_base.xml index 07f92910db2..f5610796f05 100644 --- a/WooCommerce/src/main/res/values/styles_base.xml +++ b/WooCommerce/src/main/res/values/styles_base.xml @@ -811,4 +811,8 @@ theme across the entire app. Overridden versions should be added to the styles.x + + From bb9b04dc9d10b6b299e66de66e2cb18fd2829b55 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Tue, 13 Aug 2024 00:13:37 +0300 Subject: [PATCH 171/196] Update RELEASE-NOTES --- RELEASE-NOTES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 0fcff6dcd11..f864f5b3cc5 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -3,7 +3,7 @@ *** For entries which are touching the Android Wear app's, start entry with `[WEAR]` too. 20.0 ----- - +- [*] Fixed the hidden “Write with AI” issue that occurs when the keyboard is open. [https://github.com/woocommerce/woocommerce-android/pull/12311] 19.9 ----- From ccd2a5dc7432420a68b0d7dba5549659b00e3ed0 Mon Sep 17 00:00:00 2001 From: Alejo Date: Mon, 12 Aug 2024 16:11:58 -0600 Subject: [PATCH 172/196] update FluxC version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7447b47f3a4..d6847873a68 100644 --- a/build.gradle +++ b/build.gradle @@ -99,7 +99,7 @@ tasks.register("installGitHooks", Copy) { } ext { - fluxCVersion = '2.92.0' + fluxCVersion = '2.92.1' glideVersion = '4.16.0' coilVersion = '2.1.0' constraintLayoutVersion = '1.2.0' From b743693e0507a58f033e0502bf0cb8a0d2699df7 Mon Sep 17 00:00:00 2001 From: Automattic Release Bot Date: Mon, 12 Aug 2024 19:00:00 -0400 Subject: [PATCH 173/196] Bump version number --- version.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.properties b/version.properties index 8e86f41ea53..274c35e0cc4 100644 --- a/version.properties +++ b/version.properties @@ -1,2 +1,2 @@ -versionName=19.9-rc-1 -versionCode=588 \ No newline at end of file +versionName=19.9-rc-2 +versionCode=589 \ No newline at end of file From 1bf05f11cd49c58cbb7cf4a5ee7b2d5dfa7ca14d Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 12 Aug 2024 21:12:33 -0300 Subject: [PATCH 174/196] Fix lint issues --- .../WCWearCrashLoggingDataProvider.kt | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt index 42452e1e4f5..812002e7f66 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt @@ -12,6 +12,7 @@ import com.woocommerce.android.wear.ui.login.LoginRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode @@ -21,7 +22,6 @@ import org.wordpress.android.fluxc.store.AccountStore import java.util.Locale import javax.inject.Inject import javax.inject.Singleton -import kotlinx.coroutines.flow.map @Singleton class WCWearCrashLoggingDataProvider @Inject constructor( @@ -64,17 +64,17 @@ class WCWearCrashLoggingDataProvider @Inject constructor( override val applicationContextProvider: Flow> = loginRepository.selectedSiteFlow - .map { site -> - site?.let { - mutableMapOf( - SITE_URL_KEY to site.url - ).apply { - site.siteId.takeIf { it != 0L }?.toString()?.let { - this[SITE_ID_KEY] = it + .map { site -> + site?.let { + mutableMapOf( + SITE_URL_KEY to site.url + ).apply { + site.siteId.takeIf { it != 0L }?.toString()?.let { + this[SITE_ID_KEY] = it + } } - } - }.orEmpty() - } + }.orEmpty() + } override val performanceMonitoringConfig: PerformanceMonitoringConfig get() = TODO("Not yet implemented") From 4f86014d70ced7dde01c2f1b12d2edc04ba52687 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 12 Aug 2024 21:13:27 -0300 Subject: [PATCH 175/196] Set performance monitoring as disabled --- .../android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt index 812002e7f66..16dd8977f64 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt @@ -77,7 +77,7 @@ class WCWearCrashLoggingDataProvider @Inject constructor( } override val performanceMonitoringConfig: PerformanceMonitoringConfig - get() = TODO("Not yet implemented") + get() = PerformanceMonitoringConfig.Disabled override fun crashLoggingEnabled(): Boolean { TODO("Not yet implemented") From 0f597bc97d0bf0b811ce300a678f84fc776b9545 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 12 Aug 2024 21:31:27 -0300 Subject: [PATCH 176/196] Refactor AppSettings to comply with detekt warnings --- .../wear/crashlogging/WCWearCrashLoggingDataProvider.kt | 2 +- .../wear/settings/{AppSettingsType.kt => AppSettings.kt} | 4 ++-- .../woocommerce/android/wear/settings/SettingsRepository.kt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/{AppSettingsType.kt => AppSettings.kt} (88%) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt index 5a5bbb7c172..d49014e1cff 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt @@ -85,7 +85,7 @@ class WCWearCrashLoggingDataProvider @Inject constructor( override fun crashLoggingEnabled(): Boolean { val preferences = PreferenceManager.getDefaultSharedPreferences(appContext) - return AppSettings.CrashReportEnabled(preferences).value + return AppSettings.CrashReportEnabledSettings(preferences).value } override fun extraKnownKeys(): List = emptyList() diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/AppSettingsType.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/AppSettings.kt similarity index 88% rename from WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/AppSettingsType.kt rename to WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/AppSettings.kt index e00e7d61a6d..cb336cd08a0 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/AppSettingsType.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/AppSettings.kt @@ -3,11 +3,11 @@ package com.woocommerce.android.wear.settings import android.content.SharedPreferences import com.woocommerce.commons.prefs.PreferenceUtils -sealed class AppSettings() { +sealed class AppSettings { abstract var value: T abstract val key: String - data class CrashReportEnabled( + data class CrashReportEnabledSettings( private val preferences: SharedPreferences ) : AppSettings() { override val key = this::class.simpleName.orEmpty() diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt index 128e8f17144..a4840dfa98b 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt @@ -22,6 +22,6 @@ class SettingsRepository @Inject constructor( ?.let { gson.fromJson(it, WearAppSettings::class.java) } ?: return - AppSettings.CrashReportEnabled(preferences).value = settings.crashReportEnabled + AppSettings.CrashReportEnabledSettings(preferences).value = settings.crashReportEnabled } } From 08212b0e9cd5cc0a3c03f6a32db0619351ce1f6c Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 12 Aug 2024 21:35:15 -0300 Subject: [PATCH 177/196] Access any AppSettings through the SettingsRepository --- .../wear/crashlogging/WCWearCrashLoggingDataProvider.kt | 7 +++---- .../android/wear/settings/SettingsRepository.kt | 6 +++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt index d49014e1cff..9c69372dfb5 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt @@ -11,6 +11,7 @@ import com.automattic.android.tracks.crashlogging.ReleaseName import com.woocommerce.android.BuildConfig import com.woocommerce.android.wear.di.AppCoroutineScope import com.woocommerce.android.wear.settings.AppSettings +import com.woocommerce.android.wear.settings.SettingsRepository import com.woocommerce.android.wear.ui.login.LoginRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow @@ -32,6 +33,7 @@ class WCWearCrashLoggingDataProvider @Inject constructor( private val appContext: Context, private val accountStore: AccountStore, private val providedLocale: Locale, + private val settingsRepository: SettingsRepository, loginRepository: LoginRepository, dispatcher: Dispatcher, ) : CrashLoggingDataProvider { @@ -83,10 +85,7 @@ class WCWearCrashLoggingDataProvider @Inject constructor( override val performanceMonitoringConfig: PerformanceMonitoringConfig get() = PerformanceMonitoringConfig.Disabled - override fun crashLoggingEnabled(): Boolean { - val preferences = PreferenceManager.getDefaultSharedPreferences(appContext) - return AppSettings.CrashReportEnabledSettings(preferences).value - } + override fun crashLoggingEnabled() = settingsRepository.crashReportEnabled.value override fun extraKnownKeys(): List = emptyList() diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt index a4840dfa98b..5676f041caf 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt @@ -4,6 +4,7 @@ import android.content.Context import androidx.preference.PreferenceManager import com.google.android.gms.wearable.DataMap import com.google.gson.Gson +import com.woocommerce.android.wear.settings.AppSettings.CrashReportEnabledSettings import com.woocommerce.commons.DataParameters.APP_SETTINGS import com.woocommerce.commons.WearAppSettings import javax.inject.Inject @@ -16,12 +17,15 @@ class SettingsRepository @Inject constructor( private val gson by lazy { Gson() } + val crashReportEnabled: CrashReportEnabledSettings + get() = CrashReportEnabledSettings(preferences) + fun receiveAppSettingsDataFromPhone(data: DataMap) { val settings = data.getString(APP_SETTINGS.value, "") .takeIf { it.isNotEmpty() } ?.let { gson.fromJson(it, WearAppSettings::class.java) } ?: return - AppSettings.CrashReportEnabledSettings(preferences).value = settings.crashReportEnabled + CrashReportEnabledSettings(preferences).value = settings.crashReportEnabled } } From 1bbb2f6c4651d09172b00399b78f67a1c58ca0af Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 12 Aug 2024 21:36:59 -0300 Subject: [PATCH 178/196] Fix import order --- .../android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt index 9c69372dfb5..64c327d80bc 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt @@ -1,7 +1,6 @@ package com.woocommerce.android.wear.crashlogging import android.content.Context -import androidx.preference.PreferenceManager import com.automattic.android.tracks.crashlogging.CrashLoggingDataProvider import com.automattic.android.tracks.crashlogging.CrashLoggingUser import com.automattic.android.tracks.crashlogging.EventLevel @@ -10,7 +9,6 @@ import com.automattic.android.tracks.crashlogging.PerformanceMonitoringConfig import com.automattic.android.tracks.crashlogging.ReleaseName import com.woocommerce.android.BuildConfig import com.woocommerce.android.wear.di.AppCoroutineScope -import com.woocommerce.android.wear.settings.AppSettings import com.woocommerce.android.wear.settings.SettingsRepository import com.woocommerce.android.wear.ui.login.LoginRepository import kotlinx.coroutines.CoroutineScope From 40290cd1a07d67d92a6d0d4f8ab3e20cc272a8e4 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 12 Aug 2024 21:44:30 -0300 Subject: [PATCH 179/196] Introduce initial WCWearCrashLoggingDataProviderTest --- .../WCWearCrashLoggingDataProviderTest.kt | 192 ++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt diff --git a/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt b/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt new file mode 100644 index 00000000000..0d5b91e45d5 --- /dev/null +++ b/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt @@ -0,0 +1,192 @@ +package com.woocommerce.android.wear.crashlogging + +import android.content.Context +import com.automattic.android.tracks.crashlogging.CrashLoggingUser +import com.automattic.android.tracks.crashlogging.EventLevel +import com.automattic.android.tracks.crashlogging.ReleaseName +import com.woocommerce.android.BaseUnitTest +import com.woocommerce.android.BuildConfig +import com.woocommerce.android.wear.settings.SettingsRepository +import com.woocommerce.android.wear.ui.login.LoginRepository +import java.util.Locale +import kotlin.test.Test +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.single +import kotlinx.coroutines.test.TestScope +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.SoftAssertions +import org.junit.Before +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever +import org.wordpress.android.fluxc.Dispatcher +import org.wordpress.android.fluxc.model.AccountModel +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.store.AccountStore + +@OptIn(ExperimentalCoroutinesApi::class) +class WCWearCrashLoggingDataProviderTest : BaseUnitTest() { + private lateinit var sut: WCWearCrashLoggingDataProvider + + private val appContext: Context = mock() + private val accountStore: AccountStore = mock() + private val providedLocale: Locale = mock() + private val settingsRepository: SettingsRepository = mock() + private val loginRepository: LoginRepository = mock() + private val dispatcher: Dispatcher = mock() + + @Before + fun setUp() { + sut = WCWearCrashLoggingDataProvider( + appScope = TestScope(coroutinesTestRule.testDispatcher), + appContext = appContext, + accountStore = accountStore, + providedLocale = providedLocale, + settingsRepository = settingsRepository, + loginRepository = loginRepository, + dispatcher = dispatcher + ) + } + + private fun reinitialize() { + setUp() + } + + @Test + fun `should provide empty apps context if selected site does not exist`() = testBlocking { + whenever(loginRepository.selectedSiteFlow).thenReturn(MutableStateFlow(null)) + reinitialize() + + val appContext = sut.applicationContextProvider.first() + + assertThat(appContext).isEmpty() + } + + @Test + fun `should enable crash logging if crash logging is enabled`() { + whenever(settingsRepository.crashReportEnabled.value).thenReturn(true) + + val crashLoggingEnabled = sut.crashLoggingEnabled() + + assertThat(crashLoggingEnabled).isTrue + } + + @Test + fun `should disable crash logging if crash logging is disabled`() { + whenever(settingsRepository.crashReportEnabled.value).thenReturn(false) + + val crashLoggingEnabled = sut.crashLoggingEnabled() + + assertThat(crashLoggingEnabled).isFalse + } + + @Test + fun `should not include extra keys for events`() { + assertThat(sut.extraKnownKeys()).isEmpty() + } + + @Test + fun `should provide correctly mapped user if user exists`() = testBlocking { + whenever(accountStore.account).thenReturn(TEST_ACCOUNT) + reinitialize() + + val user = sut.user.first() + + softlyAssertUser(user) + } + + @Test + fun `should not provide user if user does not exist`() = testBlocking { + whenever(accountStore.account).thenReturn(null) + reinitialize() + + val user = sut.user.first() + + assertThat(user).isNull() + } + + @Test + fun `should not provide user if the account is the default one`() = testBlocking { + whenever(accountStore.account).thenReturn(DEFAULT_TEST_ACCOUNT) + reinitialize() + + val user = sut.user.first() + + assertThat(user).isNull() + } + + @Test + fun `should provide updated user if user changed`() = testBlocking { + whenever(accountStore.account).thenReturn(null) + reinitialize() + + whenever(accountStore.account).thenReturn(TEST_ACCOUNT) + sut.onAccountChanged(AccountStore.OnAccountChanged()) + val user = sut.user.first() + + softlyAssertUser(user) + } + + @Test + fun `should provide recent locale after locale change`() { + whenever(loginRepository.selectedSiteFlow).thenReturn(MutableStateFlow(null)) + whenever(providedLocale).thenReturn(Locale.US) + + assertThat(sut.locale).isEqualTo(Locale.US) + + whenever(providedLocale).thenReturn(Locale.CANADA) + + assertThat(sut.locale).isEqualTo(Locale.CANADA) + } + + @Test + fun `should provide empty extras for event`() { + val extras = sut.provideExtrasForEvent(currentExtras = emptyMap(), eventLevel = EventLevel.INFO) + + assertThat(extras).isEmpty() + } + + @Test + fun `should provide version name for release name for not debug build`() { + whenever(loginRepository.selectedSiteFlow).thenReturn(MutableStateFlow(null)) + whenever(BuildConfig.DEBUG).thenReturn(false) + + reinitialize() + + assertThat(sut.releaseName).isEqualTo(ReleaseName.SetByTracksLibrary) + } + + @Test + fun `should provide debug name for release name for debug build`() { + whenever(loginRepository.selectedSiteFlow).thenReturn(MutableStateFlow(null)) + whenever(BuildConfig.DEBUG).thenReturn(true) + + reinitialize() + + assertThat(sut.releaseName).isEqualTo(ReleaseName.SetByApplication(WCWearCrashLoggingDataProvider.DEBUG_RELEASE_NAME)) + } + + private fun softlyAssertUser(user: CrashLoggingUser?) { + SoftAssertions().apply { + assertThat(user?.username).isEqualTo(TEST_ACCOUNT.userName) + assertThat(user?.email).isEqualTo(TEST_ACCOUNT.email) + assertThat(user?.userID).isEqualTo(TEST_ACCOUNT.userId.toString()) + }.assertAll() + } + + companion object { + val TEST_ACCOUNT = AccountModel().apply { + userId = 123L + email = "mail@a8c.com" + userName = "username" + } + + val DEFAULT_TEST_ACCOUNT = AccountModel() + + val TEST_SITE_MODEL = SiteModel().apply { + siteId = 7L + url = "automattic.com" + } + } +} From f3fd8e614ad6fea377da8b76cc996c2080273ba2 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 12 Aug 2024 21:48:27 -0300 Subject: [PATCH 180/196] Adjust WCWearCrashLoggingDataProviderTest to go green --- .../WCWearCrashLoggingDataProviderTest.kt | 42 ++++--------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt b/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt index 0d5b91e45d5..a22a53cfb7e 100644 --- a/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt +++ b/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt @@ -6,6 +6,8 @@ import com.automattic.android.tracks.crashlogging.EventLevel import com.automattic.android.tracks.crashlogging.ReleaseName import com.woocommerce.android.BaseUnitTest import com.woocommerce.android.BuildConfig +import com.woocommerce.android.wear.settings.AppSettings +import com.woocommerce.android.wear.settings.AppSettings.CrashReportEnabledSettings import com.woocommerce.android.wear.settings.SettingsRepository import com.woocommerce.android.wear.ui.login.LoginRepository import java.util.Locale @@ -65,7 +67,9 @@ class WCWearCrashLoggingDataProviderTest : BaseUnitTest() { @Test fun `should enable crash logging if crash logging is enabled`() { - whenever(settingsRepository.crashReportEnabled.value).thenReturn(true) + val settingsMock = mock() + whenever(settingsMock.value).thenReturn(true) + whenever(settingsRepository.crashReportEnabled).thenReturn(settingsMock) val crashLoggingEnabled = sut.crashLoggingEnabled() @@ -74,7 +78,9 @@ class WCWearCrashLoggingDataProviderTest : BaseUnitTest() { @Test fun `should disable crash logging if crash logging is disabled`() { - whenever(settingsRepository.crashReportEnabled.value).thenReturn(false) + val settingsMock = mock() + whenever(settingsMock.value).thenReturn(false) + whenever(settingsRepository.crashReportEnabled).thenReturn(settingsMock) val crashLoggingEnabled = sut.crashLoggingEnabled() @@ -128,18 +134,6 @@ class WCWearCrashLoggingDataProviderTest : BaseUnitTest() { softlyAssertUser(user) } - @Test - fun `should provide recent locale after locale change`() { - whenever(loginRepository.selectedSiteFlow).thenReturn(MutableStateFlow(null)) - whenever(providedLocale).thenReturn(Locale.US) - - assertThat(sut.locale).isEqualTo(Locale.US) - - whenever(providedLocale).thenReturn(Locale.CANADA) - - assertThat(sut.locale).isEqualTo(Locale.CANADA) - } - @Test fun `should provide empty extras for event`() { val extras = sut.provideExtrasForEvent(currentExtras = emptyMap(), eventLevel = EventLevel.INFO) @@ -147,26 +141,6 @@ class WCWearCrashLoggingDataProviderTest : BaseUnitTest() { assertThat(extras).isEmpty() } - @Test - fun `should provide version name for release name for not debug build`() { - whenever(loginRepository.selectedSiteFlow).thenReturn(MutableStateFlow(null)) - whenever(BuildConfig.DEBUG).thenReturn(false) - - reinitialize() - - assertThat(sut.releaseName).isEqualTo(ReleaseName.SetByTracksLibrary) - } - - @Test - fun `should provide debug name for release name for debug build`() { - whenever(loginRepository.selectedSiteFlow).thenReturn(MutableStateFlow(null)) - whenever(BuildConfig.DEBUG).thenReturn(true) - - reinitialize() - - assertThat(sut.releaseName).isEqualTo(ReleaseName.SetByApplication(WCWearCrashLoggingDataProvider.DEBUG_RELEASE_NAME)) - } - private fun softlyAssertUser(user: CrashLoggingUser?) { SoftAssertions().apply { assertThat(user?.username).isEqualTo(TEST_ACCOUNT.userName) From 5dcbdf08d82a03627f760963a0de9294f3e43a14 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 12 Aug 2024 21:49:44 -0300 Subject: [PATCH 181/196] Fix lint issues --- .../android/wear/settings/SettingsRepository.kt | 6 +++--- .../crashlogging/WCWearCrashLoggingDataProviderTest.kt | 8 ++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt index 5676f041caf..103ffe68fef 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/settings/SettingsRepository.kt @@ -12,11 +12,11 @@ import javax.inject.Inject class SettingsRepository @Inject constructor( private val appContext: Context ) { + private val gson by lazy { Gson() } + private val preferences get() = PreferenceManager.getDefaultSharedPreferences(appContext) - private val gson by lazy { Gson() } - val crashReportEnabled: CrashReportEnabledSettings get() = CrashReportEnabledSettings(preferences) @@ -26,6 +26,6 @@ class SettingsRepository @Inject constructor( ?.let { gson.fromJson(it, WearAppSettings::class.java) } ?: return - CrashReportEnabledSettings(preferences).value = settings.crashReportEnabled + crashReportEnabled.value = settings.crashReportEnabled } } diff --git a/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt b/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt index a22a53cfb7e..6f711b8e407 100644 --- a/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt +++ b/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt @@ -3,19 +3,13 @@ package com.woocommerce.android.wear.crashlogging import android.content.Context import com.automattic.android.tracks.crashlogging.CrashLoggingUser import com.automattic.android.tracks.crashlogging.EventLevel -import com.automattic.android.tracks.crashlogging.ReleaseName import com.woocommerce.android.BaseUnitTest -import com.woocommerce.android.BuildConfig -import com.woocommerce.android.wear.settings.AppSettings import com.woocommerce.android.wear.settings.AppSettings.CrashReportEnabledSettings import com.woocommerce.android.wear.settings.SettingsRepository import com.woocommerce.android.wear.ui.login.LoginRepository -import java.util.Locale -import kotlin.test.Test import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.single import kotlinx.coroutines.test.TestScope import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.SoftAssertions @@ -26,6 +20,8 @@ import org.wordpress.android.fluxc.Dispatcher import org.wordpress.android.fluxc.model.AccountModel import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.AccountStore +import java.util.Locale +import kotlin.test.Test @OptIn(ExperimentalCoroutinesApi::class) class WCWearCrashLoggingDataProviderTest : BaseUnitTest() { From 2945e010f5445d8c74dc01eb7300e5ea85394251 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 12 Aug 2024 21:50:29 -0300 Subject: [PATCH 182/196] Remove unused dependency from WCWearCrashLoggingDataProvider --- .../wear/crashlogging/WCWearCrashLoggingDataProvider.kt | 2 -- .../wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt | 3 --- 2 files changed, 5 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt index 64c327d80bc..e00f15214d1 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProvider.kt @@ -1,6 +1,5 @@ package com.woocommerce.android.wear.crashlogging -import android.content.Context import com.automattic.android.tracks.crashlogging.CrashLoggingDataProvider import com.automattic.android.tracks.crashlogging.CrashLoggingUser import com.automattic.android.tracks.crashlogging.EventLevel @@ -28,7 +27,6 @@ import javax.inject.Singleton @Singleton class WCWearCrashLoggingDataProvider @Inject constructor( @AppCoroutineScope private val appScope: CoroutineScope, - private val appContext: Context, private val accountStore: AccountStore, private val providedLocale: Locale, private val settingsRepository: SettingsRepository, diff --git a/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt b/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt index 6f711b8e407..963c8db121a 100644 --- a/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt +++ b/WooCommerce-Wear/src/test/java/com/woocommerce/android/wear/crashlogging/WCWearCrashLoggingDataProviderTest.kt @@ -1,6 +1,5 @@ package com.woocommerce.android.wear.crashlogging -import android.content.Context import com.automattic.android.tracks.crashlogging.CrashLoggingUser import com.automattic.android.tracks.crashlogging.EventLevel import com.woocommerce.android.BaseUnitTest @@ -27,7 +26,6 @@ import kotlin.test.Test class WCWearCrashLoggingDataProviderTest : BaseUnitTest() { private lateinit var sut: WCWearCrashLoggingDataProvider - private val appContext: Context = mock() private val accountStore: AccountStore = mock() private val providedLocale: Locale = mock() private val settingsRepository: SettingsRepository = mock() @@ -38,7 +36,6 @@ class WCWearCrashLoggingDataProviderTest : BaseUnitTest() { fun setUp() { sut = WCWearCrashLoggingDataProvider( appScope = TestScope(coroutinesTestRule.testDispatcher), - appContext = appContext, accountStore = accountStore, providedLocale = providedLocale, settingsRepository = settingsRepository, From 77f79fcf19ae9b171988ba89fa6e3e4a28995782 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 13 Aug 2024 10:24:25 +0200 Subject: [PATCH 183/196] Another interpolator for the animation --- .../android/ui/woopos/home/WooPosHomeNavigation.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeNavigation.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeNavigation.kt index c36cadba823..faf9c91d9d7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeNavigation.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeNavigation.kt @@ -1,5 +1,6 @@ package com.woocommerce.android.ui.woopos.home +import android.view.animation.AccelerateDecelerateInterpolator import android.view.animation.OvershootInterpolator import androidx.compose.animation.core.tween import androidx.compose.animation.slideInVertically @@ -23,9 +24,10 @@ fun NavGraphBuilder.homeScreen( slideInVertically( initialOffsetY = { -it }, animationSpec = tween( - durationMillis = 1000, - easing = { - OvershootInterpolator(2f).getInterpolation(it) + durationMillis = 800, + easing = { time -> + val accelerateDecelerate = AccelerateDecelerateInterpolator().getInterpolation(time) + OvershootInterpolator(1.5f).getInterpolation(accelerateDecelerate) } ) ) From 30bccce880872589b4630da4c83efa076819bd13 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 13 Aug 2024 10:54:42 +0200 Subject: [PATCH 184/196] Keep the cart open during initial loading --- .../ui/woopos/home/WooPosHomeViewModel.kt | 2 +- .../home/products/WooPosProductsScreen.kt | 7 ++++- .../home/products/WooPosProductsViewModel.kt | 26 +++++++++++++------ .../home/products/WooPosProductsViewState.kt | 5 +++- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt index 783eb1cbef5..b4b1242dbd6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt @@ -20,7 +20,7 @@ class WooPosHomeViewModel @Inject constructor( scope = viewModelScope, key = "home_state", initialValue = WooPosHomeState( - screenPositionState = WooPosHomeState.ScreenPositionState.Cart.Hidden, + screenPositionState = WooPosHomeState.ScreenPositionState.Cart.Visible.Empty, productsInfoDialog = WooPosHomeState.ProductsInfoDialog.Hidden, exitConfirmationDialog = null ) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt index 69309063a3a..f4c2cadc87a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsScreen.kt @@ -527,7 +527,12 @@ fun WooPosProductsScreenPreview(modifier: Modifier = Modifier) { @Composable @WooPosPreview fun WooPosProductsScreenLoadingPreview() { - val productState = MutableStateFlow(WooPosProductsViewState.Loading(true)) + val productState = MutableStateFlow( + WooPosProductsViewState.Loading( + reloadingProductsWithPullToRefresh = true, + withCart = false + ) + ) WooPosTheme { WooPosProductsScreen( productsStateFlow = productState, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt index 8c13b750cc3..d5906e06d2e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModel.kt @@ -29,7 +29,7 @@ class WooPosProductsViewModel @Inject constructor( private var loadMoreProductsJob: Job? = null private val _viewState = - MutableStateFlow(WooPosProductsViewState.Loading()) + MutableStateFlow(WooPosProductsViewState.Loading(withCart = true)) val viewState: StateFlow = _viewState .onEach { notifyParentAboutStatusChange(it) } .stateIn( @@ -41,7 +41,8 @@ class WooPosProductsViewModel @Inject constructor( init { loadProducts( forceRefreshProducts = false, - withPullToRefresh = false + withPullToRefresh = false, + withCart = true, ) } @@ -58,14 +59,16 @@ class WooPosProductsViewModel @Inject constructor( WooPosProductsUIEvent.PullToRefreshTriggered -> { loadProducts( forceRefreshProducts = true, - withPullToRefresh = true + withPullToRefresh = true, + withCart = true, ) } WooPosProductsUIEvent.ProductsLoadingErrorRetryButtonClicked -> { loadProducts( forceRefreshProducts = false, - withPullToRefresh = false + withPullToRefresh = false, + withCart = false, ) } @@ -106,13 +109,14 @@ class WooPosProductsViewModel @Inject constructor( private fun loadProducts( forceRefreshProducts: Boolean, - withPullToRefresh: Boolean + withPullToRefresh: Boolean, + withCart: Boolean ) { viewModelScope.launch { _viewState.value = if (withPullToRefresh) { buildProductsReloadingState() } else { - WooPosProductsViewState.Loading() + WooPosProductsViewState.Loading(withCart = withCart) } productsDataSource.loadSimpleProducts(forceRefreshProducts = forceRefreshProducts).collect { result -> @@ -198,8 +202,14 @@ class WooPosProductsViewModel @Inject constructor( is WooPosProductsViewState.Content -> ChildToParentEvent.ProductsStatusChanged.WithCart is WooPosProductsViewState.Empty, - is WooPosProductsViewState.Error, - is WooPosProductsViewState.Loading -> ChildToParentEvent.ProductsStatusChanged.FullScreen + is WooPosProductsViewState.Error -> ChildToParentEvent.ProductsStatusChanged.FullScreen + is WooPosProductsViewState.Loading -> { + if (newState.withCart) { + ChildToParentEvent.ProductsStatusChanged.WithCart + } else { + ChildToParentEvent.ProductsStatusChanged.FullScreen + } + } } ) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt index 20f56fdccf7..7b36c3ebcb8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewState.kt @@ -20,7 +20,10 @@ sealed class WooPosProductsViewState( ) } - data class Loading(override val reloadingProductsWithPullToRefresh: Boolean = false) : + data class Loading( + override val reloadingProductsWithPullToRefresh: Boolean = false, + val withCart: Boolean, + ) : WooPosProductsViewState(reloadingProductsWithPullToRefresh) data class Error(override val reloadingProductsWithPullToRefresh: Boolean = false) : From 15c597ba5b54e4ed67c09cca438f4629f668379c Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 13 Aug 2024 11:18:56 +0200 Subject: [PATCH 185/196] Supressed detekt complain --- .../woocommerce/android/ui/woopos/home/WooPosHomeNavigation.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeNavigation.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeNavigation.kt index faf9c91d9d7..f33d2e7f82c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeNavigation.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeNavigation.kt @@ -27,6 +27,7 @@ fun NavGraphBuilder.homeScreen( durationMillis = 800, easing = { time -> val accelerateDecelerate = AccelerateDecelerateInterpolator().getInterpolation(time) + @Suppress("MagicNumber") OvershootInterpolator(1.5f).getInterpolation(accelerateDecelerate) } ) From 9f64feebf6c43d17ba0fe14fd7c94847c9686e94 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 13 Aug 2024 15:05:39 +0200 Subject: [PATCH 186/196] Do not set another loading to not break the animation --- .../android/ui/woopos/splash/WooPosSplashScreen.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/splash/WooPosSplashScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/splash/WooPosSplashScreen.kt index 3bbdba76472..72661659dd2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/splash/WooPosSplashScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/splash/WooPosSplashScreen.kt @@ -33,11 +33,12 @@ fun WooPosSplashScreen(onNavigationEvent: (WooPosNavigationEvent) -> Unit) { onNavigationEvent(WooPosNavigationEvent.BackFromSplashClicked) } + Loading() + when (state.value) { - is WooPosSplashState.Loading -> Loading() + is WooPosSplashState.Loading -> {} is WooPosSplashState.Loaded -> { onNavigationEvent(WooPosNavigationEvent.OpenHomeFromSplash) - Loading() } } } From dc7f48aa26af688dd0134de0e28b2e3cee58b4c2 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 13 Aug 2024 16:07:56 +0200 Subject: [PATCH 187/196] 24dp as cut off for determining the gesture way of navigation --- .../android/ui/woopos/root/WooPosActivity.kt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosActivity.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosActivity.kt index 5a8f7838c76..204e6d115a4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosActivity.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosActivity.kt @@ -1,7 +1,9 @@ package com.woocommerce.android.ui.woopos.root +import android.content.Context import android.content.pm.ActivityInfo import android.os.Bundle +import android.util.TypedValue import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity import androidx.compose.foundation.layout.navigationBarsPadding @@ -54,7 +56,7 @@ class WooPosActivity : AppCompatActivity() { private fun Modifier.gesturesOrButtonsNavigationPadding(): Modifier { val view = LocalView.current val insets = WindowInsetsCompat.toWindowInsetsCompat(view.rootWindowInsets) - val isGestureNavigation = insets.isGestureNavigation() + val isGestureNavigation = insets.isGestureNavigation(view.context) return if (isGestureNavigation) { this.padding(bottom = 0.dp) @@ -63,10 +65,16 @@ private fun Modifier.gesturesOrButtonsNavigationPadding(): Modifier { } } -// That seems to be different on different devices, but 48dp is a common upper value -private const val GESTURE_NAVIGATION_BAR_HEIGHT = 48 -private fun WindowInsetsCompat.isGestureNavigation(): Boolean { +// That seems to be different on different devices, but 24dp is a common upper value +private const val GESTURE_NAVIGATION_BAR_HEIGHT_DP = 24 +private fun WindowInsetsCompat.isGestureNavigation(context: Context): Boolean { val bottomInset = getInsets(WindowInsetsCompat.Type.navigationBars()).bottom - return bottomInset <= GESTURE_NAVIGATION_BAR_HEIGHT + val gestureNavigationBarHeightPx = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + GESTURE_NAVIGATION_BAR_HEIGHT_DP.toFloat(), + context.resources.displayMetrics + ).toInt() + + return bottomInset in 1..gestureNavigationBarHeightPx } From 02d92fd43184c45b774d56674c88916660f0955c Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 13 Aug 2024 19:02:18 -0300 Subject: [PATCH 188/196] Add remaining paths mapping into Mobile and Wear manifests --- WooCommerce-Wear/src/main/AndroidManifest.xml | 8 ++++++++ WooCommerce/src/main/AndroidManifest.xml | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/WooCommerce-Wear/src/main/AndroidManifest.xml b/WooCommerce-Wear/src/main/AndroidManifest.xml index 6b41fc06979..555eae15a1b 100644 --- a/WooCommerce-Wear/src/main/AndroidManifest.xml +++ b/WooCommerce-Wear/src/main/AndroidManifest.xml @@ -82,6 +82,14 @@ android:pathPrefix="/order-products-data" android:scheme="wear" /> + + + + + + + + + + Date: Tue, 13 Aug 2024 21:35:00 -0600 Subject: [PATCH 189/196] fix unit tests --- .../ui/analytics/AnalyticsHubViewModelTest.kt | 27 +++++++++++++++---- .../stats/DashboardStatsViewModelTest.kt | 2 +- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/AnalyticsHubViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/AnalyticsHubViewModelTest.kt index d1f7297b360..58e4765b5ea 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/AnalyticsHubViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/AnalyticsHubViewModelTest.kt @@ -748,7 +748,7 @@ class AnalyticsHubViewModelTest : BaseUnitTest() { fun `when last update information changes, then update view state as expected`() = testBlocking { val lastUpdateTimestamp = 123456789L whenever( - observeLastUpdate.invoke(selectedRange = any(), analyticDataList = any()) + observeLastUpdate.invoke(selectedRange = any(), analyticDataList = any(), shouldAllDataBePresent = eq(true)) ).thenReturn(flowOf(lastUpdateTimestamp)) whenever(dateUtils.getDateOrTimeFromMillis(lastUpdateTimestamp)).thenReturn("9:35 AM") configureVisibleCards() @@ -845,7 +845,13 @@ class AnalyticsHubViewModelTest : BaseUnitTest() { isVisible = true ) ) - whenever(observeLastUpdate.invoke(selectedRange = any(), analyticDataList = any())).thenReturn(flowOf(null)) + whenever( + observeLastUpdate.invoke( + selectedRange = any(), + analyticDataList = any(), + shouldAllDataBePresent = eq(true) + ) + ).thenReturn(flowOf(null)) configureVisibleCards(configuration) configureSuccessfulStatsResponse() @@ -889,8 +895,11 @@ class AnalyticsHubViewModelTest : BaseUnitTest() { title = AnalyticsCards.Session.name, isVisible = true ) + ) - whenever(observeLastUpdate.invoke(selectedRange = any(), analyticDataList = any())).thenReturn(flowOf(null)) + whenever( + observeLastUpdate.invoke(selectedRange = any(), analyticDataList = any(), shouldAllDataBePresent = eq(true)) + ).thenReturn(flowOf(null)) configureVisibleCards(configuration) configureSuccessfulStatsResponse() @@ -930,7 +939,9 @@ class AnalyticsHubViewModelTest : BaseUnitTest() { val expectedVisibleCards = configuration.filter { it.isVisible }.map { it.card } - whenever(observeLastUpdate.invoke(selectedRange = any(), analyticDataList = any())).thenReturn(flowOf(null)) + whenever( + observeLastUpdate.invoke(selectedRange = any(), analyticDataList = any(), shouldAllDataBePresent = eq(true)) + ).thenReturn(flowOf(null)) configureVisibleCards(configuration) configureSuccessfulStatsResponse() @@ -972,7 +983,13 @@ class AnalyticsHubViewModelTest : BaseUnitTest() { val expectedVisibleCards = configuration.filter { it.isVisible }.map { it.card } - whenever(observeLastUpdate.invoke(selectedRange = any(), analyticDataList = any())).thenReturn(flowOf(null)) + whenever( + observeLastUpdate.invoke( + selectedRange = any(), + analyticDataList = any(), + shouldAllDataBePresent = eq(true) + ) + ).thenReturn(flowOf(null)) configureVisibleCards(configuration) configureSuccessfulStatsResponse() diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/dashboard/stats/DashboardStatsViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/dashboard/stats/DashboardStatsViewModelTest.kt index 83631b192ec..4e6af805c93 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/dashboard/stats/DashboardStatsViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/dashboard/stats/DashboardStatsViewModelTest.kt @@ -72,7 +72,7 @@ class DashboardStatsViewModelTest : BaseUnitTest() { } private val timezoneProvider: TimezoneProvider = mock() private val observeLastUpdate: ObserveLastUpdate = mock { - onBlocking { invoke(any(), ArgumentMatchers.anyList()) } doReturn flowOf(DEFAULT_LAST_UPDATE) + onBlocking { invoke(any(), ArgumentMatchers.anyList(), eq(false)) } doReturn flowOf(DEFAULT_LAST_UPDATE) } private val dateUtils: DateUtils = mock() private val parentViewModel: DashboardViewModel = mock { From 58c39a7cef8632f11a71817b9e53894634dff019 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Wed, 14 Aug 2024 08:22:00 +0200 Subject: [PATCH 190/196] Remove validate scanned value class --- .../android/ui/login/qrcode/ValidateScannedValue.kt | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/qrcode/ValidateScannedValue.kt diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/qrcode/ValidateScannedValue.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/qrcode/ValidateScannedValue.kt deleted file mode 100644 index 49040183b15..00000000000 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/qrcode/ValidateScannedValue.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.woocommerce.android.ui.login.qrcode - -object ValidateScannedValue { - - private const val MAGIC_LOGIN_ACTION = "magic-login" - private const val MAGIC_LOGIN_SCHEME = "woocommerce" - - fun validate(scannedRawValue: String?): Boolean { - return scannedRawValue != null && - scannedRawValue.contains(MAGIC_LOGIN_ACTION) && - scannedRawValue.contains(MAGIC_LOGIN_SCHEME) - } -} From 07bc95311952378d6f831039b6324fffc5d5dcff Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Wed, 14 Aug 2024 08:28:55 +0200 Subject: [PATCH 191/196] Remove unused property key --- .../com/woocommerce/android/analytics/AnalyticsTracker.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt index f0d1c141d98..cd8fa49bf6b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt @@ -531,9 +531,6 @@ class AnalyticsTracker private constructor( const val VALUE_JETPACK_SETUP_TAP_SUPPORT = "support" const val VALUE_JETPACK_SETUP_TAP_TRY_AGAIN = "try_again" - // -- Login with WordPress.com account flow - const val VALUE_LOGIN_WITH_WORDPRESS_COM = "wordpress_com" - // -- Upsell banner const val KEY_BANNER_SOURCE = "source" const val KEY_BANNER_CAMPAIGN_NAME = "campaign_name" From 47b686bf1d1ed528269692307a6f3bc4c5543f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ce=CC=81sar=20Vargas=20Casaseca?= Date: Wed, 14 Aug 2024 11:16:16 +0200 Subject: [PATCH 192/196] Update PR Template according to best practices --- .github/PULL_REQUEST_TEMPLATE.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 942a403a4df..1504cf5fe71 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -15,8 +15,14 @@ Closes: # ### Images/gif - -- [ ] I have considered adding unit tests for this change. If I decided not to add them, I have provided a brief explanation below (optional): - [ ] I have considered if this change warrants release notes and have added them to `RELEASE-NOTES.txt` if necessary. Use the "[Internal]" label for non-user-facing changes. +## Reviewer (or Author, in the case of optional code reviews): + +Please make sure these conditions are met before approving the PR, or request changes if the PR needs improvement: + +- [ ] The PR is small and has a clear, single focus, or a valid explanation is provided in the description. If needed, please request to split it into smaller PRs. +- [ ] Ensure Adequate Unit Test Coverage: The changes are reasonably covered by unit tests or an explanation is provided in the PR description. +- [ ] Manual Testing: The author listed all the tests they ran, including smoke tests when needed (e.g., for refactorings). The reviewer confirmed that the PR works as expected on all devices (phone/tablet) and no regressions are added. + From 6c3aedfa04fd655ba4d466375633f63854fccd93 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Wed, 14 Aug 2024 15:40:56 +0200 Subject: [PATCH 193/196] Add new suspended status to Blaze campaigns --- .../com/woocommerce/android/ui/blaze/BlazeUiModels.kt | 6 ++++++ WooCommerce/src/main/res/values/colors_base.xml | 2 ++ WooCommerce/src/main/res/values/strings.xml | 1 + 3 files changed, 9 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeUiModels.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeUiModels.kt index 9e9308a7bf8..5695e2e78dd 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeUiModels.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeUiModels.kt @@ -54,6 +54,11 @@ enum class CampaignStatusUi( statusDisplayText = R.string.blaze_campaign_status_canceled, textColor = R.color.blaze_campaign_status_rejected_text, backgroundColor = R.color.blaze_campaign_status_rejected_background + ), + Suspended( + statusDisplayText = R.string.blaze_campaign_status_suspended, + textColor = R.color.blaze_campaign_status_suspended_text, + backgroundColor = R.color.blaze_campaign_status_suspended_background ); companion object { @@ -63,6 +68,7 @@ enum class CampaignStatusUi( "scheduled" -> Scheduled "active" -> Active "rejected" -> Rejected + "suspended" -> Suspended "canceled" -> Canceled "finished" -> Completed else -> null diff --git a/WooCommerce/src/main/res/values/colors_base.xml b/WooCommerce/src/main/res/values/colors_base.xml index e1523b4d03a..26cf9727e7b 100644 --- a/WooCommerce/src/main/res/values/colors_base.xml +++ b/WooCommerce/src/main/res/values/colors_base.xml @@ -297,6 +297,8 @@ @color/blaze_blue_60 @color/blaze_red_5 @color/blaze_red_6 + @color/blaze_red_6 + @color/white @color/woo_gray_6 @color/woo_gray_0 @color/woo_gray_0 diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index 2810d72854c..d999f9f0080 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -3875,6 +3875,7 @@ Scheduled Rejected Canceled + Suspended Impressions Clicks Budget From 7fbc3596947a696a7581c3bfe4062bd1b1c9950b Mon Sep 17 00:00:00 2001 From: pachlava Date: Wed, 14 Aug 2024 18:10:46 +0300 Subject: [PATCH 194/196] Wait for the card to appear before asserting it. --- .../android/e2e/screens/orders/OrderListScreen.kt | 11 +++++++++++ .../android/e2e/screens/products/ProductListScreen.kt | 11 +++++++++++ .../android/e2e/screens/reviews/ReviewsListScreen.kt | 11 +++++++++++ 3 files changed, 33 insertions(+) diff --git a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/OrderListScreen.kt b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/OrderListScreen.kt index 0c596bc7522..20846b19046 100644 --- a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/OrderListScreen.kt +++ b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/OrderListScreen.kt @@ -83,6 +83,17 @@ class OrderListScreen : Screen(R.id.ordersList) { } fun assertOrderCard(order: OrderData): OrderListScreen { + // Wait for the order card to appear first. This is sometimes + // flaky on Firebase because of low emulator performance. + waitForElementToBeDisplayed( + Espresso.onView( + Matchers.allOf( + ViewMatchers.withId(R.id.orderNum), + ViewMatchers.withText("#${order.id}") + ) + ) + ) + // Using quite a complex matcher to make sure that all expected // order details belong to the same order card. Espresso.onView( diff --git a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/products/ProductListScreen.kt b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/products/ProductListScreen.kt index 0e4283526f3..e293154f5b8 100644 --- a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/products/ProductListScreen.kt +++ b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/products/ProductListScreen.kt @@ -140,6 +140,17 @@ class ProductListScreen : Screen { } fun assertProductCard(product: ProductData): ProductListScreen { + // Wait for the product card to appear first. This is sometimes + // flaky on Firebase because of low emulator performance. + waitForElementToBeDisplayed( + Espresso.onView( + Matchers.allOf( + ViewMatchers.withId(R.id.productName), + ViewMatchers.withText(product.name) + ) + ) + ) + // If a product has an SKU, value will be prefixed with "SKU :" on screen. // If a product has no SKU, the field won't be shown at all. val expectedSKU = if (product.sku.isEmpty()) "" else "SKU: ${product.sku}" diff --git a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/reviews/ReviewsListScreen.kt b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/reviews/ReviewsListScreen.kt index c1f31416987..2cef21d19dc 100644 --- a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/reviews/ReviewsListScreen.kt +++ b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/reviews/ReviewsListScreen.kt @@ -33,6 +33,17 @@ class ReviewsListScreen : Screen(R.id.reviewsList) { } fun assertReviewCard(review: ReviewData): ReviewsListScreen { + // Wait for the review card to appear first. This is sometimes + // flaky on Firebase because of low emulator performance. + waitForElementToBeDisplayed( + Espresso.onView( + Matchers.allOf( + ViewMatchers.withId(R.id.notif_title), + ViewMatchers.withText(review.title) + ) + ) + ) + // Assert that review has an expected hierarchy and content Espresso.onView( Matchers.allOf( From 3ba69e0c767176ecb0c5652399b6e7f6b3a8d896 Mon Sep 17 00:00:00 2001 From: pachlava Date: Wed, 14 Aug 2024 18:42:48 +0300 Subject: [PATCH 195/196] Fix detekt error (indentation). --- .../android/e2e/screens/orders/OrderListScreen.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/OrderListScreen.kt b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/OrderListScreen.kt index 20846b19046..b522601cc3d 100644 --- a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/OrderListScreen.kt +++ b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/OrderListScreen.kt @@ -87,10 +87,10 @@ class OrderListScreen : Screen(R.id.ordersList) { // flaky on Firebase because of low emulator performance. waitForElementToBeDisplayed( Espresso.onView( - Matchers.allOf( - ViewMatchers.withId(R.id.orderNum), - ViewMatchers.withText("#${order.id}") - ) + Matchers.allOf( + ViewMatchers.withId(R.id.orderNum), + ViewMatchers.withText("#${order.id}") + ) ) ) From 354f1034b4e5d3d55a80a36977dd888582ac1a3d Mon Sep 17 00:00:00 2001 From: pachlava Date: Wed, 14 Aug 2024 19:25:22 +0300 Subject: [PATCH 196/196] Wait for element to be enabled before tapping it. --- .../kotlin/com/woocommerce/android/e2e/helpers/util/Screen.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/helpers/util/Screen.kt b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/helpers/util/Screen.kt index 7b75333ea3b..91b03e268a2 100644 --- a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/helpers/util/Screen.kt +++ b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/helpers/util/Screen.kt @@ -170,6 +170,7 @@ open class Screen { fun clickOn(elementID: Int) { waitForElementToBeDisplayed(elementID) + waitForElementToBeEnabled(elementID) clickOn(onView(withId(elementID))) idleFor(500) // allow for transitions }