diff --git a/native/markdown/markdown-context-provider.react.js b/native/markdown/markdown-context-provider.react.js --- a/native/markdown/markdown-context-provider.react.js +++ b/native/markdown/markdown-context-provider.react.js @@ -13,17 +13,32 @@ [key: string]: boolean, }>({}); + const [spoilerRevealed, setSpoilerRevealed] = React.useState<{ + [key: string]: { + [key: number]: boolean, + }, + }>({}); + const clearMarkdownContextData = React.useCallback(() => { setLinkModalActive({}); + setSpoilerRevealed({}); }, []); const contextValue = React.useMemo( () => ({ setLinkModalActive, linkModalActive, + setSpoilerRevealed, + spoilerRevealed, clearMarkdownContextData, }), - [setLinkModalActive, linkModalActive, clearMarkdownContextData], + [ + setLinkModalActive, + linkModalActive, + setSpoilerRevealed, + spoilerRevealed, + clearMarkdownContextData, + ], ); return ( 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 @@ -7,6 +7,8 @@ export type MarkdownContextType = { +setLinkModalActive: SetState<{ [key: string]: boolean }>, +linkModalActive: { [key: string]: boolean }, + +setSpoilerRevealed: SetState<{ [key: string]: { [key: number]: boolean } }>, + +spoilerRevealed: { [key: string]: { [key: number]: boolean } }, +clearMarkdownContextData: () => void, }; diff --git a/native/markdown/markdown-spoiler.react.js b/native/markdown/markdown-spoiler.react.js --- a/native/markdown/markdown-spoiler.react.js +++ b/native/markdown/markdown-spoiler.react.js @@ -1,36 +1,79 @@ // @flow +import invariant from 'invariant'; import * as React from 'react'; import { Text } from 'react-native'; import type { ReactElement } from 'lib/shared/markdown'; +import { TextMessageMarkdownContext } from '../chat/text-message-markdown-context'; import { useStyles } from '../themes/colors'; +import { MarkdownContext } from './markdown-context'; type MarkdownSpoilerProps = { + +spoilerIdentifier: string | number | void, +text: ReactElement, +children?: React.Node, }; function MarkdownSpoiler(props: MarkdownSpoilerProps): React.Node { - const [isRevealed, setIsRevealed] = React.useState(false); + const markdownContext = React.useContext(MarkdownContext); + invariant(markdownContext, 'MarkdownContext should be set'); + + const textMessageMarkdownContext = React.useContext( + TextMessageMarkdownContext, + ); + const styles = useStyles(unboundStyles); - const { text } = props; + + const { text, spoilerIdentifier } = props; + const { spoilerRevealed, setSpoilerRevealed } = markdownContext; + const messageKey = textMessageMarkdownContext?.messageKey; + + const parsedSpoilerIdentifier = spoilerIdentifier + ? parseInt(spoilerIdentifier) + : -1; + + const isRevealed = + (messageKey && spoilerRevealed[messageKey]?.[parsedSpoilerIdentifier]) ?? + false; + + const styleBasedOnSpoilerState = React.useMemo(() => { + if (isRevealed) { + return null; + } + return styles.spoilerHidden; + }, [isRevealed, styles.spoilerHidden]); const onSpoilerClick = React.useCallback(() => { - setIsRevealed(true); - }, []); + if (isRevealed) { + return; + } + + if (messageKey && parsedSpoilerIdentifier !== -1) { + setSpoilerRevealed({ + ...spoilerRevealed, + [messageKey]: { + ...spoilerRevealed[messageKey], + [parsedSpoilerIdentifier]: true, + }, + }); + } + }, [ + isRevealed, + spoilerRevealed, + setSpoilerRevealed, + messageKey, + parsedSpoilerIdentifier, + ]); const memoizedSpoiler = React.useMemo(() => { return ( - + {text} ); - }, [onSpoilerClick, isRevealed, styles.spoilerHidden, text]); + }, [onSpoilerClick, styleBasedOnSpoilerState, text]); return memoizedSpoiler; } diff --git a/native/markdown/rules.react.js b/native/markdown/rules.react.js --- a/native/markdown/rules.react.js +++ b/native/markdown/rules.react.js @@ -201,7 +201,11 @@ output: SharedMarkdown.Output, state: SharedMarkdown.State, ) => ( - + ), }, inlineCode: {