Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix thread summary layout for narrow right panel timeline #7838

Merged
merged 9 commits into from
Feb 23, 2022
6 changes: 6 additions & 0 deletions res/css/views/right_panel/_TimelineCard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ limitations under the License.
padding-right: 36px;
}

.mx_EventTile:not([data-layout="bubble"]) .mx_ThreadInfo {
margin-left: 36px;
margin-right: 0;
max-width: min(100%, 600px);
}

.mx_GroupLayout .mx_EventTile > .mx_SenderProfile {
margin-left: 36px;
}
Expand Down
5 changes: 5 additions & 0 deletions res/css/views/rooms/_EventTile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,11 @@ $left-gutter: 64px;
}
}

.mx_MessagePanel_narrow .mx_ThreadInfo {
min-width: initial;
max-width: initial;
}

.mx_ThreadInfo_content {
text-overflow: ellipsis;
overflow: hidden;
Expand Down
28 changes: 27 additions & 1 deletion src/components/structures/MessagePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.

import React, { createRef, KeyboardEvent, ReactNode, SyntheticEvent, TransitionEvent } from 'react';
import ReactDOM from 'react-dom';
import classNames from 'classnames';
import { Room } from 'matrix-js-sdk/src/models/room';
import { EventType } from 'matrix-js-sdk/src/@types/event';
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
Expand Down Expand Up @@ -52,8 +53,10 @@ import EditorStateTransfer from "../../utils/EditorStateTransfer";
import { Action } from '../../dispatcher/actions';
import { getEventDisplayInfo } from "../../utils/EventUtils";
import { IReadReceiptInfo } from "../views/rooms/ReadReceiptMarker";
import UIStore, { UI_EVENTS } from '../../stores/UIStore';

const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes
const NARROW_MODE_BREAKPOINT = 400;
jryans marked this conversation as resolved.
Show resolved Hide resolved
const continuedTypes = [EventType.Sticker, EventType.RoomMessage];
const groupedEvents = [
EventType.RoomMember,
Expand Down Expand Up @@ -190,6 +193,7 @@ interface IState {
ghostReadMarkers: string[];
showTypingNotifications: boolean;
hideSender: boolean;
narrowMode?: boolean;
}

interface IReadReceiptForUser {
Expand Down Expand Up @@ -255,6 +259,9 @@ export default class MessagePanel extends React.Component<IProps, IState> {
private readonly showTypingNotificationsWatcherRef: string;
private eventTiles: Record<string, EventTile> = {};

private static instanceCount = 0;
private readonly instanceId: number;

constructor(props, context) {
super(props, context);

Expand All @@ -273,17 +280,24 @@ export default class MessagePanel extends React.Component<IProps, IState> {

this.showTypingNotificationsWatcherRef =
SettingsStore.watchSetting("showTypingNotifications", null, this.onShowTypingNotificationsChange);

this.instanceId = MessagePanel.instanceCount++;
}

componentDidMount() {
this.calculateRoomMembersCount();
this.props.room?.on("RoomState.members", this.calculateRoomMembersCount);
UIStore.instance.on(`MessagePanel${this.instanceId}`, this.onResize);
UIStore.instance.trackElementDimensions(`MessagePanel${this.instanceId}`,
ReactDOM.findDOMNode(this.scrollPanel.current) as Element);
this.isMounted = true;
}

componentWillUnmount() {
this.isMounted = false;
this.props.room?.off("RoomState.members", this.calculateRoomMembersCount);
UIStore.instance.off(`MessagePanel${this.instanceId}`, this.onResize);
UIStore.instance.stopTrackingElementDimensions(`MessagePanel${this.instanceId}`);
SettingsStore.unwatchSetting(this.showTypingNotificationsWatcherRef);
}

Expand Down Expand Up @@ -817,6 +831,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
callEventGrouper={callEventGrouper}
hideSender={this.state.hideSender}
timelineRenderingType={this.context.timelineRenderingType}
narrowMode={this.state.narrowMode}
/>
</TileErrorBoundary>,
);
Expand Down Expand Up @@ -926,6 +941,13 @@ export default class MessagePanel extends React.Component<IProps, IState> {
this.eventTiles[eventId] = node;
};

private onResize = (type: UI_EVENTS, entry: ResizeObserverEntry) => {
if (type !== UI_EVENTS.Resize) return;
this.setState({
narrowMode: entry.contentRect.width <= NARROW_MODE_BREAKPOINT,
});
};

// once dynamic content in the events load, make the scrollPanel check the
// scroll offsets.
public onHeightChanged = (): void => {
Expand Down Expand Up @@ -1012,11 +1034,15 @@ export default class MessagePanel extends React.Component<IProps, IState> {
/>;
}

const classes = classNames(this.props.className, {
"mx_MessagePanel_narrow": this.state.narrowMode,
});

return (
<ErrorBoundary>
<ScrollPanel
ref={this.scrollPanel}
className={this.props.className}
className={classes}
onScroll={this.props.onScroll}
onUserScroll={this.props.onUserScroll}
onFillRequest={this.props.onFillRequest}
Expand Down
13 changes: 10 additions & 3 deletions src/components/views/rooms/EventTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,9 @@ interface IProps {
// displayed to the current user either because they're
// the author or they are a moderator
isSeeingThroughMessageHiddenForModeration?: boolean;

// Whether we should assume a smaller width and adjust layout to match
narrowMode?: boolean;
jryans marked this conversation as resolved.
Show resolved Hide resolved
}

interface IState {
Expand Down Expand Up @@ -690,6 +693,12 @@ export default class EventTile extends React.Component<IProps, IState> {
<p className="mx_ThreadSummaryIcon">{ _t("From a thread") }</p>
);
} else if (this.state.threadReplyCount && this.props.mxEvent.isThreadRoot) {
let count: string | number = this.state.threadReplyCount;
if (!this.props.narrowMode) {
count = _t("%(count)s reply", {
count: this.state.threadReplyCount,
});
}
return (
<CardContext.Consumer>
{ context =>
Expand All @@ -700,9 +709,7 @@ export default class EventTile extends React.Component<IProps, IState> {
}}
>
<span className="mx_ThreadInfo_threads-amount">
{ _t("%(count)s reply", {
count: this.state.threadReplyCount,
}) }
{ count }
</span>
{ this.renderThreadLastMessagePreview() }
</div>
Expand Down