diff --git a/app/components/widgets/settings/bool_setting.js b/app/components/widgets/settings/bool_setting.js
new file mode 100644
index 000000000..c9e7f324c
--- /dev/null
+++ b/app/components/widgets/settings/bool_setting.js
@@ -0,0 +1,184 @@
+// 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,
+ Text,
+ Switch,
+} from 'react-native';
+
+import FormattedText from 'app/components/formatted_text';
+import {
+ changeOpacity,
+ makeStyleSheetFromTheme,
+} from 'app/utils/theme';
+import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
+
+export default class BoolSetting extends PureComponent {
+ static propTypes = {
+ id: PropTypes.string.isRequired,
+ label: PropTypes.oneOfType([
+ PropTypes.shape({
+ id: PropTypes.string.isRequired,
+ defaultMessage: PropTypes.string.isRequired,
+ }),
+ PropTypes.string,
+ ]),
+ value: PropTypes.bool.isRequired,
+ placeholder: PropTypes.string,
+ helpText: PropTypes.node,
+ errorText: PropTypes.node,
+ optional: PropTypes.bool,
+ theme: PropTypes.object.isRequired,
+ onChange: PropTypes.func.isRequired,
+ isLandscape: PropTypes.bool.isRequired,
+ };
+
+ static defaultProps = {
+ isLandscape: false,
+ };
+
+ handleChange = (value) => {
+ this.props.onChange(this.props.id, `${value}`);
+ };
+
+ render() {
+ const {
+ label,
+ value,
+ placeholder,
+ helpText,
+ errorText,
+ optional,
+ theme,
+ isLandscape,
+ } = this.props;
+ const style = getStyleSheet(theme);
+
+ let optionalContent;
+ let asterisk;
+ if (optional) {
+ optionalContent = (
+
+ );
+ } else {
+ asterisk = {' *'};
+ }
+
+ let labelContent;
+ if (label) {
+ labelContent = (
+
+
+ {label}
+
+ {asterisk}
+ {optionalContent}
+
+
+ );
+ }
+
+ let helpTextContent;
+ if (helpText) {
+ helpTextContent = (
+
+ {helpText}
+
+ );
+ }
+
+ let errorTextContent;
+ if (errorText) {
+ errorTextContent = (
+
+ {errorText}
+
+ );
+ }
+
+ return (
+
+ {labelContent}
+
+
+
+ {placeholder}
+
+
+
+
+
+ {helpTextContent}
+ {errorTextContent}
+
+
+ );
+ }
+}
+
+const getStyleSheet = makeStyleSheetFromTheme((theme) => {
+ return {
+ labelContainer: {
+ flexDirection: 'row',
+ marginTop: 15,
+ marginBottom: 10,
+ },
+ label: {
+ fontSize: 14,
+ color: theme.centerChannelColor,
+ marginLeft: 15,
+ },
+ inputContainer: {
+ backgroundColor: theme.centerChannelBg,
+ flexDirection: 'row',
+ alignItems: 'center',
+ paddingHorizontal: 15,
+ height: 40,
+ },
+ placeholderText: {
+ color: changeOpacity(theme.centerChannelColor, 0.5),
+ fontSize: 15,
+ },
+ inputSwitch: {
+ position: 'absolute',
+ right: 12,
+ },
+ separator: {
+ backgroundColor: changeOpacity(theme.centerChannelColor, 0.1),
+ height: 1,
+ width: '100%',
+ },
+ optional: {
+ color: changeOpacity(theme.centerChannelColor, 0.5),
+ fontSize: 14,
+ marginLeft: 5,
+ },
+ helpText: {
+ fontSize: 12,
+ color: changeOpacity(theme.centerChannelColor, 0.5),
+ marginHorizontal: 15,
+ marginTop: 10,
+ },
+ errorText: {
+ fontSize: 12,
+ color: theme.errorTextColor,
+ marginHorizontal: 15,
+ marginVertical: 10,
+ },
+ asterisk: {
+ color: theme.errorTextColor,
+ fontSize: 14,
+ },
+ };
+});
diff --git a/app/components/widgets/settings/bool_setting.test.js b/app/components/widgets/settings/bool_setting.test.js
new file mode 100644
index 000000000..72c9da7f7
--- /dev/null
+++ b/app/components/widgets/settings/bool_setting.test.js
@@ -0,0 +1,35 @@
+// 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 BoolSetting from './bool_setting.js';
+
+describe('components/widgets/settings/TextSetting', () => {
+ const theme = Preferences.THEMES.default;
+ test('onChange', () => {
+ const onChange = jest.fn();
+ const wrapper = shallow(
+
+ );
+
+ wrapper.instance().handleChange(false);
+ expect(onChange).toHaveBeenCalledTimes(1);
+ expect(onChange).toHaveBeenCalledWith('elementid', 'false');
+
+ wrapper.instance().handleChange(true);
+ expect(onChange).toHaveBeenCalledTimes(2);
+ expect(onChange).toHaveBeenCalledWith('elementid', 'true');
+ });
+});
diff --git a/app/screens/interactive_dialog/dialog_element.js b/app/screens/interactive_dialog/dialog_element.js
index 59bcf61fe..89b5f734e 100644
--- a/app/screens/interactive_dialog/dialog_element.js
+++ b/app/screens/interactive_dialog/dialog_element.js
@@ -4,6 +4,7 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
+import BoolSetting from 'app/components/widgets/settings/bool_setting';
import TextSetting from 'app/components/widgets/settings/text_setting';
import AutocompleteSelector from 'app/components/autocomplete_selector';
@@ -26,6 +27,7 @@ export default class DialogElement extends PureComponent {
value: PropTypes.any,
onChange: PropTypes.func,
theme: PropTypes.object,
+ isLandscape: PropTypes.bool.isRequired,
};
constructor(props) {
@@ -70,6 +72,7 @@ export default class DialogElement extends PureComponent {
theme,
dataSource,
options,
+ isLandscape,
} = this.props;
let {maxLength} = this.props;
@@ -133,8 +136,23 @@ export default class DialogElement extends PureComponent {
roundedBorders={false}
/>
);
+ } else if (type === 'bool') {
+ return (
+
+ );
}
return null;
}
-}
\ No newline at end of file
+}
diff --git a/app/screens/interactive_dialog/dialog_element.test.js b/app/screens/interactive_dialog/dialog_element.test.js
index cf357fbe2..2b64e9d83 100644
--- a/app/screens/interactive_dialog/dialog_element.test.js
+++ b/app/screens/interactive_dialog/dialog_element.test.js
@@ -13,6 +13,7 @@ describe('DialogElement', () => {
displayName: 'Testing',
name: 'testing',
type: 'text',
+ isLandscape: false,
};
const theme = Preferences.THEMES.default;
test('secureTextEntry is true and multiline is false when subtype is password', () => {
@@ -36,4 +37,4 @@ describe('DialogElement', () => {
);
expect(wrapper.find({secureTextEntry: false}).exists()).toBe(true);
});
-});
\ No newline at end of file
+});
diff --git a/app/screens/interactive_dialog/interactive_dialog.js b/app/screens/interactive_dialog/interactive_dialog.js
index e6bd696bb..8ac992323 100644
--- a/app/screens/interactive_dialog/interactive_dialog.js
+++ b/app/screens/interactive_dialog/interactive_dialog.js
@@ -3,7 +3,7 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
-import {ScrollView, View} from 'react-native';
+import {Dimensions, ScrollView, View} from 'react-native';
import {Navigation} from 'react-native-navigation';
import {checkDialogElementForError, checkIfErrorsMatchElements} from 'mattermost-redux/utils/integration_utils';
@@ -49,12 +49,27 @@ export default class InteractiveDialog extends PureComponent {
this.state = {
values,
errors: {},
+ isLandscape: this.isLandscape(),
submitting: false,
};
}
componentDidMount() {
this.navigationEventListener = Navigation.events().bindComponent(this);
+ Dimensions.addEventListener('change', this.orientationDidChange);
+ }
+
+ componentWillUnmount() {
+ Dimensions.removeEventListener('change', this.orientationDidChange);
+ }
+
+ orientationDidChange = () => {
+ this.setState({isLandscape: this.isLandscape()});
+ }
+
+ isLandscape = () => {
+ const {height, width} = Dimensions.get('window');
+ return width > height;
}
navigationButtonPressed({buttonId}) {
@@ -153,6 +168,7 @@ export default class InteractiveDialog extends PureComponent {
render() {
const {introductionText, elements, theme} = this.props;
+ const {errors, isLandscape, values} = this.state;
const style = getStyleFromTheme(theme);
return (
@@ -174,16 +190,17 @@ export default class InteractiveDialog extends PureComponent {
type={e.type}
subtype={e.subtype}
helpText={e.help_text}
- errorText={this.state.errors[e.name]}
+ errorText={errors[e.name]}
placeholder={e.placeholder}
minLength={e.min_length}
maxLength={e.max_length}
dataSource={e.data_source}
optional={e.optional}
options={e.options}
- value={this.state.values[e.name]}
+ value={values[e.name]}
onChange={this.onChange}
theme={theme}
+ isLandscape={isLandscape}
/>
);
})}