diff --git a/package.json b/package.json index 3858e1285..285198aae 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "react-native": "0.61.5", "react-native-actions-sheet": "^0.4.2", "react-native-actionsheet": "ecency/react-native-actionsheet", + "react-native-animatable": "^1.3.3", "react-native-autoheight-webview": "^1.5.7", "react-native-config": "luggit/react-native-config#master", "react-native-dark-mode": "^0.2.2", diff --git a/src/components/markdownEditor/view/markdownEditorStyles.js b/src/components/markdownEditor/view/markdownEditorStyles.js index aaaa3924e..c89165c32 100644 --- a/src/components/markdownEditor/view/markdownEditorStyles.js +++ b/src/components/markdownEditor/view/markdownEditorStyles.js @@ -94,4 +94,18 @@ export default EStyleSheet.create({ paddingTop: 32, 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, + }, + }), }); diff --git a/src/components/markdownEditor/view/markdownEditorView.js b/src/components/markdownEditor/view/markdownEditorView.js index a2cb3f834..4b8e1ad28 100644 --- a/src/components/markdownEditor/view/markdownEditorView.js +++ b/src/components/markdownEditor/view/markdownEditorView.js @@ -11,6 +11,8 @@ import { import ActionSheet from 'react-native-actionsheet'; import { renderPostBody } from '@ecency/render-helper'; import { useDispatch, useSelector } from 'react-redux'; +import { View as AnimatedView } from 'react-native-animatable'; +import { get } from 'lodash'; import { Icon } from '../../icon'; // Utils @@ -42,6 +44,7 @@ import { ThemeContainer } from '../../../containers'; // Styles import styles from './markdownEditorStyles'; import applySnippet from './formats/applySnippet'; +import { MainButton } from '../../mainButton'; const MIN_BODY_INPUT_HEIGHT = 300; @@ -68,12 +71,15 @@ const MarkdownEditorView = ({ getCommunity, currentAccount, autoFocusText, + sharedSnippetText, + onLoadDraftPress, }) => { const [text, setText] = useState(draftBody || ''); const [selection, setSelection] = useState({ start: 0, end: 0 }); const [editable, setEditable] = useState(true); const [bodyInputHeight, setBodyInputHeight] = useState(MIN_BODY_INPUT_HEIGHT); const [isSnippetsOpen, setIsSnippetsOpen] = useState(false); + const [showDraftLoadButton, setShowDraftLoadButton] = useState(false); const inputRef = useRef(null); const galleryRef = useRef(null); @@ -91,12 +97,38 @@ const MarkdownEditorView = ({ } }, [isPreviewActive]); + useEffect(() => { + if (onLoadDraftPress) { + setShowDraftLoadButton(true); + } + }, [onLoadDraftPress]); + useEffect(() => { if (text === '' && draftBody !== '') { _setTextAndSelection({ selection: { start: 0, end: 0 }, text: 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(() => { if (editable === null) { // workaround for android context menu issue @@ -110,14 +142,18 @@ const MarkdownEditorView = ({ }, [isLoading]); useEffect(() => { - if (uploadedImage && uploadedImage.url && uploadedImage.shouldInsert) { - applyImageLink({ - text, - selection, - setTextAndSelection: _setTextAndSelection, - item: { url: uploadedImage.url, text: uploadedImage.hash }, - isImage: !!uploadedImage, - }); + if (uploadedImage && uploadedImage.url) { + if (uploadedImage.shouldInsert) { + applyImageLink({ + text, + selection, + setTextAndSelection: _setTextAndSelection, + item: { url: uploadedImage.url, text: uploadedImage.hash }, + isImage: !!uploadedImage, + }); + } else { + uploadsGalleryModalRef.current.showModal(); + } } }, [uploadedImage]); @@ -208,7 +244,7 @@ const MarkdownEditorView = ({ ); - const _handleOnSnippetSelect = (snippetText) => { + const _handleOnSnippetReceived = (snippetText) => { applySnippet({ text, selection, @@ -244,6 +280,28 @@ const MarkdownEditorView = ({ ); + const _renderFloatingDraftButton = () => { + if (showDraftLoadButton) { + const _onPress = () => { + setShowDraftLoadButton(false); + onLoadDraftPress(); + }; + return ( + + + + ); + } + }; + const _renderEditorButtons = () => ( @@ -275,8 +333,7 @@ const MarkdownEditorView = ({ /> { - // galleryRef.current.show()} - uploadsGalleryModalRef.current.showModal(); + galleryRef.current.show(); }} style={styles.rightIcons} size={20} @@ -386,7 +443,10 @@ const MarkdownEditorView = ({ _renderPreview() )} + + {_renderFloatingDraftButton()} {!isPreviewActive && _renderEditorButtons()} + setIsSnippetsOpen(false)} @@ -398,17 +458,16 @@ const MarkdownEditorView = ({ animationType="slide" style={styles.modalStyle} > - + { - galleryRef.current.show(); - }} - isUploading={isUploading} uploadedImage={uploadedImage} /> @@ -421,13 +480,21 @@ const MarkdownEditorView = ({ intl.formatMessage({ id: 'editor.capture_photo', }), + intl.formatMessage({ + id: 'editor.uploaded_images', + }), + intl.formatMessage({ id: 'alert.cancel', }), ]} - cancelButtonIndex={2} + cancelButtonIndex={3} onPress={(index) => { - handleOpenImagePicker(index === 0 ? 'image' : index === 1 && 'camera'); + if (index == 2) { + uploadsGalleryModalRef.current.showModal(); + } else { + handleOpenImagePicker(index === 0 ? 'image' : index === 1 && 'camera'); + } }} /> void; - handleOnUploadPress:()=>void; 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 [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 ( - - - - ); - }; + const _renderContent = ( @@ -207,7 +184,6 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, handl /> } /> - {_renderFloatingButton()} ) diff --git a/src/config/locales/en-US.json b/src/config/locales/en-US.json index 7e3379cfe..2cb4e6433 100644 --- a/src/config/locales/en-US.json +++ b/src/config/locales/en-US.json @@ -281,6 +281,7 @@ "reply": "Reply", "open_gallery": "Open Gallery", "capture_photo": "Capture a photo", + "uploaded_images": "Uploaded Images", "limited_tags": "Only 10 tags allowed, remove some", "limited_length": "Maximum length of each tag should be 24", "limited_dash": "Use one dash in each tag", diff --git a/src/redux/store/store.js b/src/redux/store/store.js index b05b44d48..4c387f633 100644 --- a/src/redux/store/store.js +++ b/src/redux/store/store.js @@ -22,7 +22,7 @@ const persistedReducer = persistReducer(persistConfig, reducer); const middleware = [thunk]; if (process.env.NODE_ENV === 'development') { - middleware.push(logger); + // middleware.push(logger); } const store = createStore(persistedReducer, applyMiddleware(...middleware)); diff --git a/src/screens/application/container/applicationContainer.js b/src/screens/application/container/applicationContainer.js index 2a4fe743a..018f808ae 100644 --- a/src/screens/application/container/applicationContainer.js +++ b/src/screens/application/container/applicationContainer.js @@ -158,10 +158,10 @@ class ApplicationContainer extends Component { }); ReceiveSharingIntent.getReceivedFiles( - (files) => { + () => { navigate({ routeName: ROUTES.SCREENS.EDITOR, - params: { upload: files }, + params: { hasSharedIntent: true }, }); // files returns as JSON Array example //[{ filePath: null, text: null, weblink: null, mimeType: null, contentUri: null, fileName: null, extension: null }] diff --git a/src/screens/editor/container/editorContainer.js b/src/screens/editor/container/editorContainer.js index 0cfc5a974..ffd492380 100644 --- a/src/screens/editor/container/editorContainer.js +++ b/src/screens/editor/container/editorContainer.js @@ -8,6 +8,7 @@ import AsyncStorage from '@react-native-community/async-storage'; // Services and Actions import { Buffer } from 'buffer'; +import ReceiveSharingIntent from 'react-native-receive-sharing-intent'; import { uploadImage, addDraft, @@ -15,7 +16,7 @@ import { schedule, getDrafts, } from '../../../providers/ecency/ecency'; -import { toastNotification, setRcOffer, showActionModal } from '../../../redux/actions/uiAction'; +import { toastNotification, setRcOffer } from '../../../redux/actions/uiAction'; import { postContent, getPurePost, @@ -40,7 +41,6 @@ import { // import { generateSignature } from '../../../utils/image'; // Component import EditorScreen from '../screen/editorScreen'; -import ImageAssets from '../../../assets/ImageAssets'; /* * Props Name Description Value @@ -69,6 +69,8 @@ class EditorContainer extends Component { community: [], rewardType: 'default', beneficiaries: [], + sharedSnippetText: null, + onLoadDraftPress: false, }; } @@ -81,9 +83,11 @@ class EditorContainer extends Component { let isEdit; let post; let _draft; + let hasSharedIntent = false; if (navigation.state && navigation.state.params) { const navigationParams = navigation.state.params; + hasSharedIntent = navigationParams.hasSharedIntent; if (navigationParams.draft) { _draft = navigationParams.draft; @@ -98,30 +102,6 @@ class EditorContainer extends Component { 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) { ({ post } = navigationParams); @@ -154,11 +134,35 @@ class EditorContainer extends Component { } } - if (!isEdit && !_draft) { + if (!isEdit && !_draft && !hasSharedIntent) { 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() { @@ -285,30 +289,10 @@ class EditorContainer extends Component { this._getStorageDraft(username, isReply, _draft); }; - const leaveEmpty = () => { - console.log('Leaving editor empty'); - }; - if (drafts.length > 0 || (idLessDraft && idLessDraft.timestamp > 0)) { - dispatch( - showActionModal( - 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, - ), - ); + this.setState({ + onLoadDraftPress: loadRecentDraft, + }); } } catch (err) { console.warn('Failed to compare drafts, load general', err); @@ -433,57 +417,6 @@ class EditorContainer extends Component { 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) => { @@ -1100,6 +1033,8 @@ class EditorContainer extends Component { uploadedImage, community, isDraft, + sharedSnippetText, + onLoadDraftPress, } = this.state; const tags = navigation.state.params && navigation.state.params.tags; @@ -1133,6 +1068,8 @@ class EditorContainer extends Component { community={community} currentAccount={currentAccount} isDraft={isDraft} + sharedSnippetText={sharedSnippetText} + onLoadDraftPress={onLoadDraftPress} /> ); } diff --git a/src/screens/editor/screen/editorScreen.js b/src/screens/editor/screen/editorScreen.js index 915a315ae..428d05858 100644 --- a/src/screens/editor/screen/editorScreen.js +++ b/src/screens/editor/screen/editorScreen.js @@ -19,6 +19,7 @@ import { SelectCommunityModalContainer, Modal, UserAvatar, + MainButton, } from '../../../components'; // dhive @@ -320,6 +321,8 @@ class EditorScreen extends Component { handleBeneficiaries, currentAccount, autoFocusText, + sharedSnippetText, + onLoadDraftPress, } = this.props; const rightButtonText = intl.formatMessage({ id: isEdit ? 'basic_header.update' : isReply ? 'basic_header.reply' : 'basic_header.publish', @@ -396,6 +399,8 @@ class EditorScreen extends Component { onTitleChanged={this._handleChangeTitle} getCommunity={this._getCommunity} autoFocusText={autoFocusText} + sharedSnippetText={sharedSnippetText} + onLoadDraftPress={onLoadDraftPress} /> diff --git a/yarn.lock b/yarn.lock index 7cd19636a..f54c11acf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7398,7 +7398,7 @@ react-native-actionsheet@ecency/react-native-actionsheet: version "2.4.2" 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" resolved "https://registry.yarnpkg.com/react-native-animatable/-/react-native-animatable-1.3.3.tgz#a13a4af8258e3bb14d0a9d839917e9bb9274ec8a" integrity sha512-2ckIxZQAsvWn25Ho+DK3d1mXIgj7tITkrS4pYDvx96WyOttSvzzFeQnM2od0+FUMzILbdHDsDEqZvnz1DYNQ1w==