Page MenuHomePhabricator

D5515.id18088.diff
No OneTemporary

D5515.id18088.diff

diff --git a/native/chat/message-context.react.js b/native/chat/message-context.react.js
new file mode 100644
--- /dev/null
+++ b/native/chat/message-context.react.js
@@ -0,0 +1,15 @@
+// @flow
+
+import * as React from 'react';
+
+export type MessageContextType = {
+ +messageID: string,
+};
+
+const MessageContext: React.Context<MessageContextType> = React.createContext<MessageContextType>(
+ {
+ messageID: '',
+ },
+);
+
+export { MessageContext };
diff --git a/native/chat/text-message.react.js b/native/chat/text-message.react.js
--- a/native/chat/text-message.react.js
+++ b/native/chat/text-message.react.js
@@ -23,6 +23,7 @@
import type { ChatNavigationProp } from './chat.react';
import ComposedMessage from './composed-message.react';
import { InnerTextMessage } from './inner-text-message.react';
+import { MessageContext } from './message-context.react';
import textMessageSendFailed from './text-message-send-failed';
import { textMessageTooltipHeight } from './text-message-tooltip-modal.react';
import { getMessageTooltipKey } from './utils';
@@ -43,7 +44,7 @@
// withOverlayContext
+overlayContext: ?OverlayContextType,
// MarkdownContext
- +linkModalActive: boolean,
+ +isLinkModalActive: boolean,
+linkIsBlockingPresses: boolean,
};
class TextMessage extends React.PureComponent<Props> {
@@ -58,7 +59,7 @@
toggleFocus,
verticalBounds,
overlayContext,
- linkModalActive,
+ isLinkModalActive,
linkIsBlockingPresses,
canCreateSidebarFromMessage,
...viewProps
@@ -67,7 +68,7 @@
let swipeOptions = 'none';
const canReply = this.canReply();
const canNavigateToSidebar = this.canNavigateToSidebar();
- if (linkModalActive) {
+ if (isLinkModalActive) {
swipeOptions = 'none';
} else if (canReply && canNavigateToSidebar) {
swipeOptions = 'both';
@@ -142,6 +143,7 @@
message,
props: { verticalBounds, linkIsBlockingPresses },
} = this;
+
if (!message || !verticalBounds || linkIsBlockingPresses) {
return;
}
@@ -199,32 +201,57 @@
const ConnectedTextMessage: React.ComponentType<BaseProps> = React.memo<BaseProps>(
function ConnectedTextMessage(props: BaseProps) {
const overlayContext = React.useContext(OverlayContext);
+ const markdownContext = React.useContext(MarkdownContext);
+ invariant(markdownContext, 'markdownContext should be set');
+
+ const {
+ linkModalActive,
+ linkPressActive,
+ clearMarkdownContextData,
+ } = markdownContext;
+
+ const { id } = props.item.messageInfo;
+ invariant(id, 'messageInfo.id should exist');
+
+ // We check if there is an ID in the respective objects - if not, we
+ // default to false. The likely situation where the former statement
+ // evaluates to null is when the thread is opened for the first time.
+ const linkIsBlockingPresses =
+ (linkModalActive[id] || linkPressActive[id]) ?? false;
+
+ const isLinkModalActive = linkModalActive[id] ?? false;
- const [linkModalActive, setLinkModalActive] = React.useState(false);
- const [linkPressActive, setLinkPressActive] = React.useState(false);
- const markdownContext = React.useMemo(
- () => ({
- setLinkModalActive,
- setLinkPressActive,
- }),
- [setLinkModalActive, setLinkPressActive],
- );
const canCreateSidebarFromMessage = useCanCreateSidebarFromMessage(
props.item.threadInfo,
props.item.messageInfo,
);
- const linkIsBlockingPresses = linkModalActive || linkPressActive;
+ // We use a MessageContext to allow MarkdownLink (and MarkdownSpoiler soon)
+ // to access the messageID so it is 'self-aware'
+ const contextValue = React.useMemo(
+ () => ({
+ messageID: id,
+ }),
+ [id],
+ );
+
+ React.useEffect(() => {
+ return () => {
+ // Anything in here is fired on component unmount.
+ clearMarkdownContextData();
+ };
+ }, [clearMarkdownContextData]);
+
return (
- <MarkdownContext.Provider value={markdownContext}>
+ <MessageContext.Provider value={contextValue}>
<TextMessage
{...props}
canCreateSidebarFromMessage={canCreateSidebarFromMessage}
overlayContext={overlayContext}
- linkModalActive={linkModalActive}
+ isLinkModalActive={isLinkModalActive}
linkIsBlockingPresses={linkIsBlockingPresses}
/>
- </MarkdownContext.Provider>
+ </MessageContext.Provider>
);
},
);
diff --git a/native/markdown/markdown-context-provider.react.js b/native/markdown/markdown-context-provider.react.js
new file mode 100644
--- /dev/null
+++ b/native/markdown/markdown-context-provider.react.js
@@ -0,0 +1,48 @@
+// @flow
+
+import * as React from 'react';
+
+import { MarkdownContext } from './markdown-context.js';
+
+type Props = {
+ +children: React.Node,
+};
+
+function MarkdownContextProvider(props: Props): React.Node {
+ const [linkModalActive, setLinkModalActive] = React.useState<{
+ [key: string]: boolean,
+ }>({});
+ const [linkPressActive, setLinkPressActive] = React.useState<{
+ [key: string]: boolean,
+ }>({});
+
+ const clearMarkdownContextData = React.useCallback(() => {
+ setLinkModalActive({});
+ setLinkPressActive({});
+ }, []);
+
+ const contextValue = React.useMemo(
+ () => ({
+ setLinkModalActive,
+ linkModalActive,
+ setLinkPressActive,
+ linkPressActive,
+ clearMarkdownContextData,
+ }),
+ [
+ setLinkModalActive,
+ linkModalActive,
+ setLinkPressActive,
+ linkPressActive,
+ clearMarkdownContextData,
+ ],
+ );
+
+ return (
+ <MarkdownContext.Provider value={contextValue}>
+ {props.children}
+ </MarkdownContext.Provider>
+ );
+}
+
+export default MarkdownContextProvider;
diff --git a/native/markdown/markdown-context.js b/native/markdown/markdown-context.js
--- a/native/markdown/markdown-context.js
+++ b/native/markdown/markdown-context.js
@@ -2,9 +2,14 @@
import * as React from 'react';
+import type { SetState } from 'lib/types/hook-types';
+
export type MarkdownContextType = {
- +setLinkModalActive: boolean => void,
- +setLinkPressActive: boolean => void,
+ +setLinkModalActive: SetState<{ [key: string]: boolean }>,
+ +linkModalActive: { [key: string]: boolean },
+ +setLinkPressActive: SetState<{ [key: string]: boolean }>,
+ +linkPressActive: { [key: string]: boolean },
+ +clearMarkdownContextData: () => void,
};
const MarkdownContext: React.Context<?MarkdownContextType> = React.createContext<?MarkdownContextType>(
diff --git a/native/markdown/markdown-link.react.js b/native/markdown/markdown-link.react.js
--- a/native/markdown/markdown-link.react.js
+++ b/native/markdown/markdown-link.react.js
@@ -5,16 +5,21 @@
import { normalizeURL } from 'lib/utils/url-utils';
+import { MessageContext } from '../chat/message-context.react';
import { MarkdownContext, type MarkdownContextType } from './markdown-context';
function useDisplayLinkPrompt(
inputURL: string,
markdownContext: ?MarkdownContextType,
+ messageID: string,
) {
const setLinkModalActive = markdownContext?.setLinkModalActive;
+ const linkModalActive = markdownContext?.linkModalActive;
const onDismiss = React.useCallback(() => {
- setLinkModalActive?.(false);
- }, [setLinkModalActive]);
+ if (linkModalActive) {
+ setLinkModalActive?.({ ...linkModalActive, [messageID]: false });
+ }
+ }, [setLinkModalActive, linkModalActive, messageID]);
const url = normalizeURL(inputURL);
const onConfirm = React.useCallback(() => {
@@ -27,7 +32,9 @@
displayURL += '…';
}
return React.useCallback(() => {
- setLinkModalActive && setLinkModalActive(true);
+ setLinkModalActive &&
+ linkModalActive &&
+ setLinkModalActive({ ...linkModalActive, [messageID]: true });
Alert.alert(
'External link',
`You sure you want to open this link?\n\n${displayURL}`,
@@ -37,7 +44,14 @@
],
{ cancelable: true, onDismiss },
);
- }, [setLinkModalActive, displayURL, onConfirm, onDismiss]);
+ }, [
+ setLinkModalActive,
+ linkModalActive,
+ messageID,
+ displayURL,
+ onConfirm,
+ onDismiss,
+ ]);
}
type TextProps = React.ElementConfig<typeof Text>;
@@ -48,15 +62,22 @@
};
function MarkdownLink(props: Props): React.Node {
const markdownContext = React.useContext(MarkdownContext);
+ const messageContext = React.useContext(MessageContext);
+
+ const messageID = messageContext?.messageID;
const { target, ...rest } = props;
- const onPressLink = useDisplayLinkPrompt(target, markdownContext);
+ const onPressLink = useDisplayLinkPrompt(target, markdownContext, messageID);
const setLinkPressActive = markdownContext?.setLinkPressActive;
+ const linkPressActive = markdownContext?.linkPressActive;
+
const androidOnStartShouldSetResponderCapture = React.useCallback(() => {
- setLinkPressActive?.(true);
+ if (linkPressActive) {
+ setLinkPressActive?.({ ...linkPressActive, [messageID]: true });
+ }
return true;
- }, [setLinkPressActive]);
+ }, [setLinkPressActive, linkPressActive, messageID]);
const activePressHasMoved = React.useRef(false);
const androidOnResponderMove = React.useCallback(() => {
@@ -68,8 +89,10 @@
onPressLink();
}
activePressHasMoved.current = false;
- setLinkPressActive?.(false);
- }, [onPressLink, setLinkPressActive]);
+ if (linkPressActive) {
+ setLinkPressActive?.({ ...linkPressActive, [messageID]: false });
+ }
+ }, [onPressLink, setLinkPressActive, linkPressActive, messageID]);
if (Platform.OS !== 'android') {
return <Text onPress={onPressLink} {...rest} />;
diff --git a/native/navigation/app-navigator.react.js b/native/navigation/app-navigator.react.js
--- a/native/navigation/app-navigator.react.js
+++ b/native/navigation/app-navigator.react.js
@@ -21,6 +21,7 @@
import SWMansionIcon from '../components/swmansion-icon.react';
import { type SQLiteContextType, SQLiteContext } from '../data/sqlite-context';
import KeyboardStateContainer from '../keyboard/keyboard-state-container.react';
+import MarkdownContextProvider from '../markdown/markdown-context-provider.react';
import CameraModal from '../media/camera-modal.react';
import ImageModal from '../media/image-modal.react';
import VideoPlaybackModal from '../media/video-playback-modal.react';
@@ -212,39 +213,41 @@
}
return (
<KeyboardStateContainer>
- <App.Navigator>
- <App.Screen name={TabNavigatorRouteName} component={TabNavigator} />
- <App.Screen name={ImageModalRouteName} component={ImageModal} />
- <App.Screen
- name={MultimediaMessageTooltipModalRouteName}
- component={MultimediaMessageTooltipModal}
- />
- <App.Screen
- name={ActionResultModalRouteName}
- component={ActionResultModal}
- />
- <App.Screen
- name={TextMessageTooltipModalRouteName}
- component={TextMessageTooltipModal}
- />
- <App.Screen
- name={ThreadSettingsMemberTooltipModalRouteName}
- component={ThreadSettingsMemberTooltipModal}
- />
- <App.Screen
- name={RelationshipListItemTooltipModalRouteName}
- component={RelationshipListItemTooltipModal}
- />
- <App.Screen
- name={RobotextMessageTooltipModalRouteName}
- component={RobotextMessageTooltipModal}
- />
- <App.Screen name={CameraModalRouteName} component={CameraModal} />
- <App.Screen
- name={VideoPlaybackModalRouteName}
- component={VideoPlaybackModal}
- />
- </App.Navigator>
+ <MarkdownContextProvider>
+ <App.Navigator>
+ <App.Screen name={TabNavigatorRouteName} component={TabNavigator} />
+ <App.Screen name={ImageModalRouteName} component={ImageModal} />
+ <App.Screen
+ name={MultimediaMessageTooltipModalRouteName}
+ component={MultimediaMessageTooltipModal}
+ />
+ <App.Screen
+ name={ActionResultModalRouteName}
+ component={ActionResultModal}
+ />
+ <App.Screen
+ name={TextMessageTooltipModalRouteName}
+ component={TextMessageTooltipModal}
+ />
+ <App.Screen
+ name={ThreadSettingsMemberTooltipModalRouteName}
+ component={ThreadSettingsMemberTooltipModal}
+ />
+ <App.Screen
+ name={RelationshipListItemTooltipModalRouteName}
+ component={RelationshipListItemTooltipModal}
+ />
+ <App.Screen
+ name={RobotextMessageTooltipModalRouteName}
+ component={RobotextMessageTooltipModal}
+ />
+ <App.Screen name={CameraModalRouteName} component={CameraModal} />
+ <App.Screen
+ name={VideoPlaybackModalRouteName}
+ component={VideoPlaybackModal}
+ />
+ </App.Navigator>
+ </MarkdownContextProvider>
{pushHandler}
</KeyboardStateContainer>
);

File Metadata

Mime Type
text/plain
Expires
Sun, Nov 24, 10:10 AM (19 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2574965
Default Alt Text
D5515.id18088.diff (12 KB)

Event Timeline