Skip to content

Commit b767f93

Browse files
authored
Merge branch 'trunk' into woomob-1855-create-refund
2 parents 6e9c2ed + 89b0e1e commit b767f93

File tree

53 files changed

+1501
-837
lines changed

Some content is hidden

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

53 files changed

+1501
-837
lines changed

RELEASE-NOTES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
- [*] Fixed a rare crash in the refund flow [https://github.com/woocommerce/woocommerce-android/pull/15109]
1313
- [*][Woo POS] Prepopulate orders cache after opening POS to improve performance [https://github.com/woocommerce/woocommerce-android/pull/15066]
1414
- [*][Internal] Migrated legacy Material Icons to Material Symbols [https://github.com/woocommerce/woocommerce-android/pull/15081]
15+
- [*] Fix widget sizing issues and improve refresh rate upon switching site or logging out [https://github.com/woocommerce/woocommerce-android/pull/15127]
1516
- [*] Unified transition animations across screens [https://github.com/woocommerce/woocommerce-android/pull/15128]
1617

1718
23.8

WooCommerce-Wear/src/main/java/com/woocommerce/android/app/WooCommerceWear.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import dagger.hilt.android.HiltAndroidApp
88
import org.greenrobot.eventbus.Subscribe
99
import org.greenrobot.eventbus.ThreadMode
1010
import org.wordpress.android.fluxc.persistence.WellSqlConfig
11-
import org.wordpress.android.fluxc.persistence.WellSqlConfig.Companion.ADDON_WOOCOMMERCE
1211
import org.wordpress.android.fluxc.utils.ErrorUtils.OnUnexpectedError
1312
import javax.inject.Inject
1413

@@ -20,7 +19,7 @@ open class WooCommerceWear : Application() {
2019

2120
override fun onCreate() {
2221
super.onCreate()
23-
WellSql.init(WellSqlConfig(applicationContext, ADDON_WOOCOMMERCE))
22+
WellSql.init(WellSqlConfig(applicationContext))
2423
crashLogging.get().initialize()
2524
}
2625

WooCommerce/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ dependencies {
445445

446446
implementation(libs.google.protobuf.kotlinlite)
447447

448+
testImplementation(testFixtures(project(":libs:fluxc")))
448449
testImplementation(testFixtures(project(":libs:fluxc-plugin")))
449450
testImplementation(testFixtures(project(":libs:commons")))
450451

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/appwidgets/stats/today/TodayStatsWidgetUpdater.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import android.content.ComponentName
55
import android.content.Context
66
import androidx.work.BackoffPolicy
77
import androidx.work.ExistingPeriodicWorkPolicy
8+
import androidx.work.ExistingWorkPolicy
9+
import androidx.work.OneTimeWorkRequestBuilder
810
import androidx.work.PeriodicWorkRequestBuilder
911
import androidx.work.WorkManager
1012
import androidx.work.WorkRequest
@@ -33,6 +35,23 @@ class TodayStatsWidgetUpdater @Inject constructor() : WidgetUpdater {
3335

3436
WorkManager.getInstance(context)
3537
.enqueueUniquePeriodicWork(uniqueName, ExistingPeriodicWorkPolicy.UPDATE, workRequest)
38+
39+
val immediateWorkRequest =
40+
OneTimeWorkRequestBuilder<UpdateTodayStatsWorker>()
41+
.setInputData(data)
42+
.setBackoffCriteria(
43+
BackoffPolicy.EXPONENTIAL,
44+
WorkRequest.MIN_BACKOFF_MILLIS,
45+
TimeUnit.MILLISECONDS
46+
)
47+
.build()
48+
49+
WorkManager.getInstance(context)
50+
.enqueueUniqueWork(
51+
uniqueWorkName = "$uniqueName-immediate",
52+
existingWorkPolicy = ExistingWorkPolicy.REPLACE,
53+
request = immediateWorkRequest
54+
)
3655
}
3756

3857
override fun componentName(context: Context) = ComponentName(context, TodayStatsWidgetProvider::class.java)

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/BookingMapper.kt

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import com.woocommerce.android.ui.bookings.details.AttendanceUpdateStatus
1616
import com.woocommerce.android.ui.bookings.details.CancelStatus
1717
import com.woocommerce.android.ui.bookings.list.BookingListItem
1818
import com.woocommerce.android.util.CurrencyFormatter
19+
import com.woocommerce.android.util.DateFormatter
1920
import com.woocommerce.android.util.normalizeDuration
2021
import com.woocommerce.android.util.toHumanReadableFormat
2122
import com.woocommerce.android.viewmodel.ResourceProvider
@@ -33,23 +34,17 @@ import java.time.format.FormatStyle
3334
import javax.inject.Inject
3435

3536
class BookingMapper @Inject constructor(
37+
private val dateFormatter: DateFormatter,
3638
private val currencyFormatter: CurrencyFormatter,
3739
private val getLocations: GetLocations,
3840
private val resourceProvider: ResourceProvider
3941
) {
40-
private val summaryDateFormatter: DateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(
41-
FormatStyle.MEDIUM,
42-
FormatStyle.SHORT
43-
).withZone(ZoneOffset.UTC)
44-
4542
private val detailsDateFormatter: DateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
4643
.withZone(ZoneOffset.UTC)
47-
private val timeRangeFormatter: DateTimeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
48-
.withZone(ZoneOffset.UTC)
4944

5045
fun Booking.toBookingSummaryModel(attendanceUpdateStatus: AttendanceUpdateStatus): BookingSummaryModel {
5146
return BookingSummaryModel(
52-
date = summaryDateFormatter.format(start),
47+
date = dateFormatter.formatDateTime(start),
5348
name = order.productInfo?.name ?: "-",
5449
customerName = order.customerInfo?.fullName(),
5550
status = status.toUiModel(order.status, order.paymentInfo?.paymentMethodId),
@@ -74,7 +69,7 @@ class BookingMapper @Inject constructor(
7469
.toHumanReadableFormat(resourceProvider)
7570
return BookingAppointmentDetailsModel(
7671
date = detailsDateFormatter.format(start),
77-
time = "${timeRangeFormatter.format(start)} - ${timeRangeFormatter.format(end)}",
72+
time = "${dateFormatter.formatTime(start)} - ${dateFormatter.formatTime(end)}",
7873
staff = staffMemberStatus,
7974
// TODO replace mocked values when available from API
8075
location = "238 Willow Creek Drive, Montgomery AL 36109",
@@ -147,7 +142,7 @@ class BookingMapper @Inject constructor(
147142
?: UiString.UiStringRes(R.string.customer_detail_guest_customer)
148143
val serviceName = booking.order.productInfo?.name ?: "-"
149144
val date = detailsDateFormatter.format(booking.start)
150-
val time = timeRangeFormatter.format(booking.start)
145+
val time = dateFormatter.formatTime(booking.start)
151146
return UiString.UiStringRes(
152147
R.string.booking_cancel_dialog_message_v2,
153148
listOf(

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/filter/datetime/DateTimeFilterViewModel.kt

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.woocommerce.android.R
77
import com.woocommerce.android.ui.bookings.filter.datetime.PickerDialogState.DateDialog
88
import com.woocommerce.android.ui.bookings.filter.datetime.PickerDialogState.TimeDialog
99
import com.woocommerce.android.ui.compose.component.Time
10+
import com.woocommerce.android.util.DateFormatter
1011
import com.woocommerce.android.viewmodel.MultiLiveEvent
1112
import com.woocommerce.android.viewmodel.ScopedViewModel
1213
import dagger.assisted.Assisted
@@ -22,22 +23,18 @@ import java.time.LocalDateTime
2223
import java.time.LocalTime
2324
import java.time.ZoneId
2425
import java.time.ZoneOffset
25-
import java.time.format.DateTimeFormatter
26-
import java.time.format.FormatStyle
2726

2827
@HiltViewModel(assistedFactory = DateTimeFilterViewModel.Factory::class)
2928
class DateTimeFilterViewModel @AssistedInject constructor(
3029
savedStateHandle: SavedStateHandle,
3130
private val clock: Clock,
31+
private val dateFormatter: DateFormatter,
3232
@Assisted private val initialRange: BookingsFilterOption.DateRange? = null,
3333
@Assisted private val onTypeFilterChanged: (BookingsFilterOption.DateRange) -> Unit,
3434
) : ScopedViewModel(savedStateHandle) {
3535

3636
private val zone: ZoneId = ZoneOffset.UTC
3737

38-
private val dateFormatter: DateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
39-
private val timeFormatter: DateTimeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
40-
4138
private val _uiState = MutableStateFlow(
4239
DateTimeFilterUiState(
4340
onDateClick = { openDateDialog(it) },
@@ -255,8 +252,8 @@ class DateTimeFilterViewModel @AssistedInject constructor(
255252
)
256253
}
257254

258-
private fun LocalDateTime?.formatDate(): String = this?.let { dateFormatter.format(it) }.orEmpty()
259-
private fun LocalDateTime?.formatTime(): String = this?.let { timeFormatter.format(it) }.orEmpty()
255+
private fun LocalDateTime?.formatDate(): String = this?.let { dateFormatter.formatDate(it) }.orEmpty()
256+
private fun LocalDateTime?.formatTime(): String = this?.let { dateFormatter.formatTime(it) }.orEmpty()
260257

261258
@AssistedFactory
262259
interface Factory {

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/prefs/plugins/PluginsViewModel.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ class PluginsViewModel @Inject constructor(
5252
_viewState.emit(
5353
Loaded(
5454
plugins = response.model!!
55-
.filter { it.version.isNotNullOrEmpty() && it.name.isNotNullOrEmpty() }
56-
.map {
55+
.filter { pluginDto: SystemPluginModel ->
56+
pluginDto.version.isNotNullOrEmpty() && pluginDto.name.isNotNullOrEmpty()
57+
}.map {
5758
Plugin(
5859
name = StringEscapeUtils.unescapeHtml4(it.name),
5960
authorName = StringEscapeUtils.unescapeHtml4(it.authorName),
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.woocommerce.android.util
2+
3+
import android.content.Context
4+
import android.text.format.DateFormat
5+
import dagger.hilt.android.qualifiers.ApplicationContext
6+
import java.time.Instant
7+
import java.time.LocalDateTime
8+
import java.time.ZoneOffset
9+
import java.time.format.DateTimeFormatter
10+
import java.time.format.FormatStyle
11+
import java.util.Locale
12+
import javax.inject.Inject
13+
14+
class DateFormatter @Inject constructor(@ApplicationContext private val context: Context) {
15+
16+
/**
17+
* Formats date and time respecting system 12h/24h preference.
18+
* Example: "Dec 12, 2025, 10:47 PM" or "Dec 12, 2025, 22:47"
19+
*/
20+
fun formatDateTime(
21+
instant: Instant
22+
): String = createSkeletonFormatter(skeleton = "MMMdyyyyhm", skeleton24h = "MMMdyyyyHm").format(instant)
23+
24+
/**
25+
* Formats time only respecting system 12h/24h preference.
26+
* Example: "10:47 PM" or "22:47"
27+
*/
28+
fun formatTime(instant: Instant): String = getTimeFormatter().format(instant)
29+
30+
/**
31+
* Formats date only using localized medium style.
32+
* Example: "Dec 12, 2025"
33+
*/
34+
fun formatDate(
35+
localDateTime: LocalDateTime
36+
): String = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).format(localDateTime)
37+
38+
/**
39+
* Formats time only respecting system 12h/24h preference.
40+
* Example: "10:47 PM" or "22:47"
41+
*/
42+
fun formatTime(localDateTime: LocalDateTime): String = getTimeFormatter().format(localDateTime)
43+
44+
private fun createSkeletonFormatter(skeleton: String, skeleton24h: String? = null): DateTimeFormatter {
45+
val isSystem24h = DateFormat.is24HourFormat(context)
46+
47+
val finalSkeleton = if (isSystem24h && skeleton24h != null) skeleton24h else skeleton
48+
49+
val bestPattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), finalSkeleton)
50+
51+
return DateTimeFormatter.ofPattern(bestPattern, Locale.getDefault()).withZone(ZoneOffset.UTC)
52+
}
53+
54+
private fun getTimeFormatter() = createSkeletonFormatter(skeleton = "hm", skeleton24h = "Hm")
55+
}

0 commit comments

Comments
 (0)