Unify buttons (#8865)
* Unity buttons * Fix texts and use defineMessages * Update snapshots * Fix disabled style
This commit is contained in:
parent
705ed603bc
commit
2ad6fec90f
31 changed files with 661 additions and 821 deletions
|
|
@ -2,14 +2,13 @@
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {BottomSheetScrollView} from '@gorhom/bottom-sheet';
|
import {BottomSheetScrollView} from '@gorhom/bottom-sheet';
|
||||||
import {Button} from '@rneui/base';
|
|
||||||
import React, {useCallback, useMemo} from 'react';
|
import React, {useCallback, useMemo} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {ScrollView, Text, View} from 'react-native';
|
import {ScrollView, Text, View} from 'react-native';
|
||||||
import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
||||||
|
|
||||||
import {dismissAnnouncement} from '@actions/local/systems';
|
import {dismissAnnouncement} from '@actions/local/systems';
|
||||||
import FormattedText from '@components/formatted_text';
|
import Button from '@components/button';
|
||||||
import Markdown from '@components/markdown';
|
import Markdown from '@components/markdown';
|
||||||
import {Screens} from '@constants';
|
import {Screens} from '@constants';
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
|
|
@ -17,7 +16,6 @@ import {useTheme} from '@context/theme';
|
||||||
import {useBottomSheetListsFix} from '@hooks/bottom_sheet_lists_fix';
|
import {useBottomSheetListsFix} from '@hooks/bottom_sheet_lists_fix';
|
||||||
import {useIsTablet} from '@hooks/device';
|
import {useIsTablet} from '@hooks/device';
|
||||||
import {dismissBottomSheet} from '@screens/navigation';
|
import {dismissBottomSheet} from '@screens/navigation';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {getMarkdownTextStyles, getMarkdownBlockStyles} from '@utils/markdown';
|
import {getMarkdownTextStyles, getMarkdownBlockStyles} from '@utils/markdown';
|
||||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
@ -46,6 +44,9 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||||
color: theme.centerChannelColor,
|
color: theme.centerChannelColor,
|
||||||
...typography('Heading', 600, 'SemiBold'),
|
...typography('Heading', 600, 'SemiBold'),
|
||||||
},
|
},
|
||||||
|
dismissButtonContainer: {
|
||||||
|
marginTop: 10,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -69,20 +70,7 @@ const ExpandedAnnouncementBanner = ({
|
||||||
const dismissBanner = useCallback(() => {
|
const dismissBanner = useCallback(() => {
|
||||||
dismissAnnouncement(serverUrl, bannerText);
|
dismissAnnouncement(serverUrl, bannerText);
|
||||||
close();
|
close();
|
||||||
}, [bannerText]);
|
}, [bannerText, serverUrl]);
|
||||||
|
|
||||||
const buttonStyles = useMemo(() => {
|
|
||||||
return {
|
|
||||||
okay: {
|
|
||||||
button: buttonBackgroundStyle(theme, 'lg', 'primary'),
|
|
||||||
text: buttonTextStyle(theme, 'lg', 'primary'),
|
|
||||||
},
|
|
||||||
dismiss: {
|
|
||||||
button: [{marginTop: 10}, buttonBackgroundStyle(theme, 'lg', 'link')],
|
|
||||||
text: buttonTextStyle(theme, 'lg', 'link'),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}, [theme]);
|
|
||||||
|
|
||||||
const containerStyle = useMemo(() => {
|
const containerStyle = useMemo(() => {
|
||||||
return [style.container, {marginBottom: insets.bottom + 10}];
|
return [style.container, {marginBottom: insets.bottom + 10}];
|
||||||
|
|
@ -118,26 +106,21 @@ const ExpandedAnnouncementBanner = ({
|
||||||
/>
|
/>
|
||||||
</Scroll>
|
</Scroll>
|
||||||
<Button
|
<Button
|
||||||
buttonStyle={buttonStyles.okay.button}
|
text={intl.formatMessage({id: 'announcment_banner.okay', defaultMessage: 'Okay'})}
|
||||||
onPress={close}
|
onPress={close}
|
||||||
>
|
size='lg'
|
||||||
<FormattedText
|
theme={theme}
|
||||||
id='announcment_banner.okay'
|
/>
|
||||||
defaultMessage={'Okay'}
|
|
||||||
style={buttonStyles.okay.text}
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
{allowDismissal && (
|
{allowDismissal && (
|
||||||
<Button
|
<View style={style.dismissButtonContainer}>
|
||||||
buttonStyle={buttonStyles.dismiss.button}
|
<Button
|
||||||
onPress={dismissBanner}
|
text={intl.formatMessage({id: 'announcment_banner.dismiss', defaultMessage: 'Dismiss announcement'})}
|
||||||
>
|
onPress={dismissBanner}
|
||||||
<FormattedText
|
size='lg'
|
||||||
id='announcment_banner.dismiss'
|
theme={theme}
|
||||||
defaultMessage={'Dismiss announcement'}
|
emphasis='link'
|
||||||
style={buttonStyles.dismiss.text}
|
|
||||||
/>
|
/>
|
||||||
</Button>
|
</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import React, {useMemo, type ReactNode} from 'react';
|
||||||
import {type StyleProp, StyleSheet, Text, type TextStyle, View, type ViewStyle, type Insets} from 'react-native';
|
import {type StyleProp, StyleSheet, Text, type TextStyle, View, type ViewStyle, type Insets} from 'react-native';
|
||||||
|
|
||||||
import CompassIcon from '@components/compass_icon';
|
import CompassIcon from '@components/compass_icon';
|
||||||
|
import Loading from '@components/loading';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||||
import {changeOpacity} from '@utils/theme';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
|
|
@ -16,16 +16,17 @@ type Props = {
|
||||||
textStyle?: StyleProp<TextStyle>;
|
textStyle?: StyleProp<TextStyle>;
|
||||||
size?: ButtonSize;
|
size?: ButtonSize;
|
||||||
emphasis?: ButtonEmphasis;
|
emphasis?: ButtonEmphasis;
|
||||||
buttonType?: ButtonType;
|
|
||||||
buttonState?: ButtonState;
|
|
||||||
testID?: string;
|
testID?: string;
|
||||||
onPress: () => void;
|
onPress?: () => void;
|
||||||
text: string;
|
text: string;
|
||||||
iconComponent?: ReactNode;
|
iconComponent?: ReactNode;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
hitSlop?: Insets;
|
hitSlop?: Insets;
|
||||||
isIconOnTheRight?: boolean;
|
isIconOnTheRight?: boolean;
|
||||||
iconName?: string;
|
iconName?: string;
|
||||||
|
showLoader?: boolean;
|
||||||
|
isInverted?: boolean;
|
||||||
|
isDestructive?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
|
@ -50,8 +51,6 @@ const Button = ({
|
||||||
textStyle,
|
textStyle,
|
||||||
size = 'm',
|
size = 'm',
|
||||||
emphasis,
|
emphasis,
|
||||||
buttonType,
|
|
||||||
buttonState,
|
|
||||||
onPress,
|
onPress,
|
||||||
text,
|
text,
|
||||||
testID,
|
testID,
|
||||||
|
|
@ -60,24 +59,44 @@ const Button = ({
|
||||||
iconComponent,
|
iconComponent,
|
||||||
disabled,
|
disabled,
|
||||||
hitSlop,
|
hitSlop,
|
||||||
|
showLoader = false,
|
||||||
|
isInverted = false,
|
||||||
|
isDestructive = false,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const bgStyle = useMemo(() => [
|
let buttonType: ButtonType = 'default';
|
||||||
buttonBackgroundStyle(theme, size, emphasis, buttonType, buttonState),
|
if (isDestructive) {
|
||||||
backgroundStyle,
|
buttonType = 'destructive';
|
||||||
], [theme, backgroundStyle, size, emphasis, buttonType, buttonState]);
|
} else if (isInverted) {
|
||||||
|
buttonType = 'inverted';
|
||||||
|
}
|
||||||
|
|
||||||
const txtStyle = useMemo(() => [
|
const bgStyle = useMemo(() => [
|
||||||
|
buttonBackgroundStyle(theme, size, emphasis, buttonType),
|
||||||
|
backgroundStyle,
|
||||||
|
], [theme, backgroundStyle, size, emphasis, buttonType]);
|
||||||
|
|
||||||
|
const bgDisabledStyle = useMemo(() => [
|
||||||
|
buttonBackgroundStyle(theme, size, emphasis, 'disabled'),
|
||||||
|
backgroundStyle,
|
||||||
|
], [theme, backgroundStyle, size, emphasis]);
|
||||||
|
|
||||||
|
const txtStyle = useMemo(() => StyleSheet.flatten([
|
||||||
buttonTextStyle(theme, size, emphasis, buttonType),
|
buttonTextStyle(theme, size, emphasis, buttonType),
|
||||||
textStyle,
|
textStyle,
|
||||||
], [theme, textStyle, size, emphasis, buttonType]);
|
]), [theme, textStyle, size, emphasis, buttonType]);
|
||||||
|
|
||||||
let buttonStyle = StyleSheet.flatten(bgStyle);
|
const txtDisabledStyle = useMemo(() => StyleSheet.flatten([
|
||||||
if (disabled) {
|
buttonTextStyle(theme, size, emphasis, 'disabled'),
|
||||||
buttonStyle = {
|
textStyle,
|
||||||
...buttonStyle,
|
]), [theme, textStyle, size, emphasis]);
|
||||||
backgroundColor: changeOpacity(buttonStyle.backgroundColor! as string, 0.4),
|
|
||||||
};
|
const txtStyleToUse = disabled ? txtDisabledStyle : txtStyle;
|
||||||
}
|
|
||||||
|
const loadingComponent = (
|
||||||
|
<Loading
|
||||||
|
color={txtStyleToUse.color}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
let icon: ReactNode;
|
let icon: ReactNode;
|
||||||
|
|
||||||
|
|
@ -90,7 +109,7 @@ const Button = ({
|
||||||
<CompassIcon
|
<CompassIcon
|
||||||
name={iconName!}
|
name={iconName!}
|
||||||
size={iconSizePerSize[size]}
|
size={iconSizePerSize[size]}
|
||||||
color={StyleSheet.flatten(txtStyle).color}
|
color={txtStyleToUse.color}
|
||||||
testID={`${testID}-icon`}
|
testID={`${testID}-icon`}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
@ -99,8 +118,9 @@ const Button = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ElementButton
|
<ElementButton
|
||||||
buttonStyle={buttonStyle}
|
buttonStyle={bgStyle}
|
||||||
containerStyle={buttonContainerStyle}
|
containerStyle={buttonContainerStyle}
|
||||||
|
disabledStyle={bgDisabledStyle}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
testID={testID}
|
testID={testID}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
|
@ -110,9 +130,10 @@ const Button = ({
|
||||||
style={styles.container}
|
style={styles.container}
|
||||||
testID={`${testID}-text-container`}
|
testID={`${testID}-text-container`}
|
||||||
>
|
>
|
||||||
|
{showLoader && loadingComponent}
|
||||||
{!isIconOnTheRight && icon}
|
{!isIconOnTheRight && icon}
|
||||||
<Text
|
<Text
|
||||||
style={[txtStyle]}
|
style={txtStyleToUse}
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
>
|
>
|
||||||
{text}
|
{text}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {ActivityIndicator, type StyleProp, View, type ViewStyle, Text, type TextStyle} from 'react-native';
|
import {ActivityIndicator, type StyleProp, View, type ViewStyle, Text, type TextStyle, type ColorValue} from 'react-native';
|
||||||
|
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
|
|
||||||
type LoadingProps = {
|
type LoadingProps = {
|
||||||
containerStyle?: StyleProp<ViewStyle>;
|
containerStyle?: StyleProp<ViewStyle>;
|
||||||
size?: number | 'small' | 'large';
|
size?: number | 'small' | 'large';
|
||||||
color?: string;
|
color?: ColorValue;
|
||||||
themeColor?: keyof Theme;
|
themeColor?: keyof Theme;
|
||||||
footerText?: string;
|
footerText?: string;
|
||||||
footerTextStyles?: TextStyle;
|
footerTextStyles?: TextStyle;
|
||||||
|
|
|
||||||
|
|
@ -73,61 +73,106 @@ exports[`Loading Error should match snapshot 1`] = `
|
||||||
Error description
|
Error description
|
||||||
</Text>
|
</Text>
|
||||||
<View
|
<View
|
||||||
accessibilityState={
|
|
||||||
{
|
|
||||||
"busy": undefined,
|
|
||||||
"checked": undefined,
|
|
||||||
"disabled": undefined,
|
|
||||||
"expanded": undefined,
|
|
||||||
"selected": undefined,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
accessibilityValue={
|
|
||||||
{
|
|
||||||
"max": undefined,
|
|
||||||
"min": undefined,
|
|
||||||
"now": undefined,
|
|
||||||
"text": undefined,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
accessible={true}
|
|
||||||
collapsable={false}
|
|
||||||
focusable={true}
|
|
||||||
onClick={[Function]}
|
|
||||||
onResponderGrant={[Function]}
|
|
||||||
onResponderMove={[Function]}
|
|
||||||
onResponderRelease={[Function]}
|
|
||||||
onResponderTerminate={[Function]}
|
|
||||||
onResponderTerminationRequest={[Function]}
|
|
||||||
onStartShouldSetResponder={[Function]}
|
|
||||||
style={
|
style={
|
||||||
{
|
{
|
||||||
"backgroundColor": "#ffffff",
|
|
||||||
"borderRadius": 4,
|
|
||||||
"marginTop": 24,
|
"marginTop": 24,
|
||||||
"opacity": 1,
|
|
||||||
"paddingHorizontal": 24,
|
|
||||||
"paddingVertical": 12,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Text
|
<View
|
||||||
style={
|
style={
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"fontFamily": "OpenSans-SemiBold",
|
"overflow": "hidden",
|
||||||
"fontSize": 16,
|
|
||||||
"fontWeight": "600",
|
|
||||||
"lineHeight": 24,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"color": "#1c58d9",
|
"borderRadius": 2,
|
||||||
},
|
},
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
testID="RNE_BUTTON_WRAPPER"
|
||||||
>
|
>
|
||||||
Retry
|
<View
|
||||||
</Text>
|
accessibilityRole="button"
|
||||||
|
accessibilityState={
|
||||||
|
{
|
||||||
|
"busy": false,
|
||||||
|
"checked": undefined,
|
||||||
|
"disabled": false,
|
||||||
|
"expanded": undefined,
|
||||||
|
"selected": undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accessibilityValue={
|
||||||
|
{
|
||||||
|
"max": undefined,
|
||||||
|
"min": undefined,
|
||||||
|
"now": undefined,
|
||||||
|
"text": undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accessible={true}
|
||||||
|
collapsable={false}
|
||||||
|
focusable={true}
|
||||||
|
onClick={[Function]}
|
||||||
|
onResponderGrant={[Function]}
|
||||||
|
onResponderMove={[Function]}
|
||||||
|
onResponderRelease={[Function]}
|
||||||
|
onResponderTerminate={[Function]}
|
||||||
|
onResponderTerminationRequest={[Function]}
|
||||||
|
onStartShouldSetResponder={[Function]}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"opacity": 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"alignItems": "center",
|
||||||
|
"backgroundColor": "#1c58d9",
|
||||||
|
"borderColor": "#2089dc",
|
||||||
|
"borderRadius": 4,
|
||||||
|
"borderWidth": 0,
|
||||||
|
"flexDirection": "row",
|
||||||
|
"justifyContent": "center",
|
||||||
|
"padding": 8,
|
||||||
|
"paddingHorizontal": 24,
|
||||||
|
"paddingVertical": 12,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"alignItems": "center",
|
||||||
|
"flexDirection": "row",
|
||||||
|
"gap": 7,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testID="undefined-text-container"
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
numberOfLines={1}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"color": "#ffffff",
|
||||||
|
"fontFamily": "OpenSans-SemiBold",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontWeight": "600",
|
||||||
|
"lineHeight": 24,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Retry
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React, {useMemo} from 'react';
|
import React from 'react';
|
||||||
|
import {useIntl} from 'react-intl';
|
||||||
import {Text, View} from 'react-native';
|
import {Text, View} from 'react-native';
|
||||||
|
|
||||||
|
import Button from '@components/button';
|
||||||
import CompassIcon from '@components/compass_icon';
|
import CompassIcon from '@components/compass_icon';
|
||||||
import Loading from '@components/loading';
|
import Loading from '@components/loading';
|
||||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
||||||
|
|
@ -49,14 +49,15 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
marginTop: 4,
|
marginTop: 4,
|
||||||
},
|
},
|
||||||
|
buttonContainer: {
|
||||||
|
marginTop: 24,
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const LoadingError = ({loading, message, onRetry, title}: Props) => {
|
const LoadingError = ({loading, message, onRetry, title}: Props) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const intl = useIntl();
|
||||||
const styles = getStyleSheet(theme);
|
const styles = getStyleSheet(theme);
|
||||||
const buttonStyle = useMemo(() => {
|
|
||||||
return [{marginTop: 24}, buttonBackgroundStyle(theme, 'lg', 'primary', 'inverted')];
|
|
||||||
}, [theme]);
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -81,13 +82,14 @@ const LoadingError = ({loading, message, onRetry, title}: Props) => {
|
||||||
<Text style={[typography('Body', 200), styles.body]}>
|
<Text style={[typography('Body', 200), styles.body]}>
|
||||||
{message}
|
{message}
|
||||||
</Text>
|
</Text>
|
||||||
<TouchableWithFeedback
|
<View style={styles.buttonContainer}>
|
||||||
style={buttonStyle}
|
<Button
|
||||||
onPress={onRetry}
|
text={intl.formatMessage({id: 'loading_error.retry', defaultMessage: 'Retry'})}
|
||||||
type={'opacity'}
|
onPress={onRetry}
|
||||||
>
|
size='lg'
|
||||||
<Text style={buttonTextStyle(theme, 'lg', 'primary', 'inverted')}>{'Retry'}</Text>
|
theme={theme}
|
||||||
</TouchableWithFeedback>
|
/>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -186,22 +186,13 @@ exports[`Section notice match snapshot 1`] = `
|
||||||
<Text
|
<Text
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
style={
|
style={
|
||||||
[
|
{
|
||||||
[
|
"color": "#ffffff",
|
||||||
[
|
"fontFamily": "OpenSans-SemiBold",
|
||||||
{
|
"fontSize": 14,
|
||||||
"fontFamily": "OpenSans-SemiBold",
|
"fontWeight": "600",
|
||||||
"fontSize": 14,
|
"lineHeight": 20,
|
||||||
"fontWeight": "600",
|
}
|
||||||
"lineHeight": 20,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"color": "#ffffff",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
undefined,
|
|
||||||
],
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
primary button
|
primary button
|
||||||
|
|
@ -297,22 +288,13 @@ exports[`Section notice match snapshot 1`] = `
|
||||||
<Text
|
<Text
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
style={
|
style={
|
||||||
[
|
{
|
||||||
[
|
"color": "#1c58d9",
|
||||||
[
|
"fontFamily": "OpenSans-SemiBold",
|
||||||
{
|
"fontSize": 14,
|
||||||
"fontFamily": "OpenSans-SemiBold",
|
"fontWeight": "600",
|
||||||
"fontSize": 14,
|
"lineHeight": 20,
|
||||||
"fontWeight": "600",
|
}
|
||||||
"lineHeight": 20,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"color": "#1c58d9",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
undefined,
|
|
||||||
],
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
secondary button
|
secondary button
|
||||||
|
|
@ -408,22 +390,13 @@ exports[`Section notice match snapshot 1`] = `
|
||||||
<Text
|
<Text
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
style={
|
style={
|
||||||
[
|
{
|
||||||
[
|
"color": "#1c58d9",
|
||||||
[
|
"fontFamily": "OpenSans-SemiBold",
|
||||||
{
|
"fontSize": 14,
|
||||||
"fontFamily": "OpenSans-SemiBold",
|
"fontWeight": "600",
|
||||||
"fontSize": 14,
|
"lineHeight": 20,
|
||||||
"fontWeight": "600",
|
}
|
||||||
"lineHeight": 20,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"color": "#1c58d9",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
undefined,
|
|
||||||
],
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
link button
|
link button
|
||||||
|
|
|
||||||
|
|
@ -270,10 +270,10 @@ export default function SelectedUsers({
|
||||||
iconName={buttonIcon}
|
iconName={buttonIcon}
|
||||||
text={buttonText}
|
text={buttonText}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
buttonType={isDisabled ? 'disabled' : 'default'}
|
|
||||||
emphasis={'primary'}
|
emphasis={'primary'}
|
||||||
size={'lg'}
|
size={'lg'}
|
||||||
testID={`${testID}.start.button`}
|
testID={`${testID}.start.button`}
|
||||||
|
disabled={isDisabled}
|
||||||
/>
|
/>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {Button} from '@rneui/base';
|
|
||||||
import React, {useCallback, useEffect, useMemo, useReducer, useRef, useState} from 'react';
|
import React, {useCallback, useEffect, useMemo, useReducer, useRef, useState} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {Keyboard, ScrollView, Text, View} from 'react-native';
|
import {Keyboard, ScrollView, View} from 'react-native';
|
||||||
import {SafeAreaView} from 'react-native-safe-area-context';
|
import {SafeAreaView} from 'react-native-safe-area-context';
|
||||||
|
|
||||||
import {handleGotoLocation} from '@actions/remote/command';
|
import {handleGotoLocation} from '@actions/remote/command';
|
||||||
|
import Button from '@components/button';
|
||||||
import CompassIcon from '@components/compass_icon';
|
import CompassIcon from '@components/compass_icon';
|
||||||
import Markdown from '@components/markdown';
|
import Markdown from '@components/markdown';
|
||||||
import {Screens} from '@constants';
|
import {Screens} from '@constants';
|
||||||
|
|
@ -18,7 +18,6 @@ import useDidUpdate from '@hooks/did_update';
|
||||||
import useNavButtonPressed from '@hooks/navigation_button_pressed';
|
import useNavButtonPressed from '@hooks/navigation_button_pressed';
|
||||||
import SecurityManager from '@managers/security_manager';
|
import SecurityManager from '@managers/security_manager';
|
||||||
import {filterEmptyOptions} from '@utils/apps';
|
import {filterEmptyOptions} from '@utils/apps';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {checkDialogElementForError, checkIfErrorsMatchElements} from '@utils/integrations';
|
import {checkDialogElementForError, checkIfErrorsMatchElements} from '@utils/integrations';
|
||||||
import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown';
|
import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown';
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
|
|
@ -383,9 +382,6 @@ function AppsFormComponent({
|
||||||
useNavButtonPressed(CLOSE_BUTTON_ID, componentId, close, [close]);
|
useNavButtonPressed(CLOSE_BUTTON_ID, componentId, close, [close]);
|
||||||
useNavButtonPressed(SUBMIT_BUTTON_ID, componentId, handleSubmit, [handleSubmit]);
|
useNavButtonPressed(SUBMIT_BUTTON_ID, componentId, handleSubmit, [handleSubmit]);
|
||||||
|
|
||||||
const submitButtonStyle = useMemo(() => buttonBackgroundStyle(theme, 'lg', 'primary', 'default'), [theme]);
|
|
||||||
const submitButtonTextStyle = useMemo(() => buttonTextStyle(theme, 'lg', 'primary', 'default'), [theme]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaView
|
<SafeAreaView
|
||||||
testID='interactive_dialog.screen'
|
testID='interactive_dialog.screen'
|
||||||
|
|
@ -444,10 +440,10 @@ function AppsFormComponent({
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
onPress={() => handleSubmit(o.value)}
|
onPress={() => handleSubmit(o.value)}
|
||||||
buttonStyle={submitButtonStyle}
|
theme={theme}
|
||||||
>
|
size='lg'
|
||||||
<Text style={submitButtonTextStyle}>{o.label}</Text>
|
text={o.label || ''}
|
||||||
</Button>
|
/>
|
||||||
</View>
|
</View>
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,16 @@
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {type GestureResponderEvent, Platform, Text, useWindowDimensions, View} from 'react-native';
|
import {Platform, useWindowDimensions, View} from 'react-native';
|
||||||
|
|
||||||
import CompassIcon from '@components/compass_icon';
|
import Button from '@components/button';
|
||||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {useIsTablet} from '@hooks/device';
|
import {useIsTablet} from '@hooks/device';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onPress?: (e: GestureResponderEvent) => void;
|
onPress?: () => void;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
testID?: string;
|
testID?: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
|
|
@ -21,22 +19,12 @@ type Props = {
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||||
return {
|
return {
|
||||||
button: {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
},
|
|
||||||
buttonContainer: {
|
buttonContainer: {
|
||||||
paddingHorizontal: 20,
|
paddingHorizontal: 20,
|
||||||
},
|
},
|
||||||
container: {
|
container: {
|
||||||
backgroundColor: theme.centerChannelBg,
|
backgroundColor: theme.centerChannelBg,
|
||||||
},
|
},
|
||||||
iconContainer: {
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
top: -1,
|
|
||||||
marginRight: 4,
|
|
||||||
},
|
|
||||||
separator: {
|
separator: {
|
||||||
height: 1,
|
height: 1,
|
||||||
right: 20,
|
right: 20,
|
||||||
|
|
@ -56,40 +44,22 @@ function BottomSheetButton({disabled = false, onPress, icon, testID, text}: Prop
|
||||||
const styles = getStyleSheet(theme);
|
const styles = getStyleSheet(theme);
|
||||||
|
|
||||||
const separatorWidth = Math.max(dimensions.width, 450);
|
const separatorWidth = Math.max(dimensions.width, 450);
|
||||||
const buttonType = disabled ? 'disabled' : 'default';
|
|
||||||
const styleButtonText = buttonTextStyle(theme, 'lg', 'primary', buttonType);
|
|
||||||
const styleButtonBackground = buttonBackgroundStyle(theme, 'lg', 'primary', buttonType);
|
|
||||||
|
|
||||||
const iconColor = disabled ? changeOpacity(theme.centerChannelColor, 0.32) : theme.buttonColor;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={[styles.separator, {width: separatorWidth}]}/>
|
<View style={[styles.separator, {width: separatorWidth}]}/>
|
||||||
<View style={styles.buttonContainer}>
|
<View style={styles.buttonContainer}>
|
||||||
<TouchableWithFeedback
|
<Button
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
type='opacity'
|
text={text || ''}
|
||||||
style={[styles.button, styleButtonBackground]}
|
iconName={icon}
|
||||||
testID={testID}
|
testID={testID}
|
||||||
>
|
theme={theme}
|
||||||
{icon && (
|
size='lg'
|
||||||
<View style={styles.iconContainer}>
|
disabled={disabled}
|
||||||
<CompassIcon
|
/>
|
||||||
size={24}
|
|
||||||
name={icon}
|
|
||||||
color={iconColor}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
{text && (
|
|
||||||
<Text
|
|
||||||
style={styleButtonText}
|
|
||||||
>{text}</Text>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</TouchableWithFeedback>
|
|
||||||
<View style={{paddingBottom: Platform.select({ios: (isTablet ? 20 : 0), android: 20})}}/>
|
|
||||||
</View>
|
</View>
|
||||||
|
<View style={{paddingBottom: Platform.select({ios: (isTablet ? 20 : 0), android: 20})}}/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {type GestureResponderEvent, Text, useWindowDimensions, View} from 'react-native';
|
import {Text, useWindowDimensions, View} from 'react-native';
|
||||||
|
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {useIsTablet} from '@hooks/device';
|
import {useIsTablet} from '@hooks/device';
|
||||||
|
|
@ -15,7 +15,7 @@ type Props = {
|
||||||
buttonText?: string;
|
buttonText?: string;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
disableButton?: boolean;
|
disableButton?: boolean;
|
||||||
onPress?: (e: GestureResponderEvent) => void;
|
onPress?: () => void;
|
||||||
showButton: boolean;
|
showButton: boolean;
|
||||||
showTitle: boolean;
|
showTitle: boolean;
|
||||||
testID?: string;
|
testID?: string;
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,6 @@ const ChannelBookmarkAddOrEdit = ({
|
||||||
{canDeleteBookmarks &&
|
{canDeleteBookmarks &&
|
||||||
<View style={styles.deleteContainer}>
|
<View style={styles.deleteContainer}>
|
||||||
<Button
|
<Button
|
||||||
buttonType='destructive'
|
|
||||||
size='m'
|
size='m'
|
||||||
text='Delete bookmark'
|
text='Delete bookmark'
|
||||||
iconName='trash-can-outline'
|
iconName='trash-can-outline'
|
||||||
|
|
@ -311,6 +310,7 @@ const ChannelBookmarkAddOrEdit = ({
|
||||||
onPress={onDelete}
|
onPress={onDelete}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
|
isDestructive={true}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,6 @@ const MutedBanner = ({channelId}: Props) => {
|
||||||
/>
|
/>
|
||||||
<View style={styles.button}>
|
<View style={styles.button}>
|
||||||
<Button
|
<Button
|
||||||
buttonType='default'
|
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
text={formatMessage({
|
text={formatMessage({
|
||||||
id: 'channel_notification_preferences.unmute_content',
|
id: 'channel_notification_preferences.unmute_content',
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,13 @@ import {Text, View} from 'react-native';
|
||||||
|
|
||||||
import {convertGroupMessageToPrivateChannel, switchToChannelById} from '@actions/remote/channel';
|
import {convertGroupMessageToPrivateChannel, switchToChannelById} from '@actions/remote/channel';
|
||||||
import Button from '@components/button';
|
import Button from '@components/button';
|
||||||
import Loading from '@components/loading';
|
|
||||||
import {ServerErrors} from '@constants';
|
import {ServerErrors} from '@constants';
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {isErrorWithMessage, isServerError} from '@utils/errors';
|
import {isErrorWithMessage, isServerError} from '@utils/errors';
|
||||||
import {logError} from '@utils/log';
|
import {logError} from '@utils/log';
|
||||||
import {preventDoubleTap} from '@utils/tap';
|
import {preventDoubleTap} from '@utils/tap';
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {displayUsername} from '@utils/user';
|
import {displayUsername} from '@utils/user';
|
||||||
|
|
||||||
import {ChannelNameInput} from '../channel_name_input';
|
import {ChannelNameInput} from '../channel_name_input';
|
||||||
|
|
@ -135,13 +134,6 @@ export const ConvertGMToChannelForm = ({
|
||||||
memberNames,
|
memberNames,
|
||||||
});
|
});
|
||||||
|
|
||||||
const buttonIcon = conversionInProgress ? (
|
|
||||||
<Loading
|
|
||||||
containerStyle={styles.loadingContainerStyle}
|
|
||||||
color={changeOpacity(theme.centerChannelColor, 0.32)}
|
|
||||||
/>
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<MessageBox
|
<MessageBox
|
||||||
|
|
@ -164,9 +156,10 @@ export const ConvertGMToChannelForm = ({
|
||||||
onPress={handleOnPress}
|
onPress={handleOnPress}
|
||||||
text={confirmButtonText}
|
text={confirmButtonText}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
buttonType={submitButtonEnabled ? 'destructive' : 'disabled'}
|
|
||||||
size='lg'
|
size='lg'
|
||||||
iconComponent={buttonIcon}
|
disabled={!submitButtonEnabled}
|
||||||
|
isDestructive={true}
|
||||||
|
showLoader={conversionInProgress}
|
||||||
/>
|
/>
|
||||||
{
|
{
|
||||||
errorMessage &&
|
errorMessage &&
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,14 @@
|
||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {Button} from '@rneui/base';
|
|
||||||
import React, {type MutableRefObject, useCallback, useEffect, useRef} from 'react';
|
import React, {type MutableRefObject, useCallback, useEffect, useRef} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {defineMessages, useIntl} from 'react-intl';
|
||||||
import {Keyboard, Platform, useWindowDimensions, View} from 'react-native';
|
import {Keyboard, Platform, useWindowDimensions, View} from 'react-native';
|
||||||
|
|
||||||
|
import Button from '@components/button';
|
||||||
import FloatingTextInput, {type FloatingTextInputRef} from '@components/floating_text_input_label';
|
import FloatingTextInput, {type FloatingTextInputRef} from '@components/floating_text_input_label';
|
||||||
import FormattedText from '@components/formatted_text';
|
import FormattedText from '@components/formatted_text';
|
||||||
import Loading from '@components/loading';
|
|
||||||
import {useIsTablet} from '@hooks/device';
|
import {useIsTablet} from '@hooks/device';
|
||||||
import {t} from '@i18n';
|
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
import {removeProtocol, stripTrailingSlashes} from '@utils/url';
|
import {removeProtocol, stripTrailingSlashes} from '@utils/url';
|
||||||
|
|
@ -49,24 +46,23 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||||
marginTop: 8,
|
marginTop: 8,
|
||||||
...typography('Body', 75, 'Regular'),
|
...typography('Body', 75, 'Regular'),
|
||||||
},
|
},
|
||||||
connectButton: {
|
buttonContainer: {
|
||||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.08),
|
|
||||||
width: '100%',
|
width: '100%',
|
||||||
marginTop: 32,
|
marginTop: 32,
|
||||||
marginLeft: 20,
|
|
||||||
marginRight: 20,
|
|
||||||
},
|
|
||||||
loadingContainerStyle: {
|
|
||||||
marginRight: 10,
|
|
||||||
padding: 0,
|
|
||||||
top: -2,
|
|
||||||
},
|
|
||||||
loading: {
|
|
||||||
height: 20,
|
|
||||||
width: 20,
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
save: {
|
||||||
|
id: 'edit_server.save',
|
||||||
|
defaultMessage: 'Save',
|
||||||
|
},
|
||||||
|
saving: {
|
||||||
|
id: 'edit_server.saving',
|
||||||
|
defaultMessage: 'Saving',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const EditServerForm = ({
|
const EditServerForm = ({
|
||||||
buttonDisabled,
|
buttonDisabled,
|
||||||
connecting,
|
connecting,
|
||||||
|
|
@ -91,7 +87,7 @@ const EditServerForm = ({
|
||||||
keyboardAwareRef.current?.scrollToPosition(0, 0);
|
keyboardAwareRef.current?.scrollToPosition(0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, []);
|
}, [keyboardAwareRef]);
|
||||||
|
|
||||||
const onUpdate = useCallback(() => {
|
const onUpdate = useCallback(() => {
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
|
|
@ -114,7 +110,7 @@ const EditServerForm = ({
|
||||||
keyboardAwareRef.current?.scrollToPosition(0, offsetY);
|
keyboardAwareRef.current?.scrollToPosition(0, offsetY);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [dimensions, isTablet]);
|
}, [dimensions, isTablet, keyboardAwareRef]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (Platform.OS === 'ios' && isTablet) {
|
if (Platform.OS === 'ios' && isTablet) {
|
||||||
|
|
@ -126,25 +122,6 @@ const EditServerForm = ({
|
||||||
}
|
}
|
||||||
}, [onFocus]);
|
}, [onFocus]);
|
||||||
|
|
||||||
const buttonType = buttonDisabled ? 'disabled' : 'default';
|
|
||||||
const styleButtonText = buttonTextStyle(theme, 'lg', 'primary', buttonType);
|
|
||||||
const styleButtonBackground = buttonBackgroundStyle(theme, 'lg', 'primary', buttonType);
|
|
||||||
|
|
||||||
let buttonID = t('edit_server.save');
|
|
||||||
let buttonText = 'Save';
|
|
||||||
let buttonIcon;
|
|
||||||
|
|
||||||
if (connecting) {
|
|
||||||
buttonID = t('edit_server.saving');
|
|
||||||
buttonText = 'Saving';
|
|
||||||
buttonIcon = (
|
|
||||||
<Loading
|
|
||||||
containerStyle={styles.loadingContainerStyle}
|
|
||||||
color={theme.buttonColor}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const saveButtonTestId = buttonDisabled ? 'edit_server_form.save.button.disabled' : 'edit_server_form.save.button';
|
const saveButtonTestId = buttonDisabled ? 'edit_server_form.save.button.disabled' : 'edit_server_form.save.button';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -180,21 +157,17 @@ const EditServerForm = ({
|
||||||
values={{url: removeProtocol(stripTrailingSlashes(serverUrl))}}
|
values={{url: removeProtocol(stripTrailingSlashes(serverUrl))}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<Button
|
<View style={styles.buttonContainer}>
|
||||||
containerStyle={styles.connectButton}
|
<Button
|
||||||
buttonStyle={styleButtonBackground}
|
disabled={buttonDisabled || connecting}
|
||||||
disabledStyle={styleButtonBackground}
|
onPress={onUpdate}
|
||||||
disabled={buttonDisabled}
|
testID={saveButtonTestId}
|
||||||
onPress={onUpdate}
|
size='lg'
|
||||||
testID={saveButtonTestId}
|
theme={theme}
|
||||||
>
|
text={formatMessage(connecting ? messages.saving : messages.save)}
|
||||||
{buttonIcon}
|
showLoader={connecting}
|
||||||
<FormattedText
|
|
||||||
defaultMessage={buttonText}
|
|
||||||
id={buttonID}
|
|
||||||
style={styleButtonText}
|
|
||||||
/>
|
/>
|
||||||
</Button>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {Button} from '@rneui/base';
|
|
||||||
import React, {useCallback, useEffect, useRef, useState} from 'react';
|
import React, {useCallback, useEffect, useRef, useState} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {Keyboard, Platform, Text, useWindowDimensions, View} from 'react-native';
|
import {Keyboard, Platform, Text, useWindowDimensions, View} from 'react-native';
|
||||||
|
|
@ -11,6 +10,7 @@ import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-nati
|
||||||
import {SafeAreaView} from 'react-native-safe-area-context';
|
import {SafeAreaView} from 'react-native-safe-area-context';
|
||||||
|
|
||||||
import {sendPasswordResetEmail} from '@actions/remote/session';
|
import {sendPasswordResetEmail} from '@actions/remote/session';
|
||||||
|
import Button from '@components/button';
|
||||||
import FloatingTextInput from '@components/floating_text_input_label';
|
import FloatingTextInput from '@components/floating_text_input_label';
|
||||||
import FormattedText from '@components/formatted_text';
|
import FormattedText from '@components/formatted_text';
|
||||||
import {Screens} from '@constants';
|
import {Screens} from '@constants';
|
||||||
|
|
@ -18,7 +18,6 @@ import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
||||||
import {useAvoidKeyboard} from '@hooks/device';
|
import {useAvoidKeyboard} from '@hooks/device';
|
||||||
import SecurityManager from '@managers/security_manager';
|
import SecurityManager from '@managers/security_manager';
|
||||||
import Background from '@screens/background';
|
import Background from '@screens/background';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {isEmail} from '@utils/helpers';
|
import {isEmail} from '@utils/helpers';
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
@ -65,7 +64,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
paddingHorizontal: 24,
|
paddingHorizontal: 24,
|
||||||
},
|
},
|
||||||
returnButton: {
|
returnButtonContainer: {
|
||||||
marginTop: 32,
|
marginTop: 32,
|
||||||
},
|
},
|
||||||
subheader: {
|
subheader: {
|
||||||
|
|
@ -158,17 +157,15 @@ const ForgotPassword = ({componentId, serverUrl, theme}: Props) => {
|
||||||
<Text style={styles.successText}>
|
<Text style={styles.successText}>
|
||||||
{email}
|
{email}
|
||||||
</Text>
|
</Text>
|
||||||
<Button
|
<View style={styles.returnButtonContainer}>
|
||||||
testID='password_send.return'
|
<Button
|
||||||
onPress={onReturn}
|
testID='password_send.return'
|
||||||
buttonStyle={[styles.returnButton, buttonBackgroundStyle(theme, 'lg', 'primary', 'default')]}
|
onPress={onReturn}
|
||||||
>
|
size='lg'
|
||||||
<FormattedText
|
theme={theme}
|
||||||
id='password_send.return'
|
text={formatMessage({id: 'password_send.return', defaultMessage: 'Return to Log In'})}
|
||||||
defaultMessage='Return to Log In'
|
|
||||||
style={buttonTextStyle(theme, 'lg', 'primary', 'default')}
|
|
||||||
/>
|
/>
|
||||||
</Button>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -221,19 +218,16 @@ const ForgotPassword = ({componentId, serverUrl, theme}: Props) => {
|
||||||
theme={theme}
|
theme={theme}
|
||||||
value={email}
|
value={email}
|
||||||
/>
|
/>
|
||||||
<Button
|
<View style={styles.returnButtonContainer}>
|
||||||
testID='forgot.password.button'
|
<Button
|
||||||
buttonStyle={[styles.returnButton, buttonBackgroundStyle(theme, 'lg', 'primary', 'default'), error ? styles.error : undefined]}
|
testID='forgot.password.button'
|
||||||
disabledStyle={[styles.returnButton, buttonBackgroundStyle(theme, 'lg', 'primary', 'disabled'), error ? styles.error : undefined]}
|
disabled={!email}
|
||||||
disabled={!email}
|
onPress={submitResetPassword}
|
||||||
onPress={submitResetPassword}
|
size='lg'
|
||||||
>
|
text={formatMessage({id: 'password_send.reset', defaultMessage: 'Reset my password'})}
|
||||||
<FormattedText
|
theme={theme}
|
||||||
id='password_send.reset'
|
|
||||||
defaultMessage='Reset my password'
|
|
||||||
style={buttonTextStyle(theme, 'lg', 'primary', email ? 'default' : 'disabled')}
|
|
||||||
/>
|
/>
|
||||||
</Button>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</KeyboardAwareScrollView>
|
</KeyboardAwareScrollView>
|
||||||
|
|
|
||||||
|
|
@ -256,61 +256,106 @@ exports[`components/categories_list should render channels error 1`] = `
|
||||||
There was a problem loading content for this team.
|
There was a problem loading content for this team.
|
||||||
</Text>
|
</Text>
|
||||||
<View
|
<View
|
||||||
accessibilityState={
|
|
||||||
{
|
|
||||||
"busy": undefined,
|
|
||||||
"checked": undefined,
|
|
||||||
"disabled": undefined,
|
|
||||||
"expanded": undefined,
|
|
||||||
"selected": undefined,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
accessibilityValue={
|
|
||||||
{
|
|
||||||
"max": undefined,
|
|
||||||
"min": undefined,
|
|
||||||
"now": undefined,
|
|
||||||
"text": undefined,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
accessible={true}
|
|
||||||
collapsable={false}
|
|
||||||
focusable={true}
|
|
||||||
onClick={[Function]}
|
|
||||||
onResponderGrant={[Function]}
|
|
||||||
onResponderMove={[Function]}
|
|
||||||
onResponderRelease={[Function]}
|
|
||||||
onResponderTerminate={[Function]}
|
|
||||||
onResponderTerminationRequest={[Function]}
|
|
||||||
onStartShouldSetResponder={[Function]}
|
|
||||||
style={
|
style={
|
||||||
{
|
{
|
||||||
"backgroundColor": "#ffffff",
|
|
||||||
"borderRadius": 4,
|
|
||||||
"marginTop": 24,
|
"marginTop": 24,
|
||||||
"opacity": 1,
|
|
||||||
"paddingHorizontal": 24,
|
|
||||||
"paddingVertical": 12,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Text
|
<View
|
||||||
style={
|
style={
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"fontFamily": "OpenSans-SemiBold",
|
"overflow": "hidden",
|
||||||
"fontSize": 16,
|
|
||||||
"fontWeight": "600",
|
|
||||||
"lineHeight": 24,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"color": "#1c58d9",
|
"borderRadius": 2,
|
||||||
},
|
},
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
testID="RNE_BUTTON_WRAPPER"
|
||||||
>
|
>
|
||||||
Retry
|
<View
|
||||||
</Text>
|
accessibilityRole="button"
|
||||||
|
accessibilityState={
|
||||||
|
{
|
||||||
|
"busy": false,
|
||||||
|
"checked": undefined,
|
||||||
|
"disabled": false,
|
||||||
|
"expanded": undefined,
|
||||||
|
"selected": undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accessibilityValue={
|
||||||
|
{
|
||||||
|
"max": undefined,
|
||||||
|
"min": undefined,
|
||||||
|
"now": undefined,
|
||||||
|
"text": undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accessible={true}
|
||||||
|
collapsable={false}
|
||||||
|
focusable={true}
|
||||||
|
onClick={[Function]}
|
||||||
|
onResponderGrant={[Function]}
|
||||||
|
onResponderMove={[Function]}
|
||||||
|
onResponderRelease={[Function]}
|
||||||
|
onResponderTerminate={[Function]}
|
||||||
|
onResponderTerminationRequest={[Function]}
|
||||||
|
onStartShouldSetResponder={[Function]}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"opacity": 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"alignItems": "center",
|
||||||
|
"backgroundColor": "#1c58d9",
|
||||||
|
"borderColor": "#2089dc",
|
||||||
|
"borderRadius": 4,
|
||||||
|
"borderWidth": 0,
|
||||||
|
"flexDirection": "row",
|
||||||
|
"justifyContent": "center",
|
||||||
|
"padding": 8,
|
||||||
|
"paddingHorizontal": 24,
|
||||||
|
"paddingVertical": 12,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"alignItems": "center",
|
||||||
|
"flexDirection": "row",
|
||||||
|
"gap": 7,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testID="undefined-text-container"
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
numberOfLines={1}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"color": "#ffffff",
|
||||||
|
"fontFamily": "OpenSans-SemiBold",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontWeight": "600",
|
||||||
|
"lineHeight": 24,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Retry
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
@ -643,61 +688,106 @@ exports[`components/categories_list should render team error 1`] = `
|
||||||
There was a problem loading content for this server.
|
There was a problem loading content for this server.
|
||||||
</Text>
|
</Text>
|
||||||
<View
|
<View
|
||||||
accessibilityState={
|
|
||||||
{
|
|
||||||
"busy": undefined,
|
|
||||||
"checked": undefined,
|
|
||||||
"disabled": undefined,
|
|
||||||
"expanded": undefined,
|
|
||||||
"selected": undefined,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
accessibilityValue={
|
|
||||||
{
|
|
||||||
"max": undefined,
|
|
||||||
"min": undefined,
|
|
||||||
"now": undefined,
|
|
||||||
"text": undefined,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
accessible={true}
|
|
||||||
collapsable={false}
|
|
||||||
focusable={true}
|
|
||||||
onClick={[Function]}
|
|
||||||
onResponderGrant={[Function]}
|
|
||||||
onResponderMove={[Function]}
|
|
||||||
onResponderRelease={[Function]}
|
|
||||||
onResponderTerminate={[Function]}
|
|
||||||
onResponderTerminationRequest={[Function]}
|
|
||||||
onStartShouldSetResponder={[Function]}
|
|
||||||
style={
|
style={
|
||||||
{
|
{
|
||||||
"backgroundColor": "#ffffff",
|
|
||||||
"borderRadius": 4,
|
|
||||||
"marginTop": 24,
|
"marginTop": 24,
|
||||||
"opacity": 1,
|
|
||||||
"paddingHorizontal": 24,
|
|
||||||
"paddingVertical": 12,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Text
|
<View
|
||||||
style={
|
style={
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"fontFamily": "OpenSans-SemiBold",
|
"overflow": "hidden",
|
||||||
"fontSize": 16,
|
|
||||||
"fontWeight": "600",
|
|
||||||
"lineHeight": 24,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"color": "#1c58d9",
|
"borderRadius": 2,
|
||||||
},
|
},
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
testID="RNE_BUTTON_WRAPPER"
|
||||||
>
|
>
|
||||||
Retry
|
<View
|
||||||
</Text>
|
accessibilityRole="button"
|
||||||
|
accessibilityState={
|
||||||
|
{
|
||||||
|
"busy": false,
|
||||||
|
"checked": undefined,
|
||||||
|
"disabled": false,
|
||||||
|
"expanded": undefined,
|
||||||
|
"selected": undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accessibilityValue={
|
||||||
|
{
|
||||||
|
"max": undefined,
|
||||||
|
"min": undefined,
|
||||||
|
"now": undefined,
|
||||||
|
"text": undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accessible={true}
|
||||||
|
collapsable={false}
|
||||||
|
focusable={true}
|
||||||
|
onClick={[Function]}
|
||||||
|
onResponderGrant={[Function]}
|
||||||
|
onResponderMove={[Function]}
|
||||||
|
onResponderRelease={[Function]}
|
||||||
|
onResponderTerminate={[Function]}
|
||||||
|
onResponderTerminationRequest={[Function]}
|
||||||
|
onStartShouldSetResponder={[Function]}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"opacity": 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"alignItems": "center",
|
||||||
|
"backgroundColor": "#1c58d9",
|
||||||
|
"borderColor": "#2089dc",
|
||||||
|
"borderRadius": 4,
|
||||||
|
"borderWidth": 0,
|
||||||
|
"flexDirection": "row",
|
||||||
|
"justifyContent": "center",
|
||||||
|
"padding": 8,
|
||||||
|
"paddingHorizontal": 24,
|
||||||
|
"paddingVertical": 12,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"alignItems": "center",
|
||||||
|
"flexDirection": "row",
|
||||||
|
"gap": 7,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testID="undefined-text-container"
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
numberOfLines={1}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"color": "#ffffff",
|
||||||
|
"fontFamily": "OpenSans-SemiBold",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontWeight": "600",
|
||||||
|
"lineHeight": 24,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Retry
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
import React, {useMemo} from 'react';
|
import React from 'react';
|
||||||
|
import {useIntl} from 'react-intl';
|
||||||
import {View} from 'react-native';
|
import {View} from 'react-native';
|
||||||
|
|
||||||
import {showUnreadChannelsOnly} from '@actions/local/channel';
|
import {showUnreadChannelsOnly} from '@actions/local/channel';
|
||||||
|
import Button from '@components/button';
|
||||||
import FormattedText from '@components/formatted_text';
|
import FormattedText from '@components/formatted_text';
|
||||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@ type Props = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||||
button: {
|
buttonContainer: {
|
||||||
marginTop: 24,
|
marginTop: 24,
|
||||||
},
|
},
|
||||||
container: {
|
container: {
|
||||||
|
|
@ -45,13 +45,11 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function EmptyUnreads({onlyUnreads}: Props) {
|
function EmptyUnreads({onlyUnreads}: Props) {
|
||||||
|
const intl = useIntl();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const serverUrl = useServerUrl();
|
const serverUrl = useServerUrl();
|
||||||
const styles = getStyleSheet(theme);
|
const styles = getStyleSheet(theme);
|
||||||
|
|
||||||
const buttonStyle = useMemo(() => [buttonBackgroundStyle(theme, 'lg', 'tertiary', 'inverted'), styles.button],
|
|
||||||
[theme]);
|
|
||||||
|
|
||||||
const onPress = () => {
|
const onPress = () => {
|
||||||
showUnreadChannelsOnly(serverUrl, !onlyUnreads);
|
showUnreadChannelsOnly(serverUrl, !onlyUnreads);
|
||||||
};
|
};
|
||||||
|
|
@ -71,17 +69,16 @@ function EmptyUnreads({onlyUnreads}: Props) {
|
||||||
style={styles.paragraph}
|
style={styles.paragraph}
|
||||||
testID='unreads.empty.paragraph'
|
testID='unreads.empty.paragraph'
|
||||||
/>
|
/>
|
||||||
<TouchableWithFeedback
|
<View style={styles.buttonContainer}>
|
||||||
style={buttonStyle}
|
<Button
|
||||||
onPress={onPress}
|
text={intl.formatMessage({id: 'unreads.empty.show_all', defaultMessage: 'Show all'})}
|
||||||
type={'opacity'}
|
theme={theme}
|
||||||
>
|
size='lg'
|
||||||
<FormattedText
|
onPress={onPress}
|
||||||
id='unreads.empty.show_all'
|
emphasis='tertiary'
|
||||||
defaultMessage='Show all'
|
isInverted={true}
|
||||||
style={buttonTextStyle(theme, 'lg', 'tertiary', 'inverted')}
|
|
||||||
/>
|
/>
|
||||||
</TouchableWithFeedback>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,15 @@
|
||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {Button} from '@rneui/base';
|
|
||||||
import React, {useCallback, useMemo} from 'react';
|
import React, {useCallback, useMemo} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {defineMessages, useIntl} from 'react-intl';
|
||||||
import {View, Text, ScrollView} from 'react-native';
|
import {View, Text, ScrollView} from 'react-native';
|
||||||
|
|
||||||
import CompassIcon from '@components/compass_icon';
|
import Button from '@components/button';
|
||||||
import FormattedText from '@components/formatted_text';
|
|
||||||
import AlertSvg from '@components/illustrations/alert';
|
import AlertSvg from '@components/illustrations/alert';
|
||||||
import ErrorSvg from '@components/illustrations/error';
|
import ErrorSvg from '@components/illustrations/error';
|
||||||
import SuccessSvg from '@components/illustrations/success';
|
import SuccessSvg from '@components/illustrations/success';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {t} from '@i18n';
|
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {makeStyleSheetFromTheme, changeOpacity} from '@utils/theme';
|
import {makeStyleSheetFromTheme, changeOpacity} from '@utils/theme';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
||||||
|
|
@ -77,17 +73,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
gap: 8,
|
||||||
summaryButtonTextContainer: {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
height: 24,
|
|
||||||
},
|
|
||||||
summaryButtonIcon: {
|
|
||||||
marginRight: 7,
|
|
||||||
color: theme.buttonColor,
|
|
||||||
|
|
||||||
},
|
},
|
||||||
summaryButtonContainerStyle: {flexGrow: 1},
|
summaryButtonContainerStyle: {flexGrow: 1},
|
||||||
};
|
};
|
||||||
|
|
@ -109,6 +95,21 @@ type SummaryProps = {
|
||||||
onBack: () => void;
|
onBack: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
done: {
|
||||||
|
id: 'invite.summary.done',
|
||||||
|
defaultMessage: 'Done',
|
||||||
|
},
|
||||||
|
tryAgain: {
|
||||||
|
id: 'invite.summary.try_again',
|
||||||
|
defaultMessage: 'Try again',
|
||||||
|
},
|
||||||
|
back: {
|
||||||
|
id: 'invite.summary.back',
|
||||||
|
defaultMessage: 'Go back',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export default function Summary({
|
export default function Summary({
|
||||||
result,
|
result,
|
||||||
selectedIds,
|
selectedIds,
|
||||||
|
|
@ -118,7 +119,7 @@ export default function Summary({
|
||||||
onRetry,
|
onRetry,
|
||||||
onBack,
|
onBack,
|
||||||
}: SummaryProps) {
|
}: SummaryProps) {
|
||||||
const {formatMessage, locale} = useIntl();
|
const {formatMessage} = useIntl();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const styles = getStyleSheet(theme);
|
const styles = getStyleSheet(theme);
|
||||||
|
|
||||||
|
|
@ -183,64 +184,41 @@ export default function Summary({
|
||||||
let onPress;
|
let onPress;
|
||||||
let iconName = '';
|
let iconName = '';
|
||||||
let text;
|
let text;
|
||||||
let styleButtonText = buttonTextStyle(theme, 'lg', 'primary');
|
let emphasis: ButtonEmphasis = 'primary';
|
||||||
let styleButtonBackground = buttonBackgroundStyle(theme, 'lg', 'primary');
|
|
||||||
const styleButtonIcon = [];
|
|
||||||
styleButtonIcon.push(styles.summaryButtonIcon);
|
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SummaryButtonType.BACK:
|
case SummaryButtonType.BACK:
|
||||||
onPress = onBack;
|
onPress = onBack;
|
||||||
iconName = 'chevron-left';
|
iconName = 'chevron-left';
|
||||||
text = {
|
text = messages.back;
|
||||||
id: t('invite.summary.back'),
|
emphasis = 'tertiary';
|
||||||
defaultMessage: 'Go back',
|
|
||||||
};
|
|
||||||
styleButtonText = buttonTextStyle(theme, 'lg', 'tertiary');
|
|
||||||
styleButtonBackground = [buttonBackgroundStyle(theme, 'lg', 'tertiary'), {marginRight: 8}];
|
|
||||||
styleButtonIcon.push({color: theme.buttonBg});
|
|
||||||
break;
|
break;
|
||||||
case SummaryButtonType.RETRY:
|
case SummaryButtonType.RETRY:
|
||||||
onPress = onRetry;
|
onPress = onRetry;
|
||||||
iconName = 'refresh';
|
iconName = 'refresh';
|
||||||
text = {
|
text = messages.tryAgain;
|
||||||
id: t('invite.summary.try_again'),
|
|
||||||
defaultMessage: 'Try again',
|
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
case SummaryButtonType.DONE:
|
case SummaryButtonType.DONE:
|
||||||
default:
|
default:
|
||||||
onPress = onClose;
|
onPress = onClose;
|
||||||
text = {
|
text = messages.done;
|
||||||
id: t('invite.summary.done'),
|
|
||||||
defaultMessage: 'Done',
|
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<View style={styles.summaryButtonContainerStyle}>
|
||||||
containerStyle={styles.summaryButtonContainerStyle}
|
<Button
|
||||||
buttonStyle={styleButtonBackground}
|
onPress={onPress}
|
||||||
onPress={onPress}
|
testID={`invite.summary_button.${SummaryButtonType.RETRY}`}
|
||||||
testID={`invite.summary_button.${SummaryButtonType.RETRY}`}
|
text={formatMessage(text)}
|
||||||
>
|
iconName={iconName}
|
||||||
<View style={styles.summaryButtonTextContainer}>
|
emphasis={emphasis}
|
||||||
{iconName && (
|
size='lg'
|
||||||
<CompassIcon
|
theme={theme}
|
||||||
name={iconName}
|
/>
|
||||||
size={24}
|
</View>
|
||||||
style={styleButtonIcon}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<FormattedText
|
|
||||||
{...text}
|
|
||||||
style={styleButtonText}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</Button>
|
|
||||||
);
|
);
|
||||||
}, [theme, locale, onClose, onRetry, onBack]);
|
}, [styles.summaryButtonContainerStyle, formatMessage, theme, onBack, onRetry, onClose]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,19 @@
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {useManagedConfig} from '@mattermost/react-native-emm';
|
import {useManagedConfig} from '@mattermost/react-native-emm';
|
||||||
import {Button} from '@rneui/base';
|
import {Button as RNEButton} from '@rneui/base';
|
||||||
import React, {useCallback, useEffect, useMemo, useRef, useState, type RefObject} from 'react';
|
import React, {useCallback, useEffect, useMemo, useRef, useState, type RefObject} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {defineMessages, useIntl} from 'react-intl';
|
||||||
import {Keyboard, TextInput, TouchableOpacity, View} from 'react-native';
|
import {Keyboard, TextInput, TouchableOpacity, View} from 'react-native';
|
||||||
|
|
||||||
import {login} from '@actions/remote/session';
|
import {login} from '@actions/remote/session';
|
||||||
|
import Button from '@components/button';
|
||||||
import CompassIcon from '@components/compass_icon';
|
import CompassIcon from '@components/compass_icon';
|
||||||
import FloatingTextInput from '@components/floating_text_input_label';
|
import FloatingTextInput from '@components/floating_text_input_label';
|
||||||
import FormattedText from '@components/formatted_text';
|
import FormattedText from '@components/formatted_text';
|
||||||
import Loading from '@components/loading';
|
|
||||||
import {FORGOT_PASSWORD, MFA} from '@constants/screens';
|
import {FORGOT_PASSWORD, MFA} from '@constants/screens';
|
||||||
import {useAvoidKeyboard} from '@hooks/device';
|
import {useAvoidKeyboard} from '@hooks/device';
|
||||||
import {t} from '@i18n';
|
|
||||||
import {goToScreen, loginAnimationOptions, resetToHome} from '@screens/navigation';
|
import {goToScreen, loginAnimationOptions, resetToHome} from '@screens/navigation';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {getFullErrorMessage, getServerError, isErrorWithMessage, isServerError} from '@utils/errors';
|
import {getFullErrorMessage, getServerError, isErrorWithMessage, isServerError} from '@utils/errors';
|
||||||
import {preventDoubleTap} from '@utils/tap';
|
import {preventDoubleTap} from '@utils/tap';
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
|
|
@ -67,12 +65,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontFamily: 'OpenSans-SemiBold',
|
fontFamily: 'OpenSans-SemiBold',
|
||||||
},
|
},
|
||||||
loadingContainerStyle: {
|
loginButtonContainer: {
|
||||||
marginRight: 10,
|
|
||||||
padding: 0,
|
|
||||||
top: -2,
|
|
||||||
},
|
|
||||||
loginButton: {
|
|
||||||
marginTop: 25,
|
marginTop: 25,
|
||||||
},
|
},
|
||||||
endAdornment: {
|
endAdornment: {
|
||||||
|
|
@ -80,6 +73,17 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
signIn: {
|
||||||
|
id: 'login.signIn',
|
||||||
|
defaultMessage: 'Log In',
|
||||||
|
},
|
||||||
|
signingIn: {
|
||||||
|
id: 'login.signingIn',
|
||||||
|
defaultMessage: 'Logging In',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const LoginForm = ({config, extra, keyboardAwareRef, serverDisplayName, launchError, launchType, license, serverUrl, theme}: LoginProps) => {
|
const LoginForm = ({config, extra, keyboardAwareRef, serverDisplayName, launchError, launchType, license, serverUrl, theme}: LoginProps) => {
|
||||||
const styles = getStyleSheet(theme);
|
const styles = getStyleSheet(theme);
|
||||||
const loginRef = useRef<TextInput>(null);
|
const loginRef = useRef<TextInput>(null);
|
||||||
|
|
@ -256,44 +260,20 @@ const LoginForm = ({config, extra, keyboardAwareRef, serverDisplayName, launchEr
|
||||||
}, [loginId, password]);
|
}, [loginId, password]);
|
||||||
|
|
||||||
const renderProceedButton = useMemo(() => {
|
const renderProceedButton = useMemo(() => {
|
||||||
const buttonType = buttonDisabled ? 'disabled' : 'default';
|
|
||||||
const styleButtonText = buttonTextStyle(theme, 'lg', 'primary', buttonType);
|
|
||||||
const styleButtonBackground = buttonBackgroundStyle(theme, 'lg', 'primary', buttonType);
|
|
||||||
|
|
||||||
let buttonID = t('login.signIn');
|
|
||||||
let buttonText = 'Log In';
|
|
||||||
let buttonIcon;
|
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
buttonID = t('login.signingIn');
|
|
||||||
buttonText = 'Logging In';
|
|
||||||
buttonIcon = (
|
|
||||||
<Loading
|
|
||||||
containerStyle={styles.loadingContainerStyle}
|
|
||||||
color={theme.buttonColor}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const signinButtonTestId = buttonDisabled ? 'login_form.signin.button.disabled' : 'login_form.signin.button';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<View style={styles.loginButtonContainer}>
|
||||||
disabled={buttonDisabled}
|
<Button
|
||||||
onPress={onLogin}
|
disabled={buttonDisabled}
|
||||||
buttonStyle={[styles.loginButton, styleButtonBackground]}
|
onPress={onLogin}
|
||||||
disabledStyle={[styles.loginButton, styleButtonBackground]}
|
size='lg'
|
||||||
testID={signinButtonTestId}
|
testID={buttonDisabled ? 'login_form.signin.button.disabled' : 'login_form.signin.button'}
|
||||||
>
|
text={intl.formatMessage(isLoading ? messages.signingIn : messages.signIn)}
|
||||||
{buttonIcon}
|
showLoader={isLoading}
|
||||||
<FormattedText
|
theme={theme}
|
||||||
id={buttonID}
|
|
||||||
defaultMessage={buttonText}
|
|
||||||
style={styleButtonText}
|
|
||||||
/>
|
/>
|
||||||
</Button>
|
</View>
|
||||||
);
|
);
|
||||||
}, [buttonDisabled, loginId, password, isLoading, theme]);
|
}, [styles.loginButtonContainer, buttonDisabled, onLogin, intl, isLoading, theme]);
|
||||||
|
|
||||||
const endAdornment = (
|
const endAdornment = (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
|
|
@ -356,7 +336,7 @@ const LoginForm = ({config, extra, keyboardAwareRef, serverDisplayName, launchEr
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{(emailEnabled || usernameEnabled) && config.PasswordEnableForgotLink !== 'false' && (
|
{(emailEnabled || usernameEnabled) && config.PasswordEnableForgotLink !== 'false' && (
|
||||||
<Button
|
<RNEButton
|
||||||
onPress={onPressForgotPassword}
|
onPress={onPressForgotPassword}
|
||||||
buttonStyle={[styles.forgotPasswordBtn, error ? styles.forgotPasswordError : undefined]}
|
buttonStyle={[styles.forgotPasswordBtn, error ? styles.forgotPasswordError : undefined]}
|
||||||
testID='login_form.forgot_password.button'
|
testID='login_form.forgot_password.button'
|
||||||
|
|
@ -366,7 +346,7 @@ const LoginForm = ({config, extra, keyboardAwareRef, serverDisplayName, launchEr
|
||||||
defaultMessage='Forgot your password?'
|
defaultMessage='Forgot your password?'
|
||||||
style={styles.forgotPasswordTxt}
|
style={styles.forgotPasswordTxt}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</RNEButton>
|
||||||
)}
|
)}
|
||||||
{renderProceedButton}
|
{renderProceedButton}
|
||||||
</View>
|
</View>
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {Button} from '@rneui/base';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {Image, type ImageSourcePropType, Text, View} from 'react-native';
|
import {Image, type ImageSourcePropType, StyleSheet, View} from 'react-native';
|
||||||
|
|
||||||
import CompassIcon from '@components/compass_icon';
|
import Button from '@components/button';
|
||||||
import {Sso} from '@constants';
|
import {Sso} from '@constants';
|
||||||
import {buttonBackgroundStyle} from '@utils/buttonStyles';
|
|
||||||
import {makeStyleSheetFromTheme, changeOpacity} from '@utils/theme';
|
|
||||||
|
|
||||||
type SsoInfo = {
|
type SsoInfo = {
|
||||||
text: string;
|
text: string;
|
||||||
|
|
@ -26,8 +23,6 @@ type Props = {
|
||||||
|
|
||||||
const SsoOptions = ({goToSso, ssoOnly, ssoOptions, theme}: Props) => {
|
const SsoOptions = ({goToSso, ssoOnly, ssoOptions, theme}: Props) => {
|
||||||
const {formatMessage} = useIntl();
|
const {formatMessage} = useIntl();
|
||||||
const styles = getStyleSheet(theme);
|
|
||||||
const styleButtonBackground = buttonBackgroundStyle(theme, 'lg', 'primary');
|
|
||||||
|
|
||||||
const getSsoButtonOptions = ((ssoType: string): SsoInfo => {
|
const getSsoButtonOptions = ((ssoType: string): SsoInfo => {
|
||||||
const sso: SsoInfo = {} as SsoInfo;
|
const sso: SsoInfo = {} as SsoInfo;
|
||||||
|
|
@ -63,12 +58,8 @@ const SsoOptions = ({goToSso, ssoOnly, ssoOptions, theme}: Props) => {
|
||||||
(ssoType: string) => ssoOptions[ssoType].enabled,
|
(ssoType: string) => ssoOptions[ssoType].enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
let styleViewContainer;
|
const styleViewContainer = enabledSSOs.length === 2 && !ssoOnly ? styles.containerAsRow : undefined;
|
||||||
let styleButtonContainer;
|
const styleButtonWrapper = enabledSSOs.length === 2 && !ssoOnly ? styles.buttonWrapper : undefined;
|
||||||
if (enabledSSOs.length === 2 && !ssoOnly) {
|
|
||||||
styleViewContainer = styles.containerAsRow;
|
|
||||||
styleButtonContainer = styles.buttonContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
const componentArray = [];
|
const componentArray = [];
|
||||||
for (const ssoType of enabledSSOs) {
|
for (const ssoType of enabledSSOs) {
|
||||||
|
|
@ -78,38 +69,24 @@ const SsoOptions = ({goToSso, ssoOnly, ssoOptions, theme}: Props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
componentArray.push(
|
componentArray.push(
|
||||||
<Button
|
<View style={styleButtonWrapper}>
|
||||||
key={ssoType}
|
<Button
|
||||||
onPress={handlePress}
|
key={ssoType}
|
||||||
buttonStyle={[styleButtonBackground, styles.button]}
|
onPress={handlePress}
|
||||||
containerStyle={styleButtonContainer}
|
size='lg'
|
||||||
>
|
theme={theme}
|
||||||
{imageSrc && (
|
iconName={compassIcon}
|
||||||
<Image
|
emphasis='secondary'
|
||||||
key={'image' + ssoType}
|
iconComponent={imageSrc ? (
|
||||||
source={imageSrc}
|
<Image
|
||||||
style={styles.logoStyle}
|
key={'image' + ssoType}
|
||||||
/>
|
source={imageSrc}
|
||||||
)}
|
style={styles.logoStyle}
|
||||||
{compassIcon &&
|
/>
|
||||||
<CompassIcon
|
) : undefined}
|
||||||
name={compassIcon}
|
text={text}
|
||||||
size={16}
|
|
||||||
color={theme.centerChannelColor}
|
|
||||||
/>
|
/>
|
||||||
}
|
</View>,
|
||||||
<View
|
|
||||||
style={styles.buttonTextContainer}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
key={ssoType}
|
|
||||||
style={styles.buttonText}
|
|
||||||
testID={text}
|
|
||||||
>
|
|
||||||
{text}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</Button>,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,41 +97,23 @@ const SsoOptions = ({goToSso, ssoOnly, ssoOptions, theme}: Props) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
marginVertical: 24,
|
marginVertical: 24,
|
||||||
|
gap: 8,
|
||||||
},
|
},
|
||||||
containerAsRow: {
|
containerAsRow: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
buttonContainer: {
|
buttonWrapper: {
|
||||||
width: '48%',
|
flex: 1,
|
||||||
marginRight: 8,
|
|
||||||
},
|
|
||||||
button: {
|
|
||||||
marginVertical: 4,
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: changeOpacity(theme.centerChannelColor, 0.16),
|
|
||||||
},
|
|
||||||
buttonTextContainer: {
|
|
||||||
color: theme.centerChannelColor,
|
|
||||||
flexDirection: 'row',
|
|
||||||
marginLeft: 9,
|
|
||||||
},
|
|
||||||
buttonText: {
|
|
||||||
color: theme.centerChannelColor,
|
|
||||||
fontFamily: 'OpenSans-SemiBold',
|
|
||||||
fontSize: 16,
|
|
||||||
lineHeight: 18,
|
|
||||||
top: 2,
|
|
||||||
},
|
},
|
||||||
logoStyle: {
|
logoStyle: {
|
||||||
height: 18,
|
height: 18,
|
||||||
marginRight: 5,
|
marginRight: 5,
|
||||||
width: 18,
|
width: 18,
|
||||||
},
|
},
|
||||||
}));
|
});
|
||||||
|
|
||||||
export default SsoOptions;
|
export default SsoOptions;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {Button} from '@rneui/base';
|
|
||||||
import React, {useCallback, useEffect, useRef, useState} from 'react';
|
import React, {useCallback, useEffect, useRef, useState} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {Keyboard, Platform, useWindowDimensions, View} from 'react-native';
|
import {Keyboard, Platform, useWindowDimensions, View} from 'react-native';
|
||||||
|
|
@ -11,18 +10,16 @@ import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-nati
|
||||||
import {SafeAreaView} from 'react-native-safe-area-context';
|
import {SafeAreaView} from 'react-native-safe-area-context';
|
||||||
|
|
||||||
import {login} from '@actions/remote/session';
|
import {login} from '@actions/remote/session';
|
||||||
|
import Button from '@components/button';
|
||||||
import FloatingTextInput from '@components/floating_text_input_label';
|
import FloatingTextInput from '@components/floating_text_input_label';
|
||||||
import FormattedText from '@components/formatted_text';
|
import FormattedText from '@components/formatted_text';
|
||||||
import Loading from '@components/loading';
|
|
||||||
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
||||||
import {useAvoidKeyboard} from '@hooks/device';
|
import {useAvoidKeyboard} from '@hooks/device';
|
||||||
import {t} from '@i18n';
|
import {usePreventDoubleTap} from '@hooks/utils';
|
||||||
import SecurityManager from '@managers/security_manager';
|
import SecurityManager from '@managers/security_manager';
|
||||||
import Background from '@screens/background';
|
import Background from '@screens/background';
|
||||||
import {popTopScreen} from '@screens/navigation';
|
import {popTopScreen} from '@screens/navigation';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {getErrorMessage} from '@utils/errors';
|
import {getErrorMessage} from '@utils/errors';
|
||||||
import {preventDoubleTap} from '@utils/tap';
|
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
||||||
|
|
@ -52,9 +49,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
marginTop: Platform.select({android: 56}),
|
marginTop: Platform.select({android: 56}),
|
||||||
},
|
},
|
||||||
error: {
|
|
||||||
marginTop: 64,
|
|
||||||
},
|
|
||||||
flex: {
|
flex: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
|
|
@ -72,16 +66,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||||
paddingHorizontal: 24,
|
paddingHorizontal: 24,
|
||||||
height: '100%',
|
height: '100%',
|
||||||
},
|
},
|
||||||
loading: {
|
proceedButtonContainer: {
|
||||||
height: 20,
|
|
||||||
width: 20,
|
|
||||||
},
|
|
||||||
loadingContainerStyle: {
|
|
||||||
marginRight: 10,
|
|
||||||
padding: 0,
|
|
||||||
top: -2,
|
|
||||||
},
|
|
||||||
proceedButton: {
|
|
||||||
marginTop: 32,
|
marginTop: 32,
|
||||||
},
|
},
|
||||||
shield: {
|
shield: {
|
||||||
|
|
@ -114,12 +99,12 @@ const MFA = ({componentId, config, goToHome, license, loginId, password, serverD
|
||||||
setError('');
|
setError('');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const submit = useCallback(preventDoubleTap(async () => {
|
const submit = usePreventDoubleTap(useCallback(async () => {
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
if (!token) {
|
if (!token) {
|
||||||
setError(
|
setError(
|
||||||
formatMessage({
|
formatMessage({
|
||||||
id: t('login_mfa.tokenReq'),
|
id: 'login_mfa.tokenReq',
|
||||||
defaultMessage: 'Please enter an MFA token',
|
defaultMessage: 'Please enter an MFA token',
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
@ -133,7 +118,7 @@ const MFA = ({componentId, config, goToHome, license, loginId, password, serverD
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
goToHome(result.error);
|
goToHome(result.error);
|
||||||
}), [token]);
|
}, [config, formatMessage, goToHome, intl, license, loginId, password, serverDisplayName, serverUrl, token]));
|
||||||
|
|
||||||
const transform = useAnimatedStyle(() => {
|
const transform = useAnimatedStyle(() => {
|
||||||
const duration = Platform.OS === 'android' ? 250 : 350;
|
const duration = Platform.OS === 'android' ? 250 : 350;
|
||||||
|
|
@ -224,25 +209,18 @@ const MFA = ({componentId, config, goToHome, license, loginId, password, serverD
|
||||||
theme={theme}
|
theme={theme}
|
||||||
value={token}
|
value={token}
|
||||||
/>
|
/>
|
||||||
<Button
|
<View style={styles.proceedButtonContainer}>
|
||||||
testID='login_mfa.submit'
|
<Button
|
||||||
buttonStyle={[styles.proceedButton, buttonBackgroundStyle(theme, 'lg', 'primary', 'default'), error ? styles.error : undefined]}
|
testID='login_mfa.submit'
|
||||||
disabledStyle={[styles.proceedButton, buttonBackgroundStyle(theme, 'lg', 'primary', 'disabled'), error ? styles.error : undefined]}
|
size='lg'
|
||||||
disabled={!token}
|
disabled={!token}
|
||||||
onPress={submit}
|
onPress={submit}
|
||||||
>
|
theme={theme}
|
||||||
{isLoading &&
|
showLoader={isLoading}
|
||||||
<Loading
|
text={formatMessage({id: 'mobile.components.select_server_view.proceed', defaultMessage: 'Proceed'})}
|
||||||
containerStyle={styles.loadingContainerStyle}
|
isDestructive={Boolean(error)}
|
||||||
color={theme.buttonColor}
|
|
||||||
/>
|
/>
|
||||||
}
|
</View>
|
||||||
<FormattedText
|
|
||||||
id='mobile.components.select_server_view.proceed'
|
|
||||||
defaultMessage='Proceed'
|
|
||||||
style={buttonTextStyle(theme, 'lg', 'primary', token ? 'default' : 'disabled')}
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</KeyboardAwareScrollView>
|
</KeyboardAwareScrollView>
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,13 @@
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Pressable, useWindowDimensions, View} from 'react-native';
|
import {Pressable, StyleSheet, useWindowDimensions, View} from 'react-native';
|
||||||
import Animated, {Extrapolate, interpolate, useAnimatedStyle} from 'react-native-reanimated';
|
import Animated, {Extrapolate, interpolate, useAnimatedStyle} from 'react-native-reanimated';
|
||||||
|
|
||||||
import CompassIcon from '@components/compass_icon';
|
import CompassIcon from '@components/compass_icon';
|
||||||
import FormattedText from '@components/formatted_text';
|
import FormattedText from '@components/formatted_text';
|
||||||
import {ONBOARDING_CONTENT_MAX_WIDTH} from '@screens/onboarding/slide';
|
import {ONBOARDING_CONTENT_MAX_WIDTH} from '@screens/onboarding/slide';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
|
|
@ -19,24 +18,20 @@ type Props = {
|
||||||
scrollX: Animated.SharedValue<number>;
|
scrollX: Animated.SharedValue<number>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
const styles = StyleSheet.create({
|
||||||
button: {
|
button: {
|
||||||
marginTop: 5,
|
marginTop: 5,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
rowIcon: {
|
|
||||||
color: theme.buttonColor,
|
|
||||||
fontSize: 12,
|
|
||||||
marginLeft: 5,
|
|
||||||
marginTop: 4.5,
|
|
||||||
},
|
|
||||||
nextButtonText: {
|
nextButtonText: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
width: 120,
|
width: 120,
|
||||||
|
gap: 5,
|
||||||
},
|
},
|
||||||
footerButtonsContainer: {
|
footerButtonsContainer: {
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
|
@ -46,7 +41,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||||
width: '100%',
|
width: '100%',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
}));
|
});
|
||||||
|
|
||||||
const AnimatedButton = Animated.createAnimatedComponent(Pressable);
|
const AnimatedButton = Animated.createAnimatedComponent(Pressable);
|
||||||
const BUTTON_SIZE = 120;
|
const BUTTON_SIZE = 120;
|
||||||
|
|
@ -60,7 +55,6 @@ const FooterButtons = ({
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const {width} = useWindowDimensions();
|
const {width} = useWindowDimensions();
|
||||||
const buttonWidth = Math.min(width * 0.8, ONBOARDING_CONTENT_MAX_WIDTH);
|
const buttonWidth = Math.min(width * 0.8, ONBOARDING_CONTENT_MAX_WIDTH);
|
||||||
const styles = getStyleSheet(theme);
|
|
||||||
|
|
||||||
// keep in mind penultimate and ultimate slides to run buttons text/opacity/size animations
|
// keep in mind penultimate and ultimate slides to run buttons text/opacity/size animations
|
||||||
const penultimateSlide = lastSlideIndex - 1;
|
const penultimateSlide = lastSlideIndex - 1;
|
||||||
|
|
@ -114,6 +108,8 @@ const FooterButtons = ({
|
||||||
return {opacity: interpolatedScale};
|
return {opacity: interpolatedScale};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const textStyles = StyleSheet.flatten(buttonTextStyle(theme, 'lg', 'primary', 'default'));
|
||||||
|
|
||||||
const nextButtonText = (
|
const nextButtonText = (
|
||||||
<Animated.View style={[styles.nextButtonText, opacityNextTextStyle]}>
|
<Animated.View style={[styles.nextButtonText, opacityNextTextStyle]}>
|
||||||
<FormattedText
|
<FormattedText
|
||||||
|
|
@ -123,7 +119,8 @@ const FooterButtons = ({
|
||||||
/>
|
/>
|
||||||
<CompassIcon
|
<CompassIcon
|
||||||
name='arrow-forward-ios'
|
name='arrow-forward-ios'
|
||||||
style={styles.rowIcon}
|
size={12}
|
||||||
|
color={textStyles.color}
|
||||||
/>
|
/>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React, {useCallback, useEffect, useMemo, useState} from 'react';
|
import React, {useCallback, useEffect, useMemo, useState} from 'react';
|
||||||
|
import {useIntl} from 'react-intl';
|
||||||
import {Alert, Text, TouchableOpacity, View} from 'react-native';
|
import {Alert, Text, TouchableOpacity, View} from 'react-native';
|
||||||
import Animated from 'react-native-reanimated';
|
import Animated from 'react-native-reanimated';
|
||||||
import {type Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
|
import {type Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
|
||||||
|
|
@ -10,6 +11,7 @@ import {getPosts} from '@actions/local/post';
|
||||||
import {fetchChannelById, joinChannel, switchToChannelById} from '@actions/remote/channel';
|
import {fetchChannelById, joinChannel, switchToChannelById} from '@actions/remote/channel';
|
||||||
import {fetchPostById, fetchPostsAround, fetchPostThread} from '@actions/remote/post';
|
import {fetchPostById, fetchPostsAround, fetchPostThread} from '@actions/remote/post';
|
||||||
import {addCurrentUserToTeam, fetchTeamByName, removeCurrentUserFromTeam} from '@actions/remote/team';
|
import {addCurrentUserToTeam, fetchTeamByName, removeCurrentUserFromTeam} from '@actions/remote/team';
|
||||||
|
import Button from '@components/button';
|
||||||
import CompassIcon from '@components/compass_icon';
|
import CompassIcon from '@components/compass_icon';
|
||||||
import FormattedText from '@components/formatted_text';
|
import FormattedText from '@components/formatted_text';
|
||||||
import Loading from '@components/loading';
|
import Loading from '@components/loading';
|
||||||
|
|
@ -21,12 +23,11 @@ import {useTheme} from '@context/theme';
|
||||||
import DatabaseManager from '@database/manager';
|
import DatabaseManager from '@database/manager';
|
||||||
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
||||||
import {useIsTablet} from '@hooks/device';
|
import {useIsTablet} from '@hooks/device';
|
||||||
|
import {usePreventDoubleTap} from '@hooks/utils';
|
||||||
import SecurityManager from '@managers/security_manager';
|
import SecurityManager from '@managers/security_manager';
|
||||||
import {getChannelById, getMyChannel} from '@queries/servers/channel';
|
import {getChannelById, getMyChannel} from '@queries/servers/channel';
|
||||||
import {dismissModal} from '@screens/navigation';
|
import {dismissModal} from '@screens/navigation';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {closePermalink} from '@utils/permalink';
|
import {closePermalink} from '@utils/permalink';
|
||||||
import {preventDoubleTap} from '@utils/tap';
|
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {secureGetFromRecord} from '@utils/types';
|
import {secureGetFromRecord} from '@utils/types';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
@ -105,11 +106,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
flexDirection: 'row',
|
|
||||||
padding: 20,
|
padding: 20,
|
||||||
width: '100%',
|
|
||||||
borderBottomLeftRadius: 12,
|
borderBottomLeftRadius: 12,
|
||||||
borderBottomRightRadius: 12,
|
borderBottomRightRadius: 12,
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 1,
|
||||||
|
|
@ -139,6 +136,7 @@ function Permalink({
|
||||||
isTeamMember,
|
isTeamMember,
|
||||||
currentTeamId,
|
currentTeamId,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const intl = useIntl();
|
||||||
const [posts, setPosts] = useState<PostModel[]>([]);
|
const [posts, setPosts] = useState<PostModel[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
@ -273,17 +271,17 @@ function Permalink({
|
||||||
}
|
}
|
||||||
dismissModal({componentId: Screens.PERMALINK});
|
dismissModal({componentId: Screens.PERMALINK});
|
||||||
closePermalink();
|
closePermalink();
|
||||||
}, [error]);
|
}, [error?.joinedTeam, error?.teamId, serverUrl]);
|
||||||
|
|
||||||
useAndroidHardwareBackHandler(Screens.PERMALINK, handleClose);
|
useAndroidHardwareBackHandler(Screens.PERMALINK, handleClose);
|
||||||
|
|
||||||
const handlePress = useCallback(preventDoubleTap(() => {
|
const handlePress = usePreventDoubleTap(useCallback(() => {
|
||||||
if (channel) {
|
if (channel) {
|
||||||
switchToChannelById(serverUrl, channel.id, channel.teamId);
|
switchToChannelById(serverUrl, channel.id, channel.teamId);
|
||||||
}
|
}
|
||||||
}), [channel?.id, channel?.teamId]);
|
}, [channel, serverUrl]));
|
||||||
|
|
||||||
const handleJoin = useCallback(preventDoubleTap(async () => {
|
const handleJoin = usePreventDoubleTap(useCallback(async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(undefined);
|
setError(undefined);
|
||||||
if (error?.teamId && error.channelId) {
|
if (error?.teamId && error.channelId) {
|
||||||
|
|
@ -296,7 +294,7 @@ function Permalink({
|
||||||
}
|
}
|
||||||
setChannelId(error.channelId);
|
setChannelId(error.channelId);
|
||||||
}
|
}
|
||||||
}), [error, serverUrl]);
|
}, [error, serverUrl]));
|
||||||
|
|
||||||
let content;
|
let content;
|
||||||
if (loading) {
|
if (loading) {
|
||||||
|
|
@ -334,18 +332,13 @@ function Permalink({
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={style.footer}>
|
<View style={style.footer}>
|
||||||
<TouchableOpacity
|
<Button
|
||||||
style={[buttonBackgroundStyle(theme, 'lg', 'primary'), {width: '100%'}]}
|
size='lg'
|
||||||
|
text={intl.formatMessage({id: 'mobile.search.jump', defaultMessage: 'Jump to recent messages'})}
|
||||||
|
theme={theme}
|
||||||
onPress={handlePress}
|
onPress={handlePress}
|
||||||
testID='permalink.jump_to_recent_messages.button'
|
testID='permalink.jump_to_recent_messages.button'
|
||||||
>
|
/>
|
||||||
<FormattedText
|
|
||||||
testID='permalink.search.jump'
|
|
||||||
id='mobile.search.jump'
|
|
||||||
defaultMessage='Jump to recent messages'
|
|
||||||
style={buttonTextStyle(theme, 'lg', 'primary')}
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
</View>
|
||||||
</ExtraKeyboardProvider>
|
</ExtraKeyboardProvider>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,15 @@
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {Text, TouchableOpacity, View} from 'react-native';
|
import {Text, View} from 'react-native';
|
||||||
|
|
||||||
import FormattedText from '@components/formatted_text';
|
import Button from '@components/button';
|
||||||
import JoinPrivateChannel from '@components/illustrations/join_private_channel';
|
import JoinPrivateChannel from '@components/illustrations/join_private_channel';
|
||||||
import JoinPublicChannel from '@components/illustrations/join_public_channel';
|
import JoinPublicChannel from '@components/illustrations/join_public_channel';
|
||||||
import MessageNotViewable from '@components/illustrations/message_not_viewable';
|
import MessageNotViewable from '@components/illustrations/message_not_viewable';
|
||||||
import Markdown from '@components/markdown';
|
import Markdown from '@components/markdown';
|
||||||
import {Screens} from '@constants';
|
import {Screens} from '@constants';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown';
|
import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown';
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
@ -49,6 +48,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 1,
|
||||||
borderTopColor: changeOpacity(theme.centerChannelColor, 0.16),
|
borderTopColor: changeOpacity(theme.centerChannelColor, 0.16),
|
||||||
padding: 20,
|
padding: 20,
|
||||||
|
gap: 8,
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -63,9 +63,6 @@ function PermalinkError({
|
||||||
const style = getStyleSheet(theme);
|
const style = getStyleSheet(theme);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const buttonStylePrimary = buttonBackgroundStyle(theme, 'lg', 'primary');
|
|
||||||
const buttonTextStylePrimary = buttonTextStyle(theme, 'lg', 'primary');
|
|
||||||
|
|
||||||
if (error.notExist || error.unreachable) {
|
if (error.notExist || error.unreachable) {
|
||||||
const title = intl.formatMessage({id: 'permalink.error.access.title', defaultMessage: 'Message not viewable'});
|
const title = intl.formatMessage({id: 'permalink.error.access.title', defaultMessage: 'Message not viewable'});
|
||||||
const text = intl.formatMessage({id: 'permalink.error.access.text', defaultMessage: 'The message you are trying to view is in a channel you don’t have access to or has been deleted.'});
|
const text = intl.formatMessage({id: 'permalink.error.access.text', defaultMessage: 'The message you are trying to view is in a channel you don’t have access to or has been deleted.'});
|
||||||
|
|
@ -77,25 +74,17 @@ function PermalinkError({
|
||||||
<Text style={style.errorText}>{text}</Text>
|
<Text style={style.errorText}>{text}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={style.errorButtonContainer}>
|
<View style={style.errorButtonContainer}>
|
||||||
<TouchableOpacity
|
<Button
|
||||||
style={buttonStylePrimary}
|
size='lg'
|
||||||
|
text={intl.formatMessage({id: 'permalink.error.okay', defaultMessage: 'Okay'})}
|
||||||
|
theme={theme}
|
||||||
onPress={handleClose}
|
onPress={handleClose}
|
||||||
>
|
/>
|
||||||
<FormattedText
|
|
||||||
testID='permalink.error.okay'
|
|
||||||
id='permalink.error.okay'
|
|
||||||
defaultMessage='Okay'
|
|
||||||
style={buttonTextStylePrimary}
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const buttonStyleTertiary = buttonBackgroundStyle(theme, 'lg', 'tertiary');
|
|
||||||
const buttonTextStyleTertiary = buttonTextStyle(theme, 'lg', 'tertiary');
|
|
||||||
|
|
||||||
const isPrivate = error.privateChannel || error.privateTeam;
|
const isPrivate = error.privateChannel || error.privateTeam;
|
||||||
let image;
|
let image;
|
||||||
let title;
|
let title;
|
||||||
|
|
@ -143,23 +132,19 @@ function PermalinkError({
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={style.errorButtonContainer}>
|
<View style={style.errorButtonContainer}>
|
||||||
<TouchableOpacity
|
<Button
|
||||||
style={buttonStylePrimary}
|
size='lg'
|
||||||
|
text={button}
|
||||||
|
theme={theme}
|
||||||
onPress={handleJoin}
|
onPress={handleJoin}
|
||||||
>
|
/>
|
||||||
<Text style={buttonTextStylePrimary}>{button}</Text>
|
<Button
|
||||||
</TouchableOpacity>
|
size='lg'
|
||||||
<TouchableOpacity
|
emphasis='tertiary'
|
||||||
style={[buttonStyleTertiary, {marginTop: 8}]}
|
|
||||||
onPress={handleClose}
|
onPress={handleClose}
|
||||||
>
|
text={intl.formatMessage({id: 'permalink.error.cancel', defaultMessage: 'Cancel'})}
|
||||||
<FormattedText
|
theme={theme}
|
||||||
testID='permalink.error.cancel'
|
/>
|
||||||
id='permalink.error.cancel'
|
|
||||||
defaultMessage='Cancel'
|
|
||||||
style={buttonTextStyleTertiary}
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,10 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {StyleSheet, Text, View} from 'react-native';
|
import {Text, View} from 'react-native';
|
||||||
|
|
||||||
import Empty from '@components/illustrations/no_team';
|
import Empty from '@components/illustrations/no_team';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
||||||
|
|
@ -40,21 +39,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||||
marginTop: 12,
|
marginTop: 12,
|
||||||
...typography('Body', 200, 'Regular'),
|
...typography('Body', 200, 'Regular'),
|
||||||
},
|
},
|
||||||
buttonStyle: {
|
|
||||||
...StyleSheet.flatten(buttonBackgroundStyle(theme, 'lg', 'primary', 'default')),
|
|
||||||
flexDirection: 'row',
|
|
||||||
marginTop: 24,
|
|
||||||
},
|
|
||||||
buttonText: {
|
|
||||||
...StyleSheet.flatten(buttonTextStyle(theme, 'lg', 'primary', 'default')),
|
|
||||||
marginLeft: 8,
|
|
||||||
},
|
|
||||||
plusIcon: {
|
|
||||||
color: theme.sidebarText,
|
|
||||||
fontSize: 24,
|
|
||||||
lineHeight: 22,
|
|
||||||
},
|
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const NoTeams = () => {
|
const NoTeams = () => {
|
||||||
|
|
@ -73,7 +57,7 @@ const NoTeams = () => {
|
||||||
<Text style={styles.description}>
|
<Text style={styles.description}>
|
||||||
{intl.formatMessage({id: 'select_team.no_team.description', defaultMessage: 'To join a team, ask a team admin for an invite, or create your own team. You may also want to check your email inbox for an invitation.'})}
|
{intl.formatMessage({id: 'select_team.no_team.description', defaultMessage: 'To join a team, ask a team admin for an invite, or create your own team. You may also want to check your email inbox for an invitation.'})}
|
||||||
</Text>
|
</Text>
|
||||||
{/* {canCreateTeams && // TODO https://mattermost.atlassian.net/browse/MM-43622
|
{/* {canCreateTeams && // TODO https://mattermost.atlassian.net/browse/MM-43622 (Use Button component instead of touchable)
|
||||||
<TouchableWithFeedback
|
<TouchableWithFeedback
|
||||||
style={styles.buttonStyle}
|
style={styles.buttonStyle}
|
||||||
type={'opacity'}
|
type={'opacity'}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,14 @@
|
||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {Button} from '@rneui/base';
|
|
||||||
import React, {type RefObject, useCallback, useRef} from 'react';
|
import React, {type RefObject, useCallback, useRef} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {defineMessages, useIntl} from 'react-intl';
|
||||||
import {Keyboard, View} from 'react-native';
|
import {Keyboard, View} from 'react-native';
|
||||||
|
|
||||||
|
import Button from '@components/button';
|
||||||
import FloatingTextInput, {type FloatingTextInputRef} from '@components/floating_text_input_label';
|
import FloatingTextInput, {type FloatingTextInputRef} from '@components/floating_text_input_label';
|
||||||
import FormattedText from '@components/formatted_text';
|
import FormattedText from '@components/formatted_text';
|
||||||
import Loading from '@components/loading';
|
|
||||||
import {useAvoidKeyboard} from '@hooks/device';
|
import {useAvoidKeyboard} from '@hooks/device';
|
||||||
import {t} from '@i18n';
|
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
||||||
|
|
@ -52,22 +49,25 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||||
marginTop: 8,
|
marginTop: 8,
|
||||||
...typography('Body', 75, 'Regular'),
|
...typography('Body', 75, 'Regular'),
|
||||||
},
|
},
|
||||||
connectButton: {
|
connectButtonContainer: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
marginTop: 32,
|
marginTop: 32,
|
||||||
marginLeft: 20,
|
marginLeft: 20,
|
||||||
marginRight: 20,
|
marginRight: 20,
|
||||||
},
|
},
|
||||||
connectingIndicator: {
|
|
||||||
marginRight: 10,
|
|
||||||
},
|
|
||||||
loadingContainerStyle: {
|
|
||||||
marginRight: 10,
|
|
||||||
padding: 0,
|
|
||||||
top: -2,
|
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
connect: {
|
||||||
|
id: 'mobile.components.select_server_view.connect',
|
||||||
|
defaultMessage: 'Connect',
|
||||||
|
},
|
||||||
|
connecting: {
|
||||||
|
id: 'mobile.components.select_server_view.connecting',
|
||||||
|
defaultMessage: 'Connecting',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const ServerForm = ({
|
const ServerForm = ({
|
||||||
autoFocus = false,
|
autoFocus = false,
|
||||||
buttonDisabled,
|
buttonDisabled,
|
||||||
|
|
@ -99,25 +99,6 @@ const ServerForm = ({
|
||||||
displayNameRef.current?.focus();
|
displayNameRef.current?.focus();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const buttonType = buttonDisabled ? 'disabled' : 'default';
|
|
||||||
const styleButtonText = buttonTextStyle(theme, 'lg', 'primary', buttonType);
|
|
||||||
const styleButtonBackground = buttonBackgroundStyle(theme, 'lg', 'primary', buttonType);
|
|
||||||
|
|
||||||
let buttonID = t('mobile.components.select_server_view.connect');
|
|
||||||
let buttonText = 'Connect';
|
|
||||||
let buttonIcon;
|
|
||||||
|
|
||||||
if (connecting) {
|
|
||||||
buttonID = t('mobile.components.select_server_view.connecting');
|
|
||||||
buttonText = 'Connecting';
|
|
||||||
buttonIcon = (
|
|
||||||
<Loading
|
|
||||||
containerStyle={styles.loadingContainerStyle}
|
|
||||||
color={theme.buttonColor}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const connectButtonTestId = buttonDisabled ? 'server_form.connect.button.disabled' : 'server_form.connect.button';
|
const connectButtonTestId = buttonDisabled ? 'server_form.connect.button.disabled' : 'server_form.connect.button';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -175,21 +156,17 @@ const ServerForm = ({
|
||||||
testID={'server_form.display_help'}
|
testID={'server_form.display_help'}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<Button
|
<View style={styles.connectButtonContainer}>
|
||||||
containerStyle={styles.connectButton}
|
<Button
|
||||||
disabled={buttonDisabled}
|
disabled={buttonDisabled}
|
||||||
onPress={onConnect}
|
onPress={onConnect}
|
||||||
testID={connectButtonTestId}
|
testID={connectButtonTestId}
|
||||||
buttonStyle={styleButtonBackground}
|
size='lg'
|
||||||
disabledStyle={styleButtonBackground}
|
theme={theme}
|
||||||
>
|
text={formatMessage(connecting ? messages.connecting : messages.connect)}
|
||||||
{buttonIcon}
|
showLoader={connecting}
|
||||||
<FormattedText
|
|
||||||
defaultMessage={buttonText}
|
|
||||||
id={buttonID}
|
|
||||||
style={styleButtonText}
|
|
||||||
/>
|
/>
|
||||||
</Button>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -187,22 +187,13 @@ exports[`SendTestNotificationNotice should match snapshot 1`] = `
|
||||||
<Text
|
<Text
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
style={
|
style={
|
||||||
[
|
{
|
||||||
[
|
"color": "#ffffff",
|
||||||
[
|
"fontFamily": "OpenSans-SemiBold",
|
||||||
{
|
"fontSize": 14,
|
||||||
"fontFamily": "OpenSans-SemiBold",
|
"fontWeight": "600",
|
||||||
"fontSize": 14,
|
"lineHeight": 20,
|
||||||
"fontWeight": "600",
|
}
|
||||||
"lineHeight": 20,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"color": "#ffffff",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
undefined,
|
|
||||||
],
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Send a test notification
|
Send a test notification
|
||||||
|
|
@ -298,22 +289,13 @@ exports[`SendTestNotificationNotice should match snapshot 1`] = `
|
||||||
<Text
|
<Text
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
style={
|
style={
|
||||||
[
|
{
|
||||||
[
|
"color": "#1c58d9",
|
||||||
[
|
"fontFamily": "OpenSans-SemiBold",
|
||||||
{
|
"fontSize": 14,
|
||||||
"fontFamily": "OpenSans-SemiBold",
|
"fontWeight": "600",
|
||||||
"fontSize": 14,
|
"lineHeight": 20,
|
||||||
"fontWeight": "600",
|
}
|
||||||
"lineHeight": 20,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"color": "#1c58d9",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
undefined,
|
|
||||||
],
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Troubleshooting docs
|
Troubleshooting docs
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {Button} from '@rneui/base';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {useIntl} from 'react-intl';
|
||||||
import {Text, View} from 'react-native';
|
import {Text, View} from 'react-native';
|
||||||
|
|
||||||
|
import Button from '@components/button';
|
||||||
import FormattedText from '@components/formatted_text';
|
import FormattedText from '@components/formatted_text';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
||||||
|
|
@ -18,7 +18,7 @@ interface AuthErrorProps {
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||||
return {
|
return {
|
||||||
button: {
|
buttonContainer: {
|
||||||
marginTop: 25,
|
marginTop: 25,
|
||||||
},
|
},
|
||||||
errorText: {
|
errorText: {
|
||||||
|
|
@ -44,6 +44,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const AuthError = ({error, retry, theme}: AuthErrorProps) => {
|
const AuthError = ({error, retry, theme}: AuthErrorProps) => {
|
||||||
|
const intl = useIntl();
|
||||||
const style = getStyleSheet(theme);
|
const style = getStyleSheet(theme);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -57,17 +58,15 @@ const AuthError = ({error, retry, theme}: AuthErrorProps) => {
|
||||||
<Text style={style.errorText}>
|
<Text style={style.errorText}>
|
||||||
{`${error}.`}
|
{`${error}.`}
|
||||||
</Text>
|
</Text>
|
||||||
<Button
|
<View style={style.buttonContainer}>
|
||||||
buttonStyle={[style.button, buttonBackgroundStyle(theme, 'lg', 'primary', 'default')]}
|
<Button
|
||||||
testID='mobile.oauth.try_again'
|
testID='mobile.oauth.try_again'
|
||||||
onPress={retry}
|
onPress={retry}
|
||||||
>
|
size='lg'
|
||||||
<FormattedText
|
text={intl.formatMessage({id: 'mobile.oauth.try_again', defaultMessage: 'Try again'})}
|
||||||
id='mobile.oauth.try_again'
|
theme={theme}
|
||||||
defaultMessage='Try again'
|
|
||||||
style={buttonTextStyle(theme, 'lg', 'primary', 'default')}
|
|
||||||
/>
|
/>
|
||||||
</Button>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,17 @@
|
||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React, {useCallback, useMemo} from 'react';
|
import React, {useCallback} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {DeviceEventEmitter, StyleSheet, TouchableOpacity, View} from 'react-native';
|
import {DeviceEventEmitter, StyleSheet, View} from 'react-native';
|
||||||
|
|
||||||
import {createDirectChannel, switchToChannelById} from '@actions/remote/channel';
|
import {createDirectChannel, switchToChannelById} from '@actions/remote/channel';
|
||||||
import CompassIcon from '@components/compass_icon';
|
import Button from '@components/button';
|
||||||
import FormattedText from '@components/formatted_text';
|
|
||||||
import OptionBox, {OPTIONS_HEIGHT} from '@components/option_box';
|
import OptionBox, {OPTIONS_HEIGHT} from '@components/option_box';
|
||||||
import {Events, Screens} from '@constants';
|
import {Events, Screens} from '@constants';
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {dismissBottomSheet} from '@screens/navigation';
|
import {dismissBottomSheet} from '@screens/navigation';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
|
||||||
|
|
||||||
import type {AvailableScreens} from '@typings/screens/navigation';
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
|
|
@ -45,9 +43,7 @@ const styles = StyleSheet.create({
|
||||||
width: '100%',
|
width: '100%',
|
||||||
},
|
},
|
||||||
singleContainer: {
|
singleContainer: {
|
||||||
flexDirection: 'row',
|
|
||||||
marginBottom: 20,
|
marginBottom: 20,
|
||||||
width: '100%',
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -56,10 +52,6 @@ const UserProfileOptions = ({location, type, userId, username}: Props) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const serverUrl = useServerUrl();
|
const serverUrl = useServerUrl();
|
||||||
|
|
||||||
const buttonStyle = useMemo(() => {
|
|
||||||
return buttonBackgroundStyle(theme, 'lg', 'tertiary', 'default');
|
|
||||||
}, [theme]);
|
|
||||||
|
|
||||||
const mentionUser = useCallback(async () => {
|
const mentionUser = useCallback(async () => {
|
||||||
await dismissBottomSheet(Screens.USER_PROFILE);
|
await dismissBottomSheet(Screens.USER_PROFILE);
|
||||||
DeviceEventEmitter.emit(Events.SEND_TO_POST_DRAFT, {location, text: `@${username}`});
|
DeviceEventEmitter.emit(Events.SEND_TO_POST_DRAFT, {location, text: `@${username}`});
|
||||||
|
|
@ -80,7 +72,7 @@ const UserProfileOptions = ({location, type, userId, username}: Props) => {
|
||||||
iconName='send'
|
iconName='send'
|
||||||
onPress={openChannel}
|
onPress={openChannel}
|
||||||
testID='user_profile_options.send_message.option'
|
testID='user_profile_options.send_message.option'
|
||||||
text={intl.formatMessage({id: 'channel_info.send_mesasge', defaultMessage: 'Send message'})}
|
text={intl.formatMessage({id: 'channel_info.send_a_mesasge', defaultMessage: 'Send message'})}
|
||||||
/>
|
/>
|
||||||
<View style={styles.divider}/>
|
<View style={styles.divider}/>
|
||||||
<OptionBox
|
<OptionBox
|
||||||
|
|
@ -95,22 +87,15 @@ const UserProfileOptions = ({location, type, userId, username}: Props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.singleContainer}>
|
<View style={styles.singleContainer}>
|
||||||
<TouchableOpacity
|
<Button
|
||||||
style={[buttonStyle, styles.singleButton]}
|
|
||||||
onPress={openChannel}
|
onPress={openChannel}
|
||||||
testID='user_profile_options.send_message.option'
|
testID='user_profile_options.send_message.option'
|
||||||
>
|
size='lg'
|
||||||
<CompassIcon
|
emphasis='tertiary'
|
||||||
color={theme.buttonBg}
|
theme={theme}
|
||||||
name='send'
|
text={intl.formatMessage({id: 'channel_info.send_mesasge', defaultMessage: 'Send message'})}
|
||||||
style={styles.icon}
|
iconName='send'
|
||||||
/>
|
/>
|
||||||
<FormattedText
|
|
||||||
id='channel_info.send_a_mesasge'
|
|
||||||
defaultMessage='Send a message'
|
|
||||||
style={[buttonTextStyle(theme, 'lg', 'tertiary', 'default'), {marginLeft: 8}]}
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -158,11 +158,17 @@ const UserProfile = ({
|
||||||
'90%',
|
'90%',
|
||||||
];
|
];
|
||||||
}, [
|
}, [
|
||||||
headerText, showUserProfileOptions, showCustomStatus,
|
headerText,
|
||||||
showNickname, showPosition, showLocalTime,
|
showUserProfileOptions,
|
||||||
manageMode, bottom, showOptions,
|
showCustomStatus,
|
||||||
canChangeMemberRoles, canManageAndRemoveMembers,
|
showNickname,
|
||||||
enableCustomAttributes,
|
showPosition,
|
||||||
|
showLocalTime,
|
||||||
|
manageMode,
|
||||||
|
bottom,
|
||||||
|
showOptions,
|
||||||
|
canChangeMemberRoles,
|
||||||
|
canManageAndRemoveMembers,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -464,6 +464,7 @@
|
||||||
"load_channels_error.title": "Couldn't load {teamDisplayName}",
|
"load_channels_error.title": "Couldn't load {teamDisplayName}",
|
||||||
"load_teams_error.message": "There was a problem loading content for this server.",
|
"load_teams_error.message": "There was a problem loading content for this server.",
|
||||||
"load_teams_error.title": "Couldn't load {serverName}",
|
"load_teams_error.title": "Couldn't load {serverName}",
|
||||||
|
"loading_error.retry": "Retry",
|
||||||
"login_mfa.enterToken": "To complete the sign in process, please enter the code from your mobile device's authenticator app.",
|
"login_mfa.enterToken": "To complete the sign in process, please enter the code from your mobile device's authenticator app.",
|
||||||
"login_mfa.token": "Enter MFA Token",
|
"login_mfa.token": "Enter MFA Token",
|
||||||
"login_mfa.tokenReq": "Please enter an MFA token",
|
"login_mfa.tokenReq": "Please enter an MFA token",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue