Skip to content

Commit

Permalink
Show JTB button with unread message badge upon new out-of-view messages
Browse files Browse the repository at this point in the history
When new messages are received in the currently-displayed room timeline,
it can be hard for the user to tell/know when a new message has arrived.
This commit provides a subtle visual cue that shows a small dot on the
jump to bottom button, indicating that new unread messages have arrived
beneath the current viewport range.

In the future, we'll also add a label with the exact count of unread messages
below the current viewport.
  • Loading branch information
kevinaboos committed Nov 9, 2024
1 parent 893f8ac commit 7086884
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 40 deletions.
29 changes: 0 additions & 29 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ version = "0.0.1-pre-alpha"
metadata.makepad-auto-version = "zqpv-Yj-K7WNVK2I8h5Okhho46Q="

[dependencies]
makepad-widgets = { git = "https://github.com/kevinaboos/makepad", branch = "widget_uid_hashable" }
# makepad-widgets = { git = "https://github.com/kevinaboos/makepad", branch = "widget_uid_hashable" }
makepad-widgets = { path = "../makepad/widgets" }

## Including this crate automatically configures all `robius-*` crates to work with Makepad.
robius-use-makepad = "0.1.1"
Expand Down
65 changes: 57 additions & 8 deletions src/home/room_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,29 +668,59 @@ live_design! {
jump_to_bottom_view = <View> {
width: Fill,
height: Fill,
flow: Down,
flow: Overlay,
align: {x: 1.0, y: 1.0},
margin: {right: 15.0, bottom: 15.0},
visible: false,

jump_to_bottom_button = <IconButton> {
margin: {right: 15.0, bottom: 15.0},
width: 50, height: 50,
draw_icon: {svg_file: (ICO_JUMP_TO_BOTTOM)},
icon_walk: {width: 20, height: 20, margin: {top: 10, right: 4.5} }
// draw a circular background for the button
draw_bg: {
instance background_color: #edededee,
instance background_color: #edededce,
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)
sdf.circle(c.x, c.x, c.x);
sdf.fill_keep(self.background_color);
return sdf.result
}
}
}
}

// A badge overlay on the jump to bottom button showing unread messages
unread_message_badge = <View> {
width: 12, height: 12,
margin: {right: 33.0, bottom: 11.0},
visible: false,

show_bg: true,
draw_bg: {
color: (COLOR_UNREAD_MESSAGE_BADGE)
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);
sdf.fill_keep(self.color);
return sdf.result;
}
}

// // Label that displays the unread message count
// unread_messages_count = <Label> {
// width: Fill,
// height: Fill,
// text: "",
// align: {x: 0.5, y: 0.5},
// draw_text: {
// color: #ffffff,
// text_style: {font_size: 8.0},
// }
// }
}
}
}

LocationPreview = {{LocationPreview}} {
Expand Down Expand Up @@ -1304,9 +1334,14 @@ impl Widget for RoomScreen {
// Handle the jump to bottom button: update its visibility, and handle clicks.
{
let jump_to_bottom_view = self.view(id!(jump_to_bottom_view));
let unread_message_badge = self.view(id!(unread_message_badge));
if portal_list.scrolled(&actions) {
// TODO: is_at_end() isn't perfect, see: <https://github.com/makepad/makepad/issues/517>
jump_to_bottom_view.set_visible(!portal_list.is_at_end());
if portal_list.is_at_end() {
jump_to_bottom_view.set_visible(false);
unread_message_badge.set_visible(false);
} else {
jump_to_bottom_view.set_visible(true);
}
}

const SCROLL_TO_BOTTOM_NUM_ANIMATION_ITEMS: usize = 30;
Expand All @@ -1318,6 +1353,7 @@ impl Widget for RoomScreen {
SCROLL_TO_BOTTOM_SPEED,
);
jump_to_bottom_view.set_visible(false);
unread_message_badge.set_visible(false);
self.redraw(cx);
}
}
Expand Down Expand Up @@ -1496,6 +1532,7 @@ impl RoomScreen {
/// Redraws this RoomScreen view if any updates were applied.
fn process_timeline_updates(&mut self, cx: &mut Cx, portal_list: &PortalListRef) {
let top_space = self.view(id!(top_space));
let jump_to_bottom_view = self.view(id!(jump_to_bottom_view));
let curr_first_id = portal_list.first_id();
let Some(tl) = self.tl_state.as_mut() else { return };

Expand All @@ -1506,7 +1543,7 @@ impl RoomScreen {
while let Ok(update) = tl.update_receiver.try_recv() {
num_updates += 1;
match update {
TimelineUpdate::NewItems { new_items, changed_indices, clear_cache } => {
TimelineUpdate::NewItems { new_items, changed_indices, is_append, clear_cache } => {
if new_items.is_empty() {
if !tl.items.is_empty() {
log!("Timeline::handle_event(): timeline (had {} items) was cleared for room {}", tl.items.len(), tl.room_id);
Expand Down Expand Up @@ -1545,6 +1582,8 @@ impl RoomScreen {
log!("Timeline::handle_event(): jumping to bottom: curr_first_id {} is out of bounds for {} new items", curr_first_id, new_items.len());
portal_list.set_first_id_and_scroll(new_items.len().saturating_sub(1), 0.0);
portal_list.set_tail_range(true);
jump_to_bottom_view.set_visible(false);
jump_to_bottom_view.view(id!(unread_message_badge)).set_visible(false);
}
else if let Some((curr_item_idx, new_item_idx, new_item_scroll, _event_id)) =
find_new_item_matching_current_item(cx, &portal_list, curr_first_id, &tl.items, &new_items)
Expand Down Expand Up @@ -1572,6 +1611,13 @@ impl RoomScreen {
warning!("!!! Couldn't find new event with matching ID for ANY event currently visible in the portal list");
}

// If new items were appended to the end of the timeline, show an unread messages badge on the jump to bottom button.
if is_append && !portal_list.is_at_end() {
log!("is_append was true, showing unread message badge on the jump to bottom button visible");
jump_to_bottom_view.set_visible(true);
jump_to_bottom_view.view(id!(unread_message_badge)).set_visible(true);
}

if clear_cache {
tl.content_drawn_since_last_update.clear();
tl.profile_drawn_since_last_update.clear();
Expand Down Expand Up @@ -2021,6 +2067,9 @@ pub enum TimelineUpdate {
/// and thus must be removed from any caches of drawn items in the timeline.
/// Any items outside of this range are assumed to be unchanged and need not be redrawn.
changed_indices: Range<usize>,
/// An optimization that informs the UI whether the changes to the timeline
/// resulted in new items being *appended to the end* of the timeline.
is_append: bool,
/// Whether to clear the entire cache of drawn items in the timeline.
/// This supercedes `index_of_first_change` and is used when the entire timeline is being redrawn.
clear_cache: bool,
Expand Down
1 change: 1 addition & 0 deletions src/home/rooms_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ live_design! {

list = <PortalList> {
keep_invisible: false
auto_tail: false
width: Fill, height: Fill
flow: Down, spacing: 0.0

Expand Down
2 changes: 2 additions & 0 deletions src/shared/styles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ live_design! {
COLOR_AVATAR_BG = #52b2ac
COLOR_AVATAR_BG_IDLE = #d8d8d8

COLOR_UNREAD_MESSAGE_BADGE = (COLOR_AVATAR_BG)

COLOR_TEXT_IDLE = #d8d8d8
COLOR_TEXT = #1C274C

Expand Down
Loading

0 comments on commit 7086884

Please sign in to comment.