feat: image loading on different thread
This commit is contained in:
parent
83c478cfd2
commit
b63e6a8892
9 changed files with 191 additions and 23 deletions
97
Cargo.lock
generated
97
Cargo.lock
generated
|
@ -362,6 +362,21 @@ dependencies = [
|
|||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdk"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5ba081bdef3b75ebcdbfc953699ed2d7417d6bd853347a42a37d76406a33646"
|
||||
dependencies = [
|
||||
"cairo-rs",
|
||||
"gdk-pixbuf",
|
||||
"gdk-sys",
|
||||
"gio",
|
||||
"glib",
|
||||
"libc",
|
||||
"pango",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdk-pixbuf"
|
||||
version = "0.18.5"
|
||||
|
@ -388,6 +403,23 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdk-sys"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31ff856cb3386dae1703a920f803abafcc580e9b5f711ca62ed1620c25b51ff2"
|
||||
dependencies = [
|
||||
"cairo-sys-rs",
|
||||
"gdk-pixbuf-sys",
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"pango-sys",
|
||||
"pkg-config",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdk4"
|
||||
version = "0.7.3"
|
||||
|
@ -878,6 +910,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
|
@ -940,13 +982,16 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"bytes",
|
||||
"futures",
|
||||
"gdk",
|
||||
"gdk-pixbuf",
|
||||
"gettext-rs",
|
||||
"glib",
|
||||
"gsettings-macro",
|
||||
"gtk4",
|
||||
"libadwaita",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
@ -1108,6 +1153,29 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
|
@ -1323,6 +1391,12 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.9.2"
|
||||
|
@ -1413,6 +1487,15 @@ dependencies = [
|
|||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
|
@ -1581,11 +1664,25 @@ dependencies = [
|
|||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.1"
|
||||
|
|
|
@ -18,6 +18,9 @@ gsettings-macro = "0.1.20"
|
|||
gdk-pixbuf = "0.18.5"
|
||||
bytes = "1.5.0"
|
||||
futures = "0.3.30"
|
||||
tokio = { version = "1.35.1", features = ["full"] }
|
||||
glib = "0.18.5"
|
||||
gdk = "0.18.0"
|
||||
|
||||
[dependencies.adw]
|
||||
package = "libadwaita"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.card image {
|
||||
min-width: 500px;
|
||||
min-height: 500px;
|
||||
min-width: 200px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@ template $Card: Box {
|
|||
orientation: horizontal;
|
||||
styles ["card"]
|
||||
|
||||
Image image {}
|
||||
Image image {
|
||||
icon-name: "image-loading";
|
||||
}
|
||||
|
||||
Box contents {
|
||||
orientation: vertical;
|
||||
|
|
54
src/api/.loaders.rs.rustfmt
Normal file
54
src/api/.loaders.rs.rustfmt
Normal file
|
@ -0,0 +1,54 @@
|
|||
use gdk_pixbuf::traits::PixbufLoaderExt;
|
||||
use gdk_pixbuf::{Pixbuf, PixbufLoader};
|
||||
use std::io::{Error, ErrorKind, Write};
|
||||
use std::thread;
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
use crate::api::*;
|
||||
|
||||
// A wrapper to be able to implement the Write trait on a PixbufLoader
|
||||
struct LocalPixbufLoader<'a>(&'a PixbufLoader);
|
||||
|
||||
impl<'a> Write for LocalPixbufLoader<'a> {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
|
||||
self.0
|
||||
.write(buf)
|
||||
.map_err(|e| Error::new(ErrorKind::Other, format!("glib error: {e}")))?;
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<(), Error> {
|
||||
self.0
|
||||
.close()
|
||||
.map_err(|e| Error::new(ErrorKind::Other, format!("glib error: {e}")))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ImageLoader {}
|
||||
|
||||
impl ImageLoader {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
pub async fn from_url(&self, url: String) -> Option<Pixbuf> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
|
||||
let pixbuf_loader = PixbufLoader::new();
|
||||
let mut loader = LocalPixbufLoader(&pixbuf_loader);
|
||||
|
||||
thread::spawn(move || {
|
||||
let client = base::get_curse_forge_client().unwrap();
|
||||
let response = client.get(url).send();
|
||||
let bytes = response.unwrap().bytes().ok().unwrap();
|
||||
sender.send(bytes).unwrap();
|
||||
});
|
||||
|
||||
let bytes = receiver.await.ok()?;
|
||||
loader.write_all(&bytes).ok()?;
|
||||
|
||||
pixbuf_loader.close().ok()?;
|
||||
pixbuf_loader.pixbuf()
|
||||
}
|
||||
}
|
|
@ -22,3 +22,17 @@ pub fn get_curse_forge_client() -> Result<reqwest::blocking::Client, reqwest::Er
|
|||
.default_headers(headers)
|
||||
.build()
|
||||
}
|
||||
|
||||
pub fn get_async_curse_forge_client() -> Result<reqwest::Client, reqwest::Error> {
|
||||
let mut api_key_header =
|
||||
reqwest::header::HeaderValue::from_str(crate::config::API_KEY).unwrap();
|
||||
api_key_header.set_sensitive(true);
|
||||
|
||||
let mut headers = reqwest::header::HeaderMap::new();
|
||||
headers.insert("x-api-key", api_key_header);
|
||||
|
||||
reqwest::Client::builder()
|
||||
.user_agent(format!("dev.mnts.ModManager/{}", crate::config::VERSION))
|
||||
.default_headers(headers)
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
// Inspired by https://github.com/xou816/spot/blob/aa1c57842c3f4e424eb62c69365438f904b2dc63/src/app/loader.rs
|
||||
// Without the caching.
|
||||
//
|
||||
use bytes::Bytes;
|
||||
use gdk_pixbuf::traits::PixbufLoaderExt;
|
||||
use gdk_pixbuf::{Pixbuf, PixbufLoader};
|
||||
use std::io::{Error, ErrorKind, Write};
|
||||
use std::thread;
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
use crate::api::*;
|
||||
|
||||
|
@ -34,20 +32,21 @@ impl ImageLoader {
|
|||
Self {}
|
||||
}
|
||||
|
||||
fn get_image(url: &str) -> Option<Bytes> {
|
||||
let client = base::get_curse_forge_client().unwrap();
|
||||
let response = client.get(url).send().ok();
|
||||
response.unwrap().bytes().ok()
|
||||
}
|
||||
pub async fn from_url(&self, url: String) -> Option<Pixbuf> {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
|
||||
pub fn load_remote(&self, url: &str, width: i32, height: i32) -> Option<Pixbuf> {
|
||||
let pixbuf_loader = PixbufLoader::new();
|
||||
pixbuf_loader.set_size(width, height);
|
||||
let mut loader = LocalPixbufLoader(&pixbuf_loader);
|
||||
|
||||
if let Some(mut resp) = Self::get_image(url) {
|
||||
loader.write_all(&resp).ok()?;
|
||||
}
|
||||
thread::spawn(move || {
|
||||
let client = base::get_curse_forge_client().unwrap();
|
||||
let response = client.get(url).send();
|
||||
let bytes = response.unwrap().bytes().ok().unwrap();
|
||||
sender.send(bytes).unwrap();
|
||||
});
|
||||
|
||||
let bytes = receiver.await.ok()?;
|
||||
loader.write_all(&bytes).ok()?;
|
||||
|
||||
pixbuf_loader.close().ok()?;
|
||||
pixbuf_loader.pixbuf()
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use adw::subclass::prelude::*;
|
||||
use glib::clone;
|
||||
use gtk::CompositeTemplate;
|
||||
use gtk::{gio, glib};
|
||||
|
||||
|
@ -64,10 +63,11 @@ impl Card {
|
|||
|
||||
let url = image_url.to_string();
|
||||
|
||||
worker.send_local_task(clone!(@weak widget => async move {
|
||||
let image = widget.image.clone();
|
||||
worker.send_local_task(async move {
|
||||
let loader = ImageLoader::new();
|
||||
let pixbuf = loader.load_remote(url.as_str(), 800, 800);
|
||||
widget.image.set_from_pixbuf(pixbuf.as_ref());
|
||||
}));
|
||||
let pixbuf = loader.from_url(url).await;
|
||||
image.set_from_pixbuf(pixbuf.as_ref());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ mod settings;
|
|||
mod windows;
|
||||
|
||||
use self::application::ModManagerApplication;
|
||||
use self::dispatch::spawn_task_handler;
|
||||
|
||||
use config::{GETTEXT_PACKAGE, LOCALEDIR, RESOURCES_FILE};
|
||||
use gettextrs::{gettext, LocaleCategory};
|
||||
|
|
Loading…
Reference in a new issue