Skip to content

Commit

Permalink
Merge pull request #244 from aaravlu/fix241
Browse files Browse the repository at this point in the history
 Display verification status as a badge atop the user profile icon
  • Loading branch information
kevinaboos authored Dec 18, 2024
2 parents 4f2712d + 641f78a commit db88316
Show file tree
Hide file tree
Showing 9 changed files with 286 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,4 @@ collapsible_else_if = "allow"
too_many_arguments = "allow"
blocks_in_conditions = "allow"
used_underscore_binding = "allow"
module_name_repetitions = "allow"
module_name_repetitions = "allow"
4 changes: 4 additions & 0 deletions resources/icons/verification_no.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions resources/icons/verification_unk.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions resources/icons/verification_yes.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
156 changes: 146 additions & 10 deletions src/home/spaces_dock.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
use makepad_widgets::*;
use matrix_sdk::encryption::VerificationState;

use crate::shared::adaptive_view::DisplayContext;
use crate::sliding_sync::get_client;
use crate::verification::VerificationStateAction;

live_design! {
import makepad_widgets::base::*;
Expand All @@ -8,6 +13,7 @@ live_design! {
import crate::shared::styles::*;
import crate::shared::helpers::*;
import crate::shared::adaptive_view::AdaptiveView;
import crate::shared::verification_badge::*;

ICON_HOME = dep("crate://self/resources/icons/home.svg")
ICON_SETTINGS = dep("crate://self/resources/icons/settings.svg")
Expand All @@ -16,21 +22,26 @@ live_design! {
height: Fill, width: Fill
}

Profile = <View> {
Profile = {{Profile}} {
flow: Overlay
width: Fit, height: Fit
align: { x: 0.5, y: 0.5 }

text_view = <View> {
width: 45., height: 45.,
flow: Overlay
width: 60, height: 60,
align: { x: 0.5, y: 0.5 }
show_bg: true,

draw_bg: {
instance background_color: (COLOR_AVATAR_BG_IDLE),
fn pixel(self) -> vec4 {
let sdf = Sdf2d::viewport(self.pos * self.rect_size);

let c = self.rect_size * 0.5;
sdf.circle(c.x, c.x, c.x)

let r = self.rect_size * 0.38;

sdf.circle(c.x, c.x, r.x);
sdf.fill_keep(self.background_color);
return sdf.result
}
Expand All @@ -46,6 +57,20 @@ live_design! {
text: "U"
}
}
<View> {
align: { x: 1.0, y: 0.0 }

verification_icon = <View> {
flow: Overlay
align:{ x: 0.5, y: 0.5 }
width: 31, height: 31

icon_yes = <IconYes> {}
icon_no = <IconNo> {}
icon_unk = <IconUnk> {}
}
}
verification_notice = <VerificationNotice> { }
}

Separator = <LineH> {
Expand Down Expand Up @@ -118,7 +143,7 @@ live_design! {
<Separator> {}

<Home> {}

<Filler> {}

<Settings> {}
Expand All @@ -137,16 +162,127 @@ live_design! {
<Filler> {}

<Profile> {}

<Filler> {}

<Home> {}

<Filler> {}

<Settings> {}

<Filler> {}
}
}
}
struct VerificationNoticeText {
yes: &'static str,
no: &'static str,
unk: &'static str,
}

impl Default for VerificationNoticeText{
fn default() -> Self {
Self {
yes: "This device is fully verified.",
no: "This device is unverified. To view your encrypted message history, please verify it from another client.",
unk: "Verification state is unknown.",
}
}
}

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

impl Profile {
fn set_verification_icon_visibility(&self) {
let (yes_visible, no_visible, unk_visible) = match self.verification_state {
VerificationState::Unknown => (false, false, true),
VerificationState::Unverified => (false, true, false),
VerificationState::Verified => (true, false, false),
};

self.view(id!(icon_yes)).set_visible(yes_visible);
self.view(id!(icon_no)).set_visible(no_visible);
self.view(id!(icon_unk)).set_visible(unk_visible);
}
}

impl Widget for Profile {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
if let Event::MouseMove(e) = event {
let mut verification_notice = self.tooltip(id!(verification_notice));

if self.view(id!(verification_icon)).area().rect(cx).contains(e.abs) {
let text = match self.verification_state {
VerificationState::Unknown => self.verification_notice_text.unk,
VerificationState::Unverified => self.verification_notice_text.no,
VerificationState::Verified => self.verification_notice_text.yes
};

//Determine if it's a desktop or mobile layout,
//then we set the relative position so that the tooltip looks like following the cursor.
if cx.get_global::<DisplayContext>().is_desktop() {
verification_notice.show_with_options(cx, DVec2 {x: 65., y: 23.}, text);
}
else {
verification_notice.apply_over(cx, live!{
content: {

// Via setting suitable align & padding,
// we can simulate a relative position to make the tootip follow widget `Profile (U)`,
// this is not a perfect solution.
// TODO: Find a way to follow widget `Profile (U)` more precisely.
align: { x: 0.43, y: 1. }
padding: { left: 30., bottom: 31. }
}
});
verification_notice.show_with_options(cx, DVec2 {x: 0., y: 0.}, text);
}
}
//Hide it if cursor is not hovering.
else {
verification_notice.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 self.verification_state != *state {
self.verification_state = *state;

self.set_verification_icon_visibility();
self.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();
self.verification_state = current_verification_state;

self.set_verification_icon_visibility();
self.redraw(cx);
}
}
}
2 changes: 2 additions & 0 deletions src/shared/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod search_bar;
pub mod styles;
pub mod text_or_image;
pub mod typing_animation;
pub mod verification_badge;

pub fn live_design(cx: &mut Cx) {
// Order matters here, as some widget definitions depend on others.
Expand All @@ -25,4 +26,5 @@ pub fn live_design(cx: &mut Cx) {
adaptive_view::live_design(cx);
typing_animation::live_design(cx);
jump_to_bottom_button::live_design(cx);
verification_badge::live_design(cx);
}
2 changes: 2 additions & 0 deletions src/shared/styles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ live_design! {
COLOR_AVATAR_BG = #52b2ac
COLOR_AVATAR_BG_IDLE = #d8d8d8

COLOR_TOOLTIP_BG = (COLOR_SECONDARY)

COLOR_UNREAD_MESSAGE_BADGE = (COLOR_AVATAR_BG)

COLOR_TEXT_IDLE = #d8d8d8
Expand Down
93 changes: 93 additions & 0 deletions src/shared/verification_badge.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use makepad_widgets::*;

live_design! {
import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*;
import makepad_draw::shader::std::*;

import crate::shared::styles::*;

VERIFICATION_YES = dep("crate://self/resources/icons/verification_yes.svg")
VERIFICATION_NO = dep("crate://self/resources/icons/verification_no.svg")
VERIFICATION_UNK = dep("crate://self/resources/icons/verification_unk.svg")

VerificationIcon = <Icon> {
icon_walk: { width: 23 }
}
IconYes = <View> {
visible: false
width: 31, height: 31
<VerificationIcon> {
draw_icon: {
svg_file: (VERIFICATION_YES),
fn get_color(self) -> vec4 {
return #x00BF00;
}
}
}
}
IconNo = <View> {
visible: false
width: 31, height: 31
<VerificationIcon> {
draw_icon: {
svg_file: (VERIFICATION_NO),
fn get_color(self) -> vec4 {
return #xBF0000;
}
}
}
}
IconUnk = <View> {
visible: false
width: 31, height: 31
<VerificationIcon> {
draw_icon: {
svg_file: (VERIFICATION_UNK),
fn get_color(self) -> vec4 {
return #x333333;
}
}
}
}

VerificationNotice = <TooltipBase> {
width: Fill, height: Fill,
flow: Overlay

draw_bg: {
fn pixel(self) -> vec4 {
return vec4(0., 0., 0., 0.0)
}
}

content: <View> {
flow: Overlay

//The 'Fill' allows it shows anywhere we want over the app screen,
//our goal is to set the global relative position to make it an illusion of following the cursor.
width: Fill, height: Fill

<RoundedView> {
width: Fit, height: Fit,
padding: 7,

draw_bg: {
color: (COLOR_TOOLTIP_BG),
border_width: 1.0,
border_color: #000000,
radius: 2.5
}

tooltip_label = <Label> {
width: 230
draw_text: {
text_style: <THEME_FONT_REGULAR>{font_size: SMALL_STATE_FONT_SIZE},
text_wrap: Word,
color: #000
}
}
}
}
}
}
Loading

0 comments on commit db88316

Please sign in to comment.