Date formatting: try to generalise usage of VectorDateFormatter and get proper formatting for Date + Time

This commit is contained in:
ganfra 2020-08-31 18:30:37 +02:00 committed by Benoit Marty
parent 73ab32fd92
commit 0ff28c4f50
18 changed files with 159 additions and 123 deletions

View File

@ -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())
}
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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 {
if (DateFormat.is24HourFormat(context)) {
DateTimeFormatter.ofPattern("EEE, d MMM yyyy H:mm", localeProvider.current())
val pattern = if (DateFormat.is24HourFormat(context)) {
DateFormat.getBestDateTimePattern(localeProvider.current(), "EEE, d MMM yyyy H:mm")
} else {
DateTimeFormatter.ofPattern("EEE, d MMM yyyy h:mm a", localeProvider.current())
DateFormat.getBestDateTimePattern(localeProvider.current(), "EEE, d MMM yyyy h:mm a")
}
DateTimeFormatter.ofPattern(pattern, 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,

View File

@ -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)

View File

@ -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<ReadReceiptData>) {
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())

View File

@ -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

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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(

View File

@ -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)
)
}

View File

@ -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_()

View File

@ -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 {

View File

@ -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

View File

@ -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)

View File

@ -45,6 +45,9 @@ abstract class DeviceItem : VectorEpoxyModel<DeviceItem.Holder>() {
@EpoxyAttribute
lateinit var deviceInfo: DeviceInfo
@EpoxyAttribute
var lastSeenFormatted: String? = null
@EpoxyAttribute
var currentDevice = false
@ -105,15 +108,7 @@ abstract class DeviceItem : VectorEpoxyModel<DeviceItem.Holder>() {
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)

View File

@ -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))
}

View File

@ -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"
}