Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use interactive buttons to display and send (toggle) reactions #168

Merged
merged 79 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
1453a13
emoji
alanpoon Sep 27, 2024
5d13dfc
emo
alanpoon Sep 29, 2024
d77281a
reaction_list
alanpoon Oct 1, 2024
20b4f0d
added emoji toggle
alanpoon Oct 1, 2024
ad3b14d
minor cleanup
alanpoon Oct 1, 2024
632eaa7
Merge branch 'main' into interactive_icon_button_#115
alanpoon Oct 2, 2024
0d0dc06
removed message annotation template
alanpoon Oct 2, 2024
c26719f
Merge branch 'main' into interactive_icon_button_#115
alanpoon Oct 3, 2024
f9bbb9f
resolve conflict
alanpoon Oct 3, 2024
39c7c58
commiting cargo.lock
alanpoon Oct 3, 2024
4f818a3
revert use main's cargo.lock
alanpoon Oct 3, 2024
3f5500c
did some formating
alanpoon Oct 4, 2024
d3a0b29
Merge branch 'main' into interactive_icon_button_#115
alanpoon Oct 11, 2024
0db2482
resolve minor issue
alanpoon Oct 11, 2024
926871d
Merge branch 'main' into interactive_icon_button_#115
alanpoon Oct 12, 2024
e585205
resolve conflict
alanpoon Oct 12, 2024
0279b2e
merge main n resolve conflict
alanpoon Oct 12, 2024
b02c4ce
Merge branch 'main' into interactive_icon_button_#115
alanpoon Oct 30, 2024
bda02cf
Merge branch 'main' of https://github.com/project-robius/robrix into …
alanpoon Nov 27, 2024
867a455
ReactionButton hide before width calculated
alanpoon Nov 28, 2024
d4efb31
Merge branch 'main' of https://github.com/project-robius/robrix into …
alanpoon Nov 28, 2024
48f22b5
resolve conflict
alanpoon Nov 28, 2024
ac13516
removed unneccessary changes
alanpoon Nov 28, 2024
1b31846
remove redraw after set_list
alanpoon Nov 28, 2024
5616b4a
Merge branch 'main' of https://github.com/project-robius/robrix into …
alanpoon Dec 3, 2024
23c74dd
fixed spelling mistake
alanpoon Dec 3, 2024
3e4ae95
fix clippy
alanpoon Dec 3, 2024
af313fb
increase padding to 5
alanpoon Dec 4, 2024
52c2b01
Added tooltip for interactive button
alanpoon Dec 6, 2024
34f1543
fix clippy
alanpoon Dec 6, 2024
d6c2bfd
Added display_name from user profile cache in tooltip
alanpoon Dec 9, 2024
dc1c4ad
changed to map
alanpoon Dec 9, 2024
33a2437
Removed tuple and slight improve in tooltip cutoff
alanpoon Dec 10, 2024
bc19f96
consistent roomscreentooltipActions
alanpoon Dec 10, 2024
70ed74c
minor change
alanpoon Dec 10, 2024
49425bb
Update src/sliding_sync.rs
alanpoon Dec 18, 2024
2be0b94
changing wording for reaction_key
alanpoon Dec 18, 2024
f3bd019
removed clientuser_id in timelinestate
alanpoon Dec 23, 2024
82e5efc
Merge branch 'main' into interactive_icon_button_#115
alanpoon Dec 23, 2024
bf1e2cf
fix tooltip
alanpoon Dec 23, 2024
b369397
Added callout tooltip widget
alanpoon Dec 23, 2024
a8ad340
remove temporary hack for tooltip
alanpoon Dec 23, 2024
21a5313
Added displayname for reaction tooltip
alanpoon Dec 25, 2024
742f1f4
Merge branch 'main' of https://github.com/project-robius/robrix into …
alanpoon Dec 31, 2024
ac2ffcb
fix tooltip overlap
alanpoon Dec 31, 2024
4693920
tooltip cleanup
alanpoon Jan 1, 2025
16f204c
remove Option for callout_y_offset
alanpoon Jan 1, 2025
8238397
Fix Doc
alanpoon Jan 2, 2025
ce504c9
Merge branch 'main' of https://github.com/project-robius/robrix into …
alanpoon Jan 2, 2025
b261b5d
use rightwrap
alanpoon Jan 3, 2025
84d5e51
remove hide for first draw in event_reaction_list
alanpoon Jan 3, 2025
6826070
Merge branch 'main' of https://github.com/project-robius/robrix into …
alanpoon Jan 3, 2025
e195ec5
remove width_calculated
alanpoon Jan 3, 2025
e8efce0
Flow:RightWrap
alanpoon Jan 4, 2025
4ca7219
margin remove parenthese
alanpoon Jan 4, 2025
211b375
format margin
alanpoon Jan 4, 2025
be4d20b
format bg_color
alanpoon Jan 4, 2025
f9709eb
early return
alanpoon Jan 4, 2025
5dcebf3
format long function line
alanpoon Jan 4, 2025
5f85166
simplifed reaction list
alanpoon Jan 7, 2025
7090dc9
restore MatrixRequest::CheckCanUserSendMessage
alanpoon Jan 7, 2025
69a16c4
doc formating
alanpoon Jan 13, 2025
c7a5045
Populate tooltip text after mouseover in reaction buttons
alanpoon Jan 13, 2025
6b54d76
merge main
alanpoon Jan 13, 2025
8bc1470
remove debugging
alanpoon Jan 13, 2025
0997f40
revert changes
alanpoon Jan 13, 2025
f29683c
Merge remote-tracking branch 'origin' into interactive_icon_button_#115
alanpoon Jan 13, 2025
368deff
Change to mouse position detection for message body
alanpoon Jan 13, 2025
c0fddf5
revert handle_event for Message
alanpoon Jan 14, 2025
fbc3ab1
Merge branch 'main' into interactive_icon_button_#115
alanpoon Jan 16, 2025
d99ac95
fix doc comment
alanpoon Jan 16, 2025
0a3118b
Fix half screening reaction button styling
alanpoon Jan 17, 2025
b5f2b93
improving tooltip clearing
alanpoon Jan 17, 2025
b39631f
Merge branch 'main' into interactive_icon_button_#115
alanpoon Jan 17, 2025
05e7d0e
fix edge toggle reaction
alanpoon Jan 17, 2025
f89ef19
Display tooltip at the bottom if the reaction button is too close to …
alanpoon Jan 19, 2025
0229149
align callout to the first line
alanpoon Jan 20, 2025
0fd23c3
Enlarge reaction font size. Left-align reaction buttons.
kevinaboos Jan 20, 2025
6189c44
Merge branch 'main' into interactive_icon_button_#115
kevinaboos Jan 20, 2025
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
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

186 changes: 186 additions & 0 deletions src/home/event_reaction.rs
alanpoon marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
use crate::sliding_sync::{submit_async_request, MatrixRequest};
use makepad_widgets::*;
use matrix_sdk::ruma::OwnedRoomId;
use matrix_sdk_ui::timeline::ReactionsByKeyBySender;

live_design! {
import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*;
import makepad_draw::shader::std::*;
import crate::shared::styles::*;
COLOR_BUTTON_DARKER = #454343
ReactionList = {{ReactionList}} {
item: <Button> {
width: Fit,
height: Fit,
spacing: 20,
padding: {top: 3, bottom: 3, left: 3, right: 3}
margin: {
top:3,
bottom:3,
left:3,
right:3

},
draw_bg: {
instance color: (COLOR_BUTTON_DARKER)
instance color_hover: #fef65b
instance border_width: 0.0
instance border_color: #D0D5DD
instance radius: 3.0

fn get_color(self) -> vec4 {
return mix(self.color, mix(self.color, self.color_hover, 0.2), self.hover)
}

fn pixel(self) -> vec4 {
let sdf = Sdf2d::viewport(self.pos * self.rect_size)
sdf.box(
self.border_width,
self.border_width,
self.rect_size.x - (self.border_width * 2.0),
self.rect_size.y - (self.border_width * 2.0),
max(1.0, self.radius)
)
sdf.fill_keep(self.get_color())
if self.border_width > 0.0 {
sdf.stroke(self.border_color, self.border_width)
}
return sdf.result;
}
}

draw_icon: {
instance color: #000
instance color_hover: #000
uniform rotation_angle: 0.0,

fn get_color(self) -> vec4 {
return mix(self.color, mix(self.color, self.color_hover, 0.2), self.hover)
}


}
icon_walk: {width: 16, height: 16}

draw_text: {
text_style: <REGULAR_TEXT>{font_size: 8},
color: #ffffff
fn get_color(self) -> vec4 {
return self.color;
}
}
}
}
}

