Show bubble tile timestamps for bubble layout inside the bubble (#7622)

pull/21833/head
Michael Telatynski 2022-01-25 13:10:17 +00:00 committed by GitHub
parent 8ddd677c35
commit fb49ccce35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 66 additions and 11 deletions

View File

@ -183,6 +183,10 @@ limitations under the License.
}
}
.mx_MessageTimestamp {
margin-left: 16px;
}
&.mx_CallEvent_narrow {
height: unset;
width: 290px;

View File

@ -22,7 +22,7 @@ limitations under the License.
max-width: 75%;
box-sizing: border-box;
display: grid;
grid-template-columns: 24px minmax(0, 1fr) min-content;
grid-template-columns: 24px minmax(0, 1fr) min-content min-content;
&::before, &::after {
position: relative;
@ -57,4 +57,11 @@ limitations under the License.
grid-column: 2;
grid-row: 2;
}
.mx_MessageTimestamp {
grid-column: 4;
grid-row: 1 / 3;
align-self: center;
margin-left: 16px;
}
}

View File

@ -450,6 +450,14 @@ limitations under the License.
}
}
.mx_EventTile.mx_EventTile_bubbleContainer[data-layout=bubble],
.mx_EventTile.mx_EventTile_leftAlignedBubble[data-layout=bubble] {
.mx_EventTile_line > a {
// hide this timestamp as the tile will render its own
display: none;
}
}
.mx_EventTile.mx_EventTile_bubbleContainer[data-layout=bubble],
.mx_EventTile.mx_EventTile_leftAlignedBubble[data-layout=bubble],
.mx_EventTile.mx_EventTile_info[data-layout=bubble],

View File

@ -33,6 +33,7 @@ const MAX_NON_NARROW_WIDTH = 450 / 70 * 100;
interface IProps {
mxEvent: MatrixEvent;
callEventGrouper: CallEventGrouper;
timestamp?: JSX.Element;
}
interface IState {
@ -145,6 +146,7 @@ export default class CallEvent extends React.PureComponent<IProps, IState> {
>
<span> { _t("Accept") } </span>
</AccessibleButton>
{ this.props.timestamp }
</div>
);
}
@ -157,6 +159,7 @@ export default class CallEvent extends React.PureComponent<IProps, IState> {
<div className="mx_CallEvent_content">
{ _t("Call declined") }
{ this.renderCallBackButton(_t("Call back")) }
{ this.props.timestamp }
</div>
);
} else if (([CallErrorCode.UserHangup, "user hangup"].includes(hangupReason) || !hangupReason)) {
@ -174,6 +177,7 @@ export default class CallEvent extends React.PureComponent<IProps, IState> {
return (
<div className="mx_CallEvent_content">
{ text }
{ this.props.timestamp }
</div>
);
} else if (hangupReason === CallErrorCode.InviteTimeout) {
@ -181,6 +185,7 @@ export default class CallEvent extends React.PureComponent<IProps, IState> {
<div className="mx_CallEvent_content">
{ _t("No answer") }
{ this.renderCallBackButton(_t("Call back")) }
{ this.props.timestamp }
</div>
);
}
@ -215,6 +220,7 @@ export default class CallEvent extends React.PureComponent<IProps, IState> {
/>
{ _t("Connection failed") }
{ this.renderCallBackButton(_t("Retry")) }
{ this.props.timestamp }
</div>
);
}
@ -222,6 +228,7 @@ export default class CallEvent extends React.PureComponent<IProps, IState> {
return (
<div className="mx_CallEvent_content">
<Clock seconds={this.state.length} />
{ this.props.timestamp }
</div>
);
}
@ -229,6 +236,7 @@ export default class CallEvent extends React.PureComponent<IProps, IState> {
return (
<div className="mx_CallEvent_content">
{ _t("Connecting") }
{ this.props.timestamp }
</div>
);
}
@ -237,6 +245,7 @@ export default class CallEvent extends React.PureComponent<IProps, IState> {
<div className="mx_CallEvent_content">
{ _t("Missed call") }
{ this.renderCallBackButton(_t("Call back")) }
{ this.props.timestamp }
</div>
);
}
@ -244,6 +253,7 @@ export default class CallEvent extends React.PureComponent<IProps, IState> {
return (
<div className="mx_CallEvent_content">
{ _t("The call is in an unknown state!") }
{ this.props.timestamp }
</div>
);
}

View File

@ -27,11 +27,12 @@ import { objectHasDiff } from "../../../utils/objects";
interface IProps {
mxEvent: MatrixEvent;
timestamp?: JSX.Element;
}
const ALGORITHM = "m.megolm.v1.aes-sha2";
const EncryptionEvent = forwardRef<HTMLDivElement, IProps>(({ mxEvent }, ref) => {
const EncryptionEvent = forwardRef<HTMLDivElement, IProps>(({ mxEvent, timestamp }, ref) => {
const cli = useContext(MatrixClientContext);
const roomId = mxEvent.getRoomId();
const isRoomEncrypted = MatrixClientPeg.get().isRoomEncrypted(roomId);
@ -60,6 +61,7 @@ const EncryptionEvent = forwardRef<HTMLDivElement, IProps>(({ mxEvent }, ref) =>
className="mx_cryptoEvent mx_cryptoEvent_icon"
title={_t("Encryption enabled")}
subtitle={subtitle}
timestamp={timestamp}
/>;
}
@ -68,6 +70,7 @@ const EncryptionEvent = forwardRef<HTMLDivElement, IProps>(({ mxEvent }, ref) =>
className="mx_cryptoEvent mx_cryptoEvent_icon"
title={_t("Encryption enabled")}
subtitle={_t("Ignored attempt to disable encryption")}
timestamp={timestamp}
/>;
}
@ -76,6 +79,7 @@ const EncryptionEvent = forwardRef<HTMLDivElement, IProps>(({ mxEvent }, ref) =>
title={_t("Encryption not enabled")}
subtitle={_t("The encryption used by this room isn't supported.")}
ref={ref}
timestamp={timestamp}
/>;
});

View File

@ -20,15 +20,23 @@ import classNames from "classnames";
interface IProps {
className: string;
title: string;
timestamp?: JSX.Element;
subtitle?: ReactNode;
children?: ReactChildren;
}
const EventTileBubble = forwardRef<HTMLDivElement, IProps>(({ className, title, subtitle, children }, ref) => {
const EventTileBubble = forwardRef<HTMLDivElement, IProps>(({
className,
title,
timestamp,
subtitle,
children,
}, ref) => {
return <div className={classNames("mx_EventTileBubble", className)} ref={ref}>
<div className="mx_EventTileBubble_title">{ title }</div>
{ subtitle && <div className="mx_EventTileBubble_subtitle">{ subtitle }</div> }
{ children }
{ timestamp }
</div>;
});

View File

@ -26,6 +26,7 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
mxEvent: MatrixEvent;
timestamp?: JSX.Element;
}
@replaceableComponent("views.messages.MJitsiWidgetEvent")
@ -54,6 +55,7 @@ export default class MJitsiWidgetEvent extends React.PureComponent<IProps> {
return <EventTileBubble
className="mx_MJitsiWidgetEvent"
title={_t('Video conference ended by %(senderName)s', { senderName })}
timestamp={this.props.timestamp}
/>;
} else if (prevUrl) {
// modified
@ -61,6 +63,7 @@ export default class MJitsiWidgetEvent extends React.PureComponent<IProps> {
className="mx_MJitsiWidgetEvent"
title={_t('Video conference updated by %(senderName)s', { senderName })}
subtitle={joinCopy}
timestamp={this.props.timestamp}
/>;
} else {
// assume added
@ -68,6 +71,7 @@ export default class MJitsiWidgetEvent extends React.PureComponent<IProps> {
className="mx_MJitsiWidgetEvent"
title={_t("Video conference started by %(senderName)s", { senderName })}
subtitle={joinCopy}
timestamp={this.props.timestamp}
/>;
}
}

View File

@ -29,6 +29,7 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
/* the MatrixEvent to show */
mxEvent: MatrixEvent;
timestamp?: JSX.Element;
}
@replaceableComponent("views.messages.MKeyVerificationConclusion")
@ -133,6 +134,7 @@ export default class MKeyVerificationConclusion extends React.Component<IProps>
className={classes}
title={title}
subtitle={userLabelForEventRoom(request.otherUserId, mxEvent.getRoomId())}
timestamp={this.props.timestamp}
/>;
}

View File

@ -30,6 +30,7 @@ import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
interface IProps {
mxEvent: MatrixEvent;
timestamp?: JSX.Element;
}
@replaceableComponent("views.messages.MKeyVerificationRequest")
@ -168,6 +169,7 @@ export default class MKeyVerificationRequest extends React.Component<IProps> {
className="mx_cryptoEvent mx_cryptoEvent_icon"
title={title}
subtitle={subtitle}
timestamp={this.props.timestamp}
>
{ stateNode }
</EventTileBubble>;

View File

@ -29,6 +29,7 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
/* the MatrixEvent to show */
mxEvent: MatrixEvent;
timestamp?: JSX.Element;
}
@replaceableComponent("views.messages.RoomCreate")
@ -65,6 +66,7 @@ export default class RoomCreate extends React.Component<IProps> {
className="mx_CreateEvent"
title={_t("This room is a continuation of another conversation.")}
subtitle={link}
timestamp={this.props.timestamp}
/>;
}
}

View File

@ -1273,12 +1273,13 @@ export default class EventTile extends React.Component<IProps, IState> {
? this.props.mxEvent.getTs()
: thread?.lastReply().getTs();
const timestamp = showTimestamp && ts ?
<MessageTimestamp
showRelative={this.props.tileShape === TileShape.ThreadPanel}
showTwelveHour={this.props.isTwelveHour}
ts={ts}
/> : null;
const messageTimestamp = <MessageTimestamp
showRelative={this.props.tileShape === TileShape.ThreadPanel}
showTwelveHour={this.props.isTwelveHour}
ts={ts}
/>;
const timestamp = showTimestamp && ts ? messageTimestamp : null;
const keyRequestHelpText =
<div className="mx_EventTile_keyRequestInfo_tooltip_contents">
@ -1339,9 +1340,10 @@ export default class EventTile extends React.Component<IProps, IState> {
{ timestamp }
</a>;
const useIRCLayout = this.props.layout == Layout.IRC;
const useIRCLayout = this.props.layout === Layout.IRC;
const groupTimestamp = !useIRCLayout ? linkedTimestamp : null;
const ircTimestamp = useIRCLayout ? linkedTimestamp : null;
const bubbleTimestamp = this.props.layout === Layout.Bubble ? messageTimestamp : null;
const groupPadlock = !useIRCLayout && !isBubbleMessage && this.renderE2EPadlock();
const ircPadlock = useIRCLayout && !isBubbleMessage && this.renderE2EPadlock();
@ -1567,7 +1569,8 @@ export default class EventTile extends React.Component<IProps, IState> {
{ groupTimestamp }
{ groupPadlock }
{ replyChain }
<EventTileType ref={this.tile}
<EventTileType
ref={this.tile}
mxEvent={this.props.mxEvent}
forExport={this.props.forExport}
replacingEventId={this.props.replacingEventId}
@ -1580,6 +1583,7 @@ export default class EventTile extends React.Component<IProps, IState> {
callEventGrouper={this.props.callEventGrouper}
getRelationsForEvent={this.props.getRelationsForEvent}
isSeeingThroughMessageHiddenForModeration={isSeeingThroughMessageHiddenForModeration}
timestamp={bubbleTimestamp}
/>
{ keyRequestInfo }
{ actionBar }