Skip to content

Commit

Permalink
Merge 201275e into e60b62c
Browse files Browse the repository at this point in the history
  • Loading branch information
borisyankov committed Feb 16, 2019
2 parents e60b62c + 201275e commit 9afbde3
Show file tree
Hide file tree
Showing 18 changed files with 332 additions and 55 deletions.
37 changes: 19 additions & 18 deletions src/account-info/AccountDetails.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
/* @flow strict-local */
import React, { PureComponent } from 'react';
import { View, Dimensions, StyleSheet } from 'react-native';
import { connect } from 'react-redux';

import type { Dispatch, User } from '../types';
import { Avatar, ComponentList, RawLabel, ZulipButton } from '../common';
import { IconPrivateChat } from '../common/Icons';
import { privateNarrow } from '../utils/narrow';
import type { GlobalState, User, UserStatusMapObject } from '../types';
import { Avatar, ComponentList, RawLabel } from '../common';
import PresenceStatusIndicator from '../common/PresenceStatusIndicator';
import { getUserStatus } from '../selectors';
import ActivityText from '../title/ActivityText';
import { getMediumAvatar } from '../utils/avatar';
import { nowInTimeZone } from '../utils/date';
import { doNarrow } from '../actions';
import styles from '../styles';

const componentStyles = StyleSheet.create({
Expand All @@ -21,22 +20,22 @@ const componentStyles = StyleSheet.create({
justifyContent: 'center',
flexDirection: 'row',
},
statusText: {
textAlign: 'center',
// backgtoundColor: 'red',
},
});

type Props = {|
dispatch: Dispatch,
user: User,
userStatus: UserStatusMapObject,
|};

export default class AccountDetails extends PureComponent<Props, void> {
handleChatPress = () => {
const { user, dispatch } = this.props;
dispatch(doNarrow(privateNarrow(user.email)));
};

class AccountDetails extends PureComponent<Props, void> {
render() {
const { user } = this.props;
const { user, userStatus } = this.props;
const screenWidth = Dimensions.get('window').width;
const statusText = userStatus[user.user_id] && userStatus[user.user_id].status_text;

return (
<View>
Expand All @@ -52,6 +51,9 @@ export default class AccountDetails extends PureComponent<Props, void> {
<PresenceStatusIndicator email={user.email} hideIfOffline={false} />
<RawLabel style={[styles.largerText, styles.halfMarginLeft]} text={user.email} />
</View>
{statusText !== undefined && (
<RawLabel style={[styles.largerText, componentStyles.statusText]} text={statusText} />
)}
<View>
<ActivityText style={styles.largerText} email={user.email} />
</View>
Expand All @@ -63,13 +65,12 @@ export default class AccountDetails extends PureComponent<Props, void> {
/>
</View>
) : null}
<ZulipButton
text="Send private message"
onPress={this.handleChatPress}
Icon={IconPrivateChat}
/>
</ComponentList>
</View>
);
}
}

export default connect((state: GlobalState) => ({
userStatus: getUserStatus(state),
}))(AccountDetails);
22 changes: 17 additions & 5 deletions src/account-info/AccountDetailsScreen.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
/* @flow strict-local */
import { connect } from 'react-redux';

import React, { PureComponent } from 'react';
import { connect } from 'react-redux';

import type { Dispatch, GlobalState, User } from '../types';
import { getAccountDetailsUserFromEmail } from '../selectors';
import { Screen } from '../common';
import { Screen, ZulipButton } from '../common';
import { IconPrivateChat } from '../common/Icons';
import { privateNarrow } from '../utils/narrow';
import AccountDetails from './AccountDetails';
import { doNarrow } from '../actions';

type Props = {|
user: User,
dispatch: Dispatch,
|};

class AccountDetailsScreen extends PureComponent<Props> {
handleChatPress = () => {
const { user, dispatch } = this.props;
dispatch(doNarrow(privateNarrow(user.email)));
};

render() {
const { dispatch, user } = this.props;
const { user } = this.props;
const title = {
text: '{_}',
values: {
Expand All @@ -26,7 +33,12 @@ class AccountDetailsScreen extends PureComponent<Props> {

return (
<Screen title={title}>
<AccountDetails dispatch={dispatch} user={user} />
<AccountDetails user={user} />
<ZulipButton
text="Send private message"
onPress={this.handleChatPress}
Icon={IconPrivateChat}
/>
</Screen>
);
}
Expand Down
44 changes: 44 additions & 0 deletions src/account-info/AwayStatusSwitch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* @flow strict-local */
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';

import type { Dispatch, GlobalState, User, UserStatusMapObject } from '../types';
import { OptionRow } from '../common';
import { getSelfUserDetail, getUserStatus } from '../selectors';
import { updateUserAwayStatus } from '../user-status/userStatusActions';

type PropsFromState = {|
selfUserDetail: User,
userStatus: UserStatusMapObject,
|};

type Props = {|
...PropsFromState,
dispatch: Dispatch,
|};

class AwayStatusSwitch extends PureComponent<Props> {
handleUpdateAwayStatus = (away: boolean) => {
const { dispatch } = this.props;
dispatch(updateUserAwayStatus(away));
};

render() {
const { selfUserDetail, userStatus } = this.props;
const selfUserStatus = userStatus[selfUserDetail.user_id];
const away = !!(selfUserStatus && selfUserStatus.away);

return (
<OptionRow
label="Set yourself to away"
defaultValue={away}
onValueChange={this.handleUpdateAwayStatus}
/>
);
}
}

export default connect((state: GlobalState) => ({
selfUserDetail: getSelfUserDetail(state),
userStatus: getUserStatus(state),
}))(AwayStatusSwitch);
58 changes: 58 additions & 0 deletions src/account-info/ProfileCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* @flow strict-local */
import React, { PureComponent } from 'react';
import { StyleSheet, View } from 'react-native';
import { connect } from 'react-redux';

import type { Dispatch, GlobalState, User } from '../types';
import { getSelfUserDetail } from '../selectors';
import { ZulipButton } from '../common';
import { navigateToUserStatus } from '../actions';
import AccountDetails from './AccountDetails';
import AwayStatusSwitch from './AwayStatusSwitch';
import SwitchAccountButton from './SwitchAccountButton';
import LogoutButton from './LogoutButton';

const componentStyles = StyleSheet.create({
accountButtons: {
alignItems: 'flex-end',
flexDirection: 'row',
marginHorizontal: 8,
},
});

type Props = {|
dispatch: Dispatch,
selfUserDetail: User,
|};

class ProfileCard extends PureComponent<Props> {
handleSetUserStatus = () => {
const { dispatch } = this.props;
dispatch(navigateToUserStatus());
};

render() {
const { selfUserDetail } = this.props;

return (
<View>
<AccountDetails user={selfUserDetail} />
<AwayStatusSwitch />
<ZulipButton
style={componentStyles.accountButtons}
secondary
text="Set a status"
onPress={this.handleSetUserStatus}
/>
<View style={componentStyles.accountButtons}>
<SwitchAccountButton />
<LogoutButton />
</View>
</View>
);
}
}

export default connect((state: GlobalState) => ({
selfUserDetail: getSelfUserDetail(state),
}))(ProfileCard);
34 changes: 34 additions & 0 deletions src/common/OwnAvatar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* @flow strict-local */
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';

import type { GlobalState, User } from '../types';
import { getCurrentRealm, getSelfUserDetail } from '../selectors';
import ImageAvatar from './ImageAvatar';
import { getAvatarFromUser } from '../utils/avatar';

type Props = {|
user: User,
size: number,
realm: string,
|};

/**
* Renders an image of the current user's avatar
*
* @prop [size] - Sets width and height in pixels.
* @prop [user] - Current presence for this user used to determine status.
* @prop [realm] - Current realm url, used if avatarUrl is relative.
*/
class OwnAvatar extends PureComponent<Props> {
render() {
const { user, size, realm } = this.props;
const fullAvatarUrl = getAvatarFromUser(user, realm);
return <ImageAvatar avatarUrl={fullAvatarUrl} size={size} shape="circle" />;
}
}

export default connect((state: GlobalState) => ({
realm: getCurrentRealm(state),
user: getSelfUserDetail(state),
}))(OwnAvatar);
1 change: 1 addition & 0 deletions src/common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export { default as OfflineNotice } from './OfflineNotice';
export { default as OptionButton } from './OptionButton';
export { default as OptionDivider } from './OptionDivider';
export { default as OptionRow } from './OptionRow';
export { default as OwnAvatar } from './OwnAvatar';
export { default as PasswordInput } from './PasswordInput';
export { default as Popup } from './Popup';
export { default as RawLabel } from './RawLabel';
Expand Down
4 changes: 2 additions & 2 deletions src/lightbox/Lightbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import LightboxHeader from './LightboxHeader';
import LightboxFooter from './LightboxFooter';
import { constructActionSheetButtons, executeActionSheetAction } from './LightboxActionSheet';
import { NAVBAR_SIZE } from '../styles';
import { getGravatarFromEmail } from '../utils/avatar';
import { getAvatarFromMessage } from '../utils/avatar';
import { navigateBack } from '../actions';

const styles = StyleSheet.create({
Expand Down Expand Up @@ -113,7 +113,7 @@ class Lightbox extends PureComponent<Props, State> {
<LightboxHeader
onPressBack={this.handlePressBack}
timestamp={message.timestamp}
avatarUrl={message.avatar_url || getGravatarFromEmail(message.sender_email)}
avatarUrl={getAvatarFromMessage(message)}
senderName={message.sender_full_name}
/>
</SlideAnimationView>
Expand Down
11 changes: 10 additions & 1 deletion src/main/MainTabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import HomeTab from './HomeTab';
import StreamTabs from './StreamTabs';
import PmConversationsCard from '../pm-conversations/PmConversationsCard';
import SettingsCard from '../settings/SettingsCard';
import { IconHome, IconStream, IconSettings } from '../common/Icons';
import { IconHome, IconSettings, IconStream } from '../common/Icons';
import { OwnAvatar } from '../common';
import IconUnreadConversations from '../nav/IconUnreadConversations';
import ProfileCard from '../account-info/ProfileCard';

export default TabNavigator(
{
Expand Down Expand Up @@ -50,6 +52,13 @@ export default TabNavigator(
),
},
},
profile: {
screen: ProfileCard,
navigationOptions: {
tabBarLabel: 'Profile',
tabBarIcon: (props: TabNavigationOptionsPropsType) => <OwnAvatar size={24} />,
},
},
},
{
backBehavior: 'none',
Expand Down
2 changes: 2 additions & 0 deletions src/nav/AppNavigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import WelcomeHelpScreen from '../start/WelcomeHelpScreen';
import WelcomeScreen from '../start/WelcomeScreen';
import EmojiPickerScreen from '../emoji/EmojiPickerScreen';
import LegalScreen from '../settings/LegalScreen';
import UserStatusScreen from '../user-status/UserStatusScreen';

export default StackNavigator(
{
Expand Down Expand Up @@ -68,6 +69,7 @@ export default StackNavigator(
'welcome-help': { screen: WelcomeHelpScreen },
welcome: { screen: WelcomeScreen },
legal: { screen: LegalScreen },
'user-status': { screen: UserStatusScreen },
},
{
initialRouteName: 'main',
Expand Down
3 changes: 3 additions & 0 deletions src/nav/navActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,6 @@ export const navigateToNotifications = (): NavigateAction =>

export const navigateToLegal = (): NavigateAction =>
NavigationActions.navigate({ routeName: 'legal' });

export const navigateToUserStatus = (): NavigateAction =>
NavigationActions.navigate({ routeName: 'user-status' });
17 changes: 2 additions & 15 deletions src/settings/SettingsCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@
import { connect } from 'react-redux';

import React, { PureComponent } from 'react';
import { StyleSheet, View, ScrollView } from 'react-native';
import { StyleSheet, ScrollView } from 'react-native';

import type { Dispatch, GlobalState } from '../types';
import { getSettings } from '../selectors';
import { OptionButton, OptionDivider, OptionRow } from '../common';
import SwitchAccountButton from '../account-info/SwitchAccountButton';
import LogoutButton from '../account-info/LogoutButton';
import { OptionButton, OptionRow } from '../common';
import {
IconDiagnostics,
IconNotifications,
Expand All @@ -28,12 +26,6 @@ const componentStyles = StyleSheet.create({
optionWrapper: {
flex: 1,
},
accountButtons: {
flex: 1,
alignItems: 'flex-end',
flexDirection: 'row',
marginTop: 8,
},
});

type Props = {|
Expand Down Expand Up @@ -86,11 +78,6 @@ class SettingsCard extends PureComponent<Props> {
dispatch(navigateToLegal());
}}
/>
<OptionDivider />
<View style={componentStyles.accountButtons}>
<SwitchAccountButton />
<LogoutButton />
</View>
</ScrollView>
);
}
Expand Down

0 comments on commit 9afbde3

Please sign in to comment.