#[derive(Live, Widget)]
pub struct ReactionList {
#[redraw]
#[rust]
area: Area,
#[live]
item: Option<LivePtr>,
#[rust]
children: ComponentMap<LiveId, ButtonRef>,
#[layout]
layout: Layout,
#[walk]
walk: Walk,
#[rust]
pub list: Vec<(String, usize)>,
alanpoon marked this conversation as resolved.
Show resolved Hide resolved
#[rust]
pub room_id: Option<OwnedRoomId>,
#[rust]
pub unique_id: Option<String>,
}
impl Widget for ReactionList {
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
cx.begin_turtle(walk, self.layout);
let rect = cx.turtle().rect();
let width: f64 = rect.size.x - 50.0;
let mut acc_width: f64 = 0.0;
let mut acc_height = 0.0;
for (index, (emoji, count)) in self.list.iter().enumerate() {
let target = self.children.get_or_insert(cx, LiveId(index as u64), |cx| {
WidgetRef::new_from_ptr(cx, self.item).as_button()
});
target.set_text(&format!("{} {}", emoji, count));
target.draw_all(cx, scope);
let used = cx.turtle().used();
acc_width = used.x;
if acc_width > width {
cx.turtle_new_line();
target.redraw(cx);
alanpoon marked this conversation as resolved.
Show resolved Hide resolved
let used = cx.turtle().used();
acc_height = used.y;
cx.turtle_mut().set_used(0.0, used.y);
}
if acc_height == 0.0 {
acc_height = used.y;
}
}
cx.end_turtle();
self.children.retain_visible();
DrawStep::done()
}
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
let Some(room_id) = &self.room_id else { return };
let Some(unique_id) = &self.unique_id else {
return;
};
self.children
.iter()
.enumerate()
.for_each(|(_index, (_id, widget_ref))| {
widget_ref.handle_event(cx, event, scope);
match event {
Event::Actions(actions) => {
if widget_ref.clicked(&actions) {
let text = widget_ref.text().clone();
let mut reaction_string_arr: Vec<&str> = text.split(" ").collect();
reaction_string_arr.pop();
let reaction_string = reaction_string_arr.join(" ");
if let Some(key) = emojis::get_by_shortcode(&reaction_string) {
submit_async_request(MatrixRequest::ToggleReaction {
room_id: room_id.clone(),
unique_id: unique_id.clone(),
reaction_key: key.as_str().to_string(),
});
}
}
}
_ => {}
}
});
}
}
impl LiveHook for ReactionList {
fn before_apply(&mut self, cx: &mut Cx, apply: &mut Apply, index: usize, nodes: &[LiveNode]) {}
}

