Merge pull request #2363 from ecency/nt/reply-modal

Nt/reply modal
This commit is contained in:
Feruz M 2022-06-24 17:06:03 +03:00 committed by GitHub
commit 5e869e31d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 132 additions and 94 deletions

View File

@ -6,12 +6,9 @@ import {
TouchableOpacity, TouchableOpacity,
View, View,
ActivityIndicator, ActivityIndicator,
} from 'react-native'; } from 'react-native';
import { MainButton, PostBody, TextButton } from '..'; import { MainButton, PostBody, TextButton } from '..';
import styles from './insertLinkModalStyles'; import styles from './insertLinkModalStyles';
import ActionSheet from 'react-native-actions-sheet';
import EStyleSheet from 'react-native-extended-stylesheet';
import TextInput from '../textInput'; import TextInput from '../textInput';
import { delay } from '../../utils/editor'; import { delay } from '../../utils/editor';
import { isStringWebLink } from '../markdownEditor/view/formats/utils'; import { isStringWebLink } from '../markdownEditor/view/formats/utils';
@ -20,6 +17,7 @@ import { ScrollView } from 'react-native-gesture-handler';
import applyWebLinkFormat from '../markdownEditor/view/formats/applyWebLinkFormat'; import applyWebLinkFormat from '../markdownEditor/view/formats/applyWebLinkFormat';
import Clipboard from '@react-native-clipboard/clipboard'; import Clipboard from '@react-native-clipboard/clipboard';
import getWindowDimensions from '../../utils/getWindowDimensions'; import getWindowDimensions from '../../utils/getWindowDimensions';
import Modal from '../modal';
interface InsertLinkModalProps { interface InsertLinkModalProps {
handleOnInsertLink: ({ handleOnInsertLink: ({
@ -32,12 +30,12 @@ interface InsertLinkModalProps {
handleOnSheetClose: () => void; handleOnSheetClose: () => void;
} }
const screenWidth = getWindowDimensions().width - 58; const screenWidth = getWindowDimensions().width - 58;
const previewWidth = (10 / 16) * getWindowDimensions().width;
export const InsertLinkModal = forwardRef( export const InsertLinkModal = forwardRef(
({ handleOnInsertLink, handleOnSheetClose }: InsertLinkModalProps, ref) => { ({ handleOnInsertLink, handleOnSheetClose }: InsertLinkModalProps, ref) => {
const intl = useIntl(); const intl = useIntl();
const [visible, setVisible] = useState(false);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [label, setLabel] = useState(''); const [label, setLabel] = useState('');
const [url, setUrl] = useState(''); const [url, setUrl] = useState('');
@ -47,10 +45,11 @@ export const InsertLinkModal = forwardRef(
const [selection, setSelection] = useState({ start: 0, end: 0 }); const [selection, setSelection] = useState({ start: 0, end: 0 });
const [selectedUrlType, setSelectedUrlType] = useState(0); const [selectedUrlType, setSelectedUrlType] = useState(0);
const [previewBody, setPreviewBody] = useState(''); const [previewBody, setPreviewBody] = useState('');
const sheetModalRef = useRef<ActionSheet>();
const labelInputRef = useRef(null); const labelInputRef = useRef(null);
const urlInputRef = useRef(null); const urlInputRef = useRef(null);
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
showModal: async ({ selectedText, selection }) => { showModal: async ({ selectedText, selection }) => {
if (selectedText) { if (selectedText) {
@ -68,12 +67,12 @@ export const InsertLinkModal = forwardRef(
setSelection(selection); setSelection(selection);
} }
sheetModalRef.current?.setModalVisible(true); setVisible(true);
await delay(1500); await delay(1500);
labelInputRef.current?.focus(); labelInputRef.current?.focus();
}, },
hideModal: () => { hideModal: () => {
sheetModalRef.current?.setModalVisible(false); setVisible(false);
}, },
})); }));
@ -118,6 +117,7 @@ export const InsertLinkModal = forwardRef(
const _handleOnCloseSheet = () => { const _handleOnCloseSheet = () => {
labelInputRef.current?.blur(); labelInputRef.current?.blur();
setVisible(false);
setLabel(''); setLabel('');
setUrl(''); setUrl('');
setSelectedUrlType(0); setSelectedUrlType(0);
@ -141,7 +141,7 @@ export const InsertLinkModal = forwardRef(
<View style={styles.floatingContainer}> <View style={styles.floatingContainer}>
<TextButton <TextButton
style={styles.cancelButton} style={styles.cancelButton}
onPress={() => sheetModalRef.current?.setModalVisible(false)} onPress={() => setVisible(false)}// sheetModalRef.current?.setModalVisible(false)}
text={'Cancel'} text={'Cancel'}
/> />
<MainButton <MainButton
@ -150,7 +150,7 @@ export const InsertLinkModal = forwardRef(
iconName="plus" iconName="plus"
iconType="MaterialCommunityIcons" iconType="MaterialCommunityIcons"
iconColor="white" iconColor="white"
text={'Insert Link'} text={intl.formatMessage({ id: 'editor.insert_link' })}
/> />
</View> </View>
); );
@ -291,17 +291,18 @@ export const InsertLinkModal = forwardRef(
); );
return ( return (
<ActionSheet
ref={sheetModalRef} <Modal
gestureEnabled={true} isOpen={visible}
keyboardShouldPersistTaps="handled" handleOnModalClose={_handleOnCloseSheet}
containerStyle={styles.sheetContent} presentationStyle="formSheet"
keyboardHandlerEnabled animationType="slide"
indicatorColor={EStyleSheet.value('$primaryWhiteLightBackground')} title={intl.formatMessage({ id: 'editor.insert_link' })}
onClose={_handleOnCloseSheet} style={styles.modalStyle}
> >
{_renderContent} {_renderContent}
</ActionSheet> </Modal>
); );
}, },
); );

View File

@ -19,8 +19,10 @@ export default EStyleSheet.create({
paddingTop: 32, paddingTop: 32,
paddingBottom: 16, paddingBottom: 16,
}, },
container: { container: {
paddingVertical: 8, paddingVertical: 8,
backgroundColor: '$primaryBackgroundColor',
}, },
bodyWrapper: { bodyWrapper: {
flex: 3, flex: 3,
@ -30,7 +32,7 @@ export default EStyleSheet.create({
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'flex-end', justifyContent: 'flex-end',
alignItems: 'center', alignItems: 'center',
paddingVertical: 8, paddingVertical: 16,
paddingHorizontal: 16, paddingHorizontal: 16,
backgroundColor: '$primaryBackgroundColor', backgroundColor: '$primaryBackgroundColor',
} as ViewStyle, } as ViewStyle,

View File

@ -1 +1,2 @@
export * from './quickProfileModal'; export * from './quickProfileModal';
export * from './inputSupportModal';

View File

@ -0,0 +1,12 @@
import {ViewStyle } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
container: {
flex: 1,
justifyContent:"flex-end",
backgroundColor: 'rgba(0, 0, 0, 0.2)',
} as ViewStyle,
})

View File

@ -0,0 +1,43 @@
import React, { Component } from 'react';
import { View as AnimatedView } from 'react-native-animatable'
import { Portal } from 'react-native-portalize';
import styles from '../children/inputSupportModal.styles';
import { KeyboardAvoidingView, Platform, View } from 'react-native';
export interface InputSupportModalProps {
visible:boolean;
onClose:()=>void;
children?:any
}
export const InputSupportModal = ({children, visible, onClose}: InputSupportModalProps, ref) => {
return (
<Portal>
{
visible && (
<AnimatedView
style={styles.container}
duration={300}
animation='fadeInUp'>
<>
<View style={styles.container} onTouchEnd={onClose} />
{
Platform.select({
ios: (
<KeyboardAvoidingView style={styles.container} behavior="padding">
{children}
</KeyboardAvoidingView>
),
android: <View style={styles.container}>{children}</View>,
})
}
</>
</AnimatedView>
)
}
</Portal>
);
};

View File

@ -0,0 +1 @@
export * from './container/inputSupportModal';

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState, useCallback } from 'react'; import React, { useEffect, useState, useCallback } from 'react';
import EStyleSheet from 'react-native-extended-stylesheet'; import EStyleSheet from 'react-native-extended-stylesheet';
import styles from './quickReplyModalStyles'; import styles from './quickReplyModalStyles';
import { View, Text, Alert, TouchableOpacity, Keyboard, Platform } from 'react-native'; import { View, Text, Alert, TouchableOpacity, Keyboard, Platform, KeyboardAvoidingView } from 'react-native';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { IconButton, MainButton, TextButton, TextInput, UserAvatar } from '..'; import { IconButton, MainButton, TextButton, TextInput, UserAvatar } from '..';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
@ -14,27 +14,26 @@ import {
updateDraftCache, updateDraftCache,
} from '../../redux/actions/cacheActions'; } from '../../redux/actions/cacheActions';
import { default as ROUTES } from '../../constants/routeNames'; import { default as ROUTES } from '../../constants/routeNames';
import {get, debounce} from 'lodash'; import { get, debounce } from 'lodash';
import { navigate } from '../../navigation/service'; import { navigate } from '../../navigation/service';
import { postBodySummary } from '@ecency/render-helper'; import { postBodySummary } from '@ecency/render-helper';
import { Draft } from '../../redux/reducers/cacheReducer'; import { Draft } from '../../redux/reducers/cacheReducer';
import { RootState } from '../../redux/store/store'; import { RootState } from '../../redux/store/store';
import comment from '../../constants/options/comment';
export interface QuickReplyModalContentProps { export interface QuickReplyModalContentProps {
fetchPost?: any; fetchPost?: any;
selectedPost?: any; selectedPost?: any;
inputRef?: any; inputRef?: any;
sheetModalRef?: any;
handleCloseRef?: any; handleCloseRef?: any;
onClose:()=>void;
} }
export const QuickReplyModalContent = ({ export const QuickReplyModalContent = ({
fetchPost, fetchPost,
selectedPost, selectedPost,
inputRef, inputRef,
sheetModalRef,
handleCloseRef, handleCloseRef,
onClose,
}: QuickReplyModalContentProps) => { }: QuickReplyModalContentProps) => {
const intl = useIntl(); const intl = useIntl();
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -51,8 +50,8 @@ export const QuickReplyModalContent = ({
let parentAuthor = selectedPost ? selectedPost.author : ''; let parentAuthor = selectedPost ? selectedPost.author : '';
let parentPermlink = selectedPost ? selectedPost.permlink : ''; let parentPermlink = selectedPost ? selectedPost.permlink : '';
let draftId = `${currentAccount.name}/${parentAuthor}/${parentPermlink}`; //different draftId for each user acount let draftId = `${currentAccount.name}/${parentAuthor}/${parentPermlink}`; //different draftId for each user acount
useEffect(() => { useEffect(() => {
handleCloseRef.current = handleSheetClose; handleCloseRef.current = handleSheetClose;
}, [commentValue]); }, [commentValue]);
@ -75,7 +74,7 @@ export const QuickReplyModalContent = ({
// add quick comment value into cache // add quick comment value into cache
const _addQuickCommentIntoCache = (value = commentValue) => { const _addQuickCommentIntoCache = (value = commentValue) => {
const quickCommentDraftData: Draft = { const quickCommentDraftData: Draft = {
author: currentAccount.name, author: currentAccount.name,
body: value body: value
@ -88,14 +87,14 @@ export const QuickReplyModalContent = ({
// handle close press // handle close press
const _handleClosePress = () => { const _handleClosePress = () => {
sheetModalRef.current?.setModalVisible(false); onClose()
}; };
// navigate to post on summary press // navigate to post on summary press
const _handleOnSummaryPress = () => { const _handleOnSummaryPress = () => {
Keyboard.dismiss(); Keyboard.dismiss();
sheetModalRef.current?.setModalVisible(false); onClose();
navigate({ navigate({
routeName: ROUTES.SCREENS.POST, routeName: ROUTES.SCREENS.POST,
params: { params: {
@ -146,7 +145,7 @@ export const QuickReplyModalContent = ({
.then(() => { .then(() => {
stateTimer = setTimeout(() => { stateTimer = setTimeout(() => {
setIsSending(false); setIsSending(false);
sheetModalRef.current?.setModalVisible(false); onClose();
setCommentValue(''); setCommentValue('');
dispatch( dispatch(
toastNotification( toastNotification(
@ -200,7 +199,7 @@ export const QuickReplyModalContent = ({
const _handleExpandBtn = async () => { const _handleExpandBtn = async () => {
if (selectedPost) { if (selectedPost) {
Keyboard.dismiss(); Keyboard.dismiss();
sheetModalRef.current?.setModalVisible(false); onClose();
await delay(50); await delay(50);
navigate({ navigate({
routeName: ROUTES.SCREENS.EDITOR, routeName: ROUTES.SCREENS.EDITOR,
@ -215,7 +214,7 @@ export const QuickReplyModalContent = ({
}; };
const _deboucedCacheUpdate = useCallback(debounce(_addQuickCommentIntoCache, 500),[]) const _deboucedCacheUpdate = useCallback(debounce(_addQuickCommentIntoCache, 500), [])
const _onChangeText = (value) => { const _onChangeText = (value) => {
setCommentValue(value); setCommentValue(value);
@ -226,18 +225,6 @@ export const QuickReplyModalContent = ({
//VIEW_RENDERERS //VIEW_RENDERERS
const _renderSheetHeader = () => (
<View style={styles.modalHeader}>
<IconButton
name="close"
iconType="MaterialCommunityIcons"
size={28}
color={EStyleSheet.value('$primaryBlack')}
iconStyle={{}}
onPress={() => _handleClosePress()}
/>
</View>
);
const _renderSummary = () => ( const _renderSummary = () => (
<TouchableOpacity onPress={() => _handleOnSummaryPress()}> <TouchableOpacity onPress={() => _handleOnSummaryPress()}>
@ -288,7 +275,9 @@ export const QuickReplyModalContent = ({
</View> </View>
); );
return (
const _renderContent = (
<View style={styles.modalContainer}> <View style={styles.modalContainer}>
{_renderSummary()} {_renderSummary()}
{_renderAvatar()} {_renderAvatar()}
@ -297,7 +286,7 @@ export const QuickReplyModalContent = ({
innerRef={inputRef} innerRef={inputRef}
onChangeText={_onChangeText} onChangeText={_onChangeText}
value={commentValue} value={commentValue}
// autoFocus autoFocus
placeholder={intl.formatMessage({ placeholder={intl.formatMessage({
id: 'quick_reply.placeholder', id: 'quick_reply.placeholder',
})} })}
@ -313,5 +302,7 @@ export const QuickReplyModalContent = ({
{_renderReplyBtn()} {_renderReplyBtn()}
</View> </View>
</View> </View>
); )
return _renderContent
}; };

View File

@ -1,26 +1,23 @@
import { Platform } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet'; import EStyleSheet from 'react-native-extended-stylesheet';
import { getBottomSpace, isIphoneX } from 'react-native-iphone-x-helper';
export default EStyleSheet.create({ export default EStyleSheet.create({
sheetContent: { sheetContent: {
backgroundColor: '$primaryBackgroundColor', backgroundColor: '$primaryBackgroundColor',
position: 'absolute', marginTop:132,
bottom: 0,
left: 0,
right: 0,
zIndex: 999,
}, },
container: { container: {
flex: 1, flex: 1,
justifyContent:"flex-end",
backgroundColor: 'rgba(0, 0, 0, 0.2)',
}, },
modalContainer: { modalContainer: {
paddingTop: 4, margin:16,
paddingBottom: Platform.select({ borderRadius:16,
ios:isIphoneX() ? getBottomSpace() - 20 : 12, backgroundColor: '$primaryBackgroundColor',
android: 20 paddingTop: 16,
}) , paddingBottom: 16,
}, },
cancelButton: { cancelButton: {

View File

@ -1,10 +1,7 @@
import React, { useImperativeHandle, useRef, useState } from 'react'; import React, { useImperativeHandle, useRef, useState } from 'react';
import ActionSheet from 'react-native-actions-sheet';
import EStyleSheet from 'react-native-extended-stylesheet';
import { forwardRef } from 'react'; import { forwardRef } from 'react';
import { Portal } from 'react-native-portalize';
import { QuickReplyModalContent } from './quickReplyModalContent'; import { QuickReplyModalContent } from './quickReplyModalContent';
import styles from './quickReplyModalStyles'; import { InputSupportModal } from '../organisms';
export interface QuickReplyModalProps { export interface QuickReplyModalProps {
fetchPost?: any; fetchPost?: any;
@ -12,47 +9,39 @@ export interface QuickReplyModalProps {
const QuickReplyModal = ({ fetchPost }: QuickReplyModalProps, ref) => { const QuickReplyModal = ({ fetchPost }: QuickReplyModalProps, ref) => {
const [selectedPost, setSelectedPost] = useState(null); const [selectedPost, setSelectedPost] = useState(null);
const sheetModalRef = useRef<ActionSheet>();
const inputRef = useRef<TextInput>(null); const inputRef = useRef<TextInput>(null);
const handleCloseRef = useRef(null); const handleCloseRef = useRef(null);
const [visible, setVisible] = useState(false);
//CALLBACK_METHOD //CALLBACK_METHOD
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
show: (post: any) => { show: (post: any) => {
setSelectedPost(post); setSelectedPost(post);
sheetModalRef.current?.setModalVisible(true); setVisible(true)
// wait for modal to open and then show the keyboard
setTimeout(() => {
inputRef.current?.focus();
}, 500);
}, },
})); }));
const _onClose = () => {
setVisible(false);
}
return ( return (
<Portal> <InputSupportModal
<ActionSheet visible={visible && !!selectedPost}
ref={sheetModalRef} onClose={_onClose}
gestureEnabled={true} >
keyboardShouldPersistTaps="always" <QuickReplyModalContent
containerStyle={styles.sheetContent} fetchPost={fetchPost}
keyboardHandlerEnabled selectedPost={selectedPost}
indicatorColor={EStyleSheet.value('$primaryWhiteLightBackground')} inputRef={inputRef}
onClose={() => { onClose={_onClose}
setSelectedPost(null); //set null on sheet close, causing inconsistant cache bug handleCloseRef={handleCloseRef}
handleCloseRef.current(); />
}} </InputSupportModal>
>
{selectedPost && (
<QuickReplyModalContent
fetchPost={fetchPost}
selectedPost={selectedPost}
inputRef={inputRef}
sheetModalRef={sheetModalRef}
handleCloseRef={handleCloseRef}
/>
)}
</ActionSheet>
</Portal>
); );
}; };

View File

@ -379,6 +379,7 @@
"url": "URL", "url": "URL",
"enter_url_placeholder":"Enter URL", "enter_url_placeholder":"Enter URL",
"link_type_text":"Type of Link", "link_type_text":"Type of Link",
"insert_link":"Insert Link",
"preview":"Preview", "preview":"Preview",
"invalid_url_error":"Please insert valid url", "invalid_url_error":"Please insert valid url",
"plain":"Plain", "plain":"Plain",