From 73ab32fd92506ae2da2f84c34c75a24f3e1a1a0c Mon Sep 17 00:00:00 2001
From: ganfra <francoisg@matrix.org>
Date: Fri, 28 Aug 2020 20:01:10 +0200
Subject: [PATCH] Start reworking date formatting

---
 .../core/date/AbbrevDateFormatterProvider.kt  | 33 ++++++++
 .../app/core/date/DateFormatterProvider.kt    | 27 ++++++
 .../app/core/date/DateFormatterProviders.kt   | 31 +++++++
 .../core/date/DefaultDateFormatterProvider.kt | 37 ++++++++
 .../app/core/date/VectorDateFormatter.kt      | 84 +++++++++++++++++--
 .../vector/app/core/resources/DateProvider.kt |  9 ++
 .../timeline/TimelineEventController.kt       | 11 ++-
 .../timeline/action/MessageActionState.kt     |  5 +-
 .../action/MessageActionsEpoxyController.kt   |  9 +-
 .../ViewEditHistoryEpoxyController.kt         |  2 +-
 .../reactions/ViewReactionsViewModel.kt       |  4 +-
 .../home/room/list/RoomSummaryItemFactory.kt  | 19 ++---
 .../media/DataAttachmentRoomProvider.kt       |  2 +-
 .../media/RoomEventsAttachmentProvider.kt     |  2 +-
 .../uploads/files/UploadsFileController.kt    |  2 +-
 .../GossipingEventsEpoxyController.kt         |  2 +-
 16 files changed, 243 insertions(+), 36 deletions(-)
 create mode 100644 vector/src/main/java/im/vector/app/core/date/AbbrevDateFormatterProvider.kt
 create mode 100644 vector/src/main/java/im/vector/app/core/date/DateFormatterProvider.kt
 create mode 100644 vector/src/main/java/im/vector/app/core/date/DateFormatterProviders.kt
 create mode 100644 vector/src/main/java/im/vector/app/core/date/DefaultDateFormatterProvider.kt

diff --git a/vector/src/main/java/im/vector/app/core/date/AbbrevDateFormatterProvider.kt b/vector/src/main/java/im/vector/app/core/date/AbbrevDateFormatterProvider.kt
new file mode 100644
index 0000000000..5108591344
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/date/AbbrevDateFormatterProvider.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.date
+
+import android.text.format.DateFormat
+import im.vector.app.core.resources.LocaleProvider
+import org.threeten.bp.format.DateTimeFormatter
+import javax.inject.Inject
+
+class AbbrevDateFormatterProvider @Inject constructor(private val localeProvider: LocaleProvider) : DateFormatterProvider {
+
+    override val dateWithMonthFormatter: DateTimeFormatter by lazy {
+        DateTimeFormatter.ofPattern("d MMM", localeProvider.current())
+    }
+
+    override val dateWithYearFormatter: DateTimeFormatter by lazy {
+        DateTimeFormatter.ofPattern("dd.MM.yyyy",localeProvider.current())
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/core/date/DateFormatterProvider.kt b/vector/src/main/java/im/vector/app/core/date/DateFormatterProvider.kt
new file mode 100644
index 0000000000..0ca2eed2a6
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/date/DateFormatterProvider.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.date
+
+import org.threeten.bp.format.DateTimeFormatter
+
+interface DateFormatterProvider {
+
+    val dateWithMonthFormatter: DateTimeFormatter
+
+    val dateWithYearFormatter: DateTimeFormatter
+}
+
diff --git a/vector/src/main/java/im/vector/app/core/date/DateFormatterProviders.kt b/vector/src/main/java/im/vector/app/core/date/DateFormatterProviders.kt
new file mode 100644
index 0000000000..a216b6b5d8
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/date/DateFormatterProviders.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.date
+
+import javax.inject.Inject
+
+class DateFormatterProviders @Inject constructor(private val defaultDateFormatterProvider: DefaultDateFormatterProvider,
+                                                 private val abbrevDateFormatterProvider: AbbrevDateFormatterProvider) {
+
+    fun provide(abbrev: Boolean): DateFormatterProvider {
+        return if (abbrev) {
+            abbrevDateFormatterProvider
+        } else {
+            defaultDateFormatterProvider
+        }
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/core/date/DefaultDateFormatterProvider.kt b/vector/src/main/java/im/vector/app/core/date/DefaultDateFormatterProvider.kt
new file mode 100644
index 0000000000..7a0f671887
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/date/DefaultDateFormatterProvider.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.date
+
+import android.content.Context
+import android.text.format.DateFormat
+import im.vector.app.core.resources.LocaleProvider
+import org.threeten.bp.format.DateTimeFormatter
+import javax.inject.Inject
+
+class DefaultDateFormatterProvider @Inject constructor(private val context: Context,
+                                                       private val localeProvider: LocaleProvider)
+    : DateFormatterProvider {
+
+    override val dateWithMonthFormatter: DateTimeFormatter by lazy {
+        DateTimeFormatter.ofPattern(DateFormat.getBestDateTimePattern(localeProvider.current(), "d MMMMM"))
+    }
+
+    override val dateWithYearFormatter: DateTimeFormatter by lazy {
+        DateTimeFormatter.ofPattern(DateFormat.getBestDateTimePattern(localeProvider.current(), "d MMM y"))
+    }
+
+}
diff --git a/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt b/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt
index 02050b0a56..8b0de26a28 100644
--- a/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt
+++ b/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt
@@ -19,8 +19,11 @@ package im.vector.app.core.date
 import android.content.Context
 import android.text.format.DateFormat
 import android.text.format.DateUtils
+import im.vector.app.core.resources.DateProvider
 import im.vector.app.core.resources.LocaleProvider
+import im.vector.app.core.resources.toTimestamp
 import org.threeten.bp.LocalDateTime
+import org.threeten.bp.Period
 import org.threeten.bp.format.DateTimeFormatter
 import java.util.Calendar
 import java.util.Date
@@ -41,22 +44,77 @@ fun startOfDay(time: Long): Long {
 }
 
 class VectorDateFormatter @Inject constructor(private val context: Context,
-                                              private val localeProvider: LocaleProvider) {
+                                              private val localeProvider: LocaleProvider,
+                                              private val dateFormatterProviders: DateFormatterProviders) {
 
-    private val messageHourFormatter by lazy {
-        DateTimeFormatter.ofPattern("H:mm", localeProvider.current())
+    private val hourFormatter by lazy {
+        if (DateFormat.is24HourFormat(context)) {
+            DateTimeFormatter.ofPattern("H:mm", localeProvider.current())
+        } else {
+            DateTimeFormatter.ofPattern("h:mm a", localeProvider.current())
+        }
     }
 
-    private val messageDayFormatter by lazy {
-        DateTimeFormatter.ofPattern(DateFormat.getBestDateTimePattern(localeProvider.current(), "EEE d MMM"))
+    private val dayFormatter by lazy {
+        DateTimeFormatter.ofPattern("EEE", localeProvider.current())
+    }
+
+    private val fullDateFormatter by lazy {
+        if (DateFormat.is24HourFormat(context)) {
+            DateTimeFormatter.ofPattern("EEE, d MMM yyyy H:mm", localeProvider.current())
+        } else {
+            DateTimeFormatter.ofPattern("EEE, d MMM yyyy h:mm a", localeProvider.current())
+        }
     }
 
     fun formatMessageHour(localDateTime: LocalDateTime): String {
-        return messageHourFormatter.format(localDateTime)
+        return hourFormatter.format(localDateTime)
     }
 
     fun formatMessageDay(localDateTime: LocalDateTime): String {
-        return messageDayFormatter.format(localDateTime)
+        return dayFormatter.format(localDateTime)
+    }
+
+    fun formatMessageDayWithMonth(localDateTime: LocalDateTime, abbrev: Boolean = false): String {
+        return dateFormatterProviders.provide(abbrev).dateWithMonthFormatter.format(localDateTime)
+    }
+
+    fun formatMessageDayWithYear(localDateTime: LocalDateTime, abbrev: Boolean = false): String {
+        return dateFormatterProviders.provide(abbrev).dateWithYearFormatter.format(localDateTime)
+    }
+
+    fun formatMessageDate(
+            date: LocalDateTime?,
+            showFullDate: Boolean = false,
+            onlyTimeIfSameDay: Boolean = false,
+            useRelative: Boolean = false,
+            alwaysShowYear: Boolean = false,
+            abbrev: Boolean = false
+    ): String {
+        if (date == null) {
+            return ""
+        }
+        if (showFullDate) {
+            return fullDateFormatter.format(date)
+        }
+        val currentDate = DateProvider.currentLocalDateTime()
+        val isSameDay = date.toLocalDate() == currentDate.toLocalDate()
+        return if (onlyTimeIfSameDay && isSameDay) {
+            formatMessageHour(date)
+        } else {
+            val period = Period.between(date.toLocalDate(), currentDate.toLocalDate())
+            if (period.years >= 1 || alwaysShowYear) {
+                formatMessageDayWithYear(date, abbrev)
+            } else if (period.months >= 1) {
+                formatMessageDayWithMonth(date, abbrev)
+            } else if (useRelative && period.days < 2) {
+                getRelativeDay(date.toTimestamp())
+            } else if (useRelative && period.days < 7) {
+                formatMessageDay(date)
+            } else {
+                formatMessageDayWithMonth(date, abbrev)
+            }
+        }
     }
 
     /**
@@ -71,12 +129,22 @@ class VectorDateFormatter @Inject constructor(private val context: Context,
             return ""
         }
         val now = System.currentTimeMillis()
+        var flags = DateUtils.FORMAT_SHOW_WEEKDAY
+
         return DateUtils.getRelativeDateTimeString(
                 context,
                 time,
                 DateUtils.DAY_IN_MILLIS,
                 now - startOfDay(now - 2 * DateUtils.DAY_IN_MILLIS),
-                DateUtils.FORMAT_SHOW_WEEKDAY or DateUtils.FORMAT_SHOW_TIME
+                flags
         ).toString()
     }
+
+    private fun getRelativeDay(ts: Long): String {
+        return DateUtils.getRelativeTimeSpanString(
+                ts,
+                System.currentTimeMillis(),
+                DateUtils.DAY_IN_MILLIS,
+                DateUtils.FORMAT_SHOW_WEEKDAY).toString()
+    }
 }
diff --git a/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt b/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt
index 5769b04d29..443a214259 100644
--- a/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt
+++ b/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt
@@ -19,10 +19,12 @@ package im.vector.app.core.resources
 import org.threeten.bp.Instant
 import org.threeten.bp.LocalDateTime
 import org.threeten.bp.ZoneId
+import org.threeten.bp.ZoneOffset
 
 object DateProvider {
 
     private val zoneId = ZoneId.systemDefault()
+    private val zoneOffset = ZoneOffset.UTC
 
     fun toLocalDateTime(timestamp: Long?): LocalDateTime {
         val instant = Instant.ofEpochMilli(timestamp ?: 0)
@@ -33,4 +35,11 @@ object DateProvider {
         val instant = Instant.now()
         return LocalDateTime.ofInstant(instant, zoneId)
     }
+
+    fun toTimestamp(localDateTime: LocalDateTime): Long {
+        return localDateTime.toInstant(zoneOffset).toEpochMilli()
+    }
 }
+
+fun LocalDateTime.toTimestamp(): Long = DateProvider.toTimestamp(this)
+
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt
index 0bf2876288..c946bec074 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt
@@ -29,6 +29,7 @@ import im.vector.app.core.date.VectorDateFormatter
 import im.vector.app.core.epoxy.LoadingItem_
 import im.vector.app.core.extensions.localDateTime
 import im.vector.app.core.extensions.nextOrNull
+import im.vector.app.core.resources.DateProvider
 import im.vector.app.features.home.room.detail.RoomDetailAction
 import im.vector.app.features.home.room.detail.RoomDetailViewState
 import im.vector.app.features.home.room.detail.UnreadState
@@ -53,7 +54,6 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageImageInfoCon
 import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
 import org.matrix.android.sdk.api.session.room.timeline.Timeline
 import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
-import org.threeten.bp.LocalDateTime
 import javax.inject.Inject
 
 class TimelineEventController @Inject constructor(private val dateFormatter: VectorDateFormatter,
@@ -333,13 +333,16 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
         ) {
             requestModelBuild()
         }
-        val daySeparatorItem = buildDaySeparatorItem(addDaySeparator, date)
+        val daySeparatorItem = buildDaySeparatorItem(addDaySeparator, event.root.originServerTs)
         return CacheItemData(event.localId, event.root.eventId, eventModel, mergedHeaderModel, daySeparatorItem)
     }
 
-    private fun buildDaySeparatorItem(addDaySeparator: Boolean, date: LocalDateTime): DaySeparatorItem? {
+    private fun buildDaySeparatorItem(addDaySeparator: Boolean, originServerTs: Long?): DaySeparatorItem? {
         return if (addDaySeparator) {
-            val formattedDay = dateFormatter.formatMessageDay(date)
+            val formattedDay = dateFormatter.formatMessageDate(
+                    date = DateProvider.toLocalDateTime(originServerTs),
+                    alwaysShowYear = true
+            )
             DaySeparatorItem_().formattedDay(formattedDay).id(formattedDay)
         } else {
             null
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt
index b1c324e12b..587400700d 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt
@@ -23,6 +23,7 @@ import im.vector.app.core.extensions.canReact
 import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData
 import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
 import java.text.SimpleDateFormat
+import java.time.LocalDateTime
 import java.util.Date
 import java.util.Locale
 
@@ -56,11 +57,7 @@ data class MessageActionState(
 
     constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId, informationData = args.informationData)
 
-    private val dateFormat = SimpleDateFormat("EEE, d MMM yyyy HH:mm", Locale.getDefault())
-
     fun senderName(): String = informationData.memberName?.toString() ?: ""
 
-    fun time(): String? = timelineEvent()?.root?.originServerTs?.let { dateFormat.format(Date(it)) } ?: ""
-
     fun canReact() = timelineEvent()?.canReact() == true && actionPermissions.canReact
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt
index f4287eb3a4..48ed73d980 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt
@@ -20,12 +20,14 @@ import com.airbnb.epoxy.TypedEpoxyController
 import com.airbnb.mvrx.Success
 import im.vector.app.EmojiCompatFontProvider
 import im.vector.app.R
+import im.vector.app.core.date.VectorDateFormatter
 import im.vector.app.core.epoxy.bottomsheet.BottomSheetQuickReactionsItem
 import im.vector.app.core.epoxy.bottomsheet.bottomSheetActionItem
 import im.vector.app.core.epoxy.bottomsheet.bottomSheetMessagePreviewItem
 import im.vector.app.core.epoxy.bottomsheet.bottomSheetQuickReactionsItem
 import im.vector.app.core.epoxy.bottomsheet.bottomSheetSendStateItem
 import im.vector.app.core.epoxy.dividerItem
+import im.vector.app.core.extensions.localDateTime
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.features.home.AvatarRenderer
 import im.vector.app.features.home.room.detail.timeline.TimelineEventController
@@ -40,13 +42,16 @@ import javax.inject.Inject
 class MessageActionsEpoxyController @Inject constructor(
         private val stringProvider: StringProvider,
         private val avatarRenderer: AvatarRenderer,
-        private val fontProvider: EmojiCompatFontProvider
+        private val fontProvider: EmojiCompatFontProvider,
+        private val dateFormatter: VectorDateFormatter
 ) : TypedEpoxyController<MessageActionState>() {
 
     var listener: MessageActionsEpoxyControllerListener? = null
 
     override fun buildModels(state: MessageActionState) {
         // Message preview
+        val date = state.timelineEvent()?.root?.localDateTime()
+        val formattedDate = dateFormatter.formatMessageDate(date, showFullDate = true)
         bottomSheetMessagePreviewItem {
             id("preview")
             avatarRenderer(avatarRenderer)
@@ -54,7 +59,7 @@ class MessageActionsEpoxyController @Inject constructor(
             movementMethod(createLinkMovementMethod(listener))
             userClicked { listener?.didSelectMenuAction(EventSharedAction.OpenUserProfile(state.informationData.senderId)) }
             body(state.messageBody.linkify(listener))
-            time(state.time())
+            time(formattedDate)
         }
 
         // Send state
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt
index deb9b64500..3db02adc0a 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt
@@ -83,7 +83,7 @@ class ViewEditHistoryEpoxyController(private val context: Context,
                 if (lastDate?.get(Calendar.DAY_OF_YEAR) != evDate.get(Calendar.DAY_OF_YEAR)) {
                     // need to display header with day
                     val dateString = if (DateUtils.isToday(evDate.timeInMillis)) context.getString(R.string.today)
-                    else dateFormatter.formatMessageDay(timelineEvent.localDateTime())
+                    else dateFormatter.formatMessageDayWithMonth(timelineEvent.localDateTime())
                     genericItemHeader {
                         id(evDate.hashCode())
                         text(dateString)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt
index 0484481019..29032ee5fa 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt
@@ -29,12 +29,12 @@ import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.home.room.detail.timeline.action.TimelineEventFragmentArgs
+import io.reactivex.Observable
+import io.reactivex.Single
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.room.model.ReactionAggregatedSummary
 import org.matrix.android.sdk.rx.RxRoom
 import org.matrix.android.sdk.rx.unwrap
-import io.reactivex.Observable
-import io.reactivex.Single
 
 data class DisplayReactionsViewState(
         val eventId: String,
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt
index da58748dea..19561280a6 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt
@@ -21,7 +21,6 @@ import im.vector.app.R
 import im.vector.app.core.date.VectorDateFormatter
 import im.vector.app.core.epoxy.VectorEpoxyModel
 import im.vector.app.core.extensions.localDateTime
-import im.vector.app.core.resources.DateProvider
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.core.utils.DebouncedClickListener
 import im.vector.app.features.home.AvatarRenderer
@@ -53,8 +52,8 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
     }
 
     private fun createInvitationItem(roomSummary: RoomSummary,
-                             changeMembershipState: ChangeMembershipState,
-                             listener: RoomSummaryController.Listener?): VectorEpoxyModel<*> {
+                                     changeMembershipState: ChangeMembershipState,
+                                     listener: RoomSummaryController.Listener?): VectorEpoxyModel<*> {
         val secondLine = if (roomSummary.isDirect) {
             roomSummary.inviterId
         } else {
@@ -87,15 +86,13 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
         var latestEventTime: CharSequence = ""
         val latestEvent = roomSummary.latestPreviewableEvent
         if (latestEvent != null) {
-            val date = latestEvent.root.localDateTime()
-            val currentDate = DateProvider.currentLocalDateTime()
-            val isSameDay = date.toLocalDate() == currentDate.toLocalDate()
             latestFormattedEvent = displayableEventFormatter.format(latestEvent, roomSummary.isDirect.not())
-            latestEventTime = if (isSameDay) {
-                dateFormatter.formatMessageHour(date)
-            } else {
-                dateFormatter.formatMessageDay(date)
-            }
+            latestEventTime = dateFormatter.formatMessageDate(
+                    date = latestEvent.root.localDateTime(),
+                    useRelative = true,
+                    onlyTimeIfSameDay = true,
+                    abbrev = true
+            )
         }
         val typingMessage = typingHelper.getTypingMessage(roomSummary.typingUsers)
         return RoomSummaryItem_()
diff --git a/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt b/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt
index daa8bbc206..76305cb6bb 100644
--- a/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt
+++ b/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt
@@ -79,7 +79,7 @@ class DataAttachmentRoomProvider(
         val timeLineEvent = room?.getTimeLineEvent(item.eventId)
         if (timeLineEvent != null) {
             val dateString = timeLineEvent.root.localDateTime().let {
-                "${dateFormatter.formatMessageDay(it)} at ${dateFormatter.formatMessageHour(it)} "
+                "${dateFormatter.formatMessageDayWithMonth(it)} at ${dateFormatter.formatMessageHour(it)} "
             }
             overlayView?.updateWith("${position + 1} of ${attachments.size}", "${timeLineEvent.senderInfo.displayName} $dateString")
             overlayView?.videoControlsGroup?.isVisible = timeLineEvent.root.isVideoMessage()
diff --git a/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt b/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt
index e5f0f481bf..c06dd261e2 100644
--- a/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt
+++ b/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt
@@ -129,7 +129,7 @@ class RoomEventsAttachmentProvider(
         super.overlayViewAtPosition(context, position)
         val item = attachments[position]
         val dateString = item.root.localDateTime().let {
-            "${dateFormatter.formatMessageDay(it)} at ${dateFormatter.formatMessageHour(it)} "
+            "${dateFormatter.formatMessageDayWithMonth(it)} at ${dateFormatter.formatMessageHour(it)} "
         }
         overlayView?.updateWith("${position + 1} of ${attachments.size}", "${item.senderInfo.displayName} $dateString")
         overlayView?.videoControlsGroup?.isVisible = item.root.isVideoMessage()
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/UploadsFileController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/UploadsFileController.kt
index 46ab4f5986..37b93ea902 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/UploadsFileController.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/UploadsFileController.kt
@@ -18,12 +18,12 @@ package im.vector.app.features.roomprofile.uploads.files
 
 import com.airbnb.epoxy.TypedEpoxyController
 import com.airbnb.epoxy.VisibilityState
-import org.matrix.android.sdk.api.session.room.uploads.UploadEvent
 import im.vector.app.R
 import im.vector.app.core.date.VectorDateFormatter
 import im.vector.app.core.epoxy.loadingItem
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.features.roomprofile.uploads.RoomUploadsViewState
+import org.matrix.android.sdk.api.session.room.uploads.UploadEvent
 import javax.inject.Inject
 
 class UploadsFileController @Inject constructor(
diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsEpoxyController.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsEpoxyController.kt
index 2acfff2463..69910bb100 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsEpoxyController.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsEpoxyController.kt
@@ -94,7 +94,7 @@ class GossipingEventsEpoxyController @Inject constructor(
                         )
                         description(
                                 span {
-                                    +vectorDateFormatter.formatMessageDay(DateProvider.toLocalDateTime(event.ageLocalTs))
+                                    +vectorDateFormatter.formatMessageDayWithMonth(DateProvider.toLocalDateTime(event.ageLocalTs))
                                     +" ${vectorDateFormatter.formatMessageHour(DateProvider.toLocalDateTime(event.ageLocalTs))}"
                                     span("\nfrom: ") {
                                         textStyle = "bold"