Commit 544fc52f authored by Julian Sparber's avatar Julian Sparber

roomsettings: show members in the room settings

This implements a new members list widget without the use of the backend
and with the use of the cached avatar, also it implements the new UI for
the members list.

https://gitlab.gnome.org/World/fractal/issues/19
parent 4e6b802a
......@@ -224,6 +224,11 @@ row .timestamp {
padding: 18px;
}
.no_member_search {
padding: 12px;
background: @theme_base_color;
}
/*#FIXME css style to remove round corners in the header*/
stack headerbar:last-child:not(:only-child) {
border-top-left-radius: 0px;
......
This diff is collapsed.
......@@ -20,6 +20,18 @@ impl AppOp {
}
pub fn close_room_settings(&mut self) {
let scroll = self.ui.builder
.get_object::<gtk::ScrolledWindow>("room_settings_scroll")
.expect("Can't find room_settings_scroll in ui file.");
let b = self.ui.builder
.get_object::<gtk::Frame>("room_settings_members_list")
.expect("Can't find room_settings_members_list in ui file.");
for w in b.get_children().iter() {
b.remove(w);
}
if let Some(adj) = scroll.get_vadjustment() {
adj.set_value(0f64);
}
self.set_state(AppState::Chat);
}
......@@ -35,7 +47,7 @@ impl AppOp {
let edit = power >= 50 && !room.direct;
let description = if room.direct {
self.get_direct_partner_uid(members)
self.get_direct_partner_uid(members.clone())
} else {
/* we don't have private groups yet
let description = Some(format!("Private Group - {} members", members.len()));
......@@ -47,6 +59,7 @@ impl AppOp {
self.room_settings_show_room_name(name, edit);
self.room_settings_show_room_topic(topic, is_room, edit);
self.room_settings_show_room_type(description);
self.room_settings_show_members(members);
None
}
......@@ -328,4 +341,21 @@ impl AppOp {
entry.set_editable(true);
self.reset_action_button(button);
}
fn room_settings_show_members(&self, members: Vec<Member>) -> Option<()> {
let entry = self.ui.builder
.get_object::<gtk::SearchEntry>("room_settings_members_search")
.expect("Can't find room_settings_members_search in ui file.");
let b = self.ui.builder
.get_object::<gtk::Frame>("room_settings_members_list")
.expect("Can't find room_settings_members_list in ui file.");
for w in b.get_children().iter() {
b.remove(w);
}
let list = widgets::MembersList::new(members, entry);
let w = list.create()?;
b.add(&w);
None
}
}
extern crate gtk;
use std::cell::RefCell;
use std::rc::Rc;
use self::gtk::prelude::*;
use glib::signal;
use fractal_api::util::cache_path;
use widgets;
use widgets::avatar::AvatarExt;
use types::Member;
#[derive(Debug, Clone)]
pub struct MembersList {
container: gtk::ListBox,
search_entry: gtk::SearchEntry,
error: gtk::Label,
members: Vec<Member>,
}
impl MembersList {
pub fn new(m: Vec<Member>, entry: gtk::SearchEntry) -> MembersList {
MembersList {
container: gtk::ListBox::new(),
error: gtk::Label::new(None),
members: m,
search_entry: entry,
}
}
pub fn create(&self) -> Option<gtk::Box> {
let b = gtk::Box::new(gtk::Orientation::Vertical, 0);
b.set_hexpand(true);
b.pack_start(&self.container, true, true, 0);
add_rows(self.container.clone(), self.members.clone());
self.error.get_style_context()?.add_class("no_member_search");
self.error.set_text("Nothing found");
b.pack_start(&self.error, true, true, 0);
self.connect();
b.show_all();
self.error.hide();
Some(b)
}
pub fn connect(&self) {
let container = self.container.clone();
let members = self.members.clone();
let error = self.error.clone();
let id = self.search_entry.connect_search_changed(move |w| {
filter_rows(container.clone(), members.clone(), error.clone(), w.get_text());
});
/* we need to remove the handler when the member list is destroyed */
let id: Rc<RefCell<Option<signal::SignalHandlerId>>> = Rc::new(RefCell::new(Some(id)));
let search_entry = self.search_entry.clone();
self.container.connect_destroy(move |_| {
let id = id.borrow_mut().take();
if let Some(id) = id {
signal::signal_handler_disconnect(&search_entry, id);
}
});
/* slowly load members when the main thread is idle */
/*
let container = self.container.clone();
let members = self.members.clone();
for (index, member) in members.iter().enumerate() {
gtk::idle_add(clone!(index, member, container => move || {
if let Some(w) = container.get_row_at_index(index as i32) {
if w.get_child().is_none() {
w.add(&load_row_content(member.clone()));
}
}
gtk::Continue(false)
}));
}
*/
}
}
fn create_row(member: Member) -> Option<gtk::ListBoxRow> {
let row = gtk::ListBoxRow::new();
row.connect_draw(clone!(member => move |w, _| {
if w.get_child().is_none() {
w.add(&load_row_content(member.clone()));
}
gtk::Inhibit(false)
}));
row.set_selectable(false);
row.set_size_request(-1, 56);
row.show();
Some(row)
}
/* creating the row is quite slow, therefore we have a small delay when scrolling the members list */
fn load_row_content(member: Member) -> gtk::Box {
let b = gtk::Box::new(gtk::Orientation::Horizontal, 12);
let avatar_path = cache_path(&member.uid).unwrap_or(String::from(""));
let avatar = widgets::Avatar::circle_avatar(avatar_path, Some(40));
let menu = gtk::Image::new_from_icon_name("view-more-symbolic", 1);
let user_box = gtk::Box::new(gtk::Orientation::Vertical, 0);
let username = gtk::Label::new(Some(member.get_alias().as_str()));
b.set_margin_start(12);
b.set_margin_end(12);
b.set_margin_top(6);
b.set_margin_bottom(6);
user_box.pack_start(&username, true, true, 0);
/* we don't have this state yet
* let state = gtk::Label::new();
* user_box.pack_end(&state, true, true, 0); */
b.pack_start(&avatar, false, true, 0);
b.pack_start(&user_box, false, true, 0);
b.pack_end(&menu, false, false, 0);
b.show_all();
b
}
fn add_rows(container: gtk::ListBox, members: Vec<Member>) -> Option<usize> {
/* Load just enough members to fill atleast the visible list */
for member in members.iter() {
container.insert(&create_row(member.clone())?, -1);
}
None
}
fn filter_rows(container: gtk::ListBox, members: Vec<Member>, label: gtk::Label, search: Option<String>) -> Option<usize> {
/* Load just enough members to fill atleast the visible list */
let search = search?;
let search = search.as_str();
let mut empty = true;
for (index, member) in members.iter().enumerate() {
if !member.get_alias().contains(search) {
container.get_row_at_index(index as i32)?.hide();
} else {
container.get_row_at_index(index as i32)?.show();
empty = false;
}
}
label.set_visible(empty);
None
}
......@@ -6,6 +6,7 @@ mod roomlist;
pub mod avatar;
mod autocomplete;
mod address;
mod members_list;
pub mod divider;
pub mod image;
mod inline_player;
......@@ -16,6 +17,7 @@ pub use self::member::MemberBox;
pub use self::autocomplete::Autocomplete;
pub use self::address::Address;
pub use self::address::AddressType;
pub use self::members_list::MembersList;
pub use self::roomrow::RoomRow;
pub use self::roomlist::RoomList;
pub use self::avatar::Avatar;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment