Compare commits

..

249 Commits

Author SHA1 Message Date
luigi1111
937cb98256 Merge pull request #3469
9cfeba9 cmake: cleanup hidapi / libusb (selsta)
2021-05-13 00:24:51 -05:00
selsta
9cfeba9ba1 cmake: cleanup hidapi / libusb 2021-05-13 07:12:28 +02:00
luigi1111
e730e3ff63 Merge pull request #3468
46dec78 cmake: move external subdir before -Werror (selsta)
2021-05-12 23:27:48 -05:00
luigi1111
6b580cbb00 Merge pull request #3467
c8c8736 js: fix getApproximateBlockchainHeight (testnet) (selsta)
2021-05-12 23:27:10 -05:00
luigi1111
cb33fe2fc0 Merge pull request #3466
380c5b5 Transfer: fix QR code scanner inline button icon (xiphon)
2021-05-12 23:26:38 -05:00
luigi1111
bff6f7587f Merge pull request #3464
9360de4 cmake: fix WITH_SCANNER static build (link against Qt5MultimediaQuick) (xiphon)
2021-05-12 23:26:11 -05:00
luigi1111
12a72970fb Merge pull request #3463
138e164 Transfer: highlight invalid address (xiphon)
2021-05-12 23:25:46 -05:00
luigi1111
16e1d64b74 Merge pull request #3462
410ad22 LineEditMulti: fix 'error' property (xiphon)
2021-05-12 23:25:23 -05:00
luigi1111
9dbad4745d Merge pull request #3461
8d59880 cmake: prepare v0.17.2.2 (selsta)
2021-05-12 23:24:59 -05:00
luigi1111
0e7d1ab65b Merge pull request #3459
7d34086 WizardSummary: display bootstrap address only in local node mode (selsta)
2021-05-12 23:24:29 -05:00
luigi1111
b69eff367c Merge pull request #3458
755d218 WizardSummary: display daemon address only in remote node mode (selsta)
2021-05-12 23:24:06 -05:00
luigi1111
54ef114370 Merge pull request #3456
b304140 Transfer: vertical center address (selsta)
2021-05-12 23:23:38 -05:00
luigi1111
e984949aa7 Merge pull request #3455
a021b71 cmake: don't add fstack-clash-protection with clang (selsta)
2021-05-12 23:22:36 -05:00
luigi1111
25be9d5b9b Merge pull request #3451
a89ac67 Docker: Linux - fix docker cache and apt update issue (xiphon)
2021-05-12 23:21:55 -05:00
selsta
46dec78806 cmake: move external subdir before -Werror 2021-05-08 23:29:57 +02:00
selsta
c8c8736cf3 js: fix getApproximateBlockchainHeight (testnet) 2021-05-08 16:45:45 +02:00
xiphon
380c5b5588 Transfer: fix QR code scanner inline button icon 2021-05-08 11:38:35 +00:00
xiphon
9360de4ef8 cmake: fix WITH_SCANNER static build (link against Qt5MultimediaQuick) 2021-05-08 11:02:05 +00:00
xiphon
138e164878 Transfer: highlight invalid address 2021-05-08 10:02:19 +00:00
xiphon
410ad22821 LineEditMulti: fix 'error' property 2021-05-08 09:56:00 +00:00
selsta
8d59880d02 cmake: prepare v0.17.2.2 2021-05-07 15:52:28 +02:00
selsta
7d340869fc WizardSummary: display bootstrap address only in local node mode 2021-05-06 20:19:16 +02:00
selsta
755d218594 WizardSummary: display daemon address only in remote node mode 2021-05-06 19:25:48 +02:00
selsta
b304140720 Transfer: vertical center address 2021-05-05 22:29:47 +02:00
selsta
a021b71261 cmake: don't add fstack-clash-protection with clang 2021-05-05 21:39:15 +02:00
xiphon
a89ac67d59 Docker: Linux - fix docker cache and apt update issue 2021-04-30 14:05:27 +00:00
luigi1111
426dc3fa47 Merge pull request #3448
2cda1fc cmake: link with wallet_api instead of wallet_merged (selsta)
2021-04-29 14:16:56 -04:00
luigi1111
947a70a638 Merge pull request #3447
dac0c04 main: fix Monero GUI window centering (xiphon)
2021-04-29 14:16:32 -04:00
luigi1111
9041e73345 Merge pull request #3446
ab5cb01 docker: fix boost bintray links (selsta)
2021-04-29 14:16:10 -04:00
luigi1111
ea01a536ce Merge pull request #3445
bc528cc main: drop unused altKeyReleased routine (xiphon)
2021-04-29 14:15:46 -04:00
luigi1111
56f471b1b6 Merge pull request #3444
ad6f26c main: drop unused enableUI routine (xiphon)
2021-04-29 14:14:51 -04:00
luigi1111
9a216682c8 Merge pull request #3443
db8c4ed main: handleTransactionConfirmed - fix 'no file specified' case (xiphon)
2021-04-29 14:14:24 -04:00
luigi1111
e2e5a3919b Merge pull request #3441
837dd61 Revert 'Animation slow down for debugging' (selsta)
2021-04-29 14:13:57 -04:00
luigi1111
adc7c02782 Merge pull request #3439
51ece5f Wallet: drop unused paymentId property (xiphon)
2021-04-29 14:12:31 -04:00
luigi1111
4c85aea7c3 Merge pull request #3438
b3ad95f cmake: WIN_DEPLOY_DLLS - update libicu version to 68 (xiphon)
2021-04-29 14:12:09 -04:00
luigi1111
5c2076daa1 Merge pull request #3437
7558a23 main: remove minor switch/case code duplication (selsta)
2021-04-29 14:11:45 -04:00
luigi1111
578324348d Merge pull request #3436
14b1476 History: cleanup unused lookupPaymentID function (selsta)
2021-04-29 14:10:53 -04:00
luigi1111
dc3e35a928 Merge pull request #3434
989f135 Navbar: fix layout bug on resize (selsta)
2021-04-29 14:08:24 -04:00
luigi1111
0ee5259466 Merge pull request #3433
e13d49f Navbar: horizontally center text (selsta)
2021-04-29 14:07:58 -04:00
luigi1111
c3e88adc6d Merge pull request #3430
db0485c main: simplify blackTheme code (selsta)
2021-04-29 14:07:24 -04:00
luigi1111
c368ce2776 Merge pull request #3428
0fb9306 Makefile: add CMAKE_BUILD_TYPE=Debug to debug build (selsta)
2021-04-29 14:06:40 -04:00
selsta
2cda1fca69 cmake: link with wallet_api instead of wallet_merged 2021-04-27 13:49:28 +02:00
xiphon
dac0c04d20 main: fix Monero GUI window centering 2021-04-26 21:11:21 +00:00
selsta
ab5cb01510 docker: fix boost bintray links 2021-04-26 19:51:03 +02:00
xiphon
bc528ccb77 main: drop unused altKeyReleased routine 2021-04-26 11:52:31 +00:00
xiphon
ad6f26c8b4 main: drop unused enableUI routine 2021-04-26 11:46:56 +00:00
xiphon
db8c4edb08 main: handleTransactionConfirmed - fix 'no file specified' case 2021-04-26 11:17:59 +00:00
selsta
837dd6184e Revert "Animation slow down for debugging"
This reverts commit baff7f213f.
2021-04-25 23:53:43 +02:00
xiphon
51ece5fd00 Wallet: drop unused paymentId property 2021-04-25 00:05:35 +00:00
xiphon
b3ad95fdfc cmake: WIN_DEPLOY_DLLS - update libicu version to 68 2021-04-24 22:08:25 +00:00
luigi1111
d2fc4e60c6 Merge pull request #3431
4e67cd0 Wallet: omit redundant 'delete' on destruction (xiphon)
2021-04-24 16:17:06 -04:00
luigi1111
1ea38be404 Merge pull request #3429
1f904d4 RemoteNodeEdit: fix getAddress() and isValid() inconsistency (xiphon)
2021-04-24 16:16:33 -04:00
luigi1111
d69b1e0520 Merge pull request #3427
0a4b017 cmake: link translations target with Qt5::Core (selsta)
2021-04-24 16:16:05 -04:00
luigi1111
c11e32f511 Merge pull request #3208
01c3c19 SuccessfulTxDialog: add View progress button (rating89us)
2021-04-24 16:14:28 -04:00
selsta
7558a23243 main: remove minor switch/case code duplication 2021-04-24 08:25:12 +02:00
selsta
14b1476786 History: cleanup unused lookupPaymentID function 2021-04-24 07:25:05 +02:00
selsta
989f135d9a Navbar: fix layout bug on resize 2021-04-24 05:32:09 +02:00
selsta
e13d49f43e Navbar: horizontally center text 2021-04-24 05:24:43 +02:00
xiphon
4e67cd0014 Wallet: omit redundant 'delete' on destruction 2021-04-22 23:08:41 +00:00
selsta
db0485c600 main: simplify blackTheme code 2021-04-22 23:14:32 +02:00
xiphon
1f904d4cff RemoteNodeEdit: fix getAddress() and isValid() inconsistency 2021-04-22 21:00:48 +00:00
selsta
0a4b017697 cmake: link translations target with Qt5::Core 2021-04-22 21:03:41 +02:00
selsta
0fb93061b1 Makefile: add CMAKE_BUILD_TYPE=Debug to debug build 2021-04-22 18:54:25 +02:00
luigi1111
bc1131ce41 Merge pull request #3425
2fcacd1 main: update estimatedBlockchainSize (rating89us)
2021-04-22 01:58:29 -04:00
luigi1111
5667526ef6 Merge pull request #3424
341b267 Merchant: display selected subaddress (selsta)
2021-04-22 01:58:02 -04:00
luigi1111
fe5992debd Merge pull request #3423
398e28e Account, Receive: add missing fallback icons (selsta)
2021-04-22 01:57:35 -04:00
luigi1111
ca09151092 Merge pull request #3422
69a6c6b WizardDaemonSettings: implement full remote node configuration support (xiphon)
2021-04-22 01:57:04 -04:00
luigi1111
4ddc6b1c90 Merge pull request #3420
becc747 WalletManager: support kdf round in device wallet restore (selsta)
2021-04-22 01:56:39 -04:00
luigi1111
46bc94fbe8 Merge pull request #3419
820b221 WizardHome: fix kdf textbox displaying incorrect value (selsta)
2021-04-22 01:55:54 -04:00
luigi1111
842a9278d0 Merge pull request #3414
23f71e1 WizardSummary: don't display node address in simple mode (selsta)
2021-04-22 01:54:27 -04:00
luigi1111
f57e115e99 Merge pull request #3413
684fd94 WizardDaemonSettings: add reset button to db location (selsta)
2021-04-22 01:53:54 -04:00
luigi1111
beb566f11e Merge pull request #2242
9fc6179 macOS: add basic menubar support (selsta)
2021-04-22 01:53:03 -04:00
rating89us
2fcacd1e84 main: update estimatedBlockchainSize 2021-04-21 19:04:55 +02:00
selsta
341b267852 Merchant: display selected subaddress 2021-04-21 04:13:39 +02:00
selsta
398e28ed24 Account, Receive: add missing fallback icons 2021-04-21 03:57:39 +02:00
xiphon
69a6c6b821 WizardDaemonSettings: implement full remote node configuration support 2021-04-20 22:15:15 +00:00
selsta
becc74714b WalletManager: support kdf round in device wallet restore 2021-04-20 21:44:23 +02:00
selsta
820b221fa5 WizardHome: fix kdf textbox displaying incorrect value 2021-04-20 21:28:04 +02:00
selsta
23f71e1959 WizardSummary: don't display node address in simple mode 2021-04-19 07:21:11 +02:00
selsta
684fd941fb WizardDaemonSettings: add reset button to db location 2021-04-19 07:17:07 +02:00
selsta
9fc617956d macOS: add basic menubar support 2021-04-18 15:50:36 +02:00
luigi1111
02ae14fd6b Merge pull request #3405
62faf4d Navbar: fix width being slightly off (selsta)
2021-04-16 12:57:35 -05:00
luigi1111
a84d7bd2cb Merge pull request #3404
ba62f9c main: omit QML Screen type, use QGuiApplication::primaryScreen() instead (xiphon)
2021-04-16 12:57:08 -05:00
luigi1111
84b9264d1d Merge pull request #3401
767b9e0 TextPlain, Label: implement tooltips. Transfer: advanced - use tooltips (xiphon)
2021-04-16 12:56:34 -05:00
luigi1111
0ae6435429 Merge pull request #3397
6f7192b Transfer: fix desktop icon style (selsta)
2021-04-16 12:55:59 -05:00
luigi1111
c47332e2f1 Merge pull request #3395
d60bbb7 Wizard: use endsWith, fix todo (selsta)
2021-04-16 12:55:37 -05:00
luigi1111
7dcd33f203 Merge pull request #3394
c60252d LanguageSidebar: simplify code (selsta)
2021-04-16 12:55:08 -05:00
luigi1111
bed56137e3 Merge pull request #3392
475f263 main: lower minimum required QtQml.Models version to 2.2 (xiphon)
2021-04-16 12:54:44 -05:00
selsta
62faf4d82e Navbar: fix width being slightly off 2021-04-16 02:37:25 +02:00
xiphon
ba62f9c686 main: omit QML Screen type, use QGuiApplication::primaryScreen() instead 2021-04-15 19:50:32 +00:00
selsta
6f7192bb12 Transfer: fix desktop icon style 2021-04-15 14:55:40 +02:00
xiphon
767b9e05b3 TextPlain, Label: implement tooltips. Transfer: advanced - use tooltips 2021-04-15 00:09:45 +00:00
selsta
d60bbb72f7 Wizard: use endsWith, fix todo 2021-04-14 21:34:17 +02:00
selsta
c60252d3ce LanguageSidebar: simplify code 2021-04-14 19:17:01 +02:00
xiphon
475f26398d main: lower minimum required QtQml.Models version to 2.2 2021-04-14 15:34:05 +00:00
luigi1111
8444a9563e Merge pull request #3391
142c6bc cmake: prepare v0.17.2.1 (selsta)
2021-04-13 16:29:45 -05:00
luigi1111
2f41a6aecf Merge pull request #3390
f53af12 Wallet: fix transfer with Qt 5.12 (selsta)
2021-04-13 16:29:13 -05:00
luigi1111
61bb6d359f Merge pull request #3386
990e92b without StartupWMClass=monero-wallet-gui gnome-shell users can not add the applications to their favorites (Tobias Strauß)
2021-04-13 16:28:31 -05:00
luigi1111
938a4fada4 Merge pull request #3383
3a37364 cmake: remove typo (selsta)
2021-04-13 16:27:53 -05:00
selsta
142c6bc19f cmake: prepare v0.17.2.1 2021-04-13 16:15:24 +02:00
selsta
f53af12e02 Wallet: fix transfer with Qt 5.12 2021-04-13 07:27:05 +02:00
Tobias Strauß
990e92ba00 without StartupWMClass=monero-wallet-gui gnome-shell users can not add the applications to their favorites 2021-04-09 09:59:35 +02:00
luigi1111
816eeb4647 Merge pull request #3382
ddec66b build: prepare v0.17.2.0 (selsta)
2021-04-08 20:19:25 -05:00
luigi1111
d5b4f43f48 Merge pull request #3381
325e99d SettingsNode: fix icon size (selsta)
2021-04-08 20:10:16 -05:00
luigi1111
4597b4d94d Merge pull request #3380
c789efb workflows: test qml of docker compiled apps (selsta)
2021-04-08 20:09:52 -05:00
luigi1111
691fdac7a4 Merge pull request #3379
76b0b60 docker: build with QtQmlModels plugin (xiphon)
2021-04-08 20:01:08 -05:00
selsta
3a37364741 cmake: remove typo 2021-04-09 01:10:04 +02:00
selsta
c789efbe8a workflows: test qml of docker compiled apps 2021-04-08 01:36:06 +02:00
selsta
ddec66b2ad build: prepare v0.17.2.0 2021-04-08 01:32:54 +02:00
selsta
325e99d202 SettingsNode: fix icon size 2021-04-07 18:14:09 +02:00
xiphon
76b0b6013a docker: build with QtQmlModels plugin 2021-04-06 21:43:55 +00:00
luigi1111
183585653f Merge pull request #3373
6bc9627 SettingsNode: implement multiple remote nodes support (xiphon)
2021-04-06 11:35:23 -05:00
xiphon
6bc9627046 SettingsNode: implement multiple remote nodes support 2021-04-06 11:58:36 +00:00
luigi1111
ba7eeb12c5 Merge pull request #3371
ecc8b8c RemoteNodeEdit: change border color on focus (xiphon)
2021-04-05 21:43:23 -05:00
luigi1111
2354c615d1 Merge pull request #3370
74e1483 Checkbox: handle Enter/Return/Space keys, change border color on focus (xiphon)
2021-04-05 21:31:48 -05:00
luigi1111
3aa530aa84 Merge pull request #3345
6b0cb8d support pruning of new databases (benevanoff)
2021-04-05 21:31:00 -05:00
benevanoff
6b0cb8dadb support pruning of new databases 2021-04-05 18:56:19 -05:00
xiphon
ecc8b8cc99 RemoteNodeEdit: change border color on focus 2021-04-02 16:42:52 +00:00
xiphon
74e1483d0b Checkbox: handle Enter/Return/Space keys, change border color on focus 2021-04-02 12:10:24 +00:00
luigi1111
b3dace6b45 Merge pull request #3363
1e4c0d2 Renamed Norwegian translation file. (Anton Kling)
2021-03-30 14:07:07 -04:00
luigi1111
a17b88d80a Merge pull request #3361
7c881d0 LeftPanel: drop Advanced submenu items, use NavBar instead (xiphon)
2021-03-30 14:06:30 -04:00
luigi1111
1ee06fb78c Merge pull request #3360
d83f147 DaemonManager: start monerod with '--non-interactive' cli option set (xiphon)
2021-03-30 14:06:05 -04:00
luigi1111
ac2e9d370b Merge pull request #3332
a0a9d9e Transfer: implement sending to multiple recipients (xiphon)
2021-03-30 14:05:28 -04:00
xiphon
a0a9d9e31e Transfer: implement sending to multiple recipients 2021-03-23 08:50:10 +00:00
Anton Kling
1e4c0d2e0d Renamed Norwegian translation file. 2021-03-21 00:12:35 +01:00
xiphon
7c881d0100 LeftPanel: drop Advanced submenu items, use NavBar instead 2021-03-20 09:20:09 +00:00
xiphon
d83f14799e DaemonManager: start monerod with '--non-interactive' cli option set 2021-03-19 10:31:43 +00:00
luigi1111
34df4e74d4 Merge pull request #3359
244d622 Docker: Android - switch to debian:stretch, build CMake from source (xiphon)
2021-03-19 01:09:50 -04:00
luigi1111
9593a16cb0 Merge pull request #3357
34d3f65 Navbar: reimplement as a reusable component, drop redundant code (xiphon)
e94ac7c Navbar: move to components (xiphon)
2021-03-19 01:08:50 -04:00
luigi1111
3e8bc1dcd3 Merge pull request #3354
ad19dbb cmake: sync submodule if DEV_MODE=ON (selsta)
2021-03-19 01:08:02 -04:00
luigi1111
8dd06bba5c Merge pull request #3325
92a2ae1 TxConfirmationDialog: implement multiple recipients support, layout fixes (xiphon)
2021-03-19 01:06:59 -04:00
xiphon
244d622818 Docker: Android - switch to debian:stretch, build CMake from source 2021-03-17 12:57:28 +00:00
xiphon
34d3f6575a Navbar: reimplement as a reusable component, drop redundant code 2021-03-17 12:00:17 +00:00
xiphon
e94ac7c75d Navbar: move to components 2021-03-17 11:28:01 +00:00
selsta
ad19dbb440 cmake: sync submodule if DEV_MODE=ON 2021-03-12 01:26:57 +01:00
luigi1111
c18614f96f Merge pull request #3347
40adc6b use preferred colors for DaemonManagerDialog (Ben Evanoff)
2021-03-05 14:01:59 -05:00
luigi1111
16fdedc4d0 Merge pull request #3342
4403387 Translations from Weblate (weblate)
2021-03-05 14:01:20 -05:00
luigi1111
057de959b9 Merge pull request #3330
16fd2b4 LineEdit: fontFamily and inputPadding properties, fix backtab (xiphon)
2021-03-05 13:58:54 -05:00
luigi1111
88d26dbecf Merge pull request #3328
2bb1092 LineEditMulti: right padding, fontFamily, backtab, inline btns vcenter (xiphon)
2021-03-05 13:58:28 -05:00
luigi1111
059af2bb49 Merge pull request #3326
4f10683 OSHelper: Linux - fix isCapsLock memory leak (xiphon)
2021-03-05 13:58:00 -05:00
Weblate
4403387fa4 Translations from Weblate
Translation files updated:

    Found 724 source text(s) (2 new and 722 already existing)
    Removed 2 obsolete entries

Translators:

* Spanish

    * Luis Alejandro Herrera Bolaños
    * ian vatega
    * Miguel Medina
    * Michael Russo
    * Samuel
    * 0x82b
    * kombometralla
    * Tony Nguyen

* Slovak

    * Boris Sipos

* Vietnamese

    * Tabula Rasa

* Italian

    * 8uDD4T
    * Gleb Golov

* Chinese (Traditional)

    * Lafudoci

* Catalan

    * Joan Montané

* Persian

    * Nima Ghotbi

* Esperanto

    * Gilberto F da Silva

* Russian

    * Russian Bear
    * Agent LvM
    * v1docq47

* Japanese

    * Scott Anecito
    * x52fws
    * Lana

* Portuguese (Portugal)

    * Demofrager
    * Ian appel
    * EvolBit

* French

    * Bertrand Jacquin
    * lir4376
    * Loué Marie
    * el00ruobuob

* Czech

    * Michal Vašíček
    * dskch83

* Polish

    * ambercookie

* Greek

    * warraxxx
    * Georgios Apostolopoulos
    * ΚΥΡΙΑΚΟΣ ΚΑΡΑΚΥΡΙΟΣ
    * Marinus Savoritias
    * Iason Andreou
    * Donald A. Iljazi

* Lithuanian

    * Vytas
    * Aivaras Kasperaitis

* Portuguese (Brazil)

    * Renato MB
    * netrik182
    * Mathkamy

* Norwegian Bokmål

    * Allan Nordhøy

* Dutch

    * obit33
    * Edwin den Boer
    * dutchcodes

* Hebrew

    * Ori Levenglick
    * Yan Abu Arab

* German

    * G. Orwell
    * mr
    * Paul Janowitz
    * Nicolas
    * GreenPiece
    * SJ
    * Deleted User
    * Wobole

Signed-off-by: erciccione <erciccione@protonmail.com>
2021-03-03 16:47:09 +01:00
xiphon
92a2ae1a11 TxConfirmationDialog: implement multiple recipients support, layout fixes 2021-03-03 00:53:51 +00:00
Ben Evanoff
40adc6bbbf use preferred colors for DaemonManagerDialog 2021-03-02 14:49:49 -06:00
luigi1111
c073867657 Merge pull request #3331
e25e44b AddressBook: don't alter tx Description on recipient selection (xiphon)
2021-02-18 15:03:27 -05:00
luigi1111
a7f5b44488 Merge pull request #3329
3c27c57 CheckBox: change opacity to 70% in disabled state (xiphon)
2021-02-18 15:02:07 -05:00
luigi1111
8b8948954d Merge pull request #3327
b20b956 Wallet: estimateTransactionFeeAsync - multi dest support (xiphon)
2021-02-18 15:01:14 -05:00
luigi1111
2c763f5014 Merge pull request #3323
f40b10e workflows: add py7zr to macos bundle (selsta)
2021-02-18 14:58:50 -05:00
luigi1111
5d566d1c02 Merge pull request #3321
38f21a3 installers/windows: fix typo in readme.htm (secure-designer)
2021-02-18 14:58:24 -05:00
luigi1111
41520b3a71 Merge pull request #3317
c948c9d README: Update the homebrew install instructions (toh995)
2021-02-18 14:57:31 -05:00
luigi1111
5039de8327 Merge pull request #3315
04d5fa5 Wallet: refactor createTransaction (xiphon)
2021-02-18 14:55:10 -05:00
xiphon
2bb1092472 LineEditMulti: right padding, fontFamily, backtab, inline btns vcenter 2021-02-08 20:30:05 +00:00
xiphon
16fd2b4447 LineEdit: fontFamily and inputPadding properties, fix backtab 2021-02-08 20:29:28 +00:00
xiphon
3c27c570d4 CheckBox: change opacity to 70% in disabled state 2021-02-05 15:32:04 +00:00
xiphon
e25e44b45f AddressBook: don't alter tx Description on recipient selection 2021-02-05 15:28:38 +00:00
xiphon
b20b956e15 Wallet: estimateTransactionFeeAsync - multi dest support 2021-02-04 11:32:30 +00:00
xiphon
4f10683c2c OSHelper: Linux - fix isCapsLock memory leak 2021-02-03 10:41:33 +00:00
selsta
f40b10ea0b workflows: add py7zr to macos bundle 2021-02-02 00:58:19 +01:00
secure-designer
38f21a3e89 installers/windows: fix typo in readme.htm 2021-01-30 20:03:55 +00:00
luigi1111
1f0f21a8e5 Merge pull request #3314
9cf7c7f DaemonManager: enable dns block list in simple mode (selsta)
2021-01-29 00:33:07 -05:00
toh995
c948c9dd7c README: Update the homebrew install instructions 2021-01-27 00:32:49 -08:00
xiphon
04d5fa51cf Wallet: refactor createTransaction 2021-01-25 11:57:49 +00:00
luigi1111
c1573c2c2a Merge pull request #3308
5848aee Navbar: cleanup layout (xiphon)
2021-01-22 15:09:07 -05:00
luigi1111
42fba21c6b Merge pull request #3306
83bb7a9 Makefile: support USE_SINGLE_BUILDDIR=OFF without git installed (xiphon)
2021-01-22 15:08:20 -05:00
luigi1111
04e3ac9200 Merge pull request #3305
d3102b1 DaemonManager: refactoring - drop singleton usage (xiphon)
2021-01-22 15:07:39 -05:00
luigi1111
f9f319d571 Merge pull request #3302
55baa8b main: restrict max window width/height, fix initial window alignment (xiphon)
2021-01-22 15:07:00 -05:00
luigi1111
090dca7848 Merge pull request #3301
18f16d9 SettingsLayout: 'Display wallet name in title bar' option (xiphon)
2021-01-22 15:05:58 -05:00
selsta
9cf7c7f03c DaemonManager: enable dns block list in simple mode
Co-authored-by: xiphon <xiphon@protonmail.com>
2021-01-22 20:50:51 +01:00
luigi1111
d3d26e37d0 Merge pull request #3309
a25b164 SettingsLog: disable daemon command input in Remote Node mode (xiphon)
2021-01-21 23:41:50 -05:00
luigi1111
b79f1b8ff4 Merge pull request #3307
a214003 README: Windows docker builds are reproducible since v0.17.1.9 (xiphon)
2021-01-21 23:40:17 -05:00
luigi1111
2a44f95f16 Merge pull request #3311
45b5150 Utils: fix removeTrailingZeros regression (xiphon)
2021-01-20 22:43:27 -05:00
luigi1111
dc0ce27963 Merge pull request #3310
bd21914 README: MacOS - add libsodium monero dependency (xiphon)
2021-01-20 22:42:54 -05:00
luigi1111
378da8093d Merge pull request #3304
93b2231 Subaddress: log account subaddresses refresh error (xiphon)
2021-01-20 22:42:01 -05:00
luigi1111
5261f79e9f Merge pull request #3298
f3a24d9 main: fix kraken fiat api (selsta)
2021-01-20 22:41:21 -05:00
luigi1111
1659c7fd1a Merge pull request #3295
07a9b0e workflows: print sha256sum of windows gui (selsta)
2021-01-20 22:40:50 -05:00
luigi1111
ec7bc577d6 Merge pull request #3292
e9b894d Transfer: implement 'Grab QR code from screen' functionality (xiphon)
2021-01-20 22:40:14 -05:00
luigi1111
3f4de99be4 Merge pull request #3289
7c32fe6 remove copy qr uri to clipboard button (Ben Evanoff)
2021-01-20 22:39:43 -05:00
luigi1111
1a11f2b192 Merge pull request #3215
cedfa5a History: search by receiving address, receiving address label, address book label (rating89us)
2021-01-20 22:39:03 -05:00
luigi1111
e21d7be725 Merge pull request #3168
baa0ffa WizardRestoreWallet1: add view-only option in placeholder of private spend key (rating89us)
2021-01-20 22:38:24 -05:00
luigi1111
4098352faf Merge pull request #3164
1373e70 account/receive: highlight background and text of selected item (rating89us)
2021-01-20 22:37:24 -05:00
xiphon
a25b164cd5 SettingsLog: disable daemon command input in Remote Node mode 2021-01-19 09:42:14 +00:00
xiphon
45b5150487 Utils: fix removeTrailingZeros regression 2021-01-16 03:31:23 +00:00
xiphon
bd21914b9b README: MacOS - add libsodium monero dependency 2021-01-15 11:34:04 +00:00
xiphon
5848aee1c3 Navbar: cleanup layout 2021-01-15 10:09:44 +00:00
xiphon
a214003559 README: Windows docker builds are reproducible since v0.17.1.9 2021-01-15 00:01:34 +00:00
xiphon
83bb7a9297 Makefile: support USE_SINGLE_BUILDDIR=OFF without git installed
# Conflicts:
#	Makefile
2021-01-14 23:21:33 +00:00
xiphon
d3102b1cc5 DaemonManager: refactoring - drop singleton usage 2021-01-14 19:14:22 +00:00
xiphon
93b22311e3 Subaddress: log account subaddresses refresh error 2021-01-14 08:19:13 +00:00
xiphon
55baa8b695 main: restrict max window width/height, fix initial window alignment 2021-01-13 03:14:57 +00:00
xiphon
18f16d9ebd SettingsLayout: 'Display wallet name in title bar' option 2021-01-12 12:59:28 +00:00
xiphon
e9b894da16 Transfer: implement 'Grab QR code from screen' functionality 2021-01-11 01:35:54 +00:00
selsta
f3a24d92a4 main: fix kraken fiat api 2021-01-11 00:29:48 +01:00
selsta
07a9b0e6f7 workflows: print sha256sum of windows gui 2021-01-08 05:33:01 +01:00
Alexander Blair
3ca5f10fa8 Merge pull request #3294
f7b81797 build: prepare v0.17.1.9 (selsta)
2021-01-07 18:00:05 -08:00
selsta
f7b817972f build: prepare v0.17.1.9 2021-01-08 02:56:28 +01:00
Alexander Blair
9399839d96 Merge pull request #3287
72ab846b installer: remove high dpi shortcut (selsta)
2021-01-03 18:46:20 -08:00
Alexander Blair
51a4d1f629 Merge pull request #3283
5662841d docker: Windows - use Qt 5.15.2 (xiphon)
2021-01-03 18:45:48 -08:00
Alexander Blair
bbe3716542 Merge pull request #3277
8d4cda03 QR-Code-scanner: integrate QUIRC library, implement QrDecoder, drop ZBar (xiphon)
2021-01-03 18:45:26 -08:00
Ben Evanoff
7c32fe6b5c remove copy qr uri to clipboard button 2021-01-02 14:34:59 -06:00
selsta
72ab846be5 installer: remove high dpi shortcut
Qt 5.15 supports high DPI natively
2021-01-01 05:13:36 +01:00
Alexander Blair
8e6a2cde0f Merge pull request #3285
c34d4ee9 build: prepare v0.17.1.8 (selsta)
2020-12-30 01:53:31 -08:00
selsta
c34d4ee97c build: prepare v0.17.1.8 2020-12-30 10:37:36 +01:00
Alexander Blair
0194cf8f22 Merge pull request #3280
ba4d6993 LineEdit: fix padding, fix inline buttons layout, multiple btns support (xiphon)
2020-12-28 11:41:47 -08:00
Alexander Blair
ad06fcc79e Merge pull request #3271
78f5360a Transfer: support pasting amount with whitespaces (xiphon)
2020-12-28 11:41:38 -08:00
Alexander Blair
7d4b82c691 Merge pull request #3270
a1fdffca WizardRestoreWallet1: fix mnemonic seed placeholder (xiphon)
2020-12-28 11:41:15 -08:00
Alexander Blair
69f989d617 Merge pull request #3281
3f0bbfb6 Transfer: updateFromQrCode - fix extra space (empty recipient name) (xiphon)
2020-12-26 13:47:31 -08:00
Alexander Blair
0f3df860e3 Merge pull request #3275
772b828b cmake: MacOS - detect ICU link directory (required by Boost.Locale) (xiphon)
2020-12-26 13:45:24 -08:00
xiphon
5662841d22 docker: Windows - use Qt 5.15.2 2020-12-26 08:37:45 +00:00
xiphon
3f0bbfb6aa Transfer: updateFromQrCode - fix extra space (empty recipient name) 2020-12-24 10:07:08 +00:00
xiphon
ba4d6993b7 LineEdit: fix padding, fix inline buttons layout, multiple btns support 2020-12-24 08:20:38 +00:00
xiphon
8d4cda030e QR-Code-scanner: integrate QUIRC library, implement QrDecoder, drop ZBar 2020-12-23 15:08:42 +00:00
xiphon
772b828b67 cmake: MacOS - detect ICU link directory (required by Boost.Locale) 2020-12-20 20:00:23 +00:00
xiphon
78f5360af2 Transfer: support pasting amount with whitespaces 2020-12-14 11:59:45 +00:00
xiphon
a1fdffcabe WizardRestoreWallet1: fix mnemonic seed placeholder 2020-12-13 11:31:14 +00:00
luigi1111
fed00a5662 Merge pull request #3269
14a4777 build: prepare v0.17.1.7 (selsta)
2020-12-12 22:16:13 -06:00
luigi1111
79f2843b09 Merge pull request #3268
cebb789 Wallet: fix initialization flag handling (xiphon)
2020-12-12 22:15:10 -06:00
selsta
14a477748e build: prepare v0.17.1.7 2020-12-13 05:11:20 +01:00
xiphon
cebb78979c Wallet: fix initialization flag handling 2020-12-12 11:22:52 +00:00
Alexander Blair
df771470c2 Merge pull request #3267
90e9968d main: get back "Sending transaction ..." splash (xiphon)
2020-12-10 18:02:11 -08:00
Alexander Blair
e359c60f00 Merge pull request #3266
841d0e01 Utils: removeTrailingZeros - handle .0* decimal part (i.e. 1.00000) (xiphon)
2020-12-10 18:01:38 -08:00
Alexander Blair
53335a8487 Merge pull request #3264
2feee9e9 workflows: shorten name (selsta)
2020-12-10 18:01:19 -08:00
Alexander Blair
3f64312283 Merge pull request #3262
486ba055 main: disable QML cache (xiphon)
2020-12-10 17:59:09 -08:00
Alexander Blair
897946af13 Merge pull request #3260
ae8394e5 main: Linux - fix missing askDesktopShortcut setting (xiphon)
2020-12-10 17:58:42 -08:00
Alexander Blair
e90626e05a Merge pull request #3259
fa79e609 workflows: bump docker cache action (selsta)
2020-12-10 17:58:06 -08:00
xiphon
90e9968dcb main: get back "Sending transaction ..." splash 2020-12-10 23:59:12 +00:00
xiphon
841d0e01dc Utils: removeTrailingZeros - handle .0* decimal part (i.e. 1.00000) 2020-12-10 23:00:39 +00:00
selsta
2feee9e956 workflows: shorten name 2020-12-10 04:01:43 +01:00
xiphon
486ba05526 main: disable QML cache 2020-12-09 14:29:02 +00:00
xiphon
ae8394e5f8 main: Linux - fix missing askDesktopShortcut setting 2020-12-08 01:02:00 +00:00
selsta
fa79e609e1 workflows: bump docker cache action 2020-12-07 19:22:37 +01:00
luigi1111
cc352e4913 Merge pull request #3258
903539b build: prepare v0.17.1.6 (selsta)
2020-12-07 10:37:31 -06:00
selsta
903539bd30 build: prepare v0.17.1.6 2020-12-07 17:34:40 +01:00
rating89us
01c3c19653 SuccessfulTxDialog: add View progress button 2020-12-04 12:53:40 +01:00
Alexander Blair
af0b3142a0 Merge pull request #3255
606dbed4 README: update Linux Docker build instructions (xiphon)
2020-12-03 12:24:50 -08:00
Alexander Blair
6fe41e6f55 Merge pull request #3254
0d5d2dbf Transfer: fix focus, cycle focus between Address, Amount and Send (xiphon)
2020-12-03 12:24:22 -08:00
Alexander Blair
2a6ad67f77 Merge pull request #3253
110b09ef TxConfirmationDialog: fix keys handling (xiphon)
2020-12-03 12:23:58 -08:00
Alexander Blair
5652284572 Merge pull request #3252
0fdf81bc SuccessfulTxDialog: fix keys handling (xiphon)
2020-12-03 12:23:24 -08:00
Alexander Blair
2eeeadfd10 Merge pull request #3251
ea1fee2f main: Linux - ask to create desktop entry on the first start (xiphon)
2020-12-03 12:23:02 -08:00
xiphon
0d5d2dbf5e Transfer: fix focus, cycle focus between Address, Amount and Send 2020-12-03 19:40:15 +00:00
xiphon
606dbed4a0 README: update Linux Docker build instructions 2020-12-03 00:55:29 +00:00
Alexander Blair
301b20d19c Merge pull request #3249
ef54a32d workflows: print hash for reproducible builds (selsta)
2020-12-01 14:25:22 -08:00
Alexander Blair
f6196d48ab Merge pull request #3169
cd3a0f85 Restore: display red border if invalid seed (rating89us)
2020-12-01 14:25:01 -08:00
xiphon
110b09efba TxConfirmationDialog: fix keys handling 2020-12-01 16:25:35 +00:00
xiphon
0fdf81bc92 SuccessfulTxDialog: fix keys handling 2020-12-01 16:19:56 +00:00
xiphon
ea1fee2f5f main: Linux - ask to create desktop entry on the first start 2020-11-30 15:36:19 +00:00
selsta
ef54a32de0 workflows: print hash for reproducible builds 2020-11-26 10:34:19 +01:00
rating89us
cedfa5aabb History: search by receiving address, receiving address label, address book label 2020-11-07 20:04:12 +01:00
rating89us
cd3a0f85a6 Restore: display red border if invalid seed 2020-10-18 17:06:34 +02:00
rating89us
1373e709d6 account/receive: highlight background and text of selected item 2020-10-17 20:19:50 +02:00
rating89us
baa0ffa5f9 WizardRestoreWallet1: add view-only option in placeholder of private spend key 2020-10-17 17:53:52 +02:00
142 changed files with 33154 additions and 23365 deletions

View File

@@ -1,4 +1,4 @@
name: continuous-integration/gh-actions/gui
name: ci/gh-actions/gui
on: [push, pull_request]
@@ -10,7 +10,7 @@ jobs:
with:
submodules: recursive
- name: install dependencies
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi zmq libpgm miniupnpc ldns expat libunwind-headers protobuf qt5 pkg-config
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi zmq libpgm libsodium miniupnpc ldns expat libunwind-headers protobuf qt5 pkg-config
- name: build
run: DEV_MODE=ON make release -j3
- name: test qml
@@ -34,7 +34,7 @@ jobs:
- name: install monero dependencies
run: sudo apt -y install build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev libprotobuf-dev protobuf-compiler
- name: install monero gui dependencies
run: sudo apt -y install qtbase5-dev qt5-default qtdeclarative5-dev qml-module-qtquick-controls qml-module-qtquick-controls2 qml-module-qtquick-dialogs qml-module-qtquick-xmllistmodel qml-module-qt-labs-settings qml-module-qt-labs-folderlistmodel qttools5-dev-tools qml-module-qtquick-templates2 libqt5svg5-dev libgcrypt20-dev xvfb
run: sudo apt -y install qtbase5-dev qt5-default qtdeclarative5-dev qml-module-qtqml-models2 qml-module-qtquick-controls qml-module-qtquick-controls2 qml-module-qtquick-dialogs qml-module-qtquick-xmllistmodel qml-module-qt-labs-settings qml-module-qt-labs-platform qml-module-qt-labs-folderlistmodel qttools5-dev-tools qml-module-qtquick-templates2 libqt5svg5-dev libgcrypt20-dev xvfb
- name: build
run: DEV_MODE=ON make release -j3
- name: test qml
@@ -67,7 +67,7 @@ jobs:
- name: install dependencies
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi zmq libpgm miniupnpc ldns expat libunwind-headers protobuf pkg-config python3 p7zip
- name: install dependencies
run: pip3 install requests semantic_version lxml
run: pip3 install requests semantic_version lxml py7zr
- name: download qt
run: |
curl -O https://raw.githubusercontent.com/engnr/qt-downloader/master/qt-downloader
@@ -79,6 +79,8 @@ jobs:
- name: deploy
run: make deploy
working-directory: build/release
- name: test qml
run: build/release/bin/monero-wallet-gui.app/Contents/MacOS/monero-wallet-gui --test-qml
- name: create .tar
run: tar -cf monero-wallet-gui.tar monero-wallet-gui.app
working-directory: build/release/bin
@@ -93,16 +95,22 @@ jobs:
- uses: actions/checkout@v1
with:
submodules: recursive
- uses: satackey/action-docker-layer-caching@v0.0.8
- uses: satackey/action-docker-layer-caching@v0.0.10
continue-on-error: true
with:
key: docker-linux-static-{hash}
restore-keys: |
docker-linux-static-
- name: install dependencies
run: sudo apt -y install xvfb libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xkb1 libxkbcommon-x11-0
- name: preprare build enviroment
run: docker build --tag monero:build-env-linux --build-arg THREADS=3 --file Dockerfile.linux .
- name: build
run: docker run --rm -v /home/runner/work/monero-gui/monero-gui:/monero-gui -w /monero-gui monero:build-env-linux sh -c 'make release-static -j3'
- name: sha256sum
run: shasum -a256 /home/runner/work/monero-gui/monero-gui/build/release/bin/monero-wallet-gui
- name: test qml
run: xvfb-run -a /home/runner/work/monero-gui/monero-gui/build/release/bin/monero-wallet-gui --test-qml
- uses: actions/upload-artifact@v2
with:
name: ${{ github.job }}
@@ -116,7 +124,7 @@ jobs:
- uses: actions/checkout@v1
with:
submodules: recursive
- uses: satackey/action-docker-layer-caching@v0.0.8
- uses: satackey/action-docker-layer-caching@v0.0.10
continue-on-error: true
with:
key: docker-windows-static-{hash}
@@ -126,6 +134,8 @@ jobs:
run: docker build --tag monero:build-env-windows --build-arg THREADS=3 --file Dockerfile.windows .
- name: build
run: docker run --rm -v /home/runner/work/monero-gui/monero-gui:/monero-gui -w /monero-gui monero:build-env-windows sh -c 'make depends root=/depends target=x86_64-w64-mingw32 tag=win-x64 -j3'
- name: sha256sum
run: shasum -a256 /home/runner/work/monero-gui/monero-gui/build/x86_64-w64-mingw32/release/bin/monero-wallet-gui.exe
- uses: actions/upload-artifact@v2
with:
name: ${{ github.job }}

3
.gitmodules vendored
View File

@@ -2,3 +2,6 @@
path = monero
url = https://github.com/monero-project/monero
ignore = all
[submodule "external/quirc"]
path = external/quirc
url = https://github.com/dlbeer/quirc/

View File

@@ -4,8 +4,8 @@ project(monero-gui)
message(STATUS "Initiating compile using CMake ${CMAKE_VERSION}")
set(VERSION_MAJOR "17")
set(VERSION_MINOR "1")
set(VERSION_REVISION "5")
set(VERSION_MINOR "2")
set(VERSION_REVISION "2")
set(VERSION "0.${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}")
option(STATIC "Link libraries statically, requires static Qt")
@@ -48,8 +48,9 @@ if(NOT MANUAL_SUBMODULES)
else()
execute_process(COMMAND ${GIT_EXECUTABLE} fetch WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/monero RESULT_VARIABLE GIT_FETCH_RESULT)
execute_process(COMMAND ${GIT_EXECUTABLE} checkout -f origin/master WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/monero RESULT_VARIABLE GIT_CHECKOUT_MASTER_RESULT)
execute_process(COMMAND ${GIT_EXECUTABLE} submodule sync --recursive WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/monero RESULT_VARIABLE GIT_SUBMODULE_SYNC_RESULT)
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --force --recursive WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/monero RESULT_VARIABLE GIT_SUBMODULE_UPDATE_RESULT)
if(NOT GIT_FETCH_RESULT EQUAL "0" OR NOT GIT_CHECKOUT_MASTER_RESULT EQUAL "0" OR NOT GIT_SUBMODULE_UPDATE_RESULT EQUAL "0")
if(NOT GIT_FETCH_RESULT EQUAL "0" OR NOT GIT_CHECKOUT_MASTER_RESULT EQUAL "0" OR NOT GIT_SUBMODULE_SYNC_RESULT EQUAL "0" OR NOT GIT_SUBMODULE_UPDATE_RESULT EQUAL "0")
message(FATAL_ERROR "Updating git submodule to master (-DDEV_MODE=ON) failed")
endif()
endif()
@@ -57,16 +58,13 @@ if(NOT MANUAL_SUBMODULES)
endif()
add_subdirectory(monero)
add_subdirectory(external)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set_property(TARGET wallet_merged PROPERTY FOLDER "monero")
get_directory_property(ARCH_WIDTH DIRECTORY "monero" DEFINITION ARCH_WIDTH)
get_directory_property(UNBOUND_LIBRARY DIRECTORY "monero" DEFINITION UNBOUND_LIBRARY)
get_directory_property(DEVICE_TREZOR_READY DIRECTORY "monero" DEFINITION DEVICE_TREZOR_READY)
get_directory_property(TREZOR_DEP_LIBS DIRECTORY "monero" DEFINITION TREZOR_DEP_LIBS)
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DQT_NO_DEBUG)
@@ -131,30 +129,14 @@ message(STATUS "OpenSSL: Version ${OPENSSL_VERSION}")
message(STATUS "OpenSSL: include dir at ${OPENSSL_INCLUDE_DIR}")
message(STATUS "OpenSSL: libraries at ${OPENSSL_LIBRARIES} ${OPENSSL_SSL_LIBRARIES}")
# Zbar (for QR scanner)
if(WITH_SCANNER)
add_definitions(-DWITH_SCANNER)
find_package(ZBar0 REQUIRED)
message(STATUS "libzbar: include dir at ${ZBAR_INCLUDE_DIR}")
message(STATUS "libzbar: libraries at ${ZBAR_LIBRARIES}")
endif()
# Sodium
find_library(SODIUM_LIBRARY sodium)
message(STATUS "libsodium: libraries at ${SODIUM_LIBRARY}")
# LibUSB
find_package(LibUSB)
message(STATUS "libusb: include dir at ${LibUSB_INCLUDE_DIRS}")
message(STATUS "libusb: libraries at ${LibUSB_LIBRARIES}")
# HIDApi
if(NOT ANDROID)
find_package(HIDAPI REQUIRED)
message(STATUS "libhidapi: include dir at ${HIDAPI_INCLUDE_DIRS}")
message(STATUS "libhidapi: libraries at ${HIDAPI_LIBRARIES}")
endif()
# Boost
if(DEBUG)
set(Boost_DEBUG ON)
@@ -302,10 +284,12 @@ list(APPEND QT5_LIBRARIES
if(STATIC)
set(QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/Qt/labs/folderlistmodel)
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/Qt/labs/settings)
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/Qt/labs/platform)
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtGraphicalEffects)
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtGraphicalEffects/private)
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtMultimedia)
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQml)
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQml/Models.2)
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick.2)
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Controls)
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Controls.2)
@@ -326,14 +310,16 @@ if(STATIC)
dialogsprivateplugin
qmlfolderlistmodelplugin
qmlsettingsplugin
qtlabsplatformplugin
qmlxmllistmodelplugin
qquicklayoutsplugin
modelsplugin
)
if(WITH_SCANNER)
list(APPEND QT5_EXTRA_LIBRARIES_LIST
declarative_multimedia
Qt5MultimediaQuick_p
Qt5MultimediaQuick
)
endif()
@@ -480,7 +466,7 @@ if (NOT OPENBSD AND NOT (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE
add_c_flag_if_supported(-fcf-protection=full C_SECURITY_FLAGS)
add_cxx_flag_if_supported(-fcf-protection=full CXX_SECURITY_FLAGS)
endif()
if (NOT WIN32 AND NOT OPENBSD)
if (NOT WIN32 AND NOT OPENBSD AND NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
add_c_flag_if_supported(-fstack-clash-protection C_SECURITY_FLAGS)
add_cxx_flag_if_supported(-fstack-clash-protection CXX_SECURITY_FLAGS)
endif()
@@ -543,26 +529,5 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 ${C_SECURITY_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${CXX_SECURITY_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LD_SECURITY_FLAGS} ${STATIC_FLAGS}")
if (HIDAPI_FOUND OR LibUSB_COMPILE_TEST_PASSED)
if (APPLE)
if(DEPENDS)
list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework IOKit")
else()
find_library(COREFOUNDATION CoreFoundation)
find_library(IOKIT IOKit)
list(APPEND EXTRA_LIBRARIES ${IOKIT})
list(APPEND EXTRA_LIBRARIES ${COREFOUNDATION})
endif()
endif()
if (WIN32)
find_library(VERSION_LIBRARY version PATHS /usr/x86_64-w64-mingw32/lib)
if(VERSION_LIBRARY STREQUAL "VERSION_LIBRARY-NOTFOUND")
set(VERSION_LIBRARY Version)
endif()
list(APPEND EXTRA_LIBRARIES setupapi ${VERSION_LIBRARY})
endif()
endif()
add_subdirectory(translations)
add_subdirectory(src)

View File

@@ -1,4 +1,4 @@
FROM debian:unstable
FROM debian:stretch
ARG THREADS=1
ARG ANDROID_NDK_REVISION=21d
@@ -22,8 +22,9 @@ ENV PREFIX=${WORKDIR}/prefix
ENV TOOLCHAIN_DIR=${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64
RUN apt-get update \
&& apt-get install -y ant automake build-essential ca-certificates-java cmake file gettext git libc6 libncurses5 \
libstdc++6 libtinfo5 libtool libz1 openjdk-8-jdk-headless openjdk-8-jre-headless pkg-config python3 unzip wget
&& apt-get install -y ant automake build-essential ca-certificates-java file gettext git libc6 libncurses5 \
libssl-dev libstdc++6 libtinfo5 libtool libz1 openjdk-8-jdk-headless openjdk-8-jre-headless pkg-config python3 \
unzip wget
RUN wget -q https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_REVISION}.zip \
&& unzip -q sdk-tools-linux-${ANDROID_SDK_REVISION}.zip \
@@ -77,11 +78,11 @@ RUN git clone git://code.qt.io/qt/qt5.git -b ${QT_VERSION} --depth 1 \
&& sed -i '213,215d' qtbase/src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h \
&& PATH=${HOST_PATH} make -j${THREADS} \
&& PATH=${HOST_PATH} make -j${THREADS} install \
&& cd qttools/src/linguist/lrelease && \
../../../../qtbase/bin/qmake && \
PATH=${HOST_PATH} make -j$THREADS install && \
cd ../../../.. && \
rm -rf $(pwd)
&& cd qttools/src/linguist/lrelease \
&& ../../../../qtbase/bin/qmake \
&& PATH=${HOST_PATH} make -j${THREADS} install \
&& cd ../../../.. \
&& rm -rf $(pwd)
ARG ICONV_VERSION=1.16
ARG ICONV_HASH=e6a1b1b589654277ee790cce3734f07876ac4ccfaecbee8afa0b649cf529cc04
@@ -97,7 +98,7 @@ RUN wget -q http://ftp.gnu.org/pub/gnu/libiconv/libiconv-${ICONV_VERSION}.tar.gz
ARG BOOST_VERSION=1_74_0
ARG BOOST_VERSION_DOT=1.74.0
ARG BOOST_HASH=83bfc1507731a0906e387fc28b7ef5417d591429e51e788417fe9ff025e116b1
RUN wget -q https://dl.bintray.com/boostorg/release/${BOOST_VERSION_DOT}/source/boost_${BOOST_VERSION}.tar.bz2 \
RUN wget -q https://downloads.sourceforge.net/project/boost/boost/${BOOST_VERSION_DOT}/boost_${BOOST_VERSION}.tar.bz2 \
&& echo "${BOOST_HASH} boost_${BOOST_VERSION}.tar.bz2" | sha256sum -c \
&& tar -xf boost_${BOOST_VERSION}.tar.bz2 \
&& rm -f boost_${BOOST_VERSION}.tar.bz2 \
@@ -151,25 +152,6 @@ RUN set -ex \
&& make -j${THREADS} install \
&& rm -rf $(pwd)
RUN git clone https://github.com/ZBar/ZBar.git --depth 1 \
&& cd ZBar \
&& git reset --hard 854a5d97059e395807091ac4d80c53f7968abb8f \
&& sed -i 's/SHARED/STATIC/' android/jni/Android.mk \
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CPP_FEATURES := exceptions rtti features\n\0/' android/jni/Android.mk \
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CFLAGS := -Wno-multichar\n\0/' android/jni/Android.mk \
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CFLAGS += -D_ANDROID\n\0/' android/jni/Android.mk \
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CFLAGS += -DLIBDIR="\\".\\""\n\0/' android/jni/Android.mk \
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CFLAGS += -DBUILDING_LIBICONV\n\0/' android/jni/Android.mk \
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CFLAGS += -DBUILDING_LIBCHARSET\n\0/' android/jni/Android.mk \
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CFLAGS += -DIN_LIBRARY\n\0/' android/jni/Android.mk \
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CFLAGS += -fno-stack-protector\n\0/' android/jni/Android.mk \
&& echo "APP_ABI := arm64-v8a \nAPP_STL := c++_shared \nTARGET_PLATFORM := ${ANDROID_API} \nTARGET_ARCH_ABI := arm64-v8a \nAPP_CFLAGS += -target aarch64-none-linux-android -fexceptions -fstack-protector-strong -fno-limit-debug-info -mfloat-abi=softfp -fno-builtin-memmove -fno-omit-frame-pointer -fno-stack-protector\n" \
>> android/jni/Application.mk \
&& cd android \
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ${ANDROID_NDK_ROOT}/ndk-build ICONV_SRC=${WORKDIR}/libiconv-${ICONV_VERSION} -B V=1 NDK_APPLICATION_MK=jni/Application.mk \
&& cp obj/local/arm64-v8a/lib* ${PREFIX}/lib \
&& cp -r ../include/* ${PREFIX}/include
RUN git clone -b libgpg-error-1.38 --depth 1 git://git.gnupg.org/libgpg-error.git \
&& cd libgpg-error \
&& git reset --hard 71d278824c5fe61865f7927a2ed1aa3115f9e439 \
@@ -194,6 +176,14 @@ RUN cd tools \
&& rm -f tools_r25.2.5-linux.zip \
&& echo y | ${ANDROID_SDK_ROOT}/tools/android update sdk --no-ui --all --filter build-tools-28.0.3
RUN git clone -b v3.19.7 --depth 1 https://github.com/Kitware/CMake \
&& cd CMake \
&& git reset --hard 22612dd53a46c7f9b4c3f4b7dbe5c78f9afd9581 \
&& PATH=${HOST_PATH} ./bootstrap \
&& PATH=${HOST_PATH} make -j${THREADS} \
&& PATH=${HOST_PATH} make -j${THREADS} install \
&& rm -rf $(pwd)
CMD set -ex \
&& cd /monero-gui \
&& mkdir -p build/Android/release \

View File

@@ -8,10 +8,12 @@ ENV CPPFLAGS="-fPIC"
ENV CXXFLAGS="-fPIC"
ENV SOURCE_DATE_EPOCH=1397818193
RUN apt update
RUN apt update && \
apt install -y automake autopoint bison gettext git gperf libgl1-mesa-dev libglib2.0-dev \
libpng12-dev libpthread-stubs0-dev libsodium-dev libtool-bin libudev-dev libusb-1.0-0-dev mesa-common-dev \
pkg-config python wget xutils-dev
RUN apt install -y automake git pkg-config python xutils-dev && \
git clone -b xorgproto-2020.1 --depth 1 https://gitlab.freedesktop.org/xorg/proto/xorgproto && \
RUN git clone -b xorgproto-2020.1 --depth 1 https://gitlab.freedesktop.org/xorg/proto/xorgproto && \
cd xorgproto && \
git reset --hard c62e8203402cafafa5ba0357b6d1c019156c9f36 && \
./autogen.sh && \
@@ -27,8 +29,7 @@ RUN git clone -b 1.12 --depth 1 https://gitlab.freedesktop.org/xorg/proto/xcbpro
make -j$THREADS install && \
rm -rf $(pwd)
RUN apt install -y libtool-bin && \
git clone -b libXau-1.0.9 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxau && \
RUN git clone -b libXau-1.0.9 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxau && \
cd libxau && \
git reset --hard d9443b2c57b512cfb250b35707378654d86c7dea && \
./autogen.sh --enable-shared --disable-static && \
@@ -36,8 +37,7 @@ RUN apt install -y libtool-bin && \
make -j$THREADS install && \
rm -rf $(pwd)
RUN apt install -y libpthread-stubs0-dev && \
git clone -b 1.12 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb && \
RUN git clone -b 1.12 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb && \
cd libxcb && \
git reset --hard d34785a34f28fa6a00f8ce00d87e3132ff0f6467 && \
./autogen.sh --enable-shared --disable-static && \
@@ -105,8 +105,7 @@ RUN git clone -b 0.4.1 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-
make -j$THREADS install && \
rm -rf $(pwd)
RUN apt install -y bison && \
git clone -b xkbcommon-0.5.0 --depth 1 https://github.com/xkbcommon/libxkbcommon && \
RUN git clone -b xkbcommon-0.5.0 --depth 1 https://github.com/xkbcommon/libxkbcommon && \
cd libxkbcommon && \
git reset --hard c43c3c866eb9d52cd8f61e75cbef1c30d07f3a28 && \
./autogen.sh --prefix=/usr --enable-shared --disable-static --enable-x11 --disable-docs && \
@@ -140,8 +139,7 @@ RUN git clone -b R_2_2_9 --depth 1 https://github.com/libexpat/libexpat && \
make -j$THREADS install && \
rm -rf $(pwd)
RUN apt install -y autopoint gettext gperf libpng12-dev && \
git clone -b 2.13.92 --depth 1 https://gitlab.freedesktop.org/fontconfig/fontconfig && \
RUN git clone -b 2.13.92 --depth 1 https://gitlab.freedesktop.org/fontconfig/fontconfig && \
cd fontconfig && \
git reset --hard b1df1101a643ae16cdfa1d83b939de2497b1bf27 && \
./autogen.sh --disable-shared --enable-static --sysconfdir=/etc --localstatedir=/var && \
@@ -157,8 +155,7 @@ RUN git clone -b release-64-2 --depth 1 https://github.com/unicode-org/icu && \
make -j$THREADS install && \
rm -rf $(pwd)
RUN apt install -y wget && \
wget https://dl.bintray.com/boostorg/release/1.73.0/source/boost_1_73_0.tar.gz && \
RUN wget https://downloads.sourceforge.net/project/boost/boost/1.73.0/boost_1_73_0.tar.gz && \
echo "9995e192e68528793755692917f9eb6422f3052a53c5e13ba278a228af6c7acf boost_1_73_0.tar.gz" | sha256sum -c && \
tar -xzf boost_1_73_0.tar.gz && \
rm boost_1_73_0.tar.gz && \
@@ -177,8 +174,7 @@ RUN wget https://www.openssl.org/source/openssl-1.1.1g.tar.gz && \
make -j$THREADS install && \
rm -rf $(pwd)
RUN apt install -y libgl1-mesa-dev libglib2.0-dev mesa-common-dev && \
rm /usr/lib/x86_64-linux-gnu/libX11.a && \
RUN rm /usr/lib/x86_64-linux-gnu/libX11.a && \
rm /usr/lib/x86_64-linux-gnu/libXext.a && \
rm /usr/lib/x86_64-linux-gnu/libX11-xcb.a && \
git clone git://code.qt.io/qt/qt5.git -b ${QT_VERSION} --depth 1 && \
@@ -218,8 +214,7 @@ RUN apt install -y libgl1-mesa-dev libglib2.0-dev mesa-common-dev && \
cd ../../../.. && \
rm -rf $(pwd)
RUN apt install -y libudev-dev && \
git clone -b v1.0.23 --depth 1 https://github.com/libusb/libusb && \
RUN git clone -b v1.0.23 --depth 1 https://github.com/libusb/libusb && \
cd libusb && \
git reset --hard e782eeb2514266f6738e242cdcb18e3ae1ed06fa && \
./autogen.sh --disable-shared --enable-static && \
@@ -236,8 +231,7 @@ RUN git clone -b hidapi-0.9.0 --depth 1 https://github.com/libusb/hidapi && \
make -j$THREADS install && \
rm -rf $(pwd)
RUN apt install -y libsodium-dev && \
git clone -b v4.3.2 --depth 1 https://github.com/zeromq/libzmq && \
RUN git clone -b v4.3.2 --depth 1 https://github.com/zeromq/libzmq && \
cd libzmq && \
git reset --hard a84ffa12b2eb3569ced199660bac5ad128bff1f0 && \
./autogen.sh && \
@@ -280,5 +274,3 @@ RUN git clone -b v3.18.4 --depth 1 https://github.com/Kitware/CMake && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
RUN apt install -y libusb-1.0-0-dev

View File

@@ -1,6 +1,8 @@
FROM ubuntu:20.04
ARG THREADS=1
ARG QT_VERSION=5.15.2
ENV SOURCE_DATE_EPOCH=1397818193
RUN apt update && \
DEBIAN_FRONTEND=noninteractive apt install -y build-essential cmake g++-mingw-w64 gettext git libtool pkg-config \
@@ -19,26 +21,35 @@ RUN git clone -b v0.17.0.0 --depth 1 https://github.com/monero-project/monero &&
RUN make -j$THREADS -C /depends HOST=x86_64-w64-mingw32 NO_QT=1
RUN curl -LO https://download.qt.io/archive/qt/5.9/5.9.9/single/qt-everywhere-opensource-src-5.9.9.tar.xz && \
echo "5ce285209290a157d7f42ec8eb22bf3f1d76f2e03a95fc0b99b553391be01642 qt-everywhere-opensource-src-5.9.9.tar.xz" > hashsum.txt && \
sha256sum -c hashsum.txt && \
tar -xf qt-everywhere-opensource-src-5.9.9.tar.xz && \
rm qt-everywhere-opensource-src-5.9.9.tar.xz && \
cd qt-everywhere-opensource-src-5.9.9 && \
RUN git clone git://code.qt.io/qt/qt5.git -b ${QT_VERSION} --depth 1 && \
cd qt5 && \
git clone git://code.qt.io/qt/qtbase.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qtdeclarative.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qtgraphicaleffects.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qtimageformats.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qtmultimedia.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qtquickcontrols.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qtquickcontrols2.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qtsvg.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qttools.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qttranslations.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qtxmlpatterns.git -b ${QT_VERSION} --depth 1 && \
./configure --prefix=/depends/x86_64-w64-mingw32 -xplatform win32-g++ \
-device-option CROSS_COMPILE=/usr/bin/x86_64-w64-mingw32- \
-I $(pwd)/qtbase/src/3rdparty/angle/include \
-opensource -confirm-license -release -static -static-runtime -opengl dynamic -no-angle \
-no-avx -no-openssl -no-sql-sqlite \
-no-feature-qml-worker-script -no-openssl -no-sql-sqlite \
-qt-freetype -qt-harfbuzz -qt-libjpeg -qt-libpng -qt-pcre -qt-zlib \
-skip gamepad -skip location -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcanvas3d -skip qtcharts \
-skip qtconnectivity -skip qtdatavis3d -skip qtdoc -skip qtgamepad -skip qtlocation -skip qtmacextras \
-skip qtmultimedia -skip qtnetworkauth -skip qtpurchasing -skip qtscript -skip qtscxml -skip qtsensors \
-skip qtserialbus -skip qtserialport -skip qtspeech -skip qttools -skip qtvirtualkeyboard -skip qtwayland \
-skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtwinextras -skip qtx11extras \
-skip gamepad -skip location -skip qt3d -skip qtactiveqt -skip qtandroidextras \
-skip qtcanvas3d -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdoc \
-skip qtgamepad -skip qtlocation -skip qtmacextras -skip qtnetworkauth -skip qtpurchasing \
-skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport \
-skip qtspeech -skip qttools -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel \
-skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtwinextras -skip qtx11extras \
-skip serialbus -skip webengine \
-nomake examples -nomake tests -nomake tools && \
make QMAKE="$(pwd)/qtbase/bin/qmake CONFIG-='debug debug_and_release'" -j$THREADS && \
make -j$THREADS && \
make -j$THREADS install && \
cd qttools/src/linguist/lrelease && \
../../../../qtbase/bin/qmake && \

View File

@@ -58,12 +58,9 @@ Rectangle {
signal historyClicked()
signal transferClicked()
signal receiveClicked()
signal txkeyClicked()
signal sharedringdbClicked()
signal advancedClicked()
signal settingsClicked()
signal addressBookClicked()
signal miningClicked()
signal signClicked()
signal accountClicked()
function selectItem(pos) {
@@ -72,10 +69,6 @@ Rectangle {
else if(pos === "Transfer") menuColumn.previousButton = transferButton
else if(pos === "Receive") menuColumn.previousButton = receiveButton
else if(pos === "AddressBook") menuColumn.previousButton = addressBookButton
else if(pos === "Mining") menuColumn.previousButton = miningButton
else if(pos === "TxKey") menuColumn.previousButton = txkeyButton
else if(pos === "SharedRingDB") menuColumn.previousButton = sharedringdbButton
else if(pos === "Sign") menuColumn.previousButton = signButton
else if(pos === "Settings") menuColumn.previousButton = settingsButton
else if(pos === "Advanced") menuColumn.previousButton = advancedButton
else if(pos === "Account") menuColumn.previousButton = accountButton
@@ -480,6 +473,7 @@ Rectangle {
onClicked: {
parent.previousButton.checked = false
parent.previousButton = advancedButton
panel.advancedClicked()
}
}
@@ -490,98 +484,6 @@ Rectangle {
anchors.leftMargin: 20
}
// ------------- Mining tab ---------------
MoneroComponents.MenuButton {
id: miningButton
visible: !isAndroid && !isIOS && appWindow.walletMode >= 2
anchors.left: parent.left
anchors.right: parent.right
text: qsTr("Mining") + translationManager.emptyString
symbol: qsTr("M") + translationManager.emptyString
under: advancedButton
onClicked: {
parent.previousButton.checked = false
parent.previousButton = miningButton
panel.miningClicked()
}
}
MoneroComponents.MenuButtonDivider {
visible: miningButton.present && appWindow.walletMode >= 2
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 20
}
// ------------- TxKey tab ---------------
MoneroComponents.MenuButton {
id: txkeyButton
visible: appWindow.walletMode >= 2
anchors.left: parent.left
anchors.right: parent.right
text: qsTr("Prove/check") + translationManager.emptyString
symbol: qsTr("K") + translationManager.emptyString
under: advancedButton
onClicked: {
parent.previousButton.checked = false
parent.previousButton = txkeyButton
panel.txkeyClicked()
}
}
MoneroComponents.MenuButtonDivider {
visible: txkeyButton.present && appWindow.walletMode >= 2
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 20
}
// ------------- Shared RingDB tab ---------------
MoneroComponents.MenuButton {
id: sharedringdbButton
visible: appWindow.walletMode >= 2
anchors.left: parent.left
anchors.right: parent.right
text: qsTr("Shared RingDB") + translationManager.emptyString
symbol: qsTr("G") + translationManager.emptyString
under: advancedButton
onClicked: {
parent.previousButton.checked = false
parent.previousButton = sharedringdbButton
panel.sharedringdbClicked()
}
}
MoneroComponents.MenuButtonDivider {
visible: sharedringdbButton.present && appWindow.walletMode >= 2
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 20
}
// ------------- Sign/verify tab ---------------
MoneroComponents.MenuButton {
id: signButton
visible: appWindow.walletMode >= 2
anchors.left: parent.left
anchors.right: parent.right
text: qsTr("Sign/verify") + translationManager.emptyString
symbol: qsTr("I") + translationManager.emptyString
under: advancedButton
onClicked: {
parent.previousButton.checked = false
parent.previousButton = signButton
panel.signClicked()
}
}
MoneroComponents.MenuButtonDivider {
visible: signButton.present && appWindow.walletMode >= 2
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 20
}
// ------------- Settings tab ---------------
MoneroComponents.MenuButton {
id: settingsButton

View File

@@ -2,8 +2,12 @@ ANDROID_STANDALONE_TOOLCHAIN_PATH ?= /usr/local/toolchain
MANUAL_SUBMODULES ?= OFF
dotgit=$(shell ls -d .git/config)
ifneq ($(dotgit), .git/config)
USE_SINGLE_BUILDDIR=1
ifeq ($(dotgit), .git/config)
ifeq ($(shell git --version > /dev/null 2>&1 ; echo $$?), 0)
git = yes
else
$(warning git command not found)
endif
endif
builddir := build
@@ -13,9 +17,11 @@ ifeq ($(USE_SINGLE_BUILDDIR), OFF)
builddir := $(builddir)/$(os)
topdir := $(topdir)/..
branch:=$(shell git branch | grep '\* ' | cut -f2- -d' '| sed -e 's|[:/\\ \(\)]|_|g')
builddir := $(builddir)/$(branch)
topdir := $(topdir)/..
ifdef git
branch := $(shell git branch | grep '\* ' | cut -f2- -d' '| sed -e 's|[:/\\ \(\)]|_|g')
builddir := $(builddir)/$(branch)
topdir := $(topdir)/..
endif
deldirs := $(builddir)
else
@@ -25,7 +31,7 @@ endif
default:
mkdir -p build && cd build && cmake -D ARCH="x86-64" -D DEV_MODE=$(or ${DEV_MODE},OFF) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release .. && $(MAKE)
debug:
mkdir -p build && cd build && cmake -D DEV_MODE=$(or ${DEV_MODE},ON) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} .. && $(MAKE) VERBOSE=1
mkdir -p build && cd build && cmake -D DEV_MODE=$(or ${DEV_MODE},ON) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -D CMAKE_BUILD_TYPE=Debug .. && $(MAKE) VERBOSE=1
depends:
mkdir -p build/$(target)/release

View File

@@ -51,22 +51,19 @@ Rectangle {
property alias flickable: mainFlickable
property Transfer transferView: Transfer {
onPaymentClicked: root.paymentClicked(address, paymentId, amount, mixinCount, priority, description)
onPaymentClicked: root.paymentClicked(recipients, paymentId, mixinCount, priority, description)
onSweepUnmixableClicked: root.sweepUnmixableClicked()
}
property Receive receiveView: Receive { }
property Merchant merchantView: Merchant { }
property TxKey txkeyView: TxKey { }
property SharedRingDB sharedringdbView: SharedRingDB { }
property History historyView: History { }
property Sign signView: Sign { }
property Advanced advancedView: Advanced { }
property Settings settingsView: Settings { }
property Mining miningView: Mining { }
property AddressBook addressBookView: AddressBook { }
property Keys keysView: Keys { }
property Account accountView: Account { }
signal paymentClicked(string address, string paymentId, string amount, int mixinCount, int priority, string description)
signal paymentClicked(var recipients, string paymentId, int mixinCount, int priority, string description)
signal sweepUnmixableClicked()
signal generatePaymentIdInvoked()
signal getProofClicked(string txid, string address, string message);
@@ -119,6 +116,12 @@ Rectangle {
transferView.sendTo(address, paymentId, description);
}
// open Transactions page with search term in search field
function searchInHistory(searchTerm){
root.state = "History";
historyView.searchInHistory(searchTerm);
}
states: [
State {
name: "History"
@@ -136,30 +139,18 @@ Rectangle {
name: "Merchant"
PropertyChanges { target: root; currentView: merchantView }
PropertyChanges { target: mainFlickable; contentHeight: merchantView.merchantHeight + 80 }
}, State {
name: "TxKey"
PropertyChanges { target: root; currentView: txkeyView }
PropertyChanges { target: mainFlickable; contentHeight: txkeyView.txkeyHeight + 80 }
}, State {
name: "SharedRingDB"
PropertyChanges { target: root; currentView: sharedringdbView }
PropertyChanges { target: mainFlickable; contentHeight: sharedringdbView.panelHeight + 80 }
}, State {
name: "AddressBook"
PropertyChanges { target: root; currentView: addressBookView }
PropertyChanges { target: mainFlickable; contentHeight: addressBookView.addressbookHeight + 80 }
}, State {
name: "Sign"
PropertyChanges { target: root; currentView: signView }
PropertyChanges { target: mainFlickable; contentHeight: signView.signHeight + 80 }
name: "Advanced"
PropertyChanges { target: root; currentView: advancedView }
PropertyChanges { target: mainFlickable; contentHeight: advancedView.panelHeight }
}, State {
name: "Settings"
PropertyChanges { target: root; currentView: settingsView }
PropertyChanges { target: mainFlickable; contentHeight: settingsView.settingsHeight }
}, State {
name: "Mining"
PropertyChanges { target: root; currentView: miningView }
PropertyChanges { target: mainFlickable; contentHeight: miningView.miningHeight + 80 }
}, State {
name: "Keys"
PropertyChanges { target: root; currentView: keysView }
@@ -168,7 +159,7 @@ Rectangle {
name: "Account"
PropertyChanges { target: root; currentView: accountView }
PropertyChanges { target: mainFlickable; contentHeight: accountView.accountHeight + 80 }
}
}
]
ColumnLayout {

View File

@@ -72,7 +72,7 @@ Packages are available for
* Debian: See the [whonix/monero-gui repository](https://gitlab.com/whonix/monero-gui#how-to-install-monero-using-apt-get)
* Void Linux: `xbps-install -S monero-gui`
* GuixSD: `guix package -i monero-gui`
* macOS (homebrew): `brew cask install monero-wallet`
* macOS (homebrew): `brew install --cask monero-wallet`
Packaging for your favorite distribution would be a welcome contribution!
@@ -80,13 +80,14 @@ Packaging for your favorite distribution would be a welcome contribution!
*Note*: Qt 5.9.7 is the minimum version required to build the GUI.
### Building Windows static binaries with Docker (any OS)
### Building Reproducible Windows static binaries with Docker (any OS)
1. Install Docker [https://docs.docker.com/engine/install/](https://docs.docker.com/engine/install/)
2. Clone the repository
```
git clone --recursive https://github.com/monero-project/monero-gui.git
git clone --branch master --recursive https://github.com/monero-project/monero-gui.git
```
\* `master` - replace with the desired version tag (e.g. `v0.17.1.9`) to build the release binaries.
3. Prepare build environment
```
cd monero-gui
@@ -102,13 +103,14 @@ Packaging for your favorite distribution would be a welcome contribution!
\* `4` - number of CPU threads to use
5. Monero GUI Windows static binaries will be placed in `monero-gui/build/x86_64-w64-mingw32/release/bin` directory
### Building Linux static binaries with Docker (any OS)
### Building Reproducible Linux static binaries with Docker (any OS)
1. Install Docker [https://docs.docker.com/engine/install/](https://docs.docker.com/engine/install/)
2. Clone the repository
```
git clone --recursive https://github.com/monero-project/monero-gui.git
git clone --branch master --recursive https://github.com/monero-project/monero-gui.git
```
\* `master` - replace with the desired version tag (e.g. `v0.17.1.9`) to build the release binaries.
3. Prepare build environment
```
cd monero-gui
@@ -123,6 +125,11 @@ Packaging for your favorite distribution would be a welcome contribution!
\* `<MONERO_GUI_DIR_FULL_PATH>` - absolute path to `monero-gui` directory
\* `4` - number of CPU threads to use
5. Monero GUI Linux static binaries will be placed in `monero-gui/build/release/bin` directory
6. (*Optional*) Compare `monero-wallet-gui` SHA-256 hash to the one obtained from a trusted source
```
docker run --rm -it -v <MONERO_GUI_DIR_FULL_PATH>:/monero-gui -w /monero-gui monero:build-env-linux sh -c 'shasum -a 256 /monero-gui/build/release/bin/monero-wallet-gui'
```
\* `<MONERO_GUI_DIR_FULL_PATH>` - absolute path to `monero-gui` directory
### Building Android APK with Docker (any OS) *Experimental*
- Minimum Android 9 Pie (API 28)
@@ -201,7 +208,7 @@ The following instructions will fetch Qt from your distribution's repositories i
- For Ubuntu 17.10+
`sudo apt install qtbase5-dev qt5-default qtdeclarative5-dev qml-module-qtquick-controls qml-module-qtquick-controls2 qml-module-qtquick-dialogs qml-module-qtquick-xmllistmodel qml-module-qt-labs-settings qml-module-qt-labs-folderlistmodel qttools5-dev-tools qml-module-qtquick-templates2 libqt5svg5-dev`
`sudo apt install qtbase5-dev qt5-default qtdeclarative5-dev qml-module-qtqml-models2 qml-module-qtquick-controls qml-module-qtquick-controls2 qml-module-qtquick-dialogs qml-module-qtquick-xmllistmodel qml-module-qt-labs-settings qml-module-qt-labs-platform qml-module-qt-labs-folderlistmodel qttools5-dev-tools qml-module-qtquick-templates2 libqt5svg5-dev`
- For Gentoo
@@ -211,13 +218,13 @@ The following instructions will fetch Qt from your distribution's repositories i
- For Ubuntu
`sudo apt install qtmultimedia5-dev qml-module-qtmultimedia libzbar-dev`
`sudo apt install qtmultimedia5-dev qml-module-qtmultimedia`
- For Gentoo
The *qml* USE flag must be enabled.
`emerge dev-qt/qtmultimedia:5 media-gfx/zbar`
`emerge dev-qt/qtmultimedia:5`
3. Clone repository
@@ -245,7 +252,7 @@ The executable can be found in the build/release/bin folder.
3. Install [monero](https://github.com/monero-project/monero) dependencies:
`brew install boost hidapi zmq libpgm miniupnpc ldns expat libunwind-headers protobuf libgcrypt`
`brew install boost hidapi zmq libpgm libsodium miniupnpc ldns expat libunwind-headers protobuf libgcrypt`
4. Install Qt:
@@ -284,12 +291,6 @@ The Monero GUI on Windows is 64 bits only; 32-bit Windows GUI builds are not off
pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb mingw-w64-x86_64-libgcrypt
```
Optional : To build the flag `WITH_SCANNER`
```
pacman -S mingw-w64-x86_64-zbar
```
You find more details about those dependencies in the [Monero documentation](https://github.com/monero-project/monero). Note that that there is no more need to compile Boost from source; like everything else, you can install it now with a MSYS2 package.
4. Install Qt5

View File

@@ -78,19 +78,19 @@ if(APPLE OR (WIN32 AND NOT STATIC))
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
list(APPEND WIN_DEPLOY_DLLS
libicudtd67.dll
libicuind67.dll
libicuiod67.dll
libicutud67.dll
libicuucd67.dll
libicudtd68.dll
libicuind68.dll
libicuiod68.dll
libicutud68.dll
libicuucd68.dll
)
else() # assume release
list(APPEND WIN_DEPLOY_DLLS
libicudt67.dll
libicuin67.dll
libicuio67.dll
libicutu67.dll
libicuuc67.dll
libicudt68.dll
libicuin68.dll
libicuio68.dll
libicutu68.dll
libicuuc68.dll
)
endif()
list(TRANSFORM WIN_DEPLOY_DLLS PREPEND "$ENV{MSYSTEM_PREFIX}/bin/")

View File

@@ -1,60 +0,0 @@
# - try to find HIDAPI library
# from http://www.signal11.us/oss/hidapi/
#
# Cache Variables: (probably not for direct use in your scripts)
# HIDAPI_INCLUDE_DIR
# HIDAPI_LIBRARY
#
# Non-cache variables you might use in your CMakeLists.txt:
# HIDAPI_FOUND
# HIDAPI_INCLUDE_DIRS
# HIDAPI_LIBRARIES
#
# Requires these CMake modules:
# FindPackageHandleStandardArgs (known included with CMake >=2.6.2)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
find_library(HIDAPI_LIBRARY
NAMES hidapi hidapi-libusb)
find_path(HIDAPI_INCLUDE_DIR
NAMES hidapi.h
PATH_SUFFIXES
hidapi)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(HIDAPI
DEFAULT_MSG
HIDAPI_LIBRARY
HIDAPI_INCLUDE_DIR)
if(HIDAPI_FOUND)
set(HIDAPI_LIBRARIES "${HIDAPI_LIBRARY}")
if((STATIC AND UNIX AND NOT APPLE) OR (DEPENDS AND CMAKE_SYSTEM_NAME STREQUAL "Linux"))
find_library(LIBUSB-1.0_LIBRARY usb-1.0)
find_library(LIBUDEV_LIBRARY udev)
if(LIBUSB-1.0_LIBRARY)
set(HIDAPI_LIBRARIES "${HIDAPI_LIBRARIES};${LIBUSB-1.0_LIBRARY}")
if(LIBUDEV_LIBRARY)
set(HIDAPI_LIBRARIES "${HIDAPI_LIBRARIES};${LIBUDEV_LIBRARY}")
else()
message(WARNING "libudev library not found, binaries may fail to link.")
endif()
else()
message(WARNING "libusb-1.0 library not found, binaries may fail to link.")
endif()
endif()
set(HIDAPI_INCLUDE_DIRS "${HIDAPI_INCLUDE_DIR}")
endif()
mark_as_advanced(HIDAPI_INCLUDE_DIR HIDAPI_LIBRARY)

View File

@@ -1,149 +0,0 @@
# - Find libusb for portable USB support
# This module will find libusb as published by
# http://libusb.sf.net and
# http://libusb-win32.sf.net
#
# It will use PkgConfig if present and supported, else search
# it on its own. If the LibUSB_ROOT_DIR environment variable
# is defined, it will be used as base path.
# The following standard variables get defined:
# LibUSB_FOUND: true if LibUSB was found
# LibUSB_HEADER_FILE: the location of the C header file
# LibUSB_INCLUDE_DIRS: the directory that contains the include file
# LibUSB_LIBRARIES: the library
# source: https://github.com/IntelRealSense/librealsense
include ( CheckLibraryExists )
include ( CheckIncludeFile )
find_package ( PkgConfig )
if ( PKG_CONFIG_FOUND )
pkg_check_modules ( PKGCONFIG_LIBUSB libusb-1.0 )
if ( NOT PKGCONFIG_LIBUSB_FOUND )
pkg_check_modules ( PKGCONFIG_LIBUSB libusb )
endif ( NOT PKGCONFIG_LIBUSB_FOUND )
endif ( PKG_CONFIG_FOUND )
if ( PKGCONFIG_LIBUSB_FOUND )
set ( LibUSB_INCLUDE_DIRS ${PKGCONFIG_LIBUSB_INCLUDE_DIRS} )
foreach ( i ${PKGCONFIG_LIBUSB_LIBRARIES} )
string ( REGEX MATCH "[^-]*" ibase "${i}" )
find_library ( ${ibase}_LIBRARY
NAMES ${i}
PATHS ${PKGCONFIG_LIBUSB_LIBRARY_DIRS}
)
if ( ${ibase}_LIBRARY )
list ( APPEND LibUSB_LIBRARIES ${${ibase}_LIBRARY} )
endif ( ${ibase}_LIBRARY )
mark_as_advanced ( ${ibase}_LIBRARY )
endforeach ( i )
else ( PKGCONFIG_LIBUSB_FOUND )
find_file ( LibUSB_HEADER_FILE
NAMES
libusb.h usb.h
PATHS
$ENV{ProgramFiles}/LibUSB-Win32
$ENV{LibUSB_ROOT_DIR}
PATH_SUFFIXES
include
libusb-1.0
include/libusb-1.0
)
mark_as_advanced ( LibUSB_HEADER_FILE )
get_filename_component ( LibUSB_INCLUDE_DIRS "${LibUSB_HEADER_FILE}" PATH )
if ( ${CMAKE_SYSTEM_NAME} STREQUAL "Windows" )
# LibUSB-Win32 binary distribution contains several libs.
# Use the lib that got compiled with the same compiler.
if ( MSVC )
if ( WIN32 )
set ( LibUSB_LIBRARY_PATH_SUFFIX lib/msvc )
else ( WIN32 )
set ( LibUSB_LIBRARY_PATH_SUFFIX lib/msvc_x64 )
endif ( WIN32 )
elseif ( BORLAND )
set ( LibUSB_LIBRARY_PATH_SUFFIX lib/bcc )
elseif ( CMAKE_COMPILER_IS_GNUCC )
set ( LibUSB_LIBRARY_PATH_SUFFIX lib/gcc )
endif ( MSVC )
endif ( ${CMAKE_SYSTEM_NAME} STREQUAL "Windows" )
find_library ( usb_LIBRARY
NAMES
usb-1.0 libusb usb
PATHS
$ENV{ProgramFiles}/LibUSB-Win32
$ENV{LibUSB_ROOT_DIR}
PATH_SUFFIXES
${LibUSB_LIBRARY_PATH_SUFFIX}
)
mark_as_advanced ( usb_LIBRARY )
if ( usb_LIBRARY )
set ( LibUSB_LIBRARIES ${usb_LIBRARY} )
endif ( usb_LIBRARY )
endif ( PKGCONFIG_LIBUSB_FOUND )
if ( LibUSB_INCLUDE_DIRS AND LibUSB_LIBRARIES )
set ( LibUSB_FOUND true )
endif ( LibUSB_INCLUDE_DIRS AND LibUSB_LIBRARIES )
if ( LibUSB_FOUND )
set ( CMAKE_REQUIRED_INCLUDES "${LibUSB_INCLUDE_DIRS}" )
check_include_file ( "${LibUSB_HEADER_FILE}" LibUSB_FOUND )
endif ( LibUSB_FOUND )
if ( LibUSB_FOUND )
check_library_exists ( "${LibUSB_LIBRARIES}" usb_open "" LibUSB_FOUND )
check_library_exists ( "${LibUSB_LIBRARIES}" libusb_get_device_list "" LibUSB_VERSION_1.0 )
check_library_exists ( "${LibUSB_LIBRARIES}" libusb_get_port_numbers "" LibUSB_VERSION_1.0.16 )
if((STATIC AND UNIX AND NOT APPLE) OR (DEPENDS AND CMAKE_SYSTEM_NAME STREQUAL "Linux"))
find_library(LIBUDEV_LIBRARY udev)
if(LIBUDEV_LIBRARY)
set(LibUSB_LIBRARIES "${LibUSB_LIBRARIES};${LIBUDEV_LIBRARY}")
else()
message(WARNING "libudev library not found, binaries may fail to link.")
endif()
endif()
# Library 1.0.16+ compilation test.
# The check_library_exists does not work well on Apple with shared libs.
if (APPLE OR LibUSB_VERSION_1.0.16 OR STATIC)
if (APPLE)
if(DEPENDS)
list(APPEND TEST_COMPILE_EXTRA_LIBRARIES "-framework Foundation -framework IOKit")
else()
find_library(COREFOUNDATION CoreFoundation)
find_library(IOKIT IOKit)
list(APPEND TEST_COMPILE_EXTRA_LIBRARIES ${IOKIT})
list(APPEND TEST_COMPILE_EXTRA_LIBRARIES ${COREFOUNDATION})
endif()
endif()
if (WIN32)
list(APPEND TEST_COMPILE_EXTRA_LIBRARIES setupapi)
endif()
list(APPEND TEST_COMPILE_EXTRA_LIBRARIES ${LibUSB_LIBRARIES})
try_compile(LibUSB_COMPILE_TEST_PASSED
${CMAKE_BINARY_DIR}
"${CMAKE_SOURCE_DIR}/cmake/test-libusb-version.c"
CMAKE_FLAGS
"-DINCLUDE_DIRECTORIES=${LibUSB_INCLUDE_DIRS}"
"-DLINK_DIRECTORIES=${LibUSB_LIBRARIES}"
LINK_LIBRARIES ${TEST_COMPILE_EXTRA_LIBRARIES}
OUTPUT_VARIABLE OUTPUT)
unset(TEST_COMPILE_EXTRA_LIBRARIES)
message(STATUS "LibUSB Compilation test: ${LibUSB_COMPILE_TEST_PASSED}")
endif()
endif ( LibUSB_FOUND )
if ( NOT LibUSB_FOUND )
if ( NOT LibUSB_FIND_QUIETLY )
message ( STATUS "LibUSB not found, try setting LibUSB_ROOT_DIR environment variable." )
endif ( NOT LibUSB_FIND_QUIETLY )
if ( LibUSB_FIND_REQUIRED )
message ( FATAL_ERROR "" )
endif ( LibUSB_FIND_REQUIRED )
endif ( NOT LibUSB_FOUND )

View File

@@ -1,38 +0,0 @@
# from http://code.google.com/p/low-cost-vision-2012/source/browse/CMakeModules/FindZBar0.cmake?name=2-helium-1&r=d61f248bd5565b3c086bf4769a04bfd98f7079df
# - Try to find ZBar
# This will define
#
# ZBAR_FOUND -
# ZBAR_LIBRARY_DIR -
# ZBAR_INCLUDE_DIR -
# ZBAR_LIBRARIES -
#
find_package(PkgConfig)
if(PkgConfig_FOUND)
pkg_check_modules(PC_ZBAR QUIET zbar)
if(PC_ZBAR_FOUND)
set(ZBAR_DEFINITIONS ${PC_ZBAR_CFLAGS_OTHER})
find_library(ZBAR_LIBRARIES NAMES zbar HINTS ${PC_ZBAR_LIBDIR} ${PC_ZBAR_LIBRARY_DIRS})
find_path(ZBAR_INCLUDE_DIR Decoder.h HINTS ${PC_ZBAR_INCLUDEDIR} ${PC_ZBAR_INCLUDE_DIRS} PATH_SUFFIXES zbar)
endif()
endif()
if(NOT ZBAR_LIBRARIES AND ANDROID)
find_library(ZBARJNI_LIBRARY NAMES zbarjni)
find_library(ICONV_LIBRARY NAMES iconv)
if(ZBARJNI_LIBRARY AND ICONV_LIBRARY)
set(ZBAR_LIBRARIES ${ZBARJNI_LIBRARY} ${ICONV_LIBRARY})
endif()
endif()
if(NOT ZBAR_INCLUDE_DIR)
find_path(ZBAR_H_PATH zbar.h)
if(ZBAR_H_PATH)
set(ZBAR_INCLUDE_DIR "${ZBAR_H_PATH}/zbar")
endif()
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ZBAR DEFAULT_MSG ZBAR_LIBRARIES ZBAR_INCLUDE_DIR)
message(STATUS "Found zbar libraries ${ZBAR_LIBRARIES}")

View File

@@ -1,19 +1,17 @@
import QtQuick 2.9
import QtQuick.Layouts 1.1
import FontAwesome 1.0
import "../components" as MoneroComponents
RowLayout {
id: advancedOptionsItem
property alias title: title.text
property alias tooltip: title.tooltip
property alias button1: button1
property alias button2: button2
property alias button3: button3
property alias helpTextLarge: helpTextLarge
property alias helpTextSmall: helpTextSmall
RowLayout {
id: titlecolumn
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
@@ -26,22 +24,6 @@ RowLayout {
fontSize: 14
}
MoneroComponents.Label {
id: iconLabel
fontSize: 12
text: FontAwesome.questionCircle
fontFamily: FontAwesome.fontFamily
opacity: 0.3
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: helpText.visible = !helpText.visible
onEntered: parent.opacity = 0.4
onExited: parent.opacity = 0.3
}
}
Rectangle {
id: separator
Layout.fillWidth: true
@@ -78,29 +60,5 @@ RowLayout {
visible: button3.text
}
}
ColumnLayout {
id: helpText
visible: false
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
MoneroComponents.TextPlain {
id: helpTextLarge
visible: helpTextLarge.text
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 13
color: MoneroComponents.Style.defaultFontColor
}
MoneroComponents.TextPlain {
id: helpTextSmall
visible: helpTextSmall.text
Layout.leftMargin: 5
textFormat: Text.RichText
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 12
color: MoneroComponents.Style.defaultFontColor
}
}
}
}

View File

@@ -49,8 +49,14 @@ Item {
property alias fontColor: label.color
property bool iconOnTheLeft: true
signal clicked()
height: 25
width: checkBoxLayout.width
opacity: enabled ? 1 : 0.7
Keys.onEnterPressed: toggle()
Keys.onReturnPressed: Keys.onEnterPressed(event)
Keys.onSpacePressed: Keys.onEnterPressed(event)
function toggle(){
if (checkBox.toggleOnClick) {
@@ -76,7 +82,7 @@ Item {
radius: 3
color: checkBox.enabled ? "transparent" : MoneroComponents.Style.inputBoxBackgroundDisabled
border.color:
if(checkBox.checked){
if (checkBox.activeFocus) {
return MoneroComponents.Style.inputBorderColorActive;
} else {
return MoneroComponents.Style.inputBorderColorInActive;

View File

@@ -52,6 +52,7 @@ Window {
// TODO: implement without hardcoding sizes
width: 480
height: 200
color: MoneroComponents.Style.middlePanelBackgroundColor
// Make window draggable
MouseArea {
@@ -96,7 +97,7 @@ Window {
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
themeTransition: false
color: "black"
color: MoneroComponents.Style.defaultFontColor
}
}

66
components/Dialog.qml Normal file
View File

@@ -0,0 +1,66 @@
// Copyright (c) 2021, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.1
import "." as MoneroComponents
Popup {
id: dialog
default property alias content: mainLayout.children
property alias title: header.text
background: Rectangle {
border.color: MoneroComponents.Style.blackTheme ? Qt.rgba(255, 255, 255, 0.25) : Qt.rgba(0, 0, 0, 0.25)
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "white"
radius: 10
}
closePolicy: Popup.CloseOnEscape
focus: true
padding: 20
x: (appWindow.width - width) / 2
y: (appWindow.height - height) / 2
ColumnLayout {
id: mainLayout
spacing: dialog.padding
Text {
id: header
color: MoneroComponents.Style.defaultFontColor
font.bold: true
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 18
visible: text != ""
}
}
}

View File

@@ -30,30 +30,26 @@ import QtQuick 2.9
import QtQuick.Layouts 1.1
import QtGraphicalEffects 1.0
import FontAwesome 1.0
import "." as MoneroComponents
import "./effects/" as MoneroEffects
Item {
id: inlineButton
height: parent.height
anchors.top: parent.top
anchors.bottom: parent.bottom
property bool small: false
property string shadowPressedColor: "#B32D00"
property string shadowReleasedColor: "#FF4304"
property string pressedColor: "#FF4304"
property string releasedColor: "#FF6C3C"
property string icon: ""
property string textColor: MoneroComponents.Style.inlineButtonTextColor
property int fontSize: small ? 14 : 16
property int rectHeight: small ? 24 : 24
property int rectHMargin: small ? 16 : 22
property alias text: inlineText.text
property alias fontPixelSize: inlineText.font.pixelSize
property alias fontFamily: inlineText.font.family
property alias fontStyleName: inlineText.font.styleName
property bool isFontAwesomeIcon: fontFamily == FontAwesome.fontFamily || fontFamily == FontAwesome.fontFamilySolid
property alias buttonColor: rect.color
property alias buttonHeight: rect.height
height: isFontAwesomeIcon ? 30 : 24
width: isFontAwesomeIcon ? height : inlineText.width + 16
signal clicked()
function doClick() {
@@ -64,20 +60,16 @@ Item {
Rectangle{
id: rect
anchors.fill: parent
color: MoneroComponents.Style.buttonInlineBackgroundColor
height: 24
width: inlineText.text ? (inlineText.width + 16) : inlineButton.icon ? (inlineImage.width + 16) : rect.height
radius: 4
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 4
MoneroComponents.TextPlain {
id: inlineText
font.family: MoneroComponents.Style.fontBold.name
font.bold: true
font.pixelSize: inlineButton.fontSize
font.pixelSize: inlineButton.isFontAwesomeIcon ? 22 : inlineButton.small ? 14 : 16
color: inlineButton.textColor
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
@@ -90,13 +82,6 @@ Item {
}
}
Image {
id: inlineImage
visible: inlineButton.icon !== ""
anchors.centerIn: parent
source: inlineButton.icon
}
MouseArea {
id: buttonArea
cursorShape: rect.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor

View File

@@ -34,6 +34,7 @@ import "../components" as MoneroComponents
Item {
id: item
property alias text: label.text
property alias tooltip: label.tooltip
property alias color: label.color
property int textFormat: Text.PlainText
property string tipText: ""

View File

@@ -37,17 +37,6 @@ import QtQuick.Controls 2.0
Drawer {
id: sideBar
// @TODO: Qt 5.10 introduces `opened` built-in for Drawer
property bool isOpened: false
onClosed: {
isOpened = false;
}
onOpened: {
isOpened = true;
}
width: 240
height: parent.height - (persistentSettings.customDecorations ? 50 : 0)
y: titleBar.height

View File

@@ -29,11 +29,15 @@
import FontAwesome 1.0
import QtQuick 2.9
import QtGraphicalEffects 1.0
import QtQuick.Layouts 1.1
import "../components" as MoneroComponents
Item {
id: item
default property alias content: inlineButtons.children
property alias input: input
property alias text: input.text
@@ -48,13 +52,20 @@ Item {
property int placeholderFontSize: 18
property string placeholderColor: MoneroComponents.Style.defaultFontColor
property real placeholderOpacity: 0.35
property real placeholderLeftMargin: {
if (placeholderCenter) {
return undefined;
} else if (inlineIcon.visible) {
return inlineIcon.width + inlineIcon.anchors.leftMargin + inputPadding;
} else {
return inputPadding;
}
}
property alias acceptableInput: input.acceptableInput
property alias validator: input.validator
property alias readOnly : input.readOnly
property alias cursorPosition: input.cursorPosition
property alias inlineButton: inlineButtonId
property alias inlineButtonText: inlineButtonId.text
property alias inlineIcon: inlineIcon.visible
property bool copyButton: false
property alias copyButtonText: copyButtonId.text
@@ -71,6 +82,7 @@ Item {
}
}
property string fontFamily: MoneroComponents.Style.fontRegular.name
property int fontSize: 18
property bool fontBold: false
property alias fontColor: input.color
@@ -86,14 +98,16 @@ Item {
property alias labelHorizontalAlignment: inputLabel.horizontalAlignment
property bool showingHeader: inputLabel.text !== "" || copyButton
property int inputHeight: 42
property int inputPadding: 10
signal labelLinkActivated(); // input label, rich text <a> signal
signal editingFinished();
signal accepted();
signal textUpdated();
height: showingHeader ? (inputLabel.height + inputItem.height + 2) : 42
height: showingHeader ? (inputLabel.height + inputItem.height + 2) : inputHeight
onActiveFocusChanged: activeFocus && input.forceActiveFocus()
onTextUpdated: {
// check to remove placeholder text when there is content
if(item.isEmpty()){
@@ -174,7 +188,7 @@ Item {
id: inputItem
height: inputHeight
anchors.top: showingHeader ? inputLabel.bottom : parent.top
anchors.topMargin: showingHeader ? 12 : 2
anchors.topMargin: showingHeader ? 12 : 0
width: parent.width
clip: true
@@ -184,13 +198,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: placeholderCenter ? parent.horizontalCenter : undefined
anchors.left: placeholderCenter ? undefined : parent.left
anchors.leftMargin: {
if(placeholderCenter){
return undefined;
}
else if(inlineIcon.visible){ return 50; }
else { return 10; }
}
anchors.leftMargin: placeholderLeftMargin
opacity: item.placeholderOpacity
color: item.placeholderColor
@@ -232,13 +240,18 @@ Item {
id: input
anchors.fill: parent
anchors.leftMargin: inlineIcon.visible ? 44 : 0
font.family: item.fontFamily
font.pixelSize: item.fontSize
font.bold: item.fontBold
KeyNavigation.backtab: item.KeyNavigation.backtab
KeyNavigation.tab: item.KeyNavigation.tab
onEditingFinished: item.editingFinished()
onAccepted: item.accepted();
onTextChanged: item.textUpdated()
topPadding: 10
bottomPadding: 10
leftPadding: inputPadding
rightPadding: (inlineButtons.width > 0 ? inlineButtons.width + inlineButtons.spacing : 0) + inputPadding
topPadding: inputPadding
bottomPadding: inputPadding
echoMode: isPasswordHidden() ? TextInput.Password : TextInput.Normal
MoneroComponents.Label {
@@ -260,13 +273,17 @@ Item {
onClicked: passwordToggle()
}
}
}
MoneroComponents.InlineButton {
id: inlineButtonId
visible: item.inlineButtonText ? true : false
anchors.right: parent.right
anchors.rightMargin: 8
RowLayout {
id: inlineButtons
anchors.bottom: parent.bottom
anchors.top: parent.top
anchors.right: parent.right
anchors.topMargin: inputPadding
anchors.bottomMargin: inputPadding
anchors.rightMargin: inputPadding
spacing: 4
}
}
}
}

View File

@@ -36,6 +36,8 @@ ColumnLayout {
Layout.fillWidth: true
default property alias content: inlineButtons.children
property alias text: input.text
property alias labelText: inputLabel.text
property alias labelButtonText: labelButton.text
@@ -65,7 +67,7 @@ ColumnLayout {
}
}
property bool error: false
property alias error: input.error
property string labelFontColor: MoneroComponents.Style.defaultFontColor
property bool labelFontBold: false
@@ -73,6 +75,7 @@ ColumnLayout {
property bool labelButtonVisible: false
property string fontColor: MoneroComponents.Style.defaultFontColor
property string fontFamily: MoneroComponents.Style.fontRegular.name
property bool fontBold: false
property int fontSize: 16
@@ -85,15 +88,12 @@ ColumnLayout {
property alias addressValidation: input.addressValidation
property string backgroundColor: "" // mock
property alias inlineButton: inlineButtonId
property bool inlineButtonVisible: false
property alias inlineButton2: inlineButton2Id
property bool inlineButton2Visible: false
signal labelButtonClicked();
signal inputLabelLinkActivated();
signal editingFinished();
onActiveFocusChanged: activeFocus && input.forceActiveFocus()
spacing: 0
Rectangle {
id: inputLabelRect
@@ -159,20 +159,23 @@ ColumnLayout {
id: input
readOnly: false
addressValidation: false
KeyNavigation.backtab: item.KeyNavigation.backtab
KeyNavigation.priority: KeyNavigation.BeforeItem
KeyNavigation.tab: item.KeyNavigation.tab
Layout.fillWidth: true
leftPadding: item.inputPaddingLeft
rightPadding: item.inputPaddingRight
rightPadding: (inlineButtons.width > 0 ? inlineButtons.width + inlineButtons.spacing : 0) + inputPaddingRight
topPadding: item.inputPaddingTop
bottomPadding: item.inputPaddingBottom
wrapMode: item.wrapMode
font.family: item.fontFamily
fontSize: item.fontSize
fontBold: item.fontBold
fontColor: item.fontColor
mouseSelection: item.mouseSelection
onEditingFinished: item.editingFinished()
error: item.error
MoneroComponents.TextPlain {
id: placeholderLabel
@@ -198,18 +201,12 @@ ColumnLayout {
visible: !item.borderDisabled
}
MoneroComponents.InlineButton {
id: inlineButtonId
visible: (inlineButtonId.text || inlineButtonId.icon) && inlineButtonVisible ? true : false
RowLayout {
id: inlineButtons
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 8
}
MoneroComponents.InlineButton {
id: inlineButton2Id
visible: (inlineButton2Id.text || inlineButton2Id.icon) && inlineButton2Visible ? true : false
anchors.right: parent.right
anchors.rightMargin: inlineButtonVisible ? 48 : 8
anchors.rightMargin: inputPaddingRight
spacing: 4
}
}
}

55
components/MenuBar.qml Normal file
View File

@@ -0,0 +1,55 @@
// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import Qt.labs.platform 1.0 as PlatformLabs
import "." as MoneroComponents
PlatformLabs.MenuBar {
PlatformLabs.Menu {
title: qsTr("File")
PlatformLabs.MenuItem {
enabled: appWindow.viewState === "normal"
text: qsTr("Close Wallet")
onTriggered: appWindow.showWizard()
}
}
PlatformLabs.Menu {
title: qsTr("View")
PlatformLabs.MenuItem {
text: MoneroComponents.Style.blackTheme ? qsTr("Light Theme") : qsTr("Dark Theme")
onTriggered: {
MoneroComponents.Style.blackTheme = !MoneroComponents.Style.blackTheme;
}
}
PlatformLabs.MenuItem {
text: qsTr("Change Language")
onTriggered: appWindow.toggleLanguageView();
}
}
}

208
components/Navbar.qml Normal file
View File

@@ -0,0 +1,208 @@
// Copyright (c) 2014-2021, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.9
import QtQuick.Layouts 1.1
import "." as MoneroComponents
Rectangle {
default property list<MoneroComponents.NavbarItem> items
color: "transparent"
height: grid.height
width: grid.width
GridLayout {
id: grid
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
columnSpacing: 0
property string fontColorActive: MoneroComponents.Style.blackTheme ? "white" : "white"
property string fontColorInActive: MoneroComponents.Style.blackTheme ? "white" : MoneroComponents.Style.dimmedFontColor
property int fontSize: 15
property bool fontBold: true
property var fontFamily: MoneroComponents.Style.fontRegular.name
property string borderColor: MoneroComponents.Style.blackTheme ? "#808080" : "#B9B9B9"
property int textMargin: {
// left-right margins for a given cell
if(appWindow.width < 890){
return 32;
} else {
return 64;
}
}
Rectangle {
// navbar left side border
id: navBarLeft
Layout.preferredWidth: 2
Layout.preferredHeight: 32
color: "transparent"
Rectangle {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: 1
height: parent.height - 2
color: grid.borderColor
}
ColumnLayout {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 1
spacing: 0
Rectangle {
Layout.preferredHeight: 1
Layout.preferredWidth: 1
color: grid.borderColor
}
Rectangle {
Layout.fillHeight: true
width: 1
color: items.length > 0 && items[0].active ? grid.borderColor : "transparent";
}
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.preferredWidth: 1
}
}
}
Repeater {
model: items.length
RowLayout {
spacing: 0
Rectangle {
Layout.preferredWidth: 1
Layout.preferredHeight: 32
color: grid.borderColor
visible: index > 0 && items[index - 1].visible
}
ColumnLayout {
Layout.minimumWidth: 72
Layout.preferredHeight: 32
Layout.fillWidth: true
spacing: 0
visible: items[index].visible
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.fillWidth: true
}
Rectangle {
Layout.minimumHeight: 30
Layout.fillWidth: true
color: items[index].active ? grid.borderColor : "transparent"
implicitHeight: children[0].implicitHeight
implicitWidth: children[0].implicitWidth
MoneroComponents.TextPlain {
anchors.centerIn: parent
font.family: grid.fontFamily
font.pixelSize: grid.fontSize
font.bold: grid.fontBold
leftPadding: grid.textMargin / 2
rightPadding: grid.textMargin / 2
text: items[index].text
color: items[index].active ? grid.fontColorActive : grid.fontColorInActive
themeTransition: false
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: items[index].selected()
}
}
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.fillWidth: true
}
}
}
}
Rectangle {
// navbar right side border
id: navBarRight
Layout.preferredWidth: 2
Layout.preferredHeight: 32
color: "transparent"
rotation: 180
Rectangle {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: 1
height: parent.height - 2
color: grid.borderColor
}
ColumnLayout {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 1
spacing: 0
Rectangle {
Layout.preferredHeight: 1
Layout.preferredWidth: 1
color: grid.borderColor
}
Rectangle {
Layout.fillHeight: true
width: 1
color: items.length > 0 && items[items.length - 1].active ? grid.borderColor : "transparent"
}
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.preferredWidth: 1
}
}
}
}
}

37
components/NavbarItem.qml Normal file
View File

@@ -0,0 +1,37 @@
// Copyright (c) 2021, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.9
QtObject {
property bool active: false
property string text
property bool visible: true
signal selected()
}

View File

@@ -0,0 +1,153 @@
// Copyright (c) 2021, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.1
import "." as MoneroComponents
MoneroComponents.Dialog {
id: root
title: (editMode ? qsTr("Edit remote node") : qsTr("Add remote node")) + translationManager.emptyString
property var callbackOnSuccess: null
property bool editMode: false
property bool success: false
onActiveFocusChanged: activeFocus && remoteNodeAddress.forceActiveFocus()
function add(callbackOnSuccess) {
root.editMode = false;
root.callbackOnSuccess = callbackOnSuccess;
open();
}
function edit(remoteNode, callbackOnSuccess) {
const hostPort = remoteNode.address.match(/^(.*?)(?:\:?(\d*))$/);
if (hostPort) {
remoteNodeAddress.daemonAddrText = hostPort[1];
remoteNodeAddress.daemonPortText = hostPort[2];
}
daemonUsername.text = remoteNode.username;
daemonPassword.text = remoteNode.password;
setTrustedDaemonCheckBox.checked = remoteNode.trusted;
root.callbackOnSuccess = callbackOnSuccess;
root.editMode = true;
open();
}
onClosed: {
if (root.success && callbackOnSuccess) {
callbackOnSuccess({
address: remoteNodeAddress.getAddress(),
username: daemonUsername.text,
password: daemonPassword.text,
trusted: setTrustedDaemonCheckBox.checked,
});
}
remoteNodeAddress.daemonAddrText = "";
remoteNodeAddress.daemonPortText = "";
daemonUsername.text = "";
daemonPassword.text = "";
setTrustedDaemonCheckBox.checked = false;
root.success = false;
}
MoneroComponents.RemoteNodeEdit {
id: remoteNodeAddress
Layout.fillWidth: true
placeholderFontSize: 15
daemonAddrLabelText: qsTr("Address") + translationManager.emptyString
daemonPortLabelText: qsTr("Port") + translationManager.emptyString
}
RowLayout {
Layout.fillWidth: true
spacing: 32
MoneroComponents.LineEdit {
id: daemonUsername
Layout.fillWidth: true
Layout.minimumWidth: 220
labelText: qsTr("Daemon username") + translationManager.emptyString
placeholderText: qsTr("(optional)") + translationManager.emptyString
placeholderFontSize: 15
labelFontSize: 14
fontSize: 15
}
MoneroComponents.LineEdit {
id: daemonPassword
Layout.fillWidth: true
Layout.minimumWidth: 220
labelText: qsTr("Daemon password") + translationManager.emptyString
placeholderText: qsTr("Password") + translationManager.emptyString
password: true
placeholderFontSize: 15
labelFontSize: 14
fontSize: 15
}
}
MoneroComponents.CheckBox {
id: setTrustedDaemonCheckBox
activeFocusOnTab: true
text: qsTr("Mark as Trusted Daemon") + translationManager.emptyString
}
RowLayout {
Layout.alignment: Qt.AlignRight
spacing: parent.spacing
MoneroComponents.StandardButton {
activeFocusOnTab: true
fontBold: false
primary: false
text: qsTr("Cancel") + translationManager.emptyString
onClicked: root.close()
}
MoneroComponents.StandardButton {
activeFocusOnTab: true
fontBold: false
enabled: remoteNodeAddress.getAddress() != ""
text: qsTr("Ok") + translationManager.emptyString
onClicked: {
root.success = true;
root.close();
}
}
}
}

View File

@@ -56,7 +56,6 @@ GridLayout {
property int labelFontSize: 14
property string lineEditBackgroundColor: "transparent"
property string lineEditBorderColor: MoneroComponents.Style.inputBorderColorInActive
property string lineEditFontColor: MoneroComponents.Style.defaultFontColor
property bool lineEditFontBold: false
property int lineEditFontSize: 15
@@ -67,18 +66,19 @@ GridLayout {
signal editingFinished()
signal textChanged()
onActiveFocusChanged: activeFocus && daemonAddr.forceActiveFocus()
function isValid() {
return daemonAddr.text.trim().length > 0 && daemonPort.acceptableInput
}
function getAddress() {
if (!isValid()) {
return "";
}
var addr = daemonAddr.text.trim();
var port = daemonPort.text.trim();
// validation
if(addr === "" || addr.length < 2) return "";
if(!Utils.isNumeric(port)) return "";
return addr + ":" + port;
}
@@ -92,7 +92,6 @@ GridLayout {
placeholderColor: root.placeholderColor
placeholderOpacity: root.placeholderOpacity
labelFontSize: root.labelFontSize
borderColor: lineEditBorderColor
backgroundColor: lineEditBackgroundColor
fontColor: lineEditFontColor
fontBold: lineEditFontBold
@@ -115,7 +114,6 @@ GridLayout {
placeholderColor: root.placeholderColor
placeholderOpacity: root.placeholderOpacity
labelFontSize: root.labelFontSize
borderColor: lineEditBorderColor
backgroundColor: lineEditBackgroundColor
fontColor: lineEditFontColor
fontBold: lineEditFontBold

View File

@@ -0,0 +1,131 @@
// Copyright (c) 2021, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.9
import QtQuick.Layouts 1.1
import FontAwesome 1.0
import "." as MoneroComponents
import "effects/" as MoneroEffects
ColumnLayout {
id: remoteNodeList
spacing: 20
MoneroComponents.CheckBox {
border: false
checkedIcon: FontAwesome.minusCircle
uncheckedIcon: FontAwesome.plusCircle
fontAwesomeIcons: true
fontSize: 16
iconOnTheLeft: true
text: qsTr("Add remote node") + translationManager.emptyString
toggleOnClick: false
onClicked: remoteNodeDialog.add(remoteNodesModel.append)
}
ColumnLayout {
spacing: 0
Repeater {
model: remoteNodesModel
Rectangle {
height: 30
Layout.fillWidth: true
color: itemMouseArea.containsMouse || index === remoteNodesModel.selected ? MoneroComponents.Style.titleBarButtonHoverColor : "transparent"
Rectangle {
color: MoneroComponents.Style.appWindowBorderColor
anchors.right: parent.right
anchors.left: parent.left
anchors.top: parent.top
height: 1
visible: index > 0
MoneroEffects.ColorTransition {
targetObj: parent
blackColor: MoneroComponents.Style._b_appWindowBorderColor
whiteColor: MoneroComponents.Style._w_appWindowBorderColor
}
}
Rectangle {
anchors.fill: parent
anchors.rightMargin: 80
color: "transparent"
MoneroComponents.TextPlain {
color: index === remoteNodesModel.selected ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 6
font.pixelSize: 16
text: address
themeTransition: false
}
MouseArea {
id: itemMouseArea
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
hoverEnabled: true
onClicked: remoteNodesModel.applyRemoteNode(index)
}
}
RowLayout {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 6
height: 30
spacing: 10
MoneroComponents.InlineButton {
buttonColor: "transparent"
fontFamily: FontAwesome.fontFamily
fontPixelSize: 18
text: FontAwesome.edit
onClicked: remoteNodeDialog.edit(remoteNodesModel.get(index), function (remoteNode) {
remoteNodesModel.set(index, remoteNode)
})
}
MoneroComponents.InlineButton {
buttonColor: "transparent"
fontFamily: FontAwesome.fontFamily
text: FontAwesome.times
visible: remoteNodesModel.count > 1
onClicked: remoteNodesModel.removeSelectNextIfNeeded(index)
}
}
}
}
}
}

View File

@@ -68,7 +68,7 @@ Item {
id: buttonRect
anchors.fill: parent
radius: 3
border.width: parent.focus ? 1 : 0
border.width: parent.focus && parent.enabled ? 1 : 0
state: button.enabled ? "active" : "disabled"
Component.onCompleted: state = state
@@ -76,7 +76,7 @@ Item {
states: [
State {
name: "hover"
when: buttonArea.containsMouse || button.focus
when: button.enabled && (buttonArea.containsMouse || button.focus)
PropertyChanges {
target: buttonRect
color: primary

View File

@@ -45,20 +45,11 @@ Rectangle {
radius: 10
border.color: MoneroComponents.Style.blackTheme ? Qt.rgba(255, 255, 255, 0.25) : Qt.rgba(0, 0, 0, 0.25)
border.width: 1
focus: true
Keys.enabled: true
Keys.onEscapePressed: {
root.close()
root.rejected()
}
Keys.onEnterPressed: {
root.close()
root.accepted()
}
Keys.onReturnPressed: {
root.close()
root.accepted()
}
KeyNavigation.tab: doneButton
Clipboard { id: clipboard }
@@ -72,7 +63,6 @@ Rectangle {
function open(txid) {
root.transactionID = txid;
root.visible = true;
root.forceActiveFocus();
}
function close() {
@@ -142,7 +132,7 @@ Rectangle {
fontSize: 16
}
// open folder / done buttons
// view progress / open folder / done buttons
RowLayout {
id: buttons
spacing: 70
@@ -150,19 +140,26 @@ Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 50
MoneroComponents.StandardButton {
id: viewProgressButton
visible: !appWindow.viewOnly
text: qsTr("View progress") + translationManager.emptyString;
width: 200
primary: false
KeyNavigation.tab: doneButton
onClicked: {
doSearchInHistory(root.transactionID);
root.close()
root.rejected()
}
}
MoneroComponents.StandardButton {
id: openFolderButton
visible: appWindow.viewOnly
text: qsTr("Open folder") + translationManager.emptyString;
width: 200
KeyNavigation.tab: doneButton
Keys.enabled: openFolderButton.visible
Keys.onReturnPressed: openFolderButton.onClicked
Keys.onEnterPressed: openFolderButton.onClicked
Keys.onEscapePressed: {
root.close()
root.rejected()
}
onClicked: {
oshelper.openContainingFolder(walletManager.urlToLocalPath(saveTxDialog.fileUrl))
}
@@ -172,15 +169,8 @@ Rectangle {
id: doneButton
text: qsTr("Done") + translationManager.emptyString;
width: 200
focus: true
KeyNavigation.tab: openFolderButton
Keys.enabled: doneButton.visible
Keys.onReturnPressed: doneButton.onClicked
Keys.onEnterPressed: doneButton.onClicked
Keys.onEscapePressed: {
root.close()
root.rejected()
}
focus: root.visible
KeyNavigation.tab: appWindow.viewOnly ? openFolderButton : viewProgressButton
onClicked: {
root.close()
root.accepted()

View File

@@ -12,6 +12,7 @@ Text {
property bool themeTransition: true
property string themeTransitionBlackColor: ""
property string themeTransitionWhiteColor: ""
property alias tooltip: tooltip.text
font.family: MoneroComponents.Style.fontMedium.name
font.bold: false
font.pixelSize: 14
@@ -25,4 +26,10 @@ Text {
blackColor: root.themeTransitionBlackColor !== "" ? root.themeTransitionBlackColor : MoneroComponents.Style._b_defaultFontColor
whiteColor: root.themeTransitionWhiteColor !== "" ? root.themeTransitionWhiteColor : MoneroComponents.Style._w_defaultFontColor
}
MoneroComponents.Tooltip {
id: tooltip
anchors.top: parent.top
anchors.left: parent.right
}
}

View File

@@ -173,7 +173,6 @@ Rectangle {
onExited: parent.color = "transparent"
onClicked: {
MoneroComponents.Style.blackTheme = !MoneroComponents.Style.blackTheme;
persistentSettings.blackTheme = MoneroComponents.Style.blackTheme;
}
}
}

92
components/Tooltip.qml Normal file
View File

@@ -0,0 +1,92 @@
// Copyright (c) 2021, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.1
import FontAwesome 1.0
import "." as MoneroComponents
Rectangle {
property alias text: tooltip.text
color: "transparent"
height: icon.height
width: icon.width
visible: text != ""
Text {
id: icon
color: MoneroComponents.Style.orange
font.family: FontAwesome.fontFamily
font.pixelSize: 10
font.styleName: "Regular"
leftPadding: 5
rightPadding: 5
text: FontAwesome.questionCircle
opacity: mouseArea.containsMouse ? 0.7 : 1
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.WhatsThisCursor
onEntered: popup.open()
onExited: popup.close()
}
}
Popup {
id: popup
background: Rectangle {
border.color: MoneroComponents.Style.buttonInlineBackgroundColor
border.width: 1
color: MoneroComponents.Style.titleBarBackgroundGradientStart
radius: 4
}
closePolicy: Popup.NoAutoClose
padding: 10
x: icon.x + icon.width
y: icon.y - height
RowLayout {
Text {
id: tooltip
Layout.maximumWidth: 350
width: contentWidth > Layout.maximumWidth ? Layout.maximumWidth : contentWidth
color: MoneroComponents.Style.defaultFontColor
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 12
textFormat: Text.RichText
wrapMode: Text.WordWrap
}
}
}
}

View File

@@ -27,7 +27,8 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.9
import QtQuick.Controls 1.4
import QtQuick.Controls 1.4 as QtQuickControls1
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.1
import "../components" as MoneroComponents
@@ -35,47 +36,29 @@ import FontAwesome 1.0
Rectangle {
id: root
property int margins: 25
x: parent.width/2 - root.width/2
y: parent.height/2 - root.height/2
// TODO: implement without hardcoding sizes
width: 580
height: 400
width: 590
height: layout.height + layout.anchors.margins * 2
color: MoneroComponents.Style.blackTheme ? "black" : "white"
visible: false
radius: 10
border.color: MoneroComponents.Style.blackTheme ? Qt.rgba(255, 255, 255, 0.25) : Qt.rgba(0, 0, 0, 0.25)
border.width: 1
focus: true
Keys.enabled: true
Keys.onEscapePressed: {
root.close()
root.clearFields()
root.rejected()
}
Keys.onEnterPressed: {
if (root.state == "default") {
root.close()
root.accepted()
} else if (root.state == "error") {
root.close()
root.clearFields()
root.rejected()
}
}
Keys.onReturnPressed: {
if (root.state == "default") {
root.close()
root.accepted()
} else if (root.state == "error") {
root.close()
root.clearFields()
root.rejected()
}
}
KeyNavigation.tab: confirmButton
property var recipients: []
property var transactionAmount: ""
property var transactionAddress: ""
property var transactionDescription: ""
property var transactionFee: ""
property var transactionPriority: ""
@@ -101,7 +84,7 @@ Rectangle {
PropertyChanges { target: bottomMessage; visible: false }
PropertyChanges { target: buttons; visible: true }
PropertyChanges { target: backButton; visible: true; primary: false }
PropertyChanges { target: confirmButton; visible: true }
PropertyChanges { target: confirmButton; visible: true; focus: true }
}, State {
// error message being displayed, show only back button
name: "error";
@@ -115,7 +98,7 @@ Rectangle {
PropertyChanges { target: bottom; visible: true }
PropertyChanges { target: bottomMessage; visible: false }
PropertyChanges { target: buttons; visible: true }
PropertyChanges { target: backButton; visible: true; primary: true }
PropertyChanges { target: backButton; visible: true; primary: true; focus: true }
PropertyChanges { target: confirmButton; visible: false }
}, State {
// creating or sending transaction, show tx details and don't show any button
@@ -141,7 +124,6 @@ Rectangle {
//clean previous error message
errorText.text = "";
root.forceActiveFocus()
}
function close() {
@@ -149,8 +131,8 @@ Rectangle {
}
function clearFields() {
root.recipients = [];
root.transactionAmount = "";
root.transactionAddress = "";
root.transactionDescription = "";
root.transactionFee = "";
root.transactionPriority = "";
@@ -163,9 +145,12 @@ Rectangle {
}
ColumnLayout {
id: layout
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: parent.margins
spacing: 10
anchors.fill: parent
anchors.margins: 25
RowLayout {
Layout.topMargin: 10
@@ -203,11 +188,11 @@ Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 71
BusyIndicator {
id: txAmountBusyIndicator
Layout.fillWidth: true
Layout.alignment : Qt.AlignTop | Qt.AlignLeft
running: root.transactionAmount == "(all)"
QtQuickControls1.BusyIndicator {
id: txAmountBusyIndicator
Layout.fillHeight: true
Layout.fillWidth: true
running: root.transactionAmount == "(all)"
}
Text {
@@ -242,16 +227,10 @@ Rectangle {
columnSpacing: 15
rowSpacing: 16
ColumnLayout {
Layout.fillWidth: true
Layout.alignment : Qt.AlignTop | Qt.AlignLeft
Text {
Layout.fillWidth: true
color: MoneroComponents.Style.dimmedFontColor
text: qsTr("From") + ":" + translationManager.emptyString
font.pixelSize: 15
}
Text {
color: MoneroComponents.Style.dimmedFontColor
text: qsTr("From") + ":" + translationManager.emptyString
font.pixelSize: 15
}
ColumnLayout {
@@ -288,57 +267,70 @@ Rectangle {
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.alignment : Qt.AlignTop | Qt.AlignLeft
Text {
Layout.fillWidth: true
font.pixelSize: 15
color: MoneroComponents.Style.dimmedFontColor
text: qsTr("To") + ":" + translationManager.emptyString
}
Text {
font.pixelSize: 15
color: MoneroComponents.Style.dimmedFontColor
text: qsTr("To") + ":" + translationManager.emptyString
}
ColumnLayout {
Flickable {
id: flickable
property int linesInMultipleRecipientsMode: 7
Layout.fillWidth: true
spacing: 16
Layout.preferredHeight: recipients.length > 1
? linesInMultipleRecipientsMode * (recipientsArea.contentHeight / recipientsArea.lineCount)
: recipientsArea.contentHeight
boundsBehavior: isMac ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
clip: true
Text {
Layout.fillWidth: true
font.pixelSize: 15
font.family: MoneroComponents.Style.fontRegular.name
textFormat: Text.RichText
wrapMode: Text.Wrap
TextArea.flickable: TextArea {
id : recipientsArea
color: MoneroComponents.Style.defaultFontColor
font.family: MoneroComponents.Style.fontMonoRegular.name
font.pixelSize: 14
topPadding: 0
bottomPadding: 0
leftPadding: 0
textMargin: 0
readOnly: true
selectByKeyboard: true
selectByMouse: true
selectionColor: MoneroComponents.Style.textSelectionColor
textFormat: TextEdit.RichText
wrapMode: TextEdit.Wrap
text: {
if (root.transactionAddress) {
const addressBookName = currentWallet ? currentWallet.addressBook.getDescription(root.transactionAddress) : null;
var fulladdress = root.transactionAddress;
var spacedaddress = fulladdress.match(/.{1,4}/g);
var spacedaddress = spacedaddress.join(' ');
if (!addressBookName) {
return qsTr("Monero address") + "<br>" + spacedaddress + translationManager.emptyString;
} else {
return FontAwesome.addressBook + " " + addressBookName + "<br>" + spacedaddress;
return recipients.map(function (recipient, index) {
var addressBookName = null;
if (currentWallet) {
addressBookName = currentWallet.addressBook.getDescription(recipient.address);
}
} else {
return "";
}
var title;
if (addressBookName) {
title = FontAwesome.addressBook + " " + addressBookName;
} else {
title = qsTr("Monero address") + translationManager.emptyString;
}
if (recipients.length > 1) {
title = "%1. %2 - %3 XMR".arg(index + 1).arg(title).arg(recipient.amount);
if (persistentSettings.fiatPriceEnabled) {
title += " (%1)".arg(showFiatConversion(recipient.amount));
}
}
const spacedaddress = recipient.address.match(/.{1,4}/g).join(' ');
return title + "<br>" + spacedaddress;
}).join("<br><br>");
}
}
ScrollBar.vertical: ScrollBar {
policy: recipientsArea.contentHeight > flickable.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.alignment : Qt.AlignTop | Qt.AlignLeft
Text {
Layout.fillWidth: true
color: MoneroComponents.Style.dimmedFontColor
text: qsTr("Fee") + ":" + translationManager.emptyString
font.pixelSize: 15
}
Text {
color: MoneroComponents.Style.dimmedFontColor
text: qsTr("Fee") + ":" + translationManager.emptyString
font.pixelSize: 15
}
RowLayout {
@@ -386,7 +378,7 @@ Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 50
BusyIndicator {
QtQuickControls1.BusyIndicator {
visible: !bottomTextAnimation.running
running: !bottomTextAnimation.running
scale: .5
@@ -422,17 +414,8 @@ Rectangle {
id: backButton
text: qsTr("Back") + translationManager.emptyString;
width: 200
focus: false
primary: false
KeyNavigation.tab: confirmButton
Keys.enabled: backButton.visible
Keys.onReturnPressed: backButton.onClicked
Keys.onEnterPressed: backButton.onClicked
Keys.onEscapePressed: {
root.close()
root.clearFields()
root.rejected()
}
onClicked: {
root.close()
root.clearFields()
@@ -445,16 +428,7 @@ Rectangle {
text: qsTr("Confirm") + translationManager.emptyString;
rightIcon: "qrc:///images/rightArrow.png"
width: 200
focus: false
KeyNavigation.tab: backButton
Keys.enabled: confirmButton.visible
Keys.onReturnPressed: confirmButton.onClicked
Keys.onEnterPressed: confirmButton.onClicked
Keys.onEscapePressed: {
root.close()
root.clearFields()
root.rejected()
}
onClicked: {
root.close()
root.accepted()

7
external/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,7 @@
add_library(quirc STATIC
quirc/lib/decode.c
quirc/lib/identify.c
quirc/lib/quirc.c
quirc/lib/version_db.c
)
target_include_directories(quirc PUBLIC quirc/lib)

1
external/quirc vendored Submodule

Submodule external/quirc added at 7e7ab596e4

View File

@@ -403,6 +403,7 @@ Object {
property string inbox : "\uf01c"
property string indent : "\uf03c"
property string industry : "\uf275"
property string infinity : "\uf534"
property string info : "\uf129"
property string infoCircle : "\uf05a"
property string inr : "\uf156"

View File

@@ -105,9 +105,6 @@ Source: "bin\extras\monero-gen-ssl-cert.exe"; DestDir: "{app}"; Flags: ignorever
; Qt Quick 2D Renderer fallback for systems / environments with "low-level graphics" i.e. without 3D support
Source: "bin\start-low-graphics-mode.bat"; DestDir: "{app}"; Flags: ignoreversion
; Use a scale factor of 2 for Qt for high-DPI systems, as long as Qt does not handle some such systems adequately
Source: "bin\start-high-dpi.bat"; DestDir: "{app}"; Flags: ignoreversion
; Mesa, open-source OpenGL implementation; part of "low-level graphics" support
Source: "bin\opengl32sw.dll"; DestDir: "{app}"; Flags: ignoreversion
@@ -170,6 +167,7 @@ Type: files; Name: "{app}\libssp-0.dll"
Type: files; Name: "{app}\libhidapi-0.dll"
Type: files; Name: "{app}\libeay32.dll"
Type: files; Name: "{app}\ssleay32.dll"
Type: files; Name: "{app}\start-high-dpi.bat"
Type: files; Name: "{group}\Utilities\x (Check Blockchain Folder).lnk"

View File

@@ -105,8 +105,8 @@
<p>The Monero software and especially the GUI wallet are "work in progress", and sometimes things go wrong.</p>
<p>Please note that despite any technical problems that you may encounter your Moneroj are almost always safe: You may
not be able to move them or you even may not see how many you currently have, but you most probably won't loose any.
But do remember that the seed needed to re-create the wallet <b>is</b> critical, however: <b>Never loose your
not be able to move them or you even may not see how many you currently have, but you most probably won't lose any.
But do remember that the seed needed to re-create the wallet <b>is</b> critical, however: <b>Never lose your
seed!</b></p>
<p>In the <i>Utilities</i> sub-folder there are several more icons that may help you to solve problems.

View File

@@ -113,5 +113,5 @@ function capitalize(s){
}
function removeTrailingZeros(value) {
return (value + '').replace(/(\.\d*[1-9])0+$/, '$1');
return (value + '').replace(/(\.\d*?)0+$/, '$1').replace(/\.$/, '');
}

View File

@@ -69,10 +69,7 @@ function walletPathExists(accountsDir, directory, filename, isIOS, walletManager
if(!filename || filename === "") return false;
if(!directory || directory === "") return false;
// make sure directory endswith path seperator
// @TODO: use .endswith() after Qt 5.8
var trailing_path_sep = directory[directory.length-1];
if(trailing_path_sep !== "/" && trailing_path_sep !== "\\")
if (!directory.endsWith("/") && !directory.endsWith("\\"))
directory += "/"
if(isIOS)
@@ -158,7 +155,7 @@ function getApproximateBlockchainHeight(_date, _nettype){
if(_nettype == "Testnet"){
// testnet got some huge rollbacks, so the estimation is way off
var approximateTestnetRolledBackBlocks = 303967;
var approximateTestnetRolledBackBlocks = 342100;
if(approxBlockchainHeight > approximateTestnetRolledBackBlocks)
approxBlockchainHeight -= approximateTestnetRolledBackBlocks
}

329
main.qml
View File

@@ -26,6 +26,7 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQml.Models 2.2
import QtQuick 2.9
import QtQuick.Window 2.0
import QtQuick.Controls 1.1
@@ -53,7 +54,10 @@ import "version.js" as Version
ApplicationWindow {
id: appWindow
title: "Monero" + (walletName ? " - " + walletName : "")
title: "Monero" +
(persistentSettings.displayWalletNameInTitleBar && walletName
? " - " + walletName
: "")
minimumWidth: 750
minimumHeight: 450
@@ -69,7 +73,7 @@ ApplicationWindow {
property int restoreHeight:0
property bool daemonSynced: false
property bool walletSynced: false
property int maxWindowHeight: (isAndroid || isIOS)? screenHeight : (screenHeight < 900)? 720 : 800;
property int maxWindowHeight: (isAndroid || isIOS)? screenAvailableHeight : (screenAvailableHeight < 900)? 720 : 800;
property bool daemonRunning: !persistentSettings.useRemoteNode && !disconnected
property int daemonStartStopInProgress: 0
property alias toolTip: toolTip
@@ -88,7 +92,7 @@ ApplicationWindow {
readonly property string localDaemonAddress : "localhost:" + getDefaultDaemonRpcPort(persistentSettings.nettype)
property string currentDaemonAddress;
property int disconnectedEpoch: 0
property int estimatedBlockchainSize: 75 // GB
property int estimatedBlockchainSize: 105 // GB
property alias viewState: rootItem.state
property string prevSplashText;
property bool splashDisplayedBeforeButtonRequest;
@@ -123,8 +127,6 @@ ApplicationWindow {
property var current_address_label: "Primary"
property int current_subaddress_table_index: 0
function altKeyReleased() { ctrlPressed = false; }
function showPageRequest(page) {
middlePanel.state = page
leftPanel.selectItem(page)
@@ -140,12 +142,8 @@ ApplicationWindow {
if(seq === "Ctrl+S") middlePanel.state = "Transfer"
else if(seq === "Ctrl+R") middlePanel.state = "Receive"
else if(seq === "Ctrl+K") middlePanel.state = "TxKey"
else if(seq === "Ctrl+H") middlePanel.state = "History"
else if(seq === "Ctrl+B") middlePanel.state = "AddressBook"
else if(seq === "Ctrl+M") middlePanel.state = "Mining"
else if(seq === "Ctrl+I") middlePanel.state = "Sign"
else if(seq === "Ctrl+G") middlePanel.state = "SharedRingDB"
else if(seq === "Ctrl+E") middlePanel.state = "Settings"
else if(seq === "Ctrl+D") middlePanel.state = "Advanced"
else if(seq === "Ctrl+T") middlePanel.state = "Account"
@@ -165,11 +163,8 @@ ApplicationWindow {
else if(middlePanel.state === "Transfer") middlePanel.state = "AddressBook"
else if(middlePanel.state === "AddressBook") middlePanel.state = "Receive"
else if(middlePanel.state === "Receive") middlePanel.state = "History"
else if(middlePanel.state === "History") middlePanel.state = "Mining"
else if(middlePanel.state === "Mining") middlePanel.state = "TxKey"
else if(middlePanel.state === "TxKey") middlePanel.state = "SharedRingDB"
else if(middlePanel.state === "SharedRingDB") middlePanel.state = "Sign"
else if(middlePanel.state === "Sign") middlePanel.state = "Settings"
else if(middlePanel.state === "History") middlePanel.state = "Advanced"
else if(middlePanel.state === "Advanced") middlePanel.state = "Settings"
} else if(seq === "Ctrl+Shift+Backtab" || seq === "Alt+Shift+Backtab") {
/*
if(middlePanel.state === "Settings") middlePanel.state = "Sign"
@@ -181,11 +176,8 @@ ApplicationWindow {
else if(middlePanel.state === "TxKey") middlePanel.state = "Receive"
else if(middlePanel.state === "Receive") middlePanel.state = "Transfer"
*/
if(middlePanel.state === "Settings") middlePanel.state = "Sign"
else if(middlePanel.state === "Sign") middlePanel.state = "SharedRingDB"
else if(middlePanel.state === "SharedRingDB") middlePanel.state = "TxKey"
else if(middlePanel.state === "TxKey") middlePanel.state = "Mining"
else if(middlePanel.state === "Mining") middlePanel.state = "History"
if(middlePanel.state === "Settings") middlePanel.state = "Advanced"
else if(middlePanel.state === "Advanced") middlePanel.state = "History"
else if(middlePanel.state === "History") middlePanel.state = "Receive"
else if(middlePanel.state === "Receive") middlePanel.state = "AddressBook"
else if(middlePanel.state === "AddressBook") middlePanel.state = "Transfer"
@@ -371,13 +363,13 @@ ApplicationWindow {
console.log("Recovering from seed: ", persistentSettings.is_recovering)
console.log("restore Height", persistentSettings.restore_height)
// Use saved daemon rpc login settings
currentWallet.setDaemonLogin(persistentSettings.daemonUsername, persistentSettings.daemonPassword)
if(persistentSettings.useRemoteNode)
currentDaemonAddress = persistentSettings.remoteNodeAddress
else
currentDaemonAddress = localDaemonAddress
if (persistentSettings.useRemoteNode) {
const remoteNode = remoteNodesModel.currentRemoteNode();
currentDaemonAddress = remoteNode.address;
currentWallet.setDaemonLogin(remoteNode.username, remoteNode.password);
} else {
currentDaemonAddress = localDaemonAddress;
}
console.log("initializing with daemon address: ", currentDaemonAddress)
currentWallet.initAsync(
@@ -394,7 +386,7 @@ ApplicationWindow {
}
function isTrustedDaemon() {
return !persistentSettings.useRemoteNode || persistentSettings.is_trusted_daemon;
return !persistentSettings.useRemoteNode || remoteNodesModel.currentRemoteNode().trusted;
}
function usefulName(path) {
@@ -496,7 +488,7 @@ ApplicationWindow {
walletInitialized = true
// check if daemon was already mining and add mining logo if true
middlePanel.miningView.update();
middlePanel.advancedView.miningView.update();
}
}
@@ -540,12 +532,6 @@ ApplicationWindow {
// try to resolve common wallet cache errors automatically
switch (wallet.errorString) {
case "basic_string::_M_replace_aux":
walletManager.clearWalletCache(wallet.path);
walletPassword = passwordDialog.password;
appWindow.initialize();
console.error("Repairing wallet cache with error: ", wallet.errorString);
appWindow.showStatusMessage(qsTr("Repairing incompatible wallet cache. Resyncing wallet."),6);
return;
case "std::bad_alloc":
walletManager.clearWalletCache(wallet.path);
walletPassword = passwordDialog.password;
@@ -623,7 +609,9 @@ ApplicationWindow {
const callback = function() {
persistentSettings.useRemoteNode = true;
currentDaemonAddress = persistentSettings.remoteNodeAddress;
const remoteNode = remoteNodesModel.currentRemoteNode();
currentDaemonAddress = remoteNode.address;
currentWallet.setDaemonLogin(remoteNode.username, remoteNode.password);
currentWallet.initAsync(
currentDaemonAddress,
isTrustedDaemon(),
@@ -649,6 +637,7 @@ ApplicationWindow {
console.log("disconnecting remote node");
persistentSettings.useRemoteNode = false;
currentDaemonAddress = localDaemonAddress
currentWallet.setDaemonLogin("", "");
currentWallet.initAsync(
currentDaemonAddress,
isTrustedDaemon(),
@@ -721,7 +710,7 @@ ApplicationWindow {
const noSync = appWindow.walletMode === 0;
const bootstrapNodeAddress = persistentSettings.walletMode < 2 ? "auto" : persistentSettings.bootstrapNodeAddress
daemonManager.start(flags, persistentSettings.nettype, persistentSettings.blockchainDataDir, bootstrapNodeAddress, noSync);
daemonManager.start(flags, persistentSettings.nettype, persistentSettings.blockchainDataDir, bootstrapNodeAddress, noSync, persistentSettings.pruneBlockchain);
}
function stopDaemon(callback, splash){
@@ -817,7 +806,7 @@ ApplicationWindow {
return false;
}
function onTransactionCreated(pendingTransaction,address,paymentId,mixinCount){
function onTransactionCreated(pendingTransaction, addresses, paymentId, mixinCount) {
console.log("Transaction created");
txConfirmationPopup.bottomText.text = "";
transaction = pendingTransaction;
@@ -849,48 +838,49 @@ ApplicationWindow {
}
}
function getDisplayAmountTotal(recipients) {
const amounts = recipients.map(function (recipient) {
return recipient.amount;
});
const total = walletManager.amountsSumFromStrings(amounts);
return Utils.removeTrailingZeros(walletManager.displayAmount(total));
}
// called on "transfer"
function handlePayment(address, paymentId, amount, mixinCount, priority, description, createFile) {
function handlePayment(recipients, paymentId, mixinCount, priority, description, createFile) {
console.log("Creating transaction: ")
console.log("\taddress: ", address,
console.log("\trecipients: ", recipients,
", payment_id: ", paymentId,
", amount: ", amount,
", mixins: ", mixinCount,
", priority: ", priority,
", description: ", description);
txConfirmationPopup.bottomTextAnimation.running = false
txConfirmationPopup.bottomText.text = qsTr("Creating transaction...") + translationManager.emptyString;
txConfirmationPopup.transactionAddress = address;
txConfirmationPopup.transactionAmount = Utils.removeTrailingZeros(amount);
txConfirmationPopup.transactionPriority = priority;
txConfirmationPopup.transactionDescription = description;
// validate amount;
if (amount !== "(all)") {
var amountxmr = walletManager.amountFromString(amount);
console.log("integer amount: ", amountxmr);
console.log("integer unlocked", currentWallet.unlockedBalance())
if (amountxmr <= 0) {
txConfirmationPopup.errorText.text = qsTr("Amount is wrong: expected number from %1 to %2")
.arg(walletManager.displayAmount(0))
.arg(walletManager.displayAmount(currentWallet.unlockedBalance()))
+ translationManager.emptyString;
return;
} else if (amountxmr > currentWallet.unlockedBalance()) {
txConfirmationPopup.errorText.text = qsTr("Insufficient funds. Unlocked balance: %1")
.arg(walletManager.displayAmount(currentWallet.unlockedBalance()))
+ translationManager.emptyString;
return;
}
const recipientAll = recipients.find(function (recipient) {
return recipient.amount == "(all)";
});
if (recipientAll && recipients.length > 1) {
throw "Sending all requires one destination address";
}
txConfirmationPopup.bottomTextAnimation.running = false;
txConfirmationPopup.bottomText.text = qsTr("Creating transaction...") + translationManager.emptyString;
txConfirmationPopup.recipients = recipients;
txConfirmationPopup.transactionAmount = recipientAll ? "(all)" : getDisplayAmountTotal(recipients);
txConfirmationPopup.transactionPriority = priority;
txConfirmationPopup.transactionDescription = description;
txConfirmationPopup.open();
if (amount === "(all)")
currentWallet.createTransactionAllAsync(address, paymentId, mixinCount, priority);
else
currentWallet.createTransactionAsync(address, paymentId, amountxmr, mixinCount, priority);
if (recipientAll) {
currentWallet.createTransactionAllAsync(recipientAll.address, paymentId, mixinCount, priority);
} else {
const addresses = recipients.map(function (recipient) {
return recipient.address;
});
const amountsxmr = recipients.map(function (recipient) {
return recipient.amount;
});
currentWallet.createTransactionAsync(addresses, paymentId, amountsxmr, mixinCount, priority);
}
}
//Choose where to save transaction
@@ -940,7 +930,7 @@ ApplicationWindow {
// called after user confirms transaction
function handleTransactionConfirmed(fileName) {
// View only wallet - we save the tx
if(viewOnly && saveTxDialog.fileUrl){
if(viewOnly){
// No file specified - abort
if(!saveTxDialog.fileUrl) {
currentWallet.disposeTransaction(transaction)
@@ -952,10 +942,12 @@ ApplicationWindow {
// Store to file
transaction.setFilename(path);
}
appWindow.showProcessingSplash(qsTr("Sending transaction ..."));
currentWallet.commitTransactionAsync(transaction);
}
function onTransactionCommitted(success, transaction, txid) {
hideProcessingSplash();
if (!success) {
console.log("Error committing transaction: " + transaction.errorString);
informationPopup.title = qsTr("Error") + translationManager.emptyString
@@ -983,6 +975,11 @@ ApplicationWindow {
});
}
function doSearchInHistory(searchTerm) {
middlePanel.searchInHistory(searchTerm);
leftPanel.selectItem(middlePanel.state)
}
// called on "getProof"
function handleGetProof(txid, address, message) {
console.log("Getting payment proof: ")
@@ -1070,12 +1067,6 @@ ApplicationWindow {
informationPopup.open()
}
// blocks UI if wallet can't be opened or no connection to the daemon
function enableUI(enable) {
middlePanel.enabled = enable;
leftPanel.enabled = enable;
}
function showProcessingSplash(message) {
console.log("Displaying processing splash")
if (typeof message != 'undefined') {
@@ -1113,19 +1104,22 @@ ApplicationWindow {
middlePanel.addressBookView.clearFields();
middlePanel.transferView.clearFields();
middlePanel.receiveView.clearFields();
middlePanel.historyView.clearFields();
// disable timers
userInActivityTimer.running = false;
});
}
objectName: "appWindow"
visible: true
width: screenWidth > 980 ? 980 : 800
height: screenHeight > maxWindowHeight ? maxWindowHeight : 700
width: screenAvailableWidth > 980
? 980
: Math.min(screenAvailableWidth, 800)
height: screenAvailableHeight > maxWindowHeight
? maxWindowHeight
: Math.min(screenAvailableHeight, 700)
color: MoneroComponents.Style.appWindowBackgroundColor
flags: persistentSettings.customDecorations ? Windows.flagsCustomDecorations : Windows.flags
onWidthChanged: x -= 0
Timer {
id: fiatPriceTimer
@@ -1148,7 +1142,7 @@ ApplicationWindow {
}
var key = currency === "xmreur" ? "XXMRZEUR" : "XXMRZUSD";
var ticker = resp.result[key]["o"];
var ticker = resp.result[key]["c"][0];
return ticker;
} else if(url.startsWith("https://api.coingecko.com/api/v3/")){
var key = currency === "xmreur" ? "eur" : "usd";
@@ -1282,8 +1276,12 @@ ApplicationWindow {
}
Component.onCompleted: {
x = (Screen.width - width) / 2
y = (Screen.height - maxWindowHeight) / 2
if (screenAvailableWidth > width) {
x = (screenAvailableWidth - width) / 2;
}
if (screenAvailableHeight > height) {
y = (screenAvailableHeight - height) / 2;
}
translationManager.setLanguage(persistentSettings.locale.split("_")[0]);
@@ -1332,6 +1330,27 @@ ApplicationWindow {
appWindow.fiatApiRefresh();
appWindow.fiatTimerStart();
}
if (persistentSettings.askDesktopShortcut && !persistentSettings.portable) {
persistentSettings.askDesktopShortcut = false;
if (isTails) {
oshelper.createDesktopEntry();
} else if (isLinux) {
confirmationDialog.title = qsTr("Desktop entry") + translationManager.emptyString;
confirmationDialog.text = qsTr("Would you like to register Monero GUI Desktop entry?") + translationManager.emptyString;
confirmationDialog.icon = StandardIcon.Question;
confirmationDialog.cancelText = qsTr("No") + translationManager.emptyString;
confirmationDialog.okText = qsTr("Yes") + translationManager.emptyString;
confirmationDialog.onAcceptedCallback = function() {
oshelper.createDesktopEntry();
};
confirmationDialog.onRejectedCallback = null;
confirmationDialog.open();
}
}
remoteNodesModel.initialize();
}
MoneroSettings {
@@ -1342,6 +1361,7 @@ ApplicationWindow {
return "";
}
property bool askDesktopShortcut: isLinux
property string language: 'English (US)'
property string language_wallet: 'English'
property string locale: 'en_US'
@@ -1351,36 +1371,49 @@ ApplicationWindow {
property bool miningIgnoreBattery : true
property var nettype: NetworkType.MAINNET
property int restore_height : 0
property bool is_trusted_daemon : false
property bool is_trusted_daemon : false // TODO: drop after v0.17.2.0 release
property bool is_recovering : false
property bool is_recovering_from_device : false
property bool customDecorations : true
property string daemonFlags
property int logLevel: 0
property string logCategories: ""
property string daemonUsername: ""
property string daemonPassword: ""
property string daemonUsername: "" // TODO: drop after v0.17.2.0 release
property string daemonPassword: "" // TODO: drop after v0.17.2.0 release
property bool transferShowAdvanced: false
property bool receiveShowAdvanced: false
property bool historyShowAdvanced: false
property bool historyHumanDates: true
property string blockchainDataDir: ""
property bool useRemoteNode: false
property string remoteNodeAddress: ""
property string remoteNodeAddress: "" // TODO: drop after v0.17.2.0 release
property string remoteNodesSerialized: JSON.stringify({
selected: 0,
nodes: remoteNodeAddress != ""
? [{
address: remoteNodeAddress,
username: daemonUsername,
password: daemonPassword,
trusted: is_trusted_daemon,
}]
: [],
})
property string bootstrapNodeAddress: ""
property bool segregatePreForkOutputs: true
property bool keyReuseMitigation2: true
property int segregationHeight: 0
property int kdfRounds: 1
property bool displayWalletNameInTitleBar: true
property bool hideBalance: false
property bool askPasswordBeforeSending: true
property bool lockOnUserInActivity: true
property int walletMode: 2
property int lockOnUserInActivityInterval: 10 // minutes
property bool blackTheme: true
property bool blackTheme: MoneroComponents.Style.blackTheme
property bool checkForUpdates: true
property bool autosave: true
property int autosaveMinutes: 10
property bool pruneBlockchain: false
property bool fiatPriceEnabled: false
property bool fiatPriceToggle: false
@@ -1411,6 +1444,88 @@ ApplicationWindow {
}
}
ListModel {
id: remoteNodesModel
property int selected: 0
signal store()
function initialize() {
try {
const remoteNodes = JSON.parse(persistentSettings.remoteNodesSerialized);
for (var index = 0; index < remoteNodes.nodes.length; ++index) {
const remoteNode = remoteNodes.nodes[index];
remoteNodesModel.append(remoteNode);
}
selected = remoteNodes.selected % remoteNodesModel.count || 0;
} catch (e) {
console.error('failed to parse remoteNodesSerialized', e);
}
store.connect(function() {
var remoteNodes = [];
for (var index = 0; index < remoteNodesModel.count; ++index) {
remoteNodes.push(remoteNodesModel.get(index));
}
persistentSettings.remoteNodesSerialized = JSON.stringify({
selected: selected,
nodes: remoteNodes
});
});
}
function appendIfNotExists(newRemoteNode) {
for (var index = 0; index < remoteNodesModel.count; ++index) {
const remoteNode = remoteNodesModel.get(index);
if (remoteNode.address == newRemoteNode.address &&
remoteNode.username == newRemoteNode.username &&
remoteNode.password == newRemoteNode.password &&
remoteNode.trusted == newRemoteNode.trusted) {
return index;
}
}
remoteNodesModel.append(newRemoteNode);
return remoteNodesModel.count - 1;
}
function applyRemoteNode(index) {
selected = index;
const remoteNode = currentRemoteNode();
persistentSettings.useRemoteNode = true;
if (currentWallet) {
currentWallet.setDaemonLogin(remoteNode.username, remoteNode.password);
currentWallet.setTrustedDaemon(remoteNode.trusted);
appWindow.connectRemoteNode();
}
}
function currentRemoteNode() {
if (selected < remoteNodesModel.count) {
return remoteNodesModel.get(selected);
}
return {
address: "",
username: "",
password: "",
trusted: false,
};
}
function removeSelectNextIfNeeded(index) {
remoteNodesModel.remove(index);
if (selected == index) {
applyRemoteNode(selected % remoteNodesModel.count || 0);
} else if (selected > index) {
selected = selected - 1;
}
}
onCountChanged: store()
onDataChanged: store()
onSelectedChanged: store()
}
// Information dialog
StandardDialog {
// dynamically change onclose handler
@@ -1491,6 +1606,10 @@ ApplicationWindow {
y: (parent.height - height) / 2
}
MoneroComponents.RemoteNodeDialog {
id: remoteNodeDialog
}
// Choose blockchain folder
FileDialog {
id: blockchainFileDialog
@@ -1662,18 +1781,6 @@ ApplicationWindow {
updateBalance();
}
onTxkeyClicked: {
middlePanel.state = "TxKey";
middlePanel.flickable.contentY = 0;
updateBalance();
}
onSharedringdbClicked: {
middlePanel.state = "SharedRingDB";
middlePanel.flickable.contentY = 0;
updateBalance();
}
onHistoryClicked: {
middlePanel.state = "History";
middlePanel.flickable.contentY = 0;
@@ -1686,14 +1793,8 @@ ApplicationWindow {
updateBalance();
}
onMiningClicked: {
middlePanel.state = "Mining";
middlePanel.flickable.contentY = 0;
updateBalance();
}
onSignClicked: {
middlePanel.state = "Sign";
onAdvancedClicked: {
middlePanel.state = "Advanced";
middlePanel.flickable.contentY = 0;
updateBalance();
}
@@ -1736,7 +1837,9 @@ ApplicationWindow {
anchors.fill: blurredArea
source: blurredArea
radius: 64
visible: passwordDialog.visible || inputDialog.visible || splash.visible || updateDialog.visible || devicePassphraseDialog.visible || txConfirmationPopup.visible || successfulTxPopup.visible
visible: passwordDialog.visible || inputDialog.visible || splash.visible || updateDialog.visible ||
devicePassphraseDialog.visible || txConfirmationPopup.visible || successfulTxPopup.visible ||
remoteNodeDialog.visible
}
@@ -1789,7 +1892,7 @@ ApplicationWindow {
TitleBar {
id: titleBar
visible: persistentSettings.customDecorations && middlePanel.state !== "Merchant"
walletName: appWindow.walletName
walletName: persistentSettings.displayWalletNameInTitleBar ? appWindow.walletName : ""
anchors.left: parent.left
anchors.right: parent.right
onCloseClicked: appWindow.close();
@@ -1840,7 +1943,7 @@ ApplicationWindow {
}
function toggleLanguageView(){
languageSidebar.isOpened ? languageSidebar.close() : languageSidebar.open();
languageSidebar.visible ? languageSidebar.close() : languageSidebar.open();
resetLanguageFields()
}
@@ -1916,12 +2019,13 @@ ApplicationWindow {
return;
}
const simpleModeFlags = "--enable-dns-blocklist --out-peers 16";
if (appWindow.daemonRunning) {
appWindow.stopDaemon(function() {
appWindow.startDaemon("")
appWindow.startDaemon(simpleModeFlags)
});
} else {
appWindow.startDaemon("");
appWindow.startDaemon(simpleModeFlags);
}
}
@@ -2125,6 +2229,7 @@ ApplicationWindow {
passwordDialog.onRejectedCallback = function() { appWindow.showWizard(); }
if (inputDialogVisible) inputDialog.close()
remoteNodeDialog.close();
passwordDialog.open();
}
@@ -2247,6 +2352,8 @@ ApplicationWindow {
dragMargin: 0
}
MoneroComponents.MenuBar { }
Network {
id: network
proxyAddress: persistentSettings.getProxyAddress()

2
monero

Submodule monero updated: 3942a1cd04...f6e63ef260

View File

@@ -190,7 +190,7 @@ Rectangle {
height: subaddressAccountListRow.subaddressAccountListItemHeight
width: parent ? parent.width : undefined
Layout.fillWidth: true
color: "transparent"
color: itemMouseArea.containsMouse || index === currentAccountIndex ? MoneroComponents.Style.titleBarButtonHoverColor : "transparent"
Rectangle {
color: MoneroComponents.Style.appWindowBorderColor
@@ -226,7 +226,7 @@ Rectangle {
MoneroComponents.Label {
id: nameLabel
color: MoneroComponents.Style.dimmedFontColor
color: index === currentAccountIndex ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
anchors.verticalCenter: parent.verticalCenter
anchors.left: idLabel.right
anchors.leftMargin: 6
@@ -276,11 +276,10 @@ Rectangle {
}
MouseArea {
id: itemMouseArea
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
hoverEnabled: true
onEntered: tableItem2.color = MoneroComponents.Style.titleBarButtonHoverColor
onExited: tableItem2.color = "transparent"
onClicked: {
appWindow.currentWallet.switchSubaddressAccount(index);
if (selectAndSend)
@@ -299,6 +298,8 @@ Rectangle {
MoneroComponents.IconButton {
id: renameButton
image: "qrc:///images/edit.svg"
fontAwesomeFallbackIcon: FontAwesome.edit
fontAwesomeFallbackSize: 22
color: MoneroComponents.Style.defaultFontColor
opacity: 0.5
Layout.preferredWidth: 23
@@ -310,6 +311,8 @@ Rectangle {
MoneroComponents.IconButton {
id: copyButton
image: "qrc:///images/copy.svg"
fontAwesomeFallbackIcon: FontAwesome.clipboard
fontAwesomeFallbackSize: 22
color: MoneroComponents.Style.defaultFontColor
opacity: 0.5
Layout.preferredWidth: 16

View File

@@ -138,7 +138,7 @@ Rectangle {
function doSend() {
console.log("Sending to: ", address +" "+ paymentId);
middlePanel.sendTo(address, paymentId, description);
middlePanel.sendTo(address, paymentId);
leftPanel.selectItem(middlePanel.state)
}
@@ -314,16 +314,16 @@ Rectangle {
}
}
inlineButton.text: FontAwesome.qrcode
inlineButton.fontPixelSize: 22
inlineButton.fontFamily: FontAwesome.fontFamily
inlineButton.textColor: MoneroComponents.Style.defaultFontColor
inlineButton.buttonColor: MoneroComponents.Style.orange
inlineButton.onClicked: {
cameraUi.state = "Capture"
cameraUi.qrcode_decoded.connect(root.updateFromQrCode)
MoneroComponents.InlineButton {
buttonColor: MoneroComponents.Style.orange
fontFamily: FontAwesome.fontFamily
text: FontAwesome.qrcode
visible : appWindow.qrScannerEnabled && !addressLine.text
onClicked: {
cameraUi.state = "Capture"
cameraUi.qrcode_decoded.connect(root.updateFromQrCode)
}
}
inlineButtonVisible : appWindow.qrScannerEnabled && !addressLine.text
}
MoneroComponents.StandardButton {

148
pages/Advanced.qml Normal file
View File

@@ -0,0 +1,148 @@
// Copyright (c) 2021, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.9
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.1
import "../components" as MoneroComponents
import "."
ColumnLayout {
id: root
Layout.fillWidth: true
Layout.preferredHeight: 900
spacing: 0
property int panelHeight: 900
property alias miningView: stateView.miningView
property alias state: stateView.state
MoneroComponents.Navbar {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: height
Layout.bottomMargin: height
MoneroComponents.NavbarItem {
active: state == "Mining"
text: qsTr("Mining") + translationManager.emptyString
onSelected: state = "Mining"
}
MoneroComponents.NavbarItem {
active: state == "Prove"
text: qsTr("Prove/check") + translationManager.emptyString
onSelected: state = "Prove"
}
MoneroComponents.NavbarItem {
active: state == "SharedRingDB"
text: qsTr("Shared RingDB") + translationManager.emptyString
onSelected: state = "SharedRingDB"
}
MoneroComponents.NavbarItem {
active: state == "Sign"
text: qsTr("Sign/verify") + translationManager.emptyString
onSelected: state = "Sign"
}
}
Rectangle{
id: stateView
property Item currentView
property Item previousView
property Mining miningView: Mining { }
property TxKey prooveView: TxKey { }
property SharedRingDB sharedRingDBView: SharedRingDB { }
property Sign signView: Sign { }
Layout.fillWidth: true
Layout.preferredHeight: panelHeight
color: "transparent"
state: "Mining"
onCurrentViewChanged: {
if (previousView) {
if (typeof previousView.onPageClosed === "function") {
previousView.onPageClosed();
}
}
previousView = currentView
if (currentView) {
stackView.replace(currentView)
if (typeof currentView.onPageCompleted === "function") {
currentView.onPageCompleted();
}
}
}
states: [
State {
name: "Mining"
PropertyChanges { target: stateView; currentView: stateView.miningView }
PropertyChanges { target: root; panelHeight: stateView.miningView.miningHeight + 140 }
}, State {
name: "Prove"
PropertyChanges { target: stateView; currentView: stateView.prooveView }
PropertyChanges { target: root; panelHeight: stateView.prooveView.txkeyHeight + 140 }
}, State {
name: "SharedRingDB"
PropertyChanges { target: stateView; currentView: stateView.sharedRingDBView }
PropertyChanges { target: root; panelHeight: stateView.sharedRingDBView.panelHeight + 140 }
}, State {
name: "Sign"
PropertyChanges { target: stateView; currentView: stateView.signView }
PropertyChanges { target: root; panelHeight: stateView.signView.signHeight + 140 }
}
]
StackView {
id: stackView
initialItem: stateView.miningView
anchors.fill: parent
clip: false // otherwise animation will affect left panel
delegate: StackViewDelegate {
pushTransition: StackViewTransition {
PropertyAnimation {
target: enterItem
property: "x"
from: 0 - target.width
to: 0
duration: 300
easing.type: Easing.OutCubic
}
PropertyAnimation {
target: exitItem
property: "x"
from: 0
to: target.width
duration: 300
easing.type: Easing.OutCubic
}
}
}
}
}
}

View File

@@ -588,6 +588,7 @@ Rectangle {
color: "transparent"
Rectangle {
visible: !isFailed && !isPending
anchors.top: parent.top
anchors.topMargin: 24
anchors.horizontalCenter: parent.horizontalCenter
@@ -596,6 +597,19 @@ Rectangle {
radius: 8
color: isout ? "#d85a00" : "#2eb358"
}
MoneroComponents.TextPlain {
visible: isFailed || isPending
anchors.top: parent.top
anchors.topMargin: 24
anchors.horizontalCenter: parent.horizontalCenter
font.family: FontAwesome.fontFamilySolid
font.styleName: isFailed ? "Solid" : ""
font.pixelSize: 15
text: isFailed ? FontAwesome.times : FontAwesome.clockO
color: isFailed ? "#FF0000" : MoneroComponents.Style.defaultFontColor
themeTransition: false
}
}
ColumnLayout {
@@ -633,7 +647,7 @@ Rectangle {
MoneroComponents.TextPlain {
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 15
text: (isout ? qsTr("Sent") : qsTr("Received")) + translationManager.emptyString
text: (isout ? qsTr("Sent") : qsTr("Received")) + (isFailed ? " (" + qsTr("Failed") + ")" : (isPending ? " (" + qsTr("Pending") + ")" : "")) + translationManager.emptyString
color: MoneroComponents.Style.historyHeaderTextColor
anchors.verticalCenter: parent.verticalCenter
themeTransitionBlackColor: MoneroComponents.Style._b_historyHeaderTextColor
@@ -764,14 +778,7 @@ Rectangle {
font.pixelSize: 15
text: {
if (isout) {
if (isFailed) {
return qsTr("Failed") + translationManager.emptyString;
}
if (isPending) {
return qsTr("Waiting confirmation...") + translationManager.emptyString;
}
if (address) {
const addressBookName = currentWallet ? currentWallet.addressBook.getDescription(address) : null;
return (addressBookName ? FontAwesome.addressBook + " " + addressBookName : TxUtils.addressTruncate(address, 8));
}
if (amount != 0) {
@@ -780,8 +787,6 @@ Rectangle {
return qsTr("My wallet") + translationManager.emptyString;
}
} else {
const receivingAddress = currentWallet ? currentWallet.address(subaddrAccount, subaddrIndex) : null;
const receivingAddressLabel = currentWallet ? appWindow.currentWallet.getSubaddressLabel(subaddrAccount, subaddrIndex) : null;
if (receivingAddress) {
if (subaddrIndex == 0) {
return qsTr("Address") + " #0" + " (" + qsTr("Primary address") + ")" + translationManager.emptyString;
@@ -1341,7 +1346,7 @@ Rectangle {
checked: persistentSettings.historyHumanDates
onClicked: {
persistentSettings.historyHumanDates = !persistentSettings.historyHumanDates
root.updateDisplay(root.txOffset, root.txMax, false);
root.updateDisplay(root.txOffset, root.txMax);
}
text: qsTr("Human readable date format") + translationManager.emptyString
}
@@ -1417,6 +1422,12 @@ Rectangle {
txs.push(item);
} else if(item.address !== "" && item.address.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
txs.push(item);
} else if(item.receivingAddress !== "" && item.receivingAddress.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
txs.push(item);
} else if(item.receivingAddressLabel !== "" && item.receivingAddressLabel.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
txs.push(item);
} else if(item.addressBookName !== "" && item.addressBookName.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
txs.push(item);
} else if(typeof item.blockheight !== "undefined" && item.blockheight.toString().startsWith(root.sortSearchString)) {
txs.push(item);
} else if(item.tx_note.toLowerCase().indexOf(root.sortSearchString.toLowerCase()) !== -1) {
@@ -1447,15 +1458,14 @@ Rectangle {
root.updateDisplay(root.txOffset, root.txMax);
}
function updateDisplay(tx_offset, tx_max, auto_collapse) {
if(typeof auto_collapse === 'undefined') auto_collapse = false;
function updateDisplay(tx_offset, tx_max) {
txListViewModel.clear();
// limit results as per tx_max (root.txMax)
var txs = root.txData.slice(tx_offset, tx_offset + tx_max);
// make first result on the first page collapsed by default
if(auto_collapse && root.txPage === 1 && txs.length > 0 && (root.sortSearchString == null || root.sortSearchString === ""))
// collapse tx if there is a single result
if(root.txPage === 1 && txs.length === 1)
root.txDataCollapsed.push(txs[0]['hash']);
// populate listview
@@ -1522,8 +1532,16 @@ Rectangle {
var tx_note = currentWallet.getUserNote(hash);
var address = "";
if(isout) {
var addressBookName = "";
var receivingAddress = "";
var receivingAddressLabel = "";
if (isout) {
address = TxUtils.destinationsToAddress(destinations);
addressBookName = currentWallet ? currentWallet.addressBook.getDescription(address) : null;
} else {
receivingAddress = currentWallet ? currentWallet.address(subaddrAccount, subaddrIndex) : null;
receivingAddressLabel = currentWallet ? appWindow.currentWallet.getSubaddressLabel(subaddrAccount, subaddrIndex) : null;
}
if (isout)
@@ -1541,6 +1559,7 @@ Rectangle {
"hash": hash,
"paymentId": paymentId,
"address": address,
"addressBookName": addressBookName,
"destinations": destinations,
"tx_note": tx_note,
"dateHuman": dateHuman,
@@ -1551,6 +1570,8 @@ Rectangle {
"fee": fee,
"confirmations": confirmations,
"confirmationsRequired": confirmationsRequired,
"receivingAddress": receivingAddress,
"receivingAddressLabel": receivingAddressLabel,
"subaddrAccount": subaddrAccount,
"subaddrIndex": subaddrIndex
});
@@ -1682,16 +1703,6 @@ Rectangle {
+ translationManager.emptyString;
}
function lookupPaymentID(paymentId) {
if (!addressBookModel)
return ""
var idx = addressBookModel.lookupPaymentID(paymentId)
if (idx < 0)
return ""
idx = addressBookModel.index(idx, 0)
return addressBookModel.data(idx, AddressBookModel.AddressBookDescriptionRole)
}
FileDialog {
id: writeCSVFileDialog
title: qsTr("Please choose a folder") + translationManager.emptyString
@@ -1741,10 +1752,22 @@ Rectangle {
root.reset();
root.refresh();
root.initialized = true;
root.updateFilter();
}
function onPageClosed(){
root.initialized = false;
root.reset(true);
root.clearFields();
}
function searchInHistory(searchTerm){
searchInput.text = searchTerm;
sortAndFilter.collapsed = true;
}
function clearFields() {
searchInput.text = "";
root.txDataCollapsed = [];
}
}

View File

@@ -42,7 +42,7 @@ Rectangle {
id: mainLayout
Layout.fillWidth: true
anchors.margins: 20
anchors.topMargin: 40
anchors.topMargin: 0
anchors.left: parent.left
anchors.top: parent.top
anchors.right: parent.right

View File

@@ -107,7 +107,7 @@ Rectangle {
height: subaddressListRow.subaddressListItemHeight
width: parent ? parent.width : undefined
Layout.fillWidth: true
color: "transparent"
color: itemMouseArea.containsMouse || index === appWindow.current_subaddress_table_index ? MoneroComponents.Style.titleBarButtonHoverColor : "transparent"
Rectangle{
anchors.right: parent.right
@@ -143,7 +143,7 @@ Rectangle {
MoneroComponents.Label {
id: nameLabel
color: MoneroComponents.Style.dimmedFontColor
color: index === appWindow.current_subaddress_table_index ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
anchors.verticalCenter: parent.verticalCenter
anchors.left: idLabel.right
anchors.leftMargin: 6
@@ -167,11 +167,10 @@ Rectangle {
}
MouseArea {
id: itemMouseArea
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
hoverEnabled: true
onEntered: tableItem2.color = MoneroComponents.Style.titleBarButtonHoverColor
onExited: tableItem2.color = "transparent"
onClicked: subaddressListView.currentIndex = index;
}
}
@@ -186,6 +185,8 @@ Rectangle {
MoneroComponents.IconButton {
id: renameButton
image: "qrc:///images/edit.svg"
fontAwesomeFallbackIcon: FontAwesome.edit
fontAwesomeFallbackSize: 22
color: MoneroComponents.Style.defaultFontColor
opacity: 0.5
Layout.preferredWidth: 23
@@ -200,6 +201,8 @@ Rectangle {
MoneroComponents.IconButton {
id: copyButton
image: "qrc:///images/copy.svg"
fontAwesomeFallbackIcon: FontAwesome.clipboard
fontAwesomeFallbackSize: 22
color: MoneroComponents.Style.defaultFontColor
opacity: 0.5
Layout.preferredWidth: 16
@@ -299,18 +302,6 @@ Rectangle {
onClicked: qrFileDialog.open()
}
MoneroComponents.StandardButton {
Layout.preferredWidth: 220
small: true
text: FontAwesome.clipboard + " %1".arg(qsTr("Copy to clipboard")) + translationManager.emptyString
label.font.family: FontAwesome.fontFamily
fontSize: 13
onClicked: {
clipboard.setText(TxUtils.makeQRCodeString(appWindow.current_address));
appWindow.showStatusMessage(qsTr("Copied to clipboard") + translationManager.emptyString, 3);
}
}
MoneroComponents.StandardButton {
Layout.preferredWidth: 220
small: true

View File

@@ -81,8 +81,7 @@ Rectangle {
id: mainLayout
Layout.fillWidth: true
anchors.margins: 20
anchors.topMargin: 40
anchors.topMargin: 0
anchors.left: parent.left
anchors.top: parent.top
anchors.right: parent.right

View File

@@ -89,8 +89,7 @@ Rectangle {
id: mainLayout
Layout.fillWidth: true
anchors.margins: 20
anchors.topMargin: 40
anchors.topMargin: 0
anchors.left: parent.left
anchors.top: parent.top
anchors.right: parent.right

View File

@@ -26,6 +26,7 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQml.Models 2.2
import QtQuick 2.9
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
@@ -44,8 +45,7 @@ import "../js/Utils.js" as Utils
Rectangle {
id: root
signal paymentClicked(string address, string paymentId, string amount, int mixinCount,
int priority, string description)
signal paymentClicked(var recipients, string paymentId, int mixinCount, int priority, string description)
signal sweepUnmixableClicked()
color: "transparent"
@@ -61,19 +61,18 @@ Rectangle {
}
// There are sufficient unlocked funds available
if (walletManager.amountFromString(amountLine.text) > appWindow.getUnlockedBalance()) {
if (recipientModel.getAmountTotal() > appWindow.getUnlockedBalance()) {
return qsTr("Amount is more than unlocked balance.") + translationManager.emptyString;
}
if (addressLine.text)
{
if (!recipientModel.hasEmptyAddress()) {
// Address is valid
if (!TxUtils.checkAddress(addressLine.text, appWindow.persistentSettings.nettype)) {
if (recipientModel.hasInvalidAddress()) {
return qsTr("Address is invalid.") + translationManager.emptyString;
}
// Amount is nonzero
if (!amountLine.text || parseFloat(amountLine.text) <= 0) {
if (recipientModel.hasEmptyAmount()) {
return qsTr("Enter an amount.") + translationManager.emptyString;
}
}
@@ -93,12 +92,22 @@ Rectangle {
oaPopup.open()
}
function fillPaymentDetails(address, payment_id, amount, tx_description, recipient_name) {
if (recipientModel.count > 0) {
const last = recipientModel.count - 1;
if (recipientModel.get(recipientModel.count - 1).address == "") {
recipientModel.remove(last);
}
}
recipientModel.newRecipient(address, Utils.removeTrailingZeros(amount || ""));
setPaymentId(payment_id || "");
setDescription((recipient_name ? recipient_name + " " : "") + (tx_description || ""));
}
function updateFromQrCode(address, payment_id, amount, tx_description, recipient_name) {
console.log("updateFromQrCode")
addressLine.text = address
setPaymentId(payment_id);
amountLine.text = amount
setDescription(recipient_name + " " + tx_description);
fillPaymentDetails(address, payment_id, amount, tx_description, recipient_name);
cameraUi.qrcode_decoded.disconnect(updateFromQrCode)
}
@@ -113,10 +122,8 @@ Rectangle {
}
function clearFields() {
addressLine.text = ""
setPaymentId("");
amountLine.text = ""
setDescription("");
recipientModel.clear();
fillPaymentDetails("", "", "", "", "");
priorityDropdown.currentIndex = 0
}
@@ -163,166 +170,499 @@ Rectangle {
}
}
// recipient address input
RowLayout {
id: addressLineRow
Layout.fillWidth: true
ListModel {
id: recipientModel
LineEditMulti {
id: addressLine
spacing: 0
inputPaddingRight: inlineButtonVisible && inlineButton2Visible ? 100 : 60
fontBold: true
labelText: qsTr("Address") + translationManager.emptyString
labelButtonText: qsTr("Resolve") + translationManager.emptyString
placeholderText: {
if(persistentSettings.nettype == NetworkType.MAINNET){
return "4.. / 8.. / OpenAlias";
} else if (persistentSettings.nettype == NetworkType.STAGENET){
return "5.. / 7..";
} else if(persistentSettings.nettype == NetworkType.TESTNET){
return "9.. / B..";
}
}
wrapMode: Text.WrapAnywhere
addressValidation: true
onTextChanged: {
const parsed = walletManager.parse_uri_to_object(text);
if (!parsed.error) {
addressLine.text = parsed.address;
setPaymentId(parsed.payment_id);
amountLine.text = parsed.amount;
setDescription(parsed.tx_description);
}
}
inlineButton.text: FontAwesome.addressBook
inlineButton.buttonHeight: 30
inlineButton.fontPixelSize: 22
inlineButton.fontFamily: FontAwesome.fontFamily
inlineButton.textColor: MoneroComponents.Style.defaultFontColor
inlineButton.onClicked: {
middlePanel.addressBookView.selectAndSend = true;
appWindow.showPageRequest("AddressBook");
}
inlineButtonVisible: true
inlineButton2.text: FontAwesome.qrcode
inlineButton2.buttonHeight: 30
inlineButton2.fontPixelSize: 22
inlineButton2.fontFamily: FontAwesome.fontFamily
inlineButton2.textColor: MoneroComponents.Style.defaultFontColor
inlineButton2.onClicked: {
cameraUi.state = "Capture"
cameraUi.qrcode_decoded.connect(updateFromQrCode)
}
inlineButton2Visible: appWindow.qrScannerEnabled
}
}
readonly property int maxRecipients: 16
StandardButton {
id: resolveButton
width: 80
text: qsTr("Resolve") + translationManager.emptyString
visible: TxUtils.isValidOpenAliasAddress(addressLine.text)
enabled : visible
onClicked: {
var result = walletManager.resolveOpenAlias(addressLine.text)
if (result) {
var parts = result.split("|")
if (parts.length == 2) {
var address_ok = walletManager.addressValid(parts[1], appWindow.persistentSettings.nettype)
if (parts[0] === "true") {
if (address_ok) {
// prepend openalias to description
descriptionLine.text = descriptionLine.text ? addressLine.text + " " + descriptionLine.text : addressLine.text
descriptionCheckbox.checked = true
addressLine.text = parts[1]
}
else
oa_message(qsTr("No valid address found at this OpenAlias address"))
}
else if (parts[0] === "false") {
if (address_ok) {
addressLine.text = parts[1]
oa_message(qsTr("Address found, but the DNSSEC signatures could not be verified, so this address may be spoofed"))
}
else
{
oa_message(qsTr("No valid address found at this OpenAlias address, but the DNSSEC signatures could not be verified, so this may be spoofed"))
}
}
else {
oa_message(qsTr("Internal error"))
}
}
else {
oa_message(qsTr("Internal error"))
}
}
else {
oa_message(qsTr("No address found"))
}
}
}
ListElement {
address: ""
amount: ""
}
GridLayout {
columns: appWindow.walletMode < 2 ? 1 : 2
Layout.fillWidth: true
columnSpacing: 32
function newRecipient(address, amount) {
if (recipientModel.count < maxRecipients) {
recipientModel.append({address: address, amount: amount});
return true;
}
return false;
}
ColumnLayout {
Layout.fillWidth: true
Layout.minimumWidth: 200
function getRecipients() {
var recipients = [];
for (var index = 0; index < recipientModel.count; ++index) {
const recipient = recipientModel.get(index);
recipients.push({
address: recipient.address,
amount: recipient.amount,
});
}
return recipients;
}
// Amount input
LineEdit {
id: amountLine
Layout.fillWidth: true
inlineIcon: true
labelText: "<style type='text/css'>a {text-decoration: none; color: #858585; font-size: 14px;}</style>\
%1 <a href='#'>(%2)</a>".arg(qsTr("Amount")).arg(qsTr("Change account"))
+ translationManager.emptyString
copyButton: !isNaN(amountLine.text) && persistentSettings.fiatPriceEnabled
copyButtonText: "~%1 %2".arg(fiatApiConvertToFiat(amountLine.text)).arg(fiatApiCurrencySymbol())
copyButtonEnabled: false
function getAmountTotal() {
var sum = [];
for (var index = 0; index < recipientModel.count; ++index) {
const amount = recipientModel.get(index).amount;
if (amount == "(all)") {
return appWindow.getUnlockedBalance();
}
sum.push(amount || "0");
}
return walletManager.amountsSumFromStrings(sum);
}
onLabelLinkActivated: {
middlePanel.accountView.selectAndSend = true;
appWindow.showPageRequest("Account")
}
placeholderText: "0.00"
width: 100
fontBold: true
inlineButtonText: qsTr("All") + translationManager.emptyString
inlineButton.onClicked: amountLine.text = "(all)"
onTextChanged: {
amountLine.text = amountLine.text.replace(",", ".");
const match = amountLine.text.match(/^0+(\d.*)/);
if (match) {
const cursorPosition = amountLine.cursorPosition;
amountLine.text = match[1];
amountLine.cursorPosition = Math.max(cursorPosition, 1) - 1;
} else if(amountLine.text.indexOf('.') === 0){
amountLine.text = '0' + amountLine.text;
if (amountLine.text.length > 2) {
amountLine.cursorPosition = 1;
function hasEmptyAmount() {
for (var index = 0; index < recipientModel.count; ++index) {
if (recipientModel.get(index).amount === "") {
return true;
}
}
return false;
}
function hasEmptyAddress() {
for (var index = 0; index < recipientModel.count; ++index) {
if (recipientModel.get(index).address === "") {
return true;
}
}
return false;
}
function hasInvalidAddress() {
for (var index = 0; index < recipientModel.count; ++index) {
if (!TxUtils.checkAddress(recipientModel.get(index).address, appWindow.persistentSettings.nettype)) {
return true;
}
}
return false;
}
}
Item {
Layout.fillWidth: true
implicitHeight: recipientLayout.height
ColumnLayout {
id: recipientLayout
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
readonly property int colSpacing: 10
readonly property int rowSpacing: 10
readonly property int secondRowWidth: 125
readonly property int thirdRowWidth: 50
RowLayout {
Layout.bottomMargin: recipientLayout.rowSpacing / 2
spacing: recipientLayout.colSpacing
RowLayout {
id: addressLabel
spacing: 6
Layout.fillWidth: true
MoneroComponents.TextPlain {
Layout.leftMargin: 10
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 16
color: MoneroComponents.Style.defaultFontColor
text: qsTr("Address") + translationManager.emptyString
}
MoneroComponents.InlineButton {
fontFamily: FontAwesome.fontFamilySolid
fontStyleName: "Solid"
fontPixelSize: 18
text: FontAwesome.desktop
onClicked: {
clearFields();
const codes = oshelper.grabQrCodesFromScreen();
for (var index = 0; index < codes.length; ++index) {
const parsed = walletManager.parse_uri_to_object(codes[index]);
if (!parsed.error) {
fillPaymentDetails(parsed.address, parsed.payment_id, parsed.amount, parsed.tx_description, parsed.recipient_name);
break;
}
}
}
}
amountLine.error = walletManager.amountFromString(amountLine.text) > appWindow.getUnlockedBalance()
}
validator: RegExpValidator {
regExp: /^(\d{1,8})?([\.,]\d{1,12})?$/
}
}
MoneroComponents.InlineButton {
fontFamily: FontAwesome.fontFamilySolid
fontStyleName: "Solid"
text: FontAwesome.qrcode
visible: appWindow.qrScannerEnabled
onClicked: {
cameraUi.state = "Capture"
cameraUi.qrcode_decoded.connect(updateFromQrCode)
}
}
MoneroComponents.InlineButton {
fontFamily: FontAwesome.fontFamily
text: FontAwesome.addressBook
onClicked: {
middlePanel.addressBookView.selectAndSend = true;
appWindow.showPageRequest("AddressBook");
}
}
Item {
Layout.fillWidth: true
}
}
MoneroComponents.TextPlain {
Layout.preferredWidth: recipientLayout.secondRowWidth
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 16
color: MoneroComponents.Style.defaultFontColor
text: qsTr("Amount") + translationManager.emptyString
}
Item {
Layout.preferredWidth: recipientLayout.thirdRowWidth
}
}
Repeater {
id: recipientRepeater
model: recipientModel
ColumnLayout {
spacing: 0
Rectangle {
Layout.fillWidth: true
Layout.rightMargin: recipientLayout.thirdRowWidth
color: MoneroComponents.Style.inputBorderColorInActive
height: 1
visible: index > 0
}
RowLayout {
spacing: 0
MoneroComponents.LineEditMulti {
KeyNavigation.backtab: index > 0 ? recipientRepeater.itemAt(index - 1).children[1].children[2] : sendButton
KeyNavigation.tab: parent.children[2]
Layout.alignment: Qt.AlignVCenter
Layout.topMargin: recipientLayout.rowSpacing / 2
Layout.bottomMargin: recipientLayout.rowSpacing / 2
Layout.fillWidth: true
addressValidation: true
borderDisabled: true
fontColor: error ? MoneroComponents.Style.errorColor : MoneroComponents.Style.defaultFontColor
fontFamily: MoneroComponents.Style.fontMonoRegular.name
fontSize: 14
inputPaddingBottom: 0
inputPaddingTop: 0
inputPaddingRight: 0
placeholderFontFamily: MoneroComponents.Style.fontMonoRegular.name
placeholderFontSize: 14
spacing: 0
wrapMode: Text.WrapAnywhere
placeholderText: {
if(persistentSettings.nettype == NetworkType.MAINNET){
return "4.. / 8.. / OpenAlias";
} else if (persistentSettings.nettype == NetworkType.STAGENET){
return "5.. / 7..";
} else if(persistentSettings.nettype == NetworkType.TESTNET){
return "9.. / B..";
}
}
onTextChanged: {
const parsed = walletManager.parse_uri_to_object(text);
if (!parsed.error) {
fillPaymentDetails(parsed.address, parsed.payment_id, parsed.amount, parsed.tx_description);
}
address = text;
}
text: address
MoneroComponents.InlineButton {
small: true
text: qsTr("Resolve") + translationManager.emptyString
visible: TxUtils.isValidOpenAliasAddress(address)
onClicked: {
var result = walletManager.resolveOpenAlias(address)
if (result) {
var parts = result.split("|")
if (parts.length == 2) {
var address_ok = walletManager.addressValid(parts[1], appWindow.persistentSettings.nettype)
if (parts[0] === "true") {
if (address_ok) {
// prepend openalias to description
descriptionLine.text = descriptionLine.text ? address + " " + descriptionLine.text : address
descriptionCheckbox.checked = true
recipientRepeater.itemAt(index).children[1].children[0].text = parts[1];
}
else
oa_message(qsTr("No valid address found at this OpenAlias address"))
}
else if (parts[0] === "false") {
if (address_ok) {
recipientRepeater.itemAt(index).children[1].children[0].text = parts[1];
oa_message(qsTr("Address found, but the DNSSEC signatures could not be verified, so this address may be spoofed"))
}
else
{
oa_message(qsTr("No valid address found at this OpenAlias address, but the DNSSEC signatures could not be verified, so this may be spoofed"))
}
}
else {
oa_message(qsTr("Internal error"))
}
}
else {
oa_message(qsTr("Internal error"))
}
}
else {
oa_message(qsTr("No address found"))
}
}
}
}
Rectangle {
Layout.fillHeight: true
Layout.leftMargin: recipientLayout.colSpacing / 2 - width
Layout.rightMargin: recipientLayout.colSpacing / 2
color: MoneroComponents.Style.inputBorderColorInActive
width: 1
}
MoneroComponents.LineEdit {
KeyNavigation.backtab: parent.children[0]
KeyNavigation.tab: index + 1 < recipientRepeater.count ? recipientRepeater.itemAt(index + 1).children[1].children[0] : sendButton
Layout.alignment: Qt.AlignVCenter
Layout.topMargin: recipientLayout.rowSpacing / 2
Layout.bottomMargin: recipientLayout.rowSpacing / 2
Layout.rightMargin: recipientLayout.colSpacing / 2
Layout.preferredWidth: 125
borderDisabled: true
fontFamily: MoneroComponents.Style.fontMonoRegular.name
fontSize: 14
inputPadding: 0
placeholderFontFamily: MoneroComponents.Style.fontMonoRegular.name
placeholderFontSize: 14
placeholderLeftMargin: 0
placeholderText: "0.00"
text: amount
onTextChanged: {
text = text.trim().replace(",", ".");
const match = text.match(/^0+(\d.*)/);
if (match) {
const cursorPosition = cursorPosition;
text = match[1];
cursorPosition = Math.max(cursorPosition, 1) - 1;
} else if(text.indexOf('.') === 0){
text = '0' + text;
if (text.length > 2) {
cursorPosition = 1;
}
}
error = walletManager.amountFromString(text) > appWindow.getUnlockedBalance();
amount = text;
}
validator: RegExpValidator {
regExp: /^\s*(\d{1,8})?([\.,]\d{1,12})?\s*$/
}
}
MoneroComponents.TextPlain {
Layout.leftMargin: recipientLayout.colSpacing / 2
Layout.preferredWidth: recipientLayout.thirdRowWidth
font.family: FontAwesome.fontFamilySolid
font.styleName: "Solid"
horizontalAlignment: Text.AlignHCenter
opacity: mouseArea.containsMouse ? 1 : 0.85
text: recipientModel.count == 1 ? FontAwesome.infinity : FontAwesome.times
MouseArea {
id: mouseArea
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
if (recipientModel.count == 1) {
parent.parent.children[2].text = "(all)";
} else {
recipientModel.remove(index);
}
}
}
}
}
}
}
GridLayout {
id: totalLayout
Layout.topMargin: recipientLayout.rowSpacing / 2
Layout.fillWidth: true
columns: 3
columnSpacing: recipientLayout.colSpacing
rowSpacing: 0
RowLayout {
Layout.column: 0
Layout.row: 0
Layout.fillWidth: true
spacing: 0
CheckBox {
border: false
checked: false
enabled: {
if (recipientModel.count > 0 && recipientModel.get(0).amount == "(all)") {
return false;
}
if (recipientModel.count >= recipientModel.maxRecipients) {
return false;
}
return true;
}
fontAwesomeIcons: true
fontSize: descriptionLine.labelFontSize
iconOnTheLeft: true
text: qsTr("Add recipient") + translationManager.emptyString
toggleOnClick: false
uncheckedIcon: FontAwesome.plusCircle
onClicked: {
recipientModel.newRecipient("", "");
}
}
MoneroComponents.TextPlain {
Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 16
text: recipientModel.count > 1 ? qsTr("Total") + translationManager.emptyString : ""
}
}
MoneroComponents.LineEdit {
id: totalValue
Layout.column: 1
Layout.row: 0
Layout.preferredWidth: recipientLayout.secondRowWidth
borderDisabled: true
fontFamily: MoneroComponents.Style.fontMonoRegular.name
fontSize: 14
inputHeight: 30
inputPadding: 0
readOnly: true
text: Utils.removeTrailingZeros(walletManager.displayAmount(recipientModel.getAmountTotal()))
visible: recipientModel.count > 1
}
MoneroComponents.TextPlain {
Layout.column: 2
Layout.row: 0
Layout.preferredWidth: recipientLayout.thirdRowWidth
horizontalAlignment: Text.AlignHCenter
font.family: MoneroComponents.Style.fontRegular.name
text: "XMR"
visible: recipientModel.count > 1
}
MoneroComponents.LineEdit {
Layout.column: 1
Layout.row: recipientModel.count > 1 ? 1 : 0
Layout.preferredWidth: recipientLayout.secondRowWidth
borderDisabled: true
fontFamily: MoneroComponents.Style.fontMonoRegular.name
fontSize: 14
inputHeight: 30
inputPadding: 0
opacity: 0.7
readOnly: true
text: fiatApiConvertToFiat(walletManager.displayAmount(recipientModel.getAmountTotal()))
visible: persistentSettings.fiatPriceEnabled
}
MoneroComponents.TextPlain {
Layout.column: 2
Layout.row: recipientModel.count > 1 ? 1 : 0
Layout.preferredWidth: recipientLayout.thirdRowWidth
font.family: MoneroComponents.Style.fontRegular.name
horizontalAlignment: Text.AlignHCenter
opacity: 0.7
text: fiatApiCurrencySymbol()
visible: persistentSettings.fiatPriceEnabled
}
}
}
Rectangle {
anchors.top: recipientLayout.top
anchors.topMargin: addressLabel.height + recipientLayout.rowSpacing / 2
anchors.bottom: recipientLayout.bottom
anchors.bottomMargin: totalLayout.height + recipientLayout.rowSpacing / 2
anchors.left: recipientLayout.left
anchors.right: recipientLayout.right
anchors.rightMargin: recipientLayout.thirdRowWidth
color: "transparent"
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
radius: 4
}
}
ColumnLayout {
spacing: 0
visible: appWindow.walletMode >= 2
Label {
id: transactionPriority
Layout.topMargin: 0
text: qsTr("Transaction priority") + translationManager.emptyString
fontBold: false
fontSize: 16
}
// Note: workaround for translations in listElements
// ListElement: cannot use script for property value, so
// code like this wont work:
// ListElement { column1: qsTr("LOW") + translationManager.emptyString ; column2: ""; priority: PendingTransaction.Priority_Low }
// For translations to work, the strings need to be listed in
// the file components/StandardDropdown.qml too.
// Priorites after v5
ListModel {
id: priorityModelV5
ListElement { column1: qsTr("Automatic") ; column2: ""; priority: 0}
ListElement { column1: qsTr("Slow (x0.2 fee)") ; column2: ""; priority: 1}
ListElement { column1: qsTr("Normal (x1 fee)") ; column2: ""; priority: 2 }
ListElement { column1: qsTr("Fast (x5 fee)") ; column2: ""; priority: 3 }
ListElement { column1: qsTr("Fastest (x200 fee)") ; column2: ""; priority: 4 }
}
RowLayout {
Layout.topMargin: 5
spacing: 10
StandardDropdown {
Layout.preferredWidth: 200
id: priorityDropdown
currentIndex: 0
dataModel: priorityModelV5
}
MoneroComponents.TextPlain {
id: feeLabel
Layout.alignment: Qt.AlignRight
Layout.topMargin: 12
Layout.alignment: Qt.AlignVCenter
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 14
color: MoneroComponents.Style.defaultFontColor
opacity: 0.7
property bool estimating: false
property var estimatedFee: null
property string estimatedFeeFiat: {
@@ -338,12 +678,21 @@ Rectangle {
if (!sendButton.enabled || !currentWallet) {
return;
}
var addresses = [];
var amounts = [];
for (var index = 0; index < recipientModel.count; ++index) {
const recipient = recipientModel.get(index);
addresses.push(recipient.address);
amounts.push(walletManager.amountFromString(recipient.amount));
}
currentWallet.estimateTransactionFeeAsync(
addressLine.text,
walletManager.amountFromString(amountLine.text),
addresses,
amounts,
priorityModelV5.get(priorityDropdown.currentIndex).priority,
function (amount) {
estimatedFee = Utils.removeTrailingZeros(amount);
if (amount) {
estimatedFee = Utils.removeTrailingZeros(amount);
}
estimating = false;
});
}
@@ -351,56 +700,20 @@ Rectangle {
if (!sendButton.enabled || estimatedFee == null) {
return ""
}
return "%1: ~%2 XMR".arg(qsTr("Fee")).arg(estimatedFee) +
estimatedFeeFiat +
translationManager.emptyString;
return "~%1 XMR%2 %3".arg(estimatedFee)
.arg(estimatedFeeFiat)
.arg(qsTr("fee") + translationManager.emptyString);
}
BusyIndicator {
anchors.right: parent.right
anchors.left: parent.left
running: feeLabel.estimating
height: parent.height
width: height
}
}
}
ColumnLayout {
visible: appWindow.walletMode >= 2
Layout.alignment: Qt.AlignTop
Label {
id: transactionPriority
Layout.topMargin: 0
text: qsTr("Transaction priority") + translationManager.emptyString
fontBold: false
fontSize: 16
}
// Note: workaround for translations in listElements
// ListElement: cannot use script for property value, so
// code like this wont work:
// ListElement { column1: qsTr("LOW") + translationManager.emptyString ; column2: ""; priority: PendingTransaction.Priority_Low }
// For translations to work, the strings need to be listed in
// the file components/StandardDropdown.qml too.
// Priorites after v5
ListModel {
id: priorityModelV5
ListElement { column1: qsTr("Automatic") ; column2: ""; priority: 0}
ListElement { column1: qsTr("Slow (x0.2 fee)") ; column2: ""; priority: 1}
ListElement { column1: qsTr("Normal (x1 fee)") ; column2: ""; priority: 2 }
ListElement { column1: qsTr("Fast (x5 fee)") ; column2: ""; priority: 3 }
ListElement { column1: qsTr("Fastest (x200 fee)") ; column2: ""; priority: 4 }
}
StandardDropdown {
Layout.preferredWidth: 200
id: priorityDropdown
Layout.topMargin: 5
currentIndex: 0
dataModel: priorityModelV5
}
}
}
}
}
MoneroComponents.WarningBox {
text: qsTr("Description field contents match long payment ID format. \
@@ -492,21 +805,21 @@ Rectangle {
rightIconInactive: "qrc:///images/rightArrowInactive.png"
Layout.topMargin: 4
text: qsTr("Send") + translationManager.emptyString
enabled: !sendButtonWarningBox.visible && !warningContent && addressLine.text && !paymentIdWarningBox.visible
enabled: !sendButtonWarningBox.visible && !warningContent && !recipientModel.hasEmptyAddress() && !paymentIdWarningBox.visible
onClicked: {
console.log("Transfer: paymentClicked")
var priority = priorityModelV5.get(priorityDropdown.currentIndex).priority
console.log("priority: " + priority)
console.log("amount: " + amountLine.text)
addressLine.text = addressLine.text.trim()
setPaymentId(paymentIdLine.text.trim());
root.paymentClicked(addressLine.text, paymentIdLine.text, amountLine.text, root.mixin, priority, descriptionLine.text)
root.paymentClicked(recipientModel.getRecipients(), paymentIdLine.text, root.mixin, priority, descriptionLine.text)
}
}
}
function checkInformation(amount, address, nettype) {
return amount.length > 0 && walletManager.amountFromString(amountLine.text) <= appWindow.getUnlockedBalance() && TxUtils.checkAddress(address, nettype)
function checkInformation() {
return !recipientModel.hasEmptyAmount() &&
recipientModel.getAmountTotal() <= appWindow.getUnlockedBalance() &&
!recipientModel.hasInvalidAddress();
}
} // pageRoot
@@ -547,34 +860,32 @@ Rectangle {
console.log("Transfer: import key images clicked")
importKeyImagesDialog.open();
}
helpTextLarge.text: qsTr("Required for view-only wallets to display the real balance") + translationManager.emptyString
helpTextSmall.text: {
tooltip: {
var errorMessage = "";
if (appWindow.viewOnly && !appWindow.isTrustedDaemon()){
errorMessage = "<p class='orange'>" + qsTr("* To import, you must connect to a local node or a trusted remote node") + "</p>";
}
return "<style type='text/css'>p{line-height:20px; margin-top:0px; margin-bottom:0px; color:" + MoneroComponents.Style.defaultFontColor +
var header = qsTr("Required for view-only wallets to display the real balance") + translationManager.emptyString;
return "<style type='text/css'>.header{ font-size: 13px; } p{line-height:20px; margin-top:0px; margin-bottom:0px; " +
";} p.orange{color:#ff9323;}</style>" +
"<div class='header'>" + header + "</div>" +
"<p>" + qsTr("1. Using cold wallet, export the key images into a file") + "</p>" +
"<p>" + qsTr("2. Using view-only wallet, import the key images file") + "</p>" +
errorMessage + translationManager.emptyString
}
helpTextSmall.themeTransition: false
}
AdvancedOptionsItem {
visible: persistentSettings.transferShowAdvanced && appWindow.walletMode >= 2
title: qsTr("Offline transaction signing") + translationManager.emptyString
button1.text: qsTr("Create") + translationManager.emptyString
button1.enabled: appWindow.viewOnly && pageRoot.checkInformation(amountLine.text, addressLine.text, appWindow.persistentSettings.nettype)
button1.enabled: appWindow.viewOnly && pageRoot.checkInformation()
button1.onClicked: {
console.log("Transfer: saveTx Clicked")
var priority = priorityModelV5.get(priorityDropdown.currentIndex).priority
console.log("priority: " + priority)
console.log("amount: " + amountLine.text)
addressLine.text = addressLine.text.trim()
setPaymentId(paymentIdLine.text.trim());
root.paymentClicked(addressLine.text, paymentIdLine.text, amountLine.text, root.mixin, priority, descriptionLine.text)
root.paymentClicked(recipientModel.getRecipients(), paymentIdLine.text, root.mixin, priority, descriptionLine.text)
}
button2.text: qsTr("Sign (offline)") + translationManager.emptyString
button2.enabled: !appWindow.viewOnly
@@ -588,14 +899,15 @@ Rectangle {
console.log("Transfer: submit tx clicked")
submitTxDialog.open();
}
helpTextLarge.text: qsTr("Spend XMR from a cold (offline) wallet") + translationManager.emptyString
helpTextSmall.text: {
tooltip: {
var errorMessage = "";
if (appWindow.viewOnly && !pageRoot.checkInformation(amountLine.text, addressLine.text, appWindow.persistentSettings.nettype)){
if (appWindow.viewOnly && !pageRoot.checkInformation()) {
errorMessage = "<p class='orange'>" + qsTr("* To create a transaction file, please enter address and amount above") + "</p>";
}
return "<style type='text/css'>p{line-height:20px; margin-top:0px; margin-bottom:0px; color:" + MoneroComponents.Style.defaultFontColor +
var header = qsTr("Spend XMR from a cold (offline) wallet") + translationManager.emptyString;
return "<style type='text/css'>.header{ font-size: 13px; } p{line-height:20px; margin-top:0px; margin-bottom:0px; " +
";} p.orange{color:#ff9323;}</style>" +
"<div class='header'>" + header + "</div>" +
"<p>" + qsTr("1. Using view-only wallet, export the outputs into a file") + "</p>" +
"<p>" + qsTr("2. Using cold wallet, import the outputs file and export the key images") + "</p>" +
"<p>" + qsTr("3. Using view-only wallet, import the key images file and create a transaction file") + "</p>" +
@@ -603,7 +915,6 @@ Rectangle {
"<p>" + qsTr("4. Using cold wallet, sign your transaction file") + "</p>" +
"<p>" + qsTr("5. Using view-only wallet, submit your signed transaction") + "</p>" + translationManager.emptyString
}
helpTextSmall.themeTransition: false
}
AdvancedOptionsItem {
@@ -615,7 +926,7 @@ Rectangle {
console.log("Transfer: sweepUnmixableClicked")
root.sweepUnmixableClicked()
}
helpTextLarge.text: qsTr("Create a transaction that spends old unmovable outputs") + translationManager.emptyString
tooltip: qsTr("Create a transaction that spends old unmovable outputs") + translationManager.emptyString
}
}
@@ -792,19 +1103,9 @@ Rectangle {
}
// Popuplate fields from addressbook.
function sendTo(address, paymentId, description, amount){
function sendTo(address, paymentId, description, amount) {
middlePanel.state = 'Transfer';
if(typeof address !== 'undefined')
addressLine.text = address
if(typeof paymentId !== 'undefined')
setPaymentId(paymentId);
if(typeof description !== 'undefined')
setDescription(description);
if(typeof amount !== 'undefined')
amountLine.text = amount;
fillPaymentDetails(address, paymentId, amount, description);
}
}

View File

@@ -46,7 +46,7 @@ Rectangle {
ColumnLayout {
id: mainLayout
anchors.margins: 20
anchors.topMargin: 40
anchors.topMargin: 0
anchors.left: parent.left
anchors.top: parent.top
anchors.right: parent.right

View File

@@ -35,7 +35,7 @@ Item {
function onPageCompleted() {
if (appWindow.currentWallet) {
appWindow.current_address = appWindow.currentWallet.address(appWindow.currentWallet.currentSubaddressAccount, 0)
appWindow.current_address = appWindow.currentWallet.address(appWindow.currentWallet.currentSubaddressAccount, appWindow.current_subaddress_table_index);
}
// prepare tracking
trackingCheckbox.checked = root.enableTracking

View File

@@ -1,423 +0,0 @@
// Copyright (c) 2014-2018, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.9
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.2
import "../../js/Windows.js" as Windows
import "../../js/Utils.js" as Utils
import "../../components" as MoneroComponents
import "../../pages"
import "."
import moneroComponents.Clipboard 1.0
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 96
color: "transparent"
ColumnLayout {
spacing: 0
Layout.preferredHeight: 32
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
GridLayout {
id: grid
Layout.alignment: Qt.AlignHCenter
columnSpacing: 0
property string fontColorActive: MoneroComponents.Style.blackTheme ? "white" : "white"
property string fontColorInActive: MoneroComponents.Style.blackTheme ? "white" : MoneroComponents.Style.dimmedFontColor
property int fontSize: 15
property bool fontBold: true
property var fontFamily: MoneroComponents.Style.fontRegular.name
property string borderColor: MoneroComponents.Style.blackTheme ? "#808080" : "#B9B9B9"
property int textMargin: {
// left-right margins for a given cell
if(appWindow.width < 890){
return 32;
} else {
return 64;
}
}
Rectangle {
// navbar left side border
id: navBarLeft
property bool isActive: settingsStateView.state === "Wallet"
Layout.preferredWidth: 2
Layout.preferredHeight: 32
color: "transparent"
Rectangle {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: 1
height: parent.height - 2
color: grid.borderColor
}
ColumnLayout {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 1
spacing: 0
Rectangle {
Layout.preferredHeight: 1
Layout.preferredWidth: 1
color: grid.borderColor
}
Rectangle {
Layout.fillHeight: true
width: 1
color: navBarLeft.isActive ? grid.borderColor : "transparent"
}
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.preferredWidth: 1
}
}
}
ColumnLayout {
// WALLET
id: navWallet
property bool isActive: settingsStateView.state === "Wallet"
Layout.preferredWidth: navWalletText.width + grid.textMargin
Layout.minimumWidth: 72
Layout.preferredHeight: 32
spacing: 0
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.fillWidth: true
}
Rectangle {
color: parent.isActive ? grid.borderColor : "transparent"
height: 30
Layout.fillWidth: true
MoneroComponents.TextPlain {
id: navWalletText
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
font.family: grid.fontFamily
font.pixelSize: grid.fontSize
font.bold: grid.fontBold
text: qsTr("Wallet") + translationManager.emptyString
color: navWallet.isActive ? grid.fontColorActive : grid.fontColorInActive
themeTransition: false
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: { settingsStateView.state = "Wallet" }
}
}
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.fillWidth: true
}
}
Rectangle{
Layout.preferredWidth: 1
Layout.preferredHeight: 32
color: grid.borderColor
}
ColumnLayout {
// UI
id: navUI
property bool isActive: settingsStateView.state === "UI"
Layout.preferredWidth: navUIText.width + grid.textMargin
Layout.preferredHeight: 32
Layout.minimumWidth: 72
spacing: 0
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.fillWidth: true
}
Rectangle {
color: parent.isActive ? grid.borderColor : "transparent"
height: 30
Layout.fillWidth: true
MoneroComponents.TextPlain {
id: navUIText
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
font.family: grid.fontFamily
font.pixelSize: grid.fontSize
font.bold: grid.fontBold
text: qsTr("Interface") + translationManager.emptyString
color: navUI.isActive ? grid.fontColorActive : grid.fontColorInActive
themeTransition: false
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: { settingsStateView.state = "UI" }
}
}
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.fillWidth: true
}
}
Rectangle{
Layout.preferredWidth: 1
Layout.preferredHeight: 32
color: grid.borderColor
}
ColumnLayout {
// NODE
id: navNode
property bool isActive: settingsStateView.state === "Node"
visible: appWindow.walletMode >= 2
Layout.preferredWidth: navNodeText.width + grid.textMargin
Layout.preferredHeight: 32
Layout.minimumWidth: 72
spacing: 0
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.fillWidth: true
}
Rectangle {
color: parent.isActive ? grid.borderColor : "transparent"
height: 30
Layout.fillWidth: true
MoneroComponents.TextPlain {
id: navNodeText
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
font.family: grid.fontFamily
font.pixelSize: grid.fontSize
font.bold: grid.fontBold
text: qsTr("Node") + translationManager.emptyString
color: navNode.isActive ? grid.fontColorActive : grid.fontColorInActive
themeTransition: false
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: { settingsStateView.state = "Node" }
}
}
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.fillWidth: true
}
}
Rectangle{
visible: appWindow.walletMode >= 2
Layout.preferredWidth: 1
Layout.preferredHeight: 32
color: grid.borderColor
}
ColumnLayout {
// LOG
id: navLog
property bool isActive: settingsStateView.state === "Log"
Layout.preferredWidth: navLogText.width + grid.textMargin
Layout.preferredHeight: 32
Layout.minimumWidth: 72
spacing: 0
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.fillWidth: true
}
Rectangle {
color: parent.isActive ? grid.borderColor : "transparent"
height: 30
Layout.fillWidth: true
MoneroComponents.TextPlain {
id: navLogText
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
font.family: grid.fontFamily
font.pixelSize: grid.fontSize
font.bold: grid.fontBold
text: qsTr("Log") + translationManager.emptyString
color: navLog.isActive ? grid.fontColorActive : grid.fontColorInActive
themeTransition: false
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: { settingsStateView.state = "Log" }
}
}
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.fillWidth: true
}
}
Rectangle{
visible: appWindow.walletMode >= 2
Layout.preferredWidth: 1
Layout.preferredHeight: 32
color: grid.borderColor
}
ColumnLayout {
// INFO
id: navInfo
property bool isActive: settingsStateView.state === "Info"
Layout.preferredWidth: navInfoText.width + grid.textMargin
Layout.preferredHeight: 32
Layout.minimumWidth: 72
spacing: 0
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.fillWidth: true
}
Rectangle {
color: parent.isActive ? grid.borderColor : "transparent"
height: 30
Layout.fillWidth: true
MoneroComponents.TextPlain {
id: navInfoText
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
font.family: grid.fontFamily
font.pixelSize: grid.fontSize
font.bold: grid.fontBold
text: qsTr("Info") + translationManager.emptyString
color: navInfo.isActive ? grid.fontColorActive : grid.fontColorInActive
themeTransition: false
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: { settingsStateView.state = "Info" }
}
}
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.fillWidth: true
}
}
Rectangle {
// navbar right side border
id: navBarRight
property bool isActive: settingsStateView.state === "Info"
Layout.preferredWidth: 2
Layout.preferredHeight: 32
color: "transparent"
rotation: 180
Rectangle {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: 1
height: parent.height - 2
color: grid.borderColor
}
ColumnLayout {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 1
spacing: 0
Rectangle {
Layout.preferredHeight: 1
Layout.preferredWidth: 1
color: grid.borderColor
}
Rectangle {
Layout.fillHeight: true
width: 1
color: navBarRight.isActive ? grid.borderColor : "transparent"
}
Rectangle {
color: grid.borderColor
Layout.preferredHeight: 1
Layout.preferredWidth: 1
}
}
}
Rectangle {
color: "transparent"
Layout.fillWidth: true
}
}
}
}

View File

@@ -48,7 +48,38 @@ ColumnLayout {
property int settingsHeight: 900
property alias settingsStateViewState: settingsStateView.state
Navbar{}
MoneroComponents.Navbar {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: height
Layout.bottomMargin: height
MoneroComponents.NavbarItem {
active: settingsStateView.state == "Wallet"
text: qsTr("Wallet") + translationManager.emptyString
onSelected: settingsStateView.state = "Wallet"
}
MoneroComponents.NavbarItem {
active: settingsStateView.state == "UI"
text: qsTr("Interface") + translationManager.emptyString
onSelected: settingsStateView.state = "UI"
}
MoneroComponents.NavbarItem {
active: settingsStateView.state == "Node"
text: qsTr("Node") + translationManager.emptyString
visible: appWindow.walletMode >= 2
onSelected: settingsStateView.state = "Node"
}
MoneroComponents.NavbarItem {
active: settingsStateView.state == "Log"
text: qsTr("Log") + translationManager.emptyString
onSelected: settingsStateView.state = "Log"
}
MoneroComponents.NavbarItem {
active: settingsStateView.state == "Info"
text: qsTr("Info") + translationManager.emptyString
onSelected: settingsStateView.state = "Info"
}
}
Rectangle{
id: settingsStateView

View File

@@ -66,6 +66,12 @@ Rectangle {
text: qsTr("Check for updates periodically") + translationManager.emptyString
}
MoneroComponents.CheckBox {
checked: persistentSettings.displayWalletNameInTitleBar
onClicked: persistentSettings.displayWalletNameInTitleBar = !persistentSettings.displayWalletNameInTitleBar
text: qsTr("Display wallet name in title bar") + translationManager.emptyString
}
MoneroComponents.CheckBox {
id: hideBalanceCheckBox
checked: persistentSettings.hideBalance
@@ -83,7 +89,6 @@ Rectangle {
toggleOnClick: false
onClicked: {
MoneroComponents.Style.blackTheme = !MoneroComponents.Style.blackTheme;
persistentSettings.blackTheme = MoneroComponents.Style.blackTheme;
}
}

View File

@@ -215,6 +215,7 @@ Rectangle {
Layout.fillWidth: true
property var lastCommands: []
property int currentCommandIndex
enabled: !persistentSettings.useRemoteNode
fontBold: false
placeholderText: qsTr("command + enter (e.g 'help' or 'status')") + translationManager.emptyString
placeholderFontSize: 16

View File

@@ -130,7 +130,7 @@ Rectangle{
topPadding: 0
text: qsTr("The blockchain is downloaded to your computer. Provides higher security and requires more local storage.") + translationManager.emptyString
width: parent.width - (localNodeIcon.width + localNodeIcon.anchors.leftMargin + anchors.leftMargin)
}
}
}
MouseArea {
@@ -248,96 +248,16 @@ Rectangle{
}
}
ColumnLayout {
id: remoteNodeLayout
anchors.margins: 0
spacing: 20
Layout.fillWidth: true
Layout.topMargin: 20
MoneroComponents.WarningBox {
Layout.topMargin: 46
text: qsTr("To find a remote node, type 'Monero remote node' into your favorite search engine. Please ensure the node is run by a trusted third-party.") + translationManager.emptyString
visible: persistentSettings.useRemoteNode
}
MoneroComponents.WarningBox {
Layout.topMargin: 26
Layout.bottomMargin: 6
text: qsTr("To find a remote node, type 'Monero remote node' into your favorite search engine. Please ensure the node is run by a trusted third-party.") + translationManager.emptyString
}
MoneroComponents.RemoteNodeEdit {
id: remoteNodeEdit
Layout.minimumWidth: 100
placeholderFontSize: 15
daemonAddrLabelText: qsTr("Address") + translationManager.emptyString
daemonPortLabelText: qsTr("Port") + translationManager.emptyString
initialAddress: persistentSettings.remoteNodeAddress
onEditingFinished: {
persistentSettings.remoteNodeAddress = remoteNodeEdit.getAddress();
console.log("setting remote node to " + persistentSettings.remoteNodeAddress);
if (persistentSettings.is_trusted_daemon) {
persistentSettings.is_trusted_daemon = !persistentSettings.is_trusted_daemon
currentWallet.setTrustedDaemon(persistentSettings.is_trusted_daemon)
setTrustedDaemonCheckBox.checked = !setTrustedDaemonCheckBox.checked
appWindow.showStatusMessage(qsTr("Remote node updated. Trusted daemon has been reset. Mark again, if desired."), 8);
}
}
}
GridLayout {
columns: 2
columnSpacing: 32
MoneroComponents.LineEdit {
id: daemonUsername
Layout.fillWidth: true
labelText: qsTr("Daemon username") + translationManager.emptyString
text: persistentSettings.daemonUsername
placeholderText: qsTr("(optional)") + translationManager.emptyString
placeholderFontSize: 15
labelFontSize: 14
fontSize: 15
}
MoneroComponents.LineEdit {
id: daemonPassword
Layout.fillWidth: true
labelText: qsTr("Daemon password") + translationManager.emptyString
text: persistentSettings.daemonPassword
placeholderText: qsTr("Password") + translationManager.emptyString
password: true
placeholderFontSize: 15
labelFontSize: 14
fontSize: 15
}
}
MoneroComponents.CheckBox {
id: setTrustedDaemonCheckBox
checked: persistentSettings.is_trusted_daemon
onClicked: {
persistentSettings.is_trusted_daemon = !persistentSettings.is_trusted_daemon
currentWallet.setTrustedDaemon(persistentSettings.is_trusted_daemon)
}
text: qsTr("Mark as Trusted Daemon") + translationManager.emptyString
}
MoneroComponents.StandardButton {
id: btnConnectRemote
enabled: remoteNodeEdit.isValid()
small: true
text: qsTr("Connect") + translationManager.emptyString
onClicked: {
// Update daemon login
persistentSettings.remoteNodeAddress = remoteNodeEdit.getAddress();
persistentSettings.daemonUsername = daemonUsername.text;
persistentSettings.daemonPassword = daemonPassword.text;
persistentSettings.useRemoteNode = true
currentWallet.setDaemonLogin(persistentSettings.daemonUsername, persistentSettings.daemonPassword);
appWindow.connectRemoteNode()
}
}
MoneroComponents.RemoteNodeList {
Layout.fillWidth: true
Layout.topMargin: 26
visible: persistentSettings.useRemoteNode
}
ColumnLayout {
@@ -398,7 +318,7 @@ Rectangle{
placeholderFontSize: 15
text: persistentSettings.daemonFlags
addressValidation: false
error: text.match(/(^|\s)--(data-dir|bootstrap-daemon-address)/)
error: text.match(/(^|\s)--(data-dir|bootstrap-daemon-address|non-interactive)/)
onEditingFinished: {
if (!daemonFlags.error) {
persistentSettings.daemonFlags = daemonFlags.text;
@@ -431,7 +351,7 @@ Rectangle{
}
}
}
}
}
}
}

View File

@@ -3,10 +3,16 @@
<file>main.qml</file>
<file>LeftPanel.qml</file>
<file>MiddlePanel.qml</file>
<file>components/Dialog.qml</file>
<file>components/Label.qml</file>
<file>components/LanguageButton.qml</file>
<file>components/Navbar.qml</file>
<file>components/NavbarItem.qml</file>
<file>components/RemoteNodeDialog.qml</file>
<file>components/RemoteNodeList.qml</file>
<file>components/SettingsListItem.qml</file>
<file>components/Slider.qml</file>
<file>components/Tooltip.qml</file>
<file>components/UpdateDialog.qml</file>
<file>images/whatIsIcon.png</file>
<file>images/whatIsIcon@2x.png</file>
@@ -15,6 +21,7 @@
<file>monero/utils/gpg_keys/fluffypony.asc</file>
<file>monero/utils/gpg_keys/luigi1111.asc</file>
<file>pages/Account.qml</file>
<file>pages/Advanced.qml</file>
<file>pages/Transfer.qml</file>
<file>pages/History.qml</file>
<file>pages/AddressBook.qml</file>
@@ -39,6 +46,7 @@
<file>images/prevMonth.png</file>
<file>images/prevMonth@2x.png</file>
<file>components/TitleBar.qml</file>
<file>components/MenuBar.qml</file>
<file>images/resize.png</file>
<file>images/resize@2x.png</file>
<file>images/resizeHovered.png</file>
@@ -162,7 +170,6 @@
<file>pages/settings/SettingsLog.qml</file>
<file>pages/settings/SettingsLayout.qml</file>
<file>pages/settings/SettingsInfo.qml</file>
<file>pages/settings/Navbar.qml</file>
<file>components/WarningBox.qml</file>
<file>images/miningxmr.png</file>
<file>images/miningxmr@2x.png</file>

View File

@@ -20,7 +20,7 @@ file(GLOB SOURCE_FILES
"libwalletqt/PendingTransaction.cpp"
"libwalletqt/TransactionHistory.cpp"
"libwalletqt/TransactionInfo.cpp"
"libwalletqt/QRCodeImageProvider.cpp" QR
"libwalletqt/QRCodeImageProvider.cpp"
"libwalletqt/AddressBook.cpp"
"libwalletqt/Subaddress.cpp"
"libwalletqt/SubaddressAccount.cpp"
@@ -55,13 +55,6 @@ if(ENABLE_PASS_STRENGTH_METER)
)
endif()
if(WITH_SCANNER)
file(GLOB QR_CODE_FILES
"QR-Code-scanner/*.h"
"QR-Code-scanner/*.cpp"
)
endif()
set(EXECUTABLE_FLAG)
if(MINGW)
set(EXECUTABLE_FLAG WIN32)
@@ -84,7 +77,6 @@ endif()
set(monero_wallet_gui_sources
${SOURCE_FILES}
${PASS_STRENGTH_FILES}
${QR_CODE_FILES}
${RESOURCES}
)
@@ -123,12 +115,9 @@ target_include_directories(monero-wallet-gui PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/model
${CMAKE_CURRENT_SOURCE_DIR}/QR-Code-scanner
${CMAKE_CURRENT_SOURCE_DIR}/zxcvbn-c
${LibUSB_INCLUDE_DIRS}
${HIDAPI_INCLUDE_DIRS}
${X11_INCLUDE_DIR}
${Boost_INCLUDE_DIRS}
${OPENSSL_INCLUDE_DIR}
${ZBAR_INCLUDE_DIR}
)
target_compile_definitions(monero-wallet-gui
@@ -137,50 +126,43 @@ target_compile_definitions(monero-wallet-gui
${Qt5Qml_DEFINITIONS}
)
if(APPLE)
if(NOT ICU_ROOT)
execute_process(COMMAND brew --prefix icu4c OUTPUT_VARIABLE ICU_ROOT OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
find_package(ICU REQUIRED COMPONENTS data i18n uc)
target_link_directories(monero-wallet-gui PRIVATE ${ICU_ROOT}/lib)
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
target_link_libraries(monero-wallet-gui
wallet_merged
${LMDB_LIBRARY}
epee
wallet_api
qrcodegen
${UNBOUND_LIBRARY}
${SODIUM_LIBRARY}
easylogging
blockchain_db
randomx
hardforks
${Boost_LIBRARIES}
${OPENSSL_LIBRARIES}
${CMAKE_DL_LIBS}
${LibUSB_LIBRARIES}
${HIDAPI_LIBRARIES}
${QT5_LIBRARIES}
${EXTRA_LIBRARIES}
${ICU_LIBRARIES}
openpgp
qrdecoder
translations
)
if(DEVICE_TREZOR_READY)
target_link_libraries(monero-wallet-gui ${TREZOR_DEP_LIBS})
endif()
if(X11_FOUND)
target_link_libraries(monero-wallet-gui ${X11_LIBRARIES})
endif()
if(WITH_SCANNER)
if(NOT ANDROID)
target_link_libraries(monero-wallet-gui qrscanner)
if(LINUX AND NOT ANDROID)
target_link_libraries(monero-wallet-gui
${ZBAR_LIBRARIES}
jpeg
v4l2
v4lconvert
rt
)
else()
target_link_libraries(monero-wallet-gui ${ZBAR_LIBRARIES})
endif()
endif()

View File

@@ -1,4 +1,21 @@
file(GLOB_RECURSE SRC_SOURCES *.cpp)
file(GLOB_RECURSE SRC_HEADERS *.h)
add_library(qrdecoder STATIC
Decoder.cpp
)
target_link_libraries(qrdecoder
PUBLIC
Qt5::Gui
PRIVATE
quirc
)
if(WITH_SCANNER)
add_library(qrscanner
QrCodeScanner.cpp
QrScanThread.cpp
)
target_link_libraries(qrscanner
PUBLIC
Qt5::Multimedia
qrdecoder
)
endif()

View File

@@ -0,0 +1,99 @@
// Copyright (c) 2020, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "Decoder.h"
#include <limits>
#include "quirc.h"
QrDecoder::QrDecoder()
: m_qr(quirc_new())
{
if (m_qr == nullptr)
{
throw std::runtime_error("QUIRC: failed to allocate memory");
}
}
QrDecoder::~QrDecoder()
{
quirc_destroy(m_qr);
}
std::vector<std::string> QrDecoder::decode(const QImage &image)
{
if (image.format() == QImage::Format_Grayscale8)
{
return decodeGrayscale8(image);
}
return decodeGrayscale8(image.convertToFormat(QImage::Format_Grayscale8));
}
std::vector<std::string> QrDecoder::decodeGrayscale8(const QImage &image)
{
if (quirc_resize(m_qr, image.width(), image.height()) < 0)
{
throw std::runtime_error("QUIRC: failed to allocate video memory");
}
uint8_t *rawImage = quirc_begin(m_qr, nullptr, nullptr);
if (rawImage == nullptr)
{
throw std::runtime_error("QUIRC: failed to get image buffer");
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
std::copy(image.constBits(), image.constBits() + image.sizeInBytes(), rawImage);
#else
std::copy(image.constBits(), image.constBits() + image.byteCount(), rawImage);
#endif
quirc_end(m_qr);
const int count = quirc_count(m_qr);
if (count < 0)
{
throw std::runtime_error("QUIRC: failed to get the number of recognized QR-codes");
}
std::vector<std::string> result;
result.reserve(static_cast<size_t>(count));
for (int index = 0; index < count; ++index)
{
quirc_code code;
quirc_extract(m_qr, index, &code);
quirc_data data;
const quirc_decode_error_t err = quirc_decode(&code, &data);
if (err == QUIRC_SUCCESS)
{
result.emplace_back(&data.payload[0], &data.payload[data.payload_len]);
}
}
return result;
}

View File

@@ -0,0 +1,49 @@
// Copyright (c) 2020, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QImage>
struct quirc;
class QrDecoder
{
public:
QrDecoder(const QrDecoder &) = delete;
QrDecoder &operator=(const QrDecoder &) = delete;
QrDecoder();
~QrDecoder();
std::vector<std::string> decode(const QImage &image);
private:
std::vector<std::string> decodeGrayscale8(const QImage &image);
private:
quirc *m_qr;
};

View File

@@ -27,7 +27,6 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "QrCodeScanner.h"
#include <WalletManager.h>
#include <QVideoProbe>
#include <QCamera>
@@ -40,7 +39,7 @@ QrCodeScanner::QrCodeScanner(QObject *parent)
m_probe = new QVideoProbe(this);
m_thread = new QrScanThread(this);
m_thread->start();
QObject::connect(m_thread, SIGNAL(decoded(int, QString)), this, SIGNAL(decoded(int, QString)));
QObject::connect(m_thread, SIGNAL(decoded(QString)), this, SIGNAL(decoded(QString)));
QObject::connect(m_thread, SIGNAL(notifyError(const QString &, bool)), this, SIGNAL(notifyError(const QString &, bool)));
connect(m_probe, SIGNAL(videoFrameProbed(QVideoFrame)), this, SLOT(processFrame(QVideoFrame)));
}

View File

@@ -56,8 +56,7 @@ public Q_SLOTS:
Q_SIGNALS:
void enabledChanged();
void decoded(int type, const QString &data);
void decode(int type, const QString &data);
void decoded(const QString &data);
void notifyError(const QString &error, bool warning = false);
protected:

View File

@@ -38,62 +38,15 @@ QrScanThread::QrScanThread(QObject *parent)
: QThread(parent)
,m_running(true)
{
m_scanner.set_handler(*this);
}
void QrScanThread::image_callback(zbar::Image &image)
{
qDebug() << "image_callback : Found Code ! " ;
for(zbar::Image::SymbolIterator sym = image.symbol_begin();
sym != image.symbol_end();
++sym)
if(!sym->get_count()) {
QString data = QString::fromStdString(sym->get_data());
emit decoded(sym->get_type(), data);
}
}
void QrScanThread::processZImage(zbar::Image &image)
{
m_scanner.recycle_image(image);
zbar::Image tmp = image.convert(*(long*)"Y800");
m_scanner.scan(tmp);
image.set_symbols(tmp.get_symbols());
}
bool QrScanThread::zimageFromQImage(const QImage &qimg, zbar::Image &dst)
{
switch( qimg.format() ){
case QImage::Format_RGB32 :
case QImage::Format_ARGB32 :
case QImage::Format_ARGB32_Premultiplied :
break;
default :
emit notifyError(QString("Invalid QImage Format !"));
return false;
}
unsigned int bpl( qimg.bytesPerLine() ), width( bpl / 4), height( qimg.height());
dst.set_size(width, height);
dst.set_format("BGR4");
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
unsigned long datalen = qimg.sizeInBytes();
#else
unsigned long datalen = qimg.byteCount();
#endif
dst.set_data(qimg.bits(), datalen);
if((width * 4 != bpl) || (width * height * 4 > datalen)){
emit notifyError(QString("QImage to Zbar::Image failed !"));
return false;
}
return true;
}
void QrScanThread::processQImage(const QImage &qimg)
{
try {
m_image = QSharedPointer<zbar::Image>(new zbar::Image());
if( ! zimageFromQImage(qimg, *m_image) )
return;
processZImage(*m_image);
for (const std::string &code : m_decoder.decode(qimg))
{
emit decoded(QString::fromStdString(code));
}
}
catch(std::exception &e) {
qDebug() << "ERROR: " << e.what();

View File

@@ -35,9 +35,10 @@
#include <QEvent>
#include <QVideoFrame>
#include <QCamera>
#include <zbar.h>
class QrScanThread : public QThread, public zbar::Image::Handler
#include "Decoder.h"
class QrScanThread : public QThread
{
Q_OBJECT
@@ -47,20 +48,16 @@ public:
virtual void stop();
Q_SIGNALS:
void decoded(int type, const QString &data);
void decoded(const QString &data);
void notifyError(const QString &error, bool warning = false);
protected:
virtual void run();
void processVideoFrame(const QVideoFrame &);
void processQImage(const QImage &);
void processZImage(zbar::Image &image);
virtual void image_callback(zbar::Image &image);
bool zimageFromQImage(const QImage&, zbar::Image &);
private:
zbar::ImageScanner m_scanner;
QSharedPointer<zbar::Image> m_image;
QrDecoder m_decoder;
bool m_running;
QMutex m_mutex;
QWaitCondition m_waitCondition;

View File

@@ -27,6 +27,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "DaemonManager.h"
#include "common/util.h"
#include <QElapsedTimer>
#include <QFile>
#include <QMutexLocker>
@@ -47,24 +48,7 @@ namespace {
static const int DAEMON_START_TIMEOUT_SECONDS = 120;
}
DaemonManager * DaemonManager::m_instance = nullptr;
QStringList DaemonManager::m_clArgs;
DaemonManager *DaemonManager::instance(const QStringList *args/* = nullptr*/)
{
if (!m_instance) {
m_instance = new DaemonManager;
// store command line arguments for later use
if (args != nullptr)
{
m_clArgs = *args;
}
}
return m_instance;
}
bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const QString &dataDir, const QString &bootstrapNodeAddress, bool noSync /* = false*/)
bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const QString &dataDir, const QString &bootstrapNodeAddress, bool noSync /* = false*/, bool pruneBlockchain /* = false*/)
{
if (!QFileInfo(m_monerod).isFile())
{
@@ -85,12 +69,6 @@ bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const
else if (nettype == NetworkType::STAGENET)
arguments << "--stagenet";
foreach (const QString &str, m_clArgs) {
qDebug() << QString(" [%1] ").arg(str);
if (!str.isEmpty())
arguments << str;
}
// Custom startup flags for daemon
foreach (const QString &str, flags.split(" ")) {
qDebug() << QString(" [%1] ").arg(str);
@@ -108,15 +86,18 @@ bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const
arguments << "--bootstrap-daemon-address" << bootstrapNodeAddress;
}
if (pruneBlockchain) {
if (!checkLmdbExists(dataDir)) { // check that DB has not already been created
arguments << "--prune-blockchain";
}
}
if (noSync) {
arguments << "--no-sync";
}
if (!flags.contains("--out-peers", Qt::CaseSensitive) && bootstrapNodeAddress == "auto") {
arguments << "--out-peers" << "16";
}
arguments << "--check-updates" << "disabled";
arguments << "--non-interactive";
// --max-concurrency based on threads available.
int32_t concurrency = qMax(1, QThread::idealThreadCount() / 2);
@@ -349,6 +330,13 @@ QVariantMap DaemonManager::validateDataDir(const QString &dataDir) const
return result;
}
bool DaemonManager::checkLmdbExists(QString datadir) {
if (datadir.isEmpty() || datadir.isNull()) {
datadir = QString::fromStdString(tools::get_default_data_dir());
}
return validateDataDir(datadir).value("lmdbExists").value<bool>();
}
DaemonManager::DaemonManager(QObject *parent)
: QObject(parent)
, m_scheduler(this)

View File

@@ -44,10 +44,10 @@ class DaemonManager : public QObject
Q_OBJECT
public:
explicit DaemonManager(QObject *parent = 0);
~DaemonManager();
static DaemonManager * instance(const QStringList *args = nullptr);
Q_INVOKABLE bool start(const QString &flags, NetworkType::Type nettype, const QString &dataDir = "", const QString &bootstrapNodeAddress = "", bool noSync = false);
Q_INVOKABLE bool start(const QString &flags, NetworkType::Type nettype, const QString &dataDir = "", const QString &bootstrapNodeAddress = "", bool noSync = false, bool pruneBlockchain = false);
Q_INVOKABLE void stopAsync(NetworkType::Type nettype, const QJSValue& callback);
Q_INVOKABLE bool noSync() const noexcept;
@@ -57,6 +57,7 @@ public:
Q_INVOKABLE void sendCommandAsync(const QStringList &cmd, NetworkType::Type nettype, const QJSValue& callback) const;
Q_INVOKABLE void exit();
Q_INVOKABLE QVariantMap validateDataDir(const QString &dataDir) const;
Q_INVOKABLE bool checkLmdbExists(QString datadir);
private:
@@ -76,11 +77,6 @@ public slots:
void stateChanged(QProcess::ProcessState state);
private:
explicit DaemonManager(QObject *parent = 0);
~DaemonManager();
static DaemonManager * m_instance;
static QStringList m_clArgs;
std::unique_ptr<QProcess> m_daemon;
QMutex m_daemonMutex;
QString m_monerod;

View File

@@ -121,13 +121,6 @@ quint64 AddressBook::count() const
return m_rows.size();
}
int AddressBook::lookupPaymentID(const QString &payment_id) const
{
QReadLocker locker(&m_lock);
return m_addressBookImpl->lookupPaymentID(payment_id.toStdString());
}
QString AddressBook::getDescription(const QString &address) const
{
QReadLocker locker(&m_lock);

View File

@@ -51,7 +51,6 @@ public:
quint64 count() const;
Q_INVOKABLE QString errorString() const;
Q_INVOKABLE int errorCode() const;
Q_INVOKABLE int lookupPaymentID(const QString &payment_id) const;
Q_INVOKABLE QString getDescription(const QString &address) const;
enum ErrorCode {

View File

@@ -78,7 +78,14 @@ void Subaddress::setLabel(quint32 accountIndex, quint32 addressIndex, const QStr
void Subaddress::refresh(quint32 accountIndex) const
{
m_subaddressImpl->refresh(accountIndex);
try
{
m_subaddressImpl->refresh(accountIndex);
}
catch (const std::exception &e)
{
qCritical() << "Failed to refresh account" << accountIndex << "subaddresses:" << e.what();
}
getAll();
}

View File

@@ -104,10 +104,7 @@ void Wallet::updateConnectionStatusAsync()
setConnectionStatus(ConnectionStatus_Connecting);
}
ConnectionStatus newStatus = static_cast<ConnectionStatus>(m_walletImpl->connected());
if (newStatus != m_connectionStatus || !m_initialized) {
m_initialized = true;
setConnectionStatus(newStatus);
}
setConnectionStatus(newStatus);
// Release lock
m_connectionStatusRunning = false;
});
@@ -115,8 +112,13 @@ void Wallet::updateConnectionStatusAsync()
Wallet::ConnectionStatus Wallet::connected(bool forceCheck)
{
if (!m_initialized)
{
return ConnectionStatus_Connecting;
}
// cache connection status
if (forceCheck || !m_initialized || (m_connectionStatusTime.elapsed() / 1000 > m_connectionStatusTtl && !m_connectionStatusRunning) || m_connectionStatusTime.elapsed() > 30000) {
if (forceCheck || (m_connectionStatusTime.elapsed() / 1000 > m_connectionStatusTtl && !m_connectionStatusRunning) || m_connectionStatusTime.elapsed() > 30000) {
qDebug() << "Checking connection status";
m_connectionStatusRunning = true;
m_connectionStatusTime.restart();
@@ -277,14 +279,25 @@ void Wallet::initAsync(
{
qDebug() << "initAsync: " + daemonAddress;
const auto future = m_scheduler.run([this, daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight, proxyAddress] {
bool success = init(daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight, proxyAddress);
if (success)
m_initialized = init(
daemonAddress,
trustedDaemon,
upperTransactionLimit,
isRecovering,
isRecoveringFromDevice,
restoreHeight,
proxyAddress);
if (m_initialized)
{
emit walletCreationHeightChanged();
qDebug() << "init async finished - starting refresh";
connected(true);
startRefresh();
}
else
{
qCritical() << "Failed to initialize the wallet";
}
});
if (future.first)
{
@@ -519,25 +532,44 @@ void Wallet::pauseRefresh()
m_refreshEnabled = false;
}
PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QString &payment_id,
quint64 amount, quint32 mixin_count,
PendingTransaction::Priority priority)
PendingTransaction *Wallet::createTransaction(
const QVector<QString> &destinationAddresses,
const QString &payment_id,
const QVector<QString> &destinationAmounts,
quint32 mixin_count,
PendingTransaction::Priority priority)
{
std::vector<std::string> destinations;
for (const auto &address : destinationAddresses) {
destinations.push_back(address.toStdString());
}
std::vector<uint64_t> amounts;
for (const auto &amount : destinationAmounts) {
amounts.push_back(Monero::Wallet::amountFromString(amount.toStdString()));
}
std::set<uint32_t> subaddr_indices;
Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction(
dst_addr.toStdString(), payment_id.toStdString(), amount, mixin_count,
static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices);
PendingTransaction * result = new PendingTransaction(ptImpl,0);
Monero::PendingTransaction *ptImpl = m_walletImpl->createTransactionMultDest(
destinations,
payment_id.toStdString(),
amounts,
mixin_count,
static_cast<Monero::PendingTransaction::Priority>(priority),
currentSubaddressAccount(),
subaddr_indices);
PendingTransaction *result = new PendingTransaction(ptImpl, 0);
return result;
}
void Wallet::createTransactionAsync(const QString &dst_addr, const QString &payment_id,
quint64 amount, quint32 mixin_count,
PendingTransaction::Priority priority)
void Wallet::createTransactionAsync(
const QVector<QString> &destinationAddresses,
const QString &payment_id,
const QVector<QString> &destinationAmounts,
quint32 mixin_count,
PendingTransaction::Priority priority)
{
m_scheduler.run([this, dst_addr, payment_id, amount, mixin_count, priority] {
PendingTransaction *tx = createTransaction(dst_addr, payment_id, amount, mixin_count, priority);
emit transactionCreated(tx, dst_addr, payment_id, mixin_count);
m_scheduler.run([this, destinationAddresses, payment_id, destinationAmounts, mixin_count, priority] {
PendingTransaction *tx = createTransaction(destinationAddresses, payment_id, destinationAmounts, mixin_count, priority);
emit transactionCreated(tx, destinationAddresses, payment_id, mixin_count);
});
}
@@ -558,7 +590,7 @@ void Wallet::createTransactionAllAsync(const QString &dst_addr, const QString &p
{
m_scheduler.run([this, dst_addr, payment_id, mixin_count, priority] {
PendingTransaction *tx = createTransactionAll(dst_addr, payment_id, mixin_count, priority);
emit transactionCreated(tx, dst_addr, payment_id, mixin_count);
emit transactionCreated(tx, {dst_addr}, payment_id, mixin_count);
});
}
@@ -573,7 +605,7 @@ void Wallet::createSweepUnmixableTransactionAsync()
{
m_scheduler.run([this] {
PendingTransaction *tx = createSweepUnmixableTransaction();
emit transactionCreated(tx, "", "", 0);
emit transactionCreated(tx, {""}, "", 0);
});
}
@@ -613,17 +645,32 @@ void Wallet::disposeTransaction(UnsignedTransaction *t)
delete t;
}
void Wallet::estimateTransactionFeeAsync(const QString &destination,
quint64 amount,
PendingTransaction::Priority priority,
const QJSValue &callback)
void Wallet::estimateTransactionFeeAsync(
const QVector<QString> &destinationAddresses,
const QVector<quint64> &amounts,
PendingTransaction::Priority priority,
const QJSValue &callback)
{
m_scheduler.run([this, destination, amount, priority] {
const uint64_t fee = m_walletImpl->estimateTransactionFee(
{std::make_pair(destination.toStdString(), amount)},
static_cast<Monero::PendingTransaction::Priority>(priority));
return QJSValueList({QString::fromStdString(Monero::Wallet::displayAmount(fee))});
}, callback);
m_scheduler.run(
[this, destinationAddresses, amounts, priority] {
if (destinationAddresses.size() != amounts.size())
{
return QJSValueList({""});
}
std::vector<std::pair<std::string, uint64_t>> destinations;
destinations.reserve(destinationAddresses.size());
for (size_t index = 0; index < destinationAddresses.size(); ++index)
{
destinations.emplace_back(std::make_pair(destinationAddresses[index].toStdString(), amounts[index]));
}
const uint64_t fee = m_walletImpl->estimateTransactionFee(
destinations,
static_cast<Monero::PendingTransaction::Priority>(priority));
return QJSValueList({QString::fromStdString(Monero::Wallet::displayAmount(fee))});
},
callback);
}
TransactionHistory *Wallet::history() const
@@ -699,16 +746,6 @@ QString Wallet::integratedAddress(const QString &paymentId) const
return QString::fromStdString(m_walletImpl->integratedAddress(paymentId.toStdString()));
}
QString Wallet::paymentId() const
{
return m_paymentId;
}
void Wallet::setPaymentId(const QString &paymentId)
{
m_paymentId = paymentId;
}
QString Wallet::getCacheAttribute(const QString &key) const {
return QString::fromStdString(m_walletImpl->getCacheAttribute(key.toStdString()));
}
@@ -1043,9 +1080,9 @@ void Wallet::onPassphraseEntered(const QString &passphrase, bool enter_on_device
Wallet::Wallet(Monero::Wallet *w, QObject *parent)
: QObject(parent)
, m_walletImpl(w)
, m_history(nullptr)
, m_history(new TransactionHistory(m_walletImpl->history(), this))
, m_historyModel(nullptr)
, m_addressBook(nullptr)
, m_addressBook(new AddressBook(m_walletImpl->addressBook(), this))
, m_addressBookModel(nullptr)
, m_daemonBlockChainHeight(0)
, m_daemonBlockChainHeightTtl(DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS)
@@ -1054,19 +1091,16 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
, m_connectionStatus(Wallet::ConnectionStatus_Disconnected)
, m_connectionStatusTtl(WALLET_CONNECTION_STATUS_CACHE_TTL_SECONDS)
, m_disconnected(true)
, m_initialized(false)
, m_currentSubaddressAccount(0)
, m_subaddress(nullptr)
, m_subaddress(new Subaddress(m_walletImpl->subaddress(), this))
, m_subaddressModel(nullptr)
, m_subaddressAccount(nullptr)
, m_subaddressAccount(new SubaddressAccount(m_walletImpl->subaddressAccount(), this))
, m_subaddressAccountModel(nullptr)
, m_refreshEnabled(false)
, m_refreshing(false)
, m_scheduler(this)
{
m_history = new TransactionHistory(m_walletImpl->history(), this);
m_addressBook = new AddressBook(m_walletImpl->addressBook(), this);
m_subaddress = new Subaddress(m_walletImpl->subaddress(), this);
m_subaddressAccount = new SubaddressAccount(m_walletImpl->subaddressAccount(), this);
m_walletListener = new WalletListenerImpl(this);
m_walletImpl->setListener(m_walletListener);
m_currentSubaddressAccount = getCacheAttribute(ATTRIBUTE_SUBADDRESS_ACCOUNT).toUInt();
@@ -1074,7 +1108,6 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
m_connectionStatusTime.start();
m_daemonBlockChainHeightTime.start();
m_daemonBlockChainTargetHeightTime.start();
m_initialized = false;
m_connectionStatusRunning = false;
m_daemonUsername = "";
m_daemonPassword = "";
@@ -1090,17 +1123,6 @@ Wallet::~Wallet()
m_walletImpl->stop();
m_scheduler.shutdownWaitForFinished();
delete m_addressBook;
m_addressBook = NULL;
delete m_history;
m_history = NULL;
delete m_addressBook;
m_addressBook = NULL;
delete m_subaddress;
m_subaddress = NULL;
delete m_subaddressAccount;
m_subaddressAccount = NULL;
//Monero::WalletManagerFactory::getWalletManager()->closeWallet(m_walletImpl);
if(status() == Status_Critical)
qDebug("Not storing wallet cache");

View File

@@ -29,6 +29,8 @@
#ifndef WALLET_H
#define WALLET_H
#include <atomic>
#include <QElapsedTimer>
#include <QObject>
#include <QMutex>
@@ -73,7 +75,6 @@ class Wallet : public QObject, public PassprasePrompter
Q_PROPERTY(bool synchronized READ synchronized)
Q_PROPERTY(QString errorString READ errorString)
Q_PROPERTY(TransactionHistory * history READ history)
Q_PROPERTY(QString paymentId READ paymentId WRITE setPaymentId)
Q_PROPERTY(TransactionHistorySortFilterModel * historyModel READ historyModel NOTIFY historyModelChanged)
Q_PROPERTY(QString path READ path)
Q_PROPERTY(AddressBookModel * addressBookModel READ addressBookModel)
@@ -214,15 +215,13 @@ public:
Q_INVOKABLE void startRefresh();
Q_INVOKABLE void pauseRefresh();
//! creates transaction
Q_INVOKABLE PendingTransaction * createTransaction(const QString &dst_addr, const QString &payment_id,
quint64 amount, quint32 mixin_count,
PendingTransaction::Priority priority);
//! creates async transaction
Q_INVOKABLE void createTransactionAsync(const QString &dst_addr, const QString &payment_id,
quint64 amount, quint32 mixin_count,
PendingTransaction::Priority priority);
Q_INVOKABLE void createTransactionAsync(
const QVector<QString> &destinationAddresses,
const QString &payment_id,
const QVector<QString> &destinationAmounts,
quint32 mixin_count,
PendingTransaction::Priority priority);
//! creates transaction with all outputs
Q_INVOKABLE PendingTransaction * createTransactionAll(const QString &dst_addr, const QString &payment_id,
@@ -253,10 +252,11 @@ public:
//! deletes unsigned transaction and frees memory
Q_INVOKABLE void disposeTransaction(UnsignedTransaction * t);
Q_INVOKABLE void estimateTransactionFeeAsync(const QString &destination,
quint64 amount,
PendingTransaction::Priority priority,
const QJSValue &callback);
Q_INVOKABLE void estimateTransactionFeeAsync(
const QVector<QString> &destinationAddresses,
const QVector<quint64> &amounts,
PendingTransaction::Priority priority,
const QJSValue &callback);
//! returns transaction history
TransactionHistory * history() const;
@@ -297,11 +297,6 @@ public:
//! Parse URI
Q_INVOKABLE bool parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error);
//! saved payment id
QString paymentId() const;
void setPaymentId(const QString &paymentId);
//! Namespace your cacheAttribute keys to avoid collisions
Q_INVOKABLE bool setCacheAttribute(const QString &key, const QString &val);
Q_INVOKABLE QString getCacheAttribute(const QString &key) const;
@@ -380,7 +375,11 @@ signals:
void deviceShowAddressShowed();
// emitted when transaction is created async
void transactionCreated(PendingTransaction * transaction, QString address, QString paymentId, quint32 mixinCount);
void transactionCreated(
PendingTransaction *transaction,
const QVector<QString> &addresses,
const QString &paymentId,
quint32 mixinCount);
void connectionStatusChanged(int status) const;
void currentSubaddressAccountChanged() const;
@@ -413,6 +412,13 @@ private:
quint64 restoreHeight,
const QString& proxyAddress);
PendingTransaction *createTransaction(
const QVector<QString> &destinationAddresses,
const QString &payment_id,
const QVector<QString> &destinationAmounts,
quint32 mixin_count,
PendingTransaction::Priority priority);
bool disconnected() const;
bool refreshing() const;
void refreshingSet(bool value);
@@ -431,7 +437,6 @@ private:
// Used for UI history view
mutable TransactionHistoryModel * m_historyModel;
mutable TransactionHistorySortFilterModel * m_historySortFilterModel;
QString m_paymentId;
AddressBook * m_addressBook;
mutable AddressBookModel * m_addressBookModel;
mutable QElapsedTimer m_daemonBlockChainHeightTime;
@@ -444,7 +449,7 @@ private:
int m_connectionStatusTtl;
mutable QElapsedTimer m_connectionStatusTime;
bool m_disconnected;
mutable bool m_initialized;
std::atomic<bool> m_initialized;
uint32_t m_currentSubaddressAccount;
Subaddress * m_subaddress;
mutable SubaddressModel * m_subaddressModel;

View File

@@ -169,7 +169,7 @@ Wallet *WalletManager::createWalletFromKeys(const QString &path, const QString &
}
Wallet *WalletManager::createWalletFromDevice(const QString &path, const QString &password, NetworkType::Type nettype,
const QString &deviceName, quint64 restoreHeight, const QString &subaddressLookahead)
const QString &deviceName, quint64 restoreHeight, const QString &subaddressLookahead, quint64 kdfRounds)
{
QMutexLocker locker(&m_mutex);
WalletPassphraseListenerImpl tmpListener(this);
@@ -187,7 +187,7 @@ Wallet *WalletManager::createWalletFromDevice(const QString &path, const QString
m_currentWallet = NULL;
}
Monero::Wallet * w = m_pimpl->createWalletFromDevice(path.toStdString(), password.toStdString(), static_cast<Monero::NetworkType>(nettype),
deviceName.toStdString(), restoreHeight, subaddressLookahead.toStdString(), 1, &tmpListener);
deviceName.toStdString(), restoreHeight, subaddressLookahead.toStdString(), kdfRounds, &tmpListener);
w->setListener(nullptr);
m_currentWallet = new Wallet(w);
@@ -202,10 +202,10 @@ Wallet *WalletManager::createWalletFromDevice(const QString &path, const QString
void WalletManager::createWalletFromDeviceAsync(const QString &path, const QString &password, NetworkType::Type nettype,
const QString &deviceName, quint64 restoreHeight, const QString &subaddressLookahead)
const QString &deviceName, quint64 restoreHeight, const QString &subaddressLookahead, quint64 kdfRounds)
{
m_scheduler.run([this, path, password, nettype, deviceName, restoreHeight, subaddressLookahead] {
Wallet *wallet = createWalletFromDevice(path, password, nettype, deviceName, restoreHeight, subaddressLookahead);
m_scheduler.run([this, path, password, nettype, deviceName, restoreHeight, subaddressLookahead, kdfRounds] {
Wallet *wallet = createWalletFromDevice(path, password, nettype, deviceName, restoreHeight, subaddressLookahead, kdfRounds);
emit walletCreated(wallet);
});
}
@@ -251,7 +251,7 @@ QString WalletManager::errorString() const
return tr("Unknown error");
}
quint64 WalletManager::maximumAllowedAmount() const
quint64 WalletManager::maximumAllowedAmount()
{
return Monero::Wallet::maximumAllowedAmount();
}
@@ -266,7 +266,7 @@ QString WalletManager::displayAmount(quint64 amount)
return QString::fromStdString(Monero::Wallet::displayAmount(amount));
}
quint64 WalletManager::amountFromString(const QString &amount) const
quint64 WalletManager::amountFromString(const QString &amount)
{
return Monero::Wallet::amountFromString(amount.toStdString());
}
@@ -276,6 +276,17 @@ quint64 WalletManager::amountFromDouble(double amount) const
return Monero::Wallet::amountFromDouble(amount);
}
QString WalletManager::amountsSumFromStrings(const QVector<QString> &amounts)
{
quint64 sum = 0;
for (const auto &amountString : amounts)
{
const quint64 amount = amountFromString(amountString);
sum = sum + std::min(maximumAllowedAmount() - sum, amount);
}
return QString::number(sum);
}
bool WalletManager::paymentIdValid(const QString &payment_id) const
{
return Monero::Wallet::paymentIdValid(payment_id.toStdString());

View File

@@ -103,14 +103,16 @@ public:
NetworkType::Type nettype,
const QString &deviceName,
quint64 restoreHeight = 0,
const QString &subaddressLookahead = "");
const QString &subaddressLookahead = "",
quint64 kdfRounds = 1);
Q_INVOKABLE void createWalletFromDeviceAsync(const QString &path,
const QString &password,
NetworkType::Type nettype,
const QString &deviceName,
quint64 restoreHeight = 0,
const QString &subaddressLookahead = "");
const QString &subaddressLookahead = "",
quint64 kdfRounds = 1);
/*!
* \brief closeWallet - closes current open wallet and frees memory
* \return wallet address
@@ -133,9 +135,10 @@ public:
//! since we can't call static method from QML, move it to this class
Q_INVOKABLE static QString displayAmount(quint64 amount);
Q_INVOKABLE quint64 amountFromString(const QString &amount) const;
Q_INVOKABLE static quint64 amountFromString(const QString &amount);
Q_INVOKABLE quint64 amountFromDouble(double amount) const;
Q_INVOKABLE quint64 maximumAllowedAmount() const;
Q_INVOKABLE static QString amountsSumFromStrings(const QVector<QString> &amounts);
Q_INVOKABLE static quint64 maximumAllowedAmount();
// QML JS engine doesn't support unsigned integers
Q_INVOKABLE QString maximumAllowedAmountAsString() const;

View File

@@ -27,14 +27,9 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "filter.h"
#include <QtGlobal>
#include <QKeyEvent>
#include <QDebug>
#ifdef QT_DEBUG
#include "private/qabstractanimation_p.h"
#endif
filter::filter(QObject *parent) :
QObject(parent)
{
@@ -91,21 +86,6 @@ bool filter::eventFilter(QObject *obj, QEvent *ev) {
case QEvent::KeyRelease: {
QKeyEvent *ke = static_cast<QKeyEvent*>(ev);
#ifdef QT_DEBUG
if(ke->key() == Qt::Key_F9){
QUnifiedTimer::instance()->setSlowModeEnabled(true);
QUnifiedTimer::instance()->setSlowdownFactor(10);
qDebug() << "Slow animations enabled";
}
if(ke->key() == Qt::Key_F10){
QUnifiedTimer::instance()->setSlowModeEnabled(false);
QUnifiedTimer::instance()->setSlowdownFactor(1);
qDebug() << "Slow animations disabled";
}
#endif
if(ke->key() == Qt::Key_Backtab)
m_backtabPressed = false;

View File

@@ -72,6 +72,9 @@
#include "qt/KeysFiles.h"
#include "qt/MoneroSettings.h"
#include "qt/NetworkAccessBlockingFactory.h"
#ifdef Q_OS_MAC
#include "qt/macoshelper.h"
#endif
// IOS exclusions
#ifndef Q_OS_IOS
@@ -123,6 +126,7 @@ Q_IMPORT_PLUGIN(QGenericEnginePlugin)
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
Q_IMPORT_PLUGIN(QtQmlPlugin)
#endif
Q_IMPORT_PLUGIN(QtQmlModelsPlugin)
Q_IMPORT_PLUGIN(QtQuick2Plugin)
Q_IMPORT_PLUGIN(QtQuickLayoutsPlugin)
Q_IMPORT_PLUGIN(QtGraphicalEffectsPlugin)
@@ -132,6 +136,7 @@ Q_IMPORT_PLUGIN(QtQuickControls1Plugin)
Q_IMPORT_PLUGIN(QtQuick2DialogsPlugin)
Q_IMPORT_PLUGIN(QmlFolderListModelPlugin)
Q_IMPORT_PLUGIN(QmlSettingsPlugin)
Q_IMPORT_PLUGIN(QtLabsPlatformPlugin)
Q_IMPORT_PLUGIN(QtQuick2DialogsPrivatePlugin)
Q_IMPORT_PLUGIN(QtQuick2PrivateWidgetsPlugin)
Q_IMPORT_PLUGIN(QtQuickControls2Plugin)
@@ -177,6 +182,10 @@ int main(int argc, char *argv[])
if(qgetenv("QMLSCENE_DEVICE") == "softwarecontext")
isOpenGL = false;
#ifdef Q_OS_MAC
// macOS window tabbing is not supported
MacOSHelper::disableWindowTabbing();
#endif
// disable "QApplication: invalid style override passed" warning
if (isDesktop) qputenv("QT_STYLE_OVERRIDE", "fusion");
#ifdef Q_OS_LINUX
@@ -194,15 +203,7 @@ int main(int argc, char *argv[])
QDir::setCurrent(QDir(MacOSHelper::bundlePath() + QDir::separator() + "..").canonicalPath());
#endif
if (MoneroSettings::portableConfigExists())
{
const QString cacheDir(MoneroSettings::portableFolderName() + QDir::separator() + ".cache");
if (!qputenv("QML_DISK_CACHE_PATH", cacheDir.toUtf8()))
{
qCritical() << "Error: failed to set QML disk cache path";
return 1;
}
}
qputenv("QML_DISABLE_DISK_CACHE", "1");
MainApp app(argc, argv);
@@ -319,11 +320,6 @@ Verify update binary using 'shasum'-compatible (SHA256 algo) output signed by tw
return 1;
}
// Desktop entry
#ifdef Q_OS_LINUX
registerXdgMime(app);
#endif
IPC *ipc = new IPC(&app);
QStringList posArgs = parser.positionalArguments();
@@ -343,7 +339,7 @@ Verify update binary using 'shasum'-compatible (SHA256 algo) output signed by tw
// screen settings
// Mobile is designed on 128dpi
qreal ref_dpi = 128;
QRect geo = QGuiApplication::primaryScreen()->availableGeometry();
QSize screenAvailableSize = QGuiApplication::primaryScreen()->availableSize();
QRect rect = QGuiApplication::primaryScreen()->geometry();
qreal dpi = QGuiApplication::primaryScreen()->logicalDotsPerInch();
qreal physicalDpi = QGuiApplication::primaryScreen()->physicalDotsPerInch();
@@ -366,6 +362,7 @@ Verify update binary using 'shasum'-compatible (SHA256 algo) output signed by tw
qWarning().nospace().noquote() << "Qt:" << QT_VERSION_STR << " GUI:" << GUI_VERSION
<< " | screen: " << rect.width() << "x" << rect.height()
<< " - available: " << screenAvailableSize
<< " - dpi: " << dpi << " - ratio:" << calculated_ratio;
// registering types for QML
@@ -464,8 +461,8 @@ Verify update binary using 'shasum'-compatible (SHA256 algo) output signed by tw
// Exclude daemon manager from IOS
#ifndef Q_OS_IOS
DaemonManager * daemonManager = DaemonManager::instance();
engine.rootContext()->setContextProperty("daemonManager", daemonManager);
DaemonManager daemonManager;
engine.rootContext()->setContextProperty("daemonManager", &daemonManager);
#endif
engine.rootContext()->setContextProperty("isWindows", isWindows);
@@ -476,8 +473,8 @@ Verify update binary using 'shasum'-compatible (SHA256 algo) output signed by tw
engine.rootContext()->setContextProperty("isOpenGL", isOpenGL);
engine.rootContext()->setContextProperty("isTails", isTails);
engine.rootContext()->setContextProperty("screenWidth", geo.width());
engine.rootContext()->setContextProperty("screenHeight", geo.height());
engine.rootContext()->setContextProperty("screenAvailableWidth", screenAvailableSize.width());
engine.rootContext()->setContextProperty("screenAvailableHeight", screenAvailableSize.height());
#ifndef Q_OS_IOS
const QString desktopFolder = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);

View File

@@ -27,10 +27,16 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "oshelper.h"
#include <unordered_set>
#include <QCoreApplication>
#include <QGuiApplication>
#include <QFileDialog>
#include <QScreen>
#include <QStandardPaths>
#include <QTemporaryFile>
#include <QWindow>
#include <QDir>
#include <QDebug>
#include <QDesktopServices>
@@ -46,13 +52,49 @@
#endif
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
#include <X11/XKBlib.h>
#undef Bool
#undef KeyPress
#undef KeyRelease
#undef FocusIn
#undef FocusOut
// #undef those Xlib #defines that conflict with QEvent::Type enum
#include "qt/utils.h"
#endif
#include "QR-Code-scanner/Decoder.h"
#include "qt/ScopeGuard.h"
namespace
{
QPixmap screenshot()
{
#ifdef Q_OS_MAC
return MacOSHelper::screenshot();
#else
std::unordered_set<QWindow *> hidden;
const QWindowList windows = QGuiApplication::allWindows();
for (QWindow *window : windows)
{
if (window->isVisible())
{
hidden.emplace(window);
window->hide();
}
}
const auto unhide = sg::make_scope_guard([&hidden]() {
for (QWindow *window : hidden)
{
window->show();
}
});
return QGuiApplication::primaryScreen()->grabWindow(0);
#endif
}
} // namespace
#if defined(Q_OS_WIN)
bool openFolderAndSelectItem(const QString &filePath)
{
@@ -85,11 +127,38 @@ OSHelper::OSHelper(QObject *parent) : QObject(parent)
}
void OSHelper::createDesktopEntry() const
{
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
registerXdgMime();
#endif
}
QString OSHelper::downloadLocation() const
{
return QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
}
QList<QString> OSHelper::grabQrCodesFromScreen() const
{
QList<QString> codes;
try
{
const QImage image = screenshot().toImage();
const std::vector<std::string> decoded = QrDecoder().decode(image);
std::for_each(decoded.begin(), decoded.end(), [&codes](const std::string &code) {
codes.push_back(QString::fromStdString(code));
});
}
catch (const std::exception &e)
{
qWarning() << e.what();
}
return codes;
}
bool OSHelper::openContainingFolder(const QString &filePath) const
{
QString canonicalFilePath = QFileInfo(filePath).canonicalFilePath();
@@ -154,6 +223,7 @@ bool OSHelper::isCapsLock() const
unsigned n;
XkbGetIndicatorState(d, XkbUseCoreKbd, &n);
caps_state = (n & 0x01) == 1;
XCloseDisplay(d);
}
return caps_state;
#elif defined(Q_OS_MAC)

View File

@@ -29,7 +29,9 @@
#ifndef OSHELPER_H
#define OSHELPER_H
#include <QList>
#include <QObject>
#include <QString>
/**
* @brief The OSHelper class - exports to QML some OS-related functions
*/
@@ -41,7 +43,9 @@ class OSHelper : public QObject
public:
explicit OSHelper(QObject *parent = 0);
Q_INVOKABLE void createDesktopEntry() const;
Q_INVOKABLE QString downloadLocation() const;
Q_INVOKABLE QList<QString> grabQrCodesFromScreen() const;
Q_INVOKABLE bool openContainingFolder(const QString &filePath) const;
Q_INVOKABLE QString openSaveFileDialog(const QString &title, const QString &folder, const QString &filename) const;
Q_INVOKABLE QString temporaryFilename() const;

View File

@@ -87,11 +87,6 @@ bool AddressBookModel::deleteRow(int row)
return m_addressBook->deleteRow(row);
}
int AddressBookModel::lookupPaymentID(const QString &payment_id) const
{
return m_addressBook->lookupPaymentID(payment_id);
}
QHash<int, QByteArray> AddressBookModel::roleNames() const
{
QHash<int, QByteArray> roleNames = QAbstractListModel::roleNames();

View File

@@ -52,7 +52,6 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Q_INVOKABLE bool deleteRow(int row);
Q_INVOKABLE int lookupPaymentID(const QString &payment_id) const;
virtual QHash<int, QByteArray> roleNames() const override;
public slots:

View File

@@ -29,6 +29,8 @@
#ifndef MACOSHELPER_H
#define MACOSHELPER_H
#include <QPixmap>
class MacOSHelper
{
MacOSHelper() {}
@@ -36,7 +38,9 @@ class MacOSHelper
public:
static bool isCapsLock();
static bool openFolderAndSelectItem(const QUrl &path);
static QPixmap screenshot();
static QString bundlePath();
static void disableWindowTabbing();
};
#endif //MACOSHELPER_H

View File

@@ -26,6 +26,8 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unordered_set>
#include <QtCore>
#include <QtGui>
#include <QtMac>
@@ -37,6 +39,16 @@
#include <ApplicationServices/ApplicationServices.h>
#include <Availability.h>
#include "ScopeGuard.h"
void MacOSHelper::disableWindowTabbing()
{
#ifdef __MAC_10_12
if ([NSWindow respondsToSelector:@selector(allowsAutomaticWindowTabbing)])
[NSWindow setAllowsAutomaticWindowTabbing: NO];
#endif
}
bool MacOSHelper::isCapsLock()
{
#ifdef __MAC_10_12
@@ -56,6 +68,41 @@ bool MacOSHelper::openFolderAndSelectItem(const QUrl &path)
return true;
}
QPixmap MacOSHelper::screenshot()
{
std::unordered_set<uintptr_t> appWindowIds;
for (NSWindow *window in [NSApp windows])
{
appWindowIds.insert((uintptr_t)[window windowNumber]);
}
CFArrayRef onScreenWindows = CGWindowListCreate(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
const auto onScreenWindowsClenaup = sg::make_scope_guard([&onScreenWindows]() {
CFRelease(onScreenWindows);
});
CFMutableArrayRef foreignWindows = CFArrayCreateMutable(NULL, CFArrayGetCount(onScreenWindows), NULL);
const auto foreignWindowsClenaup = sg::make_scope_guard([&foreignWindows]() {
CFRelease(foreignWindows);
});
for (CFIndex index = 0, count = CFArrayGetCount(onScreenWindows); index < count; ++index)
{
const uintptr_t windowId = reinterpret_cast<const uintptr_t>(CFArrayGetValueAtIndex(onScreenWindows, index));
if (appWindowIds.find(windowId) == appWindowIds.end())
{
CFArrayAppendValue(foreignWindows, reinterpret_cast<const void *>(windowId));
}
}
CGImageRef image = CGWindowListCreateImageFromArray(CGRectInfinite, foreignWindows, kCGWindowListOptionAll);
const auto imageClenaup = sg::make_scope_guard([&image]() {
CFRelease(image);
});
return QtMac::fromCGImageRef(image);
}
QString MacOSHelper::bundlePath()
{
NSBundle *main = [NSBundle mainBundle];

View File

@@ -27,7 +27,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtCore>
#include <QApplication>
#include <QCoreApplication>
#include <QtGlobal>
#include "TailsOS.h"
@@ -88,7 +88,7 @@ QString getAccountName(){
}
#ifdef Q_OS_LINUX
QString xdgMime(QApplication &app){
QString xdgMime(){
return QString(
"[Desktop Entry]\n"
"Name=Monero GUI\n"
@@ -105,32 +105,32 @@ QString xdgMime(QApplication &app){
"StartupNotify=true\n"
"X-GNOME-Bugzilla-Bugzilla=GNOME\n"
"X-GNOME-UsesNotifications=true\n"
).arg(app.applicationFilePath());
"StartupWMClass=monero-wallet-gui\n"
).arg(QCoreApplication::applicationFilePath());
}
void registerXdgMime(QApplication &app){
void registerXdgMime(){
// Register desktop entry
// - MacOS handled via Info.plist
// - Windows handled in the installer by rbrunner7
// - Linux written to `QStandardPaths::ApplicationsLocation`
// - Tails written to persistent dotfiles
QString mime = xdgMime(app);
QString mime = xdgMime();
QString appPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
QString filePath = QString("%1/monero-gui.desktop").arg(appPath);
if (TailsOS::detect() && TailsOS::detectDotPersistence() && TailsOS::usePersistence) {
TailsOS::persistXdgMime(filePath, mime);
return;
if (TailsOS::detect())
{
if (TailsOS::detectDotPersistence() && TailsOS::usePersistence)
{
TailsOS::persistXdgMime(filePath, mime);
}
}
else
{
QDir().mkpath(QFileInfo(filePath).path());
fileWrite(filePath, mime);
}
QFileInfo file(filePath);
QDir().mkpath(file.path()); // ensure directory exists
#ifdef QT_DEBUG
qDebug() << "Writing xdg mime: " << filePath;
#endif
fileWrite(filePath, mime);
}
#endif

View File

@@ -39,8 +39,8 @@ QByteArray fileOpen(QString path);
bool fileWrite(QString path, QString data);
QString getAccountName();
#ifdef Q_OS_LINUX
QString xdgMime(QApplication &app);
void registerXdgMime(QApplication &app);
QString xdgMime();
void registerXdgMime();
#endif
const static QRegExp reURI = QRegExp("^\\w+:\\/\\/([\\w+\\-?\\-_\\-=\\-&]+)");
QString randomUserAgent();

View File

@@ -46,3 +46,4 @@ set_source_files_properties(${TRANSLATIONS_CPP} PROPERTIES SKIP_AUTOMOC ON)
set_source_files_properties(${TRANSLATIONS_CPP} PROPERTIES SKIP_AUTOUIC ON)
add_library(translations ${TRANSLATIONS_CPP})
target_link_libraries(translations PUBLIC Qt5::Core)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More