impl ReactionListRef {
pub fn set_list(
&mut self,
looper: &ReactionsByKeyBySender,
alanpoon marked this conversation as resolved.
Show resolved Hide resolved
room_id: OwnedRoomId,
unique_id: &str,
) {
if let Some(mut instance) = self.borrow_mut() {
let mut text_to_display_vec = Vec::with_capacity(looper.len());
for (reaction_raw, reaction_senders) in looper.iter() {
// Just take the first char of the emoji, which ignores any variant selectors.
let reaction_first_char = reaction_raw.chars().next().map(|c| c.to_string());
let reaction_str = reaction_first_char.as_deref().unwrap_or(reaction_raw);
let text_to_display = emojis::get(reaction_str)
.and_then(|e| e.shortcode())
.unwrap_or(reaction_raw);
let count = reaction_senders.len();
text_to_display_vec.push((text_to_display.to_string(), count));
}
instance.list = text_to_display_vec;
instance.room_id = Some(room_id);
instance.unique_id = Some(unique_id.to_string());
}
}
}
2 changes: 2 additions & 0 deletions src/home/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod rooms_list;
pub mod rooms_sidebar;
pub mod spaces_dock;
pub mod welcome_screen;
pub mod event_reaction;
pub mod light_themed_dock;

pub fn live_design(cx: &mut Cx) {
Expand All @@ -22,4 +23,5 @@ pub fn live_design(cx: &mut Cx) {
spaces_dock::live_design(cx);
welcome_screen::live_design(cx);
light_themed_dock::live_design(cx);
event_reaction::live_design(cx);
}
96 changes: 28 additions & 68 deletions src/home/room_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use matrix_sdk::{
OwnedServerName,
};
use matrix_sdk_ui::timeline::{
self, EventTimelineItem, MemberProfileChange, Profile, ReactionsByKeyBySender, RepliedToInfo,
self, EventTimelineItem, MemberProfileChange, Profile, RepliedToInfo,
RoomMembershipChange, TimelineDetails, TimelineItem, TimelineItemContent, TimelineItemKind,
VirtualTimelineItem,
};
Expand All @@ -33,7 +33,8 @@ use crate::{
html_or_plaintext::{HtmlOrPlaintextRef, HtmlOrPlaintextWidgetRefExt},
text_or_image::{TextOrImageRef, TextOrImageWidgetRefExt},
typing_animation::TypingAnimationWidgetExt,
}, sliding_sync::{get_client, submit_async_request, take_timeline_update_receiver, MatrixRequest, PaginationDirection}, utils::{self, unix_time_millis_to_datetime, MediaFormatConst}
}, sliding_sync::{get_client, submit_async_request, take_timeline_update_receiver, MatrixRequest, PaginationDirection}, utils::{self, unix_time_millis_to_datetime, MediaFormatConst},
home::event_reaction::ReactionListWidgetRefExt
};
use rangemap::RangeSet;

Expand All @@ -51,6 +52,7 @@ live_design! {
import crate::shared::text_or_image::TextOrImage;
import crate::shared::html_or_plaintext::*;
import crate::profile::user_profile::UserProfileSlidingPane;
import crate::home::event_reaction::*;
import crate::shared::typing_animation::TypingAnimation;
import crate::shared::icon_button::RobrixIconButton;

Expand Down Expand Up @@ -270,27 +272,6 @@ live_design! {
}
}

// An optional view used to show reactions beneath a message.
MessageAnnotations = <View> {
visible: false,
width: Fill,
height: Fit,
padding: {top: 5.0}

html_content = <RobrixHtml> {
width: Fill,
height: Fit,
padding: { bottom: 5.0, top: 0.0 },
font_size: 10.5,
font_color: (REACTION_TEXT_COLOR),
draw_normal: { color: (REACTION_TEXT_COLOR) },
draw_italic: { color: (REACTION_TEXT_COLOR) },
draw_bold: { color: (REACTION_TEXT_COLOR) },
draw_bold_italic: { color: (REACTION_TEXT_COLOR) },
draw_fixed: { color: (REACTION_TEXT_COLOR) },
body: ""
}
}

// An empty view that takes up no space in the portal list.
Empty = <View> { }
Expand Down Expand Up @@ -416,7 +397,11 @@ live_design! {
// margin: {top: 13.0, bottom: 5.0}
// }

message_annotations = <MessageAnnotations> {}
reaction_list = <ReactionList> {
width: Fill,
height: Fit,
margin: {top: (5.0)}
alanpoon marked this conversation as resolved.
Show resolved Hide resolved
}
}

