Merge pull request #1931 from ecency/nt/editor-tweaks

Nt/editor tweaks
This commit is contained in:
Feruz M 2021-04-25 13:36:23 +03:00 committed by GitHub
commit f35ce3d27f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 152 additions and 151 deletions

View File

@ -67,6 +67,7 @@
"react-native": "0.61.5", "react-native": "0.61.5",
"react-native-actions-sheet": "^0.4.2", "react-native-actions-sheet": "^0.4.2",
"react-native-actionsheet": "ecency/react-native-actionsheet", "react-native-actionsheet": "ecency/react-native-actionsheet",
"react-native-animatable": "^1.3.3",
"react-native-autoheight-webview": "^1.5.7", "react-native-autoheight-webview": "^1.5.7",
"react-native-config": "luggit/react-native-config#master", "react-native-config": "luggit/react-native-config#master",
"react-native-dark-mode": "^0.2.2", "react-native-dark-mode": "^0.2.2",

View File

@ -94,4 +94,18 @@ export default EStyleSheet.create({
paddingTop: 32, paddingTop: 32,
paddingBottom: 16, paddingBottom: 16,
}, },
floatingContainer: Platform.select({
//absolute positioning makes button hide behind keyboard on ios
ios: {
alignItems: 'flex-end',
margin: 16,
marginBottom: 24,
},
//on android the appearing of button was causing momentary glitch with ios variant style
android: {
position: 'absolute',
right: 16,
bottom: 56,
},
}),
}); });

View File

