mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 11:59:12 +03:00
Date formatting: try to generalise usage of VectorDateFormatter and get proper formatting for Date + Time
This commit is contained in:
parent
73ab32fd92
commit
0ff28c4f50
18 changed files with 159 additions and 123 deletions
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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_()
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue