[fractal] backend: add a RoomMembership to Room type



commit 6f643c12c7fe28af3d4c053c7df9086c53475f89
Author: Julian Sparber <julian sparber net>
Date:   Thu Jan 3 01:48:35 2019 +0100

    backend: add a RoomMembership to Room type
    
    This replaces some boolean properties of the Room Model with a single
    property called membership. This makes the room membership (joined, left,
    invited) and tag (favourties, low priority, etc) mutch more
    understandable and gives the Model a better structure.

 fractal-gtk/src/appop/room.rs               | 18 ++++++---
 fractal-gtk/src/appop/start_chat.rs         |  5 ++-
 fractal-gtk/src/widgets/roomlist.rs         | 14 ++++---
 fractal-gtk/src/widgets/roomrow.rs          | 14 +++----
 fractal-matrix-api/src/backend/directory.rs | 38 ++++++++++--------
 fractal-matrix-api/src/backend/room.rs      |  9 +++--
 fractal-matrix-api/src/model/room.rs        | 62 ++++++++++++++++++++++++-----
 fractal-matrix-api/src/types.rs             |  2 +
 fractal-matrix-api/src/util.rs              | 48 +++++++++++-----------
 9 files changed, 134 insertions(+), 76 deletions(-)
---
diff --git a/fractal-gtk/src/appop/room.rs b/fractal-gtk/src/appop/room.rs
index d57fde7d..96c0e985 100644
--- a/fractal-gtk/src/appop/room.rs
+++ b/fractal-gtk/src/appop/room.rs
@@ -14,7 +14,7 @@ use crate::actions::AppState;
 use crate::cache;
 use crate::widgets;
 
-use crate::types::Room;
+use crate::types::{Room, RoomMembership, RoomTag};
 
 use crate::util::markup_text;
 
