diff --git a/Cargo.lock b/Cargo.lock
index e0cc8b6..883e891 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -232,6 +232,12 @@ dependencies = [
"syn",
]
+[[package]]
+name = "doc-comment"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
+
[[package]]
name = "easy-parallel"
version = "3.1.0"
@@ -299,9 +305,9 @@ dependencies = [
[[package]]
name = "futures"
-version = "0.3.19"
+version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4"
+checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e"
dependencies = [
"futures-channel",
"futures-core",
@@ -314,9 +320,9 @@ dependencies = [
[[package]]
name = "futures-channel"
-version = "0.3.19"
+version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
+checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
dependencies = [
"futures-core",
"futures-sink",
@@ -324,15 +330,15 @@ dependencies = [
[[package]]
name = "futures-core"
-version = "0.3.19"
+version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
+checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
[[package]]
name = "futures-executor"
-version = "0.3.19"
+version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a"
+checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6"
dependencies = [
"futures-core",
"futures-task",
@@ -341,9 +347,9 @@ dependencies = [
[[package]]
name = "futures-io"
-version = "0.3.19"
+version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2"
+checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
[[package]]
name = "futures-lite"
@@ -362,9 +368,9 @@ dependencies = [
[[package]]
name = "futures-macro"
-version = "0.3.19"
+version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c"
+checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
dependencies = [
"proc-macro2",
"quote",
@@ -373,21 +379,21 @@ dependencies = [
[[package]]
name = "futures-sink"
-version = "0.3.19"
+version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508"
+checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
[[package]]
name = "futures-task"
-version = "0.3.19"
+version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
+checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
[[package]]
name = "futures-util"
-version = "0.3.19"
+version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
+checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
dependencies = [
"futures-channel",
"futures-core",
@@ -863,14 +869,17 @@ version = "0.1.0"
dependencies = [
"anyhow",
"ashpd",
+ "futures",
"futures-channel",
"gettext-rs",
+ "gio",
"gtk-macros",
"gtk4",
"libadwaita",
"log",
"once_cell",
"pretty_env_logger",
+ "svg_metadata",
]
[[package]]
@@ -1157,6 +1166,15 @@ version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+[[package]]
+name = "roxmltree"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbf7d7b1ea646d380d0e8153158063a6da7efe30ddbf3184042848e3f8a6f671"
+dependencies = [
+ "xmlparser",
+]
+
[[package]]
name = "rustc_version"
version = "0.3.3"
@@ -1249,6 +1267,18 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+[[package]]
+name = "svg_metadata"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d39f36262efe61096a17aa42140b0e44b9189806c3fa71ab3cff123429938eb0"
+dependencies = [
+ "doc-comment",
+ "lazy_static",
+ "regex",
+ "roxmltree",
+]
+
[[package]]
name = "syn"
version = "1.0.83"
@@ -1399,6 +1429,12 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+[[package]]
+name = "xmlparser"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8"
+
[[package]]
name = "zbus"
version = "2.1.1"
diff --git a/Cargo.toml b/Cargo.toml
index f0a26a2..60facf8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,6 +10,8 @@ log = "0.4.11"
once_cell = "1.9.0"
pretty_env_logger = "0.4.0"
futures-channel = "0.3.19"
+futures = "0.3.21"
+svg_metadata = "0.4.2"
[dependencies.ashpd]
version = "0.2.2"
@@ -20,6 +22,11 @@ package = "gtk4"
version = "0.4.4"
features = ["v4_6"]
+[dependencies.gio]
+package = "gio"
+version = "0.15.2"
+features = ["v2_70"]
+
[dependencies.adw]
package = "libadwaita"
version = "0.1.0"
diff --git a/data/gtk/properties_view.ui b/data/gtk/properties_view.ui
new file mode 100644
index 0000000..0dec98b
--- /dev/null
+++ b/data/gtk/properties_view.ui
@@ -0,0 +1,110 @@
+
+
+
+ 255
+
+
+
+
+
diff --git a/data/gtk/window.ui b/data/gtk/window.ui
index b7ba5de..a1eeb1c 100644
--- a/data/gtk/window.ui
+++ b/data/gtk/window.ui
@@ -18,6 +18,12 @@
False
true
false
+
+
+ LpWindow
+ properties_flap
+
+
+
+
+ help-about-symbolic
+
+
-
- status_page
- True
-
-
- Image Viewer
- Click "Open File…" or drag an image here.
+
+ end
+ never
+ True
+
+
+
+ status_page
+ True
-
- center
- Open File…
- win.open
-
+
+ Image Viewer
+ Click "Open File…" or drag an image here.
+
+
+ center
+ Open File…
+ win.open
+
+
+
+
+
+
+
+
+
+
+ copy
-
-
-
-
-
-
- copy
+
+
+
+
+
+
+
-
+
diff --git a/data/loupe.gresource.xml b/data/loupe.gresource.xml
index e321c41..e481948 100644
--- a/data/loupe.gresource.xml
+++ b/data/loupe.gresource.xml
@@ -5,6 +5,8 @@
gtk/window.ui
gtk/image_page.ui
gtk/image_view.ui
+ gtk/properties_view.ui
style.css
+ style-hc.css
diff --git a/data/style-hc.css b/data/style-hc.css
new file mode 100644
index 0000000..5376146
--- /dev/null
+++ b/data/style-hc.css
@@ -0,0 +1,3 @@
+row.property label.title {
+ opacity: 0.9;
+}
diff --git a/data/style.css b/data/style.css
index 702c76d..e9db6f5 100644
--- a/data/style.css
+++ b/data/style.css
@@ -36,4 +36,14 @@ flap.fullscreen-widget dimming, shadow, border, outline {
);
background-size: 20px 20px;
background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
-}
\ No newline at end of file
+}
+
+row.property label.title {
+ opacity: 0.55;
+ font-size: smaller;
+}
+
+row.property label.subtitle {
+ opacity: 1.0;
+ font-size: 11pt;
+}
diff --git a/src/meson.build b/src/meson.build
index 0299cda..11b7671 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -17,6 +17,7 @@ rust_sources = files(
'widgets/image_page.rs',
'widgets/image_view.rs',
'widgets/mod.rs',
+ 'widgets/properties_view.rs',
'application.rs',
'config.rs',
'file_model.rs',
diff --git a/src/util.rs b/src/util.rs
index 9d0a988..df6451b 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -37,6 +37,25 @@ pub fn query_attributes(file: &gio::File, attributes: Vec<&str>) -> anyhow::Resu
.context("Failed to query string")
}
+pub async fn query_attributes_future(
+ file: &gio::File,
+ attributes: Vec<&str>,
+) -> anyhow::Result {
+ let mut attr_str = String::from(*attributes.get(0).context("No attributes")?);
+
+ for attr in &attributes[1..] {
+ write!(attr_str, ",{}", attr)?;
+ }
+
+ file.query_info_future(
+ &attr_str,
+ gio::FileQueryInfoFlags::empty(),
+ glib::Priority::default(),
+ )
+ .await
+ .context("Failed to query attributes")
+}
+
pub fn compare_by_name(file_a: &gio::File, file_b: &gio::File) -> std::cmp::Ordering {
let name_a = get_file_display_name(file_a).unwrap_or_default();
let name_b = get_file_display_name(file_b).unwrap_or_default();
diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs
index 076921a..c491c20 100644
--- a/src/widgets/mod.rs
+++ b/src/widgets/mod.rs
@@ -20,7 +20,9 @@
mod image;
mod image_page;
mod image_view;
+mod properties_view;
pub use image::LpImage;
pub use image_page::LpImagePage;
pub use image_view::LpImageView;
+pub use properties_view::LpPropertiesView;
diff --git a/src/widgets/properties_view.rs b/src/widgets/properties_view.rs
new file mode 100644
index 0000000..551b278
--- /dev/null
+++ b/src/widgets/properties_view.rs
@@ -0,0 +1,388 @@
+// properties_view.rs
+//
+// Copyright $year Christopher Davis
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+use crate::deps::*;
+use crate::util;
+
+use adw::prelude::*;
+use adw::subclass::prelude::*;
+use glib::clone;
+use gtk::subclass::prelude::*;
+use gtk::CompositeTemplate;
+
+use anyhow::Context;
+use ashpd::desktop::open_uri;
+use ashpd::WindowIdentifier;
+use futures::future::{AbortHandle, Abortable};
+use once_cell::sync::Lazy;
+use std::cell::RefCell;
+
+const MB: f64 = 1_000_000.0;
+const KB: f64 = 1_000.0;
+const FALLBACK: &str = "-";
+
+mod imp {
+ use super::*;
+
+ #[derive(Debug, Default, CompositeTemplate)]
+ #[template(resource = "/org/gnome/Loupe/gtk/properties_view.ui")]
+ pub struct LpPropertiesView {
+ pub file: RefCell