Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3360276
D7067.id24006.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
13 KB
Referenced Files
None
Subscribers
None
D7067.id24006.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,19 @@
styles.alignment,
{ marginBottom: containerMarginBottom },
];
- const messageBoxStyle = { maxWidth: composedMessageMaxWidth };
+ const messageBoxStyle = [{ maxWidth: composedMessageMaxWidth }];
+ if (shouldRenderAvatars) {
+ messageBoxStyle.push(styles.swipeableContainer);
+ }
+ const messageBoxStyleContainerStyle = [styles.messageBox];
+ if (shouldRenderAvatars) {
+ messageBoxStyleContainerStyle.push({ flex: 1 });
+
+ const positioningStyle = isViewer
+ ? { alignItems: 'flex-end' }
+ : { alignItems: 'flex-start' };
+ messageBoxStyleContainerStyle.push(positioningStyle);
+ }
let deliveryIcon = null;
let failedSendInfo = null;
@@ -121,8 +139,21 @@
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}
@@ -130,6 +161,7 @@
messageBoxStyle={messageBoxStyle}
threadColor={item.threadInfo.color}
>
+ {avatar}
<AnimatedView style={{ opacity: contentAndHeaderOpacity }}>
{children}
</AnimatedView>
@@ -143,10 +175,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 +226,12 @@
marginLeft: composedMessageStyle.marginLeft,
marginRight: composedMessageStyle.marginRight,
},
+ avatarContainer: {
+ marginRight: 8,
+ },
+ avatarOffset: {
+ width: avatarOffset,
+ },
content: {
alignItems: 'center',
flexDirection: 'row-reverse',
@@ -223,6 +268,10 @@
right: inlineEngagementRightStyle.marginRight,
top: inlineEngagementRightStyle.topOffset,
},
+ swipeableContainer: {
+ alignItems: 'flex-end',
+ flexDirection: 'row',
+ },
});
const ConnectedComposedMessage: React.ComponentType<BaseProps> =
@@ -233,6 +282,8 @@
const navigateToSidebar = useNavigateToSidebar(props.item);
const contentAndHeaderOpacity = useContentAndHeaderOpacity(props.item);
const deliveryIconOpacity = useDeliveryIconOpacity(props.item);
+ const shouldRenderAvatars = useShouldRenderAvatars();
+
return (
<ComposedMessage
{...props}
@@ -242,6 +293,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/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
@@ -1,12 +1,15 @@
// @flow
import * as React from 'react';
+import { StyleSheet, View } from 'react-native';
import Animated from 'react-native-reanimated';
import EmojiPicker from 'rn-emoji-keyboard';
+import { getAvatarForUser } from 'lib/shared/avatar-utils.js';
import { localIDPrefix } from 'lib/shared/message-utils.js';
import { useCanCreateReactionFromMessage } from 'lib/shared/reaction-utils.js';
+import { avatarOffset } from './chat-constants.js';
import { TooltipInlineEngagement } from './inline-engagement.react.js';
import { InnerMultimediaMessage } from './inner-multimedia-message.react.js';
import { MessageHeader } from './message-header.react.js';
@@ -14,10 +17,12 @@
import ReactionSelectionPopover from './reaction-selection-popover.react.js';
import SidebarInputBarHeightMeasurer from './sidebar-input-bar-height-measurer.react.js';
import { useAnimatedMessageTooltipButton } from './utils.js';
+import Avatar from '../components/avatar.react.js';
import type { AppNavigationProp } from '../navigation/app-navigator.react.js';
import { useSelector } from '../redux/redux-utils.js';
import { useTooltipActions } from '../tooltip/tooltip-hooks.js';
import type { TooltipRoute } from '../tooltip/tooltip.react.js';
+import { useShouldRenderAvatars } from '../utils/avatar-utils.js';
/* eslint-disable import/no-named-as-default-member */
const { Node, Extrapolate, interpolateNode } = Animated;
@@ -151,6 +156,23 @@
[sendReaction, dismissTooltip],
);
+ const avatarInfo = React.useMemo(
+ () => getAvatarForUser(item.messageInfo.creator),
+ [item.messageInfo.creator],
+ );
+ const shouldRenderAvatars = useShouldRenderAvatars();
+
+ const avatar = React.useMemo(() => {
+ if (item.messageInfo.creator.isViewer || !shouldRenderAvatars) {
+ return null;
+ }
+ return (
+ <View style={styles.avatarContainer}>
+ <Avatar size="small" avatarInfo={avatarInfo} />
+ </View>
+ );
+ }, [avatarInfo, item.messageInfo.creator.isViewer, shouldRenderAvatars]);
+
return (
<>
<Animated.View style={messageContainerStyle}>
@@ -161,6 +183,7 @@
<Animated.View style={headerStyle}>
<MessageHeader item={item} focused={true} display="modal" />
</Animated.View>
+ {avatar}
{reactionSelectionPopover}
{innerMultimediaMessage}
{inlineEngagement}
@@ -174,4 +197,12 @@
);
}
+const styles = StyleSheet.create({
+ avatarContainer: {
+ bottom: 0,
+ left: -avatarOffset,
+ position: 'absolute',
+ },
+});
+
export default MultimediaMessageTooltipButton;
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
@@ -1,12 +1,15 @@
// @flow
import * as React from 'react';
+import { StyleSheet, View } from 'react-native';
import Animated from 'react-native-reanimated';
import EmojiPicker from 'rn-emoji-keyboard';
+import { getAvatarForUser } from 'lib/shared/avatar-utils.js';
import { localIDPrefix } from 'lib/shared/message-utils.js';
import { useCanCreateReactionFromMessage } from 'lib/shared/reaction-utils.js';
+import { avatarOffset } from './chat-constants.js';
import { TooltipInlineEngagement } from './inline-engagement.react.js';
import { InnerTextMessage } from './inner-text-message.react.js';
import { MessageHeader } from './message-header.react.js';
@@ -16,10 +19,12 @@
import ReactionSelectionPopover from './reaction-selection-popover.react.js';
import SidebarInputBarHeightMeasurer from './sidebar-input-bar-height-measurer.react.js';
import { useAnimatedMessageTooltipButton } from './utils.js';
+import Avatar from '../components/avatar.react.js';
import type { AppNavigationProp } from '../navigation/app-navigator.react.js';
import { useSelector } from '../redux/redux-utils.js';
import { useTooltipActions } from '../tooltip/tooltip-hooks.js';
import type { TooltipRoute } from '../tooltip/tooltip.react.js';
+import { useShouldRenderAvatars } from '../utils/avatar-utils.js';
/* eslint-disable import/no-named-as-default-member */
const { Node, interpolateNode, Extrapolate } = Animated;
@@ -148,6 +153,23 @@
[sendReaction, dismissTooltip],
);
+ const avatarInfo = React.useMemo(
+ () => getAvatarForUser(item.messageInfo.creator),
+ [item.messageInfo.creator],
+ );
+ const shouldRenderAvatars = useShouldRenderAvatars();
+
+ const avatar = React.useMemo(() => {
+ if (item.messageInfo.creator.isViewer || !shouldRenderAvatars) {
+ return null;
+ }
+ return (
+ <View style={styles.avatarContainer}>
+ <Avatar size="small" avatarInfo={avatarInfo} />
+ </View>
+ );
+ }, [avatarInfo, item.messageInfo.creator.isViewer, shouldRenderAvatars]);
+
return (
<MessageListContextProvider threadInfo={threadInfo}>
<SidebarInputBarHeightMeasurer
@@ -158,6 +180,7 @@
<Animated.View style={headerStyle}>
<MessageHeader item={item} focused={true} display="modal" />
</Animated.View>
+ {avatar}
{reactionSelectionPopover}
<MessagePressResponderContext.Provider
value={messagePressResponderContext}
@@ -180,4 +203,12 @@
);
}
+const styles = StyleSheet.create({
+ avatarContainer: {
+ bottom: 0,
+ left: -avatarOffset,
+ position: 'absolute',
+ },
+});
+
export default TextMessageTooltipButton;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Nov 25, 12:33 PM (22 h, 5 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2579733
Default Alt Text
D7067.id24006.diff (13 KB)
Attached To
Mode
D7067: [native] render user avatars in chat screen
Attached
Detach File
Event Timeline
Log In to Comment