@@ -32,7 +32,7 @@ use crate::{
3232 } ,
3333 room:: { BasicRoomDetails , room_input_bar:: { RoomInputBarState , RoomInputBarWidgetRefExt } , typing_notice:: TypingNoticeWidgetExt } ,
3434 shared:: {
35- attachment_download:: { enqueue_already_downloading_notification, DownloadDisplayState , DownloadKind , DownloadableAttachment , PendingDownload , PendingDownloadState , media_source_mxc, start_attachment_download} , avatar:: { AvatarState , AvatarWidgetRefExt } , confirmation_modal:: ConfirmationModalContent , file_upload_modal:: FileUploadAttemptId , html_or_plaintext:: { HtmlOrPlaintextRef , HtmlOrPlaintextWidgetRefExt , RobrixHtmlLinkAction } , image_viewer:: { ImageViewerAction , ImageViewerMetaData , LoadState } , jump_to_bottom_button:: { JumpToBottomButtonWidgetExt , UnreadMessageCount } , popup_list:: { PopupKind , enqueue_popup_notification} , restore_status_view:: RestoreStatusViewWidgetExt , styles:: * , text_or_image:: { TextOrImageAction , TextOrImageRef , TextOrImageStatus , TextOrImageWidgetRefExt } , timestamp:: TimestampWidgetRefExt
35+ attachment_download:: { enqueue_already_downloading_notification, DownloadDisplayState , DownloadKind , DownloadableAttachment , PendingDownload , PendingDownloadState , media_source_mxc, start_attachment_download} , avatar:: { AvatarState , AvatarWidgetRefExt } , confirmation_modal:: ConfirmationModalContent , file_upload_modal:: FileUploadAttemptId , html_or_plaintext:: { HtmlOrPlaintextRef , HtmlOrPlaintextWidgetRefExt , RobrixHtmlLinkAction } , image_viewer:: { ImageViewerAction , ImageViewerMetaData , LoadState } , jump_to_bottom_button:: { JumpToBottomButtonWidgetExt , UnreadMessageCount } , popup_list:: { PopupKind , enqueue_popup_notification} , restore_status_view:: RestoreStatusViewWidgetExt , room_input_popup_menu :: { RoomInputPopupMenuAction , RoomInputPopupMenuWidgetExt } , styles:: * , text_or_image:: { TextOrImageAction , TextOrImageRef , TextOrImageStatus , TextOrImageWidgetRefExt } , timestamp:: TimestampWidgetRefExt
3636 } ,
3737 sliding_sync:: { BackwardsPaginateUntilEventRequest , MatrixRequest , PaginationDirection , TimelineEndpoints , TimelineKind , TimelineRequestSender , UserPowerLevels , get_client, submit_async_request, take_timeline_endpoints} , utils:: { self , ImageFormat , MEDIA_THUMBNAIL_FORMAT , RoomNameId , unix_time_millis_to_datetime}
3838} ;
@@ -693,6 +693,10 @@ script_mod! {
693693 // to finish loading, e.g., when loading an older replied-to message.
694694 loading_pane : = LoadingPane { }
695695
696+ // The popup menu for uploading/sending other content to this room,
697+ // which is controlled by actions from the RoomInputBar.
698+ room_input_popup_menu : = RoomInputPopupMenu { }
699+
696700
697701 /*
698702 * TODO: add the action bar back in as a series of floating buttons.
@@ -766,13 +770,18 @@ impl Widget for RoomScreen {
766770 let portal_list = self . portal_list ( cx, ids ! ( timeline. list) ) ;
767771 let user_profile_sliding_pane = self . user_profile_sliding_pane ( cx, ids ! ( user_profile_sliding_pane) ) ;
768772 let loading_pane = self . loading_pane ( cx, ids ! ( loading_pane) ) ;
773+ let room_input_popup_menu = self . room_input_popup_menu ( cx, ids ! ( room_input_popup_menu) ) ;
769774
770775 // Handle actions here before processing timeline updates.
771776 // Normally (in most other widgets), the order of event handling doesn't matter much.
772777 // However, since actions may refer to a specific timeline item's index,
773778 // we want to handle those before processing any updates that might change
774779 // the set of timeline indices (which would invalidate the index values in any actions).
775780 if let Event :: Actions ( actions) = event {
781+ if let Some ( action) = room_input_popup_menu. selected ( actions) {
782+ self . handle_room_input_popup_menu_action ( cx, action) ;
783+ }
784+
776785 for ( index, wr) in portal_list. items_with_actions ( actions) {
777786 // Handle a hover-in action on the reaction list: show a reaction summary.
778787 let reaction_list = wr. reaction_list ( cx, ids ! ( reaction_list) ) ;
@@ -1016,7 +1025,27 @@ impl Widget for RoomScreen {
10161025 //
10171026 let is_interactive_hit = utils:: is_interactive_hit_event ( event) ;
10181027 let is_pane_shown: bool ;
1019- if loading_pane. is_currently_shown ( cx) {
1028+ let mut close_room_input_popup_menu_after_forwarding = false ;
1029+ if room_input_popup_menu. is_open ( ) {
1030+ if event. back_pressed ( ) || matches ! ( event, Event :: KeyUp ( KeyEvent { key_code: KeyCode :: Escape , .. } ) ) {
1031+ room_input_popup_menu. close ( cx) ;
1032+ is_pane_shown = true ;
1033+ }
1034+ else if is_interactive_hit {
1035+ if room_input_popup_menu. is_event_within_popup_menu ( cx, event) {
1036+ is_pane_shown = true ;
1037+ room_input_popup_menu. handle_event ( cx, event, scope) ;
1038+ } else {
1039+ // Let outside clicks, hovers, and mouse moves fall through to the underlying UI.
1040+ close_room_input_popup_menu_after_forwarding =
1041+ room_input_popup_menu. should_dismiss_for_outside_event ( cx, event) ;
1042+ is_pane_shown = false ;
1043+ }
1044+ } else {
1045+ is_pane_shown = false ;
1046+ }
1047+ }
1048+ else if loading_pane. is_currently_shown ( cx) {
10201049 is_pane_shown = true ;
10211050 if is_interactive_hit {
10221051 loading_pane. handle_event ( cx, event, scope) ;
@@ -1102,6 +1131,15 @@ impl Widget for RoomScreen {
11021131 return false ;
11031132 }
11041133
1134+ // Handle actions related to the room input popup menu.
1135+ match action. as_widget_action ( ) . cast ( ) {
1136+ RoomInputPopupMenuAction :: None => { }
1137+ room_popup_menu_action => {
1138+ self . handle_room_input_popup_menu_action ( cx, room_popup_menu_action) ;
1139+ return false ;
1140+ }
1141+ }
1142+
11051143 // Handle the action that requests to show the user profile sliding pane.
11061144 if let ShowUserProfileAction :: ShowUserProfile ( profile_and_room_id) = action. as_widget_action ( ) . cast ( ) {
11071145 self . show_user_profile (
@@ -1160,10 +1198,17 @@ impl Widget for RoomScreen {
11601198 } ) ;
11611199 // Add back any unhandled actions to the global action list.
11621200 cx. extend_actions ( actions_generated_within_this_room_screen) ;
1201+
1202+ if close_room_input_popup_menu_after_forwarding {
1203+ let room_input_popup_menu =
1204+ self . room_input_popup_menu ( cx, ids ! ( room_input_popup_menu) ) ;
1205+ if room_input_popup_menu. is_open ( ) {
1206+ room_input_popup_menu. close ( cx) ;
1207+ }
1208+ }
11631209 }
11641210 }
11651211
1166-
11671212 fn draw_walk ( & mut self , cx : & mut Cx2d , scope : & mut Scope , walk : Walk ) -> DrawStep {
11681213 // If the room isn't loaded yet, we show the restore status label only.
11691214 if !self . is_loaded {
@@ -1375,6 +1420,51 @@ impl RoomScreen {
13751420 self . room_name_id . as_ref ( ) . map ( |r| r. room_id ( ) )
13761421 }
13771422
1423+ fn show_room_input_popup_menu ( & mut self , cx : & mut Cx , button_rect : Rect ) {
1424+ let popup_menu = self . room_input_popup_menu ( cx, ids ! ( room_input_popup_menu) ) ;
1425+ let room_screen_rect = self . view ( cx, ids ! ( room_screen_wrapper) ) . area ( ) . rect ( cx) ;
1426+ let margin = Inset {
1427+ left : button_rect. pos . x - room_screen_rect. pos . x ,
1428+ top : 0.0 ,
1429+ right : 0.0 ,
1430+ bottom : room_screen_rect. pos . y + room_screen_rect. size . y
1431+ - button_rect. pos . y
1432+ + 9.0
1433+ } ;
1434+
1435+ let mut main_content = popup_menu. view ( cx, ids ! ( main_content) ) ;
1436+ script_apply_eval ! ( cx, main_content, {
1437+ margin: #( margin)
1438+ } ) ;
1439+ popup_menu. show ( cx) ;
1440+ self . view . redraw ( cx) ;
1441+ }
1442+
1443+ fn handle_room_input_popup_menu_action (
1444+ & mut self ,
1445+ cx : & mut Cx ,
1446+ action : RoomInputPopupMenuAction ,
1447+ ) {
1448+ let room_input_bar = self . view . room_input_bar ( cx, ids ! ( room_input_bar) ) ;
1449+ match action {
1450+ RoomInputPopupMenuAction :: Show { button_rect } => {
1451+ self . show_room_input_popup_menu ( cx, button_rect) ;
1452+ }
1453+ RoomInputPopupMenuAction :: UploadPhotoOrVideo => {
1454+ let Some ( timeline_kind) = self . timeline_kind . clone ( ) else { return } ;
1455+ room_input_bar. open_photo_video_picker ( cx, timeline_kind) ;
1456+ }
1457+ RoomInputPopupMenuAction :: UploadFile => {
1458+ let Some ( timeline_kind) = self . timeline_kind . clone ( ) else { return } ;
1459+ room_input_bar. open_file_picker ( cx, timeline_kind) ;
1460+ }
1461+ RoomInputPopupMenuAction :: SendCurrentLocation => {
1462+ room_input_bar. show_current_location_preview ( cx) ;
1463+ }
1464+ RoomInputPopupMenuAction :: None => { }
1465+ }
1466+ }
1467+
13781468 /// Processes all pending background updates to the currently-shown timeline.
13791469 ///
13801470 /// Redraws this RoomScreen view if any updates were applied.
0 commit comments