Compare commits
424 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afc2e846fd | ||
|
|
c601313943 | ||
|
|
73c0522a56 | ||
|
|
06a66e3a00 | ||
|
|
12355deb94 | ||
|
|
cbbbf30198 | ||
|
|
40e108eb2b | ||
|
|
cdfe9f338f | ||
|
|
adb04cef71 | ||
|
|
1123dd7046 | ||
|
|
f1fdbee25d | ||
|
|
ff51dd08d3 | ||
|
|
476896864c | ||
|
|
0b7cf4a544 | ||
|
|
caff6193f2 | ||
|
|
e2a82c9037 | ||
|
|
28ee4164cd | ||
|
|
7af099958e | ||
|
|
0d8e363407 | ||
|
|
7306b84d41 | ||
|
|
9d25f7230b | ||
|
|
b28f2dae33 | ||
|
|
619b2d7947 | ||
|
|
a23c49e5b6 | ||
|
|
61fc38b29c | ||
|
|
22386aa7e1 | ||
|
|
f5c5df7b67 | ||
|
|
1aa98c3cfd | ||
|
|
67c47d468c | ||
|
|
0fcaadae53 | ||
|
|
5b5c0ac658 | ||
|
|
1b4c21700f | ||
|
|
9df9cb8da7 | ||
|
|
a32d39cc96 | ||
|
|
8ef7b7c89a | ||
|
|
1ef96f9544 | ||
|
|
d413b16d34 | ||
|
|
37fea0ee33 | ||
|
|
b12ec3b0f0 | ||
|
|
4c257aff67 | ||
|
|
be1f63f93d | ||
|
|
839167aff5 | ||
|
|
87400e781e | ||
|
|
98ce87a572 | ||
|
|
d555ba55a9 | ||
|
|
1387fd4f9c | ||
|
|
6ff43fa81e | ||
|
|
076c70906a | ||
|
|
923a32cfd5 | ||
|
|
e7c37fc7bc | ||
|
|
2b83edc982 | ||
|
|
4208b66baf | ||
|
|
b9e74f6b6d | ||
|
|
270b86b142 | ||
|
|
6c67a39d2e | ||
|
|
91239881f1 | ||
|
|
2d464a1266 | ||
|
|
0dda5796ec | ||
|
|
e1987522e2 | ||
|
|
1b519b8302 | ||
|
|
d488979351 | ||
|
|
d313c2de37 | ||
|
|
560dd09f8a | ||
|
|
ea778c41dd | ||
|
|
6595a7b1c1 | ||
|
|
dea513fc84 | ||
|
|
55759545d1 | ||
|
|
248ec22eb5 | ||
|
|
04eab65b10 | ||
|
|
8643f85fef | ||
|
|
e0679ce5e6 | ||
|
|
31dbe7ea42 | ||
|
|
f745670b36 | ||
|
|
a80746adf1 | ||
|
|
2e8bec15da | ||
|
|
24d8360da1 | ||
|
|
f75d988437 | ||
|
|
3a1601f132 | ||
|
|
fd956b54b5 | ||
|
|
6467333fe7 | ||
|
|
4effbd3c8e | ||
|
|
8845ce6d49 | ||
|
|
3aeaf99057 | ||
|
|
c41e3d8e7a | ||
|
|
9d05462715 | ||
|
|
394e56915d | ||
|
|
749c166b10 | ||
|
|
a563582d95 | ||
|
|
a000b8d850 | ||
|
|
4b626924e6 | ||
|
|
e97fb0b3d8 | ||
|
|
aa1ab4f448 | ||
|
|
1752fde08b | ||
|
|
121904f340 | ||
|
|
05f63a24cc | ||
|
|
e2085bdaa3 | ||
|
|
7e83173c77 | ||
|
|
183c8084a5 | ||
|
|
5bc305679c | ||
|
|
2557bdb35f | ||
|
|
79a87ca03b | ||
|
|
a8eab144e4 | ||
|
|
83cffa469e | ||
|
|
b1b7307578 | ||
|
|
e0dfda2189 | ||
|
|
370607a7dc | ||
|
|
dc1d0a68c8 | ||
|
|
fed38b9e06 | ||
|
|
17213bfe8c | ||
|
|
e1b5ee24e9 | ||
|
|
35f92b76a2 | ||
|
|
9255d649d9 | ||
|
|
86f5aae63d | ||
|
|
75e433388f | ||
|
|
f51b0f6704 | ||
|
|
1895755efb | ||
|
|
03db3f96ff | ||
|
|
1d2840f8b5 | ||
|
|
4e16698558 | ||
|
|
c013d7d125 | ||
|
|
27e4771622 | ||
|
|
e65159163d | ||
|
|
77b7a5244a | ||
|
|
3c69023135 | ||
|
|
fad8dab165 | ||
|
|
16646eb651 | ||
|
|
6898d5dd42 | ||
|
|
67be96e6d5 | ||
|
|
9ce88c6aeb | ||
|
|
5ea99a73e7 | ||
|
|
43aeea8eb7 | ||
|
|
7eeda0a8f0 | ||
|
|
9220937c4b | ||
|
|
6aaf294f0b | ||
|
|
721a0cbf91 | ||
|
|
d1bde4f8b2 | ||
|
|
380b955bce | ||
|
|
0db4c36db0 | ||
|
|
dcc040a119 | ||
|
|
63e32c4a83 | ||
|
|
7972d8a219 | ||
|
|
872b81fe39 | ||
|
|
6136e88fcb | ||
|
|
c77637d141 | ||
|
|
0d047035fb | ||
|
|
b5aa659757 | ||
|
|
88d297d8cc | ||
|
|
eb924a34d1 | ||
|
|
352da92229 | ||
|
|
99907e539a | ||
|
|
e8bcabe66b | ||
|
|
829414ed01 | ||
|
|
36262f029a | ||
|
|
13ee9b1f26 | ||
|
|
085abb798a | ||
|
|
c137a6ea36 | ||
|
|
2cea0fc669 | ||
|
|
aaa1cb47c0 | ||
|
|
1577ce278b | ||
|
|
9d48f96fc8 | ||
|
|
1a51e93e55 | ||
|
|
b62b821002 | ||
|
|
f3ee46175c | ||
|
|
17a3c51a43 | ||
|
|
410897ced7 | ||
|
|
2fd3974194 | ||
|
|
7c50e1ff4b | ||
|
|
dec5dcf25c | ||
|
|
9fc260c62d | ||
|
|
c9d36b1302 | ||
|
|
d931022963 | ||
|
|
df885b6eaa | ||
|
|
f78c95b73b | ||
|
|
b22fb24e47 | ||
|
|
8c8faf29e4 | ||
|
|
b7b1221221 | ||
|
|
38c3534ead | ||
|
|
f631b75f0a | ||
|
|
11fd19e0f8 | ||
|
|
1572b4cf79 | ||
|
|
10a47d783e | ||
|
|
14cc1d096a | ||
|
|
840421fd7b | ||
|
|
51739dfb22 | ||
|
|
be5e6772a4 | ||
|
|
c869390272 | ||
|
|
50c22ca300 | ||
|
|
f1b4eb6c56 | ||
|
|
d37c4ddef2 | ||
|
|
2522ff13fe | ||
|
|
596b71b293 | ||
|
|
8159b75be3 | ||
|
|
7677103f1b | ||
|
|
fead82b198 | ||
|
|
f55bf48bad | ||
|
|
e0faddf964 | ||
|
|
a00ed6a75a | ||
|
|
b54127e997 | ||
|
|
c672d8016d | ||
|
|
ccd8eb1c3a | ||
|
|
d5b165bde2 | ||
|
|
c978027933 | ||
|
|
9deec4dad0 | ||
|
|
e306992ce8 | ||
|
|
19daa074ca | ||
|
|
1c62edeff4 | ||
|
|
34439af67e | ||
|
|
e1e862bce4 | ||
|
|
0b2e74cdb5 | ||
|
|
3fee17e564 | ||
|
|
1e7d8293cb | ||
|
|
a3fc6754e0 | ||
|
|
8354c251c5 | ||
|
|
8f5053bd61 | ||
|
|
92b0a115f4 | ||
|
|
6a3e1aaf40 | ||
|
|
c32e11d3e8 | ||
|
|
9580c19da3 | ||
|
|
27532dc1bf | ||
|
|
c0e0626b84 | ||
|
|
c6d5c5dc3a | ||
|
|
749460fb46 | ||
|
|
c9ee76c2ee | ||
|
|
94dbf179d5 | ||
|
|
7deecbfdf6 | ||
|
|
29a742ba26 | ||
|
|
47559e51be | ||
|
|
f64dcde600 | ||
|
|
52c090b82f | ||
|
|
1edc068047 | ||
|
|
d18af7da72 | ||
|
|
53066ae92b | ||
|
|
333c9ee311 | ||
|
|
ff4de8e8f7 | ||
|
|
ef5d855950 | ||
|
|
e6f30578c0 | ||
|
|
f1e3926192 | ||
|
|
7f0c19950b | ||
|
|
1580c3a574 | ||
|
|
c8f4355e15 | ||
|
|
39561f8ead | ||
|
|
b15dbbb9b0 | ||
|
|
a73a4363ec | ||
|
|
55cbc562b6 | ||
|
|
e6c4c32d01 | ||
|
|
e36d4a918f | ||
|
|
0355ca2747 | ||
|
|
c946905907 | ||
|
|
a8bd2ab77e | ||
|
|
149e373367 | ||
|
|
fa3c8b5f89 | ||
|
|
e0f6577afd | ||
|
|
43f0854de9 | ||
|
|
f38e460842 | ||
|
|
527adcba17 | ||
|
|
0de1ba9f51 | ||
|
|
66e769603c | ||
|
|
15038850c2 | ||
|
|
efc9ad45e4 | ||
|
|
754a968706 | ||
|
|
c20a0ef928 | ||
|
|
eab98e3a48 | ||
|
|
2a8960bc2c | ||
|
|
fe68f59763 | ||
|
|
80e8dd6aef | ||
|
|
c82bd94bc3 | ||
|
|
28ca9503df | ||
|
|
73cc400ae8 | ||
|
|
8b7438ace2 | ||
|
|
210248e6ef | ||
|
|
f82948f4b0 | ||
|
|
da4e0dbf0f | ||
|
|
9dd3f4fecb | ||
|
|
abbe042c8a | ||
|
|
72a3b346bb | ||
|
|
d662e46146 | ||
|
|
bbc9ca8f08 | ||
|
|
f7271d1c7b | ||
|
|
afe1ae9b9c | ||
|
|
7f5b8ea0ad | ||
|
|
aa5000f556 | ||
|
|
8b6978b2a5 | ||
|
|
86d21a34ba | ||
|
|
4354a76df9 | ||
|
|
b616a14f88 | ||
|
|
7536e922e9 | ||
|
|
5bf0dd9684 | ||
|
|
cdf4ce2d6f | ||
|
|
37a8bcb525 | ||
|
|
2f8c0ca499 | ||
|
|
38612c1285 | ||
|
|
1d3a201077 | ||
|
|
a91a4f51ab | ||
|
|
52fbbae484 | ||
|
|
8f70fb4f79 | ||
|
|
c439d6814b | ||
|
|
f26f1469ca | ||
|
|
487e706f06 | ||
|
|
503c1af5f8 | ||
|
|
ca79525fdb | ||
|
|
7db5de082d | ||
|
|
ce6cc47afe | ||
|
|
a10a94f51c | ||
|
|
1833c16e39 | ||
|
|
d7207bfde3 | ||
|
|
5265e52b8b | ||
|
|
b6fdb709ba | ||
|
|
9aef3bab33 | ||
|
|
4b55197e18 | ||
|
|
11617d2f76 | ||
|
|
765e93cfd0 | ||
|
|
d31e661cd1 | ||
|
|
7f9b28c05f | ||
|
|
4a7ccd8d82 | ||
|
|
be954cc2c4 | ||
|
|
387e643ae9 | ||
|
|
6f71d47806 | ||
|
|
135c970ad9 | ||
|
|
fd5d1f584e | ||
|
|
2195c67f58 | ||
|
|
5c13624596 | ||
|
|
cfdba59584 | ||
|
|
4141832a4d | ||
|
|
5f183da6e3 | ||
|
|
30c54b1c6e | ||
|
|
c1da3d1c97 | ||
|
|
cbd03229dd | ||
|
|
2fc1b287dd | ||
|
|
7c8c6a116f | ||
|
|
ef93139a80 | ||
|
|
1b7844ec34 | ||
|
|
8f63e8870f | ||
|
|
286c75aa5b | ||
|
|
0a4d65dd99 | ||
|
|
83ccadb6a8 | ||
|
|
eae7eff9db | ||
|
|
2102e4be0d | ||
|
|
02eec351b9 | ||
|
|
ce4cb6512d | ||
|
|
3d24300963 | ||
|
|
9748974ce0 | ||
|
|
120b5285fb | ||
|
|
b022735506 | ||
|
|
33c1a6f4fc | ||
|
|
4b0dcb95bf | ||
|
|
fdb7f806fa | ||
|
|
a810bf3eb7 | ||
|
|
a99eef68f5 | ||
|
|
7ebdb884a1 | ||
|
|
c7f9ac926b | ||
|
|
9b98e0a2f5 | ||
|
|
3835387eea | ||
|
|
238b1b777f | ||
|
|
3af99e91e4 | ||
|
|
07ecca5af4 | ||
|
|
b245d0af7a | ||
|
|
585fb2810d | ||
|
|
0784532001 | ||
|
|
dcbdae0954 | ||
|
|
2bef74fe8a | ||
|
|
81d5dd1cae | ||
|
|
50767570f0 | ||
|
|
1d5b940349 | ||
|
|
3563d44d99 | ||
|
|
ffceda9159 | ||
|
|
a75a0fb8c5 | ||
|
|
5fa64c34ec | ||
|
|
376421667a | ||
|
|
8a73fd241e | ||
|
|
9760886eff | ||
|
|
34089599cd | ||
|
|
4a7a98034e | ||
|
|
79f78f48e2 | ||
|
|
fee81ba210 | ||
|
|
a078705ec6 | ||
|
|
de6a9b6779 | ||
|
|
3f13a5c9a4 | ||
|
|
fb7470a2a6 | ||
|
|
e2c6ae6472 | ||
|
|
ea25b71ca6 | ||
|
|
5ebe3f5092 | ||
|
|
8e4124f06a | ||
|
|
e47fd5f760 | ||
|
|
8767c71107 | ||
|
|
2156a6533b | ||
|
|
7eac690d44 | ||
|
|
31adc6cfd6 | ||
|
|
d582fd338d | ||
|
|
eed51e3ffa | ||
|
|
6a889bdaa1 | ||
|
|
5f27a45910 | ||
|
|
e1258e0ada | ||
|
|
925cced7d7 | ||
|
|
94083e746f | ||
|
|
a49d579bd3 | ||
|
|
6ed7fcec67 | ||
|
|
6d7db135e7 | ||
|
|
042400b83f | ||
|
|
df54439972 | ||
|
|
86252506f0 | ||
|
|
a9fea2462b | ||
|
|
58987b2ec6 | ||
|
|
aecd218d15 | ||
|
|
856843b52a | ||
|
|
fc740a89ab | ||
|
|
0643607ec3 | ||
|
|
5872bc8a2b | ||
|
|
d07da76383 | ||
|
|
c092de97f2 | ||
|
|
c84a8fb07d | ||
|
|
63b4566475 | ||
|
|
3699dc9f2e | ||
|
|
eee48ce74c | ||
|
|
9072f89a4e | ||
|
|
c9e461dcb6 | ||
|
|
55b548f31c | ||
|
|
dede10ea1a | ||
|
|
b739cdd52a | ||
|
|
94a27b964a | ||
|
|
c7df74dab7 | ||
|
|
bf9b04b126 | ||
|
|
d21c22b444 | ||
|
|
b5fafb55c9 | ||
|
|
48aab5c6e5 |
1
.dockerignore
Normal file
@@ -0,0 +1 @@
|
||||
*
|
||||
79
.github/workflows/build.yml
vendored
@@ -4,49 +4,90 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build-macos:
|
||||
|
||||
runs-on: macOS-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: update brew and install dependencies
|
||||
run: brew update && brew install boost hidapi zmq libpgm miniupnpc ldns expat libunwind-headers protobuf qt5
|
||||
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
|
||||
- name: build
|
||||
run: export PATH=$PATH:/usr/local/opt/qt/bin && ./build.sh
|
||||
run: DEV_MODE=ON make release -j3
|
||||
- name: test qml
|
||||
run: build/release/bin/monero-wallet-gui.app/Contents/MacOS/monero-wallet-gui --test-qml
|
||||
|
||||
build-ubuntu:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: remove bundled boost
|
||||
run: sudo rm -rf /usr/local/share/boost
|
||||
- name: set apt conf
|
||||
run: |
|
||||
echo "Acquire::Retries \"3\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
|
||||
echo "Acquire::http::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
|
||||
echo "Acquire::ftp::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
|
||||
- name: update apt
|
||||
run: sudo apt update
|
||||
- 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
|
||||
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 xvfb
|
||||
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
|
||||
- name: build
|
||||
run: ./build.sh
|
||||
run: DEV_MODE=ON make release -j3
|
||||
- name: test qml
|
||||
run: xvfb-run -a build/release/bin/monero-wallet-gui --test-qml
|
||||
|
||||
build-windows:
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: numworks/setup-msys2@v1
|
||||
- name: update pacman
|
||||
run: msys2do pacman -Syu --noconfirm
|
||||
- name: install monero dependencies
|
||||
run: msys2do pacman -S --noconfirm 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 git mingw-w64-x86_64-qt5
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: eine/setup-msys2@v1
|
||||
with:
|
||||
update: true
|
||||
install: 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 git mingw-w64-x86_64-qt5 mingw-w64-x86_64-libgcrypt
|
||||
- name: build
|
||||
run: msys2do ./build.sh release
|
||||
run: DEV_MODE=ON make release-win64 -j2
|
||||
- name: test qml
|
||||
run: msys2do build/release/bin/monero-wallet-gui --test-qml
|
||||
run: build/release/bin/monero-wallet-gui --test-qml
|
||||
|
||||
docker-linux-static:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: satackey/action-docker-layer-caching@v0.0.8
|
||||
continue-on-error: true
|
||||
with:
|
||||
key: docker-linux-static-{hash}
|
||||
restore-keys: |
|
||||
docker-linux-static-
|
||||
- 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'
|
||||
|
||||
docker-windows-static:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: satackey/action-docker-layer-caching@v0.0.8
|
||||
continue-on-error: true
|
||||
with:
|
||||
key: docker-windows-static-{hash}
|
||||
restore-keys: |
|
||||
docker-windows-static-
|
||||
- name: preprare build enviroment
|
||||
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'
|
||||
|
||||
1
.gitignore
vendored
@@ -13,6 +13,7 @@ monero-wallet-gui_plugin_import.cpp
|
||||
monero-wallet-gui_qml_plugin_import.cpp
|
||||
*.qmlc
|
||||
*.jsc
|
||||
qml_qmlcache.qrc
|
||||
|
||||
### Vim ###
|
||||
# Swap
|
||||
|
||||
338
CMakeLists.txt
@@ -3,81 +3,70 @@ project(monero-gui)
|
||||
|
||||
message(STATUS "Initiating compile using CMake ${CMAKE_VERSION}")
|
||||
|
||||
set(VERSION_MAJOR "14")
|
||||
set(VERSION_MAJOR "17")
|
||||
set(VERSION_MINOR "0")
|
||||
set(VERSION_REVISION "3")
|
||||
set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}")
|
||||
set(VERSION_REVISION "1")
|
||||
set(VERSION "0.${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}")
|
||||
|
||||
# libwallet requires a static build, so we only allow static compilation
|
||||
set(STATIC ON)
|
||||
option(STATIC "Link libraries statically, requires static Qt")
|
||||
|
||||
option(USE_DEVICE_TREZOR ON)
|
||||
option(ENABLE_PASS_STRENGTH_METER "Disable zxcvbn" OFF)
|
||||
option(USE_DEVICE_TREZOR "Trezor support compilation" ON)
|
||||
option(ENABLE_PASS_STRENGTH_METER "Enable zxcvbn library for password strength" OFF)
|
||||
option(WITH_SCANNER "Enable webcam QR scanner" OFF)
|
||||
option(DEV_MODE "Checkout latest monero master on build" OFF)
|
||||
|
||||
list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake")
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
include(CheckCCompilerFlag)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckLinkerFlag)
|
||||
include(FindCcache)
|
||||
|
||||
if(DEBUG)
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
endif()
|
||||
|
||||
set(BUILD_GUI_DEPS ON)
|
||||
set(ARCH "x86-64")
|
||||
set(BUILD_64 ON)
|
||||
set(INSTALL_VENDORED_LIBUNBOUND=ON)
|
||||
set(ARCH "x86-64" CACHE STRING "Target architecture")
|
||||
set(BUILD_64 ON CACHE BOOL "Build 64-bit binaries")
|
||||
|
||||
function (add_c_flag_if_supported flag var)
|
||||
string(REPLACE "-" "_" supported ${flag}_c)
|
||||
check_c_compiler_flag(${flag} ${supported})
|
||||
if(${${supported}})
|
||||
set(${var} "${${var}} ${flag}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function (add_cxx_flag_if_supported flag var)
|
||||
string(REPLACE "-" "_" supported ${flag}_cxx)
|
||||
check_cxx_compiler_flag(${flag} ${supported})
|
||||
if(${${supported}})
|
||||
set(${var} "${${var}} ${flag}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function (add_linker_flag_if_supported flag var)
|
||||
string(REPLACE "-" "_" supported ${flag}_ld)
|
||||
string(REPLACE "," "_" supported ${flag}_ld)
|
||||
check_linker_flag(${flag} ${supported})
|
||||
if(${${supported}})
|
||||
set(${var} "${${var}} ${flag}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
find_package(Git)
|
||||
if(GIT_FOUND)
|
||||
if(NOT DEV_MODE)
|
||||
find_package(Git)
|
||||
function (check_submodule relative_path)
|
||||
execute_process(COMMAND git rev-parse "HEAD" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${relative_path} OUTPUT_VARIABLE localHead)
|
||||
execute_process(COMMAND git rev-parse "HEAD:${relative_path}" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE checkedHead)
|
||||
string(COMPARE EQUAL "${localHead}" "${checkedHead}" upToDate)
|
||||
if (upToDate)
|
||||
message(STATUS "Submodule '${relative_path}' is up-to-date")
|
||||
else()
|
||||
message(FATAL_ERROR "Submodule '${relative_path}' is not using the checked head. Please update all submodules with\ngit submodule update --init --force\nor run cmake with -DMANUAL_SUBMODULES=1,\n or if you want to build from latest master run cmake with -DEV_MODE,\n or run make devmode")
|
||||
if(NOT MANUAL_SUBMODULES)
|
||||
find_package(Git)
|
||||
if(GIT_FOUND)
|
||||
if(NOT DEV_MODE)
|
||||
function (check_submodule relative_path)
|
||||
execute_process(COMMAND git rev-parse "HEAD" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${relative_path} OUTPUT_VARIABLE localHead)
|
||||
execute_process(COMMAND git rev-parse "HEAD:${relative_path}" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE checkedHead)
|
||||
string(COMPARE EQUAL "${localHead}" "${checkedHead}" upToDate)
|
||||
if (upToDate)
|
||||
message(STATUS "Submodule '${relative_path}' is up-to-date")
|
||||
else()
|
||||
message(FATAL_ERROR "Submodule '${relative_path}' is not using the checked head. Please update all submodules with\ngit submodule update --init --force --recursive\nor run cmake with -DMANUAL_SUBMODULES=1,\n or if you want to build from latest master run cmake with -DDEV_MODE=ON,\n or run make devmode")
|
||||
endif()
|
||||
endfunction ()
|
||||
message(STATUS "Checking submodules")
|
||||
check_submodule(monero)
|
||||
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 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")
|
||||
message(FATAL_ERROR "Updating git submodule to master (-DDEV_MODE=ON) failed")
|
||||
endif()
|
||||
endfunction ()
|
||||
message(STATUS "Checking submodules")
|
||||
check_submodule(monero)
|
||||
else()
|
||||
execute_process(COMMAND cd monero && git checkout origin/master)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(monero)
|
||||
|
||||
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)
|
||||
@@ -93,12 +82,11 @@ endif()
|
||||
|
||||
# Include password strength library
|
||||
if(ENABLE_PASS_STRENGTH_METER)
|
||||
message(STATUS "Buildin with pass strength meter support.")
|
||||
message(STATUS "Building with pass strength meter support.")
|
||||
else()
|
||||
add_definitions(-DDISABLE_PASS_STRENGTH_METER)
|
||||
endif()
|
||||
|
||||
include(CheckTrezor) # Trezor support check
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
# force version update
|
||||
@@ -135,6 +123,9 @@ monero_gui_add_library(gui_version SOURCES version.js DEPENDS genversiongui)
|
||||
message(STATUS "${CMAKE_MODULE_PATH}")
|
||||
|
||||
# OpenSSL
|
||||
if(APPLE AND NOT OPENSSL_ROOT_DIR)
|
||||
execute_process(COMMAND brew --prefix openssl OUTPUT_VARIABLE OPENSSL_ROOT_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
find_package(OpenSSL REQUIRED)
|
||||
message(STATUS "OpenSSL: Version ${OPENSSL_VERSION}")
|
||||
message(STATUS "OpenSSL: include dir at ${OPENSSL_INCLUDE_DIR}")
|
||||
@@ -166,7 +157,13 @@ message(STATUS "libhidapi: libraries at ${HIDAPI_LIBRARIES}")
|
||||
if(DEBUG)
|
||||
set(Boost_DEBUG ON)
|
||||
endif()
|
||||
find_package(Boost 1.62 REQUIRED COMPONENTS
|
||||
if(APPLE AND NOT BOOST_ROOT)
|
||||
execute_process(COMMAND brew --prefix boost OUTPUT_VARIABLE BOOST_ROOT OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
if(MINGW)
|
||||
set(Boost_THREADAPI win32)
|
||||
endif()
|
||||
find_package(Boost 1.58 REQUIRED COMPONENTS
|
||||
system
|
||||
filesystem
|
||||
thread
|
||||
@@ -194,21 +191,6 @@ if(MINGW)
|
||||
string(REGEX MATCH "^[^/]:/[^/]*" msys2_install_path "${CMAKE_C_COMPILER}")
|
||||
message(STATUS "MSYS location: ${msys2_install_path}")
|
||||
set(CMAKE_INCLUDE_PATH "${msys2_install_path}/mingw${ARCH_WIDTH}/include")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/Qt/labs/folderlistmodel")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/Qt/labs/settings")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/QtGraphicalEffects")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/QtGraphicalEffects/private")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/QtMultimedia")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/QtQuick.2")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/QtQuick/Controls")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/QtQuick/Controls.2")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/QtQuick/Dialogs")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/QtQuick/Dialogs/Private")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/QtQuick/Layouts")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/QtQuick/PrivateWidgets")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/QtQuick/Templates.2")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/QtQuick/Window.2")
|
||||
link_directories("${msys2_install_path}/mingw${ARCH_WIDTH}/qml/QtQuick/XmlListModel")
|
||||
# This is necessary because otherwise CMake will make Boost libraries -lfoo
|
||||
# rather than a full path. Unfortunately, this makes the shared libraries get
|
||||
# linked due to a bug in CMake which misses putting -static flags around the
|
||||
@@ -221,35 +203,77 @@ endif()
|
||||
set(QT5_LIBRARIES
|
||||
Qt5Core
|
||||
Qt5Quick
|
||||
Qt5QuickControls2
|
||||
Qt5Widgets
|
||||
Qt5Gui
|
||||
Qt5Network
|
||||
Qt5Qml
|
||||
Qt5Multimedia
|
||||
Qt5Xml
|
||||
Qt5XmlPatterns
|
||||
Qt5Svg
|
||||
Qt5Xml
|
||||
)
|
||||
|
||||
if(WITH_SCANNER)
|
||||
list(APPEND QT5_LIBRARIES Qt5Multimedia)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
list(APPEND QT5_LIBRARIES Qt5MacExtras)
|
||||
|
||||
if(NOT CMAKE_PREFIX_PATH AND DEFINED ENV{CMAKE_PREFIX_PATH})
|
||||
message(STATUS "Using CMAKE_PREFIX_PATH environment variable: '$ENV{CMAKE_PREFIX_PATH}'")
|
||||
set(CMAKE_PREFIX_PATH $ENV{CMAKE_PREFIX_PATH})
|
||||
endif()
|
||||
if(NOT CMAKE_PREFIX_PATH)
|
||||
execute_process(COMMAND brew --prefix qt5 OUTPUT_VARIABLE QT5_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
list(APPEND CMAKE_PREFIX_PATH ${QT5_DIR})
|
||||
endif()
|
||||
|
||||
if(CMAKE_PREFIX_PATH)
|
||||
include_directories(${CMAKE_PREFIX_PATH}/include)
|
||||
set(CMAKE_BUILD_RPATH "${CMAKE_PREFIX_PATH}/lib")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
# TODO: drop this once we switch to Qt 5.14+
|
||||
pkg_check_modules(Qt5QmlModels_PKG_CONFIG QUIET Qt5QmlModels)
|
||||
if(Qt5QmlModels_PKG_CONFIG_FOUND)
|
||||
list(APPEND QT5_LIBRARIES Qt5QmlModels)
|
||||
endif()
|
||||
|
||||
# TODO: drop this once we switch to Qt 5.12+
|
||||
find_package(Qt5XmlPatterns QUIET)
|
||||
if(Qt5XmlPatterns_FOUND)
|
||||
list(APPEND QT5_LIBRARIES Qt5XmlPatterns)
|
||||
endif()
|
||||
|
||||
foreach(QT5_MODULE ${QT5_LIBRARIES})
|
||||
find_package(${QT5_MODULE} REQUIRED)
|
||||
include_directories(${${QT5_MODULE}_INCLUDE_DIRS})
|
||||
endforeach()
|
||||
|
||||
find_package(PkgConfig)
|
||||
if(PKGCONFIG_FOUND)
|
||||
pkg_check_modules(QT5_PKG_CONFIG ${QT5_LIBRARIES})
|
||||
pkg_check_modules(QT5_PKG_CONFIG REQUIRED ${QT5_LIBRARIES})
|
||||
|
||||
if(QT5_PKG_CONFIG_FOUND)
|
||||
set(QT5_PKG_CONFIG "QT5_PKG_CONFIG")
|
||||
if(STATIC)
|
||||
set(QT5_PKG_CONFIG "${QT5_PKG_CONFIG}_STATIC")
|
||||
endif()
|
||||
|
||||
set(QT5_LIBRARIES ${${QT5_PKG_CONFIG}_LIBRARIES} ${${QT5_PKG_CONFIG}_LDFLAGS_OTHER})
|
||||
include_directories(${${QT5_PKG_CONFIG}_INCLUDE_DIRS})
|
||||
link_directories(${${QT5_PKG_CONFIG}_LIBRARY_DIRS})
|
||||
if(QT5_PKG_CONFIG_FOUND)
|
||||
set(QT5_PKG_CONFIG "QT5_PKG_CONFIG")
|
||||
if(STATIC)
|
||||
set(QT5_PKG_CONFIG "${QT5_PKG_CONFIG}_STATIC")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
list(JOIN ${QT5_PKG_CONFIG}_LDFLAGS_OTHER " " ${QT5_PKG_CONFIG}_LDFLAGS_OTHER)
|
||||
list(JOIN ${QT5_PKG_CONFIG}_LIBRARIES " " ${QT5_PKG_CONFIG}_LIBRARIES)
|
||||
list(JOIN ${QT5_PKG_CONFIG}_INCLUDE_DIRS " " ${QT5_PKG_CONFIG}_INCLUDE_DIRS)
|
||||
|
||||
# temporal workaround for https://bugreports.qt.io/browse/QTBUG-80922
|
||||
STRING(REPLACE "${QT5_PKG_CONFIG_Qt5Core_PREFIX}" "${CMAKE_PREFIX_PATH}" ${QT5_PKG_CONFIG}_LDFLAGS_OTHER "${${QT5_PKG_CONFIG}_LDFLAGS_OTHER}")
|
||||
STRING(REPLACE "${QT5_PKG_CONFIG_Qt5Core_PREFIX}" "${CMAKE_PREFIX_PATH}" ${QT5_PKG_CONFIG}_LIBRARIES "${${QT5_PKG_CONFIG}_LIBRARIES}")
|
||||
STRING(REPLACE "${QT5_PKG_CONFIG_Qt5Core_PREFIX}" "${CMAKE_PREFIX_PATH}" ${QT5_PKG_CONFIG}_INCLUDE_DIRS "${${QT5_PKG_CONFIG}_INCLUDE_DIRS}")
|
||||
endif()
|
||||
|
||||
set(QT5_LIBRARIES ${${QT5_PKG_CONFIG}_LIBRARIES} ${${QT5_PKG_CONFIG}_LDFLAGS_OTHER})
|
||||
include_directories(${${QT5_PKG_CONFIG}_INCLUDE_DIRS})
|
||||
link_directories(${${QT5_PKG_CONFIG}_LIBRARY_DIRS})
|
||||
endif()
|
||||
|
||||
list(APPEND QT5_LIBRARIES
|
||||
@@ -260,37 +284,95 @@ list(APPEND QT5_LIBRARIES
|
||||
)
|
||||
|
||||
if(STATIC)
|
||||
set(QT5_LIBRARIES
|
||||
qtquickcontrols2plugin # has to be the first one, depends on Qt5QuickControls2
|
||||
${QT5_LIBRARIES}
|
||||
declarative_multimedia
|
||||
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/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/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)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Dialogs)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Dialogs/Private)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Layouts)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/PrivateWidgets)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Templates.2)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Window.2)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/XmlListModel)
|
||||
|
||||
set(QT5_EXTRA_LIBRARIES_LIST
|
||||
qtquicktemplates2plugin
|
||||
Qt5QuickTemplates2
|
||||
qtquickcontrols2plugin
|
||||
Qt5QuickControls2
|
||||
dialogplugin
|
||||
dialogsprivateplugin
|
||||
qmlfolderlistmodelplugin
|
||||
qmlsettingsplugin
|
||||
qmlxmllistmodelplugin
|
||||
qquicklayoutsplugin
|
||||
Qt5EventDispatcherSupport
|
||||
Qt5FontDatabaseSupport
|
||||
Qt5MultimediaQuick_p
|
||||
Qt5PacketProtocol
|
||||
Qt5ThemeSupport
|
||||
)
|
||||
|
||||
if(WITH_SCANNER)
|
||||
list(APPEND QT5_EXTRA_LIBRARIES_LIST
|
||||
declarative_multimedia
|
||||
Qt5MultimediaQuick_p
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND QT5_EXTRA_LIBRARIES_LIST
|
||||
qtgraphicaleffectsplugin
|
||||
qtgraphicaleffectsprivate
|
||||
qtquick2plugin
|
||||
qtquickcontrolsplugin
|
||||
qtquicktemplates2plugin
|
||||
widgetsplugin
|
||||
windowplugin
|
||||
)
|
||||
|
||||
if(MINGW)
|
||||
list(APPEND QT5_LIBRARIES qtfreetype)
|
||||
set(QT5_EXTRA_LIBRARIES)
|
||||
foreach(LIBRARY ${QT5_EXTRA_LIBRARIES_LIST})
|
||||
find_library(${LIBRARY}_LIBRARY ${LIBRARY} PATHS ${QT5_EXTRA_PATHS} REQUIRED)
|
||||
list(APPEND QT5_EXTRA_LIBRARIES ${${LIBRARY}_LIBRARY})
|
||||
endforeach()
|
||||
|
||||
if(MINGW)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
list(APPEND QT5_LIBRARIES D3D11 Dwrite D2d1)
|
||||
list(APPEND QT5_EXTRA_LIBRARIES D3D11 Dwrite D2d1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(QT5_LIBRARIES
|
||||
${QT5_EXTRA_LIBRARIES}
|
||||
${QT5_LIBRARIES}
|
||||
)
|
||||
|
||||
set(QT5_INTEGRATION_LIBRARIES_LIST
|
||||
Qt5EventDispatcherSupport
|
||||
Qt5PacketProtocol
|
||||
Qt5ThemeSupport
|
||||
Qt5FontDatabaseSupport
|
||||
)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
list(APPEND QT5_INTEGRATION_LIBRARIES_LIST
|
||||
Qt5XcbQpa
|
||||
xcb-static
|
||||
Qt5ServiceSupport
|
||||
Qt5GlxSupport
|
||||
)
|
||||
elseif(MINGW)
|
||||
list(APPEND QT5_INTEGRATION_LIBRARIES_LIST qtfreetype)
|
||||
endif()
|
||||
|
||||
foreach(LIBRARY ${QT5_INTEGRATION_LIBRARIES_LIST})
|
||||
find_library(${LIBRARY}_LIBRARY ${LIBRARY} PATHS ${QT5_EXTRA_PATHS} REQUIRED)
|
||||
list(APPEND QT5_LIBRARIES ${${LIBRARY}_LIBRARY})
|
||||
endforeach()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
pkg_check_modules(X11XCB_XCBGLX_FONTCONFIG REQUIRED x11-xcb xcb-glx fontconfig)
|
||||
list(APPEND QT5_LIBRARIES ${X11XCB_XCBGLX_FONTCONFIG_STATIC_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Using Boost include dir at ${Boost_INCLUDE_DIRS}")
|
||||
@@ -305,7 +387,9 @@ if(MINGW)
|
||||
else()
|
||||
set(ICU_LIBRARIES icuio icuin icuuc icudt icutu iconv)
|
||||
endif()
|
||||
elseif(APPLE OR OPENBSD OR ANDROID)
|
||||
elseif(APPLE)
|
||||
set(EXTRA_LIBRARIES "-framework AppKit")
|
||||
elseif(OPENBSD OR ANDROID)
|
||||
set(EXTRA_LIBRARIES "")
|
||||
elseif(FREEBSD)
|
||||
set(EXTRA_LIBRARIES execinfo)
|
||||
@@ -369,7 +453,12 @@ if (NOT (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VER
|
||||
endif()
|
||||
|
||||
# linker
|
||||
if (NOT (WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "GNU"))
|
||||
if (APPLE)
|
||||
add_linker_flag_if_supported(-Wl,-bind_at_load LD_SECURITY_FLAGS)
|
||||
add_linker_flag_if_supported(-Wl,-dead_strip LD_SECURITY_FLAGS)
|
||||
add_linker_flag_if_supported(-Wl,-dead_strip_dylibs LD_SECURITY_FLAGS)
|
||||
endif()
|
||||
if (NOT APPLE AND NOT (WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "GNU"))
|
||||
# Windows binaries die on startup with PIE when compiled with GCC
|
||||
add_linker_flag_if_supported(-pie LD_SECURITY_FLAGS)
|
||||
endif()
|
||||
@@ -384,13 +473,36 @@ if (noexecheap_SUPPORTED)
|
||||
set(LD_SECURITY_FLAGS "${LD_SECURITY_FLAGS} -Wl,-z,noexecheap")
|
||||
endif()
|
||||
|
||||
# some windows linker bits
|
||||
if (WIN32)
|
||||
add_linker_flag_if_supported(-Wl,--dynamicbase LD_SECURITY_FLAGS)
|
||||
add_linker_flag_if_supported(-Wl,--nxcompat LD_SECURITY_FLAGS)
|
||||
add_linker_flag_if_supported(-Wl,--high-entropy-va LD_SECURITY_FLAGS)
|
||||
endif()
|
||||
|
||||
if(STATIC)
|
||||
add_linker_flag_if_supported(-static-libgcc STATIC_FLAGS)
|
||||
add_linker_flag_if_supported(-static-libstdc++ STATIC_FLAGS)
|
||||
if(MINGW)
|
||||
add_linker_flag_if_supported(-static STATIC_FLAGS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that
|
||||
# is fixed in the code (Issue #847), force compiler to be conservative.
|
||||
add_c_flag_if_supported(-fno-strict-aliasing C_SECURITY_FLAGS)
|
||||
add_cxx_flag_if_supported(-fno-strict-aliasing CXX_SECURITY_FLAGS)
|
||||
|
||||
add_c_flag_if_supported(-fPIC C_SECURITY_FLAGS)
|
||||
add_cxx_flag_if_supported(-fPIC CXX_SECURITY_FLAGS)
|
||||
|
||||
message(STATUS "Using C security hardening flags: ${C_SECURITY_FLAGS}")
|
||||
message(STATUS "Using C++ security hardening flags: ${CXX_SECURITY_FLAGS}")
|
||||
message(STATUS "Using linker security hardening flags: ${LD_SECURITY_FLAGS}")
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_SECURITY_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_SECURITY_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LD_SECURITY_FLAGS}")
|
||||
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)
|
||||
@@ -404,12 +516,14 @@ if (HIDAPI_FOUND OR LibUSB_COMPILE_TEST_PASSED)
|
||||
endif()
|
||||
endif()
|
||||
if (WIN32)
|
||||
list(APPEND EXTRA_LIBRARIES setupapi Version)
|
||||
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)
|
||||
|
||||
# Required to make wallet_merged build before the gui
|
||||
add_dependencies(monero-gui wallet_merged)
|
||||
|
||||
|
||||
44
DEPLOY.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# macOS:
|
||||
|
||||
Use macOS 10.12 - 10.13 for better backwards compability.
|
||||
|
||||
1. `HOMEBREW_OPTFLAGS="-march=core2" HOMEBREW_OPTIMIZATION_LEVEL="O0" brew install boost zmq libpgm miniupnpc libsodium expat libunwind-headers protobuf libgcrypt`
|
||||
|
||||
2. `HOMEBREW_OPTFLAGS="-march=core2" HOMEBREW_OPTIMIZATION_LEVEL="O0" brew install --HEAD hidapi`
|
||||
|
||||
3. Get the latest LTS from here: https://www.qt.io/offline-installers and install
|
||||
|
||||
4. `git clone --recursive -b v0.X.Y.Z --depth 1 https://github.com/monero-project/monero-gui`
|
||||
|
||||
5. `CMAKE_PREFIX_PATH=~/Qt5.12.8/5.12.8/clang_64 make release`
|
||||
|
||||
6. `cd build/release && make deploy`
|
||||
|
||||
7. Replace the `monerod` binary inside `monero-wallet-gui.app/Contents/MacOS/` with one built using deterministic builds / gitian.
|
||||
|
||||
## Codesigning and notarizing
|
||||
|
||||
1. Save the following text as `entitlements.plist`
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.disable-executable-page-protection</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
2. `codesign --deep --force --verify --verbose --options runtime --timestamp --entitlements entitlements.plist --sign 'XXXXXXXXXX' monero-wallet-gui.app`
|
||||
|
||||
You can check if this step worked by using `codesign -dvvv monero-wallet-gui.app`
|
||||
|
||||
3. `hdiutil create -fs HFS+ -srcfolder monero-gui-v0.X.Y.Z -volname monero-wallet-gui monero-gui-mac-x64-v0.X.Y.Z.dmg`
|
||||
|
||||
4. `xcrun altool -t osx --file monero-gui-mac-x64-v0.X.Y.Z.dmg --primary-bundle-id org.monero-project.monero-wallet-gui.dmg --notarize-app --username email@address.org`
|
||||
|
||||
5. `xcrun altool --notarization-info aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeee -u email@address.org`
|
||||
|
||||
6. `xcrun stapler staple -v monero-gui-mac-x64-v0.X.Y.Z.dmg`
|
||||
207
Dockerfile.linux
Normal file
@@ -0,0 +1,207 @@
|
||||
FROM ubuntu:16.04
|
||||
|
||||
ARG THREADS=1
|
||||
|
||||
RUN apt update
|
||||
|
||||
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 && \
|
||||
cd xorgproto && \
|
||||
git reset --hard c62e8203402cafafa5ba0357b6d1c019156c9f36 && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b 1.12 --depth 1 https://gitlab.freedesktop.org/xorg/proto/xcbproto && \
|
||||
cd xcbproto && \
|
||||
git reset --hard 6398e42131eedddde0d98759067dde933191f049 && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
|
||||
make -j$THREADS && \
|
||||
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 && \
|
||||
cd libxau && \
|
||||
git reset --hard d9443b2c57b512cfb250b35707378654d86c7dea && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
|
||||
make -j$THREADS && \
|
||||
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 && \
|
||||
cd libxcb && \
|
||||
git reset --hard d34785a34f28fa6a00f8ce00d87e3132ff0f6467 && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b v1.2.11 --depth 1 https://github.com/madler/zlib && \
|
||||
cd zlib && \
|
||||
git reset --hard cacf7f1d4e3d44d871b605da3b647f07d718623f && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b VER-2-10-2 --depth 1 https://git.sv.nongnu.org/r/freetype/freetype2.git && \
|
||||
cd freetype2 && \
|
||||
git reset --hard 132f19b779828b194b3fede187cee719785db4d8 && \
|
||||
./autogen.sh && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --with-zlib=no && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b R_2_2_9 --depth 1 https://github.com/libexpat/libexpat && \
|
||||
cd libexpat/expat && \
|
||||
git reset --hard a7bc26b69768f7fb24f0c7976fae24b157b85b13 && \
|
||||
./buildconf.sh && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static && \
|
||||
make -j$THREADS && \
|
||||
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 && \
|
||||
cd fontconfig && \
|
||||
git reset --hard b1df1101a643ae16cdfa1d83b939de2497b1bf27 && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static --sysconfdir=/etc --localstatedir=/var && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b release-64-2 --depth 1 https://github.com/unicode-org/icu && \
|
||||
cd icu/icu4c/source && \
|
||||
git reset --hard e2d85306162d3a0691b070b4f0a73e4012433444 && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --disable-tests --disable-samples && \
|
||||
make -j$THREADS && \
|
||||
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 && \
|
||||
echo "9995e192e68528793755692917f9eb6422f3052a53c5e13ba278a228af6c7acf boost_1_73_0.tar.gz" > hashsum.txt && \
|
||||
sha256sum -c hashsum.txt && \
|
||||
tar -xzf boost_1_73_0.tar.gz && \
|
||||
rm boost_1_73_0.tar.gz && \
|
||||
cd boost_1_73_0 && \
|
||||
./bootstrap.sh && \
|
||||
./b2 --with-atomic --with-system --with-filesystem --with-thread --with-date_time --with-chrono --with-regex --with-serialization --with-program_options --with-locale variant=release link=static runtime-link=static cflags='-fPIC' cxxflags='-fPIC' install -a --prefix=/usr && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN wget https://www.openssl.org/source/openssl-1.1.1g.tar.gz && \
|
||||
echo "ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46 openssl-1.1.1g.tar.gz" > hashsum.txt && \
|
||||
sha256sum -c hashsum.txt && \
|
||||
tar -xzf openssl-1.1.1g.tar.gz && \
|
||||
rm openssl-1.1.1g.tar.gz && \
|
||||
cd openssl-1.1.1g && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./config no-asm no-shared no-zlib-dynamic --openssldir=/usr && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y libgl1-mesa-dev libglib2.0-dev libxkbcommon-dev && \
|
||||
wget 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 && \
|
||||
sed -ri s/\(Libs:.*\)/\\1\ -lexpat/ /usr/local/lib/pkgconfig/fontconfig.pc && \
|
||||
sed -ri s/\(Libs:.*\)/\\1\ -lz/ /usr/local/lib/pkgconfig/freetype2.pc && \
|
||||
sed -ri s/\(Libs:.*\)/\\1\ -lXau/ /usr/local/lib/pkgconfig/xcb.pc && \
|
||||
./configure --prefix=/usr -platform linux-g++-64 -opensource -confirm-license -release -static -no-avx \
|
||||
-opengl desktop -qpa xcb -system-freetype -fontconfig -glib \
|
||||
-no-dbus -no-openssl -no-sql-sqlite -no-use-gold-linker \
|
||||
-qt-harfbuzz -qt-libjpeg -qt-libpng -qt-pcre -qt-zlib \
|
||||
-skip qt3d -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 gamepad -skip serialbus -skip location -skip webengine \
|
||||
-nomake examples -nomake tests -nomake tools && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
cd qttools/src/linguist/lrelease && \
|
||||
../../../../qtbase/bin/qmake && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
cd ../../../.. && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y libudev-dev && \
|
||||
git clone -b v1.0.23 --depth 1 https://github.com/libusb/libusb && \
|
||||
cd libusb && \
|
||||
git reset --hard e782eeb2514266f6738e242cdcb18e3ae1ed06fa && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b hidapi-0.9.0 --depth 1 https://github.com/libusb/hidapi && \
|
||||
cd hidapi && \
|
||||
git reset --hard 7da5cc91fc0d2dbe4df4f08cd31f6ca1a262418f && \
|
||||
./bootstrap && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b libX11-1.6.9 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libx11 && \
|
||||
cd libx11 && \
|
||||
git reset --hard db7cca17ad7807e92a928da9d4c68a00f4836da2 && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b libXext-1.3.4 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxext && \
|
||||
cd libxext && \
|
||||
git reset --hard ebb167f34a3514783966775fb12573c4ed209625 && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
|
||||
make -j$THREADS && \
|
||||
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 && \
|
||||
cd libzmq && \
|
||||
git reset --hard a84ffa12b2eb3569ced199660bac5ad128bff1f0 && \
|
||||
./autogen.sh && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --disable-libunwind --with-libsodium && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b libgpg-error-1.38 --depth 1 git://git.gnupg.org/libgpg-error.git && \
|
||||
cd libgpg-error && \
|
||||
git reset --hard 71d278824c5fe61865f7927a2ed1aa3115f9e439 && \
|
||||
./autogen.sh && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --disable-doc --disable-tests && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b libgcrypt-1.8.5 --depth 1 git://git.gnupg.org/libgcrypt.git && \
|
||||
cd libgcrypt && \
|
||||
git reset --hard 56606331bc2a80536db9fc11ad53695126007298 && \
|
||||
./autogen.sh && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --disable-doc && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b v3.10.0 --depth 1 https://github.com/protocolbuffers/protobuf && \
|
||||
cd protobuf && \
|
||||
git reset --hard 6d4e7fd7966c989e38024a8ea693db83758944f1 && \
|
||||
./autogen.sh && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --enable-static --disable-shared && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y cmake libusb-1.0-0-dev
|
||||
71
Dockerfile.windows
Normal file
@@ -0,0 +1,71 @@
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ARG THREADS=1
|
||||
|
||||
RUN apt update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt install -y build-essential cmake g++-mingw-w64 gettext git libtool pkg-config \
|
||||
python && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN update-alternatives --set x86_64-w64-mingw32-g++ $(which x86_64-w64-mingw32-g++-posix) && \
|
||||
update-alternatives --set x86_64-w64-mingw32-gcc $(which x86_64-w64-mingw32-gcc-posix)
|
||||
|
||||
RUN git clone -b v0.17.0.0 --depth 1 https://github.com/monero-project/monero && \
|
||||
cd monero && \
|
||||
git reset --hard d27d4526fe89b7cdeb4b296280c4a6cf7efe21f8 && \
|
||||
cp -a contrib/depends / && \
|
||||
cd .. && \
|
||||
rm -rf 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 && \
|
||||
./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 \
|
||||
-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 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 install && \
|
||||
cd qttools/src/linguist/lrelease && \
|
||||
../../../../qtbase/bin/qmake && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
cd ../../../.. && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b libgpg-error-1.38 --depth 1 git://git.gnupg.org/libgpg-error.git && \
|
||||
cd libgpg-error && \
|
||||
git reset --hard 71d278824c5fe61865f7927a2ed1aa3115f9e439 && \
|
||||
./autogen.sh && \
|
||||
./configure --disable-shared --enable-static --disable-doc --disable-tests \
|
||||
--host=x86_64-w64-mingw32 --prefix=/depends/x86_64-w64-mingw32 && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
cd .. && \
|
||||
rm -rf libgpg-error
|
||||
|
||||
RUN git clone -b libgcrypt-1.8.5 --depth 1 git://git.gnupg.org/libgcrypt.git && \
|
||||
cd libgcrypt && \
|
||||
git reset --hard 56606331bc2a80536db9fc11ad53695126007298 && \
|
||||
./autogen.sh && \
|
||||
./configure --disable-shared --enable-static --disable-doc \
|
||||
--host=x86_64-w64-mingw32 --prefix=/depends/x86_64-w64-mingw32 \
|
||||
--with-gpg-error-prefix=/depends/x86_64-w64-mingw32 && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
cd .. && \
|
||||
rm -rf libgcrypt
|
||||
@@ -64,7 +64,6 @@ Rectangle {
|
||||
signal addressBookClicked()
|
||||
signal miningClicked()
|
||||
signal signClicked()
|
||||
signal merchantClicked()
|
||||
signal accountClicked()
|
||||
|
||||
function selectItem(pos) {
|
||||
@@ -72,7 +71,6 @@ Rectangle {
|
||||
if(pos === "History") menuColumn.previousButton = historyButton
|
||||
else if(pos === "Transfer") menuColumn.previousButton = transferButton
|
||||
else if(pos === "Receive") menuColumn.previousButton = receiveButton
|
||||
else if(pos === "Merchant") menuColumn.previousButton = merchantButton
|
||||
else if(pos === "AddressBook") menuColumn.previousButton = addressBookButton
|
||||
else if(pos === "Mining") menuColumn.previousButton = miningButton
|
||||
else if(pos === "TxKey") menuColumn.previousButton = txkeyButton
|
||||
@@ -223,7 +221,7 @@ Rectangle {
|
||||
MoneroComponents.Label {
|
||||
fontSize: 16
|
||||
visible: isSyncing
|
||||
text: qsTr("Syncing...")
|
||||
text: qsTr("Syncing...") + translationManager.emptyString
|
||||
color: MoneroComponents.Style.blackTheme ? "white" : "black"
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 20
|
||||
@@ -265,6 +263,10 @@ Rectangle {
|
||||
anchors.leftMargin: 58
|
||||
anchors.baseline: currencyLabel.baseline
|
||||
color: MoneroComponents.Style.blackTheme ? "white" : "black"
|
||||
Binding on color {
|
||||
when: balancePart1MouseArea.containsMouse || balancePart2MouseArea.containsMouse
|
||||
value: MoneroComponents.Style.orange
|
||||
}
|
||||
text: {
|
||||
if (persistentSettings.fiatPriceEnabled && persistentSettings.fiatPriceToggle) {
|
||||
return balanceFiatString.split('.')[0] + "."
|
||||
@@ -286,14 +288,6 @@ Rectangle {
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: {
|
||||
balancePart1.color = MoneroComponents.Style.orange
|
||||
balancePart2.color = MoneroComponents.Style.orange
|
||||
}
|
||||
onExited: {
|
||||
balancePart1.color = Qt.binding(function() { return MoneroComponents.Style.blackTheme ? "white" : "black" })
|
||||
balancePart2.color = Qt.binding(function() { return MoneroComponents.Style.blackTheme ? "white" : "black" })
|
||||
}
|
||||
onClicked: {
|
||||
console.log("Copied to clipboard");
|
||||
clipboard.setText(balancePart1.text + balancePart2.text);
|
||||
@@ -307,7 +301,7 @@ Rectangle {
|
||||
anchors.left: balancePart1.right
|
||||
anchors.leftMargin: 2
|
||||
anchors.baseline: currencyLabel.baseline
|
||||
color: MoneroComponents.Style.blackTheme ? "white" : "black"
|
||||
color: balancePart1.color
|
||||
text: {
|
||||
if (persistentSettings.fiatPriceEnabled && persistentSettings.fiatPriceToggle) {
|
||||
return balanceFiatString.split('.')[1]
|
||||
@@ -317,11 +311,10 @@ Rectangle {
|
||||
}
|
||||
font.pixelSize: 16
|
||||
MouseArea {
|
||||
id: balancePart2MouseArea
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: balancePart1MouseArea.entered()
|
||||
onExited: balancePart1MouseArea.exited()
|
||||
onClicked: balancePart1MouseArea.clicked(mouse)
|
||||
}
|
||||
}
|
||||
@@ -454,30 +447,6 @@ Rectangle {
|
||||
anchors.leftMargin: 20
|
||||
}
|
||||
|
||||
// ------------- Merchant tab ---------------
|
||||
|
||||
MoneroComponents.MenuButton {
|
||||
id: merchantButton
|
||||
visible: appWindow.walletMode >= 2
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text: qsTr("Merchant") + translationManager.emptyString
|
||||
symbol: qsTr("U") + translationManager.emptyString
|
||||
under: receiveButton
|
||||
onClicked: {
|
||||
parent.previousButton.checked = false
|
||||
parent.previousButton = merchantButton
|
||||
panel.merchantClicked()
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.MenuButtonDivider {
|
||||
visible: merchantButton.present && appWindow.walletMode >= 2
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 20
|
||||
}
|
||||
|
||||
// ------------- History tab ---------------
|
||||
|
||||
MoneroComponents.MenuButton {
|
||||
|
||||
19
Makefile
@@ -6,7 +6,7 @@ ifneq ($(dotgit), .git/config)
|
||||
endif
|
||||
|
||||
subbuilddir:=$(shell echo `uname | sed -e 's|[:/\\ \(\)]|_|g'`/`git branch | grep '\* ' | cut -f2- -d' '| sed -e 's|[:/\\ \(\)]|_|g'`)
|
||||
ifeq ($(USE_SINGLE_BUILDDIR),)
|
||||
ifeq ($(USE_SINGLE_BUILDDIR), OFF)
|
||||
builddir := build/"$(subbuilddir)"
|
||||
topdir := ../../../..
|
||||
deldirs := $(builddir)
|
||||
@@ -21,6 +21,11 @@ default:
|
||||
mkdir -p build && cd build && cmake -D ARCH="x86-64" -D DEV_MODE=$(or ${DEV_MODE},OFF) -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release .. && $(MAKE)
|
||||
debug:
|
||||
mkdir -p build && cd build && cmake -D DEV_MODE=$(or ${DEV_MODE},ON) .. && $(MAKE) VERBOSE=1
|
||||
|
||||
depends:
|
||||
mkdir -p build/$(target)/release
|
||||
cd build/$(target)/release && cmake -D STATIC=ON -D DEV_MODE=$(or ${DEV_MODE},OFF) -D BUILD_TAG=$(tag) -D CMAKE_BUILD_TYPE=Release -D CMAKE_TOOLCHAIN_FILE=$(root)/$(target)/share/toolchain.cmake ../../.. && $(MAKE)
|
||||
|
||||
devmode:
|
||||
mkdir -p build && cd build && cmake -D ARCH="x86-64" -D DEV_MODE=$(or ${DEV_MODE},ON) -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release .. && $(MAKE)
|
||||
clean:
|
||||
@@ -28,13 +33,21 @@ clean:
|
||||
scanner:
|
||||
mkdir -p build && cd build && cmake -D ARCH="x86-64" -D DEV_MODE=$(or ${DEV_MODE},ON) -D WITH_SCANNER=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release .. && $(MAKE)
|
||||
|
||||
release:
|
||||
mkdir -p $(builddir)/release && cd $(builddir)/release && cmake -D DEV_MODE=$(or ${DEV_MODE},OFF) -D ARCH="x86-64" -D CMAKE_BUILD_TYPE=Release $(topdir) && $(MAKE)
|
||||
|
||||
release-static:
|
||||
mkdir -p $(builddir)/release && cd $(builddir)/release && cmake -D STATIC=ON -D DEV_MODE=$(or ${DEV_MODE},OFF) -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release $(topdir) && $(MAKE)
|
||||
|
||||
debug-static-win64:
|
||||
mkdir -p $(builddir)/debug && cd $(builddir)/debug && cmake -D STATIC=ON -G "MSYS Makefiles" -D DEV_MODE=$(or ${DEV_MODE},ON) -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Debug -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=$(topdir)/cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=$(cd $MINGW_PREFIX/.. && pwd -W) -D MINGW=ON $(topdir) && $(MAKE)
|
||||
mkdir -p $(builddir)/debug && cd $(builddir)/debug && cmake -D STATIC=ON -G "MSYS Makefiles" -D DEV_MODE=$(or ${DEV_MODE},ON) -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Debug -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=$(topdir)/cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=$(shell cd ${MINGW_PREFIX}/.. && pwd -W) -D MINGW=ON $(topdir) && $(MAKE)
|
||||
|
||||
debug-static-mac64:
|
||||
mkdir -p $(builddir)/debug
|
||||
cd $(builddir)/debug && cmake -D STATIC=ON -D DEV_MODE=$(or ${DEV_MODE},ON) -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="mac-x64" $(topdir) && $(MAKE)
|
||||
|
||||
release-static-win64:
|
||||
mkdir -p $(builddir)/release && cd $(builddir)/release && cmake -D STATIC=ON -G "MSYS Makefiles" -D DEV_MODE=$(or ${DEV_MODE},OFF) -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=$(topdir)/cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=$(cd $MINGW_PREFIX/.. && pwd -W) -D MINGW=ON $(topdir) && $(MAKE)
|
||||
mkdir -p $(builddir)/release && cd $(builddir)/release && cmake -D STATIC=ON -G "MSYS Makefiles" -D DEV_MODE=$(or ${DEV_MODE},OFF) -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=$(topdir)/cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=$(shell cd ${MINGW_PREFIX}/.. && pwd -W) -D MINGW=ON $(topdir) && $(MAKE)
|
||||
|
||||
release-win64:
|
||||
mkdir -p $(builddir)/release && cd $(builddir)/release && cmake -D STATIC=OFF -G "MSYS Makefiles" -D DEV_MODE=$(or ${DEV_MODE},OFF) -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=$(topdir)/cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=$(shell cd ${MINGW_PREFIX}/.. && pwd -W) -D MINGW=ON $(topdir) && $(MAKE)
|
||||
|
||||
@@ -50,7 +50,10 @@ Rectangle {
|
||||
property alias contentHeight: mainFlickable.contentHeight
|
||||
property alias flickable: mainFlickable
|
||||
|
||||
property Transfer transferView: Transfer { }
|
||||
property Transfer transferView: Transfer {
|
||||
onPaymentClicked: root.paymentClicked(address, paymentId, amount, mixinCount, priority, description)
|
||||
onSweepUnmixableClicked: root.sweepUnmixableClicked()
|
||||
}
|
||||
property Receive receiveView: Receive { }
|
||||
property Merchant merchantView: Merchant { }
|
||||
property TxKey txkeyView: TxKey { }
|
||||
@@ -260,18 +263,4 @@ Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: borderLeft.right
|
||||
}
|
||||
|
||||
/* connect "payment" click */
|
||||
Connections {
|
||||
ignoreUnknownSignals: false
|
||||
target: transferView
|
||||
onPaymentClicked : {
|
||||
console.log("MiddlePanel: paymentClicked")
|
||||
paymentClicked(address, paymentId, amount, mixinCount, priority, description)
|
||||
}
|
||||
onSweepUnmixableClicked : {
|
||||
console.log("MiddlePanel: sweepUnmixableClicked")
|
||||
sweepUnmixableClicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
158
README.md
@@ -36,19 +36,17 @@ As with many development projects, the repository on Github is considered to be
|
||||
|
||||
Monero is a 100% community-sponsored endeavor. If you want to join our efforts, the easiest thing you can do is support the project financially. Both Monero and Bitcoin donations can be made to **donate.getmonero.org** if using a client that supports the [OpenAlias](https://openalias.org) standard.
|
||||
|
||||
The Monero donation address is: `44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A` (viewkey: `f359631075708155cc3d92a32b75a7d02a5dcf27756707b47a2b31b21c389501`)
|
||||
The Monero donation address is: `888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H` (viewkey: `f359631075708155cc3d92a32b75a7d02a5dcf27756707b47a2b31b21c389501`)
|
||||
|
||||
The Bitcoin donation address is: `1KTexdemPdxSBcG55heUuTjDRYqbC5ZL8H`
|
||||
|
||||
GUI development funding and/or some supporting services are also graciously provided by sponsors:
|
||||
GUI development funding and/or some supporting services are also graciously provided by [sponsors](https://www.getmonero.org/community/sponsorships/):
|
||||
|
||||
[<img width="80" src="https://static.getmonero.org/images/sponsors/mymonero.png"/>](https://mymonero.com)
|
||||
[<img width="150" src="https://static.getmonero.org/images/sponsors/kitware.png?1"/>](http://kitware.com)
|
||||
[<img width="100" src="https://static.getmonero.org/images/sponsors/dome9.png"/>](http://dome9.com)
|
||||
[<img width="150" src="https://static.getmonero.org/images/sponsors/araxis.png"/>](http://araxis.com)
|
||||
[<img width="150" src="https://static.getmonero.org/images/sponsors/jetbrains.png"/>](http://www.jetbrains.com/)
|
||||
[<img width="150" src="https://static.getmonero.org/images/sponsors/navicat.png"/>](http://www.navicat.com/)
|
||||
[<img width="150" src="https://static.getmonero.org/images/sponsors/symas.png"/>](http://www.symas.com/)
|
||||
[<img width="150" src="https://www.getmonero.org/img/sponsors/tarilabs.png"/>](https://tarilabs.com/)
|
||||
[<img width="150" src="https://www.getmonero.org/img/sponsors/globee.png"/>](https://globee.com/)
|
||||
[<img width="150" src="https://www.getmonero.org/img/sponsors/symas.png"/>](https://www.symas.com/)
|
||||
[<img width="150" src="https://www.getmonero.org/img/sponsors/forked_logo.png"/>](https://www.forked.net/)
|
||||
[<img width="150" src="https://www.getmonero.org/img/sponsors/macstadium.png"/>](https://www.macstadium.com/)
|
||||
|
||||
There are also several mining pools that kindly donate a portion of their fees, [a list of them can be found on our Bitcointalk post](https://bitcointalk.org/index.php?topic=583449.0).
|
||||
|
||||
@@ -62,13 +60,19 @@ Do you speak a second language and would like to help translate the Monero GUI?
|
||||
|
||||
If you need help/support or any info you can contact the localization workgroup on the IRC channel #monero-translations (relayed on matrix/riot and MatterMost) or by email at translate[at]getmonero[dot]org. For more info about the Localization workgroup: [github.com/monero-ecosystem/monero-translations](https://github.com/monero-ecosystem/monero-translations)
|
||||
|
||||
Status of the translations:
|
||||
<a href="https://translate.getmonero.org/engage/monero/?utm_source=widget">
|
||||
<img src="https://translate.getmonero.org/widgets/monero/-/gui-wallet/horizontal-auto.svg" alt="Translation status" />
|
||||
</a>
|
||||
|
||||
## Installing the Monero GUI from a package
|
||||
|
||||
Packages are available for
|
||||
|
||||
* Arch Linux: pacman -S monero-gui
|
||||
* Void Linux: xbps-install -S monero-core
|
||||
* GuixSD: guix package -i monero-core
|
||||
* Arch Linux: [monero-gui](https://www.archlinux.org/packages/community/x86_64/monero-gui/)
|
||||
* 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`
|
||||
|
||||
Packaging for your favorite distribution would be a welcome contribution!
|
||||
|
||||
@@ -76,6 +80,50 @@ 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)
|
||||
|
||||
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
|
||||
```
|
||||
3. Prepare build environment
|
||||
```
|
||||
cd monero-gui
|
||||
docker build --tag monero:build-env-windows --build-arg THREADS=4 --file Dockerfile.windows .
|
||||
```
|
||||
\* `4` - number of CPU threads to use
|
||||
|
||||
4. Build
|
||||
```
|
||||
docker run --rm -it -v <MONERO_GUI_DIR_FULL_PATH>:/monero-gui -w /monero-gui monero:build-env-windows sh -c 'make depends root=/depends target=x86_64-w64-mingw32 tag=win-x64 -j4'
|
||||
```
|
||||
\* `<MONERO_GUI_DIR_FULL_PATH>` - absolute path to `monero-gui` directory
|
||||
\* `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)
|
||||
|
||||
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
|
||||
```
|
||||
3. Prepare build environment
|
||||
```
|
||||
cd monero-gui
|
||||
docker build --tag monero:build-env-linux --build-arg THREADS=4 --file Dockerfile.linux .
|
||||
```
|
||||
\* `4` - number of CPU threads to use
|
||||
|
||||
4. Build
|
||||
```
|
||||
docker run --rm -it -v <MONERO_GUI_DIR_FULL_PATH>:/monero-gui -w /monero-gui monero:build-env-linux sh -c 'make release-static -j4'
|
||||
```
|
||||
\* `<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
|
||||
|
||||
### On Linux:
|
||||
|
||||
(Tested on Ubuntu 17.10 x64, Ubuntu 18.04 x64 and Gentoo x64)
|
||||
@@ -84,15 +132,15 @@ Packaging for your favorite distribution would be a welcome contribution!
|
||||
|
||||
- For Debian distributions (Debian, Ubuntu, Mint, Tails...)
|
||||
|
||||
`sudo apt 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`
|
||||
`sudo apt 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 libgcrypt20-dev`
|
||||
|
||||
- For Gentoo
|
||||
|
||||
`sudo emerge app-arch/xz-utils app-doc/doxygen dev-cpp/gtest dev-libs/boost dev-libs/expat dev-libs/openssl dev-util/cmake media-gfx/graphviz net-dns/unbound net-libs/ldns net-libs/miniupnpc net-libs/zeromq sys-libs/libunwind dev-libs/libsodium dev-libs/hidapi`
|
||||
`sudo emerge app-arch/xz-utils app-doc/doxygen dev-cpp/gtest dev-libs/boost dev-libs/expat dev-libs/openssl dev-util/cmake media-gfx/graphviz net-dns/unbound net-libs/ldns net-libs/miniupnpc net-libs/zeromq sys-libs/libunwind dev-libs/libsodium dev-libs/hidapi dev-libs/libgcrypt`
|
||||
|
||||
- For Fedora
|
||||
|
||||
`sudo dnf install make automake cmake gcc-c++ boost-devel miniupnpc-devel graphviz doxygen unbound-devel libunwind-devel pkgconfig openssl-devel libcurl-devel hidapi-devel libusb-devel zeromq-devel`
|
||||
`sudo dnf install make automake cmake gcc-c++ boost-devel miniupnpc-devel graphviz doxygen unbound-devel libunwind-devel pkgconfig openssl-devel libcurl-devel hidapi-devel libusb-devel zeromq-devel libgcrypt-devel`
|
||||
|
||||
2. Install Qt:
|
||||
|
||||
@@ -125,14 +173,18 @@ The following instructions will fetch Qt from your distribution's repositories i
|
||||
|
||||
3. Clone repository
|
||||
|
||||
`git clone https://github.com/monero-project/monero-gui.git`
|
||||
```
|
||||
git clone --recursive https://github.com/monero-project/monero-gui.git
|
||||
cd monero-gui
|
||||
```
|
||||
|
||||
4. Build
|
||||
|
||||
```
|
||||
cd monero-gui
|
||||
QT_SELECT=5 ./build.sh
|
||||
make release -j4
|
||||
```
|
||||
\* `4` - number of CPU threads to use
|
||||
\* Add `CMAKE_PREFIX_PATH` enviroment variable to set a custom Qt install directory, e.g. `CMAKE_PREFIX_PATH=$HOME/Qt/5.9.7/gcc_64 make release -j4`
|
||||
|
||||
The executable can be found in the build/release/bin folder.
|
||||
|
||||
@@ -144,57 +196,30 @@ The executable can be found in the build/release/bin folder.
|
||||
|
||||
3. Install [monero](https://github.com/monero-project/monero) dependencies:
|
||||
|
||||
`brew install boost`
|
||||
|
||||
`brew install openssl` - to install openssl headers
|
||||
|
||||
`brew install pkgconfig`
|
||||
|
||||
`brew install cmake`
|
||||
|
||||
`brew install zeromq`
|
||||
|
||||
*Note*: If cmake can not find zmq.hpp file on OS X, installing `zmq.hpp` from https://github.com/zeromq/cppzmq to `/usr/local/include` should fix that error.
|
||||
`brew install boost hidapi zmq libpgm miniupnpc ldns expat libunwind-headers protobuf libgcrypt`
|
||||
|
||||
4. Install Qt:
|
||||
|
||||
`brew install qt5` (or download QT 5.9.7+ from [qt.io](https://www.qt.io/download-open-source/))
|
||||
|
||||
If you have an older version of Qt installed via homebrew, you can force it to use 5.x like so:
|
||||
|
||||
`brew link --force --overwrite qt5`
|
||||
5. Grab an up-to-date copy of the monero-gui repository
|
||||
|
||||
5. Add the Qt bin directory to your path
|
||||
```
|
||||
git clone --recursive https://github.com/monero-project/monero-gui.git
|
||||
cd monero-gui
|
||||
```
|
||||
|
||||
- Example for Qt: `export PATH=$PATH:$HOME/Qt/5.9.7/clang_64/bin`
|
||||
- Example for Homebrew: `export PATH=$PATH:/usr/local/opt/qt/bin`
|
||||
6. Start the build
|
||||
|
||||
6. Grab an up-to-date copy of the monero-gui repository
|
||||
|
||||
`git clone https://github.com/monero-project/monero-gui.git`
|
||||
|
||||
7. Go into the repository
|
||||
|
||||
`cd monero-gui`
|
||||
|
||||
8. Start the build
|
||||
|
||||
`./build.sh`
|
||||
```
|
||||
make release -j4
|
||||
```
|
||||
\* `4` - number of CPU threads to use
|
||||
\* Add `CMAKE_PREFIX_PATH` enviroment variable to set a custom Qt install directory, e.g. `CMAKE_PREFIX_PATH=$HOME/Qt/5.9.7/clang_64 make release -j4`
|
||||
|
||||
The executable can be found in the `build/release/bin` folder.
|
||||
|
||||
**Note:** Workaround for "ERROR: Xcode not set up properly"
|
||||
|
||||
Edit `$HOME/Qt/5.9.7/clang_64/mkspecs/features/mac/default_pre.prf`
|
||||
|
||||
replace
|
||||
`isEmpty($$list($$system("/usr/bin/xcrun -find xcrun 2>/dev/null")))`
|
||||
|
||||
with
|
||||
`isEmpty($$list($$system("/usr/bin/xcrun -find xcodebuild 2>/dev/null")))`
|
||||
|
||||
More info: http://stackoverflow.com/a/35098040/1683164
|
||||
|
||||
For building an application bundle see `DEPLOY.md`.
|
||||
|
||||
### On Windows:
|
||||
|
||||
@@ -207,7 +232,7 @@ The Monero GUI on Windows is 64 bits only; 32-bit Windows GUI builds are not off
|
||||
3. Install MSYS2 packages for Monero dependencies; the needed 64-bit packages have `x86_64` in their names
|
||||
|
||||
```
|
||||
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
|
||||
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`
|
||||
@@ -235,18 +260,17 @@ The Monero GUI on Windows is 64 bits only; 32-bit Windows GUI builds are not off
|
||||
6. Clone repository
|
||||
|
||||
```
|
||||
git clone https://github.com/monero-project/monero-gui.git
|
||||
git clone --recursive https://github.com/monero-project/monero-gui.git
|
||||
cd monero-gui
|
||||
```
|
||||
|
||||
7. Build
|
||||
|
||||
```
|
||||
cd monero-gui
|
||||
source ./build.sh release-static
|
||||
cd build
|
||||
make release-win64 -j4
|
||||
cd build/release
|
||||
make deploy
|
||||
```
|
||||
\* `4` - number of CPU threads to use
|
||||
|
||||
**Note:** The use of `source` above is a dirty workaround for a suspected bug in the current QT version 5.11.2-3 available in the MSYS2 packaging system, see https://github.com/monero-project/monero-gui/issues/1559 for more info.
|
||||
|
||||
The executable can be found in the `.\release\bin` directory.
|
||||
The executable can be found in the `.\bin` directory.
|
||||
|
||||
7
build.sh
@@ -100,11 +100,8 @@ fi
|
||||
|
||||
# force version update
|
||||
get_tag
|
||||
echo "var GUI_VERSION = \"$TAGNAME\"" > version.js
|
||||
pushd "$MONERO_DIR"
|
||||
get_tag
|
||||
popd
|
||||
echo "var GUI_MONERO_VERSION = \"$TAGNAME\"" >> version.js
|
||||
GUI_VERSION=$(echo "$TAGNAME" | sed 's/^v\([[:digit:]]\)/\1/')
|
||||
echo "var GUI_VERSION = \"$GUI_VERSION\"" > version.js
|
||||
|
||||
cd build
|
||||
if ! QMAKE=$(find_command qmake qmake-qt5); then
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
OPTION(USE_DEVICE_TREZOR "Trezor support compilation" ON)
|
||||
OPTION(USE_DEVICE_TREZOR_LIBUSB "Trezor LibUSB compilation" ON)
|
||||
OPTION(USE_DEVICE_TREZOR_UDP_RELEASE "Trezor UdpTransport in release mode" OFF)
|
||||
OPTION(USE_DEVICE_TREZOR_DEBUG "Trezor Debugging enabled" OFF)
|
||||
OPTION(TREZOR_DEBUG "Main trezor debugging switch" OFF)
|
||||
|
||||
# Helper function to fix cmake < 3.6.0 FindProtobuf variables
|
||||
function(_trezor_protobuf_fix_vars)
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.6.0")
|
||||
foreach(UPPER
|
||||
PROTOBUF_SRC_ROOT_FOLDER
|
||||
PROTOBUF_IMPORT_DIRS
|
||||
PROTOBUF_DEBUG
|
||||
PROTOBUF_LIBRARY
|
||||
PROTOBUF_PROTOC_LIBRARY
|
||||
PROTOBUF_INCLUDE_DIR
|
||||
PROTOBUF_PROTOC_EXECUTABLE
|
||||
PROTOBUF_LIBRARY_DEBUG
|
||||
PROTOBUF_PROTOC_LIBRARY_DEBUG
|
||||
PROTOBUF_LITE_LIBRARY
|
||||
PROTOBUF_LITE_LIBRARY_DEBUG
|
||||
)
|
||||
if (DEFINED ${UPPER})
|
||||
string(REPLACE "PROTOBUF_" "Protobuf_" Camel ${UPPER})
|
||||
if (NOT DEFINED ${Camel})
|
||||
set(${Camel} ${${UPPER}} PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Use Trezor master switch
|
||||
if (USE_DEVICE_TREZOR)
|
||||
# Protobuf is required to build protobuf messages for Trezor
|
||||
include(FindProtobuf OPTIONAL)
|
||||
find_package(Protobuf)
|
||||
_trezor_protobuf_fix_vars()
|
||||
|
||||
# Protobuf handling the cache variables set in docker.
|
||||
if(NOT Protobuf_FOUND AND NOT Protobuf_LIBRARY AND NOT Protobuf_PROTOC_EXECUTABLE AND NOT Protobuf_INCLUDE_DIR)
|
||||
message(STATUS "Could not find Protobuf")
|
||||
elseif(NOT Protobuf_LIBRARY OR NOT EXISTS "${Protobuf_LIBRARY}")
|
||||
message(STATUS "Protobuf library not found: ${Protobuf_LIBRARY}")
|
||||
unset(Protobuf_FOUND)
|
||||
elseif(NOT Protobuf_PROTOC_EXECUTABLE OR NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
|
||||
message(STATUS "Protobuf executable not found: ${Protobuf_PROTOC_EXECUTABLE}")
|
||||
unset(Protobuf_FOUND)
|
||||
elseif(NOT Protobuf_INCLUDE_DIR OR NOT EXISTS "${Protobuf_INCLUDE_DIR}")
|
||||
message(STATUS "Protobuf include dir not found: ${Protobuf_INCLUDE_DIR}")
|
||||
unset(Protobuf_FOUND)
|
||||
else()
|
||||
message(STATUS "Protobuf lib: ${Protobuf_LIBRARY}, inc: ${Protobuf_INCLUDE_DIR}, protoc: ${Protobuf_PROTOC_EXECUTABLE}")
|
||||
set(Protobuf_INCLUDE_DIRS ${Protobuf_INCLUDE_DIR})
|
||||
set(Protobuf_FOUND 1) # override found if all rquired info was provided by variables
|
||||
endif()
|
||||
|
||||
if(TREZOR_DEBUG)
|
||||
set(USE_DEVICE_TREZOR_DEBUG 1)
|
||||
endif()
|
||||
|
||||
# Compile debugging support (for tests)
|
||||
if (USE_DEVICE_TREZOR_DEBUG)
|
||||
add_definitions(-DWITH_TREZOR_DEBUGGING=1)
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Trezor support disabled by USE_DEVICE_TREZOR")
|
||||
endif()
|
||||
|
||||
if(Protobuf_FOUND AND USE_DEVICE_TREZOR)
|
||||
if (NOT "$ENV{TREZOR_PYTHON}" STREQUAL "")
|
||||
set(TREZOR_PYTHON "$ENV{TREZOR_PYTHON}" CACHE INTERNAL "Copied from environment variable TREZOR_PYTHON")
|
||||
else()
|
||||
find_package(Python QUIET COMPONENTS Interpreter) # cmake 3.12+
|
||||
if(Python_Interpreter_FOUND)
|
||||
set(TREZOR_PYTHON "${Python_EXECUTABLE}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TREZOR_PYTHON)
|
||||
find_package(PythonInterp)
|
||||
if(PYTHONINTERP_FOUND AND PYTHON_EXECUTABLE)
|
||||
set(TREZOR_PYTHON "${PYTHON_EXECUTABLE}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TREZOR_PYTHON)
|
||||
message(STATUS "Trezor: Python not found")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Protobuf compilation test
|
||||
if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON)
|
||||
execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} -I "${CMAKE_SOURCE_DIR}/cmake" -I "${Protobuf_INCLUDE_DIR}" "${CMAKE_SOURCE_DIR}/cmake/test-protobuf.proto" --cpp_out ${CMAKE_BINARY_DIR} RESULT_VARIABLE RET OUTPUT_VARIABLE OUT ERROR_VARIABLE ERR)
|
||||
if(RET)
|
||||
message(STATUS "Protobuf test generation failed: ${OUT} ${ERR}")
|
||||
endif()
|
||||
|
||||
try_compile(Protobuf_COMPILE_TEST_PASSED
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
SOURCES
|
||||
"${CMAKE_BINARY_DIR}/test-protobuf.pb.cc"
|
||||
"${CMAKE_SOURCE_DIR}/cmake/test-protobuf.cpp"
|
||||
CMAKE_FLAGS
|
||||
"-DINCLUDE_DIRECTORIES=${Protobuf_INCLUDE_DIR};${CMAKE_BINARY_DIR}"
|
||||
"-DCMAKE_CXX_STANDARD=11"
|
||||
LINK_LIBRARIES ${Protobuf_LIBRARY}
|
||||
OUTPUT_VARIABLE OUTPUT
|
||||
)
|
||||
if(NOT Protobuf_COMPILE_TEST_PASSED)
|
||||
message(STATUS "Protobuf Compilation test failed: ${OUTPUT}.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Try to build protobuf messages
|
||||
if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON AND Protobuf_COMPILE_TEST_PASSED)
|
||||
set(ENV{PROTOBUF_INCLUDE_DIRS} "${Protobuf_INCLUDE_DIR}")
|
||||
set(ENV{PROTOBUF_PROTOC_EXECUTABLE} "${Protobuf_PROTOC_EXECUTABLE}")
|
||||
set(TREZOR_PROTOBUF_PARAMS "")
|
||||
if (USE_DEVICE_TREZOR_DEBUG)
|
||||
set(TREZOR_PROTOBUF_PARAMS "--debug")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${TREZOR_PYTHON} tools/build_protob.py ${TREZOR_PROTOBUF_PARAMS} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/monero/src/device_trezor/trezor RESULT_VARIABLE RET OUTPUT_VARIABLE OUT ERROR_VARIABLE ERR)
|
||||
if(RET)
|
||||
message(WARNING "Trezor protobuf messages could not be regenerated (err=${RET}, python ${PYTHON})."
|
||||
"OUT: ${OUT}, ERR: ${ERR}."
|
||||
"Please read src/device_trezor/trezor/tools/README.md")
|
||||
else()
|
||||
message(STATUS "Trezor protobuf messages regenerated out: \"${OUT}.\"")
|
||||
set(DEVICE_TREZOR_READY 1)
|
||||
add_definitions(-DDEVICE_TREZOR_READY=1)
|
||||
add_definitions(-DPROTOBUF_INLINE_NOT_IN_HEADERS=0)
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_definitions(-DTREZOR_DEBUG=1)
|
||||
endif()
|
||||
|
||||
if(USE_DEVICE_TREZOR_UDP_RELEASE)
|
||||
add_definitions(-DUSE_DEVICE_TREZOR_UDP_RELEASE=1)
|
||||
endif()
|
||||
|
||||
if (Protobuf_INCLUDE_DIR)
|
||||
include_directories(${Protobuf_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
# LibUSB support, check for particular version
|
||||
# Include support only if compilation test passes
|
||||
if (USE_DEVICE_TREZOR_LIBUSB)
|
||||
find_package(LibUSB)
|
||||
endif()
|
||||
|
||||
if (LibUSB_COMPILE_TEST_PASSED)
|
||||
add_definitions(-DHAVE_TREZOR_LIBUSB=1)
|
||||
if(LibUSB_INCLUDE_DIRS)
|
||||
include_directories(${LibUSB_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(TREZOR_LIBUSB_LIBRARIES "")
|
||||
if(LibUSB_COMPILE_TEST_PASSED)
|
||||
list(APPEND TREZOR_LIBUSB_LIBRARIES ${LibUSB_LIBRARIES})
|
||||
message(STATUS "Trezor compatible LibUSB found at: ${LibUSB_INCLUDE_DIRS}")
|
||||
endif()
|
||||
|
||||
if (BUILD_GUI_DEPS)
|
||||
set(TREZOR_DEP_LIBS "")
|
||||
set(TREZOR_DEP_LINKER "")
|
||||
|
||||
if (Protobuf_LIBRARY)
|
||||
list(APPEND TREZOR_DEP_LIBS ${Protobuf_LIBRARY})
|
||||
string(APPEND TREZOR_DEP_LINKER " -lprotobuf")
|
||||
endif()
|
||||
|
||||
if (TREZOR_LIBUSB_LIBRARIES)
|
||||
list(APPEND TREZOR_DEP_LIBS ${TREZOR_LIBUSB_LIBRARIES})
|
||||
string(APPEND TREZOR_DEP_LINKER " -lusb-1.0")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
103
cmake/Deploy.cmake
Normal file
@@ -0,0 +1,103 @@
|
||||
if(APPLE OR (WIN32 AND NOT STATIC))
|
||||
add_custom_target(deploy)
|
||||
get_target_property(_qmake_executable Qt5::qmake IMPORTED_LOCATION)
|
||||
get_filename_component(_qt_bin_dir "${_qmake_executable}" DIRECTORY)
|
||||
|
||||
if(APPLE AND NOT IOS)
|
||||
find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${_qt_bin_dir}")
|
||||
add_custom_command(TARGET deploy
|
||||
POST_BUILD
|
||||
COMMAND "${MACDEPLOYQT_EXECUTABLE}" "$<TARGET_FILE_DIR:monero-wallet-gui>/../.." -always-overwrite -qmldir="${CMAKE_SOURCE_DIR}"
|
||||
COMMENT "Running macdeployqt..."
|
||||
)
|
||||
|
||||
# workaround for a Qt bug that requires manually adding libqsvg.dylib to bundle
|
||||
find_file(_qt_svg_dylib "libqsvg.dylib" PATHS "${CMAKE_PREFIX_PATH}/plugins/imageformats" NO_DEFAULT_PATH)
|
||||
if(_qt_svg_dylib)
|
||||
add_custom_command(TARGET deploy
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${_qt_svg_dylib} $<TARGET_FILE_DIR:monero-wallet-gui>/../PlugIns/imageformats/
|
||||
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtGui.framework/Versions/5/QtGui" "@executable_path/../Frameworks/QtGui.fr amework/Versions/5/QtGui" $<TARGET_FILE_DIR:monero-wallet-gui>/../PlugIns/imageformats/libqsvg.dylib
|
||||
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtWidgets.framework/Versions/5/QtWidgets" "@executable_path/../Frameworks/ QtGui.framework/Versions/5/QtGui" $<TARGET_FILE_DIR:monero-wallet-gui>/../PlugIns/imageformats/libqsvg.dylib
|
||||
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtSvg.framework/Versions/5/QtSvg" "@executable_path/../Frameworks/QtGui.fr amework/Versions/5/QtGui" $<TARGET_FILE_DIR:monero-wallet-gui>/../PlugIns/imageformats/libqsvg.dylib
|
||||
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtCore.framework/Versions/5/QtCore" "@executable_path/../Frameworks/QtGui. framework/Versions/5/QtGui" $<TARGET_FILE_DIR:monero-wallet-gui>/../PlugIns/imageformats/libqsvg.dylib
|
||||
COMMENT "Copying libqsvg.dylib, running install_name_tool"
|
||||
)
|
||||
endif()
|
||||
|
||||
elseif(WIN32)
|
||||
find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${_qt_bin_dir}")
|
||||
add_custom_command(TARGET monero-wallet-gui POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E env PATH="${_qt_bin_dir}" "${WINDEPLOYQT_EXECUTABLE}" "$<TARGET_FILE:monero-wallet-gui>" -no-translations -qmldir="${CMAKE_SOURCE_DIR}"
|
||||
COMMENT "Running windeployqt..."
|
||||
)
|
||||
set(WIN_DEPLOY_DLLS
|
||||
libboost_chrono-mt.dll
|
||||
libboost_filesystem-mt.dll
|
||||
libboost_locale-mt.dll
|
||||
libboost_program_options-mt.dll
|
||||
libboost_regex-mt.dll
|
||||
libboost_serialization-mt.dll
|
||||
libboost_thread-mt.dll
|
||||
libprotobuf.dll
|
||||
libbrotlicommon.dll
|
||||
libbrotlidec.dll
|
||||
libusb-1.0.dll
|
||||
zlib1.dll
|
||||
libzstd.dll
|
||||
libwinpthread-1.dll
|
||||
libtiff-5.dll
|
||||
libstdc++-6.dll
|
||||
libpng16-16.dll
|
||||
libpcre16-0.dll
|
||||
libpcre-1.dll
|
||||
libmng-2.dll
|
||||
liblzma-5.dll
|
||||
liblcms2-2.dll
|
||||
libjpeg-8.dll
|
||||
libintl-8.dll
|
||||
libiconv-2.dll
|
||||
libharfbuzz-0.dll
|
||||
libgraphite2.dll
|
||||
libglib-2.0-0.dll
|
||||
libfreetype-6.dll
|
||||
libbz2-1.dll
|
||||
libssp-0.dll
|
||||
libpcre2-16-0.dll
|
||||
libhidapi-0.dll
|
||||
libdouble-conversion.dll
|
||||
libgcrypt-20.dll
|
||||
libgpg-error-0.dll
|
||||
libsodium-23.dll
|
||||
libzmq.dll
|
||||
#platform files
|
||||
libgcc_s_seh-1.dll
|
||||
#openssl files
|
||||
libssl-1_1-x64.dll
|
||||
libcrypto-1_1-x64.dll
|
||||
)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
list(APPEND WIN_DEPLOY_DLLS
|
||||
libicudtd67.dll
|
||||
libicuind67.dll
|
||||
libicuiod67.dll
|
||||
libicutud67.dll
|
||||
libicuucd67.dll
|
||||
)
|
||||
else() # assume release
|
||||
list(APPEND WIN_DEPLOY_DLLS
|
||||
libicudt67.dll
|
||||
libicuin67.dll
|
||||
libicuio67.dll
|
||||
libicutu67.dll
|
||||
libicuuc67.dll
|
||||
)
|
||||
endif()
|
||||
list(TRANSFORM WIN_DEPLOY_DLLS PREPEND "$ENV{MSYSTEM_PREFIX}/bin/")
|
||||
add_custom_command(TARGET deploy
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${WIN_DEPLOY_DLLS} "$<TARGET_FILE_DIR:monero-wallet-gui>"
|
||||
COMMENT "Copying DLLs to target folder"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
56
cmake/FindCcache.cmake
Normal file
@@ -0,0 +1,56 @@
|
||||
# Copyright (c) 2014-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.
|
||||
# - Try to find readline include dirs and libraries
|
||||
#
|
||||
# Automatically finds ccache build accelerator, if it's found in PATH.
|
||||
#
|
||||
# Usage of this module as follows:
|
||||
#
|
||||
# project(monero)
|
||||
# include(FindCcache) # Include AFTER the project() macro to be able to reach the CMAKE_CXX_COMPILER variable
|
||||
#
|
||||
# Properties modified by this module:
|
||||
#
|
||||
# GLOBAL PROPERTY RULE_LAUNCH_COMPILE set to ccache, when ccache found
|
||||
# GLOBAL PROPERTY RULE_LAUNCH_LINK set to ccache, when ccache found
|
||||
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if (CCACHE_FOUND)
|
||||
set(TEMP_CPP_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test-program.cpp")
|
||||
file(WRITE "${TEMP_CPP_FILE}" "int main() { return 0; }")
|
||||
execute_process(COMMAND "${CCACHE_FOUND}" "${CMAKE_CXX_COMPILER}" "${TEMP_CPP_FILE}" RESULT_VARIABLE RET)
|
||||
if (${RET} EQUAL 0)
|
||||
message("found usable ccache: ${CCACHE_FOUND}")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_FOUND}")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_FOUND}")
|
||||
else()
|
||||
message("found ccache ${CCACHE_FOUND}, but is UNUSABLE! Return code: ${RET}")
|
||||
endif()
|
||||
else()
|
||||
message("ccache NOT found!")
|
||||
endif()
|
||||
@@ -28,37 +28,40 @@
|
||||
#
|
||||
# Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
# Check what commit we're on
|
||||
execute_process(COMMAND "${GIT}" rev-parse --short=9 HEAD RESULT_VARIABLE RET OUTPUT_VARIABLE COMMIT OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
function (git_get_version_tag git directory result_var)
|
||||
execute_process(COMMAND "${git}" rev-parse --short HEAD
|
||||
WORKING_DIRECTORY ${directory}
|
||||
OUTPUT_VARIABLE COMMIT
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(NOT COMMIT)
|
||||
message(WARNING "${directory}: cannot determine current commit. Make sure that you are building from a Git working tree")
|
||||
set(${result_var} "unknown" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(RET)
|
||||
# Something went wrong, set the version tag to -unknown
|
||||
|
||||
message(WARNING "Cannot determine current commit. Make sure that you are building either from a Git working tree or from a source archive.")
|
||||
set(VERSIONTAG "unknown")
|
||||
configure_file("src/version.js.in" "${TO}")
|
||||
else()
|
||||
string(SUBSTRING ${COMMIT} 0 9 COMMIT)
|
||||
message(STATUS "You are currently on commit ${COMMIT}")
|
||||
|
||||
# Get all the tags
|
||||
execute_process(COMMAND "${GIT}" rev-list --tags --max-count=1 --abbrev-commit RESULT_VARIABLE RET OUTPUT_VARIABLE TAGGEDCOMMIT OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
if(NOT TAGGEDCOMMIT)
|
||||
message(WARNING "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.")
|
||||
set(VERSIONTAG "${COMMIT}")
|
||||
else()
|
||||
message(STATUS "The most recent tag was at ${TAGGEDCOMMIT}")
|
||||
|
||||
# Check if we're building that tagged commit or a different one
|
||||
if(COMMIT STREQUAL TAGGEDCOMMIT)
|
||||
message(STATUS "You are building a tagged release")
|
||||
set(VERSIONTAG "release")
|
||||
else()
|
||||
message(STATUS "You are ahead of or behind a tagged release")
|
||||
set(VERSIONTAG "${COMMIT}")
|
||||
endif()
|
||||
endif()
|
||||
execute_process(COMMAND "${git}" describe --tags --exact-match
|
||||
WORKING_DIRECTORY ${directory}
|
||||
OUTPUT_VARIABLE TAG
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(TAG)
|
||||
message(STATUS "${directory}: building tagged release ${TAG}-${COMMIT}")
|
||||
set(${result_var} "${TAG}-${COMMIT}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
configure_file("src/version.js.in" "${TO}")
|
||||
endif()
|
||||
execute_process(COMMAND "${git}" describe --tags --long
|
||||
WORKING_DIRECTORY ${directory}
|
||||
OUTPUT_VARIABLE MOST_RECENT_TAG
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(MOST_RECENT_TAG)
|
||||
message(STATUS "${directory}: ahead of or behind a tagged release, building ${MOST_RECENT_TAG}")
|
||||
set(${result_var} "${MOST_RECENT_TAG}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "${directory}: building ${COMMIT} commit")
|
||||
set(${result_var} "${COMMIT}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
@@ -26,9 +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.
|
||||
|
||||
function (write_static_version_header hash)
|
||||
set(VERSIONTAG "${hash}")
|
||||
configure_file("${CMAKE_SOURCE_DIR}/version.js.in" "${CMAKE_SOURCE_DIR}/version.js")
|
||||
function (write_static_version_header VERSION_TAG_GUI)
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/version.js.in" "${CMAKE_CURRENT_SOURCE_DIR}/version.js")
|
||||
endfunction ()
|
||||
|
||||
find_package(Git QUIET)
|
||||
@@ -37,16 +36,14 @@ if ("$Format:$" STREQUAL "")
|
||||
write_static_version_header("release")
|
||||
elseif (GIT_FOUND OR Git_FOUND)
|
||||
message(STATUS "Found Git: ${GIT_EXECUTABLE}")
|
||||
add_custom_command(
|
||||
OUTPUT "${CMAKE_SOURCE_DIR}/version.js"
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
"-D" "GIT=${GIT_EXECUTABLE}"
|
||||
"-D" "TO=${CMAKE_SOURCE_DIR}/version.js"
|
||||
"-P" "cmake/GenVersionGui.cmake"
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
||||
|
||||
include(GitGetVersionTag)
|
||||
git_get_version_tag(${GIT_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR} VERSION_TAG_GUI)
|
||||
STRING(REGEX REPLACE "^v([0-9])" "\\1" VERSION_TAG_GUI ${VERSION_TAG_GUI})
|
||||
write_static_version_header(${VERSION_TAG_GUI})
|
||||
else()
|
||||
message(STATUS "WARNING: Git was not found!")
|
||||
write_static_version_header("unknown")
|
||||
endif ()
|
||||
add_custom_target(genversiongui ALL
|
||||
DEPENDS "${CMAKE_SOURCE_DIR}/version.js")
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/version.js")
|
||||
|
||||
106
components/AdvancedOptionsItem.qml
Normal file
@@ -0,0 +1,106 @@
|
||||
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 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
|
||||
Layout.preferredWidth: 195
|
||||
Layout.maximumWidth: 195
|
||||
Layout.leftMargin: 10
|
||||
|
||||
MoneroComponents.Label {
|
||||
id: title
|
||||
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
|
||||
height: 10
|
||||
color: "transparent"
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: false
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
||||
spacing: 4
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: false
|
||||
spacing: 12
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
||||
|
||||
StandardButton {
|
||||
id: button1
|
||||
small: true
|
||||
visible: button1.text
|
||||
}
|
||||
|
||||
StandardButton {
|
||||
id: button2
|
||||
small: true
|
||||
visible: button2.text
|
||||
}
|
||||
|
||||
StandardButton {
|
||||
id: button3
|
||||
small: true
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ Item {
|
||||
visible: checkBox.border
|
||||
anchors.fill: parent
|
||||
radius: 3
|
||||
color: "transparent"
|
||||
color: checkBox.enabled ? "transparent" : MoneroComponents.Style.inputBoxBackgroundDisabled
|
||||
border.color:
|
||||
if(checkBox.checked){
|
||||
return MoneroComponents.Style.inputBorderColorActive;
|
||||
@@ -109,6 +109,7 @@ Item {
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
textFormat: Text.RichText
|
||||
wrapMode: Text.NoWrap
|
||||
visible: text != ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ Item {
|
||||
|
||||
Connections {
|
||||
target: datePicker
|
||||
onCurrentDateChanged: {
|
||||
function onCurrentDateChanged() {
|
||||
dateInput.setDate(datePicker.currentDate)
|
||||
}
|
||||
}
|
||||
|
||||
104
components/DevicePassphraseDialog.qml
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) 2014-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.
|
||||
|
||||
import QtQuick 2.9
|
||||
import "." as MoneroComponents
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var onAcceptedCallback
|
||||
property var onWalletEntryCallback
|
||||
property var onRejectedCallback
|
||||
|
||||
function open(canEnterOnDevice_) {
|
||||
var canEnterOnDevice = canEnterOnDevice_ !== null ? canEnterOnDevice_ : canEnterOnDevice
|
||||
root.visible = true;
|
||||
|
||||
if (canEnterOnDevice) {
|
||||
entryChooserDialog.okText = qsTr("Hardware wallet")
|
||||
entryChooserDialog.cancelText = qsTr("Computer")
|
||||
entryChooserDialog.open()
|
||||
} else {
|
||||
openPassphraseDialog()
|
||||
}
|
||||
}
|
||||
|
||||
function openPassphraseDialog() {
|
||||
root.visible = true
|
||||
passphraseDialog.openPassphraseDialog()
|
||||
}
|
||||
|
||||
function close() {
|
||||
root.visible = false;
|
||||
if (entryChooserDialog.visible)
|
||||
entryChooserDialog.close()
|
||||
if (passphraseDialog.visible)
|
||||
passphraseDialog.close()
|
||||
}
|
||||
|
||||
StandardDialog {
|
||||
id: entryChooserDialog
|
||||
title: qsTr("Hardware wallet passphrase") + translationManager.emptyString
|
||||
text: qsTr("Please select where you want to enter passphrase.\nIt is recommended to enter passphrase on the hardware wallet for better security.") + translationManager.emptyString
|
||||
|
||||
onAccepted: {
|
||||
if (onWalletEntryCallback){
|
||||
onWalletEntryCallback()
|
||||
}
|
||||
}
|
||||
|
||||
onRejected: {
|
||||
openPassphraseDialog()
|
||||
}
|
||||
|
||||
onCloseCallback: {
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
|
||||
PasswordDialog {
|
||||
id: passphraseDialog
|
||||
anchors.fill: parent
|
||||
passphraseDialogMode: true
|
||||
|
||||
onAcceptedPassphrase: {
|
||||
if (onAcceptedCallback)
|
||||
onAcceptedCallback(passphraseDialog.password);
|
||||
}
|
||||
|
||||
onRejectedPassphrase: {
|
||||
if (onRejectedCallback)
|
||||
onRejectedCallback();
|
||||
}
|
||||
|
||||
onCloseCallback: {
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,7 @@ Item {
|
||||
property alias fontPixelSize: inlineText.font.pixelSize
|
||||
property alias fontFamily: inlineText.font.family
|
||||
property alias buttonColor: rect.color
|
||||
property alias buttonHeight: rect.height
|
||||
signal clicked()
|
||||
|
||||
function doClick() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2014-2019, The Monero Project
|
||||
// Copyright (c) 2014-2020, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -53,7 +53,7 @@ Drawer {
|
||||
y: titleBar.height
|
||||
|
||||
background: Rectangle {
|
||||
color: "#0d0d0d"
|
||||
color: MoneroComponents.Style.blackTheme ? "#0d0d0d" : "white"
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
@@ -79,9 +79,24 @@ Drawer {
|
||||
width: sideBar.width
|
||||
height: 32
|
||||
|
||||
Rectangle {
|
||||
id: flagRect
|
||||
height: 24
|
||||
width: 24
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 4
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: "transparent"
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: flag
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 16
|
||||
anchors.leftMargin: 30
|
||||
font.bold: true
|
||||
font.pixelSize: 14
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
@@ -118,8 +133,10 @@ Drawer {
|
||||
// set wizard language settings
|
||||
wizard.language_locale = locale;
|
||||
wizard.language_wallet = wallet_language;
|
||||
wizard.language_language = display_name + " (" + locale_spl[1] + ") ";
|
||||
sideBar.close()
|
||||
wizard.language_language = display_name;
|
||||
|
||||
appWindow.showStatusMessage(qsTr("Language changed."), 3);
|
||||
appWindow.toggleLanguageView();
|
||||
}
|
||||
hoverEnabled: true
|
||||
onEntered: {
|
||||
@@ -134,15 +151,8 @@ Drawer {
|
||||
}
|
||||
}
|
||||
|
||||
ScrollIndicator.vertical: ScrollIndicator {
|
||||
// @TODO: QT 5.9 introduces `policy: ScrollBar.AlwaysOn`
|
||||
active: true
|
||||
contentItem.opacity: 0.7
|
||||
onActiveChanged: {
|
||||
if (!active) {
|
||||
active = true;
|
||||
}
|
||||
}
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
onActiveChanged: if (!active && !isMac) active = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 FontAwesome 1.0
|
||||
import QtQuick 2.9
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
@@ -36,6 +37,10 @@ Item {
|
||||
property alias input: input
|
||||
property alias text: input.text
|
||||
|
||||
property bool password: false
|
||||
property bool passwordHidden: true
|
||||
property var passwordLinked: null
|
||||
|
||||
property alias placeholderText: placeholderLabel.text
|
||||
property bool placeholderCenter: false
|
||||
property string placeholderFontFamily: MoneroComponents.Style.fontRegular.name
|
||||
@@ -48,7 +53,6 @@ Item {
|
||||
property alias validator: input.validator
|
||||
property alias readOnly : input.readOnly
|
||||
property alias cursorPosition: input.cursorPosition
|
||||
property alias echoMode: input.echoMode
|
||||
property alias inlineButton: inlineButtonId
|
||||
property alias inlineButtonText: inlineButtonId.text
|
||||
property alias inlineIcon: inlineIcon.visible
|
||||
@@ -109,6 +113,31 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
function isPasswordHidden() {
|
||||
if (password) {
|
||||
return passwordHidden;
|
||||
}
|
||||
if (passwordLinked) {
|
||||
return passwordLinked.passwordHidden;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
text = "";
|
||||
if (!passwordLinked) {
|
||||
passwordHidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
function passwordToggle() {
|
||||
if (passwordLinked) {
|
||||
passwordLinked.passwordHidden = !passwordLinked.passwordHidden;
|
||||
} else {
|
||||
passwordHidden = !passwordHidden;
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: inputLabel
|
||||
anchors.top: parent.top
|
||||
@@ -175,7 +204,7 @@ Item {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 1
|
||||
color: "transparent"
|
||||
color: item.enabled ? "transparent" : MoneroComponents.Style.inputBoxBackgroundDisabled
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -210,6 +239,27 @@ Item {
|
||||
onTextChanged: item.textUpdated()
|
||||
topPadding: 10
|
||||
bottomPadding: 10
|
||||
echoMode: isPasswordHidden() ? TextInput.Password : TextInput.Normal
|
||||
|
||||
MoneroComponents.Label {
|
||||
visible: password || passwordLinked
|
||||
fontSize: 20
|
||||
text: isPasswordHidden() ? FontAwesome.eye : FontAwesome.eyeSlash
|
||||
opacity: eyeMouseArea.containsMouse ? 0.9 : 0.7
|
||||
fontFamily: FontAwesome.fontFamily
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 15
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenterOffset: 1
|
||||
|
||||
MouseArea {
|
||||
id: eyeMouseArea
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
onClicked: passwordToggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.InlineButton {
|
||||
|
||||
@@ -87,6 +87,8 @@ ColumnLayout {
|
||||
|
||||
property alias inlineButton: inlineButtonId
|
||||
property bool inlineButtonVisible: false
|
||||
property alias inlineButton2: inlineButton2Id
|
||||
property bool inlineButton2Visible: false
|
||||
|
||||
signal labelButtonClicked();
|
||||
signal inputLabelLinkActivated();
|
||||
@@ -202,5 +204,12 @@ ColumnLayout {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ Rectangle {
|
||||
height: present ? ((appWindow.height >= 800) ? 44 : 38 ) : 0
|
||||
|
||||
LinearGradient {
|
||||
visible: isOpenGL && button.checked
|
||||
visible: isOpenGL && (button.checked || buttonArea.containsMouse)
|
||||
height: parent.height
|
||||
width: 260
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -75,13 +75,15 @@ Rectangle {
|
||||
GradientStop { position: 0.0; color: MoneroComponents.Style.menuButtonGradientStart }
|
||||
GradientStop { position: 1.0; color: MoneroComponents.Style.menuButtonGradientStop }
|
||||
}
|
||||
opacity: button.checked ? 1 : 0.3
|
||||
}
|
||||
|
||||
// fallback hover effect when opengl is not available
|
||||
Rectangle {
|
||||
visible: !isOpenGL && button.checked
|
||||
visible: !isOpenGL && (button.checked || buttonArea.containsMouse)
|
||||
anchors.fill: parent
|
||||
color: MoneroComponents.Style.menuButtonFallbackBackgroundColor
|
||||
opacity: button.checked ? 1 : 0.3
|
||||
}
|
||||
|
||||
// button decorations that are subject to leftMargin offsets
|
||||
|
||||
@@ -41,11 +41,11 @@ import "../js/Utils.js" as Utils
|
||||
Item {
|
||||
id: root
|
||||
visible: false
|
||||
z: parent.z + 2
|
||||
|
||||
property bool isHidden: true
|
||||
property alias password: passwordInput1.text
|
||||
property string walletName
|
||||
property var okButtonText
|
||||
property string okButtonIcon
|
||||
property string errorText
|
||||
property bool passwordDialogMode
|
||||
property bool passphraseDialogMode
|
||||
@@ -61,13 +61,11 @@ Item {
|
||||
signal closeCallback()
|
||||
|
||||
function _openInit(walletName, errorText) {
|
||||
isHidden = true
|
||||
capsLockTextLabel.visible = oshelper.isCapsLock();
|
||||
passwordInput1.echoMode = TextInput.Password
|
||||
passwordInput2.echoMode = TextInput.Password
|
||||
passwordInput1.text = ""
|
||||
passwordInput2.text = ""
|
||||
passwordInput1.forceActiveFocus();
|
||||
passwordInput1.reset();
|
||||
passwordInput2.reset();
|
||||
if(!appWindow.currentWallet || appWindow.active)
|
||||
passwordInput1.input.forceActiveFocus();
|
||||
root.walletName = walletName ? walletName : ""
|
||||
errorTextLabel.text = errorText ? errorText : "";
|
||||
leftPanel.enabled = false
|
||||
@@ -79,10 +77,12 @@ Item {
|
||||
appWindow.updateBalance();
|
||||
}
|
||||
|
||||
function open(walletName, errorText) {
|
||||
function open(walletName, errorText, okButtonText, okButtonIcon) {
|
||||
passwordDialogMode = true;
|
||||
passphraseDialogMode = false;
|
||||
newPasswordDialogMode = false;
|
||||
root.okButtonText = okButtonText;
|
||||
root.okButtonIcon = okButtonIcon ? okButtonIcon : "";
|
||||
_openInit(walletName, errorText);
|
||||
}
|
||||
|
||||
@@ -116,10 +116,29 @@ Item {
|
||||
closeCallback();
|
||||
}
|
||||
|
||||
function toggleIsHidden() {
|
||||
passwordInput1.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
|
||||
passwordInput2.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
|
||||
isHidden = !isHidden;
|
||||
function onOk() {
|
||||
if (!passwordDialogMode && passwordInput1.text !== passwordInput2.text) {
|
||||
return;
|
||||
}
|
||||
root.close()
|
||||
if (passwordDialogMode) {
|
||||
root.accepted()
|
||||
} else if (newPasswordDialogMode) {
|
||||
root.acceptedNewPassword()
|
||||
} else if (passphraseDialogMode) {
|
||||
root.acceptedPassphrase()
|
||||
}
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
root.close()
|
||||
if (passwordDialogMode) {
|
||||
root.rejected()
|
||||
} else if (newPasswordDialogMode) {
|
||||
root.rejectedNewPassword()
|
||||
} else if (passphraseDialogMode) {
|
||||
root.rejectedPassphrase()
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
@@ -184,15 +203,11 @@ Item {
|
||||
text: qsTr("CAPSLOCKS IS ON.") + translationManager.emptyString;
|
||||
}
|
||||
|
||||
MoneroComponents.Input {
|
||||
MoneroComponents.LineEdit {
|
||||
id: passwordInput1
|
||||
password: true
|
||||
Layout.topMargin: 6
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: TextInput.AlignLeft
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
font.family: MoneroComponents.Style.fontLight.name
|
||||
font.pixelSize: 24
|
||||
echoMode: TextInput.Password
|
||||
KeyNavigation.tab: {
|
||||
if (passwordDialogMode) {
|
||||
return okButton
|
||||
@@ -200,81 +215,12 @@ Item {
|
||||
return passwordInput2
|
||||
}
|
||||
}
|
||||
implicitHeight: 50
|
||||
bottomPadding: 10
|
||||
leftPadding: 10
|
||||
topPadding: 10
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
selectionColor: MoneroComponents.Style.textSelectionColor
|
||||
selectedTextColor: MoneroComponents.Style.textSelectedColor
|
||||
onTextChanged: capsLockTextLabel.visible = oshelper.isCapsLock();
|
||||
|
||||
background: Rectangle {
|
||||
radius: 2
|
||||
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
|
||||
border.color: MoneroComponents.Style.inputBorderColorInActive
|
||||
border.width: 1
|
||||
|
||||
MoneroEffects.ColorTransition {
|
||||
targetObj: parent
|
||||
blackColor: "black"
|
||||
whiteColor: "#A9FFFFFF"
|
||||
}
|
||||
|
||||
MoneroComponents.Label {
|
||||
fontSize: 20
|
||||
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
|
||||
opacity: 0.7
|
||||
fontFamily: FontAwesome.fontFamily
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 15
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenterOffset: 1
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
toggleIsHidden();
|
||||
}
|
||||
onEntered: {
|
||||
parent.opacity = 0.9
|
||||
parent.fontSize = 24
|
||||
}
|
||||
onExited: {
|
||||
parent.opacity = 0.7
|
||||
parent.fontSize = 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.enabled: root.visible
|
||||
Keys.onEnterPressed: Keys.onReturnPressed(event)
|
||||
Keys.onReturnPressed: {
|
||||
if (!passwordDialogMode && passwordInput1.text !== passwordInput2.text) {
|
||||
return;
|
||||
}
|
||||
root.close()
|
||||
if (passwordDialogMode) {
|
||||
root.accepted()
|
||||
} else if (newPasswordDialogMode) {
|
||||
root.acceptedNewPassword()
|
||||
} else if (passphraseDialogMode) {
|
||||
root.acceptedPassphrase()
|
||||
}
|
||||
}
|
||||
Keys.onEscapePressed: {
|
||||
root.close()
|
||||
if (passwordDialogMode) {
|
||||
root.rejected()
|
||||
} else if (newPasswordDialogMode) {
|
||||
root.rejectedNewPassword()
|
||||
} else if (passphraseDialogMode) {
|
||||
root.rejectedPassphrase()
|
||||
}
|
||||
}
|
||||
Keys.onEnterPressed: root.onOk()
|
||||
Keys.onReturnPressed: root.onOk()
|
||||
Keys.onEscapePressed: root.onCancel()
|
||||
}
|
||||
|
||||
// padding
|
||||
@@ -298,81 +244,19 @@ Item {
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
}
|
||||
|
||||
MoneroComponents.Input {
|
||||
MoneroComponents.LineEdit {
|
||||
id: passwordInput2
|
||||
passwordLinked: passwordInput1
|
||||
visible: !passwordDialogMode
|
||||
Layout.topMargin: 6
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: TextInput.AlignLeft
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
font.family: MoneroComponents.Style.fontLight.name
|
||||
font.pixelSize: 24
|
||||
echoMode: TextInput.Password
|
||||
KeyNavigation.tab: okButton
|
||||
implicitHeight: 50
|
||||
bottomPadding: 10
|
||||
leftPadding: 10
|
||||
topPadding: 10
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
selectionColor: MoneroComponents.Style.textSelectionColor
|
||||
selectedTextColor: MoneroComponents.Style.textSelectedColor
|
||||
onTextChanged: capsLockTextLabel.visible = oshelper.isCapsLock();
|
||||
|
||||
background: Rectangle {
|
||||
radius: 2
|
||||
border.color: MoneroComponents.Style.inputBorderColorInActive
|
||||
border.width: 1
|
||||
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
|
||||
|
||||
MoneroComponents.Label {
|
||||
fontSize: 20
|
||||
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
|
||||
opacity: 0.7
|
||||
fontFamily: FontAwesome.fontFamily
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 15
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenterOffset: 1
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
toggleIsHidden()
|
||||
}
|
||||
onEntered: {
|
||||
parent.opacity = 0.9
|
||||
parent.fontSize = 24
|
||||
}
|
||||
onExited: {
|
||||
parent.opacity = 0.7
|
||||
parent.fontSize = 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.enabled: root.visible
|
||||
Keys.onEnterPressed: Keys.onReturnPressed(event)
|
||||
Keys.onReturnPressed: {
|
||||
if (passwordInput1.text === passwordInput2.text) {
|
||||
root.close()
|
||||
if (newPasswordDialogMode) {
|
||||
root.acceptedNewPassword()
|
||||
} else if (passphraseDialogMode) {
|
||||
root.acceptedPassphrase()
|
||||
}
|
||||
}
|
||||
}
|
||||
Keys.onEscapePressed: {
|
||||
root.close()
|
||||
if (newPasswordDialogMode) {
|
||||
root.rejectedNewPassword()
|
||||
} else if (passphraseDialogMode) {
|
||||
root.rejectedPassphrase()
|
||||
}
|
||||
}
|
||||
Keys.onEnterPressed: root.onOk()
|
||||
Keys.onReturnPressed: root.onOk()
|
||||
Keys.onEscapePressed: root.onCancel()
|
||||
}
|
||||
|
||||
// padding
|
||||
@@ -394,37 +278,22 @@ Item {
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
id: cancelButton
|
||||
primary: false
|
||||
small: true
|
||||
text: qsTr("Cancel") + translationManager.emptyString
|
||||
KeyNavigation.tab: passwordInput1
|
||||
onClicked: {
|
||||
root.close()
|
||||
if (passwordDialogMode) {
|
||||
root.rejected()
|
||||
} else if (newPasswordDialogMode) {
|
||||
root.rejectedNewPassword()
|
||||
} else if (passphraseDialogMode) {
|
||||
root.rejectedPassphrase()
|
||||
}
|
||||
}
|
||||
onClicked: onCancel()
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
id: okButton
|
||||
fontAwesomeIcon: true
|
||||
rightIcon: okButtonIcon
|
||||
small: true
|
||||
text: qsTr("Ok") + translationManager.emptyString
|
||||
text: okButtonText ? okButtonText : qsTr("Ok") + translationManager.emptyString
|
||||
KeyNavigation.tab: cancelButton
|
||||
enabled: (passwordDialogMode == true) ? true : passwordInput1.text === passwordInput2.text
|
||||
onClicked: {
|
||||
root.close()
|
||||
if (passwordDialogMode) {
|
||||
root.accepted()
|
||||
} else if (newPasswordDialogMode) {
|
||||
root.acceptedNewPassword()
|
||||
} else if (passphraseDialogMode) {
|
||||
root.acceptedPassphrase()
|
||||
}
|
||||
}
|
||||
onClicked: onOk()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,21 +29,23 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Window 2.1
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import "../components" as MoneroComponents
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: MoneroComponents.Style.blackTheme ? "white" : "transparent"
|
||||
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
|
||||
z: 11
|
||||
property alias messageText: messageTitle.text
|
||||
property alias heightProgressText : heightProgress.text
|
||||
|
||||
width: 200
|
||||
height: 100
|
||||
opacity: 0.7
|
||||
width: 100
|
||||
height: 50
|
||||
|
||||
function show() {
|
||||
root.visible = true;
|
||||
@@ -56,44 +58,55 @@ Rectangle {
|
||||
ColumnLayout {
|
||||
id: rootLayout
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.centerIn: parent
|
||||
|
||||
anchors.leftMargin: 30
|
||||
anchors.rightMargin: 30
|
||||
|
||||
spacing: 12
|
||||
spacing: 21
|
||||
|
||||
BusyIndicator {
|
||||
running: parent.visible
|
||||
Item {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
Layout.preferredHeight: 80
|
||||
|
||||
Image {
|
||||
id: imgLogo
|
||||
width: 60
|
||||
height: 60
|
||||
anchors.centerIn: parent
|
||||
source: "qrc:///images/monero-vector.svg"
|
||||
mipmap: true
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
running: parent.visible
|
||||
anchors.centerIn: imgLogo
|
||||
style: BusyIndicatorStyle {
|
||||
indicator: Image {
|
||||
visible: control.running
|
||||
source: "qrc:///images/busy-indicator.png"
|
||||
RotationAnimator on rotation {
|
||||
running: control.running
|
||||
loops: Animation.Infinite
|
||||
duration: 1000
|
||||
from: 0
|
||||
to: 360
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: messageTitle
|
||||
text: "Please wait..."
|
||||
font {
|
||||
pixelSize: 22
|
||||
}
|
||||
text: qsTr("Please wait...") + translationManager.emptyString
|
||||
font.pixelSize: 24
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
themeTransition: false
|
||||
color: "black"
|
||||
}
|
||||
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: heightProgress
|
||||
font {
|
||||
pixelSize: 18
|
||||
}
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
themeTransition: false
|
||||
color: "black"
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ Rectangle {
|
||||
function updateProgress(currentBlock,targetBlock, blocksToSync, statusTxt){
|
||||
if(targetBlock > 0) {
|
||||
var remaining = (currentBlock < targetBlock) ? targetBlock - currentBlock : 0
|
||||
var progressLevel = (blocksToSync > 0 && blocksToSync != remaining) ? (100*(blocksToSync - remaining)/blocksToSync).toFixed(0) : (100*(currentBlock / targetBlock)).toFixed(0)
|
||||
var progressLevel = (blocksToSync > 0 ) ? (100*(blocksToSync - remaining)/blocksToSync).toFixed(0) : 100
|
||||
fillLevel = progressLevel
|
||||
if(typeof statusTxt != "undefined" && statusTxt != "") {
|
||||
progressText.text = statusTxt;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
// Copyright (c) 2014-2020, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -53,6 +53,7 @@ Rectangle {
|
||||
script: {
|
||||
root.visible = true
|
||||
camera.captureMode = Camera.CaptureStillImage
|
||||
camera.cameraState = Camera.ActiveState
|
||||
camera.start()
|
||||
finder.enabled = true
|
||||
}
|
||||
@@ -65,6 +66,7 @@ Rectangle {
|
||||
camera.stop()
|
||||
root.visible = false
|
||||
finder.enabled = false
|
||||
camera.cameraState = Camera.UnloadedState
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,6 +76,7 @@ Rectangle {
|
||||
id: camera
|
||||
objectName: "qrCameraQML"
|
||||
captureMode: Camera.CaptureStillImage
|
||||
cameraState: Camera.UnloadedState
|
||||
|
||||
focus {
|
||||
focusMode: Camera.FocusContinuous
|
||||
@@ -83,9 +86,14 @@ Rectangle {
|
||||
id : finder
|
||||
objectName: "QrFinder"
|
||||
onDecoded : {
|
||||
root.qrcode_decoded(address, payment_id, amount, tx_description, recipient_name, extra_parameters)
|
||||
root.state = "Stopped"
|
||||
}
|
||||
const parsed = walletManager.parse_uri_to_object(data);
|
||||
if (!parsed.error) {
|
||||
root.qrcode_decoded(parsed.address, parsed.payment_id, parsed.amount, parsed.tx_description, parsed.recipient_name, parsed.extra_parameters);
|
||||
root.state = "Stopped";
|
||||
} else {
|
||||
onNotifyError(parsed.error);
|
||||
}
|
||||
}
|
||||
onNotifyError : {
|
||||
if( warning )
|
||||
messageDialog.icon = StandardIcon.Critical
|
||||
|
||||
@@ -43,6 +43,9 @@ GridLayout {
|
||||
property alias daemonAddrLabelText: daemonAddr.labelText
|
||||
property alias daemonPortLabelText: daemonPort.labelText
|
||||
|
||||
property string initialAddress: ""
|
||||
property var initialHostPort: initialAddress.match(/^(.*?)(?:\:?(\d*))$/)
|
||||
|
||||
// TODO: LEGACY; remove these placeHolder variables when
|
||||
// the wizards get redesigned to the black-theme
|
||||
property string placeholderFontFamily: MoneroComponents.Style.fontRegular.name
|
||||
@@ -58,6 +61,9 @@ GridLayout {
|
||||
property bool lineEditFontBold: false
|
||||
property int lineEditFontSize: 15
|
||||
|
||||
// Author: David M. Syzdek https://github.com/syzdek https://gist.github.com/syzdek/6086792
|
||||
readonly property var ipv6Regex: /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/
|
||||
|
||||
signal editingFinished()
|
||||
signal textChanged()
|
||||
|
||||
@@ -91,8 +97,12 @@ GridLayout {
|
||||
fontColor: lineEditFontColor
|
||||
fontBold: lineEditFontBold
|
||||
fontSize: lineEditFontSize
|
||||
onEditingFinished: root.editingFinished()
|
||||
onEditingFinished: {
|
||||
text = text.replace(ipv6Regex, "[$1]");
|
||||
root.editingFinished();
|
||||
}
|
||||
onTextChanged: root.textChanged()
|
||||
text: initialHostPort[1]
|
||||
}
|
||||
|
||||
LineEdit {
|
||||
@@ -114,5 +124,6 @@ GridLayout {
|
||||
|
||||
onEditingFinished: root.editingFinished()
|
||||
onTextChanged: root.textChanged()
|
||||
text: initialHostPort[2]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +1,71 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Layouts 1.1
|
||||
import FontAwesome 1.0
|
||||
|
||||
import "../components" as MoneroComponents
|
||||
|
||||
ColumnLayout {
|
||||
property alias buttonText: button.text
|
||||
property alias description: description.text
|
||||
property alias title: title.text
|
||||
id: settingsListItem
|
||||
property alias iconText: iconLabel.text
|
||||
property alias description: area.text
|
||||
property alias title: header.text
|
||||
property bool isLast: false
|
||||
signal clicked()
|
||||
|
||||
id: settingsListItem
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
// divider
|
||||
Layout.preferredHeight: 1
|
||||
id: root
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 8
|
||||
color: MoneroComponents.Style.dividerColor
|
||||
opacity: MoneroComponents.Style.dividerOpacity
|
||||
}
|
||||
Layout.minimumHeight: 75
|
||||
Layout.preferredHeight: rect.height + 15
|
||||
color: "transparent"
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
Rectangle {
|
||||
id: divider
|
||||
anchors.topMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 1
|
||||
color: MoneroComponents.Style.dividerColor
|
||||
opacity: MoneroComponents.Style.dividerOpacity
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
spacing: 0
|
||||
Rectangle {
|
||||
id: rect
|
||||
width: parent.width
|
||||
height: header.height + area.contentHeight
|
||||
color: "transparent";
|
||||
anchors.left: parent.left
|
||||
anchors.bottomMargin: 4
|
||||
anchors.topMargin: 4
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Rectangle {
|
||||
id: icon
|
||||
color: "transparent"
|
||||
height: 32
|
||||
width: 32
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 16
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MoneroComponents.Label {
|
||||
id: iconLabel
|
||||
fontSize: 32
|
||||
fontFamily: FontAwesome.fontFamilySolid
|
||||
anchors.centerIn: parent
|
||||
fontColor: MoneroComponents.Style.defaultFontColor
|
||||
styleName: "Solid"
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: title
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 20
|
||||
Layout.topMargin: 8
|
||||
id: header
|
||||
anchors.left: icon.right
|
||||
anchors.leftMargin: 16
|
||||
anchors.top: parent.top
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
opacity: MoneroComponents.Style.blackTheme ? 1.0 : 0.8
|
||||
font.bold: true
|
||||
@@ -43,23 +73,43 @@ ColumnLayout {
|
||||
font.pixelSize: 16
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlainArea {
|
||||
id: description
|
||||
Text {
|
||||
id: area
|
||||
anchors.top: header.bottom
|
||||
anchors.topMargin: 4
|
||||
anchors.left: icon.right
|
||||
anchors.leftMargin: 16
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
colorBlackTheme: MoneroComponents.Style._b_dimmedFontColor
|
||||
colorWhiteTheme: MoneroComponents.Style._w_dimmedFontColor
|
||||
Layout.fillWidth: true
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 15
|
||||
horizontalAlignment: TextInput.AlignLeft
|
||||
wrapMode: Text.WordWrap;
|
||||
leftPadding: 0
|
||||
topPadding: 0
|
||||
width: parent.width - (icon.width + icon.anchors.leftMargin + anchors.leftMargin)
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
id: button
|
||||
small: true
|
||||
Rectangle {
|
||||
id: bottomDivider
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 1
|
||||
color: MoneroComponents.Style.dividerColor
|
||||
opacity: MoneroComponents.Style.dividerOpacity
|
||||
visible: settingsListItem.isLast
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: root.color = MoneroComponents.Style.titleBarButtonHoverColor
|
||||
onExited: root.color = "transparent"
|
||||
onClicked: {
|
||||
settingsListItem.clicked()
|
||||
}
|
||||
width: 135
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
68
components/Slider.qml
Normal file
@@ -0,0 +1,68 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.0 as QtQuickControls
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import "../components" as MoneroComponents
|
||||
|
||||
ColumnLayout {
|
||||
property alias from: slider.from
|
||||
property alias stepSize: slider.stepSize
|
||||
property alias to: slider.to
|
||||
property alias value: slider.value
|
||||
|
||||
property alias text: label.text
|
||||
|
||||
signal moved()
|
||||
|
||||
spacing: 0
|
||||
|
||||
Text {
|
||||
id: label
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
font.pixelSize: 14
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
QtQuickControls.Slider {
|
||||
id: slider
|
||||
leftPadding: 0
|
||||
snapMode: QtQuickControls.Slider.SnapAlways
|
||||
|
||||
background: Rectangle {
|
||||
x: parent.leftPadding
|
||||
y: parent.topPadding + parent.availableHeight / 2 - height / 2
|
||||
implicitWidth: 200
|
||||
implicitHeight: 4
|
||||
width: parent.availableWidth
|
||||
height: implicitHeight
|
||||
radius: 2
|
||||
color: MoneroComponents.Style.progressBarBackgroundColor
|
||||
|
||||
Rectangle {
|
||||
width: parent.visualPosition * parent.width
|
||||
height: parent.height
|
||||
color: MoneroComponents.Style.green
|
||||
radius: 2
|
||||
}
|
||||
}
|
||||
|
||||
handle: Rectangle {
|
||||
x: parent.leftPadding + parent.visualPosition * (parent.availableWidth - width)
|
||||
y: parent.topPadding + parent.availableHeight / 2 - height / 2
|
||||
implicitWidth: 18
|
||||
implicitHeight: 18
|
||||
radius: 8
|
||||
color: parent.pressed ? "#f0f0f0" : "#f6f6f6"
|
||||
border.color: MoneroComponents.Style.grey
|
||||
}
|
||||
|
||||
onMoved: parent.moved()
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,15 +29,24 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import FontAwesome 1.0
|
||||
|
||||
import "../components" as MoneroComponents
|
||||
|
||||
Item {
|
||||
id: button
|
||||
property bool fontAwesomeIcon: false
|
||||
property bool primary: true
|
||||
property string rightIcon: ""
|
||||
property string rightIconInactive: ""
|
||||
property string textColor: button.enabled? MoneroComponents.Style.buttonTextColor: MoneroComponents.Style.buttonTextColorDisabled
|
||||
property color textColor: !button.enabled
|
||||
? MoneroComponents.Style.buttonTextColorDisabled
|
||||
: primary
|
||||
? MoneroComponents.Style.buttonTextColor
|
||||
: MoneroComponents.Style.buttonSecondaryTextColor;
|
||||
property bool small: false
|
||||
property alias text: label.text
|
||||
property alias fontBold: label.font.bold
|
||||
property int fontSize: {
|
||||
if(small) return 14;
|
||||
else return 16;
|
||||
@@ -70,7 +79,9 @@ Item {
|
||||
when: buttonArea.containsMouse || button.focus
|
||||
PropertyChanges {
|
||||
target: buttonRect
|
||||
color: MoneroComponents.Style.buttonBackgroundColorHover
|
||||
color: primary
|
||||
? MoneroComponents.Style.buttonBackgroundColorHover
|
||||
: MoneroComponents.Style.buttonSecondaryBackgroundColorHover
|
||||
}
|
||||
},
|
||||
State {
|
||||
@@ -78,7 +89,9 @@ Item {
|
||||
when: button.enabled
|
||||
PropertyChanges {
|
||||
target: buttonRect
|
||||
color: MoneroComponents.Style.buttonBackgroundColor
|
||||
color: primary
|
||||
? MoneroComponents.Style.buttonBackgroundColor
|
||||
: MoneroComponents.Style.buttonSecondaryBackgroundColor
|
||||
}
|
||||
},
|
||||
State {
|
||||
@@ -125,7 +138,7 @@ Item {
|
||||
}
|
||||
|
||||
Image {
|
||||
visible: button.rightIcon !== ""
|
||||
visible: !fontAwesomeIcon && button.rightIcon !== ""
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
||||
width: button.small ? 16 : 20
|
||||
height: button.small ? 16 : 20
|
||||
@@ -136,6 +149,16 @@ Item {
|
||||
return button.rightIcon;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
font.family: FontAwesome.fontFamilySolid
|
||||
font.pixelSize: button.small ? 16 : 20
|
||||
font.styleName: "Solid"
|
||||
text: button.rightIcon
|
||||
visible: fontAwesomeIcon && button.rightIcon !== ""
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
|
||||
@@ -90,6 +90,10 @@ Rectangle {
|
||||
|
||||
function close() {
|
||||
root.visible = false;
|
||||
// reset button text
|
||||
okButton.text = qsTr("OK")
|
||||
cancelButton.text = qsTr("Cancel")
|
||||
|
||||
closeCallback();
|
||||
}
|
||||
|
||||
|
||||
@@ -58,11 +58,6 @@ Item {
|
||||
|
||||
onExpandedChanged: if(expanded) appWindow.currentItem = dropdown
|
||||
|
||||
// Workaroud for suspected memory leak in 5.8 causing malloc crash on app exit
|
||||
function update() {
|
||||
firstColText.text = columnid.currentIndex < repeater.model.rowCount() ? qsTr(repeater.model.get(columnid.currentIndex).column1) + translationManager.emptyString : ""
|
||||
}
|
||||
|
||||
Item {
|
||||
id: head
|
||||
anchors.left: parent.left
|
||||
@@ -80,15 +75,17 @@ Item {
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: firstColText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 12
|
||||
anchors.right: dropIndicator.left
|
||||
anchors.rightMargin: 12
|
||||
elide: Text.ElideRight
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.bold: dropdown.headerFontBold
|
||||
font.pixelSize: dropdown.fontHeaderSize
|
||||
color: dropdown.textColor
|
||||
text: columnid.currentIndex < repeater.model.count ? qsTr(repeater.model.get(columnid.currentIndex).column1) + translationManager.emptyString : ""
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -96,7 +93,8 @@ Item {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
width: 32
|
||||
anchors.rightMargin: 12
|
||||
width: dropdownIcon.width
|
||||
|
||||
Image {
|
||||
id: dropdownIcon
|
||||
@@ -214,7 +212,6 @@ Item {
|
||||
popup.close()
|
||||
columnid.currentIndex = index
|
||||
changed();
|
||||
dropdown.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ QtObject {
|
||||
property string textSelectedColor: blackTheme ? _b_textSelectedColor : _w_textSelectedColor
|
||||
|
||||
property string inputBoxBackground: blackTheme ? _b_inputBoxBackground : _w_inputBoxBackground
|
||||
property string inputBoxBackgroundDisabled: blackTheme ? _b_inputBoxBackgroundDisabled : _w_inputBoxBackgroundDisabled
|
||||
property string inputBoxBackgroundError: blackTheme ? _b_inputBoxBackgroundError : _w_inputBoxBackgroundError
|
||||
property string inputBoxColor: blackTheme ? _b_inputBoxColor : _w_inputBoxColor
|
||||
property string legacy_placeholderFontColor: blackTheme ? _b_legacy_placeholderFontColor : _w_legacy_placeholderFontColor
|
||||
@@ -43,6 +44,9 @@ QtObject {
|
||||
property string buttonInlineBackgroundColor: blackTheme ? _b_buttonInlineBackgroundColor : _w_buttonInlineBackgroundColor
|
||||
property string buttonTextColor: blackTheme ? _b_buttonTextColor : _w_buttonTextColor
|
||||
property string buttonTextColorDisabled: blackTheme ? _b_buttonTextColorDisabled : _w_buttonTextColorDisabled
|
||||
property string buttonSecondaryBackgroundColor: "#d9d9d9"
|
||||
property string buttonSecondaryBackgroundColorHover: "#a6a6a6"
|
||||
property string buttonSecondaryTextColor: "#4d4d4d"
|
||||
property string dividerColor: blackTheme ? _b_dividerColor : _w_dividerColor
|
||||
property real dividerOpacity: blackTheme ? _b_dividerOpacity : _w_dividerOpacity
|
||||
|
||||
@@ -85,6 +89,7 @@ QtObject {
|
||||
property string _b_textSelectedColor: "white"
|
||||
|
||||
property string _b_inputBoxBackground: "black"
|
||||
property string _b_inputBoxBackgroundDisabled: Qt.rgba(255, 255, 255, 0.10)
|
||||
property string _b_inputBoxBackgroundError: "#FFDDDD"
|
||||
property string _b_inputBoxColor: "white"
|
||||
property string _b_legacy_placeholderFontColor: "#BABABA"
|
||||
@@ -141,6 +146,7 @@ QtObject {
|
||||
property string _w_textSelectedColor: "black"
|
||||
|
||||
property string _w_inputBoxBackground: "white"
|
||||
property string _w_inputBoxBackgroundDisabled: Qt.rgba(0, 0, 0, 0.20)
|
||||
property string _w_inputBoxBackgroundError: "#FFDDDD"
|
||||
property string _w_inputBoxColor: "black"
|
||||
property string _w_legacy_placeholderFontColor: "#BABABA"
|
||||
|
||||
191
components/SuccessfulTxDialog.qml
Normal file
@@ -0,0 +1,191 @@
|
||||
// Copyright (c) 2014-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.
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import moneroComponents.Clipboard 1.0
|
||||
import "../components" as MoneroComponents
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
x: parent.width/2 - root.width/2
|
||||
y: parent.height/2 - root.height/2
|
||||
// TODO: implement without hardcoding sizes
|
||||
width: 580
|
||||
height: 400
|
||||
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.rejected()
|
||||
}
|
||||
Keys.onEnterPressed: {
|
||||
root.close()
|
||||
root.accepted()
|
||||
}
|
||||
Keys.onReturnPressed: {
|
||||
root.close()
|
||||
root.accepted()
|
||||
}
|
||||
KeyNavigation.tab: doneButton
|
||||
|
||||
Clipboard { id: clipboard }
|
||||
|
||||
property var transactionID;
|
||||
|
||||
// same signals as Dialog has
|
||||
signal accepted()
|
||||
signal rejected()
|
||||
|
||||
function open(txid) {
|
||||
root.transactionID = txid;
|
||||
root.visible = true;
|
||||
root.forceActiveFocus();
|
||||
}
|
||||
|
||||
function close() {
|
||||
root.visible = false;
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 10
|
||||
anchors.fill: parent
|
||||
anchors.margins: 25
|
||||
|
||||
ColumnLayout{
|
||||
Layout.topMargin: 10
|
||||
Layout.leftMargin: 0
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
MoneroComponents.Label {
|
||||
fontSize: 18
|
||||
fontFamily: "Arial"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: {
|
||||
if (appWindow.viewOnly){
|
||||
return qsTr("Transaction file successfully saved!") + translationManager.emptyString;
|
||||
} else {
|
||||
return qsTr("Transaction successfully sent!") + translationManager.emptyString;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: successImage
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
width: 140
|
||||
height: 140
|
||||
source: "qrc:///images/success.png"
|
||||
|
||||
SequentialAnimation{
|
||||
running: successImage.visible
|
||||
ScaleAnimator { target: successImage; from: 0.4; to: 1.3; duration: 125}
|
||||
ScaleAnimator { target: successImage; from: 1.3; to: 1; duration: 80}
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.LineEditMulti {
|
||||
visible: !appWindow.viewOnly
|
||||
Layout.leftMargin: 25
|
||||
Layout.rightMargin: 25
|
||||
borderDisabled: true
|
||||
readOnly: true
|
||||
copyButton: true
|
||||
wrapMode: Text.Wrap
|
||||
labelText: qsTr("Transaction ID:") + translationManager.emptyString
|
||||
text: root.transactionID ? root.transactionID : "";
|
||||
fontSize: 16
|
||||
}
|
||||
|
||||
MoneroComponents.LineEditMulti {
|
||||
visible: appWindow.viewOnly
|
||||
Layout.leftMargin: 25
|
||||
borderDisabled: true
|
||||
readOnly: true
|
||||
wrapMode: Text.Wrap
|
||||
labelText: qsTr("Transaction file location:") + translationManager.emptyString
|
||||
text: walletManager.urlToLocalPath(saveTxDialog.fileUrl)
|
||||
fontSize: 16
|
||||
}
|
||||
|
||||
// open folder / done buttons
|
||||
RowLayout {
|
||||
id: buttons
|
||||
spacing: 70
|
||||
Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 50
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
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()
|
||||
}
|
||||
onClicked: {
|
||||
root.close()
|
||||
root.accepted()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -309,8 +309,8 @@ Rectangle {
|
||||
width: 16
|
||||
image: MoneroComponents.Style.titleBarCloseSource
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
fontAwesomeFallbackIcon: FontAwesome.timesRectangle
|
||||
fontAwesomeFallbackSize: 18
|
||||
fontAwesomeFallbackIcon: FontAwesome.times
|
||||
fontAwesomeFallbackSize: 21
|
||||
fontAwesomeFallbackOpacity: MoneroComponents.Style.blackTheme ? 0.8 : 0.6
|
||||
opacity: 0.75
|
||||
}
|
||||
|
||||
204
components/UpdateDialog.qml
Normal file
@@ -0,0 +1,204 @@
|
||||
// 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.
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import moneroComponents.Downloader 1.0
|
||||
|
||||
import "../components" as MoneroComponents
|
||||
|
||||
Popup {
|
||||
id: updateDialog
|
||||
|
||||
property bool active: false
|
||||
property bool allowed: true
|
||||
property string error: ""
|
||||
property string filename: ""
|
||||
property string hash: ""
|
||||
property double progress: url && downloader.total > 0 ? downloader.loaded * 100 / downloader.total : 0
|
||||
property string url: ""
|
||||
property bool valid: false
|
||||
property string version: ""
|
||||
|
||||
background: Rectangle {
|
||||
border.color: MoneroComponents.Style.appWindowBorderColor
|
||||
border.width: 1
|
||||
color: MoneroComponents.Style.middlePanelBackgroundColor
|
||||
}
|
||||
closePolicy: Popup.NoAutoClose
|
||||
padding: 20
|
||||
visible: active && allowed
|
||||
|
||||
function show(version, url, hash) {
|
||||
updateDialog.error = "";
|
||||
updateDialog.hash = hash;
|
||||
updateDialog.url = url;
|
||||
updateDialog.valid = false;
|
||||
updateDialog.version = version;
|
||||
updateDialog.active = true;
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
spacing: updateDialog.padding
|
||||
|
||||
Text {
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
font.bold: true
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 18
|
||||
text: qsTr("New Monero version v%1 is available.").arg(updateDialog.version)
|
||||
}
|
||||
|
||||
Text {
|
||||
id: errorText
|
||||
color: "red"
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 18
|
||||
text: updateDialog.error
|
||||
visible: text
|
||||
}
|
||||
|
||||
Text {
|
||||
id: statusText
|
||||
color: updateDialog.valid ? MoneroComponents.Style.green : MoneroComponents.Style.defaultFontColor
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 18
|
||||
visible: !errorText.visible
|
||||
|
||||
text: {
|
||||
if (!updateDialog.url) {
|
||||
return qsTr("Please visit getmonero.org for details") + translationManager.emptyString;
|
||||
}
|
||||
if (downloader.active) {
|
||||
return "%1 (%2%)"
|
||||
.arg(qsTr("Downloading"))
|
||||
.arg(updateDialog.progress.toFixed(1))
|
||||
+ translationManager.emptyString;
|
||||
}
|
||||
if (updateDialog.valid) {
|
||||
return qsTr("Update downloaded, signature verified") + translationManager.emptyString;
|
||||
}
|
||||
return qsTr("Do you want to download and verify new version?") + translationManager.emptyString;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: progressBar
|
||||
color: MoneroComponents.Style.lightGreyFontColor
|
||||
height: 3
|
||||
Layout.fillWidth: true
|
||||
visible: updateDialog.valid || downloader.active
|
||||
|
||||
Rectangle {
|
||||
color: MoneroComponents.Style.buttonBackgroundColor
|
||||
height: parent.height
|
||||
width: parent.width * updateDialog.progress / 100
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
spacing: parent.spacing
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
id: cancelButton
|
||||
fontBold: false
|
||||
primary: !updateDialog.url
|
||||
text: {
|
||||
if (!updateDialog.url) {
|
||||
return qsTr("Ok") + translationManager.emptyString;
|
||||
}
|
||||
if (updateDialog.valid || downloader.active || errorText.visible) {
|
||||
return qsTr("Cancel") + translationManager.emptyString;
|
||||
}
|
||||
return qsTr("Download later") + translationManager.emptyString;
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
downloader.cancel();
|
||||
updateDialog.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
id: downloadButton
|
||||
KeyNavigation.tab: cancelButton
|
||||
fontBold: false
|
||||
text: (updateDialog.error ? qsTr("Retry") : qsTr("Download")) + translationManager.emptyString
|
||||
visible: updateDialog.url && !updateDialog.valid && !downloader.active
|
||||
|
||||
onClicked: {
|
||||
updateDialog.error = "";
|
||||
updateDialog.filename = updateDialog.url.replace(/^.*\//, '');
|
||||
const downloadingStarted = downloader.get(updateDialog.url, updateDialog.hash, function(error) {
|
||||
if (error) {
|
||||
console.error("Download failed", error);
|
||||
updateDialog.error = qsTr("Download failed") + translationManager.emptyString;
|
||||
} else {
|
||||
updateDialog.valid = true;
|
||||
}
|
||||
});
|
||||
if (!downloadingStarted) {
|
||||
updateDialog.error = qsTr("Failed to start download") + translationManager.emptyString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
id: saveButton
|
||||
KeyNavigation.tab: cancelButton
|
||||
fontBold: false
|
||||
onClicked: {
|
||||
const fullPath = oshelper.openSaveFileDialog(
|
||||
qsTr("Save as") + translationManager.emptyString,
|
||||
oshelper.downloadLocation(),
|
||||
updateDialog.filename);
|
||||
if (!fullPath) {
|
||||
return;
|
||||
}
|
||||
if (downloader.saveToFile(fullPath)) {
|
||||
cancelButton.clicked();
|
||||
oshelper.openContainingFolder(fullPath);
|
||||
} else {
|
||||
updateDialog.error = qsTr("Save operation failed") + translationManager.emptyString;
|
||||
}
|
||||
}
|
||||
text: qsTr("Save to file") + translationManager.emptyString
|
||||
visible: updateDialog.valid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Downloader {
|
||||
id: downloader
|
||||
proxyAddress: persistentSettings.getProxyAddress()
|
||||
}
|
||||
}
|
||||
@@ -149,6 +149,7 @@ Object {
|
||||
property string caretUp : "\uf0d8"
|
||||
property string cartArrowDown : "\uf218"
|
||||
property string cartPlus : "\uf217"
|
||||
property string cashRegister: "\uf788"
|
||||
property string cc : "\uf20a"
|
||||
property string ccAmex : "\uf1f3"
|
||||
property string ccDinersClub : "\uf24c"
|
||||
|
||||
@@ -17,7 +17,7 @@ if [ ! -d $MONERO_DIR/src ]; then
|
||||
fi
|
||||
git submodule update --remote
|
||||
git -C $MONERO_DIR fetch
|
||||
git -C $MONERO_DIR checkout v0.15.0.1
|
||||
git -C $MONERO_DIR checkout v0.17.0.1
|
||||
|
||||
# get monero core tag
|
||||
pushd $MONERO_DIR
|
||||
@@ -203,7 +203,7 @@ elif [ "$platform" == "linuxarmv7" ]; then
|
||||
if [ "$STATIC" == true ]; then
|
||||
cmake -D BUILD_TESTS=OFF -D ARCH="$ARCH" -D STATIC=ON -D BUILD_64=OFF -D BUILD_GUI_DEPS=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
else
|
||||
cmake -D BUILD_TESTS=OFF -D ARCH="$ARCH" -D -D BUILD_64=OFF -D BUILD_GUI_DEPS=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
cmake -D BUILD_TESTS=OFF -D ARCH="$ARCH" -D BUILD_64=OFF -D BUILD_GUI_DEPS=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
fi
|
||||
|
||||
## LINUX other
|
||||
|
||||
BIN
images/busy-indicator.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
images/busy-indicator@2x.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 493 B |
2
images/monero-vector.svg
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" viewBox="0 0 6000 6000" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><metadata><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata><defs><clipPath id="a"><path d="m0 4500h4500v-4500h-4500z"/></clipPath></defs><g transform="matrix(1.3333 0 0 -1.3333 0 6e3)"><g clip-path="url(#a)"><g transform="translate(4128 2250.2)"><path d="m0 0c0-1037.2-840.79-1878.1-1878.1-1878.1-1037.2 0-1878 840.88-1878 1878.1 0 1037.3 840.8 1878.1 1878 1878.1 1037.3 0 1878.1-840.79 1878.1-1878.1" fill="#fff"/></g><g transform="translate(2250 4128.2)"><path d="m0 0c-1036.9 0-1879.1-842.06-1877.8-1878 0.262-207.26 33.308-406.63 95.342-593.12h561.88v1579.9l1220.6-1220.6 1220.6 1220.6v-1579.9h561.96c62.117 186.48 95.008 385.85 95.369 593.12 1.809 1037-840.89 1877.8-1877.9 1877.8z" fill="#f36e36"/></g><g transform="translate(1969.3 1735.8)"><path d="m0 0-532.67 532.7v-994.14h-407.26l-384.29-0.07c329.63-540.8 925.35-902.56 1604.9-902.56 679.54 0 1275.3 361.85 1605 902.65l-384.44-0.013h-407.27v994.14l-813.3-813.31-280.62 280.61z" fill="#575757"/></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 596 B |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 440 B |
|
Before Width: | Height: | Size: 575 B |
BIN
images/success.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
images/success@2x.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -1,8 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="18" viewBox="0 0 10 18">
|
||||
<g fill="none" fill-rule="evenodd" opacity="1">
|
||||
<path fill="none" d="M-13-9h36v36h-36z" opacity="1"/>
|
||||
<g fill="#000" fill-rule="nonzero">
|
||||
<path d="M5 0C3.75 0 2.571.468 1.643 1.296A5.057 5.057 0 0 0 0 5.04c0 .396.321.72.714.72h.715a.72.72 0 0 0 .714-.72c0-.828.357-1.584.964-2.16A2.823 2.823 0 0 1 5 2.16c.107 0 .214 0 .321.036 1.322.144 2.358 1.224 2.5 2.52.143 1.188-.464 2.304-1.5 2.88-1.5.792-2.428 2.304-2.428 3.96v2.124c0 .396.321.72.714.72h.714a.72.72 0 0 0 .715-.72v-2.124c0-.828.5-1.62 1.285-2.052A4.98 4.98 0 0 0 9.93 4.5C9.714 2.16 7.857.288 5.57.036 5.393 0 5.18 0 5 0zM5.714 18H4.286a.358.358 0 0 1-.357-.36V16.2c0-.2.16-.36.357-.36h1.428c.198 0 .357.16.357.36v1.44c0 .2-.16.36-.357.36z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 848 B |
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2014-2019, The Monero Project
|
||||
Copyright (c) 2014-2020, The Monero Project
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
; Monero Carbon Chamaeleon GUI Wallet Installer for Windows
|
||||
; Copyright (c) 2017-2019, The Monero Project
|
||||
; Monero Oxygen Orion GUI Wallet Installer for Windows
|
||||
; Copyright (c) 2017-2020, The Monero Project
|
||||
; See LICENSE
|
||||
#define GuiVersion GetFileVersion("bin\monero-wallet-gui.exe")
|
||||
|
||||
@@ -11,7 +11,7 @@ AppName=Monero GUI Wallet
|
||||
|
||||
AppVersion={#GuiVersion}
|
||||
VersionInfoVersion={#GuiVersion}
|
||||
DefaultDirName={pf}\Monero GUI Wallet
|
||||
DefaultDirName={commonpf}\Monero GUI Wallet
|
||||
DefaultGroupName=Monero GUI Wallet
|
||||
UninstallDisplayIcon={app}\monero-wallet-gui.exe
|
||||
PrivilegesRequired=admin
|
||||
@@ -62,7 +62,6 @@ Name: "en"; MessagesFile: "compiler:Default.isl"
|
||||
; .exe/.dll file possibly with version info).
|
||||
;
|
||||
; This is far more robust than relying on version info or on file dates (flag "comparetimestamp").
|
||||
; As of version 0.15.0.0, the Monero .exe files do not carry version info anyway in their .exe headers.
|
||||
; The only small drawback seems to be somewhat longer update times because each and every file is
|
||||
; copied again, even if already present with correct file date and identical content.
|
||||
;
|
||||
@@ -71,17 +70,18 @@ Name: "en"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
Source: {#file AddBackslash(SourcePath) + "ReadMe.htm"}; DestDir: "{app}"; DestName: "ReadMe.htm"; Flags: ignoreversion
|
||||
Source: "FinishImage.bmp"; Flags: dontcopy
|
||||
Source: "LICENSE"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
||||
; Monero GUI wallet exe and guide
|
||||
Source: "bin\monero-wallet-gui.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\monero-gui-wallet-guide.pdf"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
||||
; Monero CLI wallet
|
||||
Source: "bin\monero-wallet-cli.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\monero-gen-trusted-multisig.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\extras\monero-wallet-cli.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\extras\monero-gen-trusted-multisig.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
||||
; Monero wallet RPC interface implementation
|
||||
Source: "bin\monero-wallet-rpc.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\extras\monero-wallet-rpc.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
||||
; Monero daemon
|
||||
Source: "bin\monerod.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
@@ -90,20 +90,24 @@ Source: "bin\monerod.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "monero-daemon.bat"; DestDir: "{app}"; Flags: ignoreversion;
|
||||
|
||||
; Monero blockchain utilities
|
||||
Source: "bin\monero-blockchain-export.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\monero-blockchain-import.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\monero-blockchain-mark-spent-outputs.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\monero-blockchain-usage.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\monero-blockchain-import.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\monero-blockchain-ancestry.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\monero-blockchain-depth.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\monero-blockchain-prune-known-spent-data.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\monero-blockchain-prune.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\monero-blockchain-stats.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\extras\monero-blockchain-export.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\extras\monero-blockchain-import.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\extras\monero-blockchain-mark-spent-outputs.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\extras\monero-blockchain-usage.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\extras\monero-blockchain-import.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\extras\monero-blockchain-ancestry.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\extras\monero-blockchain-depth.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\extras\monero-blockchain-prune-known-spent-data.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\extras\monero-blockchain-prune.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\extras\monero-blockchain-stats.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\extras\monero-gen-ssl-cert.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
||||
; 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
|
||||
|
||||
@@ -202,7 +206,7 @@ begin
|
||||
// Additional wizard page for entering a special blockchain location
|
||||
blockChainDefaultDir := ExpandConstant('{commonappdata}\bitmonero');
|
||||
s := 'The default folder to store the Monero blockchain is ' + blockChainDefaultDir;
|
||||
s := s + '. As this will need more than 74 GB of free space, you may want to use a folder on a different drive.';
|
||||
s := s + '. As this will need more than 90 GB of free space, you may want to use a folder on a different drive.';
|
||||
s := s + ' If yes, specify that folder here.';
|
||||
|
||||
BlockChainDirPage := CreateInputDirPage(wpSelectDir,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Monero GUI Wallet Windows Installer #
|
||||
|
||||
Copyright (c) 2017-2019, The Monero Project
|
||||
Copyright (c) 2017-2020, The Monero Project
|
||||
|
||||
## Introduction ##
|
||||
|
||||
This is a *Inno Setup* script `Monero.iss` plus some related files
|
||||
that allows you to build a standalone Windows installer (.exe) for
|
||||
the GUI wallet that comes with the Carbon Chamaeleon release of Monero.
|
||||
the GUI wallet that comes with the Oxygen Orion release of Monero.
|
||||
|
||||
This turns the GUI wallet into a more or less standard Windows program,
|
||||
by default installed into a subdirectory of `C:\Program Files`, a
|
||||
@@ -18,7 +18,7 @@ Monero.
|
||||
As the setup script in file [Monero.iss](Monero.iss) has to list many
|
||||
files and directories of the GUI wallet package to install by name,
|
||||
this version of the script only works with exactly the GUI wallet
|
||||
for Monero release *Carbon Chamaeleon* that you find on
|
||||
for Monero release *Oxygen Orion* that you find on
|
||||
[the official download page](https://getmonero.org/downloads/).
|
||||
|
||||
It should however be easy to modify the script for future
|
||||
@@ -32,15 +32,15 @@ See [LICENSE](LICENSE).
|
||||
|
||||
You can only build on Windows, and the result is always a
|
||||
Windows .exe file that can act as a standalone installer for the
|
||||
Carbon Chamaeleon GUI wallet.
|
||||
GUI wallet.
|
||||
|
||||
Note that the installer build process is now reproducible / deterministic. For details check the file [Deterministic.md](Deterministic.md).
|
||||
|
||||
The build steps in detail:
|
||||
|
||||
1. Install *Inno Setup*. You can get it from [here](http://www.jrsoftware.org/isdl.php)
|
||||
2. Get the Inno Setup script plus related files by cloning the whole [monero-gui GitHub repository](https://github.com/monero-project/monero-gui); you will only need the files in the installer directory `installers\windows` however. Depending on development state, additionally instead of simply using `master` you may have to checkout a specific branch, like `release-v0.15`.
|
||||
3. The setup script is written to take the GUI wallet files from a subdirectory named `bin`; so create `installers\windows\bin`, get the zip file of the GUI wallet from [here](https://getmonero.org/downloads/), unpack it somewhere, and copy all the files and subdirectories in the single subdirectory there (currently named `monero-gui-0.15.0.0`) to this `bin` subdirectory
|
||||
2. Get the Inno Setup script plus related files by cloning the whole [monero-gui GitHub repository](https://github.com/monero-project/monero-gui); you will only need the files in the installer directory `installers\windows` however. Depending on development state, additionally instead of simply using `master` you may have to checkout a specific branch, like `release-v0.17`.
|
||||
3. The setup script is written to take the GUI wallet files from a subdirectory named `bin`; so create `installers\windows\bin`, get the zip file of the GUI wallet from [here](https://getmonero.org/downloads/), unpack it somewhere, and copy all the files and subdirectories in the single subdirectory there (currently named `monero-gui-0.17.0.0`) to this `bin` subdirectory
|
||||
4. Start Inno Setup, load `Monero.iss` and compile it
|
||||
5. The result i.e. the finished installer will be the file `mysetup.exe` in the `installers\windows\Output` subdirectory
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Monero Carbon Chamaeleon GUI Wallet</title>
|
||||
<title>Monero Oxygen Orion GUI Wallet</title>
|
||||
</head>
|
||||
|
||||
<body style="font-family: Arial, Helvetica, sans-serif">
|
||||
<h1>Monero Carbon Chamaeleon GUI Wallet</h1>
|
||||
<h1>Monero Oxygen Orion GUI Wallet</h1>
|
||||
|
||||
<p>Copyright (c) 2014-2019, The Monero Project</p>
|
||||
<p>Copyright (c) 2014-2020, The Monero Project</p>
|
||||
|
||||
<h2>Preface</h2>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<h2>Content of the Package</h2>
|
||||
|
||||
<p>You just installed the <i>Monero GUI wallet</i> for Windows, release Carbon Chamaeleon, version {#GuiVersion}.
|
||||
<p>You just installed the <i>Monero GUI wallet</i> for Windows, release Oxygen Orion, version {#GuiVersion}.
|
||||
The wallet enables you to send and receive Moneroj in a secure and very private way.
|
||||
</p>
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
provides the most security and privacy possible for you.</p>
|
||||
|
||||
<p>However if your Internet access makes it difficult to run a full node, or if you have simply no room to store
|
||||
the blockchain locally (somewhat over 74 GB in November 2019, and of course growing), you can compromise and try to connect
|
||||
the blockchain locally (about 90 GB in May 2020, and of course growing), you can compromise and try to connect
|
||||
to a remote node. One way of finding such a node is checking
|
||||
<a href="https://moneroworld.com/#nodes">this page</a>.
|
||||
</p>
|
||||
@@ -104,7 +104,7 @@
|
||||
|
||||
<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
|
||||
<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
|
||||
seed!</b></p>
|
||||
|
||||
|
Before Width: | Height: | Size: 440 KiB After Width: | Height: | Size: 440 KiB |
42
js/Utils.js
@@ -55,36 +55,14 @@ function ago(epoch) {
|
||||
var now = new Date().getTime() / 1000;
|
||||
var delta = now - epoch;
|
||||
|
||||
if(delta < 60) {
|
||||
if (delta <= 1) {
|
||||
return 1 + " " + qsTr("second ago")
|
||||
} else {
|
||||
return Math.floor(delta) + " " + qsTr("seconds ago")
|
||||
}
|
||||
} else if (delta >= 60 && delta <= 3600) {
|
||||
if(delta >= 60 && delta < 120){
|
||||
return 1 + " " + qsTr("minute ago")
|
||||
} else {
|
||||
return parseInt(Math.floor(delta / 60)) + " " + qsTr("minutes ago")
|
||||
}
|
||||
} else if (delta >= 3600 && delta <= 86400) {
|
||||
if(delta >= 3600 && delta < 7200) {
|
||||
return 1 + " " + qsTr("hour ago")
|
||||
} else {
|
||||
return parseInt(Math.floor(delta / 60 / 60)) + " " + qsTr("hours ago")
|
||||
}
|
||||
} else if (delta >= 86400){
|
||||
if(delta >= 86400 && delta < 172800) {
|
||||
return 1 + " " + qsTr("day ago")
|
||||
} else {
|
||||
var _delta = parseInt(Math.floor(delta / 24 / 60 / 60));
|
||||
if(_delta === 1) {
|
||||
return 1 + " " + qsTr("day ago")
|
||||
} else {
|
||||
return _delta + " " + qsTr("days ago")
|
||||
}
|
||||
}
|
||||
}
|
||||
if(delta < 60)
|
||||
return qsTr("%n second(s) ago", "0", Math.floor(delta))
|
||||
else if (delta >= 60 && delta <= 3600)
|
||||
return qsTr("%n minute(s) ago", "0", Math.floor(delta / 60))
|
||||
else if (delta >= 3600 && delta <= 86400)
|
||||
return qsTr("%n hour(s) ago", "0", Math.floor(delta / 60 / 60))
|
||||
else if (delta >= 86400)
|
||||
return qsTr("%n day(s) ago", "0", Math.floor(delta / 24 / 60 / 60))
|
||||
}
|
||||
|
||||
function netTypeToString(){
|
||||
@@ -133,3 +111,7 @@ function capitalize(s){
|
||||
if (typeof s !== 'string') return ''
|
||||
return s.charAt(0).toUpperCase() + s.slice(1)
|
||||
}
|
||||
|
||||
function removeTrailingZeros(value) {
|
||||
return (value + '').replace(/(\.\d*[1-9])0+$/, '$1');
|
||||
}
|
||||
|
||||
15
js/Wizard.js
@@ -58,11 +58,6 @@ function switchPage(next) {
|
||||
}
|
||||
|
||||
function createWalletPath(isIOS, folder_path,account_name){
|
||||
// Remove trailing slash - (default on windows and mac)
|
||||
if (folder_path.substring(folder_path.length -1) === "/"){
|
||||
folder_path = folder_path.substring(0,folder_path.length -1)
|
||||
}
|
||||
|
||||
// Store releative path on ios.
|
||||
if(isIOS)
|
||||
folder_path = "";
|
||||
@@ -70,7 +65,7 @@ function createWalletPath(isIOS, folder_path,account_name){
|
||||
return folder_path + "/" + account_name + "/" + account_name
|
||||
}
|
||||
|
||||
function walletPathExists(directory, filename, isIOS, walletManager) {
|
||||
function walletPathExists(accountsDir, directory, filename, isIOS, walletManager) {
|
||||
if(!filename || filename === "") return false;
|
||||
if(!directory || directory === "") return false;
|
||||
|
||||
@@ -81,7 +76,7 @@ function walletPathExists(directory, filename, isIOS, walletManager) {
|
||||
directory += "/"
|
||||
|
||||
if(isIOS)
|
||||
var path = moneroAccountsDir + filename;
|
||||
var path = accountsDir + filename;
|
||||
else
|
||||
var path = directory + filename + "/" + filename;
|
||||
|
||||
@@ -102,10 +97,6 @@ function tr(text) {
|
||||
return qsTr(text) + translationManager.emptyString
|
||||
}
|
||||
|
||||
function lineBreaksToSpaces(text) {
|
||||
return text.trim().replace(/(\r\n|\n|\r)/gm, " ");
|
||||
}
|
||||
|
||||
function usefulName(path) {
|
||||
// arbitrary "short enough" limit
|
||||
if (path.length < 32)
|
||||
@@ -115,7 +106,7 @@ function usefulName(path) {
|
||||
|
||||
function checkSeed(seed) {
|
||||
console.log("Checking seed")
|
||||
var wordsArray = lineBreaksToSpaces(seed).split(" ");
|
||||
var wordsArray = seed.split(/\s+/);
|
||||
return wordsArray.length === 25 || wordsArray.length === 24
|
||||
}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 11 KiB |
@@ -53,7 +53,6 @@ Lojban
|
||||
<language display_name="Українська" locale="uk_UA" wallet_language="English" flag="/lang/flags/ua.png" qs="none"/>
|
||||
<language display_name="Lietuvių" locale="lt_LT" wallet_language="English" flag="/lang/flags/lt.png" qs="none"/>
|
||||
<language display_name="Suomi" locale="fi_FI" wallet_language="English" flag="/lang/flags/fi.png" qs="none"/>
|
||||
<language display_name="Pirate" locale="prt" wallet_language="English" flag="/lang/flags/pirate.png" qs="none"/>
|
||||
<language display_name="Български" locale="bg_BG" wallet_language="English" flag="/lang/flags/bg.png" qs="none"/>
|
||||
<language display_name="Norwegian" locale="nb_NO" wallet_language="English" flag="/lang/flags/nb_NO.png" qs="none"/>
|
||||
<!-- <language display_name="اُردُو" locale="ur_UR" wallet_language="English" flag="/lang/flags/pk.png" qs="none"/> -->
|
||||
|
||||
396
main.qml
@@ -33,7 +33,11 @@ import QtQuick.Controls.Styles 1.1
|
||||
import QtQuick.Dialogs 1.2
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import FontAwesome 1.0
|
||||
|
||||
import moneroComponents.Network 1.0
|
||||
import moneroComponents.Wallet 1.0
|
||||
import moneroComponents.WalletManager 1.0
|
||||
import moneroComponents.PendingTransaction 1.0
|
||||
import moneroComponents.NetworkType 1.0
|
||||
import moneroComponents.Settings 1.0
|
||||
@@ -45,6 +49,7 @@ import "pages/merchant" as MoneroMerchant
|
||||
import "wizard"
|
||||
import "js/Utils.js" as Utils
|
||||
import "js/Windows.js" as Windows
|
||||
import "version.js" as Version
|
||||
|
||||
ApplicationWindow {
|
||||
id: appWindow
|
||||
@@ -56,6 +61,7 @@ ApplicationWindow {
|
||||
property bool hideBalanceForced: false
|
||||
property bool ctrlPressed: false
|
||||
property alias persistentSettings : persistentSettings
|
||||
property string accountsDir: !persistentSettings.portable ? moneroAccountsDir : persistentSettings.portableFolderName + "/wallets"
|
||||
property var currentWallet;
|
||||
property bool disconnected: currentWallet ? currentWallet.disconnected : false
|
||||
property var transaction;
|
||||
@@ -66,12 +72,14 @@ ApplicationWindow {
|
||||
property bool walletSynced: false
|
||||
property int maxWindowHeight: (isAndroid || isIOS)? screenHeight : (screenHeight < 900)? 720 : 800;
|
||||
property bool daemonRunning: !persistentSettings.useRemoteNode && !disconnected
|
||||
property bool daemonStartStopInProgress: false
|
||||
property alias toolTip: toolTip
|
||||
property string walletName
|
||||
property bool viewOnly: false
|
||||
property bool foundNewBlock: false
|
||||
property bool qrScannerEnabled: (typeof builtWithScanner != "undefined") && builtWithScanner
|
||||
property int blocksToSync: 1
|
||||
property int firstBlockSeen
|
||||
property bool isMining: false
|
||||
property int walletMode: persistentSettings.walletMode
|
||||
property var cameraUi
|
||||
@@ -214,7 +222,7 @@ ApplicationWindow {
|
||||
appWindow.viewState = prevState;
|
||||
}
|
||||
};
|
||||
passwordDialog.open(usefulName(walletPath()));
|
||||
passwordDialog.open(usefulName(persistentSettings.wallet_path));
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
@@ -250,12 +258,11 @@ ApplicationWindow {
|
||||
|
||||
// enable timers
|
||||
userInActivityTimer.running = true;
|
||||
simpleModeConnectionTimer.running = true;
|
||||
|
||||
// wallet already opened with wizard, we just need to initialize it
|
||||
var wallet_path = walletPath();
|
||||
var wallet_path = persistentSettings.wallet_path;
|
||||
if(isIOS)
|
||||
wallet_path = moneroAccountsDir + wallet_path;
|
||||
wallet_path = appWindow.accountsDir + wallet_path;
|
||||
// console.log("opening wallet at: ", wallet_path, "with password: ", appWindow.walletPassword);
|
||||
console.log("opening wallet at: ", wallet_path, ", network type: ", persistentSettings.nettype == NetworkType.MAINNET ? "mainnet" : persistentSettings.nettype == NetworkType.TESTNET ? "testnet" : "stagenet");
|
||||
|
||||
@@ -291,6 +298,7 @@ ApplicationWindow {
|
||||
currentWallet.connectionStatusChanged.disconnect(onWalletConnectionStatusChanged)
|
||||
currentWallet.deviceButtonRequest.disconnect(onDeviceButtonRequest);
|
||||
currentWallet.deviceButtonPressed.disconnect(onDeviceButtonPressed);
|
||||
currentWallet.walletPassphraseNeeded.disconnect(onWalletPassphraseNeededWallet);
|
||||
currentWallet.transactionCommitted.disconnect(onTransactionCommitted);
|
||||
middlePanel.paymentClicked.disconnect(handlePayment);
|
||||
middlePanel.sweepUnmixableClicked.disconnect(handleSweepUnmixable);
|
||||
@@ -358,7 +366,9 @@ ApplicationWindow {
|
||||
currentWallet.connectionStatusChanged.connect(onWalletConnectionStatusChanged)
|
||||
currentWallet.deviceButtonRequest.connect(onDeviceButtonRequest);
|
||||
currentWallet.deviceButtonPressed.connect(onDeviceButtonPressed);
|
||||
currentWallet.walletPassphraseNeeded.connect(onWalletPassphraseNeededWallet);
|
||||
currentWallet.transactionCommitted.connect(onTransactionCommitted);
|
||||
currentWallet.proxyAddress = Qt.binding(persistentSettings.getWalletProxyAddress);
|
||||
middlePanel.paymentClicked.connect(handlePayment);
|
||||
middlePanel.sweepUnmixableClicked.connect(handleSweepUnmixable);
|
||||
middlePanel.getProofClicked.connect(handleGetProof);
|
||||
@@ -383,7 +393,9 @@ ApplicationWindow {
|
||||
0,
|
||||
persistentSettings.is_recovering,
|
||||
persistentSettings.is_recovering_from_device,
|
||||
persistentSettings.restore_height);
|
||||
persistentSettings.restore_height,
|
||||
persistentSettings.getWalletProxyAddress());
|
||||
|
||||
// save wallet keys in case wallet settings have been changed in the init
|
||||
currentWallet.setPassword(walletPassword);
|
||||
}
|
||||
@@ -392,11 +404,6 @@ ApplicationWindow {
|
||||
return !persistentSettings.useRemoteNode || persistentSettings.is_trusted_daemon;
|
||||
}
|
||||
|
||||
function walletPath() {
|
||||
var wallet_path = persistentSettings.wallet_path
|
||||
return wallet_path;
|
||||
}
|
||||
|
||||
function usefulName(path) {
|
||||
// arbitrary "short enough" limit
|
||||
if (path.length < 32)
|
||||
@@ -429,6 +436,10 @@ ApplicationWindow {
|
||||
leftPanel.minutesToUnlock = (balance !== balanceU) ? currentWallet.history.minutesToUnlock : "";
|
||||
leftPanel.balanceString = balance
|
||||
leftPanel.balanceUnlockedString = balanceU
|
||||
if (middlePanel.state === "Account") {
|
||||
middlePanel.accountView.balanceAllText = walletManager.displayAmount(appWindow.currentWallet.balanceAll());
|
||||
middlePanel.accountView.unlockedBalanceAllText = walletManager.displayAmount(appWindow.currentWallet.unlockedBalanceAll());
|
||||
}
|
||||
}
|
||||
|
||||
function onUriHandler(uri){
|
||||
@@ -474,9 +485,9 @@ ApplicationWindow {
|
||||
console.log("Wallet connection status changed " + status)
|
||||
middlePanel.updateStatus();
|
||||
leftPanel.networkStatus.connected = status
|
||||
|
||||
// Update fee multiplier dropdown on transfer page
|
||||
middlePanel.transferView.updatePriorityDropdown();
|
||||
if (status == Wallet.ConnectionStatus_Disconnected) {
|
||||
firstBlockSeen = 0;
|
||||
}
|
||||
|
||||
// If wallet isnt connected, advanced wallet mode and no daemon is running - Ask
|
||||
if (appWindow.walletMode >= 2 && !persistentSettings.useRemoteNode && !walletInitialized && disconnected) {
|
||||
@@ -558,19 +569,32 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
function onWalletPassphraseNeeded(){
|
||||
function onWalletPassphraseNeededManager(on_device){
|
||||
onWalletPassphraseNeeded(walletManager, on_device)
|
||||
}
|
||||
|
||||
function onWalletPassphraseNeededWallet(on_device){
|
||||
onWalletPassphraseNeeded(currentWallet, on_device)
|
||||
}
|
||||
|
||||
function onWalletPassphraseNeeded(handler, on_device){
|
||||
hideProcessingSplash();
|
||||
|
||||
console.log(">>> wallet passphrase needed: ")
|
||||
passwordDialog.onAcceptedPassphraseCallback = function() {
|
||||
walletManager.onPassphraseEntered(passwordDialog.password);
|
||||
devicePassphraseDialog.onAcceptedCallback = function(passphrase) {
|
||||
handler.onPassphraseEntered(passphrase, false, false);
|
||||
appWindow.onWalletOpening();
|
||||
}
|
||||
passwordDialog.onRejectedPassphraseCallback = function() {
|
||||
walletManager.onPassphraseEntered("", true);
|
||||
devicePassphraseDialog.onWalletEntryCallback = function() {
|
||||
handler.onPassphraseEntered("", true, false);
|
||||
appWindow.onWalletOpening();
|
||||
}
|
||||
passwordDialog.openPassphraseDialog()
|
||||
devicePassphraseDialog.onRejectedCallback = function() {
|
||||
handler.onPassphraseEntered("", false, true);
|
||||
appWindow.onWalletOpening();
|
||||
}
|
||||
|
||||
devicePassphraseDialog.open(on_device)
|
||||
}
|
||||
|
||||
function onWalletUpdate() {
|
||||
@@ -593,7 +617,14 @@ ApplicationWindow {
|
||||
const callback = function() {
|
||||
persistentSettings.useRemoteNode = true;
|
||||
currentDaemonAddress = persistentSettings.remoteNodeAddress;
|
||||
currentWallet.initAsync(currentDaemonAddress, isTrustedDaemon());
|
||||
currentWallet.initAsync(
|
||||
currentDaemonAddress,
|
||||
isTrustedDaemon(),
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
persistentSettings.getWalletProxyAddress());
|
||||
walletManager.setDaemonAddressAsync(currentDaemonAddress);
|
||||
};
|
||||
|
||||
@@ -611,20 +642,31 @@ ApplicationWindow {
|
||||
console.log("disconnecting remote node");
|
||||
persistentSettings.useRemoteNode = false;
|
||||
currentDaemonAddress = localDaemonAddress
|
||||
currentWallet.initAsync(currentDaemonAddress, isTrustedDaemon());
|
||||
currentWallet.initAsync(
|
||||
currentDaemonAddress,
|
||||
isTrustedDaemon(),
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
persistentSettings.getWalletProxyAddress());
|
||||
walletManager.setDaemonAddressAsync(currentDaemonAddress);
|
||||
firstBlockSeen = 0;
|
||||
}
|
||||
|
||||
function onHeightRefreshed(bcHeight, dCurrentBlock, dTargetBlock) {
|
||||
// Daemon fully synced
|
||||
// TODO: implement onDaemonSynced or similar in wallet API and don't start refresh thread before daemon is synced
|
||||
// targetBlock = currentBlock = 1 before network connection is established.
|
||||
if (firstBlockSeen == 0 && dTargetBlock != 1) {
|
||||
firstBlockSeen = dCurrentBlock;
|
||||
}
|
||||
daemonSynced = dCurrentBlock >= dTargetBlock && dTargetBlock != 1
|
||||
walletSynced = bcHeight >= dTargetBlock
|
||||
|
||||
// Update progress bars
|
||||
if(!daemonSynced) {
|
||||
leftPanel.daemonProgressBar.updateProgress(dCurrentBlock,dTargetBlock, dTargetBlock-dCurrentBlock);
|
||||
leftPanel.daemonProgressBar.updateProgress(dCurrentBlock,dTargetBlock, dTargetBlock-firstBlockSeen);
|
||||
leftPanel.progressBar.updateProgress(0,dTargetBlock, dTargetBlock, qsTr("Waiting for daemon to sync"));
|
||||
} else {
|
||||
leftPanel.daemonProgressBar.updateProgress(dCurrentBlock,dTargetBlock, 0, qsTr("Daemon is synchronized (%1)").arg(dCurrentBlock.toFixed(0)));
|
||||
@@ -665,12 +707,11 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
function startDaemon(flags){
|
||||
daemonStartStopInProgress = true;
|
||||
|
||||
// Pause refresh while starting daemon
|
||||
currentWallet.pauseRefresh();
|
||||
|
||||
// Pause simplemode connection timer
|
||||
simpleModeConnectionTimer.stop();
|
||||
|
||||
appWindow.showProcessingSplash(qsTr("Waiting for daemon to start..."))
|
||||
const noSync = appWindow.walletMode === 0;
|
||||
const bootstrapNodeAddress = persistentSettings.walletMode < 2 ? "auto" : persistentSettings.bootstrapNodeAddress
|
||||
@@ -678,8 +719,10 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
function stopDaemon(callback){
|
||||
daemonStartStopInProgress = true;
|
||||
appWindow.showProcessingSplash(qsTr("Waiting for daemon to stop..."))
|
||||
daemonManager.stopAsync(persistentSettings.nettype, function(result) {
|
||||
daemonStartStopInProgress = false;
|
||||
hideProcessingSplash();
|
||||
callback(result);
|
||||
});
|
||||
@@ -687,13 +730,13 @@ ApplicationWindow {
|
||||
|
||||
function onDaemonStarted(){
|
||||
console.log("daemon started");
|
||||
daemonStartStopInProgress = false;
|
||||
hideProcessingSplash();
|
||||
currentWallet.connected(true);
|
||||
// resume refresh
|
||||
currentWallet.startRefresh();
|
||||
// resume simplemode connection timer
|
||||
appWindow.disconnectedEpoch = Utils.epoch();
|
||||
simpleModeConnectionTimer.start();
|
||||
}
|
||||
function onDaemonStopped(){
|
||||
currentWallet.connected(true);
|
||||
@@ -701,6 +744,7 @@ ApplicationWindow {
|
||||
|
||||
function onDaemonStartFailure(error) {
|
||||
console.log("daemon start failed");
|
||||
daemonStartStopInProgress = false;
|
||||
hideProcessingSplash();
|
||||
// resume refresh
|
||||
currentWallet.startRefresh();
|
||||
@@ -758,7 +802,7 @@ ApplicationWindow {
|
||||
function walletsFound() {
|
||||
if (persistentSettings.wallet_path.length > 0) {
|
||||
if(isIOS)
|
||||
return walletManager.walletExists(moneroAccountsDir + persistentSettings.wallet_path);
|
||||
return walletManager.walletExists(appWindow.accountsDir + persistentSettings.wallet_path);
|
||||
else
|
||||
return walletManager.walletExists(persistentSettings.wallet_path);
|
||||
}
|
||||
@@ -873,7 +917,7 @@ ApplicationWindow {
|
||||
FileDialog {
|
||||
id: saveTxDialog
|
||||
title: "Please choose a location"
|
||||
folder: "file://" +moneroAccountsDir
|
||||
folder: "file://" + appWindow.accountsDir
|
||||
selectExisting: false;
|
||||
|
||||
onAccepted: {
|
||||
@@ -970,13 +1014,18 @@ ApplicationWindow {
|
||||
|
||||
// Clear tx fields
|
||||
middlePanel.transferView.clearFields()
|
||||
successfulTxPopup.open(txid)
|
||||
|
||||
}
|
||||
informationPopup.onCloseCallback = null
|
||||
informationPopup.open()
|
||||
currentWallet.refresh()
|
||||
currentWallet.disposeTransaction(transaction)
|
||||
currentWallet.store();
|
||||
currentWallet.storeAsync(function(success) {
|
||||
if (!success) {
|
||||
appWindow.showStatusMessage(qsTr("Failed to store the wallet"), 3);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// called on "getProof"
|
||||
@@ -1076,7 +1125,6 @@ ApplicationWindow {
|
||||
console.log("Displaying processing splash")
|
||||
if (typeof message != 'undefined') {
|
||||
splash.messageText = message
|
||||
splash.heightProgressText = ""
|
||||
}
|
||||
|
||||
leftPanel.enabled = false;
|
||||
@@ -1103,14 +1151,15 @@ ApplicationWindow {
|
||||
wizard.restart();
|
||||
wizard.wizardState = "wizardHome";
|
||||
rootItem.state = "wizard"
|
||||
// reset balance
|
||||
// reset balance, clear spendable funds message
|
||||
clearMoneroCardLabelText();
|
||||
leftPanel.minutesToUnlock = "";
|
||||
// reset fields
|
||||
middlePanel.addressBookView.clearFields();
|
||||
middlePanel.transferView.clearFields();
|
||||
middlePanel.receiveView.clearFields();
|
||||
// disable timers
|
||||
userInActivityTimer.running = false;
|
||||
simpleModeConnectionTimer.running = false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1135,9 +1184,9 @@ ApplicationWindow {
|
||||
triggeredOnStart: false
|
||||
}
|
||||
|
||||
function fiatApiParseTicker(resp, currency){
|
||||
function fiatApiParseTicker(url, resp, currency){
|
||||
// parse & validate incoming JSON
|
||||
if(resp._url.startsWith("https://api.kraken.com/0/")){
|
||||
if(url.startsWith("https://api.kraken.com/0/")){
|
||||
if(resp.hasOwnProperty("error") && resp.error.length > 0 || !resp.hasOwnProperty("result")){
|
||||
appWindow.fiatApiError("Kraken API has error(s)");
|
||||
return;
|
||||
@@ -1146,14 +1195,14 @@ ApplicationWindow {
|
||||
var key = currency === "xmreur" ? "XXMRZEUR" : "XXMRZUSD";
|
||||
var ticker = resp.result[key]["o"];
|
||||
return ticker;
|
||||
} else if(resp._url.startsWith("https://api.coingecko.com/api/v3/")){
|
||||
} else if(url.startsWith("https://api.coingecko.com/api/v3/")){
|
||||
var key = currency === "xmreur" ? "eur" : "usd";
|
||||
if(!resp.hasOwnProperty("monero") || !resp["monero"].hasOwnProperty(key)){
|
||||
appWindow.fiatApiError("Coingecko API has error(s)");
|
||||
return;
|
||||
}
|
||||
return resp["monero"][key];
|
||||
} else if(resp._url.startsWith("https://min-api.cryptocompare.com/data/")){
|
||||
} else if(url.startsWith("https://min-api.cryptocompare.com/data/")){
|
||||
var key = currency === "xmreur" ? "EUR" : "USD";
|
||||
if(!resp.hasOwnProperty(key)){
|
||||
appWindow.fiatApiError("cryptocompare API has error(s)");
|
||||
@@ -1163,13 +1212,7 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
function fiatApiGetCurrency(resp){
|
||||
// map response to `appWindow.fiatPriceAPIs` object
|
||||
if (!resp.hasOwnProperty('_url')){
|
||||
appWindow.fiatApiError("invalid JSON");
|
||||
return;
|
||||
}
|
||||
|
||||
function fiatApiGetCurrency(url) {
|
||||
var apis = appWindow.fiatPriceAPIs;
|
||||
for (var api in apis){
|
||||
if (!apis.hasOwnProperty(api))
|
||||
@@ -1179,23 +1222,34 @@ ApplicationWindow {
|
||||
if(!apis[api].hasOwnProperty(cur))
|
||||
continue;
|
||||
|
||||
var url = apis[api][cur];
|
||||
if(url === resp._url){
|
||||
if (apis[api][cur] === url) {
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fiatApiJsonReceived(resp){
|
||||
function fiatApiJsonReceived(url, resp, error) {
|
||||
if (error) {
|
||||
appWindow.fiatApiError(error);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
resp = JSON.parse(resp);
|
||||
} catch (e) {
|
||||
appWindow.fiatApiError("bad JSON: " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
// handle incoming JSON, set ticker
|
||||
var currency = appWindow.fiatApiGetCurrency(resp);
|
||||
var currency = appWindow.fiatApiGetCurrency(url);
|
||||
if(typeof currency == "undefined"){
|
||||
appWindow.fiatApiError("could not get currency");
|
||||
return;
|
||||
}
|
||||
|
||||
var ticker = appWindow.fiatApiParseTicker(resp, currency);
|
||||
var ticker = appWindow.fiatApiParseTicker(url, resp, currency);
|
||||
if(ticker <= 0){
|
||||
appWindow.fiatApiError("could not get ticker");
|
||||
return;
|
||||
@@ -1227,7 +1281,7 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
var url = provider[userCurrency];
|
||||
Prices.getJSON(url);
|
||||
network.getJSON(url, fiatApiJsonReceived);
|
||||
}
|
||||
|
||||
function fiatApiCurrencySymbol() {
|
||||
@@ -1283,9 +1337,8 @@ ApplicationWindow {
|
||||
walletManager.deviceButtonRequest.connect(onDeviceButtonRequest);
|
||||
walletManager.deviceButtonPressed.connect(onDeviceButtonPressed);
|
||||
walletManager.checkUpdatesComplete.connect(onWalletCheckUpdatesComplete);
|
||||
walletManager.walletPassphraseNeeded.connect(onWalletPassphraseNeeded);
|
||||
walletManager.walletPassphraseNeeded.connect(onWalletPassphraseNeededManager);
|
||||
IPC.uriHandler.connect(onUriHandler);
|
||||
Prices.priceJsonReceived.connect(appWindow.fiatApiJsonReceived);
|
||||
|
||||
if(typeof daemonManager != "undefined") {
|
||||
daemonManager.daemonStarted.connect(onDaemonStarted);
|
||||
@@ -1317,8 +1370,6 @@ ApplicationWindow {
|
||||
openWallet("wizard");
|
||||
}
|
||||
|
||||
checkUpdates();
|
||||
|
||||
if(persistentSettings.fiatPriceEnabled){
|
||||
appWindow.fiatApiRefresh();
|
||||
appWindow.fiatTimerStart();
|
||||
@@ -1363,16 +1414,39 @@ ApplicationWindow {
|
||||
property int segregationHeight: 0
|
||||
property int kdfRounds: 1
|
||||
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 checkForUpdates: true
|
||||
property bool autosave: true
|
||||
property int autosaveMinutes: 10
|
||||
|
||||
property bool fiatPriceEnabled: false
|
||||
property bool fiatPriceToggle: false
|
||||
property string fiatPriceProvider: "kraken"
|
||||
property string fiatPriceCurrency: "xmrusd"
|
||||
|
||||
property string proxyAddress: "127.0.0.1:9050"
|
||||
property bool proxyEnabled: isTails
|
||||
function getProxyAddress() {
|
||||
if ((socksProxyFlagSet && socksProxyFlag == "") || !proxyEnabled) {
|
||||
return "";
|
||||
}
|
||||
var proxyAddressSetOrForced = socksProxyFlagSet ? socksProxyFlag : proxyAddress;
|
||||
if (proxyAddressSetOrForced == "") {
|
||||
return "127.0.0.1:0";
|
||||
}
|
||||
return proxyAddressSetOrForced;
|
||||
}
|
||||
function getWalletProxyAddress() {
|
||||
if (!useRemoteNode) {
|
||||
return "";
|
||||
}
|
||||
return getProxyAddress();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
MoneroComponents.Style.blackTheme = persistentSettings.blackTheme
|
||||
}
|
||||
@@ -1398,24 +1472,41 @@ ApplicationWindow {
|
||||
z: parent.z + 1
|
||||
id: transactionConfirmationPopup
|
||||
onAccepted: {
|
||||
var handleAccepted = function() {
|
||||
// Save transaction to file if view only wallet
|
||||
if (viewOnly) {
|
||||
saveTxDialog.open();
|
||||
} else {
|
||||
handleTransactionConfirmed()
|
||||
}
|
||||
}
|
||||
close();
|
||||
passwordDialog.onAcceptedCallback = function() {
|
||||
if(walletPassword === passwordDialog.password){
|
||||
// Save transaction to file if view only wallet
|
||||
if(viewOnly) {
|
||||
saveTxDialog.open();
|
||||
} else {
|
||||
handleTransactionConfirmed()
|
||||
}
|
||||
handleAccepted()
|
||||
} else {
|
||||
passwordDialog.showError(qsTr("Wrong password") + translationManager.emptyString);
|
||||
}
|
||||
}
|
||||
passwordDialog.onRejectedCallback = null;
|
||||
passwordDialog.open()
|
||||
if(!persistentSettings.askPasswordBeforeSending) {
|
||||
handleAccepted()
|
||||
} else {
|
||||
passwordDialog.open(
|
||||
"",
|
||||
"",
|
||||
(appWindow.viewOnly ? qsTr("Save transaction file") : qsTr("Send transaction")) + translationManager.emptyString,
|
||||
appWindow.viewOnly ? "" : FontAwesome.arrowCircleRight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction successfully sent popup
|
||||
SuccessfulTxDialog {
|
||||
id: successfulTxPopup
|
||||
z: parent.z + 1
|
||||
}
|
||||
|
||||
StandardDialog {
|
||||
z: parent.z + 1
|
||||
id: confirmationDialog
|
||||
@@ -1432,6 +1523,14 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.UpdateDialog {
|
||||
id: updateDialog
|
||||
|
||||
allowed: !passwordDialog.visible && !inputDialog.visible && !splash.visible
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
}
|
||||
|
||||
// Choose blockchain folder
|
||||
FileDialog {
|
||||
id: blockchainFileDialog
|
||||
@@ -1461,7 +1560,6 @@ ApplicationWindow {
|
||||
confirmationDialog.text += qsTr("Note: lmdb folder not found. A new folder will be created.") + "\n\n"
|
||||
|
||||
confirmationDialog.icon = StandardIcon.Question
|
||||
confirmationDialog.cancelText = qsTr("Cancel")
|
||||
|
||||
// Continue
|
||||
confirmationDialog.onAcceptedCallback = function() {
|
||||
@@ -1481,12 +1579,10 @@ ApplicationWindow {
|
||||
PasswordDialog {
|
||||
id: passwordDialog
|
||||
visible: false
|
||||
z: parent.z + 1
|
||||
z: parent.z + 2
|
||||
anchors.fill: parent
|
||||
property var onAcceptedCallback
|
||||
property var onRejectedCallback
|
||||
property var onAcceptedPassphraseCallback
|
||||
property var onRejectedPassphraseCallback
|
||||
onAccepted: {
|
||||
if (onAcceptedCallback)
|
||||
onAcceptedCallback();
|
||||
@@ -1510,14 +1606,13 @@ ApplicationWindow {
|
||||
informationPopup.open();
|
||||
}
|
||||
onRejectedNewPassword: {}
|
||||
onAcceptedPassphrase: {
|
||||
if (onAcceptedPassphraseCallback)
|
||||
onAcceptedPassphraseCallback();
|
||||
}
|
||||
onRejectedPassphrase: {
|
||||
if (onRejectedPassphraseCallback)
|
||||
onRejectedPassphraseCallback();
|
||||
}
|
||||
}
|
||||
|
||||
DevicePassphraseDialog {
|
||||
id: devicePassphraseDialog
|
||||
visible: false
|
||||
z: parent.z + 1
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
InputDialog {
|
||||
@@ -1548,8 +1643,8 @@ ApplicationWindow {
|
||||
|
||||
ProcessingSplash {
|
||||
id: splash
|
||||
width: appWindow.width / 1.5
|
||||
height: appWindow.height / 2
|
||||
width: appWindow.width / 2
|
||||
height: appWindow.height / 2.66
|
||||
x: (appWindow.width - width) / 2
|
||||
y: (appWindow.height - height) / 2
|
||||
messageText: qsTr("Please wait...") + translationManager.emptyString
|
||||
@@ -1607,12 +1702,6 @@ ApplicationWindow {
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onMerchantClicked: {
|
||||
middlePanel.state = "Merchant";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onTxkeyClicked: {
|
||||
middlePanel.state = "TxKey";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
@@ -1687,16 +1776,10 @@ ApplicationWindow {
|
||||
anchors.fill: blurredArea
|
||||
source: blurredArea
|
||||
radius: 64
|
||||
visible: passwordDialog.visible || inputDialog.visible || splash.visible
|
||||
visible: passwordDialog.visible || inputDialog.visible || splash.visible || updateDialog.visible || devicePassphraseDialog.visible || successfulTxPopup.visible
|
||||
}
|
||||
|
||||
|
||||
WizardLang {
|
||||
id: languageView
|
||||
visible: false
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
property int minWidth: 326
|
||||
property int minHeight: 400
|
||||
MouseArea {
|
||||
@@ -1794,16 +1877,10 @@ ApplicationWindow {
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
}
|
||||
|
||||
Notifier {
|
||||
visible:false
|
||||
id: notifier
|
||||
}
|
||||
}
|
||||
|
||||
function toggleLanguageView(){
|
||||
middlePanel.visible = !middlePanel.visible;
|
||||
languageView.visible = !languageView.visible
|
||||
languageSidebar.isOpened ? languageSidebar.close() : languageSidebar.open();
|
||||
resetLanguageFields()
|
||||
// update after changing language from settings page
|
||||
if (persistentSettings.language != wizard.language_language) {
|
||||
@@ -1812,6 +1889,24 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: autosaveTimer
|
||||
interval: persistentSettings.autosaveMinutes * 60 * 1000
|
||||
repeat: true
|
||||
running: persistentSettings.autosave
|
||||
onTriggered: {
|
||||
if (currentWallet) {
|
||||
currentWallet.storeAsync(function(success) {
|
||||
if (success) {
|
||||
appWindow.showStatusMessage(qsTr("Autosaved the wallet"), 3);
|
||||
} else {
|
||||
appWindow.showStatusMessage(qsTr("Failed to autosave the wallet"), 3);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make the callback dynamic
|
||||
Timer {
|
||||
id: statusMessageTimer
|
||||
@@ -1851,9 +1946,6 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
function checkSimpleModeConnection(){
|
||||
// auto-connection mechanism for simple mode
|
||||
if(appWindow.walletMode >= 2) return;
|
||||
|
||||
const disconnectedTimeoutSec = 30;
|
||||
const firstCheckDelaySec = 2;
|
||||
|
||||
@@ -1870,15 +1962,20 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
if (appWindow.daemonRunning) {
|
||||
appWindow.stopDaemon();
|
||||
appWindow.stopDaemon(function() {
|
||||
appWindow.startDaemon("")
|
||||
});
|
||||
} else {
|
||||
appWindow.startDaemon("");
|
||||
}
|
||||
appWindow.startDaemon("");
|
||||
}
|
||||
|
||||
Timer {
|
||||
// Simple mode connection check timer
|
||||
id: simpleModeConnectionTimer
|
||||
interval: 2000; running: false; repeat: true
|
||||
interval: 2000
|
||||
running: appWindow.walletMode < 2 && currentWallet != undefined && !daemonStartStopInProgress
|
||||
repeat: true
|
||||
onTriggered: appWindow.checkSimpleModeConnection()
|
||||
}
|
||||
|
||||
@@ -1952,14 +2049,26 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
// If daemon is running - prompt user before exiting
|
||||
if(typeof daemonManager != "undefined" && daemonRunning) {
|
||||
if (appWindow.walletMode == 0) {
|
||||
stopDaemon(closeAccepted);
|
||||
} else {
|
||||
showDaemonIsRunningDialog(closeAccepted);
|
||||
}
|
||||
} else {
|
||||
if(daemonManager == undefined || persistentSettings.useRemoteNode) {
|
||||
closeAccepted();
|
||||
} else if (appWindow.walletMode == 0) {
|
||||
stopDaemon(closeAccepted);
|
||||
} else {
|
||||
showProcessingSplash(qsTr("Checking local node status..."));
|
||||
const handler = function(running) {
|
||||
hideProcessingSplash();
|
||||
if (running) {
|
||||
showDaemonIsRunningDialog(closeAccepted);
|
||||
} else {
|
||||
closeAccepted();
|
||||
}
|
||||
};
|
||||
|
||||
if (currentWallet) {
|
||||
handler(!currentWallet.disconnected);
|
||||
} else {
|
||||
daemonManager.runningAsync(persistentSettings.nettype, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1971,34 +2080,42 @@ ApplicationWindow {
|
||||
closeWallet(Qt.quit);
|
||||
}
|
||||
|
||||
function onWalletCheckUpdatesComplete(update) {
|
||||
if (update === "")
|
||||
return
|
||||
print("Update found: " + update)
|
||||
var parts = update.split("|")
|
||||
if (parts.length == 4) {
|
||||
var version = parts[0]
|
||||
var hash = parts[1]
|
||||
var user_url = parts[2]
|
||||
var msg = qsTr("New version of Monero v%1 is available.").arg(version)
|
||||
if (isMac || isWindows || isLinux) {
|
||||
msg += "<br><br>%1:<br>%2<br><br>%3:<br>%4".arg(qsTr("Download")).arg(user_url).arg(qsTr("SHA256 Hash")).arg(hash) + translationManager.emptyString
|
||||
} else {
|
||||
msg += " " + qsTr("Check out getmonero.org") + translationManager.emptyString
|
||||
}
|
||||
notifier.show(msg)
|
||||
} else {
|
||||
print("Failed to parse update spec")
|
||||
function onWalletCheckUpdatesComplete(version, downloadUrl, hash, firstSigner, secondSigner) {
|
||||
const alreadyAsked = updateDialog.url == downloadUrl && updateDialog.hash == hash;
|
||||
if (!alreadyAsked)
|
||||
{
|
||||
updateDialog.show(version, isMac || isWindows || isLinux ? downloadUrl : "", hash);
|
||||
}
|
||||
}
|
||||
|
||||
function getBuildTag() {
|
||||
if (isMac) {
|
||||
return "mac-x64";
|
||||
}
|
||||
if (isWindows) {
|
||||
return oshelper.installed ? "install-win-x64" : "win-x64";
|
||||
}
|
||||
if (isLinux) {
|
||||
return "linux-x64";
|
||||
}
|
||||
return "source";
|
||||
}
|
||||
|
||||
function checkUpdates() {
|
||||
walletManager.checkUpdatesAsync("monero-gui", "gui")
|
||||
const version = Version.GUI_VERSION.match(/\d+\.\d+\.\d+\.\d+/);
|
||||
if (version) {
|
||||
walletManager.checkUpdatesAsync("monero-gui", "gui", getBuildTag(), version[0]);
|
||||
} else {
|
||||
console.error("failed to parse version number", Version.GUI_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: updatesTimer
|
||||
interval: 3600*1000; running: true; repeat: true
|
||||
interval: 3600 * 1000
|
||||
repeat: true
|
||||
running: !disableCheckUpdatesFlag && persistentSettings.checkForUpdates
|
||||
triggeredOnStart: true
|
||||
onTriggered: checkUpdates()
|
||||
}
|
||||
|
||||
@@ -2078,7 +2195,7 @@ ApplicationWindow {
|
||||
if (mode < 2) {
|
||||
persistentSettings.useRemoteNode = false;
|
||||
|
||||
if (middlePanel.settingsView.settingsStateViewState === "Node" || middlePanel.settingsView.settingsStateViewState === "Log") {
|
||||
if (middlePanel.settingsView.settingsStateViewState === "Node") {
|
||||
middlePanel.settingsView.settingsStateViewState = "Wallet"
|
||||
}
|
||||
}
|
||||
@@ -2098,6 +2215,11 @@ ApplicationWindow {
|
||||
blackColor: "black"
|
||||
whiteColor: "white"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
}
|
||||
}
|
||||
|
||||
// borders on white theme + linux
|
||||
@@ -2165,8 +2287,18 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
// @TODO: QML type 'Drawer' has issues with buildbot; debug after Qt 5.9 migration
|
||||
// MoneroComponents.LanguageSidebar {
|
||||
// id: languageSidebar
|
||||
// }
|
||||
MoneroComponents.LanguageSidebar {
|
||||
id: languageSidebar
|
||||
dragMargin: 0
|
||||
}
|
||||
|
||||
Network {
|
||||
id: network
|
||||
proxyAddress: persistentSettings.getProxyAddress()
|
||||
}
|
||||
|
||||
WalletManager {
|
||||
id: walletManager
|
||||
proxyAddress: persistentSettings.getProxyAddress()
|
||||
}
|
||||
}
|
||||
|
||||
2
monero
@@ -43,7 +43,9 @@ INCLUDEPATH += $$WALLET_ROOT/include \
|
||||
$$PWD/src/libwalletqt \
|
||||
$$PWD/src/QR-Code-generator \
|
||||
$$PWD/src \
|
||||
$$WALLET_ROOT/src
|
||||
$$WALLET_ROOT/src \
|
||||
$$WALLET_ROOT/external/easylogging++ \
|
||||
$$WALLET_ROOT/contrib/epee/include
|
||||
|
||||
HEADERS += \
|
||||
src/main/filter.h \
|
||||
@@ -51,6 +53,7 @@ HEADERS += \
|
||||
src/main/oscursor.h \
|
||||
src/libwalletqt/WalletManager.h \
|
||||
src/libwalletqt/Wallet.h \
|
||||
src/libwalletqt/PassphraseHelper.h \
|
||||
src/libwalletqt/PendingTransaction.h \
|
||||
src/libwalletqt/TransactionHistory.h \
|
||||
src/libwalletqt/TransactionInfo.h \
|
||||
@@ -74,11 +77,12 @@ HEADERS += \
|
||||
src/libwalletqt/UnsignedTransaction.h \
|
||||
src/main/Logger.h \
|
||||
src/main/MainApp.h \
|
||||
src/qt/downloader.h \
|
||||
src/qt/FutureScheduler.h \
|
||||
src/qt/ipc.h \
|
||||
src/qt/KeysFiles.h \
|
||||
src/qt/network.h \
|
||||
src/qt/utils.h \
|
||||
src/qt/prices.h \
|
||||
src/qt/macoshelper.h \
|
||||
src/qt/MoneroSettings.h \
|
||||
src/qt/TailsOS.h
|
||||
@@ -88,12 +92,15 @@ SOURCES += src/main/main.cpp \
|
||||
src/main/clipboardAdapter.cpp \
|
||||
src/main/oscursor.cpp \
|
||||
src/libwalletqt/WalletManager.cpp \
|
||||
src/libwalletqt/WalletListenerImpl.cpp \
|
||||
src/libwalletqt/Wallet.cpp \
|
||||
src/libwalletqt/PassphraseHelper.cpp \
|
||||
src/libwalletqt/PendingTransaction.cpp \
|
||||
src/libwalletqt/TransactionHistory.cpp \
|
||||
src/libwalletqt/TransactionInfo.cpp \
|
||||
src/libwalletqt/QRCodeImageProvider.cpp \
|
||||
src/main/oshelper.cpp \
|
||||
src/openpgp/openpgp.cpp \
|
||||
src/TranslationManager.cpp \
|
||||
src/model/TransactionHistoryModel.cpp \
|
||||
src/model/TransactionHistorySortFilterModel.cpp \
|
||||
@@ -110,11 +117,13 @@ SOURCES += src/main/main.cpp \
|
||||
src/libwalletqt/UnsignedTransaction.cpp \
|
||||
src/main/Logger.cpp \
|
||||
src/main/MainApp.cpp \
|
||||
src/qt/downloader.cpp \
|
||||
src/qt/FutureScheduler.cpp \
|
||||
src/qt/ipc.cpp \
|
||||
src/qt/KeysFiles.cpp \
|
||||
src/qt/network.cpp \
|
||||
src/qt/updater.cpp \
|
||||
src/qt/utils.cpp \
|
||||
src/qt/prices.cpp \
|
||||
src/qt/MoneroSettings.cpp \
|
||||
src/qt/TailsOS.cpp
|
||||
|
||||
@@ -155,6 +164,8 @@ ios:arm64 {
|
||||
}
|
||||
|
||||
LIBS_COMMON = \
|
||||
-lgcrypt \
|
||||
-lgpg-error \
|
||||
-lwallet_merged \
|
||||
-llmdb \
|
||||
-lepee \
|
||||
@@ -176,8 +187,10 @@ android {
|
||||
|
||||
|
||||
|
||||
QMAKE_CXXFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -Werror -Wformat -Wformat-security
|
||||
QMAKE_CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -Werror -Wformat -Wformat-security
|
||||
QMAKE_CXXFLAGS += -Werror -Wformat -Wformat-security
|
||||
QMAKE_CFLAGS += -Werror -Wformat -Wformat-security
|
||||
QMAKE_CXXFLAGS_RELEASE += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -O2
|
||||
QMAKE_CFLAGS_RELEASE += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -O2
|
||||
|
||||
ios {
|
||||
message("Host is IOS")
|
||||
@@ -221,6 +234,14 @@ CONFIG(WITH_SCANNER) {
|
||||
LIBS += -lzbarjni -liconv
|
||||
} else {
|
||||
LIBS += -lzbar
|
||||
macx {
|
||||
ZBAR_DIR = $$system(brew --prefix zbar, lines, EXIT_CODE)
|
||||
equals(EXIT_CODE, 0) {
|
||||
INCLUDEPATH += $$ZBAR_DIR/include
|
||||
} else {
|
||||
INCLUDEPATH += /usr/local/include
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
message("Skipping camera scanner because of Incompatible Qt Version !")
|
||||
@@ -372,11 +393,39 @@ macx {
|
||||
# LIBS+= -Wl,-Bstatic
|
||||
# }
|
||||
|
||||
OPENSSL_LIBRARY_DIRS = $$system(brew --prefix openssl, lines, EXIT_CODE)
|
||||
OPENSSL_DIR = $$system(brew --prefix openssl, lines, EXIT_CODE)
|
||||
!equals(EXIT_CODE, 0) {
|
||||
OPENSSL_DIR = /usr/local/ssl
|
||||
}
|
||||
OPENSSL_LIBRARY_DIR = $$OPENSSL_DIR/lib
|
||||
INCLUDEPATH += $$OPENSSL_DIR/include
|
||||
|
||||
BOOST_DIR = $$system(brew --prefix boost, lines, EXIT_CODE)
|
||||
equals(EXIT_CODE, 0) {
|
||||
OPENSSL_LIBRARY_DIRS = $$OPENSSL_LIBRARY_DIRS/lib
|
||||
INCLUDEPATH += $$BOOST_DIR/include
|
||||
} else {
|
||||
OPENSSL_LIBRARY_DIRS = /usr/local/ssl/lib
|
||||
INCLUDEPATH += /usr/local/include
|
||||
}
|
||||
|
||||
GCRYPT_DIR = $$system(brew --prefix libgcrypt, lines, EXIT_CODE)
|
||||
equals(EXIT_CODE, 0) {
|
||||
INCLUDEPATH += $$GCRYPT_DIR/include
|
||||
} else {
|
||||
INCLUDEPATH += /usr/local/include
|
||||
}
|
||||
|
||||
GPGP_ERROR_DIR = $$system(brew --prefix libgpg-error, lines, EXIT_CODE)
|
||||
equals(EXIT_CODE, 0) {
|
||||
INCLUDEPATH += $$GPGP_ERROR_DIR/include
|
||||
} else {
|
||||
INCLUDEPATH += /usr/local/include
|
||||
}
|
||||
|
||||
SODIUM_DIR = $$system(brew --prefix libsodium, lines, EXIT_CODE)
|
||||
equals(EXIT_CODE, 0) {
|
||||
INCLUDEPATH += $$SODIUM_DIR/include
|
||||
} else {
|
||||
INCLUDEPATH += /usr/local/include
|
||||
}
|
||||
|
||||
QT += macextras
|
||||
@@ -386,7 +435,7 @@ macx {
|
||||
LIBS+= -Wl,-bind_at_load
|
||||
LIBS+= \
|
||||
-L/usr/local/lib \
|
||||
-L$$OPENSSL_LIBRARY_DIRS \
|
||||
-L$$OPENSSL_LIBRARY_DIR \
|
||||
-L/usr/local/opt/boost/lib \
|
||||
-lboost_serialization \
|
||||
-lboost_thread-mt \
|
||||
@@ -492,7 +541,7 @@ macx {
|
||||
}
|
||||
|
||||
win32 {
|
||||
deploy.commands += windeployqt $$sprintf("%1/%2/%3.exe", $$OUT_PWD, $$DESTDIR, $$TARGET) -release -no-translations -qmldir=$$PWD
|
||||
deploy.commands += windeployqt $$sprintf("%1/%2/%3.exe", $$OUT_PWD, $$DESTDIR, $$TARGET) -no-translations -qmldir=$$PWD
|
||||
# Win64 msys2 deploy settings
|
||||
contains(QMAKE_HOST.arch, x86_64) {
|
||||
deploy.commands += $$escape_expand(\n\t) $$PWD/windeploy_helper.sh $$DESTDIR
|
||||
@@ -518,7 +567,7 @@ DISTFILES += \
|
||||
|
||||
VERSION = $$cat('version.js', lines)
|
||||
VERSION = $$find(VERSION, 'GUI_VERSION')
|
||||
VERSION_LONG = $$replace(VERSION, '.*\"v(.*)\"', '\1')
|
||||
VERSION_LONG = $$replace(VERSION, '.*\"(.*)\"', '\1')
|
||||
VERSION = $$replace(VERSION, '.*(\d+\.\d+\.\d+\.\d+).*', '\1')
|
||||
|
||||
# windows application icon
|
||||
|
||||
@@ -48,6 +48,8 @@ Rectangle {
|
||||
color: "transparent"
|
||||
property var model
|
||||
property alias accountHeight: mainLayout.height
|
||||
property alias balanceAllText: balanceAll.text
|
||||
property alias unlockedBalanceAllText: unlockedBalanceAll.text
|
||||
property bool selectAndSend: false
|
||||
property int currentAccountIndex
|
||||
|
||||
@@ -186,7 +188,7 @@ Rectangle {
|
||||
delegate: Rectangle {
|
||||
id: tableItem2
|
||||
height: subaddressAccountListRow.subaddressAccountListItemHeight
|
||||
width: parent.width
|
||||
width: parent ? parent.width : undefined
|
||||
Layout.fillWidth: true
|
||||
color: "transparent"
|
||||
|
||||
|
||||
@@ -79,13 +79,6 @@ Rectangle {
|
||||
topPadding: 0
|
||||
text: qsTr("Save your most used addresses here") + translationManager.emptyString
|
||||
width: parent.width
|
||||
|
||||
// @TODO: Legacy. Remove after Qt 5.8.
|
||||
// https://stackoverflow.com/questions/41990013
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
@@ -99,13 +92,6 @@ Rectangle {
|
||||
topPadding: 0
|
||||
text: qsTr("This makes it easier to send or receive Monero and reduces errors when typing in addresses manually.") + translationManager.emptyString
|
||||
width: parent.width
|
||||
|
||||
// @TODO: Legacy. Remove after Qt 5.8.
|
||||
// https://stackoverflow.com/questions/41990013
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
@@ -325,8 +311,6 @@ Rectangle {
|
||||
if (!parsed.error) {
|
||||
addressLine.text = parsed.address;
|
||||
descriptionLine.text = parsed.tx_description;
|
||||
} else {
|
||||
addressLine.text = clipboardText;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -569,12 +569,11 @@ Rectangle {
|
||||
delegate: Rectangle {
|
||||
id: delegate
|
||||
property bool collapsed: root.txDataCollapsed.indexOf(hash) >= 0 ? true : false
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent ? parent.left : undefined
|
||||
anchors.right: parent ? parent.right : undefined
|
||||
height: {
|
||||
if(!collapsed) return 60;
|
||||
if(isout && delegate.address !== "") return 320;
|
||||
return 220;
|
||||
return 320;
|
||||
}
|
||||
color: {
|
||||
if(!collapsed) return "transparent"
|
||||
@@ -618,6 +617,7 @@ Rectangle {
|
||||
spacing: 0
|
||||
clip: true
|
||||
Layout.preferredHeight: 120
|
||||
Layout.minimumWidth: 180
|
||||
|
||||
Rectangle {
|
||||
color: "transparent"
|
||||
@@ -633,17 +633,7 @@ Rectangle {
|
||||
MoneroComponents.TextPlain {
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 15
|
||||
text: {
|
||||
if (!isout) {
|
||||
return qsTr("Received") + translationManager.emptyString;
|
||||
}
|
||||
const addressBookName = currentWallet ? currentWallet.addressBook.getDescription(address) : null;
|
||||
if (!addressBookName)
|
||||
{
|
||||
return qsTr("Sent") + translationManager.emptyString;
|
||||
}
|
||||
return addressBookName;
|
||||
}
|
||||
text: (isout ? qsTr("Sent") : qsTr("Received")) + translationManager.emptyString
|
||||
color: MoneroComponents.Style.historyHeaderTextColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
themeTransitionBlackColor: MoneroComponents.Style._b_historyHeaderTextColor
|
||||
@@ -659,7 +649,7 @@ Rectangle {
|
||||
MoneroComponents.TextPlain {
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 15
|
||||
text: displayAmount
|
||||
text: (amount == 0 ? qsTr("Unknown amount") : displayAmount) + translationManager.emptyString
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -711,7 +701,7 @@ Rectangle {
|
||||
font.pixelSize: 15
|
||||
text: {
|
||||
if(!isout && confirmationsRequired === 60) return qsTr("Yes") + translationManager.emptyString;
|
||||
if(fee !== "") return fee + " XMR";
|
||||
if(fee !== "") return Utils.removeTrailingZeros(fee) + " XMR";
|
||||
return "-";
|
||||
}
|
||||
|
||||
@@ -739,6 +729,7 @@ Rectangle {
|
||||
spacing: 0
|
||||
clip: true
|
||||
Layout.preferredHeight: 120
|
||||
Layout.minimumWidth: 230
|
||||
|
||||
Rectangle {
|
||||
color: "transparent"
|
||||
@@ -754,7 +745,7 @@ Rectangle {
|
||||
MoneroComponents.TextPlain {
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 15
|
||||
text: qsTr("Blockheight") + translationManager.emptyString
|
||||
text: (isout ? qsTr("To") : qsTr("In")) + translationManager.emptyString
|
||||
color: MoneroComponents.Style.historyHeaderTextColor
|
||||
themeTransitionBlackColor: MoneroComponents.Style._b_historyHeaderTextColor
|
||||
themeTransitionWhiteColor: MoneroComponents.Style._w_historyHeaderTextColor
|
||||
@@ -768,15 +759,44 @@ Rectangle {
|
||||
Layout.preferredHeight: 20
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: addressField
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 14
|
||||
text: blockheight > 0 ? blockheight : qsTr('Pending') + translationManager.emptyString;
|
||||
font.pixelSize: 15
|
||||
text: {
|
||||
if (isout) {
|
||||
if (address) {
|
||||
const addressBookName = currentWallet ? currentWallet.addressBook.getDescription(address) : null;
|
||||
return (addressBookName ? FontAwesome.addressBook + " " + addressBookName : TxUtils.addressTruncate(address, 8));
|
||||
}
|
||||
if (amount != 0) {
|
||||
return (blockheight ? qsTr("Unknown recipient") : qsTr("Waiting confirmation...")) + translationManager.emptyString;
|
||||
} else {
|
||||
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;
|
||||
} else {
|
||||
if (receivingAddressLabel) {
|
||||
return qsTr("Address") + " #" + subaddrIndex + " (" + receivingAddressLabel + ")" + translationManager.emptyString;
|
||||
} else {
|
||||
return qsTr("Address") + " #" + subaddrIndex + " (" + TxUtils.addressTruncate(receivingAddress, 4) + ")" + translationManager.emptyString;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return qsTr("Unknown address") + translationManager.emptyString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MouseArea {
|
||||
state: "copyable"
|
||||
state: isout ? "copyable_address" : "copyable_receiving_address"
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: parent.color = MoneroComponents.Style.orange
|
||||
@@ -847,6 +867,7 @@ Rectangle {
|
||||
spacing: 0
|
||||
clip: true
|
||||
Layout.preferredHeight: 120
|
||||
Layout.minimumWidth: 130
|
||||
|
||||
Rectangle {
|
||||
color: "transparent"
|
||||
@@ -909,9 +930,15 @@ Rectangle {
|
||||
Layout.preferredHeight: 10
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: "transparent"
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 10
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 60
|
||||
Layout.preferredHeight: 50
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
id: btnDetails
|
||||
@@ -919,7 +946,7 @@ Rectangle {
|
||||
small: true
|
||||
label.font.family: FontAwesome.fontFamily
|
||||
fontSize: 18
|
||||
width: 28
|
||||
width: 34
|
||||
|
||||
MouseArea {
|
||||
state: "details"
|
||||
@@ -949,7 +976,7 @@ Rectangle {
|
||||
small: true
|
||||
label.font.family: FontAwesome.fontFamilyBrands
|
||||
fontSize: 18
|
||||
width: 36
|
||||
width: 34
|
||||
|
||||
MouseArea {
|
||||
state: "proof"
|
||||
@@ -1128,7 +1155,6 @@ Rectangle {
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: isout
|
||||
color: "transparent"
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 20
|
||||
@@ -1136,7 +1162,7 @@ Rectangle {
|
||||
MoneroComponents.TextPlain {
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 15
|
||||
text: qsTr("Address sent to") + translationManager.emptyString
|
||||
text: qsTr("Blockheight") + translationManager.emptyString
|
||||
color: MoneroComponents.Style.historyHeaderTextColor
|
||||
themeTransitionBlackColor: MoneroComponents.Style._b_historyHeaderTextColor
|
||||
themeTransitionWhiteColor: MoneroComponents.Style._w_historyHeaderTextColor
|
||||
@@ -1145,30 +1171,20 @@ Rectangle {
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: isout
|
||||
color: "transparent"
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 20
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 15
|
||||
text: {
|
||||
if(isout && address !== ""){
|
||||
return TxUtils.addressTruncate(address, 24);
|
||||
}
|
||||
|
||||
if(isout && blockheight === 0)
|
||||
return qsTr("Waiting for transaction to leave txpool.") + translationManager.emptyString
|
||||
else
|
||||
return qsTr("Unknown recipient") + translationManager.emptyString;
|
||||
}
|
||||
font.pixelSize: 14
|
||||
text: (blockheight > 0 ? blockheight : qsTr('Pending')) + translationManager.emptyString;
|
||||
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MouseArea {
|
||||
state: "copyable_address"
|
||||
state: "copyable"
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: parent.color = MoneroComponents.Style.orange
|
||||
@@ -1202,7 +1218,8 @@ Rectangle {
|
||||
for(var i = 0; i < res.length; i+=1){
|
||||
if(res[i].containsMouse === true){
|
||||
if(res[i].state === 'copyable' && res[i].parent.hasOwnProperty('text')) toClipboard(res[i].parent.text);
|
||||
if(res[i].state === 'copyable_address') root.toClipboard(address);
|
||||
if(res[i].state === 'copyable_address') (address ? root.toClipboard(address) : root.toClipboard(addressField.text));
|
||||
if(res[i].state === 'copyable_receiving_address') root.toClipboard(currentWallet.address(subaddrAccount, subaddrIndex));
|
||||
if(res[i].state === 'copyable_txkey') root.getTxKey(hash, res[i]);
|
||||
if(res[i].state === 'set_tx_note') root.editDescription(hash, tx_note);
|
||||
if(res[i].state === 'details') root.showTxDetails(hash, paymentId, destinations, subaddrAccount, subaddrIndex, dateTime, displayAmount, isout);
|
||||
@@ -1394,7 +1411,7 @@ Rectangle {
|
||||
txs.push(item);
|
||||
} else if(item.address !== "" && item.address.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
|
||||
txs.push(item);
|
||||
} else if(item.blockheight.toString().startsWith(root.sortSearchString)) {
|
||||
} 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) {
|
||||
txs.push(item);
|
||||
@@ -1488,13 +1505,12 @@ Rectangle {
|
||||
var timestamp = new Date(date + " " + time).getTime() / 1000;
|
||||
var dateHuman = Utils.ago(timestamp);
|
||||
|
||||
var displayAmount = amount;
|
||||
if(displayAmount === 0){
|
||||
// *sometimes* amount is 0, while the 'destinations string'
|
||||
if (amount === 0) {
|
||||
// transactions to the same account have amount === 0, while the 'destinations string'
|
||||
// has the correct amount, so we try to fetch it from that instead.
|
||||
displayAmount = TxUtils.destinationsToAmount(destinations);
|
||||
displayAmount = Number(displayAmount *1);
|
||||
amount = Number(TxUtils.destinationsToAmount(destinations));
|
||||
}
|
||||
var displayAmount = Utils.removeTrailingZeros(amount.toFixed(12)) + " XMR";
|
||||
|
||||
var tx_note = currentWallet.getUserNote(hash);
|
||||
var address = "";
|
||||
@@ -1510,8 +1526,8 @@ Rectangle {
|
||||
root.txModelData.push({
|
||||
"i": i,
|
||||
"isout": isout,
|
||||
"amount": Number(amount),
|
||||
"displayAmount": displayAmount + " XMR",
|
||||
"amount": amount,
|
||||
"displayAmount": displayAmount,
|
||||
"hash": hash,
|
||||
"paymentId": paymentId,
|
||||
"address": address,
|
||||
@@ -1692,7 +1708,7 @@ Rectangle {
|
||||
informationPopup.open();
|
||||
}
|
||||
Component.onCompleted: {
|
||||
var _folder = 'file://' + moneroAccountsDir;
|
||||
var _folder = 'file://' + appWindow.accountsDir;
|
||||
try {
|
||||
_folder = 'file://' + desktopFolder;
|
||||
}
|
||||
|
||||
@@ -251,7 +251,19 @@ Rectangle {
|
||||
|
||||
function updateStatusText() {
|
||||
if (appWindow.isMining) {
|
||||
statusText.text = qsTr("Mining at %1 H/s").arg(walletManager.miningHashRate()) + translationManager.emptyString;
|
||||
var userHashRate = walletManager.miningHashRate();
|
||||
if (userHashRate === 0) {
|
||||
statusText.text = qsTr("Mining temporarily suspended.") + translationManager.emptyString;
|
||||
}
|
||||
else {
|
||||
var blockTime = 120;
|
||||
var blocksPerDay = 86400 / blockTime;
|
||||
var globalHashRate = walletManager.networkDifficulty() / blockTime;
|
||||
var probabilityFindNextBlock = userHashRate / globalHashRate;
|
||||
var probabilityFindBlockDay = 1 - Math.pow(1 - probabilityFindNextBlock, blocksPerDay);
|
||||
var chanceFindBlockDay = Math.round(1 / probabilityFindBlockDay);
|
||||
statusText.text = qsTr("Mining at %1 H/s. It gives you a 1 in %2 daily chance of finding a block.").arg(userHashRate).arg(chanceFindBlockDay) + translationManager.emptyString;
|
||||
}
|
||||
}
|
||||
else {
|
||||
statusText.text = qsTr("Not mining") + translationManager.emptyString;
|
||||
|
||||
@@ -105,7 +105,7 @@ Rectangle {
|
||||
delegate: Rectangle {
|
||||
id: tableItem2
|
||||
height: subaddressListRow.subaddressListItemHeight
|
||||
width: parent.width
|
||||
width: parent ? parent.width : undefined
|
||||
Layout.fillWidth: true
|
||||
color: "transparent"
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
// 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.Layouts 1.1
|
||||
import QtQuick.Dialogs 1.2
|
||||
import moneroComponents.Clipboard 1.0
|
||||
@@ -38,6 +39,7 @@ import "../components"
|
||||
import "../components" as MoneroComponents
|
||||
import "." 1.0
|
||||
import "../js/TxUtils.js" as TxUtils
|
||||
import "../js/Utils.js" as Utils
|
||||
|
||||
|
||||
Rectangle {
|
||||
@@ -54,8 +56,8 @@ Rectangle {
|
||||
property string sendButtonWarning: {
|
||||
// Currently opened wallet is not view-only
|
||||
if (appWindow.viewOnly) {
|
||||
return qsTr("Wallet is view-only and sends are not possible. Unless key images are imported, " +
|
||||
"the balance reflects only incoming but not outgoing transactions.") + translationManager.emptyString;
|
||||
return qsTr("Wallet is view-only and sends are only possible by using offline transaction signing. " +
|
||||
"Unless key images are imported, the balance reflects only incoming but not outgoing transactions.") + translationManager.emptyString;
|
||||
}
|
||||
|
||||
// There are sufficient unlocked funds available
|
||||
@@ -116,7 +118,6 @@ Rectangle {
|
||||
amountLine.text = ""
|
||||
setDescription("");
|
||||
priorityDropdown.currentIndex = 0
|
||||
updatePriorityDropdown()
|
||||
}
|
||||
|
||||
// Information dialog
|
||||
@@ -162,96 +163,6 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
columns: appWindow.walletMode < 2 ? 1 : 2
|
||||
Layout.fillWidth: true
|
||||
columnSpacing: 32
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumWidth: 200
|
||||
|
||||
// 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: fiatApiCurrencySymbol() + " ~" + fiatApiConvertToFiat(amountLine.text)
|
||||
copyButtonEnabled: false
|
||||
|
||||
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: {
|
||||
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;
|
||||
}
|
||||
}
|
||||
amountLine.error = walletManager.amountFromString(amountLine.text) > appWindow.getUnlockedBalance()
|
||||
}
|
||||
|
||||
validator: RegExpValidator {
|
||||
regExp: /^(\d{1,8})?([\.]\d{1,12})?$/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
visible: appWindow.walletMode >= 2
|
||||
Layout.fillWidth: true
|
||||
Label {
|
||||
id: transactionPriority
|
||||
Layout.topMargin: 12
|
||||
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.fillWidth: true
|
||||
id: priorityDropdown
|
||||
Layout.topMargin: 5
|
||||
currentIndex: 0
|
||||
}
|
||||
}
|
||||
// Make sure dropdown is on top
|
||||
z: parent.z + 1
|
||||
}
|
||||
|
||||
// recipient address input
|
||||
RowLayout {
|
||||
id: addressLineRow
|
||||
@@ -260,10 +171,9 @@ Rectangle {
|
||||
LineEditMulti {
|
||||
id: addressLine
|
||||
spacing: 0
|
||||
inputPaddingRight: inlineButtonVisible && inlineButton2Visible ? 100 : 60
|
||||
fontBold: true
|
||||
labelText: qsTr("<style type='text/css'>a {text-decoration: none; color: #858585; font-size: 14px;}</style>\
|
||||
%1 <a href='#'>(%2)</a>").arg(qsTr("Address")).arg(qsTr("Address book"))
|
||||
+ translationManager.emptyString
|
||||
labelText: qsTr("Address") + translationManager.emptyString
|
||||
labelButtonText: qsTr("Resolve") + translationManager.emptyString
|
||||
placeholderText: {
|
||||
if(persistentSettings.nettype == NetworkType.MAINNET){
|
||||
@@ -276,10 +186,6 @@ Rectangle {
|
||||
}
|
||||
wrapMode: Text.WrapAnywhere
|
||||
addressValidation: true
|
||||
onInputLabelLinkActivated: {
|
||||
middlePanel.addressBookView.selectAndSend = true;
|
||||
appWindow.showPageRequest("AddressBook");
|
||||
}
|
||||
onTextChanged: {
|
||||
const parsed = walletManager.parse_uri_to_object(text);
|
||||
if (!parsed.error) {
|
||||
@@ -289,16 +195,27 @@ Rectangle {
|
||||
setDescription(parsed.tx_description);
|
||||
}
|
||||
}
|
||||
inlineButton.text: FontAwesome.qrcode
|
||||
inlineButton.text: FontAwesome.addressBook
|
||||
inlineButton.buttonHeight: 30
|
||||
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(updateFromQrCode)
|
||||
middlePanel.addressBookView.selectAndSend = true;
|
||||
appWindow.showPageRequest("AddressBook");
|
||||
}
|
||||
inlineButtonVisible : appWindow.qrScannerEnabled && !addressLine.text
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,6 +265,143 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
columns: appWindow.walletMode < 2 ? 1 : 2
|
||||
Layout.fillWidth: true
|
||||
columnSpacing: 32
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumWidth: 200
|
||||
|
||||
// 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
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
amountLine.error = walletManager.amountFromString(amountLine.text) > appWindow.getUnlockedBalance()
|
||||
}
|
||||
|
||||
validator: RegExpValidator {
|
||||
regExp: /^(\d{1,8})?([\.,]\d{1,12})?$/
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: feeLabel
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Layout.topMargin: 12
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 14
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
property bool estimating: false
|
||||
property var estimatedFee: null
|
||||
property string estimatedFeeFiat: {
|
||||
if (!persistentSettings.fiatPriceEnabled || estimatedFee == null) {
|
||||
return "";
|
||||
}
|
||||
const fiatFee = fiatApiConvertToFiat(estimatedFee);
|
||||
return " (%1 %3)".arg(fiatFee < 0.01 ? "<0.01" : "~" + fiatFee).arg(fiatApiCurrencySymbol());
|
||||
}
|
||||
property var fee: {
|
||||
estimatedFee = null;
|
||||
estimating = sendButton.enabled;
|
||||
if (!sendButton.enabled || !currentWallet) {
|
||||
return;
|
||||
}
|
||||
currentWallet.estimateTransactionFeeAsync(
|
||||
addressLine.text,
|
||||
walletManager.amountFromString(amountLine.text),
|
||||
priorityModelV5.get(priorityDropdown.currentIndex).priority,
|
||||
function (amount) {
|
||||
estimatedFee = Utils.removeTrailingZeros(amount);
|
||||
estimating = false;
|
||||
});
|
||||
}
|
||||
text: {
|
||||
if (!sendButton.enabled || estimatedFee == null) {
|
||||
return ""
|
||||
}
|
||||
return "%1: ~%2 XMR".arg(qsTr("Fee")).arg(estimatedFee) +
|
||||
estimatedFeeFiat +
|
||||
translationManager.emptyString;
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
anchors.right: parent.right
|
||||
running: feeLabel.estimating
|
||||
height: parent.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. \
|
||||
Please don't paste long payment ID into description field, your funds might be lost.") + translationManager.emptyString;
|
||||
@@ -461,10 +515,9 @@ Rectangle {
|
||||
id: advancedLayout
|
||||
anchors.top: pageRoot.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 32
|
||||
spacing: 26
|
||||
spacing: 10
|
||||
enabled: !viewOnly || pageRoot.enabled
|
||||
|
||||
RowLayout {
|
||||
@@ -479,84 +532,88 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
AdvancedOptionsItem {
|
||||
visible: persistentSettings.transferShowAdvanced && appWindow.walletMode >= 2
|
||||
columns: 6
|
||||
|
||||
StandardButton {
|
||||
id: sweepUnmixableButton
|
||||
text: qsTr("Sweep Unmixable") + translationManager.emptyString
|
||||
enabled : pageRoot.enabled
|
||||
small: true
|
||||
onClicked: {
|
||||
console.log("Transfer: sweepUnmixableClicked")
|
||||
root.sweepUnmixableClicked()
|
||||
}
|
||||
title: qsTr("Key images") + translationManager.emptyString
|
||||
button1.text: qsTr("Export") + translationManager.emptyString
|
||||
button1.enabled: !appWindow.viewOnly
|
||||
button1.onClicked: {
|
||||
console.log("Transfer: export key images clicked")
|
||||
exportKeyImagesDialog.open();
|
||||
}
|
||||
|
||||
StandardButton {
|
||||
id: saveTxButton
|
||||
text: qsTr("Create tx file") + translationManager.emptyString
|
||||
visible: appWindow.viewOnly
|
||||
enabled: pageRoot.checkInformation(amountLine.text, addressLine.text, appWindow.persistentSettings.nettype)
|
||||
small: true
|
||||
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)
|
||||
|
||||
}
|
||||
button2.text: qsTr("Import") + translationManager.emptyString
|
||||
button2.enabled: appWindow.viewOnly && appWindow.isTrustedDaemon()
|
||||
button2.onClicked: {
|
||||
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: {
|
||||
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:#ffffff;} p.orange{color:#ff9323;}</style>" +
|
||||
"<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.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)
|
||||
}
|
||||
button2.text: qsTr("Sign (offline)") + translationManager.emptyString
|
||||
button2.enabled: !appWindow.viewOnly
|
||||
button2.onClicked: {
|
||||
console.log("Transfer: sign tx clicked")
|
||||
signTxDialog.open();
|
||||
}
|
||||
button3.text: qsTr("Submit") + translationManager.emptyString
|
||||
button3.enabled: appWindow.viewOnly
|
||||
button3.onClicked: {
|
||||
console.log("Transfer: submit tx clicked")
|
||||
submitTxDialog.open();
|
||||
}
|
||||
helpTextLarge.text: qsTr("Spend XMR from a cold (offline) wallet") + translationManager.emptyString
|
||||
helpTextSmall.text: {
|
||||
var errorMessage = "";
|
||||
if (appWindow.viewOnly && !pageRoot.checkInformation(amountLine.text, addressLine.text, appWindow.persistentSettings.nettype)){
|
||||
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:#ffffff;} p.orange{color:#ff9323;}</style>" +
|
||||
"<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>" +
|
||||
errorMessage +
|
||||
"<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
|
||||
}
|
||||
|
||||
StandardButton {
|
||||
id: signTxButton
|
||||
text: qsTr("Sign tx file") + translationManager.emptyString
|
||||
small: true
|
||||
visible: !appWindow.viewOnly
|
||||
onClicked: {
|
||||
console.log("Transfer: sign tx clicked")
|
||||
signTxDialog.open();
|
||||
}
|
||||
}
|
||||
|
||||
StandardButton {
|
||||
id: submitTxButton
|
||||
text: qsTr("Submit tx file") + translationManager.emptyString
|
||||
small: true
|
||||
visible: appWindow.viewOnly
|
||||
enabled: pageRoot.enabled
|
||||
onClicked: {
|
||||
console.log("Transfer: submit tx clicked")
|
||||
submitTxDialog.open();
|
||||
}
|
||||
}
|
||||
|
||||
StandardButton {
|
||||
id: exportKeyImagesButton
|
||||
text: qsTr("Export key images") + translationManager.emptyString
|
||||
small: true
|
||||
visible: !appWindow.viewOnly
|
||||
enabled: pageRoot.enabled
|
||||
onClicked: {
|
||||
console.log("Transfer: export key images clicked")
|
||||
exportKeyImagesDialog.open();
|
||||
}
|
||||
}
|
||||
|
||||
StandardButton {
|
||||
id: importKeyImagesButton
|
||||
text: qsTr("Import key images") + translationManager.emptyString
|
||||
small: true
|
||||
enabled: appWindow.viewOnly && appWindow.isTrustedDaemon()
|
||||
onClicked: {
|
||||
console.log("Transfer: import key images clicked")
|
||||
importKeyImagesDialog.open();
|
||||
}
|
||||
AdvancedOptionsItem {
|
||||
visible: persistentSettings.transferShowAdvanced && appWindow.walletMode >= 2
|
||||
title: qsTr("Unmixable outputs") + translationManager.emptyString
|
||||
button1.text: qsTr("Sweep") + translationManager.emptyString
|
||||
button1.enabled : pageRoot.enabled
|
||||
button1.onClicked: {
|
||||
console.log("Transfer: sweepUnmixableClicked")
|
||||
root.sweepUnmixableClicked()
|
||||
}
|
||||
helpTextLarge.text: qsTr("Create a transaction that spends old unmovable outputs") + translationManager.emptyString
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,7 +621,7 @@ Rectangle {
|
||||
FileDialog {
|
||||
id: signTxDialog
|
||||
title: qsTr("Please choose a file") + translationManager.emptyString
|
||||
folder: "file://" +moneroAccountsDir
|
||||
folder: "file://" + appWindow.accountsDir
|
||||
nameFilters: [ "Unsigned transfers (*)"]
|
||||
|
||||
onAccepted: {
|
||||
@@ -625,7 +682,7 @@ Rectangle {
|
||||
FileDialog {
|
||||
id: submitTxDialog
|
||||
title: qsTr("Please choose a file") + translationManager.emptyString
|
||||
folder: "file://" +moneroAccountsDir
|
||||
folder: "file://" + appWindow.accountsDir
|
||||
nameFilters: [ "signed transfers (*)"]
|
||||
|
||||
onAccepted: {
|
||||
@@ -689,12 +746,6 @@ Rectangle {
|
||||
function onPageCompleted() {
|
||||
console.log("transfer page loaded")
|
||||
updateStatus();
|
||||
updatePriorityDropdown()
|
||||
}
|
||||
|
||||
function updatePriorityDropdown() {
|
||||
priorityDropdown.dataModel = priorityModelV5;
|
||||
priorityDropdown.update()
|
||||
}
|
||||
|
||||
//TODO: Add daemon sync status
|
||||
@@ -717,6 +768,8 @@ Rectangle {
|
||||
|
||||
switch (currentWallet.connected()) {
|
||||
case Wallet.ConnectionStatus_Connecting:
|
||||
root.warningContent = qsTr("Wallet is connecting to daemon.")
|
||||
break
|
||||
case Wallet.ConnectionStatus_Disconnected:
|
||||
root.warningContent = messageNotConnected;
|
||||
break
|
||||
|
||||
@@ -25,6 +25,7 @@ Item {
|
||||
anchors.margins: 0
|
||||
|
||||
property int minWidth: 900
|
||||
property int minHeight: 600
|
||||
property int qrCodeSize: 220
|
||||
property bool enableTracking: false
|
||||
property string trackingError: "" // setting this will show a message @ tracking table
|
||||
@@ -33,6 +34,9 @@ Item {
|
||||
property var hiddenAmounts: []
|
||||
|
||||
function onPageCompleted() {
|
||||
if (appWindow.currentWallet) {
|
||||
appWindow.current_address = appWindow.currentWallet.address(appWindow.currentWallet.currentSubaddressAccount, 0)
|
||||
}
|
||||
// prepare tracking
|
||||
trackingCheckbox.checked = root.enableTracking
|
||||
root.update();
|
||||
@@ -67,7 +71,7 @@ Item {
|
||||
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
visible: parent.width >= root.minWidth
|
||||
visible: parent.width >= root.minWidth && appWindow.height >= root.minHeight
|
||||
spacing: 0
|
||||
|
||||
// emulates max-width + center for container
|
||||
@@ -544,7 +548,7 @@ Item {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: appWindow.showPageRequest("Receive")
|
||||
onClicked: appWindow.showPageRequest("Settings")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -553,7 +557,7 @@ Item {
|
||||
|
||||
Rectangle {
|
||||
// Shows when the window is too small
|
||||
visible: parent.width < root.minWidth
|
||||
visible: parent.width < root.minWidth || appWindow.height < root.minHeight
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 100;
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -570,6 +574,13 @@ Item {
|
||||
text: qsTr("The merchant page requires a larger window") + translationManager.emptyString
|
||||
themeTransition: false
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: appWindow.showPageRequest("Settings")
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
@@ -589,9 +600,7 @@ Item {
|
||||
|
||||
var model = appWindow.currentWallet.historyModel
|
||||
var count = model.rowCount()
|
||||
var totalAmount = 0
|
||||
var nTransactions = 0
|
||||
var blockchainHeight = null
|
||||
var txs = []
|
||||
|
||||
// Currently selected subaddress as per Receive page
|
||||
@@ -607,8 +616,6 @@ Item {
|
||||
var subaddrIndex = model.data(idx, TransactionHistoryModel.TransactionSubaddrIndexRole);
|
||||
|
||||
if (!isout && subaddrAccount == appWindow.currentWallet.currentSubaddressAccount && subaddrIndex == current_subaddress_table_index) {
|
||||
var amount = model.data(idx, TransactionHistoryModel.TransactionAtomicAmountRole);
|
||||
totalAmount = walletManager.addi(totalAmount, amount)
|
||||
nTransactions += 1
|
||||
|
||||
var txid = model.data(idx, TransactionHistoryModel.TransactionHashRole);
|
||||
@@ -616,21 +623,17 @@ Item {
|
||||
|
||||
var in_txpool = false;
|
||||
var confirmations = 0;
|
||||
var displayAmount = 0;
|
||||
var displayAmount = model.data(idx, TransactionHistoryModel.TransactionDisplayAmountRole);
|
||||
|
||||
if (blockHeight == 0) {
|
||||
if (blockHeight === undefined) {
|
||||
in_txpool = true;
|
||||
} else {
|
||||
if (blockchainHeight == null)
|
||||
blockchainHeight = walletManager.blockchainHeight()
|
||||
confirmations = blockchainHeight - blockHeight - 1
|
||||
displayAmount = model.data(idx, TransactionHistoryModel.TransactionDisplayAmountRole);
|
||||
confirmations = model.data(idx, TransactionHistoryModel.TransactionConfirmationsRole);
|
||||
}
|
||||
|
||||
txs.push({
|
||||
"amount": displayAmount,
|
||||
"confirmations": confirmations,
|
||||
"blockheight": blockHeight,
|
||||
"in_txpool": in_txpool,
|
||||
"txid": txid,
|
||||
"time_epoch": timeEpoch,
|
||||
@@ -650,9 +653,7 @@ Item {
|
||||
txs.forEach(function(tx){
|
||||
trackingModel.append({
|
||||
"amount": tx.amount,
|
||||
"blockheight": tx.blockheight,
|
||||
"confirmations": tx.confirmations,
|
||||
"blockheight": tx.blockHeight,
|
||||
"in_txpool": tx.in_txpool,
|
||||
"txid": tx.txid,
|
||||
"time_epoch": tx.time_epoch,
|
||||
|
||||
@@ -47,7 +47,7 @@ ListView {
|
||||
id: trackingTableItem
|
||||
visible: trackingListView.message === ""
|
||||
height: 53
|
||||
width: parent.width
|
||||
width: parent ? parent.width : undefined
|
||||
Layout.fillWidth: true
|
||||
|
||||
RowLayout {
|
||||
@@ -125,7 +125,7 @@ ListView {
|
||||
font.pixelSize: 14
|
||||
font.bold: true
|
||||
color: hide_amount ? "#707070" : "#009F1E"
|
||||
text: hide_amount ? '-' : '+' + amount
|
||||
text: hide_amount ? '-' : '+' + amount + (in_txpool ? ' (%1)'.arg(qsTr('unconfirmed')) : '')
|
||||
selectionColor: MoneroComponents.Style.textSelectionColor
|
||||
selectByMouse: true
|
||||
readOnly: true
|
||||
|
||||
@@ -273,7 +273,6 @@ Rectangle {
|
||||
// LOG
|
||||
id: navLog
|
||||
property bool isActive: settingsStateView.state === "Log"
|
||||
visible: appWindow.walletMode >= 2
|
||||
Layout.preferredWidth: navLogText.width + grid.textMargin
|
||||
Layout.preferredHeight: 32
|
||||
Layout.minimumWidth: 72
|
||||
|
||||
@@ -103,7 +103,7 @@ Rectangle {
|
||||
MoneroComponents.TextBlock {
|
||||
font.pixelSize: 14
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
text: Version.GUI_MONERO_VERSION + translationManager.emptyString
|
||||
text: moneroVersion
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -131,10 +131,11 @@ Rectangle {
|
||||
}
|
||||
|
||||
MoneroComponents.TextBlock {
|
||||
id: walletLocation
|
||||
Layout.fillWidth: true
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
font.pixelSize: 14
|
||||
property string walletPath: (isIOS ? moneroAccountsDir : "") + appWindow.walletPath()
|
||||
property string walletPath: (isIOS ? appWindow.accountsDir : "") + persistentSettings.wallet_path
|
||||
text: "\
|
||||
<style type='text/css'>\
|
||||
a {cursor:pointer;text-decoration: none; color: #FF6C3C}\
|
||||
@@ -212,7 +213,6 @@ Rectangle {
|
||||
+ "The old wallet cache file will be renamed and can be restored later.\n"
|
||||
);
|
||||
confirmationDialog.icon = StandardIcon.Question
|
||||
confirmationDialog.cancelText = qsTr("Cancel")
|
||||
confirmationDialog.onAcceptedCallback = function() {
|
||||
appWindow.closeWallet(function() {
|
||||
walletManager.clearWalletCache(persistentSettings.wallet_path);
|
||||
@@ -230,7 +230,7 @@ Rectangle {
|
||||
appWindow.showStatusMessage(qsTr("Invalid restore height specified. Must be a number or a date formatted YYYY-MM-DD"),3);
|
||||
}
|
||||
inputDialog.onRejectedCallback = null;
|
||||
inputDialog.open(currentWallet ? currentWallet.walletCreationHeight : "0")
|
||||
inputDialog.open(currentWallet ? currentWallet.walletCreationHeight.toFixed(0) : "0")
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -381,32 +381,40 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
// Copy info to clipboard
|
||||
MoneroComponents.StandardButton {
|
||||
small: true
|
||||
text: qsTr("Copy to clipboard") + translationManager.emptyString
|
||||
onClicked: {
|
||||
var data = "";
|
||||
data += "GUI version: " + Version.GUI_VERSION + " (Qt " + qtRuntimeVersion + ")";
|
||||
data += "\nEmbedded Monero version: " + Version.GUI_MONERO_VERSION;
|
||||
data += "\nWallet path: ";
|
||||
RowLayout {
|
||||
spacing: 20;
|
||||
|
||||
var wallet_path = walletPath();
|
||||
if(isIOS)
|
||||
wallet_path = moneroAccountsDir + wallet_path;
|
||||
data += wallet_path;
|
||||
MoneroComponents.StandardButton {
|
||||
small: true
|
||||
text: qsTr("Copy to clipboard") + translationManager.emptyString
|
||||
onClicked: {
|
||||
var data = "";
|
||||
data += "GUI version: " + Version.GUI_VERSION + " (Qt " + qtRuntimeVersion + ")";
|
||||
data += "\nEmbedded Monero version: " + moneroVersion;
|
||||
data += "\nWallet path: " + walletLocation.walletPath;
|
||||
|
||||
data += "\nWallet creation height: ";
|
||||
if(currentWallet)
|
||||
data += currentWallet.walletCreationHeight;
|
||||
data += "\nWallet restore height: ";
|
||||
if(currentWallet)
|
||||
data += currentWallet.walletCreationHeight;
|
||||
|
||||
data += "\nWallet log path: " + walletLogPath;
|
||||
data += "\nWallet mode: " + walletModeString;
|
||||
data += "\nGraphics: " + isOpenGL ? "OpenGL" : "Low graphics mode";
|
||||
data += "\nWallet log path: " + walletLogPath;
|
||||
data += "\nWallet mode: " + walletModeString;
|
||||
data += "\nGraphics mode: " + isOpenGL ? "OpenGL" : "Low graphics mode";
|
||||
if (isTails)
|
||||
data += "\nTails: " + tailsUsePersistence ? "persistent" : "persistence disabled";
|
||||
|
||||
console.log("Copied to clipboard");
|
||||
clipboard.setText(data);
|
||||
appWindow.showStatusMessage(qsTr("Copied to clipboard"), 3);
|
||||
console.log("Copied to clipboard");
|
||||
clipboard.setText(data);
|
||||
appWindow.showStatusMessage(qsTr("Copied to clipboard"), 3);
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
small: true
|
||||
text: qsTr("Donate to Monero") + translationManager.emptyString
|
||||
onClicked: {
|
||||
middlePanel.sendTo("888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H", "", "Donation to Monero Core Team");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,14 @@ Rectangle {
|
||||
text: qsTr("Custom decorations") + translationManager.emptyString
|
||||
}
|
||||
|
||||
MoneroComponents.CheckBox {
|
||||
id: checkForUpdatesCheckBox
|
||||
enabled: !disableCheckUpdatesFlag
|
||||
checked: persistentSettings.checkForUpdates && !disableCheckUpdatesFlag
|
||||
onClicked: persistentSettings.checkForUpdates = !persistentSettings.checkForUpdates
|
||||
text: qsTr("Check for updates periodically") + translationManager.emptyString
|
||||
}
|
||||
|
||||
MoneroComponents.CheckBox {
|
||||
id: hideBalanceCheckBox
|
||||
checked: persistentSettings.hideBalance
|
||||
@@ -78,6 +86,46 @@ Rectangle {
|
||||
persistentSettings.blackTheme = MoneroComponents.Style.blackTheme;
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.CheckBox {
|
||||
checked: persistentSettings.askPasswordBeforeSending
|
||||
text: qsTr("Ask for password before sending a transaction") + translationManager.emptyString
|
||||
toggleOnClick: false
|
||||
onClicked: {
|
||||
if (persistentSettings.askPasswordBeforeSending) {
|
||||
passwordDialog.onAcceptedCallback = function() {
|
||||
if (appWindow.walletPassword === passwordDialog.password){
|
||||
persistentSettings.askPasswordBeforeSending = false;
|
||||
} else {
|
||||
passwordDialog.showError(qsTr("Wrong password"));
|
||||
}
|
||||
}
|
||||
passwordDialog.onRejectedCallback = null;
|
||||
passwordDialog.open()
|
||||
} else {
|
||||
persistentSettings.askPasswordBeforeSending = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.CheckBox {
|
||||
checked: persistentSettings.autosave
|
||||
onClicked: persistentSettings.autosave = !persistentSettings.autosave
|
||||
text: qsTr("Autosave") + translationManager.emptyString
|
||||
}
|
||||
|
||||
MoneroComponents.Slider {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 35
|
||||
Layout.topMargin: 6
|
||||
visible: persistentSettings.autosave
|
||||
from: 1
|
||||
stepSize: 1
|
||||
to: 60
|
||||
value: persistentSettings.autosaveMinutes
|
||||
text: "%1 %2 %3".arg(qsTr("Every")).arg(value).arg(qsTr("minute(s)")) + translationManager.emptyString
|
||||
onMoved: persistentSettings.autosaveMinutes = value
|
||||
}
|
||||
|
||||
MoneroComponents.CheckBox {
|
||||
id: userInActivityCheckbox
|
||||
@@ -86,70 +134,20 @@ Rectangle {
|
||||
text: qsTr("Lock wallet on inactivity") + translationManager.emptyString
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
MoneroComponents.Slider {
|
||||
visible: userInActivityCheckbox.checked
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 6
|
||||
Layout.leftMargin: 42
|
||||
spacing: 0
|
||||
|
||||
Text {
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
font.pixelSize: 14
|
||||
Layout.fillWidth: true
|
||||
text: {
|
||||
var val = userInactivitySlider.value;
|
||||
var minutes = val > 1 ? qsTr("minutes") : qsTr("minute");
|
||||
|
||||
qsTr("After ") + val + " " + minutes + translationManager.emptyString;
|
||||
}
|
||||
}
|
||||
|
||||
Slider {
|
||||
id: userInactivitySlider
|
||||
from: 1
|
||||
value: persistentSettings.lockOnUserInActivityInterval
|
||||
to: 60
|
||||
leftPadding: 0
|
||||
stepSize: 1
|
||||
snapMode: Slider.SnapAlways
|
||||
|
||||
background: Rectangle {
|
||||
x: parent.leftPadding
|
||||
y: parent.topPadding + parent.availableHeight / 2 - height / 2
|
||||
implicitWidth: 200
|
||||
implicitHeight: 4
|
||||
width: parent.availableWidth
|
||||
height: implicitHeight
|
||||
radius: 2
|
||||
color: MoneroComponents.Style.progressBarBackgroundColor
|
||||
|
||||
Rectangle {
|
||||
width: parent.visualPosition * parent.width
|
||||
height: parent.height
|
||||
color: MoneroComponents.Style.green
|
||||
radius: 2
|
||||
}
|
||||
}
|
||||
|
||||
handle: Rectangle {
|
||||
x: parent.leftPadding + parent.visualPosition * (parent.availableWidth - width)
|
||||
y: parent.topPadding + parent.availableHeight / 2 - height / 2
|
||||
implicitWidth: 18
|
||||
implicitHeight: 18
|
||||
radius: 8
|
||||
color: parent.pressed ? "#f0f0f0" : "#f6f6f6"
|
||||
border.color: MoneroComponents.Style.grey
|
||||
}
|
||||
|
||||
onMoved: persistentSettings.lockOnUserInActivityInterval = userInactivitySlider.value;
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
Layout.leftMargin: 35
|
||||
from: 1
|
||||
stepSize: 1
|
||||
to: 60
|
||||
value: persistentSettings.lockOnUserInActivityInterval
|
||||
text: {
|
||||
var minutes = value > 1 ? qsTr("minutes") : qsTr("minute");
|
||||
return qsTr("After ") + value + " " + minutes + translationManager.emptyString;
|
||||
}
|
||||
onMoved: persistentSettings.lockOnUserInActivityInterval = value
|
||||
}
|
||||
|
||||
//! Manage pricing
|
||||
@@ -212,6 +210,7 @@ Rectangle {
|
||||
MoneroComponents.StandardDropdown {
|
||||
id: fiatPriceCurrencyDropdown
|
||||
Layout.fillWidth: true
|
||||
currentIndex: persistentSettings.fiatPriceCurrency === "xmrusd" ? 0 : 1
|
||||
dataModel: fiatPriceCurrencyModel
|
||||
onChanged: {
|
||||
var obj = dataModel.get(currentIndex);
|
||||
@@ -252,6 +251,37 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.CheckBox {
|
||||
id: proxyCheckbox
|
||||
Layout.topMargin: 6
|
||||
enabled: !socksProxyFlagSet
|
||||
checked: socksProxyFlagSet ? socksProxyFlag : persistentSettings.proxyEnabled
|
||||
onClicked: {
|
||||
persistentSettings.proxyEnabled = !persistentSettings.proxyEnabled;
|
||||
}
|
||||
text: qsTr("Socks5 proxy (%1%2)")
|
||||
.arg(appWindow.walletMode >= 2 ? qsTr("remote node connections, ") : "")
|
||||
.arg(qsTr("updates downloading, fetching price sources")) + translationManager.emptyString
|
||||
}
|
||||
|
||||
MoneroComponents.RemoteNodeEdit {
|
||||
id: proxyEdit
|
||||
enabled: proxyCheckbox.enabled
|
||||
Layout.leftMargin: 36
|
||||
Layout.topMargin: 6
|
||||
Layout.minimumWidth: 100
|
||||
placeholderFontSize: 15
|
||||
visible: proxyCheckbox.checked
|
||||
|
||||
daemonAddrLabelText: qsTr("IP address") + translationManager.emptyString
|
||||
daemonPortLabelText: qsTr("Port") + translationManager.emptyString
|
||||
|
||||
initialAddress: socksProxyFlagSet ? socksProxyFlag : persistentSettings.proxyAddress
|
||||
onEditingFinished: {
|
||||
persistentSettings.proxyAddress = proxyEdit.getAddress();
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
visible: !persistentSettings.customDecorations
|
||||
Layout.topMargin: 10
|
||||
@@ -297,10 +327,6 @@ Rectangle {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
fiatPriceProviderDropDown.update();
|
||||
fiatPriceCurrencyDropdown.currentIndex = persistentSettings.fiatPriceCurrency === "xmrusd" ? 0 : 1;
|
||||
fiatPriceCurrencyDropdown.update();
|
||||
|
||||
console.log('SettingsLayout loaded');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ Rectangle {
|
||||
textFormat: TextEdit.RichText
|
||||
selectByMouse: true
|
||||
selectByKeyboard: true
|
||||
font.family: MoneroComponents.Style.defaultFontColor
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 14
|
||||
wrapMode: TextEdit.Wrap
|
||||
readOnly: true
|
||||
@@ -213,9 +213,27 @@ Rectangle {
|
||||
MoneroComponents.LineEdit {
|
||||
id: sendCommandText
|
||||
Layout.fillWidth: true
|
||||
property var lastCommands: []
|
||||
property int currentCommandIndex
|
||||
fontBold: false
|
||||
placeholderText: qsTr("command + enter (e.g 'help' or 'status')") + translationManager.emptyString
|
||||
placeholderFontSize: 16
|
||||
Keys.onUpPressed: {
|
||||
if (currentCommandIndex != 0) {
|
||||
sendCommandText.text = lastCommands[currentCommandIndex - 1]
|
||||
currentCommandIndex = currentCommandIndex - 1
|
||||
}
|
||||
}
|
||||
Keys.onDownPressed: {
|
||||
if (currentCommandIndex == lastCommands.length - 1) {
|
||||
currentCommandIndex = lastCommands.length;
|
||||
return text = "";
|
||||
}
|
||||
if (currentCommandIndex != lastCommands.length) {
|
||||
sendCommandText.text = lastCommands[currentCommandIndex + 1]
|
||||
currentCommandIndex = currentCommandIndex + 1
|
||||
}
|
||||
}
|
||||
onAccepted: {
|
||||
if(text.length > 0) {
|
||||
consoleArea.logCommand(">>> " + text)
|
||||
@@ -225,15 +243,14 @@ Rectangle {
|
||||
}
|
||||
});
|
||||
}
|
||||
lastCommands.push(text);
|
||||
currentCommandIndex = lastCommands.length;
|
||||
text = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
logLevelDropdown.currentIndex = appWindow.persistentSettings.logLevel;
|
||||
logLevelDropdown.update();
|
||||
|
||||
if(typeof daemonManager != "undefined")
|
||||
daemonManager.daemonConsoleUpdated.connect(onDaemonConsoleUpdated)
|
||||
}
|
||||
|
||||
@@ -130,13 +130,6 @@ 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)
|
||||
|
||||
// @TODO: Legacy. Remove after Qt 5.8.
|
||||
// https://stackoverflow.com/questions/41990013
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,13 +222,6 @@ Rectangle{
|
||||
topPadding: 0
|
||||
text: qsTr("Uses a third-party server to connect to the Monero network. Less secure, but easier on your computer.") + translationManager.emptyString
|
||||
width: parent.width - (remoteNodeIcon.width + remoteNodeIcon.anchors.leftMargin + anchors.leftMargin)
|
||||
|
||||
// @TODO: Legacy. Remove after Qt 5.8.
|
||||
// https://stackoverflow.com/questions/41990013
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -279,12 +265,10 @@ Rectangle{
|
||||
Layout.minimumWidth: 100
|
||||
placeholderFontSize: 15
|
||||
|
||||
daemonAddrLabelText: qsTr("Address")
|
||||
daemonPortLabelText: qsTr("Port")
|
||||
daemonAddrLabelText: qsTr("Address") + translationManager.emptyString
|
||||
daemonPortLabelText: qsTr("Port") + translationManager.emptyString
|
||||
|
||||
property var rna: persistentSettings.remoteNodeAddress
|
||||
daemonAddrText: rna.search(":") != -1 ? rna.split(":")[0].trim() : ""
|
||||
daemonPortText: rna.search(":") != -1 ? (rna.split(":")[1].trim() == "") ? appWindow.getDefaultDaemonRpcPort(persistentSettings.nettype) : rna.split(":")[1] : ""
|
||||
initialAddress: persistentSettings.remoteNodeAddress
|
||||
onEditingFinished: {
|
||||
persistentSettings.remoteNodeAddress = remoteNodeEdit.getAddress();
|
||||
console.log("setting remote node to " + persistentSettings.remoteNodeAddress);
|
||||
@@ -318,7 +302,7 @@ Rectangle{
|
||||
labelText: qsTr("Daemon password") + translationManager.emptyString
|
||||
text: persistentSettings.daemonPassword
|
||||
placeholderText: qsTr("Password") + translationManager.emptyString
|
||||
echoMode: TextInput.Password
|
||||
password: true
|
||||
placeholderFontSize: 15
|
||||
labelFontSize: 14
|
||||
fontSize: 15
|
||||
@@ -382,14 +366,12 @@ Rectangle{
|
||||
labelFontSize: 14
|
||||
property string style: "<style type='text/css'>a {cursor:pointer;text-decoration: none; color: #FF6C3C}</style>"
|
||||
labelText: qsTr("Blockchain location") + style + " <a href='#'> (%1)</a>".arg(qsTr("Change")) + translationManager.emptyString
|
||||
labelButtonText: qsTr("Reset") + translationManager.emptyString
|
||||
labelButtonVisible: text
|
||||
placeholderText: qsTr("(default)") + translationManager.emptyString
|
||||
placeholderFontSize: 15
|
||||
readOnly: true
|
||||
text: {
|
||||
if(persistentSettings.blockchainDataDir.length > 0){
|
||||
return persistentSettings.blockchainDataDir;
|
||||
} else { return "" }
|
||||
}
|
||||
text: persistentSettings.blockchainDataDir
|
||||
addressValidation: false
|
||||
onInputLabelLinkActivated: {
|
||||
//mouse.accepted = false
|
||||
@@ -399,6 +381,7 @@ Rectangle{
|
||||
blockchainFileDialog.open();
|
||||
blockchainFolder.focus = true;
|
||||
}
|
||||
onLabelButtonClicked: persistentSettings.blockchainDataDir = ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,7 +396,12 @@ Rectangle{
|
||||
placeholderFontSize: 15
|
||||
text: persistentSettings.daemonFlags
|
||||
addressValidation: false
|
||||
onEditingFinished: persistentSettings.daemonFlags = daemonFlags.text;
|
||||
error: text.match(/(^|\s)--(data-dir|bootstrap-daemon-address)/)
|
||||
onEditingFinished: {
|
||||
if (!daemonFlags.error) {
|
||||
persistentSettings.daemonFlags = daemonFlags.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
@@ -427,17 +415,9 @@ Rectangle{
|
||||
Layout.minimumWidth: 100
|
||||
Layout.bottomMargin: 20
|
||||
|
||||
daemonAddrLabelText: qsTr("Bootstrap Address")
|
||||
daemonPortLabelText: qsTr("Bootstrap Port")
|
||||
daemonAddrText: persistentSettings.bootstrapNodeAddress.split(":")[0].trim()
|
||||
daemonPortText: {
|
||||
var node_split = persistentSettings.bootstrapNodeAddress.split(":");
|
||||
if(node_split.length == 2){
|
||||
(node_split[1].trim() == "") ? appWindow.getDefaultDaemonRpcPort(persistentSettings.nettype) : node_split[1];
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
daemonAddrLabelText: qsTr("Bootstrap Address") + translationManager.emptyString
|
||||
daemonPortLabelText: qsTr("Bootstrap Port") + translationManager.emptyString
|
||||
initialAddress: persistentSettings.bootstrapNodeAddress
|
||||
onEditingFinished: {
|
||||
if (daemonAddrText == "auto") {
|
||||
persistentSettings.bootstrapNodeAddress = daemonAddrText;
|
||||
|
||||
@@ -30,6 +30,7 @@ import QtQuick 2.9
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Dialogs 1.2
|
||||
import FontAwesome 1.0
|
||||
|
||||
import "../../js/Utils.js" as Utils
|
||||
import "../../components" as MoneroComponents
|
||||
@@ -47,10 +48,10 @@ Rectangle {
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 0
|
||||
spacing: 8
|
||||
spacing: 0
|
||||
|
||||
MoneroComponents.SettingsListItem {
|
||||
buttonText: qsTr("Close wallet") + translationManager.emptyString
|
||||
iconText: FontAwesome.signOutAlt
|
||||
description: qsTr("Logs out of this wallet.") + translationManager.emptyString
|
||||
title: qsTr("Close this wallet") + translationManager.emptyString
|
||||
|
||||
@@ -58,7 +59,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
MoneroComponents.SettingsListItem {
|
||||
buttonText: qsTr("Create wallet") + translationManager.emptyString
|
||||
iconText: FontAwesome.eye
|
||||
description: qsTr("Creates a new wallet that can only view and initiate transactions, but requires a spendable wallet to sign transactions before sending.") + translationManager.emptyString
|
||||
title: qsTr("Create a view-only wallet") + translationManager.emptyString
|
||||
visible: !appWindow.viewOnly
|
||||
@@ -80,7 +81,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
MoneroComponents.SettingsListItem {
|
||||
buttonText: qsTr("Show seed") + translationManager.emptyString
|
||||
iconText: FontAwesome.key
|
||||
description: qsTr("Store this information safely to recover your wallet in the future.") + translationManager.emptyString
|
||||
title: qsTr("Show seed & keys") + translationManager.emptyString
|
||||
|
||||
@@ -90,7 +91,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
MoneroComponents.SettingsListItem {
|
||||
buttonText: qsTr("Rescan") + translationManager.emptyString
|
||||
iconText: FontAwesome.repeat
|
||||
description: qsTr("Use this feature if you think the shown balance is not accurate.") + translationManager.emptyString
|
||||
title: qsTr("Rescan wallet balance") + translationManager.emptyString
|
||||
visible: appWindow.walletMode >= 2
|
||||
@@ -114,7 +115,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
MoneroComponents.SettingsListItem {
|
||||
buttonText: qsTr("Change password") + translationManager.emptyString
|
||||
iconText: FontAwesome.ellipsisH
|
||||
description: qsTr("Change the password of your wallet.") + translationManager.emptyString
|
||||
title: qsTr("Change wallet password") + translationManager.emptyString
|
||||
|
||||
@@ -135,6 +136,19 @@ Rectangle {
|
||||
passwordDialog.open()
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.SettingsListItem {
|
||||
iconText: FontAwesome.cashRegister
|
||||
isLast: true
|
||||
description: qsTr("Receive Monero for your business, easily.") + translationManager.emptyString
|
||||
title: qsTr("Enter merchant mode") + translationManager.emptyString
|
||||
|
||||
onClicked: {
|
||||
middlePanel.state = "Merchant";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
updateBalance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
||||
24
qml.qrc
@@ -5,10 +5,14 @@
|
||||
<file>MiddlePanel.qml</file>
|
||||
<file>components/Label.qml</file>
|
||||
<file>components/SettingsListItem.qml</file>
|
||||
<file>components/Slider.qml</file>
|
||||
<file>components/UpdateDialog.qml</file>
|
||||
<file>images/whatIsIcon.png</file>
|
||||
<file>images/whatIsIcon@2x.png</file>
|
||||
<file>images/lockIcon.png</file>
|
||||
<file>components/MenuButton.qml</file>
|
||||
<file>monero/utils/gpg_keys/binaryfate.asc</file>
|
||||
<file>monero/utils/gpg_keys/fluffypony.asc</file>
|
||||
<file>monero/utils/gpg_keys/luigi1111.asc</file>
|
||||
<file>pages/Account.qml</file>
|
||||
<file>pages/Transfer.qml</file>
|
||||
<file>pages/History.qml</file>
|
||||
@@ -23,7 +27,7 @@
|
||||
<file>components/TipItem.qml</file>
|
||||
<file>images/tip.png</file>
|
||||
<file>components/MenuButtonDivider.qml</file>
|
||||
<file>images/moneroIcon.png</file>
|
||||
<file>images/monero-vector.svg</file>
|
||||
<file>components/StandardDropdown.qml</file>
|
||||
<file>images/whiteDropIndicator.png</file>
|
||||
<file>images/whiteDropIndicator@2x.png</file>
|
||||
@@ -34,7 +38,6 @@
|
||||
<file>images/prevMonth.png</file>
|
||||
<file>images/prevMonth@2x.png</file>
|
||||
<file>components/TitleBar.qml</file>
|
||||
<file>images/moneroLogo2.png</file>
|
||||
<file>images/resize.png</file>
|
||||
<file>images/resize@2x.png</file>
|
||||
<file>images/resizeHovered.png</file>
|
||||
@@ -84,7 +87,6 @@
|
||||
<file>lang/flags/ua.png</file>
|
||||
<file>lang/flags/gb.png</file>
|
||||
<file>lang/flags/us.png</file>
|
||||
<file>lang/flags/pirate.png</file>
|
||||
<file>lang/flags/nb_NO.png</file>
|
||||
<file>pages/Receive.qml</file>
|
||||
<file>pages/TxKey.qml</file>
|
||||
@@ -96,11 +98,11 @@
|
||||
<file>components/ProcessingSplash.qml</file>
|
||||
<file>components/ProgressBar.qml</file>
|
||||
<file>components/StandardDialog.qml</file>
|
||||
<file>components/DevicePassphraseDialog.qml</file>
|
||||
<file>pages/Sign.qml</file>
|
||||
<file>components/DaemonManagerDialog.qml</file>
|
||||
<file>version.js</file>
|
||||
<file>components/QRCodeScanner.qml</file>
|
||||
<file>components/Notifier.qml</file>
|
||||
<file>components/TextBlock.qml</file>
|
||||
<file>components/RemoteNodeEdit.qml</file>
|
||||
<file>pages/Keys.qml</file>
|
||||
@@ -110,8 +112,6 @@
|
||||
<file>images/card-background-white.png</file>
|
||||
<file>images/card-background-white@2x.png</file>
|
||||
<file>images/moneroLogo_white.png</file>
|
||||
<file>images/question.png</file>
|
||||
<file>images/question@2x.png</file>
|
||||
<file>images/titlebarLogo.png</file>
|
||||
<file>images/titlebarLogo@2x.png</file>
|
||||
<file>pages/merchant/MerchantTitlebar.qml</file>
|
||||
@@ -188,7 +188,6 @@
|
||||
<file>wizard/WizardHeader.qml</file>
|
||||
<file>wizard/WizardHome.qml</file>
|
||||
<file>wizard/WizardLanguage.qml</file>
|
||||
<file>wizard/WizardLang.qml</file>
|
||||
<file>wizard/WizardNav.qml</file>
|
||||
<file>wizard/WizardWalletInput.qml</file>
|
||||
<file>wizard/WizardRestoreWallet1.qml</file>
|
||||
@@ -204,7 +203,6 @@
|
||||
<file>js/Wizard.js</file>
|
||||
<file>components/LanguageSidebar.qml</file>
|
||||
<file>images/world-flags-globe.png</file>
|
||||
<file>images/langFlagGrey.png</file>
|
||||
<file>images/restore-wallet-from-hardware@2x.png</file>
|
||||
<file>images/restore-wallet-from-hardware.png</file>
|
||||
<file>images/open-wallet-from-file@2x.png</file>
|
||||
@@ -219,7 +217,6 @@
|
||||
<file>images/local-node@2x.png</file>
|
||||
<file>images/local-node-full.png</file>
|
||||
<file>images/local-node-full@2x.png</file>
|
||||
<file>wizard/WizardNavProgressDot.qml</file>
|
||||
<file>wizard/WizardOpenWallet1.qml</file>
|
||||
<file>images/arrow-right-in-circle.png</file>
|
||||
<file>images/arrow-right-in-circle@2x.png</file>
|
||||
@@ -233,7 +230,6 @@
|
||||
<file>images/themes/white/close.svg</file>
|
||||
<file>images/themes/white/fullscreen.svg</file>
|
||||
<file>images/themes/white/minimize.svg</file>
|
||||
<file>images/themes/white/question.svg</file>
|
||||
<file>components/effects/ColorTransition.qml</file>
|
||||
<file>components/effects/GradientBackground.qml</file>
|
||||
<file>images/check-white.svg</file>
|
||||
@@ -241,5 +237,11 @@
|
||||
<file>images/edit.svg</file>
|
||||
<file>images/arrow-right-in-circle-outline-medium-white.svg</file>
|
||||
<file>images/tails-grey.png</file>
|
||||
<file>components/AdvancedOptionsItem.qml</file>
|
||||
<file>images/busy-indicator.png</file>
|
||||
<file>images/busy-indicator@2x.png</file>
|
||||
<file>images/success.png</file>
|
||||
<file>images/success@2x.png</file>
|
||||
<file>components/SuccessfulTxDialog.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
add_subdirectory(QR-Code-generator)
|
||||
add_subdirectory(QR-Code-scanner)
|
||||
add_subdirectory(daemon)
|
||||
add_subdirectory(libwalletqt)
|
||||
add_subdirectory(model)
|
||||
add_subdirectory(openpgp)
|
||||
add_subdirectory(zxcvbn-c)
|
||||
|
||||
qt5_add_resources(RESOURCES ../qml.qrc)
|
||||
@@ -14,39 +14,39 @@ file(GLOB SOURCE_FILES
|
||||
"main/*.h"
|
||||
"main/*.cpp"
|
||||
"libwalletqt/WalletManager.cpp"
|
||||
"libwalletqt/WalletListenerImpl.cpp"
|
||||
"libwalletqt/Wallet.cpp"
|
||||
"libwalletqt/PassphraseHelper.cpp"
|
||||
"libwalletqt/PendingTransaction.cpp"
|
||||
"libwalletqt/TransactionHistory.cpp"
|
||||
"libwalletqt/TransactionInfo.cpp"
|
||||
"libwalletqt/QRCodeImageProvider.cpp" QR
|
||||
"QR-Code-generator/BitBuffer.cpp"
|
||||
"QR-Code-generator/QrCode.cpp"
|
||||
"QR-Code-generator/QrSegment.cpp"
|
||||
"libwalletqt/AddressBook.cpp"
|
||||
"libwalletqt/Subaddress.cpp"
|
||||
"libwalletqt/SubaddressAccount.cpp"
|
||||
"libwalletqt/UnsignedTransaction.cpp"
|
||||
"libwalletqt/WalletManager.h"
|
||||
"libwalletqt/Wallet.h"
|
||||
"libwalletqt/PassphraseHelper.h"
|
||||
"libwalletqt/PendingTransaction.h"
|
||||
"libwalletqt/TransactionHistory.h"
|
||||
"libwalletqt/TransactionInfo.h"
|
||||
"libwalletqt/QRCodeImageProvider.h"
|
||||
"QR-Code-generator/BitBuffer.h"
|
||||
"QR-Code-generator/QrCode.h"
|
||||
"QR-Code-generator/QrSegment.h"
|
||||
"libwalletqt/Transfer.h"
|
||||
"libwalletqt/AddressBook.h"
|
||||
"libwalletqt/Subaddress.h"
|
||||
"libwalletqt/SubaddressAccount.h"
|
||||
"libwalletqt/UnsignedTransaction.h"
|
||||
"daemon/*.h"
|
||||
"daemon/*.cpp"
|
||||
"model/*.h"
|
||||
"model/*.cpp"
|
||||
"qt/*.h"
|
||||
"daemon/*.h"
|
||||
"daemon/*.cpp"
|
||||
"model/*.h"
|
||||
"model/*.cpp"
|
||||
"qt/*.h"
|
||||
"qt/*.cpp"
|
||||
)
|
||||
if(APPLE)
|
||||
list(APPEND SOURCE_FILES "qt/macoshelper.mm")
|
||||
endif()
|
||||
|
||||
if(ENABLE_PASS_STRENGTH_METER)
|
||||
file(GLOB PASS_STRENGTH_FILES
|
||||
@@ -57,8 +57,6 @@ endif()
|
||||
|
||||
if(WITH_SCANNER)
|
||||
file(GLOB QR_CODE_FILES
|
||||
"QR-Code-generator/*.h"
|
||||
"QR-Code-generator/*.cpp"
|
||||
"QR-Code-scanner/*.h"
|
||||
"QR-Code-scanner/*.cpp"
|
||||
)
|
||||
@@ -72,36 +70,50 @@ if(MINGW)
|
||||
set(ICON_RC ${CMAKE_CURRENT_BINARY_DIR}/icon.rc)
|
||||
set(ICON_RES ${CMAKE_CURRENT_BINARY_DIR}/icon.o)
|
||||
file(WRITE ${ICON_RC} "IDI_ICON1 ICON DISCARDABLE \"${ICON}\"")
|
||||
add_custom_command(OUTPUT ${ICON_RES} COMMAND windres ${ICON_RC} ${ICON_RES} MAIN_DEPENDENCY ${ICON_RC})
|
||||
find_program(Qt5_WINDRES_EXECUTABLE NAMES windres x86_64-w64-mingw32-windres REQUIRED CMAKE_FIND_ROOT_PATH_BOTH)
|
||||
add_custom_command(OUTPUT ${ICON_RES} COMMAND ${Qt5_WINDRES_EXECUTABLE} ${ICON_RC} ${ICON_RES} MAIN_DEPENDENCY ${ICON_RC})
|
||||
list(APPEND RESOURCES ${ICON_RES})
|
||||
endif()
|
||||
|
||||
add_executable(monero-gui ${EXECUTABLE_FLAG} main/main.cpp
|
||||
if(APPLE)
|
||||
set(ICON ${PROJECT_SOURCE_DIR}/images/appicon.icns)
|
||||
set_source_files_properties(${ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||
list(APPEND RESOURCES ${ICON})
|
||||
endif()
|
||||
|
||||
add_executable(monero-wallet-gui ${EXECUTABLE_FLAG} main/main.cpp
|
||||
${SOURCE_FILES}
|
||||
${PASS_STRENGTH_FILES}
|
||||
${QR_CODE_FILES}
|
||||
${RESOURCES}
|
||||
)
|
||||
set_property(TARGET monero-gui PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
|
||||
set_target_properties(monero-wallet-gui PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/share/Info.plist"
|
||||
)
|
||||
|
||||
# OpenGL
|
||||
target_include_directories(monero-gui PUBLIC ${OPENGL_INCLUDE_DIR})
|
||||
target_include_directories(monero-wallet-gui PUBLIC ${OPENGL_INCLUDE_DIR})
|
||||
message(STATUS "OpenGL: include dir at ${OPENGL_INCLUDE_DIR}")
|
||||
message(STATUS "OpenGL: libraries at ${OPENGL_LIBRARIES}")
|
||||
|
||||
target_include_directories(monero-gui PUBLIC ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
target_include_directories(monero-wallet-gui PUBLIC ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
|
||||
file(GLOB_RECURSE SRC_SOURCES *.cpp)
|
||||
file(GLOB_RECURSE SRC_HEADERS *.h)
|
||||
|
||||
target_include_directories(monero-gui PUBLIC
|
||||
target_include_directories(monero-wallet-gui PUBLIC
|
||||
${CMAKE_SOURCE_DIR}/monero/include
|
||||
${CMAKE_SOURCE_DIR}/monero/src
|
||||
${CMAKE_SOURCE_DIR}/monero/external/easylogging++
|
||||
${CMAKE_SOURCE_DIR}/monero/contrib/epee/include
|
||||
${CMAKE_SOURCE_DIR}/monero/external/qrcodegen
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/daemon
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libwalletqt
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/model
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/QR-Code-generator
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/QR-Code-scanner
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/zxcvbn-c
|
||||
${LibUSB_INCLUDE_DIRS}
|
||||
@@ -112,33 +124,25 @@ target_include_directories(monero-gui PUBLIC
|
||||
${ZBAR_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_compile_definitions(monero-gui
|
||||
target_compile_definitions(monero-wallet-gui
|
||||
PUBLIC
|
||||
${Qt5Widgets_DEFINITIONS}
|
||||
${Qt5Qml_DEFINITIONS}
|
||||
)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
|
||||
if(X11_FOUND)
|
||||
target_link_libraries(monero-gui ${X11_LIBRARIES} pthread dl Xt xcb X11)
|
||||
endif()
|
||||
|
||||
if(DEVICE_TREZOR_READY)
|
||||
target_link_libraries(monero-gui ${TREZOR_DEP_LIBS})
|
||||
endif()
|
||||
|
||||
target_link_libraries(monero-gui
|
||||
${CMAKE_BINARY_DIR}/lib/libwallet_merged.a
|
||||
target_link_libraries(monero-wallet-gui
|
||||
wallet_merged
|
||||
${LMDB_LIBRARY}
|
||||
${CMAKE_BINARY_DIR}/monero/contrib/epee/src/libepee.a
|
||||
${CMAKE_BINARY_DIR}/monero/external/unbound/libunbound.a
|
||||
epee
|
||||
qrcodegen
|
||||
${UNBOUND_LIBRARY}
|
||||
${SODIUM_LIBRARY}
|
||||
${CMAKE_BINARY_DIR}/monero/external/easylogging++/libeasylogging.a
|
||||
${CMAKE_BINARY_DIR}/monero/src/blockchain_db/libblockchain_db.a
|
||||
${CMAKE_BINARY_DIR}/monero/external/randomx/librandomx.a
|
||||
${CMAKE_BINARY_DIR}/monero/src/hardforks/libhardforks.a
|
||||
easylogging
|
||||
blockchain_db
|
||||
randomx
|
||||
hardforks
|
||||
${Boost_LIBRARIES}
|
||||
${OPENSSL_LIBRARIES}
|
||||
${CMAKE_DL_LIBS}
|
||||
@@ -147,10 +151,20 @@ target_link_libraries(monero-gui
|
||||
${QT5_LIBRARIES}
|
||||
${EXTRA_LIBRARIES}
|
||||
${ICU_LIBRARIES}
|
||||
openpgp
|
||||
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)
|
||||
target_link_libraries(monero-gui
|
||||
target_link_libraries(monero-wallet-gui
|
||||
${ZBAR_LIBRARIES}
|
||||
jpeg
|
||||
v4l2
|
||||
@@ -159,6 +173,10 @@ if(WITH_SCANNER)
|
||||
)
|
||||
endif()
|
||||
|
||||
install(TARGETS monero-gui
|
||||
add_custom_command(TARGET monero-wallet-gui POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:daemon> $<TARGET_FILE_DIR:monero-wallet-gui>)
|
||||
|
||||
include(Deploy)
|
||||
|
||||
install(TARGETS monero-wallet-gui
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}
|
||||
)
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* QR Code generator library (C++)
|
||||
*
|
||||
* Copyright (c) 2016 Project Nayuki
|
||||
* https://www.nayuki.io/page/qr-code-generator-library
|
||||
*
|
||||
* (MIT License)
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
* - The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* - The Software is provided "as is", without warranty of any kind, express or
|
||||
* implied, including but not limited to the warranties of merchantability,
|
||||
* fitness for a particular purpose and noninfringement. In no event shall the
|
||||
* authors or copyright holders be liable for any claim, damages or other
|
||||
* liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
* out of or in connection with the Software or the use or other dealings in the
|
||||
* Software.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include "BitBuffer.hpp"
|
||||
|
||||
|
||||
qrcodegen::BitBuffer::BitBuffer() :
|
||||
data(),
|
||||
bitLength(0) {}
|
||||
|
||||
|
||||
int qrcodegen::BitBuffer::getBitLength() const {
|
||||
return bitLength;
|
||||
}
|
||||
|
||||
|
||||
std::vector<uint8_t> qrcodegen::BitBuffer::getBytes() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void qrcodegen::BitBuffer::appendBits(uint32_t val, int len) {
|
||||
if (len < 0 || len > 32 || (len < 32 && (val >> len) != 0))
|
||||
throw "Value out of range";
|
||||
size_t newBitLen = bitLength + len;
|
||||
while (data.size() * 8 < newBitLen)
|
||||
data.push_back(0);
|
||||
for (int i = len - 1; i >= 0; i--, bitLength++) // Append bit by bit
|
||||
data.at(bitLength >> 3) |= ((val >> i) & 1) << (7 - (bitLength & 7));
|
||||
}
|
||||
|
||||
|
||||
void qrcodegen::BitBuffer::appendData(const QrSegment &seg) {
|
||||
size_t newBitLen = bitLength + seg.bitLength;
|
||||
while (data.size() * 8 < newBitLen)
|
||||
data.push_back(0);
|
||||
for (int i = 0; i < seg.bitLength; i++, bitLength++) { // Append bit by bit
|
||||
int bit = (seg.data.at(i >> 3) >> (7 - (i & 7))) & 1;
|
||||
data.at(bitLength >> 3) |= bit << (7 - (bitLength & 7));
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* QR Code generator library (C++)
|
||||
*
|
||||
* Copyright (c) 2016 Project Nayuki
|
||||
* https://www.nayuki.io/page/qr-code-generator-library
|
||||
*
|
||||
* (MIT License)
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
* - The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* - The Software is provided "as is", without warranty of any kind, express or
|
||||
* implied, including but not limited to the warranties of merchantability,
|
||||
* fitness for a particular purpose and noninfringement. In no event shall the
|
||||
* authors or copyright holders be liable for any claim, damages or other
|
||||
* liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
* out of or in connection with the Software or the use or other dealings in the
|
||||
* Software.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "QrSegment.hpp"
|
||||
|
||||
|
||||
namespace qrcodegen {
|
||||
|
||||
/*
|
||||
* An appendable sequence of bits. Bits are packed in big endian within a byte.
|
||||
*/
|
||||
class BitBuffer final {
|
||||
|
||||
/*---- Fields ----*/
|
||||
private:
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
int bitLength;
|
||||
|
||||
|
||||
|
||||
/*---- Constructor ----*/
|
||||
public:
|
||||
|
||||
// Creates an empty bit buffer (length 0).
|
||||
BitBuffer();
|
||||
|
||||
|
||||
|
||||
/*---- Methods ----*/
|
||||
public:
|
||||
|
||||
// Returns the number of bits in the buffer, which is a non-negative value.
|
||||
int getBitLength() const;
|
||||
|
||||
|
||||
// Returns a copy of all bytes, padding up to the nearest byte.
|
||||
std::vector<uint8_t> getBytes() const;
|
||||
|
||||
|
||||
// Appends the given number of bits of the given value to this sequence.
|
||||
// If 0 <= len <= 31, then this requires 0 <= val < 2^len.
|
||||
void appendBits(uint32_t val, int len);
|
||||
|
||||
|
||||
// Appends the data of the given segment to this bit buffer.
|
||||
void appendData(const QrSegment &seg);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
file(GLOB_RECURSE SRC_SOURCES *.cpp)
|
||||
file(GLOB_RECURSE SRC_HEADERS *.h)
|
||||
|
||||
|
||||
@@ -1,644 +0,0 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* QR Code generator library (C++)
|
||||
*
|
||||
* Copyright (c) 2016 Project Nayuki
|
||||
* https://www.nayuki.io/page/qr-code-generator-library
|
||||
*
|
||||
* (MIT License)
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
* - The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* - The Software is provided "as is", without warranty of any kind, express or
|
||||
* implied, including but not limited to the warranties of merchantability,
|
||||
* fitness for a particular purpose and noninfringement. In no event shall the
|
||||
* authors or copyright holders be liable for any claim, damages or other
|
||||
* liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
* out of or in connection with the Software or the use or other dealings in the
|
||||
* Software.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <sstream>
|
||||
#include "BitBuffer.hpp"
|
||||
#include "QrCode.hpp"
|
||||
|
||||
|
||||
qrcodegen::QrCode::Ecc::Ecc(int ord, int fb) :
|
||||
ordinal(ord),
|
||||
formatBits(fb) {}
|
||||
|
||||
|
||||
const qrcodegen::QrCode::Ecc qrcodegen::QrCode::Ecc::LOW (0, 1);
|
||||
const qrcodegen::QrCode::Ecc qrcodegen::QrCode::Ecc::MEDIUM (1, 0);
|
||||
const qrcodegen::QrCode::Ecc qrcodegen::QrCode::Ecc::QUARTILE(2, 3);
|
||||
const qrcodegen::QrCode::Ecc qrcodegen::QrCode::Ecc::HIGH (3, 2);
|
||||
|
||||
|
||||
qrcodegen::QrCode qrcodegen::QrCode::encodeText(const char *text, const Ecc &ecl) {
|
||||
std::vector<QrSegment> segs(QrSegment::makeSegments(text));
|
||||
return encodeSegments(segs, ecl);
|
||||
}
|
||||
|
||||
|
||||
qrcodegen::QrCode qrcodegen::QrCode::encodeBinary(const std::vector<uint8_t> &data, const Ecc &ecl) {
|
||||
std::vector<QrSegment> segs;
|
||||
segs.push_back(QrSegment::makeBytes(data));
|
||||
return encodeSegments(segs, ecl);
|
||||
}
|
||||
|
||||
|
||||
qrcodegen::QrCode qrcodegen::QrCode::encodeSegments(const std::vector<QrSegment> &segs, const Ecc &ecl,
|
||||
int minVersion, int maxVersion, int mask, bool boostEcl) {
|
||||
if (!(1 <= minVersion && minVersion <= maxVersion && maxVersion <= 40) || mask < -1 || mask > 7)
|
||||
throw "Invalid value";
|
||||
|
||||
// Find the minimal version number to use
|
||||
int version, dataUsedBits;
|
||||
for (version = minVersion; ; version++) {
|
||||
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
|
||||
dataUsedBits = QrSegment::getTotalBits(segs, version);
|
||||
if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
|
||||
break; // This version number is found to be suitable
|
||||
if (version >= maxVersion) // All versions in the range could not fit the given data
|
||||
throw "Data too long";
|
||||
}
|
||||
if (dataUsedBits == -1)
|
||||
throw "Assertion error";
|
||||
|
||||
// Increase the error correction level while the data still fits in the current version number
|
||||
const Ecc *newEcl = &ecl;
|
||||
if (boostEcl) {
|
||||
if (dataUsedBits <= getNumDataCodewords(version, Ecc::MEDIUM ) * 8) newEcl = &Ecc::MEDIUM ;
|
||||
if (dataUsedBits <= getNumDataCodewords(version, Ecc::QUARTILE) * 8) newEcl = &Ecc::QUARTILE;
|
||||
if (dataUsedBits <= getNumDataCodewords(version, Ecc::HIGH ) * 8) newEcl = &Ecc::HIGH ;
|
||||
}
|
||||
|
||||
// Create the data bit string by concatenating all segments
|
||||
int dataCapacityBits = getNumDataCodewords(version, *newEcl) * 8;
|
||||
BitBuffer bb;
|
||||
for (size_t i = 0; i < segs.size(); i++) {
|
||||
const QrSegment &seg(segs.at(i));
|
||||
bb.appendBits(seg.mode.modeBits, 4);
|
||||
bb.appendBits(seg.numChars, seg.mode.numCharCountBits(version));
|
||||
bb.appendData(seg);
|
||||
}
|
||||
|
||||
// Add terminator and pad up to a byte if applicable
|
||||
bb.appendBits(0, std::min(4, dataCapacityBits - bb.getBitLength()));
|
||||
bb.appendBits(0, (8 - bb.getBitLength() % 8) % 8);
|
||||
|
||||
// Pad with alternate bytes until data capacity is reached
|
||||
for (uint8_t padByte = 0xEC; bb.getBitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
|
||||
bb.appendBits(padByte, 8);
|
||||
if (bb.getBitLength() % 8 != 0)
|
||||
throw "Assertion error";
|
||||
|
||||
// Create the QR Code symbol
|
||||
return QrCode(version, *newEcl, bb.getBytes(), mask);
|
||||
}
|
||||
|
||||
|
||||
qrcodegen::QrCode::QrCode(int ver, const Ecc &ecl, const std::vector<uint8_t> &dataCodewords, int mask) :
|
||||
// Initialize scalar fields
|
||||
version(ver),
|
||||
size(1 <= ver && ver <= 40 ? ver * 4 + 17 : -1), // Avoid signed overflow undefined behavior
|
||||
errorCorrectionLevel(ecl) {
|
||||
|
||||
// Check arguments
|
||||
if (ver < 1 || ver > 40 || mask < -1 || mask > 7)
|
||||
throw "Value out of range";
|
||||
|
||||
std::vector<bool> row(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
modules.push_back(row);
|
||||
isFunction.push_back(row);
|
||||
}
|
||||
|
||||
// Draw function patterns, draw all codewords, do masking
|
||||
drawFunctionPatterns();
|
||||
const std::vector<uint8_t> allCodewords(appendErrorCorrection(dataCodewords));
|
||||
drawCodewords(allCodewords);
|
||||
this->mask = handleConstructorMasking(mask);
|
||||
}
|
||||
|
||||
|
||||
qrcodegen::QrCode::QrCode(const QrCode &qr, int mask) :
|
||||
// Copy scalar fields
|
||||
version(qr.version),
|
||||
size(qr.size),
|
||||
errorCorrectionLevel(qr.errorCorrectionLevel) {
|
||||
|
||||
// Check arguments
|
||||
if (mask < -1 || mask > 7)
|
||||
throw "Mask value out of range";
|
||||
|
||||
// Handle grid fields
|
||||
modules = qr.modules;
|
||||
isFunction = qr.isFunction;
|
||||
|
||||
// Handle masking
|
||||
applyMask(qr.mask); // Undo old mask
|
||||
this->mask = handleConstructorMasking(mask);
|
||||
}
|
||||
|
||||
|
||||
int qrcodegen::QrCode::getMask() const {
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
||||
int qrcodegen::QrCode::getModule(int x, int y) const {
|
||||
if (0 <= x && x < size && 0 <= y && y < size)
|
||||
return modules.at(y).at(x) ? 1 : 0;
|
||||
else
|
||||
return 0; // Infinite white border
|
||||
}
|
||||
|
||||
|
||||
std::string qrcodegen::QrCode::toSvgString(int border) const {
|
||||
if (border < 0)
|
||||
throw "Border must be non-negative";
|
||||
std::ostringstream sb;
|
||||
sb << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
sb << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n";
|
||||
sb << "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 ";
|
||||
sb << (size + border * 2) << " " << (size + border * 2) << "\">\n";
|
||||
sb << "\t<rect width=\"100%\" height=\"100%\" fill=\"#FFFFFF\" stroke-width=\"0\"/>\n";
|
||||
sb << "\t<path d=\"";
|
||||
bool head = true;
|
||||
for (int y = -border; y < size + border; y++) {
|
||||
for (int x = -border; x < size + border; x++) {
|
||||
if (getModule(x, y) == 1) {
|
||||
if (head)
|
||||
head = false;
|
||||
else
|
||||
sb << " ";
|
||||
sb << "M" << (x + border) << "," << (y + border) << "h1v1h-1z";
|
||||
}
|
||||
}
|
||||
}
|
||||
sb << "\" fill=\"#000000\" stroke-width=\"0\"/>\n";
|
||||
sb << "</svg>\n";
|
||||
return sb.str();
|
||||
}
|
||||
|
||||
|
||||
void qrcodegen::QrCode::drawFunctionPatterns() {
|
||||
// Draw the horizontal and vertical timing patterns
|
||||
for (int i = 0; i < size; i++) {
|
||||
setFunctionModule(6, i, i % 2 == 0);
|
||||
setFunctionModule(i, 6, i % 2 == 0);
|
||||
}
|
||||
|
||||
// Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
|
||||
drawFinderPattern(3, 3);
|
||||
drawFinderPattern(size - 4, 3);
|
||||
drawFinderPattern(3, size - 4);
|
||||
|
||||
// Draw the numerous alignment patterns
|
||||
const std::vector<int> alignPatPos(getAlignmentPatternPositions(version));
|
||||
int numAlign = alignPatPos.size();
|
||||
for (int i = 0; i < numAlign; i++) {
|
||||
for (int j = 0; j < numAlign; j++) {
|
||||
if ((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))
|
||||
continue; // Skip the three finder corners
|
||||
else
|
||||
drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j));
|
||||
}
|
||||
}
|
||||
|
||||
// Draw configuration data
|
||||
drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
|
||||
drawVersion();
|
||||
}
|
||||
|
||||
|
||||
void qrcodegen::QrCode::drawFormatBits(int mask) {
|
||||
// Calculate error correction code and pack bits
|
||||
int data = errorCorrectionLevel.formatBits << 3 | mask; // errCorrLvl is uint2, mask is uint3
|
||||
int rem = data;
|
||||
for (int i = 0; i < 10; i++)
|
||||
rem = (rem << 1) ^ ((rem >> 9) * 0x537);
|
||||
data = data << 10 | rem;
|
||||
data ^= 0x5412; // uint15
|
||||
if (data >> 15 != 0)
|
||||
throw "Assertion error";
|
||||
|
||||
// Draw first copy
|
||||
for (int i = 0; i <= 5; i++)
|
||||
setFunctionModule(8, i, ((data >> i) & 1) != 0);
|
||||
setFunctionModule(8, 7, ((data >> 6) & 1) != 0);
|
||||
setFunctionModule(8, 8, ((data >> 7) & 1) != 0);
|
||||
setFunctionModule(7, 8, ((data >> 8) & 1) != 0);
|
||||
for (int i = 9; i < 15; i++)
|
||||
setFunctionModule(14 - i, 8, ((data >> i) & 1) != 0);
|
||||
|
||||
// Draw second copy
|
||||
for (int i = 0; i <= 7; i++)
|
||||
setFunctionModule(size - 1 - i, 8, ((data >> i) & 1) != 0);
|
||||
for (int i = 8; i < 15; i++)
|
||||
setFunctionModule(8, size - 15 + i, ((data >> i) & 1) != 0);
|
||||
setFunctionModule(8, size - 8, true);
|
||||
}
|
||||
|
||||
|
||||
void qrcodegen::QrCode::drawVersion() {
|
||||
if (version < 7)
|
||||
return;
|
||||
|
||||
// Calculate error correction code and pack bits
|
||||
int rem = version; // version is uint6, in the range [7, 40]
|
||||
for (int i = 0; i < 12; i++)
|
||||
rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
|
||||
int data = version << 12 | rem; // uint18
|
||||
if (data >> 18 != 0)
|
||||
throw "Assertion error";
|
||||
|
||||
// Draw two copies
|
||||
for (int i = 0; i < 18; i++) {
|
||||
bool bit = ((data >> i) & 1) != 0;
|
||||
int a = size - 11 + i % 3, b = i / 3;
|
||||
setFunctionModule(a, b, bit);
|
||||
setFunctionModule(b, a, bit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void qrcodegen::QrCode::drawFinderPattern(int x, int y) {
|
||||
for (int i = -4; i <= 4; i++) {
|
||||
for (int j = -4; j <= 4; j++) {
|
||||
int dist = std::max(std::abs(i), std::abs(j)); // Chebyshev/infinity norm
|
||||
int xx = x + j, yy = y + i;
|
||||
if (0 <= xx && xx < size && 0 <= yy && yy < size)
|
||||
setFunctionModule(xx, yy, dist != 2 && dist != 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void qrcodegen::QrCode::drawAlignmentPattern(int x, int y) {
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
for (int j = -2; j <= 2; j++)
|
||||
setFunctionModule(x + j, y + i, std::max(std::abs(i), std::abs(j)) != 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void qrcodegen::QrCode::setFunctionModule(int x, int y, bool isBlack) {
|
||||
modules.at(y).at(x) = isBlack;
|
||||
isFunction.at(y).at(x) = true;
|
||||
}
|
||||
|
||||
|
||||
std::vector<uint8_t> qrcodegen::QrCode::appendErrorCorrection(const std::vector<uint8_t> &data) const {
|
||||
if (data.size() != static_cast<unsigned int>(getNumDataCodewords(version, errorCorrectionLevel)))
|
||||
throw "Invalid argument";
|
||||
|
||||
// Calculate parameter numbers
|
||||
int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[errorCorrectionLevel.ordinal][version];
|
||||
int totalEcc = NUM_ERROR_CORRECTION_CODEWORDS[errorCorrectionLevel.ordinal][version];
|
||||
if (totalEcc % numBlocks != 0)
|
||||
throw "Assertion error";
|
||||
int blockEccLen = totalEcc / numBlocks;
|
||||
int numShortBlocks = numBlocks - getNumRawDataModules(version) / 8 % numBlocks;
|
||||
int shortBlockLen = getNumRawDataModules(version) / 8 / numBlocks;
|
||||
|
||||
// Split data into blocks and append ECC to each block
|
||||
std::vector<std::vector<uint8_t>> blocks;
|
||||
const ReedSolomonGenerator rs(blockEccLen);
|
||||
for (int i = 0, k = 0; i < numBlocks; i++) {
|
||||
std::vector<uint8_t> dat;
|
||||
dat.insert(dat.begin(), data.begin() + k, data.begin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)));
|
||||
k += dat.size();
|
||||
const std::vector<uint8_t> ecc(rs.getRemainder(dat));
|
||||
if (i < numShortBlocks)
|
||||
dat.push_back(0);
|
||||
dat.insert(dat.end(), ecc.begin(), ecc.end());
|
||||
blocks.push_back(dat);
|
||||
}
|
||||
|
||||
// Interleave (not concatenate) the bytes from every block into a single sequence
|
||||
std::vector<uint8_t> result;
|
||||
for (int i = 0; static_cast<unsigned int>(i) < blocks.at(0).size(); i++) {
|
||||
for (int j = 0; static_cast<unsigned int>(j) < blocks.size(); j++) {
|
||||
// Skip the padding byte in short blocks
|
||||
if (i != shortBlockLen - blockEccLen || j >= numShortBlocks)
|
||||
result.push_back(blocks.at(j).at(i));
|
||||
}
|
||||
}
|
||||
if (result.size() != static_cast<unsigned int>(getNumRawDataModules(version) / 8))
|
||||
throw "Assertion error";
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void qrcodegen::QrCode::drawCodewords(const std::vector<uint8_t> &data) {
|
||||
if (data.size() != static_cast<unsigned int>(getNumRawDataModules(version) / 8))
|
||||
throw "Invalid argument";
|
||||
|
||||
size_t i = 0; // Bit index into the data
|
||||
// Do the funny zigzag scan
|
||||
for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
|
||||
if (right == 6)
|
||||
right = 5;
|
||||
for (int vert = 0; vert < size; vert++) { // Vertical counter
|
||||
for (int j = 0; j < 2; j++) {
|
||||
int x = right - j; // Actual x coordinate
|
||||
bool upwards = ((right & 2) == 0) ^ (x < 6);
|
||||
int y = upwards ? size - 1 - vert : vert; // Actual y coordinate
|
||||
if (!isFunction.at(y).at(x) && i < data.size() * 8) {
|
||||
modules.at(y).at(x) = ((data.at(i >> 3) >> (7 - (i & 7))) & 1) != 0;
|
||||
i++;
|
||||
}
|
||||
// If there are any remainder bits (0 to 7), they are already
|
||||
// set to 0/false/white when the grid of modules was initialized
|
||||
}
|
||||
}
|
||||
}
|
||||
if (static_cast<unsigned int>(i) != data.size() * 8)
|
||||
throw "Assertion error";
|
||||
}
|
||||
|
||||
|
||||
void qrcodegen::QrCode::applyMask(int mask) {
|
||||
if (mask < 0 || mask > 7)
|
||||
throw "Mask value out of range";
|
||||
for (int y = 0; y < size; y++) {
|
||||
for (int x = 0; x < size; x++) {
|
||||
bool invert;
|
||||
switch (mask) {
|
||||
case 0: invert = (x + y) % 2 == 0; break;
|
||||
case 1: invert = y % 2 == 0; break;
|
||||
case 2: invert = x % 3 == 0; break;
|
||||
case 3: invert = (x + y) % 3 == 0; break;
|
||||
case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
|
||||
case 5: invert = x * y % 2 + x * y % 3 == 0; break;
|
||||
case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
|
||||
case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
|
||||
default: throw "Assertion error";
|
||||
}
|
||||
modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int qrcodegen::QrCode::handleConstructorMasking(int mask) {
|
||||
if (mask == -1) { // Automatically choose best mask
|
||||
int32_t minPenalty = INT32_MAX;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
drawFormatBits(i);
|
||||
applyMask(i);
|
||||
int penalty = getPenaltyScore();
|
||||
if (penalty < minPenalty) {
|
||||
mask = i;
|
||||
minPenalty = penalty;
|
||||
}
|
||||
applyMask(i); // Undoes the mask due to XOR
|
||||
}
|
||||
}
|
||||
if (mask < 0 || mask > 7)
|
||||
throw "Assertion error";
|
||||
drawFormatBits(mask); // Overwrite old format bits
|
||||
applyMask(mask); // Apply the final choice of mask
|
||||
return mask; // The caller shall assign this value to the final-declared field
|
||||
}
|
||||
|
||||
|
||||
int qrcodegen::QrCode::getPenaltyScore() const {
|
||||
int result = 0;
|
||||
|
||||
// Adjacent modules in row having same color
|
||||
for (int y = 0; y < size; y++) {
|
||||
bool colorX = modules.at(y).at(0);
|
||||
for (int x = 1, runX = 1; x < size; x++) {
|
||||
if (modules.at(y).at(x) != colorX) {
|
||||
colorX = modules.at(y).at(x);
|
||||
runX = 1;
|
||||
} else {
|
||||
runX++;
|
||||
if (runX == 5)
|
||||
result += PENALTY_N1;
|
||||
else if (runX > 5)
|
||||
result++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Adjacent modules in column having same color
|
||||
for (int x = 0; x < size; x++) {
|
||||
bool colorY = modules.at(0).at(x);
|
||||
for (int y = 1, runY = 1; y < size; y++) {
|
||||
if (modules.at(y).at(x) != colorY) {
|
||||
colorY = modules.at(y).at(x);
|
||||
runY = 1;
|
||||
} else {
|
||||
runY++;
|
||||
if (runY == 5)
|
||||
result += PENALTY_N1;
|
||||
else if (runY > 5)
|
||||
result++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2*2 blocks of modules having same color
|
||||
for (int y = 0; y < size - 1; y++) {
|
||||
for (int x = 0; x < size - 1; x++) {
|
||||
bool color = modules.at(y).at(x);
|
||||
if ( color == modules.at(y).at(x + 1) &&
|
||||
color == modules.at(y + 1).at(x) &&
|
||||
color == modules.at(y + 1).at(x + 1))
|
||||
result += PENALTY_N2;
|
||||
}
|
||||
}
|
||||
|
||||
// Finder-like pattern in rows
|
||||
for (int y = 0; y < size; y++) {
|
||||
for (int x = 0, bits = 0; x < size; x++) {
|
||||
bits = ((bits << 1) & 0x7FF) | (modules.at(y).at(x) ? 1 : 0);
|
||||
if (x >= 10 && (bits == 0x05D || bits == 0x5D0)) // Needs 11 bits accumulated
|
||||
result += PENALTY_N3;
|
||||
}
|
||||
}
|
||||
// Finder-like pattern in columns
|
||||
for (int x = 0; x < size; x++) {
|
||||
for (int y = 0, bits = 0; y < size; y++) {
|
||||
bits = ((bits << 1) & 0x7FF) | (modules.at(y).at(x) ? 1 : 0);
|
||||
if (y >= 10 && (bits == 0x05D || bits == 0x5D0)) // Needs 11 bits accumulated
|
||||
result += PENALTY_N3;
|
||||
}
|
||||
}
|
||||
|
||||
// Balance of black and white modules
|
||||
int black = 0;
|
||||
for (int y = 0; y < size; y++) {
|
||||
for (int x = 0; x < size; x++) {
|
||||
if (modules.at(y).at(x))
|
||||
black++;
|
||||
}
|
||||
}
|
||||
int total = size * size;
|
||||
// Find smallest k such that (45-5k)% <= dark/total <= (55+5k)%
|
||||
for (int k = 0; black*20 < (9-k)*total || black*20 > (11+k)*total; k++)
|
||||
result += PENALTY_N4;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::vector<int> qrcodegen::QrCode::getAlignmentPatternPositions(int ver) {
|
||||
if (ver < 1 || ver > 40)
|
||||
throw "Version number out of range";
|
||||
else if (ver == 1)
|
||||
return std::vector<int>();
|
||||
else {
|
||||
int numAlign = ver / 7 + 2;
|
||||
int step;
|
||||
if (ver != 32)
|
||||
step = (ver * 4 + numAlign * 2 + 1) / (2 * numAlign - 2) * 2; // ceil((size - 13) / (2*numAlign - 2)) * 2
|
||||
else // C-C-C-Combo breaker!
|
||||
step = 26;
|
||||
|
||||
std::vector<int> result;
|
||||
int size = ver * 4 + 17;
|
||||
for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step)
|
||||
result.insert(result.begin(), pos);
|
||||
result.insert(result.begin(), 6);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int qrcodegen::QrCode::getNumRawDataModules(int ver) {
|
||||
if (ver < 1 || ver > 40)
|
||||
throw "Version number out of range";
|
||||
int result = (16 * ver + 128) * ver + 64;
|
||||
if (ver >= 2) {
|
||||
int numAlign = ver / 7 + 2;
|
||||
result -= (25 * numAlign - 10) * numAlign - 55;
|
||||
if (ver >= 7)
|
||||
result -= 18 * 2; // Subtract version information
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int qrcodegen::QrCode::getNumDataCodewords(int ver, const Ecc &ecl) {
|
||||
if (ver < 1 || ver > 40)
|
||||
throw "Version number out of range";
|
||||
return getNumRawDataModules(ver) / 8 - NUM_ERROR_CORRECTION_CODEWORDS[ecl.ordinal][ver];
|
||||
}
|
||||
|
||||
|
||||
/*---- Tables of constants ----*/
|
||||
|
||||
const int qrcodegen::QrCode::PENALTY_N1 = 3;
|
||||
const int qrcodegen::QrCode::PENALTY_N2 = 3;
|
||||
const int qrcodegen::QrCode::PENALTY_N3 = 40;
|
||||
const int qrcodegen::QrCode::PENALTY_N4 = 10;
|
||||
|
||||
|
||||
const int16_t qrcodegen::QrCode::NUM_ERROR_CORRECTION_CODEWORDS[4][41] = {
|
||||
// Version: (note that index 0 is for padding, and is set to an illegal value)
|
||||
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
|
||||
{-1, 7, 10, 15, 20, 26, 36, 40, 48, 60, 72, 80, 96, 104, 120, 132, 144, 168, 180, 196, 224, 224, 252, 270, 300, 312, 336, 360, 390, 420, 450, 480, 510, 540, 570, 570, 600, 630, 660, 720, 750}, // Low
|
||||
{-1, 10, 16, 26, 36, 48, 64, 72, 88, 110, 130, 150, 176, 198, 216, 240, 280, 308, 338, 364, 416, 442, 476, 504, 560, 588, 644, 700, 728, 784, 812, 868, 924, 980, 1036, 1064, 1120, 1204, 1260, 1316, 1372}, // Medium
|
||||
{-1, 13, 22, 36, 52, 72, 96, 108, 132, 160, 192, 224, 260, 288, 320, 360, 408, 448, 504, 546, 600, 644, 690, 750, 810, 870, 952, 1020, 1050, 1140, 1200, 1290, 1350, 1440, 1530, 1590, 1680, 1770, 1860, 1950, 2040}, // Quartile
|
||||
{-1, 17, 28, 44, 64, 88, 112, 130, 156, 192, 224, 264, 308, 352, 384, 432, 480, 532, 588, 650, 700, 750, 816, 900, 960, 1050, 1110, 1200, 1260, 1350, 1440, 1530, 1620, 1710, 1800, 1890, 1980, 2100, 2220, 2310, 2430}, // High
|
||||
};
|
||||
|
||||
const int8_t qrcodegen::QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
|
||||
// Version: (note that index 0 is for padding, and is set to an illegal value)
|
||||
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
|
||||
{-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
|
||||
{-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium
|
||||
{-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile
|
||||
{-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High
|
||||
};
|
||||
|
||||
|
||||
qrcodegen::QrCode::ReedSolomonGenerator::ReedSolomonGenerator(int degree) :
|
||||
coefficients() {
|
||||
if (degree < 1 || degree > 255)
|
||||
throw "Degree out of range";
|
||||
|
||||
// Start with the monomial x^0
|
||||
coefficients.resize(degree);
|
||||
coefficients.at(degree - 1) = 1;
|
||||
|
||||
// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
|
||||
// drop the highest term, and store the rest of the coefficients in order of descending powers.
|
||||
// Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
|
||||
int root = 1;
|
||||
for (int i = 0; i < degree; i++) {
|
||||
// Multiply the current product by (x - r^i)
|
||||
for (size_t j = 0; j < coefficients.size(); j++) {
|
||||
coefficients.at(j) = multiply(coefficients.at(j), static_cast<uint8_t>(root));
|
||||
if (j + 1 < coefficients.size())
|
||||
coefficients.at(j) ^= coefficients.at(j + 1);
|
||||
}
|
||||
root = (root << 1) ^ ((root >> 7) * 0x11D); // Multiply by 0x02 mod GF(2^8/0x11D)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<uint8_t> qrcodegen::QrCode::ReedSolomonGenerator::getRemainder(const std::vector<uint8_t> &data) const {
|
||||
// Compute the remainder by performing polynomial division
|
||||
std::vector<uint8_t> result(coefficients.size());
|
||||
for (size_t i = 0; i < data.size(); i++) {
|
||||
uint8_t factor = data.at(i) ^ result.at(0);
|
||||
result.erase(result.begin());
|
||||
result.push_back(0);
|
||||
for (size_t j = 0; j < result.size(); j++)
|
||||
result.at(j) ^= multiply(coefficients.at(j), factor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
uint8_t qrcodegen::QrCode::ReedSolomonGenerator::multiply(uint8_t x, uint8_t y) {
|
||||
// Russian peasant multiplication
|
||||
int z = 0;
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
z = (z << 1) ^ ((z >> 7) * 0x11D);
|
||||
z ^= ((y >> i) & 1) * x;
|
||||
}
|
||||
if (z >> 8 != 0)
|
||||
throw "Assertion error";
|
||||
return static_cast<uint8_t>(z);
|
||||
}
|
||||
@@ -1,342 +0,0 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* QR Code generator library (C++)
|
||||
*
|
||||
* Copyright (c) 2016 Project Nayuki
|
||||
* https://www.nayuki.io/page/qr-code-generator-library
|
||||
*
|
||||
* (MIT License)
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
* - The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* - The Software is provided "as is", without warranty of any kind, express or
|
||||
* implied, including but not limited to the warranties of merchantability,
|
||||
* fitness for a particular purpose and noninfringement. In no event shall the
|
||||
* authors or copyright holders be liable for any claim, damages or other
|
||||
* liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
* out of or in connection with the Software or the use or other dealings in the
|
||||
* Software.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "QrSegment.hpp"
|
||||
|
||||
|
||||
namespace qrcodegen {
|
||||
|
||||
/*
|
||||
* Represents an immutable square grid of black and white cells for a QR Code symbol, and
|
||||
* provides static functions to create a QR Code from user-supplied textual or binary data.
|
||||
* This class covers the QR Code model 2 specification, supporting all versions (sizes)
|
||||
* from 1 to 40, all 4 error correction levels, and only 3 character encoding modes.
|
||||
*/
|
||||
class QrCode final {
|
||||
|
||||
/*---- Public helper enumeration ----*/
|
||||
public:
|
||||
|
||||
/*
|
||||
* Represents the error correction level used in a QR Code symbol.
|
||||
*/
|
||||
class Ecc final {
|
||||
// Constants declared in ascending order of error protection.
|
||||
public:
|
||||
const static Ecc LOW, MEDIUM, QUARTILE, HIGH;
|
||||
|
||||
// Fields.
|
||||
public:
|
||||
const int ordinal; // (Public) In the range 0 to 3 (unsigned 2-bit integer).
|
||||
const int formatBits; // (Package-private) In the range 0 to 3 (unsigned 2-bit integer).
|
||||
|
||||
// Constructor.
|
||||
private:
|
||||
Ecc(int ord, int fb);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*---- Public static factory functions ----*/
|
||||
public:
|
||||
|
||||
/*
|
||||
* Returns a QR Code symbol representing the given Unicode text string at the given error correction level.
|
||||
* As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer Unicode
|
||||
* code points (not UTF-16 code units). The smallest possible QR Code version is automatically chosen for the output.
|
||||
* The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
|
||||
*/
|
||||
static QrCode encodeText(const char *text, const Ecc &ecl);
|
||||
|
||||
|
||||
/*
|
||||
* Returns a QR Code symbol representing the given binary data string at the given error correction level.
|
||||
* This function always encodes using the binary segment mode, not any text mode. The maximum number of
|
||||
* bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
|
||||
* The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
|
||||
*/
|
||||
static QrCode encodeBinary(const std::vector<uint8_t> &data, const Ecc &ecl);
|
||||
|
||||
|
||||
/*
|
||||
* Returns a QR Code symbol representing the specified data segments with the specified encoding parameters.
|
||||
* The smallest possible QR Code version within the specified range is automatically chosen for the output.
|
||||
* This function allows the user to create a custom sequence of segments that switches
|
||||
* between modes (such as alphanumeric and binary) to encode text more efficiently.
|
||||
* This function is considered to be lower level than simply encoding text or binary data.
|
||||
*/
|
||||
static QrCode encodeSegments(const std::vector<QrSegment> &segs, const Ecc &ecl,
|
||||
int minVersion=1, int maxVersion=40, int mask=-1, bool boostEcl=true); // All optional parameters
|
||||
|
||||
|
||||
|
||||
/*---- Instance fields ----*/
|
||||
|
||||
// Public immutable scalar parameters
|
||||
public:
|
||||
|
||||
/* This QR Code symbol's version number, which is always between 1 and 40 (inclusive). */
|
||||
const int version;
|
||||
|
||||
/* The width and height of this QR Code symbol, measured in modules.
|
||||
* Always equal to version × 4 + 17, in the range 21 to 177. */
|
||||
const int size;
|
||||
|
||||
/* The error correction level used in this QR Code symbol. */
|
||||
const Ecc &errorCorrectionLevel;
|
||||
|
||||
/* The mask pattern used in this QR Code symbol, in the range 0 to 7 (i.e. unsigned 3-bit integer).
|
||||
* Note that even if a constructor was called with automatic masking requested
|
||||
* (mask = -1), the resulting object will still have a mask value between 0 and 7. */
|
||||
private:
|
||||
int mask;
|
||||
|
||||
// Private grids of modules/pixels (conceptually immutable)
|
||||
private:
|
||||
std::vector<std::vector<bool>> modules; // The modules of this QR Code symbol (false = white, true = black)
|
||||
std::vector<std::vector<bool>> isFunction; // Indicates function modules that are not subjected to masking
|
||||
|
||||
|
||||
|
||||
/*---- Constructors ----*/
|
||||
public:
|
||||
|
||||
/*
|
||||
* Creates a new QR Code symbol with the given version number, error correction level, binary data array,
|
||||
* and mask number. This is a cumbersome low-level constructor that should not be invoked directly by the user.
|
||||
* To go one level up, see the encodeSegments() function.
|
||||
*/
|
||||
QrCode(int ver, const Ecc &ecl, const std::vector<uint8_t> &dataCodewords, int mask);
|
||||
|
||||
|
||||
/*
|
||||
* Creates a new QR Code symbol based on the given existing object, but with a potentially
|
||||
* different mask pattern. The version, error correction level, codewords, etc. of the newly
|
||||
* created object are all identical to the argument object; only the mask may differ.
|
||||
*/
|
||||
QrCode(const QrCode &qr, int mask);
|
||||
|
||||
|
||||
|
||||
/*---- Public instance methods ----*/
|
||||
public:
|
||||
|
||||
int getMask() const;
|
||||
|
||||
|
||||
/*
|
||||
* Returns the color of the module (pixel) at the given coordinates, which is either 0 for white or 1 for black. The top
|
||||
* left corner has the coordinates (x=0, y=0). If the given coordinates are out of bounds, then 0 (white) is returned.
|
||||
*/
|
||||
int getModule(int x, int y) const;
|
||||
|
||||
|
||||
/*
|
||||
* Based on the given number of border modules to add as padding, this returns a
|
||||
* string whose contents represents an SVG XML file that depicts this QR Code symbol.
|
||||
* Note that Unix newlines (\n) are always used, regardless of the platform.
|
||||
*/
|
||||
std::string toSvgString(int border) const;
|
||||
|
||||
|
||||
|
||||
/*---- Private helper methods for constructor: Drawing function modules ----*/
|
||||
private:
|
||||
|
||||
void drawFunctionPatterns();
|
||||
|
||||
|
||||
// Draws two copies of the format bits (with its own error correction code)
|
||||
// based on the given mask and this object's error correction level field.
|
||||
void drawFormatBits(int mask);
|
||||
|
||||
|
||||
// Draws two copies of the version bits (with its own error correction code),
|
||||
// based on this object's version field (which only has an effect for 7 <= version <= 40).
|
||||
void drawVersion();
|
||||
|
||||
|
||||
// Draws a 9*9 finder pattern including the border separator, with the center module at (x, y).
|
||||
void drawFinderPattern(int x, int y);
|
||||
|
||||
|
||||
// Draws a 5*5 alignment pattern, with the center module at (x, y).
|
||||
void drawAlignmentPattern(int x, int y);
|
||||
|
||||
|
||||
// Sets the color of a module and marks it as a function module.
|
||||
// Only used by the constructor. Coordinates must be in range.
|
||||
void setFunctionModule(int x, int y, bool isBlack);
|
||||
|
||||
|
||||
/*---- Private helper methods for constructor: Codewords and masking ----*/
|
||||
private:
|
||||
|
||||
// Returns a new byte string representing the given data with the appropriate error correction
|
||||
// codewords appended to it, based on this object's version and error correction level.
|
||||
std::vector<uint8_t> appendErrorCorrection(const std::vector<uint8_t> &data) const;
|
||||
|
||||
|
||||
// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
|
||||
// data area of this QR Code symbol. Function modules need to be marked off before this is called.
|
||||
void drawCodewords(const std::vector<uint8_t> &data);
|
||||
|
||||
|
||||
// XORs the data modules in this QR Code with the given mask pattern. Due to XOR's mathematical
|
||||
// properties, calling applyMask(m) twice with the same value is equivalent to no change at all.
|
||||
// This means it is possible to apply a mask, undo it, and try another mask. Note that a final
|
||||
// well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.).
|
||||
void applyMask(int mask);
|
||||
|
||||
|
||||
// A messy helper function for the constructors. This QR Code must be in an unmasked state when this
|
||||
// method is called. The given argument is the requested mask, which is -1 for auto or 0 to 7 for fixed.
|
||||
// This method applies and returns the actual mask chosen, from 0 to 7.
|
||||
int handleConstructorMasking(int mask);
|
||||
|
||||
|
||||
// Calculates and returns the penalty score based on state of this QR Code's current modules.
|
||||
// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
|
||||
int getPenaltyScore() const;
|
||||
|
||||
|
||||
|
||||
/*---- Private static helper functions ----*/
|
||||
private:
|
||||
|
||||
// Returns a set of positions of the alignment patterns in ascending order. These positions are
|
||||
// used on both the x and y axes. Each value in the resulting array is in the range [0, 177).
|
||||
// This stateless pure function could be implemented as table of 40 variable-length lists of unsigned bytes.
|
||||
static std::vector<int> getAlignmentPatternPositions(int ver);
|
||||
|
||||
|
||||
// Returns the number of raw data modules (bits) available at the given version number.
|
||||
// These data modules are used for both user data codewords and error correction codewords.
|
||||
// This stateless pure function could be implemented as a 40-entry lookup table.
|
||||
static int getNumRawDataModules(int ver);
|
||||
|
||||
|
||||
// Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
|
||||
// QR Code of the given version number and error correction level, with remainder bits discarded.
|
||||
// This stateless pure function could be implemented as a (40*4)-cell lookup table.
|
||||
static int getNumDataCodewords(int ver, const Ecc &ecl);
|
||||
|
||||
|
||||
/*---- Private tables of constants ----*/
|
||||
private:
|
||||
|
||||
// For use in getPenaltyScore(), when evaluating which mask is best.
|
||||
static const int PENALTY_N1;
|
||||
static const int PENALTY_N2;
|
||||
static const int PENALTY_N3;
|
||||
static const int PENALTY_N4;
|
||||
|
||||
static const int16_t NUM_ERROR_CORRECTION_CODEWORDS[4][41];
|
||||
static const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
|
||||
|
||||
|
||||
|
||||
/*---- Private helper class ----*/
|
||||
private:
|
||||
|
||||
/*
|
||||
* Computes the Reed-Solomon error correction codewords for a sequence of data codewords
|
||||
* at a given degree. Objects are immutable, and the state only depends on the degree.
|
||||
* This class exists because the divisor polynomial does not need to be recalculated for every input.
|
||||
*/
|
||||
class ReedSolomonGenerator final {
|
||||
|
||||
/*-- Immutable field --*/
|
||||
private:
|
||||
|
||||
// Coefficients of the divisor polynomial, stored from highest to lowest power, excluding the leading term which
|
||||
// is always 1. For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
|
||||
std::vector<uint8_t> coefficients;
|
||||
|
||||
|
||||
/*-- Constructor --*/
|
||||
public:
|
||||
|
||||
/*
|
||||
* Creates a Reed-Solomon ECC generator for the given degree. This could be implemented
|
||||
* as a lookup table over all possible parameter values, instead of as an algorithm.
|
||||
*/
|
||||
ReedSolomonGenerator(int degree);
|
||||
|
||||
|
||||
/*-- Method --*/
|
||||
public:
|
||||
|
||||
/*
|
||||
* Computes and returns the Reed-Solomon error correction codewords for the given sequence of data codewords.
|
||||
* The returned object is always a new byte array. This method does not alter this object's state (because it is immutable).
|
||||
*/
|
||||
std::vector<uint8_t> getRemainder(const std::vector<uint8_t> &data) const;
|
||||
|
||||
|
||||
/*-- Static function --*/
|
||||
private:
|
||||
|
||||
// Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
|
||||
// are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
|
||||
static uint8_t multiply(uint8_t x, uint8_t y);
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* QR Code generator library (C++)
|
||||
*
|
||||
* Copyright (c) 2016 Project Nayuki
|
||||
* https://www.nayuki.io/page/qr-code-generator-library
|
||||
*
|
||||
* (MIT License)
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
* - The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* - The Software is provided "as is", without warranty of any kind, express or
|
||||
* implied, including but not limited to the warranties of merchantability,
|
||||
* fitness for a particular purpose and noninfringement. In no event shall the
|
||||
* authors or copyright holders be liable for any claim, damages or other
|
||||
* liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
* out of or in connection with the Software or the use or other dealings in the
|
||||
* Software.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include "BitBuffer.hpp"
|
||||
#include "QrSegment.hpp"
|
||||
|
||||
|
||||
qrcodegen::QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) :
|
||||
modeBits(mode) {
|
||||
numBitsCharCount[0] = cc0;
|
||||
numBitsCharCount[1] = cc1;
|
||||
numBitsCharCount[2] = cc2;
|
||||
}
|
||||
|
||||
|
||||
int qrcodegen::QrSegment::Mode::numCharCountBits(int ver) const {
|
||||
if ( 1 <= ver && ver <= 9) return numBitsCharCount[0];
|
||||
else if (10 <= ver && ver <= 26) return numBitsCharCount[1];
|
||||
else if (27 <= ver && ver <= 40) return numBitsCharCount[2];
|
||||
else throw "Version number out of range";
|
||||
}
|
||||
|
||||
|
||||
const qrcodegen::QrSegment::Mode qrcodegen::QrSegment::Mode::NUMERIC (0x1, 10, 12, 14);
|
||||
const qrcodegen::QrSegment::Mode qrcodegen::QrSegment::Mode::ALPHANUMERIC(0x2, 9, 11, 13);
|
||||
const qrcodegen::QrSegment::Mode qrcodegen::QrSegment::Mode::BYTE (0x4, 8, 16, 16);
|
||||
const qrcodegen::QrSegment::Mode qrcodegen::QrSegment::Mode::KANJI (0x8, 8, 10, 12);
|
||||
|
||||
|
||||
|
||||
qrcodegen::QrSegment qrcodegen::QrSegment::makeBytes(const std::vector<uint8_t> &data) {
|
||||
return QrSegment(Mode::BYTE, data.size(), data, data.size() * 8);
|
||||
}
|
||||
|
||||
|
||||
qrcodegen::QrSegment qrcodegen::QrSegment::makeNumeric(const char *digits) {
|
||||
BitBuffer bb;
|
||||
int accumData = 0;
|
||||
int accumCount = 0;
|
||||
int charCount = 0;
|
||||
for (; *digits != '\0'; digits++, charCount++) {
|
||||
char c = *digits;
|
||||
if (c < '0' || c > '9')
|
||||
throw "String contains non-numeric characters";
|
||||
accumData = accumData * 10 + (c - '0');
|
||||
accumCount++;
|
||||
if (accumCount == 3) {
|
||||
bb.appendBits(accumData, 10);
|
||||
accumData = 0;
|
||||
accumCount = 0;
|
||||
}
|
||||
}
|
||||
if (accumCount > 0) // 1 or 2 digits remaining
|
||||
bb.appendBits(accumData, accumCount * 3 + 1);
|
||||
return QrSegment(Mode::NUMERIC, charCount, bb.getBytes(), bb.getBitLength());
|
||||
}
|
||||
|
||||
|
||||
qrcodegen::QrSegment qrcodegen::QrSegment::makeAlphanumeric(const char *text) {
|
||||
BitBuffer bb;
|
||||
int accumData = 0;
|
||||
int accumCount = 0;
|
||||
int charCount = 0;
|
||||
for (; *text != '\0'; text++, charCount++) {
|
||||
char c = *text;
|
||||
if (c < ' ' || c > 'Z')
|
||||
throw "String contains unencodable characters in alphanumeric mode";
|
||||
accumData = accumData * 45 + ALPHANUMERIC_ENCODING_TABLE[c - ' '];
|
||||
accumCount++;
|
||||
if (accumCount == 2) {
|
||||
bb.appendBits(accumData, 11);
|
||||
accumData = 0;
|
||||
accumCount = 0;
|
||||
}
|
||||
}
|
||||
if (accumCount > 0) // 1 character remaining
|
||||
bb.appendBits(accumData, 6);
|
||||
return QrSegment(Mode::ALPHANUMERIC, charCount, bb.getBytes(), bb.getBitLength());
|
||||
}
|
||||
|
||||
|
||||
std::vector<qrcodegen::QrSegment> qrcodegen::QrSegment::makeSegments(const char *text) {
|
||||
// Select the most efficient segment encoding automatically
|
||||
std::vector<QrSegment> result;
|
||||
if (*text == '\0'); // Leave the vector empty
|
||||
else if (QrSegment::isNumeric(text))
|
||||
result.push_back(QrSegment::makeNumeric(text));
|
||||
else if (QrSegment::isAlphanumeric(text))
|
||||
result.push_back(QrSegment::makeAlphanumeric(text));
|
||||
else {
|
||||
std::vector<uint8_t> bytes;
|
||||
for (; *text != '\0'; text++)
|
||||
bytes.push_back(static_cast<uint8_t>(*text));
|
||||
result.push_back(QrSegment::makeBytes(bytes));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
qrcodegen::QrSegment::QrSegment(const Mode &md, int numCh, const std::vector<uint8_t> &b, int bitLen) :
|
||||
mode(md),
|
||||
numChars(numCh),
|
||||
data(b),
|
||||
bitLength(bitLen) {
|
||||
if (numCh < 0 || bitLen < 0 || b.size() != static_cast<unsigned int>((bitLen + 7) / 8))
|
||||
throw "Invalid value";
|
||||
}
|
||||
|
||||
|
||||
int qrcodegen::QrSegment::getTotalBits(const std::vector<QrSegment> &segs, int version) {
|
||||
if (version < 1 || version > 40)
|
||||
throw "Version number out of range";
|
||||
int result = 0;
|
||||
for (size_t i = 0; i < segs.size(); i++) {
|
||||
const QrSegment &seg(segs.at(i));
|
||||
int ccbits = seg.mode.numCharCountBits(version);
|
||||
// Fail if segment length value doesn't fit in the length field's bit-width
|
||||
if (seg.numChars >= (1 << ccbits))
|
||||
return -1;
|
||||
result += 4 + ccbits + seg.bitLength;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool qrcodegen::QrSegment::isAlphanumeric(const char *text) {
|
||||
for (; *text != '\0'; text++) {
|
||||
char c = *text;
|
||||
if (c < ' ' || c > 'Z' || ALPHANUMERIC_ENCODING_TABLE[c - ' '] == -1)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool qrcodegen::QrSegment::isNumeric(const char *text) {
|
||||
for (; *text != '\0'; text++) {
|
||||
char c = *text;
|
||||
if (c < '0' || c > '9')
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const int8_t qrcodegen::QrSegment::ALPHANUMERIC_ENCODING_TABLE[59] = {
|
||||
// SP, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, @, // ASCII codes 32 to 64
|
||||
36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, -1, // Array indices 0 to 32
|
||||
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, // Array indices 33 to 58
|
||||
// A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, // ASCII codes 65 to 90
|
||||
};
|
||||
@@ -1,198 +0,0 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* QR Code generator library (C++)
|
||||
*
|
||||
* Copyright (c) 2016 Project Nayuki
|
||||
* https://www.nayuki.io/page/qr-code-generator-library
|
||||
*
|
||||
* (MIT License)
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
* - The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* - The Software is provided "as is", without warranty of any kind, express or
|
||||
* implied, including but not limited to the warranties of merchantability,
|
||||
* fitness for a particular purpose and noninfringement. In no event shall the
|
||||
* authors or copyright holders be liable for any claim, damages or other
|
||||
* liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
* out of or in connection with the Software or the use or other dealings in the
|
||||
* Software.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace qrcodegen {
|
||||
|
||||
/*
|
||||
* Represents a character string to be encoded in a QR Code symbol. Each segment has
|
||||
* a mode, and a sequence of characters that is already encoded as a sequence of bits.
|
||||
* Instances of this class are immutable.
|
||||
* This segment class imposes no length restrictions, but QR Codes have restrictions.
|
||||
* Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
|
||||
* Any segment longer than this is meaningless for the purpose of generating QR Codes.
|
||||
*/
|
||||
class QrSegment final {
|
||||
|
||||
/*---- Public helper enumeration ----*/
|
||||
|
||||
/*
|
||||
* The mode field of a segment. Immutable. Provides methods to retrieve closely related values.
|
||||
*/
|
||||
public:
|
||||
class Mode final {
|
||||
|
||||
/*-- Constants --*/
|
||||
public:
|
||||
|
||||
static const Mode NUMERIC;
|
||||
static const Mode ALPHANUMERIC;
|
||||
static const Mode BYTE;
|
||||
static const Mode KANJI;
|
||||
|
||||
|
||||
/*-- Fields --*/
|
||||
|
||||
/* (Package-private) An unsigned 4-bit integer value (range 0 to 15) representing the mode indicator bits for this mode object. */
|
||||
public:
|
||||
const int modeBits;
|
||||
|
||||
private:
|
||||
int numBitsCharCount[3];
|
||||
|
||||
|
||||
/*-- Constructor --*/
|
||||
|
||||
private:
|
||||
Mode(int mode, int cc0, int cc1, int cc2);
|
||||
|
||||
|
||||
/*-- Method --*/
|
||||
|
||||
/*
|
||||
* (Package-private) Returns the bit width of the segment character count field for this mode object at the given version number.
|
||||
*/
|
||||
public:
|
||||
int numCharCountBits(int ver) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*---- Public static factory functions ----*/
|
||||
public:
|
||||
|
||||
/*
|
||||
* Returns a segment representing the given binary data encoded in byte mode.
|
||||
*/
|
||||
static QrSegment makeBytes(const std::vector<uint8_t> &data);
|
||||
|
||||
|
||||
/*
|
||||
* Returns a segment representing the given string of decimal digits encoded in numeric mode.
|
||||
*/
|
||||
static QrSegment makeNumeric(const char *digits);
|
||||
|
||||
|
||||
/*
|
||||
* Returns a segment representing the given text string encoded in alphanumeric mode. The characters allowed are:
|
||||
* 0 to 9, A to Z (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
|
||||
*/
|
||||
static QrSegment makeAlphanumeric(const char *text);
|
||||
|
||||
|
||||
/*
|
||||
* Returns a list of zero or more segments to represent the given text string.
|
||||
* The result may use various segment modes and switch modes to optimize the length of the bit stream.
|
||||
*/
|
||||
static std::vector<QrSegment> makeSegments(const char *text);
|
||||
|
||||
|
||||
/*---- Public static helper functions ----*/
|
||||
public:
|
||||
|
||||
/*
|
||||
* Tests whether the given string can be encoded as a segment in alphanumeric mode.
|
||||
*/
|
||||
static bool isAlphanumeric(const char *text);
|
||||
|
||||
|
||||
/*
|
||||
* Tests whether the given string can be encoded as a segment in numeric mode.
|
||||
*/
|
||||
static bool isNumeric(const char *text);
|
||||
|
||||
|
||||
|
||||
/*---- Instance fields ----*/
|
||||
public:
|
||||
|
||||
/* The mode indicator for this segment. */
|
||||
const Mode mode;
|
||||
|
||||
/* The length of this segment's unencoded data, measured in characters. Always zero or positive. */
|
||||
const int numChars;
|
||||
|
||||
/* The bits of this segment packed into a byte array in big endian. */
|
||||
const std::vector<uint8_t> data;
|
||||
|
||||
/* The length of this segment's encoded data, measured in bits. Satisfies ceil(bitLength / 8) = data.size(). */
|
||||
const int bitLength;
|
||||
|
||||
|
||||
/*---- Constructor ----*/
|
||||
public:
|
||||
|
||||
/*
|
||||
* Creates a new QR Code data segment with the given parameters and data.
|
||||
*/
|
||||
QrSegment(const Mode &md, int numCh, const std::vector<uint8_t> &b, int bitLen);
|
||||
|
||||
|
||||
// Package-private helper function.
|
||||
static int getTotalBits(const std::vector<QrSegment> &segs, int version);
|
||||
|
||||
|
||||
/*---- Private constant ----*/
|
||||
private:
|
||||
|
||||
/* Maps shifted ASCII codes to alphanumeric mode character codes. */
|
||||
static const int8_t ALPHANUMERIC_ENCODING_TABLE[59];
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
QR Code generator library
|
||||
=========================
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This project aims to provide the best and clearest QR Code generator library. The primary goals are flexible options and absolute correctness. The secondary goals are compact implementation size and good documentation comments.
|
||||
|
||||
Home page with live JavaScript demo and extensive description: [https://www.nayuki.io/page/qr-code-generator-library](https://www.nayuki.io/page/qr-code-generator-library)
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
Core features:
|
||||
|
||||
* Available in 4 programming languages, all with nearly equal functionality: Java, JavaScript, Python, C++
|
||||
* Significantly shorter code but more documentation comments compared to competing libraries
|
||||
* Supports encoding all 40 versions (sizes) and all 4 error correction levels, as per the QR Code Model 2 standard
|
||||
* Output formats: Raw modules/pixels of the QR symbol (all languages), SVG XML string (all languages), BufferedImage raster bitmap (Java only)
|
||||
* Encodes numeric and special-alphanumeric text in less space than general text
|
||||
* Open source code under the permissive MIT License
|
||||
|
||||
Manual parameters:
|
||||
|
||||
* User can specify minimum and maximum version numbers allowed, then library will automatically choose smallest version in the range that fits the data
|
||||
* User can specify mask pattern manually, otherwise library will automatically evaluate all 8 masks and select the optimal one
|
||||
* User can specify absolute error correction level, or allow the library to boost it if it doesn't increase the version number
|
||||
|
||||
Optional advanced features (Java only):
|
||||
|
||||
* Encodes Japanese Unicode text in kanji mode to save a lot of space compared to UTF-8 bytes
|
||||
* Computes optimal segment mode switching for text with mixed numeric/alphanumeric/general parts
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Java language:
|
||||
|
||||
import io.nayuki.qrcodegen.*;
|
||||
|
||||
// Simple operation
|
||||
QrCode qr0 = QrCode.encodeText("Hello, world!", QrCode.Ecc.MEDIUM);
|
||||
BufferedImage img = qr0.toImage(4, 10);
|
||||
ImageIO.write(img, "png", new File("qr-code.png"));
|
||||
|
||||
// Manual operation
|
||||
List<QrSegment> segs = QrSegment.makeSegments("3141592653589793238462643383");
|
||||
QrCode qr1 = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, 5, 5, 2, false);
|
||||
|
||||
JavaScript language:
|
||||
|
||||
// Name abbreviated for the sake of these examples here
|
||||
var QRC = qrcodegen.QrCode;
|
||||
|
||||
// Simple operation
|
||||
var qr0 = QRC.encodeText("Hello, world!", QRC.Ecc.MEDIUM);
|
||||
var svg = qr0.toSvgString(4);
|
||||
|
||||
// Manual operation
|
||||
var segs = qrcodegen.QrSegment.makeSegments("3141592653589793238462643383");
|
||||
var qr1 = QRC.encodeSegments(segs, QRC.Ecc.HIGH, 5, 5, 2, false);
|
||||
|
||||
Python language:
|
||||
|
||||
from qrcodegen import *
|
||||
|
||||
# Simple operation
|
||||
qr0 = QrCode.encode_text("Hello, world!", QrCode.Ecc.MEDIUM)
|
||||
svg = qr0.to_svg_str(4)
|
||||
|
||||
# Manual operation
|
||||
segs = QrSegment.make_segments("3141592653589793238462643383")
|
||||
qr1 = QrCode.encode_segments(segs, QrCode.Ecc.HIGH, 5, 5, 2, False)
|
||||
|
||||
C++ language:
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "QrCode.hpp"
|
||||
using namespace qrcodegen;
|
||||
|
||||
// Simple operation
|
||||
QrCode qr0 = QrCode::encodeText("Hello, world!", QrCode::Ecc::MEDIUM);
|
||||
std::string svg = qr0.toSvgString(4);
|
||||
|
||||
// Manual operation
|
||||
std::vector<QrSegment> segs =
|
||||
QrSegment::makeSegments("3141592653589793238462643383");
|
||||
QrCode qr1 = QrCode::encodeSegments(segs, QrCode::Ecc::HIGH, 5, 5, 2, false);
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Copyright © 2016 Project Nayuki
|
||||
[https://www.nayuki.io/page/qr-code-generator-library](https://www.nayuki.io/page/qr-code-generator-library)
|
||||
|
||||
(MIT License)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
* The Software is provided "as is", without warranty of any kind, express or
|
||||
implied, including but not limited to the warranties of merchantability,
|
||||
fitness for a particular purpose and noninfringement. In no event shall the
|
||||
authors or copyright holders be liable for any claim, damages or other
|
||||
liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
out of or in connection with the Software or the use or other dealings in the
|
||||
Software.
|
||||
@@ -40,7 +40,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, SLOT(processCode(int,QString)));
|
||||
QObject::connect(m_thread, SIGNAL(decoded(int, QString)), this, SIGNAL(decoded(int, 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)));
|
||||
}
|
||||
@@ -48,37 +48,6 @@ void QrCodeScanner::setSource(QCamera *camera)
|
||||
{
|
||||
m_probe->setSource(camera);
|
||||
}
|
||||
void QrCodeScanner::processCode(int type, const QString &data)
|
||||
{
|
||||
if (! m_enabled) return;
|
||||
qDebug() << "decoded - type: " << type << " data: " << data;
|
||||
QString address, payment_id, tx_description, recipient_name, error;
|
||||
QVector<QString> unknown_parameters;
|
||||
uint64_t amount(0);
|
||||
if( ! WalletManager::instance()->parse_uri(data, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error) )
|
||||
{
|
||||
qDebug() << "Failed to parse_uri : " << error;
|
||||
emit notifyError(error);
|
||||
return;
|
||||
}
|
||||
QVariantMap parsed_unknown_parameters;
|
||||
if(unknown_parameters.size() > 0)
|
||||
{
|
||||
qDebug() << "unknown parameters " << unknown_parameters;
|
||||
foreach(const QString &item, unknown_parameters )
|
||||
{
|
||||
QStringList parsed_item = item.split("=");
|
||||
if(parsed_item.size() == 2) {
|
||||
parsed_unknown_parameters.insert(parsed_item[0], parsed_item[1]);
|
||||
}
|
||||
}
|
||||
emit notifyError(error, true);
|
||||
}
|
||||
qDebug() << "Parsed URI : " << address << " " << payment_id << " " << amount << " " << tx_description << " " << recipient_name << " " << error;
|
||||
QString s_amount = WalletManager::instance()->displayAmount(amount);
|
||||
qDebug() << "Amount passed " << s_amount ;
|
||||
emit decoded(address, payment_id, s_amount, tx_description, recipient_name, parsed_unknown_parameters);
|
||||
}
|
||||
void QrCodeScanner::processFrame(QVideoFrame frame)
|
||||
{
|
||||
if(frame.isValid()){
|
||||
|
||||
@@ -51,13 +51,12 @@ public:
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
public Q_SLOTS:
|
||||
void processCode(int type, const QString &data);
|
||||
void processFrame(QVideoFrame);
|
||||
|
||||
Q_SIGNALS:
|
||||
void enabledChanged();
|
||||
|
||||
void decoded(const QString &address, const QString &payment_id, const QString &amount, const QString &tx_description, const QString &recipient_name, const QVariantMap &extra_parameters);
|
||||
void decoded(int type, const QString &data);
|
||||
void decode(int type, const QString &data);
|
||||
void notifyError(const QString &error, bool warning = false);
|
||||
|
||||
|
||||
@@ -30,13 +30,8 @@
|
||||
#include <QtGlobal>
|
||||
#include <QDebug>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||
extern QImage qt_imageFromVideoFrame(const QVideoFrame &f);
|
||||
#else
|
||||
QImage qt_imageFromVideoFrame(const QVideoFrame &f){
|
||||
Q_ASSERT_X(0 != 0, "qt_imageFromVideoFrame", "Should have been managed in .pro");
|
||||
return QImage();
|
||||
}
|
||||
#endif
|
||||
|
||||
QrScanThread::QrScanThread(QObject *parent)
|
||||
@@ -80,7 +75,11 @@ bool QrScanThread::zimageFromQImage(const QImage &qimg, zbar::Image &dst)
|
||||
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 !"));
|
||||
@@ -104,7 +103,11 @@ void QrScanThread::processQImage(const QImage &qimg)
|
||||
|
||||
void QrScanThread::processVideoFrame(const QVideoFrame &frame)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||
processQImage( qt_imageFromVideoFrame(frame) );
|
||||
#else
|
||||
processQImage(frame.image());
|
||||
#endif
|
||||
}
|
||||
|
||||
void QrScanThread::stop()
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "DaemonManager.h"
|
||||
#include <QElapsedTimer>
|
||||
#include <QFile>
|
||||
#include <QMutexLocker>
|
||||
#include <QThread>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
@@ -113,8 +114,8 @@ bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const
|
||||
|
||||
arguments << "--check-updates" << "disabled";
|
||||
|
||||
// --max-concurrency based on threads available. max: 6
|
||||
int32_t concurrency = qBound(1, QThread::idealThreadCount() / 2, 6);
|
||||
// --max-concurrency based on threads available.
|
||||
int32_t concurrency = qMax(1, QThread::idealThreadCount() / 2);
|
||||
|
||||
if(!flags.contains("--max-concurrency", Qt::CaseSensitive)){
|
||||
arguments << "--max-concurrency" << QString::number(concurrency);
|
||||
@@ -123,18 +124,19 @@ bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const
|
||||
qDebug() << "starting monerod " + m_monerod;
|
||||
qDebug() << "With command line arguments " << arguments;
|
||||
|
||||
m_daemon = new QProcess();
|
||||
initialized = true;
|
||||
QMutexLocker locker(&m_daemonMutex);
|
||||
|
||||
m_daemon.reset(new QProcess());
|
||||
|
||||
// Connect output slots
|
||||
connect (m_daemon, SIGNAL(readyReadStandardOutput()), this, SLOT(printOutput()));
|
||||
connect (m_daemon, SIGNAL(readyReadStandardError()), this, SLOT(printError()));
|
||||
connect(m_daemon.get(), SIGNAL(readyReadStandardOutput()), this, SLOT(printOutput()));
|
||||
connect(m_daemon.get(), SIGNAL(readyReadStandardError()), this, SLOT(printError()));
|
||||
|
||||
// Start monerod
|
||||
bool started = m_daemon->startDetached(m_monerod, arguments);
|
||||
|
||||
// add state changed listener
|
||||
connect(m_daemon,SIGNAL(stateChanged(QProcess::ProcessState)),this,SLOT(stateChanged(QProcess::ProcessState)));
|
||||
connect(m_daemon.get(), SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(stateChanged(QProcess::ProcessState)));
|
||||
|
||||
if (!started) {
|
||||
qDebug() << "Daemon start error: " + m_daemon->errorString();
|
||||
@@ -200,9 +202,9 @@ bool DaemonManager::stopWatcher(NetworkType::Type nettype) const
|
||||
if(counter >= 5) {
|
||||
qDebug() << "Killing it! ";
|
||||
#ifdef Q_OS_WIN
|
||||
QProcess::execute("taskkill /F /IM monerod.exe");
|
||||
QProcess::execute("taskkill", {"/F", "/IM", "monerod.exe"});
|
||||
#else
|
||||
QProcess::execute("pkill monerod");
|
||||
QProcess::execute("pkill", {"monerod"});
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -223,7 +225,10 @@ void DaemonManager::stateChanged(QProcess::ProcessState state)
|
||||
|
||||
void DaemonManager::printOutput()
|
||||
{
|
||||
QByteArray byteArray = m_daemon->readAllStandardOutput();
|
||||
QByteArray byteArray = [this]() {
|
||||
QMutexLocker locker(&m_daemonMutex);
|
||||
return m_daemon->readAllStandardOutput();
|
||||
}();
|
||||
QStringList strLines = QString(byteArray).split("\n");
|
||||
|
||||
foreach (QString line, strLines) {
|
||||
@@ -234,7 +239,10 @@ void DaemonManager::printOutput()
|
||||
|
||||
void DaemonManager::printError()
|
||||
{
|
||||
QByteArray byteArray = m_daemon->readAllStandardError();
|
||||
QByteArray byteArray = [this]() {
|
||||
QMutexLocker locker(&m_daemonMutex);
|
||||
return m_daemon->readAllStandardError();
|
||||
}();
|
||||
QStringList strLines = QString(byteArray).split("\n");
|
||||
|
||||
foreach (QString line, strLines) {
|
||||
@@ -351,7 +359,6 @@ DaemonManager::DaemonManager(QObject *parent)
|
||||
|
||||
if (m_monerod.length() == 0) {
|
||||
qCritical() << "no daemon binary defined for current platform";
|
||||
m_has_daemon = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
#ifndef DAEMONMANAGER_H
|
||||
#define DAEMONMANAGER_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
#include <QProcess>
|
||||
@@ -78,10 +81,9 @@ private:
|
||||
|
||||
static DaemonManager * m_instance;
|
||||
static QStringList m_clArgs;
|
||||
QProcess *m_daemon;
|
||||
bool initialized = false;
|
||||
std::unique_ptr<QProcess> m_daemon;
|
||||
QMutex m_daemonMutex;
|
||||
QString m_monerod;
|
||||
bool m_has_daemon = true;
|
||||
bool m_app_exit = false;
|
||||
bool m_noSync = false;
|
||||
|
||||
|
||||
70
src/libwalletqt/PassphraseHelper.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) 2014-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 "PassphraseHelper.h"
|
||||
#include <QMutexLocker>
|
||||
#include <QDebug>
|
||||
|
||||
Monero::optional<std::string> PassphraseHelper::onDevicePassphraseRequest(bool & on_device)
|
||||
{
|
||||
qDebug() << __FUNCTION__;
|
||||
QMutexLocker locker(&m_mutex_pass);
|
||||
m_passphrase_on_device = true;
|
||||
m_passphrase_abort = false;
|
||||
|
||||
if (m_prompter != nullptr){
|
||||
m_prompter->onWalletPassphraseNeeded(on_device);
|
||||
}
|
||||
|
||||
m_cond_pass.wait(&m_mutex_pass);
|
||||
|
||||
if (m_passphrase_abort)
|
||||
{
|
||||
throw std::runtime_error("Passphrase entry abort");
|
||||
}
|
||||
|
||||
on_device = m_passphrase_on_device;
|
||||
if (!on_device) {
|
||||
auto tmpPass = m_passphrase.toStdString();
|
||||
m_passphrase = QString();
|
||||
return Monero::optional<std::string>(tmpPass);
|
||||
} else {
|
||||
return Monero::optional<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
void PassphraseHelper::onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort)
|
||||
{
|
||||
qDebug() << __FUNCTION__;
|
||||
QMutexLocker locker(&m_mutex_pass);
|
||||
m_passphrase = passphrase;
|
||||
m_passphrase_abort = entry_abort;
|
||||
m_passphrase_on_device = enter_on_device;
|
||||
|
||||
m_cond_pass.wakeAll();
|
||||
}
|
||||
74
src/libwalletqt/PassphraseHelper.h
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2014-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.
|
||||
|
||||
#ifndef MONERO_GUI_PASSPHRASEHELPER_H
|
||||
#define MONERO_GUI_PASSPHRASEHELPER_H
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <wallet/api/wallet2_api.h>
|
||||
#include <QMutex>
|
||||
#include <QPointer>
|
||||
#include <QWaitCondition>
|
||||
#include <QMutex>
|
||||
|
||||
/**
|
||||
* Implements component responsible for showing entry prompt to the user,
|
||||
* typically Wallet / Wallet manager.
|
||||
*/
|
||||
class PassprasePrompter {
|
||||
public:
|
||||
virtual void onWalletPassphraseNeeded(bool onDevice) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements receiver of the passphrase responsible for passing it back to the wallet,
|
||||
* typically wallet listener.
|
||||
*/
|
||||
class PassphraseReceiver {
|
||||
public:
|
||||
virtual void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) = 0;
|
||||
};
|
||||
|
||||
class PassphraseHelper {
|
||||
public:
|
||||
PassphraseHelper(PassprasePrompter * prompter=nullptr): m_prompter(prompter) {};
|
||||
PassphraseHelper(const PassphraseHelper & h): PassphraseHelper(h.m_prompter) {};
|
||||
Monero::optional<std::string> onDevicePassphraseRequest(bool & on_device);
|
||||
void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort);
|
||||
|
||||
private:
|
||||
PassprasePrompter * m_prompter;
|
||||
QWaitCondition m_cond_pass;
|
||||
QMutex m_mutex_pass;
|
||||
QString m_passphrase;
|
||||
bool m_passphrase_abort;
|
||||
bool m_passphrase_on_device;
|
||||
|
||||
};
|
||||
|
||||
#endif //MONERO_GUI_PASSPHRASEHELPER_H
|
||||
@@ -38,7 +38,7 @@ QImage QRCodeImageProvider::genQrImage(const QString &id, QSize *size)
|
||||
unsigned int black = 0;
|
||||
unsigned int white = 1;
|
||||
unsigned int borderSize = 4;
|
||||
unsigned int imageSize = qrcode.size + (2 * borderSize);
|
||||
unsigned int imageSize = qrcode.getSize() + (2 * borderSize);
|
||||
QImage img = QImage(imageSize, imageSize, QImage::Format_Mono);
|
||||
|
||||
for (unsigned int y = 0; y < imageSize; ++y)
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <QDebug>
|
||||
#include <QReadLocker>
|
||||
#include <QWriteLocker>
|
||||
#include <QtGlobal>
|
||||
|
||||
|
||||
bool TransactionHistory::transaction(int index, std::function<void (TransactionInfo &)> callback)
|
||||
@@ -58,7 +59,11 @@ bool TransactionHistory::transaction(int index, std::function<void (TransactionI
|
||||
|
||||
void TransactionHistory::refresh(quint32 accountIndex)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
QDateTime firstDateTime = QDate(2014, 4, 18).startOfDay();
|
||||
#else
|
||||
QDateTime firstDateTime = QDateTime(QDate(2014, 4, 18)); // the genesis block
|
||||
#endif
|
||||
QDateTime lastDateTime = QDateTime::currentDateTime().addDays(1); // tomorrow (guard against jitter and timezones)
|
||||
|
||||
emit refreshStarted();
|
||||
@@ -143,7 +148,11 @@ bool TransactionHistory::TransactionHistory::locked() const
|
||||
TransactionHistory::TransactionHistory(Monero::TransactionHistory *pimpl, QObject *parent)
|
||||
: QObject(parent), m_pimpl(pimpl), m_minutesToUnlock(0), m_locked(false)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
m_firstDateTime = QDate(2014, 4, 18).startOfDay();
|
||||
#else
|
||||
m_firstDateTime = QDateTime(QDate(2014, 4, 18)); // the genesis block
|
||||
#endif
|
||||
m_lastDateTime = QDateTime::currentDateTime().addDays(1); // tomorrow (guard against jitter and timezones)
|
||||
}
|
||||
|
||||
|
||||
@@ -61,14 +61,14 @@ quint64 TransactionInfo::atomicAmount() const
|
||||
|
||||
QString TransactionInfo::displayAmount() const
|
||||
{
|
||||
return WalletManager::instance()->displayAmount(m_amount);
|
||||
return WalletManager::displayAmount(m_amount);
|
||||
}
|
||||
|
||||
QString TransactionInfo::fee() const
|
||||
{
|
||||
if(m_fee == 0)
|
||||
return "";
|
||||
return WalletManager::instance()->displayAmount(m_fee);
|
||||
return WalletManager::displayAmount(m_fee);
|
||||
}
|
||||
|
||||
quint64 TransactionInfo::blockHeight() const
|
||||
@@ -132,7 +132,7 @@ QString TransactionInfo::destinations_formatted() const
|
||||
for (auto const& t: m_transfers) {
|
||||
if (!destinations.isEmpty())
|
||||
destinations += "<br> ";
|
||||
destinations += WalletManager::instance()->displayAmount(t->amount()) + ": " + t->address();
|
||||
destinations += WalletManager::displayAmount(t->amount()) + ": " + t->address();
|
||||
}
|
||||
return destinations;
|
||||
}
|
||||
|
||||