Fix missing avatars in groups

This commit is contained in:
Evan Hahn 2021-01-27 15:15:43 -06:00 committed by GitHub
parent a8787e7c9e
commit 1da724edf2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 182 additions and 92 deletions

View file

@ -103,10 +103,6 @@
margin-left: 32px; margin-left: 32px;
} }
.module-message--incoming.module-message--group {
margin-left: 52px;
}
.module-message__buttons { .module-message__buttons {
position: absolute; position: absolute;
top: 0; top: 0;
@ -298,6 +294,11 @@
right: 8px; right: 8px;
} }
.module-message__container-outer {
line-height: 0;
display: flex;
flex-direction: column;
}
.module-message__container { .module-message__container {
position: relative; position: relative;
display: inline-block; display: inline-block;
@ -1387,13 +1388,21 @@
} }
} }
.module-message__author-avatar-container {
align-items: flex-end;
display: flex;
justify-content: center;
margin-right: 8px;
&--with-reactions {
padding-bottom: 12px;
}
}
.module-message__author-avatar { .module-message__author-avatar {
@include button-reset; @include button-reset;
cursor: pointer; cursor: pointer;
position: absolute;
bottom: 0px;
right: calc(100% + 8px);
&:focus { &:focus {
outline: none; outline: none;
@ -1415,11 +1424,21 @@
} }
.module-message__reactions { .module-message__reactions {
position: absolute; position: relative;
bottom: 0px;
z-index: 2; z-index: 2;
height: 22px; height: 22px;
display: flex; display: flex;
&--incoming {
align-self: flex-end;
padding-right: 8px;
margin-left: 8px;
}
&--outgoing {
align-self: flex-start;
padding-left: 8px;
margin-right: 8px;
}
} }
.module-message__reactions__reaction { .module-message__reactions__reaction {
@ -10764,8 +10783,16 @@ $contact-modal-padding: 18px;
// 2px to allow for 1px border // 2px to allow for 1px border
max-width: 302px; max-width: 302px;
&--incoming {
align-self: flex-start;
}
&--outgoing {
align-self: flex-end;
}
&--with-reactions { &--with-reactions {
margin-bottom: 12px; margin-bottom: -10px;
} }
&--deleted-for-everyone { &--deleted-for-everyone {

View file

@ -1,4 +1,4 @@
// Copyright 2020 Signal Messenger, LLC // Copyright 2020-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import * as React from 'react'; import * as React from 'react';
@ -201,7 +201,7 @@ story.add('Older', () => {
return renderBothDirections(props); return renderBothDirections(props);
}); });
story.add('Reactions', () => { story.add('Reactions (wider message)', () => {
const props = createProps({ const props = createProps({
text: 'Hello there from a pal!', text: 'Hello there from a pal!',
timestamp: Date.now() - 180 * 24 * 60 * 60 * 1000, timestamp: Date.now() - 180 * 24 * 60 * 60 * 1000,
@ -293,6 +293,98 @@ story.add('Reactions', () => {
return renderBothDirections(props); return renderBothDirections(props);
}); });
story.add('Reactions (short message)', () => {
const props = createProps({
text: 'h',
timestamp: Date.now(),
reactions: [
{
emoji: '👍',
from: {
isMe: true,
id: '+14155552672',
phoneNumber: '+14155552672',
name: 'Me',
title: 'Me',
},
timestamp: Date.now(),
},
{
emoji: '👍',
from: {
id: '+14155552672',
phoneNumber: '+14155552672',
name: 'Amelia Briggs',
title: 'Amelia',
},
timestamp: Date.now(),
},
{
emoji: '👍',
from: {
id: '+14155552673',
phoneNumber: '+14155552673',
name: 'Amelia Briggs',
title: 'Amelia',
},
timestamp: Date.now(),
},
{
emoji: '😂',
from: {
id: '+14155552674',
phoneNumber: '+14155552674',
name: 'Amelia Briggs',
title: 'Amelia',
},
timestamp: Date.now(),
},
{
emoji: '😂',
from: {
id: '+14155552676',
phoneNumber: '+14155552676',
name: 'Amelia Briggs',
title: 'Amelia',
},
timestamp: Date.now(),
},
{
emoji: '😡',
from: {
id: '+14155552677',
phoneNumber: '+14155552677',
name: 'Amelia Briggs',
title: 'Amelia',
},
timestamp: Date.now(),
},
{
emoji: '👎',
from: {
id: '+14155552678',
phoneNumber: '+14155552678',
name: 'Amelia Briggs',
title: 'Amelia',
},
timestamp: Date.now(),
},
{
emoji: '❤️',
from: {
id: '+14155552679',
phoneNumber: '+14155552679',
name: 'Amelia Briggs',
title: 'Amelia',
},
timestamp: Date.now(),
},
],
});
return renderBothDirections(props);
});
story.add('Avatar in Group', () => { story.add('Avatar in Group', () => {
const props = createProps({ const props = createProps({
authorAvatarPath: pngUrl, authorAvatarPath: pngUrl,

View file

@ -1,10 +1,9 @@
// Copyright 2018-2020 Signal Messenger, LLC // Copyright 2018-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import React from 'react'; import React from 'react';
import ReactDOM, { createPortal } from 'react-dom'; import ReactDOM, { createPortal } from 'react-dom';
import classNames from 'classnames'; import classNames from 'classnames';
import Measure from 'react-measure';
import { drop, groupBy, orderBy, take } from 'lodash'; import { drop, groupBy, orderBy, take } from 'lodash';
import { ContextMenu, ContextMenuTrigger, MenuItem } from 'react-contextmenu'; import { ContextMenu, ContextMenuTrigger, MenuItem } from 'react-contextmenu';
import { Manager, Popper, Reference } from 'react-popper'; import { Manager, Popper, Reference } from 'react-popper';
@ -203,7 +202,6 @@ type State = {
isWide: boolean; isWide: boolean;
containerWidth: number;
canDeleteForEveryone: boolean; canDeleteForEveryone: boolean;
}; };
@ -252,7 +250,6 @@ export class Message extends React.PureComponent<Props, State> {
isWide: this.wideMl.matches, isWide: this.wideMl.matches,
containerWidth: 0,
canDeleteForEveryone: props.canDeleteForEveryone, canDeleteForEveryone: props.canDeleteForEveryone,
}; };
} }
@ -286,6 +283,11 @@ export class Message extends React.PureComponent<Props, State> {
return newState; return newState;
} }
private hasReactions(): boolean {
const { reactions } = this.props;
return Boolean(reactions && reactions.length);
}
public handleWideMlChange = (event: MediaQueryListEvent): void => { public handleWideMlChange = (event: MediaQueryListEvent): void => {
this.setState({ isWide: event.matches }); this.setState({ isWide: event.matches });
}; };
@ -532,7 +534,6 @@ export class Message extends React.PureComponent<Props, State> {
expirationTimestamp, expirationTimestamp,
isSticker, isSticker,
isTapToViewExpired, isTapToViewExpired,
reactions,
status, status,
text, text,
textPending, textPending,
@ -544,7 +545,6 @@ export class Message extends React.PureComponent<Props, State> {
const isShowingImage = this.isShowingImage(); const isShowingImage = this.isShowingImage();
const withImageNoCaption = Boolean(!isSticker && !text && isShowingImage); const withImageNoCaption = Boolean(!isSticker && !text && isShowingImage);
const withReactions = reactions && reactions.length > 0;
const metadataDirection = isSticker ? undefined : direction; const metadataDirection = isSticker ? undefined : direction;
return ( return (
@ -552,7 +552,9 @@ export class Message extends React.PureComponent<Props, State> {
className={classNames( className={classNames(
'module-message__metadata', 'module-message__metadata',
`module-message__metadata--${direction}`, `module-message__metadata--${direction}`,
withReactions ? 'module-message__metadata--with-reactions' : null, this.hasReactions()
? 'module-message__metadata--with-reactions'
: null,
withImageNoCaption withImageNoCaption
? 'module-message__metadata--with-image-no-caption' ? 'module-message__metadata--with-image-no-caption'
: null : null
@ -1061,6 +1063,11 @@ export class Message extends React.PureComponent<Props, State> {
} }
return ( return (
<div
className={classNames('module-message__author-avatar-container', {
'module-message__author-avatar-container--with-reactions': this.hasReactions(),
})}
>
<button <button
type="button" type="button"
className="module-message__author-avatar" className="module-message__author-avatar"
@ -1079,6 +1086,7 @@ export class Message extends React.PureComponent<Props, State> {
size={28} size={28}
/> />
</button> </button>
</div>
); );
} }
@ -1718,9 +1726,9 @@ export class Message extends React.PureComponent<Props, State> {
}; };
public renderReactions(outgoing: boolean): JSX.Element | null { public renderReactions(outgoing: boolean): JSX.Element | null {
const { reactions, i18n } = this.props; const { reactions = [], i18n } = this.props;
if (!reactions || (reactions && reactions.length === 0)) { if (!this.hasReactions()) {
return null; return null;
} }
@ -1763,25 +1771,7 @@ export class Message extends React.PureComponent<Props, State> {
someNotRendered && someNotRendered &&
maybeNotRendered.some(res => res.some(re => Boolean(re.from.isMe))); maybeNotRendered.some(res => res.some(re => Boolean(re.from.isMe)));
const { reactionViewerRoot, containerWidth } = this.state; const { reactionViewerRoot } = this.state;
// Calculate the width of the reactions container
const reactionsWidth = toRender.reduce((sum, res, i, arr) => {
if (someNotRendered && i === arr.length - 1) {
return sum + 28;
}
if (res.count > 1) {
return sum + 40;
}
return sum + 28;
}, 0);
const reactionsXAxisOffset = Math.max(
containerWidth - reactionsWidth - 6,
6
);
const popperPlacement = outgoing ? 'bottom-end' : 'bottom-start'; const popperPlacement = outgoing ? 'bottom-end' : 'bottom-start';
@ -1800,9 +1790,6 @@ export class Message extends React.PureComponent<Props, State> {
? 'module-message__reactions--outgoing' ? 'module-message__reactions--outgoing'
: 'module-message__reactions--incoming' : 'module-message__reactions--incoming'
)} )}
style={{
[outgoing ? 'right' : 'left']: `${reactionsXAxisOffset}px`,
}}
> >
{toRender.map((re, i) => { {toRender.map((re, i) => {
const isLast = i === toRender.length - 1; const isLast = i === toRender.length - 1;
@ -2101,7 +2088,6 @@ export class Message extends React.PureComponent<Props, State> {
isTapToView, isTapToView,
isTapToViewExpired, isTapToViewExpired,
isTapToViewError, isTapToViewError,
reactions,
} = this.props; } = this.props;
const { isSelected } = this.state; const { isSelected } = this.state;
@ -2131,9 +2117,7 @@ export class Message extends React.PureComponent<Props, State> {
isTapToViewError isTapToViewError
? 'module-message__container--with-tap-to-view-error' ? 'module-message__container--with-tap-to-view-error'
: null, : null,
reactions && reactions.length > 0 this.hasReactions() ? 'module-message__container--with-reactions' : null,
? 'module-message__container--with-reactions'
: null,
deletedForEveryone deletedForEveryone
? 'module-message__container--deleted-for-everyone' ? 'module-message__container--deleted-for-everyone'
: null : null
@ -2143,24 +2127,13 @@ export class Message extends React.PureComponent<Props, State> {
}; };
return ( return (
<Measure <div className="module-message__container-outer">
bounds <div className={containerClassnames} style={containerStyles}>
onResize={({ bounds = { width: 0 } }) => {
this.setState({ containerWidth: bounds.width });
}}
>
{({ measureRef }) => (
<div
ref={measureRef}
className={containerClassnames}
style={containerStyles}
>
{this.renderAuthor()} {this.renderAuthor()}
{this.renderContents()} {this.renderContents()}
{this.renderAvatar()}
</div> </div>
)} {this.renderReactions(direction === 'outgoing')}
</Measure> </div>
); );
} }
@ -2168,7 +2141,6 @@ export class Message extends React.PureComponent<Props, State> {
const { const {
authorPhoneNumber, authorPhoneNumber,
attachments, attachments,
conversationType,
direction, direction,
id, id,
isSticker, isSticker,
@ -2194,8 +2166,7 @@ export class Message extends React.PureComponent<Props, State> {
'module-message', 'module-message',
`module-message--${direction}`, `module-message--${direction}`,
isSelected ? 'module-message--selected' : null, isSelected ? 'module-message--selected' : null,
expiring ? 'module-message--expired' : null, expiring ? 'module-message--expired' : null
conversationType === 'group' ? 'module-message--group' : null
)} )}
tabIndex={0} tabIndex={0}
// We pretend to be a button because we sometimes contain buttons and a button // We pretend to be a button because we sometimes contain buttons and a button
@ -2208,11 +2179,11 @@ export class Message extends React.PureComponent<Props, State> {
> >
{this.renderError(direction === 'incoming')} {this.renderError(direction === 'incoming')}
{this.renderMenu(direction === 'outgoing', triggerId)} {this.renderMenu(direction === 'outgoing', triggerId)}
{this.renderAvatar()}
{this.renderContainer()} {this.renderContainer()}
{this.renderError(direction === 'outgoing')} {this.renderError(direction === 'outgoing')}
{this.renderMenu(direction === 'incoming', triggerId)} {this.renderMenu(direction === 'incoming', triggerId)}
{this.renderContextMenu(triggerId)} {this.renderContextMenu(triggerId)}
{this.renderReactions(direction === 'outgoing')}
</div> </div>
); );
} }

View file

@ -14815,7 +14815,7 @@
"rule": "React-createRef", "rule": "React-createRef",
"path": "ts/components/conversation/Message.js", "path": "ts/components/conversation/Message.js",
"line": " this.audioRef = react_1.default.createRef();", "line": " this.audioRef = react_1.default.createRef();",
"lineNumber": 74, "lineNumber": 73,
"reasonCategory": "usageTrusted", "reasonCategory": "usageTrusted",
"updated": "2020-08-28T16:12:19.904Z" "updated": "2020-08-28T16:12:19.904Z"
}, },
@ -14823,7 +14823,7 @@
"rule": "React-createRef", "rule": "React-createRef",
"path": "ts/components/conversation/Message.js", "path": "ts/components/conversation/Message.js",
"line": " this.focusRef = react_1.default.createRef();", "line": " this.focusRef = react_1.default.createRef();",
"lineNumber": 75, "lineNumber": 74,
"reasonCategory": "usageTrusted", "reasonCategory": "usageTrusted",
"updated": "2020-09-11T17:24:56.124Z", "updated": "2020-09-11T17:24:56.124Z",
"reasonDetail": "Used for managing focus only" "reasonDetail": "Used for managing focus only"
@ -14832,7 +14832,7 @@
"rule": "React-createRef", "rule": "React-createRef",
"path": "ts/components/conversation/Message.js", "path": "ts/components/conversation/Message.js",
"line": " this.reactionsContainerRef = react_1.default.createRef();", "line": " this.reactionsContainerRef = react_1.default.createRef();",
"lineNumber": 76, "lineNumber": 75,
"reasonCategory": "usageTrusted", "reasonCategory": "usageTrusted",
"updated": "2020-08-28T16:12:19.904Z", "updated": "2020-08-28T16:12:19.904Z",
"reasonDetail": "Used for detecting clicks outside reaction viewer" "reasonDetail": "Used for detecting clicks outside reaction viewer"
@ -14841,7 +14841,7 @@
"rule": "React-createRef", "rule": "React-createRef",
"path": "ts/components/conversation/Message.tsx", "path": "ts/components/conversation/Message.tsx",
"line": " public audioRef: React.RefObject<HTMLAudioElement> = React.createRef();", "line": " public audioRef: React.RefObject<HTMLAudioElement> = React.createRef();",
"lineNumber": 216, "lineNumber": 214,
"reasonCategory": "usageTrusted", "reasonCategory": "usageTrusted",
"updated": "2020-09-08T20:19:01.913Z" "updated": "2020-09-08T20:19:01.913Z"
}, },
@ -14849,7 +14849,7 @@
"rule": "React-createRef", "rule": "React-createRef",
"path": "ts/components/conversation/Message.tsx", "path": "ts/components/conversation/Message.tsx",
"line": " public focusRef: React.RefObject<HTMLDivElement> = React.createRef();", "line": " public focusRef: React.RefObject<HTMLDivElement> = React.createRef();",
"lineNumber": 218, "lineNumber": 216,
"reasonCategory": "usageTrusted", "reasonCategory": "usageTrusted",
"updated": "2020-09-08T20:19:01.913Z" "updated": "2020-09-08T20:19:01.913Z"
}, },
@ -14857,7 +14857,7 @@
"rule": "React-createRef", "rule": "React-createRef",
"path": "ts/components/conversation/Message.tsx", "path": "ts/components/conversation/Message.tsx",
"line": " > = React.createRef();", "line": " > = React.createRef();",
"lineNumber": 222, "lineNumber": 220,
"reasonCategory": "usageTrusted", "reasonCategory": "usageTrusted",
"updated": "2020-08-28T19:36:40.817Z" "updated": "2020-08-28T19:36:40.817Z"
}, },