Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3359822
D7067.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
12 KB
Referenced Files
None
Subscribers
None
D7067.diff
View Options
diff --git a/native/chat/chat-constants.js b/native/chat/chat-constants.js
--- a/native/chat/chat-constants.js
+++ b/native/chat/chat-constants.js
@@ -24,3 +24,5 @@
};
export const clusterEndHeight = 7;
+
+export const avatarOffset = 32;
diff --git a/native/chat/composed-message-width.js b/native/chat/composed-message-width.js
--- a/native/chat/composed-message-width.js
+++ b/native/chat/composed-message-width.js
@@ -1,6 +1,8 @@
// @flow
+import { avatarOffset } from './chat-constants.js';
import { useSelector } from '../redux/redux-utils.js';
+import { useShouldRenderAvatars } from '../utils/avatar-utils.js';
function useMessageListScreenWidth(): number {
return useSelector(state => {
@@ -12,6 +14,12 @@
// Keep sorta synced with styles.alignment/styles.messageBox in ComposedMessage
function useComposedMessageMaxWidth(): number {
const messageListScreenWidth = useMessageListScreenWidth();
+ const shouldRenderAvatars = useShouldRenderAvatars();
+
+ if (shouldRenderAvatars) {
+ return (messageListScreenWidth - 24 - avatarOffset) * 0.8;
+ }
+
return (messageListScreenWidth - 24) * 0.8;
}
diff --git a/native/chat/composed-message.react.js b/native/chat/composed-message.react.js
--- a/native/chat/composed-message.react.js
+++ b/native/chat/composed-message.react.js
@@ -6,6 +6,7 @@
import { StyleSheet, View } from 'react-native';
import Animated from 'react-native-reanimated';
+import { getAvatarForUser } from 'lib/shared/avatar-utils.js';
import { createMessageReply } from 'lib/shared/message-utils.js';
import { assertComposableMessageType } from 'lib/types/message-types.js';
@@ -15,6 +16,7 @@
inlineEngagementLeftStyle,
inlineEngagementRightStyle,
composedMessageStyle,
+ avatarOffset,
} from './chat-constants.js';
import { useComposedMessageMaxWidth } from './composed-message-width.js';
import { FailedSend } from './failed-send.react.js';
@@ -23,10 +25,12 @@
import { useNavigateToSidebar } from './sidebar-navigation.js';
import SwipeableMessage from './swipeable-message.react.js';
import { useContentAndHeaderOpacity, useDeliveryIconOpacity } from './utils.js';
+import Avatar from '../components/avatar.react.js';
import { type InputState, InputStateContext } from '../input/input-state.js';
import { type Colors, useColors } from '../themes/colors.js';
import type { ChatMessageInfoItemWithHeight } from '../types/chat-types.js';
import { type AnimatedStyleObj, AnimatedView } from '../types/styles.js';
+import { useShouldRenderAvatars } from '../utils/avatar-utils.js';
/* eslint-disable import/no-named-as-default-member */
const { Node } = Animated;
@@ -51,6 +55,7 @@
// withInputState
+inputState: ?InputState,
+navigateToSidebar: () => mixed,
+ +shouldRenderAvatars: boolean,
};
class ComposedMessage extends React.PureComponent<Props> {
render() {
@@ -67,6 +72,7 @@
navigateToSidebar,
contentAndHeaderOpacity,
deliveryIconOpacity,
+ shouldRenderAvatars,
...viewProps
} = this.props;
const { id, creator } = item.messageInfo;
@@ -85,7 +91,16 @@
styles.alignment,
{ marginBottom: containerMarginBottom },
];
- const messageBoxStyle = { maxWidth: composedMessageMaxWidth };
+ const swipeableMessageBoxStyle = [
+ styles.swipeableContainer,
+ { maxWidth: composedMessageMaxWidth },
+ ];
+
+ const messageBoxStyleContainerStyle = [styles.messageBoxContainer];
+ const positioningStyle = isViewer
+ ? { alignItems: 'flex-end' }
+ : { alignItems: 'flex-start' };
+ messageBoxStyleContainerStyle.push(positioningStyle);
let deliveryIcon = null;
let failedSendInfo = null;
@@ -121,15 +136,29 @@
swipeOptions === 'sidebar' || swipeOptions === 'both'
? navigateToSidebar
: undefined;
+
+ let avatar;
+ if (!isViewer && item.endsCluster && shouldRenderAvatars) {
+ const avatarInfo = getAvatarForUser(item.messageInfo.creator);
+ avatar = (
+ <View style={styles.avatarContainer}>
+ <Avatar size="small" avatarInfo={avatarInfo} />
+ </View>
+ );
+ } else if (!isViewer && shouldRenderAvatars) {
+ avatar = <View style={styles.avatarOffset} />;
+ }
+
const messageBox = (
- <View style={styles.messageBox}>
+ <View style={messageBoxStyleContainerStyle}>
<SwipeableMessage
triggerReply={triggerReply}
triggerSidebar={triggerSidebar}
isViewer={isViewer}
- messageBoxStyle={messageBoxStyle}
+ messageBoxStyle={swipeableMessageBoxStyle}
threadColor={item.threadInfo.color}
>
+ {avatar}
<AnimatedView style={{ opacity: contentAndHeaderOpacity }}>
{children}
</AnimatedView>
@@ -143,10 +172,17 @@
Object.keys(item.reactions).length > 0
) {
const positioning = isViewer ? 'right' : 'left';
- const inlineEngagementPositionStyle =
- positioning === 'left'
- ? styles.leftInlineEngagement
- : styles.rightInlineEngagement;
+
+ const inlineEngagementPositionStyle = [];
+ if (positioning === 'left') {
+ inlineEngagementPositionStyle.push(styles.leftInlineEngagement);
+ } else {
+ inlineEngagementPositionStyle.push(styles.rightInlineEngagement);
+ }
+ if (this.props.shouldRenderAvatars) {
+ inlineEngagementPositionStyle.push({ marginLeft: avatarOffset });
+ }
+
inlineEngagement = (
<View style={[styles.inlineEngagement, inlineEngagementPositionStyle]}>
<InlineEngagement
@@ -187,6 +223,12 @@
marginLeft: composedMessageStyle.marginLeft,
marginRight: composedMessageStyle.marginRight,
},
+ avatarContainer: {
+ marginRight: 8,
+ },
+ avatarOffset: {
+ width: avatarOffset,
+ },
content: {
alignItems: 'center',
flexDirection: 'row-reverse',
@@ -211,7 +253,8 @@
position: 'relative',
top: inlineEngagementLeftStyle.topOffset,
},
- messageBox: {
+ messageBoxContainer: {
+ flex: 1,
marginRight: 5,
},
rightChatBubble: {
@@ -223,6 +266,10 @@
right: inlineEngagementRightStyle.marginRight,
top: inlineEngagementRightStyle.topOffset,
},
+ swipeableContainer: {
+ alignItems: 'flex-end',
+ flexDirection: 'row',
+ },
});
const ConnectedComposedMessage: React.ComponentType<BaseProps> =
@@ -233,6 +280,8 @@
const navigateToSidebar = useNavigateToSidebar(props.item);
const contentAndHeaderOpacity = useContentAndHeaderOpacity(props.item);
const deliveryIconOpacity = useDeliveryIconOpacity(props.item);
+ const shouldRenderAvatars = useShouldRenderAvatars();
+
return (
<ComposedMessage
{...props}
@@ -242,6 +291,7 @@
navigateToSidebar={navigateToSidebar}
contentAndHeaderOpacity={contentAndHeaderOpacity}
deliveryIconOpacity={deliveryIconOpacity}
+ shouldRenderAvatars={shouldRenderAvatars}
/>
);
});
diff --git a/native/chat/message-header.react.js b/native/chat/message-header.react.js
--- a/native/chat/message-header.react.js
+++ b/native/chat/message-header.react.js
@@ -5,12 +5,13 @@
import { useStringForUser } from 'lib/hooks/ens-cache.js';
-import { clusterEndHeight } from './chat-constants.js';
+import { clusterEndHeight, avatarOffset } from './chat-constants.js';
import type { DisplayType } from './timestamp.react.js';
import { Timestamp, timestampHeight } from './timestamp.react.js';
import { SingleLine } from '../components/single-line.react.js';
import { useStyles } from '../themes/colors.js';
import type { ChatMessageInfoItemWithHeight } from '../types/chat-types.js';
+import { useShouldRenderAvatars } from '../utils/avatar-utils.js';
type Props = {
+item: ChatMessageInfoItemWithHeight,
@@ -27,12 +28,21 @@
const shouldShowUsername = !isViewer && (modalDisplay || item.startsCluster);
const stringForUser = useStringForUser(shouldShowUsername ? creator : null);
+ const shouldRenderAvatars = useShouldRenderAvatars();
+
let authorName = null;
if (stringForUser) {
const style = [styles.authorName];
if (modalDisplay) {
style.push(styles.modal);
}
+
+ if (shouldRenderAvatars) {
+ style.push({ marginLeft: 12 + avatarOffset });
+ } else {
+ style.push({ marginLeft: 12 });
+ }
+
authorName = <SingleLine style={style}>{stringForUser}</SingleLine>;
}
@@ -69,7 +79,6 @@
color: 'listBackgroundSecondaryLabel',
fontSize: 14,
height: authorNameHeight,
- marginLeft: 12,
marginRight: 7,
paddingHorizontal: 12,
paddingVertical: 4,
diff --git a/native/chat/message-tooltip-button-avatar.react.js b/native/chat/message-tooltip-button-avatar.react.js
new file mode 100644
--- /dev/null
+++ b/native/chat/message-tooltip-button-avatar.react.js
@@ -0,0 +1,48 @@
+// @flow
+
+import * as React from 'react';
+import { View, StyleSheet } from 'react-native';
+
+import { getAvatarForUser } from 'lib/shared/avatar-utils.js';
+
+import { avatarOffset } from './chat-constants.js';
+import Avatar from '../components/avatar.react.js';
+import type { ChatMessageInfoItemWithHeight } from '../types/chat-types.js';
+import { useShouldRenderAvatars } from '../utils/avatar-utils.js';
+
+type Props = {
+ +item: ChatMessageInfoItemWithHeight,
+};
+
+function MessageTooltipButtonAvatar(props: Props): React.Node {
+ const { item } = props;
+
+ const avatarInfo = React.useMemo(
+ () => getAvatarForUser(item.messageInfo.creator),
+ [item.messageInfo.creator],
+ );
+
+ const shouldRenderAvatars = useShouldRenderAvatars();
+
+ if (item.messageInfo.creator.isViewer || !shouldRenderAvatars) {
+ return null;
+ }
+ return (
+ <View style={styles.avatarContainer}>
+ <Avatar size="small" avatarInfo={avatarInfo} />
+ </View>
+ );
+}
+
+const styles = StyleSheet.create({
+ avatarContainer: {
+ bottom: 0,
+ left: -avatarOffset,
+ position: 'absolute',
+ },
+});
+
+const MemoizedMessageTooltipButtonAvatar: React.ComponentType<Props> =
+ React.memo(MessageTooltipButtonAvatar);
+
+export default MemoizedMessageTooltipButtonAvatar;
diff --git a/native/chat/multimedia-message-tooltip-button.react.js b/native/chat/multimedia-message-tooltip-button.react.js
--- a/native/chat/multimedia-message-tooltip-button.react.js
+++ b/native/chat/multimedia-message-tooltip-button.react.js
@@ -10,6 +10,7 @@
import { TooltipInlineEngagement } from './inline-engagement.react.js';
import { InnerMultimediaMessage } from './inner-multimedia-message.react.js';
import { MessageHeader } from './message-header.react.js';
+import MessageTooltipButtonAvatar from './message-tooltip-button-avatar.react.js';
import { useSendReaction } from './reaction-message-utils.js';
import ReactionSelectionPopover from './reaction-selection-popover.react.js';
import SidebarInputBarHeightMeasurer from './sidebar-input-bar-height-measurer.react.js';
@@ -161,6 +162,7 @@
<Animated.View style={headerStyle}>
<MessageHeader item={item} focused={true} display="modal" />
</Animated.View>
+ <MessageTooltipButtonAvatar item={item} />
{reactionSelectionPopover}
{innerMultimediaMessage}
{inlineEngagement}
diff --git a/native/chat/text-message-tooltip-button.react.js b/native/chat/text-message-tooltip-button.react.js
--- a/native/chat/text-message-tooltip-button.react.js
+++ b/native/chat/text-message-tooltip-button.react.js
@@ -12,6 +12,7 @@
import { MessageHeader } from './message-header.react.js';
import { MessageListContextProvider } from './message-list-types.js';
import { MessagePressResponderContext } from './message-press-responder-context.js';
+import MessageTooltipButtonAvatar from './message-tooltip-button-avatar.react.js';
import { useSendReaction } from './reaction-message-utils.js';
import ReactionSelectionPopover from './reaction-selection-popover.react.js';
import SidebarInputBarHeightMeasurer from './sidebar-input-bar-height-measurer.react.js';
@@ -158,6 +159,7 @@
<Animated.View style={headerStyle}>
<MessageHeader item={item} focused={true} display="modal" />
</Animated.View>
+ <MessageTooltipButtonAvatar item={item} />
{reactionSelectionPopover}
<MessagePressResponderContext.Provider
value={messagePressResponderContext}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Nov 25, 11:05 AM (19 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2579428
Default Alt Text
D7067.diff (12 KB)
Attached To
Mode
D7067: [native] render user avatars in chat screen
Attached
Detach File
Event Timeline
Log In to Comment