From b93a2efd5eda11ed0b54431ee5fedd01f258d274 Mon Sep 17 00:00:00 2001 From: ardocrat Date: Tue, 16 Apr 2024 15:24:22 +0300 Subject: [PATCH] build + android + wallet + ui: new lib to get IPs, egui, android and grin deps, add input from soft keyboard to text edit, receive txs, filter txs by account, finalize input (in rework), wallet creation copy/paste buttons --- Cargo.lock | 1020 +++++++++-------- Cargo.toml | 22 +- app/build.gradle | 2 +- app/src/main/AndroidManifest.xml | 1 - .../java/mw/gri/android/MainActivity.java | 34 +- build.gradle | 4 +- build_run_android.sh | 4 + gradle.properties | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- locales/en.yml | 15 +- locales/ru.yml | 17 +- src/gui/app.rs | 23 +- src/gui/platform/android/mod.rs | 34 +- src/gui/views/network/content.rs | 13 +- src/gui/views/root.rs | 40 +- src/gui/views/title_panel.rs | 9 +- src/gui/views/views.rs | 110 +- src/gui/views/wallets/content.rs | 14 +- src/gui/views/wallets/creation/creation.rs | 191 +-- src/gui/views/wallets/creation/mnemonic.rs | 8 +- src/gui/views/wallets/creation/types.rs | 2 +- src/gui/views/wallets/setup/recovery.rs | 16 +- src/gui/views/wallets/wallet/content.rs | 4 +- src/gui/views/wallets/wallet/info.rs | 4 +- src/gui/views/wallets/wallet/receive.rs | 446 +++++-- src/gui/views/wallets/wallet/send.rs | 4 +- src/lib.rs | 18 +- src/main.rs | 5 +- src/node/config.rs | 8 +- src/wallet/mnemonic.rs | 18 + src/wallet/types.rs | 32 + src/wallet/wallet.rs | 137 ++- 32 files changed, 1518 insertions(+), 743 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 253f93f..508d8e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,9 +20,9 @@ checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] name = "accesskit" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76eb1adf08c5bcaa8490b9851fd53cca27fa9880076f178ea9d29f05196728a8" +checksum = "74a4b14f3d99c1255dcba8f45621ab1a2e7540a0009652d33989005a4d0bfc6b" dependencies = [ "enumn", "serde", @@ -30,59 +30,61 @@ dependencies = [ [[package]] name = "accesskit_consumer" -version = "0.15.2" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04bb4d9e4772fe0d47df57d0d5dbe5d85dd05e2f37ae1ddb6b105e76be58fb00" +checksum = "8c17cca53c09fbd7288667b22a201274b9becaa27f0b91bf52a526db95de45e6" dependencies = [ "accesskit", ] [[package]] name = "accesskit_macos" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134d0acf6acb667c89d3332999b1a5df4edbc8d6113910f392ebb73f2b03bb56" +checksum = "cd3b6ae1eabbfbced10e840fd3fce8a93ae84f174b3e4ba892ab7bcb42e477a7" dependencies = [ "accesskit", "accesskit_consumer", - "objc2", + "objc2 0.3.0-beta.3.patch-leaks.3", "once_cell", ] [[package]] name = "accesskit_unix" -version = "0.5.2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e084cb5168790c0c112626175412dc5ad127083441a8248ae49ddf6725519e83" +checksum = "09f46c18d99ba61ad7123dd13eeb0c104436ab6af1df6a1cd8c11054ed394a08" dependencies = [ "accesskit", "accesskit_consumer", - "async-channel 1.9.0", + "async-channel", + "async-once-cell", "atspi", "futures-lite 1.13.0", + "once_cell", "serde", "zbus", ] [[package]] name = "accesskit_windows" -version = "0.14.3" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eac0a7f2d7cd7a93b938af401d3d8e8b7094217989a7c25c55a953023436e31" +checksum = "afcae27ec0974fc7c3b0b318783be89fd1b2e66dd702179fe600166a38ff4a0b" dependencies = [ "accesskit", "accesskit_consumer", - "arrayvec 0.7.4", "once_cell", "paste", + "static_assertions", "windows 0.48.0", ] [[package]] name = "accesskit_winit" -version = "0.14.4" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "825d23acee1bd6d25cbaa3ca6ed6e73faf24122a774ec33d52c5c86c6ab423c0" +checksum = "5284218aca17d9e150164428a0ebc7b955f70e3a9a78b4c20894513aabf98a67" dependencies = [ "accesskit", "accesskit_macos", @@ -166,6 +168,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if 1.0.0", + "getrandom 0.2.14", "once_cell", "serde", "version_check", @@ -189,20 +192,23 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "android-activity" -version = "0.4.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64529721f27c2314ced0890ce45e469574a73e5e6fdd6e9da1860eb29285f5e0" +checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" dependencies = [ "android-properties", - "bitflags 1.3.2", + "bitflags 2.5.0", "cc", + "cesu8", + "jni", "jni-sys", "libc", "log", "ndk", "ndk-context", "ndk-sys", - "num_enum 0.6.1", + "num_enum", + "thiserror", ] [[package]] @@ -251,7 +257,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2041f1943049c7978768d84e6d0fd95de98b76d6c4727b09e78ec253d29fa58" dependencies = [ "clipboard-win", - "core-graphics 0.23.2", + "core-graphics", "image", "log", "objc", @@ -306,6 +312,12 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + [[package]] name = "ash" version = "0.37.3+1.3.251" @@ -327,20 +339,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "1.9.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" +checksum = "136d4d23bcc79e27423727b36823d86233aad06dfea531837b038394d11e9928" dependencies = [ "concurrent-queue", "event-listener 5.3.0", @@ -433,6 +434,12 @@ dependencies = [ "pin-project-lite 0.2.14", ] +[[package]] +name = "async-once-cell" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9338790e78aa95a416786ec8389546c4b6a1dfc3dc36071ed9518a9413a542eb" + [[package]] name = "async-process" version = "1.8.1" @@ -504,29 +511,50 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "atspi" -version = "0.10.1" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "674e7a3376837b2e7d12d34d58ac47073c491dc3bf6f71a7adaf687d4d817faa" +checksum = "6059f350ab6f593ea00727b334265c4dfc7fd442ee32d264794bd9bdc68e87ca" dependencies = [ - "async-recursion", - "async-trait", - "atspi-macros", - "enumflags2", - "futures-lite 1.13.0", - "serde", - "tracing", - "zbus", - "zbus_names", + "atspi-common", + "atspi-connection", + "atspi-proxies", ] [[package]] -name = "atspi-macros" -version = "0.2.0" +name = "atspi-common" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb4870a32c0eaa17e35bca0e6b16020635157121fb7d45593d242c295bc768" +checksum = "92af95f966d2431f962bc632c2e68eda7777330158bf640c4af4249349b2cdf5" dependencies = [ - "quote 1.0.36", - "syn 1.0.109", + "enumflags2", + "serde", + "static_assertions", + "zbus", + "zbus_names", + "zvariant", +] + +[[package]] +name = "atspi-connection" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c65e7d70f86d4c0e3b2d585d9bf3f979f0b19d635a336725a88d279f76b939" +dependencies = [ + "atspi-common", + "atspi-proxies", + "futures-lite 1.13.0", + "zbus", +] + +[[package]] +name = "atspi-proxies" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6495661273703e7a229356dcbe8c8f38223d697aacfaf0e13590a9ac9977bb52" +dependencies = [ + "atspi-common", + "serde", + "zbus", ] [[package]] @@ -699,7 +727,16 @@ version = "0.1.0-beta.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146" dependencies = [ - "objc-sys", + "objc-sys 0.2.0-beta.2", +] + +[[package]] +name = "block-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" +dependencies = [ + "objc-sys 0.3.2", ] [[package]] @@ -708,8 +745,18 @@ version = "0.2.0-alpha.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42" dependencies = [ - "block-sys", - "objc2-encode", + "block-sys 0.1.0-beta.1", + "objc2-encode 2.0.0-pre.2", +] + +[[package]] +name = "block2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" +dependencies = [ + "block-sys 0.2.1", + "objc2 0.4.1", ] [[package]] @@ -718,7 +765,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" dependencies = [ - "async-channel 2.2.0", + "async-channel", "async-lock 3.3.0", "async-task", "fastrand 2.0.2", @@ -815,16 +862,28 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "calloop" -version = "0.10.6" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e0d00eb1ea24371a97d2da6201c6747a633dc6dc1988ef503403b4c59504a8" +checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "log", - "nix 0.25.1", - "slotmap", + "polling 3.6.0", + "rustix 0.38.32", + "slab", "thiserror", - "vec_map", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" +dependencies = [ + "calloop", + "rustix 0.38.32", + "wayland-backend", + "wayland-client", ] [[package]] @@ -939,16 +998,16 @@ dependencies = [ [[package]] name = "cocoa" -version = "0.24.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" +checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" dependencies = [ "bitflags 1.3.2", "block", "cocoa-foundation", "core-foundation 0.9.4", - "core-graphics 0.22.3", - "foreign-types 0.3.2", + "core-graphics", + "foreign-types 0.5.0", "libc", "objc", ] @@ -984,10 +1043,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] -name = "com-rs" -version = "0.2.1" +name = "com" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf43edc576402991846b093a7ca18a3477e0ef9c588cde84964b5d3e43016642" +checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6" +dependencies = [ + "com_macros", +] + +[[package]] +name = "com_macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5" +dependencies = [ + "com_macros_support", + "proc-macro2 1.0.79", + "syn 1.0.109", +] + +[[package]] +name = "com_macros_support" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c" +dependencies = [ + "proc-macro2 1.0.79", + "quote 1.0.36", + "syn 1.0.109", +] [[package]] name = "combine" @@ -1055,19 +1139,6 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" -[[package]] -name = "core-graphics" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "core-graphics-types", - "foreign-types 0.3.2", - "libc", -] - [[package]] name = "core-graphics" version = "0.23.2" @@ -1204,6 +1275,12 @@ dependencies = [ "sct", ] +[[package]] +name = "cursor-icon" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" + [[package]] name = "curve25519-dalek" version = "2.1.3" @@ -1230,17 +1307,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "d3d12" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16e44ab292b1dddfdaf7be62cfd8877df52f2f3fde5858d95bab606be259f20" -dependencies = [ - "bitflags 2.5.0", - "libloading 0.8.3", - "winapi 0.3.9", -] - [[package]] name = "dashmap" version = "5.5.3" @@ -1389,6 +1455,15 @@ dependencies = [ "libloading 0.8.3", ] +[[package]] +name = "document-features" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" +dependencies = [ + "litrs", +] + [[package]] name = "downcast-rs" version = "1.2.1" @@ -1422,9 +1497,9 @@ dependencies = [ [[package]] name = "ecolor" -version = "0.23.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfdf4e52dbbb615cfd30cf5a5265335c217b5fd8d669593cea74a517d9c605af" +checksum = "20930a432bbd57a6d55e07976089708d4893f3d556cf42a0d79e9e321fa73b10" dependencies = [ "bytemuck", "serde", @@ -1455,12 +1530,13 @@ dependencies = [ [[package]] name = "eframe" -version = "0.23.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d9efede6c8905d3fc51a5ec9a506d4da4011bbcae0253d0304580fe40af3f5" +checksum = "020e2ccef6bbcec71dbc542f7eed64a5846fc3076727f5746da8fd307c91bab2" dependencies = [ "bytemuck", "cocoa", + "document-features", "egui", "egui-wgpu", "egui-winit", @@ -1475,12 +1551,14 @@ dependencies = [ "parking_lot 0.12.1", "percent-encoding", "pollster", - "raw-window-handle", + "raw-window-handle 0.5.2", + "raw-window-handle 0.6.0", "static_assertions", "thiserror", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "web-time", "wgpu", "winapi 0.3.9", "winit", @@ -1488,9 +1566,9 @@ dependencies = [ [[package]] name = "egui" -version = "0.23.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd69fed5fcf4fbb8225b24e80ea6193b61e17a625db105ef0c4d71dde6eb8b7" +checksum = "584c5d1bf9a67b25778a3323af222dbe1a1feb532190e103901187f92c7fe29a" dependencies = [ "accesskit", "ahash", @@ -1502,30 +1580,33 @@ dependencies = [ [[package]] name = "egui-wgpu" -version = "0.23.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62d4c9ab93d9528c184ef1d695c8c99b2e6d50833696ec3f513063efeee0fe77" +checksum = "469ff65843f88a702b731a1532b7d03b0e8e96d283e70f3a22b0e06c46cb9b37" dependencies = [ "bytemuck", + "document-features", + "egui", "epaint", "log", "thiserror", "type-map 0.5.0", + "web-time", "wgpu", "winit", ] [[package]] name = "egui-winit" -version = "0.23.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15479a96d9fadccf5dac690bdc6373b97b8e1c0dd28367058f25a5298da0195" +checksum = "2e3da0cbe020f341450c599b35b92de4af7b00abde85624fd16f09c885573609" dependencies = [ "accesskit_winit", "arboard", "egui", "log", - "raw-window-handle", + "raw-window-handle 0.6.0", "smithay-clipboard", "web-time", "webbrowser", @@ -1534,31 +1615,32 @@ dependencies = [ [[package]] name = "egui_extras" -version = "0.23.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ffe3fe5c00295f91c2a61a74ee271c32f74049c94ba0b1cea8f26eb478bc07" +checksum = "1b78779f35ded1a853786c9ce0b43fe1053e10a21ea3b23ebea411805ce41593" dependencies = [ "egui", "enum-map", "image", "log", - "mime_guess", + "mime_guess2", "serde", ] [[package]] name = "egui_glow" -version = "0.23.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6726c08798822280038bbad2e32f4fc3cbed800cd51c6e34e99cd2d60cc1bc" +checksum = "e0e5d975f3c86edc3d35b1db88bb27c15dde7c55d3b5af164968ab5ede3f44ca" dependencies = [ "bytemuck", "egui", "glow", "log", - "memoffset 0.6.5", + "memoffset 0.9.1", "wasm-bindgen", "web-sys", + "winit", ] [[package]] @@ -1569,9 +1651,9 @@ checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "emath" -version = "0.23.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ef2b29de53074e575c18b694167ccbe6e5191f7b25fe65175a0d905a32eeec0" +checksum = "e4c3a552cfca14630702449d35f41c84a0d15963273771c6059175a803620f3f" dependencies = [ "bytemuck", "serde", @@ -1669,9 +1751,9 @@ dependencies = [ [[package]] name = "epaint" -version = "0.23.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58067b840d009143934d91d8dcb8ded054d8301d7c11a517ace0a99bb1e1595e" +checksum = "b381f8b149657a4acf837095351839f32cd5c4aec1817fc4df84e18d76334176" dependencies = [ "ab_glyph", "ahash", @@ -2189,9 +2271,9 @@ dependencies = [ [[package]] name = "glow" -version = "0.12.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0fe580e4b60a8ab24a868bc08e2f03cbcb20d3d676601fa909386713333728" +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" dependencies = [ "js-sys", "slotmap", @@ -2201,11 +2283,11 @@ dependencies = [ [[package]] name = "glutin" -version = "0.30.10" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc93b03242719b8ad39fb26ed2b01737144ce7bd4bfc7adadcef806596760fe" +checksum = "18fcd4ae4e86d991ad1300b8f57166e5be0c95ef1f63f3f5b827f8a164548746" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "cfg_aliases", "cgl", "core-foundation 0.9.4", @@ -2213,42 +2295,43 @@ dependencies = [ "glutin_egl_sys", "glutin_glx_sys", "glutin_wgl_sys", - "libloading 0.7.4", - "objc2", + "icrate", + "libloading 0.8.3", + "objc2 0.4.1", "once_cell", - "raw-window-handle", - "wayland-sys 0.30.1", - "windows-sys 0.45.0", + "raw-window-handle 0.5.2", + "wayland-sys", + "windows-sys 0.48.0", "x11-dl", ] [[package]] name = "glutin-winit" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629a873fc04062830bfe8f97c03773bcd7b371e23bcc465d0a61448cd1588fa4" +checksum = "1ebcdfba24f73b8412c5181e56f092b5eff16671c514ce896b258a0a64bd7735" dependencies = [ "cfg_aliases", "glutin", - "raw-window-handle", + "raw-window-handle 0.5.2", "winit", ] [[package]] name = "glutin_egl_sys" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af784eb26c5a68ec85391268e074f0aa618c096eadb5d6330b0911cf34fe57c5" +checksum = "77cc5623f5309ef433c3dd4ca1223195347fe62c413da8e2fdd0eb76db2d9bcd" dependencies = [ "gl_generator", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "glutin_glx_sys" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b53cb5fe568964aa066a3ba91eac5ecbac869fb0842cd0dc9e412434f1a1494" +checksum = "a165fd686c10dcc2d45380b35796e577eacfd43d4660ee741ec8ebe2201b3b4f" dependencies = [ "gl_generator", "x11-dl", @@ -2256,9 +2339,9 @@ dependencies = [ [[package]] name = "glutin_wgl_sys" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef89398e90033fc6bc65e9bd42fd29bbbfd483bda5b56dc5562f455550618165" +checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" dependencies = [ "gl_generator", ] @@ -2284,15 +2367,15 @@ dependencies = [ [[package]] name = "gpu-allocator" -version = "0.22.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce95f9e2e11c2c6fadfce42b5af60005db06576f231f5c92550fdded43c423e8" +checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884" dependencies = [ - "backtrace", "log", + "presser", "thiserror", "winapi 0.3.9", - "windows 0.44.0", + "windows 0.51.1", ] [[package]] @@ -2345,9 +2428,9 @@ dependencies = [ "grin_wallet_util", "jni", "lazy_static", + "local-ip-address", "log", "openssl-sys", - "pnet", "rand 0.8.5", "rust-i18n", "serde", @@ -2808,14 +2891,14 @@ dependencies = [ [[package]] name = "hassle-rs" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1397650ee315e8891a0df210707f0fc61771b0cc518c3023896064c5407cb3b0" +checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" dependencies = [ - "bitflags 1.3.2", - "com-rs", + "bitflags 2.5.0", + "com", "libc", - "libloading 0.7.4", + "libloading 0.8.3", "thiserror", "widestring", "winapi 0.3.9", @@ -3097,7 +3180,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -3109,6 +3192,17 @@ dependencies = [ "cc", ] +[[package]] +name = "icrate" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" +dependencies = [ + "block2 0.3.0", + "dispatch", + "objc2 0.4.1", +] + [[package]] name = "idna" version = "0.5.0" @@ -3176,9 +3270,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if 1.0.0", - "js-sys", - "wasm-bindgen", - "web-sys", ] [[package]] @@ -3226,15 +3317,6 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" -[[package]] -name = "ipnetwork" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" -dependencies = [ - "serde", -] - [[package]] name = "is-terminal" version = "0.4.12" @@ -3338,12 +3420,12 @@ dependencies = [ [[package]] name = "khronos-egl" -version = "4.1.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading 0.7.4", + "libloading 0.8.3", "pkg-config", ] @@ -3458,6 +3540,12 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "lmdb-zero" version = "0.4.4" @@ -3470,6 +3558,18 @@ dependencies = [ "supercow", ] +[[package]] +name = "local-ip-address" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136ef34e18462b17bf39a7826f8f3bbc223341f8e83822beb8b77db9a3d49696" +dependencies = [ + "libc", + "neli", + "thiserror", + "windows-sys 0.48.0", +] + [[package]] name = "lock_api" version = "0.3.4" @@ -3565,22 +3665,13 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.5.10" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg 1.2.0", -] - [[package]] name = "memoffset" version = "0.7.1" @@ -3601,9 +3692,9 @@ dependencies = [ [[package]] name = "metal" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "623b5e6cefd76e58f774bd3cc0c6f5c7615c58c03a97815245a25c3c9bdee318" +checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25" dependencies = [ "bitflags 2.5.0", "block", @@ -3630,6 +3721,16 @@ dependencies = [ "unicase", ] +[[package]] +name = "mime_guess2" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a3333bb1609500601edc766a39b4c1772874a4ce26022f4d866854dc020c41" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -3672,7 +3773,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", - "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", ] @@ -3723,15 +3823,15 @@ dependencies = [ [[package]] name = "naga" -version = "0.13.0" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ceaaa4eedaece7e4ec08c55c640ba03dbb73fb812a6570a59bcf1930d0f70e" +checksum = "50e3524642f53d9af419ab5e8dd29d3ba155708267667c2f3f06c88c9e130843" dependencies = [ "bit-set", "bitflags 2.5.0", "codespan-reporting", "hexf-parse", - "indexmap 1.9.3", + "indexmap 2.2.6", "log", "num-traits 0.2.18", "rustc-hash", @@ -3761,15 +3861,17 @@ dependencies = [ [[package]] name = "ndk" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "jni-sys", + "log", "ndk-sys", - "num_enum 0.5.11", - "raw-window-handle", + "num_enum", + "raw-window-handle 0.5.2", + "raw-window-handle 0.6.0", "thiserror", ] @@ -3781,13 +3883,38 @@ checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-sys" -version = "0.4.1+23.1.7779620" +version = "0.5.0+25.2.9519653" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" dependencies = [ "jni-sys", ] +[[package]] +name = "neli" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43" +dependencies = [ + "byteorder", + "libc", + "log", + "neli-proc-macros", +] + +[[package]] +name = "neli-proc-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4" +dependencies = [ + "either", + "proc-macro2 1.0.79", + "quote 1.0.36", + "serde", + "syn 1.0.109", +] + [[package]] name = "net2" version = "0.2.39" @@ -3799,31 +3926,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "nix" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" -dependencies = [ - "bitflags 1.3.2", - "cfg-if 1.0.0", - "libc", - "memoffset 0.6.5", -] - -[[package]] -name = "nix" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" -dependencies = [ - "autocfg 1.2.0", - "bitflags 1.3.2", - "cfg-if 1.0.0", - "libc", - "memoffset 0.6.5", -] - [[package]] name = "nix" version = "0.26.4" @@ -3836,12 +3938,6 @@ dependencies = [ "memoffset 0.7.1", ] -[[package]] -name = "no-std-net" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" - [[package]] name = "nodrop" version = "0.1.14" @@ -3979,41 +4075,20 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.11" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ - "num_enum_derive 0.5.11", -] - -[[package]] -name = "num_enum" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" -dependencies = [ - "num_enum_derive 0.6.1", + "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.11" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate", - "proc-macro2 1.0.79", - "quote 1.0.36", - "syn 1.0.109", -] - -[[package]] -name = "num_enum_derive" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" -dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.1.0", "proc-macro2 1.0.79", "quote 1.0.36", "syn 2.0.58", @@ -4046,15 +4121,31 @@ version = "0.2.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7" +[[package]] +name = "objc-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c71324e4180d0899963fc83d9d241ac39e699609fc1025a850aadac8257459" + [[package]] name = "objc2" version = "0.3.0-beta.3.patch-leaks.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468" dependencies = [ - "block2", - "objc-sys", - "objc2-encode", + "block2 0.2.0-alpha.6", + "objc-sys 0.2.0-beta.2", + "objc2-encode 2.0.0-pre.2", +] + +[[package]] +name = "objc2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +dependencies = [ + "objc-sys 0.3.2", + "objc2-encode 3.0.0", ] [[package]] @@ -4063,9 +4154,15 @@ version = "2.0.0-pre.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512" dependencies = [ - "objc-sys", + "objc-sys 0.2.0-beta.2", ] +[[package]] +name = "objc2-encode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" + [[package]] name = "objc_exception" version = "0.1.2" @@ -4367,97 +4464,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[package]] -name = "pnet" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "130c5b738eeda2dc5796fe2671e49027e6935e817ab51b930a36ec9e6a206a64" -dependencies = [ - "ipnetwork", - "pnet_base", - "pnet_datalink", - "pnet_packet", - "pnet_sys", - "pnet_transport", -] - -[[package]] -name = "pnet_base" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cf6fb3ab38b68d01ab2aea03ed3d1132b4868fa4e06285f29f16da01c5f4c" -dependencies = [ - "no-std-net", -] - -[[package]] -name = "pnet_datalink" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad5854abf0067ebbd3967f7d45ebc8976ff577ff0c7bd101c4973ae3c70f98fe" -dependencies = [ - "ipnetwork", - "libc", - "pnet_base", - "pnet_sys", - "winapi 0.3.9", -] - -[[package]] -name = "pnet_macros" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688b17499eee04a0408aca0aa5cba5fc86401d7216de8a63fdf7a4c227871804" -dependencies = [ - "proc-macro2 1.0.79", - "quote 1.0.36", - "regex", - "syn 2.0.58", -] - -[[package]] -name = "pnet_macros_support" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eea925b72f4bd37f8eab0f221bbe4c78b63498350c983ffa9dd4bcde7e030f56" -dependencies = [ - "pnet_base", -] - -[[package]] -name = "pnet_packet" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a005825396b7fe7a38a8e288dbc342d5034dac80c15212436424fef8ea90ba" -dependencies = [ - "glob", - "pnet_base", - "pnet_macros", - "pnet_macros_support", -] - -[[package]] -name = "pnet_sys" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "417c0becd1b573f6d544f73671070b039051e5ad819cc64aa96377b536128d00" -dependencies = [ - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "pnet_transport" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2637e14d7de974ee2f74393afccbc8704f3e54e6eb31488715e72481d1662cc3" -dependencies = [ - "libc", - "pnet_base", - "pnet_packet", - "pnet_sys", -] - [[package]] name = "png" version = "0.17.13" @@ -4525,6 +4531,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + [[package]] name = "prettytable-rs" version = "0.10.0" @@ -4549,6 +4561,15 @@ dependencies = [ "toml_edit 0.19.15", ] +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -4609,6 +4630,15 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "0.6.13" @@ -4817,18 +4847,18 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "range-alloc" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" - [[package]] name = "raw-window-handle" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" +[[package]] +name = "raw-window-handle" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" + [[package]] name = "rayon" version = "1.10.0" @@ -5240,9 +5270,9 @@ dependencies = [ [[package]] name = "sctk-adwaita" -version = "0.5.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda4e97be1fd174ccc2aae81c8b694e803fa99b34e8fd0f057a9d70698e3ed09" +checksum = "82b2eaf3a5b264a521b988b2e73042e742df700c4f962cde845d1541adb46550" dependencies = [ "ab_glyph", "log", @@ -5528,31 +5558,47 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smithay-client-toolkit" -version = "0.16.1" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870427e30b8f2cbe64bf43ec4b86e88fe39b0a84b3f15efd9c9c2d020bc86eb9" +checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "calloop", - "dlib", - "lazy_static", + "calloop-wayland-source", + "cursor-icon", + "libc", "log", "memmap2", - "nix 0.24.3", - "pkg-config", + "rustix 0.38.32", + "thiserror", + "wayland-backend", "wayland-client", + "wayland-csd-frame", "wayland-cursor", "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", ] [[package]] name = "smithay-clipboard" -version = "0.6.6" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a345c870a1fae0b1b779085e81b51e614767c239e93503588e54c5b17f4b0e8" +checksum = "c091e7354ea8059d6ad99eace06dd13ddeedbb0ac72d40a9a6e7ff790525882d" dependencies = [ + "libc", "smithay-client-toolkit", - "wayland-client", + "wayland-backend", +] + +[[package]] +name = "smol_str" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49" +dependencies = [ + "serde", ] [[package]] @@ -5594,12 +5640,11 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spirv" -version = "0.2.0+1.5.4" +version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 1.3.2", - "num-traits 0.2.18", + "bitflags 2.5.0", ] [[package]] @@ -5802,23 +5847,23 @@ dependencies = [ [[package]] name = "tiny-skia" -version = "0.8.4" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" dependencies = [ "arrayref", "arrayvec 0.7.4", "bytemuck", "cfg-if 1.0.0", - "png", + "log", "tiny-skia-path", ] [[package]] name = "tiny-skia-path" -version = "0.8.4" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adbfb5d3f3dd57a0e11d12f4f13d4ebbbc1b5c15b7ab0a156d030b21da5f677c" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" dependencies = [ "arrayref", "bytemuck", @@ -6068,6 +6113,17 @@ dependencies = [ "winnow 0.5.40", ] +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + [[package]] name = "toml_edit" version = "0.22.9" @@ -6316,12 +6372,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.4" @@ -6434,87 +6484,111 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] -name = "wayland-client" -version = "0.29.5" +name = "wayland-backend" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" +checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40" dependencies = [ - "bitflags 1.3.2", + "cc", "downcast-rs", - "libc", - "nix 0.24.3", + "rustix 0.38.32", "scoped-tls", - "wayland-commons", - "wayland-scanner", - "wayland-sys 0.29.5", + "smallvec", + "wayland-sys", ] [[package]] -name = "wayland-commons" -version = "0.29.5" +name = "wayland-client" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" +checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f" dependencies = [ - "nix 0.24.3", - "once_cell", - "smallvec", - "wayland-sys 0.29.5", + "bitflags 2.5.0", + "rustix 0.38.32", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.5.0", + "cursor-icon", + "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.29.5" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" +checksum = "71ce5fa868dd13d11a0d04c5e2e65726d0897be8de247c0c5a65886e283231ba" dependencies = [ - "nix 0.24.3", + "rustix 0.38.32", "wayland-client", "xcursor", ] [[package]] name = "wayland-protocols" -version = "0.29.5" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" +checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", + "wayland-backend", "wayland-client", - "wayland-commons", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" +dependencies = [ + "bitflags 2.5.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" +dependencies = [ + "bitflags 2.5.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", "wayland-scanner", ] [[package]] name = "wayland-scanner" -version = "0.29.5" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" +checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283" dependencies = [ "proc-macro2 1.0.79", + "quick-xml", "quote 1.0.36", - "xml-rs", ] [[package]] name = "wayland-sys" -version = "0.29.5" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" +checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af" dependencies = [ "dlib", - "lazy_static", - "pkg-config", -] - -[[package]] -name = "wayland-sys" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b2a02ac608e07132978689a6f9bf4214949c85998c247abadd4f4129b1aa06" -dependencies = [ - "dlib", - "lazy_static", "log", + "once_cell", "pkg-config", ] @@ -6550,7 +6624,7 @@ dependencies = [ "log", "ndk-context", "objc", - "raw-window-handle", + "raw-window-handle 0.5.2", "url", "web-sys", ] @@ -6582,18 +6656,19 @@ checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" [[package]] name = "wgpu" -version = "0.17.2" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "752e44d3998ef35f71830dd1ad3da513e628e2e4d4aedb0ab580f850827a0b41" +checksum = "a4b1213b52478a7631d6e387543ed8f642bc02c578ef4e3b49aca2a29a7df0cb" dependencies = [ "arrayvec 0.7.4", "cfg-if 1.0.0", + "cfg_aliases", "js-sys", "log", "naga", "parking_lot 0.12.1", "profiling", - "raw-window-handle", + "raw-window-handle 0.6.0", "smallvec", "static_assertions", "wasm-bindgen", @@ -6606,19 +6681,22 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.17.1" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f8a44dd301a30ceeed3c27d8c0090433d3da04d7b2a4042738095a424d12ae7" +checksum = "f9f6b033c2f00ae0bc8ea872c5989777c60bc241aac4e58b24774faa8b391f78" dependencies = [ "arrayvec 0.7.4", "bit-vec", "bitflags 2.5.0", + "cfg_aliases", "codespan-reporting", + "indexmap 2.2.6", "log", "naga", + "once_cell", "parking_lot 0.12.1", "profiling", - "raw-window-handle", + "raw-window-handle 0.6.0", "rustc-hash", "smallvec", "thiserror", @@ -6629,19 +6707,19 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "0.17.2" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a80bf0e3c77399bb52850cb0830af9bad073d5cfcb9dd8253bef8125c42db17" +checksum = "49f972c280505ab52ffe17e94a7413d9d54b58af0114ab226b9fc4999a47082e" dependencies = [ "android_system_properties", "arrayvec 0.7.4", "ash", - "bit-set", "bitflags 2.5.0", "block", + "cfg_aliases", "core-graphics-types", - "d3d12", "glow", + "glutin_wgl_sys", "gpu-alloc", "gpu-allocator", "gpu-descriptor", @@ -6653,11 +6731,12 @@ dependencies = [ "log", "metal", "naga", + "ndk-sys", "objc", + "once_cell", "parking_lot 0.12.1", "profiling", - "range-alloc", - "raw-window-handle", + "raw-window-handle 0.6.0", "renderdoc-sys", "rustc-hash", "smallvec", @@ -6670,9 +6749,9 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "0.17.0" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee64d7398d0c2f9ca48922c902ef69c42d000c759f3db41e355f4a570b052b67" +checksum = "b671ff9fb03f78b46ff176494ee1ebe7d603393f42664be55b64dc8d53969805" dependencies = [ "bitflags 2.5.0", "js-sys", @@ -6728,15 +6807,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.44.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows" version = "0.48.0" @@ -6748,6 +6818,25 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +dependencies = [ + "windows-core 0.51.1", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -6986,37 +7075,51 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winit" -version = "0.28.7" +version = "0.29.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9596d90b45384f5281384ab204224876e8e8bf7d58366d9b795ad99aa9894b94" +checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" dependencies = [ + "ahash", "android-activity", - "bitflags 1.3.2", + "atomic-waker", + "bitflags 2.5.0", + "bytemuck", + "calloop", "cfg_aliases", "core-foundation 0.9.4", - "core-graphics 0.22.3", - "dispatch", - "instant", + "core-graphics", + "cursor-icon", + "icrate", + "js-sys", "libc", "log", - "mio 0.8.11", + "memmap2", "ndk", - "objc2", + "ndk-sys", + "objc2 0.4.1", "once_cell", "orbclient", "percent-encoding", - "raw-window-handle", + "raw-window-handle 0.5.2", + "raw-window-handle 0.6.0", "redox_syscall 0.3.5", + "rustix 0.38.32", "sctk-adwaita", "smithay-client-toolkit", + "smol_str", + "unicode-segmentation", "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", "wayland-client", - "wayland-commons", "wayland-protocols", - "wayland-scanner", + "wayland-protocols-plasma", "web-sys", - "windows-sys 0.45.0", + "web-time", + "windows-sys 0.48.0", "x11-dl", + "x11rb", + "xkbcommon-dl", ] [[package]] @@ -7073,7 +7176,11 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a" dependencies = [ + "as-raw-xcb-connection", "gethostname", + "libc", + "libloading 0.8.3", + "once_cell", "rustix 0.38.32", "x11rb-protocol", ] @@ -7122,6 +7229,25 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.5.0", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054a8e68b76250b253f671d1268cb7f1ae089ec35e195b2efb2a4e9a836d0621" + [[package]] name = "xml-rs" version = "0.8.20" @@ -7161,7 +7287,7 @@ dependencies = [ "futures-sink", "futures-util", "hex", - "nix 0.26.4", + "nix", "once_cell", "ordered-stream", "rand 0.8.5", @@ -7184,7 +7310,7 @@ version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2 1.0.79", "quote 1.0.36", "regex", @@ -7274,7 +7400,7 @@ version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2 1.0.79", "quote 1.0.36", "syn 1.0.109", diff --git a/Cargo.toml b/Cargo.toml index 61e8152..30de838 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,24 +33,24 @@ grin_wallet_util = { git = "https://github.com/mimblewimble/grin-wallet", branch grin_wallet_controller = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" } ## ui -egui = { version = "0.23.0", default-features = false } -egui_extras = { version = "0.23.0", features = ["image"] } +egui = { version = "0.27.2", default-features = false } +egui_extras = { version = "0.27.2", features = ["image"] } rust-i18n = "2.1.0" ## other futures = "0.3" dirs = "5.0.1" sys-locale = "0.3.0" -chrono = "0.4.37" +chrono = "0.4.31" lazy_static = "1.4.0" toml = "0.8.2" serde = "1.0.170" -pnet = "0.34.0" +local-ip-address = "0.6.1" url = "2.4.0" # stratum server -serde_derive = "1" -serde_json = "1" +serde_derive = "1.0.197" +serde_json = "1.0.115" tokio = {version = "1.29.1", features = ["full"] } tokio-util = { version = "0.7.8", features = ["codec"] } rand = "0.8.5" @@ -60,13 +60,13 @@ built = { version = "0.7.0", features = ["git2"]} [target.'cfg(not(target_os = "android"))'.dependencies] env_logger = "0.10.0" -winit = { version = "0.28" } -eframe = { version = "0.23.0", features = [ "wgpu" ] } +winit = { version = "0.29.15" } +eframe = { version = "0.27.2", features = [ "wgpu" ] } arboard = "3.2.0" [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.13.1" jni = "0.21.1" -android-activity = "0.4.3" -winit = { version = "0.28", features = [ "android-game-activity" ] } -eframe = { version = "0.23.0", features = [ "wgpu", "android-game-activity" ] } \ No newline at end of file +android-activity = "0.5.2" +winit = { version = "0.29", features = [ "android-game-activity" ] } +eframe = { version = "0.27.2", features = [ "wgpu", "android-game-activity" ] } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3701d99..1431656 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,7 +41,7 @@ dependencies { //implementation "androidx.games:games-performance-tuner:1.5.0" // To use the Games Activity library - implementation "androidx.games:games-activity:1.1.0" + implementation "androidx.games:games-activity:2.0.2" // To use the Games Controller Library //implementation "androidx.games:games-controller:1.1.0" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5a889f0..f28299c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,7 +3,6 @@ > - diff --git a/app/src/main/java/mw/gri/android/MainActivity.java b/app/src/main/java/mw/gri/android/MainActivity.java index 56b67b3..a595211 100644 --- a/app/src/main/java/mw/gri/android/MainActivity.java +++ b/app/src/main/java/mw/gri/android/MainActivity.java @@ -7,6 +7,7 @@ import android.system.ErrnoException; import android.system.Os; import android.view.KeyEvent; import android.view.View; +import android.view.inputmethod.InputMethodManager; import androidx.core.graphics.Insets; import androidx.core.view.DisplayCutoutCompat; import androidx.core.view.ViewCompat; @@ -80,12 +81,33 @@ public class MainActivity extends GameActivity { }); } + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + // To support non-english input. + if (event.getAction() == KeyEvent.ACTION_MULTIPLE && event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN) { + if (!event.getCharacters().isEmpty()) { + onInput(event.getCharacters()); + return false; + } + // Pass any other input values into native code. + } else if (event.getAction() == KeyEvent.ACTION_UP && + event.getKeyCode() != KeyEvent.KEYCODE_ENTER && + event.getKeyCode() != KeyEvent.KEYCODE_BACK) { + onInput(String.valueOf((char)event.getUnicodeChar())); + return false; + } + return super.dispatchKeyEvent(event); + } + + // Provide last entered character from soft keyboard into native code. + public native void onInput(String character); + // Implemented into native code to handle display insets change. native void onDisplayInsets(int[] cutouts); @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { + if (keyCode == KeyEvent.KEYCODE_BACK) { onBack(); return true; } @@ -146,4 +168,14 @@ public class MainActivity extends GameActivity { } return text; } + + public void showKeyboard() { + InputMethodManager imm = (InputMethodManager )getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(getWindow().getDecorView(), InputMethodManager.SHOW_IMPLICIT); + } + + public void hideKeyboard() { + InputMethodManager imm = (InputMethodManager )getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0); + } } \ No newline at end of file diff --git a/build.gradle b/build.gradle index 44ca6e4..3d408a5 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '7.4.1' apply false - id 'com.android.library' version '7.4.1' apply false + id 'com.android.application' version '8.1.0' apply false + id 'com.android.library' version '8.1.0' apply false } task clean(type: Delete) { diff --git a/build_run_android.sh b/build_run_android.sh index d4e08d5..d39b007 100755 --- a/build_run_android.sh +++ b/build_run_android.sh @@ -29,6 +29,10 @@ type=$1 [[ $2 == "v7" ]] && platform+=(armv7-linux-androideabi) [[ $2 == "v8" ]] && platform+=(aarch64-linux-android) +# Install platform +[[ $2 == "v7" ]] && rustup target install armv7-linux-androideabi +[[ $2 == "v8" ]] && rustup target install aarch64-linux-android + export CPPFLAGS="-DMDB_USE_ROBUST=0" && export CFLAGS="-DMDB_USE_ROBUST=0" \ && cargo ndk -t ${arch} build ${release_param[@]} diff --git a/gradle.properties b/gradle.properties index dab7c28..ec63151 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,4 +18,6 @@ android.useAndroidX=true # Enables namespacing of each library's R class so that its R class includes only the # resources declared in the library itself and none from the library's dependencies, # thereby reducing the size of the R class for that library -android.nonTransitiveRClass=true \ No newline at end of file +android.nonTransitiveRClass=true +android.defaults.buildfeatures.buildconfig=true +android.nonFinalResIds=false \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0460660..5538f03 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Mon May 02 15:39:12 BST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/locales/en.yml b/locales/en.yml index 4e62b5d..bc5287a 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -64,11 +64,18 @@ wallets: tx_canceled: Canceled tx_confirmed: Confirmed manually: Manually - receive_paste_slatepack: 'Enter Slatepack message received from the sender to create a response:' - receive_send_slatepack: 'Send response to the sender to finalize the transaction:' - receive_slatepack_err: An error occurred during creation of the response, check input data. - response_copied: Response copied to the clipboard. + receive_slatepack_desc: 'Enter Slatepack message received from the sender to create response or finalize the transaction:' + receive_send_slatepack: 'Send Slatepack message to the sender to finalize the transaction:' + receive_slatepack_err: 'An error occurred during creation of the response, check input data:' create_response: Create response + invoice: Invoice + issue_invoice: Issue invoice + issue_invoice_desc: 'Create a request to receive funds by entering the required amount:' + invoice_desc: 'You have created a request to receive %{amount} ツ. Send Slatepack message to the sender:' + invoice_slatepack_err: An error occurred during issuing of the invoice, check input data. + finalize_slatepack_err: 'An error occurred during finalization of the transaction, check input data:' + finalize: Finalize + enter_amount: 'Enter amount:' recovery: Recovery repair_wallet: Repair wallet repair_desc: Check a wallet, repairing and restoring missing outputs if required. This operation will take time. diff --git a/locales/ru.yml b/locales/ru.yml index 58e76f6..40bffd5 100644 --- a/locales/ru.yml +++ b/locales/ru.yml @@ -44,7 +44,7 @@ wallets: locked: Заблокирован unlocked: Разблокирован enable_node: 'Чтобы использовать кошелёк, включите встроенный узел или измените настройки подключения, выбрав %{settings} внизу экрана.' - node_loading: Кошелёк будет загружен после синхронизации встроенного узла, вы можете изменить настройки подключения, выбрав %{settings} внизу экрана. + node_loading: 'Кошелёк будет загружен после синхронизации встроенного узла, вы можете изменить настройки подключения, выбрав %{settings} внизу экрана.' loading: Загружается closing: Закрывается checking: Проверяется @@ -64,11 +64,18 @@ wallets: tx_canceled: Отменено tx_confirmed: Подтверждено manually: Вручную - receive_paste_slatepack: 'Введите Slatepack сообщение, полученное от отправителя для создания ответа:' - receive_send_slatepack: 'Отправьте ответ отправителю для завершения транзакции:' - receive_slatepack_err: Во время создания ответа произошла ошибка, проверьте входные данные. - response_copied: Ответ скопирован в буфер обмена. + receive_slatepack_desc: 'Введите Slatepack сообщение, полученное от отправителя, для создания ответа или завершения транзакции:' + receive_send_slatepack: 'Отправьте Slatepack сообщение отправителю для завершения транзакции:' + receive_slatepack_err: 'Во время создания ответа произошла ошибка, проверьте входные данные:' create_response: Создать ответ + invoice: Инвойс + issue_invoice: Выставить счёт + issue_invoice_desc: 'Создайте запрос на получение средств, введя требуемое количество:' + invoice_desc: 'Вы создали запрос на получение %{amount} ツ. Отправьте Slatepack сообщение отправителю:' + invoice_slatepack_err: Во время выставления счёта произошла ошибка, проверьте входные данные. + finalize_slatepack_err: 'Во время завершения транзакции произошла ошибка, проверьте входные данные:' + finalize: Завершить + enter_amount: 'Введите количество:' recovery: Восстановление repair_wallet: Починить кошелёк repair_desc: Проверить кошелёк, исправляя и восстанавливая недостающие выходы, если это необходимо. Эта операция займёт время. diff --git a/src/gui/app.rs b/src/gui/app.rs index d2c6e2d..93e81d1 100644 --- a/src/gui/app.rs +++ b/src/gui/app.rs @@ -45,12 +45,21 @@ impl eframe::App for PlatformApp { // Handle Esc keyboard key event and platform Back button key event. let back_button_pressed = BACK_BUTTON_PRESSED.load(Ordering::Relaxed); if ctx.input_mut(|i| i.consume_key(Modifiers::NONE, egui::Key::Escape)) || back_button_pressed { - if back_button_pressed { - BACK_BUTTON_PRESSED.store(false, Ordering::Relaxed); - } self.root.on_back(); // Request repaint to update previous content. ctx.request_repaint(); + + if back_button_pressed { + BACK_BUTTON_PRESSED.store(false, Ordering::Relaxed); + } + } + + // Handle Close event (on desktop). + if ctx.input(|i| i.viewport().close_requested()) { + if !self.root.exit_allowed { + ctx.send_viewport_cmd(egui::ViewportCommand::CancelClose); + Root::show_exit_modal(); + } } // Show main content. @@ -63,14 +72,6 @@ impl eframe::App for PlatformApp { self.root.ui(ui, frame, &self.platform); }); } - - fn on_close_event(&mut self) -> bool { - let exit = self.root.exit_allowed; - if !exit { - Root::show_exit_modal(); - } - exit - } } #[allow(dead_code)] diff --git a/src/gui/platform/android/mod.rs b/src/gui/platform/android/mod.rs index 0a8eaae..264e945 100644 --- a/src/gui/platform/android/mod.rs +++ b/src/gui/platform/android/mod.rs @@ -30,11 +30,41 @@ impl Android { impl PlatformCallbacks for Android { fn show_keyboard(&self) { - self.android_app.show_soft_input(true); + // Disable NDK soft input show call before fix for egui. + // self.android_app.show_soft_input(false); + + use jni::objects::{JObject}; + + let vm = unsafe { jni::JavaVM::from_raw(self.android_app.vm_as_ptr() as _) }.unwrap(); + let mut env = vm.attach_current_thread().unwrap(); + let activity = unsafe { + JObject::from_raw(self.android_app.activity_as_ptr() as jni::sys::jobject) + }; + let _ = env.call_method( + activity, + "showKeyboard", + "()V", + &[] + ).unwrap(); } fn hide_keyboard(&self) { - self.android_app.hide_soft_input(true); + // Disable NDK soft input hide call before fix for egui. + // self.android_app.hide_soft_input(false); + + use jni::objects::{JObject}; + + let vm = unsafe { jni::JavaVM::from_raw(self.android_app.vm_as_ptr() as _) }.unwrap(); + let mut env = vm.attach_current_thread().unwrap(); + let activity = unsafe { + JObject::from_raw(self.android_app.activity_as_ptr() as jni::sys::jobject) + }; + let _ = env.call_method( + activity, + "hideKeyboard", + "()V", + &[] + ).unwrap(); } fn copy_string_to_buffer(&self, data: String) { diff --git a/src/gui/views/network/content.rs b/src/gui/views/network/content.rs index c34656f..4abf9c0 100644 --- a/src/gui/views/network/content.rs +++ b/src/gui/views/network/content.rs @@ -12,8 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{RichText, ScrollArea, Stroke}; -use egui::style::Margin; +use egui::{Margin, RichText, ScrollArea, Stroke}; use crate::AppConfig; use crate::gui::Colors; @@ -57,7 +56,7 @@ impl NetworkContent { fill: Colors::FILL, inner_margin: Margin { left: View::get_left_inset() + 4.0, - right: View::far_right_inset_margin(ui, frame) + 4.0, + right: View::far_right_inset_margin(ui) + 4.0, top: 4.0, bottom: View::get_bottom_inset() + 4.0, }, @@ -82,7 +81,7 @@ impl NetworkContent { stroke: View::DEFAULT_STROKE, inner_margin: Margin { left: View::get_left_inset() + 4.0, - right: View::far_right_inset_margin(ui, frame) + 4.0, + right: View::far_right_inset_margin(ui) + 4.0, top: 3.0, bottom: 4.0, }, @@ -108,7 +107,7 @@ impl NetworkContent { 0.0 }, right: if show_connections { - View::far_right_inset_margin(ui, frame) + 4.0 + View::far_right_inset_margin(ui) + 4.0 } else { 0.0 }, @@ -128,7 +127,7 @@ impl NetworkContent { .show(ui, |ui| { ui.add_space(1.0); ui.vertical_centered(|ui| { - let max_width = if !Root::is_dual_panel_mode(frame) { + let max_width = if !Root::is_dual_panel_mode(ui) { Root::SIDE_PANEL_WIDTH * 1.3 } else { ui.available_width() @@ -212,7 +211,7 @@ impl NetworkContent { }); } }, |ui, frame| { - if !Root::is_dual_panel_mode(frame) { + if !Root::is_dual_panel_mode(ui) { View::title_button(ui, CARDHOLDER, || { Root::toggle_network_panel(); }); diff --git a/src/gui/views/root.rs b/src/gui/views/root.rs index 8f886e6..b91598c 100644 --- a/src/gui/views/root.rs +++ b/src/gui/views/root.rs @@ -13,7 +13,6 @@ // limitations under the License. use std::sync::atomic::{AtomicBool, Ordering}; - use egui::os::OperatingSystem; use egui::RichText; use lazy_static::lazy_static; @@ -70,11 +69,11 @@ impl ModalContainer for Root { fn modal_ui(&mut self, ui: &mut egui::Ui, - frame: &mut eframe::Frame, + _: &mut eframe::Frame, modal: &Modal, _: &dyn PlatformCallbacks) { match modal.id { - Self::EXIT_MODAL_ID => self.exit_modal_content(ui, frame, modal), + Self::EXIT_MODAL_ID => self.exit_modal_content(ui, modal), _ => {} } } @@ -91,7 +90,7 @@ impl Root { // Draw modal content for current ui container. self.current_modal_ui(ui, frame, cb); - let (is_panel_open, panel_width) = Self::network_panel_state_width(frame); + let (is_panel_open, panel_width) = Self::network_panel_state_width(ui); // Show network content. egui::SidePanel::left("network_panel") .resizable(false) @@ -103,7 +102,8 @@ impl Root { .show_animated_inside(ui, is_panel_open, |ui| { // Set content height as window height. let mut rect = ui.available_rect_before_wrap(); - rect.set_height(frame.info().window_info.size.y); + let window_size = View::window_size(ui); + rect.set_height(window_size.1); ui.allocate_ui_at_rect(rect, |ui| { self.network.ui(ui, frame, cb); }); @@ -118,7 +118,8 @@ impl Root { .show_inside(ui, |ui| { // Set content height as window height. let mut rect = ui.available_rect_before_wrap(); - rect.set_height(frame.info().window_info.size.y); + let window_size = View::window_size(ui); + rect.set_height(window_size.1); ui.allocate_ui_at_rect(rect, |ui| { self.wallets.ui(ui, frame, cb); }); @@ -126,21 +127,20 @@ impl Root { } /// Get [`NetworkContent`] panel state and width. - fn network_panel_state_width(frame: &mut eframe::Frame) -> (bool, f32) { - let dual_panel_mode = Self::is_dual_panel_mode(frame); + fn network_panel_state_width(ui: &mut egui::Ui) -> (bool, f32) { + let dual_panel_mode = Self::is_dual_panel_mode(ui); let is_panel_open = dual_panel_mode || Self::is_network_panel_open(); let panel_width = if dual_panel_mode { Self::SIDE_PANEL_WIDTH + View::get_left_inset() } else { - frame.info().window_info.size.x + View::window_size(ui).0 }; (is_panel_open, panel_width) } /// Check if ui can show [`NetworkContent`] and [`WalletsContent`] at same time. - pub fn is_dual_panel_mode(frame: &mut eframe::Frame) -> bool { - let w = frame.info().window_info.size.x; - let h = frame.info().window_info.size.y; + pub fn is_dual_panel_mode(ui: &mut egui::Ui) -> bool { + let (w, h) = View::window_size(ui); // Screen is wide if width is greater than height or just 20% smaller. let is_wide_screen = w > h || w + (w * 0.2) >= h; // Dual panel mode is available when window is wide and its width is at least 2 times @@ -168,10 +168,11 @@ impl Root { } /// Draw exit confirmation modal content. - fn exit_modal_content(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, modal: &Modal) { + fn exit_modal_content(&mut self, ui: &mut egui::Ui, modal: &Modal) { if self.show_exit_progress { if !Node::is_running() { - self.exit(frame); + self.exit_allowed = true; + ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close); modal.close(); } ui.add_space(16.0); @@ -199,9 +200,10 @@ impl Root { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal_exit.exit"), Colors::WHITE, || { + View::button_ui(ui, t!("modal_exit.exit"), Colors::WHITE, |ui| { if !Node::is_running() { - self.exit(frame); + self.exit_allowed = true; + ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close); modal.close(); } else { Node::stop(true); @@ -221,12 +223,6 @@ impl Root { } } - /// Exit from the application. - fn exit(&mut self, frame: &mut eframe::Frame) { - self.exit_allowed = true; - frame.close(); - } - /// Handle Back key event. pub fn on_back(&mut self) { if Modal::on_back() { diff --git a/src/gui/views/title_panel.rs b/src/gui/views/title_panel.rs index db52a86..43fdccf 100644 --- a/src/gui/views/title_panel.rs +++ b/src/gui/views/title_panel.rs @@ -12,8 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{Color32, Id, lerp, Rgba}; -use egui::style::Margin; +use egui::{Margin, Color32, Id, lerp, Rgba}; use egui_extras::{Size, Strip, StripBuilder}; use crate::gui::Colors; @@ -59,7 +58,7 @@ impl TitlePanel { .resizable(false) .exact_height(Self::DEFAULT_HEIGHT) .frame(egui::Frame { - inner_margin: Self::inner_margin(ui, frame), + inner_margin: Self::inner_margin(ui), fill: Colors::YELLOW, ..Default::default() }) @@ -132,10 +131,10 @@ impl TitlePanel { } /// Calculate inner margin based on display insets (cutouts). - fn inner_margin(ui: &mut egui::Ui, frame: &mut eframe::Frame) -> Margin { + fn inner_margin(ui: &mut egui::Ui) -> Margin { Margin { left: View::far_left_inset_margin(ui), - right: View::far_right_inset_margin(ui, frame), + right: View::far_right_inset_margin(ui), top: View::get_top_inset(), bottom: 0.0, } diff --git a/src/gui/views/views.rs b/src/gui/views/views.rs index e52962e..01a8894 100644 --- a/src/gui/views/views.rs +++ b/src/gui/views/views.rs @@ -12,13 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::ops::Add; use std::sync::atomic::{AtomicI32, Ordering}; +use std::sync::{Arc, RwLock}; +use lazy_static::lazy_static; -use egui::{Align, Button, CursorIcon, Layout, PointerState, Rect, Response, RichText, Sense, Spinner, TextStyle, Vec2, Widget}; +use egui::{Align, Button, CursorIcon, Layout, PointerState, Rect, Response, RichText, Sense, Spinner, TextBuffer, TextStyle, Widget}; use egui::epaint::{CircleShape, Color32, FontId, RectShape, Rounding, Stroke}; use egui::epaint::text::TextWrapping; +use egui::os::OperatingSystem; use egui::text::{LayoutJob, TextFormat}; -use lazy_static::lazy_static; +use egui::text_edit::TextEditState; use crate::gui::Colors; use crate::gui::icons::{CHECK_SQUARE, CLIPBOARD_TEXT, COPY, EYE, EYE_SLASH, SQUARE}; @@ -54,6 +58,21 @@ impl View { }); } + /// Get width and height of app window. + pub fn window_size(ui: &mut egui::Ui) -> (f32, f32) { + ui.ctx().input(|i| { + return match i.viewport().inner_rect { + None => { + let size = i.viewport().monitor_size.unwrap(); + (size.x, size.y) + } + Some(rect) => { + (rect.width(), rect.height()) + } + }; + }) + } + /// Callback on Enter key press event. pub fn on_enter_key(ui: &mut egui::Ui, cb: impl FnOnce()) { if ui.ctx().input(|i| i.key_pressed(egui::Key::Enter)) { @@ -71,9 +90,10 @@ impl View { } /// Calculate margin for far left view based on display insets (cutouts). - pub fn far_right_inset_margin(ui: &mut egui::Ui, frame: &mut eframe::Frame) -> f32 { + pub fn far_right_inset_margin(ui: &mut egui::Ui) -> f32 { let container_width = ui.available_rect_before_wrap().max.x as i32; - let display_width = frame.info().window_info.size.x as i32; + let window_size = Self::window_size(ui); + let display_width = window_size.0 as i32; // Means end of the screen. if container_width == display_width { Self::get_right_inset() @@ -198,6 +218,19 @@ impl View { } } + /// Draw [`Button`] with specified background fill color. + pub fn button_ui(ui: &mut egui::Ui, text: String, fill: Color32, action: impl FnOnce(&mut egui::Ui)) { + let button_text = Self::ellipsize(text.to_uppercase(), 17.0, Colors::TEXT_BUTTON); + let br = Button::new(button_text) + .stroke(Self::DEFAULT_STROKE) + .fill(fill) + .ui(ui) + .on_hover_cursor(CursorIcon::PointingHand); + if Self::touched(ui, br) { + (action)(ui); + } + } + /// Draw list item [`Button`] with provided rounding. pub fn item_button(ui: &mut egui::Ui, rounding: Rounding, @@ -336,15 +369,17 @@ impl View { // Setup text edit size. let mut edit_rect = ui.available_rect_before_wrap(); edit_rect.set_height(Self::TEXT_EDIT_HEIGHT); + // Show text edit. let text_edit_resp = egui::TextEdit::singleline(value) .id(options.id) - .margin(Vec2::new(2.0, 0.0)) + .margin(egui::Vec2::new(2.0, 0.0)) .font(TextStyle::Heading) .min_size(edit_rect.size()) .horizontal_align(if options.h_center { Align::Center } else { Align::Min }) .vertical_align(Align::Center) .password(show_pass) + .cursor_at_end(true) .ui(ui); // Show keyboard on click. if text_edit_resp.clicked() { @@ -355,6 +390,42 @@ impl View { text_edit_resp.request_focus(); cb.show_keyboard(); } + // Apply text from input on Android as temporary fix for egui. + let os = OperatingSystem::from_target_os(); + if os == OperatingSystem::Android && text_edit_resp.has_focus() { + let mut w_input = LAST_SOFT_KEYBOARD_INPUT.write().unwrap(); + + if !w_input.is_empty() { + let mut state = TextEditState::load(ui.ctx(), options.id).unwrap(); + match state.cursor.char_range() { + None => {} + Some(range) => { + let mut r = range.clone(); + + let mut index = r.primary.index; + println!("insert_str {} {}", index, w_input.as_str()); + + value.insert_text(w_input.as_str(), index); + index = index + 1; + + println!("12345 {} {}", value, r.primary.index); + + if index == 0 { + r.primary.index = value.len(); + r.secondary.index = r.primary.index; + } else { + r.primary.index = index; + r.secondary.index = r.primary.index; + } + state.cursor.set_char_range(Some(r)); + TextEditState::store(state, ui.ctx(), options.id); + } + } + } + + *w_input = "".to_string(); + ui.ctx().request_repaint(); + } }); }); } @@ -571,4 +642,33 @@ pub extern "C" fn Java_mw_gri_android_MainActivity_onDisplayInsets( RIGHT_DISPLAY_INSET.store(array[1], Ordering::Relaxed); BOTTOM_DISPLAY_INSET.store(array[2], Ordering::Relaxed); LEFT_DISPLAY_INSET.store(array[3], Ordering::Relaxed); +} + +lazy_static! { + static ref LAST_SOFT_KEYBOARD_INPUT: Arc> = Arc::new(RwLock::new("".to_string())); +} + +#[allow(dead_code)] +#[cfg(target_os = "android")] +#[allow(non_snake_case)] +#[no_mangle] +/// Callback from Java code with last entered character from soft keyboard. +pub extern "C" fn Java_mw_gri_android_MainActivity_onInput( + _env: jni::JNIEnv, + _class: jni::objects::JObject, + char: jni::sys::jstring +) { + use jni::objects::{JString}; + + unsafe { + let j_obj = JString::from_raw(char); + let j_str = _env.get_string_unchecked(j_obj.as_ref()).unwrap(); + match j_str.to_str() { + Ok(str) => { + let mut w_input = LAST_SOFT_KEYBOARD_INPUT.write().unwrap(); + *w_input = w_input.clone().add(str); + } + Err(_) => {} + } + } } \ No newline at end of file diff --git a/src/gui/views/wallets/content.rs b/src/gui/views/wallets/content.rs index 6c55329..2024329 100644 --- a/src/gui/views/wallets/content.rs +++ b/src/gui/views/wallets/content.rs @@ -98,7 +98,7 @@ impl WalletsContent { let show_wallet = self.wallets.is_selected_open(); // Setup panels parameters. - let dual_panel = is_dual_panel_mode(ui, frame); + let dual_panel = is_dual_panel_mode(ui); let open_wallet_panel = dual_panel || show_wallet || create_wallet || empty_list; let wallet_panel_width = self.wallet_panel_width(ui, empty_list, dual_panel, show_wallet); let content_width = ui.available_width(); @@ -131,10 +131,10 @@ impl WalletsContent { if create_wallet || !show_wallet { // Show wallet creation content. self.creation_content.ui(ui, frame, cb, |wallet| { - // Reset wallet content. - self.wallet_content = WalletContent::default(); // Add created wallet to list. self.wallets.add(wallet); + // Reset wallet content. + self.wallet_content = WalletContent::default(); }); } else { let selected_id = self.wallets.selected_id.clone(); @@ -180,7 +180,7 @@ impl WalletsContent { right: if list_hidden { 0.0 } else { - View::far_right_inset_margin(ui, frame) + 4.0 + View::far_right_inset_margin(ui) + 4.0 }, top: 4.0, bottom: View::get_bottom_inset() + 4.0, @@ -274,7 +274,7 @@ impl WalletsContent { self.show_wallets_at_dual_panel = !show_list; AppConfig::toggle_show_wallets_at_dual_panel(); }); - } else if !Root::is_dual_panel_mode(frame) { + } else if !Root::is_dual_panel_mode(ui) { View::title_button(ui, GLOBE, || { Root::toggle_network_panel(); }); @@ -605,8 +605,8 @@ impl WalletsContent { } /// Check if it's possible to show [`WalletsContent`] and [`WalletContent`] panels at same time. -fn is_dual_panel_mode(ui: &mut egui::Ui, frame: &mut eframe::Frame) -> bool { - let dual_panel_root = Root::is_dual_panel_mode(frame); +fn is_dual_panel_mode(ui: &mut egui::Ui) -> bool { + let dual_panel_root = Root::is_dual_panel_mode(ui); let max_width = ui.available_width(); dual_panel_root && max_width >= (Root::SIDE_PANEL_WIDTH * 2.0) + View::get_right_inset() } \ No newline at end of file diff --git a/src/gui/views/wallets/creation/creation.rs b/src/gui/views/wallets/creation/creation.rs index a90f4b4..9795a74 100644 --- a/src/gui/views/wallets/creation/creation.rs +++ b/src/gui/views/wallets/creation/creation.rs @@ -17,7 +17,7 @@ use egui_extras::{RetainedImage, Size, StripBuilder}; use crate::built_info; use crate::gui::Colors; -use crate::gui::icons::{CHECK, EYE, EYE_SLASH, FOLDER_PLUS, SHARE_FAT}; +use crate::gui::icons::{CHECK, CLIPBOARD_TEXT, COPY, EYE, EYE_SLASH, FOLDER_PLUS, SHARE_FAT}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, Root, View}; use crate::gui::views::types::{ModalPosition, TextEditOptions}; @@ -86,7 +86,7 @@ impl WalletCreation { ui.vertical_centered(|ui| { ui.vertical_centered(|ui| { View::max_width_ui(ui, Root::SIDE_PANEL_WIDTH * 2.0, |ui| { - self.step_control_ui(ui, on_create); + self.step_control_ui(ui, on_create, cb); }); }); @@ -130,17 +130,12 @@ impl WalletCreation { }); } - /// Reset wallet creation to default values. - fn reset(&mut self) { - self.step = None; - self.name_edit = String::from(""); - self.pass_edit = String::from(""); - self.mnemonic_setup.reset(); - } - /// Draw [`Step`] description and confirmation control. - fn step_control_ui(&mut self, ui: &mut egui::Ui, on_create: impl FnOnce(Wallet)) { - if let Some(step) = &self.step { + fn step_control_ui(&mut self, + ui: &mut egui::Ui, + on_create: impl FnOnce(Wallet), + cb: &dyn PlatformCallbacks) { + if let Some(step) = self.step.clone() { // Setup step description text and availability. let (step_text, mut step_available) = match step { Step::EnterMnemonic => { @@ -179,27 +174,121 @@ impl WalletCreation { .color(Colors::RED)); ui.add_space(2.0); } - - // Show next step button if there are no empty words. - if step_available { - // Setup button text. - let (next_text, color) = if step == &Step::SetupConnection { - (format!("{} {}", CHECK, t!("complete")), Colors::GOLD) + if step == Step::EnterMnemonic { + ui.add_space(4.0); + if !step_available { + self.copy_or_paste_button_ui(ui, cb); } else { - let text = format!("{} {}", SHARE_FAT, t!("continue")); - (text, Colors::WHITE) - }; + // Setup spacing between buttons. + ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0); - ui.add_space(4.0); - // Show button. - View::button(ui, next_text.to_uppercase(), color, || { - self.forward(on_create); + ui.columns(2, |columns| { + // Show copy or paste button for mnemonic phrase step. + columns[0].vertical_centered_justified(|ui| { + self.copy_or_paste_button_ui(ui, cb); + }); + + // Show next step button if there are no empty words. + if step_available { + columns[1].vertical_centered_justified(|ui| { + self.next_step_button_ui(ui, step, on_create); + }); + } + }); + } + } else { + if step_available { + ui.add_space(4.0); + self.next_step_button_ui(ui, step, on_create); + } + } + ui.add_space(4.0); + } + } + + /// Draw copy or paste button at [`Step::EnterMnemonic`]. + fn copy_or_paste_button_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + match self.mnemonic_setup.mnemonic.mode { + PhraseMode::Generate => { + // Show copy button. + let c_t = format!("{} {}", COPY, t!("copy").to_uppercase()); + View::button(ui, c_t.to_uppercase(), Colors::WHITE, || { + cb.copy_string_to_buffer(self.mnemonic_setup.mnemonic.get_phrase()); + }); + } + PhraseMode::Import => { + // Show paste button. + let p_t = format!("{} {}", CLIPBOARD_TEXT, t!("paste").to_uppercase()); + View::button(ui, p_t, Colors::WHITE, || { + self.mnemonic_setup.mnemonic.import_text(cb.get_string_from_buffer()); }); - ui.add_space(4.0); } } } + /// Draw button to go to next [`Step`]. + fn next_step_button_ui(&mut self, + ui: &mut egui::Ui, + step: Step, + on_create: impl FnOnce(Wallet)) { + // Setup button text. + let (next_text, color) = if step == Step::SetupConnection { + (format!("{} {}", CHECK, t!("complete")), Colors::GOLD) + } else { + let text = format!("{} {}", SHARE_FAT, t!("continue")); + (text, Colors::WHITE) + }; + + + // Show next step button. + View::button(ui, next_text.to_uppercase(), color, || { + self.step = if let Some(step) = &self.step { + match step { + Step::EnterMnemonic => { + if self.mnemonic_setup.mnemonic.mode == PhraseMode::Generate { + Some(Step::ConfirmMnemonic) + } else { + // Check if entered phrase was valid. + if self.mnemonic_setup.valid_phrase { + Some(Step::SetupConnection) + } else { + Some(Step::EnterMnemonic) + } + } + } + Step::ConfirmMnemonic => { + // Check external connections availability on connection setup. + ExternalConnection::start_ext_conn_availability_check(); + Some(Step::SetupConnection) + }, + Step::SetupConnection => { + // Create wallet at last step. + let name = self.name_edit.clone(); + let pass = self.pass_edit.clone(); + let phrase = self.mnemonic_setup.mnemonic.get_phrase(); + let conn_method = &self.network_setup.method; + let mut wallet = Wallet::create(name, + pass.clone(), + phrase, + conn_method).unwrap(); + // Open created wallet. + wallet.open(pass).unwrap(); + // Pass created wallet to callback. + (on_create)(wallet); + // Reset input data. + self.step = None; + self.name_edit = String::from(""); + self.pass_edit = String::from(""); + self.mnemonic_setup.reset(); + None + } + } + } else { + Some(Step::EnterMnemonic) + }; + }); + } + /// Draw wallet creation [`Step`] content. fn step_content_ui(&mut self, ui: &mut egui::Ui, @@ -256,7 +345,12 @@ impl WalletCreation { None => {} Some(step) => { match step { - Step::EnterMnemonic => self.reset(), + Step::EnterMnemonic => { + self.step = None; + self.name_edit = String::from(""); + self.pass_edit = String::from(""); + self.mnemonic_setup.reset(); + }, Step::ConfirmMnemonic => self.step = Some(Step::EnterMnemonic), Step::SetupConnection => self.step = Some(Step::EnterMnemonic) } @@ -264,49 +358,6 @@ impl WalletCreation { } } - /// Go to the next wallet creation [`Step`]. - fn forward(&mut self, on_create: impl FnOnce(Wallet)) { - self.step = if let Some(step) = &self.step { - match step { - Step::EnterMnemonic => { - if self.mnemonic_setup.mnemonic.mode == PhraseMode::Generate { - Some(Step::ConfirmMnemonic) - } else { - // Check if entered phrase was valid. - if self.mnemonic_setup.valid_phrase { - Some(Step::SetupConnection) - } else { - Some(Step::EnterMnemonic) - } - } - } - Step::ConfirmMnemonic => { - // Check external connections availability on connection setup. - ExternalConnection::start_ext_conn_availability_check(); - Some(Step::SetupConnection) - }, - Step::SetupConnection => { - // Create wallet at last step. - let name = self.name_edit.clone(); - let pass = self.pass_edit.clone(); - let phrase = self.mnemonic_setup.mnemonic.get_phrase(); - let conn_method = &self.network_setup.method; - let mut wallet - = Wallet::create(name, pass.clone(), phrase, conn_method).unwrap(); - // Open created wallet. - wallet.open(pass).unwrap(); - // Pass created wallet to callback. - (on_create)(wallet); - // Reset input data. - self.reset(); - None - } - } - } else { - Some(Step::EnterMnemonic) - }; - } - /// Start wallet creation from showing [`Modal`] to enter name and password. pub fn show_name_pass_modal(&mut self, cb: &dyn PlatformCallbacks) { // Reset modal values. diff --git a/src/gui/views/wallets/creation/mnemonic.rs b/src/gui/views/wallets/creation/mnemonic.rs index 689c316..d532398 100644 --- a/src/gui/views/wallets/creation/mnemonic.rs +++ b/src/gui/views/wallets/creation/mnemonic.rs @@ -167,13 +167,13 @@ impl MnemonicSetup { let words = match self.mnemonic.mode { PhraseMode::Generate => { if edit_words { - self.mnemonic.confirm_words.clone() + &self.mnemonic.confirm_words } else { - self.mnemonic.words.clone() + &self.mnemonic.words } } - PhraseMode::Import => self.mnemonic.words.clone() - }; + PhraseMode::Import => &self.mnemonic.words + }.clone(); let mut word_number = 0; let cols = list_columns_count(ui); diff --git a/src/gui/views/wallets/creation/types.rs b/src/gui/views/wallets/creation/types.rs index 58f6dfa..4a48e23 100644 --- a/src/gui/views/wallets/creation/types.rs +++ b/src/gui/views/wallets/creation/types.rs @@ -13,7 +13,7 @@ // limitations under the License. /// Wallet creation step. -#[derive(PartialEq)] +#[derive(PartialEq, Clone)] pub enum Step { /// Mnemonic phrase input. EnterMnemonic, diff --git a/src/gui/views/wallets/setup/recovery.rs b/src/gui/views/wallets/setup/recovery.rs index ddcafeb..b849f71 100644 --- a/src/gui/views/wallets/setup/recovery.rs +++ b/src/gui/views/wallets/setup/recovery.rs @@ -185,22 +185,20 @@ impl RecoverySetup { .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); - }); - // Draw current wallet password text edit. - let pass_edit_id = Id::from(modal.id).with(wallet.get_config().id); - let pass_edit_opts = TextEditOptions::new(pass_edit_id).password(); - View::text_edit(ui, cb, &mut self.pass_edit, pass_edit_opts); + // Draw current wallet password text edit. + let pass_edit_id = Id::from(modal.id).with(wallet.get_config().id); + let pass_edit_opts = TextEditOptions::new(pass_edit_id).password(); + View::text_edit(ui, cb, &mut self.pass_edit, pass_edit_opts); - // Show information when password is empty. - ui.vertical_centered(|ui| { + // Show information when password is empty or wrong. if self.pass_edit.is_empty() { - ui.add_space(10.0); + ui.add_space(12.0); ui.label(RichText::new(t!("wallets.pass_empty")) .size(17.0) .color(Colors::INACTIVE_TEXT)); } else if self.wrong_pass { - ui.add_space(10.0); + ui.add_space(12.0); ui.label(RichText::new(t!("wallets.wrong_pass")) .size(17.0) .color(Colors::RED)); diff --git a/src/gui/views/wallets/wallet/content.rs b/src/gui/views/wallets/wallet/content.rs index 16664a1..24bdb9a 100644 --- a/src/gui/views/wallets/wallet/content.rs +++ b/src/gui/views/wallets/wallet/content.rs @@ -375,7 +375,7 @@ impl WalletContent { } /// Draw content when wallet is syncing and not ready to use, returns `true` at this case. - pub fn sync_ui(ui: &mut egui::Ui, frame: &mut eframe::Frame, wallet: &Wallet) -> bool { + pub fn sync_ui(ui: &mut egui::Ui, wallet: &Wallet) -> bool { if wallet.is_repairing() && !wallet.sync_error() { Self::sync_progress_ui(ui, wallet); return true; @@ -384,7 +384,7 @@ impl WalletContent { return true; } else if wallet.get_current_ext_conn_id().is_none() { if !Node::is_running() || Node::is_stopping() { - let dual_panel_root = Root::is_dual_panel_mode(frame); + let dual_panel_root = Root::is_dual_panel_mode(ui); View::center_content(ui, 108.0, |ui| { let text = t!("wallets.enable_node", "settings" => GEAR_FINE); ui.label(RichText::new(text).size(16.0).color(Colors::INACTIVE_TEXT)); diff --git a/src/gui/views/wallets/wallet/info.rs b/src/gui/views/wallets/wallet/info.rs index ba2e793..0b40c06 100644 --- a/src/gui/views/wallets/wallet/info.rs +++ b/src/gui/views/wallets/wallet/info.rs @@ -37,10 +37,10 @@ impl WalletTab for WalletInfo { fn ui(&mut self, ui: &mut egui::Ui, - frame: &mut eframe::Frame, + _: &mut eframe::Frame, wallet: &mut Wallet, _: &dyn PlatformCallbacks) { - if WalletContent::sync_ui(ui, frame, wallet) { + if WalletContent::sync_ui(ui, wallet) { return; } diff --git a/src/gui/views/wallets/wallet/receive.rs b/src/gui/views/wallets/wallet/receive.rs index 9364e7a..48dd3ed 100644 --- a/src/gui/views/wallets/wallet/receive.rs +++ b/src/gui/views/wallets/wallet/receive.rs @@ -12,35 +12,58 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{Id, Margin, RichText, ScrollArea, Widget}; +use egui::{Id, Margin, RichText, ScrollArea}; +use egui::scroll_area::ScrollBarVisibility; +use grin_core::core::{amount_from_hr_string, amount_to_hr_string}; use crate::gui::Colors; -use crate::gui::icons::{ARCHIVE_BOX, BROOM, CLIPBOARD_TEXT, COPY, HAND_COINS}; +use crate::gui::icons::{BROOM, CLIPBOARD_TEXT, COPY, HAND_COINS, RECEIPT}; use crate::gui::platform::PlatformCallbacks; -use crate::gui::views::{Root, View}; -use crate::gui::views::wallets::wallet::types::{WalletTab, WalletTabType}; +use crate::gui::views::{Modal, Root, View}; +use crate::gui::views::types::{ModalPosition, TextEditOptions}; +use crate::gui::views::wallets::wallet::types::{SLATEPACK_MESSAGE_HINT, WalletTab, WalletTabType}; use crate::gui::views::wallets::wallet::WalletContent; use crate::wallet::Wallet; /// Receiving tab content. pub struct WalletReceive { - /// Slatepack text from sender to create response. + /// Flag to check if there is invoice transaction type. + is_invoice: bool, + + /// Slatepack message from sender to create response message. message_edit: String, - /// Generated Slatepack response. + /// Generated Slatepack response message for sender. response_edit: String, - /// Flag to check if there is an error happened on receive. - receive_error: bool, - /// Flag to check if response was copied to the clipboard. - response_copied: bool, + /// Flag to check if there is an error happened on response creation. + response_error: bool, + + /// Amount to receive for invoice transaction type. + amount_edit: String, + /// Generated Slatepack message for invoice transaction. + request_edit: String, + /// Flag to check if there is an error happened on invoice creation. + request_error: bool, + /// Slatepack message from sender to finalize transaction. + finalization_edit: String, + /// Flag to check if there is an error happened on transaction finalization. + finalization_error: bool, } +/// Identifier for invoice amount [`Modal`]. +const INVOICE_AMOUNT_MODAL: &'static str = "invoice_amount_modal"; + impl Default for WalletReceive { fn default() -> Self { Self { + is_invoice: false, message_edit: "".to_string(), response_edit: "".to_string(), - receive_error: false, - response_copied: false, + response_error: false, + amount_edit: "".to_string(), + request_edit: "".to_string(), + request_error: false, + finalization_edit: "".to_string(), + finalization_error: false, } } } @@ -52,13 +75,16 @@ impl WalletTab for WalletReceive { fn ui(&mut self, ui: &mut egui::Ui, - frame: &mut eframe::Frame, + _: &mut eframe::Frame, wallet: &mut Wallet, cb: &dyn PlatformCallbacks) { - if WalletContent::sync_ui(ui, frame, wallet) { + if WalletContent::sync_ui(ui, wallet) { return; } + // Show modal content for this ui container. + self.modal_content_ui(ui, wallet, cb); + // Show receiving content panel. egui::CentralPanel::default() .frame(egui::Frame { @@ -73,18 +99,21 @@ impl WalletTab for WalletReceive { ..Default::default() }) .show_inside(ui, |ui| { - ui.vertical_centered(|ui| { - View::max_width_ui(ui, Root::SIDE_PANEL_WIDTH * 1.3, |ui| { - self.receive_ui(ui, wallet, cb); + ScrollArea::vertical() + .scroll_bar_visibility(ScrollBarVisibility::AlwaysVisible) + .id_source(Id::from("wallet_receive").with(wallet.get_config().id)) + .auto_shrink([false; 2]) + .show(ui, |ui| { + ui.vertical_centered(|ui| { + View::max_width_ui(ui, Root::SIDE_PANEL_WIDTH * 1.3, |ui| { + self.receive_ui(ui, wallet, cb); + }); + }); }); - }); }); } } -/// Hint for Slatepack Message input. -const RECEIVE_SLATEPACK_HINT: &'static str = "BEGINSLATEPACK.\n...\n...\n...\nENDSLATEPACK."; - impl WalletReceive { /// Draw receiving content. pub fn receive_ui(&mut self, @@ -95,18 +124,91 @@ impl WalletReceive { View::sub_title(ui, format!("{} {}", HAND_COINS, t!("wallets.manually"))); View::horizontal_line(ui, Colors::ITEM_STROKE); ui.add_space(3.0); + // Show manual receiving content. + self.manual_ui(ui, wallet, cb); + } - // Setup manual sending description. - let response_empty = self.response_edit.is_empty(); - let desc_text = if response_empty { - t!("wallets.receive_paste_slatepack") + /// Draw [`Modal`] content for this ui container. + fn modal_content_ui(&mut self, + ui: &mut egui::Ui, + wallet: &mut Wallet, + cb: &dyn PlatformCallbacks) { + match Modal::opened() { + None => {} + Some(id) => { + match id { + INVOICE_AMOUNT_MODAL => { + Modal::ui(ui.ctx(), |ui, modal| { + self.invoice_amount_modal(ui, wallet, modal, cb); + }); + } + _ => {} + } + } + } + } + + /// Draw manual receiving content. + fn manual_ui(&mut self, ui: &mut egui::Ui, wallet: &mut Wallet, cb: &dyn PlatformCallbacks) { + ui.add_space(10.0); + ui.columns(2, |columns| { + let mut is_invoice = self.is_invoice; + columns[0].vertical_centered(|ui| { + View::radio_value(ui, &mut is_invoice, false, t!("wallets.receive")); + }); + columns[1].vertical_centered(|ui| { + View::radio_value(ui, &mut is_invoice, true, t!("wallets.invoice")); + }); + if is_invoice != self.is_invoice { + self.is_invoice = is_invoice; + // Reset fields to default values on mode change. + if is_invoice { + self.amount_edit = "".to_string(); + self.request_edit = "".to_string(); + self.request_error = false; + self.finalization_edit = "".to_string(); + self.finalization_error = false; + } else { + self.message_edit = "".to_string(); + self.response_edit = "".to_string(); + self.response_error = false; + } + } + }); + ui.add_space(10.0); + + if self.is_invoice { + // Show invoice creation content. + self.manual_invoice_ui(ui, wallet, cb); } else { - t!("wallets.receive_send_slatepack") - }; - ui.label(RichText::new(desc_text).size(16.0).color(Colors::INACTIVE_TEXT)); - ui.add_space(3.0); + // Show manual transaction receiving content. + self.manual_receive_ui(ui, wallet, cb); + } + } - // Show Slatepack text input. + /// Draw manual receiving content. + fn manual_receive_ui(&mut self, + ui: &mut egui::Ui, + wallet: &mut Wallet, + cb: &dyn PlatformCallbacks) { + // Setup description. + let response_empty = self.response_edit.is_empty(); + + if self.response_error { + ui.label(RichText::new(t!("wallets.receive_slatepack_err")) + .size(16.0) + .color(Colors::RED)); + } else { + let desc_text = if response_empty { + t!("wallets.receive_slatepack_desc") + } else { + t!("wallets.receive_send_slatepack") + }; + ui.label(RichText::new(desc_text).size(16.0).color(Colors::INACTIVE_TEXT)); + } + ui.add_space(6.0); + + // Setup Slatepack message text input. let message = if response_empty { &mut self.message_edit } else { @@ -126,12 +228,12 @@ impl WalletReceive { .font(egui::TextStyle::Small) .desired_rows(5) .interactive(response_empty) - .hint_text(RECEIVE_SLATEPACK_HINT) + .hint_text(SLATEPACK_MESSAGE_HINT) .desired_width(f32::INFINITY) .show(ui); // Clear an error when message changed. if &message_before != message { - self.receive_error = false; + self.response_error = false; } ui.add_space(6.0); }); @@ -139,38 +241,27 @@ impl WalletReceive { View::horizontal_line(ui, Colors::ITEM_STROKE); ui.add_space(10.0); - // Show receiving input control buttons. - self.receive_buttons_ui(ui, wallet, cb); - } - - /// Draw manual receiving input control buttons. - fn receive_buttons_ui(&mut self, - ui: &mut egui::Ui, - wallet: &mut Wallet, - cb: &dyn PlatformCallbacks) { + // Draw buttons to clear/copy/paste. let field_is_empty = self.message_edit.is_empty() && self.response_edit.is_empty(); let columns_num = if !field_is_empty { 2 } else { 1 }; - - // Draw buttons to clear/copy/paste. ui.scope(|ui| { // Setup spacing between buttons. ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0); ui.columns(columns_num, |columns| { let first_column_content = |ui: &mut egui::Ui| { - if !field_is_empty { + if !self.response_edit.is_empty() && !self.response_error { let clear_text = format!("{} {}", BROOM, t!("clear")); View::button(ui, clear_text, Colors::BUTTON, || { - self.receive_error = false; - self.response_copied = false; + self.response_error = false; self.message_edit.clear(); self.response_edit.clear(); }); - } else if self.message_edit.is_empty() { + } else { let paste_text = format!("{} {}", CLIPBOARD_TEXT, t!("paste")); View::button(ui, paste_text, Colors::BUTTON, || { self.message_edit = cb.get_string_from_buffer(); - self.receive_error = false; + self.response_error = false; }); } }; @@ -178,56 +269,253 @@ impl WalletReceive { columns[0].vertical_centered(first_column_content); } else { columns[0].vertical_centered_justified(first_column_content); - } - if !field_is_empty { columns[1].vertical_centered_justified(|ui| { - if !self.message_edit.is_empty() { - let paste_text = format!("{} {}", CLIPBOARD_TEXT, t!("paste")); - View::button(ui, paste_text, Colors::BUTTON, || { - self.message_edit = cb.get_string_from_buffer(); - self.receive_error = false; + if self.response_error { + let clear_text = format!("{} {}", BROOM, t!("clear")); + View::button(ui, clear_text, Colors::BUTTON, || { + self.response_error = false; + self.message_edit.clear(); + self.response_edit.clear(); }); } else if !self.response_edit.is_empty() { let copy_text = format!("{} {}", COPY, t!("copy")); View::button(ui, copy_text, Colors::BUTTON, || { cb.copy_string_to_buffer(self.response_edit.clone()); - self.response_copied = true; + }); + } else { + View::button(ui, t!("wallets.create_response"), Colors::GOLD, || { + match wallet.receive(self.message_edit.clone()) { + Ok(response) => { + self.response_edit = response.trim().to_string(); + self.message_edit.clear(); + cb.copy_string_to_buffer(response); + }, + Err(e) => { + wallet.sync(); + println!("error {}", e); + self.response_error = true + } + } }); } }); } }); }); + } - // Draw button to create response. - if !self.message_edit.is_empty() && !self.receive_error { - ui.add_space(8.0); - let create_text = format!("{} {}", ARCHIVE_BOX, t!("wallets.create_response")); - View::button(ui, create_text, Colors::GOLD, || { - match wallet.receive(self.message_edit.clone()) { - Ok(response) => { - self.response_edit = response.trim().to_string(); - self.message_edit.clear(); - // Copy response to clipboard. - cb.copy_string_to_buffer(response); - self.response_copied = true; - }, - Err(_) => self.receive_error = true + /// Draw invoice creation content. + fn manual_invoice_ui(&mut self, + ui: &mut egui::Ui, + wallet: &mut Wallet, + cb: &dyn PlatformCallbacks) { + ui.label(RichText::new(t!("wallets.issue_invoice_desc")) + .size(16.0) + .color(Colors::INACTIVE_TEXT)); + ui.add_space(6.0); + + // Draw invoice creation button. + let invoice_text = format!("{} {}", RECEIPT, t!("wallets.issue_invoice")); + View::button(ui, invoice_text, Colors::BUTTON, || { + // Reset modal values. + self.amount_edit = "".to_string(); + self.request_error = false; + // Show invoice amount modal. + Modal::new(INVOICE_AMOUNT_MODAL) + .position(ModalPosition::CenterTop) + .title(t!("wallets.issue_invoice")) + .show(); + cb.show_keyboard(); + }); + + ui.add_space(12.0); + View::horizontal_line(ui, Colors::ITEM_STROKE); + ui.add_space(6.0); + ui.label(RichText::new(t!("wallets.receive_slatepack_desc")) + .size(16.0) + .color(Colors::INACTIVE_TEXT)); + ui.add_space(6.0); + View::horizontal_line(ui, Colors::ITEM_STROKE); + ui.add_space(3.0); + + // Draw invoice finalization text input. + ScrollArea::vertical() + .max_height(128.0) + .id_source(Id::from("receive_input").with(wallet.get_config().id)) + .auto_shrink([false; 2]) + .show(ui, |ui| { + ui.add_space(7.0); + let finalization_before = self.finalization_edit.clone(); + egui::TextEdit::multiline(&mut self.finalization_edit) + .font(egui::TextStyle::Small) + .desired_rows(5) + .interactive(true) + .hint_text(SLATEPACK_MESSAGE_HINT) + .desired_width(f32::INFINITY) + .show(ui); + // Clear an error when message changed. + if finalization_before != self.finalization_edit { + self.finalization_error = false; } + ui.add_space(6.0); }); + ui.add_space(2.0); + View::horizontal_line(ui, Colors::ITEM_STROKE); + ui.add_space(10.0); + + // Draw buttons to clear/paste. + ui.scope(|ui| { + // Setup spacing between buttons. + ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0); + + ui.columns(2, |columns| { + columns[0].vertical_centered_justified(|ui| { + let paste_text = format!("{} {}", CLIPBOARD_TEXT, t!("paste")); + View::button(ui, paste_text, Colors::BUTTON, || { + self.finalization_edit = cb.get_string_from_buffer(); + self.response_error = false; + }); + }); + columns[1].vertical_centered_justified(|ui| { + View::button(ui, t!("wallets.finalize"), Colors::GOLD, || { + wallet.finalize(); + //TODO: finalize + }); + }); + }); + }); + + if self.finalization_error { ui.add_space(8.0); - } else if self.receive_error { - ui.add_space(8.0); - ui.label(RichText::new(t!("wallets.receive_slatepack_err")) + ui.label(RichText::new(t!("wallets.finalize_slatepack_err")) .size(16.0) .color(Colors::RED)); + } + ui.add_space(8.0); + } + + /// Draw invoice amount [`Modal`] content. + fn invoice_amount_modal(&mut self, + ui: &mut egui::Ui, + wallet: &mut Wallet, + modal: &Modal, + cb: &dyn PlatformCallbacks) { + ui.add_space(6.0); + if self.request_edit.is_empty() { + ui.vertical_centered(|ui| { + ui.label(RichText::new(t!("wallets.enter_amount")) + .size(17.0) + .color(Colors::GRAY)); + }); ui.add_space(8.0); - } else if self.response_copied { - ui.add_space(8.0); - ui.label(RichText::new(t!("wallets.response_copied")) - .size(16.0) - .color(Colors::GREEN)); - ui.add_space(8.0); + + // Draw invoice amount text edit. + let amount_edit_id = Id::from(modal.id).with(wallet.get_config().id); + let amount_edit_opts = TextEditOptions::new(amount_edit_id).h_center(); + let mut amount_edit = self.amount_edit.clone(); + View::text_edit(ui, cb, &mut amount_edit, amount_edit_opts); + if amount_edit != self.amount_edit { + self.request_error = false; + match amount_from_hr_string(amount_edit.as_str()) { + Ok(_) => { + self.amount_edit = amount_edit; + } + Err(_) => {} + } + } + + // Show invoice creation error. + if self.request_error { + ui.add_space(12.0); + ui.label(RichText::new(t!("wallets.invoice_slatepack_err")) + .size(17.0) + .color(Colors::RED)); + } + + // Show modal buttons. + ui.add_space(12.0); + ui.scope(|ui| { + // Setup spacing between buttons. + ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0); + + ui.columns(2, |columns| { + columns[0].vertical_centered_justified(|ui| { + View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + self.amount_edit = "".to_string(); + self.request_error = false; + modal.close(); + }); + }); + columns[1].vertical_centered_justified(|ui| { + View::button(ui, t!("continue"), Colors::WHITE, || { + match amount_from_hr_string(self.amount_edit.as_str()) { + Ok(amount) => { + match wallet.issue_invoice(amount) { + Ok(message) => { + self.request_edit = message; + cb.hide_keyboard(); + } + Err(_) => { + self.request_error = true; + } + } + } + Err(_) => { + self.request_error = true; + } + } + }); + }); + }); + }); + ui.add_space(6.0); + } else { + ui.vertical_centered(|ui| { + let amount = amount_from_hr_string(self.amount_edit.as_str()).unwrap(); + let amount_format = amount_to_hr_string(amount, true); + let desc_text = t!("wallets.invoice_desc","amount" => amount_format); + ui.label(RichText::new(desc_text).size(16.0).color(Colors::INACTIVE_TEXT)); + ui.add_space(6.0); + View::horizontal_line(ui, Colors::ITEM_STROKE); + ui.add_space(3.0); + + // Draw invoice request text. + ScrollArea::vertical() + .max_height(128.0) + .id_source(Id::from("receive_input").with(wallet.get_config().id)) + .auto_shrink([false; 2]) + .show(ui, |ui| { + ui.add_space(7.0); + egui::TextEdit::multiline(&mut self.request_edit) + .font(egui::TextStyle::Small) + .desired_rows(5) + .interactive(false) + .hint_text(SLATEPACK_MESSAGE_HINT) + .desired_width(f32::INFINITY) + .show(ui); + ui.add_space(6.0); + }); + ui.add_space(2.0); + View::horizontal_line(ui, Colors::ITEM_STROKE); + ui.add_space(10.0); + + // Draw copy button. + let copy_text = format!("{} {}", COPY, t!("copy")); + View::button(ui, copy_text, Colors::BUTTON, || { + cb.copy_string_to_buffer(self.request_edit.clone()); + }); + }); + + // Draw button to close modal. + ui.add_space(12.0); + ui.vertical_centered_justified(|ui| { + View::button(ui, t!("close"), Colors::WHITE, || { + self.amount_edit = "".to_string(); + self.request_edit = "".to_string(); + modal.close(); + }); + }); + ui.add_space(6.0); } } } \ No newline at end of file diff --git a/src/gui/views/wallets/wallet/send.rs b/src/gui/views/wallets/wallet/send.rs index b3b260a..4c47bae 100644 --- a/src/gui/views/wallets/wallet/send.rs +++ b/src/gui/views/wallets/wallet/send.rs @@ -31,10 +31,10 @@ impl WalletTab for WalletSend { fn ui(&mut self, ui: &mut egui::Ui, - frame: &mut eframe::Frame, + _: &mut eframe::Frame, wallet: &mut Wallet, _: &dyn PlatformCallbacks) { - if WalletContent::sync_ui(ui, frame, wallet) { + if WalletContent::sync_ui(ui, wallet) { return; } diff --git a/src/lib.rs b/src/lib.rs index 2173f96..7260520 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ extern crate rust_i18n; use eframe::wgpu; -use egui::{Context, Stroke}; +use egui::{Context, Stroke, vec2}; #[cfg(target_os = "android")] use winit::platform::android::activity::AndroidApp; @@ -61,16 +61,21 @@ fn android_main(app: AndroidApp) { use gui::PlatformApp; let platform = Android::new(app.clone()); - use winit::platform::android::EventLoopBuilderExtAndroid; - let mut options = eframe::NativeOptions::default(); + + let width = app.config().screen_width_dp().unwrap() as f32; + let height = app.config().screen_height_dp().unwrap() as f32; + let mut options = eframe::NativeOptions { + viewport: egui::ViewportBuilder::default().with_inner_size(vec2(width, height)), + ..Default::default() + }; // Setup limits that are guaranteed to be compatible with Android devices. options.wgpu_options.device_descriptor = std::sync::Arc::new(|adapter| { let base_limits = wgpu::Limits::downlevel_webgl2_defaults(); wgpu::DeviceDescriptor { label: Some("egui wgpu device"), - features: wgpu::Features::default(), - limits: wgpu::Limits { + required_features: wgpu::Features::default(), + required_limits: wgpu::Limits { max_texture_dimension_2d: 8192, ..base_limits }, @@ -102,7 +107,6 @@ pub fn app_creator(app: PlatformApp) -> eframe::AppCreator pub fn start(mut options: eframe::NativeOptions, app_creator: eframe::AppCreator) { options.default_theme = eframe::Theme::Light; options.renderer = eframe::Renderer::Wgpu; - options.initial_window_size = Some(egui::Vec2::new(1200.0, 720.0)); // Setup translations. setup_i18n(); // Start integrated node if needed. @@ -119,7 +123,7 @@ pub fn setup_visuals(ctx: &Context) { // Setup spacing for buttons. style.spacing.button_padding = egui::vec2(12.0, 8.0); // Make scroll-bar thinner. - style.spacing.scroll_bar_width = 4.0; + style.spacing.scroll.bar_width = 4.0; // Disable spacing between items. style.spacing.item_spacing = egui::vec2(0.0, 0.0); // Setup radio button/checkbox size and spacing. diff --git a/src/main.rs b/src/main.rs index f8f996f..06c73db 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,6 +31,9 @@ fn real_main() { use grim::gui::PlatformApp; let platform = Desktop::default(); - let options = eframe::NativeOptions::default(); + let options = eframe::NativeOptions { + viewport: egui::ViewportBuilder::default().with_inner_size([1200.0, 720.0]), + ..Default::default() + }; grim::start(options, grim::app_creator(PlatformApp::new(platform))); } \ No newline at end of file diff --git a/src/node/config.rs b/src/node/config.rs index 2bb606b..fd5a6e7 100644 --- a/src/node/config.rs +++ b/src/node/config.rs @@ -24,6 +24,7 @@ use grin_core::global::ChainTypes; use grin_p2p::{PeerAddr, Seeding}; use grin_p2p::msg::PeerAddrs; use grin_servers::common::types::ChainValidationMode; +use local_ip_address::list_afinet_netifas; use serde::{Deserialize, Serialize}; use crate::{AppConfig, Settings}; @@ -244,10 +245,11 @@ impl NodeConfig { /// List of available IP addresses. pub fn get_ip_addrs() -> Vec { let mut ip_addrs = Vec::new(); - for net_if in pnet::datalink::interfaces() { - for ip in net_if.ips { + let network_interfaces = list_afinet_netifas(); + if let Ok(network_interfaces) = network_interfaces { + for (_, ip) in network_interfaces.iter() { if ip.is_ipv4() { - ip_addrs.push(ip.ip().to_string()); + ip_addrs.push(ip.to_string()); } } } diff --git a/src/wallet/mnemonic.rs b/src/wallet/mnemonic.rs index 78ab853..537cd8c 100644 --- a/src/wallet/mnemonic.rs +++ b/src/wallet/mnemonic.rs @@ -103,4 +103,22 @@ impl Mnemonic { } words } + + /// Set words from provided text if possible. + pub fn import_text(&mut self, text: String) { + if self.mode != PhraseMode::Import { + return; + } + let words_split = text.trim().split(" "); + let count = words_split.clone().count(); + if PhraseSize::is_correct_count(count) { + if self.size == PhraseSize::type_for_value(count).unwrap() { + let mut words = vec![]; + words_split.enumerate().for_each(|(i, word)| { + words.insert(i, word.to_string()) + }); + self.words = words; + } + } + } } \ No newline at end of file diff --git a/src/wallet/types.rs b/src/wallet/types.rs index a866edd..c263494 100644 --- a/src/wallet/types.rs +++ b/src/wallet/types.rs @@ -62,6 +62,38 @@ impl PhraseSize { PhraseSize::Words24 => 32 } } + + pub fn type_for_value(count: usize) -> Option { + if Self::is_correct_count(count) { + match count { + 12 => { + Some(PhraseSize::Words12) + } + 15 => { + Some(PhraseSize::Words15) + } + 18 => { + Some(PhraseSize::Words18) + } + 21 => { + Some(PhraseSize::Words21) + } + 24 => { + Some(PhraseSize::Words24) + } + _ => { + None + } + } + } else { + None + } + } + + /// Check if correct word count provided. + pub fn is_correct_count(count: usize) -> bool { + count == 12 || count == 15 || count == 18 || count == 21 || count == 24 + } } /// Wallet connection method. diff --git a/src/wallet/wallet.rs b/src/wallet/wallet.rs index 00f3743..2c505a9 100644 --- a/src/wallet/wallet.rs +++ b/src/wallet/wallet.rs @@ -27,7 +27,7 @@ use futures::channel::oneshot; use grin_api::{ApiServer, Router}; use grin_chain::SyncStatus; use grin_core::global; -use grin_keychain::{ExtKeychain, Keychain}; +use grin_keychain::{ExtKeychain, Identifier, Keychain}; use grin_util::Mutex; use grin_util::types::ZeroingString; use grin_wallet_api::Owner; @@ -35,7 +35,7 @@ use grin_wallet_controller::command::parse_slatepack; use grin_wallet_controller::controller; use grin_wallet_controller::controller::ForeignAPIHandlerV2; use grin_wallet_impls::{DefaultLCProvider, DefaultWalletImpl, HTTPNodeClient}; -use grin_wallet_libwallet::{AcctPathMapping, Error, NodeClient, StatusMessage, TxLogEntryType, WalletInst, WalletLCProvider}; +use grin_wallet_libwallet::{Error, InitTxArgs, IssueInvoiceTxArgs, NodeClient, RetrieveTxQueryArgs, Slate, StatusMessage, TxLogEntry, TxLogEntryType, WalletInst, WalletLCProvider}; use grin_wallet_libwallet::api_impl::owner::{cancel_tx, retrieve_summary_info, retrieve_txs}; use crate::node::{Node, NodeConfig}; @@ -205,6 +205,15 @@ impl Wallet { Ok(Arc::new(Mutex::new(wallet))) } + /// Get parent key identifier for current account. + pub fn get_parent_key_id(&self) -> Result { + let instance = self.instance.clone().unwrap(); + let mut w_lock = instance.lock(); + let lc = w_lock.lc_provider()?; + let w_inst = lc.wallet_inst()?; + Ok(w_inst.parent_key_id()) + } + /// Get wallet config. pub fn get_config(&self) -> WalletConfig { self.config.read().unwrap().clone() @@ -238,7 +247,7 @@ impl Wallet { } // Create new wallet instance if sync thread was stopped or instance was not created. - if self.sync_thread.write().unwrap().is_none() || self.instance.is_none() { + if self.sync_thread.read().unwrap().is_none() || self.instance.is_none() { let config = self.get_config(); let new_instance = Self::create_wallet_instance(config.clone())?; self.instance = Some(new_instance); @@ -352,6 +361,9 @@ impl Wallet { let mut api = Owner::new(self.instance.clone().unwrap(), None); controller::owner_single_use(None, None, Some(&mut api), |api, m| { api.create_account_path(m, label)?; + + // Sync wallet data. + self.sync(); Ok(()) }) } @@ -448,7 +460,28 @@ impl Wallet { } } - /// Receive transaction via Slatepack Message. + /// Create Slatepack message from provided slate. + fn create_slatepack_message(&self, slate: Slate) -> Result { + let mut message = "".to_string(); + let mut api = Owner::new(self.instance.clone().unwrap(), None); + controller::owner_single_use(None, None, Some(&mut api), |api, m| { + message = api.create_slatepack_message(m, &slate, Some(0), vec![])?; + Ok(()) + })?; + + // Create a directory to which slatepack files will be output. + let mut slatepack_dir = self.get_config().get_slatepacks_path(); + let slatepack_file_name = format!("{}.{}.slatepack", slate.id, slate.state); + slatepack_dir.push(slatepack_file_name); + + // Write Slatepack response into the file. + let mut output = File::create(slatepack_dir)?; + output.write_all(message.as_bytes())?; + output.sync_all()?; + Ok(message) + } + + /// Receive transaction via Slatepack message, return response to sender. pub fn receive(&self, message: String) -> Result { let mut api = Owner::new(self.instance.clone().unwrap(), None); match parse_slatepack(&mut api, None, None, Some(message.clone())) { @@ -458,21 +491,37 @@ impl Wallet { slate = api.receive_tx(&slate, Some(config.account.as_str()), None)?; Ok(()) })?; - let mut response = "".to_string(); - controller::owner_single_use(None, None, Some(&mut api), |api, m| { - response = api.create_slatepack_message(m, &slate, Some(0), vec![])?; - Ok(()) - })?; + // Create Slatepack message response. + let response = self.create_slatepack_message(slate)?; - // Create a directory to which slatepack files will be output. - let mut slatepack_dir = config.get_slatepacks_path(); - let slatepack_file_name = format!("{}.{}.slatepack", slate.id, slate.state); - slatepack_dir.push(slatepack_file_name); + // Sync wallet info. + self.sync(); + Ok(response) + } + Err(_) => { + Err(Error::GenericError("Parsing error".to_string())) + } + } + } - // Write Slatepack response into the file. - let mut output = File::create(slatepack_dir)?; - output.write_all(response.as_bytes())?; - output.sync_all()?; + /// S transaction via Slatepack message and return response to sender. + pub fn pay(&self, message: String) -> Result { + let mut api = Owner::new(self.instance.clone().unwrap(), None); + match parse_slatepack(&mut api, None, None, Some(message.clone())) { + Ok((mut slate, _)) => { + let config = self.get_config(); + let args = InitTxArgs { + src_acct_name: None, + amount: slate.amount, + minimum_confirmations: config.min_confirmations, + selection_strategy_is_use_all: false, + ..Default::default() + }; + let mut api = Owner::new(self.instance.clone().unwrap(), None); + let slate = api.process_invoice_tx(None, &slate, args)?; + + // Create Slatepack message response. + let response = self.create_slatepack_message(slate)?; // Sync wallet info. self.sync(); @@ -485,6 +534,25 @@ impl Wallet { } } + /// Initialize an invoice transaction. + pub fn issue_invoice(&self, amount: u64) -> Result { + let args = IssueInvoiceTxArgs { + dest_acct_name: None, + amount, + target_slate_version: None, + }; + let mut api = Owner::new(self.instance.clone().unwrap(), None); + let slate = api.issue_invoice_tx(None, args)?; + + // Create Slatepack message response. + let response = self.create_slatepack_message(slate)?; + + // Sync wallet info. + self.sync(); + + Ok(response) + } + pub fn send(&self) { } @@ -513,6 +581,7 @@ impl Wallet { cancelling_r.contains(id) } + /// Finalize transaction from provided Slatepack message. pub fn finalize(&self) { } @@ -571,7 +640,7 @@ impl Wallet { wallet_delete.is_open.store(false, Ordering::Relaxed); wallet_delete.deleted.store(true, Ordering::Relaxed); - // Wake up thread to exit. + // Start sync to exit. wallet_delete.sync(); }); } @@ -786,16 +855,13 @@ fn sync_wallet_data(wallet: &Wallet) { } }); - // Retrieve txs. - match retrieve_txs( - instance.clone(), - None, - &Some(txs_tx), - true, - None, - None, - None - ) { + match retrieve_txs(instance.clone(), + None, + &Some(txs_tx), + true, + None, + None, + None) { Ok(txs) => { // Do not sync data if wallet was closed. if !wallet.is_open() { @@ -807,9 +873,20 @@ fn sync_wallet_data(wallet: &Wallet) { wallet.reset_sync_attempts(); // Setup transactions. - let mut txs = txs.1; + let mut sort_txs = txs.1; // Sort txs by creation date. - txs.sort_by_key(|tx| -tx.creation_ts.timestamp()); + sort_txs.sort_by_key(|tx| -tx.creation_ts.timestamp()); + // Filter txs by current wallet account. + let mut txs = sort_txs.iter().map(|v| v.clone()).filter(|tx| { + match wallet.get_parent_key_id() { + Ok(key) => { + tx.parent_key_id == key + } + Err(_) => { + true + } + } + }).collect::>(); // Update txs statuses. for tx in &txs { if tx.tx_type == TxLogEntryType::TxSentCancelled