diff --git a/Cargo.toml b/Cargo.toml
index de46ba31..b0fe90e0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -215,4 +215,4 @@ collapsible_else_if = "allow"
too_many_arguments = "allow"
blocks_in_conditions = "allow"
used_underscore_binding = "allow"
-module_name_repetitions = "allow"
\ No newline at end of file
+module_name_repetitions = "allow"
diff --git a/resources/icons/verification_no.svg b/resources/icons/verification_no.svg
new file mode 100644
index 00000000..7059a301
--- /dev/null
+++ b/resources/icons/verification_no.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/resources/icons/verification_unk.svg b/resources/icons/verification_unk.svg
new file mode 100644
index 00000000..18b3e747
--- /dev/null
+++ b/resources/icons/verification_unk.svg
@@ -0,0 +1,18 @@
+
+
+
diff --git a/resources/icons/verification_yes.svg b/resources/icons/verification_yes.svg
new file mode 100644
index 00000000..a5d02837
--- /dev/null
+++ b/resources/icons/verification_yes.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/src/home/spaces_dock.rs b/src/home/spaces_dock.rs
index 70e6964b..7b194863 100644
--- a/src/home/spaces_dock.rs
+++ b/src/home/spaces_dock.rs
@@ -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::*;
@@ -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")
@@ -16,21 +22,26 @@ live_design! {
height: Fill, width: Fill
}
- Profile = {
+ Profile = {{Profile}} {
+ flow: Overlay
width: Fit, height: Fit
align: { x: 0.5, y: 0.5 }
text_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
}
@@ -46,6 +57,20 @@ live_design! {
text: "U"
}
}
+ {
+ align: { x: 1.0, y: 0.0 }
+
+ verification_icon = {
+ flow: Overlay
+ align:{ x: 0.5, y: 0.5 }
+ width: 31, height: 31
+
+ icon_yes = {}
+ icon_no = {}
+ icon_unk = {}
+ }
+ }
+ verification_notice = { }
}
Separator = {
@@ -118,7 +143,7 @@ live_design! {
{}
{}
-
+
{}
{}
@@ -137,16 +162,127 @@ live_design! {
{}
{}
-
+
{}
-
+
{}
-
+
{}
-
+
{}
-
+
{}
}
}
}
+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::().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);
+ }
+ }
+}
diff --git a/src/shared/mod.rs b/src/shared/mod.rs
index 478b47ca..cc896b0e 100644
--- a/src/shared/mod.rs
+++ b/src/shared/mod.rs
@@ -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.
@@ -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);
}
diff --git a/src/shared/styles.rs b/src/shared/styles.rs
index 82097d60..06e64d72 100644
--- a/src/shared/styles.rs
+++ b/src/shared/styles.rs
@@ -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
diff --git a/src/shared/verification_badge.rs b/src/shared/verification_badge.rs
new file mode 100644
index 00000000..e594cc90
--- /dev/null
+++ b/src/shared/verification_badge.rs
@@ -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_walk: { width: 23 }
+ }
+ IconYes = {
+ visible: false
+ width: 31, height: 31
+ {
+ draw_icon: {
+ svg_file: (VERIFICATION_YES),
+ fn get_color(self) -> vec4 {
+ return #x00BF00;
+ }
+ }
+ }
+ }
+ IconNo = {
+ visible: false
+ width: 31, height: 31
+ {
+ draw_icon: {
+ svg_file: (VERIFICATION_NO),
+ fn get_color(self) -> vec4 {
+ return #xBF0000;
+ }
+ }
+ }
+ }
+ IconUnk = {
+ visible: false
+ width: 31, height: 31
+ {
+ draw_icon: {
+ svg_file: (VERIFICATION_UNK),
+ fn get_color(self) -> vec4 {
+ return #x333333;
+ }
+ }
+ }
+ }
+
+ VerificationNotice = {
+ width: Fill, height: Fill,
+ flow: Overlay
+
+ draw_bg: {
+ fn pixel(self) -> vec4 {
+ return vec4(0., 0., 0., 0.0)
+ }
+ }
+
+ content: {
+ 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
+
+ {
+ width: Fit, height: Fit,
+ padding: 7,
+
+ draw_bg: {
+ color: (COLOR_TOOLTIP_BG),
+ border_width: 1.0,
+ border_color: #000000,
+ radius: 2.5
+ }
+
+ tooltip_label =