From d230bdac1ef48575d82c874cf216a49a51da9576 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Fri, 2 Aug 2019 13:50:31 -0400 Subject: [PATCH] MM-17424 Setting to enable/disable fixed sidebar (#3060) --- .../__snapshots__/main_sidebar.test.js.snap | 2 +- app/components/sidebars/main/main_sidebar.js | 18 ++- .../sidebars/main/main_sidebar.test.js | 29 ++++- app/constants/device.js | 1 + app/init/device.js | 13 ++ app/mattermost.js | 1 + .../channel_nav_bar.test.js.snap | 65 ++++++++++ .../channel_nav_bar/channel_nav_bar.js | 16 ++- .../channel_nav_bar/channel_nav_bar.test.js | 52 ++++++++ app/screens/index.js | 11 +- .../clock_display/clock_display.android.js | 2 +- .../clock_display/clock_display.ios.js | 0 .../clock_display/clock_display_base.js | 0 .../{ => settings}/clock_display/index.js | 0 .../display_settings.test.js.snap | 115 +++++++++++++++++ .../display_settings/display_settings.js | 32 ++++- .../display_settings/display_settings.test.js | 20 ++- .../__snapshots__/sidebar.test.js.snap | 119 ++++++++++++++++++ app/screens/settings/sidebar/index.js | 119 ++++++++++++++++++ app/screens/settings/sidebar/sidebar.test.js | 79 ++++++++++++ .../theme/__snapshots__/theme.test.js.snap | 0 app/screens/{ => settings}/theme/index.js | 0 app/screens/{ => settings}/theme/theme.js | 0 .../{ => settings}/theme/theme.test.js | 0 .../{ => settings}/theme/theme_tile.js | 0 app/screens/{ => settings}/timezone/index.js | 0 .../timezone/select_timezone/index.js | 0 .../select_timezone/select_timezone.js | 0 .../select_timezone/select_timezone_row.js | 0 .../{ => settings}/timezone/timezone.js | 0 assets/base/i18n/en.json | 4 +- 31 files changed, 679 insertions(+), 19 deletions(-) create mode 100644 app/init/device.js create mode 100644 app/screens/channel/channel_nav_bar/__snapshots__/channel_nav_bar.test.js.snap create mode 100644 app/screens/channel/channel_nav_bar/channel_nav_bar.test.js rename app/screens/{ => settings}/clock_display/clock_display.android.js (99%) rename app/screens/{ => settings}/clock_display/clock_display.ios.js (100%) rename app/screens/{ => settings}/clock_display/clock_display_base.js (100%) rename app/screens/{ => settings}/clock_display/index.js (100%) create mode 100644 app/screens/settings/sidebar/__snapshots__/sidebar.test.js.snap create mode 100644 app/screens/settings/sidebar/index.js create mode 100644 app/screens/settings/sidebar/sidebar.test.js rename app/screens/{ => settings}/theme/__snapshots__/theme.test.js.snap (100%) rename app/screens/{ => settings}/theme/index.js (100%) rename app/screens/{ => settings}/theme/theme.js (100%) rename app/screens/{ => settings}/theme/theme.test.js (100%) rename app/screens/{ => settings}/theme/theme_tile.js (100%) rename app/screens/{ => settings}/timezone/index.js (100%) rename app/screens/{ => settings}/timezone/select_timezone/index.js (100%) rename app/screens/{ => settings}/timezone/select_timezone/select_timezone.js (100%) rename app/screens/{ => settings}/timezone/select_timezone/select_timezone_row.js (100%) rename app/screens/{ => settings}/timezone/timezone.js (100%) diff --git a/app/components/sidebars/main/__snapshots__/main_sidebar.test.js.snap b/app/components/sidebars/main/__snapshots__/main_sidebar.test.js.snap index b60408525..418e1ebf4 100644 --- a/app/components/sidebars/main/__snapshots__/main_sidebar.test.js.snap +++ b/app/components/sidebars/main/__snapshots__/main_sidebar.test.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`ChannelSidebar should match, full snapshot 1`] = ` +exports[`MainSidebar should match, full snapshot 1`] = ` { + if (DeviceTypes.IS_TABLET && this.mounted) { + const enabled = await AsyncStorage.getItem(DeviceTypes.PERMANENT_SIDEBAR_SETTINGS); + this.setState({permanentSidebar: enabled === 'true'}); + } + }; + handleShowDrawerContent = () => { requestAnimationFrame(() => this.setState({show: true})); }; @@ -396,7 +408,7 @@ export default class ChannelSidebar extends Component { render() { const {children, deviceWidth} = this.props; const {openDrawerOffset} = this.state; - const isTablet = DeviceTypes.IS_TABLET && !this.state.isSplitView; + const isTablet = DeviceTypes.IS_TABLET && !this.state.isSplitView && this.state.permanentSidebar; const drawerWidth = DeviceTypes.IS_TABLET ? TABLET_WIDTH : (deviceWidth - openDrawerOffset); return ( diff --git a/app/components/sidebars/main/main_sidebar.test.js b/app/components/sidebars/main/main_sidebar.test.js index a2bbabb42..8e6d48f66 100644 --- a/app/components/sidebars/main/main_sidebar.test.js +++ b/app/components/sidebars/main/main_sidebar.test.js @@ -6,11 +6,13 @@ import {shallow} from 'enzyme'; import Preferences from 'mattermost-redux/constants/preferences'; -import ChannelSidebar from './main_sidebar'; +import {DeviceTypes} from 'app/constants'; + +import MainSidebar from './main_sidebar'; jest.mock('react-intl'); -describe('ChannelSidebar', () => { +describe('MainSidebar', () => { const baseProps = { actions: { getTeams: jest.fn(), @@ -30,9 +32,30 @@ describe('ChannelSidebar', () => { test('should match, full snapshot', () => { const wrapper = shallow( - + ); expect(wrapper.getElement()).toMatchSnapshot(); }); + + test('should not set the permanentSidebar state if not Tablet', () => { + const wrapper = shallow( + + ); + + wrapper.instance().handlePermanentSidebar(); + expect(wrapper.state('permanentSidebar')).toBeUndefined(); + }); + + test('should set the permanentSidebar state if Tablet', async () => { + const wrapper = shallow( + + ); + + DeviceTypes.IS_TABLET = true; + + await wrapper.instance().handlePermanentSidebar(); + + expect(wrapper.state('permanentSidebar')).toBeDefined(); + }); }); diff --git a/app/constants/device.js b/app/constants/device.js index a7b66ad20..71f56eefb 100644 --- a/app/constants/device.js +++ b/app/constants/device.js @@ -20,4 +20,5 @@ export default { IS_IPHONE_X: DeviceInfo.getModel().includes('iPhone X'), IS_TABLET: DeviceInfo.isTablet(), VIDEOS_PATH: `${RNFetchBlobFS.dirs.CacheDir}/Videos`, + PERMANENT_SIDEBAR_SETTINGS: '@PERMANENT_SIDEBAR_SETTINGS', }; diff --git a/app/init/device.js b/app/init/device.js new file mode 100644 index 000000000..ada744c66 --- /dev/null +++ b/app/init/device.js @@ -0,0 +1,13 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import AsyncStorage from '@react-native-community/async-storage'; +import {DeviceTypes} from 'app/constants'; + +if (DeviceTypes.IS_TABLET) { + AsyncStorage.getItem(DeviceTypes.PERMANENT_SIDEBAR_SETTINGS).then((value) => { + if (!value) { + AsyncStorage.setItem(DeviceTypes.PERMANENT_SIDEBAR_SETTINGS, 'true'); + } + }); +} diff --git a/app/mattermost.js b/app/mattermost.js index 67636f3a7..cbe4fffe0 100644 --- a/app/mattermost.js +++ b/app/mattermost.js @@ -12,6 +12,7 @@ import {setDeepLinkURL} from 'app/actions/views/root'; import initialState from 'app/initial_state'; import {getAppCredentials} from 'app/init/credentials'; import emmProvider from 'app/init/emm_provider'; +import 'app/init/device'; import 'app/init/fetch'; import globalEventHandler from 'app/init/global_event_handler'; import {registerScreens} from 'app/screens'; diff --git a/app/screens/channel/channel_nav_bar/__snapshots__/channel_nav_bar.test.js.snap b/app/screens/channel/channel_nav_bar/__snapshots__/channel_nav_bar.test.js.snap new file mode 100644 index 000000000..65f503959 --- /dev/null +++ b/app/screens/channel/channel_nav_bar/__snapshots__/channel_nav_bar.test.js.snap @@ -0,0 +1,65 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ChannelNavBar should match, full snapshot 1`] = ` + + + + + + +`; diff --git a/app/screens/channel/channel_nav_bar/channel_nav_bar.js b/app/screens/channel/channel_nav_bar/channel_nav_bar.js index 40b9c6e2c..a8db7f6b7 100644 --- a/app/screens/channel/channel_nav_bar/channel_nav_bar.js +++ b/app/screens/channel/channel_nav_bar/channel_nav_bar.js @@ -4,6 +4,9 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import {Dimensions, Platform, View} from 'react-native'; +import AsyncStorage from '@react-native-community/async-storage'; + +import EventEmitter from 'mattermost-redux/utils/event_emitter'; import {DeviceTypes, ViewTypes} from 'app/constants'; import mattermostManaged from 'app/mattermost_managed'; @@ -38,12 +41,15 @@ export default class ChannelNavBar extends PureComponent { componentDidMount() { this.mounted = true; this.handleDimensions(); + this.handlePermanentSidebar(); Dimensions.addEventListener('change', this.handleDimensions); + EventEmitter.on(DeviceTypes.PERMANENT_SIDEBAR_SETTINGS, this.handlePermanentSidebar); } componentWillUnmount() { this.mounted = false; Dimensions.removeEventListener('change', this.handleDimensions); + EventEmitter.off(DeviceTypes.PERMANENT_SIDEBAR_SETTINGS, this.handlePermanentSidebar); } handleDimensions = () => { @@ -55,6 +61,14 @@ export default class ChannelNavBar extends PureComponent { } }; + handlePermanentSidebar = () => { + if (DeviceTypes.IS_TABLET && this.mounted) { + AsyncStorage.getItem(DeviceTypes.PERMANENT_SIDEBAR_SETTINGS).then((enabled) => { + this.setState({permanentSidebar: enabled === 'true'}); + }); + } + }; + render() { const {isLandscape, onPress, theme} = this.props; const {openChannelDrawer, openSettingsDrawer} = this.props; @@ -87,7 +101,7 @@ export default class ChannelNavBar extends PureComponent { } let drawerButtonVisible = false; - if (!DeviceTypes.IS_TABLET || this.state.isSplitView) { + if (!DeviceTypes.IS_TABLET || this.state.isSplitView || !this.state.permanentSidebar) { drawerButtonVisible = true; } diff --git a/app/screens/channel/channel_nav_bar/channel_nav_bar.test.js b/app/screens/channel/channel_nav_bar/channel_nav_bar.test.js new file mode 100644 index 000000000..c7529aa8d --- /dev/null +++ b/app/screens/channel/channel_nav_bar/channel_nav_bar.test.js @@ -0,0 +1,52 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {shallow} from 'enzyme'; + +import Preferences from 'mattermost-redux/constants/preferences'; + +import {DeviceTypes} from 'app/constants'; + +import ChannelNavBar from './channel_nav_bar'; + +jest.mock('react-intl'); + +describe('ChannelNavBar', () => { + const baseProps = { + isLandscape: false, + openChannelDrawer: jest.fn(), + openSettingsDrawer: jest.fn(), + onPress: jest.fn(), + theme: Preferences.THEMES.default, + }; + + test('should match, full snapshot', () => { + const wrapper = shallow( + + ); + + expect(wrapper.getElement()).toMatchSnapshot(); + }); + + test('should not set the permanentSidebar state if not Tablet', () => { + const wrapper = shallow( + + ); + + wrapper.instance().handlePermanentSidebar(); + expect(wrapper.state('permanentSidebar')).toBeUndefined(); + }); + + test('should set the permanentSidebar state if Tablet', async () => { + const wrapper = shallow( + + ); + + DeviceTypes.IS_TABLET = true; + + await wrapper.instance().handlePermanentSidebar(); + + expect(wrapper.state('permanentSidebar')).toBeDefined(); + }); +}); diff --git a/app/screens/index.js b/app/screens/index.js index 498e7171a..3228745d0 100644 --- a/app/screens/index.js +++ b/app/screens/index.js @@ -28,7 +28,7 @@ export function registerScreens(store, Provider) { Navigation.registerComponent('ChannelMembers', () => wrapper(require('app/screens/channel_members').default), () => require('app/screens/channel_members').default); Navigation.registerComponent('ChannelPeek', () => wrapper(require('app/screens/channel_peek').default), () => require('app/screens/channel_peek').default); Navigation.registerComponent('ClientUpgrade', () => wrapper(require('app/screens/client_upgrade').default), () => require('app/screens/client_upgrade').default); - Navigation.registerComponent('ClockDisplay', () => wrapper(require('app/screens/clock_display').default), () => require('app/screens/clock_display').default); + Navigation.registerComponent('ClockDisplaySettings', () => wrapper(require('app/screens/settings/clock_display').default), () => require('app/screens/settings/clock_display').default); Navigation.registerComponent('Code', () => wrapper(require('app/screens/code').default), () => require('app/screens/code').default); Navigation.registerComponent('CreateChannel', () => wrapper(require('app/screens/create_channel').default), () => require('app/screens/create_channel').default); Navigation.registerComponent('DisplaySettings', () => wrapper(require('app/screens/settings/display_settings').default), () => require('app/screens/settings/display_settings').default); @@ -64,16 +64,17 @@ export function registerScreens(store, Provider) { Navigation.registerComponent('SelectorScreen', () => wrapper(require('app/screens/selector_screen').default), () => require('app/screens/selector_screen').default); Navigation.registerComponent('SelectServer', () => wrapper(SelectServer), () => SelectServer); Navigation.registerComponent('SelectTeam', () => wrapper(require('app/screens/select_team').default), () => require('app/screens/select_team').default); - Navigation.registerComponent('SelectTimezone', () => wrapper(require('app/screens/timezone/select_timezone').default), () => require('app/screens/timezone/select_timezone').default); + Navigation.registerComponent('SelectTimezone', () => wrapper(require('app/screens/settings/timezone/select_timezone').default), () => require('app/screens/settings/timezone/select_timezone').default); Navigation.registerComponent('Settings', () => wrapper(require('app/screens/settings/general').default), () => require('app/screens/settings/general').default); + Navigation.registerComponent('SidebarSettings', () => wrapper(require('app/screens//settings/sidebar').default), () => require('app/screens/settings/sidebar').default); Navigation.registerComponent('SSO', () => wrapper(require('app/screens/sso').default), () => require('app/screens/sso').default); Navigation.registerComponent('Table', () => wrapper(require('app/screens/table').default), () => require('app/screens/table').default); Navigation.registerComponent('TableImage', () => wrapper(require('app/screens/table_image').default), () => require('app/screens/table_image').default); Navigation.registerComponent('TermsOfService', () => wrapper(require('app/screens/terms_of_service').default), () => require('app/screens/terms_of_service').default); Navigation.registerComponent('TextPreview', () => wrapper(require('app/screens/text_preview').default), () => require('app/screens/text_preview').default); - Navigation.registerComponent('ThemeSettings', () => wrapper(require('app/screens/theme').default), () => require('app/screens/theme').default); + Navigation.registerComponent('ThemeSettings', () => wrapper(require('app/screens/settings/theme').default), () => require('app/screens/settings/theme').default); Navigation.registerComponent('Thread', () => wrapper(require('app/screens/thread').default), () => require('app/screens/thread').default); - Navigation.registerComponent('TimezoneSettings', () => wrapper(require('app/screens/timezone').default), () => require('app/screens/timezone').default); + Navigation.registerComponent('TimezoneSettings', () => wrapper(require('app/screens/settings/timezone').default), () => require('app/screens/settings/timezone').default); Navigation.registerComponent('ErrorTeamsList', () => wrapper(require('app/screens/error_teams_list').default), () => require('app/screens/error_teams_list').default); Navigation.registerComponent('UserProfile', () => wrapper(require('app/screens/user_profile').default), () => require('app/screens/user_profile').default); -} \ No newline at end of file +} diff --git a/app/screens/clock_display/clock_display.android.js b/app/screens/settings/clock_display/clock_display.android.js similarity index 99% rename from app/screens/clock_display/clock_display.android.js rename to app/screens/settings/clock_display/clock_display.android.js index 25ddeb905..f24470c87 100644 --- a/app/screens/clock_display/clock_display.android.js +++ b/app/screens/settings/clock_display/clock_display.android.js @@ -19,7 +19,7 @@ import ClockDisplayBase from './clock_display_base'; export default class ClockDisplay extends ClockDisplayBase { static propTypes = { showModal: PropTypes.bool.isRequired, - militaryTime: PropTypes.bool.isRequired, + militaryTime: PropTypes.string.isRequired, onClose: PropTypes.func.isRequired, }; diff --git a/app/screens/clock_display/clock_display.ios.js b/app/screens/settings/clock_display/clock_display.ios.js similarity index 100% rename from app/screens/clock_display/clock_display.ios.js rename to app/screens/settings/clock_display/clock_display.ios.js diff --git a/app/screens/clock_display/clock_display_base.js b/app/screens/settings/clock_display/clock_display_base.js similarity index 100% rename from app/screens/clock_display/clock_display_base.js rename to app/screens/settings/clock_display/clock_display_base.js diff --git a/app/screens/clock_display/index.js b/app/screens/settings/clock_display/index.js similarity index 100% rename from app/screens/clock_display/index.js rename to app/screens/settings/clock_display/index.js diff --git a/app/screens/settings/display_settings/__snapshots__/display_settings.test.js.snap b/app/screens/settings/display_settings/__snapshots__/display_settings.test.js.snap index 21cf7668f..5ad51bbf2 100644 --- a/app/screens/settings/display_settings/__snapshots__/display_settings.test.js.snap +++ b/app/screens/settings/display_settings/__snapshots__/display_settings.test.js.snap @@ -76,3 +76,118 @@ exports[`DisplaySettings should match snapshot 1`] = ` `; + +exports[`DisplaySettings should match snapshot on Tablet devices 1`] = ` + + + + + + + + + +`; diff --git a/app/screens/settings/display_settings/display_settings.js b/app/screens/settings/display_settings/display_settings.js index a4ca423c5..363ecc24f 100644 --- a/app/screens/settings/display_settings/display_settings.js +++ b/app/screens/settings/display_settings/display_settings.js @@ -9,13 +9,13 @@ import { View, } from 'react-native'; -import SettingsItem from 'app/screens/settings/settings_item'; +import {DeviceTypes} from 'app/constants'; import StatusBar from 'app/components/status_bar'; +import ClockDisplay from 'app/screens/settings/clock_display'; +import SettingsItem from 'app/screens/settings/settings_item'; import {preventDoubleTap} from 'app/utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; -import ClockDisplay from 'app/screens/clock_display'; - export default class DisplaySettings extends PureComponent { static propTypes = { actions: PropTypes.shape({ @@ -53,6 +53,15 @@ export default class DisplaySettings extends PureComponent { this.setState({showClockDisplaySettings: true}); }); + goToSidebarSettings = preventDoubleTap(() => { + const {actions, theme} = this.props; + const {intl} = this.context; + const screen = 'SidebarSettings'; + const title = intl.formatMessage({id: 'mobile.display_settings.sidebar', defaultMessage: 'Sidebar'}); + + actions.goToScreen(screen, title, {theme}); + }); + goToTimezoneSettings = preventDoubleTap(() => { const {actions} = this.props; const {intl} = this.context; @@ -104,11 +113,28 @@ export default class DisplaySettings extends PureComponent { ); } + let sidebar; + if (DeviceTypes.IS_TABLET) { + sidebar = ( + + ); + } + return ( + {sidebar} {enableTheme && ( { wrapper.setProps({enableTimezone: true}); expect(wrapper.find(SettingsItem).length).toBe(3); }); + + test('should match snapshot on Tablet devices', () => { + DeviceTypes.IS_TABLET = true; + + const wrapper = shallow( + , + ); + + expect(wrapper.getElement()).toMatchSnapshot(); + expect(wrapper.find(SettingsItem).length).toBe(2); + wrapper.setProps({enableTheme: true}); + expect(wrapper.find(SettingsItem).length).toBe(3); + wrapper.setProps({enableTimezone: true}); + expect(wrapper.find(SettingsItem).length).toBe(4); + }); }); diff --git a/app/screens/settings/sidebar/__snapshots__/sidebar.test.js.snap b/app/screens/settings/sidebar/__snapshots__/sidebar.test.js.snap new file mode 100644 index 000000000..861ccb1f1 --- /dev/null +++ b/app/screens/settings/sidebar/__snapshots__/sidebar.test.js.snap @@ -0,0 +1,119 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SidebarSettings should match, full snapshot 1`] = `null`; + +exports[`SidebarSettings should match, full snapshot 2`] = ` + + + +
+ + + } + label={ + + } + selected={false} + theme={ + Object { + "awayIndicator": "#ffbc42", + "buttonBg": "#166de0", + "buttonColor": "#ffffff", + "centerChannelBg": "#ffffff", + "centerChannelColor": "#3d3c40", + "codeTheme": "github", + "dndIndicator": "#f74343", + "errorTextColor": "#fd5960", + "linkColor": "#2389d7", + "mentionBj": "#ffffff", + "mentionColor": "#145dbf", + "mentionHighlightBg": "#ffe577", + "mentionHighlightLink": "#166de0", + "newMessageSeparator": "#ff8800", + "onlineIndicator": "#06d6a0", + "sidebarBg": "#145dbf", + "sidebarHeaderBg": "#1153ab", + "sidebarHeaderTextColor": "#ffffff", + "sidebarText": "#ffffff", + "sidebarTextActiveBorder": "#579eff", + "sidebarTextActiveColor": "#ffffff", + "sidebarTextHoverBg": "#4578bf", + "sidebarUnreadText": "#ffffff", + "type": "Mattermost", + } + } + /> + +
+
+
+`; diff --git a/app/screens/settings/sidebar/index.js b/app/screens/settings/sidebar/index.js new file mode 100644 index 000000000..299d0d402 --- /dev/null +++ b/app/screens/settings/sidebar/index.js @@ -0,0 +1,119 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React, {PureComponent} from 'react'; +import PropTypes from 'prop-types'; +import { + View, + Platform, +} from 'react-native'; +import {intlShape} from 'react-intl'; +import AsyncStorage from '@react-native-community/async-storage'; + +import EventEmitter from 'mattermost-redux/utils/event_emitter'; + +import {DeviceTypes} from 'app/constants'; +import FormattedText from 'app/components/formatted_text'; +import StatusBar from 'app/components/status_bar'; +import Section from 'app/screens/settings/section'; +import SectionItem from 'app/screens/settings/section_item'; +import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; + +export default class SidebarSettings extends PureComponent { + static propTypes = { + theme: PropTypes.object.isRequired, + }; + + static contextTypes = { + intl: intlShape, + }; + + constructor(props) { + super(props); + + this.loadSetting(); + } + + loadSetting = async () => { + const value = await AsyncStorage.getItem(DeviceTypes.PERMANENT_SIDEBAR_SETTINGS); + const enabled = Boolean(value === 'true'); + this.setState({enabled}); + }; + + saveSetting = (enabled) => { + AsyncStorage.setItem(DeviceTypes.PERMANENT_SIDEBAR_SETTINGS, enabled.toString()); + this.setState({enabled}, () => EventEmitter.emit(DeviceTypes.PERMANENT_SIDEBAR_SETTINGS)); + }; + + render() { + if (!this.state) { + return null; + } + + const { + theme, + } = this.props; + const {enabled} = this.state; + const style = getStyleSheet(theme); + + return ( + + + +
+ + + )} + description={( + + )} + action={this.saveSetting} + actionType='toggle' + selected={enabled} + theme={theme} + /> + +
+
+
+ ); + } +} + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + container: { + flex: 1, + backgroundColor: theme.centerChannelBg, + }, + wrapper: { + backgroundColor: changeOpacity(theme.centerChannelColor, 0.06), + flex: 1, + ...Platform.select({ + ios: { + paddingTop: 35, + }, + }), + }, + divider: { + backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), + height: 1, + }, + separator: { + backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), + height: 1, + marginLeft: 15, + }, + }; +}); diff --git a/app/screens/settings/sidebar/sidebar.test.js b/app/screens/settings/sidebar/sidebar.test.js new file mode 100644 index 000000000..96f85384d --- /dev/null +++ b/app/screens/settings/sidebar/sidebar.test.js @@ -0,0 +1,79 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {shallow} from 'enzyme'; + +import Preferences from 'mattermost-redux/constants/preferences'; + +import {DeviceTypes} from 'app/constants'; +import MainSidebar from 'app/components/sidebars/main/main_sidebar'; +import SidebarSettings from './index'; + +jest.mock('react-intl'); +jest.mock('app/mattermost_managed', () => ({ + isRunningInSplitView: jest.fn().mockResolvedValue(false), +})); + +describe('SidebarSettings', () => { + const baseProps = { + theme: Preferences.THEMES.default, + }; + + test('should match, full snapshot', async () => { + const wrapper = shallow( + + ); + + expect(wrapper.getElement()).toMatchSnapshot(); + + await wrapper.instance().loadSetting(); + expect(wrapper.getElement()).toMatchSnapshot(); + }); + + test('should set the Permanent Sidebar value to false', async () => { + const wrapper = shallow( + + ); + + await wrapper.instance().loadSetting(); + expect(wrapper.state('enabled')).toBe(false); + }); + + test('should set the Permanent Sidebar value to true and update the sidebar', async () => { + DeviceTypes.IS_TABLET = true; + + const wrapper = shallow( + + ); + + const mainProps = { + actions: { + getTeams: jest.fn(), + logChannelSwitch: jest.fn(), + makeDirectChannel: jest.fn(), + setChannelDisplayName: jest.fn(), + setChannelLoading: jest.fn(), + }, + blurPostTextBox: jest.fn(), + currentTeamId: 'current-team-id', + currentUserId: 'current-user-id', + deviceWidth: 10, + isLandscape: false, + teamsCount: 2, + theme: Preferences.THEMES.default, + }; + + const mainSidebar = shallow( + + ); + + await wrapper.instance().loadSetting(); + expect(wrapper.state('enabled')).toBe(false); + + await wrapper.instance().saveSetting(true); + + expect(wrapper.state('enabled')).toBe(true); + expect(mainSidebar.state('permanentSidebar')).toBe(true); + }); +}); diff --git a/app/screens/theme/__snapshots__/theme.test.js.snap b/app/screens/settings/theme/__snapshots__/theme.test.js.snap similarity index 100% rename from app/screens/theme/__snapshots__/theme.test.js.snap rename to app/screens/settings/theme/__snapshots__/theme.test.js.snap diff --git a/app/screens/theme/index.js b/app/screens/settings/theme/index.js similarity index 100% rename from app/screens/theme/index.js rename to app/screens/settings/theme/index.js diff --git a/app/screens/theme/theme.js b/app/screens/settings/theme/theme.js similarity index 100% rename from app/screens/theme/theme.js rename to app/screens/settings/theme/theme.js diff --git a/app/screens/theme/theme.test.js b/app/screens/settings/theme/theme.test.js similarity index 100% rename from app/screens/theme/theme.test.js rename to app/screens/settings/theme/theme.test.js diff --git a/app/screens/theme/theme_tile.js b/app/screens/settings/theme/theme_tile.js similarity index 100% rename from app/screens/theme/theme_tile.js rename to app/screens/settings/theme/theme_tile.js diff --git a/app/screens/timezone/index.js b/app/screens/settings/timezone/index.js similarity index 100% rename from app/screens/timezone/index.js rename to app/screens/settings/timezone/index.js diff --git a/app/screens/timezone/select_timezone/index.js b/app/screens/settings/timezone/select_timezone/index.js similarity index 100% rename from app/screens/timezone/select_timezone/index.js rename to app/screens/settings/timezone/select_timezone/index.js diff --git a/app/screens/timezone/select_timezone/select_timezone.js b/app/screens/settings/timezone/select_timezone/select_timezone.js similarity index 100% rename from app/screens/timezone/select_timezone/select_timezone.js rename to app/screens/settings/timezone/select_timezone/select_timezone.js diff --git a/app/screens/timezone/select_timezone/select_timezone_row.js b/app/screens/settings/timezone/select_timezone/select_timezone_row.js similarity index 100% rename from app/screens/timezone/select_timezone/select_timezone_row.js rename to app/screens/settings/timezone/select_timezone/select_timezone_row.js diff --git a/app/screens/timezone/timezone.js b/app/screens/settings/timezone/timezone.js similarity index 100% rename from app/screens/timezone/timezone.js rename to app/screens/settings/timezone/timezone.js diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 26c3fb32c..fbb3099f8 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -207,6 +207,7 @@ "mobile.create_channel.public": "New Public Channel", "mobile.create_post.read_only": "This channel is read-only", "mobile.custom_list.no_results": "No Results", + "mobile.display_settings.sidebar": "Sidebar", "mobile.display_settings.theme": "Theme", "mobile.document_preview.failed_description": "An error occurred while opening the document. Please make sure you have a {fileType} viewer installed and try again.\n", "mobile.document_preview.failed_title": "Open Document failed", @@ -435,11 +436,12 @@ "mobile.share_extension.error_message": "An error has occurred while using the share extension.", "mobile.share_extension.error_title": "Extension Error", "mobile.share_extension.team": "Team", + "mobile.sidebar_settings.permanent": "Permanent Sidebar", + "mobile.sidebar_settings.permanent_description": "Keep the sidebar open permanently", "mobile.suggestion.members": "Members", "mobile.terms_of_service.alert_cancel": "Cancel", "mobile.terms_of_service.alert_ok": "OK", "mobile.terms_of_service.alert_retry": "Try Again", - "mobile.terms_of_service.get_terms_error_description": "Make sure you have an internet connection or {refresh}. If this issue persists, contact your System Administrator.", "mobile.terms_of_service.terms_rejected": "You must agree to the terms of service before accessing {siteName}. Please contact your System Administrator for more details.", "mobile.timezone_settings.automatically": "Set automatically", "mobile.timezone_settings.manual": "Change timezone",