Page MenuHomePhabricator

D6454.id21712.diff
No OneTemporary

D6454.id21712.diff

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
@@ -3,12 +3,21 @@
import * as React from 'react';
import Animated from 'react-native-reanimated';
+import { localIDPrefix } from 'lib/shared/message-utils';
+import { useCanCreateReactionFromMessage } from 'lib/shared/reaction-utils';
+import type { SetState } from 'lib/types/hook-types';
+
import type { AppNavigationProp } from '../navigation/app-navigator.react';
import type { TooltipRoute } from '../navigation/tooltip.react';
import { useSelector } from '../redux/redux-utils';
import { TooltipInlineEngagement } from './inline-engagement.react';
import { InnerMultimediaMessage } from './inner-multimedia-message.react';
import { MessageHeader } from './message-header.react';
+import {
+ useSendReaction,
+ useReactionSelectionPopoverPosition,
+} from './reaction-message-utils';
+import ReactionSelectionPopover from './reaction-selection-popover.react';
import SidebarInputBarHeightMeasurer from './sidebar-input-bar-height-measurer.react';
import { useAnimatedMessageTooltipButton } from './utils';
@@ -23,10 +32,12 @@
+route: TooltipRoute<'MultimediaMessageTooltipModal'>,
+progress: Node,
+isOpeningSidebar: boolean,
+ +setHideTooltip: SetState<boolean>,
};
function MultimediaMessageTooltipButton(props: Props): React.Node {
+ const { navigation, progress, isOpeningSidebar, setHideTooltip } = props;
+
const windowWidth = useSelector(state => state.dimensions.width);
- const { progress } = props;
const [
sidebarInputBarHeight,
@@ -36,7 +47,13 @@
setSidebarInputBarHeight(height);
}, []);
- const { item, verticalBounds, initialCoordinates } = props.route.params;
+ const {
+ item,
+ verticalBounds,
+ initialCoordinates,
+ margin,
+ } = props.route.params;
+
const { style: messageContainerStyle } = useAnimatedMessageTooltipButton({
sourceMessage: item,
initialCoordinates,
@@ -61,8 +78,6 @@
};
}, [initialCoordinates.height, initialCoordinates.x, progress, windowWidth]);
- const { navigation, isOpeningSidebar } = props;
-
const inlineEngagement = React.useMemo(() => {
if (!item.threadCreatedFromMessage) {
return null;
@@ -79,6 +94,46 @@
);
}, [initialCoordinates, isOpeningSidebar, item, progress, windowWidth]);
+ const { messageInfo, threadInfo, reactions } = item;
+ const nextLocalID = useSelector(state => state.nextLocalID);
+ const localID = `${localIDPrefix}${nextLocalID}`;
+
+ const canCreateReactionFromMessage = useCanCreateReactionFromMessage(
+ threadInfo,
+ messageInfo,
+ );
+
+ const sendReaction = useSendReaction(messageInfo.id, localID, threadInfo.id);
+
+ const reactionSelectionPopoverPosition = useReactionSelectionPopoverPosition({
+ initialCoordinates,
+ verticalBounds,
+ margin,
+ });
+
+ const reactionSelectionPopover = React.useMemo(() => {
+ if (!canCreateReactionFromMessage) {
+ return null;
+ }
+
+ return (
+ <ReactionSelectionPopover
+ reactions={reactions}
+ setHideTooltip={setHideTooltip}
+ reactionSelectionPopoverContainerStyle={
+ reactionSelectionPopoverPosition
+ }
+ sendReaction={sendReaction}
+ />
+ );
+ }, [
+ canCreateReactionFromMessage,
+ reactionSelectionPopoverPosition,
+ reactions,
+ sendReaction,
+ setHideTooltip,
+ ]);
+
return (
<Animated.View style={messageContainerStyle}>
<SidebarInputBarHeightMeasurer
@@ -88,6 +143,7 @@
<Animated.View style={headerStyle}>
<MessageHeader item={item} focused={true} display="modal" />
</Animated.View>
+ {reactionSelectionPopover}
<InnerMultimediaMessage
item={item}
verticalBounds={verticalBounds}
diff --git a/native/chat/reaction-selection-popover.react.js b/native/chat/reaction-selection-popover.react.js
new file mode 100644
--- /dev/null
+++ b/native/chat/reaction-selection-popover.react.js
@@ -0,0 +1,100 @@
+// @flow
+
+import * as React from 'react';
+import { View, TouchableOpacity, Text } from 'react-native';
+
+import type { MessageReactionInfo } from 'lib/selectors/chat-selectors';
+import type { SetState } from 'lib/types/hook-types';
+
+import { useStyles } from '../themes/colors';
+import type { ViewStyle } from '../types/styles';
+
+type ReactionSelectionPopoverProps = {
+ +reactions: $ReadOnlyMap<string, MessageReactionInfo>,
+ +setHideTooltip: SetState<boolean>,
+ +reactionSelectionPopoverContainerStyle: ViewStyle,
+ +sendReaction: (
+ reaction: string,
+ action: 'add_reaction' | 'remove_reaction',
+ ) => mixed,
+};
+
+function ReactionSelectionPopover(
+ props: ReactionSelectionPopoverProps,
+): React.Node {
+ const {
+ reactions,
+ setHideTooltip,
+ reactionSelectionPopoverContainerStyle,
+ sendReaction,
+ } = props;
+
+ const styles = useStyles(unboundStyles);
+
+ const containerStyle = React.useMemo(
+ () => [
+ styles.reactionSelectionPopoverContainer,
+ reactionSelectionPopoverContainerStyle,
+ ],
+ [
+ reactionSelectionPopoverContainerStyle,
+ styles.reactionSelectionPopoverContainer,
+ ],
+ );
+
+ const onPressDefaultEmoji = React.useCallback(
+ (emoji: string) => {
+ const reactionInput = emoji;
+ const viewerReacted = !!reactions.get(reactionInput)?.viewerReacted;
+ const action = viewerReacted ? 'remove_reaction' : 'add_reaction';
+
+ sendReaction(reactionInput, action);
+ setHideTooltip(true);
+ },
+ [reactions, sendReaction, setHideTooltip],
+ );
+
+ const defaultEmojis = React.useMemo(() => {
+ const defaultEmojisData = ['❤️', '😆', '😮', '😠', '👍'];
+
+ return defaultEmojisData.map(emoji => (
+ <TouchableOpacity key={emoji} onPress={() => onPressDefaultEmoji(emoji)}>
+ <View style={styles.reactionSelectionItemContainer}>
+ <Text style={styles.reactionSelectionItemEmoji}>{emoji}</Text>
+ </View>
+ </TouchableOpacity>
+ ));
+ }, [
+ onPressDefaultEmoji,
+ styles.reactionSelectionItemContainer,
+ styles.reactionSelectionItemEmoji,
+ ]);
+
+ return <View style={containerStyle}>{defaultEmojis}</View>;
+}
+
+const unboundStyles = {
+ reactionSelectionPopoverContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: 'tooltipBackground',
+ padding: 8,
+ borderRadius: 8,
+ flex: 1,
+ },
+ reactionSelectionItemContainer: {
+ backgroundColor: 'reactionSelectionPopoverItemBackground',
+ justifyContent: 'center',
+ alignItems: 'center',
+ padding: 8,
+ borderRadius: 20,
+ width: 40,
+ height: 40,
+ marginRight: 12,
+ },
+ reactionSelectionItemEmoji: {
+ fontSize: 18,
+ },
+};
+
+export default ReactionSelectionPopover;
diff --git a/native/chat/robotext-message-tooltip-button.react.js b/native/chat/robotext-message-tooltip-button.react.js
--- a/native/chat/robotext-message-tooltip-button.react.js
+++ b/native/chat/robotext-message-tooltip-button.react.js
@@ -3,11 +3,20 @@
import * as React from 'react';
import Animated from 'react-native-reanimated';
+import { localIDPrefix } from 'lib/shared/message-utils';
+import { useCanCreateReactionFromMessage } from 'lib/shared/reaction-utils';
+import type { SetState } from 'lib/types/hook-types';
+
import type { AppNavigationProp } from '../navigation/app-navigator.react';
import type { TooltipRoute } from '../navigation/tooltip.react';
import { useSelector } from '../redux/redux-utils';
import { TooltipInlineEngagement } from './inline-engagement.react';
import { InnerRobotextMessage } from './inner-robotext-message.react';
+import {
+ useSendReaction,
+ useReactionSelectionPopoverPosition,
+} from './reaction-message-utils';
+import ReactionSelectionPopover from './reaction-selection-popover.react';
import SidebarInputBarHeightMeasurer from './sidebar-input-bar-height-measurer.react';
import { Timestamp } from './timestamp.react';
import { useAnimatedMessageTooltipButton } from './utils';
@@ -21,9 +30,11 @@
+route: TooltipRoute<'RobotextMessageTooltipModal'>,
+progress: Node,
+isOpeningSidebar: boolean,
+ +setHideTooltip: SetState<boolean>,
};
function RobotextMessageTooltipButton(props: Props): React.Node {
- const { progress } = props;
+ const { navigation, progress, isOpeningSidebar, setHideTooltip } = props;
+
const windowWidth = useSelector(state => state.dimensions.width);
const [
@@ -34,7 +45,13 @@
setSidebarInputBarHeight(height);
}, []);
- const { item, verticalBounds, initialCoordinates } = props.route.params;
+ const {
+ item,
+ verticalBounds,
+ initialCoordinates,
+ margin,
+ } = props.route.params;
+
const { style: messageContainerStyle } = useAnimatedMessageTooltipButton({
sourceMessage: item,
initialCoordinates,
@@ -59,8 +76,6 @@
};
}, [initialCoordinates.height, initialCoordinates.x, progress, windowWidth]);
- const { navigation, isOpeningSidebar } = props;
-
const inlineEngagement = React.useMemo(() => {
if (!item.threadCreatedFromMessage) {
return null;
@@ -77,6 +92,46 @@
);
}, [initialCoordinates, isOpeningSidebar, item, progress, windowWidth]);
+ const { messageInfo, threadInfo, reactions } = item;
+ const nextLocalID = useSelector(state => state.nextLocalID);
+ const localID = `${localIDPrefix}${nextLocalID}`;
+
+ const canCreateReactionFromMessage = useCanCreateReactionFromMessage(
+ threadInfo,
+ messageInfo,
+ );
+
+ const sendReaction = useSendReaction(messageInfo.id, localID, threadInfo.id);
+
+ const reactionSelectionPopoverPosition = useReactionSelectionPopoverPosition({
+ initialCoordinates,
+ verticalBounds,
+ margin,
+ });
+
+ const reactionSelectionPopover = React.useMemo(() => {
+ if (!canCreateReactionFromMessage) {
+ return null;
+ }
+
+ return (
+ <ReactionSelectionPopover
+ reactions={reactions}
+ setHideTooltip={setHideTooltip}
+ reactionSelectionPopoverContainerStyle={
+ reactionSelectionPopoverPosition
+ }
+ sendReaction={sendReaction}
+ />
+ );
+ }, [
+ canCreateReactionFromMessage,
+ reactionSelectionPopoverPosition,
+ reactions,
+ sendReaction,
+ setHideTooltip,
+ ]);
+
return (
<Animated.View style={messageContainerStyle}>
<SidebarInputBarHeightMeasurer
@@ -86,6 +141,7 @@
<Animated.View style={headerStyle}>
<Timestamp time={item.messageInfo.time} display="modal" />
</Animated.View>
+ {reactionSelectionPopover}
<InnerRobotextMessage item={item} onPress={navigation.goBackOnce} />
{inlineEngagement}
</Animated.View>
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
@@ -3,6 +3,10 @@
import * as React from 'react';
import Animated from 'react-native-reanimated';
+import { localIDPrefix } from 'lib/shared/message-utils';
+import { useCanCreateReactionFromMessage } from 'lib/shared/reaction-utils';
+import type { SetState } from 'lib/types/hook-types';
+
import type { AppNavigationProp } from '../navigation/app-navigator.react';
import type { TooltipRoute } from '../navigation/tooltip.react';
import { useSelector } from '../redux/redux-utils';
@@ -11,6 +15,11 @@
import { MessageHeader } from './message-header.react';
import { MessageListContextProvider } from './message-list-types';
import { MessagePressResponderContext } from './message-press-responder-context';
+import {
+ useSendReaction,
+ useReactionSelectionPopoverPosition,
+} from './reaction-message-utils';
+import ReactionSelectionPopover from './reaction-selection-popover.react';
import SidebarInputBarHeightMeasurer from './sidebar-input-bar-height-measurer.react';
import { useAnimatedMessageTooltipButton } from './utils';
@@ -23,9 +32,11 @@
+route: TooltipRoute<'TextMessageTooltipModal'>,
+progress: Node,
+isOpeningSidebar: boolean,
+ +setHideTooltip: SetState<boolean>,
};
function TextMessageTooltipButton(props: Props): React.Node {
- const { progress } = props;
+ const { navigation, progress, isOpeningSidebar, setHideTooltip } = props;
+
const windowWidth = useSelector(state => state.dimensions.width);
const [
@@ -36,7 +47,13 @@
setSidebarInputBarHeight(height);
}, []);
- const { item, verticalBounds, initialCoordinates } = props.route.params;
+ const {
+ item,
+ verticalBounds,
+ initialCoordinates,
+ margin,
+ } = props.route.params;
+
const {
style: messageContainerStyle,
threadColorOverride,
@@ -66,7 +83,6 @@
}, [initialCoordinates.height, initialCoordinates.x, progress, windowWidth]);
const threadID = item.threadInfo.id;
- const { navigation, isOpeningSidebar } = props;
const messagePressResponderContext = React.useMemo(
() => ({
@@ -90,6 +106,47 @@
/>
);
}, [initialCoordinates, isOpeningSidebar, item, progress, windowWidth]);
+
+ const { messageInfo, threadInfo, reactions } = item;
+ const nextLocalID = useSelector(state => state.nextLocalID);
+ const localID = `${localIDPrefix}${nextLocalID}`;
+
+ const canCreateReactionFromMessage = useCanCreateReactionFromMessage(
+ threadInfo,
+ messageInfo,
+ );
+
+ const sendReaction = useSendReaction(messageInfo.id, localID, threadInfo.id);
+
+ const reactionSelectionPopoverPosition = useReactionSelectionPopoverPosition({
+ initialCoordinates,
+ verticalBounds,
+ margin,
+ });
+
+ const reactionSelectionPopover = React.useMemo(() => {
+ if (!canCreateReactionFromMessage) {
+ return null;
+ }
+
+ return (
+ <ReactionSelectionPopover
+ reactions={reactions}
+ setHideTooltip={setHideTooltip}
+ reactionSelectionPopoverContainerStyle={
+ reactionSelectionPopoverPosition
+ }
+ sendReaction={sendReaction}
+ />
+ );
+ }, [
+ canCreateReactionFromMessage,
+ reactionSelectionPopoverPosition,
+ reactions,
+ sendReaction,
+ setHideTooltip,
+ ]);
+
return (
<MessageListContextProvider threadID={threadID}>
<SidebarInputBarHeightMeasurer
@@ -100,6 +157,7 @@
<Animated.View style={headerStyle}>
<MessageHeader item={item} focused={true} display="modal" />
</Animated.View>
+ {reactionSelectionPopover}
<MessagePressResponderContext.Provider
value={messagePressResponderContext}
>
diff --git a/native/navigation/tooltip.react.js b/native/navigation/tooltip.react.js
--- a/native/navigation/tooltip.react.js
+++ b/native/navigation/tooltip.react.js
@@ -111,6 +111,7 @@
...Base,
+progress: Node,
+isOpeningSidebar: boolean,
+ +setHideTooltip: SetState<boolean>,
};
type TooltipProps<Base> = {
...Base,
@@ -510,6 +511,7 @@
...navAndRouteForFlow,
progress: position,
isOpeningSidebar,
+ setHideTooltip,
};
const itemsStyles = [styles.items, styles.itemsFixed];
diff --git a/native/themes/colors.js b/native/themes/colors.js
--- a/native/themes/colors.js
+++ b/native/themes/colors.js
@@ -68,6 +68,7 @@
panelSecondaryForegroundBorder: '#CCCCCC',
purpleLink: '#7E57C2',
purpleButton: '#7E57C2',
+ reactionSelectionPopoverItemBackground: '#404040',
redText: '#F53100',
spoiler: '#33332C',
tabBarAccent: '#7E57C2',
@@ -151,6 +152,7 @@
panelSecondaryForegroundBorder: '#666666',
purpleLink: '#AE94DB',
purpleButton: '#7E57C2',
+ reactionSelectionPopoverItemBackground: '#404040',
redText: '#F53100',
spoiler: '#33332C',
tabBarAccent: '#AE94DB',

File Metadata

Mime Type
text/plain
Expires
Fri, Dec 20, 2:40 PM (16 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2681943
Default Alt Text
D6454.id21712.diff (15 KB)

Event Timeline