diff --git a/app/components/floating_text_input_label/index.tsx b/app/components/floating_text_input_label/index.tsx index 89ccc9ef7..5208dd182 100644 --- a/app/components/floating_text_input_label/index.tsx +++ b/app/components/floating_text_input_label/index.tsx @@ -5,12 +5,14 @@ import {debounce} from 'lodash'; import React, {useState, useEffect, useRef, useImperativeHandle, forwardRef, useMemo, useCallback} from 'react'; -import {GestureResponderEvent, LayoutChangeEvent, NativeSyntheticEvent, Platform, StyleProp, TargetedEvent, Text, TextInput, TextInputFocusEventData, TextInputProps, TextStyle, TouchableWithoutFeedback, View, ViewStyle} from 'react-native'; +import {GestureResponderEvent, LayoutChangeEvent, NativeSyntheticEvent, StyleProp, TargetedEvent, Text, TextInput, TextInputFocusEventData, TextInputProps, TextStyle, TouchableWithoutFeedback, View, ViewStyle} from 'react-native'; import Animated, {useAnimatedStyle, withTiming, Easing} from 'react-native-reanimated'; import CompassIcon from '@components/compass_icon'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {getLabelPositions, onExecution} from './utils'; + const DEFAULT_INPUT_HEIGHT = 48; const BORDER_DEFAULT_WIDTH = 1; const BORDER_FOCUSED_WIDTH = 2; @@ -36,6 +38,9 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ lineHeight: 16, paddingVertical: 5, }, + input: { + flex: 1, + }, label: { position: 'absolute', color: changeOpacity(theme.centerChannelColor, 0.64), @@ -52,6 +57,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ fontSize: 10, }, textInput: { + flexDirection: 'row', fontFamily: 'OpenSans', fontSize: 16, paddingTop: 12, @@ -65,29 +71,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ }, })); -const onExecution = ( - e: NativeSyntheticEvent, - innerFunc?: () => void, - outerFunc?: ((event: NativeSyntheticEvent) => void), -) => { - innerFunc?.(); - outerFunc?.(e); -}; - -const getLabelPositions = (style: TextStyle, labelStyle: TextStyle, smallLabelStyle: TextStyle) => { - const top: number = style.paddingTop as number || 0; - const bottom: number = style.paddingBottom as number || 0; - - const height: number = (style.height as number || (top + bottom) || style.padding as number) || 0; - const textInputFontSize = style.fontSize || 13; - const labelFontSize = labelStyle.fontSize || 16; - const smallLabelFontSize = smallLabelStyle.fontSize || 10; - const fontSizeDiff = textInputFontSize - labelFontSize; - const unfocused = (height * 0.5) + (fontSizeDiff * (Platform.OS === 'android' ? 0.5 : 0.6)); - const focused = -(labelFontSize + smallLabelFontSize) * 0.25; - return [unfocused, focused]; -}; - export type FloatingTextInputRef = { blur: () => void; focus: () => void; @@ -97,6 +80,7 @@ export type FloatingTextInputRef = { type FloatingTextInputProps = TextInputProps & { containerStyle?: ViewStyle; editable?: boolean; + endAdornment?: React.ReactNode; error?: string; errorIcon?: string; isKeyboardInput?: boolean; @@ -120,6 +104,7 @@ const FloatingTextInput = forwardRef { + const combinedTextInputContainerStyle = useMemo(() => { const res: StyleProp = [styles.textInput]; if (!editable) { res.push(styles.readOnly); @@ -253,21 +238,24 @@ const FloatingTextInput = forwardRef {label} - + + + {endAdornment} + {Boolean(error) && ( {showErrorIcon && errorIcon && diff --git a/app/components/floating_text_input_label/utils.ts b/app/components/floating_text_input_label/utils.ts new file mode 100644 index 000000000..eb6973014 --- /dev/null +++ b/app/components/floating_text_input_label/utils.ts @@ -0,0 +1,28 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {NativeSyntheticEvent, Platform, TargetedEvent, TextInputFocusEventData, TextStyle} from 'react-native'; + +export const onExecution = ( + e: NativeSyntheticEvent, + innerFunc?: () => void, + outerFunc?: ((event: NativeSyntheticEvent) => void), +) => { + innerFunc?.(); + outerFunc?.(e); +}; + +export const getLabelPositions = (style: TextStyle, labelStyle: TextStyle, smallLabelStyle: TextStyle) => { + const top: number = style.paddingTop as number || 0; + const bottom: number = style.paddingBottom as number || 0; + + const height: number = (style.height as number || (top + bottom) || style.padding as number) || 0; + const textInputFontSize = style.fontSize || 13; + const labelFontSize = labelStyle.fontSize || 16; + const smallLabelFontSize = smallLabelStyle.fontSize || 10; + const fontSizeDiff = textInputFontSize - labelFontSize; + const unfocused = (height * 0.5) + (fontSizeDiff * (Platform.OS === 'android' ? 0.5 : 0.6)); + const focused = -(labelFontSize + smallLabelFontSize) * 0.25; + return [unfocused, focused]; +}; + diff --git a/app/screens/login/form.tsx b/app/screens/login/form.tsx index 7d6d7b595..38f62d114 100644 --- a/app/screens/login/form.tsx +++ b/app/screens/login/form.tsx @@ -4,11 +4,12 @@ import {useManagedConfig} from '@mattermost/react-native-emm'; import React, {MutableRefObject, useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {useIntl} from 'react-intl'; -import {Keyboard, Platform, TextInput, useWindowDimensions, View} from 'react-native'; +import {Keyboard, Platform, TextInput, TouchableOpacity, useWindowDimensions, View} from 'react-native'; import Button from 'react-native-button'; import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view'; import {login} from '@actions/remote/session'; +import CompassIcon from '@app/components/compass_icon'; import ClientError from '@client/rest/error'; import FloatingTextInput from '@components/floating_text_input_label'; import FormattedText from '@components/formatted_text'; @@ -20,7 +21,7 @@ import {goToScreen, loginAnimationOptions, resetToHome, resetToTeams} from '@scr import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles'; import {isServerError} from '@utils/errors'; import {preventDoubleTap} from '@utils/tap'; -import {makeStyleSheetFromTheme} from '@utils/theme'; +import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import type {LaunchProps} from '@typings/launch'; @@ -34,6 +35,7 @@ interface LoginProps extends LaunchProps { } export const MFA_EXPECTED_ERRORS = ['mfa.validate_token.authenticate.app_error', 'ent.mfa.validate_token.authenticate.app_error']; +const hitSlop = {top: 8, right: 8, bottom: 8, left: 8}; const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ container: { @@ -69,6 +71,9 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ loginButton: { marginTop: 25, }, + endAdornment: { + top: 2, + }, })); const LoginForm = ({config, extra, keyboardAwareRef, numberSSOs, serverDisplayName, launchError, launchType, license, serverUrl, theme}: LoginProps) => { @@ -84,6 +89,7 @@ const LoginForm = ({config, extra, keyboardAwareRef, numberSSOs, serverDisplayNa const [loginId, setLoginId] = useState(''); const [password, setPassword] = useState(''); const [buttonDisabled, setButtonDisabled] = useState(true); + const [isPasswordVisible, setIsPasswordVisible] = useState(false); const emailEnabled = config.EnableSignInWithEmail === 'true'; const usernameEnabled = config.EnableSignInWithUsername === 'true'; const ldapEnabled = license.IsLicensed === 'true' && config.EnableLdap === 'true' && license.LDAP === 'true'; @@ -266,6 +272,10 @@ const LoginForm = ({config, extra, keyboardAwareRef, numberSSOs, serverDisplayNa goToScreen(FORGOT_PASSWORD, '', passProps, loginAnimationOptions()); }, [theme]); + const togglePasswordVisiblity = useCallback(() => { + setIsPasswordVisible((prevState) => !prevState); + }, []); + // useEffect to set userName for EMM useEffect(() => { const setEmmUsernameIfAvailable = async () => { @@ -324,6 +334,20 @@ const LoginForm = ({config, extra, keyboardAwareRef, numberSSOs, serverDisplayNa ); }, [buttonDisabled, loginId, password, isLoading, theme]); + const endAdornment = ( + + + + ); + return ( {(emailEnabled || usernameEnabled) && ( diff --git a/app/screens/settings/notification_mention/mention_settings.tsx b/app/screens/settings/notification_mention/mention_settings.tsx index 450ac8296..03b7316d2 100644 --- a/app/screens/settings/notification_mention/mention_settings.tsx +++ b/app/screens/settings/notification_mention/mention_settings.tsx @@ -42,6 +42,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { alignSelf: 'center', paddingHorizontal: 18.5, }, + labelTextStyle: {left: 32}, keywordLabelStyle: { paddingHorizontal: 18.5, marginTop: 4, @@ -201,7 +202,7 @@ const MentionSettings = ({componentId, currentUser, isCRTEnabled}: MentionSectio blurOnSubmit={true} containerStyle={styles.containerStyle} keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} - label={intl.formatMessage({id: 'notification_settings.mentions.keywords', defaultMessage: 'Enter other keywords'})} + label={intl.formatMessage({id: 'notification_settings.mentions.keywords', defaultMessage: 'Keywords'})} multiline={true} onChangeText={onChangeText} placeholder={intl.formatMessage({id: 'notification_settings.mentions..keywordsDescription', defaultMessage: 'Other words that trigger a mention'})} @@ -213,6 +214,7 @@ const MentionSettings = ({componentId, currentUser, isCRTEnabled}: MentionSectio theme={theme} underlineColorAndroid='transparent' value={mentionKeywords} + labelTextStyle={styles.labelTextStyle} />