PLT-7567: Integration of Team Icons (#1470)
* PLT-7567: Integration of team icons in channel drawer teams, switch team button, team selection, os share extenions * PLT-7567: adopt updated eslint changes * PLT-7567: Component for team icon display, refactoring * PLT-7567: removed redundant styles * PLT-7567: redux connected component for team icon, error handling
This commit is contained in:
parent
31d48fa49c
commit
98fee5e473
8 changed files with 178 additions and 101 deletions
|
|
@ -13,7 +13,6 @@ function mapStateToProps(state) {
|
|||
|
||||
return {
|
||||
currentTeamId: team.id,
|
||||
displayName: team.display_name,
|
||||
mentionCount: getChannelDrawerBadgeCount(state),
|
||||
teamsCount: getMyTeamsCount(state),
|
||||
theme: getTheme(state),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import {
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
View,
|
||||
} from 'react-native';
|
||||
|
|
@ -14,10 +13,11 @@ import Badge from 'app/components/badge';
|
|||
import {preventDoubleTap} from 'app/utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
import TeamIcon from 'app/components/team_icon';
|
||||
|
||||
export default class SwitchTeamsButton extends React.PureComponent {
|
||||
static propTypes = {
|
||||
currentTeamId: PropTypes.string,
|
||||
displayName: PropTypes.string,
|
||||
searching: PropTypes.bool.isRequired,
|
||||
onShowTeams: PropTypes.func.isRequired,
|
||||
mentionCount: PropTypes.number.isRequired,
|
||||
|
|
@ -32,7 +32,6 @@ export default class SwitchTeamsButton extends React.PureComponent {
|
|||
render() {
|
||||
const {
|
||||
currentTeamId,
|
||||
displayName,
|
||||
mentionCount,
|
||||
searching,
|
||||
teamsCount,
|
||||
|
|
@ -69,12 +68,13 @@ export default class SwitchTeamsButton extends React.PureComponent {
|
|||
<AwesomeIcon
|
||||
name='chevron-left'
|
||||
size={12}
|
||||
color={theme.sidebarHeaderBg}
|
||||
style={styles.switcherArrow}
|
||||
/>
|
||||
<TeamIcon
|
||||
teamId={currentTeamId}
|
||||
styleContainer={styles.teamIconContainer}
|
||||
styleText={styles.teamIconText}
|
||||
/>
|
||||
<View style={styles.switcherDivider}/>
|
||||
<Text style={styles.switcherTeam}>
|
||||
{displayName.substr(0, 2).toUpperCase()}
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
{badge}
|
||||
|
|
@ -86,25 +86,26 @@ export default class SwitchTeamsButton extends React.PureComponent {
|
|||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
||||
return {
|
||||
switcherContainer: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: theme.sidebarHeaderTextColor,
|
||||
borderRadius: 2,
|
||||
flexDirection: 'row',
|
||||
height: 32,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: 32,
|
||||
borderRadius: 2,
|
||||
marginLeft: 6,
|
||||
marginRight: 5,
|
||||
paddingHorizontal: 6,
|
||||
marginRight: 6,
|
||||
paddingHorizontal: 3,
|
||||
},
|
||||
switcherDivider: {
|
||||
backgroundColor: theme.sidebarHeaderBg,
|
||||
height: 15,
|
||||
marginHorizontal: 6,
|
||||
width: 1,
|
||||
},
|
||||
switcherTeam: {
|
||||
switcherArrow: {
|
||||
color: theme.sidebarHeaderBg,
|
||||
fontFamily: 'OpenSans',
|
||||
marginRight: 3,
|
||||
},
|
||||
teamIconContainer: {
|
||||
width: 26,
|
||||
height: 26,
|
||||
marginLeft: 3,
|
||||
},
|
||||
teamIconText: {
|
||||
fontSize: 14,
|
||||
},
|
||||
badge: {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import {
|
|||
import IonIcon from 'react-native-vector-icons/Ionicons';
|
||||
|
||||
import Badge from 'app/components/badge';
|
||||
import TeamIcon from 'app/components/team_icon';
|
||||
|
||||
import {preventDoubleTap} from 'app/utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
|
|
@ -71,11 +73,11 @@ export default class TeamsListItem extends React.PureComponent {
|
|||
onPress={this.selectTeam}
|
||||
>
|
||||
<View style={styles.teamContainer}>
|
||||
<View style={styles.teamIconContainer}>
|
||||
<Text style={styles.teamIcon}>
|
||||
{displayName.substr(0, 2).toUpperCase()}
|
||||
</Text>
|
||||
</View>
|
||||
<TeamIcon
|
||||
teamId={teamId}
|
||||
styleContainer={styles.teamIconContainer}
|
||||
styleText={styles.teamIconText}
|
||||
/>
|
||||
<View style={styles.teamNameContainer}>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
|
|
@ -112,20 +114,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|||
flexDirection: 'row',
|
||||
marginHorizontal: 16,
|
||||
},
|
||||
teamIconContainer: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: theme.sidebarText,
|
||||
borderRadius: 2,
|
||||
height: 40,
|
||||
justifyContent: 'center',
|
||||
width: 40,
|
||||
},
|
||||
teamIcon: {
|
||||
color: theme.sidebarBg,
|
||||
fontFamily: 'OpenSans',
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
},
|
||||
teamNameContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
|
|
@ -135,6 +123,13 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|||
color: theme.sidebarText,
|
||||
fontSize: 18,
|
||||
},
|
||||
teamIconContainer: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
},
|
||||
teamIconText: {
|
||||
fontSize: 18,
|
||||
},
|
||||
teamUrl: {
|
||||
color: changeOpacity(theme.sidebarText, 0.5),
|
||||
fontSize: 12,
|
||||
|
|
|
|||
18
app/components/team_icon/index.js
Normal file
18
app/components/team_icon/index.js
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {getTeam} from 'mattermost-redux/selectors/entities/teams';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
import TeamIcon from './team_icon';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
team: getTeam(state, ownProps.teamId),
|
||||
theme: getTheme(state),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(TeamIcon);
|
||||
97
app/components/team_icon/team_icon.js
Normal file
97
app/components/team_icon/team_icon.js
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {
|
||||
Text,
|
||||
Image,
|
||||
View,
|
||||
} from 'react-native';
|
||||
|
||||
import {makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
import {Client4} from 'mattermost-redux/client';
|
||||
|
||||
export default class TeamIcon extends React.PureComponent {
|
||||
static propTypes = {
|
||||
teamId: PropTypes.string.isRequired, // eslint-disable-line react/no-unused-prop-types
|
||||
styleContainer: PropTypes.any,
|
||||
styleText: PropTypes.any,
|
||||
styleImage: PropTypes.any,
|
||||
team: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
imageError: false,
|
||||
};
|
||||
|
||||
componentWillReceiveProps() {
|
||||
this.setState({imageError: false});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
team,
|
||||
theme,
|
||||
styleContainer,
|
||||
styleText,
|
||||
styleImage,
|
||||
} = this.props;
|
||||
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
let teamIconContent;
|
||||
if (team.last_team_icon_update && !this.state.imageError) {
|
||||
const teamIconUrl = Client4.getTeamIconUrl(team.id, team.last_team_icon_update);
|
||||
teamIconContent = (
|
||||
<Image
|
||||
style={[styles.image, styleImage]}
|
||||
source={{uri: teamIconUrl}}
|
||||
onError={() => this.setState({imageError: true})}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
teamIconContent = (
|
||||
<Text style={[styles.text, styleText]}>
|
||||
{team.display_name.substr(0, 2).toUpperCase()}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[styles.container, styleContainer]}>
|
||||
{teamIconContent}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
||||
return {
|
||||
container: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 2,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: theme.sidebarText,
|
||||
},
|
||||
text: {
|
||||
color: theme.sidebarBg,
|
||||
fontFamily: 'OpenSans',
|
||||
fontWeight: '600',
|
||||
fontSize: 15,
|
||||
},
|
||||
image: {
|
||||
borderRadius: 2,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
@ -23,6 +23,8 @@ import {ListTypes} from 'app/constants';
|
|||
import {preventDoubleTap} from 'app/utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/utils/theme';
|
||||
|
||||
import TeamIcon from 'app/components/team_icon';
|
||||
|
||||
const VIEWABILITY_CONFIG = ListTypes.VISIBILITY_CONFIG_DEFAULTS;
|
||||
|
||||
export default class SelectTeam extends PureComponent {
|
||||
|
|
@ -177,11 +179,11 @@ export default class SelectTeam extends PureComponent {
|
|||
onPress={preventDoubleTap(() => this.onSelectTeam(item))}
|
||||
>
|
||||
<View style={styles.teamContainer}>
|
||||
<View style={styles.teamIconContainer}>
|
||||
<Text style={styles.teamIcon}>
|
||||
{item.display_name.substr(0, 2).toUpperCase()}
|
||||
</Text>
|
||||
</View>
|
||||
<TeamIcon
|
||||
teamId={item.id}
|
||||
styleContainer={styles.teamIconContainer}
|
||||
styleText={styles.teamIconText}
|
||||
/>
|
||||
<View style={styles.teamNameContainer}>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
|
|
@ -271,23 +273,16 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|||
marginHorizontal: 16,
|
||||
},
|
||||
teamIconContainer: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: theme.buttonBg,
|
||||
borderRadius: 2,
|
||||
height: 40,
|
||||
justifyContent: 'center',
|
||||
width: 40,
|
||||
height: 40,
|
||||
},
|
||||
teamIconText: {
|
||||
fontSize: 18,
|
||||
},
|
||||
noTeam: {
|
||||
color: theme.centerChannelColor,
|
||||
fontSize: 14,
|
||||
},
|
||||
teamIcon: {
|
||||
color: theme.buttonColor,
|
||||
fontFamily: 'OpenSans',
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
},
|
||||
teamNameContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import IonIcon from 'react-native-vector-icons/Ionicons';
|
|||
import {wrapWithPreventDoubleTap} from 'app/utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
import TeamIcon from 'app/components/team_icon';
|
||||
|
||||
export default class TeamItem extends PureComponent {
|
||||
static propTypes = {
|
||||
currentTeamId: PropTypes.string.isRequired,
|
||||
|
|
@ -46,14 +48,6 @@ export default class TeamItem extends PureComponent {
|
|||
);
|
||||
}
|
||||
|
||||
const icon = (
|
||||
<View style={styles.iconContainer}>
|
||||
<Text style={styles.icon}>
|
||||
{team.display_name.substr(0, 2).toUpperCase()}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
return (
|
||||
<TouchableHighlight
|
||||
underlayColor={changeOpacity(theme.sidebarTextHoverBg, 0.5)}
|
||||
|
|
@ -61,7 +55,11 @@ export default class TeamItem extends PureComponent {
|
|||
>
|
||||
<View style={styles.container}>
|
||||
<View style={styles.item}>
|
||||
{icon}
|
||||
<TeamIcon
|
||||
teamId={team.id}
|
||||
styleContainer={styles.teamIconContainer}
|
||||
styleText={styles.teamIconText}
|
||||
/>
|
||||
<Text
|
||||
style={[styles.text]}
|
||||
ellipsizeMode='tail'
|
||||
|
|
@ -97,21 +95,9 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|||
fontSize: 16,
|
||||
paddingRight: 5,
|
||||
},
|
||||
iconContainer: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: theme.linkColor,
|
||||
borderRadius: 2,
|
||||
height: 30,
|
||||
justifyContent: 'center',
|
||||
width: 30,
|
||||
teamIconContainer: {
|
||||
marginRight: 10,
|
||||
},
|
||||
icon: {
|
||||
color: theme.sidebarText,
|
||||
fontFamily: 'OpenSans',
|
||||
fontSize: 15,
|
||||
fontWeight: '600',
|
||||
},
|
||||
checkmarkContainer: {
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import {
|
|||
import {wrapWithPreventDoubleTap} from 'app/utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
import TeamIcon from 'app/components/team_icon';
|
||||
|
||||
export default class TeamsListItem extends React.PureComponent {
|
||||
static propTypes = {
|
||||
currentTeamId: PropTypes.string.isRequired,
|
||||
|
|
@ -33,14 +35,6 @@ export default class TeamsListItem extends React.PureComponent {
|
|||
} = this.props;
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
const icon = (
|
||||
<View style={styles.iconContainer}>
|
||||
<Text style={styles.icon}>
|
||||
{team.display_name.substr(0, 2).toUpperCase()}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const wrapperStyle = [styles.wrapper];
|
||||
if (team.id === currentTeamId) {
|
||||
wrapperStyle.push({
|
||||
|
|
@ -56,7 +50,11 @@ export default class TeamsListItem extends React.PureComponent {
|
|||
>
|
||||
<View style={styles.container}>
|
||||
<View style={styles.item}>
|
||||
{icon}
|
||||
<TeamIcon
|
||||
teamId={team.id}
|
||||
styleContainer={styles.teamIconContainer}
|
||||
styleText={styles.teamIconText}
|
||||
/>
|
||||
<Text
|
||||
style={[styles.text]}
|
||||
ellipsizeMode='tail'
|
||||
|
|
@ -97,21 +95,9 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|||
lineHeight: 16,
|
||||
paddingRight: 5,
|
||||
},
|
||||
iconContainer: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: theme.linkColor,
|
||||
borderRadius: 2,
|
||||
height: 30,
|
||||
justifyContent: 'center',
|
||||
width: 30,
|
||||
teamIconContainer: {
|
||||
marginRight: 10,
|
||||
},
|
||||
icon: {
|
||||
color: theme.sidebarText,
|
||||
fontFamily: 'OpenSans',
|
||||
fontSize: 15,
|
||||
fontWeight: '600',
|
||||
},
|
||||
checkmarkContainer: {
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue