[IMPROVE] Use UI Elements from react-navigation (#4314)
Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
2e8b7d7755
commit
1027b6c9e6
|
@ -97,7 +97,7 @@ const ActionSheetContentWithInputAndSubmit = ({
|
|||
const { hideActionSheet } = useActionSheet();
|
||||
|
||||
return (
|
||||
<View style={sharedStyles.containerScrollView}>
|
||||
<View style={sharedStyles.containerScrollView} testID='action-sheet-content-with-input-and-submit'>
|
||||
<>
|
||||
<View style={styles.titleContainer}>
|
||||
{iconName ? <CustomIcon name={iconName} size={32} color={iconColor || colors.dangerColor} /> : null}
|
||||
|
|
|
@ -10,7 +10,7 @@ export const IconSet = createIconSetFromIcoMoon(icoMoonConfig, 'custom', 'custom
|
|||
|
||||
export type TIconsName = keyof typeof mappedIcons;
|
||||
|
||||
interface ICustomIcon extends TextProps {
|
||||
export interface ICustomIcon extends TextProps {
|
||||
name: TIconsName;
|
||||
size: number;
|
||||
color: string;
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
import React from 'react';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
import { themes } from '../../lib/constants';
|
||||
import { themedHeader } from '../../lib/methods/helpers/navigation';
|
||||
import { isIOS, isTablet } from '../../lib/methods/helpers';
|
||||
import { useTheme } from '../../theme';
|
||||
|
||||
export const headerHeight = isIOS ? 50 : 56;
|
||||
|
||||
export const getHeaderHeight = (isLandscape: boolean): number => {
|
||||
if (isIOS) {
|
||||
if (isLandscape && !isTablet) {
|
||||
return 32;
|
||||
}
|
||||
return 44;
|
||||
}
|
||||
return 56;
|
||||
};
|
||||
|
||||
interface IHeaderTitlePosition {
|
||||
insets: {
|
||||
left: number;
|
||||
right: number;
|
||||
};
|
||||
numIconsRight: number;
|
||||
}
|
||||
|
||||
export const getHeaderTitlePosition = ({
|
||||
insets,
|
||||
numIconsRight
|
||||
}: IHeaderTitlePosition): {
|
||||
left: number;
|
||||
right: number;
|
||||
} => ({
|
||||
left: insets.left,
|
||||
right: insets.right + Math.max(45 * numIconsRight, 15)
|
||||
});
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
height: headerHeight,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
elevation: 4
|
||||
}
|
||||
});
|
||||
|
||||
interface IHeader {
|
||||
headerLeft: () => React.ReactElement | null;
|
||||
headerTitle: () => React.ReactElement;
|
||||
headerRight: () => React.ReactElement | null;
|
||||
}
|
||||
|
||||
const Header = ({ headerLeft, headerTitle, headerRight }: IHeader): React.ReactElement => {
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<SafeAreaView style={{ backgroundColor: themes[theme].headerBackground }} edges={['top', 'left', 'right']}>
|
||||
<View style={[styles.container, { ...themedHeader(theme).headerStyle }]}>
|
||||
{headerLeft ? headerLeft() : null}
|
||||
{headerTitle ? headerTitle() : null}
|
||||
{headerRight ? headerRight() : null}
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
|
@ -3,12 +3,10 @@ import React from 'react';
|
|||
import { isIOS } from '../../lib/methods/helpers';
|
||||
import I18n from '../../i18n';
|
||||
import Container from './HeaderButtonContainer';
|
||||
import Item from './HeaderButtonItem';
|
||||
import Item, { IHeaderButtonItem } from './HeaderButtonItem';
|
||||
|
||||
interface IHeaderButtonCommon {
|
||||
interface IHeaderButtonCommon extends IHeaderButtonItem {
|
||||
navigation?: any; // TODO: Evaluate proper type
|
||||
onPress?: () => void;
|
||||
testID?: string;
|
||||
}
|
||||
|
||||
// Left
|
||||
|
@ -28,20 +26,20 @@ export const CloseModal = React.memo(
|
|||
)
|
||||
);
|
||||
|
||||
export const CancelModal = React.memo(({ onPress, testID }: Partial<IHeaderButtonCommon>) => (
|
||||
export const CancelModal = React.memo(({ onPress, testID, ...props }: IHeaderButtonCommon) => (
|
||||
<Container left>
|
||||
{isIOS ? (
|
||||
<Item title={I18n.t('Cancel')} onPress={onPress} testID={testID} />
|
||||
<Item title={I18n.t('Cancel')} onPress={onPress} testID={testID} {...props} />
|
||||
) : (
|
||||
<Item iconName='close' onPress={onPress} testID={testID} />
|
||||
<Item iconName='close' onPress={onPress} testID={testID} {...props} />
|
||||
)}
|
||||
</Container>
|
||||
));
|
||||
|
||||
// Right
|
||||
export const More = React.memo(({ onPress, testID }: Partial<IHeaderButtonCommon>) => (
|
||||
export const More = React.memo(({ onPress, testID, ...props }: IHeaderButtonCommon) => (
|
||||
<Container>
|
||||
<Item iconName='kebab' onPress={onPress} testID={testID} />
|
||||
<Item iconName='kebab' onPress={onPress} testID={testID} {...props} />
|
||||
</Container>
|
||||
));
|
||||
|
||||
|
@ -58,7 +56,7 @@ export const Preferences = React.memo(({ onPress, testID, ...props }: IHeaderBut
|
|||
));
|
||||
|
||||
export const Legal = React.memo(
|
||||
({ navigation, testID, onPress = () => navigation?.navigate('LegalView') }: IHeaderButtonCommon) => (
|
||||
<More onPress={onPress} testID={testID} />
|
||||
({ navigation, testID, onPress = () => navigation?.navigate('LegalView'), ...props }: IHeaderButtonCommon) => (
|
||||
<More onPress={onPress} testID={testID} {...props} />
|
||||
)
|
||||
);
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import React from 'react';
|
||||
import { Platform, StyleSheet, Text } from 'react-native';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
import { PlatformPressable } from '@react-navigation/elements';
|
||||
|
||||
import { CustomIcon, TIconsName } from '../CustomIcon';
|
||||
import { CustomIcon, ICustomIcon, TIconsName } from '../CustomIcon';
|
||||
import { useTheme } from '../../theme';
|
||||
import { themes } from '../../lib/constants';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
|
||||
interface IHeaderButtonItem {
|
||||
export interface IHeaderButtonItem extends Omit<ICustomIcon, 'name' | 'size' | 'color'> {
|
||||
title?: string;
|
||||
iconName?: TIconsName;
|
||||
onPress?: <T>(arg: T) => void;
|
||||
testID?: string;
|
||||
badge?(): void;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
export const BUTTON_HIT_SLOP = {
|
||||
|
@ -24,7 +24,7 @@ export const BUTTON_HIT_SLOP = {
|
|||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
marginHorizontal: 6
|
||||
padding: 6
|
||||
},
|
||||
title: {
|
||||
...Platform.select({
|
||||
|
@ -39,19 +39,21 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
const Item = ({ title, iconName, onPress, testID, badge }: IHeaderButtonItem): React.ReactElement => {
|
||||
const { theme } = useTheme();
|
||||
const Item = ({ title, iconName, onPress, testID, badge, color, ...props }: IHeaderButtonItem): React.ReactElement => {
|
||||
const { colors } = useTheme();
|
||||
return (
|
||||
<Touchable onPress={onPress} testID={testID} hitSlop={BUTTON_HIT_SLOP} style={styles.container}>
|
||||
<PlatformPressable onPress={onPress} testID={testID} hitSlop={BUTTON_HIT_SLOP} style={styles.container}>
|
||||
<>
|
||||
{iconName ? (
|
||||
<CustomIcon name={iconName} size={24} color={themes[theme].headerTintColor} />
|
||||
<CustomIcon name={iconName} size={24} color={color || colors.headerTintColor} {...props} />
|
||||
) : (
|
||||
<Text style={[styles.title, { color: themes[theme].headerTintColor }]}>{title}</Text>
|
||||
<Text style={[styles.title, { color: color || colors.headerTintColor }]} {...props}>
|
||||
{title}
|
||||
</Text>
|
||||
)}
|
||||
{badge ? badge() : null}
|
||||
</>
|
||||
</Touchable>
|
||||
</PlatformPressable>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ const styles = StyleSheet.create({
|
|||
badgeContainer: {
|
||||
padding: 2,
|
||||
position: 'absolute',
|
||||
right: -3,
|
||||
top: -3,
|
||||
right: 2,
|
||||
top: 2,
|
||||
borderRadius: 10,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
|
|
|
@ -1,25 +1,33 @@
|
|||
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions, react/prop-types, react/destructuring-assignment */
|
||||
import React from 'react';
|
||||
import { Dimensions, View } from 'react-native';
|
||||
import { Dimensions, SafeAreaView } from 'react-native';
|
||||
import { storiesOf } from '@storybook/react-native';
|
||||
import { Provider } from 'react-redux';
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
import { Header, HeaderBackground } from '@react-navigation/elements';
|
||||
|
||||
import Header from '../Header';
|
||||
import { longText } from '../../../storybook/utils';
|
||||
import { ThemeContext } from '../../theme';
|
||||
import { store } from '../../../storybook/stories';
|
||||
import { colors } from '../../lib/constants';
|
||||
import { colors, themes } from '../../lib/constants';
|
||||
import RoomHeaderComponent from './RoomHeader';
|
||||
|
||||
const stories = storiesOf('RoomHeader', module).addDecorator(story => <Provider store={store}>{story()}</Provider>);
|
||||
|
||||
// TODO: refactor after react-navigation v6
|
||||
const HeaderExample = ({ title }) => (
|
||||
<Header headerTitle={() => <View style={{ flex: 1, paddingHorizontal: 12 }}>{title()}</View>} />
|
||||
);
|
||||
const stories = storiesOf('RoomHeader', module)
|
||||
.addDecorator(story => <Provider store={store}>{story()}</Provider>)
|
||||
.addDecorator(story => <SafeAreaProvider>{story()}</SafeAreaProvider>);
|
||||
|
||||
const { width, height } = Dimensions.get('window');
|
||||
|
||||
const HeaderExample = ({ title, theme = 'light' }) => (
|
||||
<SafeAreaView>
|
||||
<Header
|
||||
title=''
|
||||
headerTitle={title}
|
||||
headerTitleAlign='left'
|
||||
headerBackground={() => <HeaderBackground style={{ backgroundColor: themes[theme].headerBackground }} />}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
|
||||
const RoomHeader = ({ ...props }) => (
|
||||
<RoomHeaderComponent
|
||||
width={width}
|
||||
|
@ -28,6 +36,8 @@ const RoomHeader = ({ ...props }) => (
|
|||
type='p'
|
||||
testID={props.title}
|
||||
onPress={() => alert('header pressed!')}
|
||||
status={props.status}
|
||||
usersTyping={props.usersTyping}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
@ -84,7 +94,7 @@ stories.add('thread', () => (
|
|||
|
||||
const ThemeStory = ({ theme }) => (
|
||||
<ThemeContext.Provider value={{ theme, colors: colors[theme] }}>
|
||||
<HeaderExample title={() => <RoomHeader subtitle='subtitle' />} />
|
||||
<HeaderExample title={() => <RoomHeader subtitle='subtitle' />} theme={theme} />
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -64,7 +64,7 @@ export const colors = {
|
|||
passcodeDotEmpty: '#CBCED1',
|
||||
passcodeDotFull: '#6C727A',
|
||||
previewBackground: '#1F2329',
|
||||
previewTintColor: '#ffffff',
|
||||
previewTintColor: '#f9f9f9',
|
||||
backdropOpacity: 0.3,
|
||||
attachmentLoadingOpacity: 0.7,
|
||||
collapsibleQuoteBorder: '#CBCED1',
|
||||
|
@ -116,7 +116,7 @@ export const colors = {
|
|||
passcodeDotEmpty: '#CBCED1',
|
||||
passcodeDotFull: '#6C727A',
|
||||
previewBackground: '#030b1b',
|
||||
previewTintColor: '#ffffff',
|
||||
previewTintColor: '#f9f9f9',
|
||||
backdropOpacity: 0.9,
|
||||
attachmentLoadingOpacity: 0.3,
|
||||
collapsibleQuoteBorder: '#CBCED1',
|
||||
|
@ -168,7 +168,7 @@ export const colors = {
|
|||
passcodeDotEmpty: '#CBCED1',
|
||||
passcodeDotFull: '#6C727A',
|
||||
previewBackground: '#000000',
|
||||
previewTintColor: '#ffffff',
|
||||
previewTintColor: '#f9f9f9',
|
||||
backdropOpacity: 0.9,
|
||||
attachmentLoadingOpacity: 0.3,
|
||||
collapsibleQuoteBorder: '#CBCED1',
|
||||
|
|
|
@ -3,6 +3,7 @@ import { DarkTheme, DefaultTheme } from '@react-navigation/native';
|
|||
|
||||
import { themes } from '../../../constants';
|
||||
import { TSupportedThemes } from '../../../../theme';
|
||||
import { isIOS } from '../deviceInfo';
|
||||
|
||||
export * from './animations';
|
||||
|
||||
|
@ -26,6 +27,9 @@ export const drawerStyle = {
|
|||
width: 320
|
||||
};
|
||||
|
||||
// TODO: Remove it once we migrate dropdowns to action sheet
|
||||
export const headerHeight = isIOS ? 50 : 56;
|
||||
|
||||
export const themedHeader = (theme: TSupportedThemes) => ({
|
||||
headerStyle: {
|
||||
...borderBottom(theme),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import { PermissionsAndroid, StyleSheet, View } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
import { RouteProp } from '@react-navigation/native';
|
||||
import CameraRoll from '@react-native-community/cameraroll';
|
||||
import * as mime from 'react-native-mime-types';
|
||||
|
@ -9,6 +9,7 @@ import RNFetchBlob from 'rn-fetch-blob';
|
|||
import { Video } from 'expo-av';
|
||||
import { sha256 } from 'js-sha256';
|
||||
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { HeaderBackground, HeaderHeightContext } from '@react-navigation/elements';
|
||||
|
||||
import { LISTENER } from '../containers/Toast';
|
||||
import EventEmitter from '../lib/methods/helpers/events';
|
||||
|
@ -21,7 +22,6 @@ import * as HeaderButton from '../containers/HeaderButton';
|
|||
import { isAndroid, formatAttachmentUrl } from '../lib/methods/helpers';
|
||||
import { getUserSelector } from '../selectors/login';
|
||||
import { withDimensions } from '../dimensions';
|
||||
import { getHeaderHeight } from '../containers/Header';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import { InsideStackParamList } from '../stacks/types';
|
||||
import { IApplicationState, IUser, IAttachment } from '../definitions';
|
||||
|
@ -86,18 +86,25 @@ class AttachmentView extends React.Component<IAttachmentViewProps, IAttachmentVi
|
|||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
const options = {
|
||||
title,
|
||||
headerLeft: () => <HeaderButton.CloseModal testID='close-attachment-view' navigation={navigation} />,
|
||||
headerRight: () =>
|
||||
Allow_Save_Media_to_Gallery ? <HeaderButton.Download testID='save-image' onPress={this.handleSave} /> : null,
|
||||
headerBackground: () => <View style={{ flex: 1, backgroundColor: themes[theme].previewBackground }} />,
|
||||
const options: StackNavigationOptions = {
|
||||
title: title || '',
|
||||
headerTitleAlign: 'center',
|
||||
headerTitleStyle: { color: themes[theme].previewTintColor },
|
||||
headerTintColor: themes[theme].previewTintColor,
|
||||
headerTitleStyle: { color: themes[theme].previewTintColor, paddingHorizontal: 20 },
|
||||
headerTitleContainerStyle: { marginHorizontal: -20 },
|
||||
headerTitleAlign: 'center'
|
||||
headerTitleContainerStyle: { flex: 1, maxWidth: undefined },
|
||||
headerLeftContainerStyle: { flexGrow: undefined, flexBasis: undefined },
|
||||
headerRightContainerStyle: { flexGrow: undefined, flexBasis: undefined },
|
||||
headerLeft: () => (
|
||||
<HeaderButton.CloseModal testID='close-attachment-view' navigation={navigation} color={themes[theme].previewTintColor} />
|
||||
),
|
||||
headerRight: () =>
|
||||
Allow_Save_Media_to_Gallery ? (
|
||||
<HeaderButton.Download testID='save-image' onPress={this.handleSave} color={themes[theme].previewTintColor} />
|
||||
) : null,
|
||||
headerBackground: () => (
|
||||
<HeaderBackground style={{ backgroundColor: themes[theme].previewBackground, shadowOpacity: 0, elevation: 0 }} />
|
||||
)
|
||||
};
|
||||
// @ts-ignore
|
||||
navigation.setOptions(options);
|
||||
};
|
||||
|
||||
|
@ -147,14 +154,17 @@ class AttachmentView extends React.Component<IAttachmentViewProps, IAttachmentVi
|
|||
|
||||
renderImage = (uri: string) => {
|
||||
const { width, height, insets } = this.props;
|
||||
const headerHeight = getHeaderHeight(width > height);
|
||||
return (
|
||||
<ImageViewer
|
||||
uri={uri}
|
||||
onLoadEnd={() => this.setState({ loading: false })}
|
||||
width={width}
|
||||
height={height - insets.top - insets.bottom - headerHeight}
|
||||
/>
|
||||
<HeaderHeightContext.Consumer>
|
||||
{headerHeight => (
|
||||
<ImageViewer
|
||||
uri={uri}
|
||||
onLoadEnd={() => this.setState({ loading: false })}
|
||||
width={width}
|
||||
height={height - insets.top - insets.bottom - (headerHeight || 0)}
|
||||
/>
|
||||
)}
|
||||
</HeaderHeightContext.Consumer>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { FlatList } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { RouteProp } from '@react-navigation/native';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
import { HeaderBackButton } from '@react-navigation/elements';
|
||||
|
@ -12,7 +11,6 @@ import StatusBar from '../../containers/StatusBar';
|
|||
import ActivityIndicator from '../../containers/ActivityIndicator';
|
||||
import SearchHeader from '../../containers/SearchHeader';
|
||||
import BackgroundContainer from '../../containers/BackgroundContainer';
|
||||
import { getHeaderTitlePosition } from '../../containers/Header';
|
||||
import { useTheme } from '../../theme';
|
||||
import Navigation from '../../lib/navigation/appNavigation';
|
||||
import { goRoom } from '../../lib/methods/helpers/goRoom';
|
||||
|
@ -73,7 +71,6 @@ const CannedResponsesListView = ({ navigation, route }: ICannedResponsesListView
|
|||
const [loading, setLoading] = useState(true);
|
||||
const [offset, setOffset] = useState(0);
|
||||
|
||||
const insets = useSafeAreaInsets();
|
||||
const { theme } = useTheme();
|
||||
const isMasterDetail = useAppSelector(state => state.app.isMasterDetail);
|
||||
const rooms = useAppSelector(state => state.room.rooms);
|
||||
|
@ -248,9 +245,10 @@ const CannedResponsesListView = ({ navigation, route }: ICannedResponsesListView
|
|||
|
||||
const getHeader = (): StackNavigationOptions => {
|
||||
if (isSearching) {
|
||||
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: 1 });
|
||||
return {
|
||||
headerTitleAlign: 'left',
|
||||
headerTitleContainerStyle: { flex: 1, marginHorizontal: 0, marginRight: 15, maxWidth: undefined },
|
||||
headerRightContainerStyle: { flexGrow: 0 },
|
||||
headerLeft: () => (
|
||||
<HeaderButton.Container left>
|
||||
<HeaderButton.Item
|
||||
|
@ -263,35 +261,29 @@ const CannedResponsesListView = ({ navigation, route }: ICannedResponsesListView
|
|||
</HeaderButton.Container>
|
||||
),
|
||||
headerTitle: () => <SearchHeader onSearchChangeText={onChangeText} testID='team-channels-view-search-header' />,
|
||||
headerTitleContainerStyle: {
|
||||
left: headerTitlePosition.left,
|
||||
right: headerTitlePosition.right
|
||||
},
|
||||
headerRight: () => null
|
||||
};
|
||||
}
|
||||
|
||||
const options: StackNavigationOptions = {
|
||||
headerTitleAlign: undefined,
|
||||
headerTitle: I18n.t('Canned_Responses'),
|
||||
headerTitleContainerStyle: { maxWidth: undefined },
|
||||
headerRightContainerStyle: { flexGrow: 1 },
|
||||
headerLeft: () => (
|
||||
<HeaderBackButton labelVisible={false} onPress={() => navigation.pop()} tintColor={themes[theme].headerTintColor} />
|
||||
),
|
||||
headerTitleAlign: 'center',
|
||||
headerTitle: I18n.t('Canned_Responses'),
|
||||
headerTitleContainerStyle: {
|
||||
left: 0,
|
||||
right: 0
|
||||
}
|
||||
headerRight: () => (
|
||||
<HeaderButton.Container>
|
||||
<HeaderButton.Item iconName='search' onPress={() => setIsSearching(true)} />
|
||||
</HeaderButton.Container>
|
||||
)
|
||||
};
|
||||
|
||||
if (isMasterDetail) {
|
||||
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} />;
|
||||
}
|
||||
|
||||
options.headerRight = () => (
|
||||
<HeaderButton.Container>
|
||||
<HeaderButton.Item iconName='search' onPress={() => setIsSearching(true)} />
|
||||
</HeaderButton.Container>
|
||||
);
|
||||
return options;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import React, { useEffect, useLayoutEffect, useState } from 'react';
|
||||
import { FlatList, StyleSheet } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
import { HeaderBackButton } from '@react-navigation/elements';
|
||||
import { RouteProp } from '@react-navigation/core';
|
||||
|
||||
import { IMessageFromServer } from '../../definitions';
|
||||
import { IMessageFromServer, TThreadModel } from '../../definitions';
|
||||
import { ChatsStackParamList } from '../../stacks/types';
|
||||
import ActivityIndicator from '../../containers/ActivityIndicator';
|
||||
import I18n from '../../i18n';
|
||||
|
@ -16,10 +15,8 @@ import SafeAreaView from '../../containers/SafeAreaView';
|
|||
import * as HeaderButton from '../../containers/HeaderButton';
|
||||
import * as List from '../../containers/List';
|
||||
import BackgroundContainer from '../../containers/BackgroundContainer';
|
||||
import { getHeaderTitlePosition } from '../../containers/Header';
|
||||
import { useTheme } from '../../theme';
|
||||
import SearchHeader from '../../containers/SearchHeader';
|
||||
import { TThreadModel } from '../../definitions/IThread';
|
||||
import Item from './Item';
|
||||
import { Services } from '../../lib/services';
|
||||
import { useAppSelector } from '../../lib/hooks';
|
||||
|
@ -53,7 +50,6 @@ const DiscussionsView = ({ navigation, route }: IDiscussionsViewProps): React.Re
|
|||
const [searchTotal, setSearchTotal] = useState(0);
|
||||
|
||||
const { colors } = useTheme();
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
const load = async (text = '') => {
|
||||
if (loading) {
|
||||
|
@ -103,9 +99,10 @@ const DiscussionsView = ({ navigation, route }: IDiscussionsViewProps): React.Re
|
|||
const setHeader = () => {
|
||||
let options: Partial<StackNavigationOptions>;
|
||||
if (isSearching) {
|
||||
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: 1 });
|
||||
options = {
|
||||
headerTitleAlign: 'left',
|
||||
headerTitleContainerStyle: { flex: 1, marginHorizontal: 0, marginRight: 15, maxWidth: undefined },
|
||||
headerRightContainerStyle: { flexGrow: 0 },
|
||||
headerLeft: () => (
|
||||
<HeaderButton.Container left>
|
||||
<HeaderButton.Item iconName='close' onPress={onCancelSearchPress} />
|
||||
|
@ -114,25 +111,18 @@ const DiscussionsView = ({ navigation, route }: IDiscussionsViewProps): React.Re
|
|||
headerTitle: () => (
|
||||
<SearchHeader onSearchChangeText={onSearchChangeText} testID='discussion-messages-view-search-header' />
|
||||
),
|
||||
headerTitleContainerStyle: {
|
||||
left: headerTitlePosition.left,
|
||||
right: headerTitlePosition.right
|
||||
},
|
||||
headerRight: () => null
|
||||
};
|
||||
return options;
|
||||
}
|
||||
|
||||
options = {
|
||||
headerTitleAlign: 'center',
|
||||
headerTitle: I18n.t('Discussions'),
|
||||
headerRightContainerStyle: { flexGrow: 1 },
|
||||
headerLeft: () => (
|
||||
<HeaderBackButton labelVisible={false} onPress={() => navigation.pop()} tintColor={colors.headerTintColor} />
|
||||
),
|
||||
headerTitleAlign: 'center',
|
||||
headerTitle: I18n.t('Discussions'),
|
||||
headerTitleContainerStyle: {
|
||||
left: 0,
|
||||
right: 0
|
||||
},
|
||||
headerRight: () => (
|
||||
<HeaderButton.Container>
|
||||
<HeaderButton.Item iconName='search' onPress={onSearchPress} />
|
||||
|
|
|
@ -63,7 +63,7 @@ export function DeleteAccountActionSheetContent(): React.ReactElement {
|
|||
onCancel={hideActionSheet}
|
||||
onSubmit={password => handleDeleteAccount(password)}
|
||||
placeholder={i18n.t('Password')}
|
||||
testID='room-info-edit-view-name'
|
||||
testID='profile-view-delete-account-sheet'
|
||||
iconName='warning'
|
||||
confirmTitle={i18n.t('Delete_Account')}
|
||||
confirmBackgroundColor={colors.dangerColor}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import { StyleSheet } from 'react-native';
|
||||
import { StyleSheet, Platform } from 'react-native';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import { HeaderBackButton } from '@react-navigation/elements';
|
||||
|
||||
|
@ -7,11 +7,19 @@ import { themes } from '../../lib/constants';
|
|||
import Avatar from '../../containers/Avatar';
|
||||
import { ChatsStackParamList } from '../../stacks/types';
|
||||
import { TSupportedThemes } from '../../theme';
|
||||
import { isIOS } from '../../lib/methods/helpers';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
...Platform.select({
|
||||
ios: {
|
||||
minWidth: 60
|
||||
}
|
||||
})
|
||||
},
|
||||
avatar: {
|
||||
borderRadius: 10,
|
||||
marginHorizontal: 16
|
||||
marginHorizontal: 15
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -59,9 +67,11 @@ const LeftButtons = ({
|
|||
return (
|
||||
<HeaderBackButton
|
||||
label={label}
|
||||
labelVisible={isIOS}
|
||||
onPress={onPress}
|
||||
tintColor={themes[theme].headerTintColor}
|
||||
labelStyle={{ fontSize, marginLeft }}
|
||||
style={styles.container}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ import RoomHeader from '../../containers/RoomHeader';
|
|||
import StatusBar from '../../containers/StatusBar';
|
||||
import ReactionsModal from '../../containers/ReactionsModal';
|
||||
import { LISTENER } from '../../containers/Toast';
|
||||
import { getBadgeColor, isBlocked, isTeamRoom, makeThreadName } from '../../lib/methods/helpers/room';
|
||||
import { getBadgeColor, isBlocked, makeThreadName } from '../../lib/methods/helpers/room';
|
||||
import { isReadOnly } from '../../lib/methods/helpers/isReadOnly';
|
||||
import { showErrorAlert } from '../../lib/methods/helpers/info';
|
||||
import { withTheme } from '../../theme';
|
||||
|
@ -574,7 +574,6 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
let token: string | undefined;
|
||||
let avatar: string | undefined;
|
||||
let visitor: IVisitor | undefined;
|
||||
let status: string | undefined;
|
||||
let sourceType: IOmnichannelSource | undefined;
|
||||
if ('id' in room) {
|
||||
subtitle = room.topic;
|
||||
|
@ -585,7 +584,6 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
({ id: userId, token } = user);
|
||||
avatar = room.name;
|
||||
visitor = room.visitor;
|
||||
status = room.status;
|
||||
}
|
||||
|
||||
if ('source' in room) {
|
||||
|
@ -594,19 +592,18 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
visitor = room.visitor;
|
||||
}
|
||||
|
||||
let numIconsRight = 2;
|
||||
if (tmid || (status && joined)) {
|
||||
numIconsRight = 1;
|
||||
} else if (teamId && isTeamRoom({ teamId, joined })) {
|
||||
numIconsRight = 3;
|
||||
}
|
||||
const omnichannelPermissions = { canForwardGuest, canReturnQueue, canPlaceLivechatOnHold };
|
||||
|
||||
const paddingRight = this.getPaddingLeft(numIconsRight, isMasterDetail);
|
||||
navigation.setOptions({
|
||||
headerShown: true,
|
||||
headerTitleAlign: 'left',
|
||||
headerTitleContainerStyle: { paddingRight },
|
||||
headerTitleContainerStyle: {
|
||||
flex: 1,
|
||||
marginLeft: 0,
|
||||
marginRight: 4,
|
||||
maxWidth: undefined
|
||||
},
|
||||
headerRightContainerStyle: { flexGrow: undefined, flexBasis: undefined },
|
||||
headerLeft: () => (
|
||||
<LeftButtons
|
||||
tmid={tmid}
|
||||
|
@ -656,13 +653,6 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
});
|
||||
};
|
||||
|
||||
getPaddingLeft = (numIcons: number, isMasterDetail: boolean) => {
|
||||
if (numIcons === 3) {
|
||||
return isMasterDetail ? 40 : 35;
|
||||
}
|
||||
return isMasterDetail ? 20 : 0;
|
||||
};
|
||||
|
||||
goRoomActionsView = (screen?: keyof ModalStackParamList) => {
|
||||
logEvent(events.ROOM_GO_RA);
|
||||
const { room, member, joined, canForwardGuest, canReturnQueue, canViewCannedResponse, canPlaceLivechatOnHold } = this.state;
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
import React from 'react';
|
||||
import { StyleSheet, Text, TextInputProps, TouchableOpacity, TouchableOpacityProps, View } from 'react-native';
|
||||
|
||||
import { TextInput } from '../../../containers/TextInput';
|
||||
import I18n from '../../../i18n';
|
||||
import sharedStyles from '../../Styles';
|
||||
import { themes } from '../../../lib/constants';
|
||||
import { CustomIcon } from '../../../containers/CustomIcon';
|
||||
import { isIOS, isTablet } from '../../../lib/methods/helpers';
|
||||
import { useOrientation } from '../../../dimensions';
|
||||
import { useTheme } from '../../../theme';
|
||||
import SearchHeader from '../../../containers/SearchHeader';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
marginLeft: isTablet ? 10 : 0
|
||||
justifyContent: 'center'
|
||||
},
|
||||
button: {
|
||||
flexDirection: 'row',
|
||||
|
@ -56,26 +54,14 @@ const Header = React.memo(
|
|||
onSearchChangeText,
|
||||
onPress
|
||||
}: IRoomHeader) => {
|
||||
const { theme } = useTheme();
|
||||
const titleColorStyle = { color: themes[theme].headerTitleColor };
|
||||
const isLight = theme === 'light';
|
||||
const { colors } = useTheme();
|
||||
const { isLandscape } = useOrientation();
|
||||
const scale = isIOS && isLandscape && !isTablet ? 0.8 : 1;
|
||||
const titleFontSize = 16 * scale;
|
||||
const subTitleFontSize = 14 * scale;
|
||||
|
||||
if (showSearchHeader) {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<TextInput
|
||||
autoFocus
|
||||
style={[styles.subtitle, isLight && titleColorStyle, { fontSize: titleFontSize }]}
|
||||
placeholder='Search'
|
||||
onChangeText={onSearchChangeText}
|
||||
testID='rooms-list-view-search-input'
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
return <SearchHeader onSearchChangeText={onSearchChangeText} testID='rooms-list-view-search-input' />;
|
||||
}
|
||||
let subtitle;
|
||||
if (connecting) {
|
||||
|
@ -91,12 +77,12 @@ const Header = React.memo(
|
|||
<View style={styles.container}>
|
||||
<TouchableOpacity onPress={onPress} testID='rooms-list-header-server-dropdown-button'>
|
||||
<View style={styles.button}>
|
||||
<Text style={[styles.title, titleColorStyle, { fontSize: titleFontSize }]} numberOfLines={1}>
|
||||
<Text style={[styles.title, { fontSize: titleFontSize, color: colors.headerTitleColor }]} numberOfLines={1}>
|
||||
{serverName}
|
||||
</Text>
|
||||
<CustomIcon
|
||||
name='chevron-down'
|
||||
color={themes[theme].headerTintColor}
|
||||
color={colors.headerTintColor}
|
||||
style={[showServerDropdown && styles.upsideDown]}
|
||||
size={18}
|
||||
/>
|
||||
|
@ -104,7 +90,7 @@ const Header = React.memo(
|
|||
{subtitle ? (
|
||||
<Text
|
||||
testID='rooms-list-header-server-subtitle'
|
||||
style={[styles.subtitle, { color: themes[theme].auxiliaryText, fontSize: subTitleFontSize }]}
|
||||
style={[styles.subtitle, { color: colors.auxiliaryText, fontSize: subTitleFontSize }]}
|
||||
numberOfLines={1}>
|
||||
{subtitle}
|
||||
</Text>
|
||||
|
|
|
@ -3,7 +3,6 @@ import { connect } from 'react-redux';
|
|||
import { Dispatch } from 'redux';
|
||||
|
||||
import { toggleServerDropdown, closeServerDropdown, setSearch } from '../../../actions/rooms';
|
||||
import { TSupportedThemes, withTheme } from '../../../theme';
|
||||
import EventEmitter from '../../../lib/methods/helpers/events';
|
||||
import { KEY_COMMAND, handleCommandOpenServerDropdown, IKeyCommandEvent } from '../../../commands';
|
||||
import { isTablet } from '../../../lib/methods/helpers';
|
||||
|
@ -18,7 +17,6 @@ interface IRoomsListHeaderViewProps {
|
|||
connecting: boolean;
|
||||
connected: boolean;
|
||||
isFetching: boolean;
|
||||
theme: TSupportedThemes;
|
||||
server: string;
|
||||
dispatch: Dispatch;
|
||||
}
|
||||
|
@ -87,4 +85,4 @@ const mapStateToProps = (state: IApplicationState) => ({
|
|||
server: state.server.server
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withTheme(RoomsListHeaderView));
|
||||
export default connect(mapStateToProps)(RoomsListHeaderView);
|
||||
|
|
|
@ -20,7 +20,7 @@ import { isTablet } from '../../lib/methods/helpers';
|
|||
import { localAuthenticate } from '../../lib/methods/helpers/localAuthentication';
|
||||
import { showConfirmationAlert } from '../../lib/methods/helpers/info';
|
||||
import log, { events, logEvent } from '../../lib/methods/helpers/log';
|
||||
import { headerHeight } from '../../containers/Header';
|
||||
import { headerHeight } from '../../lib/methods/helpers/navigation';
|
||||
import { goRoom } from '../../lib/methods/helpers/goRoom';
|
||||
import UserPreferences from '../../lib/methods/userPreferences';
|
||||
import { IApplicationState, IBaseScreen, RootEnum, TServerModel } from '../../definitions';
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Q } from '@nozbe/watermelondb';
|
|||
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { StackNavigationOptions } from '@react-navigation/stack';
|
||||
import { Header } from '@react-navigation/elements';
|
||||
|
||||
import database from '../../lib/database';
|
||||
import RoomItem, { ROW_HEIGHT, ROW_HEIGHT_CONDENSED } from '../../containers/RoomItem';
|
||||
|
@ -21,6 +22,7 @@ import { serverInitAdd } from '../../actions/server';
|
|||
import { animateNextTransition } from '../../lib/methods/helpers/layoutAnimation';
|
||||
import { withTheme } from '../../theme';
|
||||
import EventEmitter from '../../lib/methods/helpers/events';
|
||||
import { themedHeader } from '../../lib/methods/helpers/navigation';
|
||||
import {
|
||||
KEY_COMMAND,
|
||||
handleCommandAddNewServer,
|
||||
|
@ -35,7 +37,6 @@ import {
|
|||
import { getUserSelector } from '../../selectors/login';
|
||||
import { goRoom } from '../../lib/methods/helpers/goRoom';
|
||||
import SafeAreaView from '../../containers/SafeAreaView';
|
||||
import Header, { getHeaderTitlePosition } from '../../containers/Header';
|
||||
import { withDimensions } from '../../dimensions';
|
||||
import { getInquiryQueueSelector } from '../../ee/omnichannel/selectors/inquiry';
|
||||
import {
|
||||
|
@ -415,55 +416,59 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
this.setState({ canCreateRoom }, () => this.setHeader());
|
||||
};
|
||||
|
||||
getHeader = () => {
|
||||
getHeader = (): StackNavigationOptions => {
|
||||
const { searching, canCreateRoom } = this.state;
|
||||
const { navigation, isMasterDetail, insets, theme } = this.props;
|
||||
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: searching ? 0 : 3 });
|
||||
|
||||
return {
|
||||
headerTitleAlign: 'left',
|
||||
headerLeft: () =>
|
||||
searching ? (
|
||||
const { navigation, isMasterDetail } = this.props;
|
||||
if (searching) {
|
||||
return {
|
||||
headerTitleAlign: 'left',
|
||||
headerTitleContainerStyle: { flex: 1, marginHorizontal: 0, marginRight: 15, maxWidth: undefined },
|
||||
headerRightContainerStyle: { flexGrow: 0 },
|
||||
headerLeft: () => (
|
||||
<HeaderButton.Container left>
|
||||
<HeaderButton.Item iconName='close' onPress={this.cancelSearch} />
|
||||
</HeaderButton.Container>
|
||||
) : (
|
||||
<HeaderButton.Drawer
|
||||
navigation={navigation}
|
||||
testID='rooms-list-view-sidebar'
|
||||
onPress={
|
||||
isMasterDetail
|
||||
? () => navigation.navigate('ModalStackNavigator', { screen: 'SettingsView' })
|
||||
: // @ts-ignore
|
||||
() => navigation.toggleDrawer()
|
||||
}
|
||||
/>
|
||||
),
|
||||
headerTitle: () => <RoomsListHeaderView theme={theme} />,
|
||||
headerTitleContainerStyle: {
|
||||
left: headerTitlePosition.left,
|
||||
right: headerTitlePosition.right
|
||||
},
|
||||
headerRight: () =>
|
||||
searching ? null : (
|
||||
<HeaderButton.Container>
|
||||
{canCreateRoom ? (
|
||||
<HeaderButton.Item iconName='create' onPress={this.goToNewMessage} testID='rooms-list-view-create-channel' />
|
||||
) : null}
|
||||
<HeaderButton.Item iconName='search' onPress={this.initSearching} testID='rooms-list-view-search' />
|
||||
<HeaderButton.Item iconName='directory' onPress={this.goDirectory} testID='rooms-list-view-directory' />
|
||||
</HeaderButton.Container>
|
||||
)
|
||||
headerTitle: () => <RoomsListHeaderView />,
|
||||
headerRight: () => null
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
headerTitleAlign: 'left',
|
||||
headerTitleContainerStyle: { flex: 1, marginHorizontal: 4, maxWidth: undefined },
|
||||
headerRightContainerStyle: { flexGrow: undefined, flexBasis: undefined },
|
||||
headerLeft: () => (
|
||||
<HeaderButton.Drawer
|
||||
navigation={navigation}
|
||||
testID='rooms-list-view-sidebar'
|
||||
onPress={
|
||||
isMasterDetail
|
||||
? () => navigation.navigate('ModalStackNavigator', { screen: 'SettingsView' })
|
||||
: // @ts-ignore
|
||||
() => navigation.toggleDrawer()
|
||||
}
|
||||
/>
|
||||
),
|
||||
headerTitle: () => <RoomsListHeaderView />,
|
||||
headerRight: () => (
|
||||
<HeaderButton.Container>
|
||||
{canCreateRoom ? (
|
||||
<HeaderButton.Item iconName='create' onPress={this.goToNewMessage} testID='rooms-list-view-create-channel' />
|
||||
) : null}
|
||||
<HeaderButton.Item iconName='search' onPress={this.initSearching} testID='rooms-list-view-search' />
|
||||
<HeaderButton.Item iconName='directory' onPress={this.goDirectory} testID='rooms-list-view-directory' />
|
||||
</HeaderButton.Container>
|
||||
)
|
||||
};
|
||||
};
|
||||
|
||||
setHeader = () => {
|
||||
const { navigation } = this.props;
|
||||
const options = this.getHeader() as Partial<StackNavigationOptions>;
|
||||
const options = this.getHeader();
|
||||
navigation.setOptions(options);
|
||||
};
|
||||
|
||||
// internalSetState = (...args: { chats: TSubscriptionModel; chatsUpdate: TSubscriptionModel; loading: boolean }[]) => {
|
||||
internalSetState = (
|
||||
state:
|
||||
| ((
|
||||
|
@ -923,14 +928,14 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
};
|
||||
|
||||
renderHeader = () => {
|
||||
const { isMasterDetail } = this.props;
|
||||
const { isMasterDetail, theme } = this.props;
|
||||
|
||||
if (!isMasterDetail) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const options = this.getHeader();
|
||||
return <Header {...options} />;
|
||||
return <Header title='' {...themedHeader(theme)} {...options} />;
|
||||
};
|
||||
|
||||
renderItem = ({ item }: { item: IRoomItem }) => {
|
||||
|
|
|
@ -3,11 +3,11 @@ import { Video } from 'expo-av';
|
|||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { ScrollView, StyleSheet, Text } from 'react-native';
|
||||
import prettyBytes from 'pretty-bytes';
|
||||
import { useHeaderHeight } from '@react-navigation/elements';
|
||||
|
||||
import { CustomIcon, TIconsName } from '../../containers/CustomIcon';
|
||||
import { ImageViewer, types } from '../../containers/ImageViewer';
|
||||
import { useDimensions, useOrientation } from '../../dimensions';
|
||||
import { getHeaderHeight } from '../../containers/Header';
|
||||
import { useDimensions } from '../../dimensions';
|
||||
import sharedStyles from '../Styles';
|
||||
import I18n from '../../i18n';
|
||||
import { isAndroid } from '../../lib/methods/helpers';
|
||||
|
@ -66,9 +66,8 @@ interface IPreview {
|
|||
const Preview = React.memo(({ item, theme, isShareExtension, length }: IPreview) => {
|
||||
const type = item?.mime;
|
||||
const { width, height } = useDimensions();
|
||||
const { isLandscape } = useOrientation();
|
||||
const insets = useSafeAreaInsets();
|
||||
const headerHeight = getHeaderHeight(isLandscape);
|
||||
const headerHeight = useHeaderHeight();
|
||||
const thumbsHeight = length > 1 ? THUMBS_HEIGHT : 0;
|
||||
const calculatedHeight = height - insets.top - insets.bottom - MESSAGEBOX_HEIGHT - thumbsHeight - headerHeight;
|
||||
|
||||
|
|
|
@ -106,13 +106,13 @@ class ShareView extends Component<IShareViewProps, IShareViewState> {
|
|||
|
||||
// if is share extension show default back button
|
||||
if (!this.isShareExtension) {
|
||||
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} />;
|
||||
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} color={themes[theme].previewTintColor} />;
|
||||
}
|
||||
|
||||
if (!attachments.length && !readOnly) {
|
||||
options.headerRight = () => (
|
||||
<HeaderButton.Container>
|
||||
<HeaderButton.Item title={I18n.t('Send')} onPress={this.send} />
|
||||
<HeaderButton.Item title={I18n.t('Send')} onPress={this.send} color={themes[theme].previewTintColor} />
|
||||
</HeaderButton.Container>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ import { StackNavigationOptions } from '@react-navigation/stack';
|
|||
import { HeaderBackButton } from '@react-navigation/elements';
|
||||
import React from 'react';
|
||||
import { Alert, FlatList, Keyboard } from 'react-native';
|
||||
import { EdgeInsets, withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { deleteRoom } from '../actions/room';
|
||||
|
@ -11,7 +10,6 @@ import { DisplayMode, themes } from '../lib/constants';
|
|||
import { TActionSheetOptions, TActionSheetOptionsItem, withActionSheet } from '../containers/ActionSheet';
|
||||
import ActivityIndicator from '../containers/ActivityIndicator';
|
||||
import BackgroundContainer from '../containers/BackgroundContainer';
|
||||
import { getHeaderTitlePosition } from '../containers/Header';
|
||||
import * as HeaderButton from '../containers/HeaderButton';
|
||||
import RoomHeader from '../containers/RoomHeader';
|
||||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
|
@ -74,7 +72,6 @@ interface ITeamChannelsViewState {
|
|||
}
|
||||
|
||||
interface ITeamChannelsViewProps extends IBaseScreen<ChatsStackParamList, 'TeamChannelsView'> {
|
||||
insets: EdgeInsets;
|
||||
useRealName: boolean;
|
||||
width: number;
|
||||
StoreLastMessage: boolean;
|
||||
|
@ -190,18 +187,18 @@ class TeamChannelsView extends React.Component<ITeamChannelsViewProps, ITeamChan
|
|||
|
||||
setHeader = () => {
|
||||
const { isSearching, showCreate, data } = this.state;
|
||||
const { navigation, isMasterDetail, insets, theme } = this.props;
|
||||
const { navigation, isMasterDetail, theme } = this.props;
|
||||
|
||||
const { team } = this;
|
||||
if (!team) {
|
||||
return;
|
||||
}
|
||||
|
||||
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: 2 });
|
||||
|
||||
if (isSearching) {
|
||||
const options: StackNavigationOptions = {
|
||||
headerTitleAlign: 'left',
|
||||
headerTitleContainerStyle: { flex: 1, marginHorizontal: 0, marginRight: 15, maxWidth: undefined },
|
||||
headerRightContainerStyle: { flexGrow: 0 },
|
||||
headerLeft: () => (
|
||||
<HeaderButton.Container left>
|
||||
<HeaderButton.Item iconName='close' onPress={this.onCancelSearchPress} />
|
||||
|
@ -210,27 +207,33 @@ class TeamChannelsView extends React.Component<ITeamChannelsViewProps, ITeamChan
|
|||
headerTitle: () => (
|
||||
<SearchHeader onSearchChangeText={this.onSearchChangeText} testID='team-channels-view-search-header' />
|
||||
),
|
||||
headerTitleContainerStyle: {
|
||||
left: headerTitlePosition.left,
|
||||
right: headerTitlePosition.right
|
||||
},
|
||||
headerRight: () => null
|
||||
};
|
||||
return navigation.setOptions(options);
|
||||
}
|
||||
|
||||
const options: StackNavigationOptions = {
|
||||
headerShown: true,
|
||||
headerTitleAlign: 'left',
|
||||
headerTitleContainerStyle: {
|
||||
left: headerTitlePosition.left,
|
||||
right: headerTitlePosition.right
|
||||
},
|
||||
headerTitleContainerStyle: { flex: 1, marginLeft: 0, marginRight: 4, maxWidth: undefined },
|
||||
headerLeftContainerStyle: { minWidth: 60 },
|
||||
headerRightContainerStyle: { flexGrow: undefined, flexBasis: undefined },
|
||||
headerLeft: () => (
|
||||
<HeaderBackButton labelVisible={false} onPress={() => navigation.pop()} tintColor={themes[theme].headerTintColor} />
|
||||
),
|
||||
headerTitle: () => (
|
||||
<RoomHeader title={getRoomTitle(team)} subtitle={team.topic} type={team.t} onPress={this.goRoomActionsView} teamMain />
|
||||
),
|
||||
headerRight: () => (
|
||||
<HeaderButton.Container>
|
||||
{showCreate ? (
|
||||
<HeaderButton.Item
|
||||
iconName='create'
|
||||
testID='team-channels-view-create'
|
||||
onPress={() => navigation.navigate('AddChannelTeamView', { teamId: this.teamId, teamChannels: data })}
|
||||
/>
|
||||
) : null}
|
||||
<HeaderButton.Item iconName='search' testID='team-channels-view-search' onPress={this.onSearchPress} />
|
||||
</HeaderButton.Container>
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -238,18 +241,6 @@ class TeamChannelsView extends React.Component<ITeamChannelsViewProps, ITeamChan
|
|||
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} />;
|
||||
}
|
||||
|
||||
options.headerRight = () => (
|
||||
<HeaderButton.Container>
|
||||
{showCreate ? (
|
||||
<HeaderButton.Item
|
||||
iconName='create'
|
||||
testID='team-channels-view-create'
|
||||
onPress={() => navigation.navigate('AddChannelTeamView', { teamId: this.teamId, teamChannels: data })}
|
||||
/>
|
||||
) : null}
|
||||
<HeaderButton.Item iconName='search' testID='team-channels-view-search' onPress={this.onSearchPress} />
|
||||
</HeaderButton.Container>
|
||||
);
|
||||
navigation.setOptions(options);
|
||||
};
|
||||
|
||||
|
@ -575,4 +566,4 @@ const mapStateToProps = (state: IApplicationState) => ({
|
|||
displayMode: state.sortPreferences.displayMode
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withDimensions(withSafeAreaInsets(withTheme(withActionSheet(TeamChannelsView)))));
|
||||
export default connect(mapStateToProps)(withDimensions(withTheme(withActionSheet(TeamChannelsView))));
|
||||
|
|
|
@ -5,7 +5,7 @@ import { EdgeInsets, withSafeAreaInsets } from 'react-native-safe-area-context';
|
|||
import styles from '../styles';
|
||||
import { themes } from '../../../lib/constants';
|
||||
import { TSupportedThemes, withTheme } from '../../../theme';
|
||||
import { headerHeight } from '../../../containers/Header';
|
||||
import { headerHeight } from '../../../lib/methods/helpers/navigation';
|
||||
import * as List from '../../../containers/List';
|
||||
import { Filter } from '../filters';
|
||||
import DropdownItemFilter from './DropdownItemFilter';
|
||||
|
|
|
@ -3,7 +3,6 @@ import { FlatList } from 'react-native';
|
|||
import { connect } from 'react-redux';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import { EdgeInsets, withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { StackNavigationOptions } from '@react-navigation/stack';
|
||||
import { HeaderBackButton } from '@react-navigation/elements';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
|
@ -24,7 +23,6 @@ import * as HeaderButton from '../../containers/HeaderButton';
|
|||
import * as List from '../../containers/List';
|
||||
import BackgroundContainer from '../../containers/BackgroundContainer';
|
||||
import { getBadgeColor, makeThreadName } from '../../lib/methods/helpers/room';
|
||||
import { getHeaderTitlePosition } from '../../containers/Header';
|
||||
import EventEmitter from '../../lib/methods/helpers/events';
|
||||
import { LISTENER } from '../../containers/Toast';
|
||||
import SearchHeader from '../../containers/SearchHeader';
|
||||
|
@ -58,7 +56,6 @@ interface IThreadMessagesViewProps extends IBaseScreen<ChatsStackParamList, 'Thr
|
|||
useRealName: boolean;
|
||||
theme: TSupportedThemes;
|
||||
isMasterDetail: boolean;
|
||||
insets: EdgeInsets;
|
||||
}
|
||||
|
||||
class ThreadMessagesView extends React.Component<IThreadMessagesViewProps, IThreadMessagesViewState> {
|
||||
|
@ -100,13 +97,6 @@ class ThreadMessagesView extends React.Component<IThreadMessagesViewProps, IThre
|
|||
this.init();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: IThreadMessagesViewProps) {
|
||||
const { insets } = this.props;
|
||||
if (insets.left !== prevProps.insets.left || insets.right !== prevProps.insets.right) {
|
||||
this.setHeader();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
console.countReset(`${this.constructor.name}.render calls`);
|
||||
if (this.subSubscription && this.subSubscription.unsubscribe) {
|
||||
|
@ -119,12 +109,13 @@ class ThreadMessagesView extends React.Component<IThreadMessagesViewProps, IThre
|
|||
|
||||
getHeader = (): StackNavigationOptions => {
|
||||
const { isSearching } = this.state;
|
||||
const { navigation, isMasterDetail, insets, theme } = this.props;
|
||||
const { navigation, isMasterDetail, theme } = this.props;
|
||||
|
||||
if (isSearching) {
|
||||
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: 1 });
|
||||
return {
|
||||
headerTitleAlign: 'left',
|
||||
headerTitleContainerStyle: { flex: 1, marginHorizontal: 0, marginRight: 15, maxWidth: undefined },
|
||||
headerRightContainerStyle: { flexGrow: 0 },
|
||||
headerLeft: () => (
|
||||
<HeaderButton.Container left>
|
||||
<HeaderButton.Item iconName='close' onPress={this.onCancelSearchPress} />
|
||||
|
@ -133,35 +124,28 @@ class ThreadMessagesView extends React.Component<IThreadMessagesViewProps, IThre
|
|||
headerTitle: () => (
|
||||
<SearchHeader onSearchChangeText={this.onSearchChangeText} testID='thread-messages-view-search-header' />
|
||||
),
|
||||
headerTitleContainerStyle: {
|
||||
left: headerTitlePosition.left,
|
||||
right: headerTitlePosition.right
|
||||
},
|
||||
headerRight: () => null
|
||||
};
|
||||
}
|
||||
|
||||
const options: StackNavigationOptions = {
|
||||
headerTitleAlign: 'center',
|
||||
headerTitle: I18n.t('Threads'),
|
||||
headerRightContainerStyle: { flexGrow: 1 },
|
||||
headerLeft: () => (
|
||||
<HeaderBackButton labelVisible={false} onPress={() => navigation.pop()} tintColor={themes[theme].headerTintColor} />
|
||||
),
|
||||
headerTitleAlign: 'center',
|
||||
headerTitle: I18n.t('Threads'),
|
||||
headerTitleContainerStyle: {
|
||||
left: 0,
|
||||
right: 0
|
||||
}
|
||||
headerRight: () => (
|
||||
<HeaderButton.Container>
|
||||
<HeaderButton.Item iconName='search' onPress={this.onSearchPress} />
|
||||
</HeaderButton.Container>
|
||||
)
|
||||
};
|
||||
|
||||
if (isMasterDetail) {
|
||||
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} />;
|
||||
}
|
||||
|
||||
options.headerRight = () => (
|
||||
<HeaderButton.Container>
|
||||
<HeaderButton.Item iconName='search' onPress={this.onSearchPress} />
|
||||
</HeaderButton.Container>
|
||||
);
|
||||
return options;
|
||||
};
|
||||
|
||||
|
@ -549,4 +533,4 @@ const mapStateToProps = (state: IApplicationState) => ({
|
|||
isMasterDetail: state.app.isMasterDetail
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withTheme(withSafeAreaInsets(ThreadMessagesView)));
|
||||
export default connect(mapStateToProps)(withTheme(ThreadMessagesView));
|
||||
|
|
|
@ -108,8 +108,13 @@ describe('Profile screen', () => {
|
|||
await element(by.id('profile-view-email')).replaceText(`mobile+profileChangesNew${data.random}@rocket.chat`);
|
||||
await element(by.id('profile-view-new-password')).replaceText(`${profileChangeUser.password}new`);
|
||||
await element(by.id('profile-view-submit')).tap();
|
||||
await element(by.type(textInputType)).replaceText(`${profileChangeUser.password}`);
|
||||
await element(by[textMatcher]('Save').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('profile-view-enter-password-sheet')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('profile-view-enter-password-sheet')).replaceText(`${profileChangeUser.password}`);
|
||||
await element(by[textMatcher]('Save').withAncestor(by.id('action-sheet-content-with-input-and-submit')))
|
||||
.atIndex(0)
|
||||
.tap();
|
||||
await waitForToast();
|
||||
});
|
||||
|
||||
|
|
|
@ -272,6 +272,9 @@ describe('Room actions screen', () => {
|
|||
|
||||
describe('Notification', () => {
|
||||
it('should navigate to notification preference view', async () => {
|
||||
await waitFor(element(by.id('room-actions-scrollview')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-actions-scrollview')).scrollTo('bottom');
|
||||
await waitFor(element(by.id('room-actions-notifications')))
|
||||
.toExist()
|
||||
|
@ -307,8 +310,6 @@ describe('Room actions screen', () => {
|
|||
});
|
||||
|
||||
it('should have notification sound option', async () => {
|
||||
// Ugly hack to scroll on detox
|
||||
await element(by.id('room-actions-scrollview')).scrollTo('bottom');
|
||||
await waitFor(element(by.id('notification-preference-view-sound')))
|
||||
.toExist()
|
||||
.withTimeout(4000);
|
||||
|
@ -338,6 +339,9 @@ describe('Room actions screen', () => {
|
|||
const user = data.users.alternate;
|
||||
|
||||
it('should tap on leave channel and raise alert', async () => {
|
||||
await waitFor(element(by.id('room-actions-scrollview')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-actions-scrollview')).scrollTo('bottom');
|
||||
await waitFor(element(by.id('room-actions-leave-channel')))
|
||||
.toExist()
|
||||
|
|
|
@ -290,10 +290,11 @@ describe('Room info screen', () => {
|
|||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by[textMatcher]('Yes, archive it!').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('room-info-edit-view-unarchive')))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await expect(element(by.id('room-info-edit-view-archive'))).toBeNotVisible();
|
||||
await waitForToast();
|
||||
// await waitFor(element(by.id('room-info-edit-view-unarchive')))
|
||||
// .toExist()
|
||||
// .withTimeout(60000);
|
||||
// await expect(element(by.id('room-info-edit-view-archive'))).toBeNotVisible();
|
||||
});
|
||||
|
||||
it('should delete room', async () => {
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
diff --git a/node_modules/@react-navigation/elements/src/Header/HeaderBackButton.tsx b/node_modules/@react-navigation/elements/src/Header/HeaderBackButton.tsx
|
||||
index 39a39b2..7a60a15 100644
|
||||
--- a/node_modules/@react-navigation/elements/src/Header/HeaderBackButton.tsx
|
||||
+++ b/node_modules/@react-navigation/elements/src/Header/HeaderBackButton.tsx
|
||||
@@ -30,7 +30,7 @@ export default function HeaderBackButton({
|
||||
titleLayout,
|
||||
truncatedLabel = 'Back',
|
||||
accessibilityLabel = label && label !== 'Back' ? `${label}, back` : 'Go back',
|
||||
- testID,
|
||||
+ testID = 'header-back',
|
||||
style,
|
||||
}: HeaderBackButtonProps) {
|
||||
const { colors } = useTheme();
|
|
@ -1,16 +1,31 @@
|
|||
/* 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 { SafeAreaView } from 'react-native';
|
||||
import { Header, HeaderBackground } from '@react-navigation/elements';
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
|
||||
import * as HeaderButton from '../../app/containers/HeaderButton';
|
||||
import Header from '../../app/containers/Header';
|
||||
import { ThemeContext } from '../../app/theme';
|
||||
import { TColors, ThemeContext, TSupportedThemes } from '../../app/theme';
|
||||
import { colors } from '../../app/lib/constants';
|
||||
|
||||
const stories = storiesOf('Header Buttons', module);
|
||||
const stories = storiesOf('Header Buttons', module).addDecorator(story => <SafeAreaProvider>{story()}</SafeAreaProvider>);
|
||||
|
||||
const HeaderExample = ({ left, right }) => (
|
||||
<Header headerLeft={left} headerTitle={() => <View style={{ flex: 1 }} />} headerRight={right} />
|
||||
interface IHeader {
|
||||
left?: () => React.ReactElement | null;
|
||||
right?: () => React.ReactElement;
|
||||
title?: string;
|
||||
colors?: TColors;
|
||||
}
|
||||
|
||||
const HeaderExample = ({ left, right, colors, title = '' }: IHeader) => (
|
||||
<SafeAreaView>
|
||||
<Header
|
||||
title={title}
|
||||
headerLeft={left}
|
||||
headerRight={right}
|
||||
headerBackground={() => <HeaderBackground style={{ backgroundColor: colors?.headerBackground }} />}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
|
||||
stories.add('title', () => (
|
||||
|
@ -89,8 +104,8 @@ stories.add('badge', () => (
|
|||
</>
|
||||
));
|
||||
|
||||
const ThemeStory = ({ theme }) => (
|
||||
<ThemeContext.Provider value={{ theme }}>
|
||||
const ThemeStory = ({ theme }: { theme: TSupportedThemes }) => (
|
||||
<ThemeContext.Provider value={{ theme, colors: colors[theme] }}>
|
||||
<HeaderExample
|
||||
left={() => (
|
||||
<HeaderButton.Container left>
|
||||
|
@ -103,6 +118,7 @@ const ThemeStory = ({ theme }) => (
|
|||
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.Badge tunread={[1]} />} />
|
||||
</HeaderButton.Container>
|
||||
)}
|
||||
colors={colors[theme]}
|
||||
/>
|
||||
</ThemeContext.Provider>
|
||||
);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue