diff --git a/src/components/switch_loading_row.ui b/src/components/switch_loading_row.ui index 36bb7a2b..6c0c6d86 100644 --- a/src/components/switch_loading_row.ui +++ b/src/components/switch_loading_row.ui @@ -9,6 +9,7 @@ 6 + False status diff --git a/src/session/model/room/mod.rs b/src/session/model/room/mod.rs index 4f86fa58..96209127 100644 --- a/src/session/model/room/mod.rs +++ b/src/session/model/room/mod.rs @@ -20,7 +20,7 @@ use ruma::{ events::{ receipt::{ReceiptEventContent, ReceiptType}, relation::Annotation, - room::encryption::SyncRoomEncryptionEvent, + room::{encryption::SyncRoomEncryptionEvent, guest_access::GuestAccess}, tag::{TagInfo, TagName}, typing::TypingEventContent, AnyMessageLikeEventContent, AnyRoomAccountDataEvent, AnySyncStateEvent, @@ -195,6 +195,9 @@ mod imp { /// The join rule of this room. #[property(get)] pub join_rule: JoinRule, + /// Whether guests are allowed. + #[property(get)] + pub guests_allowed: Cell, pub typing_drop_guard: OnceCell, pub receipts_drop_guard: OnceCell, } @@ -380,6 +383,7 @@ impl Room { self.init_timeline(); self.set_up_is_encrypted(); self.aliases().init(self); + self.update_guests_allowed(); spawn!( glib::Priority::DEFAULT_IDLE, @@ -1257,6 +1261,9 @@ impl Room { AnySyncStateEvent::RoomTombstone(_) => { self.load_tombstone(); } + AnySyncStateEvent::RoomGuestAccess(_) => { + self.update_guests_allowed(); + } _ => {} } } @@ -2037,4 +2044,17 @@ impl Room { Err(failed) } } + + /// Update whether guests are allowed. + fn update_guests_allowed(&self) { + let matrix_room = self.matrix_room(); + let guests_allowed = matrix_room.guest_access() == GuestAccess::CanJoin; + + if self.guests_allowed() == guests_allowed { + return; + } + + self.imp().guests_allowed.set(guests_allowed); + self.notify_guests_allowed(); + } } diff --git a/src/session/view/content/room_details/general_page/mod.rs b/src/session/view/content/room_details/general_page/mod.rs index 5f9aca96..096b16ee 100644 --- a/src/session/view/content/room_details/general_page/mod.rs +++ b/src/session/view/content/room_details/general_page/mod.rs @@ -10,7 +10,11 @@ use ruma::{ api::client::{discovery::get_capabilities::Capabilities, room::upgrade_room}, assign, events::{ - room::{avatar::ImageInfo, power_levels::PowerLevelAction}, + room::{ + avatar::ImageInfo, + guest_access::{GuestAccess, RoomGuestAccessEventContent}, + power_levels::PowerLevelAction, + }, StateEventType, }, }; @@ -20,7 +24,7 @@ use super::room_upgrade_dialog::confirm_room_upgrade; use crate::{ components::{ AvatarData, AvatarImage, CheckLoadingRow, ComboLoadingRow, CopyableRow, CustomEntry, - EditableAvatar, SpinnerButton, + EditableAvatar, SpinnerButton, SwitchLoadingRow, }, prelude::*, session::model::{JoinRuleValue, MemberList, NotificationsRoomSetting, Room}, @@ -92,6 +96,8 @@ mod imp { #[template_child] pub join_rule: TemplateChild, #[template_child] + pub guest_access: TemplateChild, + #[template_child] pub upgrade_button: TemplateChild, #[template_child] pub room_federated: TemplateChild, @@ -184,6 +190,7 @@ mod imp { obj.update_upgrade_button(); obj.update_edit_addresses_button(); obj.update_join_rule(); + obj.update_guest_access(); })); self.permissions_handler.replace(Some(permissions_handler)); @@ -225,6 +232,9 @@ mod imp { room.connect_is_tombstoned_notify(clone!(@weak obj => move |_| { obj.update_upgrade_button(); })), + room.connect_guests_allowed_notify(clone!(@weak obj => move |_| { + obj.update_guest_access(); + })), ]; obj.member_count_changed(room.joined_members_count()); @@ -259,6 +269,7 @@ mod imp { obj.update_federated(); obj.update_sections(); obj.update_join_rule(); + obj.update_guest_access(); obj.update_upgrade_button(); self.load_capabilities(); } @@ -1001,6 +1012,56 @@ impl GeneralPage { })); } + /// Update the guest access row. + fn update_guest_access(&self) { + let Some(room) = self.room() else { + return; + }; + + let row = &self.imp().guest_access; + row.set_is_active(room.guests_allowed()); + row.set_is_loading(false); + + let can_change = room + .permissions() + .is_allowed_to(PowerLevelAction::SendState(StateEventType::RoomGuestAccess)); + row.set_sensitive(can_change); + } + + /// Toggle the guest access. + #[template_callback] + fn toggle_guest_access(&self) { + let Some(room) = self.room() else { return }; + + let row = &self.imp().guest_access; + let guests_allowed = row.is_active(); + + if room.guests_allowed() == guests_allowed { + return; + } + + row.set_is_loading(true); + row.set_sensitive(false); + + spawn!(clone!(@weak self as obj => async move { + let guest_access = if guests_allowed { + GuestAccess::CanJoin + } else { + GuestAccess::Forbidden + }; + let content = RoomGuestAccessEventContent::new(guest_access); + + let matrix_room = room.matrix_room().clone(); + let handle = spawn_tokio!(async move { matrix_room.send_state_event(content).await }); + + if let Err(error) = handle.await.unwrap() { + error!("Could not change guest access: {error}"); + toast!(obj, gettext("Failed to change guest access")); + obj.update_guest_access(); + } + })); + } + /// Update the room upgrade button. fn update_upgrade_button(&self) { let Some(room) = self.room() else { diff --git a/src/session/view/content/room_details/general_page/mod.ui b/src/session/view/content/room_details/general_page/mod.ui index 3052f5d8..02f688f1 100644 --- a/src/session/view/content/room_details/general_page/mod.ui +++ b/src/session/view/content/room_details/general_page/mod.ui @@ -296,6 +296,13 @@ + + + Allow Guests + Guests are Matrix users without a registered account + + +