[NEW] Change Avatar View
This commit is contained in:
parent
a2722f07b0
commit
49f2c28b3e
|
@ -3,11 +3,15 @@ import React, { useEffect, useRef, useState } from 'react';
|
||||||
import { shallowEqual, useSelector } from 'react-redux';
|
import { shallowEqual, useSelector } from 'react-redux';
|
||||||
import { Observable, Subscription } from 'rxjs';
|
import { Observable, Subscription } from 'rxjs';
|
||||||
|
|
||||||
|
import Button from '../Button';
|
||||||
import { IApplicationState, TSubscriptionModel, TUserModel } from '../../definitions';
|
import { IApplicationState, TSubscriptionModel, TUserModel } from '../../definitions';
|
||||||
import database from '../../lib/database';
|
import database from '../../lib/database';
|
||||||
import { getUserSelector } from '../../selectors/login';
|
import { getUserSelector } from '../../selectors/login';
|
||||||
import Avatar from './Avatar';
|
import Avatar from './Avatar';
|
||||||
import { IAvatar } from './interfaces';
|
import { IAvatar } from './interfaces';
|
||||||
|
import I18n from '../../i18n';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
const AvatarContainer = ({
|
const AvatarContainer = ({
|
||||||
style,
|
style,
|
||||||
|
@ -21,10 +25,12 @@ const AvatarContainer = ({
|
||||||
onPress,
|
onPress,
|
||||||
getCustomEmoji,
|
getCustomEmoji,
|
||||||
isStatic,
|
isStatic,
|
||||||
rid
|
rid,
|
||||||
}: IAvatar): React.ReactElement => {
|
handleEdit
|
||||||
|
}: IAvatar & { handleEdit?: () => void }): React.ReactElement => {
|
||||||
const subscription = useRef<Subscription>();
|
const subscription = useRef<Subscription>();
|
||||||
const [avatarETag, setAvatarETag] = useState<string | undefined>('');
|
const [avatarETag, setAvatarETag] = useState<string | undefined>('');
|
||||||
|
const { colors } = useTheme();
|
||||||
|
|
||||||
const isDirect = () => type === 'd';
|
const isDirect = () => type === 'd';
|
||||||
|
|
||||||
|
@ -85,27 +91,39 @@ const AvatarContainer = ({
|
||||||
}, [text, type, size, avatarETag, externalProviderUrl]);
|
}, [text, type, size, avatarETag, externalProviderUrl]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Avatar
|
<>
|
||||||
server={server}
|
<Avatar
|
||||||
style={style}
|
server={server}
|
||||||
text={text}
|
style={style}
|
||||||
avatar={avatar}
|
text={text}
|
||||||
emoji={emoji}
|
avatar={avatar}
|
||||||
size={size}
|
emoji={emoji}
|
||||||
borderRadius={borderRadius}
|
size={size}
|
||||||
type={type}
|
borderRadius={borderRadius}
|
||||||
children={children}
|
type={type}
|
||||||
userId={id}
|
children={children}
|
||||||
token={token}
|
userId={id}
|
||||||
onPress={onPress}
|
token={token}
|
||||||
getCustomEmoji={getCustomEmoji}
|
onPress={onPress}
|
||||||
isStatic={isStatic}
|
getCustomEmoji={getCustomEmoji}
|
||||||
rid={rid}
|
isStatic={isStatic}
|
||||||
blockUnauthenticatedAccess={blockUnauthenticatedAccess}
|
rid={rid}
|
||||||
externalProviderUrl={externalProviderUrl}
|
blockUnauthenticatedAccess={blockUnauthenticatedAccess}
|
||||||
avatarETag={avatarETag}
|
externalProviderUrl={externalProviderUrl}
|
||||||
serverVersion={serverVersion}
|
avatarETag={avatarETag}
|
||||||
/>
|
serverVersion={serverVersion}
|
||||||
|
/>
|
||||||
|
{handleEdit ? (
|
||||||
|
<Button
|
||||||
|
title={I18n.t('Edit')}
|
||||||
|
type='secondary'
|
||||||
|
backgroundColor={colors.passcodeButtonActive}
|
||||||
|
onPress={handleEdit}
|
||||||
|
testID='avatar-edit-button'
|
||||||
|
style={styles.editAvatarButton}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
export default StyleSheet.create({
|
||||||
|
editAvatarButton: {
|
||||||
|
marginTop: 8,
|
||||||
|
paddingVertical: 8,
|
||||||
|
paddingHorizontal: 12
|
||||||
|
}
|
||||||
|
});
|
|
@ -876,5 +876,7 @@
|
||||||
"Call": "Call",
|
"Call": "Call",
|
||||||
"Reply_in_direct_message": "Reply in Direct Message",
|
"Reply_in_direct_message": "Reply in Direct Message",
|
||||||
"room_archived": "archived room",
|
"room_archived": "archived room",
|
||||||
"room_unarchived": "unarchived room"
|
"room_unarchived": "unarchived room",
|
||||||
|
"Upload_image": "Upload image",
|
||||||
|
"Delete_image": "Delete image"
|
||||||
}
|
}
|
|
@ -68,6 +68,7 @@ import AddChannelTeamView from '../views/AddChannelTeamView';
|
||||||
import AddExistingChannelView from '../views/AddExistingChannelView';
|
import AddExistingChannelView from '../views/AddExistingChannelView';
|
||||||
import SelectListView from '../views/SelectListView';
|
import SelectListView from '../views/SelectListView';
|
||||||
import DiscussionsView from '../views/DiscussionsView';
|
import DiscussionsView from '../views/DiscussionsView';
|
||||||
|
import ChangeAvatarView from '../views/ChangeAvatarView';
|
||||||
import {
|
import {
|
||||||
AdminPanelStackParamList,
|
AdminPanelStackParamList,
|
||||||
ChatsStackParamList,
|
ChatsStackParamList,
|
||||||
|
@ -96,6 +97,7 @@ const ChatsStackNavigator = () => {
|
||||||
<ChatsStack.Screen name='SelectListView' component={SelectListView} options={SelectListView.navigationOptions} />
|
<ChatsStack.Screen name='SelectListView' component={SelectListView} options={SelectListView.navigationOptions} />
|
||||||
<ChatsStack.Screen name='RoomInfoView' component={RoomInfoView} options={RoomInfoView.navigationOptions} />
|
<ChatsStack.Screen name='RoomInfoView' component={RoomInfoView} options={RoomInfoView.navigationOptions} />
|
||||||
<ChatsStack.Screen name='RoomInfoEditView' component={RoomInfoEditView} options={RoomInfoEditView.navigationOptions} />
|
<ChatsStack.Screen name='RoomInfoEditView' component={RoomInfoEditView} options={RoomInfoEditView.navigationOptions} />
|
||||||
|
<ProfileStack.Screen name='ChangeAvatarView' component={ChangeAvatarView} />
|
||||||
<ChatsStack.Screen name='RoomMembersView' component={RoomMembersView} />
|
<ChatsStack.Screen name='RoomMembersView' component={RoomMembersView} />
|
||||||
<ChatsStack.Screen name='DiscussionsView' component={DiscussionsView} />
|
<ChatsStack.Screen name='DiscussionsView' component={DiscussionsView} />
|
||||||
<ChatsStack.Screen
|
<ChatsStack.Screen
|
||||||
|
@ -155,6 +157,7 @@ const ProfileStackNavigator = () => {
|
||||||
>
|
>
|
||||||
<ProfileStack.Screen name='ProfileView' component={ProfileView} options={ProfileView.navigationOptions} />
|
<ProfileStack.Screen name='ProfileView' component={ProfileView} options={ProfileView.navigationOptions} />
|
||||||
<ProfileStack.Screen name='UserPreferencesView' component={UserPreferencesView} />
|
<ProfileStack.Screen name='UserPreferencesView' component={UserPreferencesView} />
|
||||||
|
<ProfileStack.Screen name='ChangeAvatarView' component={ChangeAvatarView} />
|
||||||
<ProfileStack.Screen name='UserNotificationPrefView' component={UserNotificationPrefView} />
|
<ProfileStack.Screen name='UserNotificationPrefView' component={UserNotificationPrefView} />
|
||||||
<ProfileStack.Screen name='PickerView' component={PickerView} options={PickerView.navigationOptions} />
|
<ProfileStack.Screen name='PickerView' component={PickerView} options={PickerView.navigationOptions} />
|
||||||
</ProfileStack.Navigator>
|
</ProfileStack.Navigator>
|
||||||
|
|
|
@ -180,6 +180,10 @@ export type ChatsStackParamList = {
|
||||||
onlyAudio?: boolean;
|
onlyAudio?: boolean;
|
||||||
videoConf?: boolean;
|
videoConf?: boolean;
|
||||||
};
|
};
|
||||||
|
ChangeAvatarView: {
|
||||||
|
fromUser?: boolean;
|
||||||
|
titleHeader?: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ProfileStackParamList = {
|
export type ProfileStackParamList = {
|
||||||
|
@ -194,6 +198,10 @@ export type ProfileStackParamList = {
|
||||||
goBack?: Function;
|
goBack?: Function;
|
||||||
onChangeValue: Function;
|
onChangeValue: Function;
|
||||||
};
|
};
|
||||||
|
ChangeAvatarView: {
|
||||||
|
fromUser?: boolean;
|
||||||
|
titleHeader?: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SettingsStackParamList = {
|
export type SettingsStackParamList = {
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
import I18n from '../../i18n';
|
||||||
|
import { FormTextInput } from '../../containers/TextInput';
|
||||||
|
|
||||||
|
const AvatarUrl = ({ onSubmit }: { onSubmit: (value: string) => void }) => {
|
||||||
|
const [avatarUrl, setAvatarUrl] = useState('');
|
||||||
|
return (
|
||||||
|
<FormTextInput
|
||||||
|
label={I18n.t('Avatar_Url')}
|
||||||
|
placeholder={I18n.t('Avatar_Url')}
|
||||||
|
value={avatarUrl || undefined}
|
||||||
|
onChangeText={setAvatarUrl}
|
||||||
|
onSubmitEditing={() => onSubmit(avatarUrl)}
|
||||||
|
testID='change-avatar-view-avatar-url'
|
||||||
|
containerStyle={{ marginBottom: 0 }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AvatarUrl;
|
|
@ -0,0 +1,72 @@
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { ScrollView, View } from 'react-native';
|
||||||
|
|
||||||
|
import KeyboardView from '../../containers/KeyboardView';
|
||||||
|
import sharedStyles from '../Styles';
|
||||||
|
import scrollPersistTaps from '../../lib/methods/helpers/scrollPersistTaps';
|
||||||
|
import StatusBar from '../../containers/StatusBar';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
import SafeAreaView from '../../containers/SafeAreaView';
|
||||||
|
import * as List from '../../containers/List';
|
||||||
|
import styles from './styles';
|
||||||
|
import { useAppSelector } from '../../lib/hooks';
|
||||||
|
import { getUserSelector } from '../../selectors/login';
|
||||||
|
import Avatar from '../../containers/Avatar';
|
||||||
|
import AvatarUrl from './AvatarUrl';
|
||||||
|
import Button from '../../containers/Button';
|
||||||
|
import I18n from '../../i18n';
|
||||||
|
|
||||||
|
const ChangeAvatarView = () => {
|
||||||
|
const [avatarUrl, setAvatarUrl] = useState('');
|
||||||
|
const { colors } = useTheme();
|
||||||
|
|
||||||
|
const user = useAppSelector(state => getUserSelector(state));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<KeyboardView
|
||||||
|
style={{ backgroundColor: colors.auxiliaryBackground }}
|
||||||
|
contentContainerStyle={sharedStyles.container}
|
||||||
|
keyboardVerticalOffset={128}
|
||||||
|
>
|
||||||
|
<StatusBar />
|
||||||
|
<SafeAreaView testID='change-avatar-view'>
|
||||||
|
<ScrollView
|
||||||
|
contentContainerStyle={sharedStyles.containerScrollView}
|
||||||
|
testID='change-avatar-view-list'
|
||||||
|
{...scrollPersistTaps}
|
||||||
|
>
|
||||||
|
<View style={styles.avatarContainer} testID='change-avatar-view-avatar'>
|
||||||
|
<Avatar text={user.username} avatar={avatarUrl} isStatic={avatarUrl} size={100} />
|
||||||
|
</View>
|
||||||
|
<AvatarUrl onSubmit={(value: string) => setAvatarUrl(value)} />
|
||||||
|
<List.Separator style={styles.separator} />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
title={I18n.t('Upload_image')}
|
||||||
|
type='secondary'
|
||||||
|
backgroundColor={colors.chatComponentBackground}
|
||||||
|
onPress={() => {}}
|
||||||
|
testID='change-avatar-view-logout-other-locations'
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
title={I18n.t('Delete_image')}
|
||||||
|
type='primary'
|
||||||
|
backgroundColor={colors.dangerColor}
|
||||||
|
onPress={() => {}}
|
||||||
|
testID='change-avatar-view-delete-my-account'
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
title={I18n.t('Save')}
|
||||||
|
type='primary'
|
||||||
|
onPress={() => {}}
|
||||||
|
// disabled={!this.formIsChanged()}
|
||||||
|
testID='change-avatar-view-submit'
|
||||||
|
// loading={saving}
|
||||||
|
/>
|
||||||
|
</ScrollView>
|
||||||
|
</SafeAreaView>
|
||||||
|
</KeyboardView>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChangeAvatarView;
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
export default StyleSheet.create({
|
||||||
|
disabled: {
|
||||||
|
opacity: 0.3
|
||||||
|
},
|
||||||
|
avatarContainer: {
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
marginBottom: 32
|
||||||
|
},
|
||||||
|
separator: {
|
||||||
|
marginVertical: 16
|
||||||
|
}
|
||||||
|
});
|
|
@ -369,6 +369,11 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
|
||||||
this.setAvatar({ url: avatarUrl, data: avatarUrl, service: 'url' });
|
this.setAvatar({ url: avatarUrl, data: avatarUrl, service: 'url' });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleEditAvatar = () => {
|
||||||
|
const { navigation } = this.props;
|
||||||
|
navigation.navigate('ChangeAvatarView', { fromUser: true });
|
||||||
|
};
|
||||||
|
|
||||||
renderAvatarButton = ({ key, child, onPress, disabled = false }: IAvatarButton) => {
|
renderAvatarButton = ({ key, child, onPress, disabled = false }: IAvatarButton) => {
|
||||||
const { theme } = this.props;
|
const { theme } = this.props;
|
||||||
return (
|
return (
|
||||||
|
@ -543,7 +548,13 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
|
||||||
<SafeAreaView testID='profile-view'>
|
<SafeAreaView testID='profile-view'>
|
||||||
<ScrollView contentContainerStyle={sharedStyles.containerScrollView} testID='profile-view-list' {...scrollPersistTaps}>
|
<ScrollView contentContainerStyle={sharedStyles.containerScrollView} testID='profile-view-list' {...scrollPersistTaps}>
|
||||||
<View style={styles.avatarContainer} testID='profile-view-avatar'>
|
<View style={styles.avatarContainer} testID='profile-view-avatar'>
|
||||||
<Avatar text={user.username} avatar={avatar?.url} isStatic={avatar?.url} size={100} />
|
<Avatar
|
||||||
|
text={user.username}
|
||||||
|
avatar={avatar?.url}
|
||||||
|
isStatic={avatar?.url}
|
||||||
|
size={100}
|
||||||
|
handleEdit={Accounts_AllowUserAvatarChange ? this.handleEditAvatar : undefined}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
<FormTextInput
|
<FormTextInput
|
||||||
editable={Accounts_AllowRealNameChange}
|
editable={Accounts_AllowRealNameChange}
|
||||||
|
|
|
@ -7,7 +7,7 @@ export default StyleSheet.create({
|
||||||
avatarContainer: {
|
avatarContainer: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
marginBottom: 10
|
marginBottom: 24
|
||||||
},
|
},
|
||||||
avatarButtons: {
|
avatarButtons: {
|
||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
|
|
Loading…
Reference in New Issue