Use full date format for day dividers in timeline (#3057)
* Use full date format for day dividers in timeline * Use AM/PM for `DefaultLastMessageTimestampFormatter` when the locale needs it
This commit is contained in:
parent
c9dc5c5d97
commit
edd61e96c2
4 changed files with 27 additions and 8 deletions
1
changelog.d/2916.misc
Normal file
1
changelog.d/2916.misc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Use a more natural date format for day dividers in the timeline. Also improve the time format for last messages in the room list.
|
||||||
|
|
@ -26,19 +26,18 @@ import kotlinx.datetime.toJavaLocalDate
|
||||||
import kotlinx.datetime.toJavaLocalDateTime
|
import kotlinx.datetime.toJavaLocalDateTime
|
||||||
import java.time.Period
|
import java.time.Period
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
|
import java.time.format.FormatStyle
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
// TODO rework this date formatting
|
|
||||||
class DateFormatters @Inject constructor(
|
class DateFormatters @Inject constructor(
|
||||||
private val locale: Locale,
|
private val locale: Locale,
|
||||||
private val clock: Clock,
|
private val clock: Clock,
|
||||||
private val timeZone: TimeZone,
|
private val timeZone: TimeZone,
|
||||||
) {
|
) {
|
||||||
private val onlyTimeFormatter: DateTimeFormatter by lazy {
|
private val onlyTimeFormatter: DateTimeFormatter by lazy {
|
||||||
val pattern = DateFormat.getBestDateTimePattern(locale, "HH:mm") ?: "HH:mm"
|
DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withLocale(locale)
|
||||||
DateTimeFormatter.ofPattern(pattern, locale)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val dateWithMonthFormatter: DateTimeFormatter by lazy {
|
private val dateWithMonthFormatter: DateTimeFormatter by lazy {
|
||||||
|
|
@ -51,6 +50,10 @@ class DateFormatters @Inject constructor(
|
||||||
DateTimeFormatter.ofPattern(pattern, locale)
|
DateTimeFormatter.ofPattern(pattern, locale)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val dateWithFullFormatFormatter: DateTimeFormatter by lazy {
|
||||||
|
DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(locale)
|
||||||
|
}
|
||||||
|
|
||||||
internal fun formatTime(localDateTime: LocalDateTime): String {
|
internal fun formatTime(localDateTime: LocalDateTime): String {
|
||||||
return onlyTimeFormatter.format(localDateTime.toJavaLocalDateTime())
|
return onlyTimeFormatter.format(localDateTime.toJavaLocalDateTime())
|
||||||
}
|
}
|
||||||
|
|
@ -63,6 +66,10 @@ class DateFormatters @Inject constructor(
|
||||||
return dateWithYearFormatter.format(localDateTime.toJavaLocalDateTime())
|
return dateWithYearFormatter.format(localDateTime.toJavaLocalDateTime())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun formatDateWithFullFormat(localDateTime: LocalDateTime): String {
|
||||||
|
return dateWithFullFormatFormatter.format(localDateTime.toJavaLocalDateTime())
|
||||||
|
}
|
||||||
|
|
||||||
internal fun formatDate(
|
internal fun formatDate(
|
||||||
dateToFormat: LocalDateTime,
|
dateToFormat: LocalDateTime,
|
||||||
currentDate: LocalDateTime,
|
currentDate: LocalDateTime,
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ class DefaultDaySeparatorFormatter @Inject constructor(
|
||||||
) : DaySeparatorFormatter {
|
) : DaySeparatorFormatter {
|
||||||
override fun format(timestamp: Long): String {
|
override fun format(timestamp: Long): String {
|
||||||
val dateToFormat = localDateTimeProvider.providesFromTimestamp(timestamp)
|
val dateToFormat = localDateTimeProvider.providesFromTimestamp(timestamp)
|
||||||
return dateFormatters.formatDateWithYear(dateToFormat)
|
// TODO use relative formatting once iOS uses it too
|
||||||
|
return dateFormatters.formatDateWithFullFormat(dateToFormat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormat
|
||||||
import io.element.android.libraries.dateformatter.test.FakeClock
|
import io.element.android.libraries.dateformatter.test.FakeClock
|
||||||
import kotlinx.datetime.Instant
|
import kotlinx.datetime.Instant
|
||||||
import kotlinx.datetime.TimeZone
|
import kotlinx.datetime.TimeZone
|
||||||
|
import kotlinx.datetime.toLocalDateTime
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
|
|
@ -44,7 +45,7 @@ class DefaultLastMessageTimestampFormatterTest {
|
||||||
val now = "1980-04-06T18:35:24.00Z"
|
val now = "1980-04-06T18:35:24.00Z"
|
||||||
val dat = "1980-04-06T18:35:24.00Z"
|
val dat = "1980-04-06T18:35:24.00Z"
|
||||||
val formatter = createFormatter(now)
|
val formatter = createFormatter(now)
|
||||||
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("18:35")
|
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("6:35 PM")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -52,7 +53,7 @@ class DefaultLastMessageTimestampFormatterTest {
|
||||||
val now = "1980-04-06T18:35:24.00Z"
|
val now = "1980-04-06T18:35:24.00Z"
|
||||||
val dat = "1980-04-06T18:35:23.00Z"
|
val dat = "1980-04-06T18:35:23.00Z"
|
||||||
val formatter = createFormatter(now)
|
val formatter = createFormatter(now)
|
||||||
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("18:35")
|
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("6:35 PM")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -60,7 +61,7 @@ class DefaultLastMessageTimestampFormatterTest {
|
||||||
val now = "1980-04-06T18:35:24.00Z"
|
val now = "1980-04-06T18:35:24.00Z"
|
||||||
val dat = "1980-04-06T18:34:24.00Z"
|
val dat = "1980-04-06T18:34:24.00Z"
|
||||||
val formatter = createFormatter(now)
|
val formatter = createFormatter(now)
|
||||||
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("18:34")
|
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("6:34 PM")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -68,7 +69,7 @@ class DefaultLastMessageTimestampFormatterTest {
|
||||||
val now = "1980-04-06T18:35:24.00Z"
|
val now = "1980-04-06T18:35:24.00Z"
|
||||||
val dat = "1980-04-06T17:35:24.00Z"
|
val dat = "1980-04-06T17:35:24.00Z"
|
||||||
val formatter = createFormatter(now)
|
val formatter = createFormatter(now)
|
||||||
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("17:35")
|
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("5:35 PM")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -96,6 +97,15 @@ class DefaultLastMessageTimestampFormatterTest {
|
||||||
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("06.04.1979")
|
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("06.04.1979")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test full format`() {
|
||||||
|
val now = "1980-04-06T18:35:24.00Z"
|
||||||
|
val dat = "1979-04-06T18:35:24.00Z"
|
||||||
|
val clock = FakeClock().apply { givenInstant(Instant.parse(now)) }
|
||||||
|
val dateFormatters = DateFormatters(Locale.US, clock, TimeZone.UTC)
|
||||||
|
assertThat(dateFormatters.formatDateWithFullFormat(Instant.parse(dat).toLocalDateTime(TimeZone.UTC))).isEqualTo("Friday, April 6, 1979")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create DefaultLastMessageFormatter and set current time to the provided date.
|
* Create DefaultLastMessageFormatter and set current time to the provided date.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue