Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions res/css/structures/_RoomView.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Please see LICENSE files in the repository root for full details.
}

.mx_MessageComposer {
position: relative;
width: 100%;
flex: 0 0 auto;
margin-right: 2px;
Expand Down Expand Up @@ -156,9 +157,6 @@ Please see LICENSE files in the repository root for full details.
list-style-type: none;
padding: var(--RoomView_MessageList-padding); /* mx_ProfileResizer depends on this value */
margin: 0;
/* needed as min-height is set to clientHeight in ScrollPanel
to prevent shrinking when WhoIsTypingTile is hidden */
box-sizing: border-box;

li {
clear: both;
Expand Down
8 changes: 0 additions & 8 deletions res/css/views/right_panel/_TimelineCard.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,6 @@ Please see LICENSE files in the repository root for full details.
}
}

.mx_WhoIsTypingTile {
margin-left: -12px; /* undo padding on the message list */
}

.mx_WhoIsTypingTile_avatars {
flex-basis: 48px; /* 12 (padding on message list) + 36 (padding on event lines) */
}

.mx_GenericEventListSummary_unstyledList, /* RR next to a message on the event list summary */
.mx_RoomView_MessageList {
/* RR next to a message on the messsge list */
Expand Down
12 changes: 10 additions & 2 deletions res/css/views/rooms/_WhoIsTypingTile.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ Please see LICENSE files in the repository root for full details.
*/

.mx_WhoIsTypingTile {
margin-left: -18px; /* offset padding from mx_RoomView_MessageList to center avatars */
padding-top: 18px;
--padding-top: 9px;
position: absolute;
background: linear-gradient(to top, var(--cpd-color-bg-canvas-default) var(--padding-top), transparent);
left: 0;
right: 0;
top: calc((1lh + var(--padding-top)) * -1);
margin-left: 0;
padding-top: var(--padding-top);
display: flex;
align-items: center;
}
Expand All @@ -25,6 +31,7 @@ Please see LICENSE files in the repository root for full details.
.mx_WhoIsTypingTile_avatars .mx_BaseAvatar {
border: 1px solid $background;
border-radius: 40px;
vertical-align: middle;
}

.mx_WhoIsTypingTile_remainingAvatarPlaceholder {
Expand All @@ -45,6 +52,7 @@ Please see LICENSE files in the repository root for full details.
.mx_WhoIsTypingTile_label {
flex: 1;
font: var(--cpd-font-body-md-semibold);
font-size: var(--cpd-font-size-body-sm);
color: $roomtopic-color;
}

Expand Down
80 changes: 0 additions & 80 deletions src/components/structures/MessagePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import EventTile, {
import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResizer";
import defaultDispatcher from "../../dispatcher/dispatcher";
import type LegacyCallEventGrouper from "./LegacyCallEventGrouper";
import WhoIsTypingTile from "../views/rooms/WhoIsTypingTile";
import ScrollPanel, { type IScrollState } from "./ScrollPanel";
import DateSeparator from "../views/messages/DateSeparator";
import TimelineSeparator, { SeparatorKind } from "../views/messages/TimelineSeparator";
Expand Down Expand Up @@ -188,7 +187,6 @@ interface IProps {

interface IState {
ghostReadMarkers: string[];
showTypingNotifications: boolean;
hideSender: boolean;
}

Expand Down Expand Up @@ -248,10 +246,8 @@ export default class MessagePanel extends React.Component<IProps, IState> {
private unmounted = false;

private readMarkerNode = createRef<HTMLLIElement>();
private whoIsTyping = createRef<WhoIsTypingTile>();
public scrollPanel = createRef<ScrollPanel>();

private showTypingNotificationsWatcherRef?: string;
private eventTiles: Record<string, UnwrappedEventTile> = {};

// A map to allow groupers to maintain consistent keys even if their first event is uprooted due to back-pagination.
Expand All @@ -264,7 +260,6 @@ export default class MessagePanel extends React.Component<IProps, IState> {
// previous positions the read marker has been in, so we can
// display 'ghost' read markers that are animating away
ghostReadMarkers: [],
showTypingNotifications: SettingsStore.getValue("showTypingNotifications"),
hideSender: this.shouldHideSender(),
};

Expand All @@ -276,19 +271,13 @@ export default class MessagePanel extends React.Component<IProps, IState> {

public componentDidMount(): void {
this.unmounted = false;
this.showTypingNotificationsWatcherRef = SettingsStore.watchSetting(
"showTypingNotifications",
null,
this.onShowTypingNotificationsChange,
);
this.calculateRoomMembersCount();
this.props.room?.currentState.on(RoomStateEvent.Update, this.calculateRoomMembersCount);
}

public componentWillUnmount(): void {
this.unmounted = true;
this.props.room?.currentState.off(RoomStateEvent.Update, this.calculateRoomMembersCount);
SettingsStore.unwatchSetting(this.showTypingNotificationsWatcherRef);
this.readReceiptMap = {};
this.resizeObserver.disconnect();
}
Expand Down Expand Up @@ -335,12 +324,6 @@ export default class MessagePanel extends React.Component<IProps, IState> {
});
};

private onShowTypingNotificationsChange = (): void => {
this.setState({
showTypingNotifications: SettingsStore.getValue("showTypingNotifications"),
});
};

/* get the DOM node representing the given event */
public getNodeForEventId(eventId: string): HTMLElement | undefined {
if (!this.eventTiles) {
Expand Down Expand Up @@ -959,52 +942,6 @@ export default class MessagePanel extends React.Component<IProps, IState> {

private resizeObserver = new ResizeObserver(this.onHeightChanged);

private onTypingShown = (): void => {
const scrollPanel = this.scrollPanel.current;
// this will make the timeline grow, so checkScroll
scrollPanel?.checkScroll();
if (scrollPanel && scrollPanel.getScrollState().stuckAtBottom) {
scrollPanel.preventShrinking();
}
};

private onTypingHidden = (): void => {
const scrollPanel = this.scrollPanel.current;
if (scrollPanel) {
// as hiding the typing notifications doesn't
// update the scrollPanel, we tell it to apply
// the shrinking prevention once the typing notifs are hidden
scrollPanel.updatePreventShrinking();
// order is important here as checkScroll will scroll down to
// reveal added padding to balance the notifs disappearing.
scrollPanel.checkScroll();
}
};

public updateTimelineMinHeight(): void {
const scrollPanel = this.scrollPanel.current;

if (scrollPanel) {
const isAtBottom = scrollPanel.isAtBottom();
const whoIsTyping = this.whoIsTyping.current;
const isTypingVisible = whoIsTyping && whoIsTyping.isVisible();
// when messages get added to the timeline,
// but somebody else is still typing,
// update the min-height, so once the last
// person stops typing, no jumping occurs
if (isAtBottom && isTypingVisible) {
scrollPanel.preventShrinking();
}
}
}

public onTimelineReset(): void {
const scrollPanel = this.scrollPanel.current;
if (scrollPanel) {
scrollPanel.clearPreventShrinking();
}
}

public render(): React.ReactNode {
let topSpinner;
let bottomSpinner;
Expand All @@ -1025,22 +962,6 @@ export default class MessagePanel extends React.Component<IProps, IState> {

const style = this.props.hidden ? { display: "none" } : {};

let whoIsTyping;
if (
this.props.room &&
this.state.showTypingNotifications &&
this.context.timelineRenderingType === TimelineRenderingType.Room
) {
whoIsTyping = (
<WhoIsTypingTile
room={this.props.room}
onShown={this.onTypingShown}
onHidden={this.onTypingHidden}
ref={this.whoIsTyping}
/>
);
}

let ircResizer: JSX.Element | undefined;
if (this.props.layout == Layout.IRC) {
ircResizer = (
Expand All @@ -1066,7 +987,6 @@ export default class MessagePanel extends React.Component<IProps, IState> {
>
{topSpinner}
{this.getEventTiles()}
{whoIsTyping}
{bottomSpinner}
</ScrollPanel>
</ErrorBoundary>
Expand Down
92 changes: 0 additions & 92 deletions src/components/structures/ScrollPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,6 @@ export interface IScrollState {
pixelOffset?: number;
}

interface IPreventShrinkingState {
offsetFromBottom: number;
offsetNode: HTMLElement;
}

export default class ScrollPanel extends React.Component<IProps> {
// noinspection JSUnusedLocalSymbols
public static defaultProps = {
Expand Down Expand Up @@ -177,7 +172,6 @@ export default class ScrollPanel extends React.Component<IProps> {
// Is that next fill request scheduled because of a props update?
private pendingFillDueToPropsUpdate = false;
private scrollState!: IScrollState;
private preventShrinkingState: IPreventShrinkingState | null = null;
private unfillDebouncer: number | null = null;
private bottomGrowth!: number;
private minListHeight!: number;
Expand Down Expand Up @@ -206,7 +200,6 @@ export default class ScrollPanel extends React.Component<IProps> {
//
// This will also re-check the fill state, in case the pagination was inadequate
this.checkScroll(true);
this.updatePreventShrinking();
}

public componentWillUnmount(): void {
Expand All @@ -227,7 +220,6 @@ export default class ScrollPanel extends React.Component<IProps> {
debuglog("onScroll called past resize gate; scroll node top:", this.getScrollNode().scrollTop);
this.scrollTimeout?.restart();
this.saveScrollState();
this.updatePreventShrinking();
this.props.onScroll?.(ev);
// noinspection JSIgnoredPromiseFromCall
this.checkFillState();
Expand All @@ -236,10 +228,6 @@ export default class ScrollPanel extends React.Component<IProps> {
private onResize = (): void => {
debuglog("onResize called");
this.checkScroll();
// update preventShrinkingState if present
if (this.preventShrinkingState) {
this.preventShrinking();
}
};

// after an update to the contents of the panel, check that the scroll is
Expand Down Expand Up @@ -849,86 +837,6 @@ export default class ScrollPanel extends React.Component<IProps> {
this.divScroll = divScroll;
};

/**
Mark the bottom offset of the last tile, so we can balance it out when
anything below it changes, by calling updatePreventShrinking, to keep
the same minimum bottom offset, effectively preventing the timeline to shrink.
*/
public preventShrinking = (): void => {
const messageList = this.itemlist.current;
const tiles = messageList?.children;
if (!tiles) {
return;
}
let lastTileNode;
for (let i = tiles.length - 1; i >= 0; i--) {
const node = tiles[i] as HTMLElement;
if (node.dataset.scrollTokens) {
lastTileNode = node;
break;
}
}
if (!lastTileNode) {
return;
}
this.clearPreventShrinking();
const offsetFromBottom = messageList.clientHeight - (lastTileNode.offsetTop + lastTileNode.clientHeight);
this.preventShrinkingState = {
offsetFromBottom: offsetFromBottom,
offsetNode: lastTileNode,
};
debuglog("prevent shrinking, last tile ", offsetFromBottom, "px from bottom");
};

/** Clear shrinking prevention. Used internally, and when the timeline is reloaded. */
public clearPreventShrinking = (): void => {
const messageList = this.itemlist.current;
const balanceElement = messageList && messageList.parentElement;
if (balanceElement) balanceElement.style.removeProperty("paddingBottom");
this.preventShrinkingState = null;
debuglog("prevent shrinking cleared");
};

/**
update the container padding to balance
the bottom offset of the last tile since
preventShrinking was called.
Clears the prevent-shrinking state ones the offset
from the bottom of the marked tile grows larger than
what it was when marking.
*/
public updatePreventShrinking = (): void => {
if (this.preventShrinkingState && this.itemlist.current) {
const sn = this.getScrollNode();
const scrollState = this.scrollState;
const messageList = this.itemlist.current;
const { offsetNode, offsetFromBottom } = this.preventShrinkingState;
// element used to set paddingBottom to balance the typing notifs disappearing
const balanceElement = messageList.parentElement;
// if the offsetNode got unmounted, clear
let shouldClear = !offsetNode.parentElement;
// also if 200px from bottom
if (!shouldClear && !scrollState.stuckAtBottom) {
const spaceBelowViewport = sn.scrollHeight - (sn.scrollTop + sn.clientHeight);
shouldClear = spaceBelowViewport >= 200;
}
// try updating if not clearing
if (!shouldClear) {
const currentOffset = messageList.clientHeight - (offsetNode.offsetTop + offsetNode.clientHeight);
const offsetDiff = offsetFromBottom - currentOffset;
if (offsetDiff > 0 && balanceElement) {
balanceElement.style.paddingBottom = `${offsetDiff}px`;
debuglog("update prevent shrinking ", offsetDiff, "px from bottom");
} else if (offsetDiff < 0) {
shouldClear = true;
}
}
if (shouldClear) {
this.clearPreventShrinking();
}
}
};

public render(): ReactNode {
// TODO: the classnames on the div and ol could do with being updated to
// reflect the fact that we don't necessarily contain a list of messages.
Expand Down
3 changes: 0 additions & 3 deletions src/components/structures/TimelinePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,6 @@ class TimelinePanel extends React.Component<IProps, IState> {
}

this.setState(updatedState as IState, () => {
this.messagePanel.current?.updateTimelineMinHeight();
if (callRMUpdated) {
this.props.onReadMarkerUpdated?.();
}
Expand Down Expand Up @@ -1447,8 +1446,6 @@ class TimelinePanel extends React.Component<IProps, IState> {
const onLoaded = (): void => {
if (this.unmounted) return;

// clear the timeline min-height when (re)loading the timeline
this.messagePanel.current?.onTimelineReset();
this.reloadEvents();

// If we switched away from the room while there were pending
Expand Down
Loading
Loading