feat: image loading on different thread
Some checks failed
CI / Rustfmt (push) Failing after 11m14s
CI / Flatpak (push) Failing after 11m8s

This commit is contained in:
Tine Jozelj 2024-01-11 19:14:06 +01:00
parent 83c478cfd2
commit 6240c59e24
Signed by: mentos1386
SSH key fingerprint: SHA256:MNtTsLbihYaWF8j1fkOHfkKNlnN1JQfxEU/rBU8nCGw
8 changed files with 137 additions and 23 deletions

97
Cargo.lock generated
View file

@ -362,6 +362,21 @@ dependencies = [
"slab", "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]] [[package]]
name = "gdk-pixbuf" name = "gdk-pixbuf"
version = "0.18.5" version = "0.18.5"
@ -388,6 +403,23 @@ dependencies = [
"system-deps", "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]] [[package]]
name = "gdk4" name = "gdk4"
version = "0.7.3" version = "0.7.3"
@ -878,6 +910,16 @@ dependencies = [
"winapi", "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]] [[package]]
name = "log" name = "log"
version = "0.4.20" version = "0.4.20"
@ -940,13 +982,16 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures", "futures",
"gdk",
"gdk-pixbuf", "gdk-pixbuf",
"gettext-rs", "gettext-rs",
"glib",
"gsettings-macro", "gsettings-macro",
"gtk4", "gtk4",
"libadwaita", "libadwaita",
"reqwest", "reqwest",
"serde", "serde",
"tokio",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
] ]
@ -1108,6 +1153,29 @@ dependencies = [
"system-deps", "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]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.3.1" version = "2.3.1"
@ -1323,6 +1391,12 @@ dependencies = [
"windows-sys 0.52.0", "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]] [[package]]
name = "security-framework" name = "security-framework"
version = "2.9.2" version = "2.9.2"
@ -1413,6 +1487,15 @@ dependencies = [
"lazy_static", "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]] [[package]]
name = "slab" name = "slab"
version = "0.4.9" version = "0.4.9"
@ -1581,11 +1664,25 @@ dependencies = [
"libc", "libc",
"mio", "mio",
"num_cpus", "num_cpus",
"parking_lot",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry",
"socket2", "socket2",
"tokio-macros",
"windows-sys 0.48.0", "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]] [[package]]
name = "tokio-native-tls" name = "tokio-native-tls"
version = "0.3.1" version = "0.3.1"

View file

@ -18,6 +18,9 @@ gsettings-macro = "0.1.20"
gdk-pixbuf = "0.18.5" gdk-pixbuf = "0.18.5"
bytes = "1.5.0" bytes = "1.5.0"
futures = "0.3.30" futures = "0.3.30"
tokio = { version = "1.35.1", features = ["full"] }
glib = "0.18.5"
gdk = "0.18.0"
[dependencies.adw] [dependencies.adw]
package = "libadwaita" package = "libadwaita"

View file

@ -1,4 +1,4 @@
.card image { .card image {
min-width: 500px; min-width: 200px;
min-height: 500px; min-height: 200px;
} }

View file

@ -5,7 +5,9 @@ template $Card: Box {
orientation: horizontal; orientation: horizontal;
styles ["card"] styles ["card"]
Image image {} Image image {
icon-name: "image-loading";
}
Box contents { Box contents {
orientation: vertical; orientation: vertical;

View file

@ -22,3 +22,17 @@ pub fn get_curse_forge_client() -> Result<reqwest::blocking::Client, reqwest::Er
.default_headers(headers) .default_headers(headers)
.build() .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()
}

View file

@ -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::traits::PixbufLoaderExt;
use gdk_pixbuf::{Pixbuf, PixbufLoader}; use gdk_pixbuf::{Pixbuf, PixbufLoader};
use std::io::{Error, ErrorKind, Write}; use std::io::{Error, ErrorKind, Write};
use std::thread;
use tokio::sync::oneshot;
use crate::api::*; use crate::api::*;
@ -34,20 +32,21 @@ impl ImageLoader {
Self {} Self {}
} }
fn get_image(url: &str) -> Option<Bytes> { pub async fn from_url(&self, url: String) -> Option<Pixbuf> {
let client = base::get_curse_forge_client().unwrap(); let (sender, receiver) = oneshot::channel();
let response = client.get(url).send().ok();
response.unwrap().bytes().ok()
}
pub fn load_remote(&self, url: &str, width: i32, height: i32) -> Option<Pixbuf> {
let pixbuf_loader = PixbufLoader::new(); let pixbuf_loader = PixbufLoader::new();
pixbuf_loader.set_size(width, height);
let mut loader = LocalPixbufLoader(&pixbuf_loader); let mut loader = LocalPixbufLoader(&pixbuf_loader);
if let Some(mut resp) = Self::get_image(url) { thread::spawn(move || {
loader.write_all(&resp).ok()?; 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.close().ok()?;
pixbuf_loader.pixbuf() pixbuf_loader.pixbuf()

View file

@ -1,5 +1,4 @@
use adw::subclass::prelude::*; use adw::subclass::prelude::*;
use glib::clone;
use gtk::CompositeTemplate; use gtk::CompositeTemplate;
use gtk::{gio, glib}; use gtk::{gio, glib};
@ -64,10 +63,11 @@ impl Card {
let url = image_url.to_string(); 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 loader = ImageLoader::new();
let pixbuf = loader.load_remote(url.as_str(), 800, 800); let pixbuf = loader.from_url(url).await;
widget.image.set_from_pixbuf(pixbuf.as_ref()); image.set_from_pixbuf(pixbuf.as_ref());
})); });
} }
} }

View file

@ -24,7 +24,6 @@ mod settings;
mod windows; mod windows;
use self::application::ModManagerApplication; use self::application::ModManagerApplication;
use self::dispatch::spawn_task_handler;
use config::{GETTEXT_PACKAGE, LOCALEDIR, RESOURCES_FILE}; use config::{GETTEXT_PACKAGE, LOCALEDIR, RESOURCES_FILE};
use gettextrs::{gettext, LocaleCategory}; use gettextrs::{gettext, LocaleCategory};