created image upload

This commit is contained in:
ue 2019-09-08 14:52:16 +03:00
parent 7b9f8af42c
commit 81af8d4f03
10 changed files with 219 additions and 103 deletions

View File

@ -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,
}) => (
<LinearGradient
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
@ -25,13 +32,19 @@ const AvatarHeader = ({ username, name, reputation, navigation, avatarUrl }) =>
size={25}
/>
<View style={styles.wrapper}>
<UserAvatar noAction size="xl" username={username} avatarUrl={avatarUrl} />
<UserAvatar
key={avatarUrl || username}
noAction
size="xl"
username={username}
avatarUrl={avatarUrl}
/>
<IconButton
iconStyle={styles.addIcon}
style={styles.addButton}
iconType="MaterialCommunityIcons"
name="plus"
onPress={() => alert('upload')}
onPress={() => showImageUploadActions()}
size={15}
/>
<View style={styles.textWrapper}>

View File

@ -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 {
<View style={styles.textInput}>
<TextInput
style={inputStyle}
onFocus={() => this._handleOnFocus()}
onFocus={() => this.setState({ inputBorderColor: '#357ce6' })}
onBlur={() => this.setState({ inputBorderColor: '#e7e7e7' })}
autoCapitalize="none"
secureTextEntry={secureTextEntry}
height={height}

View File

@ -65,5 +65,7 @@ export default EStyleSheet.create({
fontSize: 14,
color: '$primaryDarkText',
alignSelf: 'flex-start',
width: '100%',
height: 30,
},
});

View File

@ -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
}) => (
<View style={styles.container}>
<IconButton
iconStyle={styles.saveIcon}
style={styles.saveButton}
iconType="MaterialIcons"
name="save"
onPress={() => alert('upload')}
onPress={() => alert('asd')}
size={30}
/>
<KeyboardAwareScrollView
enableAutoAutomaticScroll={Platform.OS === 'ios'}
contentContainerStyle={{ flexGrow: 1 }}
>
<TouchableOpacity style={styles.coverImgWrapper} onPress={() => alert('upload')}>
<TouchableOpacity style={styles.coverImgWrapper} onPress={showImageUploadActions}>
<Image
style={styles.coverImg}
source={{ uri: `https://steemitimages.com/400x0/${coverUrl}` }}
@ -40,7 +48,7 @@ const ProfileEditFormView = ({ avatarUrl, coverUrl, isDarkTheme, formData, intl,
style={styles.addButton}
iconType="MaterialCommunityIcons"
name="plus"
onPress={() => alert('upload')}
onPress={showImageUploadActions}
size={15}
/>
</TouchableOpacity>
@ -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,
/>
</View>
))}
{/*
<View style={styles.formItem}>
<Text style={styles.label}>About</Text>
<FormInput
wrapperStyle={styles.formStyle}
isValid
height={30}
onChange={value => console.log('changed')}
placeholder="About"
isEditable
type="text"
value={about}
inputStyle={styles.input}
/>
</View>
<View style={styles.formItem}>
<Text style={styles.label}>Location</Text>
<FormInput
wrapperStyle={styles.formStyle}
isValid
height={30}
onChange={value => console.log('changed')}
placeholder="Location"
isEditable
type="text"
value={location}
inputStyle={styles.input}
/>
</View>
<View style={styles.formItem}>
<Text style={styles.label}>Website</Text>
<FormInput
wrapperStyle={styles.formStyle}
isValid
height={30}
onChange={value => console.log('changed')}
placeholder="Website"
isEditable
type="text"
value={website}
inputStyle={styles.input}
/>
</View> */}
</KeyboardAwareScrollView>
</View>
);

View File

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

View File

@ -101,7 +101,7 @@
"edit": {
"display_name": "Display Name",
"about": "About",
"location": "location",
"location": "Location",
"website": "Website"
}
},

View File

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

View File

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

View File

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

View File

@ -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 (
<ProfileEditContainer>
{({ currentAccount, isDarkTheme, formData }) => (
{({
currentAccount,
isDarkTheme,
formData,
handleOnItemChange,
handleMediaAction,
name,
location,
website,
about,
avatarUrl,
coverUrl,
}) => (
<Fragment>
<AvatarHeader
username={get(currentAccount, 'name')}
name={get(currentAccount, 'about.profile.name')}
name={name}
reputation={get(currentAccount, 'reputation')}
avatarUrl={get(currentAccount, 'avatar')}
avatarUrl={avatarUrl}
showImageUploadActions={() => this._showImageUploadActions('avatarUrl')}
/>
<ProfileEditForm
formData={formData}
isDarkTheme={isDarkTheme}
about={get(currentAccount, 'about.profile.about')}
name={get(currentAccount, 'about.profile.name')}
location={get(currentAccount, 'about.profile.profile.location')}
website={get(currentAccount, 'about.profile.profile.website')}
coverUrl={get(currentAccount, 'about.profile.cover_image')}
avatarUrl={get(currentAccount, 'avatar')}
about={about}
name={name}
location={location}
website={website}
coverUrl={coverUrl}
showImageUploadActions={() => this._showImageUploadActions('coverUrl')}
handleOnItemChange={handleOnItemChange}
/>
<ActionSheet
ref={this.galleryRef}
options={[
intl.formatMessage({
id: 'editor.open_gallery',
}),
intl.formatMessage({
id: 'editor.capture_photo',
}),
intl.formatMessage({
id: 'alert.cancel',
}),
]}
cancelButtonIndex={2}
onPress={index => {
handleMediaAction(
index === 0 ? 'image' : index === 1 && 'camera',
selectedUploadAction,
);
}}
/>
</Fragment>
)}