Read Receipts "Fall from the Sky" (#8414)

* fix: don't pass hideTitle to base avatar
* fix: correctly position read receipt markers
t3chguy/dedup-icons-17oct
Janne Mareike Koschinski 2022-04-26 18:09:41 +02:00 committed by GitHub
parent 942ca74316
commit e718242912
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 79 additions and 30 deletions

View File

@ -107,8 +107,16 @@ export default class MemberAvatar extends React.PureComponent<IProps, IState> {
} }
render() { render() {
// eslint-disable-next-line @typescript-eslint/no-unused-vars let {
let { member, fallbackUserId, onClick, viewUserOnClick, forceHistorical, ...otherProps } = this.props; member,
fallbackUserId,
onClick,
viewUserOnClick,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
forceHistorical,
hideTitle,
...otherProps
} = this.props;
const userId = member ? member.userId : fallbackUserId; const userId = member ? member.userId : fallbackUserId;
if (viewUserOnClick) { if (viewUserOnClick) {
@ -125,7 +133,7 @@ export default class MemberAvatar extends React.PureComponent<IProps, IState> {
<BaseAvatar <BaseAvatar
{...otherProps} {...otherProps}
name={this.state.name} name={this.state.name}
title={this.props.hideTitle ? undefined : this.state.title} title={hideTitle ? undefined : this.state.title}
idName={userId} idName={userId}
url={this.state.imageUrl} url={this.state.imageUrl}
onClick={onClick} onClick={onClick}

View File

@ -22,6 +22,7 @@ import { logger } from "matrix-js-sdk/src/logger";
import NodeAnimator from "../../../NodeAnimator"; import NodeAnimator from "../../../NodeAnimator";
import { toPx } from "../../../utils/units"; import { toPx } from "../../../utils/units";
import MemberAvatar from '../avatars/MemberAvatar'; import MemberAvatar from '../avatars/MemberAvatar';
import { READ_AVATAR_SIZE } from "./ReadReceiptGroup";
export interface IReadReceiptInfo { export interface IReadReceiptInfo {
top?: number; top?: number;
@ -101,10 +102,7 @@ export default class ReadReceiptMarker extends React.PureComponent<IProps, IStat
return; return;
} }
const avatarNode = this.avatar.current; this.buildReadReceiptInfo(rrInfo);
rrInfo.top = avatarNode.offsetTop;
rrInfo.right = avatarNode.getBoundingClientRect().right - avatarNode.offsetParent.getBoundingClientRect().right;
rrInfo.parent = avatarNode.offsetParent;
} }
public componentDidMount(): void { public componentDidMount(): void {
@ -123,42 +121,85 @@ export default class ReadReceiptMarker extends React.PureComponent<IProps, IStat
} }
} }
private animateMarker(): void { private buildReadReceiptInfo(target: IReadReceiptInfo = {}): IReadReceiptInfo {
// treat new RRs as though they were off the top of the screen const element = this.avatar.current;
let oldTop = -15; // this is the mx_ReadReceiptsGroup_container
const horizontalContainer = element.offsetParent;
const oldInfo = this.props.readReceiptInfo; if (!horizontalContainer || !(horizontalContainer instanceof HTMLElement)) {
if (oldInfo && oldInfo.parent) {
oldTop = oldInfo.top + oldInfo.parent.getBoundingClientRect().top;
}
const newElement = this.avatar.current;
let startTopOffset;
if (!newElement.offsetParent) {
// this seems to happen sometimes for reasons I don't understand // this seems to happen sometimes for reasons I don't understand
// the docs for `offsetParent` say it may be null if `display` is // the docs for `offsetParent` say it may be null if `display` is
// `none`, but I can't see why that would happen. // `none`, but I can't see why that would happen.
logger.warn( logger.warn(
`ReadReceiptMarker for ${this.props.fallbackUserId} in has no offsetParent`, `ReadReceiptMarker for ${this.props.fallbackUserId} has no valid horizontalContainer`,
); );
startTopOffset = 0;
} else { target.top = 0;
startTopOffset = oldTop - newElement.offsetParent.getBoundingClientRect().top; target.right = 0;
target.parent = null;
return;
} }
// this is the mx_ReadReceiptsGroup
const verticalContainer = horizontalContainer.offsetParent;
if (!verticalContainer || !(verticalContainer instanceof HTMLElement)) {
// this seems to happen sometimes for reasons I don't understand
// the docs for `offsetParent` say it may be null if `display` is
// `none`, but I can't see why that would happen.
logger.warn(
`ReadReceiptMarker for ${this.props.fallbackUserId} has no valid verticalContainer`,
);
target.top = 0;
target.right = 0;
target.parent = null;
return;
}
target.top = element.offsetTop;
target.right = element.getBoundingClientRect().right - horizontalContainer.getBoundingClientRect().right;
target.parent = verticalContainer;
return target;
}
private readReceiptPosition(info: IReadReceiptInfo): number {
if (!info.parent) {
// this seems to happen sometimes for reasons I don't understand
// the docs for `offsetParent` say it may be null if `display` is
// `none`, but I can't see why that would happen.
logger.warn(
`ReadReceiptMarker for ${this.props.fallbackUserId} has no offsetParent`,
);
return 0;
}
return info.top + info.parent.getBoundingClientRect().top;
}
private animateMarker(): void {
const oldInfo = this.props.readReceiptInfo;
const newInfo = this.buildReadReceiptInfo();
const newPosition = this.readReceiptPosition(newInfo);
const oldPosition = oldInfo
// start at the old height and in the old h pos
? this.readReceiptPosition(oldInfo)
// treat new RRs as though they were off the top of the screen
: -READ_AVATAR_SIZE;
const startStyles = []; const startStyles = [];
if (oldInfo && oldInfo.right) { if (oldInfo && oldInfo.right) {
// start at the old height and in the old h pos startStyles.push({
startStyles.push({ top: startTopOffset+"px", top: oldPosition - newPosition,
right: toPx(oldInfo.right) }); right: oldInfo.right,
});
} }
startStyles.push({
startStyles.push({ top: startTopOffset+'px', right: '0' }); top: oldPosition - newPosition,
right: 0,
});
this.setState({ this.setState({
suppressDisplay: false, suppressDisplay: false,
startStyles: startStyles, startStyles,
}); });
} }