[fractal/split-async-state-ui-appop-mgmt: 7/12] Move stuff in member from AppOp to UI




commit c606ed939623b30ba24ef7943d9df4b09700cf14
Author: Alejandro Domínguez <adomu net-c com>
Date:   Sat Dec 5 10:38:37 2020 +0100

    Move stuff in member from AppOp to UI

 fractal-gtk/src/appop/invite.rs         |  30 ++---
 fractal-gtk/src/appop/member.rs         | 156 ++++-------------------
 fractal-gtk/src/appop/mod.rs            |   2 +-
 fractal-gtk/src/meson.build             |   2 +-
 fractal-gtk/src/ui/member.rs            | 211 ++++++++++++++++++++++++++++++++
 fractal-gtk/src/ui/mod.rs               |   1 +
 fractal-gtk/src/widgets/autocomplete.rs |  33 +++--
 fractal-gtk/src/widgets/member.rs       | 128 -------------------
 fractal-gtk/src/widgets/mod.rs          |   2 -
 9 files changed, 272 insertions(+), 293 deletions(-)
---
diff --git a/fractal-gtk/src/appop/invite.rs b/fractal-gtk/src/appop/invite.rs
index 425fe3da..e681c68e 100644
--- a/fractal-gtk/src/appop/invite.rs
+++ b/fractal-gtk/src/appop/invite.rs
@@ -1,23 +1,23 @@
 use crate::util::i18n::{i18n, i18n_k};
 
-use crate::backend::room;
-use gtk::prelude::*;
-use matrix_sdk::identifiers::{RoomId, UserId};
-
 use crate::app::RUNTIME;
 use crate::appop::member::SearchType;
 use crate::appop::AppOp;
+use crate::backend::room;
 use crate::backend::HandleError;
-
 use crate::globals;
-
-use crate::widgets;
-
 use crate::model::member::Member;
+use crate::ui::member::build_memberbox_pill;
+use gtk::prelude::*;
+use matrix_sdk::identifiers::{RoomId, UserId};
 
 impl AppOp {
-    pub fn add_to_invite(&mut self, u: Member) {
-        if self.ui.invite_list.iter().any(|(mem, _)| *mem == u) {
+    pub fn add_to_invite(&mut self, member: Member) {
+        let session_client =
+            unwrap_or_unit_return!(self.login_data.as_ref().map(|ld| ld.session_client.clone()));
+        let user_info_cache = self.user_info_cache.clone();
+
+        if self.ui.invite_list.iter().any(|(mem, _)| *mem == member) {
             return;
         }
 
@@ -69,15 +69,9 @@ impl AppOp {
             buffer.delete(&mut start_word, &mut end_word);
 
             if let Some(anchor) = buffer.create_child_anchor(&mut end_word) {
-                let w;
-                {
-                    let mb = widgets::MemberBox::new(&u, &self);
-                    w = mb.pill();
-                }
-
+                let w = build_memberbox_pill(session_client, user_info_cache, member.clone());
                 invite_entry.add_child_at_anchor(&w, &anchor);
-
-                self.ui.invite_list.push((u, anchor));
+                self.ui.invite_list.push((member, anchor));
             }
         }
     }
diff --git a/fractal-gtk/src/appop/member.rs b/fractal-gtk/src/appop/member.rs
index 42b8d1d4..1a6b3d35 100644
--- a/fractal-gtk/src/appop/member.rs
+++ b/fractal-gtk/src/appop/member.rs
@@ -1,7 +1,10 @@
+use crate::actions::AppState;
+use crate::app::RUNTIME;
+use crate::appop::AppOp;
 use crate::backend::{user, HandleError};
+use crate::model::member::Member;
+use crate::model::room::RoomList;
 use either::Either;
-use glib::clone;
-use gtk::prelude::*;
 use matrix_sdk::{
     events::{
         room::member::{MemberEventContent, MembershipState},
@@ -11,37 +14,16 @@ use matrix_sdk::{
 };
 use url::Url;
 
-use std::collections::HashMap;
-use std::convert::TryFrom;
-
-use crate::actions::AppState;
-use crate::app::RUNTIME;
-use crate::appop::AppOp;
-use crate::widgets;
-
-use crate::model::member::Member;
-
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Copy)]
 pub enum SearchType {
     Invite,
     DirectChat,
 }
 
 impl AppOp {
-    pub fn member_level(&self, member: &Member) -> i64 {
-        self.active_room
-            .as_ref()
-            .and_then(|a_room| self.rooms.get(a_room)?.admins.get(&member.uid))
-            .copied()
-            .unwrap_or(0)
-    }
-
     pub fn set_room_members(&mut self, room_id: RoomId, members: Vec<Member>) {
         if let Some(r) = self.rooms.get_mut(&room_id) {
-            r.members = HashMap::new();
-            for m in members {
-                r.members.insert(m.uid.clone(), m);
-            }
+            r.members = members.into_iter().map(|m| (m.uid.clone(), m)).collect();
         }
 
         self.recalculate_room_name(room_id);
@@ -83,114 +65,17 @@ impl AppOp {
     }
 
     pub fn user_search_finished(&self, users: Vec<Member>) {
-        match self.search_type {
-            SearchType::Invite => {
-                let entry = self
-                    .ui
-                    .builder
-                    .get_object::<gtk::TextView>("invite_entry")
-                    .expect("Can't find invite_entry in ui file.");
-                let listbox = self
-                    .ui
-                    .builder
-                    .get_object::<gtk::ListBox>("user_search_box")
-                    .expect("Can't find user_search_box in ui file.");
-                let scroll = self
-                    .ui
-                    .builder
-                    .get_object::<gtk::Widget>("user_search_scroll")
-                    .expect("Can't find user_search_scroll in ui file.");
-
-                if let Some(buffer) = entry.get_buffer() {
-                    let start = buffer.get_start_iter();
-                    let end = buffer.get_end_iter();
-
-                    self.search_finished(
-                        users,
-                        listbox,
-                        scroll,
-                        buffer
-                            .get_text(&start, &end, false)
-                            .map(|gstr| gstr.to_string()),
-                    );
-                }
-            }
-            SearchType::DirectChat => {
-                let entry = self
-                    .ui
-                    .builder
-                    .get_object::<gtk::TextView>("to_chat_entry")
-                    .expect("Can't find to_chat_entry in ui file.");
-                let listbox = self
-                    .ui
-                    .builder
-                    .get_object::<gtk::ListBox>("direct_chat_search_box")
-                    .expect("Can't find direct_chat_search_box in ui file.");
-                let scroll = self
-                    .ui
-                    .builder
-                    .get_object::<gtk::Widget>("direct_chat_search_scroll")
-                    .expect("Can't find direct_chat_search_scroll in ui file.");
-
-                if let Some(buffer) = entry.get_buffer() {
-                    let start = buffer.get_start_iter();
-                    let end = buffer.get_end_iter();
-
-                    self.search_finished(
-                        users,
-                        listbox,
-                        scroll,
-                        buffer
-                            .get_text(&start, &end, false)
-                            .map(|gstr| gstr.to_string()),
-                    );
-                }
-            }
-        }
-    }
-
-    pub fn search_finished(
-        &self,
-        mut users: Vec<Member>,
-        listbox: gtk::ListBox,
-        scroll: gtk::Widget,
-        term: Option<String>,
-    ) {
-        for ch in listbox.get_children().iter() {
-            listbox.remove(ch);
-        }
-        scroll.hide();
-
-        let uid_term = term.and_then(|t| UserId::try_from(t.as_str()).ok());
-        // Adding a new user if the user
-        if let Some(uid) = uid_term {
-            if users.iter().find(|u| u.uid == uid).is_none() {
-                let member = Member {
-                    avatar: None,
-                    alias: None,
-                    uid,
-                };
-                users.insert(0, member);
-            }
-        }
-
-        for (i, u) in users.iter().enumerate() {
-            let w;
-            {
-                let mb = widgets::MemberBox::new(u, &self);
-                w = mb.widget(true);
-            }
-
-            w.connect_button_press_event(clone!(@strong u => move |_, _| {
-                /* FIXME: Create Action */
-                let u = u.clone();
-                APPOP!(add_to_invite, (u));
-                glib::signal::Inhibit(true)
-            }));
+        let session_client =
+            unwrap_or_unit_return!(self.login_data.as_ref().map(|ld| ld.session_client.clone()));
 
-            listbox.insert(&w, i as i32);
-            scroll.show();
-        }
+        self.ui.user_search_finished(
+            session_client,
+            self.user_info_cache.clone(),
+            self.active_room.as_ref(),
+            &self.rooms,
+            users,
+            self.search_type,
+        );
     }
 
     pub fn search_invite_user(&self, term: String) {
@@ -208,3 +93,10 @@ impl AppOp {
         });
     }
 }
+
+pub fn member_level(active_room: Option<&RoomId>, rooms: &RoomList, member_uid: &UserId) -> i64 {
+    active_room
+        .and_then(|a_room| rooms.get(a_room)?.admins.get(member_uid))
+        .copied()
+        .unwrap_or(0)
+}
diff --git a/fractal-gtk/src/appop/mod.rs b/fractal-gtk/src/appop/mod.rs
index 77fe3739..fdf51fe5 100644
--- a/fractal-gtk/src/appop/mod.rs
+++ b/fractal-gtk/src/appop/mod.rs
@@ -26,7 +26,7 @@ mod directory;
 mod invite;
 mod login;
 mod media_viewer;
-mod member;
+pub mod member;
 mod message;
 mod notifications;
 mod notify;
diff --git a/fractal-gtk/src/meson.build b/fractal-gtk/src/meson.build
index 4d53f52c..14bfc92b 100644
--- a/fractal-gtk/src/meson.build
+++ b/fractal-gtk/src/meson.build
@@ -102,6 +102,7 @@ app_sources = files(
   'ui/about.rs',
   'ui/attach.rs',
   'ui/directory.rs',
+  'ui/member.rs',
   'ui/mod.rs',
   'ui/start_chat.rs',
   'util/i18n.rs',
@@ -118,7 +119,6 @@ app_sources = files(
   'widgets/kicked_dialog.rs',
   'widgets/login.rs',
   'widgets/media_viewer.rs',
-  'widgets/member.rs',
   'widgets/members_list.rs',
   'widgets/message_menu.rs',
   'widgets/message.rs',
diff --git a/fractal-gtk/src/ui/member.rs b/fractal-gtk/src/ui/member.rs
new file mode 100644
index 00000000..77711365
--- /dev/null
+++ b/fractal-gtk/src/ui/member.rs
@@ -0,0 +1,211 @@
+use super::UI;
+use crate::appop::member::member_level;
+use crate::appop::member::SearchType;
+use crate::appop::UserInfoCache;
+use crate::cache::download_to_cache;
+use crate::globals;
+use crate::model::member::Member;
+use crate::model::room::RoomList;
+use crate::widgets;
+use crate::widgets::AvatarExt;
+use crate::APPOP;
+use gtk::prelude::*;
+use matrix_sdk::identifiers::{RoomId, UserId};
+use matrix_sdk::Client as MatrixClient;
+use std::convert::TryFrom;
+
+impl UI {
+    pub fn user_search_finished(
+        &self,
+        session_client: MatrixClient,
+        user_info_cache: UserInfoCache,
+        active_room: Option<&RoomId>,
+        rooms: &RoomList,
+        users: Vec<Member>,
+        search_type: SearchType,
+    ) {
+        let (entry_label, listbox_label, scroll_label) = match search_type {
+            SearchType::Invite => ("invite_entry", "user_search_box", "user_search_scroll"),
+            SearchType::DirectChat => (
+                "to_chat_entry",
+                "direct_chat_search_box",
+                "direct_chat_search_scroll",
+            ),
+        };
+
+        let entry = self
+            .builder
+            .get_object::<gtk::TextView>(entry_label)
+            .expect("Can't find invite_entry in ui file.");
+        let listbox = self
+            .builder
+            .get_object::<gtk::ListBox>(listbox_label)
+            .expect("Can't find user_search_box in ui file.");
+        let scroll = self
+            .builder
+            .get_object::<gtk::Widget>(scroll_label)
+            .expect("Can't find user_search_scroll in ui file.");
+
+        if let Some(buffer) = entry.get_buffer() {
+            let start = buffer.get_start_iter();
+            let end = buffer.get_end_iter();
+
+            search_finished(
+                session_client,
+                user_info_cache,
+                active_room,
+                rooms,
+                users,
+                listbox,
+                scroll,
+                buffer
+                    .get_text(&start, &end, false)
+                    .map(|gstr| gstr.to_string()),
+            );
+        }
+    }
+}
+
+fn search_finished(
+    session_client: MatrixClient,
+    user_info_cache: UserInfoCache,
+    active_room: Option<&RoomId>,
+    rooms: &RoomList,
+    mut users: Vec<Member>,
+    listbox: gtk::ListBox,
+    scroll: gtk::Widget,
+    term: Option<String>,
+) {
+    for ch in listbox.get_children().iter() {
+        listbox.remove(ch);
+    }
+    scroll.hide();
+
+    let uid_term = term.and_then(|t| UserId::try_from(t.as_str()).ok());
+    // Adding a new user if the user
+    if let Some(uid) = uid_term {
+        if users.iter().find(|u| u.uid == uid).is_none() {
+            let member = Member {
+                avatar: None,
+                alias: None,
+                uid,
+            };
+            users.insert(0, member);
+        }
+    }
+
+    for (i, member) in users.into_iter().enumerate() {
+        let member_level = member_level(active_room, rooms, &member.uid);
+        let w = build_memberbox_widget(
+            session_client.clone(),
+            user_info_cache.clone(),
+            member.clone(),
+            member_level,
+            true,
+        );
+
+        w.connect_button_press_event(move |_, _| {
+            /* FIXME: Create Action */
+            let member = member.clone();
+            APPOP!(add_to_invite, (member));
+            glib::signal::Inhibit(true)
+        });
+
+        listbox.insert(&w, i as i32);
+        scroll.show();
+    }
+}
+
+pub fn build_memberbox_widget(
+    session_client: MatrixClient,
+    user_info_cache: UserInfoCache,
+    member: Member,
+    member_level: i64,
+    show_uid: bool,
+) -> gtk::EventBox {
+    let username = gtk::Label::new(None);
+    let uid = gtk::Label::new(None);
+    let event_box = gtk::EventBox::new();
+    let w = gtk::Box::new(gtk::Orientation::Horizontal, 5);
+    let v = gtk::Box::new(gtk::Orientation::Vertical, 0);
+
+    uid.set_text(&member.uid.to_string());
+    uid.set_valign(gtk::Align::Start);
+    uid.set_halign(gtk::Align::Start);
+    uid.get_style_context().add_class("member-uid");
+
+    username.set_text(&member.get_alias());
+    let mut alias = member.get_alias();
+    alias.push_str("\n");
+    alias.push_str(&member.uid.to_string());
+    username.set_tooltip_text(Some(&alias[..]));
+    username.set_margin_end(5);
+    username.set_ellipsize(pango::EllipsizeMode::End);
+    username.set_valign(gtk::Align::Center);
+    username.set_halign(gtk::Align::Start);
+    username.get_style_context().add_class("member");
+
+    let avatar = widgets::Avatar::avatar_new(Some(globals::USERLIST_ICON_SIZE));
+    let badge = match member_level {
+        0..=49 => None,
+        50..=99 => Some(widgets::AvatarBadgeColor::Silver),
+        _ => Some(widgets::AvatarBadgeColor::Gold),
+    };
+    let data = avatar.circle(
+        member.uid.to_string(),
+        Some(alias),
+        globals::USERLIST_ICON_SIZE,
+        badge,
+        None,
+    );
+
+    download_to_cache(session_client, user_info_cache, member.uid, data);
+
+    avatar.set_margin_start(3);
+    avatar.set_valign(gtk::Align::Center);
+
+    v.set_margin_start(3);
+    v.pack_start(&username, true, true, 0);
+    if show_uid {
+        v.pack_start(&uid, true, true, 0);
+    }
+
+    w.add(&avatar);
+    w.add(&v);
+
+    event_box.add(&w);
+    event_box.show_all();
+    event_box
+}
+
+pub fn build_memberbox_pill(
+    session_client: MatrixClient,
+    user_info_cache: UserInfoCache,
+    member: Member,
+) -> gtk::Box {
+    let pill = gtk::Box::new(gtk::Orientation::Horizontal, 3);
+
+    let username = gtk::Label::new(None);
+
+    username.set_text(&member.get_alias());
+    username.set_margin_end(3);
+    username.get_style_context().add_class("msg-highlighted");
+
+    let avatar = widgets::Avatar::avatar_new(Some(globals::PILL_ICON_SIZE));
+    let data = avatar.circle(
+        member.uid.to_string(),
+        Some(member.get_alias()),
+        globals::PILL_ICON_SIZE,
+        None,
+        None,
+    );
+
+    download_to_cache(session_client, user_info_cache, member.uid, data);
+
+    avatar.set_margin_start(3);
+
+    pill.pack_start(&avatar, true, true, 0);
+    pill.pack_start(&username, true, true, 0);
+    pill.show_all();
+    pill
+}
diff --git a/fractal-gtk/src/ui/mod.rs b/fractal-gtk/src/ui/mod.rs
index 2915829c..b353c9b7 100644
--- a/fractal-gtk/src/ui/mod.rs
+++ b/fractal-gtk/src/ui/mod.rs
@@ -12,6 +12,7 @@ pub mod about;
 pub mod attach;
 pub mod connect;
 pub mod directory;
+pub mod member;
 pub mod start_chat;
 
 pub struct UI {
diff --git a/fractal-gtk/src/widgets/autocomplete.rs b/fractal-gtk/src/widgets/autocomplete.rs
index 29b8a499..fb03b955 100644
--- a/fractal-gtk/src/widgets/autocomplete.rs
+++ b/fractal-gtk/src/widgets/autocomplete.rs
@@ -1,18 +1,15 @@
+use crate::app::AppRuntime;
+use crate::appop::{member::member_level, AppOp};
+use crate::model::member::Member;
+use crate::ui::member::build_memberbox_widget;
 use glib::clone;
+use gtk::prelude::*;
+use gtk::TextTag;
 use log::info;
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::rc::Rc;
 
-use gtk::prelude::*;
-use gtk::TextTag;
-
-use crate::model::member::Member;
-
-use crate::app::AppRuntime;
-use crate::appop::AppOp;
-use crate::widgets;
-
 pub struct Autocomplete {
     app_runtime: AppRuntime,
     entry: sourceview4::View,
@@ -425,12 +422,19 @@ impl Autocomplete {
         list: Vec<Member>,
         op: &AppOp,
     ) -> HashMap<String, gtk::EventBox> {
+        let session_client = op
+            .login_data
+            .as_ref()
+            .map(|ld| ld.session_client.clone())
+            .expect("The client is not logged in");
+        let user_info_cache = op.user_info_cache.clone();
+
         for ch in self.listbox.get_children().iter() {
             self.listbox.remove(ch);
         }
 
         let widget_list: HashMap<String, gtk::EventBox> = list
-            .iter()
+            .into_iter()
             .map(|member| {
                 let alias = member
                     .alias
@@ -438,7 +442,14 @@ impl Autocomplete {
                     .unwrap_or_default()
                     .trim_end_matches(" (IRC)")
                     .to_owned();
-                let widget = widgets::MemberBox::new(&member, op).widget(true);
+                let member_level = member_level(op.active_room.as_ref(), &op.rooms, &member.uid);
+                let widget = build_memberbox_widget(
+                    session_client.clone(),
+                    user_info_cache.clone(),
+                    member,
+                    member_level,
+                    true,
+                );
 
                 (alias, widget)
             })
diff --git a/fractal-gtk/src/widgets/mod.rs b/fractal-gtk/src/widgets/mod.rs
index 2d8709a5..e88a8dec 100644
--- a/fractal-gtk/src/widgets/mod.rs
+++ b/fractal-gtk/src/widgets/mod.rs
@@ -12,7 +12,6 @@ pub mod inline_player;
 mod kicked_dialog;
 mod login;
 pub mod media_viewer;
-mod member;
 pub mod members_list;
 mod message;
 pub mod message_menu;
@@ -42,7 +41,6 @@ pub use self::inline_player::VideoPlayerWidget;
 pub use self::kicked_dialog::KickedDialog;
 pub use self::login::LoginWidget;
 pub use self::media_viewer::MediaViewer;
-pub use self::member::MemberBox;
 pub use self::members_list::MembersList;
 pub use self::message::MessageBox;
 pub use self::room_history::RoomHistory;


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