[IMPROVEMENT] Support badge number on header buttons (#2566)

* Beginning header buttons refactor

* Add HeaderButtons

* item with title

* Refactor

* Remove lib

* Refactor

* Update snapshot

* Refactor

* Update tests

* Lint
This commit is contained in:
Diego Mello 2020-10-30 13:15:58 -03:00 committed by GitHub
parent 7cccd02cb3
commit 81bb89da6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 4553 additions and 332 deletions

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,7 @@ export const SWITCH_TRACK_COLOR = {
const mentions = {
unreadBackground: '#6C727A',
tunreadBackground: '#1d74f5',
mentionMeColor: '#DB0C27',
mentionMeBackground: '#F5455C',
mentionGroupColor: '#E26D0E',

View File

@ -5,6 +5,7 @@ import { View, StyleSheet } from 'react-native';
import { themes } from '../../constants/colors';
import { themedHeader } from '../../utils/navigation';
import { isIOS, isTablet } from '../../utils/deviceInfo';
import { withTheme } from '../../theme';
// Get from https://github.com/react-navigation/react-navigation/blob/master/packages/stack/src/views/Header/HeaderSegment.tsx#L69
export const headerHeight = isIOS ? 44 : 56;
@ -53,4 +54,4 @@ Header.propTypes = {
headerRight: PropTypes.element
};
export default Header;
export default withTheme(Header);

View File

@ -1,107 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { HeaderButtons, HeaderButton, Item } from 'react-navigation-header-buttons';
import { CustomIcon } from '../lib/Icons';
import { isIOS } from '../utils/deviceInfo';
import { themes } from '../constants/colors';
import I18n from '../i18n';
import { withTheme } from '../theme';
export const headerIconSize = 23;
const CustomHeaderButton = React.memo(withTheme(({ theme, ...props }) => (
<HeaderButton
{...props}
IconComponent={CustomIcon}
iconSize={headerIconSize}
color={themes[theme].headerTintColor}
/>
)));
export const CustomHeaderButtons = React.memo(props => (
<HeaderButtons
HeaderButtonComponent={CustomHeaderButton}
{...props}
/>
));
export const DrawerButton = React.memo(({ navigation, testID, ...otherProps }) => (
<CustomHeaderButtons left>
<Item title='drawer' iconName='hamburguer' onPress={navigation.toggleDrawer} testID={testID} {...otherProps} />
</CustomHeaderButtons>
));
export const CloseModalButton = React.memo(({
navigation, testID, onPress = () => navigation.pop(), ...props
}) => (
<CustomHeaderButtons left>
<Item title='close' iconName='close' onPress={onPress} testID={testID} {...props} />
</CustomHeaderButtons>
));
export const CancelModalButton = React.memo(({ onPress, testID }) => (
<CustomHeaderButtons left>
{isIOS
? <Item title={I18n.t('Cancel')} onPress={onPress} testID={testID} />
: <Item title='close' iconName='close' onPress={onPress} testID={testID} />
}
</CustomHeaderButtons>
));
export const MoreButton = React.memo(({ onPress, testID }) => (
<CustomHeaderButtons>
<Item title='more' iconName='kebab' onPress={onPress} testID={testID} />
</CustomHeaderButtons>
));
export const SaveButton = React.memo(({ onPress, testID, ...props }) => (
<CustomHeaderButtons>
<Item title='save' iconName='download' onPress={onPress} testID={testID} {...props} />
</CustomHeaderButtons>
));
export const PreferencesButton = React.memo(({ onPress, testID, ...props }) => (
<CustomHeaderButtons>
<Item title='preferences' iconName='settings' onPress={onPress} testID={testID} {...props} />
</CustomHeaderButtons>
));
export const LegalButton = React.memo(({ navigation, testID }) => (
<MoreButton onPress={() => navigation.navigate('LegalView')} testID={testID} />
));
CustomHeaderButton.propTypes = {
theme: PropTypes.string
};
DrawerButton.propTypes = {
navigation: PropTypes.object.isRequired,
testID: PropTypes.string.isRequired
};
CloseModalButton.propTypes = {
navigation: PropTypes.object.isRequired,
testID: PropTypes.string.isRequired,
onPress: PropTypes.func
};
CancelModalButton.propTypes = {
onPress: PropTypes.func.isRequired,
testID: PropTypes.string.isRequired
};
MoreButton.propTypes = {
onPress: PropTypes.func.isRequired,
testID: PropTypes.string.isRequired
};
SaveButton.propTypes = {
onPress: PropTypes.func.isRequired,
testID: PropTypes.string.isRequired
};
PreferencesButton.propTypes = {
onPress: PropTypes.func.isRequired,
testID: PropTypes.string.isRequired
};
LegalButton.propTypes = {
navigation: PropTypes.object.isRequired,
testID: PropTypes.string.isRequired
};
export { Item };

View File

@ -0,0 +1,84 @@
import React from 'react';
import PropTypes from 'prop-types';
import { isIOS } from '../../utils/deviceInfo';
import I18n from '../../i18n';
import Container from './HeaderButtonContainer';
import Item from './HeaderButtonItem';
// Left
export const Drawer = React.memo(({ navigation, testID, ...props }) => (
<Container left>
<Item iconName='hamburguer' onPress={() => navigation.toggleDrawer()} testID={testID} {...props} />
</Container>
));
export const CloseModal = React.memo(({
navigation, testID, onPress = () => navigation.pop(), ...props
}) => (
<Container left>
<Item iconName='close' onPress={onPress} testID={testID} {...props} />
</Container>
));
export const CancelModal = React.memo(({ onPress, testID }) => (
<Container left>
{isIOS
? <Item title={I18n.t('Cancel')} onPress={onPress} testID={testID} />
: <Item iconName='close' onPress={onPress} testID={testID} />
}
</Container>
));
// Right
export const More = React.memo(({ onPress, testID }) => (
<Container>
<Item iconName='kebab' onPress={onPress} testID={testID} />
</Container>
));
export const Download = React.memo(({ onPress, testID, ...props }) => (
<Container>
<Item iconName='download' onPress={onPress} testID={testID} {...props} />
</Container>
));
export const Preferences = React.memo(({ onPress, testID, ...props }) => (
<Container>
<Item iconName='settings' onPress={onPress} testID={testID} {...props} />
</Container>
));
export const Legal = React.memo(({ navigation, testID }) => (
<More onPress={() => navigation.navigate('LegalView')} testID={testID} />
));
Drawer.propTypes = {
navigation: PropTypes.object.isRequired,
testID: PropTypes.string.isRequired
};
CloseModal.propTypes = {
navigation: PropTypes.object.isRequired,
testID: PropTypes.string.isRequired,
onPress: PropTypes.func
};
CancelModal.propTypes = {
onPress: PropTypes.func.isRequired,
testID: PropTypes.string.isRequired
};
More.propTypes = {
onPress: PropTypes.func.isRequired,
testID: PropTypes.string.isRequired
};
Download.propTypes = {
onPress: PropTypes.func.isRequired,
testID: PropTypes.string.isRequired
};
Preferences.propTypes = {
onPress: PropTypes.func.isRequired,
testID: PropTypes.string.isRequired
};
Legal.propTypes = {
navigation: PropTypes.object.isRequired,
testID: PropTypes.string.isRequired
};

View File

@ -0,0 +1,36 @@
import React from 'react';
import { View, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center'
},
left: {
marginLeft: 5
},
right: {
marginRight: 5
}
});
const Container = ({ children, left }) => (
<View style={[styles.container, left ? styles.left : styles.right]}>
{children}
</View>
);
Container.propTypes = {
children: PropTypes.arrayOf(PropTypes.element),
left: PropTypes.bool
};
Container.defaultProps = {
left: false
};
Container.displayName = 'HeaderButton.Container';
export default Container;

View File

@ -0,0 +1,58 @@
import React from 'react';
import { Text, StyleSheet, Platform } from 'react-native';
import PropTypes from 'prop-types';
import Touchable from 'react-native-platform-touchable';
import { CustomIcon } from '../../lib/Icons';
import { withTheme } from '../../theme';
import { themes } from '../../constants/colors';
import sharedStyles from '../../views/Styles';
export const BUTTON_HIT_SLOP = {
top: 5, right: 5, bottom: 5, left: 5
};
const styles = StyleSheet.create({
container: {
marginHorizontal: 6
},
title: {
...Platform.select({
android: {
fontSize: 14
},
default: {
fontSize: 17
}
}),
...sharedStyles.textRegular
}
});
const Item = ({
title, iconName, onPress, testID, theme, badge
}) => (
<Touchable onPress={onPress} testID={testID} hitSlop={BUTTON_HIT_SLOP} style={styles.container}>
<>
{
iconName
? <CustomIcon name={iconName} size={24} color={themes[theme].headerTintColor} />
: <Text style={[styles.title, { color: themes[theme].headerTintColor }]}>{title}</Text>
}
{badge ? badge() : null}
</>
</Touchable>
);
Item.propTypes = {
onPress: PropTypes.func.isRequired,
title: PropTypes.string,
iconName: PropTypes.string,
testID: PropTypes.string,
theme: PropTypes.string,
badge: PropTypes.func
};
Item.displayName = 'HeaderButton.Item';
export default withTheme(Item);

View File

@ -0,0 +1,26 @@
import React from 'react';
import { StyleSheet } from 'react-native';
import UnreadBadge from '../../presentation/UnreadBadge';
const styles = StyleSheet.create({
badgeContainer: {
padding: 2,
position: 'absolute',
right: -3,
top: -3,
borderRadius: 10,
alignItems: 'center',
justifyContent: 'center'
}
});
export const Badge = ({ ...props }) => (
<UnreadBadge
{...props}
style={styles.badgeContainer}
small
/>
);
export default Badge;

View File

@ -0,0 +1,4 @@
export { default as Container } from './HeaderButtonContainer';
export { default as Item } from './HeaderButtonItem';
export { default as Badge } from './HeaderButtonItemBadge';
export * from './Common';

View File

@ -15,7 +15,7 @@ import SafeAreaView from '../../../containers/SafeAreaView';
import { themes } from '../../../constants/colors';
import StatusBar from '../../../containers/StatusBar';
import { goRoom } from '../../../utils/goRoom';
import { CloseModalButton } from '../../../containers/HeaderButton';
import * as HeaderButton from '../../../containers/HeaderButton';
import RocketChat from '../../../lib/rocketchat';
import { logEvent, events } from '../../../utils/log';
import { getInquiryQueueSelector } from '../selectors/inquiry';
@ -34,7 +34,7 @@ class QueueListView extends React.Component {
title: I18n.t('Queued_chats')
};
if (isMasterDetail) {
options.headerLeft = () => <CloseModalButton navigation={navigation} testID='directory-view-close' />;
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} testID='directory-view-close' />;
}
return options;
}

