import * as React from 'react'; import { Platform, TextInput as RNTextInput, View } from 'react-native'; import { SafeAreaView, useSafeAreaInsets, } from 'react-native-safe-area-context'; import { useConfigContext } from '../../config'; import { useColors } from '../../hook'; import { useI18nContext } from '../../i18n'; import { ChatMessage, ChatMessageType, ChatTextMessageBody, } from '../../rename.chat'; import { usePaletteContext, useThemeContext } from '../../theme'; import { IconButton } from '../../ui/Button'; import { Icon } from '../../ui/Image'; import { SlideModal, SlideModalRef } from '../../ui/Modal'; import { Text } from '../../ui/Text'; import { TextInput } from '../../ui/TextInput'; /** * Referencing Values of the `MessageInputEditMessage` component. */ export type MessageInputEditMessageRef = SlideModalRef & { /** * While displaying the component, the menu items will also be dynamically changed. */ startShowWithInit: (msg: ChatMessage) => void; }; /** * Properties of the `MessageInputEditMessage` component. */ export type MessageInputEditMessageProps = { /** * To request to close the component, you usually need to call the `startHide` method here. */ onRequestModalClose: () => void; /** * The callback function when the send button is clicked. */ onEditMessageFinished?: (msgId: string, text: string) => void; /** * Must be a text message. */ initMsg?: ChatMessage; /** * Keyboard offset setting required. If safe area is used. */ top?: number; bottom?: number; /** * The maximum number of lines in the input box. */ numberOfLines?: number; }; /** * The MessageInputEditMessage component provides menu functionality. * * @example * * ```tsx * const ref = React.useRef({} as any); * // ... * { * ref.current.startHide(); * }} * initMsg={msg} * /> * ``` */ export const MessageInputEditMessage = React.forwardRef< MessageInputEditMessageRef, MessageInputEditMessageProps >(function ( props: MessageInputEditMessageProps, ref?: React.ForwardedRef ) { const { onRequestModalClose, initMsg, numberOfLines = 2, bottom: propsBottom, onEditMessageFinished, } = props; const { style } = useThemeContext(); const { tr } = useI18nContext(); const { colors } = usePaletteContext(); const { bottom } = useSafeAreaInsets(); const _bottom = propsBottom ?? bottom; const { fontFamily } = useConfigContext(); const modalRef = React.useRef({} as any); const { getColor } = useColors({ state: { light: colors.neutralSpecial[5], dark: colors.neutralSpecial[6], }, btn_disable: { light: colors.neutral[7], dark: colors.neutral[4], }, btn_enable: { light: colors.primary[5], dark: colors.primary[6], }, }); const isShow = React.useRef(false); // !!! needs improvement const pseudoMsg = React.useMemo(() => { return ChatMessage.createTextMessage('xxx', '', 0); }, []); const { updateMsg, msg: updatedMsg, inputRef, value, setValue, onBlur, onFocus, disable, onEdited, } = useMessageInputEditMessage({ msg: initMsg ?? pseudoMsg, onEditMessageFinished, }); React.useImperativeHandle(ref, () => { return { startHide: (onFinished?: () => void) => { isShow.current = false; modalRef?.current?.startHide?.(onFinished); }, startShow: () => { isShow.current = true; modalRef?.current?.startShow?.(); }, startShowWithInit: (msg: ChatMessage) => { isShow.current = true; updateMsg(msg); // if (updatedMsg !== msg) { // isShow.current = true; // updateMsg(msg); // } else { // isShow.current = true; // modalRef?.current?.startShow?.(); // } }, }; }, [updateMsg]); React.useEffect(() => { if (isShow.current === true) { modalRef?.current?.startShow?.(); } }, [updatedMsg]); return ( {/* */} {tr('editing')} ); }); export function useMessageInputEditMessage({ msg, onEditMessageFinished, }: { msg: ChatMessage; onEditMessageFinished?: (msgId: string, text: string) => void; }) { const [_msg, _setMsg] = React.useState(msg); const valueRef = React.useRef((msg.body as ChatTextMessageBody).content); const [value, _setValue] = React.useState( (msg.body as ChatTextMessageBody).content ); const inputRef = React.useRef>(null); const [disable, setDisable] = React.useState(true); const _updateMsg = (msg: ChatMessage) => { if (msg.body.type !== ChatMessageType.TXT) { return; } const body = msg.body as ChatTextMessageBody; valueRef.current = body.content; _setMsg({ ...msg } as ChatMessage); onChangeValue(body.content); }; const onFocus = () => {}; const onBlur = () => {}; const onChangeValue = (t: string) => { if (valueRef.current !== t) { setDisable(false); } else { setDisable(true); } _setValue(t); }; const onEdited = () => { onEditMessageFinished?.(_msg.msgId, value); }; return { msg: _msg, updateMsg: _updateMsg, value, setValue: onChangeValue, inputRef, onFocus, onBlur, disable, onEdited, }; }