Merge branch 'develop' into update.enable-multiline-android-tablets
This commit is contained in:
commit
ac61087940
|
@ -5,15 +5,15 @@ import { themes } from '../constants/colors';
|
||||||
import sharedStyles from '../views/Styles';
|
import sharedStyles from '../views/Styles';
|
||||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||||
import KeyboardView from '../presentation/KeyboardView';
|
import KeyboardView from '../presentation/KeyboardView';
|
||||||
|
import { useTheme } from '../theme';
|
||||||
import StatusBar from './StatusBar';
|
import StatusBar from './StatusBar';
|
||||||
import AppVersion from './AppVersion';
|
import AppVersion from './AppVersion';
|
||||||
import { isTablet } from '../utils/deviceInfo';
|
import { isTablet } from '../utils/deviceInfo';
|
||||||
import SafeAreaView from './SafeAreaView';
|
import SafeAreaView from './SafeAreaView';
|
||||||
|
|
||||||
interface IFormContainer extends ScrollViewProps {
|
interface IFormContainer extends ScrollViewProps {
|
||||||
theme: string;
|
|
||||||
testID: string;
|
testID: string;
|
||||||
children: React.ReactNode;
|
children: React.ReactElement | React.ReactElement[] | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
@ -22,11 +22,14 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const FormContainerInner = ({ children }: { children: React.ReactNode }): JSX.Element => (
|
export const FormContainerInner = ({ children }: { children: (React.ReactElement | null)[] }) => (
|
||||||
<View style={[sharedStyles.container, isTablet && sharedStyles.tabletScreenContent]}>{children}</View>
|
<View style={[sharedStyles.container, isTablet && sharedStyles.tabletScreenContent]}>{children}</View>
|
||||||
);
|
);
|
||||||
|
|
||||||
const FormContainer = ({ children, theme, testID, ...props }: IFormContainer): JSX.Element => (
|
const FormContainer = ({ children, testID, ...props }: IFormContainer) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
<KeyboardView
|
<KeyboardView
|
||||||
style={{ backgroundColor: themes[theme].backgroundColor }}
|
style={{ backgroundColor: themes[theme].backgroundColor }}
|
||||||
contentContainerStyle={sharedStyles.container}
|
contentContainerStyle={sharedStyles.container}
|
||||||
|
@ -43,6 +46,7 @@ const FormContainer = ({ children, theme, testID, ...props }: IFormContainer): J
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</KeyboardView>
|
</KeyboardView>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default FormContainer;
|
export default FormContainer;
|
||||||
|
|
|
@ -11,7 +11,7 @@ const styles = StyleSheet.create({
|
||||||
});
|
});
|
||||||
|
|
||||||
interface IListContainer {
|
interface IListContainer {
|
||||||
children: React.ReactNode;
|
children: (React.ReactElement | null)[] | React.ReactElement | null;
|
||||||
testID?: string;
|
testID?: string;
|
||||||
}
|
}
|
||||||
const ListContainer = React.memo(({ children, ...props }: IListContainer) => (
|
const ListContainer = React.memo(({ children, ...props }: IListContainer) => (
|
||||||
|
|
|
@ -25,6 +25,7 @@ interface IListHeader {
|
||||||
|
|
||||||
const ListHeader = React.memo(({ title, translateTitle = true }: IListHeader) => {
|
const ListHeader = React.memo(({ title, translateTitle = true }: IListHeader) => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Text style={[styles.title, { color: themes[theme].infoText }]} numberOfLines={1}>
|
<Text style={[styles.title, { color: themes[theme].infoText }]} numberOfLines={1}>
|
||||||
|
|
|
@ -3,11 +3,10 @@ import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
|
||||||
|
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import { CustomIcon } from '../../lib/Icons';
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
import { withTheme } from '../../theme';
|
import { useTheme } from '../../theme';
|
||||||
import { ICON_SIZE } from './constants';
|
import { ICON_SIZE } from './constants';
|
||||||
|
|
||||||
interface IListIcon {
|
interface IListIcon {
|
||||||
theme?: string;
|
|
||||||
name: string;
|
name: string;
|
||||||
color?: string;
|
color?: string;
|
||||||
style?: StyleProp<ViewStyle>;
|
style?: StyleProp<ViewStyle>;
|
||||||
|
@ -21,12 +20,16 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const ListIcon = React.memo(({ theme, name, color, style, testID }: IListIcon) => (
|
const ListIcon = React.memo(({ name, color, style, testID }: IListIcon) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
<View style={[styles.icon, style]}>
|
<View style={[styles.icon, style]}>
|
||||||
<CustomIcon name={name} color={color ?? themes[theme!].auxiliaryText} size={ICON_SIZE} testID={testID} />
|
<CustomIcon name={name} color={color ?? themes[theme].auxiliaryText} size={ICON_SIZE} testID={testID} />
|
||||||
</View>
|
</View>
|
||||||
));
|
);
|
||||||
|
});
|
||||||
|
|
||||||
ListIcon.displayName = 'List.Icon';
|
ListIcon.displayName = 'List.Icon';
|
||||||
|
|
||||||
export default withTheme(ListIcon);
|
export default ListIcon;
|
||||||
|
|
|
@ -4,11 +4,11 @@ import { I18nManager, StyleSheet, Text, View } from 'react-native';
|
||||||
import Touch from '../../utils/touch';
|
import Touch from '../../utils/touch';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import sharedStyles from '../../views/Styles';
|
import sharedStyles from '../../views/Styles';
|
||||||
import { withTheme } from '../../theme';
|
import { useTheme } from '../../theme';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import { Icon } from '.';
|
import { Icon } from '.';
|
||||||
import { BASE_HEIGHT, ICON_SIZE, PADDING_HORIZONTAL } from './constants';
|
import { BASE_HEIGHT, ICON_SIZE, PADDING_HORIZONTAL } from './constants';
|
||||||
import { withDimensions } from '../../dimensions';
|
import { useDimensions } from '../../dimensions';
|
||||||
import { CustomIcon } from '../../lib/Icons';
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
@ -59,13 +59,12 @@ interface IListItemContent {
|
||||||
left?: () => JSX.Element | null;
|
left?: () => JSX.Element | null;
|
||||||
right?: () => JSX.Element | null;
|
right?: () => JSX.Element | null;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
theme: string;
|
||||||
testID?: string;
|
testID?: string;
|
||||||
theme?: string;
|
|
||||||
color?: string;
|
color?: string;
|
||||||
translateTitle?: boolean;
|
translateTitle?: boolean;
|
||||||
translateSubtitle?: boolean;
|
translateSubtitle?: boolean;
|
||||||
showActionIndicator?: boolean;
|
showActionIndicator?: boolean;
|
||||||
fontScale?: number;
|
|
||||||
alert?: boolean;
|
alert?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,26 +77,28 @@ const Content = React.memo(
|
||||||
left,
|
left,
|
||||||
right,
|
right,
|
||||||
color,
|
color,
|
||||||
theme,
|
|
||||||
fontScale,
|
|
||||||
alert,
|
alert,
|
||||||
translateTitle = true,
|
translateTitle = true,
|
||||||
translateSubtitle = true,
|
translateSubtitle = true,
|
||||||
showActionIndicator = false
|
showActionIndicator = false,
|
||||||
}: IListItemContent) => (
|
theme
|
||||||
<View style={[styles.container, disabled && styles.disabled, { height: BASE_HEIGHT * fontScale! }]} testID={testID}>
|
}: IListItemContent) => {
|
||||||
|
const { fontScale } = useDimensions();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={[styles.container, disabled && styles.disabled, { height: BASE_HEIGHT * fontScale }]} testID={testID}>
|
||||||
{left ? <View style={styles.leftContainer}>{left()}</View> : null}
|
{left ? <View style={styles.leftContainer}>{left()}</View> : null}
|
||||||
<View style={styles.textContainer}>
|
<View style={styles.textContainer}>
|
||||||
<View style={styles.textAlertContainer}>
|
<View style={styles.textAlertContainer}>
|
||||||
<Text style={[styles.title, { color: color || themes[theme!].titleText }]} numberOfLines={1}>
|
<Text style={[styles.title, { color: color || themes[theme].titleText }]} numberOfLines={1}>
|
||||||
{translateTitle ? I18n.t(title) : title}
|
{translateTitle ? I18n.t(title) : title}
|
||||||
</Text>
|
</Text>
|
||||||
{alert ? (
|
{alert ? (
|
||||||
<CustomIcon style={[styles.alertIcon, { color: themes[theme!].dangerColor }]} size={ICON_SIZE} name='info' />
|
<CustomIcon style={[styles.alertIcon, { color: themes[theme].dangerColor }]} size={ICON_SIZE} name='info' />
|
||||||
) : null}
|
) : null}
|
||||||
</View>
|
</View>
|
||||||
{subtitle ? (
|
{subtitle ? (
|
||||||
<Text style={[styles.subtitle, { color: themes[theme!].auxiliaryText }]} numberOfLines={1}>
|
<Text style={[styles.subtitle, { color: themes[theme].auxiliaryText }]} numberOfLines={1}>
|
||||||
{translateSubtitle ? I18n.t(subtitle) : subtitle}
|
{translateSubtitle ? I18n.t(subtitle) : subtitle}
|
||||||
</Text>
|
</Text>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -109,47 +110,52 @@ const Content = React.memo(
|
||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
</View>
|
</View>
|
||||||
)
|
);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
interface IListButtonPress {
|
interface IListButtonPress extends IListItemButton {
|
||||||
onPress?: Function;
|
onPress: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IListItemButton extends IListButtonPress {
|
interface IListItemButton {
|
||||||
title?: string;
|
title?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
theme?: string;
|
theme: string;
|
||||||
backgroundColor?: string;
|
backgroundColor?: string;
|
||||||
underlayColor?: string;
|
underlayColor?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Button = React.memo<IListItemButton>(({ onPress, backgroundColor, underlayColor, ...props }: IListItemButton) => (
|
const Button = React.memo(({ onPress, backgroundColor, underlayColor, ...props }: IListButtonPress) => (
|
||||||
<Touch
|
<Touch
|
||||||
onPress={() => onPress!(props.title)}
|
onPress={() => onPress(props.title)}
|
||||||
style={{ backgroundColor: backgroundColor || themes[props.theme!].backgroundColor }}
|
style={{ backgroundColor: backgroundColor || themes[props.theme].backgroundColor }}
|
||||||
underlayColor={underlayColor}
|
underlayColor={underlayColor}
|
||||||
enabled={!props.disabled}
|
enabled={!props.disabled}
|
||||||
theme={props.theme!}>
|
theme={props.theme}>
|
||||||
<Content {...props} />
|
<Content {...props} />
|
||||||
</Touch>
|
</Touch>
|
||||||
));
|
));
|
||||||
|
|
||||||
interface IListItem extends IListItemContent, IListItemButton {
|
interface IListItem extends Omit<IListItemContent, 'theme'>, Omit<IListItemButton, 'theme'> {
|
||||||
backgroundColor?: string;
|
backgroundColor?: string;
|
||||||
|
onPress?: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListItem = React.memo<IListItem>(({ ...props }: IListItem) => {
|
const ListItem = React.memo(({ ...props }: IListItem) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
if (props.onPress) {
|
if (props.onPress) {
|
||||||
return <Button {...props} />;
|
const { onPress } = props;
|
||||||
|
return <Button {...props} theme={theme} onPress={onPress} />;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<View style={{ backgroundColor: props.backgroundColor || themes[props.theme!].backgroundColor }}>
|
<View style={{ backgroundColor: props.backgroundColor || themes[theme].backgroundColor }}>
|
||||||
<Content {...props} />
|
<Content {...props} theme={theme} />
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
ListItem.displayName = 'List.Item';
|
ListItem.displayName = 'List.Item';
|
||||||
|
|
||||||
export default withTheme(withDimensions(ListItem));
|
export default ListItem;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StyleSheet, View } from 'react-native';
|
import { StyleSheet, View } from 'react-native';
|
||||||
|
|
||||||
import { withTheme } from '../../theme';
|
|
||||||
import { Header } from '.';
|
import { Header } from '.';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
@ -11,7 +10,7 @@ const styles = StyleSheet.create({
|
||||||
});
|
});
|
||||||
|
|
||||||
interface IListSection {
|
interface IListSection {
|
||||||
children: React.ReactNode;
|
children: (React.ReactElement | null)[] | React.ReactElement | null;
|
||||||
title?: string;
|
title?: string;
|
||||||
translateTitle?: boolean;
|
translateTitle?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -25,4 +24,4 @@ const ListSection = React.memo(({ children, title, translateTitle }: IListSectio
|
||||||
|
|
||||||
ListSection.displayName = 'List.Section';
|
ListSection.displayName = 'List.Section';
|
||||||
|
|
||||||
export default withTheme(ListSection);
|
export default ListSection;
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import { StyleSheet, View, ViewStyle } from 'react-native';
|
import { StyleSheet, View, ViewStyle } from 'react-native';
|
||||||
|
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import { withTheme } from '../../theme';
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
separator: {
|
separator: {
|
||||||
|
@ -12,13 +12,14 @@ const styles = StyleSheet.create({
|
||||||
|
|
||||||
interface IListSeparator {
|
interface IListSeparator {
|
||||||
style?: ViewStyle;
|
style?: ViewStyle;
|
||||||
theme?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListSeparator = React.memo(({ style, theme }: IListSeparator) => (
|
const ListSeparator = React.memo(({ style }: IListSeparator) => {
|
||||||
<View style={[styles.separator, style, { backgroundColor: themes[theme!].separatorColor }]} />
|
const { theme } = useTheme();
|
||||||
));
|
|
||||||
|
return <View style={[styles.separator, style, { backgroundColor: themes[theme].separatorColor }]} />;
|
||||||
|
});
|
||||||
|
|
||||||
ListSeparator.displayName = 'List.Separator';
|
ListSeparator.displayName = 'List.Separator';
|
||||||
|
|
||||||
export default withTheme(ListSeparator);
|
export default ListSeparator;
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { themes } from '../../constants/colors';
|
||||||
import { MarkdownPreview } from '../markdown';
|
import { MarkdownPreview } from '../markdown';
|
||||||
import RoomTypeIcon from '../RoomTypeIcon';
|
import RoomTypeIcon from '../RoomTypeIcon';
|
||||||
import { withTheme } from '../../theme';
|
import { withTheme } from '../../theme';
|
||||||
|
import { TUserStatus } from '../../definitions';
|
||||||
|
|
||||||
const HIT_SLOP = {
|
const HIT_SLOP = {
|
||||||
top: 5,
|
top: 5,
|
||||||
|
@ -67,7 +68,7 @@ interface IRoomHeader {
|
||||||
prid: string;
|
prid: string;
|
||||||
tmid: string;
|
tmid: string;
|
||||||
teamMain: boolean;
|
teamMain: boolean;
|
||||||
status: string;
|
status: TUserStatus;
|
||||||
theme?: string;
|
theme?: string;
|
||||||
usersTyping: [];
|
usersTyping: [];
|
||||||
isGroupChat: boolean;
|
isGroupChat: boolean;
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { dequal } from 'dequal';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { IApplicationState } from '../../definitions';
|
import { IApplicationState, TUserStatus } from '../../definitions';
|
||||||
import { withDimensions } from '../../dimensions';
|
import { withDimensions } from '../../dimensions';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import RoomHeader from './RoomHeader';
|
import RoomHeader from './RoomHeader';
|
||||||
|
@ -15,7 +15,7 @@ interface IRoomHeaderContainerProps {
|
||||||
tmid: string;
|
tmid: string;
|
||||||
teamMain: boolean;
|
teamMain: boolean;
|
||||||
usersTyping: [];
|
usersTyping: [];
|
||||||
status: string;
|
status: TUserStatus;
|
||||||
statusText: string;
|
statusText: string;
|
||||||
connecting: boolean;
|
connecting: boolean;
|
||||||
connected: boolean;
|
connected: boolean;
|
||||||
|
@ -140,7 +140,7 @@ const mapStateToProps = (state: IApplicationState, ownProps: any) => {
|
||||||
connecting: state.meteor.connecting || state.server.loading,
|
connecting: state.meteor.connecting || state.server.loading,
|
||||||
connected: state.meteor.connected,
|
connected: state.meteor.connected,
|
||||||
usersTyping: state.usersTyping,
|
usersTyping: state.usersTyping,
|
||||||
status,
|
status: status as TUserStatus,
|
||||||
statusText
|
statusText
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { CustomIcon } from '../lib/Icons';
|
||||||
import { STATUS_COLORS, themes } from '../constants/colors';
|
import { STATUS_COLORS, themes } from '../constants/colors';
|
||||||
import Status from './Status/Status';
|
import Status from './Status/Status';
|
||||||
import { withTheme } from '../theme';
|
import { withTheme } from '../theme';
|
||||||
|
import { TUserStatus } from '../definitions';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
icon: {
|
icon: {
|
||||||
|
@ -17,7 +18,7 @@ interface IRoomTypeIcon {
|
||||||
type: string;
|
type: string;
|
||||||
isGroupChat?: boolean;
|
isGroupChat?: boolean;
|
||||||
teamMain?: boolean;
|
teamMain?: boolean;
|
||||||
status?: string;
|
status?: TUserStatus;
|
||||||
size?: number;
|
size?: number;
|
||||||
style?: ViewStyle;
|
style?: ViewStyle;
|
||||||
}
|
}
|
||||||
|
@ -31,9 +32,10 @@ const RoomTypeIcon = React.memo(({ type, isGroupChat, status, style, theme, team
|
||||||
const iconStyle = [styles.icon, { color }, style];
|
const iconStyle = [styles.icon, { color }, style];
|
||||||
|
|
||||||
if (type === 'd' && !isGroupChat) {
|
if (type === 'd' && !isGroupChat) {
|
||||||
return (
|
if (!status) {
|
||||||
<Status style={[iconStyle, { color: STATUS_COLORS[status!] ?? STATUS_COLORS.offline }]} size={size} status={status!} />
|
status = 'offline';
|
||||||
);
|
}
|
||||||
|
return <Status style={[iconStyle, { color: STATUS_COLORS[status] }]} size={size} status={status} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move this to a separate function
|
// TODO: move this to a separate function
|
||||||
|
|
|
@ -3,15 +3,9 @@ import { StyleProp, TextStyle } from 'react-native';
|
||||||
|
|
||||||
import { CustomIcon } from '../../lib/Icons';
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
import { STATUS_COLORS } from '../../constants/colors';
|
import { STATUS_COLORS } from '../../constants/colors';
|
||||||
|
import { IStatus } from './definition';
|
||||||
|
|
||||||
interface IStatus {
|
const Status = React.memo(({ style, status = 'offline', size = 32, ...props }: Omit<IStatus, 'id'>) => {
|
||||||
status: string;
|
|
||||||
size: number;
|
|
||||||
style?: StyleProp<TextStyle>;
|
|
||||||
testID?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Status = React.memo(({ style, status = 'offline', size = 32, ...props }: IStatus) => {
|
|
||||||
const name = `status-${status}`;
|
const name = `status-${status}`;
|
||||||
const isNameValid = CustomIcon.hasIcon(name);
|
const isNameValid = CustomIcon.hasIcon(name);
|
||||||
const iconName = isNameValid ? name : 'status-offline';
|
const iconName = isNameValid ? name : 'status-offline';
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { TextProps } from 'react-native';
|
||||||
|
|
||||||
|
import { TUserStatus } from '../../definitions';
|
||||||
|
|
||||||
|
export interface IStatus extends TextProps {
|
||||||
|
id: string;
|
||||||
|
size: number;
|
||||||
|
status: TUserStatus;
|
||||||
|
}
|
|
@ -1,20 +1,15 @@
|
||||||
import React, { memo } from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { IApplicationState, TUserStatus } from '../../definitions';
|
||||||
import Status from './Status';
|
import Status from './Status';
|
||||||
|
import { IStatus } from './definition';
|
||||||
|
|
||||||
interface IStatusContainer {
|
const StatusContainer = ({ id, style, size = 32, ...props }: Omit<IStatus, 'status'>): React.ReactElement => {
|
||||||
style: any;
|
const status = useSelector((state: IApplicationState) =>
|
||||||
size: number;
|
state.meteor.connected ? state.activeUsers[id] && state.activeUsers[id].status : 'loading'
|
||||||
status: string;
|
) as TUserStatus;
|
||||||
}
|
return <Status size={size} style={style} status={status} {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
const StatusContainer = memo(({ style, size = 32, status }: IStatusContainer) => (
|
export default StatusContainer;
|
||||||
<Status size={size} style={style} status={status} />
|
|
||||||
));
|
|
||||||
|
|
||||||
const mapStateToProps = (state: any, ownProps: any) => ({
|
|
||||||
status: state.meteor.connected ? state.activeUsers[ownProps.id] && state.activeUsers[ownProps.id].status : 'loading'
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(StatusContainer);
|
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Text } from 'react-native';
|
import { StyleProp, Text, TextStyle } from 'react-native';
|
||||||
|
|
||||||
import { useTheme } from '../../theme';
|
import { useTheme } from '../../theme';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import { events, logEvent } from '../../utils/log';
|
import { events, logEvent } from '../../utils/log';
|
||||||
|
import { IUserMention } from './interfaces';
|
||||||
|
|
||||||
interface IAtMention {
|
interface IAtMention {
|
||||||
mention: string;
|
mention: string;
|
||||||
username?: string;
|
username?: string;
|
||||||
navToRoomInfo?: Function;
|
navToRoomInfo?: Function;
|
||||||
style?: any;
|
style?: StyleProp<TextStyle>[];
|
||||||
useRealName?: boolean;
|
useRealName?: boolean;
|
||||||
mentions: any;
|
mentions?: IUserMention[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const AtMention = React.memo(({ mention, mentions, username, navToRoomInfo, style = [], useRealName }: IAtMention) => {
|
const AtMention = React.memo(({ mention, mentions, username, navToRoomInfo, style = [], useRealName }: IAtMention) => {
|
||||||
|
@ -23,7 +24,7 @@ const AtMention = React.memo(({ mention, mentions, username, navToRoomInfo, styl
|
||||||
style={[
|
style={[
|
||||||
styles.mention,
|
styles.mention,
|
||||||
{
|
{
|
||||||
color: themes[theme!].mentionGroupColor
|
color: themes[theme].mentionGroupColor
|
||||||
},
|
},
|
||||||
...style
|
...style
|
||||||
]}>
|
]}>
|
||||||
|
@ -35,11 +36,11 @@ const AtMention = React.memo(({ mention, mentions, username, navToRoomInfo, styl
|
||||||
let mentionStyle = {};
|
let mentionStyle = {};
|
||||||
if (mention === username) {
|
if (mention === username) {
|
||||||
mentionStyle = {
|
mentionStyle = {
|
||||||
color: themes[theme!].mentionMeColor
|
color: themes[theme].mentionMeColor
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
mentionStyle = {
|
mentionStyle = {
|
||||||
color: themes[theme!].mentionOtherColor
|
color: themes[theme].mentionOtherColor
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ const AtMention = React.memo(({ mention, mentions, username, navToRoomInfo, styl
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Text style={[styles.text, { color: themes[theme!].bodyText }, ...style]}>{`@${mention}`}</Text>;
|
return <Text style={[styles.text, { color: themes[theme].bodyText }, ...style]}>{`@${mention}`}</Text>;
|
||||||
});
|
});
|
||||||
|
|
||||||
export default AtMention;
|
export default AtMention;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { themes } from '../../constants/colors';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
||||||
interface IBlockQuote {
|
interface IBlockQuote {
|
||||||
children: JSX.Element;
|
children: React.ReactElement | null;
|
||||||
theme: string;
|
theme: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Text, TextStyle, StyleProp } from 'react-native';
|
import { StyleProp, Text, TextStyle } from 'react-native';
|
||||||
|
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import { useTheme } from '../../theme';
|
import { useTheme } from '../../theme';
|
||||||
|
@ -33,7 +33,7 @@ const Hashtag = React.memo(({ hashtag, channels, navToRoomInfo, style = [] }: IH
|
||||||
style={[
|
style={[
|
||||||
styles.mention,
|
styles.mention,
|
||||||
{
|
{
|
||||||
color: themes[theme!].mentionOtherColor
|
color: themes[theme].mentionOtherColor
|
||||||
},
|
},
|
||||||
...style
|
...style
|
||||||
]}
|
]}
|
||||||
|
@ -42,7 +42,7 @@ const Hashtag = React.memo(({ hashtag, channels, navToRoomInfo, style = [] }: IH
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <Text style={[styles.text, { color: themes[theme!].bodyText }, ...style]}>{`#${hashtag}`}</Text>;
|
return <Text style={[styles.text, { color: themes[theme].bodyText }, ...style]}>{`#${hashtag}`}</Text>;
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Hashtag;
|
export default Hashtag;
|
||||||
|
|
|
@ -10,7 +10,7 @@ import openLink from '../../utils/openLink';
|
||||||
import { TOnLinkPress } from './interfaces';
|
import { TOnLinkPress } from './interfaces';
|
||||||
|
|
||||||
interface ILink {
|
interface ILink {
|
||||||
children: JSX.Element;
|
children: React.ReactElement | null;
|
||||||
link: string;
|
link: string;
|
||||||
theme: string;
|
theme: string;
|
||||||
onLinkPress?: TOnLinkPress;
|
onLinkPress?: TOnLinkPress;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
interface IList {
|
interface IList {
|
||||||
children: JSX.Element;
|
children: React.ReactElement[] | null;
|
||||||
ordered: boolean;
|
ordered: boolean;
|
||||||
start: number;
|
start: number;
|
||||||
tight: boolean;
|
tight: boolean;
|
||||||
|
@ -11,9 +11,8 @@ interface IList {
|
||||||
const List = React.memo(({ children, ordered, tight, start = 1, numberOfLines = 0 }: IList) => {
|
const List = React.memo(({ children, ordered, tight, start = 1, numberOfLines = 0 }: IList) => {
|
||||||
let bulletWidth = 15;
|
let bulletWidth = 15;
|
||||||
|
|
||||||
if (ordered) {
|
if (ordered && children) {
|
||||||
// @ts-ignore
|
const lastNumber = start + children?.length - 1;
|
||||||
const lastNumber = start + children.length - 1;
|
|
||||||
bulletWidth = 9 * lastNumber.toString().length + 7;
|
bulletWidth = 9 * lastNumber.toString().length + 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ const style = StyleSheet.create({
|
||||||
});
|
});
|
||||||
|
|
||||||
interface IListItem {
|
interface IListItem {
|
||||||
children: JSX.Element;
|
children: React.ReactElement | null;
|
||||||
bulletWidth: number;
|
bulletWidth: number;
|
||||||
level: number;
|
level: number;
|
||||||
ordered: boolean;
|
ordered: boolean;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StyleProp, Text, TextStyle } from 'react-native';
|
import { Text, TextStyle } from 'react-native';
|
||||||
import removeMarkdown from 'remove-markdown';
|
import removeMarkdown from 'remove-markdown';
|
||||||
|
|
||||||
import shortnameToUnicode from '../../utils/shortnameToUnicode';
|
import shortnameToUnicode from '../../utils/shortnameToUnicode';
|
||||||
|
@ -13,10 +13,10 @@ interface IMarkdownPreview {
|
||||||
msg?: string;
|
msg?: string;
|
||||||
numberOfLines?: number;
|
numberOfLines?: number;
|
||||||
testID?: string;
|
testID?: string;
|
||||||
style?: StyleProp<TextStyle>[];
|
style?: TextStyle[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const MarkdownPreview = ({ msg, numberOfLines = 1, testID, style = [] }: IMarkdownPreview): React.ReactElement | null => {
|
const MarkdownPreview = ({ msg, numberOfLines = 1, testID, style = [] }: IMarkdownPreview) => {
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import I18n from '../../i18n';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
|
|
||||||
interface ITable {
|
interface ITable {
|
||||||
children: JSX.Element;
|
children: React.ReactElement | null;
|
||||||
numColumns: number;
|
numColumns: number;
|
||||||
theme: string;
|
theme: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import styles from './styles';
|
||||||
|
|
||||||
interface ITableCell {
|
interface ITableCell {
|
||||||
align: '' | 'left' | 'center' | 'right';
|
align: '' | 'left' | 'center' | 'right';
|
||||||
children: JSX.Element;
|
children: React.ReactElement | null;
|
||||||
isLastCell: boolean;
|
isLastCell: boolean;
|
||||||
theme: string;
|
theme: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { themes } from '../../constants/colors';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
||||||
interface ITableRow {
|
interface ITableRow {
|
||||||
children: JSX.Element;
|
children: React.ReactElement | null;
|
||||||
isLastRow: boolean;
|
isLastRow: boolean;
|
||||||
theme: string;
|
theme: string;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ const TableRow = React.memo(({ isLastRow, children: _children, theme }: ITableRo
|
||||||
rowStyle.push(styles.rowBottomBorder);
|
rowStyle.push(styles.rowBottomBorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
const children: any = React.Children.toArray(_children);
|
const children = React.Children.toArray(_children) as React.ReactElement[];
|
||||||
children[children.length - 1] = React.cloneElement(children[children.length - 1], {
|
children[children.length - 1] = React.cloneElement(children[children.length - 1], {
|
||||||
isLastCell: true
|
isLastCell: true
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,6 +2,7 @@ export interface IUserMention {
|
||||||
_id: string;
|
_id: string;
|
||||||
username: string;
|
username: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
type?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUserChannel {
|
export interface IUserChannel {
|
||||||
|
|
|
@ -14,7 +14,7 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const BigEmoji = ({ value }: IBigEmojiProps): JSX.Element => (
|
const BigEmoji = ({ value }: IBigEmojiProps) => (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
{value.map(block => (
|
{value.map(block => (
|
||||||
<Emoji value={block.value} isBigEmoji />
|
<Emoji value={block.value} isBigEmoji />
|
||||||
|
|
|
@ -18,7 +18,7 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const Bold = ({ value }: IBoldProps): JSX.Element => (
|
const Bold = ({ value }: IBoldProps) => (
|
||||||
<Text style={styles.text}>
|
<Text style={styles.text}>
|
||||||
{value.map(block => {
|
{value.map(block => {
|
||||||
switch (block.type) {
|
switch (block.type) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ interface ICodeProps {
|
||||||
value: CodeProps['value'];
|
value: CodeProps['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Code = ({ value }: ICodeProps): JSX.Element => {
|
const Code = ({ value }: ICodeProps) => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -19,9 +19,9 @@ const Code = ({ value }: ICodeProps): JSX.Element => {
|
||||||
style={[
|
style={[
|
||||||
styles.codeBlock,
|
styles.codeBlock,
|
||||||
{
|
{
|
||||||
color: themes[theme!].bodyText,
|
color: themes[theme].bodyText,
|
||||||
backgroundColor: themes[theme!].bannerBackground,
|
backgroundColor: themes[theme].bannerBackground,
|
||||||
borderColor: themes[theme!].borderColor
|
borderColor: themes[theme].borderColor
|
||||||
}
|
}
|
||||||
]}>
|
]}>
|
||||||
{value.map(block => {
|
{value.map(block => {
|
||||||
|
|
|
@ -6,7 +6,7 @@ interface ICodeLineProps {
|
||||||
value: CodeLineProps['value'];
|
value: CodeLineProps['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const CodeLine = ({ value }: ICodeLineProps): JSX.Element | null => {
|
const CodeLine = ({ value }: ICodeLineProps) => {
|
||||||
if (value.type !== 'PLAIN_TEXT') {
|
if (value.type !== 'PLAIN_TEXT') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ interface IEmojiProps {
|
||||||
isBigEmoji?: boolean;
|
isBigEmoji?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Emoji = ({ value, isBigEmoji }: IEmojiProps): JSX.Element => {
|
const Emoji = ({ value, isBigEmoji }: IEmojiProps) => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
const { baseUrl, getCustomEmoji } = useContext(MarkdownContext);
|
const { baseUrl, getCustomEmoji } = useContext(MarkdownContext);
|
||||||
const emojiUnicode = shortnameToUnicode(`:${value.value}:`);
|
const emojiUnicode = shortnameToUnicode(`:${value.value}:`);
|
||||||
|
@ -23,7 +23,7 @@ const Emoji = ({ value, isBigEmoji }: IEmojiProps): JSX.Element => {
|
||||||
if (emoji) {
|
if (emoji) {
|
||||||
return <CustomEmoji baseUrl={baseUrl} style={[isBigEmoji ? styles.customEmojiBig : styles.customEmoji]} emoji={emoji} />;
|
return <CustomEmoji baseUrl={baseUrl} style={[isBigEmoji ? styles.customEmojiBig : styles.customEmoji]} emoji={emoji} />;
|
||||||
}
|
}
|
||||||
return <Text style={[{ color: themes[theme!].bodyText }, isBigEmoji ? styles.textBig : styles.text]}>{emojiUnicode}</Text>;
|
return <Text style={[{ color: themes[theme].bodyText }, isBigEmoji ? styles.textBig : styles.text]}>{emojiUnicode}</Text>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Emoji;
|
export default Emoji;
|
||||||
|
|
|
@ -11,12 +11,12 @@ interface IHeadingProps {
|
||||||
level: HeadingProps['level'];
|
level: HeadingProps['level'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Heading = ({ value, level }: IHeadingProps): JSX.Element => {
|
const Heading = ({ value, level }: IHeadingProps) => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
const textStyle = styles[`heading${level}`];
|
const textStyle = styles[`heading${level}`];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Text style={[textStyle, { color: themes[theme!].bodyText }]}>
|
<Text style={[textStyle, { color: themes[theme].bodyText }]}>
|
||||||
{value.map(block => {
|
{value.map(block => {
|
||||||
switch (block.type) {
|
switch (block.type) {
|
||||||
case 'PLAIN_TEXT':
|
case 'PLAIN_TEXT':
|
||||||
|
|
|
@ -31,11 +31,11 @@ const MessageImage = ({ img, theme }: TMessageImage) => (
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const Image = ({ value }: IImageProps): JSX.Element => {
|
const Image = ({ value }: IImageProps) => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
const { src } = value;
|
const { src } = value;
|
||||||
|
|
||||||
return <MessageImage img={src.value} theme={theme!} />;
|
return <MessageImage img={src.value} theme={theme} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Image;
|
export default Image;
|
||||||
|
|
|
@ -19,7 +19,7 @@ interface IParagraphProps {
|
||||||
value: ParagraphProps['value'];
|
value: ParagraphProps['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Inline = ({ value }: IParagraphProps): JSX.Element => {
|
const Inline = ({ value }: IParagraphProps) => {
|
||||||
const { useRealName, username, navToRoomInfo, mentions, channels } = useContext(MarkdownContext);
|
const { useRealName, username, navToRoomInfo, mentions, channels } = useContext(MarkdownContext);
|
||||||
return (
|
return (
|
||||||
<Text style={styles.inline}>
|
<Text style={styles.inline}>
|
||||||
|
|
|
@ -10,7 +10,7 @@ interface IInlineCodeProps {
|
||||||
value: InlineCodeProps['value'];
|
value: InlineCodeProps['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const InlineCode = ({ value }: IInlineCodeProps): JSX.Element => {
|
const InlineCode = ({ value }: IInlineCodeProps) => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -18,9 +18,9 @@ const InlineCode = ({ value }: IInlineCodeProps): JSX.Element => {
|
||||||
style={[
|
style={[
|
||||||
styles.codeInline,
|
styles.codeInline,
|
||||||
{
|
{
|
||||||
color: themes[theme!].bodyText,
|
color: themes[theme].bodyText,
|
||||||
backgroundColor: themes[theme!].bannerBackground,
|
backgroundColor: themes[theme].bannerBackground,
|
||||||
borderColor: themes[theme!].borderColor
|
borderColor: themes[theme].borderColor
|
||||||
}
|
}
|
||||||
]}>
|
]}>
|
||||||
{(block => {
|
{(block => {
|
||||||
|
|
|
@ -17,7 +17,7 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const Italic = ({ value }: IItalicProps): JSX.Element => (
|
const Italic = ({ value }: IItalicProps) => (
|
||||||
<Text style={styles.text}>
|
<Text style={styles.text}>
|
||||||
{value.map(block => {
|
{value.map(block => {
|
||||||
switch (block.type) {
|
switch (block.type) {
|
||||||
|
|
|
@ -18,7 +18,7 @@ interface ILinkProps {
|
||||||
value: LinkProps['value'];
|
value: LinkProps['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Link = ({ value }: ILinkProps): JSX.Element => {
|
const Link = ({ value }: ILinkProps) => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
const { onLinkPress } = useContext(MarkdownContext);
|
const { onLinkPress } = useContext(MarkdownContext);
|
||||||
const { src, label } = value;
|
const { src, label } = value;
|
||||||
|
@ -38,7 +38,7 @@ const Link = ({ value }: ILinkProps): JSX.Element => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Text onPress={handlePress} onLongPress={onLongPress} style={[styles.link, { color: themes[theme!].actionTintColor }]}>
|
<Text onPress={handlePress} onLongPress={onLongPress} style={[styles.link, { color: themes[theme].actionTintColor }]}>
|
||||||
{(block => {
|
{(block => {
|
||||||
switch (block.type) {
|
switch (block.type) {
|
||||||
case 'PLAIN_TEXT':
|
case 'PLAIN_TEXT':
|
||||||
|
|
|
@ -11,13 +11,13 @@ interface IOrderedListProps {
|
||||||
value: OrderedListProps['value'];
|
value: OrderedListProps['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const OrderedList = ({ value }: IOrderedListProps): JSX.Element => {
|
const OrderedList = ({ value }: IOrderedListProps) => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
{value.map((item, index) => (
|
{value.map((item, index) => (
|
||||||
<View style={styles.row}>
|
<View style={styles.row}>
|
||||||
<Text style={[styles.text, { color: themes[theme!].bodyText }]}>{index + 1}. </Text>
|
<Text style={[styles.text, { color: themes[theme].bodyText }]}>{index + 1}. </Text>
|
||||||
<Inline value={item.value} />
|
<Inline value={item.value} />
|
||||||
</View>
|
</View>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -11,10 +11,10 @@ interface IParagraphProps {
|
||||||
value: ParagraphProps['value'];
|
value: ParagraphProps['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Paragraph = ({ value }: IParagraphProps): JSX.Element => {
|
const Paragraph = ({ value }: IParagraphProps) => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
return (
|
return (
|
||||||
<Text style={[styles.text, { color: themes[theme!].bodyText }]}>
|
<Text style={[styles.text, { color: themes[theme].bodyText }]}>
|
||||||
<Inline value={value} />
|
<Inline value={value} />
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
|
|
|
@ -10,10 +10,10 @@ interface IPlainProps {
|
||||||
value: PlainProps['value'];
|
value: PlainProps['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Plain = ({ value }: IPlainProps): JSX.Element => {
|
const Plain = ({ value }: IPlainProps) => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
return (
|
return (
|
||||||
<Text accessibilityLabel={value} style={[styles.plainText, { color: themes[theme!].bodyText }]}>
|
<Text accessibilityLabel={value} style={[styles.plainText, { color: themes[theme].bodyText }]}>
|
||||||
{value}
|
{value}
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,11 +11,11 @@ interface IQuoteProps {
|
||||||
value: QuoteProps['value'];
|
value: QuoteProps['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Quote = ({ value }: IQuoteProps): JSX.Element => {
|
const Quote = ({ value }: IQuoteProps) => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={[styles.quote, { backgroundColor: themes[theme!].borderColor }]} />
|
<View style={[styles.quote, { backgroundColor: themes[theme].borderColor }]} />
|
||||||
<View style={styles.childContainer}>
|
<View style={styles.childContainer}>
|
||||||
{value.map(item => (
|
{value.map(item => (
|
||||||
<Paragraph value={item.value} />
|
<Paragraph value={item.value} />
|
||||||
|
|
|
@ -17,7 +17,7 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const Strike = ({ value }: IStrikeProps): JSX.Element => (
|
const Strike = ({ value }: IStrikeProps) => (
|
||||||
<Text style={styles.text}>
|
<Text style={styles.text}>
|
||||||
{value.map(block => {
|
{value.map(block => {
|
||||||
switch (block.type) {
|
switch (block.type) {
|
||||||
|
|
|
@ -11,13 +11,13 @@ interface ITasksProps {
|
||||||
value: TasksProps['value'];
|
value: TasksProps['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const TaskList = ({ value = [] }: ITasksProps): JSX.Element => {
|
const TaskList = ({ value = [] }: ITasksProps) => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
{value.map(item => (
|
{value.map(item => (
|
||||||
<View style={styles.row}>
|
<View style={styles.row}>
|
||||||
<Text style={[styles.text, { color: themes[theme!].bodyText }]}>{item.status ? '- [x] ' : '- [ ] '}</Text>
|
<Text style={[styles.text, { color: themes[theme].bodyText }]}>{item.status ? '- [x] ' : '- [ ] '}</Text>
|
||||||
<Inline value={item.value} />
|
<Inline value={item.value} />
|
||||||
</View>
|
</View>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -11,13 +11,13 @@ interface IUnorderedListProps {
|
||||||
value: UnorderedListProps['value'];
|
value: UnorderedListProps['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const UnorderedList = ({ value }: IUnorderedListProps): JSX.Element => {
|
const UnorderedList = ({ value }: IUnorderedListProps) => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
{value.map(item => (
|
{value.map(item => (
|
||||||
<View style={styles.row}>
|
<View style={styles.row}>
|
||||||
<Text style={[styles.text, { color: themes[theme!].bodyText }]}>- </Text>
|
<Text style={[styles.text, { color: themes[theme].bodyText }]}>- </Text>
|
||||||
<Inline value={item.value} />
|
<Inline value={item.value} />
|
||||||
</View>
|
</View>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -35,7 +35,7 @@ const Body = ({
|
||||||
getCustomEmoji,
|
getCustomEmoji,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
onLinkPress
|
onLinkPress
|
||||||
}: IBodyProps): React.ReactElement | null => {
|
}: IBodyProps) => {
|
||||||
if (isEmpty(tokens)) {
|
if (isEmpty(tokens)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ const Attachments = React.memo(
|
||||||
if (file && file.actions && file.actions.length > 0) {
|
if (file && file.actions && file.actions.length > 0) {
|
||||||
return <AttachedActions attachment={file} />;
|
return <AttachedActions attachment={file} />;
|
||||||
}
|
}
|
||||||
if (file.title) {
|
if (typeof file.collapsed === 'boolean') {
|
||||||
return (
|
return (
|
||||||
<CollapsibleQuote key={index} index={index} attachment={file} timeFormat={timeFormat} getCustomEmoji={getCustomEmoji} />
|
<CollapsibleQuote key={index} index={index} attachment={file} timeFormat={timeFormat} getCustomEmoji={getCustomEmoji} />
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Model from '@nozbe/watermelondb/Model';
|
import Model from '@nozbe/watermelondb/Model';
|
||||||
|
|
||||||
import { IUserEmail, IUserSettings } from './IUser';
|
import { IUserEmail, IUserSettings } from './IUser';
|
||||||
import { UserStatus } from './UserStatus';
|
import { TUserStatus } from './TUserStatus';
|
||||||
|
|
||||||
export interface ILoggedUser {
|
export interface ILoggedUser {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -9,7 +9,7 @@ export interface ILoggedUser {
|
||||||
username: string;
|
username: string;
|
||||||
name: string;
|
name: string;
|
||||||
language?: string;
|
language?: string;
|
||||||
status: UserStatus;
|
status: TUserStatus;
|
||||||
statusText?: string;
|
statusText?: string;
|
||||||
customFields?: {
|
customFields?: {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Model from '@nozbe/watermelondb/Model';
|
import Model from '@nozbe/watermelondb/Model';
|
||||||
|
|
||||||
import { UserStatus } from './UserStatus';
|
import { TUserStatus } from './TUserStatus';
|
||||||
import { IRocketChatRecord } from './IRocketChatRecord';
|
import { IRocketChatRecord } from './IRocketChatRecord';
|
||||||
import { ILoggedUser } from './ILoggedUser';
|
import { ILoggedUser } from './ILoggedUser';
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ export interface IPersonalAccessToken extends ILoginToken {
|
||||||
export interface IUserRegistered {
|
export interface IUserRegistered {
|
||||||
_id: string;
|
_id: string;
|
||||||
type: string;
|
type: string;
|
||||||
status: UserStatus;
|
status: TUserStatus;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
username: string;
|
username: string;
|
||||||
|
@ -133,14 +133,14 @@ export interface IUser extends IRocketChatRecord, Omit<ILoggedUser, 'username' |
|
||||||
name?: string;
|
name?: string;
|
||||||
services?: IUserServices;
|
services?: IUserServices;
|
||||||
emails?: IUserEmail[];
|
emails?: IUserEmail[];
|
||||||
status: UserStatus;
|
status: TUserStatus;
|
||||||
statusConnection?: string;
|
statusConnection?: string;
|
||||||
lastLogin?: Date;
|
lastLogin?: Date;
|
||||||
avatarOrigin?: string;
|
avatarOrigin?: string;
|
||||||
avatarETag?: string;
|
avatarETag?: string;
|
||||||
utcOffset?: number;
|
utcOffset?: number;
|
||||||
language?: string;
|
language?: string;
|
||||||
statusDefault?: UserStatus;
|
statusDefault?: TUserStatus;
|
||||||
statusText?: string;
|
statusText?: string;
|
||||||
oauth?: {
|
oauth?: {
|
||||||
authorizedClients: string[];
|
authorizedClients: string[];
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export const STATUSES = ['offline', 'online', 'away', 'busy'] as const;
|
||||||
|
|
||||||
|
export type TUserStatus = typeof STATUSES[number];
|
|
@ -1,6 +0,0 @@
|
||||||
export enum UserStatus {
|
|
||||||
ONLINE = 'online',
|
|
||||||
AWAY = 'away',
|
|
||||||
OFFLINE = 'offline',
|
|
||||||
BUSY = 'busy'
|
|
||||||
}
|
|
|
@ -26,6 +26,7 @@ export * from './ICertificate';
|
||||||
export * from './IUrl';
|
export * from './IUrl';
|
||||||
export * from './ICredentials';
|
export * from './ICredentials';
|
||||||
export * from './ISearch';
|
export * from './ISearch';
|
||||||
|
export * from './TUserStatus';
|
||||||
|
|
||||||
export interface IBaseScreen<T extends Record<string, object | undefined>, S extends string> {
|
export interface IBaseScreen<T extends Record<string, object | undefined>, S extends string> {
|
||||||
navigation: StackNavigationProp<T, S>;
|
navigation: StackNavigationProp<T, S>;
|
||||||
|
|
|
@ -8,7 +8,7 @@ export interface IDimensionsContextProps {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
scale?: number;
|
scale?: number;
|
||||||
fontScale?: number;
|
fontScale: number;
|
||||||
setDimensions?: ({
|
setDimensions?: ({
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
@ -22,7 +22,9 @@ export interface IDimensionsContextProps {
|
||||||
}) => void;
|
}) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DimensionsContext = React.createContext<IDimensionsContextProps>(Dimensions.get('window'));
|
export const DimensionsContext = React.createContext<IDimensionsContextProps>(
|
||||||
|
Dimensions.get('window') as IDimensionsContextProps
|
||||||
|
);
|
||||||
|
|
||||||
export function withDimensions<T extends object>(Component: React.ComponentType<T> & TNavigationOptions): typeof Component {
|
export function withDimensions<T extends object>(Component: React.ComponentType<T> & TNavigationOptions): typeof Component {
|
||||||
const DimensionsComponent = (props: T) => (
|
const DimensionsComponent = (props: T) => (
|
||||||
|
|
|
@ -73,7 +73,6 @@ export const THEME_PREFERENCES_KEY = 'RC_THEME_PREFERENCES_KEY';
|
||||||
export const CRASH_REPORT_KEY = 'RC_CRASH_REPORT_KEY';
|
export const CRASH_REPORT_KEY = 'RC_CRASH_REPORT_KEY';
|
||||||
export const ANALYTICS_EVENTS_KEY = 'RC_ANALYTICS_EVENTS_KEY';
|
export const ANALYTICS_EVENTS_KEY = 'RC_ANALYTICS_EVENTS_KEY';
|
||||||
export const MIN_ROCKETCHAT_VERSION = '0.70.0';
|
export const MIN_ROCKETCHAT_VERSION = '0.70.0';
|
||||||
export const STATUSES = ['offline', 'online', 'away', 'busy'];
|
|
||||||
|
|
||||||
const RocketChat = {
|
const RocketChat = {
|
||||||
TOKEN_KEY,
|
TOKEN_KEY,
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { Q } from '@nozbe/watermelondb';
|
||||||
|
|
||||||
import log from '../../../utils/log';
|
import log from '../../../utils/log';
|
||||||
import { onRolesChanged } from '../../methods/getRoles';
|
import { onRolesChanged } from '../../methods/getRoles';
|
||||||
import { UserStatus } from '../../../definitions/UserStatus';
|
|
||||||
import { setActiveUsers } from '../../../actions/activeUsers';
|
import { setActiveUsers } from '../../../actions/activeUsers';
|
||||||
import protectedFunction from '../../methods/helpers/protectedFunction';
|
import protectedFunction from '../../methods/helpers/protectedFunction';
|
||||||
import database from '../../database';
|
import database from '../../database';
|
||||||
|
@ -17,8 +16,8 @@ import { store } from '../../auxStore';
|
||||||
import { loginRequest, setLoginServices, setUser } from '../../../actions/login';
|
import { loginRequest, setLoginServices, setUser } from '../../../actions/login';
|
||||||
import sdk from './sdk';
|
import sdk from './sdk';
|
||||||
import I18n from '../../../i18n';
|
import I18n from '../../../i18n';
|
||||||
import RocketChat, { MIN_ROCKETCHAT_VERSION, STATUSES } from '../rocketchat';
|
import RocketChat, { MIN_ROCKETCHAT_VERSION } from '../rocketchat';
|
||||||
import { ICredentials, ILoggedUser, IRocketChat } from '../../../definitions';
|
import { ICredentials, ILoggedUser, IRocketChat, STATUSES } from '../../../definitions';
|
||||||
import { isIOS } from '../../../utils/deviceInfo';
|
import { isIOS } from '../../../utils/deviceInfo';
|
||||||
import { connectRequest, connectSuccess, disconnect as disconnectAction } from '../../../actions/connect';
|
import { connectRequest, connectSuccess, disconnect as disconnectAction } from '../../../actions/connect';
|
||||||
import { updatePermission } from '../../../actions/permissions';
|
import { updatePermission } from '../../../actions/permissions';
|
||||||
|
@ -195,7 +194,7 @@ function connect(
|
||||||
|
|
||||||
const { user: loggedUser } = store.getState().login;
|
const { user: loggedUser } = store.getState().login;
|
||||||
if (loggedUser && loggedUser.id === id) {
|
if (loggedUser && loggedUser.id === id) {
|
||||||
store.dispatch(setUser({ status: STATUSES[status] as UserStatus, statusText }));
|
store.dispatch(setUser({ status: STATUSES[status], statusText }));
|
||||||
}
|
}
|
||||||
} else if (/updateAvatar/.test(eventName)) {
|
} else if (/updateAvatar/.test(eventName)) {
|
||||||
const { username, etag } = ddpMessage.fields.args[0];
|
const { username, etag } = ddpMessage.fields.args[0];
|
||||||
|
|
|
@ -12,6 +12,7 @@ import Touchable from './Touchable';
|
||||||
import Tag from './Tag';
|
import Tag from './Tag';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import { DisplayMode } from '../../constants/constantDisplayMode';
|
import { DisplayMode } from '../../constants/constantDisplayMode';
|
||||||
|
import { TUserStatus } from '../../definitions';
|
||||||
|
|
||||||
interface IRoomItem {
|
interface IRoomItem {
|
||||||
rid: string;
|
rid: string;
|
||||||
|
@ -24,7 +25,7 @@ interface IRoomItem {
|
||||||
avatarSize: number;
|
avatarSize: number;
|
||||||
testID: string;
|
testID: string;
|
||||||
width: number;
|
width: number;
|
||||||
status: string;
|
status: TUserStatus;
|
||||||
useRealName: boolean;
|
useRealName: boolean;
|
||||||
theme: string;
|
theme: string;
|
||||||
isFocused: boolean;
|
isFocused: boolean;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import { TUserStatus } from '../../definitions';
|
||||||
import RoomTypeIcon from '../../containers/RoomTypeIcon';
|
import RoomTypeIcon from '../../containers/RoomTypeIcon';
|
||||||
|
|
||||||
interface ITypeIcon {
|
interface ITypeIcon {
|
||||||
type: string;
|
type: string;
|
||||||
status: string;
|
status: TUserStatus;
|
||||||
prid: string;
|
prid: string;
|
||||||
isGroupChat: boolean;
|
isGroupChat: boolean;
|
||||||
teamMain: boolean;
|
teamMain: boolean;
|
||||||
|
|
|
@ -5,6 +5,7 @@ import I18n from '../../i18n';
|
||||||
import { ROW_HEIGHT, ROW_HEIGHT_CONDENSED } from './styles';
|
import { ROW_HEIGHT, ROW_HEIGHT_CONDENSED } from './styles';
|
||||||
import { formatDate } from '../../utils/room';
|
import { formatDate } from '../../utils/room';
|
||||||
import RoomItem from './RoomItem';
|
import RoomItem from './RoomItem';
|
||||||
|
import { TUserStatus } from '../../definitions';
|
||||||
|
|
||||||
export { ROW_HEIGHT, ROW_HEIGHT_CONDENSED };
|
export { ROW_HEIGHT, ROW_HEIGHT_CONDENSED };
|
||||||
interface IRoomItemContainerProps {
|
interface IRoomItemContainerProps {
|
||||||
|
@ -16,7 +17,7 @@ interface IRoomItemContainerProps {
|
||||||
username: string;
|
username: string;
|
||||||
avatarSize: number;
|
avatarSize: number;
|
||||||
width: number;
|
width: number;
|
||||||
status: string;
|
status: TUserStatus;
|
||||||
toggleFav(): void;
|
toggleFav(): void;
|
||||||
toggleRead(): void;
|
toggleRead(): void;
|
||||||
hideChannel(): void;
|
hideChannel(): void;
|
||||||
|
@ -53,7 +54,7 @@ class RoomItemContainer extends React.Component<IRoomItemContainerProps, any> {
|
||||||
|
|
||||||
private roomSubscription: any;
|
private roomSubscription: any;
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps: Partial<IRoomItemContainerProps> = {
|
||||||
avatarSize: 48,
|
avatarSize: 48,
|
||||||
status: 'offline',
|
status: 'offline',
|
||||||
getUserPresence: () => {},
|
getUserPresence: () => {},
|
||||||
|
@ -233,7 +234,7 @@ const mapStateToProps = (state: any, ownProps: any) => {
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
connected: state.meteor.connected,
|
connected: state.meteor.connected,
|
||||||
status
|
status: status as TUserStatus
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { clearActiveUsers, setActiveUsers } from '../actions/activeUsers';
|
import { clearActiveUsers, setActiveUsers } from '../actions/activeUsers';
|
||||||
import { UserStatus } from '../definitions/UserStatus';
|
|
||||||
import { IActiveUsers, initialState } from './activeUsers';
|
import { IActiveUsers, initialState } from './activeUsers';
|
||||||
import { mockedStore } from './mockedStore';
|
import { mockedStore } from './mockedStore';
|
||||||
|
|
||||||
|
@ -9,7 +8,7 @@ describe('test reducer', () => {
|
||||||
expect(state).toEqual(initialState);
|
expect(state).toEqual(initialState);
|
||||||
});
|
});
|
||||||
it('should return modified store after action', () => {
|
it('should return modified store after action', () => {
|
||||||
const activeUsers: IActiveUsers = { any: { status: UserStatus.ONLINE, statusText: 'any' } };
|
const activeUsers: IActiveUsers = { any: { status: 'online', statusText: 'any' } };
|
||||||
mockedStore.dispatch(setActiveUsers(activeUsers));
|
mockedStore.dispatch(setActiveUsers(activeUsers));
|
||||||
const state = mockedStore.getState().activeUsers;
|
const state = mockedStore.getState().activeUsers;
|
||||||
expect(state).toEqual({ ...activeUsers });
|
expect(state).toEqual({ ...activeUsers });
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { ACTIVE_USERS } from '../actions/actionsTypes';
|
import { ACTIVE_USERS } from '../actions/actionsTypes';
|
||||||
import { TApplicationActions } from '../definitions';
|
import { TApplicationActions, TUserStatus } from '../definitions';
|
||||||
import { UserStatus } from '../definitions/UserStatus';
|
|
||||||
|
|
||||||
export interface IActiveUser {
|
export interface IActiveUser {
|
||||||
status: UserStatus;
|
status: TUserStatus;
|
||||||
statusText: string;
|
statusText: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { TUserStatus } from '../definitions';
|
||||||
import {
|
import {
|
||||||
clearUser,
|
clearUser,
|
||||||
loginFailure,
|
loginFailure,
|
||||||
|
@ -8,7 +9,6 @@ import {
|
||||||
setLoginServices,
|
setLoginServices,
|
||||||
setUser
|
setUser
|
||||||
} from '../actions/login';
|
} from '../actions/login';
|
||||||
import { UserStatus } from '../definitions/UserStatus';
|
|
||||||
import { initialState } from './login';
|
import { initialState } from './login';
|
||||||
import { mockedStore } from './mockedStore';
|
import { mockedStore } from './mockedStore';
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ describe('test selectedUsers reducer', () => {
|
||||||
isFromWebView: false,
|
isFromWebView: false,
|
||||||
showMessageInMainThread: false,
|
showMessageInMainThread: false,
|
||||||
enableMessageParserEarlyAdoption: false,
|
enableMessageParserEarlyAdoption: false,
|
||||||
status: UserStatus.ONLINE,
|
status: 'online' as TUserStatus,
|
||||||
statusText: 'online'
|
statusText: 'online'
|
||||||
};
|
};
|
||||||
mockedStore.dispatch(loginSuccess(user));
|
mockedStore.dispatch(loginSuccess(user));
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { UserStatus } from '../definitions/UserStatus';
|
|
||||||
import * as types from '../actions/actionsTypes';
|
import * as types from '../actions/actionsTypes';
|
||||||
import { TActionsLogin } from '../actions/login';
|
import { TActionsLogin } from '../actions/login';
|
||||||
import { IUser } from '../definitions';
|
import { IUser, TUserStatus } from '../definitions';
|
||||||
|
|
||||||
export interface IUserLogin {
|
export interface IUserLogin {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -9,7 +8,7 @@ export interface IUserLogin {
|
||||||
username: string;
|
username: string;
|
||||||
name: string;
|
name: string;
|
||||||
language?: string;
|
language?: string;
|
||||||
status: UserStatus;
|
status: TUserStatus;
|
||||||
statusText: string;
|
statusText: string;
|
||||||
roles: string[];
|
roles: string[];
|
||||||
avatarETag?: string;
|
avatarETag?: string;
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { CompositeNavigationProp } from '@react-navigation/core';
|
||||||
|
|
||||||
import * as List from '../containers/List';
|
import * as List from '../containers/List';
|
||||||
import StatusBar from '../containers/StatusBar';
|
import StatusBar from '../containers/StatusBar';
|
||||||
import { useTheme } from '../theme';
|
|
||||||
import * as HeaderButton from '../containers/HeaderButton';
|
import * as HeaderButton from '../containers/HeaderButton';
|
||||||
import SafeAreaView from '../containers/SafeAreaView';
|
import SafeAreaView from '../containers/SafeAreaView';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
|
@ -41,7 +40,6 @@ const setHeader = ({
|
||||||
|
|
||||||
const AddChannelTeamView = ({ navigation, route, isMasterDetail }: IAddChannelTeamView) => {
|
const AddChannelTeamView = ({ navigation, route, isMasterDetail }: IAddChannelTeamView) => {
|
||||||
const { teamId, teamChannels } = route.params;
|
const { teamId, teamChannels } = route.params;
|
||||||
const { theme } = useTheme();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHeader({ navigation, isMasterDetail });
|
setHeader({ navigation, isMasterDetail });
|
||||||
|
@ -67,7 +65,6 @@ const AddChannelTeamView = ({ navigation, route, isMasterDetail }: IAddChannelTe
|
||||||
testID='add-channel-team-view-create-channel'
|
testID='add-channel-team-view-create-channel'
|
||||||
left={() => <List.Icon name='team' />}
|
left={() => <List.Icon name='team' />}
|
||||||
right={() => <List.Icon name='chevron-right' />}
|
right={() => <List.Icon name='chevron-right' />}
|
||||||
theme={theme}
|
|
||||||
/>
|
/>
|
||||||
<List.Separator />
|
<List.Separator />
|
||||||
<List.Item
|
<List.Item
|
||||||
|
@ -76,7 +73,6 @@ const AddChannelTeamView = ({ navigation, route, isMasterDetail }: IAddChannelTe
|
||||||
testID='add-channel-team-view-add-existing'
|
testID='add-channel-team-view-add-existing'
|
||||||
left={() => <List.Icon name='channel-public' />}
|
left={() => <List.Icon name='channel-public' />}
|
||||||
right={() => <List.Icon name='chevron-right' />}
|
right={() => <List.Icon name='chevron-right' />}
|
||||||
theme={theme}
|
|
||||||
/>
|
/>
|
||||||
<List.Separator />
|
<List.Separator />
|
||||||
</List.Container>
|
</List.Container>
|
||||||
|
|
|
@ -92,7 +92,7 @@ class ForgotPasswordView extends React.Component<IForgotPasswordViewProps, IForg
|
||||||
const { theme } = this.props;
|
const { theme } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormContainer theme={theme} testID='forgot-password-view'>
|
<FormContainer testID='forgot-password-view'>
|
||||||
<FormContainerInner>
|
<FormContainerInner>
|
||||||
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold, { color: themes[theme].titleText }]}>
|
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold, { color: themes[theme].titleText }]}>
|
||||||
{I18n.t('Forgot_password')}
|
{I18n.t('Forgot_password')}
|
||||||
|
|
|
@ -229,7 +229,7 @@ class LoginView extends React.Component<ILoginViewProps, any> {
|
||||||
render() {
|
render() {
|
||||||
const { Accounts_ShowFormLogin, theme, navigation } = this.props;
|
const { Accounts_ShowFormLogin, theme, navigation } = this.props;
|
||||||
return (
|
return (
|
||||||
<FormContainer theme={theme} testID='login-view'>
|
<FormContainer testID='login-view'>
|
||||||
<FormContainerInner>
|
<FormContainerInner>
|
||||||
<LoginServices separator={Accounts_ShowFormLogin} navigation={navigation} theme={theme} />
|
<LoginServices separator={Accounts_ShowFormLogin} navigation={navigation} theme={theme} />
|
||||||
{this.renderUserForm()}
|
{this.renderUserForm()}
|
||||||
|
|
|
@ -321,7 +321,7 @@ class NewServerView extends React.Component<INewServerViewProps, INewServerViewS
|
||||||
const marginTop = previousServer ? 0 : 35;
|
const marginTop = previousServer ? 0 : 35;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormContainer theme={theme} testID='new-server-view' keyboardShouldPersistTaps='never'>
|
<FormContainer testID='new-server-view' keyboardShouldPersistTaps='never'>
|
||||||
<FormContainerInner>
|
<FormContainerInner>
|
||||||
<Image
|
<Image
|
||||||
style={[
|
style={[
|
||||||
|
|
|
@ -172,7 +172,9 @@ class RegisterView extends React.Component<IProps, any> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return Object.keys(this.parsedCustomFields).map((key, index, array) => {
|
return (
|
||||||
|
<>
|
||||||
|
{Object.keys(this.parsedCustomFields).map((key, index, array) => {
|
||||||
if (this.parsedCustomFields[key].type === 'select') {
|
if (this.parsedCustomFields[key].type === 'select') {
|
||||||
const options = this.parsedCustomFields[key].options.map((option: string) => ({ label: option, value: option }));
|
const options = this.parsedCustomFields[key].options.map((option: string) => ({ label: option, value: option }));
|
||||||
return (
|
return (
|
||||||
|
@ -186,7 +188,7 @@ class RegisterView extends React.Component<IProps, any> {
|
||||||
}}
|
}}
|
||||||
value={customFields[key]}>
|
value={customFields[key]}>
|
||||||
<TextInput
|
<TextInput
|
||||||
inputRef={e => {
|
inputRef={(e: any) => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this[key] = e;
|
this[key] = e;
|
||||||
}}
|
}}
|
||||||
|
@ -201,7 +203,7 @@ class RegisterView extends React.Component<IProps, any> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TextInput
|
<TextInput
|
||||||
inputRef={(e: any) => {
|
inputRef={e => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this[key] = e;
|
this[key] = e;
|
||||||
}}
|
}}
|
||||||
|
@ -225,7 +227,9 @@ class RegisterView extends React.Component<IProps, any> {
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -235,7 +239,7 @@ class RegisterView extends React.Component<IProps, any> {
|
||||||
const { saving } = this.state;
|
const { saving } = this.state;
|
||||||
const { theme, showLoginButton, navigation } = this.props;
|
const { theme, showLoginButton, navigation } = this.props;
|
||||||
return (
|
return (
|
||||||
<FormContainer theme={theme} testID='register-view'>
|
<FormContainer testID='register-view'>
|
||||||
<FormContainerInner>
|
<FormContainerInner>
|
||||||
<LoginServices navigation={navigation} theme={theme} separator />
|
<LoginServices navigation={navigation} theme={theme} separator />
|
||||||
<Text style={[styles.title, sharedStyles.textBold, { color: themes[theme].titleText }]}>{I18n.t('Sign_Up')}</Text>
|
<Text style={[styles.title, sharedStyles.textBold, { color: themes[theme].titleText }]}>{I18n.t('Sign_Up')}</Text>
|
||||||
|
|
|
@ -223,7 +223,7 @@ class ScreenLockConfigView extends React.Component<IScreenLockConfigViewProps, I
|
||||||
return (
|
return (
|
||||||
<List.Section>
|
<List.Section>
|
||||||
<List.Separator />
|
<List.Separator />
|
||||||
{items.map(item => this.renderItem({ item }))}
|
<>{items.map(item => this.renderItem({ item }))}</>
|
||||||
</List.Section>
|
</List.Section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -62,7 +62,7 @@ const SendEmailConfirmationView = ({ navigation, route }: ISendEmailConfirmation
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormContainer theme={theme} testID='send-email-confirmation-view'>
|
<FormContainer testID='send-email-confirmation-view'>
|
||||||
<FormContainerInner>
|
<FormContainerInner>
|
||||||
<TextInput
|
<TextInput
|
||||||
autoFocus
|
autoFocus
|
||||||
|
|
|
@ -19,6 +19,7 @@ import Navigation from '../../lib/Navigation';
|
||||||
import SidebarItem from './SidebarItem';
|
import SidebarItem from './SidebarItem';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import { DrawerParamList } from '../../stacks/types';
|
import { DrawerParamList } from '../../stacks/types';
|
||||||
|
import { TUserStatus } from '../../definitions';
|
||||||
|
|
||||||
interface ISeparatorProps {
|
interface ISeparatorProps {
|
||||||
theme: string;
|
theme: string;
|
||||||
|
@ -40,7 +41,7 @@ interface ISidebarProps {
|
||||||
Site_Name: string;
|
Site_Name: string;
|
||||||
user: {
|
user: {
|
||||||
statusText: string;
|
statusText: string;
|
||||||
status: string;
|
status: TUserStatus;
|
||||||
username: string;
|
username: string;
|
||||||
name: string;
|
name: string;
|
||||||
roles: string[];
|
roles: string[];
|
||||||
|
|
|
@ -2,7 +2,6 @@ import React from 'react';
|
||||||
import { FlatList, StyleSheet } from 'react-native';
|
import { FlatList, StyleSheet } from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { UserStatus } from '../definitions/UserStatus';
|
|
||||||
import { setUser } from '../actions/login';
|
import { setUser } from '../actions/login';
|
||||||
import * as HeaderButton from '../containers/HeaderButton';
|
import * as HeaderButton from '../containers/HeaderButton';
|
||||||
import * as List from '../containers/List';
|
import * as List from '../containers/List';
|
||||||
|
@ -11,7 +10,7 @@ import SafeAreaView from '../containers/SafeAreaView';
|
||||||
import Status from '../containers/Status/Status';
|
import Status from '../containers/Status/Status';
|
||||||
import TextInput from '../containers/TextInput';
|
import TextInput from '../containers/TextInput';
|
||||||
import { LISTENER } from '../containers/Toast';
|
import { LISTENER } from '../containers/Toast';
|
||||||
import { IApplicationState, IBaseScreen, IUser } from '../definitions';
|
import { IApplicationState, IBaseScreen, IUser, TUserStatus } from '../definitions';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
import RocketChat from '../lib/rocketchat';
|
import RocketChat from '../lib/rocketchat';
|
||||||
import { getUserSelector } from '../selectors/login';
|
import { getUserSelector } from '../selectors/login';
|
||||||
|
@ -20,7 +19,12 @@ import EventEmitter from '../utils/events';
|
||||||
import { showErrorAlert } from '../utils/info';
|
import { showErrorAlert } from '../utils/info';
|
||||||
import log, { events, logEvent } from '../utils/log';
|
import log, { events, logEvent } from '../utils/log';
|
||||||
|
|
||||||
const STATUS = [
|
interface IStatus {
|
||||||
|
id: TUserStatus;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const STATUS: IStatus[] = [
|
||||||
{
|
{
|
||||||
id: 'online',
|
id: 'online',
|
||||||
name: 'Online'
|
name: 'Online'
|
||||||
|
@ -135,7 +139,7 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
||||||
value={statusText}
|
value={statusText}
|
||||||
containerStyle={styles.inputContainer}
|
containerStyle={styles.inputContainer}
|
||||||
onChangeText={text => this.setState({ statusText: text })}
|
onChangeText={text => this.setState({ statusText: text })}
|
||||||
left={<Status testID={`status-view-current-${user.status}`} style={styles.inputLeft} status={user.status!} size={24} />}
|
left={<Status testID={`status-view-current-${user.status}`} style={styles.inputLeft} status={user.status} size={24} />}
|
||||||
inputStyle={styles.inputStyle}
|
inputStyle={styles.inputStyle}
|
||||||
placeholder={I18n.t('What_are_you_doing_right_now')}
|
placeholder={I18n.t('What_are_you_doing_right_now')}
|
||||||
testID='status-view-input'
|
testID='status-view-input'
|
||||||
|
@ -145,7 +149,7 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
renderItem = ({ item }: { item: { id: string; name: string } }) => {
|
renderItem = ({ item }: { item: IStatus }) => {
|
||||||
const { statusText } = this.state;
|
const { statusText } = this.state;
|
||||||
const { user, dispatch } = this.props;
|
const { user, dispatch } = this.props;
|
||||||
const { id, name } = item;
|
const { id, name } = item;
|
||||||
|
@ -159,7 +163,7 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
||||||
try {
|
try {
|
||||||
const result = await RocketChat.setUserStatus(item.id, statusText);
|
const result = await RocketChat.setUserStatus(item.id, statusText);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
dispatch(setUser({ status: item.id as UserStatus }));
|
dispatch(setUser({ status: item.id }));
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
showErrorAlert(I18n.t(e.data.errorType));
|
showErrorAlert(I18n.t(e.data.errorType));
|
||||||
|
|
|
@ -131,11 +131,11 @@ class ThemeView extends React.Component<IThemeViewProps> {
|
||||||
<List.Container>
|
<List.Container>
|
||||||
<List.Section title='Theme'>
|
<List.Section title='Theme'>
|
||||||
<List.Separator />
|
<List.Separator />
|
||||||
{themeGroup.map(item => this.renderItem({ item }))}
|
<>{themeGroup.map(item => this.renderItem({ item }))}</>
|
||||||
</List.Section>
|
</List.Section>
|
||||||
<List.Section title='Dark_level'>
|
<List.Section title='Dark_level'>
|
||||||
<List.Separator />
|
<List.Separator />
|
||||||
{darkGroup.map(item => this.renderItem({ item }))}
|
<>{darkGroup.map(item => this.renderItem({ item }))}</>
|
||||||
</List.Section>
|
</List.Section>
|
||||||
</List.Container>
|
</List.Container>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
|
|
|
@ -74,7 +74,7 @@ class WorkspaceView extends React.Component<IWorkSpaceProp, any> {
|
||||||
const { theme, Site_Name, Site_Url, Assets_favicon_512, server, showLoginButton } = this.props;
|
const { theme, Site_Name, Site_Url, Assets_favicon_512, server, showLoginButton } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormContainer theme={theme} testID='workspace-view'>
|
<FormContainer testID='workspace-view'>
|
||||||
<FormContainerInner>
|
<FormContainerInner>
|
||||||
<View style={styles.alignItemsCenter}>
|
<View style={styles.alignItemsCenter}>
|
||||||
<ServerAvatar theme={theme} url={server} image={Assets_favicon_512?.url ?? Assets_favicon_512?.defaultUrl} />
|
<ServerAvatar theme={theme} url={server} image={Assets_favicon_512?.url ?? Assets_favicon_512?.defaultUrl} />
|
||||||
|
|
File diff suppressed because one or more lines are too long
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