Skip to content
Open
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
12 changes: 6 additions & 6 deletions src/home/invite_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,10 @@ impl Widget for InviteScreen {
}

if self.invite_state != orig_state {
if let (Some(room_name_id), true) = (self.room_name_id.as_ref(), cx.has_global::<RoomsListRef>()) {
let rooms_list_ref = cx.get_global::<RoomsListRef>();
rooms_list_ref.set_invite_state(room_name_id.room_id().clone(), self.invite_state);
}
self.redraw(cx);
}
}
Expand All @@ -396,7 +400,7 @@ impl Widget for InviteScreen {
if !self.is_loaded {
let mut restore_status_view = self.view.restore_status_view(ids!(restore_status_view));
if let Some(room_name) = &self.room_name_id {
restore_status_view.set_content(cx, self.all_rooms_loaded, room_name);
restore_status_view.set_content(cx, self.all_rooms_loaded, room_name, None);
}
return restore_status_view.draw(cx, scope);
}
Expand Down Expand Up @@ -536,11 +540,7 @@ impl InviteScreen {

let restore_status_view = self.view.restore_status_view(ids!(restore_status_view));
if !self.is_loaded {
restore_status_view.set_content(
cx,
self.all_rooms_loaded,
room_name_id,
);
restore_status_view.set_content(cx, self.all_rooms_loaded, room_name_id, None);
restore_status_view.set_visible(cx, true);
} else {
restore_status_view.set_visible(cx, false);
Expand Down
292 changes: 287 additions & 5 deletions src/home/room_screen.rs

Large diffs are not rendered by default.

204 changes: 177 additions & 27 deletions src/home/rooms_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,22 @@ pub enum RoomsListUpdate {
room_id: OwnedRoomId,
is_direct: bool,
},
/// Remove the given room from the rooms list
/// Remove the given room from the rooms list, or mark it as removed for history.
RemoveRoom {
room_id: OwnedRoomId,
/// The new state of the room (which caused its removal).
new_state: RoomState,
},
/// Update the removed state of a room without removing it.
SetRemovedRoomState {
room_id: OwnedRoomId,
removed_state: Option<RoomState>,
},
/// Update the invite state for the given invited room.
SetInviteState {
room_id: OwnedRoomId,
invite_state: InviteState,
},
/// Update the tags for the given room.
Tags {
room_id: OwnedRoomId,
Expand Down Expand Up @@ -258,6 +268,8 @@ pub enum RoomsListAction {
pub struct JoinedRoomInfo {
/// The displayable name of this room (includes room ID for fallback).
pub room_name_id: RoomNameId,
/// If set, the user is no longer a member of this room but we keep it for history.
pub removed_state: Option<RoomState>,
/// The number of unread messages in this room.
pub num_unread_messages: u64,
/// The number of unread mentions in this room.
Expand Down Expand Up @@ -487,15 +499,30 @@ impl RoomsList {

/// Returns the state of the room if it is loaded and known to our client.
pub fn get_room_state(&self, room_id: &OwnedRoomId) -> Option<RoomState> {
if self.all_joined_rooms.contains_key(room_id) {
return Some(RoomState::Joined);
}
if self.invited_rooms.borrow().contains_key(room_id) {
return Some(RoomState::Invited);
}
if self.all_joined_rooms.contains_key(room_id) {
return Some(RoomState::Joined);
}
None
}

/// Returns the invite state of the room, if it is currently an invite.
pub fn get_invite_state(&self, room_id: &OwnedRoomId) -> Option<InviteState> {
self.invited_rooms
.borrow()
.get(room_id)
.map(|info| info.invite_state)
}

/// Returns the removal state of the room, if it was removed (e.g., left or banned).
pub fn get_removed_room_state(&self, room_id: &OwnedRoomId) -> Option<RoomState> {
self.all_joined_rooms
.get(room_id)
.and_then(|jr| jr.removed_state)
}

/// Handle all pending updates to the list of all rooms.
fn handle_rooms_list_updates(&mut self, cx: &mut Cx, _event: &Event, scope: &mut Scope) {
let mut num_updates: usize = 0;
Expand All @@ -506,7 +533,22 @@ impl RoomsList {
let room_id = invited_room.room_name_id.room_id().clone();
let should_display = should_display_room!(self, &room_id, &invited_room);
let _replaced = self.invited_rooms.borrow_mut().insert(room_id.clone(), invited_room);
if should_display {
let mut keep_joined_room = false;
if let Some(joined_room) = self.all_joined_rooms.get(&room_id) {
keep_joined_room = joined_room.removed_state.is_some();
let list_to_remove_from = if joined_room.is_direct {
&mut self.displayed_direct_rooms
} else {
&mut self.displayed_regular_rooms
};
list_to_remove_from.iter()
.position(|r| r == &room_id)
.map(|index| list_to_remove_from.remove(index));
}
if !keep_joined_room {
self.all_joined_rooms.remove(&room_id);
}
if should_display && !self.displayed_invited_rooms.contains(&room_id) {
self.displayed_invited_rooms.push(room_id);
}
self.update_status();
Expand All @@ -519,9 +561,19 @@ impl RoomsList {
let _replaced = self.all_joined_rooms.insert(room_id.clone(), joined_room);
if should_display {
if is_direct {
self.displayed_direct_rooms.push(room_id.clone());
if !self.displayed_direct_rooms.contains(&room_id) {
self.displayed_direct_rooms.push(room_id.clone());
}
if let Some(index) = self.displayed_regular_rooms.iter().position(|r| r == &room_id) {
self.displayed_regular_rooms.remove(index);
}
} else {
self.displayed_regular_rooms.push(room_id.clone());
if !self.displayed_regular_rooms.contains(&room_id) {
self.displayed_regular_rooms.push(room_id.clone());
}
if let Some(index) = self.displayed_direct_rooms.iter().position(|r| r == &room_id) {
self.displayed_direct_rooms.remove(index);
}
}
}

Expand Down Expand Up @@ -663,28 +715,84 @@ impl RoomsList {
error!("Error: couldn't find room {room_id} to update is_direct");
}
}
RoomsListUpdate::RemoveRoom { room_id, new_state: _ } => {
if let Some(removed) = self.all_joined_rooms.remove(&room_id) {
log!("Removed room {room_id} from the list of all joined rooms");
let list_to_remove_from = if removed.is_direct {
&mut self.displayed_direct_rooms
} else {
&mut self.displayed_regular_rooms
};
list_to_remove_from.iter()
.position(|r| r == &room_id)
.map(|index| list_to_remove_from.remove(index));
RoomsListUpdate::RemoveRoom { room_id, new_state } => {
if matches!(new_state, RoomState::Left | RoomState::Banned) {
if let Some(room) = self.all_joined_rooms.get_mut(&room_id) {
room.removed_state = Some(new_state);
room.num_unread_mentions = 0;
room.num_unread_messages = 0;
} else if let Some(_removed) = self.invited_rooms.borrow_mut().remove(&room_id) {
log!("Removed room {room_id} from the list of all invited rooms");
self.displayed_invited_rooms.iter()
.position(|r| r == &room_id)
.map(|index| self.displayed_invited_rooms.remove(index));
}
} else {
if let Some(removed) = self.all_joined_rooms.remove(&room_id) {
log!("Removed room {room_id} from the list of all joined rooms");
let list_to_remove_from = if removed.is_direct {
&mut self.displayed_direct_rooms
} else {
&mut self.displayed_regular_rooms
};
list_to_remove_from.iter()
.position(|r| r == &room_id)
.map(|index| list_to_remove_from.remove(index));
}
else if let Some(_removed) = self.invited_rooms.borrow_mut().remove(&room_id) {
log!("Removed room {room_id} from the list of all invited rooms");
self.displayed_invited_rooms.iter()
.position(|r| r == &room_id)
.map(|index| self.displayed_invited_rooms.remove(index));
}

self.hidden_rooms.remove(&room_id);
}
else if let Some(_removed) = self.invited_rooms.borrow_mut().remove(&room_id) {
log!("Removed room {room_id} from the list of all invited rooms");
self.displayed_invited_rooms.iter()
.position(|r| r == &room_id)
.map(|index| self.displayed_invited_rooms.remove(index));
self.update_status();
}
RoomsListUpdate::SetRemovedRoomState { room_id, removed_state } => {
if let Some(room) = self.all_joined_rooms.get_mut(&room_id) {
if room.removed_state != removed_state {
room.removed_state = removed_state;
if room.removed_state.is_some() {
room.num_unread_mentions = 0;
room.num_unread_messages = 0;
}
}
}

self.hidden_rooms.remove(&room_id);
self.update_status();
}
RoomsListUpdate::SetInviteState { room_id, invite_state } => {
if invite_state == InviteState::RoomLeft {
if self.invited_rooms.borrow_mut().remove(&room_id).is_some() {
self.displayed_invited_rooms.iter()
.position(|r| r == &room_id)
.map(|index| self.displayed_invited_rooms.remove(index));
if let Some(joined_room) = self.all_joined_rooms.get(&room_id) {
let should_display = should_display_room!(self, &room_id, joined_room);
if should_display {
let list_to_update = if joined_room.is_direct {
&mut self.displayed_direct_rooms
} else {
&mut self.displayed_regular_rooms
};
if !list_to_update.contains(&room_id) {
list_to_update.push(room_id.clone());
}
}
}
self.update_status();
} else {
warning!("Warning: couldn't find invited room {} to remove after reject", room_id);
num_updates -= 1;
}
} else if let Some(invite) = self.invited_rooms.borrow_mut().get_mut(&room_id) {
invite.invite_state = invite_state;
} else {
warning!("Warning: couldn't find invited room {} to update invite state", room_id);
num_updates -= 1;
}
}
RoomsListUpdate::ClearRooms => {
self.all_joined_rooms.clear();
self.displayed_direct_rooms.clear();
Expand Down Expand Up @@ -776,6 +884,8 @@ impl RoomsList {
}
if num_updates > 0 {
self.redraw(cx);
// Signal other widgets (e.g., RoomScreen) to re-evaluate room state after updates.
SignalToUI::set_ui_signal();
}
}

Expand Down Expand Up @@ -1287,7 +1397,10 @@ impl Widget for RoomsList {
self.current_active_room.as_ref() == Some(direct_room_id);

// Paginate the room if it hasn't been paginated yet.
if PREPAGINATE_VISIBLE_ROOMS && !direct_room.has_been_paginated {
if PREPAGINATE_VISIBLE_ROOMS
&& !direct_room.has_been_paginated
&& direct_room.removed_state.is_none()
{
direct_room.has_been_paginated = true;
submit_async_request(MatrixRequest::PaginateRoomTimeline {
room_id: direct_room.room_name_id.room_id().clone(),
Expand Down Expand Up @@ -1322,7 +1435,10 @@ impl Widget for RoomsList {
self.current_active_room.as_ref() == Some(regular_room_id);

// Paginate the room if it hasn't been paginated yet.
if PREPAGINATE_VISIBLE_ROOMS && !regular_room.has_been_paginated {
if PREPAGINATE_VISIBLE_ROOMS
&& !regular_room.has_been_paginated
&& regular_room.removed_state.is_none()
{
regular_room.has_been_paginated = true;
submit_async_request(MatrixRequest::PaginateRoomTimeline {
room_id: regular_room.room_name_id.room_id().clone(),
Expand Down Expand Up @@ -1375,6 +1491,40 @@ impl RoomsListRef {
self.borrow()?.get_room_state(room_id)
}

/// See [`RoomsList::get_invite_state()`].
pub fn get_invite_state(&self, room_id: &OwnedRoomId) -> Option<InviteState> {
self.borrow()?.get_invite_state(room_id)
}

/// See [`RoomsList::get_removed_room_state()`].
pub fn get_removed_room_state(&self, room_id: &OwnedRoomId) -> Option<RoomState> {
self.borrow()?.get_removed_room_state(room_id)
}

/// Updates the removed state of a room via the RoomsList update queue.
pub fn set_removed_room_state(
&self,
room_id: OwnedRoomId,
removed_state: Option<RoomState>,
) {
enqueue_rooms_list_update(RoomsListUpdate::SetRemovedRoomState {
room_id,
removed_state,
});
}

/// Updates the invite state of an invited room via the RoomsList update queue.
pub fn set_invite_state(
&self,
room_id: OwnedRoomId,
invite_state: InviteState,
) {
enqueue_rooms_list_update(RoomsListUpdate::SetInviteState {
room_id,
invite_state,
});
}

/// Returns the name of the given room, if it is known and loaded.
pub fn get_room_name(&self, room_id: &OwnedRoomId) -> Option<RoomNameId> {
let inner = self.borrow()?;
Expand Down
40 changes: 33 additions & 7 deletions src/home/rooms_list_entry.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use makepad_widgets::*;
use matrix_sdk::ruma::OwnedRoomId;
use matrix_sdk::{RoomState, ruma::OwnedRoomId};

use crate::{
room::FetchedRoomAvatar, shared::{
Expand All @@ -8,7 +8,7 @@ use crate::{
}, utils::{self, relative_format}
};

use super::rooms_list::{InvitedRoomInfo, InviterInfo, JoinedRoomInfo, RoomsListScopeProps};
use super::rooms_list::{InviteState, InvitedRoomInfo, InviterInfo, JoinedRoomInfo, RoomsListScopeProps};
live_design! {
use link::theme::*;
use link::shaders::*;
Expand Down Expand Up @@ -297,7 +297,20 @@ impl RoomsListEntryContent {
room_info: &JoinedRoomInfo,
) {
self.view.label(ids!(room_name)).set_text(cx, &room_info.room_name_id.to_string());
if let Some((ts, msg)) = room_info.latest.as_ref() {
if let Some(removed_state) = room_info.removed_state {
let status_text = match removed_state {
RoomState::Banned => "<i>You have been banned from this room.</i>",
RoomState::Left => "<i>You are no longer a member of this room.</i>",
_ => "<i>You are no longer a member of this room.</i>",
};
self.view.label(ids!(timestamp)).set_text(cx, "");
self.view
.html_or_plaintext(ids!(latest_message))
.show_html(cx, status_text);
self.view
.unread_badge(ids!(unread_badge))
.update_counts(0, 0);
} else if let Some((ts, msg)) = room_info.latest.as_ref() {
if let Some(human_readable_date) = relative_format(*ts) {
self.view
.label(ids!(timestamp))
Expand All @@ -308,9 +321,11 @@ impl RoomsListEntryContent {
.show_html(cx, msg);
}

self.view
.unread_badge(ids!(unread_badge))
.update_counts(room_info.num_unread_mentions, room_info.num_unread_messages);
if room_info.removed_state.is_none() {
self.view
.unread_badge(ids!(unread_badge))
.update_counts(room_info.num_unread_mentions, room_info.num_unread_messages);
}
self.draw_common(cx, &room_info.room_avatar, room_info.is_selected);
// Show tombstone icon if the room is tombstoned
self.view.view(ids!(tombstone_icon)).set_visible(cx, room_info.is_tombstoned);
Expand All @@ -325,11 +340,22 @@ impl RoomsListEntryContent {
self.view.label(ids!(room_name)).set_text(cx, &room_info.room_name_id.to_string());
// Hide the timestamp field, and use the latest message field to show the inviter.
self.view.label(ids!(timestamp)).set_text(cx, "");
let inviter_string = match &room_info.inviter_info {
let mut inviter_string = match &room_info.inviter_info {
Some(InviterInfo { user_id, display_name: Some(dn), .. }) => format!("Invited by <b>{dn}</b> ({user_id})"),
Some(InviterInfo { user_id, .. }) => format!("Invited by {user_id}"),
None => String::from("You were invited"),
};
let status_suffix = match room_info.invite_state {
InviteState::WaitingOnUserInput => "",
InviteState::WaitingForJoinResult => "Joining...",
InviteState::WaitingForLeaveResult => "Rejecting...",
InviteState::WaitingForJoinedRoom => "Waiting for room...",
InviteState::RoomLeft => "Invite rejected",
};
if !status_suffix.is_empty() {
inviter_string.push_str(" - ");
inviter_string.push_str(status_suffix);
}
self.view.html_or_plaintext(ids!(latest_message)).show_html(cx, &inviter_string);

match room_info.room_avatar {
Expand Down
Loading