@@ -17,7 +17,7 @@ limitations under the License.
1717import classNames from 'classnames' ;
1818import { IEventRelation } from "matrix-js-sdk/src/models/event" ;
1919import { M_POLL_START } from "matrix-events-sdk" ;
20- import React , { useContext } from 'react' ;
20+ import React , { ReactElement , useContext } from 'react' ;
2121import { Room } from 'matrix-js-sdk/src/models/room' ;
2222import { MatrixClient } from 'matrix-js-sdk/src/client' ;
2323
@@ -56,85 +56,55 @@ const MessageComposerButtons: React.FC<IProps> = (props: IProps) => {
5656 const matrixClient : MatrixClient = useContext ( MatrixClientContext ) ;
5757 const { room, roomId } = useContext ( RoomContext ) ;
5858
59- if ( props . haveRecording ) {
60- return null ;
61- }
62-
63- let uploadButtonIndex = 0 ;
64- const buttons : JSX . Element [ ] = [ ] ;
65- buttons . push (
66- < PollButton
67- key = "polls"
68- room = { room }
69- narrowMode = { props . narrowMode }
70- /> ,
71- ) ;
72- uploadButtonIndex = buttons . length ;
73- buttons . push (
74- < UploadButton key = "controls_upload" roomId = { roomId } relation = { props . relation } /> ,
75- ) ;
76- if ( props . showLocationButton ) {
77- const sender = room . getMember ( matrixClient . getUserId ( ) ) ;
78- buttons . push (
79- < LocationButton
80- key = "location"
81- roomId = { roomId }
82- sender = { sender }
83- menuPosition = { props . menuPosition }
84- narrowMode = { props . narrowMode }
85- /> ,
86- ) ;
87- }
88- buttons . push (
89- < EmojiButton key = "emoji_button" addEmoji = { props . addEmoji } menuPosition = { props . menuPosition } narrowMode = { props . narrowMode } /> ,
59+ return (
60+ props . haveRecording
61+ ? null
62+ : props . narrowMode
63+ ? narrowMode ( props , room , roomId , matrixClient )
64+ : wideMode ( props , room , roomId , matrixClient )
9065 ) ;
91- if ( props . showStickersButton ) {
92- let title : string ;
93- if ( ! props . narrowMode ) {
94- title = props . isStickerPickerOpen ? _t ( "Hide Stickers" ) : _t ( "Show Stickers" ) ;
95- }
96-
97- buttons . push (
98- < AccessibleTooltipButton
99- id = 'stickersButton'
100- key = "controls_stickers"
101- className = "mx_MessageComposer_button mx_MessageComposer_stickers"
102- onClick = { ( ) => props . setStickerPickerOpen ( ! props . isStickerPickerOpen ) }
103- title = { title }
104- label = { props . narrowMode ? _t ( "Send a sticker" ) : null }
105- /> ,
106- ) ;
107- }
108-
109- // XXX: the recording UI does not work well in narrow mode, so we hide this button for now
110- if ( ! props . narrowMode ) {
111- buttons . push (
112- < CollapsibleButton
113- key = "voice_message_send"
114- className = "mx_MessageComposer_button mx_MessageComposer_voiceMessage"
115- onClick = { props . onRecordStartEndClick }
116- title = { _t ( "Send voice message" ) }
117- narrowMode = { props . narrowMode }
118- /> ,
119- ) ;
120- }
66+ } ;
12167
122- if ( ! props . narrowMode ) {
123- return < > { buttons } </ > ;
124- }
68+ function wideMode (
69+ props : IProps ,
70+ room : Room ,
71+ roomId : string ,
72+ matrixClient : MatrixClient ,
73+ ) : ReactElement {
74+ return < >
75+ { pollButton ( props , room ) }
76+ { uploadButton ( props , roomId ) }
77+ { showLocationButton ( props , room , roomId , matrixClient ) }
78+ { emojiButton ( props ) }
79+ { showStickersButton ( props ) }
80+ { voiceRecordingButton ( props ) }
81+ </ > ;
82+ }
12583
126- const classnames = classNames ( {
84+ function narrowMode (
85+ props : IProps ,
86+ room : Room ,
87+ roomId : string ,
88+ matrixClient : MatrixClient ,
89+ ) : ReactElement {
90+ const moreOptionsClasses = classNames ( {
12791 mx_MessageComposer_button : true ,
12892 mx_MessageComposer_buttonMenu : true ,
12993 mx_MessageComposer_closeButtonMenu : props . isMenuOpen ,
13094 } ) ;
13195
132- // we render the uploadButton at top level as it is a very common interaction, splice it out of the rest
133- const [ uploadButton ] = buttons . splice ( uploadButtonIndex , 1 ) ;
96+ const moreButtons = [
97+ pollButton ( props , room ) ,
98+ showLocationButton ( props , room , roomId , matrixClient ) ,
99+ emojiButton ( props ) ,
100+ showStickersButton ( props ) ,
101+ voiceRecordingButton ( props ) ,
102+ ] . filter ( x => x ) ;
103+
134104 return < >
135- { uploadButton }
105+ { uploadButton ( props , roomId ) }
136106 < AccessibleTooltipButton
137- className = { classnames }
107+ className = { moreOptionsClasses }
138108 onClick = { props . toggleButtonMenu }
139109 title = { _t ( "More options" ) }
140110 tooltip = { false }
@@ -145,28 +115,50 @@ const MessageComposerButtons: React.FC<IProps> = (props: IProps) => {
145115 { ...props . menuPosition }
146116 wrapperClassName = "mx_MessageComposer_Menu"
147117 >
148- { buttons . map ( ( button , index ) => (
149- < MenuItem className = "mx_CallContextMenu_item" key = { index } onClick = { props . toggleButtonMenu } >
118+ { moreButtons . map ( ( button , index ) => (
119+ < MenuItem
120+ className = "mx_CallContextMenu_item"
121+ key = { index }
122+ onClick = { props . toggleButtonMenu }
123+ >
150124 { button }
151125 </ MenuItem >
152126 ) ) }
153127 </ ContextMenu >
154128 ) }
155129 </ > ;
156- } ;
130+ }
131+
132+ function emojiButton ( props : IProps ) : ReactElement {
133+ return < EmojiButton
134+ key = "emoji_button"
135+ addEmoji = { props . addEmoji }
136+ menuPosition = { props . menuPosition }
137+ narrowMode = { props . narrowMode }
138+ /> ;
139+ }
157140
158141interface IEmojiButtonProps extends Pick < ICollapsibleButtonProps , "narrowMode" > {
159142 addEmoji : ( unicode : string ) => boolean ;
160143 menuPosition : AboveLeftOf ;
161144}
162145
163- const EmojiButton : React . FC < IEmojiButtonProps > = ( { addEmoji, menuPosition, narrowMode } ) => {
146+ const EmojiButton : React . FC < IEmojiButtonProps > = (
147+ { addEmoji, menuPosition, narrowMode } ,
148+ ) => {
164149 const [ menuDisplayed , button , openMenu , closeMenu ] = useContextMenu ( ) ;
165150
166151 let contextMenu : React . ReactElement | null = null ;
167152 if ( menuDisplayed ) {
168- const position = menuPosition ?? aboveLeftOf ( button . current . getBoundingClientRect ( ) ) ;
169- contextMenu = < ContextMenu { ...position } onFinished = { closeMenu } managed = { false } >
153+ const position = (
154+ menuPosition ?? aboveLeftOf ( button . current . getBoundingClientRect ( ) )
155+ ) ;
156+
157+ contextMenu = < ContextMenu
158+ { ...position }
159+ onFinished = { closeMenu }
160+ managed = { false }
161+ >
170162 < EmojiPicker onChoose = { addEmoji } showQuickReactions = { true } />
171163 </ ContextMenu > ;
172164 }
@@ -193,6 +185,14 @@ const EmojiButton: React.FC<IEmojiButtonProps> = ({ addEmoji, menuPosition, narr
193185 </ React . Fragment > ;
194186} ;
195187
188+ function uploadButton ( props : IProps , roomId : string ) : ReactElement {
189+ return < UploadButton
190+ key = "controls_upload"
191+ roomId = { roomId }
192+ relation = { props . relation }
193+ /> ;
194+ }
195+
196196interface IUploadButtonProps {
197197 roomId : string ;
198198 relation ?: IEventRelation | null ;
@@ -270,6 +270,51 @@ class UploadButton extends React.Component<IUploadButtonProps> {
270270 ) ;
271271 }
272272}
273+
274+ function showStickersButton ( props : IProps ) : ReactElement {
275+ return (
276+ props . showStickersButton
277+ ? < AccessibleTooltipButton
278+ id = 'stickersButton'
279+ key = "controls_stickers"
280+ className = "mx_MessageComposer_button mx_MessageComposer_stickers"
281+ onClick = { ( ) => props . setStickerPickerOpen ( ! props . isStickerPickerOpen ) }
282+ title = {
283+ props . narrowMode
284+ ? null
285+ : props . isStickerPickerOpen
286+ ? _t ( "Hide Stickers" )
287+ : _t ( "Show Stickers" )
288+ }
289+ label = { props . narrowMode ? _t ( "Send a sticker" ) : null }
290+ />
291+ : null
292+ ) ;
293+ }
294+
295+ function voiceRecordingButton ( props : IProps ) : ReactElement {
296+ // XXX: recording UI does not work well in narrow mode, so hide for now
297+ return (
298+ props . narrowMode
299+ ? null
300+ : < CollapsibleButton
301+ key = "voice_message_send"
302+ className = "mx_MessageComposer_button mx_MessageComposer_voiceMessage"
303+ onClick = { props . onRecordStartEndClick }
304+ title = { _t ( "Send voice message" ) }
305+ narrowMode = { props . narrowMode }
306+ />
307+ ) ;
308+ }
309+
310+ function pollButton ( props : IProps , room : Room ) : ReactElement {
311+ return < PollButton
312+ key = "polls"
313+ room = { room }
314+ narrowMode = { props . narrowMode }
315+ /> ;
316+ }
317+
273318interface IPollButtonProps extends Pick < ICollapsibleButtonProps , "narrowMode" > {
274319 room : Room ;
275320}
@@ -281,10 +326,17 @@ class PollButton extends React.PureComponent<IPollButtonProps> {
281326 MatrixClientPeg . get ( ) . getUserId ( ) ,
282327 ) ;
283328 if ( ! canSend ) {
284- Modal . createTrackedDialog ( 'Polls' , 'permissions error: cannot start' , ErrorDialog , {
285- title : _t ( "Permission Required" ) ,
286- description : _t ( "You do not have permission to start polls in this room." ) ,
287- } ) ;
329+ Modal . createTrackedDialog (
330+ 'Polls' ,
331+ 'permissions error: cannot start' ,
332+ ErrorDialog ,
333+ {
334+ title : _t ( "Permission Required" ) ,
335+ description : _t (
336+ "You do not have permission to start polls in this room." ,
337+ ) ,
338+ } ,
339+ ) ;
288340 } else {
289341 Modal . createTrackedDialog (
290342 'Polls' ,
@@ -312,4 +364,23 @@ class PollButton extends React.PureComponent<IPollButtonProps> {
312364 }
313365}
314366
367+ function showLocationButton (
368+ props : IProps ,
369+ room : Room ,
370+ roomId : string ,
371+ matrixClient : MatrixClient ,
372+ ) : ReactElement {
373+ return (
374+ props . showLocationButton
375+ ? < LocationButton
376+ key = "location"
377+ roomId = { roomId }
378+ sender = { room . getMember ( matrixClient . getUserId ( ) ) }
379+ menuPosition = { props . menuPosition }
380+ narrowMode = { props . narrowMode }
381+ />
382+ : null
383+ ) ;
384+ }
385+
315386export default MessageComposerButtons ;
0 commit comments