Implement AI gallery example 🎉
It displays the most popular daily images of Civitai!
This commit is contained in:
parent
890d852e05
commit
e2c52c9728
8 changed files with 714 additions and 121 deletions
345
Cargo.lock
generated
345
Cargo.lock
generated
|
|
@ -85,7 +85,7 @@ dependencies = [
|
|||
"ndk-context",
|
||||
"ndk-sys 0.6.0+11769913",
|
||||
"num_enum",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -747,7 +747,7 @@ dependencies = [
|
|||
"polling 3.7.4",
|
||||
"rustix 0.38.43",
|
||||
"slab",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -821,7 +821,7 @@ dependencies = [
|
|||
"log",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing-subscriber",
|
||||
"webbrowser",
|
||||
|
|
@ -935,7 +935,7 @@ version = "0.4.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4274ea815e013e0f9f04a2633423e14194e408a0576c943ce3d14ca56c50031c"
|
||||
dependencies = [
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"x11rb",
|
||||
]
|
||||
|
||||
|
|
@ -1053,7 +1053,7 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
"core-foundation 0.9.4",
|
||||
"core-graphics-types 0.1.3",
|
||||
"foreign-types",
|
||||
"foreign-types 0.5.0",
|
||||
"libc",
|
||||
]
|
||||
|
||||
|
|
@ -1066,7 +1066,7 @@ dependencies = [
|
|||
"bitflags 2.8.0",
|
||||
"core-foundation 0.10.0",
|
||||
"core-graphics-types 0.2.0",
|
||||
"foreign-types",
|
||||
"foreign-types 0.5.0",
|
||||
"libc",
|
||||
]
|
||||
|
||||
|
|
@ -1690,6 +1690,15 @@ dependencies = [
|
|||
"ttf-parser 0.21.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.5.0"
|
||||
|
|
@ -1697,7 +1706,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
||||
dependencies = [
|
||||
"foreign-types-macros",
|
||||
"foreign-types-shared",
|
||||
"foreign-types-shared 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1711,6 +1720,12 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.3.1"
|
||||
|
|
@ -1844,6 +1859,18 @@ dependencies = [
|
|||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gallery"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"iced",
|
||||
"image",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "game_of_life"
|
||||
version = "0.1.0"
|
||||
|
|
@ -2076,7 +2103,7 @@ checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd"
|
|||
dependencies = [
|
||||
"log",
|
||||
"presser",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"windows 0.58.0",
|
||||
]
|
||||
|
||||
|
|
@ -2155,6 +2182,25 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"http 1.2.0",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.4.1"
|
||||
|
|
@ -2321,7 +2367,7 @@ dependencies = [
|
|||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"h2 0.3.26",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"httparse",
|
||||
|
|
@ -2344,6 +2390,7 @@ dependencies = [
|
|||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"h2 0.4.7",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.1",
|
||||
"httparse",
|
||||
|
|
@ -2369,7 +2416,22 @@ dependencies = [
|
|||
"tokio",
|
||||
"tokio-rustls 0.26.1",
|
||||
"tower-service",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http-body-util",
|
||||
"hyper 1.5.2",
|
||||
"hyper-util",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2427,7 +2489,7 @@ dependencies = [
|
|||
"iced_widget",
|
||||
"iced_winit",
|
||||
"image",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2445,7 +2507,7 @@ dependencies = [
|
|||
"palette",
|
||||
"rustc-hash 2.1.0",
|
||||
"smol_str",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
|
|
@ -2480,7 +2542,7 @@ dependencies = [
|
|||
"lyon_path",
|
||||
"raw-window-handle 0.6.2",
|
||||
"rustc-hash 2.1.0",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
|
|
@ -2500,7 +2562,7 @@ dependencies = [
|
|||
"iced_tiny_skia",
|
||||
"iced_wgpu",
|
||||
"log",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2511,7 +2573,7 @@ dependencies = [
|
|||
"iced_core",
|
||||
"iced_futures",
|
||||
"raw-window-handle 0.6.2",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2522,7 +2584,7 @@ dependencies = [
|
|||
"iced_runtime",
|
||||
"png",
|
||||
"sha2",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2555,7 +2617,7 @@ dependencies = [
|
|||
"lyon",
|
||||
"resvg",
|
||||
"rustc-hash 2.1.0",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"wgpu",
|
||||
]
|
||||
|
||||
|
|
@ -2571,7 +2633,7 @@ dependencies = [
|
|||
"pulldown-cmark",
|
||||
"qrcode",
|
||||
"rustc-hash 2.1.0",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"unicode-segmentation",
|
||||
"url",
|
||||
]
|
||||
|
|
@ -2586,7 +2648,7 @@ dependencies = [
|
|||
"log",
|
||||
"rustc-hash 2.1.0",
|
||||
"sysinfo",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
|
|
@ -2905,7 +2967,7 @@ dependencies = [
|
|||
"combine",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
|
@ -3277,7 +3339,7 @@ dependencies = [
|
|||
"bitflags 2.8.0",
|
||||
"block",
|
||||
"core-graphics-types 0.1.3",
|
||||
"foreign-types",
|
||||
"foreign-types 0.5.0",
|
||||
"log",
|
||||
"objc",
|
||||
"paste",
|
||||
|
|
@ -3390,10 +3452,27 @@ dependencies = [
|
|||
"rustc-hash 1.1.0",
|
||||
"spirv",
|
||||
"termcolor",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.9.0"
|
||||
|
|
@ -3406,7 +3485,7 @@ dependencies = [
|
|||
"ndk-sys 0.6.0+11769913",
|
||||
"num_enum",
|
||||
"raw-window-handle 0.6.2",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3861,6 +3940,50 @@ dependencies = [
|
|||
"pathdiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5e534d133a060a3c19daec1eb3e98ec6f4685978834f2dbadfe2ec215bab64e"
|
||||
dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
"cfg-if",
|
||||
"foreign-types 0.3.2",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "orbclient"
|
||||
version = "0.3.48"
|
||||
|
|
@ -4378,58 +4501,6 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn"
|
||||
version = "0.11.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"pin-project-lite",
|
||||
"quinn-proto",
|
||||
"quinn-udp",
|
||||
"rustc-hash 2.1.0",
|
||||
"rustls 0.23.21",
|
||||
"socket2 0.5.8",
|
||||
"thiserror 2.0.11",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-proto"
|
||||
version = "0.11.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"getrandom",
|
||||
"rand",
|
||||
"ring",
|
||||
"rustc-hash 2.1.0",
|
||||
"rustls 0.23.21",
|
||||
"rustls-pki-types",
|
||||
"slab",
|
||||
"thiserror 2.0.11",
|
||||
"tinyvec",
|
||||
"tracing",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-udp"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904"
|
||||
dependencies = [
|
||||
"cfg_aliases 0.2.1",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2 0.5.8",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
|
|
@ -4511,7 +4582,7 @@ dependencies = [
|
|||
"rand_chacha",
|
||||
"simd_helpers",
|
||||
"system-deps",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"v_frame",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
|
@ -4608,7 +4679,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
|||
dependencies = [
|
||||
"getrandom",
|
||||
"libredox",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4654,31 +4725,33 @@ checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da"
|
|||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2 0.4.7",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper 1.5.2",
|
||||
"hyper-rustls",
|
||||
"hyper-tls",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
"rustls 0.23.21",
|
||||
"rustls-pemfile",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tokio-rustls 0.26.1",
|
||||
"tokio-native-tls",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-service",
|
||||
|
|
@ -4687,7 +4760,6 @@ dependencies = [
|
|||
"wasm-bindgen-futures",
|
||||
"wasm-streams",
|
||||
"web-sys",
|
||||
"webpki-roots",
|
||||
"windows-registry",
|
||||
]
|
||||
|
||||
|
|
@ -4826,7 +4898,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki",
|
||||
"subtle",
|
||||
|
|
@ -4847,9 +4918,6 @@ name = "rustls-pki-types"
|
|||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37"
|
||||
dependencies = [
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
|
|
@ -4900,6 +4968,15 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
|
|
@ -4942,6 +5019,29 @@ dependencies = [
|
|||
"tiny-skia",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||
dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
"core-foundation 0.9.4",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.1.0"
|
||||
|
|
@ -5151,7 +5251,7 @@ dependencies = [
|
|||
"log",
|
||||
"memmap2",
|
||||
"rustix 0.38.43",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-csd-frame",
|
||||
|
|
@ -5231,7 +5331,7 @@ dependencies = [
|
|||
"core-graphics 0.24.0",
|
||||
"drm",
|
||||
"fastrand 2.3.0",
|
||||
"foreign-types",
|
||||
"foreign-types 0.5.0",
|
||||
"js-sys",
|
||||
"log",
|
||||
"memmap2",
|
||||
|
|
@ -5398,7 +5498,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
|
@ -5427,6 +5527,27 @@ dependencies = [
|
|||
"windows 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
||||
dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
"core-foundation 0.9.4",
|
||||
"system-configuration-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration-sys"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "6.2.2"
|
||||
|
|
@ -5492,16 +5613,7 @@ version = "1.0.69"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.11",
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5515,17 +5627,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.8"
|
||||
|
|
@ -5691,6 +5792,16 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.25.0"
|
||||
|
|
@ -5913,7 +6024,7 @@ dependencies = [
|
|||
"rustls 0.22.4",
|
||||
"rustls-pki-types",
|
||||
"sha1",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"url",
|
||||
"utf-8",
|
||||
]
|
||||
|
|
@ -6112,6 +6223,12 @@ version = "1.10.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "vectorial_text"
|
||||
version = "0.1.0"
|
||||
|
|
@ -6523,7 +6640,7 @@ dependencies = [
|
|||
"raw-window-handle 0.6.2",
|
||||
"rustc-hash 1.1.0",
|
||||
"smallvec",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"wgpu-hal",
|
||||
"wgpu-types",
|
||||
]
|
||||
|
|
@ -6565,7 +6682,7 @@ dependencies = [
|
|||
"renderdoc-sys",
|
||||
"rustc-hash 1.1.0",
|
||||
"smallvec",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
"wgpu-types",
|
||||
|
|
@ -6626,7 +6743,7 @@ dependencies = [
|
|||
"clipboard_wayland",
|
||||
"clipboard_x11",
|
||||
"raw-window-handle 0.6.2",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ window_clipboard = "0.4.1"
|
|||
winit = { git = "https://github.com/iced-rs/winit.git", rev = "11414b6aa45699f038114e61b4ddf5102b2d3b4b" }
|
||||
|
||||
[workspace.lints.rust]
|
||||
rust_2018_idioms = { level = "forbid", priority = -1 }
|
||||
rust_2018_idioms = { level = "deny", priority = -1 }
|
||||
missing_debug_implementations = "deny"
|
||||
missing_docs = "deny"
|
||||
unsafe_code = "deny"
|
||||
|
|
|
|||
|
|
@ -23,5 +23,4 @@ tracing-subscriber = "0.3"
|
|||
|
||||
[dependencies.reqwest]
|
||||
version = "0.12"
|
||||
default-features = false
|
||||
features = ["json", "rustls-tls"]
|
||||
features = ["json"]
|
||||
|
|
|
|||
|
|
@ -11,5 +11,4 @@ iced.features = ["tokio"]
|
|||
|
||||
[dependencies.reqwest]
|
||||
version = "0.12"
|
||||
default-features = false
|
||||
features = ["stream", "rustls-tls"]
|
||||
features = ["stream"]
|
||||
|
|
|
|||
23
examples/gallery/Cargo.toml
Normal file
23
examples/gallery/Cargo.toml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "gallery"
|
||||
version = "0.1.0"
|
||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
iced.workspace = true
|
||||
iced.features = ["tokio", "image", "web-colors", "debug"]
|
||||
|
||||
reqwest.version = "0.12"
|
||||
reqwest.features = ["json"]
|
||||
|
||||
serde.version = "1.0"
|
||||
serde.features = ["derive"]
|
||||
|
||||
bytes.workspace = true
|
||||
image.workspace = true
|
||||
tokio.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
148
examples/gallery/src/civitai.rs
Normal file
148
examples/gallery/src/civitai.rs
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
use bytes::Bytes;
|
||||
use serde::Deserialize;
|
||||
use tokio::task;
|
||||
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Image {
|
||||
pub id: Id,
|
||||
url: String,
|
||||
}
|
||||
|
||||
impl Image {
|
||||
pub async fn list() -> Result<Vec<Self>, Error> {
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Response {
|
||||
items: Vec<Image>,
|
||||
}
|
||||
|
||||
let response: Response = client
|
||||
.get(endpoint("/images"))
|
||||
.query(&[
|
||||
("sort", "Most Reactions"),
|
||||
("period", "Day"),
|
||||
("nsfw", "None"),
|
||||
("limit", "99"),
|
||||
])
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?
|
||||
.json()
|
||||
.await?;
|
||||
|
||||
Ok(response.items)
|
||||
}
|
||||
|
||||
pub async fn download(self, size: Size) -> Result<Rgba, Error> {
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let bytes = client
|
||||
.get(match size {
|
||||
Size::Original => self.url,
|
||||
Size::Thumbnail => self
|
||||
.url
|
||||
.split("/")
|
||||
.map(|part| {
|
||||
if part.starts_with("width=") {
|
||||
"width=640"
|
||||
} else {
|
||||
part
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("/"),
|
||||
})
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?
|
||||
.bytes()
|
||||
.await?;
|
||||
|
||||
let image = task::spawn_blocking(move || {
|
||||
Ok::<_, Error>(
|
||||
image::ImageReader::new(io::Cursor::new(bytes))
|
||||
.with_guessed_format()?
|
||||
.decode()?
|
||||
.to_rgba8(),
|
||||
)
|
||||
})
|
||||
.await??;
|
||||
|
||||
Ok(Rgba {
|
||||
width: image.width(),
|
||||
height: image.height(),
|
||||
pixels: Bytes::from(image.into_raw()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize,
|
||||
)]
|
||||
pub struct Id(u32);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Rgba {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub pixels: Bytes,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Rgba {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Rgba")
|
||||
.field("width", &self.width)
|
||||
.field("height", &self.height)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Size {
|
||||
Original,
|
||||
Thumbnail,
|
||||
}
|
||||
|
||||
fn endpoint(path: &str) -> String {
|
||||
const API_URL: &str = "https://civitai.com/api/v1";
|
||||
|
||||
format!("{API_URL}{path}")
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(dead_code)]
|
||||
pub enum Error {
|
||||
RequestFailed(Arc<reqwest::Error>),
|
||||
IOFailed(Arc<io::Error>),
|
||||
JoinFailed(Arc<task::JoinError>),
|
||||
ImageDecodingFailed(Arc<image::ImageError>),
|
||||
}
|
||||
|
||||
impl From<reqwest::Error> for Error {
|
||||
fn from(error: reqwest::Error) -> Self {
|
||||
Self::RequestFailed(Arc::new(error))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(error: io::Error) -> Self {
|
||||
Self::IOFailed(Arc::new(error))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<task::JoinError> for Error {
|
||||
fn from(error: task::JoinError) -> Self {
|
||||
Self::JoinFailed(Arc::new(error))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<image::ImageError> for Error {
|
||||
fn from(error: image::ImageError) -> Self {
|
||||
Self::ImageDecodingFailed(Arc::new(error))
|
||||
}
|
||||
}
|
||||
308
examples/gallery/src/main.rs
Normal file
308
examples/gallery/src/main.rs
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
//! A simple gallery that displays the daily featured images of Civitai.
|
||||
//!
|
||||
//! Showcases lazy loading of images in the background, as well as
|
||||
//! some smooth animations.
|
||||
mod civitai;
|
||||
|
||||
use crate::civitai::{Error, Id, Image, Rgba, Size};
|
||||
|
||||
use iced::animation;
|
||||
use iced::time::Instant;
|
||||
use iced::widget::{
|
||||
button, center_x, container, horizontal_space, image, mouse_area, opaque,
|
||||
pop, row, scrollable, stack,
|
||||
};
|
||||
use iced::window;
|
||||
use iced::{
|
||||
color, Animation, ContentFit, Element, Fill, Subscription, Task, Theme,
|
||||
};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn main() -> iced::Result {
|
||||
iced::application("Gallery - Iced", Gallery::update, Gallery::view)
|
||||
.subscription(Gallery::subscription)
|
||||
.theme(Gallery::theme)
|
||||
.run_with(Gallery::new)
|
||||
}
|
||||
|
||||
struct Gallery {
|
||||
images: Vec<Image>,
|
||||
thumbnails: HashMap<Id, Thumbnail>,
|
||||
viewer: Viewer,
|
||||
now: Instant,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Message {
|
||||
ImagesListed(Result<Vec<Image>, Error>),
|
||||
ImagePoppedIn(Id),
|
||||
ImageDownloaded(Result<Rgba, Error>),
|
||||
ThumbnailDownloaded(Id, Result<Rgba, Error>),
|
||||
ThumbnailHovered(Id, bool),
|
||||
Open(Id),
|
||||
Close,
|
||||
Animate(Instant),
|
||||
}
|
||||
|
||||
impl Gallery {
|
||||
pub fn new() -> (Self, Task<Message>) {
|
||||
(
|
||||
Self {
|
||||
images: Vec::new(),
|
||||
thumbnails: HashMap::new(),
|
||||
viewer: Viewer::new(),
|
||||
now: Instant::now(),
|
||||
},
|
||||
Task::perform(Image::list(), Message::ImagesListed),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn theme(&self) -> Theme {
|
||||
Theme::TokyoNight
|
||||
}
|
||||
|
||||
pub fn subscription(&self) -> Subscription<Message> {
|
||||
let is_animating = self
|
||||
.thumbnails
|
||||
.values()
|
||||
.any(|thumbnail| thumbnail.is_animating(self.now))
|
||||
|| self.viewer.is_animating(self.now);
|
||||
|
||||
if is_animating {
|
||||
window::frames().map(Message::Animate)
|
||||
} else {
|
||||
Subscription::none()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, message: Message) -> Task<Message> {
|
||||
match message {
|
||||
Message::ImagesListed(Ok(images)) => {
|
||||
self.images = images;
|
||||
|
||||
Task::none()
|
||||
}
|
||||
Message::ImagePoppedIn(id) => {
|
||||
let Some(image) = self
|
||||
.images
|
||||
.iter()
|
||||
.find(|candidate| candidate.id == id)
|
||||
.cloned()
|
||||
else {
|
||||
return Task::none();
|
||||
};
|
||||
|
||||
Task::perform(image.download(Size::Thumbnail), move |result| {
|
||||
Message::ThumbnailDownloaded(id, result)
|
||||
})
|
||||
}
|
||||
Message::ImageDownloaded(Ok(rgba)) => {
|
||||
self.viewer.show(rgba);
|
||||
|
||||
Task::none()
|
||||
}
|
||||
Message::ThumbnailDownloaded(id, Ok(rgba)) => {
|
||||
let thumbnail = Thumbnail {
|
||||
handle: image::Handle::from_rgba(
|
||||
rgba.width,
|
||||
rgba.height,
|
||||
rgba.pixels,
|
||||
),
|
||||
fade_in: Animation::new(false).slow().go(true),
|
||||
zoom: Animation::new(false)
|
||||
.quick()
|
||||
.easing(animation::Easing::EaseInOut),
|
||||
};
|
||||
|
||||
let _ = self.thumbnails.insert(id, thumbnail);
|
||||
|
||||
Task::none()
|
||||
}
|
||||
Message::ThumbnailHovered(id, is_hovered) => {
|
||||
if let Some(thumbnail) = self.thumbnails.get_mut(&id) {
|
||||
thumbnail.zoom.go_mut(is_hovered);
|
||||
}
|
||||
|
||||
Task::none()
|
||||
}
|
||||
Message::Open(id) => {
|
||||
let Some(image) = self
|
||||
.images
|
||||
.iter()
|
||||
.find(|candidate| candidate.id == id)
|
||||
.cloned()
|
||||
else {
|
||||
return Task::none();
|
||||
};
|
||||
|
||||
self.viewer.open();
|
||||
|
||||
Task::perform(
|
||||
image.download(Size::Original),
|
||||
Message::ImageDownloaded,
|
||||
)
|
||||
}
|
||||
Message::Close => {
|
||||
self.viewer.close();
|
||||
|
||||
Task::none()
|
||||
}
|
||||
Message::Animate(now) => {
|
||||
self.now = now;
|
||||
|
||||
Task::none()
|
||||
}
|
||||
Message::ImagesListed(Err(error))
|
||||
| Message::ImageDownloaded(Err(error))
|
||||
| Message::ThumbnailDownloaded(_, Err(error)) => {
|
||||
dbg!(error);
|
||||
|
||||
Task::none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view(&self) -> Element<'_, Message> {
|
||||
let gallery = row(self.images.iter().map(|image| {
|
||||
card(image, self.thumbnails.get(&image.id), self.now)
|
||||
}))
|
||||
.spacing(10)
|
||||
.wrap();
|
||||
|
||||
let content =
|
||||
container(scrollable(center_x(gallery)).spacing(10)).padding(10);
|
||||
|
||||
let viewer = self.viewer.view(self.now);
|
||||
|
||||
stack![content, viewer].into()
|
||||
}
|
||||
}
|
||||
|
||||
struct Thumbnail {
|
||||
handle: image::Handle,
|
||||
fade_in: Animation<bool>,
|
||||
zoom: Animation<bool>,
|
||||
}
|
||||
|
||||
impl Thumbnail {
|
||||
fn is_animating(&self, now: Instant) -> bool {
|
||||
self.fade_in.in_progress(now) || self.zoom.in_progress(now)
|
||||
}
|
||||
}
|
||||
|
||||
fn card<'a>(
|
||||
metadata: &'a Image,
|
||||
thumbnail: Option<&'a Thumbnail>,
|
||||
now: Instant,
|
||||
) -> Element<'a, Message> {
|
||||
let image: Element<'_, _> = if let Some(thumbnail) = thumbnail {
|
||||
image(&thumbnail.handle)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.content_fit(ContentFit::Cover)
|
||||
.opacity(thumbnail.fade_in.interpolate(0.0, 1.0, now))
|
||||
.scale(thumbnail.zoom.interpolate(1.0, 1.1, now))
|
||||
.into()
|
||||
} else {
|
||||
horizontal_space().into()
|
||||
};
|
||||
|
||||
let card = mouse_area(
|
||||
container(image)
|
||||
.width(320)
|
||||
.height(410)
|
||||
.style(container::dark),
|
||||
)
|
||||
.on_enter(Message::ThumbnailHovered(metadata.id, true))
|
||||
.on_exit(Message::ThumbnailHovered(metadata.id, false));
|
||||
|
||||
if thumbnail.is_some() {
|
||||
button(card)
|
||||
.on_press(Message::Open(metadata.id))
|
||||
.padding(0)
|
||||
.style(button::text)
|
||||
.into()
|
||||
} else {
|
||||
pop(card)
|
||||
.on_show(Message::ImagePoppedIn(metadata.id))
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
struct Viewer {
|
||||
image: Option<image::Handle>,
|
||||
background_fade_in: Animation<bool>,
|
||||
image_fade_in: Animation<bool>,
|
||||
}
|
||||
|
||||
impl Viewer {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
image: None,
|
||||
background_fade_in: Animation::new(false)
|
||||
.very_slow()
|
||||
.easing(animation::Easing::EaseInOut),
|
||||
image_fade_in: Animation::new(false)
|
||||
.very_slow()
|
||||
.easing(animation::Easing::EaseInOut),
|
||||
}
|
||||
}
|
||||
|
||||
fn open(&mut self) {
|
||||
self.image = None;
|
||||
self.background_fade_in.go_mut(true);
|
||||
}
|
||||
|
||||
fn show(&mut self, rgba: Rgba) {
|
||||
self.image = Some(image::Handle::from_rgba(
|
||||
rgba.width,
|
||||
rgba.height,
|
||||
rgba.pixels,
|
||||
));
|
||||
self.background_fade_in.go_mut(true);
|
||||
self.image_fade_in.go_mut(true);
|
||||
}
|
||||
|
||||
fn close(&mut self) {
|
||||
self.background_fade_in.go_mut(false);
|
||||
self.image_fade_in.go_mut(false);
|
||||
}
|
||||
|
||||
fn is_animating(&self, now: Instant) -> bool {
|
||||
self.background_fade_in.in_progress(now)
|
||||
|| self.image_fade_in.in_progress(now)
|
||||
}
|
||||
|
||||
fn view(&self, now: Instant) -> Element<'_, Message> {
|
||||
let opacity = self.background_fade_in.interpolate(0.0, 0.8, now);
|
||||
|
||||
let image: Element<'_, _> = if let Some(handle) = &self.image {
|
||||
image(handle)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.opacity(self.image_fade_in.interpolate(0.0, 1.0, now))
|
||||
.scale(self.image_fade_in.interpolate(1.5, 1.0, now))
|
||||
.into()
|
||||
} else {
|
||||
horizontal_space().into()
|
||||
};
|
||||
|
||||
if opacity > 0.0 {
|
||||
opaque(
|
||||
mouse_area(
|
||||
container(image)
|
||||
.center(Fill)
|
||||
.style(move |_theme| {
|
||||
container::Style::default()
|
||||
.background(color!(0x000000, opacity))
|
||||
})
|
||||
.padding(20),
|
||||
)
|
||||
.on_press(Message::Close),
|
||||
)
|
||||
} else {
|
||||
horizontal_space().into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -17,8 +17,7 @@ features = ["derive"]
|
|||
|
||||
[dependencies.reqwest]
|
||||
version = "0.12"
|
||||
default-features = false
|
||||
features = ["json", "rustls-tls"]
|
||||
features = ["json"]
|
||||
|
||||
[dependencies.rand]
|
||||
version = "0.8"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue