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 index 5108591344..e516be7e57 100644 --- a/vector/src/main/java/im/vector/app/core/date/AbbrevDateFormatterProvider.kt +++ b/vector/src/main/java/im/vector/app/core/date/AbbrevDateFormatterProvider.kt @@ -24,10 +24,12 @@ 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()) + val pattern = DateFormat.getBestDateTimePattern(localeProvider.current(), "d MMM") + DateTimeFormatter.ofPattern(pattern, localeProvider.current()) } override val dateWithYearFormatter: DateTimeFormatter by lazy { - DateTimeFormatter.ofPattern("dd.MM.yyyy",localeProvider.current()) + val pattern = DateFormat.getBestDateTimePattern(localeProvider.current(), "dd.MM.yyyy") + DateTimeFormatter.ofPattern(pattern, localeProvider.current()) } } diff --git a/vector/src/main/java/im/vector/app/core/date/DateFormatKind.kt b/vector/src/main/java/im/vector/app/core/date/DateFormatKind.kt new file mode 100644 index 0000000000..3828b13089 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/date/DateFormatKind.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 + +enum class DateFormatKind { + DEFAULT_DATE_AND_TIME, + ROOM_LIST, + TIMELINE_DAY_DIVIDER, + MESSAGE_DETAIL, + MESSAGE_SIMPLE, + EDIT_HISTORY_ROW, + EDIT_HISTORY_HEADER +} 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 index 7a0f671887..c8736f3ab1 100644 --- a/vector/src/main/java/im/vector/app/core/date/DefaultDateFormatterProvider.kt +++ b/vector/src/main/java/im/vector/app/core/date/DefaultDateFormatterProvider.kt @@ -27,11 +27,12 @@ class DefaultDateFormatterProvider @Inject constructor(private val context: Cont : DateFormatterProvider { override val dateWithMonthFormatter: DateTimeFormatter by lazy { - DateTimeFormatter.ofPattern(DateFormat.getBestDateTimePattern(localeProvider.current(), "d MMMMM")) + val pattern = DateFormat.getBestDateTimePattern(localeProvider.current(), "d MMMMM") + DateTimeFormatter.ofPattern(pattern) } override val dateWithYearFormatter: DateTimeFormatter by lazy { - DateTimeFormatter.ofPattern(DateFormat.getBestDateTimePattern(localeProvider.current(), "d MMM y")) + val pattern = DateFormat.getBestDateTimePattern(localeProvider.current(), "d MMM y") + DateTimeFormatter.ofPattern(pattern) } - } 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 8b0de26a28..ecc1d7fe12 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 @@ -25,23 +25,8 @@ 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 import javax.inject.Inject - -/** - * Returns the timestamp for the start of the day of the provided time. - * For example, for the time "Jul 21, 11:11" the start of the day: "Jul 21, 00:00" is returned. - */ -fun startOfDay(time: Long): Long { - val calendar = Calendar.getInstance() - calendar.time = Date(time) - calendar.set(Calendar.HOUR_OF_DAY, 0) - calendar.set(Calendar.MINUTE, 0) - calendar.set(Calendar.SECOND, 0) - calendar.set(Calendar.MILLISECOND, 0) - return calendar.time.time -} +import kotlin.math.absoluteValue class VectorDateFormatter @Inject constructor(private val context: Context, private val localeProvider: LocaleProvider, @@ -55,38 +40,71 @@ class VectorDateFormatter @Inject constructor(private val context: Context, } } - private val dayFormatter by lazy { - DateTimeFormatter.ofPattern("EEE", localeProvider.current()) + private val fullDateFormatter by lazy { + val pattern = if (DateFormat.is24HourFormat(context)) { + DateFormat.getBestDateTimePattern(localeProvider.current(), "EEE, d MMM yyyy H:mm") + } else { + DateFormat.getBestDateTimePattern(localeProvider.current(), "EEE, d MMM yyyy h:mm a") + } + DateTimeFormatter.ofPattern(pattern, 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()) + /** + * This method is used to format some date in the app. + * It will be able to show only time, only date or both with some logic. + * @param ts the timestamp to format or null. + * @param dateFormatKind the kind of format to use + * + * @return the formatted date as string. + */ + fun format(ts: Long?, dateFormatKind: DateFormatKind): String { + if (ts == null) return "" + val localDateTime = DateProvider.toLocalDateTime(ts) + return when (dateFormatKind) { + DateFormatKind.DEFAULT_DATE_AND_TIME -> formatDateAndTime(ts) + DateFormatKind.ROOM_LIST -> formatTimeOrDate( + date = localDateTime, + showTimeIfSameDay = true, + abbrev = true, + useRelative = true + ) + DateFormatKind.TIMELINE_DAY_DIVIDER -> formatTimeOrDate( + date = localDateTime, + alwaysShowYear = true + ) + DateFormatKind.MESSAGE_DETAIL -> formatFullDate(localDateTime) + DateFormatKind.MESSAGE_SIMPLE -> formatHour(localDateTime) + DateFormatKind.EDIT_HISTORY_ROW -> formatHour(localDateTime) + DateFormatKind.EDIT_HISTORY_HEADER -> formatTimeOrDate( + date = localDateTime, + abbrev = true, + useRelative = true + ) } } - fun formatMessageHour(localDateTime: LocalDateTime): String { + private fun formatFullDate(localDateTime: LocalDateTime): String { + return fullDateFormatter.format(localDateTime) + } + + private fun formatHour(localDateTime: LocalDateTime): String { return hourFormatter.format(localDateTime) } - fun formatMessageDay(localDateTime: LocalDateTime): String { - return dayFormatter.format(localDateTime) - } - - fun formatMessageDayWithMonth(localDateTime: LocalDateTime, abbrev: Boolean = false): String { + private fun formatDateWithMonth(localDateTime: LocalDateTime, abbrev: Boolean = false): String { return dateFormatterProviders.provide(abbrev).dateWithMonthFormatter.format(localDateTime) } - fun formatMessageDayWithYear(localDateTime: LocalDateTime, abbrev: Boolean = false): String { + private fun formatDateWithYear(localDateTime: LocalDateTime, abbrev: Boolean = false): String { return dateFormatterProviders.provide(abbrev).dateWithYearFormatter.format(localDateTime) } - fun formatMessageDate( + /** + * This method will only show time or date following the parameters. + */ + private fun formatTimeOrDate( date: LocalDateTime?, - showFullDate: Boolean = false, - onlyTimeIfSameDay: Boolean = false, + showTimeIfSameDay: Boolean = false, useRelative: Boolean = false, alwaysShowYear: Boolean = false, abbrev: Boolean = false @@ -94,52 +112,49 @@ class VectorDateFormatter @Inject constructor(private val context: Context, 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) + return if (showTimeIfSameDay && isSameDay) { + formatHour(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) - } + formatDate(date, currentDate, alwaysShowYear, abbrev, useRelative) + } + } + + private fun formatDate( + date: LocalDateTime, + currentDate: LocalDateTime, + alwaysShowYear: Boolean, + abbrev: Boolean, + useRelative: Boolean + ): String { + val period = Period.between(date.toLocalDate(), currentDate.toLocalDate()) + return if (period.years.absoluteValue >= 1 || alwaysShowYear) { + formatDateWithYear(date, abbrev) + } else if (useRelative && period.days.absoluteValue < 2 && period.months.absoluteValue < 1) { + getRelativeDay(date.toTimestamp()) + } else { + formatDateWithMonth(date, abbrev) } } /** - * Formats a localized relative date time for the last 2 days, e.g, "Today, HH:MM", "Yesterday, HH:MM" or - * "2 days ago, HH:MM". - * For earlier timestamps the absolute date time is returned, e.g. "Month Day, HH:MM". - * - * @param time the absolute timestamp [ms] that should be formatted relative to now + * This method will show date and time with a preposition */ - fun formatRelativeDateTime(time: Long?): String { - if (time == null) { - 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), - flags - ).toString() + private fun formatDateAndTime(ts: Long): String { + val date = DateProvider.toLocalDateTime(ts) + val currentDate = DateProvider.currentLocalDateTime() + // This fake date is created to be able to use getRelativeTimeSpanString so we can get a "at" + // preposition and the right am/pm management. + val fakeDate = LocalDateTime.of(currentDate.toLocalDate(), date.toLocalTime()) + val formattedTime = DateUtils.getRelativeTimeSpanString(context, fakeDate.toTimestamp(), true).toString() + val formattedDate = formatDate(date, currentDate, alwaysShowYear = false, abbrev = true, useRelative = true) + return "$formattedDate $formattedTime" } + /** + * We are using this method for the keywords Today/Yesterday + */ private fun getRelativeDay(ts: Long): String { return DateUtils.getRelativeTimeSpanString( ts, 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 443a214259..2fce3e974a 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,12 +19,14 @@ 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 + private val zoneOffset by lazy { + val now = currentLocalDateTime() + zoneId.rules.getOffset(now) + } fun toLocalDateTime(timestamp: Long?): LocalDateTime { val instant = Instant.ofEpochMilli(timestamp ?: 0) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsController.kt index 2094e7f8a9..d5133a7ea3 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsController.kt @@ -17,6 +17,7 @@ package im.vector.app.features.home.room.detail.readreceipts import com.airbnb.epoxy.TypedEpoxyController +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData @@ -36,7 +37,7 @@ class DisplayReadReceiptsController @Inject constructor(private val dateFormatte override fun buildModels(readReceipts: List) { readReceipts.forEach { - val timestamp = dateFormatter.formatRelativeDateTime(it.timestamp) + val timestamp = dateFormatter.format(it.timestamp, DateFormatKind.DEFAULT_DATE_AND_TIME) DisplayReadReceiptItem_() .id(it.userId) .matrixItem(it.toMatrixItem()) 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 c946bec074..f9635d4b85 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 @@ -25,6 +25,7 @@ import androidx.recyclerview.widget.RecyclerView import com.airbnb.epoxy.EpoxyController import com.airbnb.epoxy.EpoxyModel import com.airbnb.epoxy.VisibilityState +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.LoadingItem_ import im.vector.app.core.extensions.localDateTime @@ -339,10 +340,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec private fun buildDaySeparatorItem(addDaySeparator: Boolean, originServerTs: Long?): DaySeparatorItem? { return if (addDaySeparator) { - val formattedDay = dateFormatter.formatMessageDate( - date = DateProvider.toLocalDateTime(originServerTs), - alwaysShowYear = true - ) + val formattedDay = dateFormatter.format(originServerTs, DateFormatKind.TIMELINE_DAY_DIVIDER) DaySeparatorItem_().formattedDay(formattedDay).id(formattedDay) } else { null 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 48ed73d980..cc3d5cc463 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,6 +20,7 @@ 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.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.bottomsheet.BottomSheetQuickReactionsItem import im.vector.app.core.epoxy.bottomsheet.bottomSheetActionItem @@ -27,7 +28,6 @@ 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 @@ -50,8 +50,8 @@ class MessageActionsEpoxyController @Inject constructor( override fun buildModels(state: MessageActionState) { // Message preview - val date = state.timelineEvent()?.root?.localDateTime() - val formattedDate = dateFormatter.formatMessageDate(date, showFullDate = true) + val date = state.timelineEvent()?.root?.originServerTs + val formattedDate = dateFormatter.format(date, DateFormatKind.MESSAGE_DETAIL) bottomSheetMessagePreviewItem { id("preview") avatarRenderer(avatarRenderer) 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 3db02adc0a..65ecdfa430 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 @@ -17,27 +17,26 @@ package im.vector.app.features.home.room.detail.timeline.edithistory import android.content.Context import android.text.Spannable -import android.text.format.DateUtils import androidx.core.content.ContextCompat import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Incomplete import com.airbnb.mvrx.Success import im.vector.app.R +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter -import im.vector.app.core.extensions.localDateTime import im.vector.app.core.ui.list.genericFooterItem import im.vector.app.core.ui.list.genericItem import im.vector.app.core.ui.list.genericItemHeader import im.vector.app.core.ui.list.genericLoaderItem import im.vector.app.features.html.EventHtmlRenderer +import me.gujun.android.span.span +import name.fraser.neil.plaintext.diff_match_patch import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent import org.matrix.android.sdk.api.util.ContentUtils.extractUsefulTextFromReply import org.matrix.android.sdk.internal.session.room.send.TextContent -import me.gujun.android.span.span -import name.fraser.neil.plaintext.diff_match_patch import java.util.Calendar /** @@ -82,11 +81,9 @@ 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.formatMessageDayWithMonth(timelineEvent.localDateTime()) genericItemHeader { id(evDate.hashCode()) - text(dateString) + text(dateFormatter.format(evDate.timeInMillis, DateFormatKind.EDIT_HISTORY_ROW)) } } lastDate = evDate @@ -130,7 +127,7 @@ class ViewEditHistoryEpoxyController(private val context: Context, } genericItem { id(timelineEvent.eventId) - title(dateFormatter.formatMessageHour(timelineEvent.localDateTime())) + title(dateFormatter.format(timelineEvent.originServerTs, DateFormatKind.EDIT_HISTORY_ROW)) description(spannedDiff ?: body) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt index 49ac3ccfa9..e050889dbd 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt @@ -18,6 +18,7 @@ package im.vector.app.features.home.room.detail.timeline.helper +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.extensions.localDateTime import im.vector.app.core.resources.ColorProvider @@ -68,7 +69,7 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses || isNextMessageReceivedMoreThanOneHourAgo || isTileTypeMessage(nextEvent) - val time = dateFormatter.formatMessageHour(date) + val time = dateFormatter.format(event.root.originServerTs, DateFormatKind.MESSAGE_SIMPLE) val e2eDecoration = getE2EDecoration(event) return MessageInformationData( 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 29032ee5fa..a36f656f52 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 @@ -24,6 +24,7 @@ import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents @@ -112,7 +113,7 @@ class ViewReactionsViewModel @AssistedInject constructor(@Assisted summary.key, event.root.senderId ?: "", event.senderInfo.disambiguatedDisplayName, - dateFormatter.formatRelativeDateTime(event.root.originServerTs) + dateFormatter.format(event.root.originServerTs, DateFormatKind.DEFAULT_DATE_AND_TIME) ) } 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 19561280a6..06cb0172d0 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 @@ -18,9 +18,9 @@ package im.vector.app.features.home.room.list import android.view.View import im.vector.app.R +import im.vector.app.core.date.DateFormatKind 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.StringProvider import im.vector.app.core.utils.DebouncedClickListener import im.vector.app.features.home.AvatarRenderer @@ -87,12 +87,7 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor val latestEvent = roomSummary.latestPreviewableEvent if (latestEvent != null) { latestFormattedEvent = displayableEventFormatter.format(latestEvent, roomSummary.isDirect.not()) - latestEventTime = dateFormatter.formatMessageDate( - date = latestEvent.root.localDateTime(), - useRelative = true, - onlyTimeIfSameDay = true, - abbrev = true - ) + latestEventTime = dateFormatter.format(latestEvent.root.originServerTs, DateFormatKind.ROOM_LIST) } 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 76305cb6bb..6209179961 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 @@ -19,6 +19,7 @@ package im.vector.app.features.media import android.content.Context import android.view.View import androidx.core.view.isVisible +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.extensions.localDateTime import im.vector.lib.attachmentviewer.AttachmentInfo @@ -78,9 +79,7 @@ class DataAttachmentRoomProvider( val item = attachments[position] val timeLineEvent = room?.getTimeLineEvent(item.eventId) if (timeLineEvent != null) { - val dateString = timeLineEvent.root.localDateTime().let { - "${dateFormatter.formatMessageDayWithMonth(it)} at ${dateFormatter.formatMessageHour(it)} " - } + val dateString = dateFormatter.format(timeLineEvent.root.originServerTs, DateFormatKind.DEFAULT_DATE_AND_TIME) overlayView?.updateWith("${position + 1} of ${attachments.size}", "${timeLineEvent.senderInfo.displayName} $dateString") overlayView?.videoControlsGroup?.isVisible = timeLineEvent.root.isVideoMessage() } else { 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 c06dd261e2..5c0c33d078 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 @@ -19,8 +19,8 @@ package im.vector.app.features.media import android.content.Context import android.view.View import androidx.core.view.isVisible +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter -import im.vector.app.core.extensions.localDateTime import im.vector.lib.attachmentviewer.AttachmentInfo import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.Session @@ -128,9 +128,7 @@ class RoomEventsAttachmentProvider( override fun overlayViewAtPosition(context: Context, position: Int): View? { super.overlayViewAtPosition(context, position) val item = attachments[position] - val dateString = item.root.localDateTime().let { - "${dateFormatter.formatMessageDayWithMonth(it)} at ${dateFormatter.formatMessageHour(it)} " - } + val dateString = dateFormatter.format(item.root.originServerTs, DateFormatKind.DEFAULT_DATE_AND_TIME) overlayView?.updateWith("${position + 1} of ${attachments.size}", "${item.senderInfo.displayName} $dateString") overlayView?.videoControlsGroup?.isVisible = item.root.isVideoMessage() return overlayView 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 37b93ea902..f2c0ad2a9d 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 @@ -19,6 +19,7 @@ package im.vector.app.features.roomprofile.uploads.files import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.epoxy.VisibilityState import im.vector.app.R +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.loadingItem import im.vector.app.core.resources.StringProvider @@ -71,7 +72,7 @@ class UploadsFileController @Inject constructor( title(uploadEvent.contentWithAttachmentContent.body) subtitle(stringProvider.getString(R.string.uploads_files_subtitle, uploadEvent.senderInfo.disambiguatedDisplayName, - dateFormatter.formatRelativeDateTime(uploadEvent.root.originServerTs))) + dateFormatter.format(uploadEvent.root.originServerTs, DateFormatKind.DEFAULT_DATE_AND_TIME))) listener(object : UploadsFileItem.Listener { override fun onItemClicked() { listener?.onOpenClicked(uploadEvent) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceItem.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceItem.kt index 6025ea03b2..0b18b65314 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceItem.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceItem.kt @@ -45,6 +45,9 @@ abstract class DeviceItem : VectorEpoxyModel() { @EpoxyAttribute lateinit var deviceInfo: DeviceInfo + @EpoxyAttribute + var lastSeenFormatted: String? = null + @EpoxyAttribute var currentDevice = false @@ -105,15 +108,7 @@ abstract class DeviceItem : VectorEpoxyModel() { val lastSeenIp = deviceInfo.lastSeenIp?.takeIf { ip -> ip.isNotBlank() } ?: "-" - val lastSeenTime = deviceInfo.lastSeenTs?.let { ts -> - val dateFormatTime = SimpleDateFormat("HH:mm:ss", Locale.ROOT) - val date = Date(ts) - - val time = dateFormatTime.format(date) - val dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()) - - dateFormat.format(date) + ", " + time - } ?: "-" + val lastSeenTime = lastSeenFormatted ?: "-" holder.deviceLastSeenText.text = holder.root.context.getString(R.string.devices_details_last_seen_format, lastSeenIp, lastSeenTime) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesController.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesController.kt index 5d0c9fb1b0..ca2fea89d3 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesController.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesController.kt @@ -21,9 +21,9 @@ import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized -import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel -import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import im.vector.app.R +import im.vector.app.core.date.DateFormatKind +import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.errorWithRetryItem import im.vector.app.core.epoxy.loadingItem import im.vector.app.core.error.ErrorFormatter @@ -32,11 +32,14 @@ import im.vector.app.core.resources.StringProvider import im.vector.app.core.ui.list.genericItemHeader import im.vector.app.core.utils.DimensionConverter import im.vector.app.features.settings.VectorPreferences +import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel +import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import javax.inject.Inject class DevicesController @Inject constructor(private val errorFormatter: ErrorFormatter, private val stringProvider: StringProvider, private val colorProvider: ColorProvider, + private val dateFormatter: VectorDateFormatter, private val dimensionConverter: DimensionConverter, private val vectorPreferences: VectorPreferences) : EpoxyController() { @@ -100,6 +103,7 @@ class DevicesController @Inject constructor(private val errorFormatter: ErrorFor deviceInfo(deviceInfo) currentDevice(true) e2eCapable(true) + lastSeenFormatted(dateFormatter.format(deviceInfo.lastSeenTs, DateFormatKind.DEFAULT_DATE_AND_TIME)) itemClickAction { callback?.onDeviceClicked(deviceInfo) } trusted(DeviceTrustLevel(currentSessionCrossTrusted, true)) } 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 69910bb100..66bf6d4ff4 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 @@ -31,11 +31,11 @@ import org.matrix.android.sdk.internal.crypto.model.rest.GossipingToDeviceObject import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyShareRequest import org.matrix.android.sdk.internal.crypto.model.rest.SecretShareRequest import im.vector.app.R +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.loadingItem import im.vector.app.core.extensions.exhaustive import im.vector.app.core.resources.ColorProvider -import im.vector.app.core.resources.DateProvider import im.vector.app.core.resources.StringProvider import im.vector.app.core.ui.list.GenericItem import im.vector.app.core.ui.list.genericFooterItem @@ -94,8 +94,7 @@ class GossipingEventsEpoxyController @Inject constructor( ) description( span { - +vectorDateFormatter.formatMessageDayWithMonth(DateProvider.toLocalDateTime(event.ageLocalTs)) - +" ${vectorDateFormatter.formatMessageHour(DateProvider.toLocalDateTime(event.ageLocalTs))}" + +vectorDateFormatter.format(event.ageLocalTs, DateFormatKind.DEFAULT_DATE_AND_TIME) span("\nfrom: ") { textStyle = "bold" }