From 88b3466ee5b0063d13b50ace1951fe9190bb6f0f Mon Sep 17 00:00:00 2001 From: Rasmus Rendal Date: Fri, 8 Feb 2019 06:41:29 +0100 Subject: [PATCH 1/5] Add typing notifications Add handler for incoming typing notifications in the sync loop Add an appop handler for typing notifications to the frontend Feature added for #305 --- fractal-gtk/res/app.css | 5 +++ fractal-gtk/src/app/backend_loop.rs | 3 ++ fractal-gtk/src/appop/room.rs | 54 +++++++++++++++++++++++- fractal-gtk/src/widgets/room_history.rs | 4 ++ fractal-gtk/src/widgets/scroll_widget.rs | 28 +++++++++++- fractal-matrix-api/src/backend/sync.rs | 6 +++ fractal-matrix-api/src/backend/types.rs | 1 + fractal-matrix-api/src/util.rs | 27 ++++++++++++ 8 files changed, 126 insertions(+), 2 deletions(-) diff --git a/fractal-gtk/res/app.css b/fractal-gtk/res/app.css index 02a8ec1c2..e582257a3 100644 --- a/fractal-gtk/res/app.css +++ b/fractal-gtk/res/app.css @@ -310,3 +310,8 @@ stack.titlebar:not(headerbar) > box > separator { .scrollarea-top-border { border-top: 1px solid @borders; } + +.typing_label { + margin: 6px; + margin-left: 78px; +} diff --git a/fractal-gtk/src/app/backend_loop.rs b/fractal-gtk/src/app/backend_loop.rs index 999910e10..84e565f6f 100644 --- a/fractal-gtk/src/app/backend_loop.rs +++ b/fractal-gtk/src/app/backend_loop.rs @@ -197,6 +197,9 @@ pub fn backend_loop(rx: Receiver) { Ok(BKResponse::UserSearch(users)) => { APPOP!(user_search_finished, (users)); } + Ok(BKResponse::Typing(rooms)) => { + APPOP!(typing_notification, (rooms)); + } // errors Ok(BKResponse::AccountDestructionError(err)) => { diff --git a/fractal-gtk/src/appop/room.rs b/fractal-gtk/src/appop/room.rs index f055f6015..a3111d6a5 100644 --- a/fractal-gtk/src/appop/room.rs +++ b/fractal-gtk/src/appop/room.rs @@ -1,4 +1,4 @@ -use crate::i18n::{i18n, i18n_k}; +use crate::i18n::{i18n, i18n_k, ni18n_f}; use log::{error, warn}; use std::fs::remove_file; use std::os::unix::fs; @@ -25,6 +25,8 @@ use crate::util::markup_text; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; +use std::collections::HashMap; + pub struct Force(pub bool); impl AppOp { @@ -514,4 +516,54 @@ impl AppOp { self.backend.send(BKCommand::GetRoomAvatar(roomid)).unwrap(); } + + pub fn typing_notification(&mut self, rooms: HashMap>) { + let active_room = self.active_room.clone().unwrap_or_default(); + if let Some(ref mut history) = self.history { + if rooms.contains_key(&active_room) { + let cur_room = rooms.get(&active_room).unwrap(); + if cur_room.len() == 0 { + history.typing_notification(""); + } else if cur_room.len() > 2 { + history.typing_notification(&i18n("Several users are typing…")); + } else { + // So first, we create an array of typing usernames. After this, we create another + // array, which is full of references to the first one. Sorry, this is the best way + // I could figure out to do it. + let mut typing_users = Vec::new(); + + for r in cur_room { + typing_users.push( + self.rooms + .get(&active_room) + .unwrap() + .members + .get(r.as_str()) + .unwrap() + .get_alias() + .to_owned(), + ); + } + /* + let typing_strs: Vec<&str> = Vec::new(); + for user in typing_users.iter() { + typing_strs.push(user.cloned().as_str()); + }*/ + + let typing_string = ni18n_f( + "{} is typing…", + "{} and {} are typing…", + cur_room.len() as u32, + typing_users + .iter() + .map(std::ops::Deref::deref) + .collect::>() + .as_slice(), + ); + + history.typing_notification(&typing_string); + } + } + } + } } diff --git a/fractal-gtk/src/widgets/room_history.rs b/fractal-gtk/src/widgets/room_history.rs index bc40e24f0..9ab8a6c97 100644 --- a/fractal-gtk/src/widgets/room_history.rs +++ b/fractal-gtk/src/widgets/room_history.rs @@ -271,6 +271,10 @@ impl RoomHistory { None } + + pub fn typing_notification(&mut self, typing_str: &str) { + self.rows.borrow().view.typing_notification(typing_str); + } } /* This function creates the content for a Row based on the conntent of msg */ diff --git a/fractal-gtk/src/widgets/scroll_widget.rs b/fractal-gtk/src/widgets/scroll_widget.rs index 8fac41fed..50f9eeaab 100644 --- a/fractal-gtk/src/widgets/scroll_widget.rs +++ b/fractal-gtk/src/widgets/scroll_widget.rs @@ -35,6 +35,7 @@ pub struct Widgets { btn_revealer: gtk::Revealer, listbox: gtk::ListBox, spinner: gtk::Spinner, + typing_label: gtk::Label, } impl Widgets { @@ -67,7 +68,22 @@ impl Widgets { let column = column.downcast::().unwrap(); column.set_hexpand(true); column.set_vexpand(true); - column.add(&messages); + + let typing_label = gtk::Label::new(None); + typing_label.show(); + typing_label + .get_style_context() + .unwrap() + .add_class("typing_label"); + typing_label.set_xalign(0.0); + //typing_label.property_set("margin-start", 72); + typing_label.set_visible(false); + + let column_box = gtk::Box::new(gtk::Orientation::Vertical, 0); + column_box.add(&messages); + column_box.add(&typing_label); + column_box.show(); + column.add(&column_box); column.show(); messages @@ -93,6 +109,7 @@ impl Widgets { btn_revealer, listbox: messages, spinner, + typing_label, } } } @@ -246,6 +263,15 @@ impl ScrollWidget { self.request_sent.set(false); self.widgets.spinner.stop(); } + + pub fn typing_notification(&self, typing_str: &str) { + if typing_str.len() == 0 { + self.widgets.typing_label.set_visible(false); + } else { + self.widgets.typing_label.set_visible(true); + self.widgets.typing_label.set_text(typing_str); + } + } } /* Functions to animate the scroll */ diff --git a/fractal-matrix-api/src/backend/sync.rs b/fractal-matrix-api/src/backend/sync.rs index 23c8d9145..5f0c502a7 100644 --- a/fractal-matrix-api/src/backend/sync.rs +++ b/fractal-matrix-api/src/backend/sync.rs @@ -13,6 +13,7 @@ use crate::types::SyncResponse; use crate::types::UnreadNotificationsCount; use crate::util::json_q; use crate::util::parse_m_direct; +use crate::util::parse_typing_notifications; use log::error; use serde_json::json; use serde_json::Value as JsonValue; @@ -114,6 +115,11 @@ pub fn sync(bk: &Backend, new_since: Option, initial: bool) -> Result<() .unwrap(); } + match parse_typing_notifications(&response) { + Err(err) => tx.send(BKResponse::SyncError(err)).unwrap(), + Ok(rooms) => tx.send(BKResponse::Typing(rooms)).unwrap(), + } + // Other events join.iter() .flat_map(|(k, room)| { diff --git a/fractal-matrix-api/src/backend/types.rs b/fractal-matrix-api/src/backend/types.rs index 9f72a41d9..46037b108 100644 --- a/fractal-matrix-api/src/backend/types.rs +++ b/fractal-matrix-api/src/backend/types.rs @@ -134,6 +134,7 @@ pub enum BKResponse { RoomNotifications(String, i32, i32), UserSearch(Vec), Stickers(Vec), + Typing(HashMap>), //errors UserNameError(Error), diff --git a/fractal-matrix-api/src/util.rs b/fractal-matrix-api/src/util.rs index 1d9f9bef1..f4c6f282e 100644 --- a/fractal-matrix-api/src/util.rs +++ b/fractal-matrix-api/src/util.rs @@ -2,6 +2,7 @@ use lazy_static::lazy_static; use log::error; use serde_json::json; +use serde_json::from_value; use serde_json::Value as JsonValue; use directories::ProjectDirs; @@ -23,6 +24,7 @@ use std::time::Duration; use crate::error::Error; use crate::types::Message; use crate::types::RoomEventFilter; +use crate::types::SyncResponse; use reqwest::header::CONTENT_TYPE; @@ -473,6 +475,31 @@ pub fn get_user_avatar_img(baseu: &Url, userid: &str, avatar: &str) -> Result Result>, Error> { + let join = &r.rooms.join; + let mut room_notifications = HashMap::new(); + + for k in join.keys() { + let room = join.get(k).ok_or(Error::BackendError)?; + let ephemerals = &room.ephemeral.events; + for event in ephemerals.iter() { + if let Some(typing_users) = event + .get("content") + .and_then(|x| x.get("user_ids")) + .and_then(|x| x.as_array()) + { + let mut typing = Vec::new(); + for user in typing_users { + let user: String = from_value(user.to_owned()).unwrap(); + typing.push(user); + } + room_notifications.insert(k.to_owned(), typing); + } + } + } + Ok(room_notifications) +} + pub fn encode_uid(userid: &str) -> String { utf8_percent_encode(userid, USERINFO_ENCODE_SET).collect::() } -- GitLab From 1a165f4a64b3df9db6a44d9fa59f1f534324e981 Mon Sep 17 00:00:00 2001 From: Rasmus Rendal Date: Sat, 16 Feb 2019 11:13:13 +0100 Subject: [PATCH 2/5] Added wordchar wrap to typing label --- fractal-gtk/src/widgets/scroll_widget.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fractal-gtk/src/widgets/scroll_widget.rs b/fractal-gtk/src/widgets/scroll_widget.rs index 50f9eeaab..79dbdc341 100644 --- a/fractal-gtk/src/widgets/scroll_widget.rs +++ b/fractal-gtk/src/widgets/scroll_widget.rs @@ -76,7 +76,8 @@ impl Widgets { .unwrap() .add_class("typing_label"); typing_label.set_xalign(0.0); - //typing_label.property_set("margin-start", 72); + typing_label.set_property_wrap(true); + typing_label.set_property_wrap_mode(pango::WrapMode::WordChar); typing_label.set_visible(false); let column_box = gtk::Box::new(gtk::Orientation::Vertical, 0); -- GitLab From bf814a560f1a801ae1330ff1b06bfa57516d6ef6 Mon Sep 17 00:00:00 2001 From: Rasmus Rendal Date: Sat, 16 Feb 2019 12:03:40 +0100 Subject: [PATCH 3/5] Changed colour, and fixed bug where Fractal would crash due to bad unwraps In room.rs, I used two unwraps without any checking for None. I modified the code to use a continue statement in that case now --- fractal-gtk/res/app.css | 6 +++-- fractal-gtk/src/appop/room.rs | 33 ++++++++++-------------- fractal-gtk/src/widgets/scroll_widget.rs | 3 ++- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/fractal-gtk/res/app.css b/fractal-gtk/res/app.css index e582257a3..b41e8bcfa 100644 --- a/fractal-gtk/res/app.css +++ b/fractal-gtk/res/app.css @@ -312,6 +312,8 @@ stack.titlebar:not(headerbar) > box > separator { } .typing_label { - margin: 6px; - margin-left: 78px; + margin: 6px; + margin-left: 78px; + margin-bottom: 8px; + color: @theme_selected_bg_color; } diff --git a/fractal-gtk/src/appop/room.rs b/fractal-gtk/src/appop/room.rs index a3111d6a5..a4f7d37c7 100644 --- a/fractal-gtk/src/appop/room.rs +++ b/fractal-gtk/src/appop/room.rs @@ -4,6 +4,7 @@ use std::fs::remove_file; use std::os::unix::fs; use url::Url; +use glib::functions::markup_escape_text; use gtk; use gtk::prelude::*; @@ -527,32 +528,24 @@ impl AppOp { } else if cur_room.len() > 2 { history.typing_notification(&i18n("Several users are typing…")); } else { - // So first, we create an array of typing usernames. After this, we create another - // array, which is full of references to the first one. Sorry, this is the best way - // I could figure out to do it. let mut typing_users = Vec::new(); for r in cur_room { - typing_users.push( - self.rooms - .get(&active_room) - .unwrap() - .members - .get(r.as_str()) - .unwrap() - .get_alias() - .to_owned(), - ); + let user = self.rooms.get(&active_room); + if user.is_none() { + continue; + } + let user = user.unwrap().members.get(r.as_str()); + if user.is_none() { + continue; + } + let user = user.unwrap().get_alias().to_owned(); + typing_users.push(markup_escape_text(&user)); } - /* - let typing_strs: Vec<&str> = Vec::new(); - for user in typing_users.iter() { - typing_strs.push(user.cloned().as_str()); - }*/ let typing_string = ni18n_f( - "{} is typing…", - "{} and {} are typing…", + "{} is typing…", + "{} and {} are typing…", cur_room.len() as u32, typing_users .iter() diff --git a/fractal-gtk/src/widgets/scroll_widget.rs b/fractal-gtk/src/widgets/scroll_widget.rs index 79dbdc341..8fd536394 100644 --- a/fractal-gtk/src/widgets/scroll_widget.rs +++ b/fractal-gtk/src/widgets/scroll_widget.rs @@ -79,6 +79,7 @@ impl Widgets { typing_label.set_property_wrap(true); typing_label.set_property_wrap_mode(pango::WrapMode::WordChar); typing_label.set_visible(false); + typing_label.set_use_markup(true); let column_box = gtk::Box::new(gtk::Orientation::Vertical, 0); column_box.add(&messages); @@ -270,7 +271,7 @@ impl ScrollWidget { self.widgets.typing_label.set_visible(false); } else { self.widgets.typing_label.set_visible(true); - self.widgets.typing_label.set_text(typing_str); + self.widgets.typing_label.set_markup(typing_str); } } } -- GitLab From b65ed735fb5d7790929f9bc0821aedbc67e40f2e Mon Sep 17 00:00:00 2001 From: Rasmus Rendal Date: Mon, 4 Mar 2019 06:00:18 +0100 Subject: [PATCH 4/5] Make typing notifications a property of the room struct Instead of sending a hashmap to the front-end, make it into a part of the room struct, updating the room stored in the front-end --- fractal-gtk/src/app/backend_loop.rs | 3 +- fractal-gtk/src/appop/room.rs | 47 ++++++++++++------------- fractal-matrix-api/src/backend/sync.rs | 34 +++++++++++++++--- fractal-matrix-api/src/backend/types.rs | 2 +- fractal-matrix-api/src/model/room.rs | 1 + fractal-matrix-api/src/util.rs | 27 -------------- 6 files changed, 55 insertions(+), 59 deletions(-) diff --git a/fractal-gtk/src/app/backend_loop.rs b/fractal-gtk/src/app/backend_loop.rs index 84e565f6f..3d707dea7 100644 --- a/fractal-gtk/src/app/backend_loop.rs +++ b/fractal-gtk/src/app/backend_loop.rs @@ -198,7 +198,8 @@ pub fn backend_loop(rx: Receiver) { APPOP!(user_search_finished, (users)); } Ok(BKResponse::Typing(rooms)) => { - APPOP!(typing_notification, (rooms)); + let clear_room_list = false; + APPOP!(set_rooms, (rooms, clear_room_list)); } // errors diff --git a/fractal-gtk/src/appop/room.rs b/fractal-gtk/src/appop/room.rs index a4f7d37c7..964430656 100644 --- a/fractal-gtk/src/appop/room.rs +++ b/fractal-gtk/src/appop/room.rs @@ -4,7 +4,6 @@ use std::fs::remove_file; use std::os::unix::fs; use url::Url; -use glib::functions::markup_escape_text; use gtk; use gtk::prelude::*; @@ -26,7 +25,7 @@ use crate::util::markup_text; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; -use std::collections::HashMap; +use glib::functions::markup_escape_text; pub struct Force(pub bool); @@ -52,6 +51,8 @@ impl AppOp { } } else if self.rooms.contains_key(&room.id) { // TODO: update the existing rooms + self.rooms.get_mut(&room.id).unwrap().typing_users = room.typing_users.clone(); + self.update_typing_notification(); } else { // Request all joined members for each new room self.backend @@ -181,6 +182,7 @@ impl AppOp { self.active_room = Some(active_room); /* Mark the new active room as read */ self.mark_last_message_as_read(Force(false)); + self.update_typing_notification(); } pub fn really_leave_active_room(&mut self) { @@ -518,42 +520,37 @@ impl AppOp { self.backend.send(BKCommand::GetRoomAvatar(roomid)).unwrap(); } - pub fn typing_notification(&mut self, rooms: HashMap>) { - let active_room = self.active_room.clone().unwrap_or_default(); - if let Some(ref mut history) = self.history { - if rooms.contains_key(&active_room) { - let cur_room = rooms.get(&active_room).unwrap(); - if cur_room.len() == 0 { + pub fn update_typing_notification(&mut self) { + if let Some(active_room) = &self + .rooms + .get(&self.active_room.clone().unwrap_or_default()) + { + if let Some(ref mut history) = self.history { + let typing_users: &Vec = &active_room.typing_users; + if typing_users.len() == 0 { history.typing_notification(""); - } else if cur_room.len() > 2 { + } else if typing_users.len() > 2 { history.typing_notification(&i18n("Several users are typing…")); } else { - let mut typing_users = Vec::new(); - - for r in cur_room { - let user = self.rooms.get(&active_room); - if user.is_none() { - continue; - } - let user = user.unwrap().members.get(r.as_str()); - if user.is_none() { - continue; - } - let user = user.unwrap().get_alias().to_owned(); - typing_users.push(markup_escape_text(&user)); - } + let typing_users: Vec = typing_users + .into_iter() + .map(|user| { + markup_escape_text( + &active_room.members.get(user.as_str()).unwrap().get_alias(), + ) + }) + .collect(); let typing_string = ni18n_f( "{} is typing…", "{} and {} are typing…", - cur_room.len() as u32, + typing_users.len() as u32, typing_users .iter() .map(std::ops::Deref::deref) .collect::>() .as_slice(), ); - history.typing_notification(&typing_string); } } diff --git a/fractal-matrix-api/src/backend/sync.rs b/fractal-matrix-api/src/backend/sync.rs index 5f0c502a7..c4b1153cd 100644 --- a/fractal-matrix-api/src/backend/sync.rs +++ b/fractal-matrix-api/src/backend/sync.rs @@ -9,13 +9,16 @@ use crate::types::Message; use crate::types::Room; use crate::types::RoomEventFilter; use crate::types::RoomFilter; +use crate::types::RoomMembership; +use crate::types::RoomTag; use crate::types::SyncResponse; use crate::types::UnreadNotificationsCount; use crate::util::json_q; use crate::util::parse_m_direct; -use crate::util::parse_typing_notifications; + use log::error; use serde_json::json; +use serde_json::value::from_value; use serde_json::Value as JsonValue; use std::{thread, time}; @@ -115,10 +118,31 @@ pub fn sync(bk: &Backend, new_since: Option, initial: bool) -> Result<() .unwrap(); } - match parse_typing_notifications(&response) { - Err(err) => tx.send(BKResponse::SyncError(err)).unwrap(), - Ok(rooms) => tx.send(BKResponse::Typing(rooms)).unwrap(), - } + // Typing notifications + let rooms: Vec = join + .iter() + .map(|(k, room)| { + let ephemerals = &room.ephemeral.events; + let mut typing_room: Room = + Room::new(k.clone(), RoomMembership::Joined(RoomTag::None)); + let mut typing = Vec::new(); + for event in ephemerals.iter() { + if let Some(typing_users) = event + .get("content") + .and_then(|x| x.get("user_ids")) + .and_then(|x| x.as_array()) + { + for user in typing_users { + let user: String = from_value(user.to_owned()).unwrap(); + typing.push(user); + } + } + } + typing_room.typing_users = typing; + typing_room + }) + .collect(); + tx.send(BKResponse::Typing(rooms)).unwrap(); // Other events join.iter() diff --git a/fractal-matrix-api/src/backend/types.rs b/fractal-matrix-api/src/backend/types.rs index 46037b108..469eb694e 100644 --- a/fractal-matrix-api/src/backend/types.rs +++ b/fractal-matrix-api/src/backend/types.rs @@ -134,7 +134,7 @@ pub enum BKResponse { RoomNotifications(String, i32, i32), UserSearch(Vec), Stickers(Vec), - Typing(HashMap>), + Typing(Vec), //errors UserNameError(Error), diff --git a/fractal-matrix-api/src/model/room.rs b/fractal-matrix-api/src/model/room.rs index b2ff1f1ca..965f1dac7 100644 --- a/fractal-matrix-api/src/model/room.rs +++ b/fractal-matrix-api/src/model/room.rs @@ -81,6 +81,7 @@ pub struct Room { pub membership: RoomMembership, pub direct: bool, pub prev_batch: Option, + pub typing_users: Vec, /// Hashmap with the room users power levels /// the key will be the userid and the value will be the level diff --git a/fractal-matrix-api/src/util.rs b/fractal-matrix-api/src/util.rs index f4c6f282e..1d9f9bef1 100644 --- a/fractal-matrix-api/src/util.rs +++ b/fractal-matrix-api/src/util.rs @@ -2,7 +2,6 @@ use lazy_static::lazy_static; use log::error; use serde_json::json; -use serde_json::from_value; use serde_json::Value as JsonValue; use directories::ProjectDirs; @@ -24,7 +23,6 @@ use std::time::Duration; use crate::error::Error; use crate::types::Message; use crate::types::RoomEventFilter; -use crate::types::SyncResponse; use reqwest::header::CONTENT_TYPE; @@ -475,31 +473,6 @@ pub fn get_user_avatar_img(baseu: &Url, userid: &str, avatar: &str) -> Result Result>, Error> { - let join = &r.rooms.join; - let mut room_notifications = HashMap::new(); - - for k in join.keys() { - let room = join.get(k).ok_or(Error::BackendError)?; - let ephemerals = &room.ephemeral.events; - for event in ephemerals.iter() { - if let Some(typing_users) = event - .get("content") - .and_then(|x| x.get("user_ids")) - .and_then(|x| x.as_array()) - { - let mut typing = Vec::new(); - for user in typing_users { - let user: String = from_value(user.to_owned()).unwrap(); - typing.push(user); - } - room_notifications.insert(k.to_owned(), typing); - } - } - } - Ok(room_notifications) -} - pub fn encode_uid(userid: &str) -> String { utf8_percent_encode(userid, USERINFO_ENCODE_SET).collect::() } -- GitLab From 7964d661876c13908266001f135b9ab67466a966 Mon Sep 17 00:00:00 2001 From: Rasmus Rendal Date: Tue, 5 Mar 2019 10:15:25 +0100 Subject: [PATCH 5/5] Changed the type of typing_users to a vector of Members Also changed the BKResponse NewRooms to UpdateRooms, which better reflects the nature of the response --- fractal-gtk/src/app/backend_loop.rs | 6 +----- fractal-gtk/src/appop/room.rs | 24 ++++++++++++------------ fractal-matrix-api/src/backend/sync.rs | 13 +++++++++---- fractal-matrix-api/src/backend/types.rs | 3 +-- fractal-matrix-api/src/model/room.rs | 2 +- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/fractal-gtk/src/app/backend_loop.rs b/fractal-gtk/src/app/backend_loop.rs index 3d707dea7..4b70e155f 100644 --- a/fractal-gtk/src/app/backend_loop.rs +++ b/fractal-gtk/src/app/backend_loop.rs @@ -112,7 +112,7 @@ pub fn backend_loop(rx: Receiver) { APPOP!(set_active_room_by_id, (room_id)); } } - Ok(BKResponse::NewRooms(rooms)) => { + Ok(BKResponse::UpdateRooms(rooms)) => { let clear_room_list = false; APPOP!(set_rooms, (rooms, clear_room_list)); } @@ -197,10 +197,6 @@ pub fn backend_loop(rx: Receiver) { Ok(BKResponse::UserSearch(users)) => { APPOP!(user_search_finished, (users)); } - Ok(BKResponse::Typing(rooms)) => { - let clear_room_list = false; - APPOP!(set_rooms, (rooms, clear_room_list)); - } // errors Ok(BKResponse::AccountDestructionError(err)) => { diff --git a/fractal-gtk/src/appop/room.rs b/fractal-gtk/src/appop/room.rs index 964430656..0004f63fc 100644 --- a/fractal-gtk/src/appop/room.rs +++ b/fractal-gtk/src/appop/room.rs @@ -18,7 +18,7 @@ use crate::actions::AppState; use crate::cache; use crate::widgets; -use crate::types::{Room, RoomMembership, RoomTag}; +use crate::types::{Member, Room, RoomMembership, RoomTag}; use crate::util::markup_text; @@ -51,7 +51,13 @@ impl AppOp { } } else if self.rooms.contains_key(&room.id) { // TODO: update the existing rooms - self.rooms.get_mut(&room.id).unwrap().typing_users = room.typing_users.clone(); + let update_room = self.rooms.get_mut(&room.id).unwrap(); + let typing_users: Vec = room + .typing_users + .iter() + .map(|u| update_room.members.get(&u.uid).unwrap_or(&u).to_owned()) + .collect(); + update_room.typing_users = typing_users; self.update_typing_notification(); } else { // Request all joined members for each new room @@ -526,26 +532,20 @@ impl AppOp { .get(&self.active_room.clone().unwrap_or_default()) { if let Some(ref mut history) = self.history { - let typing_users: &Vec = &active_room.typing_users; + let typing_users = &active_room.typing_users; if typing_users.len() == 0 { history.typing_notification(""); } else if typing_users.len() > 2 { history.typing_notification(&i18n("Several users are typing…")); } else { - let typing_users: Vec = typing_users - .into_iter() - .map(|user| { - markup_escape_text( - &active_room.members.get(user.as_str()).unwrap().get_alias(), - ) - }) - .collect(); - let typing_string = ni18n_f( "{} is typing…", "{} and {} are typing…", typing_users.len() as u32, typing_users + .iter() + .map(|user| markup_escape_text(&user.get_alias())) + .collect::>() .iter() .map(std::ops::Deref::deref) .collect::>() diff --git a/fractal-matrix-api/src/backend/sync.rs b/fractal-matrix-api/src/backend/sync.rs index c4b1153cd..f76ce26cf 100644 --- a/fractal-matrix-api/src/backend/sync.rs +++ b/fractal-matrix-api/src/backend/sync.rs @@ -5,6 +5,7 @@ use crate::globals; use crate::types::Event; use crate::types::EventFilter; use crate::types::Filter; +use crate::types::Member; use crate::types::Message; use crate::types::Room; use crate::types::RoomEventFilter; @@ -96,7 +97,7 @@ pub fn sync(bk: &Backend, new_since: Option, initial: bool) -> Result<() // New rooms let rs = Room::from_sync_response(&response, &userid, &baseu); - tx.send(BKResponse::NewRooms(rs)).unwrap(); + tx.send(BKResponse::UpdateRooms(rs)).unwrap(); // Message events let msgs = join @@ -125,7 +126,7 @@ pub fn sync(bk: &Backend, new_since: Option, initial: bool) -> Result<() let ephemerals = &room.ephemeral.events; let mut typing_room: Room = Room::new(k.clone(), RoomMembership::Joined(RoomTag::None)); - let mut typing = Vec::new(); + let mut typing: Vec = Vec::new(); for event in ephemerals.iter() { if let Some(typing_users) = event .get("content") @@ -134,7 +135,11 @@ pub fn sync(bk: &Backend, new_since: Option, initial: bool) -> Result<() { for user in typing_users { let user: String = from_value(user.to_owned()).unwrap(); - typing.push(user); + typing.push(Member { + uid: user, + alias: None, + avatar: None, + }); } } } @@ -142,7 +147,7 @@ pub fn sync(bk: &Backend, new_since: Option, initial: bool) -> Result<() typing_room }) .collect(); - tx.send(BKResponse::Typing(rooms)).unwrap(); + tx.send(BKResponse::UpdateRooms(rooms)).unwrap(); // Other events join.iter() diff --git a/fractal-matrix-api/src/backend/types.rs b/fractal-matrix-api/src/backend/types.rs index 469eb694e..f9cda6129 100644 --- a/fractal-matrix-api/src/backend/types.rs +++ b/fractal-matrix-api/src/backend/types.rs @@ -105,7 +105,7 @@ pub enum BKResponse { SetUserAvatar(String), Sync(String), Rooms(Vec, Option), - NewRooms(Vec), + UpdateRooms(Vec), RoomDetail(String, String, String), RoomAvatar(String, Option), NewRoomAvatar(String), @@ -134,7 +134,6 @@ pub enum BKResponse { RoomNotifications(String, i32, i32), UserSearch(Vec), Stickers(Vec), - Typing(Vec), //errors UserNameError(Error), diff --git a/fractal-matrix-api/src/model/room.rs b/fractal-matrix-api/src/model/room.rs index 965f1dac7..3f4fd9557 100644 --- a/fractal-matrix-api/src/model/room.rs +++ b/fractal-matrix-api/src/model/room.rs @@ -81,7 +81,7 @@ pub struct Room { pub membership: RoomMembership, pub direct: bool, pub prev_batch: Option, - pub typing_users: Vec, + pub typing_users: Vec, /// Hashmap with the room users power levels /// the key will be the userid and the value will be the level -- GitLab