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

Redesign verification badge to handle Events as Hits directly #348

Merged
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
10 changes: 5 additions & 5 deletions src/home/event_reaction_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl Widget for ReactionList {
Hit::FingerHoverOut(_) => {
cx.widget_action(uid, &scope.path, RoomScreenTooltipActions::HoverOut);
widget_ref.apply_over(cx, live!(draw_bg: {hover: 0.0}));
cx.set_cursor(MouseCursor::Arrow);
cx.set_cursor(MouseCursor::Default);
break;
}
Hit::FingerDown(_) => {
Expand Down Expand Up @@ -176,13 +176,13 @@ impl Widget for ReactionList {
cx.set_cursor(MouseCursor::Hand);
break;
}
Hit::FingerScroll(_) => {
cx.widget_action(uid, &scope.path, RoomScreenTooltipActions::HoverOut);
cx.set_cursor(MouseCursor::Default);
}
_ => { }
}
}
if let Event::Scroll(_) = event {
cx.widget_action(uid, &scope.path, RoomScreenTooltipActions::HoverOut);
cx.set_cursor(MouseCursor::Hand);
}
}
}

Expand Down
121 changes: 27 additions & 94 deletions src/home/spaces_dock.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
use makepad_widgets::*;

use crate::shared::color_tooltip::*;
use crate::shared::verification_badge::{VerificationBadge, VerificationText};
use crate::verification::VerificationStateAction;
use crate::sliding_sync::get_client;
use matrix_sdk::encryption::VerificationState;


live_design! {
use link::theme::*;
Expand Down Expand Up @@ -172,106 +167,44 @@ live_design! {
}
}

#[derive(Live, Widget)]
/// An action emitted to show or hide the `profile_tooltip`.
#[derive(Clone, Debug, DefaultNone)]
pub enum ProfileTooltipAction {
Show {
pos: DVec2,
text: &'static str,
color: Vec4,
},
Hide,
None,
}

#[derive(Live, LiveHook, Widget)]
pub struct Profile {
#[deref]
view: View,
#[deref] view: View,
}

