mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-19 19:31:54 +03:00
Merge pull request #1973 from ecency/nt/avatar-update-bug
Nt/avatar update bug
This commit is contained in:
commit
9a117c5e85
@ -2,9 +2,11 @@ import EStyleSheet from 'react-native-extended-stylesheet';
|
|||||||
|
|
||||||
export default EStyleSheet.create({
|
export default EStyleSheet.create({
|
||||||
headerContainer: {
|
headerContainer: {
|
||||||
height: 100,
|
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
padding: 21,
|
paddingTop: 8,
|
||||||
|
paddingHorizontal: 24,
|
||||||
|
paddingBottom: 24,
|
||||||
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
backIcon: {
|
backIcon: {
|
||||||
color: '$white',
|
color: '$white',
|
||||||
@ -16,7 +18,7 @@ export default EStyleSheet.create({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
textWrapper: {
|
textWrapper: {
|
||||||
marginLeft: 16,
|
marginLeft: 24,
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
color: '$white',
|
color: '$white',
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { withNavigation } from 'react-navigation';
|
import { withNavigation } from 'react-navigation';
|
||||||
import { View, Text, SafeAreaView } from 'react-native';
|
import { View, Text, SafeAreaView, TouchableOpacity } from 'react-native';
|
||||||
import LinearGradient from 'react-native-linear-gradient';
|
import LinearGradient from 'react-native-linear-gradient';
|
||||||
|
|
||||||
import { UserAvatar } from '../userAvatar';
|
import { UserAvatar } from '../userAvatar';
|
||||||
@ -16,6 +16,7 @@ const AvatarHeader = ({
|
|||||||
navigation,
|
navigation,
|
||||||
avatarUrl,
|
avatarUrl,
|
||||||
showImageUploadActions,
|
showImageUploadActions,
|
||||||
|
isUploading,
|
||||||
}) => (
|
}) => (
|
||||||
<LinearGradient
|
<LinearGradient
|
||||||
start={{ x: 0, y: 0 }}
|
start={{ x: 0, y: 0 }}
|
||||||
@ -33,15 +34,25 @@ const AvatarHeader = ({
|
|||||||
size={25}
|
size={25}
|
||||||
/>
|
/>
|
||||||
<View style={styles.wrapper}>
|
<View style={styles.wrapper}>
|
||||||
<UserAvatar key={avatarUrl || username} noAction size="xl" username={username} />
|
<TouchableOpacity onPress={showImageUploadActions}>
|
||||||
<IconButton
|
<UserAvatar
|
||||||
iconStyle={styles.addIcon}
|
key={`${avatarUrl}-${username}`}
|
||||||
style={styles.addButton}
|
noAction
|
||||||
iconType="MaterialCommunityIcons"
|
size="xl"
|
||||||
name="plus"
|
username={username}
|
||||||
onPress={showImageUploadActions}
|
avatarUrl={avatarUrl}
|
||||||
size={15}
|
isLoading={isUploading}
|
||||||
/>
|
/>
|
||||||
|
<IconButton
|
||||||
|
iconStyle={styles.addIcon}
|
||||||
|
style={styles.addButton}
|
||||||
|
iconType="MaterialCommunityIcons"
|
||||||
|
name="plus"
|
||||||
|
onPress={showImageUploadActions}
|
||||||
|
size={15}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
<View style={styles.textWrapper}>
|
<View style={styles.textWrapper}>
|
||||||
{!!name && <Text style={styles.name}>{name}</Text>}
|
{!!name && <Text style={styles.name}>{name}</Text>}
|
||||||
<Text style={styles.username}>{`@${username} (${reputation})`}</Text>
|
<Text style={styles.username}>{`@${username} (${reputation})`}</Text>
|
||||||
|
@ -13,6 +13,7 @@ export default EStyleSheet.create({
|
|||||||
marginTop: 8,
|
marginTop: 8,
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
|
marginTop:8,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: '$primaryDarkText',
|
color: '$primaryDarkText',
|
||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
@ -25,7 +26,7 @@ export default EStyleSheet.create({
|
|||||||
height: 60,
|
height: 60,
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
alignSelf: 'stretch',
|
alignSelf: 'stretch',
|
||||||
backgroundColor: '#296CC0',
|
backgroundColor: '$primaryGray',
|
||||||
},
|
},
|
||||||
coverImageWrapper: {},
|
coverImageWrapper: {},
|
||||||
addIcon: {
|
addIcon: {
|
||||||
@ -62,13 +63,19 @@ export default EStyleSheet.create({
|
|||||||
},
|
},
|
||||||
|
|
||||||
input: {
|
input: {
|
||||||
fontSize: 14,
|
fontSize: 20,
|
||||||
color: '$primaryDarkText',
|
color: '$primaryBlack',
|
||||||
alignSelf: 'flex-start',
|
alignSelf: 'flex-start',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: 40,
|
paddingBottom:10,
|
||||||
},
|
},
|
||||||
contentContainer: {
|
contentContainer: {
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
},
|
},
|
||||||
|
activityIndicator: {
|
||||||
|
position:'absolute',
|
||||||
|
alignSelf:'center',
|
||||||
|
top:0,
|
||||||
|
bottom:8
|
||||||
|
}
|
||||||
});
|
});
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { withNavigation } from 'react-navigation';
|
import { withNavigation } from 'react-navigation';
|
||||||
import { View, TouchableOpacity, Image, Text, Platform } from 'react-native';
|
import { View, TouchableOpacity, Text, Platform, ActivityIndicator } from 'react-native';
|
||||||
|
import { View as AnimatedView } from 'react-native-animatable';
|
||||||
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
|
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
|
||||||
import { injectIntl } from 'react-intl';
|
import { injectIntl } from 'react-intl';
|
||||||
|
|
||||||
@ -17,9 +18,25 @@ import { getResizedImage } from '../../utils/image';
|
|||||||
|
|
||||||
// Styles
|
// Styles
|
||||||
import styles from './profileEditFormStyles';
|
import styles from './profileEditFormStyles';
|
||||||
|
import FastImage from 'react-native-fast-image';
|
||||||
|
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||||
|
import { MainButton } from '../mainButton';
|
||||||
|
|
||||||
|
|
||||||
|
interface ProfileEditFormProps {
|
||||||
|
coverUrl:string;
|
||||||
|
formData:any;
|
||||||
|
handleOnItemChange:()=>void;
|
||||||
|
handleOnSubmit:()=>void;
|
||||||
|
intl:any,
|
||||||
|
isDarkTheme:boolean,
|
||||||
|
isLoading:boolean,
|
||||||
|
isUploading:boolean,
|
||||||
|
showImageUploadActions:boolean,
|
||||||
|
saveEnabled:boolean,
|
||||||
|
}
|
||||||
|
|
||||||
const ProfileEditFormView = ({
|
const ProfileEditFormView = ({
|
||||||
avatarUrl,
|
|
||||||
coverUrl,
|
coverUrl,
|
||||||
formData,
|
formData,
|
||||||
handleOnItemChange,
|
handleOnItemChange,
|
||||||
@ -27,30 +44,41 @@ const ProfileEditFormView = ({
|
|||||||
intl,
|
intl,
|
||||||
isDarkTheme,
|
isDarkTheme,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
isUploading,
|
||||||
showImageUploadActions,
|
showImageUploadActions,
|
||||||
|
saveEnabled,
|
||||||
...props
|
...props
|
||||||
}) => (
|
}:ProfileEditFormProps) => (
|
||||||
|
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<IconButton
|
|
||||||
iconStyle={styles.saveIcon}
|
|
||||||
style={styles.saveButton}
|
|
||||||
iconType="MaterialIcons"
|
|
||||||
name="save"
|
|
||||||
onPress={handleOnSubmit}
|
|
||||||
size={30}
|
|
||||||
isLoading={isLoading}
|
|
||||||
/>
|
|
||||||
<KeyboardAwareScrollView
|
<KeyboardAwareScrollView
|
||||||
enableAutoAutomaticScroll={Platform.OS === 'ios'}
|
enableAutoAutomaticScroll={Platform.OS === 'ios'}
|
||||||
contentContainerStyle={styles.contentContainer}
|
contentContainerStyle={styles.contentContainer}
|
||||||
enableOnAndroid={true}
|
enableOnAndroid={true}
|
||||||
>
|
>
|
||||||
<TouchableOpacity style={styles.coverImgWrapper} onPress={showImageUploadActions}>
|
<TouchableOpacity style={styles.coverImgWrapper} onPress={showImageUploadActions}>
|
||||||
<Image
|
|
||||||
style={styles.coverImg}
|
<FastImage
|
||||||
source={{ uri: getResizedImage(coverUrl, 600) }}
|
style={styles.coverImg}
|
||||||
defaultSource={isDarkTheme ? DARK_COVER_IMAGE : LIGHT_COVER_IMAGE}
|
source={
|
||||||
/>
|
coverUrl
|
||||||
|
? { uri: getResizedImage(coverUrl, 600) }
|
||||||
|
: isDarkTheme
|
||||||
|
? DARK_COVER_IMAGE
|
||||||
|
: LIGHT_COVER_IMAGE
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
isUploading && (
|
||||||
|
<ActivityIndicator
|
||||||
|
style={styles.activityIndicator}
|
||||||
|
color={EStyleSheet.value('$white')}
|
||||||
|
size='large'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
iconStyle={styles.addIcon}
|
iconStyle={styles.addIcon}
|
||||||
@ -83,6 +111,22 @@ const ProfileEditFormView = ({
|
|||||||
</View>
|
</View>
|
||||||
))}
|
))}
|
||||||
</KeyboardAwareScrollView>
|
</KeyboardAwareScrollView>
|
||||||
|
|
||||||
|
{saveEnabled && (
|
||||||
|
<AnimatedView style={styles.floatingContainer} animation="bounceInRight">
|
||||||
|
<MainButton
|
||||||
|
style={{ width: isLoading ? null : 120, marginBottom:24, alignSelf:'flex-end' }}
|
||||||
|
onPress={handleOnSubmit}
|
||||||
|
iconName="save"
|
||||||
|
iconType="MaterialIcons"
|
||||||
|
iconColor="white"
|
||||||
|
text="SAVE"
|
||||||
|
isLoading={isLoading}
|
||||||
|
/>
|
||||||
|
</AnimatedView>
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
@ -6,4 +6,10 @@ export default EStyleSheet.create({
|
|||||||
borderColor: '$borderColor',
|
borderColor: '$borderColor',
|
||||||
backgroundColor: '$pureWhite',
|
backgroundColor: '$pureWhite',
|
||||||
},
|
},
|
||||||
|
activityIndicator: {
|
||||||
|
position:'absolute',
|
||||||
|
alignSelf:'center',
|
||||||
|
top:0,
|
||||||
|
bottom:0
|
||||||
|
}
|
||||||
});
|
});
|
@ -1,91 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
import { TouchableOpacity } from 'react-native';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import FastImage from 'react-native-fast-image';
|
|
||||||
import styles from './userAvatarStyles';
|
|
||||||
import { navigate } from '../../../navigation/service';
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
import ROUTES from '../../../constants/routeNames';
|
|
||||||
|
|
||||||
// Utils
|
|
||||||
import { getResizedAvatar } from '../../../utils/image';
|
|
||||||
|
|
||||||
const DEFAULT_IMAGE = require('../../../assets/avatar_default.png');
|
|
||||||
|
|
||||||
/* Props
|
|
||||||
* ------------------------------------------------
|
|
||||||
* @prop { type } name - Description....
|
|
||||||
*/
|
|
||||||
|
|
||||||
class UserAvatarView extends Component {
|
|
||||||
// Component Life Cycles
|
|
||||||
shouldComponentUpdate(nextProps) {
|
|
||||||
const { username } = this.props;
|
|
||||||
|
|
||||||
return nextProps.username !== username;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Component Functions
|
|
||||||
_handleOnAvatarPress = (username) => {
|
|
||||||
const {
|
|
||||||
currentUsername: { name },
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const routeName = name === username ? ROUTES.TABBAR.PROFILE : ROUTES.SCREENS.PROFILE;
|
|
||||||
|
|
||||||
navigate({
|
|
||||||
routeName,
|
|
||||||
params: {
|
|
||||||
username,
|
|
||||||
},
|
|
||||||
key: username,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
username,
|
|
||||||
size,
|
|
||||||
style,
|
|
||||||
disableSize,
|
|
||||||
noAction,
|
|
||||||
currentUsername: { name, avatar },
|
|
||||||
} = this.props;
|
|
||||||
const imageSize = 'large';
|
|
||||||
let _size;
|
|
||||||
const _avatar = username
|
|
||||||
? {
|
|
||||||
uri: getResizedAvatar(username, imageSize),
|
|
||||||
}
|
|
||||||
: DEFAULT_IMAGE;
|
|
||||||
|
|
||||||
if (!disableSize) {
|
|
||||||
_size = 32;
|
|
||||||
|
|
||||||
if (size === 'xl') {
|
|
||||||
_size = 64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableOpacity disabled={noAction} onPress={() => this._handleOnAvatarPress(username)}>
|
|
||||||
<FastImage
|
|
||||||
style={[
|
|
||||||
styles.avatar,
|
|
||||||
style,
|
|
||||||
!disableSize && { width: _size, height: _size, borderRadius: _size / 2 },
|
|
||||||
]}
|
|
||||||
source={_avatar}
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
|
||||||
currentUsername: state.account.currentAccount,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(UserAvatarView);
|
|
98
src/components/userAvatar/view/userAvatarView.tsx
Normal file
98
src/components/userAvatar/view/userAvatarView.tsx
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import { ActivityIndicator, TouchableOpacity, ViewStyle } from 'react-native';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import FastImage from 'react-native-fast-image';
|
||||||
|
import styles from './userAvatarStyles';
|
||||||
|
import { navigate } from '../../../navigation/service';
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
import ROUTES from '../../../constants/routeNames';
|
||||||
|
|
||||||
|
// Utils
|
||||||
|
import { getResizedAvatar } from '../../../utils/image';
|
||||||
|
import { useAppSelector } from '../../../hooks';
|
||||||
|
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||||
|
|
||||||
|
const DEFAULT_IMAGE = require('../../../assets/avatar_default.png');
|
||||||
|
|
||||||
|
/* Props
|
||||||
|
* ------------------------------------------------
|
||||||
|
* @prop { type } name - Description....
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface UserAvatarProps {
|
||||||
|
username:string;
|
||||||
|
avatarUrl?:string;
|
||||||
|
size?:'xl';
|
||||||
|
style?:ViewStyle;
|
||||||
|
disableSize?:boolean;
|
||||||
|
noAction?:boolean;
|
||||||
|
isLoading?:boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserAvatarView = ({
|
||||||
|
username,
|
||||||
|
avatarUrl,
|
||||||
|
size,
|
||||||
|
style,
|
||||||
|
disableSize,
|
||||||
|
noAction,
|
||||||
|
isLoading
|
||||||
|
}:UserAvatarProps) => {
|
||||||
|
|
||||||
|
const curUsername = useAppSelector(state=>state.account.currentAccount.name);
|
||||||
|
const avatarCacheStamp = useAppSelector(state=>state.ui.avatarCacheStamp);
|
||||||
|
|
||||||
|
// Component Functions
|
||||||
|
const _handleOnAvatarPress = (username:string) => {
|
||||||
|
const routeName = curUsername === username ? ROUTES.TABBAR.PROFILE : ROUTES.SCREENS.PROFILE;
|
||||||
|
navigate({
|
||||||
|
routeName,
|
||||||
|
params: {
|
||||||
|
username,
|
||||||
|
},
|
||||||
|
key: username,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const uri = avatarUrl ? avatarUrl : getResizedAvatar(username, 'large');
|
||||||
|
|
||||||
|
const _avatar = username
|
||||||
|
? { uri : `${uri}?stamp=${avatarCacheStamp}` }
|
||||||
|
: DEFAULT_IMAGE;
|
||||||
|
|
||||||
|
let _size:number;
|
||||||
|
if (!disableSize) {
|
||||||
|
_size = 32;
|
||||||
|
if (size === 'xl') {
|
||||||
|
_size = 64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity disabled={noAction} onPress={() => _handleOnAvatarPress(username)}>
|
||||||
|
<FastImage
|
||||||
|
style={[
|
||||||
|
styles.avatar,
|
||||||
|
style,
|
||||||
|
!disableSize && { width: _size, height: _size, borderRadius: _size / 2 },
|
||||||
|
]}
|
||||||
|
source={_avatar}
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
isLoading && (
|
||||||
|
<ActivityIndicator
|
||||||
|
style={styles.activityIndicator}
|
||||||
|
size='large'
|
||||||
|
color={EStyleSheet.value('$white')}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserAvatarView;
|
@ -10,6 +10,7 @@ import { uploadImage } from '../providers/ecency/ecency';
|
|||||||
|
|
||||||
import { profileUpdate, signImage } from '../providers/hive/dhive';
|
import { profileUpdate, signImage } from '../providers/hive/dhive';
|
||||||
import { updateCurrentAccount } from '../redux/actions/accountAction';
|
import { updateCurrentAccount } from '../redux/actions/accountAction';
|
||||||
|
import { setAvatarCacheStamp } from '../redux/actions/uiAction';
|
||||||
|
|
||||||
// import ROUTES from '../constants/routeNames';
|
// import ROUTES from '../constants/routeNames';
|
||||||
|
|
||||||
@ -50,6 +51,8 @@ class ProfileEditContainer extends Component {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
isUploading: false,
|
||||||
|
saveEnabled: false,
|
||||||
about: get(props.currentAccount, 'about.profile.about'),
|
about: get(props.currentAccount, 'about.profile.about'),
|
||||||
name: get(props.currentAccount, 'about.profile.name'),
|
name: get(props.currentAccount, 'about.profile.name'),
|
||||||
location: get(props.currentAccount, 'about.profile.location'),
|
location: get(props.currentAccount, 'about.profile.location'),
|
||||||
@ -64,20 +67,20 @@ class ProfileEditContainer extends Component {
|
|||||||
// Component Functions
|
// Component Functions
|
||||||
|
|
||||||
_handleOnItemChange = (val, item) => {
|
_handleOnItemChange = (val, item) => {
|
||||||
this.setState({ [item]: val });
|
this.setState({ [item]: val, saveEnabled: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
_uploadImage = async (media, action) => {
|
_uploadImage = async (media, action) => {
|
||||||
const { intl, currentAccount, pinCode } = this.props;
|
const { intl, currentAccount, pinCode } = this.props;
|
||||||
|
|
||||||
this.setState({ isLoading: true });
|
this.setState({ isUploading: true });
|
||||||
|
|
||||||
let sign = await signImage(media, currentAccount, pinCode);
|
let sign = await signImage(media, currentAccount, pinCode);
|
||||||
|
|
||||||
uploadImage(media, currentAccount.name, sign)
|
uploadImage(media, currentAccount.name, sign)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.data && res.data.url) {
|
if (res.data && res.data.url) {
|
||||||
this.setState({ [action]: res.data.url, isLoading: false });
|
this.setState({ [action]: res.data.url, isUploading: false, saveEnabled: true });
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -89,7 +92,7 @@ class ProfileEditContainer extends Component {
|
|||||||
error.message || error.toString(),
|
error.message || error.toString(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.setState({ isLoading: false });
|
this.setState({ isUploading: false });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -102,11 +105,11 @@ class ProfileEditContainer extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_handleOpenImagePicker = (action) => {
|
_handleOpenImagePicker = (action) => {
|
||||||
ImagePicker.openPicker({
|
ImagePicker.openPicker(
|
||||||
includeBase64: true,
|
action == 'avatarUrl' ? IMAGE_PICKER_AVATAR_OPTIONS : IMAGE_PICKER_COVER_OPTIONS,
|
||||||
})
|
)
|
||||||
.then((image) => {
|
.then((media) => {
|
||||||
this._handleMediaOnSelected(image, action);
|
this._uploadImage(media, action);
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
this._handleMediaOnSelectFailure(e);
|
this._handleMediaOnSelectFailure(e);
|
||||||
@ -114,23 +117,17 @@ class ProfileEditContainer extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_handleOpenCamera = (action) => {
|
_handleOpenCamera = (action) => {
|
||||||
ImagePicker.openCamera({
|
ImagePicker.openCamera(
|
||||||
includeBase64: true,
|
action == 'avatarUrl' ? IMAGE_PICKER_AVATAR_OPTIONS : IMAGE_PICKER_COVER_OPTIONS,
|
||||||
})
|
)
|
||||||
.then((image) => {
|
.then((media) => {
|
||||||
this._handleMediaOnSelected(image, action);
|
this._uploadImage(media, action);
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
this._handleMediaOnSelectFailure(e);
|
this._handleMediaOnSelectFailure(e);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleMediaOnSelected = (media, action) => {
|
|
||||||
this.setState({ isLoading: true }, () => {
|
|
||||||
this._uploadImage(media, action);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
_handleMediaOnSelectFailure = (error) => {
|
_handleMediaOnSelectFailure = (error) => {
|
||||||
const { intl } = this.props;
|
const { intl } = this.props;
|
||||||
|
|
||||||
@ -150,7 +147,7 @@ class ProfileEditContainer extends Component {
|
|||||||
const { currentAccount, pinCode, dispatch, navigation, intl } = this.props;
|
const { currentAccount, pinCode, dispatch, navigation, intl } = this.props;
|
||||||
const { name, location, website, about, coverUrl, avatarUrl } = this.state;
|
const { name, location, website, about, coverUrl, avatarUrl } = this.state;
|
||||||
|
|
||||||
await this.setState({ isLoading: true });
|
this.setState({ isLoading: true });
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
profile_image: avatarUrl,
|
profile_image: avatarUrl,
|
||||||
@ -161,31 +158,42 @@ class ProfileEditContainer extends Component {
|
|||||||
location,
|
location,
|
||||||
version: 2,
|
version: 2,
|
||||||
};
|
};
|
||||||
await profileUpdate(params, pinCode, currentAccount)
|
|
||||||
.then(async () => {
|
|
||||||
const _currentAccount = { ...currentAccount, display_name: name, avatar: avatarUrl };
|
|
||||||
_currentAccount.about.profile = { ...params };
|
|
||||||
|
|
||||||
dispatch(updateCurrentAccount(_currentAccount));
|
try {
|
||||||
|
await profileUpdate(params, pinCode, currentAccount);
|
||||||
|
|
||||||
navigation.state.params.fetchUser();
|
const _currentAccount = { ...currentAccount, display_name: name, avatar: avatarUrl };
|
||||||
navigation.goBack();
|
_currentAccount.about.profile = { ...params };
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
Alert.alert(
|
|
||||||
intl.formatMessage({
|
|
||||||
id: 'alert.fail',
|
|
||||||
}),
|
|
||||||
get(error, 'message', error.toString()),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.setState({ isLoading: false });
|
dispatch(updateCurrentAccount(_currentAccount));
|
||||||
|
dispatch(setAvatarCacheStamp(new Date().getTime()));
|
||||||
|
this.setState({ isLoading: false });
|
||||||
|
navigation.state.params.fetchUser();
|
||||||
|
navigation.goBack();
|
||||||
|
} catch (err) {
|
||||||
|
Alert.alert(
|
||||||
|
intl.formatMessage({
|
||||||
|
id: 'alert.fail',
|
||||||
|
}),
|
||||||
|
get(error, 'message', error.toString()),
|
||||||
|
);
|
||||||
|
this.setState({ isLoading: false });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { children, currentAccount, isDarkTheme } = this.props;
|
const { children, currentAccount, isDarkTheme } = this.props;
|
||||||
const { isLoading, name, location, website, about, coverUrl, avatarUrl } = this.state;
|
const {
|
||||||
|
isLoading,
|
||||||
|
isUploading,
|
||||||
|
name,
|
||||||
|
location,
|
||||||
|
website,
|
||||||
|
about,
|
||||||
|
coverUrl,
|
||||||
|
avatarUrl,
|
||||||
|
saveEnabled,
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
children &&
|
children &&
|
||||||
@ -200,9 +208,11 @@ class ProfileEditContainer extends Component {
|
|||||||
handleOnSubmit: this._handleOnSubmit,
|
handleOnSubmit: this._handleOnSubmit,
|
||||||
isDarkTheme,
|
isDarkTheme,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
isUploading,
|
||||||
location,
|
location,
|
||||||
name,
|
name,
|
||||||
website,
|
website,
|
||||||
|
saveEnabled,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -215,3 +225,14 @@ const mapStateToProps = (state) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps)(injectIntl(withNavigation(ProfileEditContainer)));
|
export default connect(mapStateToProps)(injectIntl(withNavigation(ProfileEditContainer)));
|
||||||
|
|
||||||
|
const IMAGE_PICKER_AVATAR_OPTIONS = {
|
||||||
|
includeBase64: true,
|
||||||
|
cropping: true,
|
||||||
|
width: 512,
|
||||||
|
height: 512,
|
||||||
|
};
|
||||||
|
|
||||||
|
const IMAGE_PICKER_COVER_OPTIONS = {
|
||||||
|
includeBase64: true,
|
||||||
|
};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { ButtonProps } from 'react-native';
|
||||||
import {
|
import {
|
||||||
TOAST_NOTIFICATION,
|
TOAST_NOTIFICATION,
|
||||||
UPDATE_ACTIVE_BOTTOM_TAB,
|
UPDATE_ACTIVE_BOTTOM_TAB,
|
||||||
@ -6,19 +7,20 @@ import {
|
|||||||
TOGGLE_ACCOUNTS_BOTTOM_SHEET,
|
TOGGLE_ACCOUNTS_BOTTOM_SHEET,
|
||||||
SHOW_ACTION_MODAL,
|
SHOW_ACTION_MODAL,
|
||||||
HIDE_ACTION_MODAL,
|
HIDE_ACTION_MODAL,
|
||||||
|
SET_AVATAR_CACHE_STAMP,
|
||||||
} from '../constants/constants';
|
} from '../constants/constants';
|
||||||
|
|
||||||
export const updateActiveBottomTab = (payload) => ({
|
export const updateActiveBottomTab = (payload:string) => ({
|
||||||
payload,
|
payload,
|
||||||
type: UPDATE_ACTIVE_BOTTOM_TAB,
|
type: UPDATE_ACTIVE_BOTTOM_TAB,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const toastNotification = (payload) => ({
|
export const toastNotification = (payload:string) => ({
|
||||||
payload,
|
payload,
|
||||||
type: TOAST_NOTIFICATION,
|
type: TOAST_NOTIFICATION,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const showActionModal = (title, body, buttons, headerImage, onClosed) => ({
|
export const showActionModal = (title:string, body:string, buttons:ButtonProps[], headerImage:any, onClosed:()=>void) => ({
|
||||||
payload: {
|
payload: {
|
||||||
actionModalVisible: true,
|
actionModalVisible: true,
|
||||||
actionModalData: {
|
actionModalData: {
|
||||||
@ -36,17 +38,22 @@ export const hideActionModal = () => ({
|
|||||||
type: HIDE_ACTION_MODAL,
|
type: HIDE_ACTION_MODAL,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const setRcOffer = (payload) => ({
|
export const setRcOffer = (payload:boolean) => ({
|
||||||
payload,
|
payload,
|
||||||
type: RC_OFFER,
|
type: RC_OFFER,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const hidePostsThumbnails = (payload) => ({
|
export const hidePostsThumbnails = (payload:boolean) => ({
|
||||||
payload,
|
payload,
|
||||||
type: HIDE_POSTS_THUMBNAILS,
|
type: HIDE_POSTS_THUMBNAILS,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const toggleAccountsBottomSheet = (payload) => ({
|
export const toggleAccountsBottomSheet = (payload:boolean) => ({
|
||||||
payload,
|
payload,
|
||||||
type: TOGGLE_ACCOUNTS_BOTTOM_SHEET,
|
type: TOGGLE_ACCOUNTS_BOTTOM_SHEET,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const setAvatarCacheStamp = (payload:number) => ({
|
||||||
|
payload,
|
||||||
|
type:SET_AVATAR_CACHE_STAMP
|
||||||
|
})
|
@ -54,6 +54,7 @@ export const RC_OFFER = 'RC_OFFER';
|
|||||||
export const TOGGLE_ACCOUNTS_BOTTOM_SHEET = 'TOGGLE_ACCOUNTS_BOTTOM_SHEET';
|
export const TOGGLE_ACCOUNTS_BOTTOM_SHEET = 'TOGGLE_ACCOUNTS_BOTTOM_SHEET';
|
||||||
export const SHOW_ACTION_MODAL = 'SHOW_ACTION_MODAL';
|
export const SHOW_ACTION_MODAL = 'SHOW_ACTION_MODAL';
|
||||||
export const HIDE_ACTION_MODAL = 'HIDE_ACTION_MODAL';
|
export const HIDE_ACTION_MODAL = 'HIDE_ACTION_MODAL';
|
||||||
|
export const SET_AVATAR_CACHE_STAMP = 'SET_AVATAR_CACHE_STAMP';
|
||||||
|
|
||||||
// POSTS
|
// POSTS
|
||||||
export const SET_FEED_POSTS = 'SET_FEED_POSTS';
|
export const SET_FEED_POSTS = 'SET_FEED_POSTS';
|
||||||
|
@ -6,9 +6,21 @@ import {
|
|||||||
TOGGLE_ACCOUNTS_BOTTOM_SHEET,
|
TOGGLE_ACCOUNTS_BOTTOM_SHEET,
|
||||||
SHOW_ACTION_MODAL,
|
SHOW_ACTION_MODAL,
|
||||||
HIDE_ACTION_MODAL,
|
HIDE_ACTION_MODAL,
|
||||||
|
SET_AVATAR_CACHE_STAMP,
|
||||||
} from '../constants/constants';
|
} from '../constants/constants';
|
||||||
|
|
||||||
const initialState = {
|
interface UiState {
|
||||||
|
activeBottomTab:string;
|
||||||
|
toastNotification:string;
|
||||||
|
hidePostsThumbnails:boolean;
|
||||||
|
rcOffer:boolean;
|
||||||
|
isVisibleAccountsBottomSheet:boolean;
|
||||||
|
actionModalVisible:boolean;
|
||||||
|
actionModalData:any;
|
||||||
|
avatarCacheStamp:number
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState:UiState = {
|
||||||
activeBottomTab: 'HomeTabbar',
|
activeBottomTab: 'HomeTabbar',
|
||||||
toastNotification: '',
|
toastNotification: '',
|
||||||
hidePostsThumbnails: false,
|
hidePostsThumbnails: false,
|
||||||
@ -16,6 +28,7 @@ const initialState = {
|
|||||||
isVisibleAccountsBottomSheet: false,
|
isVisibleAccountsBottomSheet: false,
|
||||||
actionModalVisible: false,
|
actionModalVisible: false,
|
||||||
actionModalData: null,
|
actionModalData: null,
|
||||||
|
avatarCacheStamp: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function (state = initialState, action) {
|
export default function (state = initialState, action) {
|
||||||
@ -65,6 +78,11 @@ export default function (state = initialState, action) {
|
|||||||
...state,
|
...state,
|
||||||
isVisibleAccountsBottomSheet: action.payload,
|
isVisibleAccountsBottomSheet: action.payload,
|
||||||
};
|
};
|
||||||
|
case SET_AVATAR_CACHE_STAMP:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
avatarCacheStamp: action.payload
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
@ -77,6 +77,7 @@ import {
|
|||||||
} from '../../../redux/actions/applicationActions';
|
} from '../../../redux/actions/applicationActions';
|
||||||
import {
|
import {
|
||||||
hideActionModal,
|
hideActionModal,
|
||||||
|
setAvatarCacheStamp,
|
||||||
setRcOffer,
|
setRcOffer,
|
||||||
toastNotification,
|
toastNotification,
|
||||||
updateActiveBottomTab,
|
updateActiveBottomTab,
|
||||||
@ -126,7 +127,6 @@ class ApplicationContainer extends Component {
|
|||||||
this._setNetworkListener();
|
this._setNetworkListener();
|
||||||
|
|
||||||
Linking.addEventListener('url', this._handleOpenURL);
|
Linking.addEventListener('url', this._handleOpenURL);
|
||||||
|
|
||||||
Linking.getInitialURL().then((url) => {
|
Linking.getInitialURL().then((url) => {
|
||||||
this._handleDeepLink(url);
|
this._handleDeepLink(url);
|
||||||
});
|
});
|
||||||
@ -145,6 +145,9 @@ class ApplicationContainer extends Component {
|
|||||||
|
|
||||||
if (!isIos) BackHandler.addEventListener('hardwareBackPress', this._onBackPress);
|
if (!isIos) BackHandler.addEventListener('hardwareBackPress', this._onBackPress);
|
||||||
|
|
||||||
|
//set avatar cache stamp to invalidate previous session avatars
|
||||||
|
dispatch(setAvatarCacheStamp(new Date().getTime()));
|
||||||
|
|
||||||
getVersionForWelcomeModal().then((version) => {
|
getVersionForWelcomeModal().then((version) => {
|
||||||
if (version < parseVersionNumber(appVersion)) {
|
if (version < parseVersionNumber(appVersion)) {
|
||||||
getUserData().then((accounts) => {
|
getUserData().then((accounts) => {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { PureComponent, Fragment } from 'react';
|
import React, { PureComponent, Fragment } from 'react';
|
||||||
|
import { StatusBar } from 'react-native';
|
||||||
import { injectIntl } from 'react-intl';
|
import { injectIntl } from 'react-intl';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import ActionSheet from 'react-native-actionsheet';
|
import ActionSheet from 'react-native-actionsheet';
|
||||||
@ -25,9 +26,10 @@ class ProfileEditScreen extends PureComponent {
|
|||||||
// Component Life Cycles
|
// Component Life Cycles
|
||||||
|
|
||||||
// Component Functions
|
// Component Functions
|
||||||
_showImageUploadActions = async (action) => {
|
_showImageUploadActions = (action) => {
|
||||||
await this.setState({ selectedUploadAction: action });
|
this.setState({ selectedUploadAction: action }, () => {
|
||||||
this.galleryRef.current.show();
|
this.galleryRef.current.show();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -49,15 +51,19 @@ class ProfileEditScreen extends PureComponent {
|
|||||||
avatarUrl,
|
avatarUrl,
|
||||||
coverUrl,
|
coverUrl,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
isUploading,
|
||||||
|
saveEnabled,
|
||||||
handleOnSubmit,
|
handleOnSubmit,
|
||||||
}) => (
|
}) => (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
<StatusBar barStyle="light-content" />
|
||||||
<AvatarHeader
|
<AvatarHeader
|
||||||
username={get(currentAccount, 'name')}
|
username={get(currentAccount, 'name')}
|
||||||
name={name}
|
name={name}
|
||||||
reputation={get(currentAccount, 'reputation')}
|
reputation={get(currentAccount, 'reputation')}
|
||||||
avatarUrl={avatarUrl}
|
avatarUrl={avatarUrl}
|
||||||
showImageUploadActions={() => this._showImageUploadActions('avatarUrl')}
|
showImageUploadActions={() => this._showImageUploadActions('avatarUrl')}
|
||||||
|
isUploading={isUploading && selectedUploadAction === 'avatarUrl'}
|
||||||
/>
|
/>
|
||||||
<ProfileEditForm
|
<ProfileEditForm
|
||||||
formData={formData}
|
formData={formData}
|
||||||
@ -70,8 +76,11 @@ class ProfileEditScreen extends PureComponent {
|
|||||||
showImageUploadActions={() => this._showImageUploadActions('coverUrl')}
|
showImageUploadActions={() => this._showImageUploadActions('coverUrl')}
|
||||||
handleOnItemChange={handleOnItemChange}
|
handleOnItemChange={handleOnItemChange}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
|
isUploading={isUploading && selectedUploadAction === 'coverUrl'}
|
||||||
|
saveEnabled={saveEnabled}
|
||||||
handleOnSubmit={handleOnSubmit}
|
handleOnSubmit={handleOnSubmit}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ActionSheet
|
<ActionSheet
|
||||||
ref={this.galleryRef}
|
ref={this.galleryRef}
|
||||||
options={[
|
options={[
|
||||||
|
Loading…
Reference in New Issue
Block a user