mirror of
https://github.com/MeexReay/bRAC.git
synced 2025-09-13 23:47:39 +03:00
fix: move avatars loading to new thread
This commit is contained in:
parent
b4d82f0e32
commit
1af2810dc0
256
src/chat/gui.rs
256
src/chat/gui.rs
@ -4,8 +4,8 @@ use std::cell::RefCell;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::hash::{DefaultHasher, Hasher};
|
use std::hash::{DefaultHasher, Hasher};
|
||||||
use std::sync::atomic::AtomicU64;
|
use std::sync::atomic::{AtomicBool, AtomicU64};
|
||||||
use std::sync::RwLockWriteGuard;
|
use std::sync::{Mutex, RwLockWriteGuard};
|
||||||
use std::sync::{atomic::Ordering, mpsc::channel, Arc, RwLock};
|
use std::sync::{atomic::Ordering, mpsc::channel, Arc, RwLock};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
@ -53,7 +53,7 @@ struct UiModel {
|
|||||||
#[cfg(all(not(feature = "libnotify"), not(feature = "notify-rust")))]
|
#[cfg(all(not(feature = "libnotify"), not(feature = "notify-rust")))]
|
||||||
notifications: Arc<RwLock<Vec<String>>>,
|
notifications: Arc<RwLock<Vec<String>>>,
|
||||||
default_avatar: Pixbuf,
|
default_avatar: Pixbuf,
|
||||||
avatars: Arc<RwLock<HashMap<u64, Pixbuf>>>,
|
avatars: Arc<Mutex<HashMap<u64, Vec<Picture>>>>,
|
||||||
latest_sign: Arc<AtomicU64>
|
latest_sign: Arc<AtomicU64>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,44 +231,25 @@ fn open_settings(ctx: Arc<Context>, app: &Application) {
|
|||||||
vbox.append(&save_button);
|
vbox.append(&save_button);
|
||||||
|
|
||||||
save_button.connect_clicked(clone!(
|
save_button.connect_clicked(clone!(
|
||||||
#[weak]
|
#[weak] ctx,
|
||||||
ctx,
|
#[weak] host_entry,
|
||||||
#[weak]
|
#[weak] name_entry,
|
||||||
host_entry,
|
#[weak] message_format_entry,
|
||||||
#[weak]
|
#[weak] update_time_entry,
|
||||||
name_entry,
|
#[weak] max_messages_entry,
|
||||||
#[weak]
|
#[weak] hide_my_ip_entry,
|
||||||
message_format_entry,
|
#[weak] show_other_ip_entry,
|
||||||
#[weak]
|
#[weak] chunked_enabled_entry,
|
||||||
update_time_entry,
|
#[weak] formatting_enabled_entry,
|
||||||
#[weak]
|
#[weak] commands_enabled_entry,
|
||||||
max_messages_entry,
|
#[weak] notifications_enabled_entry,
|
||||||
#[weak]
|
#[weak] proxy_entry,
|
||||||
hide_my_ip_entry,
|
#[weak] debug_logs_entry,
|
||||||
#[weak]
|
#[weak] oof_update_time_entry,
|
||||||
show_other_ip_entry,
|
#[weak] konata_size_entry,
|
||||||
#[weak]
|
#[weak] remove_gui_shit_entry,
|
||||||
chunked_enabled_entry,
|
#[weak] new_ui_enabled_entry,
|
||||||
#[weak]
|
#[weak] avatar_entry,
|
||||||
formatting_enabled_entry,
|
|
||||||
#[weak]
|
|
||||||
commands_enabled_entry,
|
|
||||||
#[weak]
|
|
||||||
notifications_enabled_entry,
|
|
||||||
#[weak]
|
|
||||||
proxy_entry,
|
|
||||||
#[weak]
|
|
||||||
debug_logs_entry,
|
|
||||||
#[weak]
|
|
||||||
oof_update_time_entry,
|
|
||||||
#[weak]
|
|
||||||
konata_size_entry,
|
|
||||||
#[weak]
|
|
||||||
remove_gui_shit_entry,
|
|
||||||
#[weak]
|
|
||||||
new_ui_enabled_entry,
|
|
||||||
#[weak]
|
|
||||||
avatar_entry,
|
|
||||||
move |_| {
|
move |_| {
|
||||||
let config = Config {
|
let config = Config {
|
||||||
host: host_entry.text().to_string(),
|
host: host_entry.text().to_string(),
|
||||||
@ -365,44 +346,25 @@ fn open_settings(ctx: Arc<Context>, app: &Application) {
|
|||||||
vbox.append(&reset_button);
|
vbox.append(&reset_button);
|
||||||
|
|
||||||
reset_button.connect_clicked(clone!(
|
reset_button.connect_clicked(clone!(
|
||||||
#[weak]
|
#[weak] ctx,
|
||||||
ctx,
|
#[weak] host_entry,
|
||||||
#[weak]
|
#[weak] name_entry,
|
||||||
host_entry,
|
#[weak] message_format_entry,
|
||||||
#[weak]
|
#[weak] update_time_entry,
|
||||||
name_entry,
|
#[weak] max_messages_entry,
|
||||||
#[weak]
|
#[weak] hide_my_ip_entry,
|
||||||
message_format_entry,
|
#[weak] show_other_ip_entry,
|
||||||
#[weak]
|
#[weak] chunked_enabled_entry,
|
||||||
update_time_entry,
|
#[weak] formatting_enabled_entry,
|
||||||
#[weak]
|
#[weak] commands_enabled_entry,
|
||||||
max_messages_entry,
|
#[weak] notifications_enabled_entry,
|
||||||
#[weak]
|
#[weak] proxy_entry,
|
||||||
hide_my_ip_entry,
|
#[weak] debug_logs_entry,
|
||||||
#[weak]
|
#[weak] oof_update_time_entry,
|
||||||
show_other_ip_entry,
|
#[weak] konata_size_entry,
|
||||||
#[weak]
|
#[weak] remove_gui_shit_entry,
|
||||||
chunked_enabled_entry,
|
#[weak] new_ui_enabled_entry,
|
||||||
#[weak]
|
#[weak] avatar_entry,
|
||||||
formatting_enabled_entry,
|
|
||||||
#[weak]
|
|
||||||
commands_enabled_entry,
|
|
||||||
#[weak]
|
|
||||||
notifications_enabled_entry,
|
|
||||||
#[weak]
|
|
||||||
proxy_entry,
|
|
||||||
#[weak]
|
|
||||||
debug_logs_entry,
|
|
||||||
#[weak]
|
|
||||||
oof_update_time_entry,
|
|
||||||
#[weak]
|
|
||||||
konata_size_entry,
|
|
||||||
#[weak]
|
|
||||||
remove_gui_shit_entry,
|
|
||||||
#[weak]
|
|
||||||
new_ui_enabled_entry,
|
|
||||||
#[weak]
|
|
||||||
avatar_entry,
|
|
||||||
move |_| {
|
move |_| {
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
ctx.set_config(&config);
|
ctx.set_config(&config);
|
||||||
@ -494,21 +456,7 @@ fn build_menu(ctx: Arc<Context>, app: &Application) {
|
|||||||
AboutDialog::builder()
|
AboutDialog::builder()
|
||||||
.application(&app)
|
.application(&app)
|
||||||
.authors(["MeexReay"])
|
.authors(["MeexReay"])
|
||||||
.license(
|
.license(include_str!("../../LICENSE"))
|
||||||
" DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
||||||
Version 2, December 2004
|
|
||||||
|
|
||||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
|
||||||
|
|
||||||
Everyone is permitted to copy and distribute verbatim or modified
|
|
||||||
copies of this license document, and changing it is allowed as long
|
|
||||||
as the name is changed.
|
|
||||||
|
|
||||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. You just DO WHAT THE FUCK YOU WANT TO.",
|
|
||||||
)
|
|
||||||
.comments("better RAC client")
|
.comments("better RAC client")
|
||||||
.website("https://github.com/MeexReay/bRAC")
|
.website("https://github.com/MeexReay/bRAC")
|
||||||
.website_label("source code")
|
.website_label("source code")
|
||||||
@ -814,7 +762,7 @@ fn build_ui(ctx: Arc<Context>, app: &Application) -> UiModel {
|
|||||||
#[cfg(all(not(feature = "libnotify"), not(feature = "notify-rust")))]
|
#[cfg(all(not(feature = "libnotify"), not(feature = "notify-rust")))]
|
||||||
notifications: Arc::new(RwLock::new(Vec::<String>::new())),
|
notifications: Arc::new(RwLock::new(Vec::<String>::new())),
|
||||||
default_avatar: load_pixbuf(include_bytes!("images/avatar.png")).unwrap(),
|
default_avatar: load_pixbuf(include_bytes!("images/avatar.png")).unwrap(),
|
||||||
avatars: Arc::new(RwLock::new(HashMap::new())),
|
avatars: Arc::new(Mutex::new(HashMap::new())),
|
||||||
latest_sign: Arc::new(AtomicU64::new(0))
|
latest_sign: Arc::new(AtomicU64::new(0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -868,21 +816,62 @@ fn setup(_: &Application, ctx: Arc<Context>, ui: UiModel) {
|
|||||||
move || {
|
move || {
|
||||||
while let Ok((messages, clear)) = receiver.recv() {
|
while let Ok((messages, clear)) = receiver.recv() {
|
||||||
let ctx = ctx.clone();
|
let ctx = ctx.clone();
|
||||||
|
let messages = Arc::new(messages);
|
||||||
|
let added = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
timeout_add_once(Duration::ZERO, move || {
|
timeout_add_once(Duration::ZERO, {
|
||||||
GLOBAL.with(|global| {
|
let messages = messages.clone();
|
||||||
if let Some(ui) = &*global.borrow() {
|
let added = added.clone();
|
||||||
if clear {
|
|
||||||
while let Some(row) = ui.chat_box.last_child() {
|
move || {
|
||||||
ui.chat_box.remove(&row);
|
GLOBAL.with(|global| {
|
||||||
|
if let Some(ui) = &*global.borrow() {
|
||||||
|
if clear {
|
||||||
|
while let Some(row) = ui.chat_box.last_child() {
|
||||||
|
ui.chat_box.remove(&row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for message in messages.iter() {
|
||||||
|
on_add_message(ctx.clone(), &ui, message.to_string(), !clear);
|
||||||
|
}
|
||||||
|
|
||||||
|
added.store(true, Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut avatars = HashMap::new();
|
||||||
|
|
||||||
|
for message in messages.iter() {
|
||||||
|
let Some(avatar_url) = grab_avatar(message) else { continue };
|
||||||
|
let avatar_id = get_avatar_id(&avatar_url);
|
||||||
|
let Some(avatar) = load_avatar(&avatar_url) else { continue };
|
||||||
|
|
||||||
|
avatars.insert(avatar_id, avatar);
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout_add_once(Duration::ZERO, {
|
||||||
|
move || {
|
||||||
|
while !added.load(Ordering::SeqCst) {}
|
||||||
|
|
||||||
|
GLOBAL.with(|global| {
|
||||||
|
if let Some(ui) = &*global.borrow() {
|
||||||
|
for (id, avatar) in avatars.iter() {
|
||||||
|
if let Some(pics) = ui.avatars.lock().unwrap().remove(id) {
|
||||||
|
for pic in pics {
|
||||||
|
pic.set_pixbuf(
|
||||||
|
load_pixbuf(avatar).ok()
|
||||||
|
.and_then(|o| o.scale_simple(
|
||||||
|
32, 32, InterpType::Bilinear
|
||||||
|
)).as_ref());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for message in messages.iter() {
|
});
|
||||||
prepare_avatar(&mut ui.avatars.write().unwrap(), message); // TODO: fuck
|
}
|
||||||
on_add_message(ctx.clone(), &ui, message.to_string(), !clear);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1063,37 +1052,16 @@ fn get_message_box(
|
|||||||
hbox
|
hbox
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_avatar(avatars: &mut RwLockWriteGuard<'_, HashMap<u64, Pixbuf>>, message: &str) {
|
fn get_avatar_id(url: &str) -> u64 {
|
||||||
if let Some(url) = grab_avatar(message) {
|
|
||||||
let mut hasher = DefaultHasher::new();
|
|
||||||
hasher.write(url.as_bytes());
|
|
||||||
let id = hasher.finish();
|
|
||||||
|
|
||||||
if !avatars.contains_key(&id) {
|
|
||||||
let Ok(data) = reqwest::blocking::get(&url).and_then(|o| o.bytes()) else {
|
|
||||||
return
|
|
||||||
};
|
|
||||||
let Ok(pixbuf) = load_pixbuf(&data.to_vec()) else {
|
|
||||||
return
|
|
||||||
};
|
|
||||||
let Some(pixbuf) = pixbuf.scale_simple(32, 32, InterpType::Bilinear) else {
|
|
||||||
return
|
|
||||||
};
|
|
||||||
avatars.insert(id, pixbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_avatar_or_default(ui: &UiModel, url: &str) -> Pixbuf {
|
|
||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
hasher.write(url.as_bytes());
|
hasher.write(url.as_bytes());
|
||||||
let id = hasher.finish();
|
hasher.finish()
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(pixbuf) = ui.avatars.read().unwrap().get(&id) {
|
fn load_avatar(url: &str) -> Option<Vec<u8>> {
|
||||||
pixbuf.clone() // FIXME: cloning pixbufs is a dangerous shit
|
reqwest::blocking::get(url).ok()
|
||||||
} else {
|
.and_then(|resp| resp.bytes().ok())
|
||||||
ui.default_avatar.clone()
|
.map(|bytes| bytes.to_vec())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_new_message_box(
|
fn get_new_message_box(
|
||||||
@ -1128,9 +1096,7 @@ fn get_new_message_box(
|
|||||||
nick.as_ref()
|
nick.as_ref()
|
||||||
.map(|o| o.1.to_string())
|
.map(|o| o.1.to_string())
|
||||||
.unwrap_or("#DDDDDD".to_string()),
|
.unwrap_or("#DDDDDD".to_string()),
|
||||||
avatar
|
avatar.map(|o| get_avatar_id(&o)).unwrap_or_default()
|
||||||
.map(|o| get_avatar_or_default(ui, &o))
|
|
||||||
.unwrap_or(ui.default_avatar.clone()),
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
@ -1139,7 +1105,7 @@ fn get_new_message_box(
|
|||||||
message,
|
message,
|
||||||
"System".to_string(),
|
"System".to_string(),
|
||||||
"#DDDDDD".to_string(),
|
"#DDDDDD".to_string(),
|
||||||
ui.default_avatar.clone(),
|
0
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1170,7 +1136,7 @@ fn get_new_message_box(
|
|||||||
let fixed = Fixed::new();
|
let fixed = Fixed::new();
|
||||||
fixed.set_can_target(false);
|
fixed.set_can_target(false);
|
||||||
|
|
||||||
let avatar_picture = Picture::for_pixbuf(&avatar);
|
let avatar_picture = Picture::for_pixbuf(&ui.default_avatar.clone());
|
||||||
avatar_picture.set_css_classes(&["message-avatar"]);
|
avatar_picture.set_css_classes(&["message-avatar"]);
|
||||||
avatar_picture.set_vexpand(false);
|
avatar_picture.set_vexpand(false);
|
||||||
avatar_picture.set_hexpand(false);
|
avatar_picture.set_hexpand(false);
|
||||||
@ -1178,6 +1144,16 @@ fn get_new_message_box(
|
|||||||
avatar_picture.set_halign(Align::Start);
|
avatar_picture.set_halign(Align::Start);
|
||||||
avatar_picture.set_size_request(32, 32);
|
avatar_picture.set_size_request(32, 32);
|
||||||
|
|
||||||
|
if avatar != 0 {
|
||||||
|
let mut lock = ui.avatars.lock().unwrap();
|
||||||
|
|
||||||
|
if let Some(pics) = lock.get_mut(&avatar) {
|
||||||
|
pics.push(avatar_picture.clone());
|
||||||
|
} else {
|
||||||
|
lock.insert(avatar, vec![avatar_picture.clone()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fixed.put(&avatar_picture, 0.0, 4.0);
|
fixed.put(&avatar_picture, 0.0, 4.0);
|
||||||
|
|
||||||
overlay.add_overlay(&fixed);
|
overlay.add_overlay(&fixed);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user