room: Expose the language of a room
This commit is contained in:
parent
b7e4c059e7
commit
c4c74c8aba
4 changed files with 132 additions and 10 deletions
|
@ -108,7 +108,7 @@ src/session/view/sidebar/room_row.rs
|
|||
src/session/view/sidebar/row.rs
|
||||
src/shortcuts.ui
|
||||
src/user_facing_error.rs
|
||||
src/utils/matrix.rs
|
||||
src/utils/matrix/mod.rs
|
||||
src/utils/media.rs
|
||||
src/utils/message_dialog.rs
|
||||
src/window.rs
|
||||
|
|
|
@ -21,6 +21,7 @@ use matrix_sdk::{
|
|||
DisplayName, HttpError, Result as MatrixResult, RoomInfo, RoomMemberships, RoomState,
|
||||
};
|
||||
use ruma::{
|
||||
api::client::config::set_room_account_data,
|
||||
events::{
|
||||
reaction::ReactionEventContent,
|
||||
receipt::{ReceiptEventContent, ReceiptType},
|
||||
|
@ -34,6 +35,7 @@ use ruma::{
|
|||
AnyMessageLikeEventContent, AnyRoomAccountDataEvent, AnySyncStateEvent,
|
||||
AnySyncTimelineEvent, SyncEphemeralRoomEvent, SyncStateEvent,
|
||||
},
|
||||
serde::Raw,
|
||||
OwnedEventId, OwnedRoomId, OwnedUserId, RoomId,
|
||||
};
|
||||
use tracing::{debug, error, warn};
|
||||
|
@ -53,7 +55,13 @@ use super::{
|
|||
room_list::RoomMetainfo, AvatarData, AvatarImage, AvatarUriSource, IdentityVerification,
|
||||
Session, SidebarItem, SidebarItemImpl, User,
|
||||
};
|
||||
use crate::{components::Pill, gettext_f, prelude::*, spawn, spawn_tokio};
|
||||
use crate::{
|
||||
components::Pill,
|
||||
gettext_f,
|
||||
prelude::*,
|
||||
spawn, spawn_tokio,
|
||||
utils::matrix::custom_events::{LanguageEvent, LanguageEventContent},
|
||||
};
|
||||
|
||||
mod imp {
|
||||
use std::cell::Cell;
|
||||
|
@ -105,6 +113,8 @@ mod imp {
|
|||
pub typing_list: TypingList,
|
||||
/// Whether anyone can join this room.
|
||||
pub is_join_rule_public: Cell<bool>,
|
||||
/// The language to spell check in this room.
|
||||
pub language: RefCell<Option<String>>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
|
@ -183,6 +193,9 @@ mod imp {
|
|||
glib::ParamSpecBoolean::builder("is-join-rule-public")
|
||||
.explicit_notify()
|
||||
.build(),
|
||||
glib::ParamSpecString::builder("language")
|
||||
.read_only()
|
||||
.build(),
|
||||
]
|
||||
});
|
||||
|
||||
|
@ -231,6 +244,7 @@ mod imp {
|
|||
"encrypted" => obj.is_encrypted().to_value(),
|
||||
"typing-list" => obj.typing_list().to_value(),
|
||||
"is-join-rule-public" => obj.is_join_rule_public().to_value(),
|
||||
"language" => obj.language().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
@ -360,6 +374,10 @@ impl Room {
|
|||
self.setup_receipts();
|
||||
self.setup_typing();
|
||||
|
||||
spawn!(clone!(@weak self as obj => async move {
|
||||
obj.load_language().await;
|
||||
}));
|
||||
|
||||
spawn!(clone!(@weak self as obj => async move {
|
||||
obj.watch_room_info().await;
|
||||
}));
|
||||
|
@ -1314,21 +1332,28 @@ impl Room {
|
|||
}
|
||||
|
||||
pub fn handle_left_response(&self, response_room: LeftRoom) {
|
||||
self.update_for_room_account_data(response_room.account_data);
|
||||
self.update_for_events(response_room.timeline.events);
|
||||
}
|
||||
|
||||
pub fn handle_joined_response(&self, response_room: JoinedRoom) {
|
||||
if response_room
|
||||
.account_data
|
||||
.iter()
|
||||
.any(|e| matches!(e.deserialize(), Ok(AnyRoomAccountDataEvent::Tag(_))))
|
||||
{
|
||||
self.load_category();
|
||||
}
|
||||
|
||||
self.update_for_room_account_data(response_room.account_data);
|
||||
self.update_for_events(response_room.timeline.events);
|
||||
}
|
||||
|
||||
fn update_for_room_account_data(&self, room_account_data: Vec<Raw<AnyRoomAccountDataEvent>>) {
|
||||
for raw in room_account_data {
|
||||
if let Ok(AnyRoomAccountDataEvent::Tag(_)) = raw.deserialize() {
|
||||
self.load_category();
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Ok(language) = raw.deserialize_as::<LanguageEvent>() {
|
||||
self.set_language_inner(Some(language.content.input_language));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Connect to the signal sent when a room was forgotten.
|
||||
pub fn connect_room_forgotten<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||
self.connect_local("room-forgotten", true, move |values| {
|
||||
|
@ -1701,4 +1726,85 @@ impl Room {
|
|||
self.imp().is_join_rule_public.set(is_public);
|
||||
self.notify("is-join-rule-public");
|
||||
}
|
||||
|
||||
async fn load_language(&self) {
|
||||
let matrix_room = self.matrix_room();
|
||||
|
||||
let handle = spawn_tokio!(async move {
|
||||
matrix_room
|
||||
.account_data_static::<LanguageEventContent>()
|
||||
.await
|
||||
});
|
||||
|
||||
let raw = match handle.await.unwrap() {
|
||||
Ok(Some(raw)) => raw,
|
||||
Ok(None) => return,
|
||||
Err(error) => {
|
||||
error!(room_id = %self.room_id(), "Failed to load language room account data: {error}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match raw.deserialize() {
|
||||
Ok(ev) => {
|
||||
self.set_language_inner(Some(ev.content.input_language));
|
||||
}
|
||||
Err(error) => {
|
||||
error!(room_id = %self.room_id(), "Failed to deserialize language room account data: {error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The language to spell check in this room.
|
||||
pub fn language(&self) -> Option<String> {
|
||||
self.imp().language.borrow().clone()
|
||||
}
|
||||
|
||||
/// Set the language to spell check in this room.
|
||||
pub fn set_language(&self, language: Option<String>) {
|
||||
if !self.set_language_inner(language.clone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(language) = language {
|
||||
spawn!(clone!(@weak self as obj => async move {
|
||||
obj.set_room_account_data_language(language).await;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
fn set_language_inner(&self, language: Option<String>) -> bool {
|
||||
let imp = self.imp();
|
||||
if imp.language.borrow().as_ref() == language.as_ref() {
|
||||
return false;
|
||||
}
|
||||
|
||||
imp.language.replace(language.clone());
|
||||
self.notify("language");
|
||||
true
|
||||
}
|
||||
|
||||
async fn set_room_account_data_language(&self, input_language: String) {
|
||||
let client = self.session().client();
|
||||
let user_id = client.user_id().unwrap().to_owned();
|
||||
let room_id = self.room_id().to_owned();
|
||||
|
||||
let request = match set_room_account_data::v3::Request::new(
|
||||
user_id,
|
||||
room_id,
|
||||
&LanguageEventContent { input_language },
|
||||
) {
|
||||
Ok(req) => req,
|
||||
Err(error) => {
|
||||
error!(room_id = %self.room_id(), "Failed to build request for language room account data: {error}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let handle = spawn_tokio!(async move { client.send(request, None,).await });
|
||||
|
||||
if let Err(error) = handle.await.unwrap() {
|
||||
error!(room_id = %self.room_id(), "Failed to send language room account data: {error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
14
src/utils/matrix/custom_events.rs
Normal file
14
src/utils/matrix/custom_events.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use ruma::events::macros::EventContent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// The content of an `org.gnome.fractal.language` event.
|
||||
///
|
||||
/// The language used in a room.
|
||||
///
|
||||
/// It is used to change the spell checker's language per room.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
|
||||
#[ruma_event(type = "org.gnome.fractal.language", kind = RoomAccountData)]
|
||||
pub struct LanguageEventContent {
|
||||
/// The language to spell check.
|
||||
pub input_language: String,
|
||||
}
|
|
@ -13,6 +13,8 @@ use ruma::{
|
|||
};
|
||||
use thiserror::Error;
|
||||
|
||||
pub mod custom_events;
|
||||
|
||||
use super::media::filename_for_mime;
|
||||
use crate::{
|
||||
components::{Pill, DEFAULT_PLACEHOLDER},
|
Loading…
Reference in a new issue