Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -936,10 +936,10 @@ impl MatchEvent for App {
}

// Handle an action requesting to open the new message context menu.
if let MessageAction::OpenMessageContextMenu { details, abs_pos } = action.as_widget_action().cast() {
if let MessageAction::OpenMessageContextMenu { details, abs_pos, opening_gesture } = action.as_widget_action().cast() {
self.ui.callout_tooltip(cx, ids!(app_tooltip)).hide(cx);
let new_message_context_menu = self.ui.new_message_context_menu(cx, ids!(new_message_context_menu));
let expected_dimensions = new_message_context_menu.show(cx, details, self.app_state.app_language);
let expected_dimensions = new_message_context_menu.show(cx, details, self.app_state.app_language, opening_gesture);
// Use the overlay container's rect (not the window's) to correctly position
// the context menu relative to the body area, which excludes the caption bar.
let rect = self.ui.view(cx, ids!(overlay_container)).area().rect(cx);
Expand All @@ -960,10 +960,10 @@ impl MatchEvent for App {
}

// Handle an action requesting to open the room context menu.
if let RoomsListAction::OpenRoomContextMenu { details, pos } = action.as_widget_action().cast() {
if let RoomsListAction::OpenRoomContextMenu { details, pos, opening_gesture } = action.as_widget_action().cast() {
self.ui.callout_tooltip(cx, ids!(app_tooltip)).hide(cx);
let room_context_menu = self.ui.room_context_menu(cx, ids!(room_context_menu));
let expected_dimensions = room_context_menu.show(cx, details, self.app_state.app_language);
let expected_dimensions = room_context_menu.show(cx, details, self.app_state.app_language, opening_gesture);
// Use the overlay container's rect (not the window's) to correctly position
// the context menu relative to the body area, which excludes the caption bar.
let rect = self.ui.view(cx, ids!(overlay_container)).area().rect(cx);
Expand Down
48 changes: 47 additions & 1 deletion src/home/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use makepad_widgets::ScriptVm;
use makepad_widgets::{ScriptVm, event::{DigitId, FingerDownEvent, FingerLongPressEvent, FingerUpEvent}};

pub mod add_room;
pub mod bot_binding_modal;
Expand Down Expand Up @@ -35,6 +35,52 @@ pub mod room_image_viewer;
pub mod streaming_animation;
pub mod upload_progress;

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ContextMenuOpenGesture {
digit_id: DigitId,
/// The time of the original `FingerDown` that opened the menu.
/// Matches `FingerUpEvent.capture_time` for the same capture chain
/// (see Makepad `finger.rs`: `capture_digit` stores `e.time` as `capture.time`,
/// and `FingerUpEvent` reads it back as `capture_time`).
capture_time: f64,
}

impl ContextMenuOpenGesture {
pub fn from_finger_down(event: &FingerDownEvent) -> Self {
Self {
digit_id: event.digit_id,
capture_time: event.time,
}
}

pub fn from_long_press(event: &FingerLongPressEvent) -> Self {
Self {
digit_id: event.digit_id,
capture_time: event.capture_time,
}
}

fn matches_finger_up(&self, event: &FingerUpEvent) -> bool {
self.digit_id == event.digit_id
&& self.capture_time == event.capture_time
}
}

pub fn consume_context_menu_opening_finger_up(
pending_open_gesture: &mut Option<ContextMenuOpenGesture>,
event: &FingerUpEvent,
) -> bool {
if pending_open_gesture
.as_ref()
.is_some_and(|gesture| gesture.matches_finger_up(event))
{
*pending_open_gesture = None;
true
} else {
false
}
}

pub fn script_mod(vm: &mut ScriptVm) {
search_messages::script_mod(vm);
loading_pane::script_mod(vm);
Expand Down
21 changes: 15 additions & 6 deletions src/home/new_message_context_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use matrix_sdk_ui::timeline::{EventTimelineItem, MsgLikeContent, TimelineEventIt

use crate::{i18n::{AppLanguage, tr_key}, sliding_sync::UserPowerLevels};

use super::room_screen::MessageAction;
use super::{ContextMenuOpenGesture, consume_context_menu_opening_finger_up, room_screen::MessageAction};

const BUTTON_HEIGHT: f64 = 35.0; // KEEP IN SYNC WITH BUTTON_HEIGHT BELOW
const MENU_WIDTH: f64 = 215.0; // KEEP IN SYNC WITH MENU_WIDTH BELOW
Expand Down Expand Up @@ -301,6 +301,7 @@ pub struct NewMessageContextMenu {
#[source] source: ScriptObjectRef,
#[rust] details: Option<MessageDetails>,
#[rust] app_language: AppLanguage,
#[rust] pending_open_gesture: Option<ContextMenuOpenGesture>,
}

impl Widget for NewMessageContextMenu {
Expand Down Expand Up @@ -337,9 +338,15 @@ impl Widget for NewMessageContextMenu {
false
}
Hit::FingerUp(fue) if fue.is_over => {
!self.view(cx, ids!(main_content)).area().rect(cx).contains(fue.abs)
if consume_context_menu_opening_finger_up(&mut self.pending_open_gesture, &fue) {
false
} else {
!self.view(cx, ids!(main_content)).area().rect(cx).contains(fue.abs)
}
}
Hit::FingerScroll(_) => true,
// Ignore zero-scroll events: macOS trackpad generates FingerScroll(0,0)
// on two-finger press (right-click), which would incorrectly dismiss the menu.
Hit::FingerScroll(fse) => fse.scroll.x != 0.0 || fse.scroll.y != 0.0,
_ => false,
}
};
Expand Down Expand Up @@ -519,9 +526,10 @@ impl NewMessageContextMenu {
///
/// Returns the expected (approximate) dimensions of the context menu,
/// which can be used to proactively reposition it such that it fits on screen.
pub fn show(&mut self, cx: &mut Cx, details: MessageDetails, app_language: AppLanguage) -> DVec2 {
pub fn show(&mut self, cx: &mut Cx, details: MessageDetails, app_language: AppLanguage, opening_gesture: ContextMenuOpenGesture) -> DVec2 {
self.set_app_language(cx, app_language);
self.details = Some(details);
self.pending_open_gesture = Some(opening_gesture);
self.visible = true;
cx.set_key_focus(self.view.area());

Expand Down Expand Up @@ -641,6 +649,7 @@ impl NewMessageContextMenu {
fn close(&mut self, cx: &mut Cx) {
self.visible = false;
self.details = None;
self.pending_open_gesture = None;
cx.revert_key_focus();
self.redraw(cx);
}
Expand All @@ -654,8 +663,8 @@ impl NewMessageContextMenuRef {
}

/// See [`NewMessageContextMenu::show()`].
pub fn show(&self, cx: &mut Cx, details: MessageDetails, app_language: AppLanguage) -> DVec2 {
pub fn show(&self, cx: &mut Cx, details: MessageDetails, app_language: AppLanguage, opening_gesture: ContextMenuOpenGesture) -> DVec2 {
let Some(mut inner) = self.borrow_mut() else { return DVec2::default()};
inner.show(cx, details, app_language)
inner.show(cx, details, app_language, opening_gesture)
}
}
21 changes: 16 additions & 5 deletions src/home/room_context_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use makepad_widgets::*;
use matrix_sdk::ruma::OwnedRoomId;
use crate::{app::AppState, home::{bot_binding_modal::BotBindingModalAction, invite_modal::InviteModalAction}, i18n::{AppLanguage, tr_key}, shared::popup_list::{PopupKind, enqueue_popup_notification}, sliding_sync::{MatrixRequest, submit_async_request}, utils::RoomNameId};

use super::{ContextMenuOpenGesture, consume_context_menu_opening_finger_up};

const BUTTON_HEIGHT: f64 = 35.0;
const MENU_WIDTH: f64 = 215.0;

Expand Down Expand Up @@ -148,6 +150,7 @@ pub struct RoomContextMenu {
#[source] source: ScriptObjectRef,
#[rust] details: Option<RoomContextMenuDetails>,
#[rust] app_language: AppLanguage,
#[rust] pending_open_gesture: Option<ContextMenuOpenGesture>,
}

impl Widget for RoomContextMenu {
Expand Down Expand Up @@ -177,9 +180,15 @@ impl Widget for RoomContextMenu {
|| match event.hits_with_capture_overload(cx, area, true) {
Hit::KeyUp(key) => key.key_code == KeyCode::Escape,
Hit::FingerUp(fue) if fue.is_over => {
!self.view(cx, ids!(main_content)).area().rect(cx).contains(fue.abs)
if consume_context_menu_opening_finger_up(&mut self.pending_open_gesture, &fue) {
false
} else {
!self.view(cx, ids!(main_content)).area().rect(cx).contains(fue.abs)
}
}
Hit::FingerScroll(_) => true,
// Ignore zero-scroll events: macOS trackpad generates FingerScroll(0,0)
// on two-finger press (right-click), which would incorrectly dismiss the menu.
Hit::FingerScroll(fse) => fse.scroll.x != 0.0 || fse.scroll.y != 0.0,
_ => false,
}
};
Expand Down Expand Up @@ -276,10 +285,11 @@ impl RoomContextMenu {
self.visible
}

pub fn show(&mut self, cx: &mut Cx, details: RoomContextMenuDetails, app_language: AppLanguage) -> DVec2 {
pub fn show(&mut self, cx: &mut Cx, details: RoomContextMenuDetails, app_language: AppLanguage, opening_gesture: ContextMenuOpenGesture) -> DVec2 {
self.app_language = app_language;
let height = self.update_buttons(cx, &details);
self.details = Some(details);
self.pending_open_gesture = Some(opening_gesture);
self.visible = true;
cx.set_key_focus(self.view.area());
dvec2(MENU_WIDTH, height)
Expand Down Expand Up @@ -343,6 +353,7 @@ impl RoomContextMenu {
fn close(&mut self, cx: &mut Cx) {
self.visible = false;
self.details = None;
self.pending_open_gesture = None;
cx.revert_key_focus();
self.redraw(cx);
}
Expand All @@ -354,8 +365,8 @@ impl RoomContextMenuRef {
inner.is_currently_shown(cx)
}

pub fn show(&self, cx: &mut Cx, details: RoomContextMenuDetails, app_language: AppLanguage) -> DVec2 {
pub fn show(&self, cx: &mut Cx, details: RoomContextMenuDetails, app_language: AppLanguage, opening_gesture: ContextMenuOpenGesture) -> DVec2 {
let Some(mut inner) = self.borrow_mut() else { return DVec2::default()};
inner.show(cx, details, app_language)
inner.show(cx, details, app_language, opening_gesture)
}
}
9 changes: 8 additions & 1 deletion src/home/room_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use crate::shared::mentionable_text_input::MentionableTextInputAction;

use rangemap::RangeSet;

use super::{event_reaction_list::ReactionData, invite_modal::is_invite_modal_open, loading_pane::LoadingPaneRef, new_message_context_menu::{MessageAbilities, MessageDetails}, room_read_receipt::{self, populate_read_receipts, MAX_VISIBLE_AVATARS_IN_READ_RECEIPT}};
use super::{ContextMenuOpenGesture, event_reaction_list::ReactionData, invite_modal::is_invite_modal_open, loading_pane::LoadingPaneRef, new_message_context_menu::{MessageAbilities, MessageDetails}, room_read_receipt::{self, populate_read_receipts, MAX_VISIBLE_AVATARS_IN_READ_RECEIPT}};

/// The maximum number of timeline items to search through
/// when looking for a particular event.
Expand Down Expand Up @@ -8444,6 +8444,7 @@ pub enum MessageAction {
/// The absolute position where we should show the context menu,
/// in which the (0,0) origin coordinate is the top left corner of the app window.
abs_pos: DVec2,
opening_gesture: ContextMenuOpenGesture,
},
ToggleTranslationLangPopup {
button_rect: Rect,
Expand Down Expand Up @@ -8687,6 +8688,7 @@ impl Widget for Message {
MessageAction::OpenMessageContextMenu {
details: details.clone(),
abs_pos: fe.abs,
opening_gesture: ContextMenuOpenGesture::from_finger_down(&fe),
}
);
}
Expand All @@ -8697,6 +8699,7 @@ impl Widget for Message {
MessageAction::OpenMessageContextMenu {
details: details.clone(),
abs_pos: lp.abs,
opening_gesture: ContextMenuOpenGesture::from_long_press(&lp),
}
);
}
Expand Down Expand Up @@ -8728,6 +8731,7 @@ impl Widget for Message {
MessageAction::OpenMessageContextMenu {
details: details.clone(),
abs_pos: fe.abs,
opening_gesture: ContextMenuOpenGesture::from_finger_down(&fe),
}
);
}
Expand All @@ -8744,6 +8748,7 @@ impl Widget for Message {
MessageAction::OpenMessageContextMenu {
details: details.clone(),
abs_pos: lp.abs,
opening_gesture: ContextMenuOpenGesture::from_long_press(&lp),
}
);
}
Expand Down Expand Up @@ -8779,6 +8784,7 @@ impl Widget for Message {
MessageAction::OpenMessageContextMenu {
details: details.clone(),
abs_pos: fe.abs,
opening_gesture: ContextMenuOpenGesture::from_finger_down(&fe),
}
);
}
Expand All @@ -8789,6 +8795,7 @@ impl Widget for Message {
MessageAction::OpenMessageContextMenu {
details: details.clone(),
abs_pos: lp.abs,
opening_gesture: ContextMenuOpenGesture::from_long_press(&lp),
}
);
}
Expand Down
6 changes: 4 additions & 2 deletions src/home/rooms_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use matrix_sdk::{RoomState, ruma::{events::tag::Tags, MilliSecondsSinceUnixEpoch
use crate::{
app::{AppState, SelectedRoom},
home::{
ContextMenuOpenGesture,
add_room::CreateRoomAction,
navigation_tab_bar::{NavigationBarAction, SelectedTab},
room_context_menu::RoomContextMenuDetails,
Expand Down Expand Up @@ -252,6 +253,7 @@ pub enum RoomsListAction {
OpenRoomContextMenu {
details: RoomContextMenuDetails,
pos: DVec2,
opening_gesture: ContextMenuOpenGesture,
},
#[default]
None,
Expand Down Expand Up @@ -1342,7 +1344,7 @@ impl Widget for RoomsList {
self.redraw(cx);
}
// Handle a room being right-clicked or long-pressed by opening the room context menu.
else if let RoomsListEntryAction::SecondaryClicked(room_id, pos) = action.as_widget_action().cast() {
else if let RoomsListEntryAction::SecondaryClicked(room_id, pos, opening_gesture) = action.as_widget_action().cast() {
// Determine details for the context menu
let Some(jr) = self.all_joined_rooms.get(&room_id) else {
error!("BUG: couldn't find right-clicked room details for room {room_id}");
Expand All @@ -1359,7 +1361,7 @@ impl Widget for RoomsList {
};
cx.widget_action(
self.widget_uid(),
RoomsListAction::OpenRoomContextMenu { details, pos },
RoomsListAction::OpenRoomContextMenu { details, pos, opening_gesture },
);
}
// Handle the space lobby being clicked.
Expand Down
16 changes: 12 additions & 4 deletions src/home/rooms_list_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
}, utils::{self, relative_format}
};

use super::rooms_list::{InvitedRoomInfo, InviterInfo, JoinedRoomInfo, RoomsListScopeProps};
use super::{ContextMenuOpenGesture, rooms_list::{InvitedRoomInfo, InviterInfo, JoinedRoomInfo, RoomsListScopeProps}};
script_mod! {
use mod.prelude.widgets.*
use mod.widgets.*
Expand Down Expand Up @@ -223,7 +223,7 @@ pub enum RoomsListEntryAction {
/// This RoomsListEntry was primary-clicked or tapped.
PrimaryClicked(OwnedRoomId),
/// This RoomsListEntry was right-clicked or long-pressed.
SecondaryClicked(OwnedRoomId, DVec2),
SecondaryClicked(OwnedRoomId, DVec2, ContextMenuOpenGesture),
#[default]
None,
}
Expand Down Expand Up @@ -262,14 +262,22 @@ impl Widget for RoomsListEntry {
if fe.device.mouse_button().is_some_and(|b| b.is_secondary()) {
cx.widget_action(
uid,
RoomsListEntryAction::SecondaryClicked(room_id.clone(), fe.abs),
RoomsListEntryAction::SecondaryClicked(
room_id.clone(),
fe.abs,
ContextMenuOpenGesture::from_finger_down(&fe),
),
);
}
}
Hit::FingerLongPress(fe) => {
cx.widget_action(
uid,
RoomsListEntryAction::SecondaryClicked(room_id.clone(), fe.abs),
RoomsListEntryAction::SecondaryClicked(
room_id.clone(),
fe.abs,
ContextMenuOpenGesture::from_long_press(&fe),
),
);
}
Hit::FingerUp(fe) if !rooms_list_props.was_scrolling && fe.is_over && fe.is_primary_hit() && fe.was_tap() => {
Expand Down
Loading