View File

@ -37,6 +37,7 @@ const RoomItem = ({
alert,
hideUnreadStatus,
unread,
tunread,
userMentions,
groupMentions,
roomUpdatedAt,
@ -112,6 +113,7 @@ const RoomItem = ({
/>
<UnreadBadge
unread={unread}
tunread={tunread}
userMentions={userMentions}
groupMentions={groupMentions}
theme={theme}
@ -136,6 +138,7 @@ const RoomItem = ({
/>
<UnreadBadge
unread={unread}
tunread={tunread}
userMentions={userMentions}
groupMentions={groupMentions}
theme={theme}
@ -174,6 +177,7 @@ RoomItem.propTypes = {
alert: PropTypes.bool,
hideUnreadStatus: PropTypes.bool,
unread: PropTypes.number,
tunread: PropTypes.array,
userMentions: PropTypes.number,
groupMentions: PropTypes.number,
roomUpdatedAt: PropTypes.instanceOf(Date),

View File

@ -228,6 +228,7 @@ class RoomItemContainer extends React.Component {
username={username}
useRealName={useRealName}
unread={item.unread}
tunread={item.tunread}
groupMentions={item.groupMentions}
avatarETag={avatarETag || item.avatarETag}
swipeEnabled={swipeEnabled}

View File

@ -1,73 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { View, Text, StyleSheet } from 'react-native';
import sharedStyles from '../views/Styles';
import { themes } from '../constants/colors';
const styles = StyleSheet.create({
unreadNumberContainer: {
minWidth: 21,
height: 21,
paddingVertical: 3,
paddingHorizontal: 5,
borderRadius: 10.5,
alignItems: 'center',
justifyContent: 'center',
marginLeft: 10
},
unreadText: {
overflow: 'hidden',
fontSize: 13,
...sharedStyles.textMedium,
letterSpacing: 0.56,
textAlign: 'center'
}
});
const UnreadBadge = React.memo(({
theme, unread, userMentions, groupMentions, style
}) => {
if (!unread || unread <= 0) {
return;
}
if (unread >= 1000) {
unread = '999+';
}
let backgroundColor = themes[theme].unreadBackground;
const color = themes[theme].buttonText;
if (userMentions > 0) {
backgroundColor = themes[theme].mentionMeBackground;
} else if (groupMentions > 0) {
backgroundColor = themes[theme].mentionGroupBackground;
}
return (
<View
style={[
styles.unreadNumberContainer,
{ backgroundColor },
style
]}
>
<Text
style={[
styles.unreadText,
{ color }
]}
>{unread}
</Text>
</View>
);
});
UnreadBadge.propTypes = {
theme: PropTypes.string,
unread: PropTypes.number,
userMentions: PropTypes.number,
groupMentions: PropTypes.number,
style: PropTypes.object
};
export default UnreadBadge;

View File

@ -0,0 +1,23 @@
import { themes } from '../../constants/colors';
export const getUnreadStyle = ({
unread, userMentions, groupMentions, theme, tunread, tunreadUser, tunreadGroup
}) => {
if ((!unread || unread <= 0) && (!tunread?.length)) {
return {};
}
let backgroundColor = themes[theme].unreadBackground;
const color = themes[theme].buttonText;
if (userMentions > 0 || tunreadUser?.length) {
backgroundColor = themes[theme].mentionMeColor;
} else if (groupMentions > 0 || tunreadGroup?.length) {
backgroundColor = themes[theme].mentionGroupColor;
} else if (tunread?.length > 0) {
backgroundColor = themes[theme].tunreadBackground;
}
return {
backgroundColor, color
};
};

View File

@ -0,0 +1,76 @@
/* eslint-disable no-undef */
import { themes } from '../../constants/colors';
import { getUnreadStyle } from './getUnreadStyle';
const testsForTheme = (theme) => {
const getUnreadStyleUtil = ({ ...props }) => getUnreadStyle({ theme, ...props });
test('render unread', () => {
expect(getUnreadStyleUtil({
unread: 1
})).toEqual({
backgroundColor: themes[theme].unreadBackground,
color: themes[theme].buttonText
});
});
test('render thread unread', () => {
expect(getUnreadStyleUtil({
tunread: [1]
})).toEqual({
backgroundColor: themes[theme].tunreadBackground,
color: themes[theme].buttonText
});
});
test('render user mention', () => {
expect(getUnreadStyleUtil({
unread: 1,
userMentions: 1
})).toEqual({
backgroundColor: themes[theme].mentionMeColor,
color: themes[theme].buttonText
});
});
test('render group mention', () => {
expect(getUnreadStyleUtil({
unread: 1,
groupMentions: 1
})).toEqual({
backgroundColor: themes[theme].mentionGroupColor,
color: themes[theme].buttonText
});
});
test('mentions priority', () => {
expect(getUnreadStyleUtil({
unread: 1,
userMentions: 1,
groupMentions: 1,
tunread: [1]
})).toEqual({
backgroundColor: themes[theme].mentionMeColor,
color: themes[theme].buttonText
});
expect(getUnreadStyleUtil({
unread: 1,
groupMentions: 1,
tunread: [1]
})).toEqual({
backgroundColor: themes[theme].mentionGroupColor,
color: themes[theme].buttonText
});
expect(getUnreadStyleUtil({
unread: 1,
tunread: [1]
})).toEqual({
backgroundColor: themes[theme].tunreadBackground,
color: themes[theme].buttonText
});
});
};
describe('getUnreadStyle light theme', () => testsForTheme('light'));
describe('getUnreadStyle dark theme', () => testsForTheme('dark'));
describe('getUnreadStyle black theme', () => testsForTheme('black'));

View File

@ -0,0 +1,95 @@
import React from 'react';
import PropTypes from 'prop-types';
import { View, Text, StyleSheet } from 'react-native';
import sharedStyles from '../../views/Styles';
import { getUnreadStyle } from './getUnreadStyle';
import { withTheme } from '../../theme';
const styles = StyleSheet.create({
unreadNumberContainerNormal: {
height: 21,
paddingVertical: 3,
paddingHorizontal: 5,
borderRadius: 10.5,
alignItems: 'center',
justifyContent: 'center',
marginLeft: 10
},
unreadNumberContainerSmall: {
borderRadius: 10.5,
alignItems: 'center',
justifyContent: 'center'
},
unreadText: {
// overflow: 'hidden',
fontSize: 13,
...sharedStyles.textSemibold,
fontWeight: '600'
},
textSmall: {
fontSize: 10
}
});
const UnreadBadge = React.memo(({
theme, unread, userMentions, groupMentions, style, tunread, tunreadUser, tunreadGroup, small
}) => {
if ((!unread || unread <= 0) && (!tunread?.length)) {
return;
}
const { backgroundColor, color } = getUnreadStyle({
theme, unread, userMentions, groupMentions, tunread, tunreadUser, tunreadGroup
});
if (!backgroundColor) {
return null;
}
let text = unread || tunread?.length;
if (small && text >= 100) {
text = '+99';
}
if (!small && text >= 1000) {
text = '+999';
}
text = text.toString();
let minWidth = 21;
if (small) {
minWidth = 11 + text.length * 5;
}
return (
<View
style={[
small ? styles.unreadNumberContainerSmall : styles.unreadNumberContainerNormal,
{ backgroundColor, minWidth },
style
]}
>
<Text
style={[
styles.unreadText,
small && styles.textSmall,
{ color }
]}
numberOfLines={1}
>{text}
</Text>
</View>
);
});
UnreadBadge.propTypes = {
theme: PropTypes.string,
unread: PropTypes.number,
userMentions: PropTypes.number,
groupMentions: PropTypes.number,
style: PropTypes.object,
tunread: PropTypes.array,
tunreadUser: PropTypes.array,
tunreadGroup: PropTypes.array,
small: PropTypes.bool
};
export default withTheme(UnreadBadge);

View File

@ -5,14 +5,14 @@ import { connect } from 'react-redux';
import I18n from '../../i18n';
import StatusBar from '../../containers/StatusBar';
import { DrawerButton } from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
import { withTheme } from '../../theme';
import { getUserSelector } from '../../selectors/login';
import SafeAreaView from '../../containers/SafeAreaView';
class AdminPanelView extends React.Component {
static navigationOptions = ({ navigation, isMasterDetail }) => ({
headerLeft: isMasterDetail ? undefined : () => <DrawerButton navigation={navigation} />,
headerLeft: isMasterDetail ? undefined : () => <HeaderButton.Drawer navigation={navigation} />,
title: I18n.t('Admin_Panel')
})

View File

@ -17,7 +17,7 @@ import { ImageViewer } from '../presentation/ImageViewer';
import { themes } from '../constants/colors';
import { formatAttachmentUrl } from '../lib/utils';
import RCActivityIndicator from '../containers/ActivityIndicator';
import { SaveButton, CloseModalButton } from '../containers/HeaderButton';
import * as HeaderButton from '../containers/HeaderButton';
import { isAndroid } from '../utils/deviceInfo';
import { getUserSelector } from '../selectors/login';
import { withDimensions } from '../dimensions';
@ -81,10 +81,10 @@ class AttachmentView extends React.Component {
}
const options = {
title,
headerLeft: () => <CloseModalButton testID='close-attachment-view' navigation={navigation} buttonStyle={{ color: themes[theme].previewTintColor }} />,
headerLeft: () => <HeaderButton.CloseModal testID='close-attachment-view' navigation={navigation} buttonStyle={{ color: themes[theme].previewTintColor }} />,
headerRight: () => (
Allow_Save_Media_to_Gallery
? <SaveButton testID='save-image' onPress={this.handleSave} buttonStyle={{ color: themes[theme].previewTintColor }} />
? <HeaderButton.Download testID='save-image' onPress={this.handleSave} buttonStyle={{ color: themes[theme].previewTintColor }} />
: null
),
headerBackground: () => <View style={{ flex: 1, backgroundColor: themes[theme].previewBackground }} />,

View File

@ -10,7 +10,7 @@ import StatusBar from '../containers/StatusBar';
import ActivityIndicator from '../containers/ActivityIndicator';
import { withTheme } from '../theme';
import debounce from '../utils/debounce';
import { CloseModalButton } from '../containers/HeaderButton';
import * as HeaderButton from '../containers/HeaderButton';
const userAgent = isIOS
? 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1'
@ -185,7 +185,7 @@ const mapStateToProps = state => ({
AuthenticationWebView.navigationOptions = ({ route, navigation }) => {
const { authType } = route.params;
return {
headerLeft: () => <CloseModalButton navigation={navigation} />,
headerLeft: () => <HeaderButton.CloseModal navigation={navigation} />,
title: ['saml', 'cas', 'iframe'].includes(authType) ? 'SSO' : 'OAuth'
};
};

View File

@ -15,7 +15,7 @@ import KeyboardView from '../presentation/KeyboardView';
import scrollPersistTaps from '../utils/scrollPersistTaps';
import I18n from '../i18n';
import UserItem from '../presentation/UserItem';
import { CustomHeaderButtons, Item } from '../containers/HeaderButton';
import * as HeaderButton from '../containers/HeaderButton';
import StatusBar from '../containers/StatusBar';
import { SWITCH_TRACK_COLOR, themes } from '../constants/colors';
import { withTheme } from '../theme';
@ -143,9 +143,9 @@ class CreateChannelView extends React.Component {
const { navigation } = this.props;
navigation.setOptions({
headerRight: () => channelName.trim().length > 0 && (
<CustomHeaderButtons>
<Item title={I18n.t('Create')} onPress={this.submit} testID='create-channel-submit' />
</CustomHeaderButtons>
<HeaderButton.Container>
<HeaderButton.Item title={I18n.t('Create')} onPress={this.submit} testID='create-channel-submit' />
</HeaderButton.Container>
)
});
}

View File

@ -8,7 +8,7 @@ import Loading from '../../containers/Loading';
import KeyboardView from '../../presentation/KeyboardView';
import scrollPersistTaps from '../../utils/scrollPersistTaps';
import I18n from '../../i18n';
import { CustomHeaderButtons, Item, CloseModalButton } from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
import StatusBar from '../../containers/StatusBar';
import { themes } from '../../constants/colors';
import { withTheme } from '../../theme';
@ -96,13 +96,13 @@ class CreateChannelView extends React.Component {
headerRight: (
this.valid()
? () => (
<CustomHeaderButtons>
<Item title={I18n.t('Create')} onPress={this.submit} testID='create-discussion-submit' />
</CustomHeaderButtons>
<HeaderButton.Container>
<HeaderButton.Item title={I18n.t('Create')} onPress={this.submit} testID='create-discussion-submit' />
</HeaderButton.Container>
)
: null
),
headerLeft: showCloseModal ? () => <CloseModalButton navigation={navigation} /> : undefined
headerLeft: showCloseModal ? () => <HeaderButton.CloseModal navigation={navigation} /> : undefined
});
}

View File

@ -14,7 +14,7 @@ import SearchBox from '../../containers/SearchBox';
import { CustomIcon } from '../../lib/Icons';
import StatusBar from '../../containers/StatusBar';
import ActivityIndicator from '../../containers/ActivityIndicator';
import { CloseModalButton } from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
import debounce from '../../utils/debounce';
import log, { logEvent, events } from '../../utils/log';
import Options from './Options';
@ -31,7 +31,7 @@ class DirectoryView extends React.Component {
title: I18n.t('Directory')
};
if (isMasterDetail) {
options.headerLeft = () => <CloseModalButton navigation={navigation} testID='directory-view-close' />;
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} testID='directory-view-close' />;
}
return options;
}

View File

@ -10,7 +10,7 @@ import Button from '../containers/Button';
import { themes } from '../constants/colors';
import TextInput from '../containers/TextInput';
import SafeAreaView from '../containers/SafeAreaView';
import { CloseModalButton } from '../containers/HeaderButton';
import * as HeaderButton from '../containers/HeaderButton';
import { encryptionDecodeKey as encryptionDecodeKeyAction } from '../actions/encryption';
import scrollPersistTaps from '../utils/scrollPersistTaps';
import KeyboardView from '../presentation/KeyboardView';
@ -29,7 +29,7 @@ const styles = StyleSheet.create({
});
class E2EEnterYourPasswordView extends React.Component {
static navigationOptions = ({ navigation }) => ({
headerLeft: () => <CloseModalButton navigation={navigation} testID='e2e-enter-your-password-view-close' />,
headerLeft: () => <HeaderButton.CloseModal navigation={navigation} testID='e2e-enter-your-password-view-close' />,
title: I18n.t('Enter_Your_E2E_Password')
})

View File

@ -4,7 +4,7 @@ import { StyleSheet } from 'react-native';
import SafeAreaView from '../containers/SafeAreaView';
import { themes } from '../constants/colors';
import { CloseModalButton } from '../containers/HeaderButton';
import * as HeaderButton from '../containers/HeaderButton';
import Markdown from '../containers/markdown';
import { withTheme } from '../theme';
import I18n from '../i18n';
@ -26,7 +26,7 @@ class E2EHowItWorksView extends React.Component {
const showCloseModal = route.params?.showCloseModal;
return {
title: I18n.t('How_It_Works'),
headerLeft: showCloseModal ? () => <CloseModalButton navigation={navigation} /> : undefined
headerLeft: showCloseModal ? () => <HeaderButton.CloseModal navigation={navigation} /> : undefined
};
}

View File

@ -11,7 +11,7 @@ import {
import { encryptionSetBanner as encryptionSetBannerAction } from '../actions/encryption';
import { E2E_RANDOM_PASSWORD_KEY } from '../lib/encryption/constants';
import { CloseModalButton } from '../containers/HeaderButton';
import * as HeaderButton from '../containers/HeaderButton';
import scrollPersistTaps from '../utils/scrollPersistTaps';
import SafeAreaView from '../containers/SafeAreaView';
import UserPreferences from '../lib/userPreferences';
@ -61,7 +61,7 @@ const styles = StyleSheet.create({
class E2ESaveYourPasswordView extends React.Component {
static navigationOptions = ({ navigation }) => ({
headerLeft: () => <CloseModalButton navigation={navigation} testID='e2e-save-your-password-view-close' />,
headerLeft: () => <HeaderButton.CloseModal navigation={navigation} testID='e2e-save-your-password-view-close' />,
title: I18n.t('Save_Your_E2E_Password')
})

View File

@ -9,7 +9,7 @@ import equal from 'deep-equal';
import sharedStyles from './Styles';
import Button from '../containers/Button';
import I18n from '../i18n';
import { LegalButton } from '../containers/HeaderButton';
import * as HeaderButton from '../containers/HeaderButton';
import { themes } from '../constants/colors';
import { withTheme } from '../theme';
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
@ -51,7 +51,7 @@ const styles = StyleSheet.create({
class LoginView extends React.Component {
static navigationOptions = ({ route, navigation }) => ({
title: route.params?.title ?? 'Rocket.Chat',
headerRight: () => <LegalButton testID='login-view-more' navigation={navigation} />
headerRight: () => <HeaderButton.Legal testID='login-view-more' navigation={navigation} />
})
static propTypes = {

View File

@ -8,7 +8,7 @@ import { KeyboardAwareScrollView } from '@codler/react-native-keyboard-aware-scr
import { withTheme } from '../theme';
import EventEmitter from '../utils/events';
import { themes } from '../constants/colors';
import { CustomHeaderButtons, Item } from '../containers/HeaderButton';
import * as HeaderButton from '../containers/HeaderButton';
import { modalBlockWithContext } from '../containers/UIKit/MessageBlock';
import RocketChat from '../lib/rocketchat';
import ActivityIndicator from '../containers/ActivityIndicator';
@ -128,24 +128,24 @@ class ModalBlockView extends React.Component {
navigation.setOptions({
title: textParser([title]),
headerLeft: close ? () => (
<CustomHeaderButtons>
<Item
<HeaderButton.Container>
<HeaderButton.Item
title={textParser([close.text])}
style={styles.submit}
onPress={this.cancel}
testID='close-modal-uikit'
/>
</CustomHeaderButtons>
</HeaderButton.Container>
) : null,
headerRight: submit ? () => (
<CustomHeaderButtons>
<Item
<HeaderButton.Container>
<HeaderButton.Item
title={textParser([submit.text])}
style={styles.submit}
onPress={this.submit}
testID='submit-modal-uikit'
/>
</CustomHeaderButtons>
</HeaderButton.Container>
) : null
});
}

View File

@ -17,7 +17,7 @@ import I18n from '../i18n';
import log, { logEvent, events } from '../utils/log';
import SearchBox from '../containers/SearchBox';
import { CustomIcon } from '../lib/Icons';
import { CloseModalButton } from '../containers/HeaderButton';
import * as HeaderButton from '../containers/HeaderButton';
import StatusBar from '../containers/StatusBar';
import { themes } from '../constants/colors';
import { withTheme } from '../theme';
@ -51,7 +51,7 @@ const styles = StyleSheet.create({
class NewMessageView extends React.Component {
static navigationOptions = ({ navigation }) => ({
headerLeft: () => <CloseModalButton navigation={navigation} testID='new-message-view-close' />,
headerLeft: () => <HeaderButton.CloseModal navigation={navigation} testID='new-message-view-close' />,
title: I18n.t('New_Message')
})

View File

@ -26,7 +26,7 @@ import log, { logEvent, events } from '../../utils/log';
import { animateNextTransition } from '../../utils/layoutAnimation';
import { withTheme } from '../../theme';
import { setBasicAuth, BASIC_AUTH_KEY } from '../../utils/fetch';
import { CloseModalButton } from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
import { showConfirmationAlert } from '../../utils/info';
import database from '../../lib/database';
import ServerInput from './ServerInput';
@ -111,7 +111,7 @@ class NewServerView extends React.Component {
const { adding, navigation } = this.props;
if (adding) {
navigation.setOptions({
headerLeft: () => <CloseModalButton navigation={navigation} onPress={this.close} testID='new-server-view-close' />
headerLeft: () => <HeaderButton.CloseModal navigation={navigation} onPress={this.close} testID='new-server-view-close' />
});
}
}

View File

@ -24,7 +24,7 @@ import Button from '../../containers/Button';
import Avatar from '../../containers/Avatar';
import { setUser as setUserAction } from '../../actions/login';
import { CustomIcon } from '../../lib/Icons';
import { DrawerButton, PreferencesButton } from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
import StatusBar from '../../containers/StatusBar';
import { themes } from '../../constants/colors';
import { withTheme } from '../../theme';
@ -37,10 +37,10 @@ class ProfileView extends React.Component {
title: I18n.t('Profile')
};
if (!isMasterDetail) {
options.headerLeft = () => <DrawerButton navigation={navigation} />;
options.headerLeft = () => <HeaderButton.Drawer navigation={navigation} />;
}
options.headerRight = () => (
<PreferencesButton onPress={() => navigation.navigate('UserPreferencesView')} testID='preferences-view-open' />
<HeaderButton.Preferences onPress={() => navigation.navigate('UserPreferencesView')} testID='preferences-view-open' />
);
return options;
}

View File

@ -8,7 +8,7 @@ import { connect } from 'react-redux';
import Avatar from '../../containers/Avatar';
import styles from './styles';
import ActivityIndicator from '../../containers/ActivityIndicator';
import { CloseModalButton } from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
import I18n from '../../i18n';
import RocketChat from '../../lib/rocketchat';
import StatusBar from '../../containers/StatusBar';
@ -22,7 +22,7 @@ class ReadReceiptView extends React.Component {
title: I18n.t('Read_Receipt')
};
if (isMasterDetail) {
options.headerLeft = () => <CloseModalButton navigation={navigation} testID='read-receipt-view-close' />;
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} testID='read-receipt-view-close' />;
}
return options;
}

View File

@ -10,7 +10,7 @@ import log, { logEvent, events } from '../utils/log';
import sharedStyles from './Styles';
import Button from '../containers/Button';
import I18n from '../i18n';
import { LegalButton } from '../containers/HeaderButton';
import * as HeaderButton from '../containers/HeaderButton';
import { themes } from '../constants/colors';
import { withTheme } from '../theme';
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
@ -54,7 +54,7 @@ const styles = StyleSheet.create({
class RegisterView extends React.Component {
static navigationOptions = ({ route, navigation }) => ({
title: route.params?.title ?? 'Rocket.Chat',
headerRight: () => <LegalButton testID='register-view-more' navigation={navigation} />
headerRight: () => <HeaderButton.Legal testID='register-view-more' navigation={navigation} />
});
static propTypes = {

View File

@ -21,7 +21,7 @@ import I18n from '../../i18n';
import StatusBar from '../../containers/StatusBar';
import { themes, SWITCH_TRACK_COLOR } from '../../constants/colors';
import { withTheme } from '../../theme';
import { CloseModalButton } from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
import Markdown from '../../containers/markdown';
import { showConfirmationAlert, showErrorAlert } from '../../utils/info';
import SafeAreaView from '../../containers/SafeAreaView';
@ -36,7 +36,7 @@ class RoomActionsView extends React.Component {
title: I18n.t('Actions')
};
if (isMasterDetail) {
options.headerLeft = () => <CloseModalButton navigation={navigation} testID='room-actions-view-close' />;
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} testID='room-actions-view-close' />;
}
return options;
}

View File

@ -15,7 +15,7 @@ import sharedStyles from '../Styles';
import RocketChat from '../../lib/rocketchat';
import RoomTypeIcon from '../../containers/RoomTypeIcon';
import I18n from '../../i18n';
import { CustomHeaderButtons, CloseModalButton } from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
import StatusBar from '../../containers/StatusBar';
import log, { logEvent, events } from '../../utils/log';
import { themes } from '../../constants/colors';
@ -26,7 +26,6 @@ import EventEmitter from '../../utils/events';
import Livechat from './Livechat';
import Channel from './Channel';
import Item from './Item';
import Direct from './Direct';
import SafeAreaView from '../../containers/SafeAreaView';
import { goRoom } from '../../utils/goRoom';
@ -104,12 +103,12 @@ class RoomInfoView extends React.Component {
const rid = route.params?.rid;
const showCloseModal = route.params?.showCloseModal;
navigation.setOptions({
headerLeft: showCloseModal ? () => <CloseModalButton navigation={navigation} /> : undefined,
headerLeft: showCloseModal ? () => <HeaderButton.CloseModal navigation={navigation} /> : undefined,
title: t === 'd' ? I18n.t('User_Info') : I18n.t('Room_Info'),
headerRight: showEdit
? () => (
<CustomHeaderButtons>
<Item
<HeaderButton.Container>
<HeaderButton.Item
iconName='edit'
onPress={() => {
const isLivechat = t === 'l';
@ -118,7 +117,7 @@ class RoomInfoView extends React.Component {
}}
testID='room-info-view-edit-button'
/>
</CustomHeaderButtons>
</HeaderButton.Container>
)
: null
});

View File

@ -15,7 +15,7 @@ import log from '../../utils/log';
import I18n from '../../i18n';
import SearchBox from '../../containers/SearchBox';
import protectedFunction from '../../lib/methods/helpers/protectedFunction';
import { CustomHeaderButtons, Item } from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
import StatusBar from '../../containers/StatusBar';
import ActivityIndicator from '../../containers/ActivityIndicator';
import { withTheme } from '../../theme';
@ -97,9 +97,9 @@ class RoomMembersView extends React.Component {
navigation.setOptions({
title: I18n.t('Members'),
headerRight: () => (
<CustomHeaderButtons>
<Item title={toggleText} onPress={this.toggleStatus} testID='room-members-view-toggle-status' />
</CustomHeaderButtons>
<HeaderButton.Container>
<HeaderButton.Item title={toggleText} onPress={this.toggleStatus} testID='room-members-view-toggle-status' />
</HeaderButton.Container>
)
});
}

View File

@ -2,11 +2,12 @@ import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { CustomHeaderButtons, Item } from '../../../containers/HeaderButton';
import * as HeaderButton from '../../../containers/HeaderButton';
import database from '../../../lib/database';
import { getUserSelector } from '../../../selectors/login';
import { logEvent, events } from '../../../utils/log';
class RightButtonsContainer extends React.PureComponent {
static propTypes = {
userId: PropTypes.string,
@ -99,33 +100,30 @@ class RightButtonsContainer extends React.PureComponent {
}
if (tmid) {
return (
<CustomHeaderButtons>
<Item
title='bell'
<HeaderButton.Container>
<HeaderButton.Item
iconName={isFollowingThread ? 'notification' : 'notification-disabled'}
onPress={this.toggleFollowThread}
testID={isFollowingThread ? 'room-view-header-unfollow' : 'room-view-header-follow'}
/>
</CustomHeaderButtons>
</HeaderButton.Container>
);
}
return (
<CustomHeaderButtons>
<HeaderButton.Container>
{threadsEnabled ? (
<Item
title='threads'
<HeaderButton.Item
iconName='threads'
onPress={this.goThreadsView}
testID='room-view-header-threads'
/>
) : null}
<Item
title='search'
<HeaderButton.Item
iconName='search'
onPress={this.goSearchView}
testID='room-view-search'
/>
</CustomHeaderButtons>
</HeaderButton.Container>
);
}
}

View File

@ -33,11 +33,7 @@ import { appStart as appStartAction, ROOT_BACKGROUND } from '../../actions/app';
import debounce from '../../utils/debounce';
import { isIOS, isTablet } from '../../utils/deviceInfo';
import RoomsListHeaderView from './Header';
import {
DrawerButton,
CustomHeaderButtons,
Item
} from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
import StatusBar from '../../containers/StatusBar';
import ActivityIndicator from '../../containers/ActivityIndicator';
import ListHeader from './ListHeader';
@ -346,15 +342,14 @@ class RoomsListView extends React.Component {
return {
headerTitleAlign: 'left',
headerLeft: () => (searching ? (
<CustomHeaderButtons left>
<Item
title='cancel'
<HeaderButton.Container left>
<HeaderButton.Item
iconName='close'
onPress={this.cancelSearch}
/>
</CustomHeaderButtons>
</HeaderButton.Container>
) : (
<DrawerButton
<HeaderButton.Drawer
navigation={navigation}
testID='rooms-list-view-sidebar'
onPress={isMasterDetail
@ -368,26 +363,23 @@ class RoomsListView extends React.Component {
right: headerTitlePosition.right
},
headerRight: () => (searching ? null : (
<CustomHeaderButtons>
<Item
title='new'
<HeaderButton.Container>
<HeaderButton.Item
iconName='create'
onPress={this.goToNewMessage}
testID='rooms-list-view-create-channel'
/>
<Item
title='search'
<HeaderButton.Item
iconName='search'
onPress={this.initSearching}
testID='rooms-list-view-search'
/>
<Item
title='directory'
<HeaderButton.Item
iconName='directory'
onPress={this.goDirectory}
testID='rooms-list-view-directory'
/>
</CustomHeaderButtons>
</HeaderButton.Container>
))
};
}
@ -883,7 +875,7 @@ class RoomsListView extends React.Component {
};
renderHeader = () => {
const { isMasterDetail, theme } = this.props;
const { isMasterDetail } = this.props;
if (!isMasterDetail) {
return null;
@ -892,7 +884,6 @@ class RoomsListView extends React.Component {
const options = this.getHeader();
return (
<Header
theme={theme}
{...options}
/>
);

View File

@ -20,7 +20,7 @@ import { themes } from '../../constants/colors';
import { withTheme } from '../../theme';
import { getUserSelector } from '../../selectors/login';
import SafeAreaView from '../../containers/SafeAreaView';
import { CloseModalButton } from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
import database from '../../lib/database';
import { sanitizeLikeString } from '../../lib/database/utils';
@ -31,7 +31,7 @@ class SearchMessagesView extends React.Component {
};
const showCloseModal = route.params?.showCloseModal;
if (showCloseModal) {
options.headerLeft = () => <CloseModalButton navigation={navigation} />;
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} />;
}
return options;
}

View File

@ -14,7 +14,7 @@ import I18n from '../i18n';
import log, { logEvent, events } from '../utils/log';
import SearchBox from '../containers/SearchBox';
import sharedStyles from './Styles';
import { Item, CustomHeaderButtons } from '../containers/HeaderButton';
import * as HeaderButton from '../containers/HeaderButton';
import StatusBar from '../containers/StatusBar';
import { themes } from '../constants/colors';
import { animateNextTransition } from '../utils/layoutAnimation';
@ -119,9 +119,9 @@ class SelectedUsersView extends React.Component {
title,
headerRight: () => (
(!maxUsers || showButton) && (
<CustomHeaderButtons>
<Item title={buttonText} onPress={nextAction} testID='selected-users-view-submit' />
</CustomHeaderButtons>
<HeaderButton.Container>
<HeaderButton.Item title={buttonText} onPress={nextAction} testID='selected-users-view-submit' />
</HeaderButton.Container>
)
)
};

View File

@ -12,7 +12,7 @@ import { logout as logoutAction } from '../../actions/login';
import { selectServerRequest as selectServerRequestAction } from '../../actions/server';
import { toggleCrashReport as toggleCrashReportAction, toggleAnalyticsEvents as toggleAnalyticsEventsAction } from '../../actions/crashReport';
import { SWITCH_TRACK_COLOR, themes } from '../../constants/colors';
import { DrawerButton, CloseModalButton } from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
import StatusBar from '../../containers/StatusBar';
import * as List from '../../containers/List';
import I18n from '../../i18n';
@ -42,9 +42,9 @@ import { getUserSelector } from '../../selectors/login';
class SettingsView extends React.Component {
static navigationOptions = ({ navigation, isMasterDetail }) => ({
headerLeft: () => (isMasterDetail ? (
<CloseModalButton navigation={navigation} testID='settings-view-close' />
<HeaderButton.CloseModal navigation={navigation} testID='settings-view-close' />
) : (
<DrawerButton navigation={navigation} />
<HeaderButton.Drawer navigation={navigation} />
)),
title: I18n.t('Settings')
});

View File

@ -4,7 +4,7 @@ import { Keyboard, View, StyleSheet } from 'react-native';
import ShareExtension from 'rn-extensions-share';
import SearchBox from '../../../containers/SearchBox';
import { CancelModalButton } from '../../../containers/HeaderButton';
import * as HeaderButton from '../../../containers/HeaderButton';
import { themes } from '../../../constants/colors';
import sharedStyles from '../../Styles';
@ -52,7 +52,7 @@ const Header = React.memo(({
{
!searching
? (
<CancelModalButton
<HeaderButton.CancelModal
onPress={ShareExtension.close}
testID='share-extension-close'
/>

View File

@ -15,7 +15,7 @@ import { isIOS, isAndroid } from '../../utils/deviceInfo';
import I18n from '../../i18n';
import DirectoryItem, { ROW_HEIGHT } from '../../presentation/DirectoryItem';
import ServerItem from '../../presentation/ServerItem';
import { CancelModalButton, CustomHeaderButtons, Item } from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
import ShareListHeader from './Header';
import ActivityIndicator from '../../containers/ActivityIndicator';
@ -157,12 +157,12 @@ class ShareListView extends React.Component {
navigation.setOptions({
headerLeft: () => (searching
? (
<CustomHeaderButtons left>
<Item title='cancel' iconName='close' onPress={this.cancelSearch} />
</CustomHeaderButtons>
<HeaderButton.Container left>
<HeaderButton.Item title='cancel' iconName='close' onPress={this.cancelSearch} />
</HeaderButton.Container>
)
: (
<CancelModalButton
<HeaderButton.CancelModal
onPress={ShareExtension.close}
testID='share-extension-close'
/>
@ -172,9 +172,9 @@ class ShareListView extends React.Component {
searching
? null
: (
<CustomHeaderButtons>
<Item title='search' iconName='search' onPress={this.initSearch} />
</CustomHeaderButtons>
<HeaderButton.Container>
<HeaderButton.Item iconName='search' onPress={this.initSearch} />
</HeaderButton.Container>
)
)
});

View File

@ -9,11 +9,7 @@ import { themes } from '../../constants/colors';
import I18n from '../../i18n';
import styles from './styles';
import Loading from '../../containers/Loading';
import {
Item,
CloseModalButton,
CustomHeaderButtons
} from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
import { isBlocked } from '../../utils/room';
import { isReadOnly } from '../../utils/isReadOnly';
import { withTheme } from '../../theme';
@ -75,18 +71,18 @@ class ShareView extends Component {
// if is share extension show default back button
if (!this.isShareExtension) {
options.headerLeft = () => <CloseModalButton navigation={navigation} buttonStyle={{ color: themes[theme].previewTintColor }} />;
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} buttonStyle={{ color: themes[theme].previewTintColor }} />;
}
if (!attachments.length && !readOnly) {
options.headerRight = () => (
<CustomHeaderButtons>
<Item
<HeaderButton.Container>
<HeaderButton.Item
title={I18n.t('Send')}
onPress={this.send}
buttonStyle={[styles.send, { color: themes[theme].previewTintColor }]}
/>
</CustomHeaderButtons>
</HeaderButton.Container>
);
}

View File

@ -15,7 +15,7 @@ import log, { logEvent, events } from '../utils/log';
import { LISTENER } from '../containers/Toast';
import { withTheme } from '../theme';
import { getUserSelector } from '../selectors/login';
import { CustomHeaderButtons, Item, CancelModalButton } from '../containers/HeaderButton';
import * as HeaderButton from '../containers/HeaderButton';
import store from '../lib/createStore';
import { setUser } from '../actions/login';
import SafeAreaView from '../containers/SafeAreaView';
@ -73,15 +73,15 @@ class StatusView extends React.Component {
const { navigation, isMasterDetail } = this.props;
navigation.setOptions({
title: I18n.t('Edit_Status'),
headerLeft: isMasterDetail ? undefined : () => <CancelModalButton onPress={this.close} />,
headerLeft: isMasterDetail ? undefined : () => <HeaderButton.CancelModal onPress={this.close} />,
headerRight: () => (
<CustomHeaderButtons>
<Item
<HeaderButton.Container>
<HeaderButton.Item
title={I18n.t('Done')}
onPress={this.submit}
testID='status-view-submit'
/>
</CustomHeaderButtons>
</HeaderButton.Container>
)
});
}

View File

@ -24,7 +24,7 @@ import { themes } from '../../constants/colors';
import { withTheme } from '../../theme';
import { getUserSelector } from '../../selectors/login';
import SafeAreaView from '../../containers/SafeAreaView';
import { CloseModalButton } from '../../containers/HeaderButton';
import * as HeaderButton from '../../containers/HeaderButton';
const Separator = React.memo(({ theme }) => <View style={[styles.separator, { backgroundColor: themes[theme].separatorColor }]} />);
Separator.propTypes = {
@ -39,7 +39,7 @@ class ThreadMessagesView extends React.Component {
title: I18n.t('Threads')
};
if (isMasterDetail) {
options.headerLeft = () => <CloseModalButton navigation={navigation} />;
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} />;
}
return options;
}

View File

@ -5,7 +5,7 @@ import {
import PropTypes from 'prop-types';
import ShareExtension from 'rn-extensions-share';
import { CancelModalButton } from '../containers/HeaderButton';
import * as HeaderButton from '../containers/HeaderButton';
import sharedStyles from './Styles';
import I18n from '../i18n';
import { themes } from '../constants/colors';
@ -33,7 +33,7 @@ class WithoutServerView extends React.Component {
static navigationOptions = () => ({
title: 'Rocket.Chat',
headerLeft: () => (
<CancelModalButton
<HeaderButton.CancelModal
onPress={ShareExtension.close}
testID='share-extension-close'
/>

View File

@ -109,7 +109,6 @@
"react-native-unimodules": "0.10.1",
"react-native-vector-icons": "7.0.0",
"react-native-webview": "10.3.2",
"react-navigation-header-buttons": "3.0.5",
"react-redux": "7.2.0",
"reactotron-react-native": "5.0.0",
"redux": "4.0.5",

View File

@ -1,12 +0,0 @@
diff --git a/node_modules/react-navigation-header-buttons/src/HeaderButtons.js b/node_modules/react-navigation-header-buttons/src/HeaderButtons.js
index 70ff376..01fba5e 100644
--- a/node_modules/react-navigation-header-buttons/src/HeaderButtons.js
+++ b/node_modules/react-navigation-header-buttons/src/HeaderButtons.js
@@ -144,6 +144,6 @@ const styles = StyleSheet.create({
}),
},
button: {
- marginHorizontal: 11,
+ marginHorizontal: 6
},
});

View File

@ -0,0 +1,162 @@
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions, react/prop-types */
import React from 'react';
import { storiesOf } from '@storybook/react-native';
import { View } from 'react-native';
import * as HeaderButton from '../../app/containers/HeaderButton';
import Header from '../../app/containers/Header';
import { ThemeContext } from '../../app/theme';
const stories = storiesOf('Header Buttons', module);
const HeaderExample = ({ left, right }) => (
<Header
headerLeft={left}
headerTitle={() => <View style={{ flex: 1 }} />}
headerRight={right}
/>
);
stories.add('title', () => (
<>
<HeaderExample
left={() => (
<HeaderButton.Container left>
<HeaderButton.Item title='threads' />
</HeaderButton.Container>
)}
right={() => (
<HeaderButton.Container>
<HeaderButton.Item title='threads' />
</HeaderButton.Container>
)}
/>
<HeaderExample
left={() => (
<HeaderButton.Container left>
<HeaderButton.Item title='threads' />
<HeaderButton.Item title='search' />
</HeaderButton.Container>
)}
right={() => (
<HeaderButton.Container>
<HeaderButton.Item title='threads' />
<HeaderButton.Item title='search' />
</HeaderButton.Container>
)}
/>
</>
));
stories.add('icons', () => (
<>
<HeaderExample
left={() => (
<HeaderButton.Container left>
<HeaderButton.Item iconName='threads' />
</HeaderButton.Container>
)}
right={() => (
<HeaderButton.Container>
<HeaderButton.Item iconName='threads' />
</HeaderButton.Container>
)}
/>
<HeaderExample
left={() => (
<HeaderButton.Container left>
<HeaderButton.Item iconName='threads' />
<HeaderButton.Item iconName='search' />
</HeaderButton.Container>
)}
right={() => (
<HeaderButton.Container>
<HeaderButton.Item iconName='threads' />
<HeaderButton.Item iconName='search' />
</HeaderButton.Container>
)}
/>
</>
));
stories.add('badge', () => (
<>
<HeaderExample
left={() => (
<HeaderButton.Container left>
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.Badge tunread={[1]} />} />
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.Badge tunread={[1]} tunreadUser={[1]} />} />
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.Badge tunread={[1]} tunreadGroup={[1]} />} />
</HeaderButton.Container>
)}
/>
</>
));
const ThemeStory = ({ theme }) => (
<ThemeContext.Provider
value={{ theme }}
>
<HeaderExample
left={() => (
<HeaderButton.Container left>
<HeaderButton.Item iconName='threads' />
</HeaderButton.Container>
)}
right={() => (
<HeaderButton.Container>
<HeaderButton.Item title='Threads' />
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.Badge tunread={999} />} />
</HeaderButton.Container>
)}
/>
</ThemeContext.Provider>
);
stories.add('themes', () => (
<>
<ThemeStory theme='light' />
<ThemeStory theme='dark' />
<ThemeStory theme='black' />
</>
));
stories.add('common', () => (
<>
<HeaderExample
left={() => (
<HeaderButton.Drawer />
)}
/>
<HeaderExample
left={() => (
<HeaderButton.CloseModal />
)}
/>
<HeaderExample
left={() => (
<HeaderButton.CancelModal />
)}
/>
<HeaderExample
right={() => (
<HeaderButton.More />
)}
/>
<HeaderExample
right={() => (
<HeaderButton.Download />
)}
/>
<HeaderExample
right={() => (
<HeaderButton.Preferences />
)}
/>
<HeaderExample
right={() => (
<HeaderButton.Legal />
)}
/>
</>
));

View File

@ -73,10 +73,9 @@ export default ({ theme }) => {
<RoomItem alert name='unread' unread={1} />
<RoomItem alert name='unread' unread={1000} />
<RoomItem alert name='user mentions' unread={1} userMentions={1} />
<RoomItem alert name='user mentions' unread={1000} userMentions={1} />
<RoomItem alert name='group mentions' unread={1} groupMentions={1} />
<RoomItem alert name='group mentions' unread={1000} groupMentions={1} />
<RoomItem name='user mentions > group mentions' alert unread={1000} userMentions={1} groupMentions={1} />
<RoomItem alert name='thread unread' tunread={[1]} />
<RoomItem name='user mentions > group mentions' alert unread={1} userMentions={1} groupMentions={1} />
<Separator title='Last Message' />
<RoomItem

View File

@ -0,0 +1,78 @@
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions, react/prop-types */
import React from 'react';
import { storiesOf } from '@storybook/react-native';
import { View } from 'react-native';
import UnreadBadge from '../../app/presentation/UnreadBadge';
import { ThemeContext } from '../../app/theme';
const stories = storiesOf('Unread Badge', module);
const StoryTester = ({ children }) => (
<View
style={{
flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly'
}}
>
{children}
</View>
);
stories.add('all', () => (
<StoryTester>
<UnreadBadge unread={9} small />
<UnreadBadge unread={999} small />
<UnreadBadge unread={9} />
<UnreadBadge unread={9999} />
<UnreadBadge unread={9} userMentions={1} />
<UnreadBadge unread={9} groupMentions={1} />
<UnreadBadge unread={9} tunread={[1]} />
</StoryTester>
));
stories.add('small', () => (
<StoryTester>
<UnreadBadge unread={9} small />
<UnreadBadge unread={999} small />
</StoryTester>
));
stories.add('normal', () => (
<StoryTester>
<UnreadBadge unread={9} />
<UnreadBadge unread={9999} />
</StoryTester>
));
stories.add('different mention types', () => (
<StoryTester>
<UnreadBadge unread={1} />
<UnreadBadge unread={1} userMentions={1} />
<UnreadBadge unread={1} groupMentions={1} />
<UnreadBadge unread={1} userMentions={1} groupMentions={1} />
<UnreadBadge unread={1} tunread={[1]} />
<UnreadBadge unread={1} tunreadUser={[1]} />
<UnreadBadge unread={1} tunreadGroup={[1]} />
</StoryTester>
));
const ThemeStory = ({ theme }) => (
<ThemeContext.Provider
value={{ theme }}
>
<StoryTester>
<UnreadBadge unread={1} />
<UnreadBadge unread={1} userMentions={1} />
<UnreadBadge unread={1} groupMentions={1} />
<UnreadBadge tunread={[1]} />
</StoryTester>
</ThemeContext.Provider>
);
stories.add('themes', () => (
<>
<ThemeStory theme='light' />
<ThemeStory theme='dark' />
<ThemeStory theme='black' />
</>
));

View File

@ -10,6 +10,8 @@ import Message from './Message';
import UiKitMessage from './UiKitMessage';
import UiKitModal from './UiKitModal';
import Markdown from './Markdown';
import './HeaderButtons';
import './UnreadBadge';
import Avatar from './Avatar';
// import RoomViewHeader from './RoomViewHeader';

View File

@ -12891,7 +12891,7 @@ react-native-picker-select@7.0.0:
dependencies:
lodash.isequal "^4.5.0"
react-native-platform-touchable@1.1.1, react-native-platform-touchable@^1.1.1:
react-native-platform-touchable@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/react-native-platform-touchable/-/react-native-platform-touchable-1.1.1.tgz#fde4acc65eea585d28b164d0c3716a42129a68e4"
integrity sha1-/eSsxl7qWF0osWTQw3FqQhKaaOQ=
@ -13068,13 +13068,6 @@ react-native@^0.63.1:
use-subscription "^1.0.0"
whatwg-fetch "^3.0.0"
react-navigation-header-buttons@3.0.5:
version "3.0.5"
resolved "https://registry.yarnpkg.com/react-navigation-header-buttons/-/react-navigation-header-buttons-3.0.5.tgz#5b8c0fc32bc59382f02015e4b2f19a135b99dca4"
integrity sha512-b1AsL9k6Klp72CnAq4IF0xgw94FClBIsUr/pGUKa1PI+mStdF0AYZzi9qtYgqQNDIOpqxQ2xYUM9azL2VmPUeQ==
dependencies:
react-native-platform-touchable "^1.1.1"
react-popper-tooltip@^2.8.3:
version "2.11.1"
resolved "https://registry.yarnpkg.com/react-popper-tooltip/-/react-popper-tooltip-2.11.1.tgz#3c4bdfd8bc10d1c2b9a162e859bab8958f5b2644"