qr: export to gif and png
This commit is contained in:
parent
d1d968f165
commit
00fd12cd2a
14 changed files with 614 additions and 166 deletions
277
Cargo.lock
generated
277
Cargo.lock
generated
|
@ -63,7 +63,7 @@ dependencies = [
|
||||||
"futures-lite 1.13.0",
|
"futures-lite 1.13.0",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"serde",
|
"serde",
|
||||||
"zbus",
|
"zbus 3.15.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -540,6 +540,24 @@ dependencies = [
|
||||||
"libloading 0.7.4",
|
"libloading 0.7.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ashpd"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd884d7c72877a94102c3715f3b1cd09ff4fac28221add3e57cfbe25c236d093"
|
||||||
|
dependencies = [
|
||||||
|
"async-fs 2.1.2",
|
||||||
|
"async-net",
|
||||||
|
"enumflags2",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-util",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"serde",
|
||||||
|
"serde_repr",
|
||||||
|
"url",
|
||||||
|
"zbus 4.2.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-broadcast"
|
name = "async-broadcast"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
@ -550,6 +568,18 @@ dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-broadcast"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "258b52a1aa741b9f09783b2d86cf0aeeb617bbf847f6933340a39644227acbdb"
|
||||||
|
dependencies = [
|
||||||
|
"event-listener 5.3.0",
|
||||||
|
"event-listener-strategy 0.5.2",
|
||||||
|
"futures-core",
|
||||||
|
"pin-project-lite 0.2.14",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-channel"
|
name = "async-channel"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
|
@ -603,6 +633,17 @@ dependencies = [
|
||||||
"futures-lite 1.13.0",
|
"futures-lite 1.13.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-fs"
|
||||||
|
version = "2.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a"
|
||||||
|
dependencies = [
|
||||||
|
"async-lock 3.3.0",
|
||||||
|
"blocking",
|
||||||
|
"futures-lite 2.3.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-io"
|
name = "async-io"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
|
@ -674,6 +715,17 @@ dependencies = [
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-net"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7"
|
||||||
|
dependencies = [
|
||||||
|
"async-io 2.3.2",
|
||||||
|
"blocking",
|
||||||
|
"futures-lite 2.3.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-once-cell"
|
name = "async-once-cell"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
|
@ -697,6 +749,26 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-process"
|
||||||
|
version = "2.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a53fc6301894e04a92cb2584fedde80cb25ba8e02d9dc39d4a87d036e22f397d"
|
||||||
|
dependencies = [
|
||||||
|
"async-channel",
|
||||||
|
"async-io 2.3.2",
|
||||||
|
"async-lock 3.3.0",
|
||||||
|
"async-signal",
|
||||||
|
"async-task",
|
||||||
|
"blocking",
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"event-listener 5.3.0",
|
||||||
|
"futures-lite 2.3.0",
|
||||||
|
"rustix 0.38.34",
|
||||||
|
"tracing",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-recursion"
|
name = "async-recursion"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
|
@ -812,9 +884,9 @@ dependencies = [
|
||||||
"enumflags2",
|
"enumflags2",
|
||||||
"serde",
|
"serde",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"zbus",
|
"zbus 3.15.2",
|
||||||
"zbus_names",
|
"zbus_names 2.6.1",
|
||||||
"zvariant",
|
"zvariant 3.15.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -826,7 +898,7 @@ dependencies = [
|
||||||
"atspi-common",
|
"atspi-common",
|
||||||
"atspi-proxies",
|
"atspi-proxies",
|
||||||
"futures-lite 1.13.0",
|
"futures-lite 1.13.0",
|
||||||
"zbus",
|
"zbus 3.15.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -837,7 +909,7 @@ checksum = "6495661273703e7a229356dcbe8c8f38223d697aacfaf0e13590a9ac9977bb52"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atspi-common",
|
"atspi-common",
|
||||||
"serde",
|
"serde",
|
||||||
"zbus",
|
"zbus 3.15.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2624,6 +2696,12 @@ dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "endi"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "enum-map"
|
name = "enum-map"
|
||||||
version = "2.7.3"
|
version = "2.7.3"
|
||||||
|
@ -3618,6 +3696,7 @@ dependencies = [
|
||||||
"env_logger 0.11.3",
|
"env_logger 0.11.3",
|
||||||
"fs-mistrust",
|
"fs-mistrust",
|
||||||
"futures 0.3.30",
|
"futures 0.3.30",
|
||||||
|
"gif",
|
||||||
"grin_api",
|
"grin_api",
|
||||||
"grin_chain",
|
"grin_chain",
|
||||||
"grin_config",
|
"grin_config",
|
||||||
|
@ -3643,6 +3722,7 @@ dependencies = [
|
||||||
"parking_lot 0.12.3",
|
"parking_lot 0.12.3",
|
||||||
"qrcodegen",
|
"qrcodegen",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
|
"rfd",
|
||||||
"rqrr",
|
"rqrr",
|
||||||
"rust-i18n",
|
"rust-i18n",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -5678,6 +5758,19 @@ dependencies = [
|
||||||
"memoffset 0.7.1",
|
"memoffset 0.7.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.28.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.5.0",
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"cfg_aliases",
|
||||||
|
"libc",
|
||||||
|
"memoffset 0.9.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nodrop"
|
name = "nodrop"
|
||||||
version = "0.1.14"
|
version = "0.1.14"
|
||||||
|
@ -5979,6 +6072,17 @@ dependencies = [
|
||||||
"objc_exception",
|
"objc_exception",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc-foundation"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
||||||
|
dependencies = [
|
||||||
|
"block",
|
||||||
|
"objc",
|
||||||
|
"objc_id",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc-sys"
|
name = "objc-sys"
|
||||||
version = "0.2.0-beta.2"
|
version = "0.2.0-beta.2"
|
||||||
|
@ -6129,6 +6233,15 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc_id"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
||||||
|
dependencies = [
|
||||||
|
"objc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.32.2"
|
version = "0.32.2"
|
||||||
|
@ -7327,6 +7440,29 @@ dependencies = [
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rfd"
|
||||||
|
version = "0.14.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25a73a7337fc24366edfca76ec521f51877b114e42dab584008209cca6719251"
|
||||||
|
dependencies = [
|
||||||
|
"ashpd",
|
||||||
|
"block",
|
||||||
|
"dispatch",
|
||||||
|
"js-sys",
|
||||||
|
"log",
|
||||||
|
"objc",
|
||||||
|
"objc-foundation",
|
||||||
|
"objc_id",
|
||||||
|
"pollster",
|
||||||
|
"raw-window-handle 0.6.2",
|
||||||
|
"urlencoding",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rgb"
|
name = "rgb"
|
||||||
version = "0.8.37"
|
version = "0.8.37"
|
||||||
|
@ -10168,8 +10304,15 @@ dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"idna",
|
"idna",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "urlencoding"
|
||||||
|
version = "2.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "usvg"
|
name = "usvg"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
|
@ -11281,12 +11424,12 @@ version = "3.15.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6"
|
checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-broadcast",
|
"async-broadcast 0.5.1",
|
||||||
"async-executor",
|
"async-executor",
|
||||||
"async-fs",
|
"async-fs 1.6.0",
|
||||||
"async-io 1.13.0",
|
"async-io 1.13.0",
|
||||||
"async-lock 2.8.0",
|
"async-lock 2.8.0",
|
||||||
"async-process",
|
"async-process 1.8.1",
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
"async-task",
|
"async-task",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -11299,7 +11442,7 @@ dependencies = [
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hex",
|
"hex",
|
||||||
"nix",
|
"nix 0.26.4",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"ordered-stream",
|
"ordered-stream",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
|
@ -11311,9 +11454,47 @@ dependencies = [
|
||||||
"uds_windows",
|
"uds_windows",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
"xdg-home",
|
"xdg-home",
|
||||||
"zbus_macros",
|
"zbus_macros 3.15.2",
|
||||||
"zbus_names",
|
"zbus_names 2.6.1",
|
||||||
"zvariant",
|
"zvariant 3.15.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus"
|
||||||
|
version = "4.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "989c3977a7aafa97b12b9a35d21cdcff9b0d2289762b14683f45d66b1ba6c48f"
|
||||||
|
dependencies = [
|
||||||
|
"async-broadcast 0.7.0",
|
||||||
|
"async-executor",
|
||||||
|
"async-fs 2.1.2",
|
||||||
|
"async-io 2.3.2",
|
||||||
|
"async-lock 3.3.0",
|
||||||
|
"async-process 2.2.2",
|
||||||
|
"async-recursion",
|
||||||
|
"async-task",
|
||||||
|
"async-trait",
|
||||||
|
"blocking",
|
||||||
|
"enumflags2",
|
||||||
|
"event-listener 5.3.0",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-util",
|
||||||
|
"hex",
|
||||||
|
"nix 0.28.0",
|
||||||
|
"ordered-stream",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"serde",
|
||||||
|
"serde_repr",
|
||||||
|
"sha1",
|
||||||
|
"static_assertions",
|
||||||
|
"tracing",
|
||||||
|
"uds_windows",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
"xdg-home",
|
||||||
|
"zbus_macros 4.2.2",
|
||||||
|
"zbus_names 3.0.0",
|
||||||
|
"zvariant 4.1.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -11327,7 +11508,20 @@ dependencies = [
|
||||||
"quote 1.0.36",
|
"quote 1.0.36",
|
||||||
"regex",
|
"regex",
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
"zvariant_utils",
|
"zvariant_utils 1.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus_macros"
|
||||||
|
version = "4.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6fe9de53245dcf426b7be226a4217dd5e339080e5d46e64a02d6e5dcbf90fca1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-crate 3.1.0",
|
||||||
|
"proc-macro2 1.0.84",
|
||||||
|
"quote 1.0.36",
|
||||||
|
"syn 2.0.66",
|
||||||
|
"zvariant_utils 2.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -11338,7 +11532,18 @@ checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"zvariant",
|
"zvariant 3.15.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus_names"
|
||||||
|
version = "3.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"static_assertions",
|
||||||
|
"zvariant 4.1.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -11455,7 +11660,21 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"serde",
|
"serde",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"zvariant_derive",
|
"zvariant_derive 3.15.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zvariant"
|
||||||
|
version = "4.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9aa6d31a02fbfb602bfde791de7fedeb9c2c18115b3d00f3a36e489f46ffbbc7"
|
||||||
|
dependencies = [
|
||||||
|
"endi",
|
||||||
|
"enumflags2",
|
||||||
|
"serde",
|
||||||
|
"static_assertions",
|
||||||
|
"url",
|
||||||
|
"zvariant_derive 4.1.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -11468,7 +11687,20 @@ dependencies = [
|
||||||
"proc-macro2 1.0.84",
|
"proc-macro2 1.0.84",
|
||||||
"quote 1.0.36",
|
"quote 1.0.36",
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
"zvariant_utils",
|
"zvariant_utils 1.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zvariant_derive"
|
||||||
|
version = "4.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "642bf1b6b6d527988b3e8193d20969d53700a36eac734d21ae6639db168701c8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-crate 3.1.0",
|
||||||
|
"proc-macro2 1.0.84",
|
||||||
|
"quote 1.0.36",
|
||||||
|
"syn 2.0.66",
|
||||||
|
"zvariant_utils 2.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -11481,3 +11713,14 @@ dependencies = [
|
||||||
"quote 1.0.36",
|
"quote 1.0.36",
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zvariant_utils"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc242db087efc22bd9ade7aa7809e4ba828132edc312871584a6b4391bdf8786"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.84",
|
||||||
|
"quote 1.0.36",
|
||||||
|
"syn 2.0.66",
|
||||||
|
]
|
||||||
|
|
|
@ -58,6 +58,7 @@ image = "0.25.1"
|
||||||
rqrr = "0.7.1"
|
rqrr = "0.7.1"
|
||||||
qrcodegen = "1.8.0"
|
qrcodegen = "1.8.0"
|
||||||
ur = "0.4.1"
|
ur = "0.4.1"
|
||||||
|
gif = "0.13.1"
|
||||||
|
|
||||||
## tor
|
## tor
|
||||||
arti-client = { version = "0.18.0", features = ["pt-client", "static", "onion-service-service", "onion-service-client"] }
|
arti-client = { version = "0.18.0", features = ["pt-client", "static", "onion-service-service", "onion-service-client"] }
|
||||||
|
@ -92,6 +93,7 @@ env_logger = "0.11.3"
|
||||||
winit = { version = "0.29.15" }
|
winit = { version = "0.29.15" }
|
||||||
eframe = { version = "0.27.2", features = ["wgpu"] }
|
eframe = { version = "0.27.2", features = ["wgpu"] }
|
||||||
arboard = "3.2.0"
|
arboard = "3.2.0"
|
||||||
|
rfd = "0.14.1"
|
||||||
# camera
|
# camera
|
||||||
nokhwa = { git = "https://github.com/l1npengtul/nokhwa", branch = "0.10", features = ["input-native", "output-threaded"] }
|
nokhwa = { git = "https://github.com/l1npengtul/nokhwa", branch = "0.10", features = ["input-native", "output-threaded"] }
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ scan_qr: Scan QR code
|
||||||
repeat: Repeat
|
repeat: Repeat
|
||||||
scan_result: Scan result
|
scan_result: Scan result
|
||||||
back: Back
|
back: Back
|
||||||
|
share: Share
|
||||||
wallets:
|
wallets:
|
||||||
await_conf_amount: Awaiting confirmation
|
await_conf_amount: Awaiting confirmation
|
||||||
await_fin_amount: Awaiting finalization
|
await_fin_amount: Awaiting finalization
|
||||||
|
|
|
@ -21,6 +21,7 @@ scan_qr: Сканирование QR-кода
|
||||||
repeat: Повторить
|
repeat: Повторить
|
||||||
scan_result: Результат сканирования
|
scan_result: Результат сканирования
|
||||||
back: Назад
|
back: Назад
|
||||||
|
share: Поделиться
|
||||||
wallets:
|
wallets:
|
||||||
await_conf_amount: Ожидает подтверждения
|
await_conf_amount: Ожидает подтверждения
|
||||||
await_fin_amount: Ожидает завершения
|
await_fin_amount: Ожидает завершения
|
||||||
|
|
|
@ -21,6 +21,7 @@ scan_qr: QR kod tara
|
||||||
repeat: Tekrar
|
repeat: Tekrar
|
||||||
scan_result: Tarama sonucu
|
scan_result: Tarama sonucu
|
||||||
back: Geri
|
back: Geri
|
||||||
|
share: Paylasmak
|
||||||
wallets:
|
wallets:
|
||||||
await_conf_amount: Onay bekleniyor
|
await_conf_amount: Onay bekleniyor
|
||||||
await_fin_amount: Tamamlanma bekleniyor
|
await_fin_amount: Tamamlanma bekleniyor
|
||||||
|
|
|
@ -114,6 +114,10 @@ impl PlatformCallbacks for Android {
|
||||||
fn switch_camera(&self) {
|
fn switch_camera(&self) {
|
||||||
self.call_java_method("switchCamera", "()V", &[]).unwrap();
|
self.call_java_method("switchCamera", "()V", &[]).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn share_data(&self, name: String, data: Vec<u8>) -> Result<(), std::io::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io:: Write;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
@ -20,6 +22,7 @@ use std::thread;
|
||||||
use nokhwa::Camera;
|
use nokhwa::Camera;
|
||||||
use nokhwa::pixel_format::RgbFormat;
|
use nokhwa::pixel_format::RgbFormat;
|
||||||
use nokhwa::utils::{CameraIndex, RequestedFormat, RequestedFormatType};
|
use nokhwa::utils::{CameraIndex, RequestedFormat, RequestedFormatType};
|
||||||
|
use rfd::FileDialog;
|
||||||
|
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
|
|
||||||
|
@ -124,6 +127,19 @@ impl PlatformCallbacks for Desktop {
|
||||||
fn switch_camera(&self) {
|
fn switch_camera(&self) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn share_data(&self, name: String, data: Vec<u8>) -> Result<(), std::io::Error> {
|
||||||
|
let folder = FileDialog::new()
|
||||||
|
.set_directory(dirs::home_dir().unwrap())
|
||||||
|
.set_file_name(name.clone())
|
||||||
|
.save_file();
|
||||||
|
if let Some(folder) = folder {
|
||||||
|
let mut image = File::create(folder)?;
|
||||||
|
image.write_all(data.as_slice())?;
|
||||||
|
image.sync_all()?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
|
|
@ -31,4 +31,5 @@ pub trait PlatformCallbacks {
|
||||||
fn camera_image(&self) -> Option<(Vec<u8>, u32)>;
|
fn camera_image(&self) -> Option<(Vec<u8>, u32)>;
|
||||||
fn can_switch_camera(&self) -> bool;
|
fn can_switch_camera(&self) -> bool;
|
||||||
fn switch_camera(&self);
|
fn switch_camera(&self);
|
||||||
|
fn share_data(&self, name: String, data: Vec<u8>) -> Result<(), std::io::Error>;
|
||||||
}
|
}
|
|
@ -12,15 +12,24 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::fs::{File, read};
|
||||||
|
use std::io::Cursor;
|
||||||
|
use std::mem::size_of;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use egui::{SizeHint, TextureHandle, TextureOptions};
|
use egui::{SizeHint, TextureHandle, TextureOptions};
|
||||||
use egui::load::SizedTexture;
|
use egui::load::SizedTexture;
|
||||||
use egui_extras::image::load_svg_bytes_with_size;
|
use egui_extras::image::load_svg_bytes_with_size;
|
||||||
|
use image::codecs::jpeg::JpegEncoder;
|
||||||
|
use image::{ColorType, EncodableLayout, ExtendedColorType, ImageBuffer, ImageEncoder, Rgb, RgbImage};
|
||||||
|
use image::codecs::png::{CompressionType, FilterType, PngDecoder, PngEncoder};
|
||||||
use qrcodegen::QrCode;
|
use qrcodegen::QrCode;
|
||||||
|
use crate::gui::Colors;
|
||||||
|
use crate::gui::icons::IMAGES_SQUARE;
|
||||||
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
|
|
||||||
use crate::gui::views::types::QrCreationState;
|
use crate::gui::views::types::QrImageState;
|
||||||
use crate::gui::views::View;
|
use crate::gui::views::View;
|
||||||
|
|
||||||
/// QR code image from text.
|
/// QR code image from text.
|
||||||
|
@ -38,10 +47,12 @@ pub struct QrCodeContent {
|
||||||
|
|
||||||
/// Texture handle to show image when created.
|
/// Texture handle to show image when created.
|
||||||
texture_handle: Option<TextureHandle>,
|
texture_handle: Option<TextureHandle>,
|
||||||
/// QR code image creation progress and result.
|
/// QR code view data state.
|
||||||
qr_creation_state: Arc<RwLock<QrCreationState>>,
|
qr_image_state: Arc<RwLock<QrImageState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEFAULT_QR_SIZE: u32 = 380;
|
||||||
|
|
||||||
impl QrCodeContent {
|
impl QrCodeContent {
|
||||||
pub fn new(text: String, animated: bool) -> Self {
|
pub fn new(text: String, animated: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -50,14 +61,23 @@ impl QrCodeContent {
|
||||||
animated_index: None,
|
animated_index: None,
|
||||||
animation_time: None,
|
animation_time: None,
|
||||||
texture_handle: None,
|
texture_handle: None,
|
||||||
qr_creation_state: Arc::new(RwLock::new(QrCreationState::default())),
|
qr_image_state: Arc::new(RwLock::new(QrImageState::default())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw QR code.
|
/// Draw QR code.
|
||||||
pub fn ui(&mut self, ui: &mut egui::Ui, text: String) {
|
pub fn ui(&mut self, ui: &mut egui::Ui, text: String, cb: &dyn PlatformCallbacks) {
|
||||||
if self.animated {
|
if self.animated {
|
||||||
// Create animated QR code image if not created.
|
// Show animated QR code.
|
||||||
|
self.animated_ui(ui, text, cb);
|
||||||
|
} else {
|
||||||
|
// Show static QR code.
|
||||||
|
self.static_ui(ui, text, cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw animated QR code content.
|
||||||
|
fn animated_ui(&mut self, ui: &mut egui::Ui, text: String, cb: &dyn PlatformCallbacks) {
|
||||||
if !self.has_image() {
|
if !self.has_image() {
|
||||||
let space = (ui.available_width() - View::BIG_SPINNER_SIZE) / 2.0;
|
let space = (ui.available_width() - View::BIG_SPINNER_SIZE) / 2.0;
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
|
@ -67,12 +87,12 @@ impl QrCodeContent {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create multiple vector images from text if not creating.
|
// Create multiple vector images from text if not creating.
|
||||||
if !self.creating() {
|
if !self.loading() {
|
||||||
self.create_svg_list(text);
|
self.create_svg_list(text);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let svg_list = {
|
let svg_list = {
|
||||||
let r_create = self.qr_creation_state.read();
|
let r_create = self.qr_image_state.read();
|
||||||
r_create.svg_list.clone().unwrap()
|
r_create.svg_list.clone().unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -105,10 +125,64 @@ impl QrCodeContent {
|
||||||
ui.add(egui::Image::from_texture(sized_img)
|
ui.add(egui::Image::from_texture(sized_img)
|
||||||
.max_height(ui.available_width())
|
.max_height(ui.available_width())
|
||||||
.fit_to_original_size(1.0));
|
.fit_to_original_size(1.0));
|
||||||
|
ui.add_space(6.0);
|
||||||
|
|
||||||
|
// Show QR code text.
|
||||||
|
View::ellipsize_text(ui, text.clone(), 16.0, Colors::INACTIVE_TEXT);
|
||||||
|
ui.add_space(6.0);
|
||||||
|
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
let sharing = {
|
||||||
|
let r_state = self.qr_image_state.read();
|
||||||
|
r_state.exporting || r_state.gif_creating
|
||||||
|
};
|
||||||
|
if !sharing {
|
||||||
|
// Show button to share QR.
|
||||||
|
let share_text = format!("{} {}", IMAGES_SQUARE, t!("share"));
|
||||||
|
View::button(ui, share_text, Colors::GOLD, || {
|
||||||
|
{
|
||||||
|
let mut w_state = self.qr_image_state.write();
|
||||||
|
w_state.exporting = true;
|
||||||
|
}
|
||||||
|
// Create GIF to export.
|
||||||
|
self.create_qr_gif(text, DEFAULT_QR_SIZE as usize);
|
||||||
|
});
|
||||||
|
ui.add_space(2.0);
|
||||||
|
} else {
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
ui.add_space(6.0);
|
||||||
|
View::small_loading_spinner(ui);
|
||||||
|
ui.add_space(10.0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if GIF was created to share.
|
||||||
|
let has_gif = {
|
||||||
|
let r_state = self.qr_image_state.read();
|
||||||
|
r_state.gif_data.is_some()
|
||||||
|
};
|
||||||
|
if has_gif {
|
||||||
|
let data = {
|
||||||
|
let r_state = self.qr_image_state.read();
|
||||||
|
r_state.gif_data.clone().unwrap()
|
||||||
|
};
|
||||||
|
let name = format!("{}.gif", chrono::Utc::now().timestamp());
|
||||||
|
cb.share_data(name, data).unwrap_or_default();
|
||||||
|
// Clear GIF data and exporting flag.
|
||||||
|
{
|
||||||
|
let mut w_state = self.qr_image_state.write();
|
||||||
|
w_state.gif_data = None;
|
||||||
|
w_state.exporting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ui.ctx().request_repaint();
|
ui.ctx().request_repaint();
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
// Create vector QR code image if not created.
|
|
||||||
|
/// Draw static QR code content.
|
||||||
|
fn static_ui(&mut self, ui: &mut egui::Ui, text: String, cb: &dyn PlatformCallbacks) {
|
||||||
if !self.has_image() {
|
if !self.has_image() {
|
||||||
let space = (ui.available_width() - View::BIG_SPINNER_SIZE) / 2.0;
|
let space = (ui.available_width() - View::BIG_SPINNER_SIZE) / 2.0;
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
|
@ -118,15 +192,17 @@ impl QrCodeContent {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create vector image from text if not creating.
|
// Create vector image from text if not creating.
|
||||||
if !self.creating() {
|
if !self.loading() {
|
||||||
self.create_svg(text);
|
self.create_svg(text);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create image from SVG data.
|
// Create image from SVG data.
|
||||||
let r_create = self.qr_creation_state.read();
|
let svg = {
|
||||||
let svg = r_create.svg.as_ref().unwrap();
|
let r_state = self.qr_image_state.read();
|
||||||
|
r_state.svg.clone().unwrap()
|
||||||
|
};
|
||||||
let size = SizeHint::Size(ui.available_width() as u32, ui.available_width() as u32);
|
let size = SizeHint::Size(ui.available_width() as u32, ui.available_width() as u32);
|
||||||
let color_img = load_svg_bytes_with_size(svg, Some(size)).unwrap();
|
let color_img = load_svg_bytes_with_size(svg.as_slice(), Some(size)).unwrap();
|
||||||
// Create image texture.
|
// Create image texture.
|
||||||
let texture_handle = ui.ctx().load_texture("qr_code",
|
let texture_handle = ui.ctx().load_texture("qr_code",
|
||||||
color_img.clone(),
|
color_img.clone(),
|
||||||
|
@ -139,19 +215,45 @@ impl QrCodeContent {
|
||||||
ui.add(egui::Image::from_texture(sized_img)
|
ui.add(egui::Image::from_texture(sized_img)
|
||||||
.max_height(ui.available_width())
|
.max_height(ui.available_width())
|
||||||
.fit_to_original_size(1.0));
|
.fit_to_original_size(1.0));
|
||||||
|
ui.add_space(6.0);
|
||||||
|
|
||||||
|
// Show QR code text.
|
||||||
|
View::ellipsize_text(ui, text.clone(), 16.0, Colors::INACTIVE_TEXT);
|
||||||
|
ui.add_space(6.0);
|
||||||
|
|
||||||
|
// Show button to share QR.
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
let share_text = format!("{} {}", IMAGES_SQUARE, t!("share"));
|
||||||
|
View::button(ui, share_text, Colors::GOLD, || {
|
||||||
|
if let Ok(qr) = QrCode::encode_text(text.as_str(), qrcodegen::QrCodeEcc::Low) {
|
||||||
|
if let Some(data) = Self::qr_to_image_data(qr, DEFAULT_QR_SIZE as usize) {
|
||||||
|
let mut png = vec![];
|
||||||
|
let png_enc = PngEncoder::new_with_quality(&mut png,
|
||||||
|
CompressionType::Best,
|
||||||
|
FilterType::NoFilter);
|
||||||
|
if let Ok(()) = png_enc.write_image(data.as_slice(),
|
||||||
|
DEFAULT_QR_SIZE,
|
||||||
|
DEFAULT_QR_SIZE,
|
||||||
|
ExtendedColorType::L8) {
|
||||||
|
let name = format!("{}.png", chrono::Utc::now().timestamp());
|
||||||
|
cb.share_data(name, png).unwrap_or_default();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if QR code is creating.
|
/// Check if QR code is loading.
|
||||||
fn creating(&self) -> bool {
|
fn loading(&self) -> bool {
|
||||||
let r_create = self.qr_creation_state.read();
|
let r_state = self.qr_image_state.read();
|
||||||
r_create.creating
|
r_state.loading
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create multiple vector QR code images at separate thread.
|
/// Create multiple vector QR code images at separate thread.
|
||||||
fn create_svg_list(&self, text: String) {
|
fn create_svg_list(&self, text: String) {
|
||||||
let qr_creation_state = self.qr_creation_state.clone();
|
let qr_state = self.qr_image_state.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut encoder = ur::Encoder::bytes(text.as_bytes(), 100).unwrap();
|
let mut encoder = ur::Encoder::bytes(text.as_bytes(), 100).unwrap();
|
||||||
let mut data = Vec::with_capacity(encoder.fragment_count());
|
let mut data = Vec::with_capacity(encoder.fragment_count());
|
||||||
|
@ -162,29 +264,29 @@ impl QrCodeContent {
|
||||||
data.push(svg.into_bytes());
|
data.push(svg.into_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut w_create = qr_creation_state.write();
|
let mut w_state = qr_state.write();
|
||||||
if !data.is_empty() {
|
if !data.is_empty() {
|
||||||
w_create.svg_list = Some(data);
|
w_state.svg_list = Some(data);
|
||||||
}
|
}
|
||||||
w_create.creating = false;
|
w_state.loading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if image was created.
|
/// Check if image was created.
|
||||||
fn has_image(&self) -> bool {
|
fn has_image(&self) -> bool {
|
||||||
let r_create = self.qr_creation_state.read();
|
let r_state = self.qr_image_state.read();
|
||||||
r_create.svg.is_some() || r_create.svg_list.is_some()
|
r_state.svg.is_some() || r_state.svg_list.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create vector QR code image at separate thread.
|
/// Create vector QR code image at separate thread.
|
||||||
fn create_svg(&self, text: String) {
|
fn create_svg(&self, text: String) {
|
||||||
let qr_creation_state = self.qr_creation_state.clone();
|
let qr_state = self.qr_image_state.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
if let Ok(qr) = QrCode::encode_text(text.as_str(), qrcodegen::QrCodeEcc::Low) {
|
if let Ok(qr) = QrCode::encode_text(text.as_str(), qrcodegen::QrCodeEcc::Low) {
|
||||||
let svg = Self::qr_to_svg(qr, 0);
|
let svg = Self::qr_to_svg(qr, 0);
|
||||||
let mut w_create = qr_creation_state.write();
|
let mut w_state = qr_state.write();
|
||||||
w_create.creating = false;
|
w_state.loading = false;
|
||||||
w_create.svg = Some(svg.into_bytes());
|
w_state.svg = Some(svg.into_bytes());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -214,9 +316,91 @@ impl QrCodeContent {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create GIF image at separate thread.
|
||||||
|
fn create_qr_gif(&self, text: String, size: usize) {
|
||||||
|
{
|
||||||
|
let mut w_state = self.qr_image_state.write();
|
||||||
|
w_state.gif_creating = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
let qr_state = self.qr_image_state.clone();
|
||||||
|
thread::spawn(move || {
|
||||||
|
// Setup GIF image encoder.
|
||||||
|
let mut gif = vec![];
|
||||||
|
if let Ok(mut gif_enc) = gif::Encoder::new(&mut gif,
|
||||||
|
size as u16,
|
||||||
|
size as u16,
|
||||||
|
&[]) {
|
||||||
|
gif_enc.set_repeat(gif::Repeat::Infinite).unwrap();
|
||||||
|
// Generate QR codes from text.
|
||||||
|
let mut ur_enc = ur::Encoder::bytes(text.as_bytes(), 100).unwrap();
|
||||||
|
for _ in 0..ur_enc.fragment_count() {
|
||||||
|
let ur = ur_enc.next_part().unwrap();
|
||||||
|
if let Ok(qr) = QrCode::encode_text(ur.as_str(), qrcodegen::QrCodeEcc::Low) {
|
||||||
|
// Create an image from QR data and write it to encoder.
|
||||||
|
if let Some(image) = Self::qr_to_image_data(qr, size) {
|
||||||
|
let mut frame = gif::Frame::from_indexed_pixels(size as u16,
|
||||||
|
size as u16,
|
||||||
|
image.as_slice(), None);
|
||||||
|
frame.palette = Some(vec![]);
|
||||||
|
// Write an image to GIF encoder.
|
||||||
|
if let Ok(_) = gif_enc.write_frame(&frame) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Exit on error.
|
||||||
|
let mut w_state = qr_state.write();
|
||||||
|
w_state.gif_creating = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Setup GIF image data.
|
||||||
|
let mut w_state = qr_state.write();
|
||||||
|
if !gif.is_empty() {
|
||||||
|
w_state.gif_data = Some(gif);
|
||||||
|
}
|
||||||
|
w_state.gif_creating = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert QR code to image data.
|
||||||
|
fn qr_to_image_data(qr: QrCode, size: usize) -> Option<Vec<u8>> {
|
||||||
|
if size >= 2usize.pow((size_of::<usize>() * 4) as u32) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let margin_size = 1;
|
||||||
|
let s = qr.size();
|
||||||
|
let data_length = s as usize;
|
||||||
|
let data_length_with_margin = data_length + 2 * margin_size;
|
||||||
|
let point_size = size / data_length_with_margin;
|
||||||
|
if point_size == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let margin = (size - (point_size * data_length)) / 2;
|
||||||
|
let length = size * size;
|
||||||
|
let mut img_raw: Vec<u8> = vec![255u8; length];
|
||||||
|
for i in 0..s {
|
||||||
|
for j in 0..s {
|
||||||
|
if qr.get_module(i, j) {
|
||||||
|
let x = i as usize * point_size + margin;
|
||||||
|
let y = j as usize * point_size + margin;
|
||||||
|
|
||||||
|
for j in y..(y + point_size) {
|
||||||
|
let offset = j * size;
|
||||||
|
for i in x..(x + point_size) {
|
||||||
|
img_raw[offset + i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(img_raw)
|
||||||
|
}
|
||||||
|
|
||||||
/// Reset QR code image content state to default.
|
/// Reset QR code image content state to default.
|
||||||
pub fn clear_state(&mut self) {
|
pub fn clear_state(&mut self) {
|
||||||
let mut w_create = self.qr_creation_state.write();
|
let mut w_create = self.qr_image_state.write();
|
||||||
*w_create = QrCreationState::default();
|
*w_create = QrImageState::default();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -175,11 +175,11 @@ impl QrScanResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// QR code scan state.
|
/// QR code scanning state.
|
||||||
pub struct QrScanState {
|
pub struct QrScanState {
|
||||||
// Flag to check if image is processing to find QR code.
|
/// Flag to check if image is processing to find QR code.
|
||||||
pub(crate) image_processing: bool,
|
pub image_processing: bool,
|
||||||
// Found QR code content.
|
/// Processed QR code result.
|
||||||
pub qr_scan_result: Option<QrScanResult>
|
pub qr_scan_result: Option<QrScanResult>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,20 +192,31 @@ impl Default for QrScanState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// QR code image creation state.
|
/// QR code image data state.
|
||||||
pub struct QrCreationState {
|
pub struct QrImageState {
|
||||||
// Flag to check if QR code image is creating.
|
/// Flag to check if QR code image is loading.
|
||||||
pub creating: bool,
|
pub loading: bool,
|
||||||
// Vector image data.
|
/// Flag to check if QR code image is exporting.
|
||||||
|
pub exporting: bool,
|
||||||
|
|
||||||
|
/// Created GIF data from animated QR code.
|
||||||
|
pub gif_data: Option<Vec<u8>>,
|
||||||
|
/// Flag to check if GIF is creating.
|
||||||
|
pub gif_creating: bool,
|
||||||
|
|
||||||
|
/// Vector image data.
|
||||||
pub svg: Option<Vec<u8>>,
|
pub svg: Option<Vec<u8>>,
|
||||||
// Multiple vector image data.
|
/// Multiple vector image data for animated QR code.
|
||||||
pub svg_list: Option<Vec<Vec<u8>>>
|
pub svg_list: Option<Vec<Vec<u8>>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for QrCreationState {
|
impl Default for QrImageState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
creating: false,
|
loading: false,
|
||||||
|
exporting: false,
|
||||||
|
gif_data: None,
|
||||||
|
gif_creating: false,
|
||||||
svg: None,
|
svg: None,
|
||||||
svg_list: None,
|
svg_list: None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -403,6 +403,8 @@ impl WalletContent {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ui.add_space(6.0);
|
ui.add_space(6.0);
|
||||||
|
View::horizontal_line(ui, Colors::ITEM_STROKE);
|
||||||
|
ui.add_space(6.0);
|
||||||
} else if let Some(result) = self.camera_content.qr_scan_result() {
|
} else if let Some(result) = self.camera_content.qr_scan_result() {
|
||||||
cb.stop_camera();
|
cb.stop_camera();
|
||||||
self.camera_content.clear_state();
|
self.camera_content.clear_state();
|
||||||
|
|
|
@ -224,7 +224,7 @@ impl WalletMessages {
|
||||||
}
|
}
|
||||||
QR_SLATEPACK_MESSAGE_MODAL => {
|
QR_SLATEPACK_MESSAGE_MODAL => {
|
||||||
Modal::ui(ui.ctx(), |ui, modal| {
|
Modal::ui(ui.ctx(), |ui, modal| {
|
||||||
self.qr_message_modal_ui(ui, modal);
|
self.qr_message_modal_ui(ui, modal, cb);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -483,11 +483,7 @@ impl WalletMessages {
|
||||||
if text.is_empty() {
|
if text.is_empty() {
|
||||||
self.request_qr = false;
|
self.request_qr = false;
|
||||||
}
|
}
|
||||||
self.request_qr_content.ui(ui, text.clone());
|
self.request_qr_content.ui(ui, text.clone(), cb);
|
||||||
ui.add_space(6.0);
|
|
||||||
|
|
||||||
// Show QR code text.
|
|
||||||
View::ellipsize_text(ui, text, 16.0, Colors::INACTIVE_TEXT);
|
|
||||||
ui.add_space(6.0);
|
ui.add_space(6.0);
|
||||||
|
|
||||||
// Show button to close modal.
|
// Show button to close modal.
|
||||||
|
@ -853,7 +849,7 @@ impl WalletMessages {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw QR code Slatepack message image [`Modal`] content.
|
/// Draw QR code Slatepack message image [`Modal`] content.
|
||||||
fn qr_message_modal_ui(&mut self, ui: &mut egui::Ui, modal: &Modal) {
|
fn qr_message_modal_ui(&mut self, ui: &mut egui::Ui, m: &Modal, cb: &dyn PlatformCallbacks) {
|
||||||
ui.add_space(6.0);
|
ui.add_space(6.0);
|
||||||
|
|
||||||
// Setup title for Slatepack message.
|
// Setup title for Slatepack message.
|
||||||
|
@ -871,11 +867,7 @@ impl WalletMessages {
|
||||||
|
|
||||||
// Draw QR code content.
|
// Draw QR code content.
|
||||||
let text = self.qr_message_text.clone().unwrap();
|
let text = self.qr_message_text.clone().unwrap();
|
||||||
self.qr_message_content.ui(ui, text.clone());
|
self.qr_message_content.ui(ui, text.clone(), cb);
|
||||||
ui.add_space(6.0);
|
|
||||||
|
|
||||||
// Show message text.
|
|
||||||
View::ellipsize_text(ui, text, 16.0, Colors::INACTIVE_TEXT);
|
|
||||||
ui.add_space(6.0);
|
ui.add_space(6.0);
|
||||||
|
|
||||||
ui.vertical_centered_justified(|ui| {
|
ui.vertical_centered_justified(|ui| {
|
||||||
|
@ -884,7 +876,7 @@ impl WalletMessages {
|
||||||
self.qr_message_content.clear_state();
|
self.qr_message_content.clear_state();
|
||||||
self.response_edit.clear();
|
self.response_edit.clear();
|
||||||
self.message_slate = None;
|
self.message_slate = None;
|
||||||
modal.close();
|
m.close();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ui.add_space(6.0);
|
ui.add_space(6.0);
|
||||||
|
|
|
@ -187,7 +187,7 @@ impl WalletTransport {
|
||||||
}
|
}
|
||||||
QR_ADDRESS_MODAL => {
|
QR_ADDRESS_MODAL => {
|
||||||
Modal::ui(ui.ctx(), |ui, modal| {
|
Modal::ui(ui.ctx(), |ui, modal| {
|
||||||
self.qr_address_modal_ui(ui, modal);
|
self.qr_address_modal_ui(ui, modal, cb);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -584,22 +584,18 @@ impl WalletTransport {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw QR code image address [`Modal`] content.
|
/// Draw QR code image address [`Modal`] content.
|
||||||
fn qr_address_modal_ui(&mut self, ui: &mut egui::Ui, modal: &Modal) {
|
fn qr_address_modal_ui(&mut self, ui: &mut egui::Ui, m: &Modal, cb: &dyn PlatformCallbacks) {
|
||||||
ui.add_space(6.0);
|
ui.add_space(6.0);
|
||||||
|
|
||||||
// Draw QR code content.
|
// Draw QR code content.
|
||||||
let text = self.qr_address_content.text.clone();
|
let text = self.qr_address_content.text.clone();
|
||||||
self.qr_address_content.ui(ui, text.clone());
|
self.qr_address_content.ui(ui, text.clone(), cb);
|
||||||
ui.add_space(6.0);
|
ui.add_space(10.0);
|
||||||
|
|
||||||
// Show address.
|
|
||||||
View::ellipsize_text(ui, text, 16.0, Colors::GRAY);
|
|
||||||
ui.add_space(6.0);
|
|
||||||
|
|
||||||
ui.vertical_centered_justified(|ui| {
|
ui.vertical_centered_justified(|ui| {
|
||||||
View::button(ui, t!("close"), Colors::WHITE, || {
|
View::button(ui, t!("close"), Colors::WHITE, || {
|
||||||
self.qr_address_content.clear_state();
|
self.qr_address_content.clear_state();
|
||||||
modal.close();
|
m.close();
|
||||||
});
|
});
|
||||||
ui.add_space(6.0);
|
ui.add_space(6.0);
|
||||||
});
|
});
|
||||||
|
|
|
@ -122,7 +122,7 @@ impl WalletTab for WalletTransactions {
|
||||||
.show_inside(ui, |ui| {
|
.show_inside(ui, |ui| {
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
let data = wallet.get_data().unwrap();
|
let data = wallet.get_data().unwrap();
|
||||||
self.txs_ui(ui, wallet, &data, cb);
|
self.txs_ui(ui, wallet, &data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -142,8 +142,7 @@ impl WalletTransactions {
|
||||||
fn txs_ui(&mut self,
|
fn txs_ui(&mut self,
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
wallet: &mut Wallet,
|
wallet: &mut Wallet,
|
||||||
data: &WalletData,
|
data: &WalletData) {
|
||||||
cb: &dyn PlatformCallbacks) {
|
|
||||||
let amount_conf = data.info.amount_awaiting_confirmation;
|
let amount_conf = data.info.amount_awaiting_confirmation;
|
||||||
let amount_fin = data.info.amount_awaiting_finalization;
|
let amount_fin = data.info.amount_awaiting_finalization;
|
||||||
let amount_locked = data.info.amount_locked;
|
let amount_locked = data.info.amount_locked;
|
||||||
|
@ -224,7 +223,7 @@ impl WalletTransactions {
|
||||||
// Show transaction item.
|
// Show transaction item.
|
||||||
let tx = data.txs.get(index).unwrap();
|
let tx = data.txs.get(index).unwrap();
|
||||||
let rounding = View::item_rounding(index, data.txs.len(), false);
|
let rounding = View::item_rounding(index, data.txs.len(), false);
|
||||||
self.tx_item_ui(ui, tx, rounding, padding, true, &data, wallet, cb);
|
self.tx_item_ui(ui, tx, rounding, padding, true, &data, wallet);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -291,8 +290,7 @@ impl WalletTransactions {
|
||||||
extra_padding: bool,
|
extra_padding: bool,
|
||||||
can_show_info: bool,
|
can_show_info: bool,
|
||||||
data: &WalletData,
|
data: &WalletData,
|
||||||
wallet: &mut Wallet,
|
wallet: &mut Wallet) {
|
||||||
cb: &dyn PlatformCallbacks) {
|
|
||||||
// Setup layout size.
|
// Setup layout size.
|
||||||
let mut rect = ui.available_rect_before_wrap();
|
let mut rect = ui.available_rect_before_wrap();
|
||||||
if extra_padding {
|
if extra_padding {
|
||||||
|
@ -541,7 +539,7 @@ impl WalletTransactions {
|
||||||
|
|
||||||
// Show transaction amount status and time.
|
// Show transaction amount status and time.
|
||||||
let rounding = View::item_rounding(0, 2, false);
|
let rounding = View::item_rounding(0, 2, false);
|
||||||
self.tx_item_ui(ui, tx, rounding, false, false, &data, wallet, cb);
|
self.tx_item_ui(ui, tx, rounding, false, false, &data, wallet);
|
||||||
|
|
||||||
// Show transaction ID info.
|
// Show transaction ID info.
|
||||||
if let Some(id) = tx.data.tx_slate_id {
|
if let Some(id) = tx.data.tx_slate_id {
|
||||||
|
@ -773,11 +771,7 @@ impl WalletTransactions {
|
||||||
self.tx_info_show_qr = false;
|
self.tx_info_show_qr = false;
|
||||||
} else {
|
} else {
|
||||||
// Draw QR code content.
|
// Draw QR code content.
|
||||||
self.tx_info_qr_code_content.ui(ui, text.clone());
|
self.tx_info_qr_code_content.ui(ui, text.clone(), cb);
|
||||||
ui.add_space(6.0);
|
|
||||||
|
|
||||||
// Show QR code text.
|
|
||||||
View::ellipsize_text(ui, text, 16.0, Colors::INACTIVE_TEXT);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue