feat: add graphical interface with relm4 and libadw

This commit is contained in:
uku 2025-05-09 22:35:00 +02:00
parent 837ce3ab3e
commit 601ee85b5f
Signed by: uku
SSH key fingerprint: SHA256:4P0aN6M8ajKukNi6aPOaX0LacanGYtlfjmN+m/sHY/o
6 changed files with 850 additions and 29 deletions

572
Cargo.lock generated
View file

@ -78,14 +78,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]] [[package]]
name = "cc" name = "cairo-rs"
version = "1.2.21" version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" checksum = "ae50b5510d86cf96ac2370e66d8dc960882f3df179d6a5a1e52bd94a1416c0f7"
dependencies = [
"bitflags",
"cairo-sys-rs",
"glib",
"libc",
]
[[package]]
name = "cairo-sys-rs"
version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f18b6bb8e43c7eb0f2aac7976afe0c61b6f5fc2ab7bc4c139537ea56c92290df"
dependencies = [
"glib-sys",
"libc",
"system-deps",
]
[[package]]
name = "cc"
version = "1.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1"
dependencies = [ dependencies = [
"shlex", "shlex",
] ]
[[package]]
name = "cfg-expr"
version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d4ba6e40bd1184518716a6e1a781bf9160e286d219ccdb8ab2612e74cfe4789"
dependencies = [
"smallvec",
"target-lexicon",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@ -182,6 +215,28 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "field-offset"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f"
dependencies = [
"memoffset",
"rustc_version",
]
[[package]]
name = "flume"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
dependencies = [
"futures-core",
"futures-sink",
"nanorand",
"spin",
]
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@ -197,6 +252,27 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "fragile"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619"
[[package]]
name = "futures"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.31" version = "0.3.31"
@ -213,12 +289,34 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-executor"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.31" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-macro"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.31" version = "0.3.31"
@ -237,8 +335,10 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [ dependencies = [
"futures-channel",
"futures-core", "futures-core",
"futures-io", "futures-io",
"futures-macro",
"futures-sink", "futures-sink",
"futures-task", "futures-task",
"memchr", "memchr",
@ -247,6 +347,63 @@ dependencies = [
"slab", "slab",
] ]
[[package]]
name = "gdk-pixbuf"
version = "0.20.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7563afd6ff0a221edfbb70a78add5075b8d9cb48e637a40a24c3ece3fea414d0"
dependencies = [
"gdk-pixbuf-sys",
"gio",
"glib",
"libc",
]
[[package]]
name = "gdk-pixbuf-sys"
version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67f2587c9202bf997476bbba6aaed4f78a11538a2567df002a5f57f5331d0b5c"
dependencies = [
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[package]]
name = "gdk4"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4850c9d9c1aecd1a3eb14fadc1cdb0ac0a2298037e116264c7473e1740a32d60"
dependencies = [
"cairo-rs",
"gdk-pixbuf",
"gdk4-sys",
"gio",
"glib",
"libc",
"pango",
]
[[package]]
name = "gdk4-sys"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f6eb95798e2b46f279cf59005daf297d5b69555428f185650d71974a910473a"
dependencies = [
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"pango-sys",
"pkg-config",
"system-deps",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.16" version = "0.2.16"
@ -262,9 +419,9 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.3.2" version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys", "js-sys",
@ -280,6 +437,197 @@ version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "gio"
version = "0.20.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4f00c70f8029d84ea7572dd0e1aaa79e5329667b4c17f329d79ffb1e6277487"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-util",
"gio-sys",
"glib",
"libc",
"pin-project-lite",
"smallvec",
]
[[package]]
name = "gio-sys"
version = "0.20.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "160eb5250a26998c3e1b54e6a3d4ea15c6c7762a6062a19a7b63eff6e2b33f9e"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
"windows-sys 0.59.0",
]
[[package]]
name = "glib"
version = "0.20.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707b819af8059ee5395a2de9f2317d87a53dbad8846a2f089f0bb44703f37686"
dependencies = [
"bitflags",
"futures-channel",
"futures-core",
"futures-executor",
"futures-task",
"futures-util",
"gio-sys",
"glib-macros",
"glib-sys",
"gobject-sys",
"libc",
"memchr",
"smallvec",
]
[[package]]
name = "glib-macros"
version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "715601f8f02e71baef9c1f94a657a9a77c192aea6097cf9ae7e5e177cd8cde68"
dependencies = [
"heck",
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "glib-sys"
version = "0.20.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8928869a44cfdd1fccb17d6746e4ff82c8f82e41ce705aa026a52ca8dc3aefb"
dependencies = [
"libc",
"system-deps",
]
[[package]]
name = "gobject-sys"
version = "0.20.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c773a3cb38a419ad9c26c81d177d96b4b08980e8bdbbf32dace883e96e96e7e3"
dependencies = [
"glib-sys",
"libc",
"system-deps",
]
[[package]]
name = "graphene-rs"
version = "0.20.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cbc5911bfb32d68dcfa92c9510c462696c2f715548fcd7f3f1be424c739de19"
dependencies = [
"glib",
"graphene-sys",
"libc",
]
[[package]]
name = "graphene-sys"
version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11a68d39515bf340e879b72cecd4a25c1332557757ada6e8aba8654b4b81d23a"
dependencies = [
"glib-sys",
"libc",
"pkg-config",
"system-deps",
]
[[package]]
name = "gsk4"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61f5e72f931c8c9f65fbfc89fe0ddc7746f147f822f127a53a9854666ac1f855"
dependencies = [
"cairo-rs",
"gdk4",
"glib",
"graphene-rs",
"gsk4-sys",
"libc",
"pango",
]
[[package]]
name = "gsk4-sys"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "755059de55fa6f85a46bde8caf03e2184c96bfda1f6206163c72fb0ea12436dc"
dependencies = [
"cairo-sys-rs",
"gdk4-sys",
"glib-sys",
"gobject-sys",
"graphene-sys",
"libc",
"pango-sys",
"system-deps",
]
[[package]]
name = "gtk4"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af1c491051f030994fd0cde6f3c44f3f5640210308cff1298c7673c47408091d"
dependencies = [
"cairo-rs",
"field-offset",
"futures-channel",
"gdk-pixbuf",
"gdk4",
"gio",
"glib",
"graphene-rs",
"gsk4",
"gtk4-macros",
"gtk4-sys",
"libc",
"pango",
]
[[package]]
name = "gtk4-macros"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ed1786c4703dd196baf7e103525ce0cf579b3a63a0570fe653b7ee6bac33999"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "gtk4-sys"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41e03b01e54d77c310e1d98647d73f996d04b2f29b9121fe493ea525a7ec03d6"
dependencies = [
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gdk4-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"graphene-sys",
"gsk4-sys",
"libc",
"pango-sys",
"system-deps",
]
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.4.10" version = "0.4.10"
@ -305,6 +653,12 @@ version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "http" name = "http"
version = "1.3.1" version = "1.3.1"
@ -554,6 +908,37 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libadwaita"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "500135d29c16aabf67baafd3e7741d48e8b8978ca98bac39e589165c8dc78191"
dependencies = [
"gdk4",
"gio",
"glib",
"gtk4",
"libadwaita-sys",
"libc",
"pango",
]
[[package]]
name = "libadwaita-sys"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6680988058c2558baf3f548a370e4e78da3bf7f08469daa822ac414842c912db"
dependencies = [
"gdk4-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"gtk4-sys",
"libc",
"pango-sys",
"system-deps",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.172" version = "0.2.172"
@ -576,12 +961,28 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.27" version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "lru-slab"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
[[package]] [[package]]
name = "matchers" name = "matchers"
version = "0.1.0" version = "0.1.0"
@ -597,6 +998,15 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "memoffset"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "mime" name = "mime"
version = "0.3.17" version = "0.3.17"
@ -633,6 +1043,15 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "nanorand"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
dependencies = [
"getrandom 0.2.16",
]
[[package]] [[package]]
name = "nu-ansi-term" name = "nu-ansi-term"
version = "0.46.0" version = "0.46.0"
@ -676,6 +1095,30 @@ version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564"
[[package]]
name = "pango"
version = "0.20.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b1f5dc1b8cf9bc08bfc0843a04ee0fa2e78f1e1fa4b126844a383af4f25f0ec"
dependencies = [
"gio",
"glib",
"libc",
"pango-sys",
]
[[package]]
name = "pango-sys"
version = "0.20.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dbb9b751673bd8fe49eb78620547973a1e719ed431372122b20abd12445bab5"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.3.1" version = "2.3.1"
@ -694,6 +1137,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]] [[package]]
name = "potential_utf" name = "potential_utf"
version = "0.1.2" version = "0.1.2"
@ -712,6 +1161,15 @@ dependencies = [
"zerocopy", "zerocopy",
] ]
[[package]]
name = "proc-macro-crate"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35"
dependencies = [
"toml_edit",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.95" version = "1.0.95"
@ -723,9 +1181,9 @@ dependencies = [
[[package]] [[package]]
name = "quinn" name = "quinn"
version = "0.11.7" version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8"
dependencies = [ dependencies = [
"bytes", "bytes",
"cfg_aliases", "cfg_aliases",
@ -743,12 +1201,13 @@ dependencies = [
[[package]] [[package]]
name = "quinn-proto" name = "quinn-proto"
version = "0.11.11" version = "0.11.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcbafbbdbb0f638fe3f35f3c56739f77a8a1d070cb25603226c83339b391472b" checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e"
dependencies = [ dependencies = [
"bytes", "bytes",
"getrandom 0.3.2", "getrandom 0.3.3",
"lru-slab",
"rand", "rand",
"ring", "ring",
"rustc-hash", "rustc-hash",
@ -816,7 +1275,7 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [ dependencies = [
"getrandom 0.3.2", "getrandom 0.3.3",
] ]
[[package]] [[package]]
@ -874,6 +1333,41 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "relm4"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30837553c1a8cfea1a404c83ec387c5c8ff9358e1060b057c274c5daa5035ad1"
dependencies = [
"flume",
"fragile",
"futures",
"gtk4",
"libadwaita",
"once_cell",
"relm4-css",
"relm4-macros",
"tokio",
"tracing",
]
[[package]]
name = "relm4-css"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d3b924557df1cddc687b60b313c4b76620fdbf0e463afa4b29f67193ccf37f9"
[[package]]
name = "relm4-macros"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a895a7455441a857d100ca679bd24a92f91d28b5e3df63296792ac1af2eddde"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.12.15" version = "0.12.15"
@ -947,6 +1441,15 @@ version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.23.27" version = "0.23.27"
@ -1003,6 +1506,18 @@ version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.219" version = "1.0.219"
@ -1096,6 +1611,15 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"lock_api",
]
[[package]] [[package]]
name = "stable_deref_trait" name = "stable_deref_trait"
version = "1.2.0" version = "1.2.0"
@ -1139,6 +1663,25 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "system-deps"
version = "7.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66d23aaf9f331227789a99e8de4c91bf46703add012bdfd45fdecdfb2975a005"
dependencies = [
"cfg-expr",
"heck",
"pkg-config",
"toml",
"version-compare",
]
[[package]]
name = "target-lexicon"
version = "0.12.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "2.0.12" version = "2.0.12"
@ -1383,6 +1926,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"color-eyre", "color-eyre",
"dirs", "dirs",
"relm4",
"reqwest", "reqwest",
"serde", "serde",
"toml", "toml",
@ -1438,6 +1982,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
name = "version-compare"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
[[package]] [[package]]
name = "want" name = "want"
version = "0.3.1" version = "0.3.1"

View file

@ -6,6 +6,7 @@ edition = "2024"
[dependencies] [dependencies]
color-eyre = "0.6.4" color-eyre = "0.6.4"
dirs = "6.0.0" dirs = "6.0.0"
relm4 = { version = "0.9.1", features = ["gnome_47", "libadwaita"] }
reqwest = { version = "0.12.15", default-features = false, features = ["http2", "charset", "rustls-tls", "blocking", "json", "multipart"] } reqwest = { version = "0.12.15", default-features = false, features = ["http2", "charset", "rustls-tls", "blocking", "json", "multipart"] }
serde = { version = "1.0.219", features = ["derive"] } serde = { version = "1.0.219", features = ["derive"] }
toml = "0.8.22" toml = "0.8.22"

View file

@ -3,6 +3,9 @@
lib, lib,
craneLib, craneLib,
mold-wrapped, mold-wrapped,
libadwaita,
pkg-config,
wrapGAppsHook4,
}: }:
let let
cargoToml = lib.importTOML ./Cargo.toml; cargoToml = lib.importTOML ./Cargo.toml;
@ -14,7 +17,13 @@ craneLib.buildPackage {
src = craneLib.cleanCargoSource ./.; src = craneLib.cleanCargoSource ./.;
nativeBuildInputs = [ mold-wrapped ]; nativeBuildInputs = [
mold-wrapped
pkg-config
wrapGAppsHook4
];
buildInputs = [ libadwaita ];
RUSTFLAGS = "-C link-arg=-fuse-ld=mold"; RUSTFLAGS = "-C link-arg=-fuse-ld=mold";

80
src/gobject.rs Normal file
View file

@ -0,0 +1,80 @@
use std::{cell::Cell, sync::LazyLock};
use relm4::{
adw::subclass::prelude::ObjectSubclassType,
gtk::{
glib::{self, ParamSpecString, Type, object::ObjectExt, value::ToValue},
subclass::prelude::{ObjectImpl, ObjectSubclass},
},
};
use crate::zipline::ZiplineFolder;
glib::wrapper! {
pub struct GtkZiplineFolder(ObjectSubclass<GtkZiplineFolderImpl>);
}
impl GtkZiplineFolder {
pub fn r#type() -> Type {
GtkZiplineFolderImpl::type_()
}
pub fn from_folder(folder: &ZiplineFolder) -> Self {
glib::Object::builder()
.property("id", folder.id.clone())
.property("name", folder.name.clone())
.build()
}
pub fn as_folder(&self) -> ZiplineFolder {
ZiplineFolder {
id: self.property("id"),
name: self.property("name"),
}
}
}
#[derive(Default)]
pub struct GtkZiplineFolderImpl {
id: Cell<String>,
name: Cell<String>,
}
#[glib::object_subclass]
impl ObjectSubclass for GtkZiplineFolderImpl {
const NAME: &str = "TyrolienneZiplineFolder";
type Type = GtkZiplineFolder;
}
impl ObjectImpl for GtkZiplineFolderImpl {
fn properties() -> &'static [glib::ParamSpec] {
static PARAMS: LazyLock<[glib::ParamSpec; 2]> = LazyLock::new(|| {
[
ParamSpecString::builder("id").build(),
ParamSpecString::builder("name").build(),
]
});
PARAMS.as_ref()
}
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
let value = value.get().unwrap();
match pspec.name() {
"id" => self.id.replace(value),
"name" => self.name.replace(value),
_ => unreachable!(),
};
}
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
unsafe {
match pspec.name() {
"id" => (*self.id.as_ptr()).to_value(),
"name" => (*self.name.as_ptr()).to_value(),
_ => unreachable!(),
}
}
}
}

View file

@ -1,11 +1,19 @@
mod gobject;
mod zipline; mod zipline;
use std::{path::Path, time::Duration}; use std::{borrow::Cow, path::PathBuf, time::Duration};
use color_eyre::eyre::{OptionExt, Result, bail}; use color_eyre::eyre::{OptionExt, Result, bail};
use gobject::GtkZiplineFolder;
use relm4::{
ComponentParts, RelmApp, SimpleComponent,
adw::{self, prelude::*},
gtk::{self, gio, glib::clone},
};
use tracing::Level; use tracing::Level;
use tracing_subscriber::EnvFilter; use tracing_subscriber::EnvFilter;
use urlencoding::encode; use urlencoding::Encoded;
use zipline::ZiplineFolder;
#[derive(Debug, Default, serde::Deserialize, serde::Serialize)] #[derive(Debug, Default, serde::Deserialize, serde::Serialize)]
struct Config { struct Config {
@ -27,6 +35,172 @@ impl Config {
} }
} }
#[derive(Debug)]
enum Message {
SetPath(PathBuf),
SetFolder(ZiplineFolder),
StartTheProcess,
}
struct Widgets {
file_picker_row: adw::ActionRow,
send_button: gtk::Button,
}
struct Tyrolienne {
config: Config,
video_path: Option<PathBuf>,
folder: ZiplineFolder,
}
impl Tyrolienne {
fn display_video_path(&self) -> Cow<'_, str> {
self.video_path
.as_ref()
.map(|p| p.to_string_lossy())
.unwrap_or(Cow::Borrowed("None"))
}
}
impl SimpleComponent for Tyrolienne {
type Input = Message;
type Output = ();
type Init = (Config, Vec<ZiplineFolder>);
type Root = adw::ApplicationWindow;
type Widgets = Widgets;
fn init_root() -> Self::Root {
adw::ApplicationWindow::builder()
.title("Tyrolienne")
.default_width(500)
.build()
}
fn init(
(config, folders): Self::Init,
root: Self::Root,
sender: relm4::ComponentSender<Self>,
) -> relm4::ComponentParts<Self> {
let model = Tyrolienne {
config,
video_path: None,
folder: folders[0].clone(),
};
let file_picker_row = adw::ActionRow::builder()
.activatable(true)
.title("Video file")
.subtitle(model.display_video_path())
.css_classes(["property"])
.build();
file_picker_row.connect_activated(clone!(
#[strong]
sender,
#[strong]
root,
move |_| {
let file_dialog = gtk::FileDialog::new();
file_dialog.open(
Some(&root),
gio::Cancellable::NONE,
clone!(
#[strong]
sender,
move |file| {
if let Some(path) = file.ok().and_then(|f| f.path()) {
sender.input(Message::SetPath(path));
}
}
),
);
}
));
let gtk_folders = folders
.iter()
.map(GtkZiplineFolder::from_folder)
.collect::<Vec<_>>();
let store = gio::ListStore::new::<GtkZiplineFolder>();
store.extend_from_slice(&gtk_folders);
let folder_row = adw::ComboRow::builder()
.title("Folder")
.model(&store)
.expression(gtk::PropertyExpression::new(
GtkZiplineFolder::r#type(),
None::<&gtk::Expression>,
"name",
))
.build();
folder_row.connect_activated(clone!(
#[strong]
sender,
move |r| {
if let Some(item) = r
.selected_item()
.and_then(|i| i.downcast::<GtkZiplineFolder>().ok())
{
sender.input(Message::SetFolder(item.as_folder()));
}
}
));
let send_button = gtk::Button::builder()
.label("Send")
.sensitive(false)
.margin_start(32)
.margin_end(32)
.margin_bottom(32)
.build();
send_button.connect_clicked(clone!(
#[strong]
sender,
move |_| sender.input(Message::StartTheProcess)
));
let list = gtk::ListBox::builder()
.margin_top(32)
.margin_end(32)
.margin_bottom(32)
.margin_start(32)
.selection_mode(gtk::SelectionMode::None)
.css_classes(["boxed-list"])
.build();
list.append(&file_picker_row);
list.append(&folder_row);
let root_box = gtk::Box::new(gtk::Orientation::Vertical, 0);
root_box.append(&adw::HeaderBar::new());
root_box.append(&list);
root_box.append(&send_button);
root.set_content(Some(&root_box));
let widgets = Widgets {
file_picker_row,
send_button,
};
ComponentParts { model, widgets }
}
fn update(&mut self, message: Self::Input, _sender: relm4::ComponentSender<Self>) {
match message {
Message::SetPath(path) => self.video_path = Some(path),
Message::SetFolder(folder) => self.folder = folder,
Message::StartTheProcess => the_process(self).unwrap(),
}
}
fn update_view(&self, widgets: &mut Self::Widgets, _sender: relm4::ComponentSender<Self>) {
widgets
.file_picker_row
.set_subtitle(&self.display_video_path());
widgets.send_button.set_sensitive(self.video_path.is_some());
}
}
fn main() -> Result<()> { fn main() -> Result<()> {
tracing_subscriber::fmt() tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env().add_directive(Level::INFO.into())) .with_env_filter(EnvFilter::from_default_env().add_directive(Level::INFO.into()))
@ -34,6 +208,17 @@ fn main() -> Result<()> {
color_eyre::install()?; color_eyre::install()?;
// TODO: show dialog in case these error
let config = get_config()?;
let folders = zipline::get_folders(&config)?;
let app = RelmApp::new("net.uku3lig.Tyrolienne");
app.run::<Tyrolienne>((config, folders));
Ok(())
}
fn get_config() -> Result<Config> {
let Some(config_dir) = dirs::config_dir() else { let Some(config_dir) = dirs::config_dir() else {
bail!("could not get config dir!"); bail!("could not get config dir!");
}; };
@ -59,37 +244,33 @@ fn main() -> Result<()> {
bail!("zipline url is empty! please set it at {config_file_path:?}"); bail!("zipline url is empty! please set it at {config_file_path:?}");
} }
let args: Vec<String> = std::env::args().collect(); Ok(config)
let file = args.get(1).ok_or_eyre( }
"please specify the path to the file you want to upload as the first command line argument",
)?;
let folders = zipline::get_folders(&config)?; fn the_process(app: &Tyrolienne) -> Result<()> {
let folder = &folders[0]; tracing::info!("uploading to folder '{}'...", app.folder.name);
tracing::info!("uploading to folder '{}'...", folder.name); let res = zipline::upload_file(&app.config, &app.folder, app.video_path.as_ref().unwrap())?;
let res = zipline::upload_file(&config, folder, Path::new(file))?;
let zp_file = &res.files[0]; let zp_file = &res.files[0];
tracing::info!("recalculating thumbnails..."); tracing::info!("recalculating thumbnails...");
zipline::recalc_thumbnails(&config)?; zipline::recalc_thumbnails(&app.config)?;
std::thread::sleep(Duration::from_secs(5)); std::thread::sleep(Duration::from_secs(5));
tracing::info!("fetching thumbnail url..."); tracing::info!("fetching thumbnail url...");
let res = zipline::get_file_details(&config, &zp_file.id)?; let res = zipline::get_file_details(&app.config, &zp_file.id)?;
let thumbnail_url = res let thumbnail_url = res
.thumbnail_url(&config) .thumbnail_url(&app.config)
.ok_or_eyre("could not get thumbnail url")?; .ok_or_eyre("could not get thumbnail url")?;
// TODO get w&h from video // TODO get w&h from video
let autocomp_url = format!( let autocomp_url = format!(
"https://autocompressor.net/av1?v={}&i={}&w=1920&h=1080", "https://autocompressor.net/av1?v={}&i={}&w=1920&h=1080",
encode(&zp_file.url), Encoded(&zp_file.url),
encode(&thumbnail_url) Encoded(&thumbnail_url)
); );
tracing::info!("url: {autocomp_url}"); tracing::info!("url: {autocomp_url}");

View file

@ -9,7 +9,7 @@ use crate::Config;
static CLIENT: LazyLock<Client> = LazyLock::new(Client::new); static CLIENT: LazyLock<Client> = LazyLock::new(Client::new);
#[derive(Debug, serde::Deserialize)] #[derive(Debug, Clone, serde::Deserialize)]
pub struct ZiplineFolder { pub struct ZiplineFolder {
pub id: String, pub id: String,
pub name: String, pub name: String,