diff --git a/native/avatars/emoji-avatar-creation.react.js b/native/avatars/emoji-avatar-creation.react.js index 3bb07a8a5..03defb419 100644 --- a/native/avatars/emoji-avatar-creation.react.js +++ b/native/avatars/emoji-avatar-creation.react.js @@ -1,213 +1,213 @@ // @flow import * as React from 'react'; import { View, Text, TouchableWithoutFeedback, ActivityIndicator, } from 'react-native'; -import EmojiPicker from 'rn-emoji-keyboard'; import type { UpdateUserAvatarRequest, ClientEmojiAvatar, } from 'lib/types/avatar-types'; import Avatar from './avatar.react.js'; import Button from '../components/button.react.js'; import ColorRows from '../components/color-rows.react.js'; +import EmojiKeyboard from '../components/emoji-keyboard.react.js'; import { useStyles } from '../themes/colors.js'; type Props = { +saveAvatarCall: (newAvatarRequest: UpdateUserAvatarRequest) => mixed, +saveAvatarCallLoading: boolean, +savedEmojiAvatarFunc: () => ClientEmojiAvatar, }; function EmojiAvatarCreation(props: Props): React.Node { const { saveAvatarCall, saveAvatarCallLoading, savedEmojiAvatarFunc } = props; const [pendingEmoji, setPendingEmoji] = React.useState( () => savedEmojiAvatarFunc().emoji, ); const [pendingColor, setPendingColor] = React.useState( () => savedEmojiAvatarFunc().color, ); const [emojiKeyboardOpen, setEmojiKeyboardOpen] = React.useState(false); const styles = useStyles(unboundStyles); const onPressEditEmoji = React.useCallback(() => { setEmojiKeyboardOpen(true); }, []); const onPressSetAvatar = React.useCallback(() => { const newEmojiAvatarRequest = { type: 'emoji', emoji: pendingEmoji, color: pendingColor, }; saveAvatarCall(newEmojiAvatarRequest); }, [pendingColor, pendingEmoji, saveAvatarCall]); const onPressReset = React.useCallback(() => { const resetEmojiAvatar = savedEmojiAvatarFunc(); setPendingEmoji(resetEmojiAvatar.emoji); setPendingColor(resetEmojiAvatar.color); }, [savedEmojiAvatarFunc]); const onEmojiSelected = React.useCallback(emoji => { setPendingEmoji(emoji.emoji); }, []); const onEmojiKeyboardClose = React.useCallback( () => setEmojiKeyboardOpen(false), [], ); const stagedAvatarInfo: ClientEmojiAvatar = React.useMemo( () => ({ type: 'emoji', emoji: pendingEmoji, color: pendingColor, }), [pendingColor, pendingEmoji], ); const loadingContainer = React.useMemo(() => { if (!saveAvatarCallLoading) { return null; } return ( ); }, [saveAvatarCallLoading, styles.loadingContainer]); return ( {loadingContainer} Edit Emoji - ); } const unboundStyles = { container: { flexGrow: 1, flex: 1, justifyContent: 'space-between', }, emojiAvatarCreationContainer: { paddingTop: 16, }, stagedAvatarSection: { backgroundColor: 'panelForeground', paddingVertical: 24, alignItems: 'center', }, editEmojiText: { color: 'purpleLink', marginTop: 16, fontWeight: '500', fontSize: 16, lineHeight: 24, textAlign: 'center', }, colorRowsSection: { paddingVertical: 24, marginTop: 24, backgroundColor: 'panelForeground', alignItems: 'center', }, selectedColorOuterRing: { backgroundColor: 'modalSubtext', }, buttonsContainer: { flexGrow: 1, paddingHorizontal: 16, paddingBottom: 8, justifyContent: 'flex-end', }, saveButton: { backgroundColor: 'purpleButton', paddingVertical: 12, borderRadius: 8, }, saveButtonText: { color: 'whiteText', textAlign: 'center', fontWeight: '500', fontSize: 16, lineHeight: 24, }, resetButton: { padding: 12, borderRadius: 8, marginTop: 8, alignSelf: 'center', }, resetButtonText: { color: 'redText', textAlign: 'center', fontWeight: '500', fontSize: 16, lineHeight: 24, }, loadingContainer: { position: 'absolute', backgroundColor: 'black', width: 112, height: 112, borderRadius: 56, opacity: 0.6, justifyContent: 'center', }, }; export default EmojiAvatarCreation; diff --git a/native/chat/multimedia-message-tooltip-button.react.js b/native/chat/multimedia-message-tooltip-button.react.js index f1f22d92d..a474e8bbf 100644 --- a/native/chat/multimedia-message-tooltip-button.react.js +++ b/native/chat/multimedia-message-tooltip-button.react.js @@ -1,179 +1,179 @@ // @flow import * as React from 'react'; import Animated from 'react-native-reanimated'; -import EmojiPicker from 'rn-emoji-keyboard'; import { localIDPrefix } from 'lib/shared/message-utils.js'; import { useCanCreateReactionFromMessage } from 'lib/shared/reaction-utils.js'; 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'; import { useAnimatedMessageTooltipButton } from './utils.js'; +import EmojiKeyboard from '../components/emoji-keyboard.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'; /* eslint-disable import/no-named-as-default-member */ const { Node, Extrapolate, interpolateNode } = Animated; /* eslint-enable import/no-named-as-default-member */ function noop() {} type Props = { +navigation: AppNavigationProp<'MultimediaMessageTooltipModal'>, +route: TooltipRoute<'MultimediaMessageTooltipModal'>, +progress: Node, +isOpeningSidebar: boolean, }; function MultimediaMessageTooltipButton(props: Props): React.Node { const { navigation, route, progress, isOpeningSidebar } = props; const windowWidth = useSelector(state => state.dimensions.width); const [sidebarInputBarHeight, setSidebarInputBarHeight] = React.useState(null); const onInputBarMeasured = React.useCallback((height: number) => { setSidebarInputBarHeight(height); }, []); const { item, verticalBounds, initialCoordinates } = route.params; const { style: messageContainerStyle } = useAnimatedMessageTooltipButton({ sourceMessage: item, initialCoordinates, messageListVerticalBounds: verticalBounds, progress, targetInputBarHeight: sidebarInputBarHeight, }); const headerStyle = React.useMemo(() => { const bottom = initialCoordinates.height; const opacity = interpolateNode(progress, { inputRange: [0, 0.05], outputRange: [0, 1], extrapolate: Extrapolate.CLAMP, }); return { opacity, position: 'absolute', left: -initialCoordinates.x, width: windowWidth, bottom, }; }, [initialCoordinates.height, initialCoordinates.x, progress, windowWidth]); const inlineEngagement = React.useMemo(() => { if (!item.threadCreatedFromMessage) { return null; } return ( ); }, [initialCoordinates, isOpeningSidebar, item, progress, windowWidth]); const innerMultimediaMessage = React.useMemo( () => ( ), [item, navigation.goBackOnce, verticalBounds], ); 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, reactions, ); const [emojiPickerOpen, setEmojiPickerOpen] = React.useState(false); const openEmojiPicker = React.useCallback(() => { setEmojiPickerOpen(true); }, []); const reactionSelectionPopover = React.useMemo(() => { if (!canCreateReactionFromMessage) { return null; } return ( ); }, [ navigation, route, openEmojiPicker, canCreateReactionFromMessage, sendReaction, ]); const tooltipRouteKey = route.key; const { dismissTooltip } = useTooltipActions(navigation, tooltipRouteKey); const onEmojiSelected = React.useCallback( emoji => { sendReaction(emoji.emoji); dismissTooltip(); }, [sendReaction, dismissTooltip], ); return ( <> {reactionSelectionPopover} {innerMultimediaMessage} {inlineEngagement} - ); } export default MultimediaMessageTooltipButton; diff --git a/native/chat/robotext-message-tooltip-button.react.js b/native/chat/robotext-message-tooltip-button.react.js index a1ea482b7..6e0000d0d 100644 --- a/native/chat/robotext-message-tooltip-button.react.js +++ b/native/chat/robotext-message-tooltip-button.react.js @@ -1,161 +1,161 @@ // @flow import * as React from 'react'; import Animated from 'react-native-reanimated'; -import EmojiPicker from 'rn-emoji-keyboard'; import { localIDPrefix } from 'lib/shared/message-utils.js'; import { useCanCreateReactionFromMessage } from 'lib/shared/reaction-utils.js'; import { TooltipInlineEngagement } from './inline-engagement.react.js'; import { InnerRobotextMessage } from './inner-robotext-message.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'; import { Timestamp } from './timestamp.react.js'; import { useAnimatedMessageTooltipButton } from './utils.js'; +import EmojiKeyboard from '../components/emoji-keyboard.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'; /* eslint-disable import/no-named-as-default-member */ const { Node, interpolateNode, Extrapolate } = Animated; /* eslint-enable import/no-named-as-default-member */ type Props = { +navigation: AppNavigationProp<'RobotextMessageTooltipModal'>, +route: TooltipRoute<'RobotextMessageTooltipModal'>, +progress: Node, +isOpeningSidebar: boolean, }; function RobotextMessageTooltipButton(props: Props): React.Node { const { navigation, route, progress, isOpeningSidebar } = props; const windowWidth = useSelector(state => state.dimensions.width); const [sidebarInputBarHeight, setSidebarInputBarHeight] = React.useState(null); const onInputBarMeasured = React.useCallback((height: number) => { setSidebarInputBarHeight(height); }, []); const { item, verticalBounds, initialCoordinates } = route.params; const { style: messageContainerStyle } = useAnimatedMessageTooltipButton({ sourceMessage: item, initialCoordinates, messageListVerticalBounds: verticalBounds, progress, targetInputBarHeight: sidebarInputBarHeight, }); const headerStyle = React.useMemo(() => { const bottom = initialCoordinates.height; const opacity = interpolateNode(progress, { inputRange: [0, 0.05], outputRange: [0, 1], extrapolate: Extrapolate.CLAMP, }); return { opacity, position: 'absolute', left: -initialCoordinates.x, width: windowWidth, bottom, }; }, [initialCoordinates.height, initialCoordinates.x, progress, windowWidth]); const inlineEngagement = React.useMemo(() => { if (!item.threadCreatedFromMessage) { return null; } return ( ); }, [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, reactions, ); const [emojiPickerOpen, setEmojiPickerOpen] = React.useState(false); const openEmojiPicker = React.useCallback(() => { setEmojiPickerOpen(true); }, []); const reactionSelectionPopover = React.useMemo(() => { if (!canCreateReactionFromMessage) { return null; } return ( ); }, [ navigation, route, openEmojiPicker, canCreateReactionFromMessage, sendReaction, ]); const tooltipRouteKey = route.key; const { dismissTooltip } = useTooltipActions(navigation, tooltipRouteKey); const onEmojiSelected = React.useCallback( emoji => { sendReaction(emoji.emoji); dismissTooltip(); }, [sendReaction, dismissTooltip], ); return ( <> {reactionSelectionPopover} {inlineEngagement} - ); } export default RobotextMessageTooltipButton; diff --git a/native/chat/text-message-tooltip-button.react.js b/native/chat/text-message-tooltip-button.react.js index a4976fc09..6d6d52554 100644 --- a/native/chat/text-message-tooltip-button.react.js +++ b/native/chat/text-message-tooltip-button.react.js @@ -1,185 +1,185 @@ // @flow import * as React from 'react'; import Animated from 'react-native-reanimated'; -import EmojiPicker from 'rn-emoji-keyboard'; import { localIDPrefix } from 'lib/shared/message-utils.js'; import { useCanCreateReactionFromMessage } from 'lib/shared/reaction-utils.js'; import { TooltipInlineEngagement } from './inline-engagement.react.js'; import { InnerTextMessage } from './inner-text-message.react.js'; 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'; import { useAnimatedMessageTooltipButton } from './utils.js'; +import EmojiKeyboard from '../components/emoji-keyboard.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'; /* eslint-disable import/no-named-as-default-member */ const { Node, interpolateNode, Extrapolate } = Animated; /* eslint-enable import/no-named-as-default-member */ type Props = { +navigation: AppNavigationProp<'TextMessageTooltipModal'>, +route: TooltipRoute<'TextMessageTooltipModal'>, +progress: Node, +isOpeningSidebar: boolean, }; function TextMessageTooltipButton(props: Props): React.Node { const { navigation, route, progress, isOpeningSidebar } = props; const windowWidth = useSelector(state => state.dimensions.width); const [sidebarInputBarHeight, setSidebarInputBarHeight] = React.useState(null); const onInputBarMeasured = React.useCallback((height: number) => { setSidebarInputBarHeight(height); }, []); const { item, verticalBounds, initialCoordinates } = route.params; const { style: messageContainerStyle, threadColorOverride, isThreadColorDarkOverride, } = useAnimatedMessageTooltipButton({ sourceMessage: item, initialCoordinates, messageListVerticalBounds: verticalBounds, progress, targetInputBarHeight: sidebarInputBarHeight, }); const headerStyle = React.useMemo(() => { const bottom = initialCoordinates.height; const opacity = interpolateNode(progress, { inputRange: [0, 0.05], outputRange: [0, 1], extrapolate: Extrapolate.CLAMP, }); return { opacity, position: 'absolute', left: -initialCoordinates.x, width: windowWidth, bottom, }; }, [initialCoordinates.height, initialCoordinates.x, progress, windowWidth]); const messagePressResponderContext = React.useMemo( () => ({ onPressMessage: navigation.goBackOnce, }), [navigation.goBackOnce], ); const inlineEngagement = React.useMemo(() => { if (!item.threadCreatedFromMessage) { return null; } return ( ); }, [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, reactions, ); const [emojiPickerOpen, setEmojiPickerOpen] = React.useState(false); const openEmojiPicker = React.useCallback(() => { setEmojiPickerOpen(true); }, []); const reactionSelectionPopover = React.useMemo(() => { if (!canCreateReactionFromMessage) { return null; } return ( ); }, [ navigation, route, openEmojiPicker, canCreateReactionFromMessage, sendReaction, ]); const tooltipRouteKey = route.key; const { dismissTooltip } = useTooltipActions(navigation, tooltipRouteKey); const onEmojiSelected = React.useCallback( emoji => { sendReaction(emoji.emoji); dismissTooltip(); }, [sendReaction, dismissTooltip], ); return ( {reactionSelectionPopover} {inlineEngagement} - ); } export default TextMessageTooltipButton; diff --git a/native/components/emoji-keyboard.react.js b/native/components/emoji-keyboard.react.js new file mode 100644 index 000000000..f33d76d13 --- /dev/null +++ b/native/components/emoji-keyboard.react.js @@ -0,0 +1,24 @@ +// @flow + +import * as React from 'react'; +import EmojiPicker from 'rn-emoji-keyboard'; + +type Props = { + +onEmojiSelected: (emoji: { emoji: string, ... }) => mixed, + +emojiKeyboardOpen: boolean, + +onEmojiKeyboardClose: () => mixed, +}; + +function EmojiKeyboard(props: Props): React.Node { + const { onEmojiSelected, emojiKeyboardOpen, onEmojiKeyboardClose } = props; + + return ( + + ); +} + +export default EmojiKeyboard;