From 81af8d4f0308465a49e361d29baaa9815eadf2f4 Mon Sep 17 00:00:00 2001 From: ue Date: Sun, 8 Sep 2019 14:52:16 +0300 Subject: [PATCH] created image upload --- .../avatarHeader/avatarHeaderView.js | 19 +++- .../formInput/view/formInputView.js | 20 ++-- .../profileEditForm/profileEditFormStyles.js | 2 + .../profileEditForm/profileEditFormView.js | 63 +++-------- .../userAvatar/view/userAvatarView.js | 4 +- src/config/locales/en-US.json | 2 +- src/containers/profileEditContainer.js | 105 +++++++++++++++++- src/providers/esteem/esteem.js | 9 +- .../editor/container/editorContainer.js | 31 ++---- .../profileEdit/screen/profileEditScreen.js | 67 +++++++++-- 10 files changed, 219 insertions(+), 103 deletions(-) diff --git a/src/components/avatarHeader/avatarHeaderView.js b/src/components/avatarHeader/avatarHeaderView.js index d3eb1673f..a3640e8d8 100644 --- a/src/components/avatarHeader/avatarHeaderView.js +++ b/src/components/avatarHeader/avatarHeaderView.js @@ -9,7 +9,14 @@ import { IconButton } from '../iconButton'; // Styles import styles from './avatarHeaderStyles'; -const AvatarHeader = ({ username, name, reputation, navigation, avatarUrl }) => ( +const AvatarHeader = ({ + username, + name, + reputation, + navigation, + avatarUrl, + showImageUploadActions, +}) => ( size={25} /> - + alert('upload')} + onPress={() => showImageUploadActions()} size={15} /> diff --git a/src/components/formInput/view/formInputView.js b/src/components/formInput/view/formInputView.js index 12fe06fa8..3b22aeaa4 100644 --- a/src/components/formInput/view/formInputView.js +++ b/src/components/formInput/view/formInputView.js @@ -1,12 +1,11 @@ import React, { Component } from 'react'; import { View } from 'react-native'; import FastImage from 'react-native-fast-image'; -import { Icon } from '../../icon'; - -// Constants // Components import { TextInput } from '../../textInput'; +import { Icon } from '../../icon'; + // Styles import styles from './formInputStyles'; @@ -19,16 +18,13 @@ class FormInputView extends Component { * @prop { boolean } isEditable - Can permission edit. * @prop { boolean } isValid - This delegate input valit or not. * @prop { boolean } secureTextEntry - For hiding password value. - * - * - * */ constructor(props) { super(props); this.state = { value: props.value || '', - inputBorderColor: '#c1c5c7', + inputBorderColor: '#e7e7e7', isValid: true, }; } @@ -47,14 +43,11 @@ class FormInputView extends Component { const { onChange } = this.props; this.setState({ value }); - onChange && onChange(value); + if (onChange) onChange(value); }; _handleOnFocus = () => { - const { inputBorderColor } = this.state; - if (inputBorderColor !== '#357ce6') { - this.setState({ inputBorderColor: '#357ce6' }); - } + this.setState({ inputBorderColor: '#357ce6' }); }; render() { @@ -101,7 +94,8 @@ class FormInputView extends Component { this._handleOnFocus()} + onFocus={() => this.setState({ inputBorderColor: '#357ce6' })} + onBlur={() => this.setState({ inputBorderColor: '#e7e7e7' })} autoCapitalize="none" secureTextEntry={secureTextEntry} height={height} diff --git a/src/components/profileEditForm/profileEditFormStyles.js b/src/components/profileEditForm/profileEditFormStyles.js index 996a5ec52..53a092327 100644 --- a/src/components/profileEditForm/profileEditFormStyles.js +++ b/src/components/profileEditForm/profileEditFormStyles.js @@ -65,5 +65,7 @@ export default EStyleSheet.create({ fontSize: 14, color: '$primaryDarkText', alignSelf: 'flex-start', + width: '100%', + height: 30, }, }); diff --git a/src/components/profileEditForm/profileEditFormView.js b/src/components/profileEditForm/profileEditFormView.js index f87eaf515..5f0407bac 100644 --- a/src/components/profileEditForm/profileEditFormView.js +++ b/src/components/profileEditForm/profileEditFormView.js @@ -14,21 +14,29 @@ import { IconButton } from '../iconButton'; // Styles import styles from './profileEditFormStyles'; -const ProfileEditFormView = ({ avatarUrl, coverUrl, isDarkTheme, formData, intl, ...props }) => ( +const ProfileEditFormView = ({ + coverUrl, + isDarkTheme, + formData, + intl, + handleOnItemChange, + showImageUploadActions, + ...props +}) => ( alert('upload')} + onPress={() => alert('asd')} size={30} /> - alert('upload')}> + alert('upload')} + onPress={showImageUploadActions} size={15} /> @@ -56,7 +64,7 @@ const ProfileEditFormView = ({ avatarUrl, coverUrl, isDarkTheme, formData, intl, wrapperStyle={styles.formStyle} isValid height={30} - onChange={value => console.log(value, item.valueKey)} + onChange={value => handleOnItemChange(value, item.valueKey)} placeholder={item.placeholder} isEditable type={item.type} @@ -65,51 +73,6 @@ const ProfileEditFormView = ({ avatarUrl, coverUrl, isDarkTheme, formData, intl, /> ))} - {/* - - About - console.log('changed')} - placeholder="About" - isEditable - type="text" - value={about} - inputStyle={styles.input} - /> - - - - Location - console.log('changed')} - placeholder="Location" - isEditable - type="text" - value={location} - inputStyle={styles.input} - /> - - - - Website - console.log('changed')} - placeholder="Website" - isEditable - type="text" - value={website} - inputStyle={styles.input} - /> - */} ); diff --git a/src/components/userAvatar/view/userAvatarView.js b/src/components/userAvatar/view/userAvatarView.js index 1e7e62f51..d7c48f7a2 100644 --- a/src/components/userAvatar/view/userAvatarView.js +++ b/src/components/userAvatar/view/userAvatarView.js @@ -46,8 +46,8 @@ class UserAvatarView extends Component { const imageSize = size === 'xl' ? 'large' : 'small'; let _size; const _avatar = username - ? { uri: `https://steemitimages.com/u/${username}/avatar/${imageSize}` } - : avatarUrl || DEFAULT_IMAGE; + ? { uri: avatarUrl || `https://steemitimages.com/u/${username}/avatar/${imageSize}` } + : DEFAULT_IMAGE; if (!disableSize) { _size = 32; diff --git a/src/config/locales/en-US.json b/src/config/locales/en-US.json index 0c66bb808..3fc9222c8 100644 --- a/src/config/locales/en-US.json +++ b/src/config/locales/en-US.json @@ -101,7 +101,7 @@ "edit": { "display_name": "Display Name", "about": "About", - "location": "location", + "location": "Location", "website": "Website" } }, diff --git a/src/containers/profileEditContainer.js b/src/containers/profileEditContainer.js index f57bbbe00..f20786628 100644 --- a/src/containers/profileEditContainer.js +++ b/src/containers/profileEditContainer.js @@ -1,6 +1,11 @@ import { Component } from 'react'; +import { Alert } from 'react-native'; import { connect } from 'react-redux'; +import { injectIntl } from 'react-intl'; +import ImagePicker from 'react-native-image-crop-picker'; +import get from 'lodash/get'; +import { uploadImage } from '../providers/esteem/esteem'; // import ROUTES from '../constants/routeNames'; const FORM_DATA = [ @@ -38,7 +43,15 @@ class ProfileEditContainer extends Component { constructor(props) { super(props); - this.state = {}; + this.state = { + isUploading: false, + about: get(props.currentAccount, 'about.profile.about'), + name: get(props.currentAccount, 'about.profile.name'), + location: get(props.currentAccount, 'about.profile.location'), + website: get(props.currentAccount, 'about.profile.website'), + coverUrl: get(props.currentAccount, 'about.profile.cover_image'), + avatarUrl: get(props.currentAccount, 'avatar'), + }; } // Component Life Cycles @@ -47,8 +60,87 @@ class ProfileEditContainer extends Component { _handleOnSave = () => {}; + _handleOnItemChange = (val, item) => { + console.log(val, item); + }; + + _uploadImage = (media, action) => { + const { intl } = this.props; + uploadImage(media) + .then(res => { + if (res.data && res.data.url) { + this.setState({ [action]: res.data.url, isUploading: false }); + } + }) + .catch(error => { + if (error) { + Alert.alert( + intl.formatMessage({ + id: 'alert.fail', + }), + error.message || error.toString(), + ); + } + this.setState({ isUploading: false }); + }); + }; + + _handleMediaAction = (type, uploadAction) => { + if (type === 'camera') { + this._handleOpenCamera(uploadAction); + } else if (type === 'image') { + this._handleOpenImagePicker(uploadAction); + } + }; + + _handleOpenImagePicker = action => { + ImagePicker.openPicker({ + includeBase64: true, + }) + .then(image => { + this._handleMediaOnSelected(image, action); + }) + .catch(e => { + this._handleMediaOnSelectFailure(e); + }); + }; + + _handleOpenCamera = action => { + ImagePicker.openCamera({ + includeBase64: true, + }) + .then(image => { + this._handleMediaOnSelected(image, action); + }) + .catch(e => { + this._handleMediaOnSelectFailure(e); + }); + }; + + _handleMediaOnSelected = (media, action) => { + this.setState({ isUploading: true }, () => { + this._uploadImage(media, action); + }); + }; + + _handleMediaOnSelectFailure = error => { + const { intl } = this.props; + + if (get(error, 'code') === 'E_PERMISSION_MISSING') { + Alert.alert( + intl.formatMessage({ + id: 'alert.permission_denied', + }), + intl.formatMessage({ + id: 'alert.permission_text', + }), + ); + } + }; + render() { const { children, currentAccount, isDarkTheme } = this.props; + const { isUploading, name, location, website, about, coverUrl, avatarUrl } = this.state; return ( children && @@ -56,6 +148,15 @@ class ProfileEditContainer extends Component { currentAccount, isDarkTheme, formData: FORM_DATA, + isUploading, + handleMediaAction: this._handleMediaAction, + handleOnItemChange: this._handleOnItemChange, + name, + location, + website, + about, + coverUrl, + avatarUrl, }) ); } @@ -66,4 +167,4 @@ const mapStateToProps = state => ({ isDarkTheme: state.application.isDarkTheme, }); -export default connect(mapStateToProps)(ProfileEditContainer); +export default connect(mapStateToProps)(injectIntl(ProfileEditContainer)); diff --git a/src/providers/esteem/esteem.js b/src/providers/esteem/esteem.js index e8e049903..5ff899b34 100644 --- a/src/providers/esteem/esteem.js +++ b/src/providers/esteem/esteem.js @@ -300,7 +300,14 @@ export const getImages = username => api.get(`api/images/${username}`).then(resp export const addMyImage = (user, url) => api.post('/image', { username: user, image_url: url }); -export const uploadImage = file => { +export const uploadImage = media => { + const file = { + uri: media.path, + type: media.mime, + name: media.filename || `IMG_${Math.random()}.JPG`, + size: media.size, + }; + const fData = new FormData(); fData.append('postimage', file); diff --git a/src/screens/editor/container/editorContainer.js b/src/screens/editor/container/editorContainer.js index 4a61e5a1c..3db98c28b 100644 --- a/src/screens/editor/container/editorContainer.js +++ b/src/screens/editor/container/editorContainer.js @@ -42,7 +42,6 @@ class EditorContainer extends Component { autoFocusText: false, draftId: null, draftPost: null, - isCameraOrPickerOpen: false, isDraftSaved: false, isDraftSaving: false, isEdit: false, @@ -141,8 +140,6 @@ class EditorContainer extends Component { }; _handleRoutingAction = routingAction => { - this.setState({ isCameraOrPickerOpen: true }); - if (routingAction === 'camera') { this._handleOpenCamera(); } else if (routingAction === 'image') { @@ -175,7 +172,7 @@ class EditorContainer extends Component { }; _handleMediaOnSelected = media => { - this.setState({ isCameraOrPickerOpen: false, isUploading: true }, () => { + this.setState({ isUploading: true }, () => { this._uploadImage(media); }); // For new image api @@ -189,33 +186,27 @@ class EditorContainer extends Component { _uploadImage = media => { const { intl } = this.props; - const file = { - uri: media.path, - type: media.mime, - name: media.filename || `IMG_${Math.random()}.JPG`, - size: media.size, - }; - - uploadImage(file) + uploadImage(media) .then(res => { if (res.data && res.data.url) { this.setState({ uploadedImage: res.data, isUploading: false }); } }) .catch(error => { - Alert.alert( - intl.formatMessage({ - id: 'alert.fail', - }), - error.message || error.toString(), - ); + if (error) { + Alert.alert( + intl.formatMessage({ + id: 'alert.fail', + }), + error.message || error.toString(), + ); + } this.setState({ isUploading: false }); }); }; _handleMediaOnSelectFailure = error => { const { intl } = this.props; - this.setState({ isCameraOrPickerOpen: false }); if (get(error, 'code') === 'E_PERMISSION_MISSING') { Alert.alert( @@ -567,7 +558,6 @@ class EditorContainer extends Component { const { autoFocusText, draftPost, - isCameraOrPickerOpen, isDraftSaved, isDraftSaving, isEdit, @@ -589,7 +579,6 @@ class EditorContainer extends Component { handleOnImagePicker={this._handleRoutingAction} handleOnSubmit={this._handleSubmit} initialEditor={this._initialEditor} - isCameraOrPickerOpen={isCameraOrPickerOpen} isDarkTheme={isDarkTheme} isDraftSaved={isDraftSaved} isDraftSaving={isDraftSaving} diff --git a/src/screens/profileEdit/screen/profileEditScreen.js b/src/screens/profileEdit/screen/profileEditScreen.js index a4cba13fe..a42ceb087 100644 --- a/src/screens/profileEdit/screen/profileEditScreen.js +++ b/src/screens/profileEdit/screen/profileEditScreen.js @@ -1,6 +1,7 @@ import React, { PureComponent, Fragment } from 'react'; import { injectIntl } from 'react-intl'; import get from 'lodash/get'; +import ActionSheet from 'react-native-actionsheet'; import { ProfileEditContainer } from '../../../containers'; @@ -15,33 +16,79 @@ class ProfileEditScreen extends PureComponent { constructor(props) { super(props); - this.state = {}; + this.state = { + selectedUploadAction: '', + }; + + this.galleryRef = React.createRef(); } // Component Life Cycles // Component Functions + _showImageUploadActions = async action => { + await this.setState({ selectedUploadAction: action }); + this.galleryRef.current.show(); + }; render() { + const { intl } = this.props; + const { selectedUploadAction } = this.state; + return ( - {({ currentAccount, isDarkTheme, formData }) => ( + {({ + currentAccount, + isDarkTheme, + formData, + handleOnItemChange, + handleMediaAction, + name, + location, + website, + about, + avatarUrl, + coverUrl, + }) => ( this._showImageUploadActions('avatarUrl')} /> this._showImageUploadActions('coverUrl')} + handleOnItemChange={handleOnItemChange} + /> + { + handleMediaAction( + index === 0 ? 'image' : index === 1 && 'camera', + selectedUploadAction, + ); + }} /> )}