diff options
| -rw-r--r-- | Cargo.lock | 218 | ||||
| -rw-r--r-- | src/dialogs.rs | 118 | ||||
| -rw-r--r-- | src/error.rs | 7 | ||||
| -rw-r--r-- | src/main.rs | 189 | ||||
| -rw-r--r-- | src/types.rs | 23 |
5 files changed, 323 insertions, 232 deletions
@@ -322,9 +322,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +checksum = "cde3f4e40e6021d7acffc90095cbd6dc54cb593903d1de5832f435eb274b85dc" dependencies = [ "async-channel 2.3.1", "async-io", @@ -335,7 +335,7 @@ dependencies = [ "cfg-if", "event-listener 5.4.0", "futures-lite", - "rustix 0.38.44", + "rustix 1.0.7", "tracing", ] @@ -352,9 +352,9 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +checksum = "d7605a4e50d4b06df3898d5a70bf5fde51ed9059b0434b73105193bc27acce0d" dependencies = [ "async-io", "async-lock", @@ -362,7 +362,7 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 0.38.44", + "rustix 1.0.7", "signal-hook-registry", "slab", "windows-sys 0.59.0", @@ -587,9 +587,9 @@ checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "bytemuck" @@ -676,15 +676,15 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" [[package]] name = "cc" -version = "1.2.24" +version = "1.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" +checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" dependencies = [ "jobserver", "libc", @@ -821,9 +821,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -855,7 +855,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ "bitflags 2.9.1", - "core-foundation 0.10.0", + "core-foundation 0.10.1", "core-graphics-types 0.2.0", "foreign-types 0.5.0", "libc", @@ -879,7 +879,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ "bitflags 2.9.1", - "core-foundation 0.10.0", + "core-foundation 0.10.1", "libc", ] @@ -1015,7 +1015,7 @@ dependencies = [ "objc2 0.5.2", "objc2-foundation 0.2.2", "web-sys", - "winreg", + "winreg 0.52.0", ] [[package]] @@ -1197,16 +1197,16 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "embed-resource" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbc6e0d8e0c03a655b53ca813f0463d2c956bc4db8138dbc89f120b066551e3" +checksum = "e8fe7d068ca6b3a5782ca5ec9afc244acd99dd441e4686a83b1c3973aba1d489" dependencies = [ "cc", "memchr", "rustc_version", "toml", "vswhom", - "winreg", + "winreg 0.55.0", ] [[package]] @@ -1355,9 +1355,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "miniz_oxide", @@ -1808,9 +1808,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "foldhash", ] @@ -1829,12 +1829,6 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hermit-abi" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" @@ -1922,9 +1916,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.6" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ "http", "hyper", @@ -1954,22 +1948,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9f1e950e0d9d1d3c47184416723cf29c0d1f93bd8cccf37e4beb6b44f31710" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ + "base64", "bytes", "futures-channel", + "futures-core", "futures-util", "http", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -2102,7 +2102,7 @@ dependencies = [ [[package]] name = "iced_dialog" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced_dialog?branch=iced%2Fpersonal#f751cf15df8533882ee9741701f0997df9529a6f" +source = "git+https://github.com/pml68/iced_dialog?branch=iced%2Fpersonal#0f4f9283f733e17facca9299c6e8c0060e1e9cd5" dependencies = [ "iced_core", "iced_widget", @@ -2458,6 +2458,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] name = "itertools" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2599,9 +2609,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", "windows-targets 0.53.0", @@ -2665,9 +2675,9 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -3060,11 +3070,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", ] @@ -3361,9 +3371,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "openssl" -version = "0.10.72" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ "bitflags 2.9.1", "cfg-if", @@ -3393,9 +3403,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.108" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -3472,9 +3482,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -3482,9 +3492,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -3591,7 +3601,7 @@ checksum = "b53a684391ad002dd6a596ceb6c74fd004fdce75f4be2e3f615068abbea5fd50" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi 0.5.1", + "hermit-abi", "pin-project-lite", "rustix 1.0.7", "tracing", @@ -3897,9 +3907,9 @@ dependencies = [ [[package]] name = "read-fonts" -version = "0.29.1" +version = "0.29.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e85935612710191461ec9df47b4b5880dd6359d4fad3b2f2ed696215f6f3146" +checksum = "04ca636dac446b5664bd16c069c00a9621806895b8bb02c2dc68542b23b8f25d" dependencies = [ "bytemuck", "font-types", @@ -3971,9 +3981,9 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119" dependencies = [ "base64", "bytes", @@ -3998,21 +4008,20 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-native-tls", "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows-registry", ] [[package]] @@ -4157,15 +4166,6 @@ dependencies = [ ] [[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - -[[package]] name = "rustls-pki-types" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4340,9 +4340,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -4428,9 +4428,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "skrifa" -version = "0.31.1" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9c3bb8cab5196b98d70c866ce1ea81ab516104d5b396f84ae80f8766b5d5b4e" +checksum = "dbeb4ca4399663735553a09dd17ce7e49a0a0203f03b706b39628c4d913a8607" dependencies = [ "bytemuck", "read-fonts", @@ -4456,9 +4456,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smithay-client-toolkit" @@ -4507,9 +4507,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -4961,9 +4961,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -4973,18 +4973,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", @@ -4996,9 +4996,9 @@ dependencies = [ [[package]] name = "toml_write" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "tower" @@ -5016,6 +5016,24 @@ dependencies = [ ] [[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.9.1", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] name = "tower-layer" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5040,9 +5058,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" dependencies = [ "proc-macro2", "quote", @@ -5051,9 +5069,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", ] @@ -5755,13 +5773,13 @@ checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" [[package]] name = "windows-registry" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" dependencies = [ + "windows-link", "windows-result 0.3.4", - "windows-strings 0.3.1", - "windows-targets 0.53.0", + "windows-strings 0.4.2", ] [[package]] @@ -5794,9 +5812,9 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] @@ -6160,6 +6178,16 @@ dependencies = [ ] [[package]] +name = "winreg" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +dependencies = [ + "cfg-if", + "windows-sys 0.59.0", +] + +[[package]] name = "wit-bindgen-rt" version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6541,9 +6569,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" +checksum = "3e4a518c0ea2576f4da876349d7f67a7be489297cd77c2cf9e04c2e05fcd3974" dependencies = [ "zune-core", ] diff --git a/src/dialogs.rs b/src/dialogs.rs index c1933ec..68bbd6e 100644 --- a/src/dialogs.rs +++ b/src/dialogs.rs @@ -1,47 +1,103 @@ -use iced::Task; +use std::borrow::Cow; + +use iced::widget::text; use iced_dialog::button; use crate::Message; -use crate::types::{DialogAction, DialogButtons, Element}; +use crate::types::Element; -pub const UNSAVED_CHANGES_TITLE: &str = "Unsaved changes"; +pub const UNSAVED_CHANGES_TITLE: &str = "Hold on for a sec!"; pub const WARNING_TITLE: &str = "Heads up!"; pub const ERROR_TITLE: &str = "Oops! Something went wrong."; -pub fn ok_button<'a>() -> Element<'a, Message> { - button("Ok", Message::DialogOk).into() +#[derive(Debug, Clone, Copy, Default)] +pub enum Action { + #[default] + None, + Close, + UnsavedChanges(UnsavedChanges), } -pub fn cancel_button<'a>() -> Element<'a, Message> { - button("Cancel", Message::DialogCancel).into() +#[derive(Debug, Clone, Copy)] +pub enum UnsavedChanges { + New, + Open, + Exit, } -pub fn error_dialog(description: impl Into<String>) -> Task<Message> { - Task::done(Message::OpenDialog( - ERROR_TITLE, - description.into(), - DialogButtons::Ok, - DialogAction::None, - )) +impl From<Action> for Vec<Element<'_, Message>> { + fn from(action: Action) -> Self { + match action { + Action::None => vec![], + Action::Close => vec![button("Close", Message::DialogYes).into()], + Action::UnsavedChanges(_) => vec![ + button("Don't Save", Message::DialogNo).into(), + button("Save", Message::DialogYes).into(), + button("Cancel", Message::DialogCancel).into(), + ], + } + } } -pub fn warning_dialog(description: impl Into<String>) -> Task<Message> { - Task::done(Message::OpenDialog( - WARNING_TITLE, - description.into(), - DialogButtons::Ok, - DialogAction::None, - )) +#[derive(Debug, Default)] +pub struct Dialog { + is_open: bool, + title: Cow<'static, str>, + content: Cow<'static, str>, + action: Action, } -pub fn unsaved_changes_dialog( - description: impl Into<String>, - action: DialogAction, -) -> Task<Message> { - Task::done(Message::OpenDialog( - UNSAVED_CHANGES_TITLE, - description.into(), - DialogButtons::OkCancel, - action, - )) +impl Dialog { + pub fn new( + title: impl Into<Cow<'static, str>>, + content: impl Into<Cow<'static, str>>, + action: Action, + ) -> Self { + Self { + is_open: true, + title: title.into(), + content: content.into(), + action, + } + } + + pub fn error(content: impl Into<Cow<'static, str>>) -> Self { + Self::new(ERROR_TITLE, content, Action::Close) + } + + pub fn warning(content: impl Into<Cow<'static, str>>) -> Self { + Self::new(WARNING_TITLE, content, Action::Close) + } + + pub fn unsaved_changes( + content: impl Into<Cow<'static, str>>, + unsaved_changes: UnsavedChanges, + ) -> Self { + Self::new( + UNSAVED_CHANGES_TITLE, + content, + Action::UnsavedChanges(unsaved_changes), + ) + } + + pub fn close(&mut self) { + self.is_open = false; + } + + pub fn action(&self) -> Action { + self.action + } + + pub fn as_iced_dialog<'a>( + &'a self, + base: impl Into<Element<'a, Message>>, + ) -> iced_dialog::Dialog<'a, Message, material_theme::Theme> { + iced_dialog::Dialog::with_buttons( + self.is_open, + base, + text(&*self.content), + self.action.into(), + ) + .title(&*self.title) + } } diff --git a/src/error.rs b/src/error.rs index 9e1ee9d..c8405f4 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::io; use std::sync::Arc; @@ -57,3 +58,9 @@ impl From<Error> for String { value.to_string() } } + +impl From<Error> for Cow<'static, str> { + fn from(value: Error) -> Self { + value.to_string().into() + } +} diff --git a/src/main.rs b/src/main.rs index 4d8c351..6be8d5c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,25 +15,18 @@ use std::path::PathBuf; use std::sync::Arc; use config::Config; -use dialogs::{ - cancel_button, error_dialog, ok_button, unsaved_changes_dialog, - warning_dialog, -}; +use dialogs::{Action as DialogAction, Dialog, UnsavedChanges}; use error::Error; use iced::advanced::widget::Id; -use iced::widget::{ - Column, container, pane_grid, pick_list, row, text, text_editor, +use iced::widget::{Column, container, pane_grid, pick_list, row, text_editor}; +use iced::{ + Alignment, Length, Subscription, Task, clipboard, keyboard, window, }; -use iced::{Alignment, Length, Task, clipboard, keyboard}; use iced_anim::transition::Easing; use iced_anim::{Animated, Animation}; -use iced_dialog::dialog::Dialog; use material_theme::Theme; use panes::{code_view, designer_view, element_list}; -use types::{ - Action, DesignerPane, DialogAction, DialogButtons, Element, Message, - Project, -}; +use types::{Action, DesignerPane, Element, Message, Project}; fn main() -> Result<(), Box<dyn std::error::Error>> { let version = std::env::args() @@ -54,7 +47,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { ) .title(IcedBuilder::title) .subscription(IcedBuilder::subscription) - .theme(|state| state.theme.value().clone()) + .theme(IcedBuilder::theme) + .exit_on_close_request(false) .font(icon::FONT) .antialiasing(true) .centered() @@ -73,11 +67,7 @@ struct IcedBuilder { pane_state: pane_grid::State<Panes>, focus: Option<pane_grid::Pane>, designer_page: DesignerPane, - dialog_is_open: bool, - dialog_title: &'static str, - dialog_content: String, - dialog_buttons: DialogButtons, - dialog_action: DialogAction, + dialog: Dialog, editor_content: text_editor::Content, } @@ -112,11 +102,7 @@ impl IcedBuilder { pane_state: state, focus: None, designer_page: DesignerPane::DesignerView, - dialog_is_open: false, - dialog_title: "", - dialog_content: String::new(), - dialog_buttons: DialogButtons::None, - dialog_action: DialogAction::None, + dialog: Dialog::default(), editor_content: text_editor::Content::new(), }, Task::perform(Config::load(), Message::ConfigLoad), @@ -143,6 +129,10 @@ impl IcedBuilder { format!("iced Builder{project_name}{saved_state}") } + fn theme(&self) -> Theme { + self.theme.value().clone() + } + fn update(&mut self, message: Message) -> Task<Message> { match message { Message::ConfigLoad(result) => match result { @@ -151,20 +141,20 @@ impl IcedBuilder { self.theme.settle_at(self.config.selected_theme()); if let Some(path) = self.config.last_project() { - return if path.exists() && path.is_file() { - Task::perform( + if path.exists() && path.is_file() { + return Task::perform( Project::from_path(path.to_owned()), Message::FileOpened, - ) + ); } else { - warning_dialog(format!( + self.dialog = Dialog::warning(format!( "The file {} does not exist, or isn't a file.", path.to_string_lossy() - )) + )); }; }; } - Err(error) => return error_dialog(error), + Err(error) => self.dialog = Dialog::error(error), }, Message::SwitchTheme(event) => self.theme.update(event), Message::CopyCode => { @@ -181,7 +171,7 @@ impl IcedBuilder { self.editor_content = text_editor::Content::with_text(&code); } - Err(error) => return error_dialog(error), + Err(error) => self.dialog = Dialog::error(error), }, Message::DropNewElement(name, point, _) => { return iced_drop::zones_on_point( @@ -192,9 +182,6 @@ impl IcedBuilder { ); } Message::HandleNew(name, zones) => { - let refresh_editor_task = - Task::done(Message::RefreshEditorContent); - let ids: Vec<Id> = zones.into_iter().map(|z| z.0).collect(); if !ids.is_empty() { let action = Action::new( @@ -212,12 +199,11 @@ impl IcedBuilder { self.project.element_tree = Some(element.clone()); } Err(error) => { - return error_dialog(error) - .chain(refresh_editor_task); + self.dialog = Dialog::error(error); } _ => {} } - return refresh_editor_task; + return self.update(Message::RefreshEditorContent); } } Message::MoveElement(element, point, _) => { @@ -241,11 +227,11 @@ impl IcedBuilder { action, ); if let Err(error) = result { - return error_dialog(error); + self.dialog = Dialog::error(error); } self.is_dirty = true; - return Task::done(Message::RefreshEditorContent); + return self.update(Message::RefreshEditorContent); } } Message::PaneResized(pane_grid::ResizeEvent { split, ratio }) => { @@ -257,37 +243,53 @@ impl IcedBuilder { target, }) => self.pane_state.drop(pane, target), Message::PaneDragged(_) => {} - Message::OpenDialog(title, content, buttons, action) => { - self.dialog_title = title; - self.dialog_content = content; - self.dialog_buttons = buttons; - self.dialog_action = action; - self.dialog_is_open = true; + Message::CloseDialog => self.dialog.close(), + Message::DialogYes => { + return if matches!( + self.dialog.action(), + DialogAction::UnsavedChanges(_) + ) { + self.is_loading = true; + Task::perform( + self.project + .clone() + .write_to_file(self.project_path.clone()), + Message::FileSaved, + ) + .chain(Task::done(Message::DialogNo)) + } else { + self.update(Message::CloseDialog) + }; } - Message::CloseDialog => self.dialog_is_open = false, - Message::DialogOk => { - let close_dialog_task = Task::done(Message::CloseDialog); - - match self.dialog_action { - DialogAction::None => {} - DialogAction::NewFile => { - self.is_dirty = false; - self.project = Project::new(); - self.project_path = None; - self.editor_content = text_editor::Content::new(); - } - DialogAction::OpenFile => { - self.is_dirty = false; - self.is_loading = true; - return Task::perform( - Project::from_file(), - Message::FileOpened, - ) - .chain(close_dialog_task); + Message::DialogNo => { + let mut task = Task::done(Message::CloseDialog); + + if let DialogAction::UnsavedChanges(unsaved_changes) = + self.dialog.action() + { + match unsaved_changes { + UnsavedChanges::New => { + self.is_dirty = false; + self.project = Project::new(); + self.project_path = None; + self.editor_content = text_editor::Content::new(); + } + UnsavedChanges::Open => { + self.is_dirty = false; + self.is_loading = true; + task = Task::perform( + Project::from_file(), + Message::FileOpened, + ) + .chain(task); + } + UnsavedChanges::Exit => { + return self.update(Message::CloseApp); + } } } - return close_dialog_task; + return task; } Message::DialogCancel => return Task::done(Message::CloseDialog), Message::NewFile => { @@ -297,9 +299,9 @@ impl IcedBuilder { self.project_path = None; self.editor_content = text_editor::Content::new(); } else { - return unsaved_changes_dialog( - "You have unsaved changes. Do you wish to discard these and create a new project?", - DialogAction::NewFile, + self.dialog = Dialog::unsaved_changes( + "You have unsaved changes. Do you want to save them before creating a new project?", + UnsavedChanges::New, ); } } @@ -314,9 +316,9 @@ impl IcedBuilder { Message::FileOpened, ); } else { - return unsaved_changes_dialog( - "You have unsaved changes. Do you wish to discard these and open another project?", - DialogAction::OpenFile, + self.dialog = Dialog::unsaved_changes( + "You have unsaved changes. Do you want to save them before opening another project?", + UnsavedChanges::Open, ); } } @@ -325,13 +327,13 @@ impl IcedBuilder { self.is_loading = false; self.is_dirty = false; - return match result { + match result { Ok((path, project)) => { self.project = project; self.project_path = Some(path); - Task::done(Message::RefreshEditorContent) + return self.update(Message::RefreshEditorContent); } - Err(error) => return error_dialog(error), + Err(error) => self.dialog = Dialog::error(error), }; } Message::SaveFile => { @@ -364,16 +366,30 @@ impl IcedBuilder { self.project_path = Some(path); self.is_dirty = false; } - Err(error) => return error_dialog(error), + Err(error) => self.dialog = Dialog::error(error), + } + } + Message::CloseApp => { + return window::get_latest().and_then(window::close); + } + Message::WindowEvent(window::Event::CloseRequested) => { + if self.is_dirty { + self.dialog = Dialog::unsaved_changes( + "You have unsaved changes. Do you want to save them before closing iced Builder?", + UnsavedChanges::Exit, + ); + } else { + return self.update(Message::CloseApp); } } + Message::WindowEvent(_) => {} } Task::none() } fn subscription(&self) -> iced::Subscription<Message> { - keyboard::on_key_press(|key, modifiers| { + let keyboard = keyboard::on_key_press(|key, modifiers| { if modifiers.command() { match key.as_ref() { keyboard::Key::Character("o") => Some(Message::OpenFile), @@ -390,7 +406,12 @@ impl IcedBuilder { } else { None } - }) + }); + + let window_events = + window::events().map(|(_id, event)| Message::WindowEvent(event)); + + Subscription::batch([keyboard, window_events]) } fn view(&self) -> Element<'_, Message> { @@ -433,17 +454,9 @@ impl IcedBuilder { .align_x(Alignment::Center) .width(Length::Fill); - let content = Dialog::with_buttons( - self.dialog_is_open, - container(base).height(Length::Fill), - text(&self.dialog_content), - match self.dialog_buttons { - DialogButtons::None => vec![], - DialogButtons::Ok => vec![ok_button()], - DialogButtons::OkCancel => vec![ok_button(), cancel_button()], - }, - ) - .title(self.dialog_title); + let content = self + .dialog + .as_iced_dialog(container(base).height(Length::Fill)); Animation::new(&self.theme, content) .on_update(Message::SwitchTheme) diff --git a/src/types.rs b/src/types.rs index 608f285..ef6d5c3 100644 --- a/src/types.rs +++ b/src/types.rs @@ -7,6 +7,7 @@ use std::path::PathBuf; pub use element_name::ElementName; use iced::advanced::widget::Id; use iced::widget::{pane_grid, text_editor}; +use iced::window; use iced_anim::Event; use material_theme::Theme; pub use project::Project; @@ -33,9 +34,9 @@ pub enum Message { PaneResized(pane_grid::ResizeEvent), PaneClicked(pane_grid::Pane), PaneDragged(pane_grid::DragEvent), - OpenDialog(&'static str, String, DialogButtons, DialogAction), CloseDialog, - DialogOk, + DialogYes, + DialogNo, DialogCancel, NewFile, OpenFile, @@ -43,22 +44,8 @@ pub enum Message { SaveFile, SaveFileAs, FileSaved(Result<PathBuf, Error>), -} - -#[derive(Debug, Clone, Copy, Default)] -pub enum DialogButtons { - #[default] - None, - Ok, - OkCancel, -} - -#[derive(Debug, Clone, Copy, Default)] -pub enum DialogAction { - #[default] - None, - NewFile, - OpenFile, + CloseApp, + WindowEvent(window::Event), } #[derive(Debug, Clone, Copy)] |
