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-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",

View File

@ -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,
},
}),
});

View File

@ -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 = ({
</ScrollView>
);
const _handleOnSnippetSelect = (snippetText) => {
const _handleOnSnippetReceived = (snippetText) => {
applySnippet({
text,
selection,
@ -244,6 +280,28 @@ const MarkdownEditorView = ({
</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 = () => (
<StickyBar>
<View style={styles.leftButtonsWrapper}>
@ -275,8 +333,7 @@ const MarkdownEditorView = ({
/>
<IconButton
onPress={() => {
// galleryRef.current.show()}
uploadsGalleryModalRef.current.showModal();
galleryRef.current.show();
}}
style={styles.rightIcons}
size={20}
@ -386,7 +443,10 @@ const MarkdownEditorView = ({
_renderPreview()
)}
</ScrollView>
{_renderFloatingDraftButton()}
{!isPreviewActive && _renderEditorButtons()}
<Modal
isOpen={isSnippetsOpen}
handleOnModalClose={() => setIsSnippetsOpen(false)}
@ -398,17 +458,16 @@ const MarkdownEditorView = ({
animationType="slide"
style={styles.modalStyle}
>
<SnippetsModal username={currentAccount.username} handleOnSelect={_handleOnSnippetSelect} />
<SnippetsModal
username={currentAccount.username}
handleOnSelect={_handleOnSnippetReceived}
/>
</Modal>
<UploadsGalleryModal
ref={uploadsGalleryModalRef}
username={currentAccount.username}
handleOnSelect={_handleOnMediaSelect}
handleOnUploadPress={() => {
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');
}
}}
/>
<ActionSheet

View File

@ -21,13 +21,11 @@ interface MediaInsertData {
interface UploadsGalleryModalProps {
username:string;
isUploading:boolean;
handleOnSelect:(data:MediaInsertData)=>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 (
<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 = (
@ -207,7 +184,6 @@ export const UploadsGalleryModal = forwardRef(({username, handleOnSelect, handl
/>
}
/>
{_renderFloatingButton()}
</View>
</View>
)

View File

@ -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",

View File

@ -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));

View File

@ -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 }]

View File

@ -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}
/>
);
}

View File

@ -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}
/>
</PostForm>
</View>

View File

@ -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==