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
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 @@
+
+
+