[IMPROVEMENT] Unified header UX (#2234)
* Change drawer icon * Removed iOS variation * Patch to react-navigation-header-buttons... easier to patch then to overwrite its behaviour :( * Correctly position title * Header subtitle * Layout * Alignment * RoomView header * Renamed RoomHeaderLeft to LeftButtons * RoomView back button * Search icon on RoomView * Refactor * Fix header on tablet * Fix search messages close button on tablet * Search key command * Network status on RoomView header subtitle * Update tests * Scale content * SearchBox cancel color
This commit is contained in:
parent
2ec2a52f45
commit
5834ab5e22
|
@ -1,5 +1,3 @@
|
||||||
import { isIOS, isAndroid } from '../utils/deviceInfo';
|
|
||||||
|
|
||||||
export const STATUS_COLORS = {
|
export const STATUS_COLORS = {
|
||||||
online: '#2de0a5',
|
online: '#2de0a5',
|
||||||
busy: '#f5455c',
|
busy: '#f5455c',
|
||||||
|
@ -8,7 +6,7 @@ export const STATUS_COLORS = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SWITCH_TRACK_COLOR = {
|
export const SWITCH_TRACK_COLOR = {
|
||||||
false: isAndroid ? '#f5455c' : null,
|
false: '#f5455c',
|
||||||
true: '#2de0a5'
|
true: '#2de0a5'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,11 +32,11 @@ export const themes = {
|
||||||
separatorColor: '#cbcbcc',
|
separatorColor: '#cbcbcc',
|
||||||
navbarBackground: '#ffffff',
|
navbarBackground: '#ffffff',
|
||||||
headerBorder: '#B2B2B2',
|
headerBorder: '#B2B2B2',
|
||||||
headerBackground: isIOS ? '#f8f8f8' : '#2f343d',
|
headerBackground: '#EEEFF1',
|
||||||
headerSecondaryBackground: '#ffffff',
|
headerSecondaryBackground: '#ffffff',
|
||||||
headerTintColor: isAndroid ? '#ffffff' : '#1d74f5',
|
headerTintColor: '#6C727A',
|
||||||
headerTitleColor: isAndroid ? '#ffffff' : '#0d0e12',
|
headerTitleColor: '#0C0D0F',
|
||||||
headerSecondaryText: isAndroid ? '#9ca2a8' : '#1d74f5',
|
headerSecondaryText: '#1d74f5',
|
||||||
toastBackground: '#0C0D0F',
|
toastBackground: '#0C0D0F',
|
||||||
videoBackground: '#1f2329',
|
videoBackground: '#1f2329',
|
||||||
favoriteBackground: '#ffbb00',
|
favoriteBackground: '#ffbb00',
|
||||||
|
@ -63,7 +61,7 @@ export const themes = {
|
||||||
chatComponentBackground: '#192132',
|
chatComponentBackground: '#192132',
|
||||||
auxiliaryBackground: '#07101e',
|
auxiliaryBackground: '#07101e',
|
||||||
bannerBackground: '#0e1f38',
|
bannerBackground: '#0e1f38',
|
||||||
titleText: '#FFFFFF',
|
titleText: '#f9f9f9',
|
||||||
bodyText: '#e8ebed',
|
bodyText: '#e8ebed',
|
||||||
backdropColor: '#000000',
|
backdropColor: '#000000',
|
||||||
dangerColor: '#f5455c',
|
dangerColor: '#f5455c',
|
||||||
|
@ -80,9 +78,9 @@ export const themes = {
|
||||||
headerBorder: '#2F3A4B',
|
headerBorder: '#2F3A4B',
|
||||||
headerBackground: '#0b182c',
|
headerBackground: '#0b182c',
|
||||||
headerSecondaryBackground: '#0b182c',
|
headerSecondaryBackground: '#0b182c',
|
||||||
headerTintColor: isAndroid ? '#ffffff' : '#1d74f5',
|
headerTintColor: '#f9f9f9',
|
||||||
headerTitleColor: '#FFFFFF',
|
headerTitleColor: '#f9f9f9',
|
||||||
headerSecondaryText: isAndroid ? '#9297a2' : '#1d74f5',
|
headerSecondaryText: '#9297a2',
|
||||||
toastBackground: '#0C0D0F',
|
toastBackground: '#0C0D0F',
|
||||||
videoBackground: '#1f2329',
|
videoBackground: '#1f2329',
|
||||||
favoriteBackground: '#ffbb00',
|
favoriteBackground: '#ffbb00',
|
||||||
|
@ -124,9 +122,9 @@ export const themes = {
|
||||||
headerBorder: '#323232',
|
headerBorder: '#323232',
|
||||||
headerBackground: '#0d0d0d',
|
headerBackground: '#0d0d0d',
|
||||||
headerSecondaryBackground: '#0d0d0d',
|
headerSecondaryBackground: '#0d0d0d',
|
||||||
headerTintColor: isAndroid ? '#ffffff' : '#1e9bfe',
|
headerTintColor: '#f9f9f9',
|
||||||
headerTitleColor: '#f9f9f9',
|
headerTitleColor: '#f9f9f9',
|
||||||
headerSecondaryText: isAndroid ? '#b2b8c6' : '#1e9bfe',
|
headerSecondaryText: '#b2b8c6',
|
||||||
toastBackground: '#0C0D0F',
|
toastBackground: '#0C0D0F',
|
||||||
videoBackground: '#1f2329',
|
videoBackground: '#1f2329',
|
||||||
favoriteBackground: '#ffbb00',
|
favoriteBackground: '#ffbb00',
|
||||||
|
|
|
@ -17,7 +17,7 @@ const styles = StyleSheet.create({
|
||||||
export const DisclosureImage = React.memo(({ theme }) => (
|
export const DisclosureImage = React.memo(({ theme }) => (
|
||||||
<CustomIcon
|
<CustomIcon
|
||||||
name='chevron-right'
|
name='chevron-right'
|
||||||
color={themes[theme].auxiliaryTintColor}
|
color={themes[theme].auxiliaryText}
|
||||||
size={20}
|
size={20}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
|
|
@ -20,6 +20,11 @@ export const getHeaderHeight = (isLandscape) => {
|
||||||
return 56;
|
return 56;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getHeaderTitlePosition = insets => ({
|
||||||
|
left: 60 + insets.left,
|
||||||
|
right: 80 + insets.right
|
||||||
|
});
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
height: headerHeight,
|
height: headerHeight,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||||
import { HeaderButtons, HeaderButton, Item } from 'react-navigation-header-buttons';
|
import { HeaderButtons, HeaderButton, Item } from 'react-navigation-header-buttons';
|
||||||
|
|
||||||
import { CustomIcon } from '../lib/Icons';
|
import { CustomIcon } from '../lib/Icons';
|
||||||
import { isIOS, isAndroid } from '../utils/deviceInfo';
|
import { isIOS } from '../utils/deviceInfo';
|
||||||
import { themes } from '../constants/colors';
|
import { themes } from '../constants/colors';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
import { withTheme } from '../theme';
|
import { withTheme } from '../theme';
|
||||||
|
@ -15,11 +15,7 @@ const CustomHeaderButton = React.memo(withTheme(({ theme, ...props }) => (
|
||||||
{...props}
|
{...props}
|
||||||
IconComponent={CustomIcon}
|
IconComponent={CustomIcon}
|
||||||
iconSize={headerIconSize}
|
iconSize={headerIconSize}
|
||||||
color={
|
color={themes[theme].headerTintColor}
|
||||||
isAndroid
|
|
||||||
? themes[theme].headerTitleColor
|
|
||||||
: themes[theme].headerTintColor
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
)));
|
)));
|
||||||
|
|
||||||
|
@ -32,7 +28,7 @@ export const CustomHeaderButtons = React.memo(props => (
|
||||||
|
|
||||||
export const DrawerButton = React.memo(({ navigation, testID, ...otherProps }) => (
|
export const DrawerButton = React.memo(({ navigation, testID, ...otherProps }) => (
|
||||||
<CustomHeaderButtons left>
|
<CustomHeaderButtons left>
|
||||||
<Item title='drawer' iconName='customize' onPress={navigation.toggleDrawer} testID={testID} {...otherProps} />
|
<Item title='drawer' iconName='menu_hamburguer' onPress={navigation.toggleDrawer} testID={testID} {...otherProps} />
|
||||||
</CustomHeaderButtons>
|
</CustomHeaderButtons>
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ const styles = StyleSheet.create({
|
||||||
|
|
||||||
const CancelButton = (onCancelPress, theme) => (
|
const CancelButton = (onCancelPress, theme) => (
|
||||||
<Touchable onPress={onCancelPress} style={styles.cancel}>
|
<Touchable onPress={onCancelPress} style={styles.cancel}>
|
||||||
<Text style={[styles.cancelText, { color: themes[theme].tintColor }]}>{I18n.t('Cancel')}</Text>
|
<Text style={[styles.cancelText, { color: themes[theme].headerTintColor }]}>{I18n.t('Cancel')}</Text>
|
||||||
</Touchable>
|
</Touchable>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,12 @@ import React from 'react';
|
||||||
import { StatusBar as StatusBarRN } from 'react-native';
|
import { StatusBar as StatusBarRN } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { isIOS } from '../utils/deviceInfo';
|
|
||||||
import { themes } from '../constants/colors';
|
import { themes } from '../constants/colors';
|
||||||
|
|
||||||
const StatusBar = React.memo(({ theme, barStyle, backgroundColor }) => {
|
const StatusBar = React.memo(({ theme, barStyle, backgroundColor }) => {
|
||||||
if (!barStyle) {
|
if (!barStyle) {
|
||||||
barStyle = 'light-content';
|
barStyle = 'light-content';
|
||||||
if (theme === 'light' && isIOS) {
|
if (theme === 'light') {
|
||||||
barStyle = 'dark-content';
|
barStyle = 'dark-content';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -543,6 +543,7 @@ export default {
|
||||||
Video_call: 'Video call',
|
Video_call: 'Video call',
|
||||||
View_Original: 'View Original',
|
View_Original: 'View Original',
|
||||||
Voice_call: 'Voice call',
|
Voice_call: 'Voice call',
|
||||||
|
Waiting_for_network: 'Waiting for network...',
|
||||||
Websocket_disabled: 'Websocket is disabled for this server.\n{{contact}}',
|
Websocket_disabled: 'Websocket is disabled for this server.\n{{contact}}',
|
||||||
Welcome: 'Welcome',
|
Welcome: 'Welcome',
|
||||||
What_are_you_doing_right_now: 'What are you doing right now?',
|
What_are_you_doing_right_now: 'What are you doing right now?',
|
||||||
|
|
|
@ -479,6 +479,7 @@ export default {
|
||||||
Verify_your_email_for_the_code_we_sent: 'Verifique em seu e-mail o código que enviamos',
|
Verify_your_email_for_the_code_we_sent: 'Verifique em seu e-mail o código que enviamos',
|
||||||
Video_call: 'Chamada de vídeo',
|
Video_call: 'Chamada de vídeo',
|
||||||
Voice_call: 'Chamada de voz',
|
Voice_call: 'Chamada de voz',
|
||||||
|
Waiting_for_network: 'Aguardando rede...',
|
||||||
Websocket_disabled: 'Websocket está desativado para esse servidor.\n{{contact}}',
|
Websocket_disabled: 'Websocket está desativado para esse servidor.\n{{contact}}',
|
||||||
Welcome: 'Bem vindo',
|
Welcome: 'Bem vindo',
|
||||||
Whats_your_2fa: 'Qual seu código de autenticação?',
|
Whats_your_2fa: 'Qual seu código de autenticação?',
|
||||||
|
|
|
@ -6,28 +6,20 @@ import {
|
||||||
|
|
||||||
import I18n from '../../../i18n';
|
import I18n from '../../../i18n';
|
||||||
import sharedStyles from '../../Styles';
|
import sharedStyles from '../../Styles';
|
||||||
import { isAndroid, isTablet } from '../../../utils/deviceInfo';
|
|
||||||
import Icon from './Icon';
|
import Icon from './Icon';
|
||||||
import { themes } from '../../../constants/colors';
|
import { themes } from '../../../constants/colors';
|
||||||
import Markdown from '../../../containers/markdown';
|
import Markdown from '../../../containers/markdown';
|
||||||
|
|
||||||
const androidMarginLeft = isTablet ? 0 : 4;
|
|
||||||
|
|
||||||
const TITLE_SIZE = 16;
|
const TITLE_SIZE = 16;
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
marginRight: isAndroid ? 15 : 5,
|
|
||||||
marginLeft: isAndroid ? androidMarginLeft : -10,
|
|
||||||
justifyContent: 'center'
|
justifyContent: 'center'
|
||||||
},
|
},
|
||||||
titleContainer: {
|
titleContainer: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
flexDirection: 'row'
|
flexDirection: 'row'
|
||||||
},
|
},
|
||||||
threadContainer: {
|
|
||||||
marginRight: isAndroid ? 20 : undefined
|
|
||||||
},
|
|
||||||
title: {
|
title: {
|
||||||
...sharedStyles.textSemibold,
|
...sharedStyles.textSemibold,
|
||||||
fontSize: TITLE_SIZE
|
fontSize: TITLE_SIZE
|
||||||
|
@ -36,7 +28,6 @@ const styles = StyleSheet.create({
|
||||||
alignItems: 'center'
|
alignItems: 'center'
|
||||||
},
|
},
|
||||||
subtitle: {
|
subtitle: {
|
||||||
marginRight: -16,
|
|
||||||
...sharedStyles.textRegular,
|
...sharedStyles.textRegular,
|
||||||
fontSize: 12
|
fontSize: 12
|
||||||
},
|
},
|
||||||
|
@ -87,12 +78,8 @@ SubTitle.propTypes = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const HeaderTitle = React.memo(({
|
const HeaderTitle = React.memo(({
|
||||||
title, tmid, prid, scale, connecting, theme
|
title, tmid, prid, scale, theme
|
||||||
}) => {
|
}) => {
|
||||||
if (connecting) {
|
|
||||||
title = I18n.t('Connecting');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tmid && !prid) {
|
if (!tmid && !prid) {
|
||||||
return (
|
return (
|
||||||
<Text
|
<Text
|
||||||
|
@ -122,7 +109,6 @@ HeaderTitle.propTypes = {
|
||||||
tmid: PropTypes.string,
|
tmid: PropTypes.string,
|
||||||
prid: PropTypes.string,
|
prid: PropTypes.string,
|
||||||
scale: PropTypes.number,
|
scale: PropTypes.number,
|
||||||
connecting: PropTypes.bool,
|
|
||||||
theme: PropTypes.string
|
theme: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -147,7 +133,7 @@ const Header = React.memo(({
|
||||||
style={styles.container}
|
style={styles.container}
|
||||||
disabled={tmid}
|
disabled={tmid}
|
||||||
>
|
>
|
||||||
<View style={[styles.titleContainer, tmid && styles.threadContainer]}>
|
<View style={styles.titleContainer}>
|
||||||
<Icon type={prid ? 'discussion' : type} status={status} roomUserId={roomUserId} theme={theme} />
|
<Icon type={prid ? 'discussion' : type} status={status} roomUserId={roomUserId} theme={theme} />
|
||||||
<HeaderTitle
|
<HeaderTitle
|
||||||
title={title}
|
title={title}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import PropTypes from 'prop-types';
|
||||||
import { STATUS_COLORS, themes } from '../../../constants/colors';
|
import { STATUS_COLORS, themes } from '../../../constants/colors';
|
||||||
import { CustomIcon } from '../../../lib/Icons';
|
import { CustomIcon } from '../../../lib/Icons';
|
||||||
import Status from '../../../containers/Status/Status';
|
import Status from '../../../containers/Status/Status';
|
||||||
import { isAndroid } from '../../../utils/deviceInfo';
|
|
||||||
|
|
||||||
const ICON_SIZE = 15;
|
const ICON_SIZE = 15;
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ const Icon = React.memo(({
|
||||||
if (type === 'l') {
|
if (type === 'l') {
|
||||||
colorStyle = { color: STATUS_COLORS[status] };
|
colorStyle = { color: STATUS_COLORS[status] };
|
||||||
} else {
|
} else {
|
||||||
colorStyle = { color: isAndroid && theme === 'light' ? themes[theme].buttonText : themes[theme].auxiliaryText };
|
colorStyle = { color: themes[theme].auxiliaryText };
|
||||||
}
|
}
|
||||||
|
|
||||||
let icon;
|
let icon;
|
||||||
|
|
|
@ -13,16 +13,21 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const RoomHeaderLeft = React.memo(({
|
const LeftButtons = React.memo(({
|
||||||
tmid, unreadsCount, navigation, baseUrl, userId, token, title, t, theme, goRoomActionsView, isMasterDetail
|
tmid, unreadsCount, navigation, baseUrl, userId, token, title, t, theme, goRoomActionsView, isMasterDetail
|
||||||
}) => {
|
}) => {
|
||||||
if (!isMasterDetail || tmid) {
|
if (!isMasterDetail || tmid) {
|
||||||
const onPress = useCallback(() => navigation.goBack());
|
const onPress = useCallback(() => navigation.goBack());
|
||||||
|
const label = unreadsCount > 99 ? '+99' : unreadsCount || ' ';
|
||||||
|
const labelLength = label.length ? label.length : 1;
|
||||||
|
const marginLeft = -2 * labelLength;
|
||||||
|
const fontSize = labelLength > 1 ? 14 : 17;
|
||||||
return (
|
return (
|
||||||
<HeaderBackButton
|
<HeaderBackButton
|
||||||
label={unreadsCount > 999 ? '+999' : unreadsCount || ' '}
|
label={label}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
tintColor={themes[theme].headerTintColor}
|
tintColor={themes[theme].headerTintColor}
|
||||||
|
labelStyle={{ fontSize, marginLeft }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -44,7 +49,7 @@ const RoomHeaderLeft = React.memo(({
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
RoomHeaderLeft.propTypes = {
|
LeftButtons.propTypes = {
|
||||||
tmid: PropTypes.string,
|
tmid: PropTypes.string,
|
||||||
unreadsCount: PropTypes.number,
|
unreadsCount: PropTypes.number,
|
||||||
navigation: PropTypes.object,
|
navigation: PropTypes.object,
|
||||||
|
@ -58,4 +63,4 @@ RoomHeaderLeft.propTypes = {
|
||||||
isMasterDetail: PropTypes.bool
|
isMasterDetail: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|
||||||
export default RoomHeaderLeft;
|
export default LeftButtons;
|
|
@ -68,6 +68,17 @@ class RightButtonsContainer extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goSearchView = () => {
|
||||||
|
const {
|
||||||
|
rid, navigation, isMasterDetail
|
||||||
|
} = this.props;
|
||||||
|
if (isMasterDetail) {
|
||||||
|
navigation.navigate('ModalStackNavigator', { screen: 'SearchMessagesView', params: { rid, showCloseModal: true } });
|
||||||
|
} else {
|
||||||
|
navigation.navigate('SearchMessagesView', { rid });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
toggleFollowThread = () => {
|
toggleFollowThread = () => {
|
||||||
const { isFollowingThread } = this.state;
|
const { isFollowingThread } = this.state;
|
||||||
const { toggleFollowThread } = this.props;
|
const { toggleFollowThread } = this.props;
|
||||||
|
@ -104,6 +115,12 @@ class RightButtonsContainer extends React.PureComponent {
|
||||||
testID='room-view-header-threads'
|
testID='room-view-header-threads'
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
<Item
|
||||||
|
title='search'
|
||||||
|
iconName='magnifier'
|
||||||
|
onPress={this.goSearchView}
|
||||||
|
testID='room-view-search'
|
||||||
|
/>
|
||||||
</CustomHeaderButtons>
|
</CustomHeaderButtons>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,11 @@ import { connect } from 'react-redux';
|
||||||
import equal from 'deep-equal';
|
import equal from 'deep-equal';
|
||||||
|
|
||||||
import Header from './Header';
|
import Header from './Header';
|
||||||
|
import LeftButtons from './LeftButtons';
|
||||||
import RightButtons from './RightButtons';
|
import RightButtons from './RightButtons';
|
||||||
import { withTheme } from '../../../theme';
|
import { withTheme } from '../../../theme';
|
||||||
import RoomHeaderLeft from './RoomHeaderLeft';
|
|
||||||
import { withDimensions } from '../../../dimensions';
|
import { withDimensions } from '../../../dimensions';
|
||||||
|
import I18n from '../../../i18n';
|
||||||
|
|
||||||
class RoomHeaderView extends Component {
|
class RoomHeaderView extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -20,6 +21,7 @@ class RoomHeaderView extends Component {
|
||||||
status: PropTypes.string,
|
status: PropTypes.string,
|
||||||
statusText: PropTypes.string,
|
statusText: PropTypes.string,
|
||||||
connecting: PropTypes.bool,
|
connecting: PropTypes.bool,
|
||||||
|
connected: PropTypes.bool,
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string,
|
||||||
roomUserId: PropTypes.string,
|
roomUserId: PropTypes.string,
|
||||||
widthOffset: PropTypes.number,
|
widthOffset: PropTypes.number,
|
||||||
|
@ -30,7 +32,7 @@ class RoomHeaderView extends Component {
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps) {
|
||||||
const {
|
const {
|
||||||
type, title, subtitle, status, statusText, connecting, goRoomActionsView, usersTyping, theme, width, height
|
type, title, subtitle, status, statusText, connecting, connected, goRoomActionsView, usersTyping, theme, width, height
|
||||||
} = this.props;
|
} = this.props;
|
||||||
if (nextProps.theme !== theme) {
|
if (nextProps.theme !== theme) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -53,6 +55,9 @@ class RoomHeaderView extends Component {
|
||||||
if (nextProps.connecting !== connecting) {
|
if (nextProps.connecting !== connecting) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (nextProps.connected !== connected) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (nextProps.width !== width) {
|
if (nextProps.width !== width) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -70,9 +75,18 @@ class RoomHeaderView extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
title, subtitle, type, prid, tmid, widthOffset, status = 'offline', statusText, connecting, usersTyping, goRoomActionsView, roomUserId, theme, width, height
|
title, subtitle: subtitleProp, type, prid, tmid, widthOffset, status = 'offline', statusText, connecting, connected, usersTyping, goRoomActionsView, roomUserId, theme, width, height
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
let subtitle;
|
||||||
|
if (connecting) {
|
||||||
|
subtitle = I18n.t('Connecting');
|
||||||
|
} else if (!connected) {
|
||||||
|
subtitle = I18n.t('Waiting_for_network');
|
||||||
|
} else {
|
||||||
|
subtitle = subtitleProp;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Header
|
<Header
|
||||||
prid={prid}
|
prid={prid}
|
||||||
|
@ -108,7 +122,8 @@ const mapStateToProps = (state, ownProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
connecting: state.meteor.connecting,
|
connecting: state.meteor.connecting || state.server.loading,
|
||||||
|
connected: state.meteor.connected,
|
||||||
usersTyping: state.usersTyping,
|
usersTyping: state.usersTyping,
|
||||||
status,
|
status,
|
||||||
statusText
|
statusText
|
||||||
|
@ -117,4 +132,4 @@ const mapStateToProps = (state, ownProps) => {
|
||||||
|
|
||||||
export default connect(mapStateToProps)(withDimensions(withTheme(RoomHeaderView)));
|
export default connect(mapStateToProps)(withDimensions(withTheme(RoomHeaderView)));
|
||||||
|
|
||||||
export { RightButtons, RoomHeaderLeft };
|
export { RightButtons, LeftButtons };
|
||||||
|
|
|
@ -8,6 +8,7 @@ import moment from 'moment';
|
||||||
import * as Haptics from 'expo-haptics';
|
import * as Haptics from 'expo-haptics';
|
||||||
import { Q } from '@nozbe/watermelondb';
|
import { Q } from '@nozbe/watermelondb';
|
||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
|
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
import Touch from '../../utils/touch';
|
import Touch from '../../utils/touch';
|
||||||
import {
|
import {
|
||||||
|
@ -26,7 +27,7 @@ import styles from './styles';
|
||||||
import log from '../../utils/log';
|
import log from '../../utils/log';
|
||||||
import EventEmitter from '../../utils/events';
|
import EventEmitter from '../../utils/events';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import RoomHeaderView, { RightButtons, RoomHeaderLeft } from './Header';
|
import RoomHeaderView, { RightButtons, LeftButtons } from './Header';
|
||||||
import StatusBar from '../../containers/StatusBar';
|
import StatusBar from '../../containers/StatusBar';
|
||||||
import Separator from './Separator';
|
import Separator from './Separator';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
|
@ -53,6 +54,7 @@ import Banner from './Banner';
|
||||||
import Navigation from '../../lib/Navigation';
|
import Navigation from '../../lib/Navigation';
|
||||||
import SafeAreaView from '../../containers/SafeAreaView';
|
import SafeAreaView from '../../containers/SafeAreaView';
|
||||||
import { withDimensions } from '../../dimensions';
|
import { withDimensions } from '../../dimensions';
|
||||||
|
import { getHeaderTitlePosition } from '../../containers/Header';
|
||||||
|
|
||||||
const stateAttrsUpdate = [
|
const stateAttrsUpdate = [
|
||||||
'joined',
|
'joined',
|
||||||
|
@ -91,7 +93,8 @@ class RoomView extends React.Component {
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string,
|
||||||
replyBroadcast: PropTypes.func,
|
replyBroadcast: PropTypes.func,
|
||||||
width: PropTypes.number,
|
width: PropTypes.number,
|
||||||
height: PropTypes.number
|
height: PropTypes.number,
|
||||||
|
insets: PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -178,7 +181,7 @@ class RoomView extends React.Component {
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
const { state } = this;
|
const { state } = this;
|
||||||
const { roomUpdate, member } = state;
|
const { roomUpdate, member } = state;
|
||||||
const { appState, theme } = this.props;
|
const { appState, theme, insets } = this.props;
|
||||||
if (theme !== nextProps.theme) {
|
if (theme !== nextProps.theme) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -192,12 +195,15 @@ class RoomView extends React.Component {
|
||||||
if (stateUpdated) {
|
if (stateUpdated) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (!isEqual(nextProps.insets, insets)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return roomAttrsUpdate.some(key => !isEqual(nextState.roomUpdate[key], roomUpdate[key]));
|
return roomAttrsUpdate.some(key => !isEqual(nextState.roomUpdate[key], roomUpdate[key]));
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
const { roomUpdate } = this.state;
|
const { roomUpdate } = this.state;
|
||||||
const { appState } = this.props;
|
const { appState, insets } = this.props;
|
||||||
|
|
||||||
if (appState === 'foreground' && appState !== prevProps.appState && this.rid) {
|
if (appState === 'foreground' && appState !== prevProps.appState && this.rid) {
|
||||||
this.onForegroundInteraction = InteractionManager.runAfterInteractions(() => {
|
this.onForegroundInteraction = InteractionManager.runAfterInteractions(() => {
|
||||||
|
@ -222,6 +228,9 @@ class RoomView extends React.Component {
|
||||||
if (((roomUpdate.fname !== prevState.roomUpdate.fname) || (roomUpdate.name !== prevState.roomUpdate.name)) && !this.tmid) {
|
if (((roomUpdate.fname !== prevState.roomUpdate.fname) || (roomUpdate.name !== prevState.roomUpdate.name)) && !this.tmid) {
|
||||||
this.setHeader();
|
this.setHeader();
|
||||||
}
|
}
|
||||||
|
if (insets.left !== prevProps.insets.left || insets.right !== prevProps.insets.right) {
|
||||||
|
this.setHeader();
|
||||||
|
}
|
||||||
this.setReadOnly();
|
this.setReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,7 +290,7 @@ class RoomView extends React.Component {
|
||||||
setHeader = () => {
|
setHeader = () => {
|
||||||
const { room, unreadsCount, roomUserId: stateRoomUserId } = this.state;
|
const { room, unreadsCount, roomUserId: stateRoomUserId } = this.state;
|
||||||
const {
|
const {
|
||||||
navigation, route, isMasterDetail, theme, baseUrl, user
|
navigation, route, isMasterDetail, theme, baseUrl, user, insets
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const rid = route.params?.rid;
|
const rid = route.params?.rid;
|
||||||
const prid = route.params?.prid;
|
const prid = route.params?.prid;
|
||||||
|
@ -299,9 +308,29 @@ class RoomView extends React.Component {
|
||||||
if (!rid) {
|
if (!rid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const headerTitlePosition = getHeaderTitlePosition(insets);
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
headerShown: true,
|
headerShown: true,
|
||||||
headerTitleAlign: 'left',
|
headerTitleAlign: 'left',
|
||||||
|
headerTitleContainerStyle: {
|
||||||
|
left: headerTitlePosition.left,
|
||||||
|
right: headerTitlePosition.right
|
||||||
|
},
|
||||||
|
headerLeft: () => (
|
||||||
|
<LeftButtons
|
||||||
|
tmid={tmid}
|
||||||
|
unreadsCount={unreadsCount}
|
||||||
|
navigation={navigation}
|
||||||
|
baseUrl={baseUrl}
|
||||||
|
userId={userId}
|
||||||
|
token={token}
|
||||||
|
title={avatar}
|
||||||
|
theme={theme}
|
||||||
|
t={t}
|
||||||
|
goRoomActionsView={this.goRoomActionsView}
|
||||||
|
isMasterDetail={isMasterDetail}
|
||||||
|
/>
|
||||||
|
),
|
||||||
headerTitle: () => (
|
headerTitle: () => (
|
||||||
<RoomHeaderView
|
<RoomHeaderView
|
||||||
rid={rid}
|
rid={rid}
|
||||||
|
@ -323,21 +352,6 @@ class RoomView extends React.Component {
|
||||||
navigation={navigation}
|
navigation={navigation}
|
||||||
toggleFollowThread={this.toggleFollowThread}
|
toggleFollowThread={this.toggleFollowThread}
|
||||||
/>
|
/>
|
||||||
),
|
|
||||||
headerLeft: () => (
|
|
||||||
<RoomHeaderLeft
|
|
||||||
tmid={tmid}
|
|
||||||
unreadsCount={unreadsCount}
|
|
||||||
navigation={navigation}
|
|
||||||
baseUrl={baseUrl}
|
|
||||||
userId={userId}
|
|
||||||
token={token}
|
|
||||||
title={avatar}
|
|
||||||
theme={theme}
|
|
||||||
t={t}
|
|
||||||
goRoomActionsView={this.goRoomActionsView}
|
|
||||||
isMasterDetail={isMasterDetail}
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1040,4 +1054,4 @@ const mapDispatchToProps = dispatch => ({
|
||||||
replyBroadcast: message => dispatch(replyBroadcastAction(message))
|
replyBroadcast: message => dispatch(replyBroadcastAction(message))
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(withDimensions(withTheme(RoomView)));
|
export default connect(mapStateToProps, mapDispatchToProps)(withDimensions(withTheme(withSafeAreaInsets(RoomView))));
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import {
|
|
||||||
Text, View, TouchableOpacity, StyleSheet
|
|
||||||
} from 'react-native';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import I18n from '../../../i18n';
|
|
||||||
import sharedStyles from '../../Styles';
|
|
||||||
import { themes } from '../../../constants/colors';
|
|
||||||
import { CustomIcon } from '../../../lib/Icons';
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
},
|
|
||||||
button: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center'
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
fontSize: 14,
|
|
||||||
...sharedStyles.textRegular
|
|
||||||
},
|
|
||||||
server: {
|
|
||||||
fontSize: 12,
|
|
||||||
...sharedStyles.textRegular
|
|
||||||
},
|
|
||||||
disclosure: {
|
|
||||||
marginLeft: 3,
|
|
||||||
marginTop: 1,
|
|
||||||
width: 12,
|
|
||||||
height: 9
|
|
||||||
},
|
|
||||||
upsideDown: {
|
|
||||||
transform: [{ scaleY: -1 }]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const HeaderTitle = React.memo(({ connecting, isFetching, theme }) => {
|
|
||||||
let title = I18n.t('Messages');
|
|
||||||
if (connecting) {
|
|
||||||
title = I18n.t('Connecting');
|
|
||||||
}
|
|
||||||
if (isFetching) {
|
|
||||||
title = I18n.t('Updating');
|
|
||||||
}
|
|
||||||
return <Text style={[styles.title, { color: themes[theme].headerTitleColor }]}>{title}</Text>;
|
|
||||||
});
|
|
||||||
|
|
||||||
const Header = React.memo(({
|
|
||||||
connecting, isFetching, serverName, showServerDropdown, onPress, theme
|
|
||||||
}) => (
|
|
||||||
<View style={styles.container}>
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={onPress}
|
|
||||||
testID='rooms-list-header-server-dropdown-button'
|
|
||||||
style={styles.container}
|
|
||||||
// disabled={connecting || isFetching}
|
|
||||||
>
|
|
||||||
<HeaderTitle connecting={connecting} isFetching={isFetching} theme={theme} />
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text style={[styles.server, { color: themes[theme].headerTintColor }]} numberOfLines={1}>{serverName}</Text>
|
|
||||||
<CustomIcon
|
|
||||||
name='chevron-down'
|
|
||||||
color={themes[theme].headerTintColor}
|
|
||||||
style={[showServerDropdown && styles.upsideDown]}
|
|
||||||
size={18}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
));
|
|
||||||
|
|
||||||
Header.propTypes = {
|
|
||||||
connecting: PropTypes.bool,
|
|
||||||
isFetching: PropTypes.bool,
|
|
||||||
serverName: PropTypes.string,
|
|
||||||
theme: PropTypes.string,
|
|
||||||
showServerDropdown: PropTypes.bool.isRequired,
|
|
||||||
onPress: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
Header.defaultProps = {
|
|
||||||
serverName: 'Rocket.Chat'
|
|
||||||
};
|
|
||||||
|
|
||||||
HeaderTitle.propTypes = {
|
|
||||||
connecting: PropTypes.bool,
|
|
||||||
isFetching: PropTypes.bool,
|
|
||||||
theme: PropTypes.string
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Header;
|
|
|
@ -9,26 +9,23 @@ import I18n from '../../../i18n';
|
||||||
import sharedStyles from '../../Styles';
|
import sharedStyles from '../../Styles';
|
||||||
import { themes } from '../../../constants/colors';
|
import { themes } from '../../../constants/colors';
|
||||||
import { CustomIcon } from '../../../lib/Icons';
|
import { CustomIcon } from '../../../lib/Icons';
|
||||||
|
import { isTablet, isIOS } from '../../../utils/deviceInfo';
|
||||||
|
import { useOrientation } from '../../../dimensions';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
justifyContent: 'center'
|
justifyContent: 'center',
|
||||||
|
marginLeft: isTablet ? 10 : 0
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center'
|
||||||
marginRight: 64
|
|
||||||
},
|
},
|
||||||
server: {
|
title: {
|
||||||
fontSize: 20,
|
...sharedStyles.textSemibold
|
||||||
...sharedStyles.textRegular
|
|
||||||
},
|
},
|
||||||
serverSmall: {
|
subtitle: {
|
||||||
fontSize: 16
|
|
||||||
},
|
|
||||||
updating: {
|
|
||||||
fontSize: 14,
|
|
||||||
...sharedStyles.textRegular
|
...sharedStyles.textRegular
|
||||||
},
|
},
|
||||||
upsideDown: {
|
upsideDown: {
|
||||||
|
@ -37,41 +34,55 @@ const styles = StyleSheet.create({
|
||||||
});
|
});
|
||||||
|
|
||||||
const Header = React.memo(({
|
const Header = React.memo(({
|
||||||
connecting, isFetching, serverName, showServerDropdown, showSearchHeader, theme, onSearchChangeText, onPress
|
connecting, connected, isFetching, serverName, server, showServerDropdown, showSearchHeader, theme, onSearchChangeText, onPress
|
||||||
}) => {
|
}) => {
|
||||||
const titleColorStyle = { color: themes[theme].headerTitleColor };
|
const titleColorStyle = { color: themes[theme].headerTitleColor };
|
||||||
const isLight = theme === 'light';
|
const isLight = theme === 'light';
|
||||||
|
const { isLandscape } = useOrientation();
|
||||||
|
const scale = isIOS && isLandscape && !isTablet ? 0.8 : 1;
|
||||||
|
const titleFontSize = 16 * scale;
|
||||||
|
const subTitleFontSize = 12 * scale;
|
||||||
|
|
||||||
if (showSearchHeader) {
|
if (showSearchHeader) {
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<TextInput
|
<TextInput
|
||||||
autoFocus
|
autoFocus
|
||||||
style={[styles.server, isLight && titleColorStyle]}
|
style={[styles.title, isLight && titleColorStyle, { fontSize: titleFontSize }]}
|
||||||
placeholder='Search'
|
placeholder='Search'
|
||||||
onChangeText={onSearchChangeText}
|
onChangeText={onSearchChangeText}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
|
testID='rooms-list-view-search-input'
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
let subtitle;
|
||||||
|
if (connecting) {
|
||||||
|
subtitle = I18n.t('Connecting');
|
||||||
|
} else if (isFetching) {
|
||||||
|
subtitle = I18n.t('Updating');
|
||||||
|
} else if (!connected) {
|
||||||
|
subtitle = I18n.t('Waiting_for_network');
|
||||||
|
} else {
|
||||||
|
subtitle = server?.replace(/(^\w+:|^)\/\//, '');
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
testID='rooms-list-header-server-dropdown-button'
|
testID='rooms-list-header-server-dropdown-button'
|
||||||
disabled={connecting || isFetching}
|
|
||||||
>
|
>
|
||||||
{connecting ? <Text style={[styles.updating, titleColorStyle]}>{I18n.t('Connecting')}</Text> : null}
|
|
||||||
{isFetching ? <Text style={[styles.updating, titleColorStyle]}>{I18n.t('Updating')}</Text> : null}
|
|
||||||
<View style={styles.button}>
|
<View style={styles.button}>
|
||||||
<Text style={[styles.server, isFetching && styles.serverSmall, titleColorStyle]} numberOfLines={1}>{serverName}</Text>
|
<Text style={[styles.title, isFetching && styles.serverSmall, titleColorStyle, { fontSize: titleFontSize }]} numberOfLines={1}>{serverName}</Text>
|
||||||
<CustomIcon
|
<CustomIcon
|
||||||
name='chevron-down'
|
name='chevron-down'
|
||||||
color={themes[theme].headerTintColor}
|
color={themes[theme].headerTintColor}
|
||||||
style={[showServerDropdown && styles.upsideDown]}
|
style={[showServerDropdown && styles.upsideDown, { fontSize: subTitleFontSize }]}
|
||||||
size={18}
|
size={18}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
{subtitle ? <Text style={[styles.subtitle, { color: themes[theme].auxiliaryText }]} numberOfLines={1}>{subtitle}</Text> : null}
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
@ -83,8 +94,10 @@ Header.propTypes = {
|
||||||
onPress: PropTypes.func.isRequired,
|
onPress: PropTypes.func.isRequired,
|
||||||
onSearchChangeText: PropTypes.func.isRequired,
|
onSearchChangeText: PropTypes.func.isRequired,
|
||||||
connecting: PropTypes.bool,
|
connecting: PropTypes.bool,
|
||||||
|
connected: PropTypes.bool,
|
||||||
isFetching: PropTypes.bool,
|
isFetching: PropTypes.bool,
|
||||||
serverName: PropTypes.string,
|
serverName: PropTypes.string,
|
||||||
|
server: PropTypes.string,
|
||||||
theme: PropTypes.string
|
theme: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,8 +18,10 @@ class RoomsListHeaderView extends PureComponent {
|
||||||
showSearchHeader: PropTypes.bool,
|
showSearchHeader: PropTypes.bool,
|
||||||
serverName: PropTypes.string,
|
serverName: PropTypes.string,
|
||||||
connecting: PropTypes.bool,
|
connecting: PropTypes.bool,
|
||||||
|
connected: PropTypes.bool,
|
||||||
isFetching: PropTypes.bool,
|
isFetching: PropTypes.bool,
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string,
|
||||||
|
server: PropTypes.string,
|
||||||
open: PropTypes.func,
|
open: PropTypes.func,
|
||||||
close: PropTypes.func,
|
close: PropTypes.func,
|
||||||
closeSort: PropTypes.func,
|
closeSort: PropTypes.func,
|
||||||
|
@ -68,16 +70,18 @@ class RoomsListHeaderView extends PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
serverName, showServerDropdown, showSearchHeader, connecting, isFetching, theme
|
serverName, showServerDropdown, showSearchHeader, connecting, connected, isFetching, theme, server
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Header
|
<Header
|
||||||
theme={theme}
|
theme={theme}
|
||||||
serverName={serverName}
|
serverName={serverName}
|
||||||
|
server={server}
|
||||||
showServerDropdown={showServerDropdown}
|
showServerDropdown={showServerDropdown}
|
||||||
showSearchHeader={showSearchHeader}
|
showSearchHeader={showSearchHeader}
|
||||||
connecting={connecting}
|
connecting={connecting}
|
||||||
|
connected={connected}
|
||||||
isFetching={isFetching}
|
isFetching={isFetching}
|
||||||
onPress={this.onPress}
|
onPress={this.onPress}
|
||||||
onSearchChangeText={this.onSearchChangeText}
|
onSearchChangeText={this.onSearchChangeText}
|
||||||
|
@ -91,8 +95,10 @@ const mapStateToProps = state => ({
|
||||||
showSortDropdown: state.rooms.showSortDropdown,
|
showSortDropdown: state.rooms.showSortDropdown,
|
||||||
showSearchHeader: state.rooms.showSearchHeader,
|
showSearchHeader: state.rooms.showSearchHeader,
|
||||||
connecting: state.meteor.connecting || state.server.loading,
|
connecting: state.meteor.connecting || state.server.loading,
|
||||||
|
connected: state.meteor.connected,
|
||||||
isFetching: state.rooms.isFetching,
|
isFetching: state.rooms.isFetching,
|
||||||
serverName: state.settings.Site_Name
|
serverName: state.settings.Site_Name,
|
||||||
|
server: state.server.server
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchtoProps = dispatch => ({
|
const mapDispatchtoProps = dispatch => ({
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import SearchBox from '../../../containers/SearchBox';
|
|
||||||
import { isIOS } from '../../../utils/deviceInfo';
|
|
||||||
import { withTheme } from '../../../theme';
|
|
||||||
|
|
||||||
const SearchBar = React.memo(({
|
|
||||||
theme, onChangeSearchText, inputRef, searching, onCancelSearchPress, onSearchFocus
|
|
||||||
}) => {
|
|
||||||
if (isIOS) {
|
|
||||||
return (
|
|
||||||
<SearchBox
|
|
||||||
onChangeText={onChangeSearchText}
|
|
||||||
testID='rooms-list-view-search'
|
|
||||||
inputRef={inputRef}
|
|
||||||
theme={theme}
|
|
||||||
hasCancel={searching}
|
|
||||||
onCancelPress={onCancelSearchPress}
|
|
||||||
onFocus={onSearchFocus}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
SearchBar.propTypes = {
|
|
||||||
theme: PropTypes.string,
|
|
||||||
searching: PropTypes.bool,
|
|
||||||
inputRef: PropTypes.func,
|
|
||||||
onChangeSearchText: PropTypes.func,
|
|
||||||
onCancelSearchPress: PropTypes.func,
|
|
||||||
onSearchFocus: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
export default withTheme(SearchBar);
|
|
|
@ -1,28 +1,16 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import SearchBar from './SearchBar';
|
|
||||||
import Directory from './Directory';
|
import Directory from './Directory';
|
||||||
import Sort from './Sort';
|
import Sort from './Sort';
|
||||||
|
|
||||||
const ListHeader = React.memo(({
|
const ListHeader = React.memo(({
|
||||||
searching,
|
searching,
|
||||||
sortBy,
|
sortBy,
|
||||||
onChangeSearchText,
|
|
||||||
toggleSort,
|
toggleSort,
|
||||||
goDirectory,
|
goDirectory
|
||||||
inputRef,
|
|
||||||
onCancelSearchPress,
|
|
||||||
onSearchFocus
|
|
||||||
}) => (
|
}) => (
|
||||||
<>
|
<>
|
||||||
<SearchBar
|
|
||||||
inputRef={inputRef}
|
|
||||||
searching={searching}
|
|
||||||
onChangeSearchText={onChangeSearchText}
|
|
||||||
onCancelSearchPress={onCancelSearchPress}
|
|
||||||
onSearchFocus={onSearchFocus}
|
|
||||||
/>
|
|
||||||
<Directory searching={searching} goDirectory={goDirectory} />
|
<Directory searching={searching} goDirectory={goDirectory} />
|
||||||
<Sort searching={searching} sortBy={sortBy} toggleSort={toggleSort} />
|
<Sort searching={searching} sortBy={sortBy} toggleSort={toggleSort} />
|
||||||
</>
|
</>
|
||||||
|
@ -31,12 +19,8 @@ const ListHeader = React.memo(({
|
||||||
ListHeader.propTypes = {
|
ListHeader.propTypes = {
|
||||||
searching: PropTypes.bool,
|
searching: PropTypes.bool,
|
||||||
sortBy: PropTypes.string,
|
sortBy: PropTypes.string,
|
||||||
onChangeSearchText: PropTypes.func,
|
|
||||||
toggleSort: PropTypes.func,
|
toggleSort: PropTypes.func,
|
||||||
goDirectory: PropTypes.func,
|
goDirectory: PropTypes.func
|
||||||
inputRef: PropTypes.func,
|
|
||||||
onCancelSearchPress: PropTypes.func,
|
|
||||||
onSearchFocus: PropTypes.func
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ListHeader;
|
export default ListHeader;
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { connect } from 'react-redux';
|
||||||
import { isEqual, orderBy } from 'lodash';
|
import { isEqual, orderBy } from 'lodash';
|
||||||
import Orientation from 'react-native-orientation-locker';
|
import Orientation from 'react-native-orientation-locker';
|
||||||
import { Q } from '@nozbe/watermelondb';
|
import { Q } from '@nozbe/watermelondb';
|
||||||
|
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
import database from '../../lib/database';
|
import database from '../../lib/database';
|
||||||
import RocketChat from '../../lib/rocketchat';
|
import RocketChat from '../../lib/rocketchat';
|
||||||
|
@ -30,7 +31,7 @@ import {
|
||||||
} from '../../actions/rooms';
|
} from '../../actions/rooms';
|
||||||
import { appStart as appStartAction, ROOT_BACKGROUND } from '../../actions/app';
|
import { appStart as appStartAction, ROOT_BACKGROUND } from '../../actions/app';
|
||||||
import debounce from '../../utils/debounce';
|
import debounce from '../../utils/debounce';
|
||||||
import { isIOS, isAndroid, isTablet } from '../../utils/deviceInfo';
|
import { isIOS, isTablet } from '../../utils/deviceInfo';
|
||||||
import RoomsListHeaderView from './Header';
|
import RoomsListHeaderView from './Header';
|
||||||
import {
|
import {
|
||||||
DrawerButton,
|
DrawerButton,
|
||||||
|
@ -59,10 +60,9 @@ import { MAX_SIDEBAR_WIDTH } from '../../constants/tablet';
|
||||||
import { getUserSelector } from '../../selectors/login';
|
import { getUserSelector } from '../../selectors/login';
|
||||||
import { goRoom } from '../../utils/goRoom';
|
import { goRoom } from '../../utils/goRoom';
|
||||||
import SafeAreaView from '../../containers/SafeAreaView';
|
import SafeAreaView from '../../containers/SafeAreaView';
|
||||||
import Header from '../../containers/Header';
|
import Header, { getHeaderTitlePosition } from '../../containers/Header';
|
||||||
import { withDimensions } from '../../dimensions';
|
import { withDimensions } from '../../dimensions';
|
||||||
|
|
||||||
const SCROLL_OFFSET = 56;
|
|
||||||
const INITIAL_NUM_TO_RENDER = isTablet ? 20 : 12;
|
const INITIAL_NUM_TO_RENDER = isTablet ? 20 : 12;
|
||||||
const CHATS_HEADER = 'Chats';
|
const CHATS_HEADER = 'Chats';
|
||||||
const UNREAD_HEADER = 'Unread';
|
const UNREAD_HEADER = 'Unread';
|
||||||
|
@ -129,7 +129,8 @@ class RoomsListView extends React.Component {
|
||||||
connected: PropTypes.bool,
|
connected: PropTypes.bool,
|
||||||
isMasterDetail: PropTypes.bool,
|
isMasterDetail: PropTypes.bool,
|
||||||
rooms: PropTypes.array,
|
rooms: PropTypes.array,
|
||||||
width: PropTypes.number
|
width: PropTypes.number,
|
||||||
|
insets: PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -242,7 +243,7 @@ class RoomsListView extends React.Component {
|
||||||
loading,
|
loading,
|
||||||
search
|
search
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const { rooms, width } = this.props;
|
const { rooms, width, insets } = this.props;
|
||||||
if (nextState.loading !== loading) {
|
if (nextState.loading !== loading) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -255,6 +256,9 @@ class RoomsListView extends React.Component {
|
||||||
if (!isEqual(nextProps.rooms, rooms)) {
|
if (!isEqual(nextProps.rooms, rooms)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (!isEqual(nextProps.insets, insets)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
// If it's focused and there are changes, update
|
// If it's focused and there are changes, update
|
||||||
if (chatsNotEqual) {
|
if (chatsNotEqual) {
|
||||||
this.shouldUpdate = false;
|
this.shouldUpdate = false;
|
||||||
|
@ -273,7 +277,8 @@ class RoomsListView extends React.Component {
|
||||||
connected,
|
connected,
|
||||||
roomsRequest,
|
roomsRequest,
|
||||||
rooms,
|
rooms,
|
||||||
isMasterDetail
|
isMasterDetail,
|
||||||
|
insets
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { item } = this.state;
|
const { item } = this.state;
|
||||||
|
|
||||||
|
@ -298,6 +303,9 @@ class RoomsListView extends React.Component {
|
||||||
// eslint-disable-next-line react/no-did-update-set-state
|
// eslint-disable-next-line react/no-did-update-set-state
|
||||||
this.setState({ item: { rid: rooms[0] } });
|
this.setState({ item: { rid: rooms[0] } });
|
||||||
}
|
}
|
||||||
|
if (insets.left !== prevProps.insets.left || insets.right !== prevProps.insets.right) {
|
||||||
|
this.setHeader();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
@ -318,9 +326,11 @@ class RoomsListView extends React.Component {
|
||||||
|
|
||||||
getHeader = () => {
|
getHeader = () => {
|
||||||
const { searching } = this.state;
|
const { searching } = this.state;
|
||||||
const { navigation, isMasterDetail } = this.props;
|
const { navigation, isMasterDetail, insets } = this.props;
|
||||||
|
const headerTitlePosition = getHeaderTitlePosition(insets);
|
||||||
return {
|
return {
|
||||||
headerLeft: () => (searching && isAndroid ? (
|
headerTitleAlign: 'left',
|
||||||
|
headerLeft: () => (searching ? (
|
||||||
<CustomHeaderButtons left>
|
<CustomHeaderButtons left>
|
||||||
<Item
|
<Item
|
||||||
title='cancel'
|
title='cancel'
|
||||||
|
@ -332,24 +342,31 @@ class RoomsListView extends React.Component {
|
||||||
<DrawerButton
|
<DrawerButton
|
||||||
navigation={navigation}
|
navigation={navigation}
|
||||||
testID='rooms-list-view-sidebar'
|
testID='rooms-list-view-sidebar'
|
||||||
onPress={isMasterDetail ? () => navigation.navigate('ModalStackNavigator', { screen: 'SettingsView' }) : () => navigation.toggleDrawer()}
|
onPress={isMasterDetail
|
||||||
|
? () => navigation.navigate('ModalStackNavigator', { screen: 'SettingsView' })
|
||||||
|
: () => navigation.toggleDrawer()}
|
||||||
/>
|
/>
|
||||||
)),
|
)),
|
||||||
headerTitle: () => <RoomsListHeaderView />,
|
headerTitle: () => <RoomsListHeaderView />,
|
||||||
headerRight: () => (searching && isAndroid ? null : (
|
headerTitleContainerStyle: {
|
||||||
|
left: headerTitlePosition.left,
|
||||||
|
right: headerTitlePosition.right
|
||||||
|
},
|
||||||
|
headerRight: () => (searching ? null : (
|
||||||
<CustomHeaderButtons>
|
<CustomHeaderButtons>
|
||||||
{isAndroid ? (
|
<Item
|
||||||
|
title='new'
|
||||||
|
iconName='new-chat'
|
||||||
|
onPress={isMasterDetail
|
||||||
|
? () => navigation.navigate('ModalStackNavigator', { screen: 'NewMessageView' })
|
||||||
|
: () => navigation.navigate('NewMessageStackNavigator')}
|
||||||
|
testID='rooms-list-view-create-channel'
|
||||||
|
/>
|
||||||
<Item
|
<Item
|
||||||
title='search'
|
title='search'
|
||||||
iconName='magnifier'
|
iconName='magnifier'
|
||||||
onPress={this.initSearching}
|
onPress={this.initSearching}
|
||||||
/>
|
testID='rooms-list-view-search'
|
||||||
) : null}
|
|
||||||
<Item
|
|
||||||
title='new'
|
|
||||||
iconName='new-chat'
|
|
||||||
onPress={isMasterDetail ? () => navigation.navigate('ModalStackNavigator', { screen: 'NewMessageView' }) : () => navigation.navigate('NewMessageStackNavigator')}
|
|
||||||
testID='rooms-list-view-create-channel'
|
|
||||||
/>
|
/>
|
||||||
</CustomHeaderButtons>
|
</CustomHeaderButtons>
|
||||||
))
|
))
|
||||||
|
@ -476,10 +493,8 @@ class RoomsListView extends React.Component {
|
||||||
initSearching = () => {
|
initSearching = () => {
|
||||||
const { openSearchHeader } = this.props;
|
const { openSearchHeader } = this.props;
|
||||||
this.internalSetState({ searching: true }, () => {
|
this.internalSetState({ searching: true }, () => {
|
||||||
if (isAndroid) {
|
|
||||||
openSearchHeader();
|
openSearchHeader();
|
||||||
this.setHeader();
|
this.setHeader();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -493,18 +508,11 @@ class RoomsListView extends React.Component {
|
||||||
|
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
|
|
||||||
if (isIOS && this.inputRef) {
|
|
||||||
this.inputRef.blur();
|
|
||||||
this.inputRef.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ searching: false, search: [] }, () => {
|
this.setState({ searching: false, search: [] }, () => {
|
||||||
if (isAndroid) {
|
|
||||||
this.setHeader();
|
this.setHeader();
|
||||||
closeSearchHeader();
|
closeSearchHeader();
|
||||||
}
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const offset = isAndroid ? 0 : SCROLL_OFFSET;
|
const offset = 0;
|
||||||
if (this.scroll.scrollTo) {
|
if (this.scroll.scrollTo) {
|
||||||
this.scroll.scrollTo({ x: 0, y: offset, animated: true });
|
this.scroll.scrollTo({ x: 0, y: offset, animated: true });
|
||||||
} else if (this.scroll.scrollToOffset) {
|
} else if (this.scroll.scrollToOffset) {
|
||||||
|
@ -564,7 +572,7 @@ class RoomsListView extends React.Component {
|
||||||
toggleSort = () => {
|
toggleSort = () => {
|
||||||
const { toggleSortDropdown } = this.props;
|
const { toggleSortDropdown } = this.props;
|
||||||
|
|
||||||
const offset = isAndroid ? 0 : SCROLL_OFFSET;
|
const offset = 0;
|
||||||
if (this.scroll.scrollTo) {
|
if (this.scroll.scrollTo) {
|
||||||
this.scroll.scrollTo({ x: 0, y: offset, animated: true });
|
this.scroll.scrollTo({ x: 0, y: offset, animated: true });
|
||||||
} else if (this.scroll.scrollToOffset) {
|
} else if (this.scroll.scrollToOffset) {
|
||||||
|
@ -714,8 +722,7 @@ class RoomsListView extends React.Component {
|
||||||
if (handleCommandShowPreferences(event)) {
|
if (handleCommandShowPreferences(event)) {
|
||||||
navigation.navigate('SettingsView');
|
navigation.navigate('SettingsView');
|
||||||
} else if (handleCommandSearching(event)) {
|
} else if (handleCommandSearching(event)) {
|
||||||
this.scroll.scrollToOffset({ animated: true, offset: 0 });
|
this.initSearching();
|
||||||
this.inputRef.focus();
|
|
||||||
} else if (handleCommandSelectRoom(event)) {
|
} else if (handleCommandSelectRoom(event)) {
|
||||||
this.goRoomByIndex(input);
|
this.goRoomByIndex(input);
|
||||||
} else if (handleCommandPreviousRoom(event)) {
|
} else if (handleCommandPreviousRoom(event)) {
|
||||||
|
@ -744,19 +751,13 @@ class RoomsListView extends React.Component {
|
||||||
|
|
||||||
getScrollRef = ref => (this.scroll = ref);
|
getScrollRef = ref => (this.scroll = ref);
|
||||||
|
|
||||||
getInputRef = ref => (this.inputRef = ref);
|
|
||||||
|
|
||||||
renderListHeader = () => {
|
renderListHeader = () => {
|
||||||
const { searching } = this.state;
|
const { searching } = this.state;
|
||||||
const { sortBy } = this.props;
|
const { sortBy } = this.props;
|
||||||
return (
|
return (
|
||||||
<ListHeader
|
<ListHeader
|
||||||
inputRef={this.getInputRef}
|
|
||||||
searching={searching}
|
searching={searching}
|
||||||
sortBy={sortBy}
|
sortBy={sortBy}
|
||||||
onChangeSearchText={this.search}
|
|
||||||
onCancelSearchPress={this.cancelSearch}
|
|
||||||
onSearchFocus={this.initSearching}
|
|
||||||
toggleSort={this.toggleSort}
|
toggleSort={this.toggleSort}
|
||||||
goDirectory={this.goDirectory}
|
goDirectory={this.goDirectory}
|
||||||
/>
|
/>
|
||||||
|
@ -869,7 +870,6 @@ class RoomsListView extends React.Component {
|
||||||
ref={this.getScrollRef}
|
ref={this.getScrollRef}
|
||||||
data={searching ? search : chats}
|
data={searching ? search : chats}
|
||||||
extraData={searching ? search : chats}
|
extraData={searching ? search : chats}
|
||||||
contentOffset={isIOS ? { x: 0, y: SCROLL_OFFSET } : {}}
|
|
||||||
keyExtractor={keyExtractor}
|
keyExtractor={keyExtractor}
|
||||||
style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]}
|
style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]}
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
|
@ -953,4 +953,4 @@ const mapDispatchToProps = dispatch => ({
|
||||||
closeServerDropdown: () => dispatch(closeServerDropdownAction())
|
closeServerDropdown: () => dispatch(closeServerDropdownAction())
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(withDimensions(withTheme(RoomsListView)));
|
export default connect(mapStateToProps, mapDispatchToProps)(withDimensions(withTheme(withSafeAreaInsets(RoomsListView))));
|
||||||
|
|
|
@ -23,7 +23,7 @@ export default StyleSheet.create({
|
||||||
sortToggleText: {
|
sortToggleText: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
marginLeft: 15,
|
marginLeft: 12,
|
||||||
...sharedStyles.textRegular
|
...sharedStyles.textRegular
|
||||||
},
|
},
|
||||||
dropdownContainer: {
|
dropdownContainer: {
|
||||||
|
@ -50,16 +50,16 @@ export default StyleSheet.create({
|
||||||
},
|
},
|
||||||
sortSeparator: {
|
sortSeparator: {
|
||||||
height: StyleSheet.hairlineWidth,
|
height: StyleSheet.hairlineWidth,
|
||||||
marginHorizontal: 15,
|
marginHorizontal: 12,
|
||||||
flex: 1
|
flex: 1
|
||||||
},
|
},
|
||||||
sortIcon: {
|
sortIcon: {
|
||||||
width: 22,
|
width: 22,
|
||||||
height: 22,
|
height: 22,
|
||||||
marginHorizontal: 15
|
marginHorizontal: 12
|
||||||
},
|
},
|
||||||
groupTitleContainer: {
|
groupTitleContainer: {
|
||||||
paddingHorizontal: 15,
|
paddingHorizontal: 12,
|
||||||
paddingTop: 17,
|
paddingTop: 17,
|
||||||
paddingBottom: 10
|
paddingBottom: 10
|
||||||
},
|
},
|
||||||
|
@ -75,12 +75,12 @@ export default StyleSheet.create({
|
||||||
},
|
},
|
||||||
serverHeaderText: {
|
serverHeaderText: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
marginLeft: 15,
|
marginLeft: 12,
|
||||||
...sharedStyles.textRegular
|
...sharedStyles.textRegular
|
||||||
},
|
},
|
||||||
serverHeaderAdd: {
|
serverHeaderAdd: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
marginRight: 15,
|
marginRight: 12,
|
||||||
paddingVertical: 10,
|
paddingVertical: 10,
|
||||||
...sharedStyles.textRegular
|
...sharedStyles.textRegular
|
||||||
},
|
},
|
||||||
|
@ -95,7 +95,7 @@ export default StyleSheet.create({
|
||||||
serverIcon: {
|
serverIcon: {
|
||||||
width: 42,
|
width: 42,
|
||||||
height: 42,
|
height: 42,
|
||||||
marginHorizontal: 15,
|
marginHorizontal: 12,
|
||||||
marginVertical: 13,
|
marginVertical: 13,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
resizeMode: 'contain'
|
resizeMode: 'contain'
|
||||||
|
@ -120,7 +120,7 @@ export default StyleSheet.create({
|
||||||
directoryIcon: {
|
directoryIcon: {
|
||||||
width: 22,
|
width: 22,
|
||||||
height: 22,
|
height: 22,
|
||||||
marginHorizontal: 15
|
marginHorizontal: 12
|
||||||
},
|
},
|
||||||
directoryText: {
|
directoryText: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
|
|
|
@ -72,6 +72,14 @@ async function sleep(ms) {
|
||||||
return new Promise(res => setTimeout(res, ms));
|
return new Promise(res => setTimeout(res, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function searchRoom(room) {
|
||||||
|
await element(by.id('rooms-list-view-search')).tap();
|
||||||
|
await expect(element(by.id('rooms-list-view-search-input'))).toExist();
|
||||||
|
await waitFor(element(by.id('rooms-list-view-search-input'))).toExist().withTimeout(5000);
|
||||||
|
await element(by.id('rooms-list-view-search-input')).typeText(room);
|
||||||
|
await sleep(2000);
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
navigateToWorkspace,
|
navigateToWorkspace,
|
||||||
navigateToLogin,
|
navigateToLogin,
|
||||||
|
@ -80,5 +88,6 @@ module.exports = {
|
||||||
logout,
|
logout,
|
||||||
createUser,
|
createUser,
|
||||||
tapBack,
|
tapBack,
|
||||||
sleep
|
sleep,
|
||||||
|
searchRoom
|
||||||
};
|
};
|
|
@ -3,7 +3,7 @@ const {
|
||||||
} = require('detox');
|
} = require('detox');
|
||||||
const OTP = require('otp.js');
|
const OTP = require('otp.js');
|
||||||
const GA = OTP.googleAuthenticator;
|
const GA = OTP.googleAuthenticator;
|
||||||
const { navigateToLogin, login, tapBack, sleep, createUser } = require('../../helpers/app');
|
const { navigateToLogin, login, tapBack, sleep, searchRoom } = require('../../helpers/app');
|
||||||
const data = require('../../data');
|
const data = require('../../data');
|
||||||
|
|
||||||
describe('Broadcast room', () => {
|
describe('Broadcast room', () => {
|
||||||
|
@ -73,9 +73,7 @@ describe('Broadcast room', () => {
|
||||||
await sleep(1000);
|
await sleep(1000);
|
||||||
await element(by.id('two-factor-send')).tap();
|
await element(by.id('two-factor-send')).tap();
|
||||||
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
|
||||||
await element(by.type('UIScrollView')).atIndex(1).scrollTo('top');
|
await searchRoom(`broadcast${ data.random }`);
|
||||||
await element(by.id('rooms-list-view-search')).typeText(`broadcast${ data.random }`);
|
|
||||||
await sleep(2000);
|
|
||||||
await waitFor(element(by.id(`rooms-list-view-item-broadcast${ data.random }`))).toExist().withTimeout(60000);
|
await waitFor(element(by.id(`rooms-list-view-item-broadcast${ data.random }`))).toExist().withTimeout(60000);
|
||||||
await expect(element(by.id(`rooms-list-view-item-broadcast${ data.random }`))).toExist();
|
await expect(element(by.id(`rooms-list-view-item-broadcast${ data.random }`))).toExist();
|
||||||
await element(by.id(`rooms-list-view-item-broadcast${ data.random }`)).tap();
|
await element(by.id(`rooms-list-view-item-broadcast${ data.random }`)).tap();
|
||||||
|
|
|
@ -2,7 +2,7 @@ const {
|
||||||
device, expect, element, by, waitFor
|
device, expect, element, by, waitFor
|
||||||
} = require('detox');
|
} = require('detox');
|
||||||
const data = require('../../data');
|
const data = require('../../data');
|
||||||
const { tapBack, sleep } = require('../../helpers/app');
|
const { tapBack, sleep, searchRoom } = require('../../helpers/app');
|
||||||
|
|
||||||
const room = 'detox-public';
|
const room = 'detox-public';
|
||||||
|
|
||||||
|
@ -16,9 +16,7 @@ async function mockMessage(message) {
|
||||||
|
|
||||||
async function navigateToRoom() {
|
async function navigateToRoom() {
|
||||||
await sleep(2000);
|
await sleep(2000);
|
||||||
await element(by.type('UIScrollView')).atIndex(1).scrollTo('top');
|
await searchRoom(room);
|
||||||
await element(by.id('rooms-list-view-search')).typeText(room);
|
|
||||||
await sleep(2000);
|
|
||||||
await waitFor(element(by.id(`rooms-list-view-item-${ room }`)).atIndex(0)).toBeVisible().withTimeout(60000);
|
await waitFor(element(by.id(`rooms-list-view-item-${ room }`)).atIndex(0)).toBeVisible().withTimeout(60000);
|
||||||
await element(by.id(`rooms-list-view-item-${ room }`)).atIndex(0).tap();
|
await element(by.id(`rooms-list-view-item-${ room }`)).atIndex(0).tap();
|
||||||
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const {
|
const {
|
||||||
device, expect, element, by, waitFor
|
device, expect, element, by, waitFor
|
||||||
} = require('detox');
|
} = require('detox');
|
||||||
const { logout, tapBack, sleep } = require('../../helpers/app');
|
const { logout, tapBack, sleep, searchRoom } = require('../../helpers/app');
|
||||||
|
|
||||||
describe('Rooms list screen', () => {
|
describe('Rooms list screen', () => {
|
||||||
describe('Render', () => {
|
describe('Render', () => {
|
||||||
|
@ -27,10 +27,7 @@ describe('Rooms list screen', () => {
|
||||||
|
|
||||||
describe('Usage', () => {
|
describe('Usage', () => {
|
||||||
it('should search room and navigate', async() => {
|
it('should search room and navigate', async() => {
|
||||||
await element(by.type('UIScrollView')).atIndex(1).scrollTo('top');
|
await searchRoom('rocket.cat');
|
||||||
await waitFor(element(by.id('rooms-list-view-search'))).toExist().withTimeout(2000);
|
|
||||||
await element(by.id('rooms-list-view-search')).typeText('rocket.cat');
|
|
||||||
await sleep(2000);
|
|
||||||
await waitFor(element(by.id('rooms-list-view-item-rocket.cat'))).toBeVisible().withTimeout(60000);
|
await waitFor(element(by.id('rooms-list-view-item-rocket.cat'))).toBeVisible().withTimeout(60000);
|
||||||
await expect(element(by.id('rooms-list-view-item-rocket.cat'))).toBeVisible();
|
await expect(element(by.id('rooms-list-view-item-rocket.cat'))).toBeVisible();
|
||||||
await element(by.id('rooms-list-view-item-rocket.cat')).tap();
|
await element(by.id('rooms-list-view-item-rocket.cat')).tap();
|
||||||
|
@ -41,7 +38,6 @@ describe('Rooms list screen', () => {
|
||||||
await tapBack();
|
await tapBack();
|
||||||
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||||
// await element(by.id('rooms-list-view-search')).typeText('');
|
|
||||||
await sleep(2000);
|
await sleep(2000);
|
||||||
await waitFor(element(by.id('rooms-list-view-item-rocket.cat'))).toExist().withTimeout(60000);
|
await waitFor(element(by.id('rooms-list-view-item-rocket.cat'))).toExist().withTimeout(60000);
|
||||||
await expect(element(by.id('rooms-list-view-item-rocket.cat'))).toExist();
|
await expect(element(by.id('rooms-list-view-item-rocket.cat'))).toExist();
|
||||||
|
|
|
@ -2,7 +2,7 @@ const {
|
||||||
device, expect, element, by, waitFor
|
device, expect, element, by, waitFor
|
||||||
} = require('detox');
|
} = require('detox');
|
||||||
const data = require('../../data');
|
const data = require('../../data');
|
||||||
const { tapBack, sleep } = require('../../helpers/app');
|
const { tapBack, sleep, searchRoom } = require('../../helpers/app');
|
||||||
|
|
||||||
async function mockMessage(message) {
|
async function mockMessage(message) {
|
||||||
await element(by.id('messagebox-input')).tap();
|
await element(by.id('messagebox-input')).tap();
|
||||||
|
@ -13,9 +13,7 @@ async function mockMessage(message) {
|
||||||
};
|
};
|
||||||
|
|
||||||
async function navigateToRoom() {
|
async function navigateToRoom() {
|
||||||
await element(by.type('UIScrollView')).atIndex(1).scrollTo('top');
|
await searchRoom(`private${ data.random }`);
|
||||||
await element(by.id('rooms-list-view-search')).typeText(`private${ data.random }`);
|
|
||||||
await sleep(2000);
|
|
||||||
await waitFor(element(by.id(`rooms-list-view-item-private${ data.random }`))).toExist().withTimeout(60000);
|
await waitFor(element(by.id(`rooms-list-view-item-private${ data.random }`))).toExist().withTimeout(60000);
|
||||||
await element(by.id(`rooms-list-view-item-private${ data.random }`)).tap();
|
await element(by.id(`rooms-list-view-item-private${ data.random }`)).tap();
|
||||||
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
|
||||||
|
|
|
@ -2,7 +2,7 @@ const {
|
||||||
device, expect, element, by, waitFor
|
device, expect, element, by, waitFor
|
||||||
} = require('detox');
|
} = require('detox');
|
||||||
const data = require('../../data');
|
const data = require('../../data');
|
||||||
const { tapBack, sleep } = require('../../helpers/app');
|
const { tapBack, sleep, searchRoom } = require('../../helpers/app');
|
||||||
|
|
||||||
const scrollDown = 200;
|
const scrollDown = 200;
|
||||||
|
|
||||||
|
@ -13,10 +13,7 @@ async function navigateToRoomActions(type) {
|
||||||
} else {
|
} else {
|
||||||
room = `private${ data.random }`;
|
room = `private${ data.random }`;
|
||||||
}
|
}
|
||||||
await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(10000);
|
await searchRoom(room);
|
||||||
await element(by.type('UIScrollView')).atIndex(1).scrollTo('top');
|
|
||||||
await element(by.id('rooms-list-view-search')).typeText(room);
|
|
||||||
await sleep(2000);
|
|
||||||
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(60000);
|
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(60000);
|
||||||
await element(by.id(`rooms-list-view-item-${ room }`)).tap();
|
await element(by.id(`rooms-list-view-item-${ room }`)).tap();
|
||||||
await waitFor(element(by.id('room-view'))).toExist().withTimeout(2000);
|
await waitFor(element(by.id('room-view'))).toExist().withTimeout(2000);
|
||||||
|
|
|
@ -2,7 +2,7 @@ const {
|
||||||
device, expect, element, by, waitFor
|
device, expect, element, by, waitFor
|
||||||
} = require('detox');
|
} = require('detox');
|
||||||
const data = require('../../data');
|
const data = require('../../data');
|
||||||
const { tapBack, sleep } = require('../../helpers/app');
|
const { tapBack, sleep, searchRoom } = require('../../helpers/app');
|
||||||
|
|
||||||
async function navigateToRoomInfo(type) {
|
async function navigateToRoomInfo(type) {
|
||||||
let room;
|
let room;
|
||||||
|
@ -11,10 +11,7 @@ async function navigateToRoomInfo(type) {
|
||||||
} else {
|
} else {
|
||||||
room = `private${ data.random }`;
|
room = `private${ data.random }`;
|
||||||
}
|
}
|
||||||
await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(10000);
|
await searchRoom(room);
|
||||||
await element(by.type('UIScrollView')).atIndex(1).swipe('down');
|
|
||||||
await element(by.id('rooms-list-view-search')).typeText(room);
|
|
||||||
await sleep(2000);
|
|
||||||
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(60000);
|
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(60000);
|
||||||
await element(by.id(`rooms-list-view-item-${ room }`)).tap();
|
await element(by.id(`rooms-list-view-item-${ room }`)).tap();
|
||||||
await waitFor(element(by.id('room-view'))).toExist().withTimeout(2000);
|
await waitFor(element(by.id('room-view'))).toExist().withTimeout(2000);
|
||||||
|
@ -311,7 +308,6 @@ describe('Room info screen', () => {
|
||||||
await expect(element(by.text('Yes, delete it!'))).toExist();
|
await expect(element(by.text('Yes, delete it!'))).toExist();
|
||||||
await element(by.text('Yes, delete it!')).tap();
|
await element(by.text('Yes, delete it!')).tap();
|
||||||
await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(10000);
|
await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(10000);
|
||||||
// await element(by.id('rooms-list-view-search')).typeText('');
|
|
||||||
await sleep(2000);
|
await sleep(2000);
|
||||||
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toBeNotVisible().withTimeout(60000);
|
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toBeNotVisible().withTimeout(60000);
|
||||||
await expect(element(by.id(`rooms-list-view-item-${ room }`))).toBeNotVisible();
|
await expect(element(by.id(`rooms-list-view-item-${ room }`))).toBeNotVisible();
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
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
|
||||||
|
},
|
||||||
|
});
|
Loading…
Reference in New Issue