Page MenuHomePhabricator

D7067.id24033.diff
No OneTemporary

D7067.id24033.diff

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

Mime Type
text/plain
Expires
Mon, Nov 25, 12:28 PM (21 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2579428
Default Alt Text
D7067.id24033.diff (12 KB)

Event Timeline