impl Widget for Profile {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
let mut color: Vec4 = vec4(0.2, 0.2, 0.2, 1.0); // Default Grey Color
let profile_rect = {
let view = self.view(id!(text_view));
view.area().rect(cx)
}; // view borrow end

if let Event::MouseMove(e) = event {
let (is_mouse_over_icons, verification_text, tooltip_pos) = {
if let Some(badge) = self
.widget(id!(verification_badge))
.borrow_mut::<VerificationBadge>()
{
let icons_rect = badge.get_icons_rect(cx);
let is_over = icons_rect.contains(e.abs);
let text =
VerificationText::from_state(badge.verification_state).get_text();
color = match badge.verification_state {
VerificationState::Verified => vec4(0.0, 0.75, 0.0, 1.0), // Green
VerificationState::Unverified => vec4(0.75, 0.0, 0.0, 1.0), // Red
VerificationState::Unknown => vec4(0.2, 0.2, 0.2, 1.0), // Grey
};

let tooltip_pos = if cx.display_context.is_desktop() {
DVec2 {
x: icons_rect.pos.x + icons_rect.size.x + 1.,
y: icons_rect.pos.y - 10.,
}
} else {
DVec2 {
x: profile_rect.pos.x,
y: profile_rect.pos.y - 10.,
}
};
(is_over, text.to_string(), tooltip_pos)
} else {
let tooltip_pos = DVec2 { x: 0., y: 0. };
(false, String::new(), tooltip_pos)
}
}; // badge borrow end

if let Some(mut tooltip) = self
.widget(id!(profile_tooltip))
.borrow_mut::<ColorTooltip>()
{
if is_mouse_over_icons {
tooltip.show_with_options(cx, tooltip_pos, &verification_text, color);
} else {
tooltip.hide(cx);
self.view.handle_event(cx, event, scope);

if let Event::Actions(actions) = event {
for action in actions {
match action.as_widget_action().cast() {
ProfileTooltipAction::Show { pos, text, color } => {
self.view.color_tooltip(id!(profile_tooltip))
.show_with_options(cx, pos, text, color);
}
ProfileTooltipAction::Hide => {
self.view.color_tooltip(id!(profile_tooltip)).hide(cx);
}
_ => { }
}
}
}

self.match_event(cx, event);
self.view.handle_event(cx, event, scope)
}

fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
self.view.draw_walk(cx, scope, walk)
}
}

impl MatchEvent for Profile {
fn handle_action(&mut self, cx: &mut Cx, action: &Action) {
if let Some(VerificationStateAction::Update(state)) = action.downcast_ref() {
if let Some(mut badge) = self
.widget(id!(verification_badge))
.borrow_mut::<VerificationBadge>()
{
if badge.verification_state != *state {
badge.verification_state = *state;
badge.update_icon_visibility(cx);
badge.redraw(cx);
}
}
}
}
}

impl LiveHook for Profile {
fn after_new_from_doc(&mut self, cx:&mut Cx) {
if let Some(client) = get_client() {
let current_verification_state = client.encryption().verification_state().get();
if let Some(mut badge) = self
.widget(id!(verification_badge))
.borrow_mut::<VerificationBadge>()
{
if badge.verification_state != current_verification_state {
badge.verification_state = current_verification_state;
badge.update_icon_visibility(cx);
badge.redraw(cx);
}
}
}
}
}
2 changes: 0 additions & 2 deletions src/profile/user_profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,6 @@ impl Widget for UserProfileSlidingPane {
} || match event.hits_with_capture_overload(cx, self.view.area(), true) {
// Note: ideally we should handle `Hit::KeyUp` here, but that doesn't work as expected.
Hit::FingerUp(fue) => {
log!("UserProfileSlidingPane area: {:?}, got FingerUp: {:?}", self.view.area().rect(cx), fue);

fue.mouse_button().is_some_and(|b| b.is_back()) // 4
|| !self.view(id!(main_content)).area().rect(cx).contains(fue.abs) // 5
}
Expand Down
126 changes: 80 additions & 46 deletions src/shared/verification_badge.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use makepad_widgets::*;
use matrix_sdk::encryption::VerificationState;

use crate::{home::spaces_dock::ProfileTooltipAction, sliding_sync::get_client, verification::VerificationStateAction};

// First, define the verification icons component layout
live_design! {
use link::theme::*;
Expand Down Expand Up @@ -61,8 +63,6 @@ live_design! {
flow: Overlay
align: { x: 0.5, y: 0.5 }

visible: true

verification_icons = <View> {
flow: Overlay
align: { x: 0.5, y: 0.5 }
Expand All @@ -75,69 +75,102 @@ live_design! {
}
}

// Define the verification states and messages
#[derive(Default)]
pub enum VerificationText {
#[default]
Unknown,
Verified,
Unverified,
}

impl VerificationText {
pub fn get_text(&self) -> &'static str {
match self {
VerificationText::Verified => "This device is fully verified.",
VerificationText::Unverified => "This device is unverified. To view your encrypted message history, please verify it from another client.",
VerificationText::Unknown => " Verification state is unknown.",
}
pub fn verification_state_str(state: VerificationState) -> &'static str {
match state {
VerificationState::Verified => "This device is fully verified.",
VerificationState::Unverified => "This device is unverified. To view your encrypted message history, please verify Robrix from another client.",
VerificationState::Unknown => " Verification state is unknown.",
}
}

pub fn from_state(state: VerificationState) -> Self {
match state {
VerificationState::Verified => Self::Verified,
VerificationState::Unverified => Self::Unverified,
VerificationState::Unknown => Self::Unknown,
}
pub fn verification_state_color(state: VerificationState) -> Vec4 {
match state {
VerificationState::Verified => vec4(0.0, 0.75, 0.0, 1.0), // Green
VerificationState::Unverified => vec4(0.75, 0.0, 0.0, 1.0), // Red
VerificationState::Unknown => vec4(0.2, 0.2, 0.2, 1.0), // Grey
}
}

#[derive(Live, LiveHook, Widget)]
#[derive(Live, Widget)]
pub struct VerificationBadge {
#[deref]
view: View,
#[rust(VerificationState::Unknown)]
pub verification_state: VerificationState,
}

impl VerificationBadge {
pub fn get_icons_rect(&self, cx: &Cx) -> Rect {
self.view(id!(verification_icons)).area().rect(cx)
#[deref] view: View,
#[rust(VerificationState::Unknown)] verification_state: VerificationState,
}

impl LiveHook for VerificationBadge {
fn after_new_from_doc(&mut self, cx: &mut Cx) {
if let Some(client) = get_client() {
let current_verification_state = client.encryption().verification_state().get();
if self.verification_state != current_verification_state {
self.verification_state = current_verification_state;
self.update_icon_visibility(cx);
}
}
}
}

impl Widget for VerificationBadge {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
self.view.handle_event(cx, event, scope)
self.view.handle_event(cx, event, scope);

if let Event::Actions(actions) = event {
for action in actions {
if let Some(VerificationStateAction::Update(state)) = action.downcast_ref() {
if self.verification_state != *state {
self.verification_state = *state;
self.update_icon_visibility(cx);
}
}
}
}

let badge = self.view(id!(verification_icons));
let badge_area = badge.area();
match event.hits(cx, badge_area) {
Hit::FingerDown(_)
| Hit::FingerUp(_)
| Hit::FingerHoverIn(_)
| Hit::FingerHoverOver(_) => {
let badge_rect = badge_area.rect(cx);
let tooltip_pos = if cx.display_context.is_desktop() {
DVec2 {
x: badge_rect.pos.x + badge_rect.size.x + 1.,
y: badge_rect.pos.y - 10.,
}
} else {
DVec2 {
x: badge_rect.pos.x,
y: badge_rect.pos.y - 10.,
}
};

cx.widget_action(
self.widget_uid(),
&scope.path,
ProfileTooltipAction::Show {
pos: tooltip_pos,
text: verification_state_str(self.verification_state),
color: verification_state_color(self.verification_state),
},
);
}
Hit::FingerHoverOut(_) => {
cx.widget_action(
self.widget_uid(),
&scope.path,
ProfileTooltipAction::Hide,
);
}
_ => { }
}
}

fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
self.view.draw_walk(cx, scope, walk)
}
}

impl VerificationBadgeRef {
pub fn set_verification_state(&mut self, cx: &mut Cx, state: VerificationState) {
if let Some(mut inner) = self.0.borrow_mut::<VerificationBadge>() {
if inner.verification_state != state {
inner.verification_state = state;
inner.update_icon_visibility(cx);
inner.redraw(cx);
}
}
}
}

impl VerificationBadge {
pub fn update_icon_visibility(&mut self, cx: &mut Cx) {
let (yes, no, unk) = match self.verification_state {
Expand All @@ -149,5 +182,6 @@ impl VerificationBadge {
self.view(id!(icon_yes)).set_visible(cx, yes);
self.view(id!(icon_no)).set_visible(cx, no);
self.view(id!(icon_unk)).set_visible(cx, unk);
self.redraw(cx);
}
}
Loading