message_menu = <MessageMenu> {}
Expand Down Expand Up @@ -456,7 +441,11 @@ live_design! {
padding: { left: 10.0 }

message = <HtmlOrPlaintext> { }
message_annotations = <MessageAnnotations> {}
reaction_list = <ReactionList> {
width: Fill,
height: Fit,
margin: {top: (5.0)}
}
}
}
}
Expand All @@ -471,7 +460,11 @@ live_design! {
width: Fill, height: 300,
image_view = { image = { fit: Horizontal } }
}
message_annotations = <MessageAnnotations> {}
reaction_list = <ReactionList> {
width: Fill,
height: Fit,
margin: {top: (5.0)}
}
}
}
}
Expand All @@ -486,7 +479,11 @@ live_design! {
width: Fill, height: 300,
image_view = { image = { fit: Horizontal } }
}
message_annotations = <MessageAnnotations> {}
reaction_list = <ReactionList> {
width: Fill,
height: Fit,
margin: {top: (5.0)}
}
}
}
}
Expand Down Expand Up @@ -1367,6 +1364,7 @@ impl Widget for RoomScreen {
list,
item_id,
room_id,
timeline_item.unique_id(),
event_tl_item,
message,
prev_event,
Expand Down Expand Up @@ -2216,6 +2214,7 @@ fn populate_message_view(
list: &mut PortalList,
item_id: usize,
room_id: &RoomId,
unique_id: &str,
alanpoon marked this conversation as resolved.
Show resolved Hide resolved
event_tl_item: &EventTimelineItem,
message: &timeline::Message,
prev_event: Option<&Arc<TimelineItem>>,
Expand Down Expand Up @@ -2319,7 +2318,8 @@ fn populate_message_view(

// If we didn't use a cached item, we need to draw all other message content: the reply preview and reactions.
if !used_cached_item {
draw_reactions(cx, &item, event_tl_item.reactions(), item_id);
item.reaction_list(id!(content.reaction_list))
.set_list(event_tl_item.reactions(), room_id.to_owned(), unique_id);
let (is_reply_fully_drawn, replied_to_ev_id) = draw_replied_to_message(
cx,
&item.view(id!(replied_to_message)),
Expand Down Expand Up @@ -2616,46 +2616,6 @@ fn populate_preview_of_timeline_item(
widget_out.show_html(html);
}

/// Draws the reactions beneath the given `message_item`.
fn draw_reactions(
_cx: &mut Cx2d,
message_item: &WidgetRef,
reactions: &ReactionsByKeyBySender,
id: usize,
) {
const DRAW_ITEM_ID_REACTION: bool = false;
if reactions.is_empty() && !DRAW_ITEM_ID_REACTION {
return;
}

// The message annotaions view is invisible by default, so we must set it to visible
// now that we know there are reactions to show.
message_item
.view(id!(content.message_annotations))
.set_visible(true);

let mut label_text = String::new();
for (reaction_raw, reaction_senders) in reactions.iter() {
// Just take the first char of the emoji, which ignores any variant selectors.
let reaction_first_char = reaction_raw.chars().next().map(|c| c.to_string());
let reaction_str = reaction_first_char.as_deref().unwrap_or(reaction_raw);
let text_to_display = emojis::get(reaction_str)
.and_then(|e| e.shortcode())
.unwrap_or(reaction_raw);
let count = reaction_senders.len();
// log!("Found reaction {:?} with count {}", text_to_display, count);
label_text = format!("{label_text}<i>:{}:</i> <b>{}</b> ", text_to_display, count);
}

// Debugging: draw the item ID as a reaction
if DRAW_ITEM_ID_REACTION {
label_text = format!("{label_text}<i>ID: {}</i>", id);
}

let html_reaction_view = message_item.html(id!(message_annotations.html_content));
html_reaction_view.set_text(&label_text);
}

/// A trait for abstracting over the different types of timeline events
/// that can be displayed in a `SmallStateEvent` widget.
trait SmallStateEventContent {
Expand Down
Loading