Commit dacd3683 authored by Daniel García Moreno's avatar Daniel García Moreno

Merge branch 'master' into last-viewed-messages

parents d5468436 a5d354ad
Pipeline #18909 passed with stage
in 17 minutes and 49 seconds
......@@ -381,7 +381,7 @@ dependencies = [
"gstreamer-player 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"gtk 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"html2pango 0.1.0 (git+https://gitlab.gnome.org/World/html2pango)",
"letter-avatar 0.1.0 (git+https://gitlab.gnome.org/jsparber/letter-avatar)",
"letter-avatar 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"notify-rust 3.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pango 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -924,8 +924,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "letter-avatar"
version = "0.1.0"
source = "git+https://gitlab.gnome.org/jsparber/letter-avatar#7a58d07442654e3e2dda9960e1ec3f14e2dba25a"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cairo-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pango 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -2251,7 +2251,7 @@ dependencies = [
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"
"checksum letter-avatar 0.1.0 (git+https://gitlab.gnome.org/jsparber/letter-avatar)" = "<none>"
"checksum letter-avatar 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "230b26d9d868d3d253d9734055bbb16ed22bad0f97cef015eec52d6e069e76aa"
"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b"
"checksum libflate 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "1a429b86418868c7ea91ee50e9170683f47fd9d94f5375438ec86ec3adb74e8e"
"checksum linkify 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ce9439c6f4a1092dc1861272bef01034891da39f13aa1cdcf40ca3e4081de5f"
......
......@@ -26,12 +26,12 @@ rand = "0.4.2"
html2pango = { git = "https://gitlab.gnome.org/World/html2pango" }
comrak = "0.2.9"
gettext-rs = { git = "https://github.com/danigm/gettext-rs", branch = "no-gettext", features = ["gettext-system"] }
letter-avatar = { git = "https://gitlab.gnome.org/jsparber/letter-avatar" }
unicode-segmentation = "1.2.0"
regex = "1.0.0"
tree_magic = "0.2.0"
log = "0.4.2"
fragile = "0.2.1"
letter-avatar = "0.1.1"
[dependencies.cairo-rs]
features = ["png"]
......
This diff is collapsed.
......@@ -359,11 +359,13 @@ impl AppOp {
}
}
download_to_cache(self.backend.clone(), self.uid.clone().unwrap_or_default());
let w = widgets::Avatar::avatar_new(Some(100));
w.circle(self.uid.clone().unwrap_or_default(), self.username.clone(), 100);
avatar.add(&w);
let uid = self.uid.clone().unwrap_or_default();
let data = w.circle(uid.clone(), self.username.clone(), 100);
download_to_cache(self.backend.clone(), uid.clone(), data.clone());
/* FIXME: hack to make the avatar drawing area clickable*/
let current = stack.get_visible_child_name();
stack.set_visible_child_name("loading");
......
......@@ -43,9 +43,11 @@ impl AppOp {
avatar.remove(w);
}
download_to_cache(self.backend.clone(), self.uid.clone().unwrap_or_default());
let w = widgets::Avatar::avatar_new(Some(40));
w.circle(self.uid.clone().unwrap_or_default(), self.username.clone(), 40);
let uid = self.uid.clone().unwrap_or_default();
let data = w.circle(uid.clone(), self.username.clone(), 40);
download_to_cache(self.backend.clone(), uid.clone(), data.clone());
avatar.add(&w);
stack.set_visible_child_name("info");
}
......@@ -61,9 +63,11 @@ impl AppOp {
let eb = gtk::EventBox::new();
match self.avatar.clone() {
Some(_) => {
download_to_cache(self.backend.clone(), self.uid.clone().unwrap_or_default());
let w = widgets::Avatar::avatar_new(Some(24));
w.circle(self.uid.clone().unwrap_or_default(), self.username.clone(), 24);
let uid = self.uid.clone().unwrap_or_default();
let data = w.circle(uid.clone(), self.username.clone(), 24);
download_to_cache(self.backend.clone(), uid.clone(), data.clone());
eb.add(&w);
}
None => {
......
......@@ -3,6 +3,7 @@ extern crate serde_json;
use std::fs::File;
use std::fs::remove_dir_all;
use std::io::prelude::*;
use gtk;
use types::RoomList;
use error::Error;
......@@ -13,6 +14,12 @@ use globals;
/* includes for avatar download */
use backend::BKCommand;
use std::sync::mpsc::Sender;
use std::sync::mpsc::channel;
use std::sync::mpsc::TryRecvError;
use std::cell::RefCell;
use std::rc::Rc;
use widgets::AvatarData;
#[derive(Serialize, Deserialize)]
pub struct CacheData {
......@@ -70,7 +77,19 @@ pub fn destroy() -> Result<(), Error> {
remove_dir_all(fname).or_else(|_| Err(Error::CacheError))
}
/* this downloads a avatar and stores it in the cache folder */
pub fn download_to_cache(backend: Sender<BKCommand>, name: String) {
let _ = backend.send(BKCommand::GetUserInfoAsync(name.clone(), None));
/// this downloads a avatar and stores it in the cache folder
pub fn download_to_cache(backend: Sender<BKCommand>,
name: String,
data: Rc<RefCell<AvatarData>>) {
let (tx, rx) = channel::<(String, String)>();
let _ = backend.send(BKCommand::GetUserInfoAsync(name.clone(), Some(tx)));
gtk::timeout_add(50, move || match rx.try_recv() {
Err(TryRecvError::Empty) => gtk::Continue(true),
Err(TryRecvError::Disconnected) => gtk::Continue(false),
Ok(_resp) => {
data.borrow_mut().redraw_pixbuf();
gtk::Continue(false)
}
});
}
extern crate gtk;
extern crate gdk;
extern crate glib;
extern crate gdk_pixbuf;
extern crate cairo;
extern crate letter_avatar;
......@@ -17,11 +16,40 @@ use fractal_api::util::cache_path;
pub type Avatar = gtk::Box;
pub struct AvatarData {
uid: String,
username: Option<String>,
size: i32,
cache: Option<Pixbuf>,
pub widget: gtk::DrawingArea,
fallback: cairo::ImageSurface,
}
impl AvatarData {
pub fn redraw_fallback(&mut self, username: Option<String>) {
self.username = username.clone();
/* This function should never fail */
self.fallback = letter_avatar::generate::new(self.uid.clone(),
username,
self.size as f64)
.expect("this function should never fail");
self.widget.queue_draw();
}
pub fn redraw_pixbuf(&mut self) {
let path = cache_path(&self.uid).unwrap_or(String::from(""));
let new_avatar = Pixbuf::new_from_file_at_scale(&path, self.size, -1, true);
self.cache = new_avatar.ok();
self.widget.queue_draw();
}
}
pub trait AvatarExt {
fn avatar_new(size: Option<i32>) -> gtk::Box;
fn clean(&self);
fn create_da(&self, size: Option<i32>) -> DrawingArea;
fn circle(&self, uid: String, username: Option<String>, size: i32);
fn circle(&self, uid: String, username: Option<String>, size: i32)
-> Rc<RefCell<AvatarData>>;
}
impl AvatarExt for gtk::Box {
......@@ -53,28 +81,35 @@ impl AvatarExt for gtk::Box {
b
}
fn circle(&self, uid: String, username: Option<String>, size: i32) {
struct Data {
cache : Result<Pixbuf, glib::Error>,
fallback: cairo::ImageSurface
}
fn circle(&self, uid: String, username: Option<String>, size: i32)
-> Rc<RefCell<AvatarData>> {
self.clean();
let da = self.create_da(Some(size));
let path = cache_path(&uid).unwrap_or(String::from(""));
let user_avatar = Pixbuf::new_from_file_at_scale(&path, size, -1, true);
let uname = username.clone();
/* remove IRC postfix from the username */
let username = if let Some(u) = username {
let username = if let Some(u) = username {
Some(u.trim_right_matches(" (IRC)").to_owned())
}else {
None
};
/* This function should never fail */
let fallback = letter_avatar::generate::new(uid, username, size as f64).unwrap();
let user_cache: Rc<RefCell<Data>> = Rc::new(RefCell::new(Data {cache: user_avatar, fallback: fallback}));
let fallback = letter_avatar::generate::new(uid.clone(), username, size as f64)
.expect("this function should never fail");
let data = AvatarData {
uid: uid.clone(),
username: uname,
size: size,
cache: user_avatar.ok(),
fallback: fallback,
widget: da.clone(),
};
let avatar_cache: Rc<RefCell<AvatarData>> = Rc::new(RefCell::new(data));
let user_cache = user_cache.clone();
let user_cache = avatar_cache.clone();
da.connect_draw(move |da, g| {
use std::f64::consts::PI;
let width = size as f64;
......@@ -84,7 +119,7 @@ impl AvatarExt for gtk::Box {
{
let data = user_cache.borrow();
if let Ok(ref pb) = data.cache {
if let Some(ref pb) = data.cache {
let context = da.get_style_context().unwrap();
gtk::render_background(&context, g, 0.0, 0.0, width, height);
......@@ -98,19 +133,14 @@ impl AvatarExt for gtk::Box {
g.set_source_surface(&data.fallback, 0f64, 0f64);
}
}
/* we should look into the cache only if the cache has changed, but this information is
* not yet available, we could also create our own signal and not use the draw signal*/
{
let mut data = user_cache.borrow_mut();
let new_avatar = Pixbuf::new_from_file_at_scale(&path, size, -1, true);
data.cache = new_avatar;
}
g.rectangle(0.0, 0.0, width, height);
g.fill();
Inhibit(false)
});
avatar_cache
}
}
......
......@@ -106,6 +106,7 @@ impl Image {
self
}
#[allow(dead_code)]
pub fn circle(mut self, c: bool) -> Image {
self.circle = c;
self
......
......@@ -54,10 +54,11 @@ impl<'a> MemberBox<'a> {
style.add_class("member");
}
download_to_cache(backend.clone(), self.member.uid.clone());
let avatar = widgets::Avatar::avatar_new(Some(globals::USERLIST_ICON_SIZE));
avatar.circle(self.member.uid.clone(), Some(alias.clone()), globals::USERLIST_ICON_SIZE);
//get_member_info(backend.clone(), avatar.clone(), username.clone(), self.member.uid.clone(), globals::USERLIST_ICON_SIZE, 10);
let data = avatar.circle(self.member.uid.clone(), Some(alias.clone()), globals::USERLIST_ICON_SIZE);
let member_id = self.member.uid.clone();
download_to_cache(backend.clone(), member_id.clone(), data.clone());
avatar.set_margin_start(3);
avatar.set_valign(gtk::Align::Center);
......
......@@ -6,6 +6,9 @@ extern crate glib;
use app::App;
use i18n::i18n;
use std::cell::RefCell;
use std::rc::Rc;
use self::gtk::prelude::*;
use types::Message;
......@@ -28,6 +31,7 @@ use appop::AppOp;
use globals;
use widgets;
use widgets::AvatarExt;
use widgets::AvatarData;
// Room Message item
pub struct MessageBox<'a> {
......@@ -114,7 +118,7 @@ impl<'a> MessageBox<'a> {
let msg = self.msg;
if !small {
let info = self.build_room_msg_info(self.msg);
let info = self.build_room_msg_info(self.msg, small);
info.set_margin_top(2);
info.set_margin_bottom(3);
content.pack_start(&info, false, false, 0);
......@@ -140,29 +144,37 @@ impl<'a> MessageBox<'a> {
let m = self.room.members.get(&uid);
let username = match m {
let data = match m {
Some(member) => {
self.username.set_text(&member.get_alias());
Some(member.get_alias())
let username = Some(member.get_alias());
avatar.circle(uid.clone(), username, globals::MSG_ICON_SIZE)
}
None => {
self.username.set_text(&uid);
None
let backend = self.op.backend.clone();
let data = avatar.circle(uid.clone(), None, globals::MSG_ICON_SIZE);
set_username_async(backend, &uid, self.username.clone(),
Some(data.clone()));
data
}
};
download_to_cache(self.op.backend.clone(), uid.clone());
avatar.circle(uid, username, globals::MSG_ICON_SIZE);
download_to_cache(self.op.backend.clone(), uid.clone(),
data.clone());
avatar
}
fn build_room_msg_username(&self, sender: &str, member: Option<&Member>) -> gtk::Label {
fn build_room_msg_username(&self, sender: &str, member: Option<&Member>, small: bool) -> gtk::Label {
let uname = match member {
Some(m) => m.get_alias(),
None => {
let backend = self.op.backend.clone();
set_username_async(backend, sender, self.username.clone());
// in small widget, the avatar doesn't download the username
// so we need to download here
if small {
let backend = self.op.backend.clone();
set_username_async(backend, sender, self.username.clone(), None);
}
String::from(sender)
}
};
......@@ -441,7 +453,7 @@ impl<'a> MessageBox<'a> {
date
}
fn build_room_msg_info(&self, msg: &Message) -> gtk::Box {
fn build_room_msg_info(&self, msg: &Message, small: bool) -> gtk::Box {
// info
// +----------+------+
// | username | date |
......@@ -449,7 +461,7 @@ impl<'a> MessageBox<'a> {
let info = gtk::Box::new(gtk::Orientation::Horizontal, 0);
let member = self.room.members.get(&msg.sender);
let username = self.build_room_msg_username(&msg.sender, member);
let username = self.build_room_msg_username(&msg.sender, member, small);
let date = self.build_room_msg_date(&msg.date);
self.username_event_box.add(&username);
......@@ -550,7 +562,10 @@ fn highlight_username(label: gtk::Label, alias: &String, input: String) -> Optio
Some(attr)
}
fn set_username_async(backend: Sender<BKCommand>, uid: &str, label: gtk::Label) {
fn set_username_async(backend: Sender<BKCommand>,
uid: &str,
label: gtk::Label,
avatar: Option<Rc<RefCell<AvatarData>>>) {
let (tx, rx): (Sender<String>, Receiver<String>) = channel();
backend.send(BKCommand::GetUserNameAsync(uid.to_string(), tx)).unwrap();
gtk::timeout_add(50, move || match rx.try_recv() {
......@@ -558,6 +573,11 @@ fn set_username_async(backend: Sender<BKCommand>, uid: &str, label: gtk::Label)
Err(TryRecvError::Disconnected) => gtk::Continue(false),
Ok(username) => {
label.set_text(&username);
if let Some(ref rc_data) = avatar {
let mut data = rc_data.borrow_mut();
data.redraw_fallback(Some(username));
}
gtk::Continue(false)
}
});
......
......@@ -20,6 +20,7 @@ pub use self::roomrow::RoomRow;
pub use self::roomlist::RoomList;
pub use self::avatar::Avatar;
pub use self::avatar::AvatarExt;
pub use self::avatar::AvatarData;
pub use self::avatar::admin_badge;
pub use self::avatar::AdminColor;
pub use self::inline_player::AudioPlayerWidget;
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