Skip to content

Commit

Permalink
Merge pull request #8852 from jayeshmangwani/avatar_fallback_default_…
Browse files Browse the repository at this point in the history
…when_offline

Added a fallback icon when getting error on loading image
  • Loading branch information
AndrewGable authored May 17, 2022
2 parents 44326c9 + e87646d commit 9a9e5a5
Show file tree
Hide file tree
Showing 13 changed files with 88 additions and 5 deletions.
25 changes: 25 additions & 0 deletions assets/images/avatars/fallback-avatar.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions assets/images/avatars/fallback-workspace-avatar.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 25 additions & 5 deletions src/components/Avatar.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Icon from './Icon';
import themeColors from '../styles/themes/default';
import CONST from '../CONST';
import * as StyleUtils from '../styles/StyleUtils';
import * as Expensicons from './Icon/Expensicons';

const propTypes = {
/** Source for the avatar. Can be a URL or an icon. */
Expand All @@ -23,6 +24,9 @@ const propTypes = {

/** The fill color for the icon. Can be hex, rgb, rgba, or valid react-native named color such as 'red' or 'blue' */
fill: PropTypes.string,

/** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
fallbackIcon: PropTypes.func,
};

const defaultProps = {
Expand All @@ -31,9 +35,17 @@ const defaultProps = {
containerStyles: [],
size: CONST.AVATAR_SIZE.DEFAULT,
fill: themeColors.icon,
fallbackIcon: Expensicons.FallbackAvatar,
};

class Avatar extends PureComponent {
constructor(props) {
super(props);
this.state = {
imageError: false,
};
}

render() {
if (!this.props.source) {
return null;
Expand All @@ -45,13 +57,21 @@ class Avatar extends PureComponent {
];

const iconSize = StyleUtils.getAvatarSize(this.props.size);

return (
<View pointerEvents="none" style={this.props.containerStyles}>
{
_.isFunction(this.props.source)
? <Icon src={this.props.source} fill={this.props.fill} height={iconSize} width={iconSize} />
: <Image source={{uri: this.props.source}} style={imageStyle} />
}
{_.isFunction(this.props.source) || this.state.imageError
? (
<Icon
src={this.state.imageError ? this.props.fallbackIcon : this.props.source}
height={iconSize}
width={iconSize}
fill={this.state.imageError ? themeColors.offline : this.props.fill}
/>
)
: (
<Image source={{uri: this.props.source}} style={imageStyle} onError={() => this.setState({imageError: true})} />
)}
</View>
);
}
Expand Down
6 changes: 6 additions & 0 deletions src/components/AvatarWithImagePicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ const propTypes = {
/** Size of Indicator */
size: PropTypes.oneOf([CONST.AVATAR_SIZE.LARGE, CONST.AVATAR_SIZE.DEFAULT]),

/** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
fallbackIcon: PropTypes.func,

...withLocalizePropTypes,
};

Expand All @@ -65,6 +68,7 @@ const defaultProps = {
isUsingDefaultAvatar: false,
isUploading: false,
size: CONST.AVATAR_SIZE.DEFAULT,
fallbackIcon: Expensicons.FallbackAvatar,
};

class AvatarWithImagePicker extends React.Component {
Expand Down Expand Up @@ -181,6 +185,8 @@ class AvatarWithImagePicker extends React.Component {
containerStyles={styles.avatarLarge}
imageStyles={[styles.avatarLarge, styles.alignSelfCenter]}
source={this.props.avatarURL}
fallbackIcon={this.props.fallbackIcon}
size={this.props.size}
/>
)
: (
Expand Down
1 change: 1 addition & 0 deletions src/components/AvatarWithIndicator.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class AvatarWithIndicator extends PureComponent {
<Avatar
imageStyles={[this.props.size === 'large' ? styles.avatarLarge : null]}
source={this.props.source}
size={this.props.size}
/>
</Tooltip>
<Tooltip text={this.userStatus()} absolute>
Expand Down
4 changes: 4 additions & 0 deletions src/components/Icon/Expensicons.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ import AdminRoomAvatar from '../../../assets/images/avatars/admin-room.svg';
import AnnounceRoomAvatar from '../../../assets/images/avatars/announce-room.svg';
import Connect from '../../../assets/images/connect.svg';
import DomainRoomAvatar from '../../../assets/images/avatars/domain-room.svg';
import FallbackAvatar from '../../../assets/images/avatars/fallback-avatar.svg';
import FallbackWorkspaceAvatar from '../../../assets/images/avatars/fallback-workspace-avatar.svg';

export {
ActiveRoomAvatar,
Expand Down Expand Up @@ -112,6 +114,8 @@ export {
Eye,
EyeDisabled,
ExpensifyCard,
FallbackAvatar,
FallbackWorkspaceAvatar,
Gallery,
Gear,
Hashtag,
Expand Down
2 changes: 2 additions & 0 deletions src/components/MenuItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const defaultProps = {
iconType: 'icon',
onPress: () => {},
interactive: true,
fallbackIcon: Expensicons.FallbackAvatar,
};

const MenuItem = props => (
Expand Down Expand Up @@ -87,6 +88,7 @@ const MenuItem = props => (
<Avatar
imageStyles={[styles.avatarNormal, styles.alignSelfCenter]}
source={props.icon}
fallbackIcon={props.fallbackIcon}
/>
</View>
)}
Expand Down
3 changes: 3 additions & 0 deletions src/components/menuItemPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ const propTypes = {

/** Whether the menu item should be interactive at all */
interactive: PropTypes.bool,

/** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
fallbackIcon: PropTypes.func,
};

export default propTypes;
1 change: 1 addition & 0 deletions src/pages/DetailsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ const DetailsPage = (props) => {
containerStyles={[styles.avatarLarge, styles.mb3]}
imageStyles={[styles.avatarLarge]}
source={details.avatar}
size={CONST.AVATAR_SIZE.LARGE}
/>
</PressableWithoutFocus>
)}
Expand Down
2 changes: 2 additions & 0 deletions src/pages/settings/InitialSettingsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ const InitialSettingsPage = (props) => {
action: () => Navigation.navigate(ROUTES.getWorkspaceInitialRoute(policy.id)),
iconStyles: [styles.popoverMenuIconEmphasized],
iconFill: themeColors.iconReversed,
fallbackIcon: Expensicons.FallbackWorkspaceAvatar,
}))
.value();
menuItems.push(...defaultMenuItems);
Expand Down Expand Up @@ -195,6 +196,7 @@ const InitialSettingsPage = (props) => {
iconFill={item.iconFill}
shouldShowRightIcon
badgeText={(isPaymentItem && Permissions.canUseWallet(props.betas)) ? walletBalance : undefined}
fallbackIcon={item.fallbackIcon}
/>
);
})}
Expand Down
2 changes: 2 additions & 0 deletions src/pages/workspace/WorkspaceInitialPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ class WorkspaceInitialPage extends React.Component {
containerStyles={styles.avatarLarge}
imageStyles={[styles.avatarLarge, styles.alignSelfCenter]}
source={this.props.policy.avatarURL}
fallbackIcon={Expensicons.FallbackWorkspaceAvatar}
size={CONST.AVATAR_SIZE.LARGE}
/>
)
: (
Expand Down
1 change: 1 addition & 0 deletions src/pages/workspace/WorkspaceSettingsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ class WorkspaceSettingsPage extends React.Component {
fill={defaultTheme.iconSuccessFill}
/>
)}
fallbackIcon={Expensicons.FallbackWorkspaceAvatar}
style={[styles.mb3]}
anchorPosition={{top: 172, right: 18}}
isUsingDefaultAvatar={!this.state.previewAvatarURL}
Expand Down
1 change: 1 addition & 0 deletions src/styles/StyleUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ function getAvatarStyle(size) {
height: avatarSize,
width: avatarSize,
borderRadius: avatarSize,
backgroundColor: themeColors.offline,
};
}

Expand Down

0 comments on commit 9a9e5a5

Please sign in to comment.