Skip to content

Commit 2b41899

Browse files
author
Joel Dean
committed
Merge branch 'trunk' into issue-3885/variation-delete-confirmation
2 parents 18094aa + 92810a2 commit 2b41899

File tree

99 files changed

+2773
-1068
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+2773
-1068
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
<!--
22
Contains editorialized release notes. Raw release notes should go into `RELEASE-NOTES.txt`.
33
-->
4+
## 17.2
5+
This version includes optimizations for speed and reliability. We are committed to continuously improving the app, making managing your online store more efficient and hassle-free.
6+
47
## 17.1
58
This release focuses on bug fixes and improvements to help you get your business started. Keep your feedback rolling in; it helps us figure out what to work on next.
69

RELEASE-NOTES.txt

+6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
*** PLEASE FOLLOW THIS FORMAT: [<priority indicator, more stars = higher priority>] <description> [<PR URL>]
22

3+
17.3
4+
-----
5+
6+
37
17.3
48
-----
59
- [*] [Internal] Enhanced user experience in shipping label creation with automatic scrolling to the first invalid field upon form submission failure [https://github.com/woocommerce/woocommerce-android/pull/10657]
610
- [*] [Internal] Enhanced product variation delete confirmation dialog visibility and functionality across device rotations [https://github.com/woocommerce/woocommerce-android/pull/10664]
11+
- [*] [Internal] Added a text along with the receipts file when it is shared [https://github.com/woocommerce/woocommerce-android/pull/10681]
712

813
17.2
914
-----
1015
- [**] [Available for users with WooCommerce version of 8.7+, which is not released yet] Every order have a receipt now. The receipts can be shared via many apps installed on the phone [https://github.com/woocommerce/woocommerce-android/pull/10650]
16+
- [*] Fix login for sites with Jetpack Connection Package [https://github.com/woocommerce/woocommerce-android/pull/10688]
1117

1218
17.1
1319
-----

WooCommerce/metadata/PlayStoreStrings.pot

+6-6
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ msgstr ""
1111
"Project-Id-Version: Release Notes & Play Store Descriptions\n"
1212

1313
#. translators: Release notes for this version to be displayed in the Play Store. Limit to 500 characters including spaces and commas!
14-
msgctxt "release_note_171"
14+
msgctxt "release_note_172"
1515
msgid ""
16-
"17.1:\n"
17-
"This release focuses on bug fixes and improvements to help you get your business started. Keep your feedback rolling in; it helps us figure out what to work on next.\n"
16+
"17.2:\n"
17+
"This version includes optimizations for speed and reliability. We are committed to continuously improving the app, making managing your online store more efficient and hassle-free.\n"
1818
msgstr ""
1919

20-
msgctxt "release_note_170"
20+
msgctxt "release_note_171"
2121
msgid ""
22-
"17.0:\n"
23-
"Get ready for a smoother experience with our latest update! We've ironed out the pesky bug that kept gift cards from showing up in the 'totals' section during order creation and editing. Managing your sales with our WooCommerce app is now more seamless than ever. Update now and enjoy the hassle-free enhancements!\n"
22+
"17.1:\n"
23+
"This release focuses on bug fixes and improvements to help you get your business started. Keep your feedback rolling in; it helps us figure out what to work on next.\n"
2424
msgstr ""
2525

2626
#. translators: Short description of the app to be displayed in the Play Store. Limit to 80 characters including spaces and commas!
+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
This release focuses on bug fixes and improvements to help you get your business started. Keep your feedback rolling in; it helps us figure out what to work on next.
1+
This version includes optimizations for speed and reliability. We are committed to continuously improving the app, making managing your online store more efficient and hassle-free.

WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/helpers/util/Screen.kt

+19
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
2323
import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed
2424
import androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA
2525
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
26+
import androidx.test.espresso.matcher.ViewMatchers.isEnabled
2627
import androidx.test.espresso.matcher.ViewMatchers.isNotChecked
2728
import androidx.test.espresso.matcher.ViewMatchers.withClassName
2829
import androidx.test.espresso.matcher.ViewMatchers.withId
@@ -96,6 +97,16 @@ open class Screen {
9697
}
9798
}
9899

100+
private fun isElementEnabled(element: Int): Boolean {
101+
return try {
102+
onView(withId(element))
103+
.check(matches(isEnabled()))
104+
true
105+
} catch (e: Throwable) {
106+
false
107+
}
108+
}
109+
99110
private fun isElementNotDisplayed(element: Int): Boolean {
100111
return try {
101112
onView(withId(element))
@@ -307,6 +318,14 @@ open class Screen {
307318
idleFor(1000) // allow for transitions
308319
}
309320

321+
fun waitForElementToBeEnabled(elementID: Int) {
322+
waitForConditionToBeTrue(
323+
Supplier<Boolean> {
324+
isElementEnabled(elementID)
325+
}
326+
)
327+
}
328+
310329
fun waitForElementToBeDisplayed(elementID: Int) {
311330
waitForConditionToBeTrue(
312331
Supplier<Boolean> {

WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/UnifiedOrderScreen.kt

+4-13
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ import com.woocommerce.android.R
1414
import com.woocommerce.android.e2e.helpers.util.NestedScrollViewExtension
1515
import com.woocommerce.android.e2e.helpers.util.Screen
1616
import org.hamcrest.CoreMatchers.endsWith
17-
import org.hamcrest.Matchers
1817
import org.hamcrest.core.AllOf.allOf
1918

2019
class UnifiedOrderScreen : Screen(R.id.order_creation_root) {
2120
fun createOrder(): SingleOrderScreen {
22-
clickOn(R.id.menu_create)
21+
waitForElementToBeEnabled(R.id.menu_create)
22+
Espresso.onView(withId(R.id.menu_create)).perform(click())
2323
return SingleOrderScreen()
2424
}
2525

@@ -60,18 +60,9 @@ class UnifiedOrderScreen : Screen(R.id.order_creation_root) {
6060
return this
6161
}
6262

63-
fun editCustomerNote(note: String): UnifiedOrderScreen {
64-
waitForElementToBeDisplayedWithoutFailure(R.id.notes_section)
65-
scrollTo(R.id.notes_section)
63+
fun addCustomerNote(note: String): UnifiedOrderScreen {
64+
Espresso.onView(withText(R.string.order_creation_add_customer_note)).perform(click())
6665

67-
val editNoteButton = Espresso.onView(
68-
Matchers.allOf(
69-
isDescendantOfA(withId(R.id.notes_section)),
70-
withId(R.id.edit_button)
71-
)
72-
)
73-
74-
clickOn(editNoteButton)
7566
typeTextInto(R.id.customerOrderNote_editor, note)
7667
clickOn(R.id.menu_done)
7768
return this

WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/tests/ui/OrdersUITest.kt

+1-6
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import dagger.hilt.android.testing.HiltAndroidRule
1818
import dagger.hilt.android.testing.HiltAndroidTest
1919
import org.json.JSONObject
2020
import org.junit.Before
21-
import org.junit.Ignore
2221
import org.junit.Rule
2322
import org.junit.Test
2423

@@ -48,11 +47,9 @@ class OrdersUITest : TestBase() {
4847
TabNavComponent().gotoOrdersScreen()
4948
}
5049

51-
@Ignore
5250
@Test
5351
fun e2eCreateOrderTest() {
5452
val note = "Just a placeholder text"
55-
val status = "Processing"
5653
val ordersJSONArray = MocksReader().readOrderToArray()
5754

5855
for (orderJSON in ordersJSONArray.iterator()) {
@@ -63,12 +60,10 @@ class OrdersUITest : TestBase() {
6360
OrderListScreen()
6461
.createFABTap()
6562
.assertNewOrderScreen()
66-
.updateOrderStatus(status)
63+
.addCustomerNote(note)
6764
.addProductTap()
6865
.assertProductsSelectorScreen(composeTestRule)
6966
.selectProduct(composeTestRule, orderData.productName)
70-
.editCustomerNote(note)
71-
.addShipping()
7267
.createOrder()
7368
.assertSingleOrderScreenWithProduct(orderData)
7469
.goBackToOrdersScreen()

WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/FlowExtensions.kt

+14-11
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,47 @@ package com.woocommerce.android.extensions
33
import kotlinx.coroutines.flow.Flow
44

55
@Suppress("LongParameterList")
6-
inline fun <T1, T2, T3, T4, T5, T6, T7, R> combine(
6+
inline fun <T1, T2, T3, T4, T5, T6, R> combine(
77
flow: Flow<T1>,
88
flow2: Flow<T2>,
99
flow3: Flow<T3>,
1010
flow4: Flow<T4>,
1111
flow5: Flow<T5>,
1212
flow6: Flow<T6>,
13-
flow7: Flow<T7>,
14-
crossinline transform: suspend (T1, T2, T3, T4, T5, T6, T7) -> R
13+
crossinline transform: suspend (T1, T2, T3, T4, T5, T6) -> R
1514
): Flow<R> {
16-
return kotlinx.coroutines.flow.combine(flow, flow2, flow3, flow4, flow5, flow6, flow7) { args: Array<*> ->
15+
return kotlinx.coroutines.flow.combine(
16+
flow,
17+
flow2,
18+
flow3,
19+
flow4,
20+
flow5,
21+
flow6,
22+
) { args: Array<*> ->
1723
@Suppress("UNCHECKED_CAST", "MagicNumber")
1824
transform(
1925
args[0] as T1,
2026
args[1] as T2,
2127
args[2] as T3,
2228
args[3] as T4,
2329
args[4] as T5,
24-
args[5] as T6,
25-
args[6] as T7,
30+
args[5] as T6
2631
)
2732
}
2833
}
2934

3035
@Suppress("LongParameterList")
31-
inline fun <T1, T2, T3, T4, T5, T6, T7, T8, R> combine(
36+
inline fun <T1, T2, T3, T4, T5, T6, T7, R> combine(
3237
flow: Flow<T1>,
3338
flow2: Flow<T2>,
3439
flow3: Flow<T3>,
3540
flow4: Flow<T4>,
3641
flow5: Flow<T5>,
3742
flow6: Flow<T6>,
3843
flow7: Flow<T7>,
39-
flow8: Flow<T8>,
40-
crossinline transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8) -> R
44+
crossinline transform: suspend (T1, T2, T3, T4, T5, T6, T7) -> R
4145
): Flow<R> {
42-
return kotlinx.coroutines.flow.combine(flow, flow2, flow3, flow4, flow5, flow6, flow7, flow8) { args: Array<*> ->
46+
return kotlinx.coroutines.flow.combine(flow, flow2, flow3, flow4, flow5, flow6, flow7) { args: Array<*> ->
4347
@Suppress("UNCHECKED_CAST", "MagicNumber")
4448
transform(
4549
args[0] as T1,
@@ -49,7 +53,6 @@ inline fun <T1, T2, T3, T4, T5, T6, T7, T8, R> combine(
4953
args[4] as T5,
5054
args[5] as T6,
5155
args[6] as T7,
52-
args[7] as T8,
5356
)
5457
}
5558
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubFragment.kt

+4-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ import kotlinx.coroutines.launch
2929
import java.util.Date
3030

3131
@AndroidEntryPoint
32-
class AnalyticsHubFragment :
33-
BaseFragment(R.layout.fragment_analytics) {
32+
class AnalyticsHubFragment : BaseFragment(R.layout.fragment_analytics) {
3433
companion object {
3534
const val KEY_DATE_RANGE_SELECTOR_RESULT = "key_order_status_result"
3635
const val DATE_PICKER_FRAGMENT_TAG = "DateRangePicker"
@@ -110,6 +109,9 @@ class AnalyticsHubFragment :
110109
private fun bind(view: View) {
111110
_binding = FragmentAnalyticsBinding.bind(view)
112111
binding.analyticsDateSelectorCard.setOnClickListener { viewModel.onDateRangeSelectorClick() }
112+
binding.analyticsOrdersCard.onSeeReportClickListener = { url -> viewModel.onSeeReport(url) }
113+
binding.analyticsRevenueCard.onSeeReportClickListener = { url -> viewModel.onSeeReport(url) }
114+
binding.analyticsProductsCard.onSeeReportClickListener = { url -> viewModel.onSeeReport(url) }
113115
}
114116

115117
private fun handleStateChange(viewState: AnalyticsViewState) {

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/AnalyticsHubViewModel.kt

+29-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import com.woocommerce.android.model.OrdersStat
1313
import com.woocommerce.android.model.ProductsStat
1414
import com.woocommerce.android.model.RevenueStat
1515
import com.woocommerce.android.model.SessionStat
16+
import com.woocommerce.android.tools.SelectedSite
1617
import com.woocommerce.android.ui.analytics.hub.RefreshIndicator.NotShowIndicator
1718
import com.woocommerce.android.ui.analytics.hub.RefreshIndicator.ShowIndicator
1819
import com.woocommerce.android.ui.analytics.hub.daterangeselector.AnalyticsHubDateRangeSelectorViewState
@@ -70,6 +71,8 @@ class AnalyticsHubViewModel @Inject constructor(
7071
private val feedbackRepository: FeedbackRepository,
7172
private val tracker: AnalyticsTrackerWrapper,
7273
private val dateUtils: DateUtils,
74+
private val selectedSite: SelectedSite,
75+
private val getReportUrl: GetReportUrl,
7376
savedState: SavedStateHandle
7477
) : ScopedViewModel(savedState) {
7578

@@ -132,6 +135,17 @@ class AnalyticsHubViewModel @Inject constructor(
132135
rangeSelectionState.value = selectionType.generateLocalizedSelectionData()
133136
}
134137

138+
fun onSeeReport(url: String) {
139+
selectedSite.getOrNull()?.let { site ->
140+
val event = if (site.isWpComStore) {
141+
AnalyticsViewEvent.OpenWPComWebView(url)
142+
} else {
143+
AnalyticsViewEvent.OpenUrl(url)
144+
}
145+
triggerEvent(event)
146+
} ?: triggerEvent(AnalyticsViewEvent.OpenUrl(url))
147+
}
148+
135149
fun onCustomRangeSelected(startDate: Date, endDate: Date) {
136150
rangeSelectionState.value = SelectionType.CUSTOM.generateLocalizedSelectionData(
137151
startDate = startDate,
@@ -310,7 +324,8 @@ class AnalyticsHubViewModel @Inject constructor(
310324
stats.conversionRate,
311325
null,
312326
listOf()
313-
)
327+
),
328+
reportUrl = null
314329
)
315330

316331
private fun buildRevenueDataViewState(revenueStat: RevenueStat) =
@@ -328,6 +343,10 @@ class AnalyticsHubViewModel @Inject constructor(
328343
if (revenueStat.netDelta is DeltaPercentage.Value) revenueStat.netDelta.value else null,
329344
revenueStat.netRevenueByInterval.map { it.toFloat() }
330345
),
346+
reportUrl = getReportUrl(
347+
selection = ranges,
348+
card = ReportCard.Revenue
349+
)
331350
)
332351

333352
private fun buildOrdersDataViewState(ordersStats: OrdersStat) =
@@ -352,6 +371,10 @@ class AnalyticsHubViewModel @Inject constructor(
352371
null
353372
},
354373
ordersStats.avgOrderValueByInterval.map { it.toFloat() }
374+
),
375+
reportUrl = getReportUrl(
376+
selection = ranges,
377+
card = ReportCard.Orders
355378
)
356379
)
357380

@@ -379,7 +402,11 @@ class AnalyticsHubViewModel @Inject constructor(
379402
),
380403
index != products.size - 1
381404
)
382-
}
405+
},
406+
reportUrl = getReportUrl(
407+
selection = ranges,
408+
card = ReportCard.Products
409+
)
383410
)
384411
}
385412

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.woocommerce.android.ui.analytics.hub
2+
3+
import com.woocommerce.android.extensions.adminUrlOrDefault
4+
import com.woocommerce.android.extensions.formatToYYYYmmDD
5+
import com.woocommerce.android.tools.SelectedSite
6+
import com.woocommerce.android.ui.analytics.ranges.StatsTimeRangeSelection
7+
import javax.inject.Inject
8+
9+
class GetReportUrl @Inject constructor(
10+
private val selectedSite: SelectedSite
11+
) {
12+
operator fun invoke(
13+
selection: StatsTimeRangeSelection,
14+
card: ReportCard
15+
): String? {
16+
return selectedSite.getOrNull()?.let { siteModel ->
17+
val adminURL = siteModel.adminUrlOrDefault
18+
val page = "page=wc-admin"
19+
val path = when (card) {
20+
ReportCard.Revenue -> "path=%2Fanalytics%2Frevenue"
21+
ReportCard.Orders -> "path=%2Fanalytics%2Forders"
22+
ReportCard.Products -> "path=%2Fanalytics%2Fproducts"
23+
}
24+
val period = getPeriod(selection)
25+
val compare = "compare=previous_period"
26+
"${adminURL}admin.php?$page&$path&$period&$compare"
27+
}
28+
}
29+
30+
private fun getPeriod(selection: StatsTimeRangeSelection): String {
31+
return when (selection.selectionType) {
32+
StatsTimeRangeSelection.SelectionType.TODAY -> "period=today"
33+
StatsTimeRangeSelection.SelectionType.YESTERDAY -> "period=yesterday"
34+
StatsTimeRangeSelection.SelectionType.LAST_WEEK -> "period=last_week"
35+
StatsTimeRangeSelection.SelectionType.LAST_MONTH -> "period=last_month"
36+
StatsTimeRangeSelection.SelectionType.LAST_QUARTER -> "period=last_quarter"
37+
StatsTimeRangeSelection.SelectionType.LAST_YEAR -> "period=last_year"
38+
StatsTimeRangeSelection.SelectionType.WEEK_TO_DATE -> "period=week"
39+
StatsTimeRangeSelection.SelectionType.MONTH_TO_DATE -> "period=month"
40+
StatsTimeRangeSelection.SelectionType.QUARTER_TO_DATE -> "period=quarter"
41+
StatsTimeRangeSelection.SelectionType.YEAR_TO_DATE -> "period=year"
42+
StatsTimeRangeSelection.SelectionType.CUSTOM -> {
43+
val startDate = selection.currentRange.start.formatToYYYYmmDD()
44+
val endDate = selection.currentRange.end.formatToYYYYmmDD()
45+
"period=custom&after=$startDate&before=$endDate"
46+
}
47+
}
48+
}
49+
}
50+
51+
enum class ReportCard { Revenue, Orders, Products }

0 commit comments

Comments
 (0)