From 4d9fd37a13fa00032416132136a3d9ef4c156af0 Mon Sep 17 00:00:00 2001 From: Amal Nazeem <amal@expensify.com> Date: Tue, 6 Jul 2021 18:10:16 -0400 Subject: [PATCH 1/4] Add avatars based on svg icons for default rooms --- assets/images/armchair.svg | 4 ++++ src/components/Avatar.js | 1 + src/components/Icon/Expensicons.js | 2 ++ src/components/IconAvatar.js | 32 +++++++++++++++++++++++++++++ src/components/MultipleAvatars.js | 15 +++++++++++++- src/libs/OptionsListUtils.js | 4 ++-- src/pages/home/HeaderView.js | 1 + src/pages/home/sidebar/OptionRow.js | 1 + 8 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 assets/images/armchair.svg create mode 100644 src/components/IconAvatar.js diff --git a/assets/images/armchair.svg b/assets/images/armchair.svg new file mode 100644 index 000000000000..8f6720c53bc8 --- /dev/null +++ b/assets/images/armchair.svg @@ -0,0 +1,4 @@ +<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M6.25 10.625V11.25H13.75V10.625C13.75 9.11625 14.825 7.85375 16.25 7.56375V6.25C16.25 3.48875 14.0113 1.25 11.25 1.25H8.75C5.98875 1.25 3.75 3.48875 3.75 6.25V7.56375C5.175 7.85375 6.25 9.11625 6.25 10.625Z" fill="black"/> +<path d="M16.875 8.75C15.84 8.75 15 9.59 15 10.625V12.5H5V10.625C5 9.59 4.16 8.75 3.125 8.75C2.09 8.75 1.25 9.59 1.25 10.625C1.25 11.44 1.77375 12.1275 2.5 12.385V12.5V18.75H5V16.25H15V18.75H17.5V12.5V12.385C18.2262 12.1262 18.75 11.44 18.75 10.625C18.75 9.59 17.91 8.75 16.875 8.75Z" fill="black"/> +</svg> diff --git a/src/components/Avatar.js b/src/components/Avatar.js index b6c1277869ab..ea948c749ef7 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -2,6 +2,7 @@ import React, {PureComponent} from 'react'; import {Image, View} from 'react-native'; import PropTypes from 'prop-types'; import styles from '../styles/styles'; +import armchair from '../../assets/images/armchair.svg' const propTypes = { /** Url source for the avatar */ diff --git a/src/components/Icon/Expensicons.js b/src/components/Icon/Expensicons.js index d41626c25810..fbd8304c761d 100644 --- a/src/components/Icon/Expensicons.js +++ b/src/components/Icon/Expensicons.js @@ -1,5 +1,6 @@ import Android from '../../../assets/images/android.svg'; import Apple from '../../../assets/images/apple.svg'; +import Armchair from '../../../assets/images/armchair.svg'; import ArrowRight from '../../../assets/images/arrow-right.svg'; import BackArrow from '../../../assets/images/back-left.svg'; import Bank from '../../../assets/images/bank.svg'; @@ -55,6 +56,7 @@ export { Android, Apple, ArrowRight, + Armchair, BackArrow, Bank, Building, diff --git a/src/components/IconAvatar.js b/src/components/IconAvatar.js new file mode 100644 index 000000000000..d0ad10ac41da --- /dev/null +++ b/src/components/IconAvatar.js @@ -0,0 +1,32 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Armchair} from './Icon/Expensicons'; +import variables from '../styles/variables'; + +const propTypes = { + /** The name of the icon to render. */ + icon: PropTypes.string.isRequired, +}; + +/** + * Get an icon based on the name provided + * @param {String} iconName + * @returns {Function} + */ +function getIconFromName(iconName) { + switch (iconName) { + case 'armchair': + default: + return Armchair; + } +} + +const IconAvatar = (props) => { + // PascalCase is required for React components, so capitalize the const here + const Icon = getIconFromName(props.icon); + return (<Icon width={variables.componentSizeNormal} height={variables.componentSizeNormal} />); +}; + +IconAvatar.displayName = 'IconAvatar'; +IconAvatar.propTypes = propTypes; +export default IconAvatar; diff --git a/src/components/MultipleAvatars.js b/src/components/MultipleAvatars.js index 4507e388ae41..f15e54e878e2 100644 --- a/src/components/MultipleAvatars.js +++ b/src/components/MultipleAvatars.js @@ -4,6 +4,7 @@ import {Image, View} from 'react-native'; import styles from '../styles/styles'; import Avatar from './Avatar'; import Text from './Text'; +import IconAvatar from './IconAvatar'; const propTypes = { /** Array of avatar URL */ @@ -15,16 +16,20 @@ const propTypes = { /** Style for Second Avatar */ // eslint-disable-next-line react/forbid-prop-types secondAvatarStyle: PropTypes.arrayOf(PropTypes.object), + + /** Whether we should be using an Icon for the Avatar */ + useIcon: PropTypes.bool, }; const defaultProps = { avatarImageURLs: [], size: 'default', secondAvatarStyle: [styles.secondAvatarHovered], + useIcon: false, }; const MultipleAvatars = ({ - avatarImageURLs, size, secondAvatarStyle, + avatarImageURLs, size, secondAvatarStyle, useIcon, }) => { const avatarContainerStyles = size === 'small' ? styles.emptyAvatarSmall : styles.emptyAvatar; const singleAvatarStyles = size === 'small' ? styles.singleAvatarSmall : styles.singleAvatar; @@ -37,6 +42,14 @@ const MultipleAvatars = ({ return null; } + if (useIcon) { + return ( + <View style={avatarContainerStyles}> + <IconAvatar icon={avatarImageURLs[0]} /> + </View> + ); + } + if (avatarImageURLs.length === 1) { return ( <View style={avatarContainerStyles}> diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index b727b27b1b57..df1d719bd3fe 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -663,9 +663,9 @@ function getCurrencyListForSections(currencyOptions, searchValue) { * @returns {String} */ function getReportIcons(report, personalDetails) { + // Default rooms use icons names for their avatars if (isDefaultRoom(report)) { - // Placeholder image for default rooms soon to be updated - return [`${CONST.CLOUDFRONT_URL}/images/avatars/default_avatar_external.png`]; + return ['armchair']; } return _.map(report.participants, dmParticipant => ({ firstName: lodashGet(personalDetails, [dmParticipant, 'firstName'], ''), diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 212542039e79..85cecee775db 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -122,6 +122,7 @@ const HeaderView = (props) => { <MultipleAvatars avatarImageURLs={props.report.icons} secondAvatarStyle={[styles.secondAvatarHovered]} + useIcon={isDefaultChatRoom} /> <View style={[styles.flex1, styles.flexColumn]}> <DisplayNames diff --git a/src/pages/home/sidebar/OptionRow.js b/src/pages/home/sidebar/OptionRow.js index 3b7c25565ca2..dc537a7c6632 100644 --- a/src/pages/home/sidebar/OptionRow.js +++ b/src/pages/home/sidebar/OptionRow.js @@ -183,6 +183,7 @@ const OptionRow = ({ ? getBackgroundAndBorderStyle(hoveredBackgroundColor) : undefined, ]} + useIcon={option.isDefaultChatRoom} /> ) } From 5d1cdf9133a7e6011a58167e30702c801324e0d5 Mon Sep 17 00:00:00 2001 From: Amal Nazeem <amal@expensify.com> Date: Tue, 6 Jul 2021 18:15:41 -0400 Subject: [PATCH 2/4] remove unused import --- src/components/Avatar.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Avatar.js b/src/components/Avatar.js index ea948c749ef7..b6c1277869ab 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -2,7 +2,6 @@ import React, {PureComponent} from 'react'; import {Image, View} from 'react-native'; import PropTypes from 'prop-types'; import styles from '../styles/styles'; -import armchair from '../../assets/images/armchair.svg' const propTypes = { /** Url source for the avatar */ From a02c5cd99a6169dde951e393717855a19bb5651f Mon Sep 17 00:00:00 2001 From: Amal Nazeem <amal@expensify.com> Date: Thu, 8 Jul 2021 16:07:52 -0400 Subject: [PATCH 3/4] Update avatar logic for default rooms --- assets/images/avatars/room.svg | 16 +++++++++++++++ src/components/Avatar.js | 23 +++++++++++++-------- src/components/IconAvatar.js | 32 ----------------------------- src/components/MultipleAvatars.js | 19 +++++------------ src/libs/OptionsListUtils.js | 4 ++-- src/pages/ReportDetailsPage.js | 9 +++++--- src/pages/home/HeaderView.js | 2 +- src/pages/home/sidebar/OptionRow.js | 2 +- 8 files changed, 45 insertions(+), 62 deletions(-) create mode 100644 assets/images/avatars/room.svg delete mode 100644 src/components/IconAvatar.js diff --git a/assets/images/avatars/room.svg b/assets/images/avatars/room.svg new file mode 100644 index 000000000000..2bbe41c6d5f4 --- /dev/null +++ b/assets/images/avatars/room.svg @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 40 40" style="enable-background:new 0 0 40 40;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#C6C9CA;} + .st1{fill:#FFFFFF;} +</style> +<rect class="st0" width="40" height="40"/> +<g> + <path class="st1" d="M16.2,20.6v0.6h7.5v-0.6c0-1.5,1.1-2.8,2.5-3.1v-1.3c0-2.8-2.2-5-5-5h-2.5c-2.8,0-5,2.2-5,5v1.3 + C15.2,17.9,16.2,19.1,16.2,20.6z"/> + <path class="st1" d="M26.9,18.8c-1,0-1.9,0.8-1.9,1.9v1.9H15v-1.9c0-1-0.8-1.9-1.9-1.9s-1.9,0.8-1.9,1.9c0,0.8,0.5,1.5,1.2,1.8v6.4 + H15v-2.5h10v2.5h2.5v-6.4c0.7-0.3,1.2-0.9,1.2-1.8C28.8,19.6,27.9,18.8,26.9,18.8z"/> +</g> +</svg> diff --git a/src/components/Avatar.js b/src/components/Avatar.js index b6c1277869ab..841900b2b1dd 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -1,7 +1,8 @@ import React, {PureComponent} from 'react'; -import {Image, View} from 'react-native'; +import {Image, View, StyleSheet} from 'react-native'; import PropTypes from 'prop-types'; import styles from '../styles/styles'; +import RoomAvatar from '../../assets/images/avatars/room.svg'; const propTypes = { /** Url source for the avatar */ @@ -15,6 +16,9 @@ const propTypes = { /** Set the size of Avatar */ size: PropTypes.oneOf(['default', 'small']), + + /** Whether this avatar is for a default room */ + isDefaultChatRoom: PropTypes.bool, }; const defaultProps = { @@ -22,23 +26,24 @@ const defaultProps = { imageStyles: [], containerStyles: [], size: 'default', + isDefaultChatRoom: false, }; class Avatar extends PureComponent { render() { - if (!this.props.source) { + if (!this.props.source && !this.props.isDefaultChatRoom) { return null; } + const imageStyle = [ + this.props.size === 'small' ? styles.avatarSmall : styles.avatarNormal, + ...this.props.imageStyles, + ]; return ( <View pointerEvents="none" style={this.props.containerStyles}> - <Image - source={{uri: this.props.source}} - style={[ - this.props.size === 'small' ? styles.avatarSmall : styles.avatarNormal, - ...this.props.imageStyles, - ]} - /> + {this.props.isDefaultChatRoom + ? <RoomAvatar style={StyleSheet.flatten(imageStyle)} /> + : <Image source={{uri: this.props.source}} style={imageStyle} />} </View> ); } diff --git a/src/components/IconAvatar.js b/src/components/IconAvatar.js deleted file mode 100644 index d0ad10ac41da..000000000000 --- a/src/components/IconAvatar.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {Armchair} from './Icon/Expensicons'; -import variables from '../styles/variables'; - -const propTypes = { - /** The name of the icon to render. */ - icon: PropTypes.string.isRequired, -}; - -/** - * Get an icon based on the name provided - * @param {String} iconName - * @returns {Function} - */ -function getIconFromName(iconName) { - switch (iconName) { - case 'armchair': - default: - return Armchair; - } -} - -const IconAvatar = (props) => { - // PascalCase is required for React components, so capitalize the const here - const Icon = getIconFromName(props.icon); - return (<Icon width={variables.componentSizeNormal} height={variables.componentSizeNormal} />); -}; - -IconAvatar.displayName = 'IconAvatar'; -IconAvatar.propTypes = propTypes; -export default IconAvatar; diff --git a/src/components/MultipleAvatars.js b/src/components/MultipleAvatars.js index f15e54e878e2..079ac370928b 100644 --- a/src/components/MultipleAvatars.js +++ b/src/components/MultipleAvatars.js @@ -4,7 +4,6 @@ import {Image, View} from 'react-native'; import styles from '../styles/styles'; import Avatar from './Avatar'; import Text from './Text'; -import IconAvatar from './IconAvatar'; const propTypes = { /** Array of avatar URL */ @@ -17,19 +16,19 @@ const propTypes = { // eslint-disable-next-line react/forbid-prop-types secondAvatarStyle: PropTypes.arrayOf(PropTypes.object), - /** Whether we should be using an Icon for the Avatar */ - useIcon: PropTypes.bool, + /** Whether this avatar is for a default room */ + isDefaultChatRoom: PropTypes.bool, }; const defaultProps = { avatarImageURLs: [], size: 'default', secondAvatarStyle: [styles.secondAvatarHovered], - useIcon: false, + isDefaultChatRoom: false, }; const MultipleAvatars = ({ - avatarImageURLs, size, secondAvatarStyle, useIcon, + avatarImageURLs, size, secondAvatarStyle, isDefaultChatRoom, }) => { const avatarContainerStyles = size === 'small' ? styles.emptyAvatarSmall : styles.emptyAvatar; const singleAvatarStyles = size === 'small' ? styles.singleAvatarSmall : styles.singleAvatar; @@ -42,18 +41,10 @@ const MultipleAvatars = ({ return null; } - if (useIcon) { - return ( - <View style={avatarContainerStyles}> - <IconAvatar icon={avatarImageURLs[0]} /> - </View> - ); - } - if (avatarImageURLs.length === 1) { return ( <View style={avatarContainerStyles}> - <Avatar source={avatarImageURLs[0]} size={size} /> + <Avatar source={avatarImageURLs[0]} size={size} isDefaultChatRoom={isDefaultChatRoom} /> </View> ); } diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index df1d719bd3fe..a88307f9301e 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -663,9 +663,9 @@ function getCurrencyListForSections(currencyOptions, searchValue) { * @returns {String} */ function getReportIcons(report, personalDetails) { - // Default rooms use icons names for their avatars + // Default rooms have a specific avatar so we can return any non-empty array if (isDefaultRoom(report)) { - return ['armchair']; + return ['']; } return _.map(report.participants, dmParticipant => ({ firstName: lodashGet(personalDetails, [dmParticipant, 'firstName'], ''), diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index 01c7ff98d9fe..c97e754bf922 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -3,8 +3,9 @@ import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; import Str from 'expensify-common/lib/str'; import _ from 'underscore'; -import {Image, Text, View} from 'react-native'; +import {Text, View} from 'react-native'; import lodashGet from 'lodash/get'; +import Avatar from '../components/Avatar'; import compose from '../libs/compose'; import withLocalize, {withLocalizePropTypes} from '../components/withLocalize'; import ONYXKEYS from '../ONYXKEYS'; @@ -129,9 +130,11 @@ class ReportDetailsPage extends Component { <View style={styles.reportDetailsTitleContainer} > - <Image + <Avatar + isDefaultChatRoom={isDefaultRoom(this.props.report)} + containerStyles={[styles.singleAvatarLarge, styles.mb4]} + imageStyles={[styles.singleAvatarLarge]} source={{uri: this.props.report.icons[0]}} - style={[styles.singleAvatarLarge, styles.mb4]} /> <View style={styles.reportDetailsRoomInfo}> <DisplayNames diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 85cecee775db..e4a72243299e 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -122,7 +122,7 @@ const HeaderView = (props) => { <MultipleAvatars avatarImageURLs={props.report.icons} secondAvatarStyle={[styles.secondAvatarHovered]} - useIcon={isDefaultChatRoom} + isDefaultChatRoom={isDefaultChatRoom} /> <View style={[styles.flex1, styles.flexColumn]}> <DisplayNames diff --git a/src/pages/home/sidebar/OptionRow.js b/src/pages/home/sidebar/OptionRow.js index dc537a7c6632..985e47d13b5e 100644 --- a/src/pages/home/sidebar/OptionRow.js +++ b/src/pages/home/sidebar/OptionRow.js @@ -183,7 +183,7 @@ const OptionRow = ({ ? getBackgroundAndBorderStyle(hoveredBackgroundColor) : undefined, ]} - useIcon={option.isDefaultChatRoom} + isDefaultChatRoom={option.isDefaultChatRoom} /> ) } From 1d3d928a2f6b85ac5658191aabbb56fe186e2b46 Mon Sep 17 00:00:00 2001 From: Amal Nazeem <amal@expensify.com> Date: Thu, 8 Jul 2021 16:13:05 -0400 Subject: [PATCH 4/4] remove archmair icon we are no longer using --- assets/images/armchair.svg | 4 ---- src/components/Icon/Expensicons.js | 2 -- 2 files changed, 6 deletions(-) delete mode 100644 assets/images/armchair.svg diff --git a/assets/images/armchair.svg b/assets/images/armchair.svg deleted file mode 100644 index 8f6720c53bc8..000000000000 --- a/assets/images/armchair.svg +++ /dev/null @@ -1,4 +0,0 @@ -<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M6.25 10.625V11.25H13.75V10.625C13.75 9.11625 14.825 7.85375 16.25 7.56375V6.25C16.25 3.48875 14.0113 1.25 11.25 1.25H8.75C5.98875 1.25 3.75 3.48875 3.75 6.25V7.56375C5.175 7.85375 6.25 9.11625 6.25 10.625Z" fill="black"/> -<path d="M16.875 8.75C15.84 8.75 15 9.59 15 10.625V12.5H5V10.625C5 9.59 4.16 8.75 3.125 8.75C2.09 8.75 1.25 9.59 1.25 10.625C1.25 11.44 1.77375 12.1275 2.5 12.385V12.5V18.75H5V16.25H15V18.75H17.5V12.5V12.385C18.2262 12.1262 18.75 11.44 18.75 10.625C18.75 9.59 17.91 8.75 16.875 8.75Z" fill="black"/> -</svg> diff --git a/src/components/Icon/Expensicons.js b/src/components/Icon/Expensicons.js index fbd8304c761d..d41626c25810 100644 --- a/src/components/Icon/Expensicons.js +++ b/src/components/Icon/Expensicons.js @@ -1,6 +1,5 @@ import Android from '../../../assets/images/android.svg'; import Apple from '../../../assets/images/apple.svg'; -import Armchair from '../../../assets/images/armchair.svg'; import ArrowRight from '../../../assets/images/arrow-right.svg'; import BackArrow from '../../../assets/images/back-left.svg'; import Bank from '../../../assets/images/bank.svg'; @@ -56,7 +55,6 @@ export { Android, Apple, ArrowRight, - Armchair, BackArrow, Bank, Building,