diff --git a/Cargo.lock b/Cargo.lock index f2f1eba..e47f24a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -990,7 +990,7 @@ dependencies = [ [[package]] name = "glycin" version = "1.0.2" -source = "git+https://gitlab.gnome.org/sophie-h/glycin#f89bb5e087484c8cb1e0a93dc8946e298e933eb5" +source = "git+https://gitlab.gnome.org/sophie-h/glycin#15db3397385c127f21801bcf7ca7c9503a08571c" dependencies = [ "async-fs", "async-global-executor", @@ -1014,7 +1014,7 @@ dependencies = [ [[package]] name = "glycin-utils" version = "1.0.2" -source = "git+https://gitlab.gnome.org/sophie-h/glycin#f89bb5e087484c8cb1e0a93dc8946e298e933eb5" +source = "git+https://gitlab.gnome.org/sophie-h/glycin#15db3397385c127f21801bcf7ca7c9503a08571c" dependencies = [ "libc", "libseccomp", diff --git a/Cargo.toml b/Cargo.toml index 855fd9d..808d619 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,6 @@ async-channel = "2.1.0" env_logger = "0.11.0" futures-channel = "0.3.25" futures-lite = "2.1.0" - gvdb-macros = "0.1.6" indexmap = "2.0.0" kamadak-exif = "0.5.5" diff --git a/build-aux/flatpak/org.gnome.Loupe.Devel.json b/build-aux/flatpak/org.gnome.Loupe.Devel.json index 82a5702..74ad4fb 100644 --- a/build-aux/flatpak/org.gnome.Loupe.Devel.json +++ b/build-aux/flatpak/org.gnome.Loupe.Devel.json @@ -156,7 +156,7 @@ { "type": "git", "url": "https://gitlab.gnome.org/sophie-h/glycin.git", - "commit": "5c57603d9455aa74b802f4fcc7e5121dcaa67b10" + "commit": "4b5d7f06ae23bb8f5045ce069c687c3aa05c5f84" } ] }, diff --git a/data/resources/style.css b/data/resources/style.css index feb9d0b..cdb1ad0 100644 --- a/data/resources/style.css +++ b/data/resources/style.css @@ -52,4 +52,9 @@ lpprintpreviewpage lpimage { dropdown.flat button:not(:hover) { background: none; +} + +dialog.error-details textview { + background: none; + color: inherit; } \ No newline at end of file diff --git a/src/widgets/error_details.rs b/src/widgets/error_details.rs new file mode 100644 index 0000000..c1bb345 --- /dev/null +++ b/src/widgets/error_details.rs @@ -0,0 +1,81 @@ +use adw::prelude::*; +use adw::subclass::prelude::*; +use glib::{clone, Properties}; +use gtk::prelude::*; +use gtk::CompositeTemplate; + +use crate::deps::*; +use crate::util::gettext::*; +use crate::widgets::LpImage; + +mod imp { + use super::*; + + #[derive(Debug, Default, CompositeTemplate)] + #[template(file = "error_details.ui")] + pub struct LpErrorDetails { + #[template_child] + pub(super) message: TemplateChild, + #[template_child] + pub(super) copy: TemplateChild, + #[template_child] + pub(super) report: TemplateChild, + } + + #[glib::object_subclass] + impl ObjectSubclass for LpErrorDetails { + const NAME: &'static str = "LpErrorDetails"; + type Type = super::LpErrorDetails; + type ParentType = adw::Dialog; + + fn class_init(klass: &mut Self::Class) { + Self::bind_template(klass); + } + + fn instance_init(obj: &glib::subclass::InitializingObject) { + obj.init_template(); + } + } + + impl ObjectImpl for LpErrorDetails { + fn constructed(&self) { + self.message.buffer().set_text("Some test text"); + } + } + impl WidgetImpl for LpErrorDetails {} + impl AdwDialogImpl for LpErrorDetails {} +} + +glib::wrapper! { + pub struct LpErrorDetails(ObjectSubclass) + @extends adw::Dialog, gtk::Widget; +} + +impl LpErrorDetails { + pub fn new(root: &impl IsA, text: &str) -> Self { + let obj = glib::Object::new::(); + let imp = obj.imp(); + imp.message.buffer().set_text(text); + + imp.copy + .connect_clicked(glib::clone!(@weak obj => move |_| { + let buffer = obj.imp().message.buffer(); + let (start, end) = buffer.bounds(); + obj.display() + .clipboard() + .set_text(buffer.text(&start, &end, true).as_str()) + })); + + imp.report + .connect_clicked(glib::clone!(@weak obj => move |_| { + gtk::UriLauncher::new("https://gitlab.gnome.org/sophie-h/glycin/-/issues").launch( + obj.root().and_downcast_ref::(), + gio::Cancellable::NONE, + |_| {}, + ); + })); + + obj.present(root); + obj + } +} diff --git a/src/widgets/error_details.ui b/src/widgets/error_details.ui new file mode 100644 index 0000000..499ea44 --- /dev/null +++ b/src/widgets/error_details.ui @@ -0,0 +1,65 @@ + + + + diff --git a/src/widgets/image_page.rs b/src/widgets/image_page.rs index 5a700ce..98e68ff 100644 --- a/src/widgets/image_page.rs +++ b/src/widgets/image_page.rs @@ -26,7 +26,9 @@ use glib::{clone, Properties}; use gtk::prelude::*; use gtk::CompositeTemplate; +use super::LpErrorDetails; use crate::deps::*; +use crate::util::gettext::*; use crate::widgets::LpImage; mod imp { @@ -40,8 +42,12 @@ mod imp { pub(super) stack: TemplateChild, #[template_child] pub(super) spinner_page: TemplateChild, + #[template_child] pub(super) error_page: TemplateChild, + #[template_child] + pub(super) error_more_info: TemplateChild, + #[template_child] pub(super) image_stack_page: TemplateChild, #[template_child] @@ -122,9 +128,7 @@ mod imp { obj.image() .connect_error_notify(clone!(@weak obj => move |_| { - if obj.image().error().is_some() { - obj.imp().stack.set_visible_child(&*obj.imp().error_page); - } + glib::spawn_future_local(async move { obj.show_error().await }); })); // Do not waste CPU on spinner if it is not visible @@ -183,4 +187,50 @@ impl LpImagePage { imp.popover.set_pointing_to(Some(&rect)); imp.popover.popup(); } + + pub async fn show_error(&self) { + let imp = self.imp(); + let image = self.image(); + + if image.is_unsupported() { + let message = if glycin::supported_mime_types().await.len() == 0 { + // Translators: {} is replace with a version number + gettext_f( + "No image loaders available. Mabye the “glycin-loaders” package with compatibility version “{}+” is not installed.", + [ format!("{}+", glycin::COMPAT_VERSION.to_string())]) + } else { + let mime_type = image.metadata().mime_type().unwrap_or_default(); + let content_type = gio::content_type_from_mime_type(&mime_type).unwrap_or_default(); + let description = gio::content_type_get_description(&content_type).to_string(); + + if glycin::DEFAULT_MIME_TYPES.contains(&mime_type.as_str()) { + // Translators: The first occurance of {} is replace with a description of the + // format and the second with an id (mime-type) of the format. + gettext_f( + "The image format “{} ({})” is known but not installed.", + [&description, &mime_type], + ) + } else { + // Translators: The first occurance of {} is replace with a description of the + // format and the second with an id (mime-type) of the format. + gettext_f( + "Unknown image format “{} ({}).”", + [&description, &mime_type], + ) + } + }; + + imp.error_page.set_description(Some(&message)); + } else if let Some(err) = image.error() { + imp.error_more_info + .connect_clicked(glib::clone!(@weak self as obj => move |_| { + LpErrorDetails::new(&obj.root().unwrap(), &err); + })); + + imp.error_page.set_description(Some(&gettext( + "Either the image file is corrupted or it contains unsupported elements.", + ))); + } + imp.stack.set_visible_child(&*imp.error_page); + } } diff --git a/src/widgets/image_page.ui b/src/widgets/image_page.ui index 4030005..90f0036 100644 --- a/src/widgets/image_page.ui +++ b/src/widgets/image_page.ui @@ -61,7 +61,15 @@ image-missing-symbolic Could not Load Image - + + + More Information… + center + + + @@ -118,4 +126,4 @@ - \ No newline at end of file + diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs index ac8a493..affcffd 100644 --- a/src/widgets/mod.rs +++ b/src/widgets/mod.rs @@ -18,6 +18,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later mod drag_overlay; +mod error_details; mod image; mod image_page; mod image_view; @@ -28,6 +29,7 @@ mod shy_bin; mod sliding_view; pub use drag_overlay::LpDragOverlay; +pub use error_details::LpErrorDetails; pub use image::LpImage; pub use image_page::LpImagePage; pub use image_view::LpImageView;