From 75e3617274da12a7f0f4530de3e0bcdbf978109f Mon Sep 17 00:00:00 2001 From: Kevin Boos Date: Tue, 2 Jun 2026 23:51:27 -0700 Subject: [PATCH 1/2] Show dedicated send message icons for encrypted vs unencrypted rooms Also use different colors for them to highlight the difference, as well as better different text for the message text input --- resources/{icon_send.svg => icons/send.svg} | 0 resources/icons/send_encrypted.svg | 10 +++ resources/icons/send_unencrypted.svg | 10 +++ src/home/room_screen.rs | 2 +- src/room/room_input_bar.rs | 70 +++++++++++++++------ src/shared/styles.rs | 4 +- 6 files changed, 74 insertions(+), 22 deletions(-) rename resources/{icon_send.svg => icons/send.svg} (100%) create mode 100644 resources/icons/send_encrypted.svg create mode 100644 resources/icons/send_unencrypted.svg diff --git a/resources/icon_send.svg b/resources/icons/send.svg similarity index 100% rename from resources/icon_send.svg rename to resources/icons/send.svg diff --git a/resources/icons/send_encrypted.svg b/resources/icons/send_encrypted.svg new file mode 100644 index 000000000..99fce6c47 --- /dev/null +++ b/resources/icons/send_encrypted.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/icons/send_unencrypted.svg b/resources/icons/send_unencrypted.svg new file mode 100644 index 000000000..ad6ce21e5 --- /dev/null +++ b/resources/icons/send_unencrypted.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/home/room_screen.rs b/src/home/room_screen.rs index 46340cc25..391421ed0 100644 --- a/src/home/room_screen.rs +++ b/src/home/room_screen.rs @@ -1814,7 +1814,7 @@ impl RoomScreen { TimelineUpdate::RoomEncrypted => { tl.is_encrypted = true; self.view.room_input_bar(cx, ids!(room_input_bar)) - .update_encryption_status(cx, true); + .update_encryption_state(cx, true); } TimelineUpdate::LinkPreviewFetched => {} TimelineUpdate::FileUploadStarted { upload_id, file_name, in_reply_to, abort_handle } => { diff --git a/src/room/room_input_bar.rs b/src/room/room_input_bar.rs index 2cdde437e..4788f7e86 100644 --- a/src/room/room_input_bar.rs +++ b/src/room/room_input_bar.rs @@ -82,7 +82,8 @@ script_mod! { padding: 6, open_popup_menu_button := RobrixIconButton { - margin: 4 + padding: 9 + margin: Inset { top: 4, left: 4, right: 4, bottom: 5} spacing: 0, draw_icon +: { svg: (ICON_ADD) @@ -94,7 +95,6 @@ script_mod! { color_down: #xD0D8E8 } icon_walk: Walk{width: 21, height: 21} - text: "", } // A checkbox that enables TSP signing for the outgoing message. @@ -105,7 +105,6 @@ script_mod! { mentionable_text_input := MentionableTextInput { width: Fill, - height: Fit margin: Inset { top: 3, // add some space between the top border of the text input and the top border of the room input bar bottom: 5.75, // to line up the middle of the text input with the middle of the buttons @@ -125,11 +124,11 @@ script_mod! { send_message_button := RobrixPositiveIconButton { // Disabled by default; enabled when text is inputted enabled: false, + padding: 8 + margin: Inset { top: 4, left: 4, right: 4, bottom: 5} spacing: 0, - text: "", - margin: 4 draw_icon +: { svg: (ICON_SEND) } - icon_walk: Walk{width: 21, height: 21}, + icon_walk: Walk{width: 23, height: 23}, } } @@ -175,6 +174,10 @@ pub struct RoomInputBar { /// Cached natural Fit height of the input_bar, used as the animation /// target when the editing pane is being hidden. #[rust] input_bar_natural_height: f64, + /// Whether the currently-displayed room is encrypted, used to style the send button. + #[rust] is_encrypted: bool, + /// Whether the send button is currently enabled (the message input is non-empty). + #[rust] is_send_enabled: bool, } impl ScriptHook for RoomInputBar { @@ -394,7 +397,12 @@ impl RoomInputBar { } else { text_input.text().is_empty() }; - self.enable_send_message_button(cx, !is_text_input_empty); + // Only restyle the button when its enabled state actually changes, + // not on every actions pass. + let should_enable = !is_text_input_empty; + if should_enable != self.is_send_enabled { + self.enable_send_message_button(cx, should_enable); + } // Handle the user pressing the up arrow in an empty message input box // to edit their latest sent message. @@ -557,15 +565,18 @@ impl RoomInputBar { } } - /// Sets the send_message_button to be enabled and green, or disabled and gray. + /// Enables or disables (grays out) the send_message_button. /// - /// This should be called to update the button state when the message TextInput content changes. + /// When enabled, the button color is set based on the room's encryption state. fn enable_send_message_button(&mut self, cx: &mut Cx, enable: bool) { + self.is_send_enabled = enable; let mut send_message_button = self.view.button(cx, ids!(send_message_button)); - let (fg_color, bg_color) = if enable { + let (fg_color, bg_color) = if !enable { + (COLOR_FG_DISABLED, COLOR_BG_DISABLED) + } else if self.is_encrypted { (COLOR_FG_ACCEPT_GREEN, COLOR_BG_ACCEPT_GREEN) } else { - (COLOR_FG_DISABLED, COLOR_BG_DISABLED) + (COLOR_PRIMARY, COLOR_ACTIVE_PRIMARY) }; script_apply_eval!(cx, send_message_button, { enabled: #(enable), @@ -587,15 +598,34 @@ impl RoomInputBar { self.view.view(cx, ids!(can_not_send_message_notice)).set_visible(cx, !can_send); } - /// Sets the message input's placeholder to reflect this room's encryption status. - fn update_encryption_status(&mut self, cx: &mut Cx, is_encrypted: bool) { - let empty_text = if is_encrypted { - "Send an encrypted message..." + /// Updates the send button (icon + color style) and empty message text + /// based on this room's encryption status. + fn update_encryption_state(&mut self, cx: &mut Cx, is_encrypted: bool) { + self.is_encrypted = is_encrypted; + + // The send button is a "positive" green with a closed-lock badge when encrypted, + // and a standard button with an opened-lock badge when not encrypted. + let mut send_message_button = self.view.button(cx, ids!(send_message_button)); + let empty_text: &str; + if is_encrypted { + apply_positive_button_style(cx, &mut send_message_button); + script_apply_eval!(cx, send_message_button, { + draw_icon.svg: mod.widgets.ICON_SEND_ENCRYPTED, + }); + empty_text = "Send encrypted message…"; } else { - "Send an unencrypted message..." - }; + apply_primary_button_style(cx, &mut send_message_button); + script_apply_eval!(cx, send_message_button, { + draw_icon.svg: mod.widgets.ICON_SEND_UNENCRYPTED, + }); + empty_text = "Send unencrypted message…"; + } + self.text_input(cx, ids!(input_bar.mentionable_text_input.text_input)) .set_empty_text(cx, empty_text.to_string()); + + let enable = self.is_send_enabled; + self.enable_send_message_button(cx, enable); } /// Returns true if the TSP signing checkbox is checked, false otherwise. @@ -767,9 +797,9 @@ impl RoomInputBarRef { } /// Updates the message input's placeholder based on this room's encryption status. - pub fn update_encryption_status(&self, cx: &mut Cx, is_encrypted: bool) { + pub fn update_encryption_state(&self, cx: &mut Cx, is_encrypted: bool) { let Some(mut inner) = self.borrow_mut() else { return }; - inner.update_encryption_status(cx, is_encrypted); + inner.update_encryption_state(cx, is_encrypted); } /// Opens the native picker to upload a photo or video into this room. @@ -849,7 +879,7 @@ impl RoomInputBarRef { // This must happen before we restore the state of the `EditingPane`, // because the call to `show_editing_pane()` might re-update the `input_bar`'s visibility. inner.update_user_power_levels(cx, user_power_levels); - inner.update_encryption_status(cx, is_encrypted); + inner.update_encryption_state(cx, is_encrypted); // 1. Restore the state of the TextInput within the MentionableTextInput. inner.text_input(cx, ids!(input_bar.mentionable_text_input.text_input)) diff --git a/src/shared/styles.rs b/src/shared/styles.rs index 1a06a9a94..21d50eda8 100644 --- a/src/shared/styles.rs +++ b/src/shared/styles.rs @@ -35,7 +35,9 @@ script_mod! { mod.widgets.ICON_PIN = crate_resource("self://resources/icons/pin.svg") mod.widgets.ICON_REPLY = crate_resource("self://resources/icons/reply.svg") mod.widgets.ICON_SEARCH = crate_resource("self://resources/icons/search.svg") - mod.widgets.ICON_SEND = crate_resource("self://resources/icon_send.svg") + mod.widgets.ICON_SEND = crate_resource("self://resources/icons/send.svg") + mod.widgets.ICON_SEND_ENCRYPTED = crate_resource("self://resources/icons/send_encrypted.svg") + mod.widgets.ICON_SEND_UNENCRYPTED = crate_resource("self://resources/icons/send_unencrypted.svg") mod.widgets.ICON_SETTINGS = crate_resource("self://resources/icons/settings.svg") mod.widgets.ICON_SQUARES = crate_resource("self://resources/icons/squares_filled.svg") mod.widgets.ICON_TOMBSTONE = crate_resource("self://resources/icons/tombstone.svg") From bfec5d091ac8259a9b072d9b4e01e33d6a42b5c6 Mon Sep 17 00:00:00 2001 From: Kevin Boos Date: Tue, 2 Jun 2026 23:55:15 -0700 Subject: [PATCH 2/2] clippy --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 1c7b74624..0b69a6b54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -328,6 +328,7 @@ collapsible_if = "allow" collapsible_else_if = "allow" doc_overindented_list_items = "allow" module_name_repetitions = "allow" +needless_late_init = "allow" too_many_arguments = "allow" uninlined_format_args = "allow" used_underscore_binding = "allow"