diff --git a/app/components/common_post_options/base_option/index.tsx b/app/components/common_post_options/base_option/index.tsx index c5d06f4266..df85900dba 100644 --- a/app/components/common_post_options/base_option/index.tsx +++ b/app/components/common_post_options/base_option/index.tsx @@ -1,64 +1,38 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useMemo} from 'react'; +import React from 'react'; +import {useIntl} from 'react-intl'; -import FormattedText from '@components/formatted_text'; -import MenuItem from '@components/menu_item'; -import {useTheme} from '@context/theme'; -import {makeStyleSheetFromTheme} from '@utils/theme'; -import {typography} from '@utils/typography'; - -const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ - destructive: { - color: theme.dndIndicator, - }, - label: { - color: theme.centerChannelColor, - ...typography('Body', 200), - }, - iconContainerStyle: { - marginLeft: 0, - }, -})); +import OptionItem from '@components/option_item'; type BaseOptionType = { - i18nId: string; defaultMessage: string; + i18nId: string; iconName: string; + isDestructive?: boolean; onPress: () => void; testID: string; - isDestructive?: boolean; } const BaseOption = ({ - i18nId, defaultMessage, + i18nId, iconName, + isDestructive = false, onPress, testID, - isDestructive = false, }: BaseOptionType) => { - const theme = useTheme(); - const styles = getStyleSheet(theme); - - const label = useMemo(() => ( - - ), [i18nId, defaultMessage, theme]); + const intl = useIntl(); return ( - ); }; diff --git a/app/components/menu_item/__snapshots__/index.test.tsx.snap b/app/components/menu_item/__snapshots__/index.test.tsx.snap deleted file mode 100644 index 6fde1aafa6..0000000000 --- a/app/components/menu_item/__snapshots__/index.test.tsx.snap +++ /dev/null @@ -1,235 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`DrawerItem should match snapshot 1`] = ` - - - - - - - - - - default message - - - - - - - -`; - -exports[`DrawerItem should match snapshot without separator and centered false 1`] = ` - - - - - - - - - - default message - - - - - - -`; diff --git a/app/components/menu_item/index.test.tsx b/app/components/menu_item/index.test.tsx deleted file mode 100644 index 7795dd1a18..0000000000 --- a/app/components/menu_item/index.test.tsx +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React from 'react'; - -import {Preferences} from '@constants'; -import {renderWithIntl} from '@test/intl-test-helper'; - -import MenuItem from '.'; - -describe('DrawerItem', () => { - const baseProps = { - onPress: () => null, - testID: 'test-id', - centered: true, - defaultMessage: 'default message', - i18nId: 'i18-id', - iconName: 'icon-name', - isDestructor: true, - separator: true, - theme: Preferences.THEMES.denim, - }; - - test('should match snapshot', () => { - const wrapper = renderWithIntl(); - - expect(wrapper.toJSON()).toMatchSnapshot(); - }); - - test('should match snapshot without separator and centered false', () => { - const props = { - ...baseProps, - centered: false, - separator: false, - }; - const wrapper = renderWithIntl( - , - ); - - expect(wrapper.toJSON()).toMatchSnapshot(); - }); -}); diff --git a/app/components/menu_item/index.tsx b/app/components/menu_item/index.tsx deleted file mode 100644 index 345ba9ba7a..0000000000 --- a/app/components/menu_item/index.tsx +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React, {ReactNode} from 'react'; -import {Platform, StyleProp, TextStyle, View, ViewStyle} from 'react-native'; - -import CompassIcon from '@components/compass_icon'; -import FormattedText from '@components/formatted_text'; -import TouchableWithFeedback from '@components/touchable_with_feedback'; -import {useTheme} from '@context/theme'; -import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; - -export const ITEM_HEIGHT = 50; -const getStyleSheet = makeStyleSheetFromTheme((theme) => { - return { - container: { - flexDirection: 'row', - minHeight: ITEM_HEIGHT, - }, - iconContainer: { - width: 45, - height: ITEM_HEIGHT, - alignItems: 'center', - justifyContent: 'center', - marginLeft: 5, - }, - icon: { - color: changeOpacity(theme.centerChannelColor, 0.64), - fontSize: 24, - }, - labelContainer: { - flex: 1, - justifyContent: 'center', - paddingVertical: 14, - }, - centerLabel: { - textAlign: 'center', - textAlignVertical: 'center', - }, - label: { - color: changeOpacity(theme.centerChannelColor, 0.5), - fontSize: 17, - textAlignVertical: 'center', - includeFontPadding: false, - }, - divider: { - backgroundColor: changeOpacity(theme.centerChannelColor, 0.12), - height: 1, - }, - chevron: { - alignSelf: 'center', - color: changeOpacity(theme.centerChannelColor, 0.64), - fontSize: 24, - marginRight: 8, - }, - linkContainer: { - marginHorizontal: 15, - color: theme.linkColor, - }, - mainContainer: { - flexDirection: 'column', - }, - }; -}); - -export type MenuItemProps = { - centered?: boolean; - chevronStyle?: StyleProp; - containerStyle?: StyleProp; - defaultMessage?: string; - i18nId?: string; - iconContainerStyle?: StyleProp; - iconName?: string; - isDestructor?: boolean; - isLink?: boolean; - labelComponent?: ReactNode; - labelStyle?: StyleProp; - leftComponent?: ReactNode; - messageValues?: Record; - onPress: () => void; - rightComponent?: ReactNode; - separator?: boolean; - separatorStyle?: StyleProp; - showArrow?: boolean; - testID: string; -}; -const MenuItem = ({ - centered, - chevronStyle, - containerStyle, - defaultMessage = '', - i18nId, - iconContainerStyle, - iconName, - isDestructor = false, - isLink = false, - labelComponent, - labelStyle, - leftComponent, - messageValues, - onPress, - rightComponent, - separator = true, - separatorStyle, - showArrow = false, - testID, -}: MenuItemProps) => { - const theme = useTheme(); - const style = getStyleSheet(theme); - - let icon; - if (leftComponent) { - icon = leftComponent; - } else if (iconName) { - icon = ( - - ); - } - - let label; - if (labelComponent) { - label = labelComponent; - } else if (i18nId) { - label = ( - - ); - } - - return ( - - - - {icon && ( - - {icon} - - )} - - {label} - - {rightComponent} - {Boolean(showArrow) && ( - - )} - - {Boolean(separator) && ()} - - - ); -}; - -export default MenuItem; diff --git a/app/components/option_item/index.tsx b/app/components/option_item/index.tsx index 36c0d3095c..3daa260e21 100644 --- a/app/components/option_item/index.tsx +++ b/app/components/option_item/index.tsx @@ -98,6 +98,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { export type OptionItemProps = { action?: (React.Dispatch>)|((value: string | boolean) => void); + arrowStyle?: StyleProp; containerStyle?: StyleProp; description?: string; destructive?: boolean; @@ -117,6 +118,7 @@ export type OptionItemProps = { const OptionItem = ({ action, + arrowStyle, containerStyle, description, destructive, @@ -197,6 +199,7 @@ const OptionItem = ({ color={changeOpacity(theme.centerChannelColor, 0.32)} name='chevron-right' size={24} + style={arrowStyle} /> ); } else if (type === OptionType.REMOVE) { @@ -239,14 +242,14 @@ const OptionItem = ({ {type === OptionType.RADIO && radioComponent} {label} {Boolean(description) && {description} diff --git a/app/components/status_label/index.tsx b/app/components/status_label/index.tsx index 8cc7e0c300..9d8015b131 100644 --- a/app/components/status_label/index.tsx +++ b/app/components/status_label/index.tsx @@ -2,24 +2,25 @@ // See LICENSE.txt for license information. import React from 'react'; -import {TextStyle} from 'react-native'; +import {StyleProp, TextStyle} from 'react-native'; import FormattedText from '@components/formatted_text'; import {General} from '@constants'; import {useTheme} from '@context/theme'; import {t} from '@i18n'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; type StatusLabelProps = { status?: string; - labelStyle?: TextStyle; + labelStyle?: StyleProp; } const getStyleSheet = makeStyleSheetFromTheme((theme) => { return { label: { color: changeOpacity(theme.centerChannelColor, 0.5), - fontSize: 17, + ...typography('Body', 200), textAlignVertical: 'center', includeFontPadding: false, }, diff --git a/app/database/operator/base_data_operator/index.ts b/app/database/operator/base_data_operator/index.ts index f9a59d2c58..631cf60e6d 100644 --- a/app/database/operator/base_data_operator/index.ts +++ b/app/database/operator/base_data_operator/index.ts @@ -93,8 +93,6 @@ export default class BaseDataOperator { // We found a record in the database that matches this element; hence, we'll proceed for an UPDATE operation if (existingRecord) { - // const existingRecord = createOrUpdateRaws[findIndex]; - // Some raw value has an update_at field. We'll proceed to update only if the update_at value is different from the record's value in database const updateRecords = getValidRecordsForUpdate({ tableName, @@ -125,8 +123,7 @@ export default class BaseDataOperator { * @param {RawValue[]} prepareRecord.createRaws * @param {RawValue[]} prepareRecord.updateRaws * @param {Model[]} prepareRecord.deleteRaws - * @param {(TransformerArgs) => Promise;} prepareRecord.composer - * @throws {DataOperatorException} + * @param {(TransformerArgs) => Promise;} transformer * @returns {Promise} */ prepareRecords = async ({tableName, createRaws, deleteRaws, updateRaws, transformer}: OperationArgs): Promise => { @@ -184,7 +181,6 @@ export default class BaseDataOperator { * batchRecords: Accepts an instance of Database (either Default or Server) and an array of * prepareCreate/prepareUpdate 'models' and executes the actions on the database. * @param {Array} models - * @throws {DataOperatorException} * @returns {Promise} */ async batchRecords(models: Model[]): Promise { diff --git a/app/database/operator/server_data_operator/handlers/group.ts b/app/database/operator/server_data_operator/handlers/group.ts index 6ceab3d804..0a64dd2e7f 100644 --- a/app/database/operator/server_data_operator/handlers/group.ts +++ b/app/database/operator/server_data_operator/handlers/group.ts @@ -28,7 +28,6 @@ const GroupHandler = (superclass: any) => class extends superclass implements Gr * handleGroups: Handler responsible for the Create/Update operations occurring on the Group table from the 'Server' schema * * @param {HandleGroupArgs} - * @throws DataOperatorException * @returns {Promise} */ handleGroups = async ({groups, prepareRecordsOnly = true}: HandleGroupArgs): Promise => { @@ -111,7 +110,6 @@ const GroupHandler = (superclass: any) => class extends superclass implements Gr * handleGroupMembershipsForMember: Handler responsible for the Create/Update operations occurring on the GroupMembership table from the 'Server' schema * * @param {HandleGroupMembershipForMemberArgs} - * @throws DataOperatorException * @returns {Promise} */ handleGroupMembershipsForMember = async ({userId, groups, prepareRecordsOnly = true}: HandleGroupMembershipForMemberArgs): Promise => { @@ -169,7 +167,6 @@ const GroupHandler = (superclass: any) => class extends superclass implements Gr * handleGroupTeamsForTeam: Handler responsible for the Create/Update operations occurring on the GroupTeam table from the 'Server' schema * * @param {HandleGroupTeamsForTeamArgs} - * @throws DataOperatorException * @returns {Promise} */ handleGroupTeamsForTeam = async ({teamId, groups, prepareRecordsOnly = true}: HandleGroupTeamsForTeamArgs): Promise => { diff --git a/app/screens/about/server_version.tsx b/app/screens/about/server_version.tsx deleted file mode 100644 index faf0e67290..0000000000 --- a/app/screens/about/server_version.tsx +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React from 'react'; - -import FormattedText from '@components/formatted_text'; -import {useTheme} from '@context/theme'; -import {t} from '@i18n'; -import {makeStyleSheetFromTheme} from '@utils/theme'; - -type ServerVersionProps = { - config: ClientConfig; -} - -const ServerVersion = ({config}: ServerVersionProps) => { - const buildNumber = config.BuildNumber; - const version = config.Version; - const theme = useTheme(); - const style = getStyleSheet(theme); - - let id = t('mobile.about.serverVersion'); - let defaultMessage = 'Server Version: {version} (Build {number})'; - let values: {version: string; number?: string} = { - version, - number: buildNumber, - }; - - if (buildNumber === version) { - id = t('mobile.about.serverVersionNoBuild'); - defaultMessage = 'Server Version: {version}'; - values = { - version, - number: undefined, - }; - } - return ( - - ); -}; - -const getStyleSheet = makeStyleSheetFromTheme((theme) => { - return { - info: { - color: theme.centerChannelColor, - fontSize: 16, - lineHeight: 19, - }, - }; -}); - -export default ServerVersion; diff --git a/app/screens/home/account/components/options/custom_status/custom_label.tsx b/app/screens/home/account/components/options/custom_status/custom_label.tsx index a430c85e4a..4ea11bc4e8 100644 --- a/app/screens/home/account/components/options/custom_status/custom_label.tsx +++ b/app/screens/home/account/components/options/custom_status/custom_label.tsx @@ -8,6 +8,7 @@ import {View} from 'react-native'; import ClearButton from '@components/custom_status/clear_button'; import CustomStatusExpiry from '@components/custom_status/custom_status_expiry'; import FormattedText from '@components/formatted_text'; +import {useTheme} from '@context/theme'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import CustomStatusText from './custom_status_text'; @@ -16,9 +17,8 @@ type CustomLabelProps = { customStatus: UserCustomStatus; isCustomStatusExpirySupported: boolean; isStatusSet: boolean; - showRetryMessage: boolean; - theme: Theme; onClearCustomStatus: () => void; + showRetryMessage: boolean; }; const getStyleSheet = makeStyleSheetFromTheme((theme) => { @@ -30,6 +30,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { }, customStatusTextContainer: { width: '70%', + marginLeft: 16, }, customStatusExpiryText: { paddingTop: 3, @@ -43,14 +44,14 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { }; }); -const CustomLabel = ({customStatus, isCustomStatusExpirySupported, isStatusSet, onClearCustomStatus, showRetryMessage, theme}: CustomLabelProps) => { - const style = getStyleSheet(theme); +const CustomLabel = ({customStatus, isCustomStatusExpirySupported, isStatusSet, onClearCustomStatus, showRetryMessage}: CustomLabelProps) => { + const theme = useTheme(); + const styles = getStyleSheet(theme); return ( <> - + @@ -58,7 +59,7 @@ const CustomLabel = ({customStatus, isCustomStatusExpirySupported, isStatusSet, )} {isStatusSet && ( - + { @@ -22,7 +22,8 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { }; }); -const CustomStatusEmoji = ({emoji, isStatusSet, theme}: CustomStatusEmojiProps) => { +const CustomStatusEmoji = ({emoji, isStatusSet}: CustomStatusEmojiProps) => { + const theme = useTheme(); const styles = getStyleSheet(theme); return ( diff --git a/app/screens/home/account/components/options/custom_status/custom_status_text.tsx b/app/screens/home/account/components/options/custom_status/custom_status_text.tsx index 35de980244..8ffddffe0f 100644 --- a/app/screens/home/account/components/options/custom_status/custom_status_text.tsx +++ b/app/screens/home/account/components/options/custom_status/custom_status_text.tsx @@ -5,27 +5,33 @@ import React from 'react'; import CustomText from '@components/custom_status/custom_status_text'; import FormattedText from '@components/formatted_text'; +import {useTheme} from '@context/theme'; import {makeStyleSheetFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; type CustomStatusTextProps = { customStatus?: UserCustomStatus; isStatusSet: boolean; - theme: Theme; }; const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ text: { color: theme.centerChannelColor, + ...typography('Body', 200), }, })); -const CustomStatusText = ({isStatusSet, customStatus, theme}: CustomStatusTextProps) => { +const CustomStatusText = ({isStatusSet, customStatus}: CustomStatusTextProps) => { + const theme = useTheme(); + const styles = getStyleSheet(theme); + let text: React.ReactNode | string; text = ( ); @@ -33,7 +39,6 @@ const CustomStatusText = ({isStatusSet, customStatus, theme}: CustomStatusTextPr text = customStatus.text; } - const styles = getStyleSheet(theme); return ( { + return { + label: { + color: theme.centerChannelColor, + ...typography('Body', 200), + textAlignVertical: 'center', + includeFontPadding: false, + }, + body: { + flexDirection: 'row', + marginVertical: 18, + }, + }; +}); + type CustomStatusProps = { isCustomStatusExpirySupported: boolean; isTablet: boolean; @@ -35,6 +51,7 @@ const CustomStatus = ({isCustomStatusExpirySupported, isTablet, currentUser}: Cu const customStatus = getUserCustomStatus(currentUser); const isCustomStatusExpired = checkCustomStatusIsExpired(currentUser); const isStatusSet = !isCustomStatusExpired && (customStatus?.text || customStatus?.emoji); + const styles = getStyleSheet(theme); useEffect(() => { const onSetCustomStatusError = () => { @@ -68,27 +85,23 @@ const CustomStatus = ({isCustomStatusExpirySupported, isTablet, currentUser}: Cu }), [isTablet]); return ( - + + - } - leftComponent={ - } - separator={false} - onPress={goToCustomStatusScreen} - /> + + ); }; diff --git a/app/screens/home/account/components/options/index.tsx b/app/screens/home/account/components/options/index.tsx index 587b38952a..f910870b65 100644 --- a/app/screens/home/account/components/options/index.tsx +++ b/app/screens/home/account/components/options/index.tsx @@ -36,13 +36,12 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { divider: { backgroundColor: changeOpacity(theme.centerChannelColor, 0.2), height: 1, - marginHorizontal: 15, + width: '90%', + alignSelf: 'center', + marginVertical: 8, }, - menuLabel: { - color: theme.centerChannelColor, - fontSize: 16, - lineHeight: 24, - fontFamily: 'OpenSans', + group: { + paddingLeft: 16, }, }; }); @@ -64,37 +63,29 @@ const AccountOptions = ({user, enableCustomUserStatuses, isCustomStatusExpirySup }} > - - {enableCustomUserStatuses && - } + + + {enableCustomUserStatuses && + } + - - {/* */} - + + + + - + + + ); diff --git a/app/screens/home/account/components/options/logout/index.tsx b/app/screens/home/account/components/options/logout/index.tsx index 184b3f0da2..29a2c4b8e1 100644 --- a/app/screens/home/account/components/options/logout/index.tsx +++ b/app/screens/home/account/components/options/logout/index.tsx @@ -3,75 +3,48 @@ import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; -import {TextStyle, View} from 'react-native'; import {logout} from '@actions/remote/session'; -import FormattedText from '@components/formatted_text'; -import MenuItem from '@components/menu_item'; +import OptionItem from '@components/option_item'; import {useServerDisplayName, useServerUrl} from '@context/server'; +import {useTheme} from '@context/theme'; import {alertServerLogout} from '@utils/server'; import {preventDoubleTap} from '@utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; -type Props = { - style: TextStyle; - theme: Theme; -} +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + desc: { + color: changeOpacity(theme.centerChannelColor, 0.64), + ...typography('Body', 75), + }, + }; +}); -const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ - label: { - color: theme.dndIndicator, - marginTop: 5, - }, - logOutFrom: { - color: changeOpacity(theme.centerChannelColor, 0.64), - fontSize: 12, - height: 30, - lineHeight: 16, - fontFamily: 'OpenSans', - }, -})); - -const Settings = ({style, theme}: Props) => { +const LogOut = () => { + const theme = useTheme(); const styles = getStyleSheet(theme); const intl = useIntl(); const serverUrl = useServerUrl(); const serverDisplayName = useServerDisplayName(); const onLogout = useCallback(preventDoubleTap(() => { - alertServerLogout( - serverDisplayName, - () => { - logout(serverUrl); - }, - intl, - ); + alertServerLogout(serverDisplayName, () => logout(serverUrl), intl); }), [serverDisplayName, serverUrl, intl]); return ( - - - - - )} - onPress={onLogout} - separator={false} + ); }; -export default Settings; +export default LogOut; diff --git a/app/screens/home/account/components/options/settings/index.tsx b/app/screens/home/account/components/options/settings/index.tsx index e2134be8a7..fd2f0bf986 100644 --- a/app/screens/home/account/components/options/settings/index.tsx +++ b/app/screens/home/account/components/options/settings/index.tsx @@ -3,47 +3,29 @@ import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; -import {TextStyle} from 'react-native'; -import FormattedText from '@components/formatted_text'; -import MenuItem from '@components/menu_item'; +import OptionItem from '@components/option_item'; import Screens from '@constants/screens'; import {showModal} from '@screens/navigation'; -import {logInfo} from '@utils/log'; import {preventDoubleTap} from '@utils/tap'; -type Props = { - isTablet: boolean; - style: TextStyle; -} - -const Settings = ({isTablet, style}: Props) => { +const Settings = () => { const intl = useIntl(); const openSettings = useCallback(preventDoubleTap(() => { - if (isTablet) { - //todo: https://mattermost.atlassian.net/browse/MM-39711 - logInfo('Settings on tablets need to be figured out and implemented - @Avinash'); - } showModal( Screens.SETTINGS, intl.formatMessage({id: 'mobile.screen.settings', defaultMessage: 'Settings'}), ); - }), [isTablet]); + }), []); return ( - - } - onPress={openSettings} - separator={false} + ); }; diff --git a/app/screens/home/account/components/options/user_presence/index.tsx b/app/screens/home/account/components/options/user_presence/index.tsx index f652036220..09711708f0 100644 --- a/app/screens/home/account/components/options/user_presence/index.tsx +++ b/app/screens/home/account/components/options/user_presence/index.tsx @@ -3,36 +3,54 @@ import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; -import {TextStyle} from 'react-native'; +import {TouchableOpacity, View} from 'react-native'; import {useSafeAreaInsets} from 'react-native-safe-area-context'; import {setStatus} from '@actions/remote/user'; -import MenuItem from '@components/menu_item'; import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item'; import StatusLabel from '@components/status_label'; import UserStatusIndicator from '@components/user_status'; import General from '@constants/general'; import {useServerUrl} from '@context/server'; +import {useTheme} from '@context/theme'; import {bottomSheet, dismissBottomSheet, dismissModal} from '@screens/navigation'; import {bottomSheetSnapPoint} from '@utils/helpers'; import {preventDoubleTap} from '@utils/tap'; -import {changeOpacity} from '@utils/theme'; +import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; import {confirmOutOfOfficeDisabled} from '@utils/user'; import type UserModel from '@typings/database/models/servers/user'; -type Props = { - currentUser: UserModel; - style: TextStyle; - theme: Theme; -}; +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + label: { + color: theme.centerChannelColor, + ...typography('Body', 200), + textAlignVertical: 'center', + includeFontPadding: false, + }, + body: { + flexDirection: 'row', + marginTop: 18, + }, + spacer: { + marginLeft: 16, + }, + }; +}); const {OUT_OF_OFFICE, OFFLINE, AWAY, ONLINE, DND} = General; -const UserStatus = ({currentUser, style, theme}: Props) => { +type Props = { + currentUser: UserModel; +}; +const UserStatus = ({currentUser}: Props) => { const intl = useIntl(); const insets = useSafeAreaInsets(); const serverUrl = useServerUrl(); + const theme = useTheme(); + const styles = getStyleSheet(theme); const handleSetStatus = useCallback(preventDoubleTap(() => { const renderContent = () => { @@ -47,7 +65,7 @@ const UserStatus = ({currentUser, style, theme}: Props) => { id: 'mobile.set_status.online', defaultMessage: 'Online', })} - textStyles={style} + textStyles={styles.label} /> { id: 'mobile.set_status.away', defaultMessage: 'Away', })} - textStyles={style} + textStyles={styles.label} /> { id: 'mobile.set_status.dnd', defaultMessage: 'Do Not Disturb', })} - textStyles={style} + textStyles={styles.label} /> { id: 'mobile.set_status.offline', defaultMessage: 'Offline', })} - textStyles={style} + textStyles={styles.label} /> ); @@ -119,23 +137,20 @@ const UserStatus = ({currentUser, style, theme}: Props) => { }, []); return ( - - } - leftComponent={ + + - } - onPress={handleSetStatus} - separator={false} - testID='account.status.action' - /> + + + ); }; diff --git a/app/screens/home/account/components/options/your_profile/index.tsx b/app/screens/home/account/components/options/your_profile/index.tsx index 4bbdca99c4..e49f29e36d 100644 --- a/app/screens/home/account/components/options/your_profile/index.tsx +++ b/app/screens/home/account/components/options/your_profile/index.tsx @@ -3,10 +3,9 @@ import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; -import {DeviceEventEmitter, TextStyle} from 'react-native'; +import {DeviceEventEmitter} from 'react-native'; -import FormattedText from '@components/formatted_text'; -import MenuItem from '@components/menu_item'; +import OptionItem from '@components/option_item'; import {Events, Screens} from '@constants'; import {ACCOUNT_OUTLINE_IMAGE} from '@constants/profile'; import {showModal} from '@screens/navigation'; @@ -14,11 +13,10 @@ import {preventDoubleTap} from '@utils/tap'; type Props = { isTablet: boolean; - style: TextStyle; theme: Theme; } -const YourProfile = ({isTablet, style, theme}: Props) => { +const YourProfile = ({isTablet, theme}: Props) => { const intl = useIntl(); const openProfile = useCallback(preventDoubleTap(() => { if (isTablet) { @@ -32,18 +30,12 @@ const YourProfile = ({isTablet, style, theme}: Props) => { }), [isTablet, theme]); return ( - - } - onPress={openProfile} - separator={false} + ); }; diff --git a/app/screens/home/search/initial/modifiers/show_more.tsx b/app/screens/home/search/initial/modifiers/show_more.tsx index dc84920b14..73bd533b5a 100644 --- a/app/screens/home/search/initial/modifiers/show_more.tsx +++ b/app/screens/home/search/initial/modifiers/show_more.tsx @@ -1,9 +1,9 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React from 'react'; +import {useIntl} from 'react-intl'; -import FormattedText from '@components/formatted_text'; -import MenuItem from '@components/menu_item'; +import OptionItem from '@components/option_item'; import {useTheme} from '@context/theme'; import {t} from '@i18n'; import {makeStyleSheetFromTheme} from '@utils/theme'; @@ -26,7 +26,8 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { const ShowMoreButton = ({onPress, showMore}: ShowMoreButtonProps) => { const theme = useTheme(); - const style = getStyleSheet(theme); + const intl = useIntl(); + const styles = getStyleSheet(theme); let id = t('mobile.search.show_more'); let defaultMessage = 'Show more'; @@ -36,17 +37,12 @@ const ShowMoreButton = ({onPress, showMore}: ShowMoreButtonProps) => { } return ( - - } - onPress={onPress} - separator={false} + ); }; diff --git a/app/screens/post_options/post_options.tsx b/app/screens/post_options/post_options.tsx index 20fb1c036d..a8b978689d 100644 --- a/app/screens/post_options/post_options.tsx +++ b/app/screens/post_options/post_options.tsx @@ -5,7 +5,7 @@ import {useManagedConfig} from '@mattermost/react-native-emm'; import React from 'react'; import {CopyPermalinkOption, FollowThreadOption, ReplyOption, SaveOption} from '@components/common_post_options'; -import {ITEM_HEIGHT} from '@components/menu_item'; +import {ITEM_HEIGHT} from '@components/option_item'; import {Screens} from '@constants'; import useNavButtonPressed from '@hooks/navigation_button_pressed'; import BottomSheet from '@screens/bottom_sheet'; diff --git a/app/screens/settings/about/tos_privacy.tsx b/app/screens/settings/about/tos_privacy.tsx index 69110ec624..1d365f9369 100644 --- a/app/screens/settings/about/tos_privacy.tsx +++ b/app/screens/settings/about/tos_privacy.tsx @@ -8,18 +8,37 @@ import FormattedText from '@components/formatted_text'; import {useTheme} from '@context/theme'; import {t} from '@i18n'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + noticeLink: { + color: theme.linkColor, + ...typography('Body', 50), + }, + footerText: { + color: changeOpacity(theme.centerChannelColor, 0.5), + ...typography('Body', 50), + marginBottom: 10, + }, + hyphenText: { + marginBottom: 0, + }, + }; +}); type TosPrivacyContainerProps = { config: ClientConfig; onPressTOS: () => void; onPressPrivacyPolicy: () => void; } - const TosPrivacyContainer = ({config, onPressTOS, onPressPrivacyPolicy}: TosPrivacyContainerProps) => { - const hasTermsOfServiceLink = config.TermsOfServiceLink; - const hasPrivacyPolicyLink = config.PrivacyPolicyLink; const theme = useTheme(); const style = getStyleSheet(theme); + + const hasTermsOfServiceLink = Boolean(config.TermsOfServiceLink); + const hasPrivacyPolicyLink = Boolean(config.PrivacyPolicyLink); + return ( <> {hasTermsOfServiceLink && ( @@ -49,23 +68,4 @@ const TosPrivacyContainer = ({config, onPressTOS, onPressPrivacyPolicy}: TosPriv ); }; -const getStyleSheet = makeStyleSheetFromTheme((theme) => { - return { - noticeLink: { - color: theme.linkColor, - fontSize: 11, - lineHeight: 13, - }, - footerText: { - color: changeOpacity(theme.centerChannelColor, 0.5), - fontSize: 11, - lineHeight: 13, - marginBottom: 10, - }, - hyphenText: { - marginBottom: 0, - }, - }; -}); - export default TosPrivacyContainer; diff --git a/app/screens/settings/config.ts b/app/screens/settings/config.ts index 4e1569a6b4..6b39e0ac2e 100644 --- a/app/screens/settings/config.ts +++ b/app/screens/settings/config.ts @@ -16,81 +16,87 @@ export const getSaveButton = (buttonId: string, intl: IntlShape, color: string) ...typography('Body', 100, 'SemiBold'), }); -export const SettingOptionConfig = { +type SettingConfigDetails = { + defaultMessage?: string; + i18nId?: string; + icon?: string; + testID?: string; +} + +export const SettingOptionConfig: Record = { notification: { defaultMessage: 'Notifications', i18nId: t('general_settings.notifications'), - iconName: 'bell-outline', + icon: 'bell-outline', testID: 'general_settings.notifications', }, display: { defaultMessage: 'Display', i18nId: t('general_settings.display'), - iconName: 'layers-outline', + icon: 'layers-outline', testID: 'general_settings.display', }, advanced_settings: { defaultMessage: 'Advanced Settings', i18nId: t('general_settings.advanced_settings'), - iconName: 'tune', + icon: 'tune', testID: 'general_settings.advanced', }, about: { defaultMessage: 'About {appTitle}', i18nId: t('general_settings.about'), - iconName: 'information-outline', + icon: 'information-outline', testID: 'general_settings.about', }, help: { defaultMessage: 'Help', i18nId: t('general_settings.help'), testID: 'general_settings.help', - showArrow: false, }, }; -export const NotificationsOptionConfig = { +export const NotificationsOptionConfig: Record = { mentions: { - iconName: 'at', + icon: 'at', testID: 'notification_settings.mentions_replies', }, push_notification: { defaultMessage: 'Push Notifications', i18nId: t('notification_settings.mobile'), - iconName: 'cellphone', + icon: 'cellphone', testID: 'notification_settings.push_notification', }, email: { defaultMessage: 'Email', i18nId: t('notification_settings.email'), - iconName: 'email-outline', + icon: 'email-outline', testID: 'notification_settings.email', }, automatic_dm_replies: { defaultMessage: 'Automatic replies', i18nId: t('notification_settings.ooo_auto_responder'), - iconName: 'reply-outline', + icon: 'reply-outline', testID: 'notification_settings.automatic_dm_replies', }, }; -export const DisplayOptionConfig = { +export const DisplayOptionConfig: Record = { clock: { defaultMessage: 'Clock Display', i18nId: t('mobile.display_settings.clockDisplay'), - iconName: 'clock-outline', + icon: 'clock-outline', testID: 'display_settings.clock', }, theme: { defaultMessage: 'Theme', i18nId: t('mobile.display_settings.theme'), - iconName: 'palette-outline', + icon: 'palette-outline', testID: 'display_settings.theme', }, timezone: { defaultMessage: 'Timezone', i18nId: t('mobile.display_settings.timezone'), - iconName: 'globe', + icon: 'globe', testID: 'display_settings.timezone', }, }; diff --git a/app/screens/settings/display/display.tsx b/app/screens/settings/display/display.tsx index f2d0ac97b1..1b144e66c7 100644 --- a/app/screens/settings/display/display.tsx +++ b/app/screens/settings/display/display.tsx @@ -3,7 +3,6 @@ import React, {useMemo} from 'react'; import {useIntl} from 'react-intl'; -import {StyleSheet} from 'react-native'; import {Screens} from '@constants'; import {useTheme} from '@context/theme'; @@ -14,7 +13,6 @@ import {getUserTimezoneProps} from '@utils/user'; import SettingContainer from '../setting_container'; import SettingItem from '../setting_item'; -import SettingRowLabel from '../setting_row_label'; import type UserModel from '@typings/database/models/servers/user'; @@ -40,12 +38,6 @@ const TIMEZONE_FORMAT = [ }, ]; -const styles = StyleSheet.create({ - title: { - textTransform: 'capitalize', - }, -}); - type DisplayProps = { currentUser: UserModel; hasMilitaryTimeFormat: boolean; @@ -83,32 +75,19 @@ const Display = ({currentUser, hasMilitaryTimeFormat, isThemeSwitchingEnabled, i - } + info={theme.type!} /> )} - } + info={intl.formatMessage(hasMilitaryTimeFormat ? TIME_FORMAT[1] : TIME_FORMAT[0])} /> {isTimezoneEnabled && ( - } + info={intl.formatMessage(timezone.useAutomaticTimezone ? TIMEZONE_FORMAT[0] : TIMEZONE_FORMAT[1])} /> )} diff --git a/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx b/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx index e7f29cadfd..3c173b095b 100644 --- a/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx +++ b/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx @@ -4,7 +4,7 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {useIntl} from 'react-intl'; -import {updateMe} from '@actions/remote/user'; +import {fetchStatusInBatch, updateMe} from '@actions/remote/user'; import FloatingTextInput from '@components/floating_text_input_label'; import FormattedText from '@components/formatted_text'; import {General} from '@constants'; @@ -88,8 +88,9 @@ const NotificationAutoResponder = ({currentUser, componentId}: NotificationAutoR auto_responder_message: autoResponderMessage, }, }); + fetchStatusInBatch(serverUrl, currentUser.id); close(); - }, [serverUrl, autoResponderActive, autoResponderMessage, notifyProps]); + }, [serverUrl, autoResponderActive, autoResponderMessage, notifyProps, currentUser.id]); useEffect(() => { const enabled = initialAutoResponderActive !== autoResponderActive || initialOOOMsg !== autoResponderMessage; @@ -120,7 +121,6 @@ const NotificationAutoResponder = ({currentUser, componentId}: NotificationAutoR allowFontScaling={true} autoCapitalize='none' autoCorrect={false} - blurOnSubmit={true} containerStyle={styles.textInputContainer} keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} label={intl.formatMessage(label)} @@ -128,7 +128,7 @@ const NotificationAutoResponder = ({currentUser, componentId}: NotificationAutoR onChangeText={setAutoResponderMessage} placeholder={intl.formatMessage(label)} placeholderTextColor={changeOpacity(theme.centerChannelColor, 0.4)} - returnKeyType='done' + returnKeyType='default' textAlignVertical='top' textInputStyle={styles.input} theme={theme} diff --git a/app/screens/settings/notifications/notifications.tsx b/app/screens/settings/notifications/notifications.tsx index e5e5155304..f0cfc37fd9 100644 --- a/app/screens/settings/notifications/notifications.tsx +++ b/app/screens/settings/notifications/notifications.tsx @@ -7,7 +7,6 @@ import {useIntl} from 'react-intl'; import {General, Screens} from '@constants'; import {t} from '@i18n'; import {goToScreen} from '@screens/navigation'; -import SettingRowLabel from '@screens/settings/setting_row_label'; import {getEmailInterval, getEmailIntervalTexts, getNotificationProps} from '@utils/user'; import SettingContainer from '../setting_container'; @@ -91,10 +90,12 @@ const Notifications = ({ return ( - } + info={intl.formatMessage(getEmailIntervalTexts(emailIntervalPref))} /> {enableAutoResponder && ( - } + info={currentUser.status === General.OUT_OF_OFFICE && notifyProps.auto_responder_active === 'true' ? 'On' : 'Off'} /> )} diff --git a/app/screens/settings/setting_item.tsx b/app/screens/settings/setting_item.tsx index 075d24bd26..8fcb10fe9a 100644 --- a/app/screens/settings/setting_item.tsx +++ b/app/screens/settings/setting_item.tsx @@ -2,10 +2,12 @@ // See LICENSE.txt for license information. import React from 'react'; +import {useIntl} from 'react-intl'; import {Platform} from 'react-native'; -import MenuItem, {MenuItemProps} from '@components/menu_item'; +import OptionItem, {OptionItemProps} from '@components/option_item'; import {useTheme} from '@context/theme'; +import SettingSeparator from '@screens/settings/settings_separator'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; @@ -15,7 +17,8 @@ type SettingsConfig = keyof typeof SettingOptionConfig | keyof typeof Notificati type SettingOptionProps = { optionName: SettingsConfig; onPress: () => void; -} & Omit; + separator?: boolean; +} & Partial; const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { return { @@ -23,10 +26,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { color: theme.centerChannelColor, ...typography('Body', 200, 'Regular'), }, - separatorStyle: { - width: '91%', - alignSelf: 'center', - }, chevronStyle: { marginRight: 14, color: changeOpacity(theme.centerChannelColor, 0.32), @@ -34,21 +33,35 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { }; }); -const SettingItem = ({onPress, optionName, ...rest}: SettingOptionProps) => { +const SettingItem = ({ + info, + onPress, + optionName, + separator = true, + ...props +}: SettingOptionProps) => { const theme = useTheme(); + const intl = useIntl(); const styles = getStyleSheet(theme); - const props = {...rest, ...Options[optionName]} as unknown as Omit; + const config = Options[optionName]; + + const label = props.label || intl.formatMessage({id: config.i18nId, defaultMessage: config.defaultMessage}); return ( - + <> + + {separator && } + ); }; diff --git a/app/screens/settings/setting_row_label.tsx b/app/screens/settings/setting_row_label.tsx deleted file mode 100644 index 3cdc2341cd..0000000000 --- a/app/screens/settings/setting_row_label.tsx +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React from 'react'; -import {Platform, StyleProp, Text, TextStyle} from 'react-native'; - -import {useTheme} from '@context/theme'; -import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; -import {typography} from '@utils/typography'; - -const getStyleSheet = makeStyleSheetFromTheme((theme) => { - return { - rightLabel: { - color: changeOpacity(theme.centerChannelColor, 0.56), - ...typography('Body', 100, 'Regular'), - alignSelf: 'center', - ...Platform.select({ - android: { - marginRight: 20, - }, - }), - }, - }; -}); - -type SettingRowLabelProps = { - text: string; - textStyle?: StyleProp; -} -const SettingRowLabel = ({text, textStyle}: SettingRowLabelProps) => { - const theme = useTheme(); - const styles = getStyleSheet(theme); - - return ( - - {text} - - - ); -}; - -export default SettingRowLabel; diff --git a/app/screens/settings/settings.tsx b/app/screens/settings/settings.tsx index 83ae77238d..d01cdf388c 100644 --- a/app/screens/settings/settings.tsx +++ b/app/screens/settings/settings.tsx @@ -135,18 +135,20 @@ const Settings = ({componentId, helpLink, showHelp, siteName}: SettingsProps) => optionName='advanced_settings' /> {Platform.OS === 'android' && } {showHelp && } diff --git a/app/screens/snack_bar/index.tsx b/app/screens/snack_bar/index.tsx index 96eb867856..2c75d2e949 100644 --- a/app/screens/snack_bar/index.tsx +++ b/app/screens/snack_bar/index.tsx @@ -234,10 +234,10 @@ const SnackBar = ({barType, componentId, onAction, sourceScreen}: SnackBarProps) > {config.canUndo && onAction && ( diff --git a/app/screens/thread_options/thread_options.tsx b/app/screens/thread_options/thread_options.tsx index ec6d0d218a..e1bc234b03 100644 --- a/app/screens/thread_options/thread_options.tsx +++ b/app/screens/thread_options/thread_options.tsx @@ -7,7 +7,7 @@ import {View} from 'react-native'; import {CopyPermalinkOption, FollowThreadOption, ReplyOption, SaveOption} from '@components/common_post_options'; import FormattedText from '@components/formatted_text'; -import {ITEM_HEIGHT} from '@components/menu_item'; +import {ITEM_HEIGHT} from '@components/option_item'; import {Screens} from '@constants'; import {useTheme} from '@context/theme'; import {useIsTablet} from '@hooks/device';