diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap
index d0724ff7e..299d099a4 100644
--- a/__tests__/__snapshots__/Storyshots.test.js.snap
+++ b/__tests__/__snapshots__/Storyshots.test.js.snap
@@ -59,7 +59,72 @@ exports[`Storyshots Avatar list Avatar 1`] = `
Object {
"headers": undefined,
"priority": "high",
- "uri": "https://open.rocket.chat/avatar/Avatar?format=png&size=50",
+ "uri": "https://open.rocket.chat/avatar/Avatar?format=png&size=100",
+ }
+ }
+ style={
+ Object {
+ "bottom": 0,
+ "left": 0,
+ "position": "absolute",
+ "right": 0,
+ "top": 0,
+ }
+ }
+ />
+
+
+
+ Avatar by roomId
+
+
+
+ {
- if ((!text && !avatar && !emoji) || !server) {
+ if ((!text && !avatar && !emoji && !rid) || !server) {
return null;
}
@@ -57,7 +58,8 @@ const Avatar = React.memo(({
user,
avatar,
server,
- avatarETag
+ avatarETag,
+ rid
});
}
@@ -108,7 +110,8 @@ Avatar.propTypes = {
onPress: PropTypes.func,
getCustomEmoji: PropTypes.func,
avatarETag: PropTypes.string,
- isStatic: PropTypes.bool
+ isStatic: PropTypes.bool,
+ rid: PropTypes.string
};
Avatar.defaultProps = {
diff --git a/app/containers/Avatar/index.js b/app/containers/Avatar/index.js
index fff632b85..c5769dfd6 100644
--- a/app/containers/Avatar/index.js
+++ b/app/containers/Avatar/index.js
@@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Q } from '@nozbe/watermelondb';
+import isEqual from 'react-fast-compare';
import database from '../../lib/database';
import { getUserSelector } from '../../selectors/login';
@@ -9,6 +10,7 @@ import Avatar from './Avatar';
class AvatarContainer extends React.Component {
static propTypes = {
+ rid: PropTypes.string,
text: PropTypes.string,
type: PropTypes.string
};
@@ -29,9 +31,15 @@ class AvatarContainer extends React.Component {
this.mounted = true;
}
+ componentDidUpdate(prevProps) {
+ if (!isEqual(prevProps, this.props)) {
+ this.init();
+ }
+ }
+
componentWillUnmount() {
- if (this.userSubscription?.unsubscribe) {
- this.userSubscription.unsubscribe();
+ if (this.subscription?.unsubscribe) {
+ this.subscription.unsubscribe();
}
}
@@ -41,26 +49,34 @@ class AvatarContainer extends React.Component {
}
init = async() => {
- if (this.isDirect) {
- const { text } = this.props;
- const db = database.active;
- const usersCollection = db.collections.get('users');
- try {
+ const db = database.active;
+ const usersCollection = db.collections.get('users');
+ const subsCollection = db.collections.get('subscriptions');
+
+ let record;
+ try {
+ if (this.isDirect) {
+ const { text } = this.props;
const [user] = await usersCollection.query(Q.where('username', text)).fetch();
- if (user) {
- const observable = user.observe();
- this.userSubscription = observable.subscribe((u) => {
- const { avatarETag } = u;
- if (this.mounted) {
- this.setState({ avatarETag });
- } else {
- this.state.avatarETag = avatarETag;
- }
- });
- }
- } catch {
- // User was not found
+ record = user;
+ } else {
+ const { rid } = this.props;
+ record = await subsCollection.find(rid);
}
+ } catch {
+ // Record not found
+ }
+
+ if (record) {
+ const observable = record.observe();
+ this.subscription = observable.subscribe((r) => {
+ const { avatarETag } = r;
+ if (this.mounted) {
+ this.setState({ avatarETag });
+ } else {
+ this.state.avatarETag = avatarETag;
+ }
+ });
}
}
diff --git a/app/containers/InAppNotification/NotifierComponent.js b/app/containers/InAppNotification/NotifierComponent.js
index 8d5016b7e..b69704359 100644
--- a/app/containers/InAppNotification/NotifierComponent.js
+++ b/app/containers/InAppNotification/NotifierComponent.js
@@ -70,13 +70,13 @@ const NotifierComponent = React.memo(({ notification, isMasterDetail }) => {
const { isLandscape } = useOrientation();
const { text, payload } = notification;
- const { type } = payload;
+ const { type, rid } = payload;
const name = type === 'd' ? payload.sender.username : payload.name;
// if sub is not on local database, title and avatar will be null, so we use payload from notification
const { title = name, avatar = name } = notification;
const onPress = () => {
- const { rid, prid } = payload;
+ const { prid } = payload;
if (!rid) {
return;
}
@@ -111,7 +111,7 @@ const NotifierComponent = React.memo(({ notification, isMasterDetail }) => {
background={Touchable.SelectableBackgroundBorderless()}
>
<>
-
+
{title}
{text}
diff --git a/app/containers/message/utils.js b/app/containers/message/utils.js
index a0a298eb6..383000a41 100644
--- a/app/containers/message/utils.js
+++ b/app/containers/message/utils.js
@@ -49,6 +49,7 @@ export const SYSTEM_MESSAGES = [
'room_changed_announcement',
'room_changed_topic',
'room_changed_privacy',
+ 'room_changed_avatar',
'message_snippeted',
'thread-created'
];
@@ -91,6 +92,8 @@ export const getInfoMessage = ({
return I18n.t('Room_changed_topic', { topic: msg, userBy: username });
} else if (type === 'room_changed_privacy') {
return I18n.t('Room_changed_privacy', { type: msg, userBy: username });
+ } else if (type === 'room_changed_avatar') {
+ return I18n.t('Room_changed_avatar', { userBy: username });
} else if (type === 'message_snippeted') {
return I18n.t('Created_snippet');
}
diff --git a/app/i18n/locales/en.js b/app/i18n/locales/en.js
index 18f5f22d4..1221ff9e6 100644
--- a/app/i18n/locales/en.js
+++ b/app/i18n/locales/en.js
@@ -437,6 +437,7 @@ export default {
Roles: 'Roles',
Room_actions: 'Room actions',
Room_changed_announcement: 'Room announcement changed to: {{announcement}} by {{userBy}}',
+ Room_changed_avatar: 'Room avatar changed by {{userBy}}',
Room_changed_description: 'Room description changed to: {{description}} by {{userBy}}',
Room_changed_privacy: 'Room type changed to: {{type}} by {{userBy}}',
Room_changed_topic: 'Room topic changed to: {{topic}} by {{userBy}}',
diff --git a/app/lib/database/model/Room.js b/app/lib/database/model/Room.js
index 32a3a5777..131fbaf0e 100644
--- a/app/lib/database/model/Room.js
+++ b/app/lib/database/model/Room.js
@@ -25,4 +25,6 @@ export default class Room extends Model {
@json('livechat_data', sanitizer) livechatData;
@json('tags', sanitizer) tags;
+
+ @field('avatar_etag') avatarETag;
}
diff --git a/app/lib/database/model/Subscription.js b/app/lib/database/model/Subscription.js
index afdd8391f..bc3ac88ab 100644
--- a/app/lib/database/model/Subscription.js
+++ b/app/lib/database/model/Subscription.js
@@ -115,4 +115,6 @@ export default class Subscription extends Model {
@field('encrypted') encrypted;
@field('e2e_key_id') e2eKeyId;
+
+ @field('avatar_etag') avatarETag;
}
diff --git a/app/lib/database/model/migrations.js b/app/lib/database/model/migrations.js
index d7fba898a..bcdcf90c9 100644
--- a/app/lib/database/model/migrations.js
+++ b/app/lib/database/model/migrations.js
@@ -178,6 +178,18 @@ export default schemaMigrations({
{ name: 'username', type: 'string', isIndexed: true },
{ name: 'avatar_etag', type: 'string', isOptional: true }
]
+ }),
+ addColumns({
+ table: 'subscriptions',
+ columns: [
+ { name: 'avatar_etag', type: 'string', isOptional: true }
+ ]
+ }),
+ addColumns({
+ table: 'rooms',
+ columns: [
+ { name: 'avatar_etag', type: 'string', isOptional: true }
+ ]
})
]
}
diff --git a/app/lib/database/schema/app.js b/app/lib/database/schema/app.js
index c579ba6ba..cbe886707 100644
--- a/app/lib/database/schema/app.js
+++ b/app/lib/database/schema/app.js
@@ -52,7 +52,8 @@ export default appSchema({
{ name: 'tags', type: 'string', isOptional: true },
{ name: 'e2e_key', type: 'string', isOptional: true },
{ name: 'encrypted', type: 'boolean', isOptional: true },
- { name: 'e2e_key_id', type: 'string', isOptional: true }
+ { name: 'e2e_key_id', type: 'string', isOptional: true },
+ { name: 'avatar_etag', type: 'string', isOptional: true }
]
}),
tableSchema({
@@ -67,7 +68,8 @@ export default appSchema({
{ name: 'served_by', type: 'string', isOptional: true },
{ name: 'livechat_data', type: 'string', isOptional: true },
{ name: 'tags', type: 'string', isOptional: true },
- { name: 'e2e_key_id', type: 'string', isOptional: true }
+ { name: 'e2e_key_id', type: 'string', isOptional: true },
+ { name: 'avatar_etag', type: 'string', isOptional: true }
]
}),
tableSchema({
diff --git a/app/lib/methods/helpers/findSubscriptionsRooms.js b/app/lib/methods/helpers/findSubscriptionsRooms.js
index fb3bc6d33..f1714932d 100644
--- a/app/lib/methods/helpers/findSubscriptionsRooms.js
+++ b/app/lib/methods/helpers/findSubscriptionsRooms.js
@@ -52,7 +52,8 @@ export default async(subscriptions = [], rooms = []) => {
tags: s.tags,
encrypted: s.encrypted,
e2eKeyId: s.e2eKeyId,
- E2EKey: s.E2EKey
+ E2EKey: s.E2EKey,
+ avatarETag: s.avatarETag
}));
subscriptions = subscriptions.concat(existingSubs);
@@ -80,7 +81,8 @@ export default async(subscriptions = [], rooms = []) => {
livechatData: r.livechatData,
tags: r.tags,
encrypted: r.encrypted,
- e2eKeyId: r.e2eKeyId
+ e2eKeyId: r.e2eKeyId,
+ avatarETag: r.avatarETag
}));
rooms = rooms.concat(existingRooms);
} catch {
diff --git a/app/lib/methods/helpers/mergeSubscriptionsRooms.js b/app/lib/methods/helpers/mergeSubscriptionsRooms.js
index c529102f2..5fbb1a743 100644
--- a/app/lib/methods/helpers/mergeSubscriptionsRooms.js
+++ b/app/lib/methods/helpers/mergeSubscriptionsRooms.js
@@ -30,6 +30,7 @@ export const merge = (subscription, room) => {
subscription.broadcast = room.broadcast;
subscription.encrypted = room.encrypted;
subscription.e2eKeyId = room.e2eKeyId;
+ subscription.avatarETag = room.avatarETag;
if (!subscription.roles || !subscription.roles.length) {
subscription.roles = [];
}
diff --git a/app/lib/methods/subscriptions/rooms.js b/app/lib/methods/subscriptions/rooms.js
index eee596e86..9039cce13 100644
--- a/app/lib/methods/subscriptions/rooms.js
+++ b/app/lib/methods/subscriptions/rooms.js
@@ -84,7 +84,8 @@ const createOrUpdateSubscription = async(subscription, room) => {
tags: s.tags,
encrypted: s.encrypted,
e2eKeyId: s.e2eKeyId,
- E2EKey: s.E2EKey
+ E2EKey: s.E2EKey,
+ avatarETag: s.avatarETag
};
} catch (error) {
try {
@@ -116,7 +117,8 @@ const createOrUpdateSubscription = async(subscription, room) => {
broadcast: r.broadcast,
customFields: r.customFields,
departmentId: r.departmentId,
- livechatData: r.livechatData
+ livechatData: r.livechatData,
+ avatarETag: r.avatarETag
};
} catch (error) {
// Do nothing
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index fc10267ed..76bd5e1dc 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -579,6 +579,7 @@ const RocketChat = {
rid: sub.rid,
name: sub.name,
fname: sub.fname,
+ avatarETag: sub.avatarETag,
t: sub.t,
search: true
});
diff --git a/app/presentation/DirectoryItem/index.js b/app/presentation/DirectoryItem/index.js
index c8f41202f..75b944c5e 100644
--- a/app/presentation/DirectoryItem/index.js
+++ b/app/presentation/DirectoryItem/index.js
@@ -18,7 +18,7 @@ const DirectoryItemLabel = React.memo(({ text, theme }) => {
});
const DirectoryItem = ({
- title, description, avatar, onPress, testID, style, rightLabel, type, theme
+ title, description, avatar, onPress, testID, style, rightLabel, type, rid, theme
}) => (
@@ -54,6 +55,7 @@ DirectoryItem.propTypes = {
testID: PropTypes.string.isRequired,
style: PropTypes.any,
rightLabel: PropTypes.string,
+ rid: PropTypes.string,
theme: PropTypes.string
};
diff --git a/app/presentation/RoomItem/RoomItem.js b/app/presentation/RoomItem/RoomItem.js
index 9acb0284b..da595d883 100644
--- a/app/presentation/RoomItem/RoomItem.js
+++ b/app/presentation/RoomItem/RoomItem.js
@@ -73,6 +73,7 @@ const RoomItem = ({
userId={userId}
token={token}
theme={theme}
+ rid={rid}
>
{showLastMessage
? (
diff --git a/app/presentation/RoomItem/Wrapper.js b/app/presentation/RoomItem/Wrapper.js
index c6638555a..2a0d17bc8 100644
--- a/app/presentation/RoomItem/Wrapper.js
+++ b/app/presentation/RoomItem/Wrapper.js
@@ -16,6 +16,7 @@ const Wrapper = ({
userId,
token,
theme,
+ rid,
children
}) => (
{
+ const { rid } = item;
+
+ let record;
+ if (this.isDirect) {
+ record = await usersCollection.find(id);
+ } else {
+ record = await subsCollection.find(rid);
+ }
+
+ if (record) {
+ const observable = record.observe();
+ this.avatarSubscription = observable.subscribe((u) => {
const { avatarETag } = u;
if (this.mounted) {
this.setState({ avatarETag });
@@ -130,9 +139,9 @@ class RoomItemContainer extends React.Component {
this.state.avatarETag = avatarETag;
}
});
- } catch {
- // User not found
}
+ } catch {
+ // Record not found
}
}
@@ -220,7 +229,7 @@ class RoomItemContainer extends React.Component {
useRealName={useRealName}
unread={item.unread}
groupMentions={item.groupMentions}
- avatarETag={avatarETag}
+ avatarETag={avatarETag || item.avatarETag}
swipeEnabled={swipeEnabled}
/>
);
diff --git a/app/utils/avatar.js b/app/utils/avatar.js
index 369e1914f..0cdc8e577 100644
--- a/app/utils/avatar.js
+++ b/app/utils/avatar.js
@@ -1,12 +1,18 @@
const formatUrl = (url, size, query) => `${ url }?format=png&size=${ size }${ query }`;
export const avatarURL = ({
- type, text, size, user = {}, avatar, server, avatarETag
+ type, text, size, user = {}, avatar, server, avatarETag, rid
}) => {
- const room = type === 'd' ? text : `@${ text }`;
+ let room;
+ if (type === 'd') {
+ room = text;
+ } else if (rid) {
+ room = `room/${ rid }`;
+ } else {
+ room = `@${ text }`;
+ }
- // Avoid requesting several sizes by having only two sizes on cache
- const uriSize = size === 100 ? 100 : 50;
+ const uriSize = size > 100 ? size : 100;
const { id, token } = user;
let query = '';
diff --git a/app/views/CreateDiscussionView/SelectChannel.js b/app/views/CreateDiscussionView/SelectChannel.js
index 0a47a086b..fa7110b94 100644
--- a/app/views/CreateDiscussionView/SelectChannel.js
+++ b/app/views/CreateDiscussionView/SelectChannel.js
@@ -25,8 +25,13 @@ const SelectChannel = ({
}
}, 300);
- const getAvatar = (text, type) => avatarURL({
- text, type, user: { id: userId, token }, server
+ const getAvatar = item => avatarURL({
+ text: RocketChat.getRoomAvatar(item),
+ type: item.t,
+ user: { id: userId, token },
+ server,
+ avatarETag: item.avatarETag,
+ rid: item.rid
});
return (
@@ -42,7 +47,7 @@ const SelectChannel = ({
options={channels.map(channel => ({
value: channel.rid,
text: { text: RocketChat.getRoomTitle(channel) },
- imageUrl: getAvatar(RocketChat.getRoomAvatar(channel), channel.t)
+ imageUrl: getAvatar(channel)
}))}
onClose={() => setChannels([])}
placeholder={{ text: `${ I18n.t('Select_a_Channel') }...` }}
diff --git a/app/views/DirectoryView/index.js b/app/views/DirectoryView/index.js
index 6a02092af..e21d2e9d1 100644
--- a/app/views/DirectoryView/index.js
+++ b/app/views/DirectoryView/index.js
@@ -205,7 +205,8 @@ class DirectoryView extends React.Component {
testID: `federation-view-item-${ item.name }`,
style,
user,
- theme
+ theme,
+ rid: item._id
};
if (type === 'users') {
diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js
index df4c0c0c5..70dce573c 100644
--- a/app/views/RoomActionsView/index.js
+++ b/app/views/RoomActionsView/index.js
@@ -669,7 +669,12 @@ class RoomActionsView extends React.Component {
renderRoomInfo = ({ item }) => {
const { room, member } = this.state;
- const { name, t, topic } = room;
+ const {
+ name,
+ t,
+ rid,
+ topic
+ } = room;
const { theme } = this.props;
const avatar = RocketChat.getRoomAvatar(room);
@@ -682,6 +687,7 @@ class RoomActionsView extends React.Component {
style={styles.avatar}
size={50}
type={t}
+ rid={rid}
>
{t === 'd' && member._id ? : null }
diff --git a/app/views/RoomInfoEditView/index.js b/app/views/RoomInfoEditView/index.js
index 8b4ffd6a8..92abe031e 100644
--- a/app/views/RoomInfoEditView/index.js
+++ b/app/views/RoomInfoEditView/index.js
@@ -6,7 +6,9 @@ import {
import { connect } from 'react-redux';
import equal from 'deep-equal';
import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
+import ImagePicker from 'react-native-image-crop-picker';
import isEqual from 'lodash/isEqual';
+import isEmpty from 'lodash/isEmpty';
import semver from 'semver';
import database from '../../lib/database';
@@ -31,6 +33,8 @@ import { withTheme } from '../../theme';
import { MultiSelect } from '../../containers/UIKit/MultiSelect';
import { MessageTypeValues } from '../../utils/messageTypes';
import SafeAreaView from '../../containers/SafeAreaView';
+import Avatar from '../../containers/Avatar';
+import { CustomIcon } from '../../lib/Icons';
const PERMISSION_SET_READONLY = 'set-readonly';
const PERMISSION_SET_REACT_WHEN_READONLY = 'set-react-when-readonly';
@@ -64,6 +68,7 @@ class RoomInfoEditView extends React.Component {
super(props);
this.state = {
room: {},
+ avatar: {},
permissions: {},
name: '',
description: '',
@@ -136,6 +141,7 @@ class RoomInfoEditView extends React.Component {
topic,
announcement,
t: t === 'p',
+ avatar: {},
ro,
reactWhenReadOnly,
joinCode: joinCodeRequired ? this.randomValue : '',
@@ -160,7 +166,7 @@ class RoomInfoEditView extends React.Component {
formIsChanged = () => {
const {
- room, name, description, topic, announcement, t, ro, reactWhenReadOnly, joinCode, systemMessages, enableSysMes, encrypted
+ room, name, description, topic, announcement, t, ro, reactWhenReadOnly, joinCode, systemMessages, enableSysMes, encrypted, avatar
} = this.state;
const { joinCodeRequired } = room;
return !(room.name === name
@@ -174,6 +180,7 @@ class RoomInfoEditView extends React.Component {
&& isEqual(room.sysMes, systemMessages)
&& enableSysMes === (room.sysMes && room.sysMes.length > 0)
&& room.encrypted === encrypted
+ && isEmpty(avatar)
);
}
@@ -181,7 +188,7 @@ class RoomInfoEditView extends React.Component {
logEvent(events.RI_EDIT_SAVE);
Keyboard.dismiss();
const {
- room, name, description, topic, announcement, t, ro, reactWhenReadOnly, joinCode, systemMessages, encrypted
+ room, name, description, topic, announcement, t, ro, reactWhenReadOnly, joinCode, systemMessages, encrypted, avatar
} = this.state;
this.setState({ saving: true });
@@ -201,6 +208,10 @@ class RoomInfoEditView extends React.Component {
if (room.name !== name) {
params.roomName = name;
}
+ // Avatar
+ if (!isEmpty(avatar)) {
+ params.roomAvatar = avatar.data;
+ }
// Description
if (room.description !== description) {
params.roomDescription = description;
@@ -347,6 +358,28 @@ class RoomInfoEditView extends React.Component {
);
}
+ changeAvatar = async() => {
+ const options = {
+ cropping: true,
+ compressImageQuality: 0.8,
+ cropperAvoidEmptySpaceAroundImage: false,
+ cropperChooseText: I18n.t('Choose'),
+ cropperCancelText: I18n.t('Cancel'),
+ includeBase64: true
+ };
+
+ try {
+ const response = await ImagePicker.openPicker(options);
+ this.setState({ avatar: { url: response.path, data: `data:image/jpeg;base64,${ response.data }`, service: 'upload' } });
+ } catch (e) {
+ console.log(e);
+ }
+ }
+
+ resetAvatar = () => {
+ this.setState({ avatar: { data: null } });
+ }
+
toggleRoomType = (value) => {
logEvent(events.RI_EDIT_TOGGLE_ROOM_TYPE);
this.setState(({ encrypted }) => ({ t: value, encrypted: value && encrypted }));
@@ -374,7 +407,7 @@ class RoomInfoEditView extends React.Component {
render() {
const {
- name, nameError, description, topic, announcement, t, ro, reactWhenReadOnly, room, joinCode, saving, permissions, archived, enableSysMes, encrypted
+ name, nameError, description, topic, announcement, t, ro, reactWhenReadOnly, room, joinCode, saving, permissions, archived, enableSysMes, encrypted, avatar
} = this.state;
const { serverVersion, e2eEnabled, theme } = this.props;
const { dangerColor } = themes[theme];
@@ -396,6 +429,20 @@ class RoomInfoEditView extends React.Component {
testID='room-info-edit-view-list'
{...scrollPersistTaps}
>
+
+
+
+
+
+
+
{ this.name = e; }}
label={I18n.t('Name')}
diff --git a/app/views/RoomInfoEditView/styles.js b/app/views/RoomInfoEditView/styles.js
index bf857940f..cff896af5 100644
--- a/app/views/RoomInfoEditView/styles.js
+++ b/app/views/RoomInfoEditView/styles.js
@@ -72,5 +72,17 @@ export default StyleSheet.create({
},
switchMargin: {
marginBottom: 16
+ },
+ avatarContainer: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginBottom: 10
+ },
+ resetButton: {
+ padding: 4,
+ borderRadius: 4,
+ position: 'absolute',
+ bottom: -8,
+ right: -8
}
});
diff --git a/app/views/RoomInfoView/index.js b/app/views/RoomInfoView/index.js
index 194f2e64a..34960a0bd 100644
--- a/app/views/RoomInfoView/index.js
+++ b/app/views/RoomInfoView/index.js
@@ -289,6 +289,7 @@ class RoomInfoView extends React.Component {
style={styles.avatar}
type={this.t}
size={100}
+ rid={room?.rid}
>
{this.t === 'd' && roomUser._id ? : null}
diff --git a/package.json b/package.json
index 3b8276f71..fc6425918 100644
--- a/package.json
+++ b/package.json
@@ -116,7 +116,7 @@
"redux-immutable-state-invariant": "2.1.0",
"redux-saga": "1.1.3",
"remove-markdown": "^0.3.0",
- "reselect": "^4.0.0",
+ "reselect": "4.0.0",
"rn-extensions-share": "^2.4.0",
"rn-fetch-blob": "0.12.0",
"rn-root-view": "^1.0.3",
diff --git a/storybook/stories/Avatar.js b/storybook/stories/Avatar.js
index 3a7b195a8..262896f05 100644
--- a/storybook/stories/Avatar.js
+++ b/storybook/stories/Avatar.js
@@ -35,6 +35,13 @@ const AvatarStories = ({ theme }) => (
server={server}
size={56}
/>
+
+