Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use full date format for day dividers in timeline #3057

Merged
merged 3 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/2916.misc
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,18 @@ import kotlinx.datetime.toJavaLocalDate
import kotlinx.datetime.toJavaLocalDateTime
import java.time.Period
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import java.util.Locale
import javax.inject.Inject
import kotlin.math.absoluteValue

// TODO rework this date formatting
class DateFormatters @Inject constructor(
private val locale: Locale,
private val clock: Clock,
private val timeZone: TimeZone,
) {
private val onlyTimeFormatter: DateTimeFormatter by lazy {
val pattern = DateFormat.getBestDateTimePattern(locale, "HH:mm") ?: "HH:mm"
DateTimeFormatter.ofPattern(pattern, locale)
DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withLocale(locale)
}

private val dateWithMonthFormatter: DateTimeFormatter by lazy {
Expand All @@ -51,6 +50,10 @@ class DateFormatters @Inject constructor(
DateTimeFormatter.ofPattern(pattern, locale)
}

private val dateWithFullFormatFormatter: DateTimeFormatter by lazy {
DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(locale)
}

internal fun formatTime(localDateTime: LocalDateTime): String {
return onlyTimeFormatter.format(localDateTime.toJavaLocalDateTime())
}
Expand All @@ -63,6 +66,10 @@ class DateFormatters @Inject constructor(
return dateWithYearFormatter.format(localDateTime.toJavaLocalDateTime())
}

internal fun formatDateWithFullFormat(localDateTime: LocalDateTime): String {
return dateWithFullFormatFormatter.format(localDateTime.toJavaLocalDateTime())
}

internal fun formatDate(
dateToFormat: LocalDateTime,
currentDate: LocalDateTime,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
) : DaySeparatorFormatter {
override fun format(timestamp: Long): String {
val dateToFormat = localDateTimeProvider.providesFromTimestamp(timestamp)
return dateFormatters.formatDateWithYear(dateToFormat)
// TODO use relative formatting once iOS uses it too
return dateFormatters.formatDateWithFullFormat(dateToFormat)

Check warning on line 32 in libraries/dateformatter/impl/src/main/kotlin/io/element/android/libraries/dateformatter/impl/DefaultDaySeparatorFormatter.kt

View check run for this annotation

Codecov / codecov/patch

libraries/dateformatter/impl/src/main/kotlin/io/element/android/libraries/dateformatter/impl/DefaultDaySeparatorFormatter.kt#L32

Added line #L32 was not covered by tests
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormat
import io.element.android.libraries.dateformatter.test.FakeClock
import kotlinx.datetime.Instant
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime
import org.junit.Test
import java.util.Locale

Expand All @@ -44,31 +45,31 @@ class DefaultLastMessageTimestampFormatterTest {
val now = "1980-04-06T18:35:24.00Z"
val dat = "1980-04-06T18:35:24.00Z"
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
fun `test one second before`() {
val now = "1980-04-06T18:35:24.00Z"
val dat = "1980-04-06T18:35:23.00Z"
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
fun `test one minute before`() {
val now = "1980-04-06T18:35:24.00Z"
val dat = "1980-04-06T18:34:24.00Z"
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
fun `test one hour before`() {
val now = "1980-04-06T18:35:24.00Z"
val dat = "1980-04-06T17:35:24.00Z"
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
Expand Down Expand Up @@ -96,6 +97,15 @@ class DefaultLastMessageTimestampFormatterTest {
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.
*/
Expand Down
Loading