Render timeline separator for late event groups (#11739)
* Use Compound tooltips on MessageTimestamp to improve UX of date time discovery Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Show io.element.late_event in MessageTimestamp when known Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update snapshot Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Avoid needing new Compound changes Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Move groupers into their own directory Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Refactor date separator code to be more generic Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Render timeline separator for late event groups Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix date used in copy Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update snapshot Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Move groupers into their own directory Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update copy Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update copy Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update snapshot Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * i18n Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add comments Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add comments Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
@@ -20,10 +20,9 @@ import classNames from "classnames";
|
||||
import { Room, MatrixClient, RoomStateEvent, EventStatus, MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { isSupportedReceiptType } from "matrix-js-sdk/src/utils";
|
||||
import { Optional } from "matrix-events-sdk";
|
||||
|
||||
import shouldHideEvent from "../../shouldHideEvent";
|
||||
import { wantsDateSeparator } from "../../DateUtils";
|
||||
import { formatDate, wantsDateSeparator } from "../../DateUtils";
|
||||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||
import SettingsStore from "../../settings/SettingsStore";
|
||||
import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext";
|
||||
@@ -40,6 +39,7 @@ import LegacyCallEventGrouper from "./LegacyCallEventGrouper";
|
||||
import WhoIsTypingTile from "../views/rooms/WhoIsTypingTile";
|
||||
import ScrollPanel, { IScrollState } from "./ScrollPanel";
|
||||
import DateSeparator from "../views/messages/DateSeparator";
|
||||
import TimelineSeparator, { SeparatorKind } from "../views/messages/TimelineSeparator";
|
||||
import ErrorBoundary from "../views/elements/ErrorBoundary";
|
||||
import ResizeNotifier from "../../utils/ResizeNotifier";
|
||||
import Spinner from "../views/elements/Spinner";
|
||||
@@ -54,6 +54,8 @@ import { hasThreadSummary } from "../../utils/EventUtils";
|
||||
import { BaseGrouper } from "./grouper/BaseGrouper";
|
||||
import { MainGrouper } from "./grouper/MainGrouper";
|
||||
import { CreationGrouper } from "./grouper/CreationGrouper";
|
||||
import { _t } from "../../languageHandler";
|
||||
import { getLateEventInfo } from "./grouper/LateEventGrouper";
|
||||
|
||||
const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes
|
||||
const continuedTypes = [EventType.Sticker, EventType.RoomMessage];
|
||||
@@ -739,31 +741,38 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||
|
||||
const isEditing = this.props.editState?.getEvent().getId() === mxEv.getId();
|
||||
// local echoes have a fake date, which could even be yesterday. Treat them as 'today' for the date separators.
|
||||
let ts1 = mxEv.getTs();
|
||||
let eventDate = mxEv.getDate();
|
||||
if (mxEv.status) {
|
||||
eventDate = new Date();
|
||||
ts1 = eventDate.getTime();
|
||||
}
|
||||
const ts1 = mxEv.getTs() ?? Date.now();
|
||||
|
||||
// do we need a date separator since the last event?
|
||||
const wantsDateSeparator = this.wantsDateSeparator(prevEvent, eventDate);
|
||||
if (wantsDateSeparator && !isGrouped && this.props.room) {
|
||||
const dateSeparator = (
|
||||
<li key={ts1}>
|
||||
<DateSeparator key={ts1} roomId={this.props.room.roomId} ts={ts1} />
|
||||
</li>
|
||||
);
|
||||
ret.push(dateSeparator);
|
||||
// do we need a separator since the last event?
|
||||
const wantsSeparator = this.wantsSeparator(prevEvent, mxEv);
|
||||
if (!isGrouped && this.props.room) {
|
||||
if (wantsSeparator === SeparatorKind.Date) {
|
||||
ret.push(
|
||||
<li key={ts1}>
|
||||
<DateSeparator key={ts1} roomId={this.props.room.roomId} ts={ts1} />
|
||||
</li>,
|
||||
);
|
||||
} else if (wantsSeparator === SeparatorKind.LateEvent) {
|
||||
const text = _t("timeline|late_event_separator", {
|
||||
dateTime: formatDate(mxEv.getDate() ?? new Date()),
|
||||
});
|
||||
ret.push(
|
||||
<li key={ts1}>
|
||||
<TimelineSeparator key={ts1} label={text}>
|
||||
{text}
|
||||
</TimelineSeparator>
|
||||
</li>,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const cli = MatrixClientPeg.safeGet();
|
||||
let lastInSection = true;
|
||||
if (nextEventWithTile) {
|
||||
const nextEv = nextEventWithTile;
|
||||
const willWantDateSeparator = this.wantsDateSeparator(mxEv, nextEv.getDate() || new Date());
|
||||
const willWantSeparator = this.wantsSeparator(mxEv, nextEv);
|
||||
lastInSection =
|
||||
willWantDateSeparator ||
|
||||
willWantSeparator === SeparatorKind.Date ||
|
||||
mxEv.getSender() !== nextEv.getSender() ||
|
||||
getEventDisplayInfo(cli, nextEv, this.showHiddenEvents).isInfoMessage ||
|
||||
!shouldFormContinuation(mxEv, nextEv, cli, this.showHiddenEvents, this.context.timelineRenderingType);
|
||||
@@ -771,7 +780,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||
|
||||
// is this a continuation of the previous message?
|
||||
const continuation =
|
||||
!wantsDateSeparator &&
|
||||
wantsSeparator === SeparatorKind.None &&
|
||||
shouldFormContinuation(prevEvent, mxEv, cli, this.showHiddenEvents, this.context.timelineRenderingType);
|
||||
|
||||
const eventId = mxEv.getId()!;
|
||||
@@ -816,16 +825,31 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public wantsDateSeparator(prevEvent: MatrixEvent | null, nextEventDate: Optional<Date>): boolean {
|
||||
public wantsSeparator(prevEvent: MatrixEvent | null, mxEvent: MatrixEvent): SeparatorKind {
|
||||
if (this.context.timelineRenderingType === TimelineRenderingType.ThreadsList) {
|
||||
return false;
|
||||
return SeparatorKind.None;
|
||||
}
|
||||
if (prevEvent == null) {
|
||||
// first event in the panel: depends if we could back-paginate from
|
||||
// here.
|
||||
return !this.props.canBackPaginate;
|
||||
|
||||
if (prevEvent !== null) {
|
||||
// If the previous event was late but current is not then show a date separator for orientation
|
||||
// Otherwise if the current event is of a different late group than the previous show a late event separator
|
||||
const lateEventInfo = getLateEventInfo(mxEvent);
|
||||
if (lateEventInfo?.group_id !== getLateEventInfo(prevEvent)?.group_id) {
|
||||
return lateEventInfo !== undefined ? SeparatorKind.LateEvent : SeparatorKind.Date;
|
||||
}
|
||||
}
|
||||
return wantsDateSeparator(prevEvent.getDate() || undefined, nextEventDate);
|
||||
|
||||
// first event in the panel: depends on if we could back-paginate from here.
|
||||
if (prevEvent === null && !this.props.canBackPaginate) {
|
||||
return SeparatorKind.Date;
|
||||
}
|
||||
|
||||
const nextEventDate = mxEvent.getDate() ?? new Date();
|
||||
if (prevEvent !== null && wantsDateSeparator(prevEvent.getDate() || undefined, nextEventDate)) {
|
||||
return SeparatorKind.Date;
|
||||
}
|
||||
|
||||
return SeparatorKind.None;
|
||||
}
|
||||
|
||||
// Get a list of read receipts that should be shown next to this event
|
||||
|
||||
Reference in New Issue
Block a user