fractal/session/view/content/room_details/
room_upgrade_dialog.rsuse std::{cmp::Ordering, str::FromStr};
use adw::prelude::*;
use gettextrs::gettext;
use gtk::{gio, glib, subclass::prelude::*};
use ruma::{
api::client::discovery::get_capabilities::{RoomVersionStability, RoomVersionsCapability},
RoomVersionId,
};
use crate::gettext_f;
pub async fn confirm_room_upgrade(
capability: RoomVersionsCapability,
parent: &impl IsA<gtk::Widget>,
) -> Option<RoomVersionId> {
let default = capability.default;
let mut list = capability
.available
.into_iter()
.map(|(id, stability)| {
let stability = if id == default {
RoomVersionStability::Stable
} else {
stability
};
RoomVersion::new(id, stability)
})
.collect::<Vec<_>>();
list.sort_unstable_by(|a, b| {
match (
i64::from_str(a.id().as_str()),
i64::from_str(b.id().as_str()),
) {
(Ok(a), Ok(b)) => a.cmp(&b),
(Ok(_), _) => Ordering::Less,
(_, Ok(_)) => Ordering::Greater,
_ => a.id().cmp(b.id()),
}
});
let default_pos = list
.iter()
.position(|v| *v.id() == default)
.unwrap_or_default();
let model = list.into_iter().collect::<gio::ListStore>();
let version_combo = adw::ComboRow::builder()
.title(gettext("Version"))
.selectable(false)
.expression(RoomVersion::this_expression("display-string"))
.model(&model)
.selected(default_pos.try_into().unwrap_or(u32::MAX))
.build();
let list_box = gtk::ListBox::builder()
.css_classes(["boxed-list"])
.margin_top(6)
.accessible_role(gtk::AccessibleRole::Group)
.build();
list_box.append(&version_combo);
let upgrade_dialog = adw::AlertDialog::builder()
.default_response("cancel")
.heading(gettext("Upgrade Room"))
.body(gettext("Upgrading a room to a more recent version allows to benefit from new features from the Matrix specification. It can also be used to reset the room state, which should make the room faster to join. However it should be used sparingly because it can be disruptive, as room members need to join the new room manually."))
.extra_child(&list_box)
.build();
upgrade_dialog.add_responses(&[
("cancel", &gettext("Cancel")),
("upgrade", &gettext("Upgrade")),
]);
upgrade_dialog.set_response_appearance("upgrade", adw::ResponseAppearance::Destructive);
if upgrade_dialog.choose_future(parent).await != "upgrade" {
return None;
}
version_combo
.selected_item()
.and_downcast::<RoomVersion>()
.map(|v| v.id().clone())
}
mod imp {
use std::{cell::OnceCell, marker::PhantomData};
use super::*;
#[derive(Debug, Default, glib::Properties)]
#[properties(wrapper_type = super::RoomVersion)]
pub struct RoomVersion {
pub id: OnceCell<RoomVersionId>,
pub stability: OnceCell<RoomVersionStability>,
#[property(get = Self::display_string)]
display_string: PhantomData<String>,
}
#[glib::object_subclass]
impl ObjectSubclass for RoomVersion {
const NAME: &'static str = "RoomUpgradeDialogRoomVersion";
type Type = super::RoomVersion;
}
#[glib::derived_properties]
impl ObjectImpl for RoomVersion {}
impl RoomVersion {
pub(super) fn id(&self) -> &RoomVersionId {
self.id.get().expect("id is initialized")
}
fn stability(&self) -> &RoomVersionStability {
self.stability.get().expect("stability is initialized")
}
fn display_string(&self) -> String {
let id = self.id();
let stability = self.stability();
if *stability == RoomVersionStability::Stable {
id.to_string()
} else {
gettext_f("{version} (unstable)", &[("version", id.as_str())])
}
}
}
}
glib::wrapper! {
pub struct RoomVersion(ObjectSubclass<imp::RoomVersion>);
}
impl RoomVersion {
pub fn new(id: RoomVersionId, stability: RoomVersionStability) -> Self {
let obj = glib::Object::new::<Self>();
let imp = obj.imp();
imp.id.set(id).unwrap();
imp.stability.set(stability).unwrap();
obj
}
pub(crate) fn id(&self) -> &RoomVersionId {
self.imp().id()
}
}