Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3376807
D5515.id18740.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
D5515.id18740.diff
View Options
diff --git a/native/chat/inner-text-message.react.js b/native/chat/inner-text-message.react.js
--- a/native/chat/inner-text-message.react.js
+++ b/native/chat/inner-text-message.react.js
@@ -5,6 +5,7 @@
import { View, StyleSheet, TouchableWithoutFeedback } from 'react-native';
import Animated from 'react-native-reanimated';
+import { messageKey } from 'lib/shared/message-utils';
import { colorIsDark } from 'lib/shared/thread-utils';
import GestureTouchableOpacity from '../components/gesture-touchable-opacity.react';
@@ -13,6 +14,7 @@
import { useColors, colors } from '../themes/colors';
import type { ChatTextMessageInfoItemWithHeight } from '../types/chat-types';
import { useComposedMessageMaxWidth } from './composed-message-width';
+import { MessageContext } from './message-context.react';
import { MessageListContext } from './message-list-types';
import {
allCorners,
@@ -101,6 +103,16 @@
return [styles.text, textStyle];
}, [darkColor]);
+ // We use a MessageContext to allow MarkdownLink and MarkdownSpoiler
+ // to access the messageKey so it is 'self-aware'
+ const key = messageKey(item.messageInfo);
+ const messageContextValue = React.useMemo(
+ () => ({
+ messageKey: key,
+ }),
+ [key],
+ );
+
const message = (
<TouchableWithoutFeedback>
<View>
@@ -111,9 +123,11 @@
style={[styles.message, cornerStyle]}
animatedStyle={messageStyle}
>
- <Markdown style={markdownStyles} rules={rules}>
- {text}
- </Markdown>
+ <MessageContext.Provider value={messageContextValue}>
+ <Markdown style={markdownStyles} rules={rules}>
+ {text}
+ </Markdown>
+ </MessageContext.Provider>
</GestureTouchableOpacity>
</View>
</TouchableWithoutFeedback>
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 = {
+ +messageKey: string,
+};
+
+const MessageContext: React.Context<MessageContextType> = React.createContext<MessageContextType>(
+ {
+ messageKey: '',
+ },
+);
+
+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
@@ -46,7 +46,7 @@
// ChatContext
+chatContext: ?ChatContextType,
// MarkdownContext
- +linkModalActive: boolean,
+ +isLinkModalActive: boolean,
+linkIsBlockingPresses: boolean,
};
class TextMessage extends React.PureComponent<Props> {
@@ -62,7 +62,7 @@
verticalBounds,
overlayContext,
chatContext,
- linkModalActive,
+ isLinkModalActive,
linkIsBlockingPresses,
canCreateSidebarFromMessage,
...viewProps
@@ -71,7 +71,7 @@
let swipeOptions = 'none';
const canReply = this.canReply();
const canNavigateToSidebar = this.canNavigateToSidebar();
- if (linkModalActive) {
+ if (isLinkModalActive) {
swipeOptions = 'none';
} else if (canReply && canNavigateToSidebar) {
swipeOptions = 'both';
@@ -147,6 +147,7 @@
message,
props: { verticalBounds, linkIsBlockingPresses },
} = this;
+
if (!message || !verticalBounds || linkIsBlockingPresses) {
return;
}
@@ -208,33 +209,41 @@
function ConnectedTextMessage(props: BaseProps) {
const overlayContext = React.useContext(OverlayContext);
const chatContext = React.useContext(ChatContext);
+ const markdownContext = React.useContext(MarkdownContext);
+ invariant(markdownContext, 'markdownContext should be set');
+
+ const {
+ linkModalActive,
+ linkPressActive,
+ clearMarkdownContextData,
+ } = markdownContext;
+
+ const key = messageKey(props.item.messageInfo);
+
+ // 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[key] || linkPressActive[key]) ?? false;
+
+ const isLinkModalActive = linkModalActive[key] ?? 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;
+ React.useEffect(() => clearMarkdownContextData, [clearMarkdownContextData]);
+
return (
- <MarkdownContext.Provider value={markdownContext}>
- <TextMessage
- {...props}
- canCreateSidebarFromMessage={canCreateSidebarFromMessage}
- overlayContext={overlayContext}
- chatContext={chatContext}
- linkModalActive={linkModalActive}
- linkIsBlockingPresses={linkIsBlockingPresses}
- />
- </MarkdownContext.Provider>
+ <TextMessage
+ {...props}
+ canCreateSidebarFromMessage={canCreateSidebarFromMessage}
+ overlayContext={overlayContext}
+ chatContext={chatContext}
+ isLinkModalActive={isLinkModalActive}
+ linkIsBlockingPresses={linkIsBlockingPresses}
+ />
);
},
);
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,
+ messageKey: string,
) {
const setLinkModalActive = markdownContext?.setLinkModalActive;
+ const linkModalActive = markdownContext?.linkModalActive;
const onDismiss = React.useCallback(() => {
- setLinkModalActive?.(false);
- }, [setLinkModalActive]);
+ if (linkModalActive) {
+ setLinkModalActive?.({ ...linkModalActive, [messageKey]: false });
+ }
+ }, [setLinkModalActive, linkModalActive, messageKey]);
const url = normalizeURL(inputURL);
const onConfirm = React.useCallback(() => {
@@ -27,7 +32,9 @@
displayURL += '…';
}
return React.useCallback(() => {
- setLinkModalActive && setLinkModalActive(true);
+ setLinkModalActive &&
+ linkModalActive &&
+ setLinkModalActive({ ...linkModalActive, [messageKey]: 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,
+ messageKey,
+ 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 messageKey = messageContext?.messageKey;
const { target, ...rest } = props;
- const onPressLink = useDisplayLinkPrompt(target, markdownContext);
+ const onPressLink = useDisplayLinkPrompt(target, markdownContext, messageKey);
const setLinkPressActive = markdownContext?.setLinkPressActive;
+ const linkPressActive = markdownContext?.linkPressActive;
+
const androidOnStartShouldSetResponderCapture = React.useCallback(() => {
- setLinkPressActive?.(true);
+ if (linkPressActive) {
+ setLinkPressActive?.({ ...linkPressActive, [messageKey]: true });
+ }
return true;
- }, [setLinkPressActive]);
+ }, [setLinkPressActive, linkPressActive, messageKey]);
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, [messageKey]: false });
+ }
+ }, [onPressLink, setLinkPressActive, linkPressActive, messageKey]);
if (Platform.OS !== 'android') {
return <Text onPress={onPressLink} {...rest} />;
diff --git a/native/root.react.js b/native/root.react.js
--- a/native/root.react.js
+++ b/native/root.react.js
@@ -27,6 +27,7 @@
import ErrorBoundary from './error-boundary.react';
import InputStateContainer from './input/input-state-container.react';
import LifecycleHandler from './lifecycle/lifecycle-handler.react';
+import MarkdownContextProvider from './markdown/markdown-context-provider.react';
import { defaultNavigationState } from './navigation/default-state';
import DisconnectedBarVisibilityHandler from './navigation/disconnected-bar-visibility-handler.react';
import { setGlobalNavContext } from './navigation/icky-global';
@@ -248,23 +249,25 @@
<InputStateContainer>
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
<ActionSheetProvider>
- <ChatContextProvider>
- <SQLiteContextProvider>
- <ConnectedStatusBar />
- <ReduxPersistGate persistor={getPersistor()}>
- {gated}
- </ReduxPersistGate>
- <PersistedStateGate>
- <Socket
- detectUnsupervisedBackgroundRef={
- detectUnsupervisedBackgroundRef
- }
- />
- </PersistedStateGate>
- {navigation}
- <NavigationHandler />
- </SQLiteContextProvider>
- </ChatContextProvider>
+ <MarkdownContextProvider>
+ <ChatContextProvider>
+ <SQLiteContextProvider>
+ <ConnectedStatusBar />
+ <ReduxPersistGate persistor={getPersistor()}>
+ {gated}
+ </ReduxPersistGate>
+ <PersistedStateGate>
+ <Socket
+ detectUnsupervisedBackgroundRef={
+ detectUnsupervisedBackgroundRef
+ }
+ />
+ </PersistedStateGate>
+ {navigation}
+ <NavigationHandler />
+ </SQLiteContextProvider>
+ </ChatContextProvider>
+ </MarkdownContextProvider>
</ActionSheetProvider>
</SafeAreaProvider>
</InputStateContainer>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Nov 28, 2:19 AM (19 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2592438
Default Alt Text
D5515.id18740.diff (13 KB)
Attached To
Mode
D5515: [native] Update the existing Context API for Markdown to encompass AppNavigator
Attached
Detach File
Event Timeline
Log In to Comment