From 73518da91eb23c6fb0b2e219e0e8acdc51748e9e Mon Sep 17 00:00:00 2001 From: Matheus Cardoso Date: Fri, 23 Aug 2019 14:18:05 -0300 Subject: [PATCH] Make keyboard dark on dark themes (iOS only) (#3102) * Support keyboardAppearance theme parameter * Change approach of keyboardAppearance to auto-detect * Fix style * Update snapshots * Add unit test for getKeyboardAppearanceFromTheme * Update snapshot * Fix failing test --- .../edit_channel_info/edit_channel_info.js | 11 +++++- app/components/emoji_picker/emoji_picker.js | 7 +++- .../__snapshots__/post_textbox.test.js.snap | 1 + .../post_textbox/post_textbox_base.js | 7 +++- .../search_bar/search_bar.android.js | 3 ++ app/components/search_bar/search_bar.ios.js | 1 + app/components/search_bar/search_box.js | 2 ++ .../main/channels_list/channels_list.js | 7 +++- .../widgets/settings/text_setting.js | 7 +++- .../channel_add_members.js | 8 ++++- .../channel_members.test.js.snap | 1 + .../channel_members/channel_members.js | 8 ++++- app/screens/code/code.js | 8 ++++- app/screens/edit_post/edit_post.js | 8 ++++- .../__snapshots__/more_channels.test.js.snap | 1 + app/screens/more_channels/more_channels.js | 8 ++++- app/screens/more_dms/more_dms.js | 8 ++++- app/screens/search/search.js | 7 +++- .../selector_screen.test.js.snap | 6 ++++ .../selector_screen/selector_screen.js | 8 ++++- .../notification_settings_auto_responder.js | 7 +++- .../notification_settings_mentions.android.js | 7 +++- ...on_settings_mentions_keywords.test.js.snap | 1 + ...notification_settings_mentions_keywords.js | 8 ++++- ...ication_settings_mentions_keywords.test.js | 1 + .../select_timezone/select_timezone.js | 7 +++- app/screens/text_preview/text_preview.js | 8 ++++- app/utils/theme.js | 6 ++++ app/utils/theme.test.js | 36 +++++++++++++++++++ 29 files changed, 180 insertions(+), 18 deletions(-) create mode 100644 app/utils/theme.test.js diff --git a/app/components/edit_channel_info/edit_channel_info.js b/app/components/edit_channel_info/edit_channel_info.js index 5dede691f..d7e92eda4 100644 --- a/app/components/edit_channel_info/edit_channel_info.js +++ b/app/components/edit_channel_info/edit_channel_info.js @@ -21,7 +21,12 @@ import Loading from 'app/components/loading'; import StatusBar from 'app/components/status_bar'; import TextInputWithLocalizedPlaceholder from 'app/components/text_input_with_localized_placeholder'; -import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; +import { + changeOpacity, + makeStyleSheetFromTheme, + getKeyboardAppearanceFromTheme, +} from 'app/utils/theme'; + import {getShortenedURL} from 'app/utils/url'; import {t} from 'app/utils/i18n'; import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing'; @@ -247,6 +252,7 @@ export default class EditChannelInfo extends PureComponent { placeholderTextColor={changeOpacity('#000', 0.5)} underlineColorAndroid='transparent' disableFullscreenUI={true} + keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} /> @@ -276,6 +282,7 @@ export default class EditChannelInfo extends PureComponent { placeholderTextColor={changeOpacity('#000', 0.5)} underlineColorAndroid='transparent' disableFullscreenUI={true} + keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} /> @@ -309,6 +316,7 @@ export default class EditChannelInfo extends PureComponent { textAlignVertical='top' underlineColorAndroid='transparent' disableFullscreenUI={true} + keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} /> @@ -355,6 +363,7 @@ export default class EditChannelInfo extends PureComponent { textAlignVertical='top' underlineColorAndroid='transparent' disableFullscreenUI={true} + keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} /> diff --git a/app/components/emoji_picker/emoji_picker.js b/app/components/emoji_picker/emoji_picker.js index c5fc3a2fb..2d6ba17a8 100644 --- a/app/components/emoji_picker/emoji_picker.js +++ b/app/components/emoji_picker/emoji_picker.js @@ -25,7 +25,11 @@ import SafeAreaView from 'app/components/safe_area_view'; import SearchBar from 'app/components/search_bar'; import {DeviceTypes} from 'app/constants'; import {emptyFunction} from 'app/utils/general'; -import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme'; +import { + makeStyleSheetFromTheme, + changeOpacity, + getKeyboardAppearanceFromTheme, +} from 'app/utils/theme'; import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing'; import EmojiPickerRow from './emoji_picker_row'; @@ -484,6 +488,7 @@ export default class EmojiPicker extends PureComponent { onCancelButtonPress={this.cancelSearch} autoCapitalize='none' value={searchTerm} + keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} /> diff --git a/app/components/post_textbox/__snapshots__/post_textbox.test.js.snap b/app/components/post_textbox/__snapshots__/post_textbox.test.js.snap index cc3dabb9d..afd6e02f3 100644 --- a/app/components/post_textbox/__snapshots__/post_textbox.test.js.snap +++ b/app/components/post_textbox/__snapshots__/post_textbox.test.js.snap @@ -74,6 +74,7 @@ exports[`PostTextBox should match, full snapshot 1`] = ` blurOnSubmit={false} disableFullscreenUI={true} editable={true} + keyboardAppearance="light" keyboardType="default" multiline={true} onChangeText={[Function]} diff --git a/app/components/post_textbox/post_textbox_base.js b/app/components/post_textbox/post_textbox_base.js index 1c5c5f0c2..cdae4f287 100644 --- a/app/components/post_textbox/post_textbox_base.js +++ b/app/components/post_textbox/post_textbox_base.js @@ -31,7 +31,11 @@ import {INSERT_TO_COMMENT, INSERT_TO_DRAFT, IS_REACTION_REGEX, MAX_CONTENT_HEIGH import {NOTIFY_ALL_MEMBERS} from 'app/constants/view'; import {t} from 'app/utils/i18n'; import {confirmOutOfOfficeDisabled} from 'app/utils/status'; -import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; +import { + changeOpacity, + makeStyleSheetFromTheme, + getKeyboardAppearanceFromTheme, +} from 'app/utils/theme'; import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing'; const {RNTextInputReset} = NativeModules; @@ -722,6 +726,7 @@ export default class PostTextBoxBase extends PureComponent { onEndEditing={this.handleEndEditing} disableFullscreenUI={true} editable={!channelIsReadOnly} + keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} /> diff --git a/app/components/sidebars/main/channels_list/channels_list.js b/app/components/sidebars/main/channels_list/channels_list.js index 38c4e359f..7b0f71b84 100644 --- a/app/components/sidebars/main/channels_list/channels_list.js +++ b/app/components/sidebars/main/channels_list/channels_list.js @@ -13,7 +13,11 @@ import MaterialIcon from 'react-native-vector-icons/MaterialIcons'; import SearchBar from 'app/components/search_bar'; import {ViewTypes} from 'app/constants'; import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing'; -import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; +import { + changeOpacity, + makeStyleSheetFromTheme, + getKeyboardAppearanceFromTheme, +} from 'app/utils/theme'; import List from './list'; import SwitchTeamsButton from './switch_teams_button'; @@ -149,6 +153,7 @@ export default class ChannelsList extends PureComponent { onFocus={this.onSearchFocused} searchIconCollapsedMargin={5} searchIconExpandedMargin={5} + keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} value={term} leftComponent={( diff --git a/app/screens/channel_add_members/channel_add_members.js b/app/screens/channel_add_members/channel_add_members.js index ace07d3cf..d9918ad54 100644 --- a/app/screens/channel_add_members/channel_add_members.js +++ b/app/screens/channel_add_members/channel_add_members.js @@ -24,7 +24,12 @@ import SearchBar from 'app/components/search_bar'; import StatusBar from 'app/components/status_bar'; import {alertErrorIfInvalidPermissions} from 'app/utils/general'; import {createProfilesSections, loadingText} from 'app/utils/member_list'; -import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/utils/theme'; +import { + changeOpacity, + makeStyleSheetFromTheme, + setNavigatorStyles, + getKeyboardAppearanceFromTheme, +} from 'app/utils/theme'; export default class ChannelAddMembers extends PureComponent { static propTypes = { @@ -352,6 +357,7 @@ export default class ChannelAddMembers extends PureComponent { onSearchButtonPress={this.onSearch} onCancelButtonPress={this.clearSearch} autoCapitalize='none' + keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} value={term} /> diff --git a/app/screens/channel_members/__snapshots__/channel_members.test.js.snap b/app/screens/channel_members/__snapshots__/channel_members.test.js.snap index da88b8c49..5517ea5e7 100644 --- a/app/screens/channel_members/__snapshots__/channel_members.test.js.snap +++ b/app/screens/channel_members/__snapshots__/channel_members.test.js.snap @@ -26,6 +26,7 @@ exports[`ChannelMembers should match snapshot 1`] = ` "fontSize": 15, } } + keyboardAppearance="light" leftComponent={null} onBlur={[Function]} onCancelButtonPress={[Function]} diff --git a/app/screens/channel_members/channel_members.js b/app/screens/channel_members/channel_members.js index a12db4398..173ec925c 100644 --- a/app/screens/channel_members/channel_members.js +++ b/app/screens/channel_members/channel_members.js @@ -24,7 +24,12 @@ import SearchBar from 'app/components/search_bar'; import StatusBar from 'app/components/status_bar'; import {alertErrorIfInvalidPermissions} from 'app/utils/general'; import {createProfilesSections, loadingText} from 'app/utils/member_list'; -import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/utils/theme'; +import { + changeOpacity, + makeStyleSheetFromTheme, + setNavigatorStyles, + getKeyboardAppearanceFromTheme, +} from 'app/utils/theme'; export default class ChannelMembers extends PureComponent { static propTypes = { @@ -380,6 +385,7 @@ export default class ChannelMembers extends PureComponent { onSearchButtonPress={this.onSearch} onCancelButtonPress={this.clearSearch} autoCapitalize='none' + keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} value={term} /> diff --git a/app/screens/code/code.js b/app/screens/code/code.js index 019b3346b..ef3e5e7b5 100644 --- a/app/screens/code/code.js +++ b/app/screens/code/code.js @@ -14,7 +14,12 @@ import { } from 'react-native'; import {getCodeFont} from 'app/utils/markdown'; -import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/utils/theme'; +import { + changeOpacity, + makeStyleSheetFromTheme, + setNavigatorStyles, + getKeyboardAppearanceFromTheme, +} from 'app/utils/theme'; export default class Code extends React.PureComponent { static propTypes = { @@ -75,6 +80,7 @@ export default class Code extends React.PureComponent { multiline={true} value={this.props.content} style={[style.codeText]} + keyboardAppearance={getKeyboardAppearanceFromTheme(this.props.theme)} /> ); } else { diff --git a/app/screens/edit_post/edit_post.js b/app/screens/edit_post/edit_post.js index 45a781da4..acfd7a155 100644 --- a/app/screens/edit_post/edit_post.js +++ b/app/screens/edit_post/edit_post.js @@ -13,7 +13,12 @@ import ErrorText from 'app/components/error_text'; import Loading from 'app/components/loading'; import StatusBar from 'app/components/status_bar'; import TextInputWithLocalizedPlaceholder from 'app/components/text_input_with_localized_placeholder'; -import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/utils/theme'; +import { + changeOpacity, + makeStyleSheetFromTheme, + setNavigatorStyles, + getKeyboardAppearanceFromTheme, +} from 'app/utils/theme'; import {t} from 'app/utils/i18n'; import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing'; @@ -195,6 +200,7 @@ export default class EditPost extends PureComponent { placeholderTextColor={changeOpacity(theme.centerChannelColor, 0.4)} underlineColorAndroid='transparent' disableFullscreenUI={true} + keyboardAppearance={getKeyboardAppearanceFromTheme(this.props.theme)} /> diff --git a/app/screens/more_channels/__snapshots__/more_channels.test.js.snap b/app/screens/more_channels/__snapshots__/more_channels.test.js.snap index 8913a1d8a..9023ef399 100644 --- a/app/screens/more_channels/__snapshots__/more_channels.test.js.snap +++ b/app/screens/more_channels/__snapshots__/more_channels.test.js.snap @@ -26,6 +26,7 @@ exports[`MoreChannels should match snapshot 1`] = ` "fontSize": 15, } } + keyboardAppearance="light" leftComponent={null} onBlur={[Function]} onCancelButtonPress={[Function]} diff --git a/app/screens/more_channels/more_channels.js b/app/screens/more_channels/more_channels.js index c65eb7bf0..e8a0b4525 100644 --- a/app/screens/more_channels/more_channels.js +++ b/app/screens/more_channels/more_channels.js @@ -19,7 +19,12 @@ import Loading from 'app/components/loading'; import SearchBar from 'app/components/search_bar'; import StatusBar from 'app/components/status_bar'; import {alertErrorWithFallback} from 'app/utils/general'; -import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/utils/theme'; +import { + changeOpacity, + makeStyleSheetFromTheme, + setNavigatorStyles, + getKeyboardAppearanceFromTheme, +} from 'app/utils/theme'; export default class MoreChannels extends PureComponent { static propTypes = { @@ -351,6 +356,7 @@ export default class MoreChannels extends PureComponent { onSearchButtonPress={this.searchChannels} onCancelButtonPress={this.cancelSearch} autoCapitalize='none' + keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} value={term} /> diff --git a/app/screens/more_dms/more_dms.js b/app/screens/more_dms/more_dms.js index f187ffbd6..26c50f90a 100644 --- a/app/screens/more_dms/more_dms.js +++ b/app/screens/more_dms/more_dms.js @@ -23,7 +23,12 @@ import SearchBar from 'app/components/search_bar'; import StatusBar from 'app/components/status_bar'; import {alertErrorWithFallback} from 'app/utils/general'; import {createProfilesSections, loadingText} from 'app/utils/member_list'; -import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/utils/theme'; +import { + changeOpacity, + makeStyleSheetFromTheme, + setNavigatorStyles, + getKeyboardAppearanceFromTheme, +} from 'app/utils/theme'; import {t} from 'app/utils/i18n'; import SelectedUsers from './selected_users'; @@ -470,6 +475,7 @@ export default class MoreDirectMessages extends PureComponent { onSearchButtonPress={this.onSearch} onCancelButtonPress={this.clearSearch} autoCapitalize='none' + keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} value={term} /> diff --git a/app/screens/settings/notification_settings_auto_responder/notification_settings_auto_responder.js b/app/screens/settings/notification_settings_auto_responder/notification_settings_auto_responder.js index 84c6c9e45..9609bd855 100644 --- a/app/screens/settings/notification_settings_auto_responder/notification_settings_auto_responder.js +++ b/app/screens/settings/notification_settings_auto_responder/notification_settings_auto_responder.js @@ -15,7 +15,11 @@ import FormattedText from 'app/components/formatted_text'; import StatusBar from 'app/components/status_bar'; import TextInputWithLocalizedPlaceholder from 'app/components/text_input_with_localized_placeholder'; import {getNotificationProps} from 'app/utils/notify_props'; -import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; +import { + changeOpacity, + makeStyleSheetFromTheme, + getKeyboardAppearanceFromTheme, +} from 'app/utils/theme'; import {t} from 'app/utils/i18n'; import Section from 'app/screens/settings/section'; @@ -136,6 +140,7 @@ export default class NotificationSettingsAutoResponder extends PureComponent { textAlignVertical='top' underlineColorAndroid='transparent' returnKeyType='done' + keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} /> diff --git a/app/screens/settings/notification_settings_mentions/notification_settings_mentions.android.js b/app/screens/settings/notification_settings_mentions/notification_settings_mentions.android.js index a1a14b72c..ef47e36b5 100644 --- a/app/screens/settings/notification_settings_mentions/notification_settings_mentions.android.js +++ b/app/screens/settings/notification_settings_mentions/notification_settings_mentions.android.js @@ -16,7 +16,11 @@ import RadioButtonGroup from 'app/components/radio_button'; import StatusBar from 'app/components/status_bar'; import TextInputWithLocalizedPlaceholder from 'app/components/text_input_with_localized_placeholder'; import SectionItem from 'app/screens/settings/section_item'; -import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; +import { + changeOpacity, + makeStyleSheetFromTheme, + getKeyboardAppearanceFromTheme, +} from 'app/utils/theme'; import {t} from 'app/utils/i18n'; import NotificationSettingsMentionsBase from './notification_settings_mention_base'; @@ -79,6 +83,7 @@ class NotificationSettingsMentionsAndroid extends NotificationSettingsMentionsBa returnKeyType='done' returnKeyLabel={this.props.intl.formatMessage({id: 'mobile.notification_settings.modal_save'})} underlineColorAndroid={theme.linkColor} + keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} /> diff --git a/app/screens/settings/notification_settings_mentions_keywords/notification_settings_mentions_keywords.test.js b/app/screens/settings/notification_settings_mentions_keywords/notification_settings_mentions_keywords.test.js index 3f1c11e41..2e5cbd337 100644 --- a/app/screens/settings/notification_settings_mentions_keywords/notification_settings_mentions_keywords.test.js +++ b/app/screens/settings/notification_settings_mentions_keywords/notification_settings_mentions_keywords.test.js @@ -19,6 +19,7 @@ describe('NotificationSettingsMentionsKeywords', () => { isLandscape: false, onBack: jest.fn(), theme: Preferences.THEMES.default, + isLandscape: false, }; test('should match snapshot', () => { diff --git a/app/screens/settings/timezone/select_timezone/select_timezone.js b/app/screens/settings/timezone/select_timezone/select_timezone.js index 755ebd904..8928125fd 100644 --- a/app/screens/settings/timezone/select_timezone/select_timezone.js +++ b/app/screens/settings/timezone/select_timezone/select_timezone.js @@ -16,7 +16,11 @@ import StatusBar from 'app/components/status_bar'; import SelectTimezoneRow from './select_timezone_row'; import {ListTypes} from 'app/constants'; -import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; +import { + changeOpacity, + makeStyleSheetFromTheme, + getKeyboardAppearanceFromTheme, +} from 'app/utils/theme'; import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing'; const ITEM_HEIGHT = 45; @@ -123,6 +127,7 @@ export default class Timezone extends PureComponent { value={value} containerStyle={style.searchBarContainer} showArrow={false} + keyboardAppearance={getKeyboardAppearanceFromTheme(theme)} /> ); } else { diff --git a/app/utils/theme.js b/app/utils/theme.js index c34157796..8d21d9aef 100644 --- a/app/utils/theme.js +++ b/app/utils/theme.js @@ -4,6 +4,8 @@ import {StyleSheet} from 'react-native'; import {Navigation} from 'react-native-navigation'; +import tinyColor from 'tinycolor2'; + import * as ThemeUtils from 'mattermost-redux/utils/theme_utils'; export function makeStyleSheetFromTheme(getStyleFromTheme) { @@ -45,3 +47,7 @@ export function isThemeSwitchingEnabled(state) { const {config} = state.entities.general; return config.EnableThemeSelection === 'true'; } + +export function getKeyboardAppearanceFromTheme(theme) { + return tinyColor(theme.centerChannelBg).isLight() ? 'light' : 'dark'; +} diff --git a/app/utils/theme.test.js b/app/utils/theme.test.js new file mode 100644 index 000000000..b6ae57c24 --- /dev/null +++ b/app/utils/theme.test.js @@ -0,0 +1,36 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {getKeyboardAppearanceFromTheme} from 'app/utils/theme'; + +describe('getKeyboardAppearanceFromTheme', () => { + const themes = [{ + centerChannelBg: '#ffffff', // Mattermost + }, { + centerChannelBg: '#f2f4f8', // Organization + }, { + centerChannelBg: '#2f3e4e', // Mattermost Dark + }, { + centerChannelBg: '#1f1f1f', // Windows Dark + }]; + + it('should return "light" keyboard appearance for centerChannelBg="#ffffff"', () => { + const keyboardAppearance = getKeyboardAppearanceFromTheme(themes[0]); + expect(keyboardAppearance).toBe('light'); + }); + + it('should return "light" keyboard appearance for centerChannelBg="#f2f4f8"', () => { + const keyboardAppearance = getKeyboardAppearanceFromTheme(themes[1]); + expect(keyboardAppearance).toBe('light'); + }); + + it('should return "dark" keyboard appearance for centerChannelBg="#2f3e4e"', () => { + const keyboardAppearance = getKeyboardAppearanceFromTheme(themes[2]); + expect(keyboardAppearance).toBe('dark'); + }); + + it('should return "dark" keyboard appearance for centerChannelBg="#1f1f1f"', () => { + const keyboardAppearance = getKeyboardAppearanceFromTheme(themes[3]); + expect(keyboardAppearance).toBe('dark'); + }); +});