[NEW] Change Avatar View

This commit is contained in:
Reinaldo Neto 2022-12-07 00:11:25 -03:00
parent a2722f07b0
commit 49f2c28b3e
10 changed files with 185 additions and 26 deletions

View File

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

View File

@ -0,0 +1,9 @@
import { StyleSheet } from 'react-native';
export default StyleSheet.create({
editAvatarButton: {
marginTop: 8,
paddingVertical: 8,
paddingHorizontal: 12
}
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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