diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index 704a4745a8..6b6cbc538b 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -87,6 +87,7 @@ interface IState { isMenuOpen: boolean; isStickerPickerOpen: boolean; showStickersButton: boolean; + showPollsButton: boolean; } @replaceableComponent("views.rooms.MessageComposer") @@ -117,11 +118,13 @@ export default class MessageComposer extends React.Component { isMenuOpen: false, isStickerPickerOpen: false, showStickersButton: SettingsStore.getValue("MessageComposerInput.showStickersButton"), + showPollsButton: SettingsStore.getValue("MessageComposerInput.showPollsButton"), }; this.instanceId = instanceCount++; SettingsStore.monitorSetting("MessageComposerInput.showStickersButton", null); + SettingsStore.monitorSetting("MessageComposerInput.showPollsButton", null); } private get voiceRecording(): Optional { @@ -189,6 +192,13 @@ export default class MessageComposer extends React.Component { } break; } + case "MessageComposerInput.showPollsButton": { + const showPollsButton = SettingsStore.getValue("MessageComposerInput.showPollsButton"); + if (this.state.showPollsButton !== showPollsButton) { + this.setState({ showPollsButton }); + } + break; + } } } } @@ -459,6 +469,7 @@ export default class MessageComposer extends React.Component { }} setStickerPickerOpen={this.setStickerPickerOpen} showLocationButton={!window.electron} + showPollsButton={this.state.showPollsButton} showStickersButton={this.state.showStickersButton} toggleButtonMenu={this.toggleButtonMenu} /> } diff --git a/src/components/views/rooms/MessageComposerButtons.tsx b/src/components/views/rooms/MessageComposerButtons.tsx index 7a16b23937..8171d9cb89 100644 --- a/src/components/views/rooms/MessageComposerButtons.tsx +++ b/src/components/views/rooms/MessageComposerButtons.tsx @@ -48,6 +48,7 @@ interface IProps { relation?: IEventRelation; setStickerPickerOpen: (isStickerPickerOpen: boolean) => void; showLocationButton: boolean; + showPollsButton: boolean; showStickersButton: boolean; toggleButtonMenu: () => void; } @@ -73,7 +74,7 @@ const MessageComposerButtons: React.FC = (props: IProps) => { uploadButton(), // props passed via UploadButtonContext showStickersButton(props), voiceRecordingButton(props, narrow), - pollButton(room, props.relation), + props.showPollsButton && pollButton(room, props.relation), showLocationButton(props, room, roomId, matrixClient), ]; } else { @@ -84,7 +85,7 @@ const MessageComposerButtons: React.FC = (props: IProps) => { moreButtons = [ showStickersButton(props), voiceRecordingButton(props, narrow), - pollButton(room, props.relation), + props.showPollsButton && pollButton(room, props.relation), showLocationButton(props, room, roomId, matrixClient), ]; } @@ -295,7 +296,7 @@ interface IPollButtonProps { } class PollButton extends React.PureComponent { - static contextType = OverflowMenuContext; + public static contextType = OverflowMenuContext; public context!: React.ContextType; private onCreateClick = () => { @@ -336,7 +337,7 @@ class PollButton extends React.PureComponent { } }; - render() { + public render() { // do not allow sending polls within threads at this time if (this.props.relation?.rel_type === RelationType.Thread) return null; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index a5860d382e..d146cc5ba1 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -906,6 +906,7 @@ "Use custom size": "Use custom size", "Enable Emoji suggestions while typing": "Enable Emoji suggestions while typing", "Show stickers button": "Show stickers button", + "Show polls button": "Show polls button", "Insert a trailing colon after user mentions at the start of a message": "Insert a trailing colon after user mentions at the start of a message", "Use a more compact 'Modern' layout": "Use a more compact 'Modern' layout", "Show a placeholder for removed messages": "Show a placeholder for removed messages", diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 5d1d3a1c03..0b6574a3dc 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -429,6 +429,11 @@ export const SETTINGS: {[setting: string]: ISetting} = { default: true, controller: new UIFeatureController(UIFeature.Widgets, false), }, + "MessageComposerInput.showPollsButton": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td('Show polls button'), + default: true, + }, "MessageComposerInput.insertTrailingColon": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, displayName: _td('Insert a trailing colon after user mentions at the start of a message'), diff --git a/test/components/views/rooms/MessageComposerButtons-test.tsx b/test/components/views/rooms/MessageComposerButtons-test.tsx index eaab180a5d..d89d0141a4 100644 --- a/test/components/views/rooms/MessageComposerButtons-test.tsx +++ b/test/components/views/rooms/MessageComposerButtons-test.tsx @@ -39,6 +39,7 @@ describe("MessageComposerButtons", () => { {}} />, @@ -57,6 +58,7 @@ describe("MessageComposerButtons", () => { {}} />, @@ -81,6 +83,7 @@ describe("MessageComposerButtons", () => { {}} />, @@ -98,6 +101,7 @@ describe("MessageComposerButtons", () => { {}} />, @@ -115,6 +119,56 @@ describe("MessageComposerButtons", () => { ], ]); }); + + describe('polls button', () => { + it('should render when asked to', () => { + const buttons = wrapAndRender( + {}} + />, + true, + ); + + expect(buttonLabels(buttons)).toEqual([ + "Emoji", + "More options", + [ + "Attachment", + "Sticker", + "Poll", + "Location", + ], + ]); + }); + + it('should not render when asked not to', () => { + const buttons = wrapAndRender( + {}} + />, + true, + ); + + expect(buttonLabels(buttons)).toEqual([ + "Emoji", + "More options", + [ + "Attachment", + "Sticker", + // "Poll", // should be hidden + "Location", + ], + ]); + }); + }); }); function wrapAndRender(component: React.ReactElement, narrow: boolean): ReactWrapper {