@@ -42,7 +42,7 @@ impl AppOp {
         }
         let mut roomlist = vec![];
         while let Some(room) = rooms.pop() {
-            if room.left {
+            if room.membership.is_left() {
                 // removing left rooms
                 if self.active_room.as_ref().map_or(false, |x| x == &room.id) {
                     self.really_leave_active_room();
@@ -106,8 +106,8 @@ impl AppOp {
 
     pub fn set_active_room_by_id(&mut self, id: String) {
         if let Some(room) = self.rooms.get(&id) {
-            if room.inv {
-                self.show_inv_dialog(room.inv_sender.as_ref(), room.name.as_ref());
+            if let RoomMembership::Invited(ref sender) = room.membership {
+                self.show_inv_dialog(Some(sender), room.name.as_ref());
                 self.invitation_roomid = Some(room.id.clone());
                 return;
             }
@@ -240,7 +240,8 @@ impl AppOp {
             .send(BKCommand::NewRoom(n.clone(), p, internal_id.clone()))
             .unwrap();
 
-        let fakeroom = Room::new(internal_id.clone(), Some(n));
+        let mut fakeroom = Room::new(internal_id.clone(), RoomMembership::Joined(RoomTag::None));
+        fakeroom.name = Some(n);
         self.new_room(fakeroom, None);
         self.set_active_room_by_id(internal_id);
         self.room_panel(RoomPanel::Room);
@@ -423,7 +424,12 @@ impl AppOp {
 
     pub fn added_to_fav(&mut self, roomid: String, tofav: bool) {
         if let Some(ref mut r) = self.rooms.get_mut(&roomid) {
-            r.fav = tofav;
+            let tag = if tofav {
+                RoomTag::Favourite
+            } else {
+                RoomTag::None
+            };
+            r.membership = RoomMembership::Joined(tag);
         }
     }
 
diff --git a/fractal-gtk/src/appop/start_chat.rs b/fractal-gtk/src/appop/start_chat.rs
index 465f6c59..0c0855bf 100644
--- a/fractal-gtk/src/appop/start_chat.rs
+++ b/fractal-gtk/src/appop/start_chat.rs
@@ -6,7 +6,7 @@ use crate::appop::RoomPanel;
 use crate::appop::SearchType;
 
 use crate::backend::BKCommand;
-use crate::types::Room;
+use crate::types::{Room, RoomMembership, RoomTag};
 
 use rand::distributions::Alphanumeric;
 use rand::{thread_rng, Rng};
@@ -25,7 +25,8 @@ impl AppOp {
             .unwrap();
         self.close_direct_chat_dialog();
 
-        let mut fakeroom = Room::new(internal_id.clone(), user.0.alias.clone());
+        let mut fakeroom = Room::new(internal_id.clone(), RoomMembership::Joined(RoomTag::None));
+        fakeroom.name = user.0.alias;
         fakeroom.direct = true;
 
         self.new_room(fakeroom, None);
diff --git a/fractal-gtk/src/widgets/roomlist.rs b/fractal-gtk/src/widgets/roomlist.rs
index 990217e2..0cb9a2f9 100644
--- a/fractal-gtk/src/widgets/roomlist.rs
+++ b/fractal-gtk/src/widgets/roomlist.rs
@@ -12,7 +12,7 @@ use std::collections::HashMap;
 use url::Url;
 
 use crate::globals;
-use crate::types::Room;
+use crate::types::{Room, RoomTag};
 use crate::widgets::roomrow::RoomRow;
 use std::sync::{Arc, Mutex, MutexGuard};
 
@@ -461,21 +461,21 @@ impl RoomList {
         self.inv.get().add_rooms(
             array
                 .iter()
-                .filter(|r| r.inv)
+                .filter(|r| r.membership.is_invited())
                 .cloned()
                 .collect::<Vec<Room>>(),
         );
         self.fav.get().add_rooms(
             array
                 .iter()
-                .filter(|r| r.fav)
+                .filter(|r| r.membership.match_joined_tag(RoomTag::Favourite))
                 .cloned()
                 .collect::<Vec<Room>>(),
         );
         self.rooms.get().add_rooms(
             array
                 .iter()
-                .filter(|r| !r.fav && !r.inv)
+                .filter(|r| !r.membership.match_joined_tag(RoomTag::Favourite))
                 .cloned()
                 .collect::<Vec<Room>>(),
         );
@@ -527,11 +527,13 @@ impl RoomList {
     }
 
     pub fn add_room(&mut self, r: Room) {
-        if r.inv {
+        if r.membership.is_invited() {
             self.inv.get().add_room(r);
-        } else if r.fav {
+        } else if r.membership.match_joined_tag(RoomTag::Favourite) {
+            println!("We have fav rooms");
             self.fav.get().add_room(r);
         } else {
+            println!("We have non fav rooms");
             self.rooms.get().add_room(r);
         }
         self.show_and_hide();
diff --git a/fractal-gtk/src/widgets/roomrow.rs b/fractal-gtk/src/widgets/roomrow.rs
index 008b12db..4cb65ae7 100644
--- a/fractal-gtk/src/widgets/roomrow.rs
+++ b/fractal-gtk/src/widgets/roomrow.rs
@@ -43,7 +43,7 @@ impl RoomRow {
 
         let n = room.notifications;
         let h = room.highlight;
-        let ntext = if room.inv {
+        let ntext = if room.membership.is_invited() {
             String::from("•")
         } else {
             format!("{}", n)
@@ -52,14 +52,14 @@ impl RoomRow {
         if let Some(style) = notifications.get_style_context() {
             style.add_class("notify-badge");
 
-            if h > 0 || room.inv {
+            if h > 0 || room.membership.is_invited() {
                 style.add_class("notify-highlight");
             } else {
                 style.remove_class("notify-highlight");
             }
         }
 
-        if n > 0 || room.inv {
+        if n > 0 || room.membership.is_invited() {
             notifications.show();
         } else {
             notifications.hide();
@@ -85,14 +85,14 @@ impl RoomRow {
         self.room.notifications = n;
         self.room.highlight = h;
         self.notifications.set_text(&format!("{}", n));
-        if n > 0 || self.room.inv {
+        if n > 0 || self.room.membership.is_invited() {
             self.notifications.show();
         } else {
             self.notifications.hide();
         }
 
         if let Some(style) = self.notifications.get_style_context() {
-            if h > 0 || self.room.inv {
+            if h > 0 || self.room.membership.is_invited() {
                 style.add_class("notify-highlight");
             } else {
                 style.remove_class("notify-highlight");
@@ -112,7 +112,7 @@ impl RoomRow {
 
     pub fn render_notifies(&self) {
         let n = self.room.notifications;
-        if n > 0 || self.room.inv {
+        if n > 0 || self.room.membership.is_invited() {
             self.notifications.show();
         } else {
             self.notifications.hide();
@@ -169,7 +169,7 @@ impl RoomRow {
     }
 
     pub fn connect_dnd(&self) {
-        if self.room.inv {
+        if self.room.membership.is_invited() {
             return;
         }
 
diff --git a/fractal-matrix-api/src/backend/directory.rs b/fractal-matrix-api/src/backend/directory.rs
index 30bf4131..8c71c0ea 100644
--- a/fractal-matrix-api/src/backend/directory.rs
+++ b/fractal-matrix-api/src/backend/directory.rs
@@ -15,7 +15,7 @@ use crate::util::json_q;
 use crate::util::media;
 
 use crate::types::Protocol;
-use crate::types::Room;
+use crate::types::{Room, RoomMembership};
 
 pub fn protocols(bk: &Backend) {
     let baseu = bk.get_base_url();
@@ -110,24 +110,28 @@ pub fn room_search(
 
             let mut rooms: Vec<Room> = vec![];
             for room in r["chunk"].as_array().unwrap() {
-                let alias = String::from(room["canonical_alias"].as_str().unwrap_or_default());
-                let id = String::from(room["room_id"].as_str().unwrap_or_default());
-                let name = String::from(room["name"].as_str().unwrap_or_default());
-                let mut r = Room::new(id.clone(), Some(name));
-                r.alias = Some(alias);
-                r.avatar = Some(String::from(
-                    room["avatar_url"].as_str().unwrap_or_default(),
-                ));
-                r.topic = Some(String::from(room["topic"].as_str().unwrap_or_default()));
-                r.n_members = room["num_joined_members"].as_i64().unwrap_or_default() as i32;
-                r.world_readable = room["world_readable"].as_bool().unwrap_or_default();
-                r.guest_can_join = room["guest_can_join"].as_bool().unwrap_or_default();
-                /* download the avatar */
-                if let Some(avatar) = r.avatar.clone() {
-                    if let Ok(dest) = cache_path(&id) {
-                        media(&base.clone(), &avatar, Some(&dest)).unwrap_or_default();
+                // Panic when we have rooms without an id
+                let id = room["room_id"]
+                    .as_str()
+                    .expect("Couldn't handle room: no valid id");
+                let alias = room["canonical_alias"].as_str();
+                let name = room["name"].as_str();
+                let avatar = room["avatar_url"].as_str();
+                /* download the avatar for the room */
+                if let Some(avatar) = avatar {
+                    if let Ok(dest) = cache_path(id) {
+                        let _ = media(&base.clone(), avatar, Some(&dest));
                     }
                 }
+
+                let mut r = Room::new(id.to_string(), RoomMembership::None);
+                r.name = name.map(String::from);
+                r.alias = alias.map(String::from);
+                r.avatar = avatar.map(String::from);
+                r.topic = room["topic"].as_str().map(String::from);
+                r.n_members = room["num_joined_members"].as_i64().unwrap_or(0) as i32;
+                r.world_readable = room["world_readable"].as_bool().unwrap_or(false);
+                r.guest_can_join = room["guest_can_join"].as_bool().unwrap_or(false);
                 rooms.push(r);
             }
 
diff --git a/fractal-matrix-api/src/backend/room.rs b/fractal-matrix-api/src/backend/room.rs
index e83ea8b6..27b737cf 100644
--- a/fractal-matrix-api/src/backend/room.rs
+++ b/fractal-matrix-api/src/backend/room.rs
@@ -24,7 +24,7 @@ use crate::backend::types::RoomType;
 
 use crate::types::Member;
 use crate::types::Message;
-use crate::types::Room;
+use crate::types::{Room, RoomMembership, RoomTag};
 
 use serde_json::Value as JsonValue;
 
@@ -534,8 +534,8 @@ pub fn new_room(
         &attrs,
         move |r: JsonValue| {
             let id = String::from(r["room_id"].as_str().unwrap_or_default());
-            let name = n;
-            let r = Room::new(id, Some(name));
+            let mut r = Room::new(id, RoomMembership::Joined(RoomTag::None));
+            r.name = Some(n);
             tx.send(BKResponse::NewRoom(r, internal_id)).unwrap();
         },
         |err| {
@@ -566,7 +566,8 @@ pub fn direct_chat(bk: &Backend, user: &Member, internal_id: String) -> Result<(
         &attrs,
         move |r: JsonValue| {
             let id = String::from(r["room_id"].as_str().unwrap_or_default());
-            let mut r = Room::new(id.clone(), m.alias.clone());
+            let mut r = Room::new(id.clone(), RoomMembership::Joined(RoomTag::None));
+            r.name = m.alias.clone();
             r.direct = true;
             tx.send(BKResponse::NewRoom(r, internal_id)).unwrap();
 
diff --git a/fractal-matrix-api/src/model/room.rs b/fractal-matrix-api/src/model/room.rs
index 83aecd0b..19021e79 100644
--- a/fractal-matrix-api/src/model/room.rs
+++ b/fractal-matrix-api/src/model/room.rs
@@ -6,6 +6,54 @@ use crate::model::message::Message;
 use serde::{Deserialize, Serialize};
 use std::collections::HashMap;
 
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+pub enum RoomMembership {
+    // If the user hasn't yet joined a room, e.g. in the room directory
+    None,
+    Joined(RoomTag),
+    // An invite is send by some other user
+    Invited(Member),
+    Left,
+}
+
+impl RoomMembership {
+    pub fn is_joined(&self) -> bool {
+        if let RoomMembership::Joined(_) = self {
+            true
+        } else {
+            false
+        }
+    }
+
+    pub fn is_invited(&self) -> bool {
+        if let RoomMembership::Invited(_) = self {
+            true
+        } else {
+            false
+        }
+    }
+
+    pub fn is_left(&self) -> bool {
+        self == &RoomMembership::Left
+    }
+
+    pub fn match_joined_tag(&self, tag: RoomTag) -> bool {
+        if let RoomMembership::Joined(this_tag) = self {
+            this_tag == &tag
+        } else {
+            false
+        }
+    }
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+pub enum RoomTag {
+    None,
+    Favourite,
+    LowPriority,
+    Custom(String),
+}
+
 #[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct Room {
     pub id: String,
@@ -20,12 +68,9 @@ pub struct Room {
     pub notifications: i32,
     pub highlight: i32,
     pub messages: Vec<Message>,
-    pub fav: bool,
-    pub left: bool,
-    pub inv: bool,
+    pub membership: RoomMembership,
     pub direct: bool,
     pub prev_batch: Option<String>,
-    pub inv_sender: Option<Member>,
 
     /// Hashmap with the room users power levels
     /// the key will be the userid and the value will be the level
@@ -33,10 +78,10 @@ pub struct Room {
 }
 
 impl Room {
-    pub fn new(id: String, name: Option<String>) -> Room {
+    pub fn new(id: String, membership: RoomMembership) -> Room {
         Room {
             id,
-            name,
+            name: None,
             avatar: None,
             topic: None,
             alias: None,
@@ -47,11 +92,8 @@ impl Room {
             highlight: 0,
             messages: vec![],
             members: HashMap::new(),
-            fav: false,
-            left: false,
-            inv: false,
+            membership,
             direct: false,
-            inv_sender: None,
             power_levels: HashMap::new(),
             prev_batch: None,
         }
diff --git a/fractal-matrix-api/src/types.rs b/fractal-matrix-api/src/types.rs
index 854a413f..be276b39 100644
--- a/fractal-matrix-api/src/types.rs
+++ b/fractal-matrix-api/src/types.rs
@@ -5,6 +5,8 @@ pub use crate::model::message::Message;
 pub use crate::model::protocol::Protocol;
 pub use crate::model::room::Room;
 pub use crate::model::room::RoomList;
+pub use crate::model::room::RoomMembership;
+pub use crate::model::room::RoomTag;
 pub use crate::model::stickers::Sticker;
 pub use crate::model::stickers::StickerGroup;
 pub use crate::model::userinfo::UserInfo;
diff --git a/fractal-matrix-api/src/util.rs b/fractal-matrix-api/src/util.rs
index c2a0fbf1..9e457161 100644
--- a/fractal-matrix-api/src/util.rs
+++ b/fractal-matrix-api/src/util.rs
@@ -24,7 +24,7 @@ use crate::error::Error;
 use crate::types::Event;
 use crate::types::Member;
 use crate::types::Message;
-use crate::types::Room;
+use crate::types::{Room, RoomMembership, RoomTag};
 
 use reqwest::header::CONTENT_TYPE;
 
@@ -196,7 +196,17 @@ pub fn get_rooms_from_json(r: &JsonValue, userid: &str, baseu: &Url) -> Result<V
         let ephemeral = &room["ephemeral"];
         let dataevs = &room["account_data"]["events"];
         let name = calculate_room_name(stevents, userid)?;
-        let mut r = Room::new(k.clone(), name);
+        let mut room_tag = RoomTag::None;
+        if let Some(ev) = dataevs.as_array() {
+            for tag in ev.iter().filter(|x| x["type"] == "m.tag") {
+                if tag["content"]["tags"]["m.favourite"].as_object().is_some() {
+                    room_tag = RoomTag::Favourite;
+                }
+            }
+        }
+
+        let mut r = Room::new(k.clone(), RoomMembership::Joined(room_tag));
+        r.name = name;
 
         r.avatar = Some(evc(stevents, "m.room.avatar", "url"));
         r.alias = Some(evc(stevents, "m.room.canonical_alias", "alias"));
@@ -211,14 +221,6 @@ pub fn get_rooms_from_json(r: &JsonValue, userid: &str, baseu: &Url) -> Result<V
 
         r.prev_batch = timeline["prev_batch"].as_str().map(String::from);
 
-        if let Some(ev) = dataevs.as_array() {
-            for tag in ev.iter().filter(|x| x["type"] == "m.tag") {
-                if tag["content"]["tags"]["m.favourite"].as_object().is_some() {
-                    r.fav = true;
-                }
-            }
-        }
-
         if let Some(evs) = timeline["events"].as_array() {
             let ms = Message::from_json_events_iter(&k, evs.iter());
             r.messages.extend(ms);
@@ -261,8 +263,7 @@ pub fn get_rooms_from_json(r: &JsonValue, userid: &str, baseu: &Url) -> Result<V
 
     // left rooms
     for k in leave.keys() {
-        let mut r = Room::new(k.clone(), None);
-        r.left = true;
+        let r = Room::new(k.clone(), RoomMembership::Left);
         rooms.push(r);
     }
 
@@ -271,14 +272,6 @@ pub fn get_rooms_from_json(r: &JsonValue, userid: &str, baseu: &Url) -> Result<V
         let room = invite.get(k).ok_or(Error::BackendError)?;
         let stevents = &room["invite_state"]["events"];
         let name = calculate_room_name(stevents, userid)?;
-        let mut r = Room::new(k.clone(), name);
-        r.inv = true;
-
-        r.avatar = Some(evc(stevents, "m.room.avatar", "url"));
-        r.alias = Some(evc(stevents, "m.room.canonical_alias", "alias"));
-        r.topic = Some(evc(stevents, "m.room.topic", "topic"));
-        r.direct = direct.contains(k);
-
         if let Some(arr) = stevents.as_array() {
             if let Some(ev) = arr
                 .iter()
@@ -287,16 +280,23 @@ pub fn get_rooms_from_json(r: &JsonValue, userid: &str, baseu: &Url) -> Result<V
                 if let Ok((alias, avatar)) =
                     get_user_avatar(baseu, ev["sender"].as_str().unwrap_or_default())
                 {
-                    r.inv_sender = Some(Member {
+                    let inv_sender = Member {
                         alias: Some(alias),
                         avatar: Some(avatar),
                         uid: String::from(userid),
-                    });
+                    };
+                    let mut r = Room::new(k.clone(), RoomMembership::Invited(inv_sender));
+                    r.name = name;
+
+                    r.avatar = Some(evc(stevents, "m.room.avatar", "url"));
+                    r.alias = Some(evc(stevents, "m.room.canonical_alias", "alias"));
+                    r.topic = Some(evc(stevents, "m.room.topic", "topic"));
+                    r.direct = direct.contains(k);
+
+                    rooms.push(r);
                 }
             }
         }
-
-        rooms.push(r);
     }
 
     Ok(rooms)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]