@ -11,6 +11,8 @@ import {
import ActionSheet from 'react-native-actionsheet'; import ActionSheet from 'react-native-actionsheet';
import { renderPostBody } from '@ecency/render-helper'; import { renderPostBody } from '@ecency/render-helper';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { View as AnimatedView } from 'react-native-animatable';
import { get } from 'lodash';
import { Icon } from '../../icon'; import { Icon } from '../../icon';
// Utils // Utils
@ -42,6 +44,7 @@ import { ThemeContainer } from '../../../containers';
// Styles // Styles
import styles from './markdownEditorStyles'; import styles from './markdownEditorStyles';
import applySnippet from './formats/applySnippet'; import applySnippet from './formats/applySnippet';
import { MainButton } from '../../mainButton';
const MIN_BODY_INPUT_HEIGHT = 300; const MIN_BODY_INPUT_HEIGHT = 300;
@ -68,12 +71,15 @@ const MarkdownEditorView = ({
getCommunity, getCommunity,
currentAccount, currentAccount,
autoFocusText, autoFocusText,
sharedSnippetText,
onLoadDraftPress,
}) => { }) => {
const [text, setText] = useState(draftBody || ''); const [text, setText] = useState(draftBody || '');
const [selection, setSelection] = useState({ start: 0, end: 0 }); const [selection, setSelection] = useState({ start: 0, end: 0 });
const [editable, setEditable] = useState(true); const [editable, setEditable] = useState(true);
const [bodyInputHeight, setBodyInputHeight] = useState(MIN_BODY_INPUT_HEIGHT); const [bodyInputHeight, setBodyInputHeight] = useState(MIN_BODY_INPUT_HEIGHT);
const [isSnippetsOpen, setIsSnippetsOpen] = useState(false); const [isSnippetsOpen, setIsSnippetsOpen] = useState(false);
const [showDraftLoadButton, setShowDraftLoadButton] = useState(false);
const inputRef = useRef(null); const inputRef = useRef(null);
const galleryRef = useRef(null); const galleryRef = useRef(null);
@ -91,12 +97,38 @@ const MarkdownEditorView = ({
} }
}, [isPreviewActive]); }, [isPreviewActive]);
useEffect(() => {
if (onLoadDraftPress) {
setShowDraftLoadButton(true);
}
}, [onLoadDraftPress]);
useEffect(() => { useEffect(() => {
if (text === '' && draftBody !== '') { if (text === '' && draftBody !== '') {
_setTextAndSelection({ selection: { start: 0, end: 0 }, text: draftBody }); _setTextAndSelection({ selection: { start: 0, end: 0 }, text: draftBody });
} }
}, [draftBody]); }, [draftBody]);
useEffect(() => {
//hide draft button if fields changes and button was visible
if (showDraftLoadButton) {
let isCreating =
get(fields, 'title', '') !== '' ||
get(fields, 'body', '') !== '' ||
get(fields, 'tags', []) !== [];
if (isCreating) {
setShowDraftLoadButton(false);
}
}
}, [fields]);
useEffect(() => {
if (sharedSnippetText) {
_handleOnSnippetReceived(sharedSnippetText);
}
}, [sharedSnippetText]);
useEffect(() => { useEffect(() => {
if (editable === null) { if (editable === null) {
// workaround for android context menu issue // workaround for android context menu issue
@ -110,14 +142,18 @@ const MarkdownEditorView = ({
}, [isLoading]); }, [isLoading]);
useEffect(() => { useEffect(() => {
if (uploadedImage && uploadedImage.url && uploadedImage.shouldInsert) { if (uploadedImage && uploadedImage.url) {
applyImageLink({ if (uploadedImage.shouldInsert) {
text, applyImageLink({
selection, text,
setTextAndSelection: _setTextAndSelection, selection,
item: { url: uploadedImage.url, text: uploadedImage.hash }, setTextAndSelection: _setTextAndSelection,
isImage: !!uploadedImage, item: { url: uploadedImage.url, text: uploadedImage.hash },
}); isImage: !!uploadedImage,
});
} else {
uploadsGalleryModalRef.current.showModal();
}
} }
}, [uploadedImage]); }, [uploadedImage]);
@ -208,7 +244,7 @@ const MarkdownEditorView = ({
</ScrollView> </ScrollView>
); );
const _handleOnSnippetSelect = (snippetText) => { const _handleOnSnippetReceived = (snippetText) => {
applySnippet({ applySnippet({
text, text,
selection, selection,
@ -244,6 +280,28 @@ const MarkdownEditorView = ({
</View> </View>
); );
const _renderFloatingDraftButton = () => {
if (showDraftLoadButton) {
const _onPress = () => {
setShowDraftLoadButton(false);
onLoadDraftPress();
};
return (
<AnimatedView style={styles.floatingContainer} animation="bounceInRight">
<MainButton
style={{ width: isLoading ? null : 120 }}
onPress={_onPress}
iconName="square-edit-outline"
iconType="MaterialCommunityIcons"
iconColor="white"
text="DRAFT"
isLoading={isLoading}
/>
</AnimatedView>
);
}
};
const _renderEditorButtons = () => ( const _renderEditorButtons = () => (
<StickyBar> <StickyBar>
<View style={styles.leftButtonsWrapper}> <View style={styles.leftButtonsWrapper}>
@ -275,8 +333,7 @@ const MarkdownEditorView = ({
/> />
<IconButton <IconButton
onPress={() => { onPress={() => {
// galleryRef.current.show()} galleryRef.current.show();
uploadsGalleryModalRef.current.showModal();
}} }}
style={styles.rightIcons} style={styles.rightIcons}
size={20} size={20}
@ -386,7 +443,10 @@ const MarkdownEditorView = ({
_renderPreview() _renderPreview()
)} )}
</ScrollView> </ScrollView>
{_renderFloatingDraftButton()}
{!isPreviewActive && _renderEditorButtons()} {!isPreviewActive && _renderEditorButtons()}
<Modal <Modal
isOpen={isSnippetsOpen} isOpen={isSnippetsOpen}
handleOnModalClose={() => setIsSnippetsOpen(false)} handleOnModalClose={() => setIsSnippetsOpen(false)}
@ -398,17 +458,16 @@ const MarkdownEditorView = ({
animationType="slide" animationType="slide"
style={styles.modalStyle} style={styles.modalStyle}
> >
<SnippetsModal username={currentAccount.username} handleOnSelect={_handleOnSnippetSelect} /> <SnippetsModal
username={currentAccount.username}
handleOnSelect={_handleOnSnippetReceived}
/>
</Modal> </Modal>
<UploadsGalleryModal <UploadsGalleryModal
ref={uploadsGalleryModalRef} ref={uploadsGalleryModalRef}
username={currentAccount.username} username={currentAccount.username}
handleOnSelect={_handleOnMediaSelect} handleOnSelect={_handleOnMediaSelect}
handleOnUploadPress={() => {
galleryRef.current.show();
}}
isUploading={isUploading}
uploadedImage={uploadedImage} uploadedImage={uploadedImage}
/> />
@ -421,13 +480,21 @@ const MarkdownEditorView = ({
intl.formatMessage({ intl.formatMessage({
id: 'editor.capture_photo', id: 'editor.capture_photo',
}), }),
intl.formatMessage({
id: 'editor.uploaded_images',
}),
intl.formatMessage({ intl.formatMessage({
id: 'alert.cancel', id: 'alert.cancel',
}), }),
]} ]}
cancelButtonIndex={2} cancelButtonIndex={3}
onPress={(index) => { onPress={(index) => {
handleOpenImagePicker(index === 0 ? 'image' : index === 1 && 'camera'); if (index == 2) {
uploadsGalleryModalRef.current.showModal();
} else {
handleOpenImagePicker(index === 0 ? 'image' : index === 1 && 'camera');
}
}} }}
/> />
<ActionSheet <ActionSheet

View File

@ -21,13 +21,11 @@ interface MediaInsertData {
interface UploadsGalleryModalProps { interface UploadsGalleryModalProps {
username:string; username:string;
isUploading:boolean;
handleOnSelect:(data:MediaInsertData)=>void; handleOnSelect:(data:MediaInsertData)=>void;
handleOnUploadPress:()=>void;
uploadedImage:MediaInsertData; uploadedImage:MediaInsertData;
} }
export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, handleOnUploadPress, isUploading, uploadedImage}: UploadsGalleryModalProps, ref) => { export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, uploadedImage}: UploadsGalleryModalProps, ref) => {
const intl = useIntl(); const intl = useIntl();
const [mediaUploads, setMediaUploads] = useState([]); const [mediaUploads, setMediaUploads] = useState([]);
@ -167,28 +165,7 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, handl
}; };
//renders footer with add snipept button and shows new snippet modal
const _renderFloatingButton = () => {
const _onPress = () => {
if(handleOnUploadPress){
handleOnUploadPress();
}
}
return (
<View style={styles.floatingContainer}>
<MainButton
style={{ width: isUploading?null:130}}
onPress={_onPress}
iconName="plus"
iconType="MaterialCommunityIcons"
iconColor="white"
text={intl.formatMessage({id:'uploads_modal.btn_add'})}
isLoading={isUploading}
/>
</View>
);
};
const _renderContent = ( const _renderContent = (
@ -207,7 +184,6 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, handl
/> />
} }
/> />
{_renderFloatingButton()}
</View> </View>
</View> </View>
) )

View File

@ -281,6 +281,7 @@
"reply": "Reply", "reply": "Reply",
"open_gallery": "Open Gallery", "open_gallery": "Open Gallery",
"capture_photo": "Capture a photo", "capture_photo": "Capture a photo",
"uploaded_images": "Uploaded Images",
"limited_tags": "Only 10 tags allowed, remove some", "limited_tags": "Only 10 tags allowed, remove some",
"limited_length": "Maximum length of each tag should be 24", "limited_length": "Maximum length of each tag should be 24",
"limited_dash": "Use one dash in each tag", "limited_dash": "Use one dash in each tag",

View File

@ -22,7 +22,7 @@ const persistedReducer = persistReducer(persistConfig, reducer);
const middleware = [thunk]; const middleware = [thunk];
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
middleware.push(logger); // middleware.push(logger);
} }
const store = createStore(persistedReducer, applyMiddleware(...middleware)); const store = createStore(persistedReducer, applyMiddleware(...middleware));

View File

@ -158,10 +158,10 @@ class ApplicationContainer extends Component {
}); });
ReceiveSharingIntent.getReceivedFiles( ReceiveSharingIntent.getReceivedFiles(
(files) => { () => {
navigate({ navigate({
routeName: ROUTES.SCREENS.EDITOR, routeName: ROUTES.SCREENS.EDITOR,
params: { upload: files }, params: { hasSharedIntent: true },
}); });
// files returns as JSON Array example // files returns as JSON Array example
//[{ filePath: null, text: null, weblink: null, mimeType: null, contentUri: null, fileName: null, extension: null }] //[{ filePath: null, text: null, weblink: null, mimeType: null, contentUri: null, fileName: null, extension: null }]

View File

@ -8,6 +8,7 @@ import AsyncStorage from '@react-native-community/async-storage';
// Services and Actions // Services and Actions
import { Buffer } from 'buffer'; import { Buffer } from 'buffer';
import ReceiveSharingIntent from 'react-native-receive-sharing-intent';
import { import {
uploadImage, uploadImage,
addDraft, addDraft,
@ -15,7 +16,7 @@ import {
schedule, schedule,
getDrafts, getDrafts,
} from '../../../providers/ecency/ecency'; } from '../../../providers/ecency/ecency';
import { toastNotification, setRcOffer, showActionModal } from '../../../redux/actions/uiAction'; import { toastNotification, setRcOffer } from '../../../redux/actions/uiAction';
import { import {
postContent, postContent,
getPurePost, getPurePost,
@ -40,7 +41,6 @@ import {
// import { generateSignature } from '../../../utils/image'; // import { generateSignature } from '../../../utils/image';
// Component // Component
import EditorScreen from '../screen/editorScreen'; import EditorScreen from '../screen/editorScreen';
import ImageAssets from '../../../assets/ImageAssets';
/* /*
* Props Name Description Value * Props Name Description Value
@ -69,6 +69,8 @@ class EditorContainer extends Component {
community: [], community: [],
rewardType: 'default', rewardType: 'default',
beneficiaries: [], beneficiaries: [],
sharedSnippetText: null,
onLoadDraftPress: false,
}; };
} }
@ -81,9 +83,11 @@ class EditorContainer extends Component {
let isEdit; let isEdit;
let post; let post;
let _draft; let _draft;
let hasSharedIntent = false;
if (navigation.state && navigation.state.params) { if (navigation.state && navigation.state.params) {
const navigationParams = navigation.state.params; const navigationParams = navigation.state.params;
hasSharedIntent = navigationParams.hasSharedIntent;
if (navigationParams.draft) { if (navigationParams.draft) {
_draft = navigationParams.draft; _draft = navigationParams.draft;
@ -98,30 +102,6 @@ class EditorContainer extends Component {
community: navigationParams.community, community: navigationParams.community,
}); });
} }
if (navigationParams.upload) {
const { upload } = navigationParams;
upload.forEach((el) => {
if (el.filePath && el.fileName) {
// this.setState({ isUploading: true });
const _media = {
path: el.filePath,
mime: el.mimeType,
filename: el.fileName || `img_${Math.random()}.jpg`,
};
this._uploadImage(_media, { shouldInsert: true });
} else if (el.text) {
this.setState({
draftPost: {
title: '',
body: el.text,
tags: [],
},
});
}
});
}
if (navigationParams.post) { if (navigationParams.post) {
({ post } = navigationParams); ({ post } = navigationParams);
@ -154,11 +134,35 @@ class EditorContainer extends Component {
} }
} }
if (!isEdit && !_draft) { if (!isEdit && !_draft && !hasSharedIntent) {
this._fetchDraftsForComparison(isReply); this._fetchDraftsForComparison(isReply);
} else {
this._requestKeyboardFocus();
} }
this._requestKeyboardFocus();
ReceiveSharingIntent.getReceivedFiles(
(files) => {
files.forEach((el) => {
if (el.filePath && el.fileName) {
const _media = {
path: el.filePath,
mime: el.mimeType,
filename: el.fileName || `img_${Math.random()}.jpg`,
};
this._uploadImage(_media, { shouldInsert: true });
} else if (el.text) {
this.setState({
sharedSnippetText: el.text,
});
}
});
// To clear Intents
ReceiveSharingIntent.clearReceivedFiles();
},
(error) => {
console.log('error :>> ', error);
},
);
} }
componentWillUnmount() { componentWillUnmount() {
@ -285,30 +289,10 @@ class EditorContainer extends Component {
this._getStorageDraft(username, isReply, _draft); this._getStorageDraft(username, isReply, _draft);
}; };
const leaveEmpty = () => {
console.log('Leaving editor empty');
};
if (drafts.length > 0 || (idLessDraft && idLessDraft.timestamp > 0)) { if (drafts.length > 0 || (idLessDraft && idLessDraft.timestamp > 0)) {
dispatch( this.setState({
showActionModal( onLoadDraftPress: loadRecentDraft,
intl.formatMessage({ });
id: 'editor.alert_init_title',
}),
intl.formatMessage({
id: 'editor.alert_init_body',
}),
[
{
text: intl.formatMessage({ id: 'editor.alert_btn_draft' }),
onPress: loadRecentDraft,
},
{ text: intl.formatMessage({ id: 'editor.alert_btn_new' }), onPress: leaveEmpty },
],
ImageAssets.writerMascot,
this._requestKeyboardFocus,
),
);
} }
} catch (err) { } catch (err) {
console.warn('Failed to compare drafts, load general', err); console.warn('Failed to compare drafts, load general', err);
@ -433,57 +417,6 @@ class EditorContainer extends Component {
isUploading: false, isUploading: false,
}); });
} }
// uploadImage(media, currentAccount.name, sign).then((res) => {
// if (res.data && res.data.url) {
// res.data.hash = res.data.url.split('/').pop();
// this.setState({
// uploadedImage: res.data,
// isUploading: false,
// });
// }
// })
// .catch((error) => {
// console.log(error, error.message);
// if (error.toString().includes('code 413')) {
// Alert.alert(
// intl.formatMessage({
// id: 'alert.fail',
// }),
// intl.formatMessage({
// id: 'alert.payloadTooLarge',
// }),
// );
// } else if (error.toString().includes('code 429')) {
// Alert.alert(
// intl.formatMessage({
// id: 'alert.fail',
// }),
// intl.formatMessage({
// id: 'alert.quotaExceeded',
// }),
// );
// } else if (error.toString().includes('code 400')) {
// Alert.alert(
// intl.formatMessage({
// id: 'alert.fail',
// }),
// intl.formatMessage({
// id: 'alert.invalidImage',
// }),
// );
// } else {
// Alert.alert(
// intl.formatMessage({
// id: 'alert.fail',
// }),
// error.message || error.toString(),
// );
// }
// this.setState({
// isUploading: false,
// });
// });
}; };
_handleMediaOnSelectFailure = (error) => { _handleMediaOnSelectFailure = (error) => {
@ -1100,6 +1033,8 @@ class EditorContainer extends Component {
uploadedImage, uploadedImage,
community, community,
isDraft, isDraft,
sharedSnippetText,
onLoadDraftPress,
} = this.state; } = this.state;
const tags = navigation.state.params && navigation.state.params.tags; const tags = navigation.state.params && navigation.state.params.tags;
@ -1133,6 +1068,8 @@ class EditorContainer extends Component {
community={community} community={community}
currentAccount={currentAccount} currentAccount={currentAccount}
isDraft={isDraft} isDraft={isDraft}
sharedSnippetText={sharedSnippetText}
onLoadDraftPress={onLoadDraftPress}
/> />
); );
} }

View File

@ -19,6 +19,7 @@ import {
SelectCommunityModalContainer, SelectCommunityModalContainer,
Modal, Modal,
UserAvatar, UserAvatar,
MainButton,
} from '../../../components'; } from '../../../components';
// dhive // dhive
@ -320,6 +321,8 @@ class EditorScreen extends Component {
handleBeneficiaries, handleBeneficiaries,
currentAccount, currentAccount,
autoFocusText, autoFocusText,
sharedSnippetText,
onLoadDraftPress,
} = this.props; } = this.props;
const rightButtonText = intl.formatMessage({ const rightButtonText = intl.formatMessage({
id: isEdit ? 'basic_header.update' : isReply ? 'basic_header.reply' : 'basic_header.publish', id: isEdit ? 'basic_header.update' : isReply ? 'basic_header.reply' : 'basic_header.publish',
@ -396,6 +399,8 @@ class EditorScreen extends Component {
onTitleChanged={this._handleChangeTitle} onTitleChanged={this._handleChangeTitle}
getCommunity={this._getCommunity} getCommunity={this._getCommunity}
autoFocusText={autoFocusText} autoFocusText={autoFocusText}
sharedSnippetText={sharedSnippetText}
onLoadDraftPress={onLoadDraftPress}
/> />
</PostForm> </PostForm>
</View> </View>

View File

@ -7398,7 +7398,7 @@ react-native-actionsheet@ecency/react-native-actionsheet:
version "2.4.2" version "2.4.2"
resolved "https://codeload.github.com/ecency/react-native-actionsheet/tar.gz/c74540db08a4c2049ee9c8a8077b5c476b536e2c" resolved "https://codeload.github.com/ecency/react-native-actionsheet/tar.gz/c74540db08a4c2049ee9c8a8077b5c476b536e2c"
react-native-animatable@1.3.3: react-native-animatable@1.3.3, react-native-animatable@^1.3.3:
version "1.3.3" version "1.3.3"
resolved "https://registry.yarnpkg.com/react-native-animatable/-/react-native-animatable-1.3.3.tgz#a13a4af8258e3bb14d0a9d839917e9bb9274ec8a" resolved "https://registry.yarnpkg.com/react-native-animatable/-/react-native-animatable-1.3.3.tgz#a13a4af8258e3bb14d0a9d839917e9bb9274ec8a"
integrity sha512-2ckIxZQAsvWn25Ho+DK3d1mXIgj7tITkrS4pYDvx96WyOttSvzzFeQnM2od0+FUMzILbdHDsDEqZvnz1DYNQ1w== integrity sha512-2ckIxZQAsvWn25Ho+DK3d1mXIgj7tITkrS4pYDvx96WyOttSvzzFeQnM2od0+FUMzILbdHDsDEqZvnz1DYNQ1w==