mirror of
https://github.com/monero-project/monero-gui.git
synced 2026-04-02 01:17:26 -04:00
Compare commits
221 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
816eeb4647 | ||
|
|
d5b4f43f48 | ||
|
|
4597b4d94d | ||
|
|
691fdac7a4 | ||
|
|
c789efbe8a | ||
|
|
ddec66b2ad | ||
|
|
325e99d202 | ||
|
|
76b0b6013a | ||
|
|
183585653f | ||
|
|
6bc9627046 | ||
|
|
ba7eeb12c5 | ||
|
|
2354c615d1 | ||
|
|
3aa530aa84 | ||
|
|
6b0cb8dadb | ||
|
|
ecc8b8cc99 | ||
|
|
74e1483d0b | ||
|
|
b3dace6b45 | ||
|
|
a17b88d80a | ||
|
|
1ee06fb78c | ||
|
|
ac2e9d370b | ||
|
|
a0a9d9e31e | ||
|
|
1e4c0d2e0d | ||
|
|
7c881d0100 | ||
|
|
d83f14799e | ||
|
|
34df4e74d4 | ||
|
|
9593a16cb0 | ||
|
|
3e8bc1dcd3 | ||
|
|
8dd06bba5c | ||
|
|
244d622818 | ||
|
|
34d3f6575a | ||
|
|
e94ac7c75d | ||
|
|
ad19dbb440 | ||
|
|
c18614f96f | ||
|
|
16fdedc4d0 | ||
|
|
057de959b9 | ||
|
|
88d26dbecf | ||
|
|
059af2bb49 | ||
|
|
4403387fa4 | ||
|
|
92a2ae1a11 | ||
|
|
40adc6bbbf | ||
|
|
c073867657 | ||
|
|
a7f5b44488 | ||
|
|
8b8948954d | ||
|
|
2c763f5014 | ||
|
|
5d566d1c02 | ||
|
|
41520b3a71 | ||
|
|
5039de8327 | ||
|
|
2bb1092472 | ||
|
|
16fd2b4447 | ||
|
|
3c27c570d4 | ||
|
|
e25e44b45f | ||
|
|
b20b956e15 | ||
|
|
4f10683c2c | ||
|
|
f40b10ea0b | ||
|
|
38f21a3e89 | ||
|
|
1f0f21a8e5 | ||
|
|
c948c9dd7c | ||
|
|
04d5fa51cf | ||
|
|
c1573c2c2a | ||
|
|
42fba21c6b | ||
|
|
04e3ac9200 | ||
|
|
f9f319d571 | ||
|
|
090dca7848 | ||
|
|
9cf7c7f03c | ||
|
|
d3d26e37d0 | ||
|
|
b79f1b8ff4 | ||
|
|
2a44f95f16 | ||
|
|
dc0ce27963 | ||
|
|
378da8093d | ||
|
|
5261f79e9f | ||
|
|
1659c7fd1a | ||
|
|
ec7bc577d6 | ||
|
|
3f4de99be4 | ||
|
|
1a11f2b192 | ||
|
|
e21d7be725 | ||
|
|
4098352faf | ||
|
|
a25b164cd5 | ||
|
|
45b5150487 | ||
|
|
bd21914b9b | ||
|
|
5848aee1c3 | ||
|
|
a214003559 | ||
|
|
83bb7a9297 | ||
|
|
d3102b1cc5 | ||
|
|
93b22311e3 | ||
|
|
55baa8b695 | ||
|
|
18f16d9ebd | ||
|
|
e9b894da16 | ||
|
|
f3a24d92a4 | ||
|
|
07a9b0e6f7 | ||
|
|
3ca5f10fa8 | ||
|
|
f7b817972f | ||
|
|
9399839d96 | ||
|
|
51a4d1f629 | ||
|
|
bbe3716542 | ||
|
|
7c32fe6b5c | ||
|
|
72ab846be5 | ||
|
|
8e6a2cde0f | ||
|
|
c34d4ee97c | ||
|
|
0194cf8f22 | ||
|
|
ad06fcc79e | ||
|
|
7d4b82c691 | ||
|
|
69f989d617 | ||
|
|
0f3df860e3 | ||
|
|
5662841d22 | ||
|
|
3f0bbfb6aa | ||
|
|
ba4d6993b7 | ||
|
|
8d4cda030e | ||
|
|
772b828b67 | ||
|
|
78f5360af2 | ||
|
|
a1fdffcabe | ||
|
|
fed00a5662 | ||
|
|
79f2843b09 | ||
|
|
14a477748e | ||
|
|
cebb78979c | ||
|
|
df771470c2 | ||
|
|
e359c60f00 | ||
|
|
53335a8487 | ||
|
|
3f64312283 | ||
|
|
897946af13 | ||
|
|
e90626e05a | ||
|
|
90e9968dcb | ||
|
|
841d0e01dc | ||
|
|
2feee9e956 | ||
|
|
486ba05526 | ||
|
|
ae8394e5f8 | ||
|
|
fa79e609e1 | ||
|
|
cc352e4913 | ||
|
|
903539bd30 | ||
|
|
af0b3142a0 | ||
|
|
6fe41e6f55 | ||
|
|
2a6ad67f77 | ||
|
|
5652284572 | ||
|
|
2eeeadfd10 | ||
|
|
0d5d2dbf5e | ||
|
|
606dbed4a0 | ||
|
|
301b20d19c | ||
|
|
f6196d48ab | ||
|
|
110b09efba | ||
|
|
0fdf81bc92 | ||
|
|
ea1fee2f5f | ||
|
|
ef54a32de0 | ||
|
|
96f9c11320 | ||
|
|
4a5b191f7f | ||
|
|
148d487988 | ||
|
|
7b137f7682 | ||
|
|
2e81ea2c09 | ||
|
|
5150945414 | ||
|
|
ec8cd137cc | ||
|
|
d5365298d2 | ||
|
|
30bf63b4b8 | ||
|
|
e8ee55a502 | ||
|
|
212fa083e2 | ||
|
|
3daf16e65d | ||
|
|
abfaac9772 | ||
|
|
28e6558a48 | ||
|
|
2d20bfd7ac | ||
|
|
45bfcfd2e9 | ||
|
|
46cea8db6b | ||
|
|
b4c0cb65de | ||
|
|
56e611480a | ||
|
|
ff201af778 | ||
|
|
ef2be82c21 | ||
|
|
6fce5c7a84 | ||
|
|
157166269b | ||
|
|
caa273afea | ||
|
|
d58ce3f599 | ||
|
|
19a6f399f3 | ||
|
|
18c964afca | ||
|
|
158e0c3523 | ||
|
|
770a7a344b | ||
|
|
f3ddf525a4 | ||
|
|
cedfa5aabb | ||
|
|
df2b85e7ee | ||
|
|
e86fa3e4fb | ||
|
|
5702bdef39 | ||
|
|
c7213abb9a | ||
|
|
5ee363f9f3 | ||
|
|
3e01647744 | ||
|
|
f491b41100 | ||
|
|
a564abbe6b | ||
|
|
149732af3a | ||
|
|
2bb6da5f09 | ||
|
|
11370c50eb | ||
|
|
0ae4677a25 | ||
|
|
1c2879bda3 | ||
|
|
0997b38e1e | ||
|
|
be177d6205 | ||
|
|
919b2e4f3a | ||
|
|
8b9580d621 | ||
|
|
6f5bacabfd | ||
|
|
6fab741f2e | ||
|
|
c2977ac410 | ||
|
|
1adf58793f | ||
|
|
9fa597bb58 | ||
|
|
d79f8e8b17 | ||
|
|
a817bfba05 | ||
|
|
04429e85e6 | ||
|
|
e52d86d442 | ||
|
|
7f164e739a | ||
|
|
43214de7d0 | ||
|
|
0cf683a6cf | ||
|
|
c9fd9634ee | ||
|
|
ddcee95b88 | ||
|
|
299067a273 | ||
|
|
08635e3030 | ||
|
|
fdff5f68dd | ||
|
|
9b18344d23 | ||
|
|
153154f484 | ||
|
|
ee0137056d | ||
|
|
1b0f274aed | ||
|
|
cd054f6c26 | ||
|
|
d6cb9b6c85 | ||
|
|
852378accb | ||
|
|
fe73011422 | ||
|
|
9d2f083a97 | ||
|
|
cd3a0f85a6 | ||
|
|
1373e709d6 | ||
|
|
baa0ffa5f9 | ||
|
|
25ca081109 | ||
|
|
9da52f2387 | ||
|
|
56722e4747 |
96
.github/workflows/build.yml
vendored
96
.github/workflows/build.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: continuous-integration/gh-actions/gui
|
||||
name: ci/gh-actions/gui
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: install dependencies
|
||||
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi zmq libpgm miniupnpc ldns expat libunwind-headers protobuf qt5 pkg-config
|
||||
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi zmq libpgm libsodium miniupnpc ldns expat libunwind-headers protobuf qt5 pkg-config
|
||||
- name: build
|
||||
run: DEV_MODE=ON make release -j3
|
||||
- name: test qml
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: install monero dependencies
|
||||
run: sudo apt -y install build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev libprotobuf-dev protobuf-compiler
|
||||
- name: install monero gui dependencies
|
||||
run: sudo apt -y install qtbase5-dev qt5-default qtdeclarative5-dev qml-module-qtquick-controls qml-module-qtquick-controls2 qml-module-qtquick-dialogs qml-module-qtquick-xmllistmodel qml-module-qt-labs-settings qml-module-qt-labs-folderlistmodel qttools5-dev-tools qml-module-qtquick-templates2 libqt5svg5-dev libgcrypt20-dev xvfb
|
||||
run: sudo apt -y install qtbase5-dev qt5-default qtdeclarative5-dev qml-module-qtqml-models2 qml-module-qtquick-controls qml-module-qtquick-controls2 qml-module-qtquick-dialogs qml-module-qtquick-xmllistmodel qml-module-qt-labs-settings qml-module-qt-labs-folderlistmodel qttools5-dev-tools qml-module-qtquick-templates2 libqt5svg5-dev libgcrypt20-dev xvfb
|
||||
- name: build
|
||||
run: DEV_MODE=ON make release -j3
|
||||
- name: test qml
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: eine/setup-msys2@v1
|
||||
- uses: eine/setup-msys2@v2
|
||||
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
|
||||
@@ -58,22 +58,65 @@ jobs:
|
||||
- name: test qml
|
||||
run: build/release/bin/monero-wallet-gui --test-qml
|
||||
|
||||
macos-bundle:
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: install dependencies
|
||||
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi zmq libpgm miniupnpc ldns expat libunwind-headers protobuf pkg-config python3 p7zip
|
||||
- name: install dependencies
|
||||
run: pip3 install requests semantic_version lxml py7zr
|
||||
- name: download qt
|
||||
run: |
|
||||
curl -O https://raw.githubusercontent.com/engnr/qt-downloader/master/qt-downloader
|
||||
chmod +x qt-downloader
|
||||
./qt-downloader macos desktop 5.15.2 clang_64
|
||||
working-directory: ../
|
||||
- name: build
|
||||
run: CMAKE_PREFIX_PATH=/Users/runner/work/monero-gui/5.15.2/clang_64 make release -j3
|
||||
- name: deploy
|
||||
run: make deploy
|
||||
working-directory: build/release
|
||||
- name: test qml
|
||||
run: build/release/bin/monero-wallet-gui.app/Contents/MacOS/monero-wallet-gui --test-qml
|
||||
- name: create .tar
|
||||
run: tar -cf monero-wallet-gui.tar monero-wallet-gui.app
|
||||
working-directory: build/release/bin
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ github.job }}
|
||||
path: build/release/bin/monero-wallet-gui.tar
|
||||
|
||||
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
|
||||
- uses: satackey/action-docker-layer-caching@v0.0.10
|
||||
continue-on-error: true
|
||||
with:
|
||||
key: docker-linux-static-{hash}
|
||||
restore-keys: |
|
||||
docker-linux-static-
|
||||
- name: install dependencies
|
||||
run: sudo apt -y install xvfb libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xkb1 libxkbcommon-x11-0
|
||||
- name: preprare build enviroment
|
||||
run: docker build --tag monero:build-env-linux --build-arg THREADS=3 --file Dockerfile.linux .
|
||||
- name: build
|
||||
run: docker run --rm -v /home/runner/work/monero-gui/monero-gui:/monero-gui -w /monero-gui monero:build-env-linux sh -c 'make release-static -j3'
|
||||
- name: sha256sum
|
||||
run: shasum -a256 /home/runner/work/monero-gui/monero-gui/build/release/bin/monero-wallet-gui
|
||||
- name: test qml
|
||||
run: xvfb-run -a /home/runner/work/monero-gui/monero-gui/build/release/bin/monero-wallet-gui --test-qml
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ github.job }}
|
||||
path: |
|
||||
/home/runner/work/monero-gui/monero-gui/build/release/bin/monero-wallet-gui
|
||||
/home/runner/work/monero-gui/monero-gui/build/release/bin/monerod
|
||||
|
||||
docker-windows-static:
|
||||
runs-on: ubuntu-20.04
|
||||
@@ -81,7 +124,7 @@ jobs:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: satackey/action-docker-layer-caching@v0.0.8
|
||||
- uses: satackey/action-docker-layer-caching@v0.0.10
|
||||
continue-on-error: true
|
||||
with:
|
||||
key: docker-windows-static-{hash}
|
||||
@@ -91,3 +134,44 @@ jobs:
|
||||
run: docker build --tag monero:build-env-windows --build-arg THREADS=3 --file Dockerfile.windows .
|
||||
- name: build
|
||||
run: docker run --rm -v /home/runner/work/monero-gui/monero-gui:/monero-gui -w /monero-gui monero:build-env-windows sh -c 'make depends root=/depends target=x86_64-w64-mingw32 tag=win-x64 -j3'
|
||||
- name: sha256sum
|
||||
run: shasum -a256 /home/runner/work/monero-gui/monero-gui/build/x86_64-w64-mingw32/release/bin/monero-wallet-gui.exe
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ github.job }}
|
||||
path: |
|
||||
/home/runner/work/monero-gui/monero-gui/build/x86_64-w64-mingw32/release/bin/monero-wallet-gui.exe
|
||||
/home/runner/work/monero-gui/monero-gui/build/x86_64-w64-mingw32/release/bin/monerod.exe
|
||||
|
||||
docker-android:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: preprare build enviroment
|
||||
run: docker build --tag monero:build-env-android --build-arg THREADS=3 --file Dockerfile.android .
|
||||
- name: build
|
||||
run: docker run --rm -v /home/runner/work/monero-gui/monero-gui:/monero-gui -e THREADS=3 monero:build-env-android
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ github.job }}
|
||||
path: /home/runner/work/monero-gui/monero-gui/build/Android/release/android-build/monero-gui.apk
|
||||
|
||||
source-archive:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: archive
|
||||
run: |
|
||||
pip install git-archive-all
|
||||
export VERSION="monero-gui-$(git describe)"
|
||||
export OUTPUT="$VERSION.tar"
|
||||
echo "OUTPUT=$OUTPUT" >> $GITHUB_ENV
|
||||
/home/runner/.local/bin/git-archive-all --prefix "$VERSION/" --force-submodules "$OUTPUT"
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ env.OUTPUT }}
|
||||
path: /home/runner/work/monero-gui/monero-gui/${{ env.OUTPUT }}
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -2,3 +2,6 @@
|
||||
path = monero
|
||||
url = https://github.com/monero-project/monero
|
||||
ignore = all
|
||||
[submodule "external/quirc"]
|
||||
path = external/quirc
|
||||
url = https://github.com/dlbeer/quirc/
|
||||
|
||||
105
CMakeLists.txt
105
CMakeLists.txt
@@ -1,11 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
project(monero-gui)
|
||||
|
||||
message(STATUS "Initiating compile using CMake ${CMAKE_VERSION}")
|
||||
|
||||
set(VERSION_MAJOR "17")
|
||||
set(VERSION_MINOR "1")
|
||||
set(VERSION_REVISION "1")
|
||||
set(VERSION_MINOR "2")
|
||||
set(VERSION_REVISION "0")
|
||||
set(VERSION "0.${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}")
|
||||
|
||||
option(STATIC "Link libraries statically, requires static Qt")
|
||||
@@ -48,8 +48,9 @@ if(NOT MANUAL_SUBMODULES)
|
||||
else()
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} fetch WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/monero RESULT_VARIABLE GIT_FETCH_RESULT)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} checkout -f origin/master WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/monero RESULT_VARIABLE GIT_CHECKOUT_MASTER_RESULT)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} submodule sync --recursive WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/monero RESULT_VARIABLE GIT_SUBMODULE_SYNC_RESULT)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --force --recursive WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/monero RESULT_VARIABLE GIT_SUBMODULE_UPDATE_RESULT)
|
||||
if(NOT GIT_FETCH_RESULT EQUAL "0" OR NOT GIT_CHECKOUT_MASTER_RESULT EQUAL "0" OR NOT GIT_SUBMODULE_UPDATE_RESULT EQUAL "0")
|
||||
if(NOT GIT_FETCH_RESULT EQUAL "0" OR NOT GIT_CHECKOUT_MASTER_RESULT EQUAL "0" OR NOT GIT_SUBMODULE_SYNC_RESULT EQUAL "0" OR NOT GIT_SUBMODULE_UPDATE_RESULT EQUAL "0")
|
||||
message(FATAL_ERROR "Updating git submodule to master (-DDEV_MODE=ON) failed")
|
||||
endif()
|
||||
endif()
|
||||
@@ -76,7 +77,7 @@ if(STATIC)
|
||||
message(STATUS "Initiating static build")
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_STATIC_RUNTIME ON)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
add_definitions(-DMONERO_GUI_STATIC)
|
||||
endif()
|
||||
|
||||
@@ -131,12 +132,8 @@ message(STATUS "OpenSSL: Version ${OPENSSL_VERSION}")
|
||||
message(STATUS "OpenSSL: include dir at ${OPENSSL_INCLUDE_DIR}")
|
||||
message(STATUS "OpenSSL: libraries at ${OPENSSL_LIBRARIES} ${OPENSSL_SSL_LIBRARIES}")
|
||||
|
||||
# Zbar (for QR scanner)
|
||||
if(WITH_SCANNER)
|
||||
add_definitions(-DWITH_SCANNER)
|
||||
find_package(ZBar0)
|
||||
message(STATUS "libzbar: include dir at ${ZBAR_INCLUDE_DIR}")
|
||||
message(STATUS "libzbar: libraries at ${ZBAR_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
# Sodium
|
||||
@@ -149,9 +146,11 @@ message(STATUS "libusb: include dir at ${LibUSB_INCLUDE_DIRS}")
|
||||
message(STATUS "libusb: libraries at ${LibUSB_LIBRARIES}")
|
||||
|
||||
# HIDApi
|
||||
find_package(HIDAPI REQUIRED)
|
||||
message(STATUS "libhidapi: include dir at ${HIDAPI_INCLUDE_DIRS}")
|
||||
message(STATUS "libhidapi: libraries at ${HIDAPI_LIBRARIES}")
|
||||
if(NOT ANDROID)
|
||||
find_package(HIDAPI REQUIRED)
|
||||
message(STATUS "libhidapi: include dir at ${HIDAPI_INCLUDE_DIRS}")
|
||||
message(STATUS "libhidapi: libraries at ${HIDAPI_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
# Boost
|
||||
if(DEBUG)
|
||||
@@ -174,9 +173,12 @@ find_package(Boost 1.58 REQUIRED COMPONENTS
|
||||
program_options
|
||||
locale)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
set(CMAKE_SKIP_RPATH ON)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES_PREV ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".so")
|
||||
find_package(X11 REQUIRED)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_PREV})
|
||||
message(STATUS "X11_FOUND = ${X11_FOUND}")
|
||||
message(STATUS "X11_INCLUDE_DIR = ${X11_INCLUDE_DIR}")
|
||||
message(STATUS "X11_LIBRARIES = ${X11_LIBRARIES}")
|
||||
@@ -204,9 +206,7 @@ endif()
|
||||
set(QT5_LIBRARIES
|
||||
Qt5Core
|
||||
Qt5Quick
|
||||
Qt5Widgets
|
||||
Qt5Gui
|
||||
Qt5Network
|
||||
Qt5Qml
|
||||
Qt5Svg
|
||||
Qt5Xml
|
||||
@@ -218,20 +218,17 @@ endif()
|
||||
|
||||
if(APPLE)
|
||||
list(APPEND QT5_LIBRARIES Qt5MacExtras)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
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)
|
||||
if(APPLE AND 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)
|
||||
@@ -253,7 +250,22 @@ foreach(QT5_MODULE ${QT5_LIBRARIES})
|
||||
include_directories(${${QT5_MODULE}_INCLUDE_DIRS})
|
||||
endforeach()
|
||||
|
||||
pkg_check_modules(QT5_PKG_CONFIG REQUIRED ${QT5_LIBRARIES})
|
||||
if(NOT (CMAKE_CROSSCOMPILING AND ANDROID))
|
||||
pkg_check_modules(QT5_PKG_CONFIG REQUIRED ${QT5_LIBRARIES})
|
||||
else()
|
||||
set(QT5_LIBRARIES_ABI)
|
||||
foreach(QT5_MODULE ${QT5_LIBRARIES})
|
||||
list(APPEND QT5_LIBRARIES_ABI "${QT5_MODULE}_${CMAKE_ANDROID_ARCH_ABI}")
|
||||
endforeach()
|
||||
pkg_check_modules(QT5_PKG_CONFIG REQUIRED ${QT5_LIBRARIES_ABI})
|
||||
endif()
|
||||
|
||||
get_target_property(QMAKE_IMPORTED_LOCATION Qt5::qmake IMPORTED_LOCATION)
|
||||
get_filename_component(QT_INSTALL_PREFIX "${QMAKE_IMPORTED_LOCATION}/../.." ABSOLUTE)
|
||||
|
||||
if(APPLE AND NOT STATIC)
|
||||
set(CMAKE_BUILD_RPATH "${QT_INSTALL_PREFIX}/lib")
|
||||
endif()
|
||||
|
||||
if(QT5_PKG_CONFIG_FOUND)
|
||||
set(QT5_PKG_CONFIG "QT5_PKG_CONFIG")
|
||||
@@ -261,15 +273,15 @@ if(QT5_PKG_CONFIG_FOUND)
|
||||
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)
|
||||
|
||||
if(UNIX AND CMAKE_PREFIX_PATH)
|
||||
if(APPLE)
|
||||
list(JOIN ${QT5_PKG_CONFIG}_LDFLAGS_OTHER " " ${QT5_PKG_CONFIG}_LDFLAGS_OTHER)
|
||||
endif()
|
||||
# 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}")
|
||||
STRING(REPLACE "${QT5_PKG_CONFIG_Qt5Core_PREFIX}" "${QT_INSTALL_PREFIX}" ${QT5_PKG_CONFIG}_LDFLAGS_OTHER "${${QT5_PKG_CONFIG}_LDFLAGS_OTHER}")
|
||||
STRING(REPLACE "${QT5_PKG_CONFIG_Qt5Core_PREFIX}" "${QT_INSTALL_PREFIX}" ${QT5_PKG_CONFIG}_LIBRARIES "${${QT5_PKG_CONFIG}_LIBRARIES}")
|
||||
STRING(REPLACE "${QT5_PKG_CONFIG_Qt5Core_PREFIX}" "${QT_INSTALL_PREFIX}" ${QT5_PKG_CONFIG}_INCLUDE_DIRS "${${QT5_PKG_CONFIG}_INCLUDE_DIRS}")
|
||||
STRING(REPLACE "${QT5_PKG_CONFIG_Qt5Core_PREFIX}" "${QT_INSTALL_PREFIX}" ${QT5_PKG_CONFIG}_LIBRARY_DIRS "${${QT5_PKG_CONFIG}_LIBRARY_DIRS}")
|
||||
endif()
|
||||
|
||||
set(QT5_LIBRARIES ${${QT5_PKG_CONFIG}_LIBRARIES} ${${QT5_PKG_CONFIG}_LDFLAGS_OTHER})
|
||||
@@ -290,6 +302,8 @@ if(STATIC)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtGraphicalEffects)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtGraphicalEffects/private)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtMultimedia)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQml)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQml/Models.2)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick.2)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Controls)
|
||||
list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Controls.2)
|
||||
@@ -312,6 +326,7 @@ if(STATIC)
|
||||
qmlsettingsplugin
|
||||
qmlxmllistmodelplugin
|
||||
qquicklayoutsplugin
|
||||
modelsplugin
|
||||
)
|
||||
|
||||
if(WITH_SCANNER)
|
||||
@@ -330,6 +345,10 @@ if(STATIC)
|
||||
windowplugin
|
||||
)
|
||||
|
||||
if(NOT ${Qt5Core_VERSION} VERSION_LESS 5.14)
|
||||
list(APPEND QT5_EXTRA_LIBRARIES_LIST qmlplugin)
|
||||
endif()
|
||||
|
||||
set(QT5_EXTRA_LIBRARIES)
|
||||
foreach(LIBRARY ${QT5_EXTRA_LIBRARIES_LIST})
|
||||
find_library(${LIBRARY}_LIBRARY ${LIBRARY} PATHS ${QT5_EXTRA_PATHS} REQUIRED)
|
||||
@@ -357,7 +376,6 @@ if(STATIC)
|
||||
if(UNIX AND NOT APPLE)
|
||||
list(APPEND QT5_INTEGRATION_LIBRARIES_LIST
|
||||
Qt5XcbQpa
|
||||
xcb-static
|
||||
Qt5ServiceSupport
|
||||
Qt5GlxSupport
|
||||
)
|
||||
@@ -371,11 +389,30 @@ if(STATIC)
|
||||
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})
|
||||
pkg_check_modules(X11XCB_XCBGLX REQUIRED x11-xcb xcb-glx)
|
||||
list(APPEND QT5_LIBRARIES ${X11XCB_XCBGLX_LIBRARIES})
|
||||
pkg_check_modules(FONTCONFIG REQUIRED fontconfig)
|
||||
list(APPEND QT5_LIBRARIES ${FONTCONFIG_STATIC_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
set(QT5_EXTRA_LIBRARIES_LIST
|
||||
GLESv2
|
||||
log
|
||||
z
|
||||
jnigraphics
|
||||
android
|
||||
EGL
|
||||
Qt5VirtualKeyboard_${CMAKE_ANDROID_ARCH_ABI}
|
||||
c++_shared
|
||||
)
|
||||
foreach(LIBRARY ${QT5_EXTRA_LIBRARIES_LIST})
|
||||
find_library(${LIBRARY}_LIBRARY ${LIBRARY} PATHS "${ANDROID_TOOLCHAIN_ROOT}/sysroot/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/${ANDROID_PLATFORM_LEVEL}" REQUIRED)
|
||||
list(APPEND QT5_LIBRARIES ${${LIBRARY}_LIBRARY})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
message(STATUS "Using Boost include dir at ${Boost_INCLUDE_DIRS}")
|
||||
message(STATUS "Using Boost libraries at ${Boost_LIBRARIES}")
|
||||
|
||||
@@ -525,6 +562,6 @@ if (HIDAPI_FOUND OR LibUSB_COMPILE_TEST_PASSED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(external)
|
||||
add_subdirectory(translations)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
14
DEPLOY.md
14
DEPLOY.md
@@ -2,19 +2,17 @@
|
||||
|
||||
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`
|
||||
1. `HOMEBREW_OPTFLAGS="-march=core2" HOMEBREW_OPTIMIZATION_LEVEL="O0" brew install boost zmq libpgm miniupnpc libsodium expat libunwind-headers protobuf libgcrypt hidapi`
|
||||
|
||||
2. `HOMEBREW_OPTFLAGS="-march=core2" HOMEBREW_OPTIMIZATION_LEVEL="O0" brew install --HEAD hidapi`
|
||||
2. Get the latest LTS from here: https://www.qt.io/offline-installers and install
|
||||
|
||||
3. Get the latest LTS from here: https://www.qt.io/offline-installers and install
|
||||
3. `git clone --recursive -b v0.X.Y.Z --depth 1 https://github.com/monero-project/monero-gui`
|
||||
|
||||
4. `git clone --recursive -b v0.X.Y.Z --depth 1 https://github.com/monero-project/monero-gui`
|
||||
4. `CMAKE_PREFIX_PATH=~/Qt5.12.8/5.12.8/clang_64 make release`
|
||||
|
||||
5. `CMAKE_PREFIX_PATH=~/Qt5.12.8/5.12.8/clang_64 make release`
|
||||
5. `cd build/release && make deploy`
|
||||
|
||||
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.
|
||||
6. Replace the `monerod` binary inside `monero-wallet-gui.app/Contents/MacOS/` with one built using deterministic builds / gitian.
|
||||
|
||||
## Codesigning and notarizing
|
||||
|
||||
|
||||
207
Dockerfile.android
Normal file
207
Dockerfile.android
Normal file
@@ -0,0 +1,207 @@
|
||||
FROM debian:stretch
|
||||
|
||||
ARG THREADS=1
|
||||
ARG ANDROID_NDK_REVISION=21d
|
||||
ARG ANDROID_NDK_HASH=bcf4023eb8cb6976a4c7cff0a8a8f145f162bf4d
|
||||
ARG ANDROID_SDK_REVISION=4333796
|
||||
ARG ANDROID_SDK_HASH=92ffee5a1d98d856634e8b71132e8a95d96c83a63fde1099be3d86df3106def9
|
||||
ARG QT_VERSION=5.15.2
|
||||
|
||||
WORKDIR /opt/android
|
||||
ENV WORKDIR=/opt/android
|
||||
|
||||
ENV ANDROID_NATIVE_API_LEVEL=28
|
||||
ENV ANDROID_API=android-${ANDROID_NATIVE_API_LEVEL}
|
||||
ENV ANDROID_CLANG=aarch64-linux-android${ANDROID_NATIVE_API_LEVEL}-clang
|
||||
ENV ANDROID_CLANGPP=aarch64-linux-android${ANDROID_NATIVE_API_LEVEL}-clang++
|
||||
ENV ANDROID_NDK_ROOT=${WORKDIR}/android-ndk-r${ANDROID_NDK_REVISION}
|
||||
ENV ANDROID_SDK_ROOT=${WORKDIR}/tools
|
||||
ENV JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
|
||||
ENV PATH=${JAVA_HOME}/bin:${PATH}
|
||||
ENV PREFIX=${WORKDIR}/prefix
|
||||
ENV TOOLCHAIN_DIR=${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y ant automake build-essential ca-certificates-java file gettext git libc6 libncurses5 \
|
||||
libssl-dev libstdc++6 libtinfo5 libtool libz1 openjdk-8-jdk-headless openjdk-8-jre-headless pkg-config python3 \
|
||||
unzip wget
|
||||
|
||||
RUN wget -q https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_REVISION}.zip \
|
||||
&& unzip -q sdk-tools-linux-${ANDROID_SDK_REVISION}.zip \
|
||||
&& rm -f sdk-tools-linux-${ANDROID_SDK_REVISION}.zip
|
||||
|
||||
RUN wget -q https://dl.google.com/android/repository/android-ndk-r${ANDROID_NDK_REVISION}-linux-x86_64.zip \
|
||||
&& unzip -q android-ndk-r${ANDROID_NDK_REVISION}-linux-x86_64.zip \
|
||||
&& rm -f android-ndk-r${ANDROID_NDK_REVISION}-linux-x86_64.zip
|
||||
|
||||
RUN cd ${ANDROID_SDK_ROOT} && echo y | ./bin/sdkmanager "platform-tools" "platforms;${ANDROID_API}" "tools" > /dev/null
|
||||
RUN cp -r ${WORKDIR}/platforms ${WORKDIR}/platform-tools ${ANDROID_SDK_ROOT}
|
||||
|
||||
ENV HOST_PATH=${PATH}
|
||||
ENV PATH=${TOOLCHAIN_DIR}/aarch64-linux-android/bin:${TOOLCHAIN_DIR}/bin:${PATH}
|
||||
|
||||
ARG ZLIB_VERSION=1.2.11
|
||||
ARG ZLIB_HASH=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1
|
||||
RUN wget -q https://zlib.net/zlib-${ZLIB_VERSION}.tar.gz \
|
||||
&& tar -xzf zlib-${ZLIB_VERSION}.tar.gz \
|
||||
&& rm zlib-${ZLIB_VERSION}.tar.gz \
|
||||
&& cd zlib-${ZLIB_VERSION} \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --prefix=${PREFIX} --static \
|
||||
&& make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
RUN git clone git://code.qt.io/qt/qt5.git -b ${QT_VERSION} --depth 1 \
|
||||
&& cd qt5 \
|
||||
&& perl init-repository --module-subset=default,-qtwebengine \
|
||||
&& PATH=${HOST_PATH} ./configure -v -developer-build -release \
|
||||
-xplatform android-clang \
|
||||
-android-ndk-platform ${ANDROID_API} \
|
||||
-android-ndk ${ANDROID_NDK_ROOT} \
|
||||
-android-sdk ${ANDROID_SDK_ROOT} \
|
||||
-android-ndk-host linux-x86_64 \
|
||||
-no-dbus \
|
||||
-opengl es2 \
|
||||
-no-use-gold-linker \
|
||||
-no-sql-mysql \
|
||||
-opensource -confirm-license \
|
||||
-android-arch arm64-v8a \
|
||||
-prefix ${PREFIX} \
|
||||
-nomake tools -nomake tests -nomake examples \
|
||||
-skip qtwebengine \
|
||||
-skip qtserialport \
|
||||
-skip qtconnectivity \
|
||||
-skip qttranslations \
|
||||
-skip qtpurchasing \
|
||||
-skip qtgamepad -skip qtscript -skip qtdoc \
|
||||
-no-warnings-are-errors \
|
||||
&& sed -i '213,215d' qtbase/src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} install \
|
||||
&& cd qttools/src/linguist/lrelease \
|
||||
&& ../../../../qtbase/bin/qmake \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} install \
|
||||
&& cd ../../../.. \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
ARG ICONV_VERSION=1.16
|
||||
ARG ICONV_HASH=e6a1b1b589654277ee790cce3734f07876ac4ccfaecbee8afa0b649cf529cc04
|
||||
RUN wget -q http://ftp.gnu.org/pub/gnu/libiconv/libiconv-${ICONV_VERSION}.tar.gz \
|
||||
&& echo "${ICONV_HASH} libiconv-${ICONV_VERSION}.tar.gz" | sha256sum -c \
|
||||
&& tar -xzf libiconv-${ICONV_VERSION}.tar.gz \
|
||||
&& rm -f libiconv-${ICONV_VERSION}.tar.gz \
|
||||
&& cd libiconv-${ICONV_VERSION} \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --build=x86_64-linux-gnu --host=aarch64 --prefix=${PREFIX} --disable-rpath \
|
||||
&& make -j${THREADS} \
|
||||
&& make -j${THREADS} install
|
||||
|
||||
ARG BOOST_VERSION=1_74_0
|
||||
ARG BOOST_VERSION_DOT=1.74.0
|
||||
ARG BOOST_HASH=83bfc1507731a0906e387fc28b7ef5417d591429e51e788417fe9ff025e116b1
|
||||
RUN wget -q https://dl.bintray.com/boostorg/release/${BOOST_VERSION_DOT}/source/boost_${BOOST_VERSION}.tar.bz2 \
|
||||
&& echo "${BOOST_HASH} boost_${BOOST_VERSION}.tar.bz2" | sha256sum -c \
|
||||
&& tar -xf boost_${BOOST_VERSION}.tar.bz2 \
|
||||
&& rm -f boost_${BOOST_VERSION}.tar.bz2 \
|
||||
&& cd boost_${BOOST_VERSION} \
|
||||
&& PATH=${HOST_PATH} ./bootstrap.sh --prefix=${PREFIX} \
|
||||
&& PATH=${TOOLCHAIN_DIR}/bin:${HOST_PATH} ./b2 --build-type=minimal link=static runtime-link=static \
|
||||
--with-chrono --with-date_time --with-filesystem --with-program_options --with-regex --with-serialization \
|
||||
--with-system --with-thread --with-locale --build-dir=android --stagedir=android toolset=clang threading=multi \
|
||||
threadapi=pthread target-os=android -sICONV_PATH=${PREFIX} \
|
||||
cflags='--target=aarch64-linux-android' \
|
||||
cxxflags='--target=aarch64-linux-android' \
|
||||
linkflags='--target=aarch64-linux-android --sysroot=${ANDROID_NDK_ROOT}/platforms/${ANDROID_API}/arch-arm64 ${ANDROID_NDK_ROOT}/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so -nostdlib++' \
|
||||
install -j${THREADS} \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
ARG OPENSSL_VERSION=1.1.1g
|
||||
ARG OPENSSL_HASH=ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46
|
||||
RUN wget -q https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz \
|
||||
&& tar -xzf openssl-${OPENSSL_VERSION}.tar.gz \
|
||||
&& rm openssl-${OPENSSL_VERSION}.tar.gz \
|
||||
&& cd openssl-${OPENSSL_VERSION} \
|
||||
&& ANDROID_NDK_HOME=${ANDROID_NDK_ROOT} ./Configure CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} \
|
||||
android-arm64 no-asm no-shared --static \
|
||||
--with-zlib-include=${PREFIX}/include --with-zlib-lib=${PREFIX}/lib \
|
||||
--prefix=${PREFIX} --openssldir=${PREFIX} \
|
||||
&& sed -i 's/CNF_EX_LIBS=-ldl -pthread//g;s/BIN_CFLAGS=-pie $(CNF_CFLAGS) $(CFLAGS)//g' Makefile \
|
||||
&& ANDROID_NDK_HOME=${ANDROID_NDK_ROOT} make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
ARG ZMQ_VERSION=v4.3.3
|
||||
ARG ZMQ_HASH=04f5bbedee58c538934374dc45182d8fc5926fa3
|
||||
RUN git clone https://github.com/zeromq/libzmq.git -b ${ZMQ_VERSION} --depth 1 \
|
||||
&& cd libzmq \
|
||||
&& git checkout ${ZMQ_HASH} \
|
||||
&& ./autogen.sh \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --prefix=${PREFIX} --host=aarch64-linux-android \
|
||||
--enable-static --disable-shared \
|
||||
&& make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
ARG SODIUM_VERSION=1.0.18
|
||||
ARG SODIUM_HASH=4f5e89fa84ce1d178a6765b8b46f2b6f91216677
|
||||
RUN set -ex \
|
||||
&& git clone https://github.com/jedisct1/libsodium.git -b ${SODIUM_VERSION} --depth 1 \
|
||||
&& cd libsodium \
|
||||
&& test `git rev-parse HEAD` = ${SODIUM_HASH} || exit 1 \
|
||||
&& ./autogen.sh \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --prefix=${PREFIX} --host=aarch64-linux-android --enable-static --disable-shared \
|
||||
&& 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 \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --host=aarch64-linux-android --prefix=${PREFIX} --disable-rpath --disable-shared --enable-static --disable-doc --disable-tests \
|
||||
&& PATH=${TOOLCHAIN_DIR}/bin:${HOST_PATH} 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 \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --host=aarch64-linux-android --prefix=${PREFIX} --with-gpg-error-prefix=${PREFIX} --disable-shared --enable-static --disable-doc --disable-tests \
|
||||
&& PATH=${TOOLCHAIN_DIR}/bin:${HOST_PATH} make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
RUN cd tools \
|
||||
&& wget -q http://dl-ssl.google.com/android/repository/tools_r25.2.5-linux.zip \
|
||||
&& unzip -q tools_r25.2.5-linux.zip \
|
||||
&& rm -f tools_r25.2.5-linux.zip \
|
||||
&& echo y | ${ANDROID_SDK_ROOT}/tools/android update sdk --no-ui --all --filter build-tools-28.0.3
|
||||
|
||||
RUN git clone -b v3.19.7 --depth 1 https://github.com/Kitware/CMake \
|
||||
&& cd CMake \
|
||||
&& git reset --hard 22612dd53a46c7f9b4c3f4b7dbe5c78f9afd9581 \
|
||||
&& PATH=${HOST_PATH} ./bootstrap \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
CMD set -ex \
|
||||
&& cd /monero-gui \
|
||||
&& mkdir -p build/Android/release \
|
||||
&& cd build/Android/release \
|
||||
&& cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" \
|
||||
-DCMAKE_PREFIX_PATH="${PREFIX}" \
|
||||
-DCMAKE_FIND_ROOT_PATH="${PREFIX}" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DARCH="armv8-a" \
|
||||
-DANDROID_NATIVE_API_LEVEL=${ANDROID_NATIVE_API_LEVEL} \
|
||||
-DANDROID_ABI="arm64-v8a" \
|
||||
-DANDROID_TOOLCHAIN=clang \
|
||||
-DBoost_USE_STATIC_RUNTIME=ON \
|
||||
-DLRELEASE_PATH="${PREFIX}/bin" \
|
||||
-DQT_ANDROID_APPLICATION_BINARY="monero-wallet-gui" \
|
||||
-DWITH_SCANNER=ON \
|
||||
../../.. \
|
||||
&& PATH=${HOST_PATH} make generate_translations_header \
|
||||
&& make -j${THREADS} -C src \
|
||||
&& make -j${THREADS} apk
|
||||
171
Dockerfile.linux
171
Dockerfile.linux
@@ -1,6 +1,12 @@
|
||||
FROM ubuntu:16.04
|
||||
|
||||
ARG THREADS=1
|
||||
ARG QT_VERSION=5.15.2
|
||||
|
||||
ENV CFLAGS="-fPIC"
|
||||
ENV CPPFLAGS="-fPIC"
|
||||
ENV CXXFLAGS="-fPIC"
|
||||
ENV SOURCE_DATE_EPOCH=1397818193
|
||||
|
||||
RUN apt update
|
||||
|
||||
@@ -8,7 +14,7 @@ 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 && \
|
||||
./autogen.sh && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
@@ -16,7 +22,7 @@ RUN apt install -y automake git pkg-config python xutils-dev && \
|
||||
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 && \
|
||||
./autogen.sh && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
@@ -25,7 +31,7 @@ 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 && \
|
||||
./autogen.sh --enable-shared --disable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
@@ -34,7 +40,76 @@ 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 && \
|
||||
./autogen.sh --enable-shared --disable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
make -j$THREADS clean && \
|
||||
rm /usr/local/lib/libxcb-xinerama.so && \
|
||||
./autogen.sh --disable-shared --enable-static && \
|
||||
make -j$THREADS && \
|
||||
cp src/.libs/libxcb-xinerama.a /usr/local/lib/ && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b 0.4.0 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-util && \
|
||||
cd libxcb-util && \
|
||||
git reset --hard acf790d7752f36e450d476ad79807d4012ec863b && \
|
||||
git submodule init && \
|
||||
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
|
||||
./autogen.sh --enable-shared --disable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b 0.4.0 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-image && \
|
||||
cd libxcb-image && \
|
||||
git reset --hard d882052fb2ce439c6483fce944ba8f16f7294639 && \
|
||||
git submodule init && \
|
||||
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
|
||||
./autogen.sh --enable-shared --disable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b 0.4.0 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-keysyms && \
|
||||
cd libxcb-keysyms && \
|
||||
git reset --hard 0e51ee5570a6a80bdf98770b975dfe8a57f4eeb1 && \
|
||||
git submodule init && \
|
||||
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
|
||||
./autogen.sh --enable-shared --disable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b 0.3.9 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-render-util && \
|
||||
cd libxcb-render-util && \
|
||||
git reset --hard 0317caf63de532fd7a0493ed6afa871a67253747 && \
|
||||
git submodule init && \
|
||||
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
|
||||
./autogen.sh --enable-shared --disable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b 0.4.1 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-wm && \
|
||||
cd libxcb-wm && \
|
||||
git reset --hard 24eb17df2e1245885e72c9d4bbb0a0f69f0700f2 && \
|
||||
git submodule init && \
|
||||
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
|
||||
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
|
||||
./autogen.sh --enable-shared --disable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y bison && \
|
||||
git clone -b xkbcommon-0.5.0 --depth 1 https://github.com/xkbcommon/libxkbcommon && \
|
||||
cd libxkbcommon && \
|
||||
git reset --hard c43c3c866eb9d52cd8f61e75cbef1c30d07f3a28 && \
|
||||
./autogen.sh --prefix=/usr --enable-shared --disable-static --enable-x11 --disable-docs && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
@@ -42,7 +117,7 @@ RUN apt install -y libpthread-stubs0-dev && \
|
||||
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 && \
|
||||
./configure --static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
@@ -51,7 +126,7 @@ RUN git clone -b VER-2-10-2 --depth 1 https://git.savannah.gnu.org/git/freetype/
|
||||
cd freetype2 && \
|
||||
git reset --hard 132f19b779828b194b3fede187cee719785db4d8 && \
|
||||
./autogen.sh && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --with-zlib=no && \
|
||||
./configure --disable-shared --enable-static --with-zlib=no && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
@@ -60,7 +135,7 @@ 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 && \
|
||||
./configure --disable-shared --enable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
@@ -69,7 +144,7 @@ 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 && \
|
||||
./autogen.sh --disable-shared --enable-static --sysconfdir=/etc --localstatedir=/var && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
@@ -77,46 +152,56 @@ RUN apt install -y autopoint gettext gperf libpng12-dev && \
|
||||
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 && \
|
||||
./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 && \
|
||||
echo "9995e192e68528793755692917f9eb6422f3052a53c5e13ba278a228af6c7acf boost_1_73_0.tar.gz" | sha256sum -c && \
|
||||
tar -xzf boost_1_73_0.tar.gz && \
|
||||
rm boost_1_73_0.tar.gz && \
|
||||
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 && \
|
||||
./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="${CFLAGS}" cxxflags="${CXXFLAGS}" 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 && \
|
||||
echo "ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46 openssl-1.1.1g.tar.gz" | sha256sum -c && \
|
||||
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 && \
|
||||
./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 && \
|
||||
RUN apt install -y libgl1-mesa-dev libglib2.0-dev mesa-common-dev && \
|
||||
rm /usr/lib/x86_64-linux-gnu/libX11.a && \
|
||||
rm /usr/lib/x86_64-linux-gnu/libXext.a && \
|
||||
rm /usr/lib/x86_64-linux-gnu/libX11-xcb.a && \
|
||||
git clone git://code.qt.io/qt/qt5.git -b ${QT_VERSION} --depth 1 && \
|
||||
cd qt5 && \
|
||||
git clone git://code.qt.io/qt/qtbase.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtdeclarative.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtgraphicaleffects.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtimageformats.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtmultimedia.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtquickcontrols.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtquickcontrols2.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtsvg.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qttools.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qttranslations.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtx11extras.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtxmlpatterns.git -b ${QT_VERSION} --depth 1 && \
|
||||
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 && \
|
||||
sed -i s/\\/usr\\/X11R6\\/lib64/\\/usr\\/local\\/lib/ qtbase/mkspecs/linux-g++-64/qmake.conf && \
|
||||
./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 \
|
||||
-opengl desktop -qpa xcb -xcb -xcb-xlib -feature-xlib -system-freetype -fontconfig -glib \
|
||||
-no-dbus -no-feature-qml-worker-script -no-linuxfb -no-openssl -no-sql-sqlite -no-kms -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 \
|
||||
@@ -137,7 +222,7 @@ 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 && \
|
||||
./autogen.sh --disable-shared --enable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
@@ -146,23 +231,7 @@ 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 && \
|
||||
./configure --disable-shared --enable-static && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
@@ -172,7 +241,7 @@ RUN apt install -y libsodium-dev && \
|
||||
cd libzmq && \
|
||||
git reset --hard a84ffa12b2eb3569ced199660bac5ad128bff1f0 && \
|
||||
./autogen.sh && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --disable-libunwind --with-libsodium && \
|
||||
./configure --disable-shared --enable-static --disable-libunwind --with-libsodium && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
@@ -181,7 +250,7 @@ RUN git clone -b libgpg-error-1.38 --depth 1 git://git.gnupg.org/libgpg-error.gi
|
||||
cd libgpg-error && \
|
||||
git reset --hard 71d278824c5fe61865f7927a2ed1aa3115f9e439 && \
|
||||
./autogen.sh && \
|
||||
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --disable-doc --disable-tests && \
|
||||
./configure --disable-shared --enable-static --disable-doc --disable-tests && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
@@ -190,7 +259,7 @@ 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 && \
|
||||
./configure --disable-shared --enable-static --disable-doc && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
@@ -199,9 +268,17 @@ 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 && \
|
||||
./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
|
||||
RUN git clone -b v3.18.4 --depth 1 https://github.com/Kitware/CMake && \
|
||||
cd CMake && \
|
||||
git reset --hard 3cc3d42aba879fff5e85b363ae8f21386a3f9f9b && \
|
||||
./bootstrap && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN apt install -y libusb-1.0-0-dev
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ARG THREADS=1
|
||||
ARG QT_VERSION=5.15.2
|
||||
ENV SOURCE_DATE_EPOCH=1397818193
|
||||
|
||||
RUN apt update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt install -y build-essential cmake g++-mingw-w64 gettext git libtool pkg-config \
|
||||
@@ -19,26 +21,35 @@ RUN git clone -b v0.17.0.0 --depth 1 https://github.com/monero-project/monero &&
|
||||
|
||||
RUN make -j$THREADS -C /depends HOST=x86_64-w64-mingw32 NO_QT=1
|
||||
|
||||
RUN curl -LO https://download.qt.io/archive/qt/5.9/5.9.9/single/qt-everywhere-opensource-src-5.9.9.tar.xz && \
|
||||
echo "5ce285209290a157d7f42ec8eb22bf3f1d76f2e03a95fc0b99b553391be01642 qt-everywhere-opensource-src-5.9.9.tar.xz" > hashsum.txt && \
|
||||
sha256sum -c hashsum.txt && \
|
||||
tar -xf qt-everywhere-opensource-src-5.9.9.tar.xz && \
|
||||
rm qt-everywhere-opensource-src-5.9.9.tar.xz && \
|
||||
cd qt-everywhere-opensource-src-5.9.9 && \
|
||||
RUN git clone git://code.qt.io/qt/qt5.git -b ${QT_VERSION} --depth 1 && \
|
||||
cd qt5 && \
|
||||
git clone git://code.qt.io/qt/qtbase.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtdeclarative.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtgraphicaleffects.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtimageformats.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtmultimedia.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtquickcontrols.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtquickcontrols2.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtsvg.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qttools.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qttranslations.git -b ${QT_VERSION} --depth 1 && \
|
||||
git clone git://code.qt.io/qt/qtxmlpatterns.git -b ${QT_VERSION} --depth 1 && \
|
||||
./configure --prefix=/depends/x86_64-w64-mingw32 -xplatform win32-g++ \
|
||||
-device-option CROSS_COMPILE=/usr/bin/x86_64-w64-mingw32- \
|
||||
-I $(pwd)/qtbase/src/3rdparty/angle/include \
|
||||
-opensource -confirm-license -release -static -static-runtime -opengl dynamic -no-angle \
|
||||
-no-avx -no-openssl -no-sql-sqlite \
|
||||
-no-feature-qml-worker-script -no-openssl -no-sql-sqlite \
|
||||
-qt-freetype -qt-harfbuzz -qt-libjpeg -qt-libpng -qt-pcre -qt-zlib \
|
||||
-skip gamepad -skip location -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcanvas3d -skip qtcharts \
|
||||
-skip qtconnectivity -skip qtdatavis3d -skip qtdoc -skip qtgamepad -skip qtlocation -skip qtmacextras \
|
||||
-skip qtmultimedia -skip qtnetworkauth -skip qtpurchasing -skip qtscript -skip qtscxml -skip qtsensors \
|
||||
-skip qtserialbus -skip qtserialport -skip qtspeech -skip qttools -skip qtvirtualkeyboard -skip qtwayland \
|
||||
-skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtwinextras -skip qtx11extras \
|
||||
-skip gamepad -skip location -skip qt3d -skip qtactiveqt -skip qtandroidextras \
|
||||
-skip qtcanvas3d -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdoc \
|
||||
-skip qtgamepad -skip qtlocation -skip qtmacextras -skip qtnetworkauth -skip qtpurchasing \
|
||||
-skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport \
|
||||
-skip qtspeech -skip qttools -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel \
|
||||
-skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtwinextras -skip qtx11extras \
|
||||
-skip serialbus -skip webengine \
|
||||
-nomake examples -nomake tests -nomake tools && \
|
||||
make QMAKE="$(pwd)/qtbase/bin/qmake CONFIG-='debug debug_and_release'" -j$THREADS && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
cd qttools/src/linguist/lrelease && \
|
||||
../../../../qtbase/bin/qmake && \
|
||||
|
||||
102
LeftPanel.qml
102
LeftPanel.qml
@@ -58,12 +58,9 @@ Rectangle {
|
||||
signal historyClicked()
|
||||
signal transferClicked()
|
||||
signal receiveClicked()
|
||||
signal txkeyClicked()
|
||||
signal sharedringdbClicked()
|
||||
signal advancedClicked()
|
||||
signal settingsClicked()
|
||||
signal addressBookClicked()
|
||||
signal miningClicked()
|
||||
signal signClicked()
|
||||
signal accountClicked()
|
||||
|
||||
function selectItem(pos) {
|
||||
@@ -72,10 +69,6 @@ Rectangle {
|
||||
else if(pos === "Transfer") menuColumn.previousButton = transferButton
|
||||
else if(pos === "Receive") menuColumn.previousButton = receiveButton
|
||||
else if(pos === "AddressBook") menuColumn.previousButton = addressBookButton
|
||||
else if(pos === "Mining") menuColumn.previousButton = miningButton
|
||||
else if(pos === "TxKey") menuColumn.previousButton = txkeyButton
|
||||
else if(pos === "SharedRingDB") menuColumn.previousButton = sharedringdbButton
|
||||
else if(pos === "Sign") menuColumn.previousButton = signButton
|
||||
else if(pos === "Settings") menuColumn.previousButton = settingsButton
|
||||
else if(pos === "Advanced") menuColumn.previousButton = advancedButton
|
||||
else if(pos === "Account") menuColumn.previousButton = accountButton
|
||||
@@ -480,6 +473,7 @@ Rectangle {
|
||||
onClicked: {
|
||||
parent.previousButton.checked = false
|
||||
parent.previousButton = advancedButton
|
||||
panel.advancedClicked()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,98 +484,6 @@ Rectangle {
|
||||
anchors.leftMargin: 20
|
||||
}
|
||||
|
||||
// ------------- Mining tab ---------------
|
||||
MoneroComponents.MenuButton {
|
||||
id: miningButton
|
||||
visible: !isAndroid && !isIOS && appWindow.walletMode >= 2
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text: qsTr("Mining") + translationManager.emptyString
|
||||
symbol: qsTr("M") + translationManager.emptyString
|
||||
under: advancedButton
|
||||
onClicked: {
|
||||
parent.previousButton.checked = false
|
||||
parent.previousButton = miningButton
|
||||
panel.miningClicked()
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.MenuButtonDivider {
|
||||
visible: miningButton.present && appWindow.walletMode >= 2
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 20
|
||||
}
|
||||
|
||||
// ------------- TxKey tab ---------------
|
||||
MoneroComponents.MenuButton {
|
||||
id: txkeyButton
|
||||
visible: appWindow.walletMode >= 2
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text: qsTr("Prove/check") + translationManager.emptyString
|
||||
symbol: qsTr("K") + translationManager.emptyString
|
||||
under: advancedButton
|
||||
onClicked: {
|
||||
parent.previousButton.checked = false
|
||||
parent.previousButton = txkeyButton
|
||||
panel.txkeyClicked()
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.MenuButtonDivider {
|
||||
visible: txkeyButton.present && appWindow.walletMode >= 2
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 20
|
||||
}
|
||||
|
||||
// ------------- Shared RingDB tab ---------------
|
||||
MoneroComponents.MenuButton {
|
||||
id: sharedringdbButton
|
||||
visible: appWindow.walletMode >= 2
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text: qsTr("Shared RingDB") + translationManager.emptyString
|
||||
symbol: qsTr("G") + translationManager.emptyString
|
||||
under: advancedButton
|
||||
onClicked: {
|
||||
parent.previousButton.checked = false
|
||||
parent.previousButton = sharedringdbButton
|
||||
panel.sharedringdbClicked()
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.MenuButtonDivider {
|
||||
visible: sharedringdbButton.present && appWindow.walletMode >= 2
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 20
|
||||
}
|
||||
|
||||
// ------------- Sign/verify tab ---------------
|
||||
MoneroComponents.MenuButton {
|
||||
id: signButton
|
||||
visible: appWindow.walletMode >= 2
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text: qsTr("Sign/verify") + translationManager.emptyString
|
||||
symbol: qsTr("I") + translationManager.emptyString
|
||||
under: advancedButton
|
||||
onClicked: {
|
||||
parent.previousButton.checked = false
|
||||
parent.previousButton = signButton
|
||||
panel.signClicked()
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.MenuButtonDivider {
|
||||
visible: signButton.present && appWindow.walletMode >= 2
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 20
|
||||
}
|
||||
|
||||
// ------------- Settings tab ---------------
|
||||
MoneroComponents.MenuButton {
|
||||
id: settingsButton
|
||||
|
||||
55
Makefile
55
Makefile
@@ -1,40 +1,51 @@
|
||||
ANDROID_STANDALONE_TOOLCHAIN_PATH ?= /usr/local/toolchain
|
||||
MANUAL_SUBMODULES ?= OFF
|
||||
|
||||
dotgit=$(shell ls -d .git/config)
|
||||
ifneq ($(dotgit), .git/config)
|
||||
USE_SINGLE_BUILDDIR=1
|
||||
ifeq ($(dotgit), .git/config)
|
||||
ifeq ($(shell git --version > /dev/null 2>&1 ; echo $$?), 0)
|
||||
git = yes
|
||||
else
|
||||
$(warning git command not found)
|
||||
endif
|
||||
endif
|
||||
|
||||
subbuilddir:=$(shell echo `uname | sed -e 's|[:/\\ \(\)]|_|g'`/`git branch | grep '\* ' | cut -f2- -d' '| sed -e 's|[:/\\ \(\)]|_|g'`)
|
||||
builddir := build
|
||||
topdir := ../..
|
||||
ifeq ($(USE_SINGLE_BUILDDIR), OFF)
|
||||
builddir := build/"$(subbuilddir)"
|
||||
topdir := ../../../..
|
||||
deldirs := $(builddir)
|
||||
else
|
||||
builddir := build
|
||||
topdir := ../..
|
||||
deldirs := $(builddir)/debug $(builddir)/release $(builddir)/fuzz
|
||||
endif
|
||||
os := $(shell echo `uname | sed -e 's|[:/\\ \(\)]|_|g'`)
|
||||
builddir := $(builddir)/$(os)
|
||||
topdir := $(topdir)/..
|
||||
|
||||
ifdef git
|
||||
branch := $(shell git branch | grep '\* ' | cut -f2- -d' '| sed -e 's|[:/\\ \(\)]|_|g')
|
||||
builddir := $(builddir)/$(branch)
|
||||
topdir := $(topdir)/..
|
||||
endif
|
||||
|
||||
deldirs := $(builddir)
|
||||
else
|
||||
deldirs := $(builddir)/debug $(builddir)/release $(builddir)/fuzz
|
||||
endif
|
||||
|
||||
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)
|
||||
mkdir -p build && cd build && cmake -D ARCH="x86-64" -D DEV_MODE=$(or ${DEV_MODE},OFF) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release .. && $(MAKE)
|
||||
debug:
|
||||
mkdir -p build && cd build && cmake -D DEV_MODE=$(or ${DEV_MODE},ON) .. && $(MAKE) VERBOSE=1
|
||||
mkdir -p build && cd build && cmake -D DEV_MODE=$(or ${DEV_MODE},ON) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} .. && $(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)
|
||||
cd build/$(target)/release && cmake -D STATIC=ON -D DEV_MODE=$(or ${DEV_MODE},OFF) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -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)
|
||||
mkdir -p build && cd build && cmake -D ARCH="x86-64" -D DEV_MODE=$(or ${DEV_MODE},ON) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release .. && $(MAKE)
|
||||
clean:
|
||||
mkdir -p build && cd build && rm -rf *
|
||||
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)
|
||||
mkdir -p build && cd build && cmake -D ARCH="x86-64" -D DEV_MODE=$(or ${DEV_MODE},ON) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -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)
|
||||
mkdir -p $(builddir)/release && cd $(builddir)/release && cmake -D DEV_MODE=$(or ${DEV_MODE},OFF) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -D ARCH="x86-64" -D CMAKE_BUILD_TYPE=Release $(topdir) && $(MAKE)
|
||||
|
||||
release-linux-armv8:
|
||||
mkdir -p $(builddir)/release
|
||||
@@ -42,17 +53,17 @@ release-linux-armv8:
|
||||
cmake -D DEV_MODE=$(or ${DEV_MODE},OFF) -D ARCH="armv8-a" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="linux-armv8" $(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)
|
||||
mkdir -p $(builddir)/release && cd $(builddir)/release && cmake -D STATIC=ON -D DEV_MODE=$(or ${DEV_MODE},OFF) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -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=$(shell 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) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -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)
|
||||
cd $(builddir)/debug && cmake -D STATIC=ON -D DEV_MODE=$(or ${DEV_MODE},ON) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -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=$(shell 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) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -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)
|
||||
mkdir -p $(builddir)/release && cd $(builddir)/release && cmake -D STATIC=OFF -G "MSYS Makefiles" -D DEV_MODE=$(or ${DEV_MODE},OFF) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -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)
|
||||
|
||||
@@ -51,22 +51,19 @@ Rectangle {
|
||||
property alias flickable: mainFlickable
|
||||
|
||||
property Transfer transferView: Transfer {
|
||||
onPaymentClicked: root.paymentClicked(address, paymentId, amount, mixinCount, priority, description)
|
||||
onPaymentClicked: root.paymentClicked(recipients, paymentId, mixinCount, priority, description)
|
||||
onSweepUnmixableClicked: root.sweepUnmixableClicked()
|
||||
}
|
||||
property Receive receiveView: Receive { }
|
||||
property Merchant merchantView: Merchant { }
|
||||
property TxKey txkeyView: TxKey { }
|
||||
property SharedRingDB sharedringdbView: SharedRingDB { }
|
||||
property History historyView: History { }
|
||||
property Sign signView: Sign { }
|
||||
property Advanced advancedView: Advanced { }
|
||||
property Settings settingsView: Settings { }
|
||||
property Mining miningView: Mining { }
|
||||
property AddressBook addressBookView: AddressBook { }
|
||||
property Keys keysView: Keys { }
|
||||
property Account accountView: Account { }
|
||||
|
||||
signal paymentClicked(string address, string paymentId, string amount, int mixinCount, int priority, string description)
|
||||
signal paymentClicked(var recipients, string paymentId, int mixinCount, int priority, string description)
|
||||
signal sweepUnmixableClicked()
|
||||
signal generatePaymentIdInvoked()
|
||||
signal getProofClicked(string txid, string address, string message);
|
||||
@@ -136,30 +133,18 @@ Rectangle {
|
||||
name: "Merchant"
|
||||
PropertyChanges { target: root; currentView: merchantView }
|
||||
PropertyChanges { target: mainFlickable; contentHeight: merchantView.merchantHeight + 80 }
|
||||
}, State {
|
||||
name: "TxKey"
|
||||
PropertyChanges { target: root; currentView: txkeyView }
|
||||
PropertyChanges { target: mainFlickable; contentHeight: txkeyView.txkeyHeight + 80 }
|
||||
}, State {
|
||||
name: "SharedRingDB"
|
||||
PropertyChanges { target: root; currentView: sharedringdbView }
|
||||
PropertyChanges { target: mainFlickable; contentHeight: sharedringdbView.panelHeight + 80 }
|
||||
}, State {
|
||||
name: "AddressBook"
|
||||
PropertyChanges { target: root; currentView: addressBookView }
|
||||
PropertyChanges { target: mainFlickable; contentHeight: addressBookView.addressbookHeight + 80 }
|
||||
}, State {
|
||||
name: "Sign"
|
||||
PropertyChanges { target: root; currentView: signView }
|
||||
PropertyChanges { target: mainFlickable; contentHeight: signView.signHeight + 80 }
|
||||
name: "Advanced"
|
||||
PropertyChanges { target: root; currentView: advancedView }
|
||||
PropertyChanges { target: mainFlickable; contentHeight: advancedView.panelHeight }
|
||||
}, State {
|
||||
name: "Settings"
|
||||
PropertyChanges { target: root; currentView: settingsView }
|
||||
PropertyChanges { target: mainFlickable; contentHeight: settingsView.settingsHeight }
|
||||
}, State {
|
||||
name: "Mining"
|
||||
PropertyChanges { target: root; currentView: miningView }
|
||||
PropertyChanges { target: mainFlickable; contentHeight: miningView.miningHeight + 80 }
|
||||
}, State {
|
||||
name: "Keys"
|
||||
PropertyChanges { target: root; currentView: keysView }
|
||||
@@ -168,7 +153,7 @@ Rectangle {
|
||||
name: "Account"
|
||||
PropertyChanges { target: root; currentView: accountView }
|
||||
PropertyChanges { target: mainFlickable; contentHeight: accountView.accountHeight + 80 }
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
80
README.md
80
README.md
@@ -72,7 +72,7 @@ Packages are available for
|
||||
* Debian: See the [whonix/monero-gui repository](https://gitlab.com/whonix/monero-gui#how-to-install-monero-using-apt-get)
|
||||
* Void Linux: `xbps-install -S monero-gui`
|
||||
* GuixSD: `guix package -i monero-gui`
|
||||
* macOS (homebrew): `brew cask install monero-wallet`
|
||||
* macOS (homebrew): `brew install --cask monero-wallet`
|
||||
|
||||
Packaging for your favorite distribution would be a welcome contribution!
|
||||
|
||||
@@ -80,13 +80,14 @@ Packaging for your favorite distribution would be a welcome contribution!
|
||||
|
||||
*Note*: Qt 5.9.7 is the minimum version required to build the GUI.
|
||||
|
||||
### Building Windows static binaries with Docker (any OS)
|
||||
### Building Reproducible Windows static binaries with Docker (any OS)
|
||||
|
||||
1. Install Docker [https://docs.docker.com/engine/install/](https://docs.docker.com/engine/install/)
|
||||
2. Clone the repository
|
||||
```
|
||||
git clone --recursive https://github.com/monero-project/monero-gui.git
|
||||
git clone --branch master --recursive https://github.com/monero-project/monero-gui.git
|
||||
```
|
||||
\* `master` - replace with the desired version tag (e.g. `v0.17.1.9`) to build the release binaries.
|
||||
3. Prepare build environment
|
||||
```
|
||||
cd monero-gui
|
||||
@@ -102,13 +103,14 @@ Packaging for your favorite distribution would be a welcome contribution!
|
||||
\* `4` - number of CPU threads to use
|
||||
5. Monero GUI Windows static binaries will be placed in `monero-gui/build/x86_64-w64-mingw32/release/bin` directory
|
||||
|
||||
### Building Linux static binaries with Docker (any OS)
|
||||
### Building Reproducible Linux static binaries with Docker (any OS)
|
||||
|
||||
1. Install Docker [https://docs.docker.com/engine/install/](https://docs.docker.com/engine/install/)
|
||||
2. Clone the repository
|
||||
```
|
||||
git clone --recursive https://github.com/monero-project/monero-gui.git
|
||||
git clone --branch master --recursive https://github.com/monero-project/monero-gui.git
|
||||
```
|
||||
\* `master` - replace with the desired version tag (e.g. `v0.17.1.9`) to build the release binaries.
|
||||
3. Prepare build environment
|
||||
```
|
||||
cd monero-gui
|
||||
@@ -123,6 +125,60 @@ Packaging for your favorite distribution would be a welcome contribution!
|
||||
\* `<MONERO_GUI_DIR_FULL_PATH>` - absolute path to `monero-gui` directory
|
||||
\* `4` - number of CPU threads to use
|
||||
5. Monero GUI Linux static binaries will be placed in `monero-gui/build/release/bin` directory
|
||||
6. (*Optional*) Compare `monero-wallet-gui` SHA-256 hash to the one obtained from a trusted source
|
||||
```
|
||||
docker run --rm -it -v <MONERO_GUI_DIR_FULL_PATH>:/monero-gui -w /monero-gui monero:build-env-linux sh -c 'shasum -a 256 /monero-gui/build/release/bin/monero-wallet-gui'
|
||||
```
|
||||
\* `<MONERO_GUI_DIR_FULL_PATH>` - absolute path to `monero-gui` directory
|
||||
|
||||
### Building Android APK with Docker (any OS) *Experimental*
|
||||
- Minimum Android 9 Pie (API 28)
|
||||
- ARMv8-A 64-bit CPU
|
||||
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-android --build-arg THREADS=4 --file Dockerfile.android .
|
||||
```
|
||||
\* `4` - number of CPU threads to use
|
||||
|
||||
4. Build
|
||||
```
|
||||
docker run --rm -it -v <MONERO_GUI_DIR_FULL_PATH>:/monero-gui -e THREADS=4 monero:build-env-android
|
||||
```
|
||||
\* `<MONERO_GUI_DIR_FULL_PATH>` - absolute path to `monero-gui` directory
|
||||
\* `4` - number of CPU threads to use
|
||||
5. Monero GUI APK will be placed in `monero-gui/build/Android/release/android-build` directory
|
||||
6. Deploy
|
||||
* Using ADB (Android debugger bridge)
|
||||
- [Enable adb debugging on your device](https://developer.android.com/studio/command-line/adb.html#Enabling)
|
||||
* Connect your device with USB and install Monero GUI APK with adb:
|
||||
```
|
||||
adb install build/Android/release/android-build/monero-gui.apk
|
||||
```
|
||||
* Troubleshooting:
|
||||
```
|
||||
adb devices -l
|
||||
adb logcat
|
||||
```
|
||||
* If using adb inside docker, make sure you did
|
||||
```
|
||||
docker run -v /dev/bus/usb:/dev/bus/usb --privileged
|
||||
```
|
||||
* Using a web server
|
||||
```
|
||||
mkdir /usr/tmp
|
||||
cp build/Android/release/android-build/monero-gui.apk /usr/tmp
|
||||
docker run -d -v /usr/tmp:/usr/share/nginx/html:ro -p 8080:80 nginx
|
||||
```
|
||||
Now it should be accessible through a web browser at
|
||||
```
|
||||
http://<your.local.ip>:8080/QtApp-debug.apk
|
||||
```
|
||||
|
||||
### On Linux:
|
||||
|
||||
@@ -152,7 +208,7 @@ The following instructions will fetch Qt from your distribution's repositories i
|
||||
|
||||
- For Ubuntu 17.10+
|
||||
|
||||
`sudo apt install qtbase5-dev qt5-default qtdeclarative5-dev qml-module-qtquick-controls qml-module-qtquick-controls2 qml-module-qtquick-dialogs qml-module-qtquick-xmllistmodel qml-module-qt-labs-settings qml-module-qt-labs-folderlistmodel qttools5-dev-tools qml-module-qtquick-templates2 libqt5svg5-dev`
|
||||
`sudo apt install qtbase5-dev qt5-default qtdeclarative5-dev qml-module-qtqml-models2 qml-module-qtquick-controls qml-module-qtquick-controls2 qml-module-qtquick-dialogs qml-module-qtquick-xmllistmodel qml-module-qt-labs-settings qml-module-qt-labs-folderlistmodel qttools5-dev-tools qml-module-qtquick-templates2 libqt5svg5-dev`
|
||||
|
||||
- For Gentoo
|
||||
|
||||
@@ -162,13 +218,13 @@ The following instructions will fetch Qt from your distribution's repositories i
|
||||
|
||||
- For Ubuntu
|
||||
|
||||
`sudo apt install qtmultimedia5-dev qml-module-qtmultimedia libzbar-dev`
|
||||
`sudo apt install qtmultimedia5-dev qml-module-qtmultimedia`
|
||||
|
||||
- For Gentoo
|
||||
|
||||
The *qml* USE flag must be enabled.
|
||||
|
||||
`emerge dev-qt/qtmultimedia:5 media-gfx/zbar`
|
||||
`emerge dev-qt/qtmultimedia:5`
|
||||
|
||||
|
||||
3. Clone repository
|
||||
@@ -196,7 +252,7 @@ The executable can be found in the build/release/bin folder.
|
||||
|
||||
3. Install [monero](https://github.com/monero-project/monero) dependencies:
|
||||
|
||||
`brew install boost hidapi zmq libpgm miniupnpc ldns expat libunwind-headers protobuf libgcrypt`
|
||||
`brew install boost hidapi zmq libpgm libsodium miniupnpc ldns expat libunwind-headers protobuf libgcrypt`
|
||||
|
||||
4. Install Qt:
|
||||
|
||||
@@ -235,12 +291,6 @@ The Monero GUI on Windows is 64 bits only; 32-bit Windows GUI builds are not off
|
||||
pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb mingw-w64-x86_64-libgcrypt
|
||||
```
|
||||
|
||||
Optional : To build the flag `WITH_SCANNER`
|
||||
|
||||
```
|
||||
pacman -S mingw-w64-x86_64-zbar
|
||||
```
|
||||
|
||||
You find more details about those dependencies in the [Monero documentation](https://github.com/monero-project/monero). Note that that there is no more need to compile Boost from source; like everything else, you can install it now with a MSYS2 package.
|
||||
|
||||
4. Install Qt5
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
Copyright (c) 2014-2018, The Monero Project
|
||||
|
||||
|
||||
## Current status : ALPHA
|
||||
|
||||
- Minimum Android 5.0 (api level 21)
|
||||
- Modal dialogs can appear in background giving the feeling that the application is frozen (Work around : turn screen off/on or switch to another app and back)
|
||||
|
||||
## Build using Docker
|
||||
|
||||
# Base environnement
|
||||
|
||||
cd monero/utils/build_scripts
|
||||
docker build -f android32.Dockerfile -t monero-android .
|
||||
cd ..
|
||||
|
||||
# Build GUI
|
||||
|
||||
cd android/docker
|
||||
docker build -t monero-gui-android .
|
||||
docker create -it --name monero-gui-android monero-gui-android bash
|
||||
|
||||
# Get the apk
|
||||
|
||||
docker cp monero-gui-android:/opt/android/monero-gui/build/release/bin/bin/QtApp-debug.apk .
|
||||
|
||||
## Deployment
|
||||
|
||||
- Using ADB (Android debugger bridge) :
|
||||
|
||||
First, see section [Enable adb debugging on your device](https://developer.android.com/studio/command-line/adb.html#Enabling)
|
||||
The only place where we are allowed to play is `/data/local/tmp`. So :
|
||||
|
||||
adb push /opt/android/monero-gui/build/release/bin/bin/QtApp-debug.apk /data/local/tmp
|
||||
adb shell pm install -r /data/local/tmp/QtApp-debug.apk
|
||||
|
||||
- Troubleshooting:
|
||||
|
||||
adb devices -l
|
||||
adb logcat
|
||||
|
||||
if using adb inside docker, make sure you did "docker run -v /dev/bus/usb:/dev/bus/usb --privileged"
|
||||
|
||||
- Using a web server
|
||||
|
||||
mkdir /usr/tmp
|
||||
cp QtApp-debug.apk /usr/tmp
|
||||
docker run -d -v /usr/tmp:/usr/share/nginx/html:ro -p 8080:80 nginx
|
||||
|
||||
Now it should be accessible through a web browser at
|
||||
|
||||
http://<your.local.ip>:8080/QtApp-debug.apk
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
FROM monero-android
|
||||
|
||||
#INSTALL JAVA
|
||||
RUN echo "deb http://ftp.fr.debian.org/debian/ jessie-backports main contrib non-free" >> /etc/apt/sources.list
|
||||
RUN dpkg --add-architecture i386 \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y libc6:i386 libncurses5:i386 libstdc++6:i386 libz1:i386 \
|
||||
&& apt-get install -y -t jessie-backports ca-certificates-java openjdk-8-jdk-headless openjdk-8-jre-headless ant
|
||||
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64
|
||||
ENV PATH $JAVA_HOME/bin:$PATH
|
||||
|
||||
#Get Qt
|
||||
ENV QT_VERSION 5.8
|
||||
|
||||
RUN git clone git://code.qt.io/qt/qt5.git -b ${QT_VERSION} \
|
||||
&& cd qt5 \
|
||||
&& perl init-repository
|
||||
|
||||
## Note: Need to use libc++ but Qt does not provide mkspec for libc++.
|
||||
## Their support of it is quite recent and they claim they don't use it by default
|
||||
## [only because it produces bigger binary objects](https://bugreports.qt.io/browse/QTBUG-50724).
|
||||
|
||||
#Create new mkspec for clang + libc++
|
||||
RUN cp -r qt5/qtbase/mkspecs/android-clang qt5/qtbase/mkspecs/android-clang-libc \
|
||||
&& cd qt5/qtbase/mkspecs/android-clang-libc \
|
||||
&& sed -i '16i ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/llvm-libc++/libs/$$ANDROID_TARGET_ARCH' qmake.conf \
|
||||
&& sed -i '17i ANDROID_SOURCES_CXX_STL_INCDIR = $$NDK_ROOT/sources/cxx-stl/llvm-libc++/include' qmake.conf \
|
||||
&& echo "QMAKE_LIBS_PRIVATE = -lc++_shared -llog -lz -lm -ldl -lc -lgcc " >> qmake.conf \
|
||||
&& echo "QMAKE_CFLAGS -= -mfpu=vfp " >> qmake.conf \
|
||||
&& echo "QMAKE_CXXFLAGS -= -mfpu=vfp " >> qmake.conf \
|
||||
&& echo "QMAKE_CFLAGS += -mfpu=vfp4 " >> qmake.conf \
|
||||
&& echo "QMAKE_CXXFLAGS += -mfpu=vfp4 " >> qmake.conf
|
||||
|
||||
ENV ANDROID_API android-21
|
||||
|
||||
#ANDROID SDK TOOLS
|
||||
RUN echo y | $ANDROID_SDK_ROOT/tools/android update sdk --no-ui --all --filter platform-tools
|
||||
RUN echo y | $ANDROID_SDK_ROOT/tools/android update sdk --no-ui --all --filter ${ANDROID_API}
|
||||
RUN echo y | $ANDROID_SDK_ROOT/tools/android update sdk --no-ui --all --filter build-tools-25.0.1
|
||||
|
||||
ENV CLEAN_PATH $JAVA_HOME/bin:/usr/cmake-3.6.3-Linux-x86_64/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
|
||||
#build Qt
|
||||
RUN cd qt5 && PATH=${CLEAN_PATH} ./configure -developer-build -release \
|
||||
-xplatform android-clang-libc \
|
||||
-android-ndk-platform ${ANDROID_API} \
|
||||
-android-ndk $ANDROID_NDK_ROOT \
|
||||
-android-sdk $ANDROID_SDK_ROOT \
|
||||
-opensource -confirm-license \
|
||||
-prefix ${WORKDIR}/Qt-${QT_VERSION} \
|
||||
-nomake tests -nomake examples \
|
||||
-skip qtserialport \
|
||||
-skip qtconnectivity \
|
||||
-skip qttranslations \
|
||||
-skip qtgamepad -skip qtscript -skip qtdoc
|
||||
|
||||
# build Qt tools : gnustl_shared.so is hard-coded in androiddeployqt
|
||||
# replace it with libc++_shared.so
|
||||
COPY androiddeployqt.patch qt5/qttools/androiddeployqt.patch
|
||||
RUN cd qt5/qttools \
|
||||
&& git apply androiddeployqt.patch \
|
||||
&& cd .. \
|
||||
&& PATH=${CLEAN_PATH} make -j4 \
|
||||
&& PATH=${CLEAN_PATH} make install
|
||||
|
||||
# Get iconv and ZBar
|
||||
ENV ICONV_VERSION 1.14
|
||||
RUN git clone https://github.com/ZBar/ZBar.git \
|
||||
&& curl -s -O http://ftp.gnu.org/pub/gnu/libiconv/libiconv-${ICONV_VERSION}.tar.gz \
|
||||
&& tar -xzf libiconv-${ICONV_VERSION}.tar.gz \
|
||||
&& cd libiconv-${ICONV_VERSION} \
|
||||
&& CC=arm-linux-androideabi-clang CXX=arm-linux-androideabi-clang++ ./configure --build=x86_64-linux-gnu --host=arm-eabi --prefix=${WORKDIR}/libiconv --disable-rpath
|
||||
|
||||
ENV PATH $ANDROID_SDK_ROOT/tools:$ANDROID_SDK_ROOT/platform-tools:${WORKDIR}/Qt-${QT_VERSION}/bin:$PATH
|
||||
|
||||
#Build libiconv.a and libzbarjni.a
|
||||
COPY android.mk.patch ZBar/android.mk.patch
|
||||
RUN cd ZBar \
|
||||
&& git apply android.mk.patch \
|
||||
&& echo \
|
||||
"APP_ABI := armeabi-v7a \n\
|
||||
APP_STL := c++_shared \n\
|
||||
TARGET_PLATFORM := ${ANDROID_API} \n\
|
||||
TARGET_ARCH_ABI := armeabi-v7a \n\
|
||||
APP_CFLAGS += -target armv7-none-linux-androideabi -fexceptions -fstack-protector-strong -fno-limit-debug-info -mfloat-abi=softfp -mfpu=vfp -fno-builtin-memmove -fno-omit-frame-pointer -fno-stack-protector\n"\
|
||||
>> android/jni/Application.mk \
|
||||
&& cd android \
|
||||
&& android update project --path . -t "${ANDROID_API}" \
|
||||
&& CC=arm-linux-androideabi-clang CXX=arm-linux-androideabi-clang++ ant -Dndk.dir=${ANDROID_NDK_ROOT} -Diconv.src=${WORKDIR}/libiconv-${ICONV_VERSION} zbar-clean zbar-ndk-build
|
||||
|
||||
RUN cp openssl/lib* ${ANDROID_NDK_ROOT}/platforms/${ANDROID_API}/arch-arm/usr/lib
|
||||
RUN cp boost_${BOOST_VERSION}/android32/lib/lib* ${ANDROID_NDK_ROOT}/platforms/${ANDROID_API}/arch-arm/usr/lib
|
||||
RUN cp ZBar/android/obj/local/armeabi-v7a/lib* ${ANDROID_NDK_ROOT}/platforms/${ANDROID_API}/arch-arm/usr/lib
|
||||
|
||||
RUN git clone https://github.com/monero-project/monero-gui.git \
|
||||
&& cd monero-gui \
|
||||
&& git submodule update \
|
||||
&& CC=arm-linux-androideabi-clang CXX=arm-linux-androideabi-clang++ BOOST_ROOT=/opt/android/boost_1_62_0 \
|
||||
BOOST_LIBRARYDIR=${WORKDIR}/boost_${BOOST_VERSION}/android32/lib/ \
|
||||
OPENSSL_ROOT_DIR=${WORKDIR}/openssl/ \
|
||||
CMAKE_INCLUDE_PATH=${WORKDIR}/cppzmq/ \
|
||||
CMAKE_LIBRARY_PATH=${WORKDIR}/zeromq4-1/.libs \
|
||||
CXXFLAGS="-I ${WORKDIR}/zeromq4-1/include/" \
|
||||
./build.sh release-android \
|
||||
&& cd build \
|
||||
&& make deploy
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
|
||||
index e442b07..158afd5 100644
|
||||
--- a/android/jni/Android.mk
|
||||
+++ b/android/jni/Android.mk
|
||||
@@ -12,14 +12,18 @@ LOCAL_PATH := $(ICONV_SRC)
|
||||
|
||||
LOCAL_MODULE := libiconv
|
||||
|
||||
+LOCAL_ARM_MODE := arm
|
||||
+LOCAL_CPP_FEATURES := exceptions rtti features
|
||||
LOCAL_CFLAGS := \
|
||||
-Wno-multichar \
|
||||
-D_ANDROID \
|
||||
- -DLIBDIR="c" \
|
||||
+ -DLIBDIR="\".\"" \
|
||||
-DBUILDING_LIBICONV \
|
||||
-DBUILDING_LIBCHARSET \
|
||||
-DIN_LIBRARY
|
||||
|
||||
+LOCAL_CFLAGS += -fno-stack-protector
|
||||
+
|
||||
LOCAL_SRC_FILES := \
|
||||
lib/iconv.c \
|
||||
libcharset/lib/localcharset.c \
|
||||
@@ -30,13 +34,14 @@ LOCAL_C_INCLUDES := \
|
||||
$(ICONV_SRC)/libcharset \
|
||||
$(ICONV_SRC)/libcharset/include
|
||||
|
||||
-include $(BUILD_SHARED_LIBRARY)
|
||||
+include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_LDLIBS := -llog -lcharset
|
||||
|
||||
# libzbarjni
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
+
|
||||
LOCAL_PATH := $(MY_LOCAL_PATH)
|
||||
LOCAL_MODULE := zbarjni
|
||||
LOCAL_SRC_FILES := ../../java/zbarjni.c \
|
||||
@@ -71,6 +76,17 @@ LOCAL_C_INCLUDES := ../include \
|
||||
../zbar \
|
||||
$(ICONV_SRC)/include
|
||||
|
||||
-LOCAL_SHARED_LIBRARIES := libiconv
|
||||
+LOCAL_STATIC_LIBRARIES := libiconv
|
||||
+LOCAL_ARM_MODE := arm
|
||||
+LOCAL_CPP_FEATURES := exceptions rtti features
|
||||
+
|
||||
+LOCAL_CFLAGS := \
|
||||
+ -Wno-multichar \
|
||||
+ -D_ANDROID \
|
||||
+ -DLIBDIR="\".\"" \
|
||||
+ -DBUILDING_LIBICONV \
|
||||
+ -DBUILDING_LIBCHARSET \
|
||||
+ -DIN_LIBRARY
|
||||
+
|
||||
|
||||
-include $(BUILD_SHARED_LIBRARY)
|
||||
\ No newline at end of file
|
||||
+include $(BUILD_STATIC_LIBRARY)
|
||||
@@ -1,62 +0,0 @@
|
||||
diff --git a/src/androiddeployqt/main.cpp b/src/androiddeployqt/main.cpp
|
||||
index 8a8e591..71d693e 100644
|
||||
--- a/src/androiddeployqt/main.cpp
|
||||
+++ b/src/androiddeployqt/main.cpp
|
||||
@@ -1122,7 +1122,7 @@ bool updateLibsXml(const Options &options)
|
||||
|
||||
QString libsPath = QLatin1String("libs/") + options.architecture + QLatin1Char('/');
|
||||
|
||||
- QString qtLibs = QLatin1String("<item>gnustl_shared</item>\n");
|
||||
+ QString qtLibs = QLatin1String("<item>c++_shared</item>\n");
|
||||
QString bundledInLibs;
|
||||
QString bundledInAssets;
|
||||
foreach (Options::BundledFile bundledFile, options.bundledFiles) {
|
||||
@@ -2519,6 +2519,39 @@ bool installApk(const Options &options)
|
||||
return true;
|
||||
}
|
||||
|
||||
+bool copyStl(Options *options)
|
||||
+{
|
||||
+ if (options->deploymentMechanism == Options::Debug && !options->installApk)
|
||||
+ return true;
|
||||
+
|
||||
+ if (options->verbose)
|
||||
+ fprintf(stdout, "Copying LIBC++ STL library\n");
|
||||
+
|
||||
+ QString filePath = options->ndkPath
|
||||
+ + QLatin1String("/sources/cxx-stl/llvm-libc++")
|
||||
+ + QLatin1String("/libs/")
|
||||
+ + options->architecture
|
||||
+ + QLatin1String("/libc++_shared.so");
|
||||
+ if (!QFile::exists(filePath)) {
|
||||
+ fprintf(stderr, "LIBC STL library does not exist at %s\n", qPrintable(filePath));
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ QString destinationDirectory =
|
||||
+ options->deploymentMechanism == Options::Debug
|
||||
+ ? options->temporaryDirectoryName + QLatin1String("/lib")
|
||||
+ : options->outputDirectory + QLatin1String("/libs/") + options->architecture;
|
||||
+
|
||||
+ if (!copyFileIfNewer(filePath, destinationDirectory
|
||||
+ + QLatin1String("/libc++_shared.so"), options->verbose)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (options->deploymentMechanism == Options::Debug && !deployToLocalTmp(options, QLatin1String("/lib/libc++_shared.so")))
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
bool copyGnuStl(Options *options)
|
||||
{
|
||||
if (options->deploymentMechanism == Options::Debug && !options->installApk)
|
||||
@@ -2870,7 +2903,7 @@ int main(int argc, char *argv[])
|
||||
if (Q_UNLIKELY(options.timing))
|
||||
fprintf(stdout, "[TIMING] %d ms: Read dependencies\n", options.timer.elapsed());
|
||||
|
||||
- if (options.deploymentMechanism != Options::Ministro && !copyGnuStl(&options))
|
||||
+ if (options.deploymentMechanism != Options::Ministro && !copyStl(&options))
|
||||
return CannotCopyGnuStl;
|
||||
|
||||
if (Q_UNLIKELY(options.timing))
|
||||
121
build.sh
121
build.sh
@@ -1,121 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
BUILD_TYPE=$1
|
||||
BUILD_TREZOR=${BUILD_TREZOR-true}
|
||||
source ./utils.sh
|
||||
platform=$(get_platform)
|
||||
# default build type
|
||||
if [ -z $BUILD_TYPE ]; then
|
||||
BUILD_TYPE=release
|
||||
fi
|
||||
|
||||
# Return 0 if the command exists, 1 if it does not.
|
||||
exists() {
|
||||
command -v "$1" &>/dev/null
|
||||
}
|
||||
|
||||
# Return the first value in $@ that's a runnable command.
|
||||
find_command() {
|
||||
for arg in "$@"; do
|
||||
if exists "$arg"; then
|
||||
echo "$arg"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
if [ "$BUILD_TYPE" == "release" ]; then
|
||||
echo "Building release"
|
||||
CONFIG="CONFIG+=release";
|
||||
BIN_PATH=release/bin
|
||||
elif [ "$BUILD_TYPE" == "release-static" ]; then
|
||||
echo "Building release-static"
|
||||
if [ "$platform" != "darwin" ]; then
|
||||
CONFIG="CONFIG+=release static";
|
||||
else
|
||||
# OS X: build static libwallet but dynamic Qt.
|
||||
echo "OS X: Building Qt project without static flag"
|
||||
CONFIG="CONFIG+=release";
|
||||
fi
|
||||
BIN_PATH=release/bin
|
||||
elif [ "$BUILD_TYPE" == "release-android" ]; then
|
||||
echo "Building release for ANDROID"
|
||||
CONFIG="CONFIG+=release static WITH_SCANNER DISABLE_PASS_STRENGTH_METER";
|
||||
ANDROID=true
|
||||
BIN_PATH=release/bin
|
||||
DISABLE_PASS_STRENGTH_METER=true
|
||||
elif [ "$BUILD_TYPE" == "debug-android" ]; then
|
||||
echo "Building debug for ANDROID : ultra INSECURE !!"
|
||||
CONFIG="CONFIG+=debug qml_debug WITH_SCANNER DISABLE_PASS_STRENGTH_METER";
|
||||
ANDROID=true
|
||||
BIN_PATH=debug/bin
|
||||
DISABLE_PASS_STRENGTH_METER=true
|
||||
elif [ "$BUILD_TYPE" == "debug" ]; then
|
||||
echo "Building debug"
|
||||
CONFIG="CONFIG+=debug"
|
||||
BIN_PATH=debug/bin
|
||||
else
|
||||
echo "Valid build types are release, release-static, release-android, debug-android and debug"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
|
||||
source ./utils.sh
|
||||
pushd $(pwd)
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
MONERO_DIR=monero
|
||||
MONEROD_EXEC=monerod
|
||||
|
||||
MAKE='make'
|
||||
if [[ $platform == *bsd* ]]; then
|
||||
MAKE='gmake'
|
||||
fi
|
||||
|
||||
# build libwallet
|
||||
export BUILD_TREZOR
|
||||
./get_libwallet_api.sh $BUILD_TYPE
|
||||
|
||||
# build zxcvbn
|
||||
if [ "$DISABLE_PASS_STRENGTH_METER" != true ]; then
|
||||
$MAKE -C src/zxcvbn-c || exit
|
||||
fi
|
||||
|
||||
if [ ! -d build ]; then mkdir build; fi
|
||||
|
||||
|
||||
# Platform indepenent settings
|
||||
if [ "$ANDROID" != true ] && ([ "$platform" == "linux32" ] || [ "$platform" == "linux64" ]); then
|
||||
exists lsb_release && distro="$(lsb_release -is)"
|
||||
if [ "$distro" = "Ubuntu" ] || [ "$distro" = "Fedora" ] || test -f /etc/fedora-release; then
|
||||
CONFIG="$CONFIG libunwind_off"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$platform" == "darwin" ]; then
|
||||
BIN_PATH=$BIN_PATH/monero-wallet-gui.app/Contents/MacOS/
|
||||
elif [ "$platform" == "mingw64" ] || [ "$platform" == "mingw32" ]; then
|
||||
MONEROD_EXEC=monerod.exe
|
||||
fi
|
||||
|
||||
# force version update
|
||||
get_tag
|
||||
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
|
||||
echo "Failed to find suitable qmake command."
|
||||
exit 1
|
||||
fi
|
||||
$QMAKE ../monero-wallet-gui.pro "$CONFIG" || exit
|
||||
$MAKE || exit
|
||||
|
||||
# Copy monerod to bin folder
|
||||
if [ "$platform" != "mingw32" ] && [ "$ANDROID" != true ]; then
|
||||
cp ../$MONERO_DIR/bin/$MONEROD_EXEC $BIN_PATH
|
||||
fi
|
||||
|
||||
# make deploy
|
||||
popd
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
# from http://code.google.com/p/low-cost-vision-2012/source/browse/CMakeModules/FindZBar0.cmake?name=2-helium-1&r=d61f248bd5565b3c086bf4769a04bfd98f7079df
|
||||
# - Try to find ZBar
|
||||
# This will define
|
||||
#
|
||||
# ZBAR_FOUND -
|
||||
# ZBAR_LIBRARY_DIR -
|
||||
# ZBAR_INCLUDE_DIR -
|
||||
# ZBAR_LIBRARIES -
|
||||
#
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_ZBAR QUIET zbar)
|
||||
set(ZBAR_DEFINITIONS ${PC_ZBAR_CFLAGS_OTHER})
|
||||
find_library(ZBAR_LIBRARIES NAMES zbar
|
||||
HINTS ${PC_ZBAR_LIBDIR} ${PC_ZBAR_LIBRARY_DIRS} )
|
||||
find_path(ZBAR_INCLUDE_DIR Decoder.h
|
||||
HINTS ${PC_ZBAR_INCLUDEDIR} ${PC_ZBAR_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES zbar )
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(ZBAR DEFAULT_MSG ZBAR_LIBRARIES ZBAR_INCLUDE_DIR)
|
||||
message(STATUS "Found zbar libraries ${ZBAR_LIBRARIES}")
|
||||
|
||||
@@ -49,8 +49,14 @@ Item {
|
||||
property alias fontColor: label.color
|
||||
property bool iconOnTheLeft: true
|
||||
signal clicked()
|
||||
|
||||
height: 25
|
||||
width: checkBoxLayout.width
|
||||
opacity: enabled ? 1 : 0.7
|
||||
|
||||
Keys.onEnterPressed: toggle()
|
||||
Keys.onReturnPressed: Keys.onEnterPressed(event)
|
||||
Keys.onSpacePressed: Keys.onEnterPressed(event)
|
||||
|
||||
function toggle(){
|
||||
if (checkBox.toggleOnClick) {
|
||||
@@ -76,7 +82,7 @@ Item {
|
||||
radius: 3
|
||||
color: checkBox.enabled ? "transparent" : MoneroComponents.Style.inputBoxBackgroundDisabled
|
||||
border.color:
|
||||
if(checkBox.checked){
|
||||
if (checkBox.activeFocus) {
|
||||
return MoneroComponents.Style.inputBorderColorActive;
|
||||
} else {
|
||||
return MoneroComponents.Style.inputBorderColorInActive;
|
||||
|
||||
@@ -52,6 +52,7 @@ Window {
|
||||
// TODO: implement without hardcoding sizes
|
||||
width: 480
|
||||
height: 200
|
||||
color: MoneroComponents.Style.middlePanelBackgroundColor
|
||||
|
||||
// Make window draggable
|
||||
MouseArea {
|
||||
@@ -96,7 +97,7 @@ Window {
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
themeTransition: false
|
||||
color: "black"
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
66
components/Dialog.qml
Normal file
66
components/Dialog.qml
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2021, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import "." as MoneroComponents
|
||||
|
||||
Popup {
|
||||
id: dialog
|
||||
|
||||
default property alias content: mainLayout.children
|
||||
property alias title: header.text
|
||||
|
||||
background: Rectangle {
|
||||
border.color: MoneroComponents.Style.blackTheme ? Qt.rgba(255, 255, 255, 0.25) : Qt.rgba(0, 0, 0, 0.25)
|
||||
border.width: 1
|
||||
color: MoneroComponents.Style.blackTheme ? "black" : "white"
|
||||
radius: 10
|
||||
}
|
||||
closePolicy: Popup.CloseOnEscape
|
||||
focus: true
|
||||
padding: 20
|
||||
x: (appWindow.width - width) / 2
|
||||
y: (appWindow.height - height) / 2
|
||||
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
spacing: dialog.padding
|
||||
|
||||
Text {
|
||||
id: header
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
font.bold: true
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 18
|
||||
visible: text != ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,30 +30,25 @@ import QtQuick 2.9
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import FontAwesome 1.0
|
||||
|
||||
import "." as MoneroComponents
|
||||
import "./effects/" as MoneroEffects
|
||||
|
||||
Item {
|
||||
id: inlineButton
|
||||
height: parent.height
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
property bool small: false
|
||||
property string shadowPressedColor: "#B32D00"
|
||||
property string shadowReleasedColor: "#FF4304"
|
||||
property string pressedColor: "#FF4304"
|
||||
property string releasedColor: "#FF6C3C"
|
||||
property string icon: ""
|
||||
property string textColor: MoneroComponents.Style.inlineButtonTextColor
|
||||
property int fontSize: small ? 14 : 16
|
||||
property int rectHeight: small ? 24 : 24
|
||||
property int rectHMargin: small ? 16 : 22
|
||||
property alias text: inlineText.text
|
||||
property alias fontPixelSize: inlineText.font.pixelSize
|
||||
property alias fontFamily: inlineText.font.family
|
||||
property bool isFontAwesomeIcon: fontFamily == FontAwesome.fontFamily || fontFamily == FontAwesome.fontFamilySolid
|
||||
property alias buttonColor: rect.color
|
||||
property alias buttonHeight: rect.height
|
||||
|
||||
height: isFontAwesomeIcon ? 30 : 24
|
||||
width: isFontAwesomeIcon ? height : inlineText.width + 16
|
||||
|
||||
signal clicked()
|
||||
|
||||
function doClick() {
|
||||
@@ -64,20 +59,16 @@ Item {
|
||||
|
||||
Rectangle{
|
||||
id: rect
|
||||
anchors.fill: parent
|
||||
color: MoneroComponents.Style.buttonInlineBackgroundColor
|
||||
height: 24
|
||||
width: inlineText.text ? (inlineText.width + 16) : inlineButton.icon ? (inlineImage.width + 16) : rect.height
|
||||
radius: 4
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 4
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: inlineText
|
||||
font.family: MoneroComponents.Style.fontBold.name
|
||||
font.bold: true
|
||||
font.pixelSize: inlineButton.fontSize
|
||||
font.pixelSize: inlineButton.isFontAwesomeIcon ? 22 : inlineButton.small ? 14 : 16
|
||||
color: inlineButton.textColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -90,13 +81,6 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: inlineImage
|
||||
visible: inlineButton.icon !== ""
|
||||
anchors.centerIn: parent
|
||||
source: inlineButton.icon
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: buttonArea
|
||||
cursorShape: rect.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
|
||||
67
components/LanguageButton.qml
Normal file
67
components/LanguageButton.qml
Normal file
@@ -0,0 +1,67 @@
|
||||
// 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.Layouts 1.3
|
||||
|
||||
import FontAwesome 1.0
|
||||
|
||||
import "../components" as MoneroComponents
|
||||
|
||||
Item {
|
||||
implicitHeight: layout.height
|
||||
implicitWidth: layout.width
|
||||
|
||||
RowLayout {
|
||||
id: layout
|
||||
opacity: mouseArea.containsMouse ? 1 : 0.85
|
||||
spacing: 10
|
||||
|
||||
MoneroComponents.Label {
|
||||
Layout.bottomMargin: 5
|
||||
fontColor: MoneroComponents.Style.defaultFontColor
|
||||
fontFamily: FontAwesome.fontFamilySolid
|
||||
fontSize: 26
|
||||
styleName: "Solid"
|
||||
text: FontAwesome.language
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
font.pixelSize: 14
|
||||
text: persistentSettings.language
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
onClicked: appWindow.toggleLanguageView()
|
||||
}
|
||||
}
|
||||
@@ -131,9 +131,9 @@ Drawer {
|
||||
translationManager.setLanguage(locale_spl[0]);
|
||||
|
||||
// set wizard language settings
|
||||
wizard.language_locale = locale;
|
||||
wizard.language_wallet = wallet_language;
|
||||
wizard.language_language = display_name;
|
||||
persistentSettings.locale = locale;
|
||||
persistentSettings.language = display_name;
|
||||
persistentSettings.language_wallet = wallet_language;
|
||||
|
||||
appWindow.showStatusMessage(qsTr("Language changed."), 3);
|
||||
appWindow.toggleLanguageView();
|
||||
|
||||
@@ -29,11 +29,15 @@
|
||||
import FontAwesome 1.0
|
||||
import QtQuick 2.9
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import "../components" as MoneroComponents
|
||||
|
||||
Item {
|
||||
id: item
|
||||
|
||||
default property alias content: inlineButtons.children
|
||||
|
||||
property alias input: input
|
||||
property alias text: input.text
|
||||
|
||||
@@ -48,13 +52,20 @@ Item {
|
||||
property int placeholderFontSize: 18
|
||||
property string placeholderColor: MoneroComponents.Style.defaultFontColor
|
||||
property real placeholderOpacity: 0.35
|
||||
property real placeholderLeftMargin: {
|
||||
if (placeholderCenter) {
|
||||
return undefined;
|
||||
} else if (inlineIcon.visible) {
|
||||
return inlineIcon.width + inlineIcon.anchors.leftMargin + inputPadding;
|
||||
} else {
|
||||
return inputPadding;
|
||||
}
|
||||
}
|
||||
|
||||
property alias acceptableInput: input.acceptableInput
|
||||
property alias validator: input.validator
|
||||
property alias readOnly : input.readOnly
|
||||
property alias cursorPosition: input.cursorPosition
|
||||
property alias inlineButton: inlineButtonId
|
||||
property alias inlineButtonText: inlineButtonId.text
|
||||
property alias inlineIcon: inlineIcon.visible
|
||||
property bool copyButton: false
|
||||
property alias copyButtonText: copyButtonId.text
|
||||
@@ -71,6 +82,7 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
property string fontFamily: MoneroComponents.Style.fontRegular.name
|
||||
property int fontSize: 18
|
||||
property bool fontBold: false
|
||||
property alias fontColor: input.color
|
||||
@@ -86,14 +98,16 @@ Item {
|
||||
property alias labelHorizontalAlignment: inputLabel.horizontalAlignment
|
||||
property bool showingHeader: inputLabel.text !== "" || copyButton
|
||||
property int inputHeight: 42
|
||||
property int inputPadding: 10
|
||||
|
||||
signal labelLinkActivated(); // input label, rich text <a> signal
|
||||
signal editingFinished();
|
||||
signal accepted();
|
||||
signal textUpdated();
|
||||
|
||||
height: showingHeader ? (inputLabel.height + inputItem.height + 2) : 42
|
||||
height: showingHeader ? (inputLabel.height + inputItem.height + 2) : inputHeight
|
||||
|
||||
onActiveFocusChanged: activeFocus && input.forceActiveFocus()
|
||||
onTextUpdated: {
|
||||
// check to remove placeholder text when there is content
|
||||
if(item.isEmpty()){
|
||||
@@ -174,7 +188,7 @@ Item {
|
||||
id: inputItem
|
||||
height: inputHeight
|
||||
anchors.top: showingHeader ? inputLabel.bottom : parent.top
|
||||
anchors.topMargin: showingHeader ? 12 : 2
|
||||
anchors.topMargin: showingHeader ? 12 : 0
|
||||
width: parent.width
|
||||
clip: true
|
||||
|
||||
@@ -184,13 +198,7 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: placeholderCenter ? parent.horizontalCenter : undefined
|
||||
anchors.left: placeholderCenter ? undefined : parent.left
|
||||
anchors.leftMargin: {
|
||||
if(placeholderCenter){
|
||||
return undefined;
|
||||
}
|
||||
else if(inlineIcon.visible){ return 50; }
|
||||
else { return 10; }
|
||||
}
|
||||
anchors.leftMargin: placeholderLeftMargin
|
||||
|
||||
opacity: item.placeholderOpacity
|
||||
color: item.placeholderColor
|
||||
@@ -232,13 +240,18 @@ Item {
|
||||
id: input
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: inlineIcon.visible ? 44 : 0
|
||||
font.family: item.fontFamily
|
||||
font.pixelSize: item.fontSize
|
||||
font.bold: item.fontBold
|
||||
KeyNavigation.backtab: item.KeyNavigation.backtab
|
||||
KeyNavigation.tab: item.KeyNavigation.tab
|
||||
onEditingFinished: item.editingFinished()
|
||||
onAccepted: item.accepted();
|
||||
onTextChanged: item.textUpdated()
|
||||
topPadding: 10
|
||||
bottomPadding: 10
|
||||
leftPadding: inputPadding
|
||||
rightPadding: (inlineButtons.width > 0 ? inlineButtons.width + inlineButtons.spacing : 0) + inputPadding
|
||||
topPadding: inputPadding
|
||||
bottomPadding: inputPadding
|
||||
echoMode: isPasswordHidden() ? TextInput.Password : TextInput.Normal
|
||||
|
||||
MoneroComponents.Label {
|
||||
@@ -260,13 +273,17 @@ Item {
|
||||
onClicked: passwordToggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.InlineButton {
|
||||
id: inlineButtonId
|
||||
visible: item.inlineButtonText ? true : false
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 8
|
||||
RowLayout {
|
||||
id: inlineButtons
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: inputPadding
|
||||
anchors.bottomMargin: inputPadding
|
||||
anchors.rightMargin: inputPadding
|
||||
spacing: 4
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ ColumnLayout {
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
default property alias content: inlineButtons.children
|
||||
|
||||
property alias text: input.text
|
||||
property alias labelText: inputLabel.text
|
||||
property alias labelButtonText: labelButton.text
|
||||
@@ -73,6 +75,7 @@ ColumnLayout {
|
||||
property bool labelButtonVisible: false
|
||||
|
||||
property string fontColor: MoneroComponents.Style.defaultFontColor
|
||||
property string fontFamily: MoneroComponents.Style.fontRegular.name
|
||||
property bool fontBold: false
|
||||
property int fontSize: 16
|
||||
|
||||
@@ -85,15 +88,12 @@ ColumnLayout {
|
||||
property alias addressValidation: input.addressValidation
|
||||
property string backgroundColor: "" // mock
|
||||
|
||||
property alias inlineButton: inlineButtonId
|
||||
property bool inlineButtonVisible: false
|
||||
property alias inlineButton2: inlineButton2Id
|
||||
property bool inlineButton2Visible: false
|
||||
|
||||
signal labelButtonClicked();
|
||||
signal inputLabelLinkActivated();
|
||||
signal editingFinished();
|
||||
|
||||
onActiveFocusChanged: activeFocus && input.forceActiveFocus()
|
||||
|
||||
spacing: 0
|
||||
Rectangle {
|
||||
id: inputLabelRect
|
||||
@@ -159,14 +159,18 @@ ColumnLayout {
|
||||
id: input
|
||||
readOnly: false
|
||||
addressValidation: false
|
||||
KeyNavigation.backtab: item.KeyNavigation.backtab
|
||||
KeyNavigation.priority: KeyNavigation.BeforeItem
|
||||
KeyNavigation.tab: item.KeyNavigation.tab
|
||||
Layout.fillWidth: true
|
||||
|
||||
|
||||
leftPadding: item.inputPaddingLeft
|
||||
rightPadding: item.inputPaddingRight
|
||||
rightPadding: (inlineButtons.width > 0 ? inlineButtons.width + inlineButtons.spacing : 0) + inputPaddingRight
|
||||
topPadding: item.inputPaddingTop
|
||||
bottomPadding: item.inputPaddingBottom
|
||||
|
||||
wrapMode: item.wrapMode
|
||||
font.family: item.fontFamily
|
||||
fontSize: item.fontSize
|
||||
fontBold: item.fontBold
|
||||
fontColor: item.fontColor
|
||||
@@ -198,18 +202,12 @@ ColumnLayout {
|
||||
visible: !item.borderDisabled
|
||||
}
|
||||
|
||||
MoneroComponents.InlineButton {
|
||||
id: inlineButtonId
|
||||
visible: (inlineButtonId.text || inlineButtonId.icon) && inlineButtonVisible ? true : false
|
||||
RowLayout {
|
||||
id: inlineButtons
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 8
|
||||
}
|
||||
|
||||
MoneroComponents.InlineButton {
|
||||
id: inlineButton2Id
|
||||
visible: (inlineButton2Id.text || inlineButton2Id.icon) && inlineButton2Visible ? true : false
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: inlineButtonVisible ? 48 : 8
|
||||
anchors.rightMargin: inputPaddingRight
|
||||
spacing: 4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
207
components/Navbar.qml
Normal file
207
components/Navbar.qml
Normal file
@@ -0,0 +1,207 @@
|
||||
// Copyright (c) 2014-2021, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Layouts 1.1
|
||||
import "." as MoneroComponents
|
||||
|
||||
Rectangle {
|
||||
default property list<MoneroComponents.NavbarItem> items
|
||||
|
||||
color: "transparent"
|
||||
height: grid.height
|
||||
width: grid.width
|
||||
|
||||
GridLayout {
|
||||
id: grid
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
columnSpacing: 0
|
||||
property string fontColorActive: MoneroComponents.Style.blackTheme ? "white" : "white"
|
||||
property string fontColorInActive: MoneroComponents.Style.blackTheme ? "white" : MoneroComponents.Style.dimmedFontColor
|
||||
property int fontSize: 15
|
||||
property bool fontBold: true
|
||||
property var fontFamily: MoneroComponents.Style.fontRegular.name
|
||||
property string borderColor: MoneroComponents.Style.blackTheme ? "#808080" : "#B9B9B9"
|
||||
property int textMargin: {
|
||||
// left-right margins for a given cell
|
||||
if(appWindow.width < 890){
|
||||
return 32;
|
||||
} else {
|
||||
return 64;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
// navbar left side border
|
||||
id: navBarLeft
|
||||
Layout.preferredWidth: 2
|
||||
Layout.preferredHeight: 32
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 1
|
||||
height: parent.height - 2
|
||||
color: grid.borderColor
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
width: 1
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredHeight: 1
|
||||
Layout.preferredWidth: 1
|
||||
color: grid.borderColor
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillHeight: true
|
||||
width: 1
|
||||
color: items.length > 0 && items[0].active ? grid.borderColor : "transparent";
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.preferredWidth: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: items.length
|
||||
|
||||
RowLayout {
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredWidth: 1
|
||||
Layout.preferredHeight: 32
|
||||
color: grid.borderColor
|
||||
visible: index > 0 && items[index - 1].visible
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.minimumWidth: 72
|
||||
Layout.preferredHeight: 32
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
visible: items[index].visible
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.minimumHeight: 30
|
||||
color: items[index].active ? grid.borderColor : "transparent"
|
||||
height: children[0].height
|
||||
width: children[0].width
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.family: grid.fontFamily
|
||||
font.pixelSize: grid.fontSize
|
||||
font.bold: grid.fontBold
|
||||
leftPadding: grid.textMargin / 2
|
||||
rightPadding: grid.textMargin / 2
|
||||
text: items[index].text
|
||||
color: items[index].active ? grid.fontColorActive : grid.fontColorInActive
|
||||
themeTransition: false
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: items[index].selected()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
// navbar right side border
|
||||
id: navBarRight
|
||||
Layout.preferredWidth: 2
|
||||
Layout.preferredHeight: 32
|
||||
color: "transparent"
|
||||
rotation: 180
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 1
|
||||
height: parent.height - 2
|
||||
color: grid.borderColor
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
width: 1
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredHeight: 1
|
||||
Layout.preferredWidth: 1
|
||||
color: grid.borderColor
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillHeight: true
|
||||
width: 1
|
||||
color: items.length > 0 && items[items.length - 1].active ? grid.borderColor : "transparent"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.preferredWidth: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
components/NavbarItem.qml
Normal file
37
components/NavbarItem.qml
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2021, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
QtObject {
|
||||
property bool active: false
|
||||
property string text
|
||||
property bool visible: true
|
||||
|
||||
signal selected()
|
||||
}
|
||||
153
components/RemoteNodeDialog.qml
Normal file
153
components/RemoteNodeDialog.qml
Normal file
@@ -0,0 +1,153 @@
|
||||
// Copyright (c) 2021, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import "." as MoneroComponents
|
||||
|
||||
MoneroComponents.Dialog {
|
||||
id: root
|
||||
title: (editMode ? qsTr("Edit remote node") : qsTr("Add remote node")) + translationManager.emptyString
|
||||
|
||||
property var callbackOnSuccess: null
|
||||
property bool editMode: false
|
||||
property bool success: false
|
||||
|
||||
onActiveFocusChanged: activeFocus && remoteNodeAddress.forceActiveFocus()
|
||||
|
||||
function add(callbackOnSuccess) {
|
||||
root.editMode = false;
|
||||
root.callbackOnSuccess = callbackOnSuccess;
|
||||
|
||||
open();
|
||||
}
|
||||
|
||||
function edit(remoteNode, callbackOnSuccess) {
|
||||
const hostPort = remoteNode.address.match(/^(.*?)(?:\:?(\d*))$/);
|
||||
if (hostPort) {
|
||||
remoteNodeAddress.daemonAddrText = hostPort[1];
|
||||
remoteNodeAddress.daemonPortText = hostPort[2];
|
||||
}
|
||||
daemonUsername.text = remoteNode.username;
|
||||
daemonPassword.text = remoteNode.password;
|
||||
setTrustedDaemonCheckBox.checked = remoteNode.trusted;
|
||||
root.callbackOnSuccess = callbackOnSuccess;
|
||||
root.editMode = true;
|
||||
|
||||
open();
|
||||
}
|
||||
|
||||
onClosed: {
|
||||
if (root.success && callbackOnSuccess) {
|
||||
callbackOnSuccess({
|
||||
address: remoteNodeAddress.getAddress(),
|
||||
username: daemonUsername.text,
|
||||
password: daemonPassword.text,
|
||||
trusted: setTrustedDaemonCheckBox.checked,
|
||||
});
|
||||
}
|
||||
|
||||
remoteNodeAddress.daemonAddrText = "";
|
||||
remoteNodeAddress.daemonPortText = "";
|
||||
daemonUsername.text = "";
|
||||
daemonPassword.text = "";
|
||||
setTrustedDaemonCheckBox.checked = false;
|
||||
root.success = false;
|
||||
}
|
||||
|
||||
MoneroComponents.RemoteNodeEdit {
|
||||
id: remoteNodeAddress
|
||||
Layout.fillWidth: true
|
||||
placeholderFontSize: 15
|
||||
|
||||
daemonAddrLabelText: qsTr("Address") + translationManager.emptyString
|
||||
daemonPortLabelText: qsTr("Port") + translationManager.emptyString
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 32
|
||||
|
||||
MoneroComponents.LineEdit {
|
||||
id: daemonUsername
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumWidth: 220
|
||||
labelText: qsTr("Daemon username") + translationManager.emptyString
|
||||
placeholderText: qsTr("(optional)") + translationManager.emptyString
|
||||
placeholderFontSize: 15
|
||||
labelFontSize: 14
|
||||
fontSize: 15
|
||||
}
|
||||
|
||||
MoneroComponents.LineEdit {
|
||||
id: daemonPassword
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumWidth: 220
|
||||
labelText: qsTr("Daemon password") + translationManager.emptyString
|
||||
placeholderText: qsTr("Password") + translationManager.emptyString
|
||||
password: true
|
||||
placeholderFontSize: 15
|
||||
labelFontSize: 14
|
||||
fontSize: 15
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.CheckBox {
|
||||
id: setTrustedDaemonCheckBox
|
||||
activeFocusOnTab: true
|
||||
text: qsTr("Mark as Trusted Daemon") + translationManager.emptyString
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
spacing: parent.spacing
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
activeFocusOnTab: true
|
||||
fontBold: false
|
||||
primary: false
|
||||
text: qsTr("Cancel") + translationManager.emptyString
|
||||
|
||||
onClicked: root.close()
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
activeFocusOnTab: true
|
||||
fontBold: false
|
||||
enabled: remoteNodeAddress.getAddress() != ""
|
||||
text: qsTr("Ok") + translationManager.emptyString
|
||||
|
||||
onClicked: {
|
||||
root.success = true;
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,6 @@ GridLayout {
|
||||
property int labelFontSize: 14
|
||||
|
||||
property string lineEditBackgroundColor: "transparent"
|
||||
property string lineEditBorderColor: MoneroComponents.Style.inputBorderColorInActive
|
||||
property string lineEditFontColor: MoneroComponents.Style.defaultFontColor
|
||||
property bool lineEditFontBold: false
|
||||
property int lineEditFontSize: 15
|
||||
@@ -67,6 +66,8 @@ GridLayout {
|
||||
signal editingFinished()
|
||||
signal textChanged()
|
||||
|
||||
onActiveFocusChanged: activeFocus && daemonAddr.forceActiveFocus()
|
||||
|
||||
function isValid() {
|
||||
return daemonAddr.text.trim().length > 0 && daemonPort.acceptableInput
|
||||
}
|
||||
@@ -92,7 +93,6 @@ GridLayout {
|
||||
placeholderColor: root.placeholderColor
|
||||
placeholderOpacity: root.placeholderOpacity
|
||||
labelFontSize: root.labelFontSize
|
||||
borderColor: lineEditBorderColor
|
||||
backgroundColor: lineEditBackgroundColor
|
||||
fontColor: lineEditFontColor
|
||||
fontBold: lineEditFontBold
|
||||
@@ -115,7 +115,6 @@ GridLayout {
|
||||
placeholderColor: root.placeholderColor
|
||||
placeholderOpacity: root.placeholderOpacity
|
||||
labelFontSize: root.labelFontSize
|
||||
borderColor: lineEditBorderColor
|
||||
backgroundColor: lineEditBackgroundColor
|
||||
fontColor: lineEditFontColor
|
||||
fontBold: lineEditFontBold
|
||||
|
||||
@@ -68,7 +68,7 @@ Item {
|
||||
id: buttonRect
|
||||
anchors.fill: parent
|
||||
radius: 3
|
||||
border.width: parent.focus ? 1 : 0
|
||||
border.width: parent.focus && parent.enabled ? 1 : 0
|
||||
|
||||
state: button.enabled ? "active" : "disabled"
|
||||
Component.onCompleted: state = state
|
||||
@@ -76,7 +76,7 @@ Item {
|
||||
states: [
|
||||
State {
|
||||
name: "hover"
|
||||
when: buttonArea.containsMouse || button.focus
|
||||
when: button.enabled && (buttonArea.containsMouse || button.focus)
|
||||
PropertyChanges {
|
||||
target: buttonRect
|
||||
color: primary
|
||||
|
||||
@@ -45,20 +45,11 @@ Rectangle {
|
||||
radius: 10
|
||||
border.color: MoneroComponents.Style.blackTheme ? Qt.rgba(255, 255, 255, 0.25) : Qt.rgba(0, 0, 0, 0.25)
|
||||
border.width: 1
|
||||
focus: true
|
||||
Keys.enabled: true
|
||||
Keys.onEscapePressed: {
|
||||
root.close()
|
||||
root.rejected()
|
||||
}
|
||||
Keys.onEnterPressed: {
|
||||
root.close()
|
||||
root.accepted()
|
||||
}
|
||||
Keys.onReturnPressed: {
|
||||
root.close()
|
||||
root.accepted()
|
||||
}
|
||||
KeyNavigation.tab: doneButton
|
||||
|
||||
Clipboard { id: clipboard }
|
||||
@@ -72,7 +63,6 @@ Rectangle {
|
||||
function open(txid) {
|
||||
root.transactionID = txid;
|
||||
root.visible = true;
|
||||
root.forceActiveFocus();
|
||||
}
|
||||
|
||||
function close() {
|
||||
@@ -156,13 +146,6 @@ Rectangle {
|
||||
text: qsTr("Open folder") + translationManager.emptyString;
|
||||
width: 200
|
||||
KeyNavigation.tab: doneButton
|
||||
Keys.enabled: openFolderButton.visible
|
||||
Keys.onReturnPressed: openFolderButton.onClicked
|
||||
Keys.onEnterPressed: openFolderButton.onClicked
|
||||
Keys.onEscapePressed: {
|
||||
root.close()
|
||||
root.rejected()
|
||||
}
|
||||
onClicked: {
|
||||
oshelper.openContainingFolder(walletManager.urlToLocalPath(saveTxDialog.fileUrl))
|
||||
}
|
||||
@@ -172,15 +155,8 @@ Rectangle {
|
||||
id: doneButton
|
||||
text: qsTr("Done") + translationManager.emptyString;
|
||||
width: 200
|
||||
focus: true
|
||||
focus: root.visible
|
||||
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()
|
||||
|
||||
440
components/TxConfirmationDialog.qml
Normal file
440
components/TxConfirmationDialog.qml
Normal file
@@ -0,0 +1,440 @@
|
||||
// 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 1.4 as QtQuickControls1
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import "../components" as MoneroComponents
|
||||
import FontAwesome 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property int margins: 25
|
||||
|
||||
x: parent.width/2 - root.width/2
|
||||
y: parent.height/2 - root.height/2
|
||||
// TODO: implement without hardcoding sizes
|
||||
width: 590
|
||||
height: layout.height + layout.anchors.margins * 2
|
||||
color: MoneroComponents.Style.blackTheme ? "black" : "white"
|
||||
visible: false
|
||||
radius: 10
|
||||
border.color: MoneroComponents.Style.blackTheme ? Qt.rgba(255, 255, 255, 0.25) : Qt.rgba(0, 0, 0, 0.25)
|
||||
border.width: 1
|
||||
Keys.enabled: true
|
||||
Keys.onEscapePressed: {
|
||||
root.close()
|
||||
root.clearFields()
|
||||
root.rejected()
|
||||
}
|
||||
KeyNavigation.tab: confirmButton
|
||||
|
||||
property var recipients: []
|
||||
property var transactionAmount: ""
|
||||
property var transactionDescription: ""
|
||||
property var transactionFee: ""
|
||||
property var transactionPriority: ""
|
||||
property bool sweepUnmixable: false
|
||||
property alias errorText: errorText
|
||||
property alias confirmButton: confirmButton
|
||||
property alias backButton: backButton
|
||||
property alias bottomText: bottomText
|
||||
property alias bottomTextAnimation: bottomTextAnimation
|
||||
|
||||
state: "default"
|
||||
states: [
|
||||
State {
|
||||
// waiting for user action, show tx details + back and confirm buttons
|
||||
name: "default";
|
||||
when: errorText.text == "" && bottomText.text == ""
|
||||
PropertyChanges { target: errorText; visible: false }
|
||||
PropertyChanges { target: txAmountText; visible: root.transactionAmount !== "(all)" || (root.transactionAmount === "(all)" && currentWallet.isHwBacked() === true) }
|
||||
PropertyChanges { target: txAmountBusyIndicator; visible: !txAmountText.visible }
|
||||
PropertyChanges { target: txFiatAmountText; visible: txAmountText.visible && persistentSettings.fiatPriceEnabled && root.transactionAmount !== "(all)" }
|
||||
PropertyChanges { target: txDetails; visible: true }
|
||||
PropertyChanges { target: bottom; visible: true }
|
||||
PropertyChanges { target: bottomMessage; visible: false }
|
||||
PropertyChanges { target: buttons; visible: true }
|
||||
PropertyChanges { target: backButton; visible: true; primary: false }
|
||||
PropertyChanges { target: confirmButton; visible: true; focus: true }
|
||||
}, State {
|
||||
// error message being displayed, show only back button
|
||||
name: "error";
|
||||
when: errorText.text !== ""
|
||||
PropertyChanges { target: dialogTitle; text: "Error" }
|
||||
PropertyChanges { target: errorText; visible: true }
|
||||
PropertyChanges { target: txAmountText; visible: false }
|
||||
PropertyChanges { target: txAmountBusyIndicator; visible: false }
|
||||
PropertyChanges { target: txFiatAmountText; visible: false }
|
||||
PropertyChanges { target: txDetails; visible: false }
|
||||
PropertyChanges { target: bottom; visible: true }
|
||||
PropertyChanges { target: bottomMessage; visible: false }
|
||||
PropertyChanges { target: buttons; visible: true }
|
||||
PropertyChanges { target: backButton; visible: true; primary: true; focus: true }
|
||||
PropertyChanges { target: confirmButton; visible: false }
|
||||
}, State {
|
||||
// creating or sending transaction, show tx details and don't show any button
|
||||
name: "bottomText";
|
||||
when: errorText.text == "" && bottomText.text !== ""
|
||||
PropertyChanges { target: errorText; visible: false }
|
||||
PropertyChanges { target: txAmountText; visible: root.transactionAmount !== "(all)" || (root.transactionAmount === "(all)" && currentWallet.isHwBacked() === true) }
|
||||
PropertyChanges { target: txAmountBusyIndicator; visible: !txAmountText.visible }
|
||||
PropertyChanges { target: txFiatAmountText; visible: txAmountText.visible && persistentSettings.fiatPriceEnabled && root.transactionAmount !== "(all)" }
|
||||
PropertyChanges { target: txDetails; visible: true }
|
||||
PropertyChanges { target: bottom; visible: true }
|
||||
PropertyChanges { target: bottomMessage; visible: true }
|
||||
PropertyChanges { target: buttons; visible: false }
|
||||
}
|
||||
]
|
||||
|
||||
// same signals as Dialog has
|
||||
signal accepted()
|
||||
signal rejected()
|
||||
|
||||
function open() {
|
||||
root.visible = true;
|
||||
|
||||
//clean previous error message
|
||||
errorText.text = "";
|
||||
}
|
||||
|
||||
function close() {
|
||||
root.visible = false;
|
||||
}
|
||||
|
||||
function clearFields() {
|
||||
root.recipients = [];
|
||||
root.transactionAmount = "";
|
||||
root.transactionDescription = "";
|
||||
root.transactionFee = "";
|
||||
root.transactionPriority = "";
|
||||
root.sweepUnmixable = false;
|
||||
}
|
||||
|
||||
function showFiatConversion(valueXMR) {
|
||||
const fiatFee = fiatApiConvertToFiat(valueXMR);
|
||||
return "%1 %2".arg(fiatFee < 0.01 ? "<0.01" : "~" + fiatFee).arg(fiatApiCurrencySymbol());
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: parent.margins
|
||||
spacing: 10
|
||||
|
||||
RowLayout {
|
||||
Layout.topMargin: 10
|
||||
Layout.fillWidth: true
|
||||
|
||||
MoneroComponents.Label {
|
||||
id: dialogTitle
|
||||
Layout.fillWidth: true
|
||||
fontSize: 18
|
||||
fontFamily: "Arial"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: {
|
||||
if (appWindow.viewOnly) {
|
||||
return qsTr("Create transaction file") + translationManager.emptyString;
|
||||
} else if (root.sweepUnmixable) {
|
||||
return qsTr("Sweep unmixable outputs") + translationManager.emptyString;
|
||||
} else {
|
||||
return qsTr("Confirm send") + translationManager.emptyString;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: errorText
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
wrapMode: Text.Wrap
|
||||
font.pixelSize: 15
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 71
|
||||
|
||||
QtQuickControls1.BusyIndicator {
|
||||
id: txAmountBusyIndicator
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
running: root.transactionAmount == "(all)"
|
||||
}
|
||||
|
||||
Text {
|
||||
id: txAmountText
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pixelSize: root.transactionAmount == "(all)" && currentWallet.isHwBacked() === true ? 32 : 42
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
text: {
|
||||
if (root.transactionAmount == "(all)" && currentWallet.isHwBacked() === true) {
|
||||
return qsTr("All unlocked balance") + translationManager.emptyString;
|
||||
} else {
|
||||
return root.transactionAmount + " XMR " + translationManager.emptyString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: txFiatAmountText
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pixelSize: 20
|
||||
color: MoneroComponents.Style.buttonSecondaryTextColor
|
||||
text: showFiatConversion(transactionAmount) + translationManager.emptyString
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
columns: 2
|
||||
id: txDetails
|
||||
Layout.fillWidth: true
|
||||
columnSpacing: 15
|
||||
rowSpacing: 16
|
||||
|
||||
Text {
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
text: qsTr("From") + ":" + translationManager.emptyString
|
||||
font.pixelSize: 15
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
font.pixelSize: 15
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
text: {
|
||||
if (currentWallet) {
|
||||
var walletTitle = function() {
|
||||
if (currentWallet.isLedger()) {
|
||||
return "Ledger";
|
||||
} else if (currentWallet.isTrezor()) {
|
||||
return "Trezor";
|
||||
} else {
|
||||
return qsTr("My wallet");
|
||||
}
|
||||
}
|
||||
var walletName = appWindow.walletName;
|
||||
if (appWindow.currentWallet.numSubaddressAccounts() > 1) {
|
||||
var currentSubaddressAccount = currentWallet.currentSubaddressAccount;
|
||||
var currentAccountLabel = currentWallet.getSubaddressLabel(currentWallet.currentSubaddressAccount, 0);
|
||||
return walletTitle() + " (" + walletName + ")" + "<br>" + qsTr("Account #") + currentSubaddressAccount + (currentAccountLabel !== "" ? " (" + currentAccountLabel + ")" : "") + translationManager.emptyString;
|
||||
} else {
|
||||
return walletTitle() + " (" + walletName + ")" + translationManager.emptyString;
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
font.pixelSize: 15
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
text: qsTr("To") + ":" + translationManager.emptyString
|
||||
}
|
||||
|
||||
Flickable {
|
||||
id: flickable
|
||||
property int linesInMultipleRecipientsMode: 7
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: recipients.length > 1
|
||||
? linesInMultipleRecipientsMode * (recipientsArea.contentHeight / recipientsArea.lineCount)
|
||||
: recipientsArea.contentHeight
|
||||
boundsBehavior: isMac ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
|
||||
clip: true
|
||||
|
||||
TextArea.flickable: TextArea {
|
||||
id : recipientsArea
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
font.family: MoneroComponents.Style.fontMonoRegular.name
|
||||
font.pixelSize: 14
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
leftPadding: 0
|
||||
textMargin: 0
|
||||
readOnly: true
|
||||
selectByKeyboard: true
|
||||
selectByMouse: true
|
||||
selectionColor: MoneroComponents.Style.textSelectionColor
|
||||
textFormat: TextEdit.RichText
|
||||
wrapMode: TextEdit.Wrap
|
||||
text: {
|
||||
return recipients.map(function (recipient, index) {
|
||||
var addressBookName = null;
|
||||
if (currentWallet) {
|
||||
addressBookName = currentWallet.addressBook.getDescription(recipient.address);
|
||||
}
|
||||
var title;
|
||||
if (addressBookName) {
|
||||
title = FontAwesome.addressBook + " " + addressBookName;
|
||||
} else {
|
||||
title = qsTr("Monero address") + translationManager.emptyString;
|
||||
}
|
||||
if (recipients.length > 1) {
|
||||
title = "%1. %2 - %3 XMR".arg(index + 1).arg(title).arg(recipient.amount);
|
||||
if (persistentSettings.fiatPriceEnabled) {
|
||||
title += " (%1)".arg(showFiatConversion(recipient.amount));
|
||||
}
|
||||
}
|
||||
const spacedaddress = recipient.address.match(/.{1,4}/g).join(' ');
|
||||
return title + "<br>" + spacedaddress;
|
||||
}).join("<br><br>");
|
||||
}
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: recipientsArea.contentHeight > flickable.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
text: qsTr("Fee") + ":" + translationManager.emptyString
|
||||
font.pixelSize: 15
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
|
||||
Text {
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
font.pixelSize: 15
|
||||
text: {
|
||||
if (currentWallet) {
|
||||
if (!root.transactionFee) {
|
||||
if (currentWallet.isHwBacked() === true) {
|
||||
return qsTr("See on device") + translationManager.emptyString;
|
||||
} else {
|
||||
return qsTr("Calculating fee") + "..." + translationManager.emptyString;
|
||||
}
|
||||
} else {
|
||||
return root.transactionFee + " XMR"
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 8
|
||||
color: MoneroComponents.Style.buttonSecondaryTextColor
|
||||
visible: persistentSettings.fiatPriceEnabled && root.transactionFee
|
||||
font.pixelSize: 15
|
||||
text: showFiatConversion(root.transactionFee)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: bottom
|
||||
Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
|
||||
RowLayout {
|
||||
id: bottomMessage
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 50
|
||||
|
||||
QtQuickControls1.BusyIndicator {
|
||||
visible: !bottomTextAnimation.running
|
||||
running: !bottomTextAnimation.running
|
||||
scale: .5
|
||||
}
|
||||
|
||||
Text {
|
||||
id: bottomText
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
text: ""
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
font.pixelSize: 17
|
||||
opacity: 1
|
||||
|
||||
SequentialAnimation{
|
||||
id:bottomTextAnimation
|
||||
running: false
|
||||
loops: Animation.Infinite
|
||||
alwaysRunToEnd: true
|
||||
NumberAnimation { target: bottomText; property: "opacity"; to: 0; duration: 500}
|
||||
NumberAnimation { target: bottomText; property: "opacity"; to: 1; duration: 500}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: buttons
|
||||
spacing: 70
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 50
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
id: backButton
|
||||
text: qsTr("Back") + translationManager.emptyString;
|
||||
width: 200
|
||||
primary: false
|
||||
KeyNavigation.tab: confirmButton
|
||||
onClicked: {
|
||||
root.close()
|
||||
root.clearFields()
|
||||
root.rejected()
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
id: confirmButton
|
||||
text: qsTr("Confirm") + translationManager.emptyString;
|
||||
rightIcon: "qrc:///images/rightArrow.png"
|
||||
width: 200
|
||||
KeyNavigation.tab: backButton
|
||||
onClicked: {
|
||||
root.close()
|
||||
root.accepted()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
android-no-sdk {
|
||||
target.path = /data/user/qt
|
||||
export(target.path)
|
||||
INSTALLS += target
|
||||
} else:android {
|
||||
x86 {
|
||||
target.path = /libs/x86
|
||||
} else: armeabi-v7a {
|
||||
target.path = /libs/armeabi-v7a
|
||||
} else {
|
||||
target.path = /libs/armeabi
|
||||
}
|
||||
export(target.path)
|
||||
INSTALLS += target
|
||||
} else:unix {
|
||||
isEmpty(target.path) {
|
||||
qnx {
|
||||
target.path = /tmp/$${TARGET}/bin
|
||||
} else {
|
||||
target.path = /opt/$${TARGET}/bin
|
||||
}
|
||||
export(target.path)
|
||||
}
|
||||
INSTALLS += target
|
||||
}
|
||||
|
||||
export(INSTALLS)
|
||||
7
external/CMakeLists.txt
vendored
Normal file
7
external/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
add_library(quirc STATIC
|
||||
quirc/lib/decode.c
|
||||
quirc/lib/identify.c
|
||||
quirc/lib/quirc.c
|
||||
quirc/lib/version_db.c
|
||||
)
|
||||
target_include_directories(quirc PUBLIC quirc/lib)
|
||||
1
external/quirc
vendored
Submodule
1
external/quirc
vendored
Submodule
Submodule external/quirc added at 7e7ab596e4
@@ -403,6 +403,7 @@ Object {
|
||||
property string inbox : "\uf01c"
|
||||
property string indent : "\uf03c"
|
||||
property string industry : "\uf275"
|
||||
property string infinity : "\uf534"
|
||||
property string info : "\uf129"
|
||||
property string infoCircle : "\uf05a"
|
||||
property string inr : "\uf156"
|
||||
|
||||
@@ -1,286 +0,0 @@
|
||||
#!/bin/bash
|
||||
MONERO_URL=https://github.com/monero-project/monero.git
|
||||
MONERO_BRANCH=master
|
||||
|
||||
pushd $(pwd)
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
source $ROOT_DIR/utils.sh
|
||||
|
||||
INSTALL_DIR=$ROOT_DIR/wallet
|
||||
MONERO_DIR=$ROOT_DIR/monero
|
||||
BUILD_LIBWALLET=false
|
||||
|
||||
# init and update monero submodule
|
||||
if [ ! -d $MONERO_DIR/src ]; then
|
||||
git submodule init monero
|
||||
fi
|
||||
git submodule update --remote
|
||||
git -C $MONERO_DIR fetch
|
||||
git -C $MONERO_DIR checkout v0.17.1.1
|
||||
|
||||
# get monero core tag
|
||||
pushd $MONERO_DIR
|
||||
get_tag
|
||||
popd
|
||||
# create local monero branch
|
||||
git -C $MONERO_DIR checkout -B $VERSIONTAG
|
||||
|
||||
# Merge monero PR dependencies
|
||||
|
||||
# Workaround for git username requirements
|
||||
# Save current user settings and revert back when we are done with merging PR's
|
||||
OLD_GIT_USER=$(git -C $MONERO_DIR config --local user.name)
|
||||
OLD_GIT_EMAIL=$(git -C $MONERO_DIR config --local user.email)
|
||||
git -C $MONERO_DIR config user.name "Monero GUI"
|
||||
git -C $MONERO_DIR config user.email "gui@monero.local"
|
||||
# check for PR requirements in most recent commit message (i.e requires #xxxx)
|
||||
for PR in $(git log --format=%B -n 1 | grep -io "requires #[0-9]*" | sed 's/[^0-9]*//g'); do
|
||||
echo "Merging monero push request #$PR"
|
||||
# fetch pull request and merge
|
||||
git -C $MONERO_DIR fetch origin pull/$PR/head:PR-$PR
|
||||
git -C $MONERO_DIR merge --quiet PR-$PR -m "Merge monero PR #$PR"
|
||||
BUILD_LIBWALLET=true
|
||||
done
|
||||
|
||||
# revert back to old git config
|
||||
$(git -C $MONERO_DIR config user.name "$OLD_GIT_USER")
|
||||
$(git -C $MONERO_DIR config user.email "$OLD_GIT_EMAIL")
|
||||
|
||||
git -C $MONERO_DIR submodule init
|
||||
git -C $MONERO_DIR submodule update
|
||||
|
||||
# Build libwallet if it doesnt exist
|
||||
if [ ! -f $MONERO_DIR/lib/libwallet_merged.a ]; then
|
||||
echo "libwallet_merged.a not found - Building libwallet"
|
||||
BUILD_LIBWALLET=true
|
||||
# Build libwallet if no previous version file exists
|
||||
elif [ ! -f $MONERO_DIR/version.sh ]; then
|
||||
echo "monero/version.h not found - Building libwallet"
|
||||
BUILD_LIBWALLET=true
|
||||
## Compare previously built version with submodule + merged PR's version.
|
||||
else
|
||||
source $MONERO_DIR/version.sh
|
||||
# compare submodule version with latest build
|
||||
pushd "$MONERO_DIR"
|
||||
get_tag
|
||||
popd
|
||||
echo "latest libwallet version: $GUI_MONERO_VERSION"
|
||||
echo "Installed libwallet version: $VERSIONTAG"
|
||||
# check if recent
|
||||
if [ "$VERSIONTAG" != "$GUI_MONERO_VERSION" ]; then
|
||||
echo "Building new libwallet version $GUI_MONERO_VERSION"
|
||||
BUILD_LIBWALLET=true
|
||||
else
|
||||
echo "latest libwallet ($GUI_MONERO_VERSION) is already built. Remove monero/lib/libwallet_merged.a to force rebuild"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$BUILD_LIBWALLET" != true ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "GUI_MONERO_VERSION=\"$VERSIONTAG\"" > $MONERO_DIR/version.sh
|
||||
|
||||
## Continue building libwallet
|
||||
|
||||
# default build type
|
||||
BUILD_TYPE=$1
|
||||
if [ -z $BUILD_TYPE ]; then
|
||||
BUILD_TYPE=release
|
||||
fi
|
||||
|
||||
BUILD_TREZOR_FLAGS=" -DUSE_DEVICE_TREZOR=ON"
|
||||
if [ "$BUILD_TREZOR" == false ]; then
|
||||
BUILD_TREZOR_FLAGS=" -DUSE_DEVICE_TREZOR=OFF"
|
||||
fi
|
||||
BUILD_TREZOR_FLAGS=" -DUSE_DEVICE_TREZOR_UDP_RELEASE=ON ${BUILD_TREZOR_FLAGS}"
|
||||
|
||||
STATIC=false
|
||||
ANDROID=false
|
||||
if [ "$BUILD_TYPE" == "release" ]; then
|
||||
echo "Building libwallet release"
|
||||
CMAKE_BUILD_TYPE=Release
|
||||
elif [ "$BUILD_TYPE" == "release-static" ]; then
|
||||
echo "Building libwallet release-static"
|
||||
CMAKE_BUILD_TYPE=Release
|
||||
STATIC=true
|
||||
elif [ "$BUILD_TYPE" == "release-android" ]; then
|
||||
echo "Building libwallet release-static for ANDROID"
|
||||
CMAKE_BUILD_TYPE=Release
|
||||
STATIC=true
|
||||
ANDROID=true
|
||||
elif [ "$BUILD_TYPE" == "debug-android" ]; then
|
||||
echo "Building libwallet debug-static for ANDROID"
|
||||
CMAKE_BUILD_TYPE=Debug
|
||||
STATIC=true
|
||||
ANDROID=true
|
||||
elif [ "$BUILD_TYPE" == "debug" ]; then
|
||||
echo "Building libwallet debug"
|
||||
CMAKE_BUILD_TYPE=Debug
|
||||
STATIC=true
|
||||
else
|
||||
echo "Valid build types are release, release-static, release-android, debug-android and debug"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
|
||||
echo "cleaning up existing monero build dir, libs and includes"
|
||||
rm -fr $MONERO_DIR/build
|
||||
rm -fr $MONERO_DIR/lib
|
||||
rm -fr $MONERO_DIR/include
|
||||
rm -fr $MONERO_DIR/bin
|
||||
|
||||
|
||||
mkdir -p $MONERO_DIR/build/$BUILD_TYPE
|
||||
pushd $MONERO_DIR/build/$BUILD_TYPE
|
||||
|
||||
# reusing function from "utils.sh"
|
||||
platform=$(get_platform)
|
||||
# default make executable
|
||||
make_exec="make"
|
||||
|
||||
if [ -z "$ARCH" ]; then
|
||||
ARCH="native"
|
||||
if [ "$platform" == "darwin" ]; then
|
||||
if [ "$STATIC" == true ]; then
|
||||
ARCH="x86-64"
|
||||
fi
|
||||
elif [ "$platform" == "linux64" ]; then
|
||||
if [ "$ANDROID" == true ]; then
|
||||
ARCH="armv7-a"
|
||||
elif [ "$STATIC" == true ]; then
|
||||
ARCH="x86-64"
|
||||
fi
|
||||
elif [ "$platform" == "linux32" ]; then
|
||||
if [ "$STATIC" == true ]; then
|
||||
ARCH="i686"
|
||||
fi
|
||||
elif [ "$platform" == "linuxarmv7" ]; then
|
||||
ARCH="armv7-a"
|
||||
elif [ "$platform" == "mingw32" ]; then
|
||||
ARCH="i686"
|
||||
elif [ "$platform" == "mingw64" ]; then
|
||||
ARCH="x86-64"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Building for ARCH=$ARCH"
|
||||
|
||||
## OS X
|
||||
if [ "$platform" == "darwin" ]; then
|
||||
echo "Configuring build for MacOS.."
|
||||
if [ "$STATIC" == true ]; then
|
||||
cmake -D CMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -D STATIC=ON -D ARCH="$ARCH" -D BUILD_64=ON -D BUILD_TAG="mac-x64" -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
else
|
||||
cmake -D CMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -D ARCH="$ARCH" -D BUILD_TAG="mac-x64" -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
fi
|
||||
|
||||
## LINUX 64
|
||||
elif [ "$platform" == "linux64" ]; then
|
||||
echo "Configuring build for Linux x64"
|
||||
if [ "$ANDROID" == true ]; then
|
||||
echo "Configuring build for Android on Linux host"
|
||||
cmake -D CMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -D STATIC=ON -D ARCH="$ARCH" -D ANDROID=true -D BUILD_GUI_DEPS=ON -D USE_LTO=OFF -D INSTALL_VENDORED_LIBUNBOUND=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
elif [ "$STATIC" == true ]; then
|
||||
cmake -D CMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -D STATIC=ON -D ARCH="$ARCH" -D BUILD_64=ON -D BUILD_TAG="linux-x64" -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
else
|
||||
cmake -D CMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -D ARCH="$ARCH" -D BUILD_TAG="linux-x64" -D BUILD_GUI_DEPS=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
fi
|
||||
|
||||
## LINUX 32
|
||||
elif [ "$platform" == "linux32" ]; then
|
||||
echo "Configuring build for Linux i686"
|
||||
if [ "$STATIC" == true ]; then
|
||||
cmake -D CMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -D STATIC=ON -D ARCH="$ARCH" -D BUILD_64=OFF -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
else
|
||||
cmake -D CMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -D ARCH="$ARCH" -D BUILD_GUI_DEPS=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
fi
|
||||
|
||||
## LINUX ARMv7
|
||||
elif [ "$platform" == "linuxarmv7" ]; then
|
||||
echo "Configuring build for Linux armv7"
|
||||
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 BUILD_64=OFF -D BUILD_GUI_DEPS=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
fi
|
||||
|
||||
## LINUX other
|
||||
elif [ "$platform" == "linux" ]; then
|
||||
echo "Configuring build for Linux general"
|
||||
if [ "$STATIC" == true ]; then
|
||||
cmake -D CMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -D STATIC=ON -D ARCH="$ARCH" -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
else
|
||||
cmake -D CMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -D ARCH="$ARCH" -D BUILD_GUI_DEPS=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
fi
|
||||
|
||||
## Windows 64
|
||||
## Windows is always static to work outside msys2
|
||||
elif [ "$platform" == "mingw64" ]; then
|
||||
# Do something under Windows NT platform
|
||||
echo "Configuring build for MINGW64.."
|
||||
BOOST_ROOT=/mingw64/boost
|
||||
cmake -D CMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -D STATIC=ON -D BOOST_ROOT="$BOOST_ROOT" -D ARCH="$ARCH" -D BUILD_TAG="win-x64" -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" -G "MSYS Makefiles" -D CMAKE_TOOLCHAIN_FILE=../../cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=$(cd $MINGW_PREFIX/.. && pwd -W) ../..
|
||||
|
||||
## Windows 32
|
||||
elif [ "$platform" == "mingw32" ]; then
|
||||
# Do something under Windows NT platform
|
||||
echo "Configuring build for MINGW32.."
|
||||
BOOST_ROOT=/mingw32/boost
|
||||
cmake -D CMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -D STATIC=ON -D Boost_DEBUG=ON -D BOOST_ROOT="$BOOST_ROOT" -D ARCH="$ARCH" -D BUILD_64=OFF -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" -G "MSYS Makefiles" -D CMAKE_TOOLCHAIN_FILE=../../cmake/32-bit-toolchain.cmake -D MSYS2_FOLDER=$(cd $MINGW_PREFIX/.. && pwd -W) ../..
|
||||
make_exec="mingw32-make"
|
||||
else
|
||||
echo "Unknown platform, configuring general build"
|
||||
if [ "$STATIC" == true ]; then
|
||||
cmake -D CMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -D STATIC=ON -D ARCH="$ARCH" -D BUILD_GUI_DEPS=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
else
|
||||
cmake -D CMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -D ARCH="$ARCH" -D BUILD_GUI_DEPS=ON $BUILD_TREZOR_FLAGS -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
fi
|
||||
fi
|
||||
|
||||
# set CPU core count
|
||||
# thanks to SO: http://stackoverflow.com/a/20283965/4118915
|
||||
if test -z "$CPU_CORE_COUNT"; then
|
||||
CPU_CORE_COUNT=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || sysctl -n hw.ncpu)
|
||||
fi
|
||||
|
||||
# Build libwallet_merged
|
||||
pushd $MONERO_DIR/build/$BUILD_TYPE/src/wallet
|
||||
eval $make_exec version -C ../..
|
||||
eval $make_exec -j$CPU_CORE_COUNT
|
||||
eval $make_exec install -j$CPU_CORE_COUNT
|
||||
popd
|
||||
|
||||
# Build monerod
|
||||
# win32 need to build daemon manually with msys2 toolchain
|
||||
if [ "$platform" != "mingw32" ] && [ "$ANDROID" != true ]; then
|
||||
pushd $MONERO_DIR/build/$BUILD_TYPE/src/daemon
|
||||
eval make -j$CPU_CORE_COUNT
|
||||
eval make install -j$CPU_CORE_COUNT
|
||||
popd
|
||||
fi
|
||||
|
||||
# build install epee
|
||||
eval make -C $MONERO_DIR/build/$BUILD_TYPE/contrib/epee all install
|
||||
|
||||
# install easylogging
|
||||
eval make -C $MONERO_DIR/build/$BUILD_TYPE/external/easylogging++ all install
|
||||
|
||||
# install lmdb
|
||||
eval make -C $MONERO_DIR/build/$BUILD_TYPE/external/db_drivers/liblmdb all install
|
||||
|
||||
# Install libunbound
|
||||
if [ -d $MONERO_DIR/build/$BUILD_TYPE/external/unbound ]; then
|
||||
echo "Installing libunbound..."
|
||||
pushd $MONERO_DIR/build/$BUILD_TYPE/external/unbound
|
||||
# no need to make, it was already built as dependency for libwallet
|
||||
# make -j$CPU_CORE_COUNT
|
||||
$make_exec install -j$CPU_CORE_COUNT
|
||||
popd
|
||||
fi
|
||||
|
||||
# install randomx
|
||||
eval make -C $MONERO_DIR/build/$BUILD_TYPE/external/randomx all install
|
||||
|
||||
popd
|
||||
@@ -105,9 +105,6 @@ Source: "bin\extras\monero-gen-ssl-cert.exe"; DestDir: "{app}"; Flags: ignorever
|
||||
; Qt Quick 2D Renderer fallback for systems / environments with "low-level graphics" i.e. without 3D support
|
||||
Source: "bin\start-low-graphics-mode.bat"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
||||
; Use a scale factor of 2 for Qt for high-DPI systems, as long as Qt does not handle some such systems adequately
|
||||
Source: "bin\start-high-dpi.bat"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
||||
; Mesa, open-source OpenGL implementation; part of "low-level graphics" support
|
||||
Source: "bin\opengl32sw.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
||||
@@ -170,6 +167,7 @@ Type: files; Name: "{app}\libssp-0.dll"
|
||||
Type: files; Name: "{app}\libhidapi-0.dll"
|
||||
Type: files; Name: "{app}\libeay32.dll"
|
||||
Type: files; Name: "{app}\ssleay32.dll"
|
||||
Type: files; Name: "{app}\start-high-dpi.bat"
|
||||
Type: files; Name: "{group}\Utilities\x (Check Blockchain Folder).lnk"
|
||||
|
||||
|
||||
|
||||
@@ -105,8 +105,8 @@
|
||||
<p>The Monero software and especially the GUI wallet are "work in progress", and sometimes things go wrong.</p>
|
||||
|
||||
<p>Please note that despite any technical problems that you may encounter your Moneroj are almost always safe: You may
|
||||
not be able to move them or you even may not see how many you currently have, but you most probably won't loose any.
|
||||
But do remember that the seed needed to re-create the wallet <b>is</b> critical, however: <b>Never loose your
|
||||
not be able to move them or you even may not see how many you currently have, but you most probably won't lose any.
|
||||
But do remember that the seed needed to re-create the wallet <b>is</b> critical, however: <b>Never lose your
|
||||
seed!</b></p>
|
||||
|
||||
<p>In the <i>Utilities</i> sub-folder there are several more icons that may help you to solve problems.
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# 3 header files required by monero are missing from the IOS SDK. I copied them from iphoneSimulator SDK
|
||||
# cd /Applications/XCode.app
|
||||
# sudo cp ./Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/sys/vmmeter.h ./Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/sys/
|
||||
# sudo cp ./Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/netinet/udp_var.h ./Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/netinet/
|
||||
# sudo cp ./Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/netinet/ip_var.h ./Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/netinet/
|
||||
|
||||
|
||||
if [ -z $BUILD_TYPE ]; then
|
||||
BUILD_TYPE=release
|
||||
fi
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
if [ -z $BOOST_LIBRARYDIR ]; then
|
||||
BOOST_LIBRARYDIR=${ROOT_DIR}/../ofxiOSBoost/build/ios/prefix/lib
|
||||
fi
|
||||
if [ -z $BOOST_INCLUDEDIR ]; then
|
||||
BOOST_INCLUDEDIR=${ROOT_DIR}/../ofxiOSBoost/build/ios/prefix/include
|
||||
fi
|
||||
if [ -z $OPENSSL_INCLUDE_DIR ]; then
|
||||
OPENSSL_INCLUDE_DIR=${ROOT_DIR}/../openssl/1.0.2j/include
|
||||
fi
|
||||
if [ -z $OPENSSL_ROOT_DIR ]; then
|
||||
OPENSSL_ROOT_DIR=${ROOT_DIR}/../openssl/1.0.2j
|
||||
fi
|
||||
|
||||
echo "Building IOS armv7"
|
||||
rm -r monero/build > /dev/null
|
||||
mkdir -p monero/build/release
|
||||
pushd monero/build/release
|
||||
cmake -D IOS=ON -D ARCH=armv7 -D BOOST_LIBRARYDIR=${BOOST_INCLUDEDIR} -D BOOST_INCLUDEDIR=${BOOST_INCLUDEDIR} -D OPENSSL_INCLUDE_DIR=${OPENSSL_INCLUDE_DIR} -D OPENSSL_ROOT_DIR=${OPENSSL_ROOT_DIR} -D CMAKE_BUILD_TYPE=debug -D STATIC=ON -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON -D CMAKE_INSTALL_PREFIX="/Users/jacob/crypto/monero-core/monero" ../..
|
||||
make -j4 && make install
|
||||
popd
|
||||
echo "Building IOS arm64"
|
||||
rm -r monero/build > /dev/null
|
||||
mkdir -p monero/build/release
|
||||
pushd monero/build/release
|
||||
cmake -D IOS=ON -D ARCH=armv8-a -D BOOST_LIBRARYDIR=${BOOST_INCLUDEDIR} -D BOOST_INCLUDEDIR=${BOOST_INCLUDEDIR} -D OPENSSL_INCLUDE_DIR=${OPENSSL_INCLUDE_DIR} -D OPENSSL_ROOT_DIR=${OPENSSL_ROOT_DIR} -D CMAKE_BUILD_TYPE=debug -D STATIC=ON -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON -D CMAKE_INSTALL_PREFIX="/Users/jacob/crypto/monero-core/monero" ../..
|
||||
make -j4 && make install
|
||||
popd
|
||||
|
||||
echo "Creating fat library for armv7 and arm64"
|
||||
pushd monero
|
||||
mkdir -p lib-ios
|
||||
lipo -create lib-armv7/libwallet_merged.a lib-arm64/libwallet_merged.a -output lib-ios/libwallet_merged.a
|
||||
lipo -create lib-armv7/libunbound.a lib-arm64/libunbound.a -output lib-ios/libunbound.a
|
||||
lipo -create lib-armv7/libepee.a lib-arm64/libepee.a -output lib-ios/libepee.a
|
||||
popd
|
||||
@@ -113,5 +113,5 @@ function capitalize(s){
|
||||
}
|
||||
|
||||
function removeTrailingZeros(value) {
|
||||
return (value + '').replace(/(\.\d*[1-9])0+$/, '$1');
|
||||
return (value + '').replace(/(\.\d*?)0+$/, '$1').replace(/\.$/, '');
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
source $ROOT_DIR/utils.sh
|
||||
|
||||
TARGET=$1
|
||||
|
||||
GUI_EXEC=$2
|
||||
|
||||
platform=$(get_platform)
|
||||
|
||||
if [[ "$platform" == "linux64" ]]; then
|
||||
PLAT_DIR="/usr/lib/x86_64-linux-gnu"
|
||||
elif [[ "$platform" == "linux32" ]]; then
|
||||
PLAT_DIR="/usr/lib/i386-linux-gnu"
|
||||
elif [[ "$platform" == "linuxarmv7" ]]; then
|
||||
PLAT_DIR="/usr/lib/arm-linux-gnueabihf"
|
||||
elif [[ "$platform" == "linuxarmv8" ]]; then
|
||||
PLAT_DIR="/usr/lib/aarch64-linux-gnu"
|
||||
else
|
||||
PLAT_DIR="/usr/lib"
|
||||
fi
|
||||
|
||||
if [ -z "$QT_DIR" ]; then
|
||||
QT_DIR=$PLAT_DIR/qt5
|
||||
fi
|
||||
|
||||
if [ -z "$QTXML_DIR" ]; then
|
||||
QTXML_DIR=$PLAT_DIR
|
||||
fi
|
||||
|
||||
# Copy dependencies
|
||||
EXCLUDE='libstdc++|libgcc_s.so|libc.so|libpthread'
|
||||
INCLUDE='libunbound'
|
||||
cp -rv $QT_DIR/qml $TARGET || exit
|
||||
cp -rv $QT_DIR/plugins $TARGET || exit
|
||||
mkdir -p $TARGET/libs || exit
|
||||
#ldd $TARGET/$GUI_EXEC | grep "=> /" | awk '{print $3}' | grep $INCLUDE | xargs -I '{}' cp -v '{}' $TARGET/libs || exit
|
||||
#ldd $TARGET/$GUI_EXEC | grep "=> /" | awk '{print $3}' | grep -Ev $EXCLUDE | xargs -I '{}' cp -v '{}' $TARGET/libs || exit
|
||||
#ldd $TARGET/plugins/platforms/libqxcb.so| grep "=> /" | awk '{print $3}' | grep -Ev $EXCLUDE | xargs -I '{}' cp -v '{}' $TARGET/libs || exit
|
||||
#cp -v $QTXML_DIR/libQt5XmlPatterns.so.5 $TARGET/libs || exit
|
||||
|
||||
# Create start script
|
||||
cat > $TARGET/start-gui.sh <<EOL
|
||||
#!/bin/bash
|
||||
export LD_LIBRARY_PATH=\`pwd\`/libs
|
||||
export QT_PLUGIN_PATH=\`pwd\`/plugins
|
||||
export QML2_IMPORT_PATH=\`pwd\`/qml
|
||||
# make it so that it can be called from anywhere and also through soft links
|
||||
SCRIPT_DIR="\$(dirname "\$(test -L "\${BASH_SOURCE[0]}" && readlink "\${BASH_SOURCE[0]}" || echo "\${BASH_SOURCE[0]}")")"
|
||||
"\$SCRIPT_DIR"/$GUI_EXEC "\$@"
|
||||
EOL
|
||||
|
||||
# Create start script
|
||||
cat > $TARGET/start-tails.AppImage <<EOL
|
||||
#!/bin/bash
|
||||
# Silly hack to provide a launcher that is double clickable
|
||||
bash ./start-gui.sh
|
||||
EOL
|
||||
|
||||
chmod +x $TARGET/start-gui.sh
|
||||
chmod +x $TARGET/start-tails.AppImage
|
||||
433
main.qml
433
main.qml
@@ -26,6 +26,7 @@
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQml.Models 2.12
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Window 2.0
|
||||
import QtQuick.Controls 1.1
|
||||
@@ -53,7 +54,10 @@ import "version.js" as Version
|
||||
|
||||
ApplicationWindow {
|
||||
id: appWindow
|
||||
title: "Monero" + (walletName ? " - " + walletName : "")
|
||||
title: "Monero" +
|
||||
(persistentSettings.displayWalletNameInTitleBar && walletName
|
||||
? " - " + walletName
|
||||
: "")
|
||||
minimumWidth: 750
|
||||
minimumHeight: 450
|
||||
|
||||
@@ -65,7 +69,6 @@ ApplicationWindow {
|
||||
property var currentWallet;
|
||||
property bool disconnected: currentWallet ? currentWallet.disconnected : false
|
||||
property var transaction;
|
||||
property var transactionDescription;
|
||||
property var walletPassword
|
||||
property int restoreHeight:0
|
||||
property bool daemonSynced: false
|
||||
@@ -141,12 +144,8 @@ ApplicationWindow {
|
||||
|
||||
if(seq === "Ctrl+S") middlePanel.state = "Transfer"
|
||||
else if(seq === "Ctrl+R") middlePanel.state = "Receive"
|
||||
else if(seq === "Ctrl+K") middlePanel.state = "TxKey"
|
||||
else if(seq === "Ctrl+H") middlePanel.state = "History"
|
||||
else if(seq === "Ctrl+B") middlePanel.state = "AddressBook"
|
||||
else if(seq === "Ctrl+M") middlePanel.state = "Mining"
|
||||
else if(seq === "Ctrl+I") middlePanel.state = "Sign"
|
||||
else if(seq === "Ctrl+G") middlePanel.state = "SharedRingDB"
|
||||
else if(seq === "Ctrl+E") middlePanel.state = "Settings"
|
||||
else if(seq === "Ctrl+D") middlePanel.state = "Advanced"
|
||||
else if(seq === "Ctrl+T") middlePanel.state = "Account"
|
||||
@@ -166,11 +165,8 @@ ApplicationWindow {
|
||||
else if(middlePanel.state === "Transfer") middlePanel.state = "AddressBook"
|
||||
else if(middlePanel.state === "AddressBook") middlePanel.state = "Receive"
|
||||
else if(middlePanel.state === "Receive") middlePanel.state = "History"
|
||||
else if(middlePanel.state === "History") middlePanel.state = "Mining"
|
||||
else if(middlePanel.state === "Mining") middlePanel.state = "TxKey"
|
||||
else if(middlePanel.state === "TxKey") middlePanel.state = "SharedRingDB"
|
||||
else if(middlePanel.state === "SharedRingDB") middlePanel.state = "Sign"
|
||||
else if(middlePanel.state === "Sign") middlePanel.state = "Settings"
|
||||
else if(middlePanel.state === "History") middlePanel.state = "Advanced"
|
||||
else if(middlePanel.state === "Advanced") middlePanel.state = "Settings"
|
||||
} else if(seq === "Ctrl+Shift+Backtab" || seq === "Alt+Shift+Backtab") {
|
||||
/*
|
||||
if(middlePanel.state === "Settings") middlePanel.state = "Sign"
|
||||
@@ -182,11 +178,8 @@ ApplicationWindow {
|
||||
else if(middlePanel.state === "TxKey") middlePanel.state = "Receive"
|
||||
else if(middlePanel.state === "Receive") middlePanel.state = "Transfer"
|
||||
*/
|
||||
if(middlePanel.state === "Settings") middlePanel.state = "Sign"
|
||||
else if(middlePanel.state === "Sign") middlePanel.state = "SharedRingDB"
|
||||
else if(middlePanel.state === "SharedRingDB") middlePanel.state = "TxKey"
|
||||
else if(middlePanel.state === "TxKey") middlePanel.state = "Mining"
|
||||
else if(middlePanel.state === "Mining") middlePanel.state = "History"
|
||||
if(middlePanel.state === "Settings") middlePanel.state = "Advanced"
|
||||
else if(middlePanel.state === "Advanced") middlePanel.state = "History"
|
||||
else if(middlePanel.state === "History") middlePanel.state = "Receive"
|
||||
else if(middlePanel.state === "Receive") middlePanel.state = "AddressBook"
|
||||
else if(middlePanel.state === "AddressBook") middlePanel.state = "Transfer"
|
||||
@@ -234,12 +227,6 @@ ApplicationWindow {
|
||||
else
|
||||
walletManager.setLogLevel(persistentSettings.logLevel)
|
||||
|
||||
// setup language
|
||||
var locale = persistentSettings.locale
|
||||
if (locale !== "") {
|
||||
translationManager.setLanguage(locale.split("_")[0]);
|
||||
}
|
||||
|
||||
// Reload transfer page with translations enabled
|
||||
middlePanel.transferView.onPageCompleted();
|
||||
|
||||
@@ -378,13 +365,13 @@ ApplicationWindow {
|
||||
console.log("Recovering from seed: ", persistentSettings.is_recovering)
|
||||
console.log("restore Height", persistentSettings.restore_height)
|
||||
|
||||
// Use saved daemon rpc login settings
|
||||
currentWallet.setDaemonLogin(persistentSettings.daemonUsername, persistentSettings.daemonPassword)
|
||||
|
||||
if(persistentSettings.useRemoteNode)
|
||||
currentDaemonAddress = persistentSettings.remoteNodeAddress
|
||||
else
|
||||
currentDaemonAddress = localDaemonAddress
|
||||
if (persistentSettings.useRemoteNode) {
|
||||
const remoteNode = remoteNodesModel.currentRemoteNode();
|
||||
currentDaemonAddress = remoteNode.address;
|
||||
currentWallet.setDaemonLogin(remoteNode.username, remoteNode.password);
|
||||
} else {
|
||||
currentDaemonAddress = localDaemonAddress;
|
||||
}
|
||||
|
||||
console.log("initializing with daemon address: ", currentDaemonAddress)
|
||||
currentWallet.initAsync(
|
||||
@@ -401,7 +388,7 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
function isTrustedDaemon() {
|
||||
return !persistentSettings.useRemoteNode || persistentSettings.is_trusted_daemon;
|
||||
return !persistentSettings.useRemoteNode || remoteNodesModel.currentRemoteNode().trusted;
|
||||
}
|
||||
|
||||
function usefulName(path) {
|
||||
@@ -503,21 +490,35 @@ ApplicationWindow {
|
||||
walletInitialized = true
|
||||
|
||||
// check if daemon was already mining and add mining logo if true
|
||||
middlePanel.miningView.update();
|
||||
middlePanel.advancedView.miningView.update();
|
||||
}
|
||||
}
|
||||
|
||||
function onDeviceButtonRequest(code){
|
||||
prevSplashText = splash.messageText;
|
||||
splashDisplayedBeforeButtonRequest = splash.visible;
|
||||
appWindow.showProcessingSplash(qsTr("Please proceed to the device..."));
|
||||
if (txConfirmationPopup.visible) {
|
||||
txConfirmationPopup.bottomTextAnimation.running = true
|
||||
if (!txConfirmationPopup.errorText.visible) {
|
||||
txConfirmationPopup.bottomText.text = qsTr("Please confirm transaction on the device...") + translationManager.emptyString;
|
||||
} else {
|
||||
txConfirmationPopup.bottomText.text = qsTr("Please proceed to the device...") + translationManager.emptyString;
|
||||
}
|
||||
} else {
|
||||
prevSplashText = splash.messageText;
|
||||
splashDisplayedBeforeButtonRequest = splash.visible;
|
||||
appWindow.showProcessingSplash(qsTr("Please proceed to the device..."));
|
||||
}
|
||||
}
|
||||
|
||||
function onDeviceButtonPressed(){
|
||||
if (splashDisplayedBeforeButtonRequest){
|
||||
appWindow.showProcessingSplash(prevSplashText);
|
||||
if (txConfirmationPopup.visible) {
|
||||
txConfirmationPopup.bottomTextAnimation.running = false;
|
||||
txConfirmationPopup.bottomText.text = qsTr("Signing transaction in the device...") + translationManager.emptyString;
|
||||
} else {
|
||||
hideProcessingSplash();
|
||||
if (splashDisplayedBeforeButtonRequest){
|
||||
appWindow.showProcessingSplash(prevSplashText);
|
||||
} else {
|
||||
hideProcessingSplash();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,7 +617,9 @@ ApplicationWindow {
|
||||
|
||||
const callback = function() {
|
||||
persistentSettings.useRemoteNode = true;
|
||||
currentDaemonAddress = persistentSettings.remoteNodeAddress;
|
||||
const remoteNode = remoteNodesModel.currentRemoteNode();
|
||||
currentDaemonAddress = remoteNode.address;
|
||||
currentWallet.setDaemonLogin(remoteNode.username, remoteNode.password);
|
||||
currentWallet.initAsync(
|
||||
currentDaemonAddress,
|
||||
isTrustedDaemon(),
|
||||
@@ -642,6 +645,7 @@ ApplicationWindow {
|
||||
console.log("disconnecting remote node");
|
||||
persistentSettings.useRemoteNode = false;
|
||||
currentDaemonAddress = localDaemonAddress
|
||||
currentWallet.setDaemonLogin("", "");
|
||||
currentWallet.initAsync(
|
||||
currentDaemonAddress,
|
||||
isTrustedDaemon(),
|
||||
@@ -714,7 +718,7 @@ ApplicationWindow {
|
||||
|
||||
const noSync = appWindow.walletMode === 0;
|
||||
const bootstrapNodeAddress = persistentSettings.walletMode < 2 ? "auto" : persistentSettings.bootstrapNodeAddress
|
||||
daemonManager.start(flags, persistentSettings.nettype, persistentSettings.blockchainDataDir, bootstrapNodeAddress, noSync);
|
||||
daemonManager.start(flags, persistentSettings.nettype, persistentSettings.blockchainDataDir, bootstrapNodeAddress, noSync, persistentSettings.pruneBlockchain);
|
||||
}
|
||||
|
||||
function stopDaemon(callback, splash){
|
||||
@@ -810,108 +814,81 @@ ApplicationWindow {
|
||||
return false;
|
||||
}
|
||||
|
||||
function onTransactionCreated(pendingTransaction,address,paymentId,mixinCount){
|
||||
function onTransactionCreated(pendingTransaction, addresses, paymentId, mixinCount) {
|
||||
console.log("Transaction created");
|
||||
hideProcessingSplash();
|
||||
txConfirmationPopup.bottomText.text = "";
|
||||
transaction = pendingTransaction;
|
||||
// validate address;
|
||||
if (transaction.status !== PendingTransaction.Status_Ok) {
|
||||
console.error("Can't create transaction: ", transaction.errorString);
|
||||
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
||||
if (currentWallet.connected() == Wallet.ConnectionStatus_WrongVersion)
|
||||
informationPopup.text = qsTr("Can't create transaction: Wrong daemon version: ") + transaction.errorString
|
||||
else
|
||||
informationPopup.text = qsTr("Can't create transaction: ") + transaction.errorString
|
||||
informationPopup.icon = StandardIcon.Critical
|
||||
informationPopup.onCloseCallback = null
|
||||
informationPopup.open();
|
||||
if (currentWallet.connected() == Wallet.ConnectionStatus_WrongVersion) {
|
||||
txConfirmationPopup.errorText.text = qsTr("Can't create transaction: Wrong daemon version: ") + transaction.errorString
|
||||
} else {
|
||||
txConfirmationPopup.errorText.text = qsTr("Can't create transaction: ") + transaction.errorString
|
||||
}
|
||||
// deleting transaction object, we don't want memleaks
|
||||
currentWallet.disposeTransaction(transaction);
|
||||
|
||||
} else if (transaction.txCount == 0) {
|
||||
informationPopup.title = qsTr("Error") + translationManager.emptyString
|
||||
informationPopup.text = qsTr("No unmixable outputs to sweep") + translationManager.emptyString
|
||||
informationPopup.icon = StandardIcon.Information
|
||||
informationPopup.onCloseCallback = null
|
||||
informationPopup.open()
|
||||
console.error("Can't create transaction: ", transaction.errorString);
|
||||
txConfirmationPopup.errorText.text = qsTr("No unmixable outputs to sweep") + translationManager.emptyString
|
||||
// deleting transaction object, we don't want memleaks
|
||||
currentWallet.disposeTransaction(transaction);
|
||||
} else {
|
||||
console.log("Transaction created, amount: " + walletManager.displayAmount(transaction.amount)
|
||||
+ ", fee: " + walletManager.displayAmount(transaction.fee));
|
||||
|
||||
// here we show confirmation popup;
|
||||
transactionConfirmationPopup.title = qsTr("Please confirm transaction:\n") + translationManager.emptyString;
|
||||
transactionConfirmationPopup.text = "";
|
||||
transactionConfirmationPopup.text += (address === "" ? "" : (qsTr("Address: ") + address));
|
||||
transactionConfirmationPopup.text += (paymentId === "" ? "" : (qsTr("\nPayment ID: ") + paymentId));
|
||||
transactionConfirmationPopup.text += qsTr("\n\nAmount: ") + walletManager.displayAmount(transaction.amount);
|
||||
transactionConfirmationPopup.text += qsTr("\nFee: ") + walletManager.displayAmount(transaction.fee);
|
||||
transactionConfirmationPopup.text += qsTr("\nRingsize: ") + (mixinCount + 1);
|
||||
transactionConfirmationPopup.text += qsTr("\n\nNumber of transactions: ") + transaction.txCount
|
||||
transactionConfirmationPopup.text += (transactionDescription === "" ? "" : (qsTr("\nDescription: ") + transactionDescription))
|
||||
for (var i = 0; i < transaction.subaddrIndices.length; ++i){
|
||||
transactionConfirmationPopup.text += qsTr("\nSpending address index: ") + transaction.subaddrIndices[i];
|
||||
}
|
||||
|
||||
transactionConfirmationPopup.text += translationManager.emptyString;
|
||||
transactionConfirmationPopup.icon = StandardIcon.Question
|
||||
transactionConfirmationPopup.open()
|
||||
// here we update txConfirmationPopup
|
||||
txConfirmationPopup.transactionAmount = Utils.removeTrailingZeros(walletManager.displayAmount(transaction.amount));
|
||||
txConfirmationPopup.transactionFee = Utils.removeTrailingZeros(walletManager.displayAmount(transaction.fee));
|
||||
txConfirmationPopup.confirmButton.text = viewOnly ? qsTr("Save as file") : qsTr("Confirm") + translationManager.emptyString;
|
||||
txConfirmationPopup.confirmButton.rightIcon = viewOnly ? "" : "qrc:///images/rightArrow.png"
|
||||
}
|
||||
}
|
||||
|
||||
function getDisplayAmountTotal(recipients) {
|
||||
const amounts = recipients.map(function (recipient) {
|
||||
return recipient.amount;
|
||||
});
|
||||
const total = walletManager.amountsSumFromStrings(amounts);
|
||||
return Utils.removeTrailingZeros(walletManager.displayAmount(total));
|
||||
}
|
||||
|
||||
// called on "transfer"
|
||||
function handlePayment(address, paymentId, amount, mixinCount, priority, description, createFile) {
|
||||
function handlePayment(recipients, paymentId, mixinCount, priority, description, createFile) {
|
||||
console.log("Creating transaction: ")
|
||||
console.log("\taddress: ", address,
|
||||
console.log("\trecipients: ", recipients,
|
||||
", payment_id: ", paymentId,
|
||||
", amount: ", amount,
|
||||
", mixins: ", mixinCount,
|
||||
", priority: ", priority,
|
||||
", description: ", description);
|
||||
|
||||
var splashMsg = qsTr("Creating transaction...");
|
||||
splashMsg += appWindow.currentWallet.isLedger() ? qsTr("\n\nPlease check your hardware wallet –\nyour input may be required.") : "";
|
||||
showProcessingSplash(splashMsg);
|
||||
|
||||
transactionDescription = description;
|
||||
|
||||
// validate amount;
|
||||
if (amount !== "(all)") {
|
||||
var amountxmr = walletManager.amountFromString(amount);
|
||||
console.log("integer amount: ", amountxmr);
|
||||
console.log("integer unlocked", currentWallet.unlockedBalance())
|
||||
if (amountxmr <= 0) {
|
||||
hideProcessingSplash()
|
||||
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
||||
informationPopup.text = qsTr("Amount is wrong: expected number from %1 to %2")
|
||||
.arg(walletManager.displayAmount(0))
|
||||
.arg(walletManager.displayAmount(currentWallet.unlockedBalance()))
|
||||
+ translationManager.emptyString
|
||||
|
||||
informationPopup.icon = StandardIcon.Critical
|
||||
informationPopup.onCloseCallback = null
|
||||
informationPopup.open()
|
||||
return;
|
||||
} else if (amountxmr > currentWallet.unlockedBalance()) {
|
||||
hideProcessingSplash()
|
||||
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
||||
informationPopup.text = qsTr("Insufficient funds. Unlocked balance: %1")
|
||||
.arg(walletManager.displayAmount(currentWallet.unlockedBalance()))
|
||||
+ translationManager.emptyString
|
||||
|
||||
informationPopup.icon = StandardIcon.Critical
|
||||
informationPopup.onCloseCallback = null
|
||||
informationPopup.open()
|
||||
return;
|
||||
}
|
||||
const recipientAll = recipients.find(function (recipient) {
|
||||
return recipient.amount == "(all)";
|
||||
});
|
||||
if (recipientAll && recipients.length > 1) {
|
||||
throw "Sending all requires one destination address";
|
||||
}
|
||||
|
||||
if (amount === "(all)")
|
||||
currentWallet.createTransactionAllAsync(address, paymentId, mixinCount, priority);
|
||||
else
|
||||
currentWallet.createTransactionAsync(address, paymentId, amountxmr, mixinCount, priority);
|
||||
txConfirmationPopup.bottomTextAnimation.running = false;
|
||||
txConfirmationPopup.bottomText.text = qsTr("Creating transaction...") + translationManager.emptyString;
|
||||
txConfirmationPopup.recipients = recipients;
|
||||
txConfirmationPopup.transactionAmount = recipientAll ? "(all)" : getDisplayAmountTotal(recipients);
|
||||
txConfirmationPopup.transactionPriority = priority;
|
||||
txConfirmationPopup.transactionDescription = description;
|
||||
txConfirmationPopup.open();
|
||||
|
||||
if (recipientAll) {
|
||||
currentWallet.createTransactionAllAsync(recipientAll.address, paymentId, mixinCount, priority);
|
||||
} else {
|
||||
const addresses = recipients.map(function (recipient) {
|
||||
return recipient.address;
|
||||
});
|
||||
const amountsxmr = recipients.map(function (recipient) {
|
||||
return walletManager.amountFromString(recipient.amount);
|
||||
});
|
||||
currentWallet.createTransactionAsync(addresses, paymentId, amountsxmr, mixinCount, priority);
|
||||
}
|
||||
}
|
||||
|
||||
//Choose where to save transaction
|
||||
@@ -935,40 +912,27 @@ ApplicationWindow {
|
||||
function handleSweepUnmixable() {
|
||||
console.log("Creating transaction: ")
|
||||
|
||||
txConfirmationPopup.sweepUnmixable = true;
|
||||
transaction = currentWallet.createSweepUnmixableTransaction();
|
||||
if (transaction.status !== PendingTransaction.Status_Ok) {
|
||||
console.error("Can't create transaction: ", transaction.errorString);
|
||||
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
||||
informationPopup.text = qsTr("Can't create transaction: ") + transaction.errorString
|
||||
informationPopup.icon = StandardIcon.Critical
|
||||
informationPopup.onCloseCallback = null
|
||||
informationPopup.open();
|
||||
txConfirmationPopup.errorText.text = qsTr("Can't create transaction: ") + transaction.errorString + translationManager.emptyString
|
||||
// deleting transaction object, we don't want memleaks
|
||||
currentWallet.disposeTransaction(transaction);
|
||||
|
||||
} else if (transaction.txCount == 0) {
|
||||
informationPopup.title = qsTr("Error") + translationManager.emptyString
|
||||
informationPopup.text = qsTr("No unmixable outputs to sweep") + translationManager.emptyString
|
||||
informationPopup.icon = StandardIcon.Information
|
||||
informationPopup.onCloseCallback = null
|
||||
informationPopup.open()
|
||||
console.error("No unmixable outputs to sweep");
|
||||
txConfirmationPopup.errorText.text = qsTr("No unmixable outputs to sweep") + translationManager.emptyString
|
||||
// deleting transaction object, we don't want memleaks
|
||||
currentWallet.disposeTransaction(transaction);
|
||||
} else {
|
||||
console.log("Transaction created, amount: " + walletManager.displayAmount(transaction.amount)
|
||||
+ ", fee: " + walletManager.displayAmount(transaction.fee));
|
||||
|
||||
// here we show confirmation popup;
|
||||
|
||||
transactionConfirmationPopup.title = qsTr("Confirmation") + translationManager.emptyString
|
||||
transactionConfirmationPopup.text = qsTr("Please confirm transaction:\n")
|
||||
+ qsTr("\n\nAmount: ") + walletManager.displayAmount(transaction.amount)
|
||||
+ qsTr("\nFee: ") + walletManager.displayAmount(transaction.fee)
|
||||
+ translationManager.emptyString
|
||||
transactionConfirmationPopup.icon = StandardIcon.Question
|
||||
transactionConfirmationPopup.open()
|
||||
txConfirmationPopup.transactionAmount = Utils.removeTrailingZeros(walletManager.displayAmount(transaction.amount));
|
||||
txConfirmationPopup.transactionFee = Utils.removeTrailingZeros(walletManager.displayAmount(transaction.fee));
|
||||
// committing transaction
|
||||
}
|
||||
txConfirmationPopup.open();
|
||||
}
|
||||
|
||||
// called after user confirms transaction
|
||||
@@ -986,7 +950,6 @@ ApplicationWindow {
|
||||
// Store to file
|
||||
transaction.setFilename(path);
|
||||
}
|
||||
|
||||
appWindow.showProcessingSplash(qsTr("Sending transaction ..."));
|
||||
currentWallet.commitTransactionAsync(transaction);
|
||||
}
|
||||
@@ -1001,13 +964,14 @@ ApplicationWindow {
|
||||
informationPopup.onCloseCallback = null;
|
||||
informationPopup.open();
|
||||
} else {
|
||||
if (transactionDescription.length > 0) {
|
||||
if (txConfirmationPopup.transactionDescription.length > 0) {
|
||||
for (var i = 0; i < txid.length; ++i)
|
||||
currentWallet.setUserNote(txid[i], transactionDescription);
|
||||
currentWallet.setUserNote(txid[i], txConfirmationPopup.transactionDescription);
|
||||
}
|
||||
|
||||
// Clear tx fields
|
||||
middlePanel.transferView.clearFields()
|
||||
txConfirmationPopup.clearFields()
|
||||
successfulTxPopup.open(txid)
|
||||
}
|
||||
currentWallet.refresh()
|
||||
@@ -1157,11 +1121,14 @@ ApplicationWindow {
|
||||
|
||||
objectName: "appWindow"
|
||||
visible: true
|
||||
width: screenWidth > 980 ? 980 : 800
|
||||
height: screenHeight > maxWindowHeight ? maxWindowHeight : 700
|
||||
width: Screen.desktopAvailableWidth > 980
|
||||
? 980
|
||||
: Math.min(Screen.desktopAvailableWidth, 800)
|
||||
height: Screen.desktopAvailableHeight > maxWindowHeight
|
||||
? maxWindowHeight
|
||||
: Math.min(Screen.desktopAvailableHeight, 700)
|
||||
color: MoneroComponents.Style.appWindowBackgroundColor
|
||||
flags: persistentSettings.customDecorations ? Windows.flagsCustomDecorations : Windows.flags
|
||||
onWidthChanged: x -= 0
|
||||
|
||||
Timer {
|
||||
id: fiatPriceTimer
|
||||
@@ -1184,7 +1151,7 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
var key = currency === "xmreur" ? "XXMRZEUR" : "XXMRZUSD";
|
||||
var ticker = resp.result[key]["o"];
|
||||
var ticker = resp.result[key]["c"][0];
|
||||
return ticker;
|
||||
} else if(url.startsWith("https://api.coingecko.com/api/v3/")){
|
||||
var key = currency === "xmreur" ? "eur" : "usd";
|
||||
@@ -1318,8 +1285,10 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
x = (Screen.width - width) / 2
|
||||
y = (Screen.height - maxWindowHeight) / 2
|
||||
x = (Screen.desktopAvailableWidth - width) / 2;
|
||||
y = (Screen.desktopAvailableHeight - height) / 2;
|
||||
|
||||
translationManager.setLanguage(persistentSettings.locale.split("_")[0]);
|
||||
|
||||
applyWalletMode(persistentSettings.walletMode);
|
||||
|
||||
@@ -1366,6 +1335,27 @@ ApplicationWindow {
|
||||
appWindow.fiatApiRefresh();
|
||||
appWindow.fiatTimerStart();
|
||||
}
|
||||
|
||||
if (persistentSettings.askDesktopShortcut && !persistentSettings.portable) {
|
||||
persistentSettings.askDesktopShortcut = false;
|
||||
|
||||
if (isTails) {
|
||||
oshelper.createDesktopEntry();
|
||||
} else if (isLinux) {
|
||||
confirmationDialog.title = qsTr("Desktop entry") + translationManager.emptyString;
|
||||
confirmationDialog.text = qsTr("Would you like to register Monero GUI Desktop entry?") + translationManager.emptyString;
|
||||
confirmationDialog.icon = StandardIcon.Question;
|
||||
confirmationDialog.cancelText = qsTr("No") + translationManager.emptyString;
|
||||
confirmationDialog.okText = qsTr("Yes") + translationManager.emptyString;
|
||||
confirmationDialog.onAcceptedCallback = function() {
|
||||
oshelper.createDesktopEntry();
|
||||
};
|
||||
confirmationDialog.onRejectedCallback = null;
|
||||
confirmationDialog.open();
|
||||
}
|
||||
}
|
||||
|
||||
remoteNodesModel.initialize();
|
||||
}
|
||||
|
||||
MoneroSettings {
|
||||
@@ -1376,35 +1366,49 @@ ApplicationWindow {
|
||||
return "";
|
||||
}
|
||||
|
||||
property string language
|
||||
property string locale
|
||||
property bool askDesktopShortcut: isLinux
|
||||
property string language: 'English (US)'
|
||||
property string language_wallet: 'English'
|
||||
property string locale: 'en_US'
|
||||
property string account_name
|
||||
property string wallet_path
|
||||
property bool allow_background_mining : false
|
||||
property bool miningIgnoreBattery : true
|
||||
property var nettype: NetworkType.MAINNET
|
||||
property int restore_height : 0
|
||||
property bool is_trusted_daemon : false
|
||||
property bool is_trusted_daemon : false // TODO: drop after v0.17.2.0 release
|
||||
property bool is_recovering : false
|
||||
property bool is_recovering_from_device : false
|
||||
property bool customDecorations : true
|
||||
property string daemonFlags
|
||||
property int logLevel: 0
|
||||
property string logCategories: ""
|
||||
property string daemonUsername: ""
|
||||
property string daemonPassword: ""
|
||||
property string daemonUsername: "" // TODO: drop after v0.17.2.0 release
|
||||
property string daemonPassword: "" // TODO: drop after v0.17.2.0 release
|
||||
property bool transferShowAdvanced: false
|
||||
property bool receiveShowAdvanced: false
|
||||
property bool historyShowAdvanced: false
|
||||
property bool historyHumanDates: true
|
||||
property string blockchainDataDir: ""
|
||||
property bool useRemoteNode: false
|
||||
property string remoteNodeAddress: ""
|
||||
property string remoteNodeAddress: "" // TODO: drop after v0.17.2.0 release
|
||||
property string remoteNodesSerialized: JSON.stringify({
|
||||
selected: 0,
|
||||
nodes: remoteNodeAddress != ""
|
||||
? [{
|
||||
address: remoteNodeAddress,
|
||||
username: daemonUsername,
|
||||
password: daemonPassword,
|
||||
trusted: is_trusted_daemon,
|
||||
}]
|
||||
: [],
|
||||
})
|
||||
property string bootstrapNodeAddress: ""
|
||||
property bool segregatePreForkOutputs: true
|
||||
property bool keyReuseMitigation2: true
|
||||
property int segregationHeight: 0
|
||||
property int kdfRounds: 1
|
||||
property bool displayWalletNameInTitleBar: true
|
||||
property bool hideBalance: false
|
||||
property bool askPasswordBeforeSending: true
|
||||
property bool lockOnUserInActivity: true
|
||||
@@ -1414,6 +1418,7 @@ ApplicationWindow {
|
||||
property bool checkForUpdates: true
|
||||
property bool autosave: true
|
||||
property int autosaveMinutes: 10
|
||||
property bool pruneBlockchain: false
|
||||
|
||||
property bool fiatPriceEnabled: false
|
||||
property bool fiatPriceToggle: false
|
||||
@@ -1444,6 +1449,88 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: remoteNodesModel
|
||||
|
||||
property int selected: 0
|
||||
|
||||
signal store()
|
||||
|
||||
function initialize() {
|
||||
try {
|
||||
const remoteNodes = JSON.parse(persistentSettings.remoteNodesSerialized);
|
||||
for (var index = 0; index < remoteNodes.nodes.length; ++index) {
|
||||
const remoteNode = remoteNodes.nodes[index];
|
||||
remoteNodesModel.append(remoteNode);
|
||||
}
|
||||
selected = remoteNodes.selected % remoteNodesModel.count || 0;
|
||||
} catch (e) {
|
||||
console.error('failed to parse remoteNodesSerialized', e);
|
||||
}
|
||||
|
||||
store.connect(function() {
|
||||
var remoteNodes = [];
|
||||
for (var index = 0; index < remoteNodesModel.count; ++index) {
|
||||
remoteNodes.push(remoteNodesModel.get(index));
|
||||
}
|
||||
persistentSettings.remoteNodesSerialized = JSON.stringify({
|
||||
selected: selected,
|
||||
nodes: remoteNodes
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function appendIfNotExists(newRemoteNode) {
|
||||
for (var index = 0; index < remoteNodesModel.count; ++index) {
|
||||
const remoteNode = remoteNodesModel.get(index);
|
||||
if (remoteNode.address == newRemoteNode.address &&
|
||||
remoteNode.username == newRemoteNode.username &&
|
||||
remoteNode.password == newRemoteNode.password &&
|
||||
remoteNode.trusted == newRemoteNode.trusted) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
remoteNodesModel.append(newRemoteNode);
|
||||
return remoteNodesModel.count - 1;
|
||||
}
|
||||
|
||||
function applyRemoteNode(index) {
|
||||
selected = index;
|
||||
const remoteNode = currentRemoteNode();
|
||||
persistentSettings.useRemoteNode = true;
|
||||
if (currentWallet) {
|
||||
currentWallet.setDaemonLogin(remoteNode.username, remoteNode.password);
|
||||
currentWallet.setTrustedDaemon(remoteNode.trusted);
|
||||
appWindow.connectRemoteNode();
|
||||
}
|
||||
}
|
||||
|
||||
function currentRemoteNode() {
|
||||
if (selected < remoteNodesModel.count) {
|
||||
return remoteNodesModel.get(selected);
|
||||
}
|
||||
return {
|
||||
address: "",
|
||||
username: "",
|
||||
password: "",
|
||||
trusted: false,
|
||||
};
|
||||
}
|
||||
|
||||
function removeSelectNextIfNeeded(index) {
|
||||
remoteNodesModel.remove(index);
|
||||
if (selected == index) {
|
||||
applyRemoteNode(selected % remoteNodesModel.count || 0);
|
||||
} else if (selected > index) {
|
||||
selected = selected - 1;
|
||||
}
|
||||
}
|
||||
|
||||
onCountChanged: store()
|
||||
onDataChanged: store()
|
||||
onSelectedChanged: store()
|
||||
}
|
||||
|
||||
// Information dialog
|
||||
StandardDialog {
|
||||
// dynamically change onclose handler
|
||||
@@ -1459,10 +1546,11 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
// Confrirmation aka question dialog
|
||||
StandardDialog {
|
||||
// Transaction confirmation popup
|
||||
TxConfirmationDialog {
|
||||
// dynamically change onclose handler
|
||||
id: txConfirmationPopup
|
||||
z: parent.z + 1
|
||||
id: transactionConfirmationPopup
|
||||
onAccepted: {
|
||||
var handleAccepted = function() {
|
||||
// Save transaction to file if view only wallet
|
||||
@@ -1523,6 +1611,10 @@ ApplicationWindow {
|
||||
y: (parent.height - height) / 2
|
||||
}
|
||||
|
||||
MoneroComponents.RemoteNodeDialog {
|
||||
id: remoteNodeDialog
|
||||
}
|
||||
|
||||
// Choose blockchain folder
|
||||
FileDialog {
|
||||
id: blockchainFileDialog
|
||||
@@ -1694,18 +1786,6 @@ ApplicationWindow {
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onTxkeyClicked: {
|
||||
middlePanel.state = "TxKey";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onSharedringdbClicked: {
|
||||
middlePanel.state = "SharedRingDB";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onHistoryClicked: {
|
||||
middlePanel.state = "History";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
@@ -1718,14 +1798,8 @@ ApplicationWindow {
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onMiningClicked: {
|
||||
middlePanel.state = "Mining";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onSignClicked: {
|
||||
middlePanel.state = "Sign";
|
||||
onAdvancedClicked: {
|
||||
middlePanel.state = "Advanced";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
updateBalance();
|
||||
}
|
||||
@@ -1768,7 +1842,9 @@ ApplicationWindow {
|
||||
anchors.fill: blurredArea
|
||||
source: blurredArea
|
||||
radius: 64
|
||||
visible: passwordDialog.visible || inputDialog.visible || splash.visible || updateDialog.visible || devicePassphraseDialog.visible || successfulTxPopup.visible
|
||||
visible: passwordDialog.visible || inputDialog.visible || splash.visible || updateDialog.visible ||
|
||||
devicePassphraseDialog.visible || txConfirmationPopup.visible || successfulTxPopup.visible ||
|
||||
remoteNodeDialog.visible
|
||||
}
|
||||
|
||||
|
||||
@@ -1821,7 +1897,7 @@ ApplicationWindow {
|
||||
TitleBar {
|
||||
id: titleBar
|
||||
visible: persistentSettings.customDecorations && middlePanel.state !== "Merchant"
|
||||
walletName: appWindow.walletName
|
||||
walletName: persistentSettings.displayWalletNameInTitleBar ? appWindow.walletName : ""
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
onCloseClicked: appWindow.close();
|
||||
@@ -1874,11 +1950,6 @@ ApplicationWindow {
|
||||
function toggleLanguageView(){
|
||||
languageSidebar.isOpened ? languageSidebar.close() : languageSidebar.open();
|
||||
resetLanguageFields()
|
||||
// update after changing language from settings page
|
||||
if (persistentSettings.language != wizard.language_language) {
|
||||
persistentSettings.language = wizard.language_language
|
||||
persistentSettings.locale = wizard.language_locale
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
@@ -1953,12 +2024,13 @@ ApplicationWindow {
|
||||
return;
|
||||
}
|
||||
|
||||
const simpleModeFlags = "--enable-dns-blocklist --out-peers 16";
|
||||
if (appWindow.daemonRunning) {
|
||||
appWindow.stopDaemon(function() {
|
||||
appWindow.startDaemon("")
|
||||
appWindow.startDaemon(simpleModeFlags)
|
||||
});
|
||||
} else {
|
||||
appWindow.startDaemon("");
|
||||
appWindow.startDaemon(simpleModeFlags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2162,6 +2234,7 @@ ApplicationWindow {
|
||||
|
||||
passwordDialog.onRejectedCallback = function() { appWindow.showWizard(); }
|
||||
if (inputDialogVisible) inputDialog.close()
|
||||
remoteNodeDialog.close();
|
||||
passwordDialog.open();
|
||||
}
|
||||
|
||||
|
||||
2
monero
2
monero
Submodule monero updated: 76cc82c292...f6e63ef260
@@ -1,581 +0,0 @@
|
||||
# qml components require at least QT 5.9.7
|
||||
lessThan (QT_MAJOR_VERSION, 5) | lessThan (QT_MINOR_VERSION, 9) {
|
||||
error("Can't build with Qt $${QT_VERSION}. Use at least Qt 5.9.7")
|
||||
}
|
||||
|
||||
TEMPLATE = app
|
||||
|
||||
QT += svg qml gui-private quick widgets
|
||||
|
||||
WALLET_ROOT=$$PWD/monero
|
||||
|
||||
CONFIG += c++11 link_pkgconfig
|
||||
packagesExist(libusb-1.0) {
|
||||
PKGCONFIG += libusb-1.0
|
||||
}
|
||||
packagesExist(hidapi-libusb) {
|
||||
PKGCONFIG += hidapi-libusb
|
||||
}
|
||||
|
||||
GCC_VERSION = $$system("g++ -dumpversion")
|
||||
GCC_VERSION = $$split(GCC_VERSION, .)
|
||||
GCC_VERSION_MAJOR = $$member(GCC_VERSION, 0)
|
||||
GCC_VERSION_MINOR = $$member(GCC_VERSION, 1)
|
||||
greaterThan(GCC_VERSION_MAJOR, 9) | if(equals(GCC_VERSION_MAJOR, 9) : greaterThan(GCC_VERSION_MINOR, 0)) {
|
||||
GCC_9_1_OR_GREATER = TRUE
|
||||
}
|
||||
|
||||
!win32 | !isEmpty(GCC_9_1_OR_GREATER) {
|
||||
QMAKE_CXXFLAGS += -fPIC -fstack-protector -fstack-protector-strong
|
||||
QMAKE_LFLAGS += -fstack-protector -fstack-protector-strong
|
||||
}
|
||||
|
||||
!win32 {
|
||||
packagesExist(protobuf) {
|
||||
PKGCONFIG += protobuf
|
||||
}
|
||||
}
|
||||
|
||||
# cleaning "auto-generated" bitmonero directory on "make distclean"
|
||||
QMAKE_DISTCLEAN += -r $$WALLET_ROOT
|
||||
|
||||
INCLUDEPATH += $$WALLET_ROOT/include \
|
||||
$$PWD/src/libwalletqt \
|
||||
$$PWD/src/QR-Code-generator \
|
||||
$$PWD/src \
|
||||
$$WALLET_ROOT/src \
|
||||
$$WALLET_ROOT/external/easylogging++ \
|
||||
$$WALLET_ROOT/contrib/epee/include
|
||||
|
||||
HEADERS += \
|
||||
src/main/filter.h \
|
||||
src/main/clipboardAdapter.h \
|
||||
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 \
|
||||
src/libwalletqt/QRCodeImageProvider.h \
|
||||
src/libwalletqt/Transfer.h \
|
||||
src/NetworkType.h \
|
||||
src/main/oshelper.h \
|
||||
src/TranslationManager.h \
|
||||
src/model/TransactionHistoryModel.h \
|
||||
src/model/TransactionHistorySortFilterModel.h \
|
||||
src/QR-Code-generator/BitBuffer.hpp \
|
||||
src/QR-Code-generator/QrCode.hpp \
|
||||
src/QR-Code-generator/QrSegment.hpp \
|
||||
src/model/AddressBookModel.h \
|
||||
src/libwalletqt/AddressBook.h \
|
||||
src/model/SubaddressModel.h \
|
||||
src/libwalletqt/Subaddress.h \
|
||||
src/model/SubaddressAccountModel.h \
|
||||
src/libwalletqt/SubaddressAccount.h \
|
||||
src/zxcvbn-c/zxcvbn.h \
|
||||
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/macoshelper.h \
|
||||
src/qt/MoneroSettings.h \
|
||||
src/qt/TailsOS.h
|
||||
|
||||
SOURCES += src/main/main.cpp \
|
||||
src/main/filter.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 \
|
||||
src/QR-Code-generator/BitBuffer.cpp \
|
||||
src/QR-Code-generator/QrCode.cpp \
|
||||
src/QR-Code-generator/QrSegment.cpp \
|
||||
src/model/AddressBookModel.cpp \
|
||||
src/libwalletqt/AddressBook.cpp \
|
||||
src/model/SubaddressModel.cpp \
|
||||
src/libwalletqt/Subaddress.cpp \
|
||||
src/model/SubaddressAccountModel.cpp \
|
||||
src/libwalletqt/SubaddressAccount.cpp \
|
||||
src/zxcvbn-c/zxcvbn.c \
|
||||
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/MoneroSettings.cpp \
|
||||
src/qt/TailsOS.cpp
|
||||
|
||||
CONFIG(DISABLE_PASS_STRENGTH_METER) {
|
||||
HEADERS -= src/zxcvbn-c/zxcvbn.h
|
||||
SOURCES -= src/zxcvbn-c/zxcvbn.c
|
||||
DEFINES += "DISABLE_PASS_STRENGTH_METER"
|
||||
}
|
||||
|
||||
!ios {
|
||||
HEADERS += src/daemon/DaemonManager.h
|
||||
SOURCES += src/daemon/DaemonManager.cpp
|
||||
}
|
||||
|
||||
lupdate_only {
|
||||
SOURCES = *.qml \
|
||||
components/*.qml \
|
||||
components/effects/*.qml \
|
||||
pages/*.qml \
|
||||
pages/settings/*.qml \
|
||||
pages/merchant/*.qml \
|
||||
wizard/*.qml \
|
||||
wizard/*js
|
||||
}
|
||||
|
||||
# Linker flags required by Trezor
|
||||
TREZOR_LINKER = $$cat($$WALLET_ROOT/lib/trezor_link_flags.txt)
|
||||
|
||||
ios:armv7 {
|
||||
message("target is armv7")
|
||||
LIBS += \
|
||||
-L$$PWD/../ofxiOSBoost/build/libs/boost/lib/armv7 \
|
||||
}
|
||||
ios:arm64 {
|
||||
message("target is arm64")
|
||||
LIBS += \
|
||||
-L$$PWD/../ofxiOSBoost/build/libs/boost/lib/arm64 \
|
||||
}
|
||||
|
||||
LIBS_COMMON = \
|
||||
-lgcrypt \
|
||||
-lgpg-error \
|
||||
-lwallet_merged \
|
||||
-llmdb \
|
||||
-lepee \
|
||||
-lunbound \
|
||||
-lsodium \
|
||||
-leasylogging \
|
||||
-lrandomx
|
||||
|
||||
!ios:!android {
|
||||
LIBS += -L$$WALLET_ROOT/lib \
|
||||
$$LIBS_COMMON
|
||||
}
|
||||
|
||||
android {
|
||||
message("Host is Android")
|
||||
LIBS += -L$$WALLET_ROOT/lib \
|
||||
$$LIBS_COMMON
|
||||
}
|
||||
|
||||
|
||||
|
||||
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")
|
||||
|
||||
QMAKE_LFLAGS += -v
|
||||
QMAKE_IOS_DEVICE_ARCHS = arm64
|
||||
CONFIG += arm64
|
||||
LIBS += -L$$WALLET_ROOT/lib-ios \
|
||||
$$LIBS_COMMON
|
||||
|
||||
LIBS+= \
|
||||
-L$$PWD/../OpenSSL-for-iPhone/lib \
|
||||
-L$$PWD/../ofxiOSBoost/build/libs/boost/lib/arm64 \
|
||||
-lboost_serialization \
|
||||
-lboost_thread \
|
||||
-lboost_system \
|
||||
-lboost_date_time \
|
||||
-lboost_filesystem \
|
||||
-lboost_regex \
|
||||
-lboost_chrono \
|
||||
-lboost_program_options \
|
||||
-lssl \
|
||||
-lcrypto \
|
||||
-ldl
|
||||
}
|
||||
|
||||
CONFIG(WITH_SCANNER) {
|
||||
if( greaterThan(QT_MINOR_VERSION, 5) ) {
|
||||
message("using camera scanner")
|
||||
QT += multimedia
|
||||
DEFINES += "WITH_SCANNER"
|
||||
INCLUDEPATH += $$PWD/src/QR-Code-scanner
|
||||
HEADERS += \
|
||||
src/QR-Code-scanner/QrScanThread.h \
|
||||
src/QR-Code-scanner/QrCodeScanner.h
|
||||
SOURCES += \
|
||||
src/QR-Code-scanner/QrScanThread.cpp \
|
||||
src/QR-Code-scanner/QrCodeScanner.cpp
|
||||
android {
|
||||
INCLUDEPATH += $$PWD/../ZBar/include
|
||||
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 !")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# currently we only support x86 build as qt.io only provides prebuilt qt for x86 mingw
|
||||
|
||||
win32 {
|
||||
|
||||
# QMAKE_HOST.arch is unreliable, will allways report 32bit if mingw32 shell is run.
|
||||
# Obtaining arch through uname should be reliable. This also fixes building the project in Qt creator without changes.
|
||||
MSYS_HOST_ARCH = $$system(uname -a | grep -o "x86_64")
|
||||
|
||||
# WIN64 Host settings
|
||||
contains(MSYS_HOST_ARCH, x86_64) {
|
||||
message("Host is 64bit")
|
||||
MSYS_ROOT_PATH=c:/msys64
|
||||
|
||||
# WIN32 Host settings
|
||||
} else {
|
||||
message("Host is 32bit")
|
||||
MSYS_ROOT_PATH=c:/msys32
|
||||
}
|
||||
|
||||
# WIN64 Target settings
|
||||
contains(QMAKE_HOST.arch, x86_64) {
|
||||
MSYS_MINGW_PATH=/mingw64
|
||||
|
||||
# WIN32 Target settings
|
||||
} else {
|
||||
MSYS_MINGW_PATH=/mingw32
|
||||
}
|
||||
|
||||
MSYS_PATH=$$MSYS_ROOT_PATH$$MSYS_MINGW_PATH
|
||||
|
||||
# boost root path
|
||||
BOOST_PATH=$$MSYS_PATH/boost
|
||||
BOOST_MINGW_PATH=$$MSYS_MINGW_PATH/boost
|
||||
|
||||
LIBS+=-L$$MSYS_PATH/lib
|
||||
LIBS+=-L$$MSYS_MINGW_PATH/lib
|
||||
LIBS+=-L$$BOOST_PATH/lib
|
||||
LIBS+=-L$$BOOST_MINGW_PATH/lib
|
||||
|
||||
QMAKE_LFLAGS += -static-libgcc -static-libstdc++
|
||||
|
||||
LIBS+= \
|
||||
-Wl,-Bdynamic \
|
||||
-lwinscard \
|
||||
-lwsock32 \
|
||||
-lIphlpapi \
|
||||
-lcrypt32 \
|
||||
-lhidapi \
|
||||
-lgdi32 $$TREZOR_LINKER \
|
||||
-Wl,-Bstatic \
|
||||
-lboost_serialization-mt \
|
||||
-lboost_thread-mt \
|
||||
-lboost_system-mt \
|
||||
-lboost_date_time-mt \
|
||||
-lboost_filesystem-mt \
|
||||
-lboost_regex-mt \
|
||||
-lboost_chrono-mt \
|
||||
-lboost_program_options-mt \
|
||||
-lboost_locale-mt \
|
||||
-licuio \
|
||||
-licuin \
|
||||
-licuuc \
|
||||
-licudt \
|
||||
-licutu \
|
||||
-liconv \
|
||||
-lstdc++ \
|
||||
-lpthread \
|
||||
-lsetupapi \
|
||||
-lssl \
|
||||
-lsodium \
|
||||
-lcrypto \
|
||||
-lws2_32 \
|
||||
-lole32
|
||||
|
||||
!contains(QMAKE_TARGET.arch, x86_64) {
|
||||
message("Target is 32bit")
|
||||
## Windows x86 (32bit) specific build here
|
||||
## there's 2Mb stack in libwallet allocated internally, so we set stack=4Mb
|
||||
## this fixes app crash for x86 Windows build
|
||||
QMAKE_LFLAGS += -Wl,--stack,4194304
|
||||
} else {
|
||||
message("Target is 64bit")
|
||||
}
|
||||
|
||||
QMAKE_LFLAGS += -Wl,--dynamicbase -Wl,--nxcompat
|
||||
}
|
||||
|
||||
linux {
|
||||
CONFIG(static) {
|
||||
message("using static libraries")
|
||||
LIBS+= -Wl,-Bstatic
|
||||
QMAKE_LFLAGS += -static-libgcc -static-libstdc++
|
||||
QMAKE_LIBDIR += /usr/local/ssl/lib
|
||||
# contains(QT_ARCH, x86_64) {
|
||||
LIBS+= -lunbound \
|
||||
-lusb-1.0 \
|
||||
-lhidapi-hidraw \
|
||||
-ludev
|
||||
# }
|
||||
} else {
|
||||
# On some distro's we need to add dynload
|
||||
LIBS+= -ldl
|
||||
}
|
||||
|
||||
LIBS+= \
|
||||
-lboost_serialization \
|
||||
-lboost_thread \
|
||||
-lboost_system \
|
||||
-lboost_date_time \
|
||||
-lboost_filesystem \
|
||||
-lboost_regex \
|
||||
-lboost_chrono \
|
||||
-lboost_program_options \
|
||||
-lssl \
|
||||
-llmdb \
|
||||
-lsodium \
|
||||
-lhidapi-libusb \
|
||||
-lcrypto $$TREZOR_LINKER
|
||||
|
||||
if(!android) {
|
||||
LIBS+= \
|
||||
-Wl,-Bdynamic \
|
||||
-lGL \
|
||||
-lX11
|
||||
}
|
||||
# currently monero has an issue with "static" build and linunwind-dev,
|
||||
# so we link libunwind-dev only for non-Ubuntu distros
|
||||
CONFIG(libunwind_off) {
|
||||
message(Building without libunwind)
|
||||
} else {
|
||||
message(Building with libunwind)
|
||||
LIBS += -Wl,-Bdynamic -lunwind
|
||||
}
|
||||
|
||||
QMAKE_LFLAGS += -pie -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack
|
||||
}
|
||||
|
||||
macx {
|
||||
# mixing static and shared libs are not supported on mac
|
||||
# CONFIG(static) {
|
||||
# message("using static libraries")
|
||||
# LIBS+= -Wl,-Bstatic
|
||||
# }
|
||||
|
||||
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) {
|
||||
INCLUDEPATH += $$BOOST_DIR/include
|
||||
} else {
|
||||
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
|
||||
OBJECTIVE_SOURCES += src/qt/macoshelper.mm
|
||||
LIBS+= -Wl,-dead_strip
|
||||
LIBS+= -Wl,-dead_strip_dylibs
|
||||
LIBS+= -Wl,-bind_at_load
|
||||
LIBS+= \
|
||||
-L/usr/local/lib \
|
||||
-L$$OPENSSL_LIBRARY_DIR \
|
||||
-L/usr/local/opt/boost/lib \
|
||||
-lboost_serialization \
|
||||
-lboost_thread-mt \
|
||||
-lboost_system \
|
||||
-lboost_date_time \
|
||||
-lboost_filesystem \
|
||||
-lboost_regex \
|
||||
-lboost_chrono \
|
||||
-lboost_program_options \
|
||||
-framework CoreFoundation \
|
||||
-framework AppKit \
|
||||
-lhidapi \
|
||||
-lssl \
|
||||
-lsodium \
|
||||
-lcrypto \
|
||||
-ldl $$TREZOR_LINKER
|
||||
|
||||
QMAKE_LFLAGS += -pie
|
||||
}
|
||||
|
||||
|
||||
# translation stuff
|
||||
TRANSLATIONS = $$files($$PWD/translations/monero-core_*.ts)
|
||||
|
||||
CONFIG(release, debug|release) {
|
||||
DESTDIR = release/bin
|
||||
LANGUPD_OPTIONS = -locations none -no-ui-lines -no-obsolete
|
||||
LANGREL_OPTIONS = -compress -nounfinished -removeidentical
|
||||
|
||||
} else {
|
||||
DESTDIR = debug/bin
|
||||
LANGUPD_OPTIONS =
|
||||
# LANGREL_OPTIONS = -markuntranslated "MISS_TR "
|
||||
}
|
||||
|
||||
TRANSLATION_TARGET_DIR = $$OUT_PWD/translations
|
||||
|
||||
!ios {
|
||||
isEmpty(QMAKE_LUPDATE) {
|
||||
win32:LANGUPD = $$[QT_INSTALL_BINS]\lupdate.exe
|
||||
else:LANGUPD = $$[QT_INSTALL_BINS]/lupdate
|
||||
}
|
||||
|
||||
isEmpty(QMAKE_LRELEASE) {
|
||||
win32:LANGREL = $$[QT_INSTALL_BINS]\lrelease.exe
|
||||
else:LANGREL = $$[QT_INSTALL_BINS]/lrelease
|
||||
}
|
||||
|
||||
langupd.command = \
|
||||
$$LANGUPD $$LANGUPD_OPTIONS $$shell_path($$_PRO_FILE) -ts $$_PRO_FILE_PWD/$$TRANSLATIONS
|
||||
|
||||
|
||||
|
||||
langrel.depends = langupd
|
||||
langrel.input = TRANSLATIONS
|
||||
langrel.output = $$TRANSLATION_TARGET_DIR/${QMAKE_FILE_BASE}.qm
|
||||
langrel.commands = \
|
||||
$$LANGREL $$LANGREL_OPTIONS ${QMAKE_FILE_IN} -qm $$TRANSLATION_TARGET_DIR/${QMAKE_FILE_BASE}.qm
|
||||
langrel.CONFIG += no_link
|
||||
|
||||
QMAKE_EXTRA_TARGETS += langupd deploy deploy_win
|
||||
QMAKE_EXTRA_COMPILERS += langrel
|
||||
|
||||
# Compile an initial version of translation files when running qmake
|
||||
# the first time and generate the resource file for translations.
|
||||
!exists($$TRANSLATION_TARGET_DIR) {
|
||||
mkpath($$TRANSLATION_TARGET_DIR)
|
||||
}
|
||||
qrc_entry = "<RCC>"
|
||||
qrc_entry += ' <qresource prefix="/">'
|
||||
write_file($$TRANSLATION_TARGET_DIR/translations.qrc, qrc_entry)
|
||||
for(tsfile, TRANSLATIONS) {
|
||||
qmfile = $$TRANSLATION_TARGET_DIR/$$basename(tsfile)
|
||||
qmfile ~= s/.ts$/.qm/
|
||||
system($$LANGREL $$LANGREL_OPTIONS $$tsfile -qm $$qmfile)
|
||||
qrc_entry = " <file>$$basename(qmfile)</file>"
|
||||
write_file($$TRANSLATION_TARGET_DIR/translations.qrc, qrc_entry, append)
|
||||
}
|
||||
qrc_entry = " </qresource>"
|
||||
qrc_entry += "</RCC>"
|
||||
write_file($$TRANSLATION_TARGET_DIR/translations.qrc, qrc_entry, append)
|
||||
RESOURCES += $$TRANSLATION_TARGET_DIR/translations.qrc
|
||||
}
|
||||
|
||||
|
||||
# Update: no issues with the "slow link process" anymore,
|
||||
# for development, just build debug version of libwallet_merged lib
|
||||
# by invoking 'get_libwallet_api.sh Debug'
|
||||
# so we update translations everytime even for debug build
|
||||
|
||||
PRE_TARGETDEPS += langupd compiler_langrel_make_all
|
||||
|
||||
RESOURCES += qml.qrc
|
||||
CONFIG += qtquickcompiler
|
||||
|
||||
# Additional import path used to resolve QML modules in Qt Creator's code model
|
||||
QML_IMPORT_PATH = fonts
|
||||
|
||||
# Default rules for deployment.
|
||||
include(deployment.pri)
|
||||
macx {
|
||||
deploy.commands += macdeployqt $$sprintf("%1/%2/%3.app", $$OUT_PWD, $$DESTDIR, $$TARGET) -qmldir=$$PWD
|
||||
}
|
||||
|
||||
win32 {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
linux:!android {
|
||||
deploy.commands += $$escape_expand(\n\t) $$PWD/linuxdeploy_helper.sh $$DESTDIR $$TARGET
|
||||
}
|
||||
|
||||
android{
|
||||
deploy.commands += make install INSTALL_ROOT=$$DESTDIR && androiddeployqt --input android-libmonero-wallet-gui.so-deployment-settings.json --output $$DESTDIR --deployment bundled --android-platform android-21 --jdk /usr/lib/jvm/java-8-openjdk-amd64 -qmldir=$$PWD
|
||||
}
|
||||
|
||||
|
||||
OTHER_FILES += \
|
||||
.gitignore \
|
||||
$$TRANSLATIONS
|
||||
|
||||
DISTFILES += \
|
||||
notes.txt \
|
||||
monero/src/wallet/CMakeLists.txt
|
||||
|
||||
VERSION = $$cat('version.js', lines)
|
||||
VERSION = $$find(VERSION, 'GUI_VERSION')
|
||||
VERSION_LONG = $$replace(VERSION, '.*\"(.*)\"', '\1')
|
||||
VERSION = $$replace(VERSION, '.*(\d+\.\d+\.\d+\.\d+).*', '\1')
|
||||
|
||||
# windows application icon
|
||||
RC_ICONS = images/appicon.ico
|
||||
|
||||
# mac Info.plist & application icon
|
||||
QMAKE_INFO_PLIST = $$PWD/share/Info.plist
|
||||
macx {
|
||||
QMAKE_POST_LINK += sed -i "''" -e "s/@VERSION@/$$VERSION/g" -e "s/@VERSION_LONG@/$$VERSION_LONG/g" "$$sprintf("%1/%2/%3.app", $$OUT_PWD, $$DESTDIR, $$TARGET)/Contents/Info.plist";
|
||||
}
|
||||
ICON = $$PWD/images/appicon.icns
|
||||
@@ -190,7 +190,7 @@ Rectangle {
|
||||
height: subaddressAccountListRow.subaddressAccountListItemHeight
|
||||
width: parent ? parent.width : undefined
|
||||
Layout.fillWidth: true
|
||||
color: "transparent"
|
||||
color: itemMouseArea.containsMouse || index === currentAccountIndex ? MoneroComponents.Style.titleBarButtonHoverColor : "transparent"
|
||||
|
||||
Rectangle {
|
||||
color: MoneroComponents.Style.appWindowBorderColor
|
||||
@@ -226,7 +226,7 @@ Rectangle {
|
||||
|
||||
MoneroComponents.Label {
|
||||
id: nameLabel
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
color: index === currentAccountIndex ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: idLabel.right
|
||||
anchors.leftMargin: 6
|
||||
@@ -276,11 +276,10 @@ Rectangle {
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: itemMouseArea
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: tableItem2.color = MoneroComponents.Style.titleBarButtonHoverColor
|
||||
onExited: tableItem2.color = "transparent"
|
||||
onClicked: {
|
||||
appWindow.currentWallet.switchSubaddressAccount(index);
|
||||
if (selectAndSend)
|
||||
|
||||
@@ -132,13 +132,13 @@ Rectangle {
|
||||
delegate: Rectangle {
|
||||
id: tableItem2
|
||||
height: addressBookListRow.addressBookListItemHeight
|
||||
width: parent.width
|
||||
width: parent ? parent.width : undefined
|
||||
Layout.fillWidth: true
|
||||
color: "transparent"
|
||||
|
||||
function doSend() {
|
||||
console.log("Sending to: ", address +" "+ paymentId);
|
||||
middlePanel.sendTo(address, paymentId, description);
|
||||
middlePanel.sendTo(address, paymentId);
|
||||
leftPanel.selectItem(middlePanel.state)
|
||||
}
|
||||
|
||||
@@ -314,16 +314,16 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
inlineButton.text: FontAwesome.qrcode
|
||||
inlineButton.fontPixelSize: 22
|
||||
inlineButton.fontFamily: FontAwesome.fontFamily
|
||||
inlineButton.textColor: MoneroComponents.Style.defaultFontColor
|
||||
inlineButton.buttonColor: MoneroComponents.Style.orange
|
||||
inlineButton.onClicked: {
|
||||
cameraUi.state = "Capture"
|
||||
cameraUi.qrcode_decoded.connect(root.updateFromQrCode)
|
||||
MoneroComponents.InlineButton {
|
||||
buttonColor: MoneroComponents.Style.orange
|
||||
fontFamily: FontAwesome.fontFamily
|
||||
text: FontAwesome.qrcode
|
||||
visible : appWindow.qrScannerEnabled && !addressLine.text
|
||||
onClicked: {
|
||||
cameraUi.state = "Capture"
|
||||
cameraUi.qrcode_decoded.connect(root.updateFromQrCode)
|
||||
}
|
||||
}
|
||||
inlineButtonVisible : appWindow.qrScannerEnabled && !addressLine.text
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
|
||||
148
pages/Advanced.qml
Normal file
148
pages/Advanced.qml
Normal file
@@ -0,0 +1,148 @@
|
||||
// Copyright (c) 2021, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Layouts 1.1
|
||||
import "../components" as MoneroComponents
|
||||
import "."
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 900
|
||||
spacing: 0
|
||||
property int panelHeight: 900
|
||||
property alias miningView: stateView.miningView
|
||||
property alias state: stateView.state
|
||||
|
||||
MoneroComponents.Navbar {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: height
|
||||
Layout.bottomMargin: height
|
||||
|
||||
MoneroComponents.NavbarItem {
|
||||
active: state == "Mining"
|
||||
text: qsTr("Mining") + translationManager.emptyString
|
||||
onSelected: state = "Mining"
|
||||
}
|
||||
MoneroComponents.NavbarItem {
|
||||
active: state == "Prove"
|
||||
text: qsTr("Prove/check") + translationManager.emptyString
|
||||
onSelected: state = "Prove"
|
||||
}
|
||||
MoneroComponents.NavbarItem {
|
||||
active: state == "SharedRingDB"
|
||||
text: qsTr("Shared RingDB") + translationManager.emptyString
|
||||
onSelected: state = "SharedRingDB"
|
||||
}
|
||||
MoneroComponents.NavbarItem {
|
||||
active: state == "Sign"
|
||||
text: qsTr("Sign/verify") + translationManager.emptyString
|
||||
onSelected: state = "Sign"
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle{
|
||||
id: stateView
|
||||
property Item currentView
|
||||
property Item previousView
|
||||
property Mining miningView: Mining { }
|
||||
property TxKey prooveView: TxKey { }
|
||||
property SharedRingDB sharedRingDBView: SharedRingDB { }
|
||||
property Sign signView: Sign { }
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: panelHeight
|
||||
color: "transparent"
|
||||
state: "Mining"
|
||||
|
||||
onCurrentViewChanged: {
|
||||
if (previousView) {
|
||||
if (typeof previousView.onPageClosed === "function") {
|
||||
previousView.onPageClosed();
|
||||
}
|
||||
}
|
||||
previousView = currentView
|
||||
if (currentView) {
|
||||
stackView.replace(currentView)
|
||||
if (typeof currentView.onPageCompleted === "function") {
|
||||
currentView.onPageCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "Mining"
|
||||
PropertyChanges { target: stateView; currentView: stateView.miningView }
|
||||
PropertyChanges { target: root; panelHeight: stateView.miningView.miningHeight + 140 }
|
||||
}, State {
|
||||
name: "Prove"
|
||||
PropertyChanges { target: stateView; currentView: stateView.prooveView }
|
||||
PropertyChanges { target: root; panelHeight: stateView.prooveView.txkeyHeight + 140 }
|
||||
}, State {
|
||||
name: "SharedRingDB"
|
||||
PropertyChanges { target: stateView; currentView: stateView.sharedRingDBView }
|
||||
PropertyChanges { target: root; panelHeight: stateView.sharedRingDBView.panelHeight + 140 }
|
||||
}, State {
|
||||
name: "Sign"
|
||||
PropertyChanges { target: stateView; currentView: stateView.signView }
|
||||
PropertyChanges { target: root; panelHeight: stateView.signView.signHeight + 140 }
|
||||
}
|
||||
]
|
||||
|
||||
StackView {
|
||||
id: stackView
|
||||
initialItem: stateView.miningView
|
||||
anchors.fill: parent
|
||||
clip: false // otherwise animation will affect left panel
|
||||
|
||||
delegate: StackViewDelegate {
|
||||
pushTransition: StackViewTransition {
|
||||
PropertyAnimation {
|
||||
target: enterItem
|
||||
property: "x"
|
||||
from: 0 - target.width
|
||||
to: 0
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
PropertyAnimation {
|
||||
target: exitItem
|
||||
property: "x"
|
||||
from: 0
|
||||
to: target.width
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,7 +127,7 @@ Rectangle {
|
||||
image: "qrc:///images/whiteDropIndicator.png"
|
||||
fontAwesomeFallbackIcon: FontAwesome.arrowDown
|
||||
fontAwesomeFallbackSize: 14
|
||||
rotation: sortAndFilter.collapsed ? 0 : 180
|
||||
rotation: sortAndFilter.collapsed ? 180 : 0
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
|
||||
MouseArea {
|
||||
@@ -771,7 +771,6 @@ Rectangle {
|
||||
return qsTr("Waiting confirmation...") + translationManager.emptyString;
|
||||
}
|
||||
if (address) {
|
||||
const addressBookName = currentWallet ? currentWallet.addressBook.getDescription(address) : null;
|
||||
return (addressBookName ? FontAwesome.addressBook + " " + addressBookName : TxUtils.addressTruncate(address, 8));
|
||||
}
|
||||
if (amount != 0) {
|
||||
@@ -780,8 +779,6 @@ Rectangle {
|
||||
return qsTr("My wallet") + translationManager.emptyString;
|
||||
}
|
||||
} else {
|
||||
const receivingAddress = currentWallet ? currentWallet.address(subaddrAccount, subaddrIndex) : null;
|
||||
const receivingAddressLabel = currentWallet ? appWindow.currentWallet.getSubaddressLabel(subaddrAccount, subaddrIndex) : null;
|
||||
if (receivingAddress) {
|
||||
if (subaddrIndex == 0) {
|
||||
return qsTr("Address") + " #0" + " (" + qsTr("Primary address") + ")" + translationManager.emptyString;
|
||||
@@ -1417,6 +1414,12 @@ Rectangle {
|
||||
txs.push(item);
|
||||
} else if(item.address !== "" && item.address.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
|
||||
txs.push(item);
|
||||
} else if(item.receivingAddress !== "" && item.receivingAddress.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
|
||||
txs.push(item);
|
||||
} else if(item.receivingAddressLabel !== "" && item.receivingAddressLabel.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
|
||||
txs.push(item);
|
||||
} else if(item.addressBookName !== "" && item.addressBookName.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
|
||||
txs.push(item);
|
||||
} else if(typeof item.blockheight !== "undefined" && item.blockheight.toString().startsWith(root.sortSearchString)) {
|
||||
txs.push(item);
|
||||
} else if(item.tx_note.toLowerCase().indexOf(root.sortSearchString.toLowerCase()) !== -1) {
|
||||
@@ -1522,8 +1525,16 @@ Rectangle {
|
||||
|
||||
var tx_note = currentWallet.getUserNote(hash);
|
||||
var address = "";
|
||||
if(isout) {
|
||||
var addressBookName = "";
|
||||
var receivingAddress = "";
|
||||
var receivingAddressLabel = "";
|
||||
|
||||
if (isout) {
|
||||
address = TxUtils.destinationsToAddress(destinations);
|
||||
addressBookName = currentWallet ? currentWallet.addressBook.getDescription(address) : null;
|
||||
} else {
|
||||
receivingAddress = currentWallet ? currentWallet.address(subaddrAccount, subaddrIndex) : null;
|
||||
receivingAddressLabel = currentWallet ? appWindow.currentWallet.getSubaddressLabel(subaddrAccount, subaddrIndex) : null;
|
||||
}
|
||||
|
||||
if (isout)
|
||||
@@ -1541,6 +1552,7 @@ Rectangle {
|
||||
"hash": hash,
|
||||
"paymentId": paymentId,
|
||||
"address": address,
|
||||
"addressBookName": addressBookName,
|
||||
"destinations": destinations,
|
||||
"tx_note": tx_note,
|
||||
"dateHuman": dateHuman,
|
||||
@@ -1551,6 +1563,8 @@ Rectangle {
|
||||
"fee": fee,
|
||||
"confirmations": confirmations,
|
||||
"confirmationsRequired": confirmationsRequired,
|
||||
"receivingAddress": receivingAddress,
|
||||
"receivingAddressLabel": receivingAddressLabel,
|
||||
"subaddrAccount": subaddrAccount,
|
||||
"subaddrIndex": subaddrIndex
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ Rectangle {
|
||||
id: mainLayout
|
||||
Layout.fillWidth: true
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 40
|
||||
anchors.topMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
|
||||
@@ -107,7 +107,7 @@ Rectangle {
|
||||
height: subaddressListRow.subaddressListItemHeight
|
||||
width: parent ? parent.width : undefined
|
||||
Layout.fillWidth: true
|
||||
color: "transparent"
|
||||
color: itemMouseArea.containsMouse || index === appWindow.current_subaddress_table_index ? MoneroComponents.Style.titleBarButtonHoverColor : "transparent"
|
||||
|
||||
Rectangle{
|
||||
anchors.right: parent.right
|
||||
@@ -143,7 +143,7 @@ Rectangle {
|
||||
|
||||
MoneroComponents.Label {
|
||||
id: nameLabel
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
color: index === appWindow.current_subaddress_table_index ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: idLabel.right
|
||||
anchors.leftMargin: 6
|
||||
@@ -167,11 +167,10 @@ Rectangle {
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: itemMouseArea
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: tableItem2.color = MoneroComponents.Style.titleBarButtonHoverColor
|
||||
onExited: tableItem2.color = "transparent"
|
||||
onClicked: subaddressListView.currentIndex = index;
|
||||
}
|
||||
}
|
||||
@@ -299,18 +298,6 @@ Rectangle {
|
||||
onClicked: qrFileDialog.open()
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
Layout.preferredWidth: 220
|
||||
small: true
|
||||
text: FontAwesome.clipboard + " %1".arg(qsTr("Copy to clipboard")) + translationManager.emptyString
|
||||
label.font.family: FontAwesome.fontFamily
|
||||
fontSize: 13
|
||||
onClicked: {
|
||||
clipboard.setText(TxUtils.makeQRCodeString(appWindow.current_address));
|
||||
appWindow.showStatusMessage(qsTr("Copied to clipboard") + translationManager.emptyString, 3);
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
Layout.preferredWidth: 220
|
||||
small: true
|
||||
|
||||
@@ -81,8 +81,7 @@ Rectangle {
|
||||
id: mainLayout
|
||||
Layout.fillWidth: true
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 40
|
||||
|
||||
anchors.topMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
|
||||
@@ -89,8 +89,7 @@ Rectangle {
|
||||
id: mainLayout
|
||||
Layout.fillWidth: true
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 40
|
||||
|
||||
anchors.topMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQml.Models 2.2
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Layouts 1.1
|
||||
@@ -44,8 +45,7 @@ import "../js/Utils.js" as Utils
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
signal paymentClicked(string address, string paymentId, string amount, int mixinCount,
|
||||
int priority, string description)
|
||||
signal paymentClicked(var recipients, string paymentId, int mixinCount, int priority, string description)
|
||||
signal sweepUnmixableClicked()
|
||||
|
||||
color: "transparent"
|
||||
@@ -61,19 +61,18 @@ Rectangle {
|
||||
}
|
||||
|
||||
// There are sufficient unlocked funds available
|
||||
if (walletManager.amountFromString(amountLine.text) > appWindow.getUnlockedBalance()) {
|
||||
if (recipientModel.getAmountTotal() > appWindow.getUnlockedBalance()) {
|
||||
return qsTr("Amount is more than unlocked balance.") + translationManager.emptyString;
|
||||
}
|
||||
|
||||
if (addressLine.text)
|
||||
{
|
||||
if (!recipientModel.hasEmptyAddress()) {
|
||||
// Address is valid
|
||||
if (!TxUtils.checkAddress(addressLine.text, appWindow.persistentSettings.nettype)) {
|
||||
if (recipientModel.hasInvalidAddress()) {
|
||||
return qsTr("Address is invalid.") + translationManager.emptyString;
|
||||
}
|
||||
|
||||
// Amount is nonzero
|
||||
if (!amountLine.text || parseFloat(amountLine.text) <= 0) {
|
||||
if (recipientModel.hasEmptyAmount()) {
|
||||
return qsTr("Enter an amount.") + translationManager.emptyString;
|
||||
}
|
||||
}
|
||||
@@ -93,12 +92,22 @@ Rectangle {
|
||||
oaPopup.open()
|
||||
}
|
||||
|
||||
function fillPaymentDetails(address, payment_id, amount, tx_description, recipient_name) {
|
||||
if (recipientModel.count > 0) {
|
||||
const last = recipientModel.count - 1;
|
||||
if (recipientModel.get(recipientModel.count - 1).address == "") {
|
||||
recipientModel.remove(last);
|
||||
}
|
||||
}
|
||||
|
||||
recipientModel.newRecipient(address, Utils.removeTrailingZeros(amount || ""));
|
||||
setPaymentId(payment_id || "");
|
||||
setDescription((recipient_name ? recipient_name + " " : "") + (tx_description || ""));
|
||||
}
|
||||
|
||||
function updateFromQrCode(address, payment_id, amount, tx_description, recipient_name) {
|
||||
console.log("updateFromQrCode")
|
||||
addressLine.text = address
|
||||
setPaymentId(payment_id);
|
||||
amountLine.text = amount
|
||||
setDescription(recipient_name + " " + tx_description);
|
||||
fillPaymentDetails(address, payment_id, amount, tx_description, recipient_name);
|
||||
cameraUi.qrcode_decoded.disconnect(updateFromQrCode)
|
||||
}
|
||||
|
||||
@@ -113,10 +122,8 @@ Rectangle {
|
||||
}
|
||||
|
||||
function clearFields() {
|
||||
addressLine.text = ""
|
||||
setPaymentId("");
|
||||
amountLine.text = ""
|
||||
setDescription("");
|
||||
recipientModel.clear();
|
||||
fillPaymentDetails("", "", "", "", "");
|
||||
priorityDropdown.currentIndex = 0
|
||||
}
|
||||
|
||||
@@ -163,166 +170,496 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
// recipient address input
|
||||
RowLayout {
|
||||
id: addressLineRow
|
||||
Layout.fillWidth: true
|
||||
ListModel {
|
||||
id: recipientModel
|
||||
|
||||
LineEditMulti {
|
||||
id: addressLine
|
||||
spacing: 0
|
||||
inputPaddingRight: inlineButtonVisible && inlineButton2Visible ? 100 : 60
|
||||
fontBold: true
|
||||
labelText: qsTr("Address") + translationManager.emptyString
|
||||
labelButtonText: qsTr("Resolve") + translationManager.emptyString
|
||||
placeholderText: {
|
||||
if(persistentSettings.nettype == NetworkType.MAINNET){
|
||||
return "4.. / 8.. / OpenAlias";
|
||||
} else if (persistentSettings.nettype == NetworkType.STAGENET){
|
||||
return "5.. / 7..";
|
||||
} else if(persistentSettings.nettype == NetworkType.TESTNET){
|
||||
return "9.. / B..";
|
||||
}
|
||||
}
|
||||
wrapMode: Text.WrapAnywhere
|
||||
addressValidation: true
|
||||
onTextChanged: {
|
||||
const parsed = walletManager.parse_uri_to_object(text);
|
||||
if (!parsed.error) {
|
||||
addressLine.text = parsed.address;
|
||||
setPaymentId(parsed.payment_id);
|
||||
amountLine.text = parsed.amount;
|
||||
setDescription(parsed.tx_description);
|
||||
}
|
||||
}
|
||||
inlineButton.text: FontAwesome.addressBook
|
||||
inlineButton.buttonHeight: 30
|
||||
inlineButton.fontPixelSize: 22
|
||||
inlineButton.fontFamily: FontAwesome.fontFamily
|
||||
inlineButton.textColor: MoneroComponents.Style.defaultFontColor
|
||||
inlineButton.onClicked: {
|
||||
middlePanel.addressBookView.selectAndSend = true;
|
||||
appWindow.showPageRequest("AddressBook");
|
||||
}
|
||||
inlineButtonVisible: true
|
||||
|
||||
inlineButton2.text: FontAwesome.qrcode
|
||||
inlineButton2.buttonHeight: 30
|
||||
inlineButton2.fontPixelSize: 22
|
||||
inlineButton2.fontFamily: FontAwesome.fontFamily
|
||||
inlineButton2.textColor: MoneroComponents.Style.defaultFontColor
|
||||
inlineButton2.onClicked: {
|
||||
cameraUi.state = "Capture"
|
||||
cameraUi.qrcode_decoded.connect(updateFromQrCode)
|
||||
}
|
||||
inlineButton2Visible: appWindow.qrScannerEnabled
|
||||
}
|
||||
}
|
||||
readonly property int maxRecipients: 16
|
||||
|
||||
StandardButton {
|
||||
id: resolveButton
|
||||
width: 80
|
||||
text: qsTr("Resolve") + translationManager.emptyString
|
||||
visible: TxUtils.isValidOpenAliasAddress(addressLine.text)
|
||||
enabled : visible
|
||||
onClicked: {
|
||||
var result = walletManager.resolveOpenAlias(addressLine.text)
|
||||
if (result) {
|
||||
var parts = result.split("|")
|
||||
if (parts.length == 2) {
|
||||
var address_ok = walletManager.addressValid(parts[1], appWindow.persistentSettings.nettype)
|
||||
if (parts[0] === "true") {
|
||||
if (address_ok) {
|
||||
// prepend openalias to description
|
||||
descriptionLine.text = descriptionLine.text ? addressLine.text + " " + descriptionLine.text : addressLine.text
|
||||
descriptionCheckbox.checked = true
|
||||
addressLine.text = parts[1]
|
||||
}
|
||||
else
|
||||
oa_message(qsTr("No valid address found at this OpenAlias address"))
|
||||
}
|
||||
else if (parts[0] === "false") {
|
||||
if (address_ok) {
|
||||
addressLine.text = parts[1]
|
||||
oa_message(qsTr("Address found, but the DNSSEC signatures could not be verified, so this address may be spoofed"))
|
||||
}
|
||||
else
|
||||
{
|
||||
oa_message(qsTr("No valid address found at this OpenAlias address, but the DNSSEC signatures could not be verified, so this may be spoofed"))
|
||||
}
|
||||
}
|
||||
else {
|
||||
oa_message(qsTr("Internal error"))
|
||||
}
|
||||
}
|
||||
else {
|
||||
oa_message(qsTr("Internal error"))
|
||||
}
|
||||
}
|
||||
else {
|
||||
oa_message(qsTr("No address found"))
|
||||
}
|
||||
}
|
||||
}
|
||||
ListElement {
|
||||
address: ""
|
||||
amount: ""
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
columns: appWindow.walletMode < 2 ? 1 : 2
|
||||
Layout.fillWidth: true
|
||||
columnSpacing: 32
|
||||
function newRecipient(address, amount) {
|
||||
if (recipientModel.count < maxRecipients) {
|
||||
recipientModel.append({address: address, amount: amount});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumWidth: 200
|
||||
function getRecipients() {
|
||||
var recipients = [];
|
||||
for (var index = 0; index < recipientModel.count; ++index) {
|
||||
const recipient = recipientModel.get(index);
|
||||
recipients.push({
|
||||
address: recipient.address,
|
||||
amount: recipient.amount,
|
||||
});
|
||||
}
|
||||
return recipients;
|
||||
}
|
||||
|
||||
// Amount input
|
||||
LineEdit {
|
||||
id: amountLine
|
||||
Layout.fillWidth: true
|
||||
inlineIcon: true
|
||||
labelText: "<style type='text/css'>a {text-decoration: none; color: #858585; font-size: 14px;}</style>\
|
||||
%1 <a href='#'>(%2)</a>".arg(qsTr("Amount")).arg(qsTr("Change account"))
|
||||
+ translationManager.emptyString
|
||||
copyButton: !isNaN(amountLine.text) && persistentSettings.fiatPriceEnabled
|
||||
copyButtonText: "~%1 %2".arg(fiatApiConvertToFiat(amountLine.text)).arg(fiatApiCurrencySymbol())
|
||||
copyButtonEnabled: false
|
||||
function getAmountTotal() {
|
||||
var sum = [];
|
||||
for (var index = 0; index < recipientModel.count; ++index) {
|
||||
const amount = recipientModel.get(index).amount;
|
||||
if (amount == "(all)") {
|
||||
return appWindow.getUnlockedBalance();
|
||||
}
|
||||
sum.push(amount || "0");
|
||||
}
|
||||
return walletManager.amountsSumFromStrings(sum);
|
||||
}
|
||||
|
||||
onLabelLinkActivated: {
|
||||
middlePanel.accountView.selectAndSend = true;
|
||||
appWindow.showPageRequest("Account")
|
||||
}
|
||||
placeholderText: "0.00"
|
||||
width: 100
|
||||
fontBold: true
|
||||
inlineButtonText: qsTr("All") + translationManager.emptyString
|
||||
inlineButton.onClicked: amountLine.text = "(all)"
|
||||
onTextChanged: {
|
||||
amountLine.text = amountLine.text.replace(",", ".");
|
||||
const match = amountLine.text.match(/^0+(\d.*)/);
|
||||
if (match) {
|
||||
const cursorPosition = amountLine.cursorPosition;
|
||||
amountLine.text = match[1];
|
||||
amountLine.cursorPosition = Math.max(cursorPosition, 1) - 1;
|
||||
} else if(amountLine.text.indexOf('.') === 0){
|
||||
amountLine.text = '0' + amountLine.text;
|
||||
if (amountLine.text.length > 2) {
|
||||
amountLine.cursorPosition = 1;
|
||||
function hasEmptyAmount() {
|
||||
for (var index = 0; index < recipientModel.count; ++index) {
|
||||
if (recipientModel.get(index).amount === "") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function hasEmptyAddress() {
|
||||
for (var index = 0; index < recipientModel.count; ++index) {
|
||||
if (recipientModel.get(index).address === "") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function hasInvalidAddress() {
|
||||
for (var index = 0; index < recipientModel.count; ++index) {
|
||||
if (!TxUtils.checkAddress(recipientModel.get(index).address, appWindow.persistentSettings.nettype)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: recipientLayout.height
|
||||
|
||||
ColumnLayout {
|
||||
id: recipientLayout
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: 0
|
||||
|
||||
readonly property int colSpacing: 10
|
||||
readonly property int rowSpacing: 10
|
||||
readonly property int secondRowWidth: 125
|
||||
readonly property int thirdRowWidth: 50
|
||||
|
||||
RowLayout {
|
||||
Layout.bottomMargin: recipientLayout.rowSpacing / 2
|
||||
spacing: recipientLayout.colSpacing
|
||||
|
||||
RowLayout {
|
||||
id: addressLabel
|
||||
spacing: 6
|
||||
Layout.fillWidth: true
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
Layout.leftMargin: 10
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 16
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
text: qsTr("Address") + translationManager.emptyString
|
||||
}
|
||||
|
||||
MoneroComponents.InlineButton {
|
||||
fontFamily: FontAwesome.fontFamily
|
||||
fontPixelSize: 18
|
||||
text: FontAwesome.desktop
|
||||
onClicked: {
|
||||
clearFields();
|
||||
const codes = oshelper.grabQrCodesFromScreen();
|
||||
for (var index = 0; index < codes.length; ++index) {
|
||||
const parsed = walletManager.parse_uri_to_object(codes[index]);
|
||||
if (!parsed.error) {
|
||||
fillPaymentDetails(parsed.address, parsed.payment_id, parsed.amount, parsed.tx_description, parsed.recipient_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
amountLine.error = walletManager.amountFromString(amountLine.text) > appWindow.getUnlockedBalance()
|
||||
}
|
||||
|
||||
validator: RegExpValidator {
|
||||
regExp: /^(\d{1,8})?([\.,]\d{1,12})?$/
|
||||
}
|
||||
}
|
||||
MoneroComponents.InlineButton {
|
||||
fontFamily: FontAwesome.fontFamily
|
||||
text: FontAwesome.qrcode
|
||||
visible: appWindow.qrScannerEnabled
|
||||
onClicked: {
|
||||
cameraUi.state = "Capture"
|
||||
cameraUi.qrcode_decoded.connect(updateFromQrCode)
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.InlineButton {
|
||||
fontFamily: FontAwesome.fontFamily
|
||||
text: FontAwesome.addressBook
|
||||
onClicked: {
|
||||
middlePanel.addressBookView.selectAndSend = true;
|
||||
appWindow.showPageRequest("AddressBook");
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
Layout.preferredWidth: recipientLayout.secondRowWidth
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 16
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
text: qsTr("Amount") + translationManager.emptyString
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: recipientLayout.thirdRowWidth
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: recipientRepeater
|
||||
model: recipientModel
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: recipientLayout.thirdRowWidth
|
||||
color: MoneroComponents.Style.inputBorderColorInActive
|
||||
height: 1
|
||||
visible: index > 0
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 0
|
||||
|
||||
MoneroComponents.LineEditMulti {
|
||||
KeyNavigation.backtab: index > 0 ? recipientRepeater.itemAt(index - 1).children[1].children[2] : sendButton
|
||||
KeyNavigation.tab: parent.children[2]
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.topMargin: index > 0 ? recipientLayout.rowSpacing / 2 : 0
|
||||
Layout.bottomMargin: recipientLayout.rowSpacing / 2
|
||||
Layout.fillWidth: true
|
||||
addressValidation: true
|
||||
borderDisabled: true
|
||||
fontFamily: MoneroComponents.Style.fontMonoRegular.name
|
||||
fontSize: 14
|
||||
inputPaddingBottom: 0
|
||||
inputPaddingTop: 0
|
||||
inputPaddingRight: 0
|
||||
placeholderFontFamily: MoneroComponents.Style.fontMonoRegular.name
|
||||
placeholderFontSize: 14
|
||||
spacing: 0
|
||||
wrapMode: Text.WrapAnywhere
|
||||
placeholderText: {
|
||||
if(persistentSettings.nettype == NetworkType.MAINNET){
|
||||
return "4.. / 8.. / OpenAlias";
|
||||
} else if (persistentSettings.nettype == NetworkType.STAGENET){
|
||||
return "5.. / 7..";
|
||||
} else if(persistentSettings.nettype == NetworkType.TESTNET){
|
||||
return "9.. / B..";
|
||||
}
|
||||
}
|
||||
onTextChanged: {
|
||||
const parsed = walletManager.parse_uri_to_object(text);
|
||||
if (!parsed.error) {
|
||||
fillPaymentDetails(parsed.address, parsed.payment_id, parsed.amount, parsed.tx_description);
|
||||
}
|
||||
address = text;
|
||||
}
|
||||
text: address
|
||||
|
||||
MoneroComponents.InlineButton {
|
||||
small: true
|
||||
text: qsTr("Resolve") + translationManager.emptyString
|
||||
visible: TxUtils.isValidOpenAliasAddress(address)
|
||||
onClicked: {
|
||||
var result = walletManager.resolveOpenAlias(address)
|
||||
if (result) {
|
||||
var parts = result.split("|")
|
||||
if (parts.length == 2) {
|
||||
var address_ok = walletManager.addressValid(parts[1], appWindow.persistentSettings.nettype)
|
||||
if (parts[0] === "true") {
|
||||
if (address_ok) {
|
||||
// prepend openalias to description
|
||||
descriptionLine.text = descriptionLine.text ? address + " " + descriptionLine.text : address
|
||||
descriptionCheckbox.checked = true
|
||||
recipientRepeater.itemAt(index).children[1].children[0].text = parts[1];
|
||||
}
|
||||
else
|
||||
oa_message(qsTr("No valid address found at this OpenAlias address"))
|
||||
}
|
||||
else if (parts[0] === "false") {
|
||||
if (address_ok) {
|
||||
recipientRepeater.itemAt(index).children[1].children[0].text = parts[1];
|
||||
oa_message(qsTr("Address found, but the DNSSEC signatures could not be verified, so this address may be spoofed"))
|
||||
}
|
||||
else
|
||||
{
|
||||
oa_message(qsTr("No valid address found at this OpenAlias address, but the DNSSEC signatures could not be verified, so this may be spoofed"))
|
||||
}
|
||||
}
|
||||
else {
|
||||
oa_message(qsTr("Internal error"))
|
||||
}
|
||||
}
|
||||
else {
|
||||
oa_message(qsTr("Internal error"))
|
||||
}
|
||||
}
|
||||
else {
|
||||
oa_message(qsTr("No address found"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillHeight: true
|
||||
Layout.leftMargin: recipientLayout.colSpacing / 2 - width
|
||||
Layout.rightMargin: recipientLayout.colSpacing / 2
|
||||
color: MoneroComponents.Style.inputBorderColorInActive
|
||||
width: 1
|
||||
}
|
||||
|
||||
MoneroComponents.LineEdit {
|
||||
KeyNavigation.backtab: parent.children[0]
|
||||
KeyNavigation.tab: index + 1 < recipientRepeater.count ? recipientRepeater.itemAt(index + 1).children[1].children[0] : sendButton
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.topMargin: recipientLayout.rowSpacing / 2
|
||||
Layout.bottomMargin: recipientLayout.rowSpacing / 2
|
||||
Layout.rightMargin: recipientLayout.colSpacing / 2
|
||||
Layout.preferredWidth: 125
|
||||
borderDisabled: true
|
||||
fontFamily: MoneroComponents.Style.fontMonoRegular.name
|
||||
fontSize: 14
|
||||
inputPadding: 0
|
||||
placeholderFontFamily: MoneroComponents.Style.fontMonoRegular.name
|
||||
placeholderFontSize: 14
|
||||
placeholderLeftMargin: 0
|
||||
placeholderText: "0.00"
|
||||
text: amount
|
||||
onTextChanged: {
|
||||
text = text.trim().replace(",", ".");
|
||||
const match = text.match(/^0+(\d.*)/);
|
||||
if (match) {
|
||||
const cursorPosition = cursorPosition;
|
||||
text = match[1];
|
||||
cursorPosition = Math.max(cursorPosition, 1) - 1;
|
||||
} else if(text.indexOf('.') === 0){
|
||||
text = '0' + text;
|
||||
if (text.length > 2) {
|
||||
cursorPosition = 1;
|
||||
}
|
||||
}
|
||||
error = walletManager.amountFromString(text) > appWindow.getUnlockedBalance();
|
||||
|
||||
amount = text;
|
||||
}
|
||||
validator: RegExpValidator {
|
||||
regExp: /^\s*(\d{1,8})?([\.,]\d{1,12})?\s*$/
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
Layout.leftMargin: recipientLayout.colSpacing / 2
|
||||
Layout.preferredWidth: recipientLayout.thirdRowWidth
|
||||
font.family: FontAwesome.fontFamilySolid
|
||||
font.styleName: "Solid"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
opacity: mouseArea.containsMouse ? 1 : 0.85
|
||||
text: recipientModel.count == 1 ? FontAwesome.infinity : FontAwesome.times
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
if (recipientModel.count == 1) {
|
||||
parent.parent.children[2].text = "(all)";
|
||||
} else {
|
||||
recipientModel.remove(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
id: totalLayout
|
||||
Layout.topMargin: recipientLayout.rowSpacing / 2
|
||||
Layout.fillWidth: true
|
||||
columns: 3
|
||||
columnSpacing: recipientLayout.colSpacing
|
||||
rowSpacing: 0
|
||||
|
||||
RowLayout {
|
||||
Layout.column: 0
|
||||
Layout.row: 0
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
CheckBox {
|
||||
border: false
|
||||
checked: false
|
||||
enabled: {
|
||||
if (recipientModel.count > 0 && recipientModel.get(0).amount == "(all)") {
|
||||
return false;
|
||||
}
|
||||
if (recipientModel.count >= recipientModel.maxRecipients) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
fontAwesomeIcons: true
|
||||
fontSize: descriptionLine.labelFontSize
|
||||
iconOnTheLeft: true
|
||||
text: qsTr("Add recipient") + translationManager.emptyString
|
||||
toggleOnClick: false
|
||||
uncheckedIcon: FontAwesome.plusCircle
|
||||
onClicked: {
|
||||
recipientModel.newRecipient("", "");
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignRight
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 16
|
||||
text: recipientModel.count > 1 ? qsTr("Total") + translationManager.emptyString : ""
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.LineEdit {
|
||||
id: totalValue
|
||||
Layout.column: 1
|
||||
Layout.row: 0
|
||||
Layout.preferredWidth: recipientLayout.secondRowWidth
|
||||
borderDisabled: true
|
||||
fontFamily: MoneroComponents.Style.fontMonoRegular.name
|
||||
fontSize: 14
|
||||
inputHeight: 30
|
||||
inputPadding: 0
|
||||
readOnly: true
|
||||
text: Utils.removeTrailingZeros(walletManager.displayAmount(recipientModel.getAmountTotal()))
|
||||
visible: recipientModel.count > 1
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
Layout.column: 2
|
||||
Layout.row: 0
|
||||
Layout.preferredWidth: recipientLayout.thirdRowWidth
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
text: "XMR"
|
||||
visible: recipientModel.count > 1
|
||||
}
|
||||
|
||||
MoneroComponents.LineEdit {
|
||||
Layout.column: 1
|
||||
Layout.row: recipientModel.count > 1 ? 1 : 0
|
||||
Layout.preferredWidth: recipientLayout.secondRowWidth
|
||||
borderDisabled: true
|
||||
fontFamily: MoneroComponents.Style.fontMonoRegular.name
|
||||
fontSize: 14
|
||||
inputHeight: 30
|
||||
inputPadding: 0
|
||||
opacity: 0.7
|
||||
readOnly: true
|
||||
text: fiatApiConvertToFiat(walletManager.displayAmount(recipientModel.getAmountTotal()))
|
||||
visible: persistentSettings.fiatPriceEnabled
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
Layout.column: 2
|
||||
Layout.row: recipientModel.count > 1 ? 1 : 0
|
||||
Layout.preferredWidth: recipientLayout.thirdRowWidth
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
opacity: 0.7
|
||||
text: fiatApiCurrencySymbol()
|
||||
visible: persistentSettings.fiatPriceEnabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.top: recipientLayout.top
|
||||
anchors.topMargin: addressLabel.height + recipientLayout.rowSpacing / 2
|
||||
anchors.bottom: recipientLayout.bottom
|
||||
anchors.bottomMargin: totalLayout.height + recipientLayout.rowSpacing / 2
|
||||
anchors.left: recipientLayout.left
|
||||
anchors.right: recipientLayout.right
|
||||
anchors.rightMargin: recipientLayout.thirdRowWidth
|
||||
color: "transparent"
|
||||
border.color: MoneroComponents.Style.inputBorderColorInActive
|
||||
border.width: 1
|
||||
radius: 4
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
visible: appWindow.walletMode >= 2
|
||||
|
||||
Label {
|
||||
id: transactionPriority
|
||||
Layout.topMargin: 0
|
||||
text: qsTr("Transaction priority") + translationManager.emptyString
|
||||
fontBold: false
|
||||
fontSize: 16
|
||||
}
|
||||
// Note: workaround for translations in listElements
|
||||
// ListElement: cannot use script for property value, so
|
||||
// code like this wont work:
|
||||
// ListElement { column1: qsTr("LOW") + translationManager.emptyString ; column2: ""; priority: PendingTransaction.Priority_Low }
|
||||
// For translations to work, the strings need to be listed in
|
||||
// the file components/StandardDropdown.qml too.
|
||||
|
||||
// Priorites after v5
|
||||
ListModel {
|
||||
id: priorityModelV5
|
||||
|
||||
ListElement { column1: qsTr("Automatic") ; column2: ""; priority: 0}
|
||||
ListElement { column1: qsTr("Slow (x0.2 fee)") ; column2: ""; priority: 1}
|
||||
ListElement { column1: qsTr("Normal (x1 fee)") ; column2: ""; priority: 2 }
|
||||
ListElement { column1: qsTr("Fast (x5 fee)") ; column2: ""; priority: 3 }
|
||||
ListElement { column1: qsTr("Fastest (x200 fee)") ; column2: ""; priority: 4 }
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.topMargin: 5
|
||||
spacing: 10
|
||||
|
||||
StandardDropdown {
|
||||
Layout.preferredWidth: 200
|
||||
id: priorityDropdown
|
||||
currentIndex: 0
|
||||
dataModel: priorityModelV5
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: feeLabel
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Layout.topMargin: 12
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 14
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
opacity: 0.7
|
||||
property bool estimating: false
|
||||
property var estimatedFee: null
|
||||
property string estimatedFeeFiat: {
|
||||
@@ -338,12 +675,21 @@ Rectangle {
|
||||
if (!sendButton.enabled || !currentWallet) {
|
||||
return;
|
||||
}
|
||||
var addresses = [];
|
||||
var amounts = [];
|
||||
for (var index = 0; index < recipientModel.count; ++index) {
|
||||
const recipient = recipientModel.get(index);
|
||||
addresses.push(recipient.address);
|
||||
amounts.push(walletManager.amountFromString(recipient.amount));
|
||||
}
|
||||
currentWallet.estimateTransactionFeeAsync(
|
||||
addressLine.text,
|
||||
walletManager.amountFromString(amountLine.text),
|
||||
addresses,
|
||||
amounts,
|
||||
priorityModelV5.get(priorityDropdown.currentIndex).priority,
|
||||
function (amount) {
|
||||
estimatedFee = Utils.removeTrailingZeros(amount);
|
||||
if (amount) {
|
||||
estimatedFee = Utils.removeTrailingZeros(amount);
|
||||
}
|
||||
estimating = false;
|
||||
});
|
||||
}
|
||||
@@ -351,56 +697,20 @@ Rectangle {
|
||||
if (!sendButton.enabled || estimatedFee == null) {
|
||||
return ""
|
||||
}
|
||||
return "%1: ~%2 XMR".arg(qsTr("Fee")).arg(estimatedFee) +
|
||||
estimatedFeeFiat +
|
||||
translationManager.emptyString;
|
||||
return "~%1 XMR%2 %3".arg(estimatedFee)
|
||||
.arg(estimatedFeeFiat)
|
||||
.arg(qsTr("fee") + translationManager.emptyString);
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
running: feeLabel.estimating
|
||||
height: parent.height
|
||||
width: height
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
visible: appWindow.walletMode >= 2
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Label {
|
||||
id: transactionPriority
|
||||
Layout.topMargin: 0
|
||||
text: qsTr("Transaction priority") + translationManager.emptyString
|
||||
fontBold: false
|
||||
fontSize: 16
|
||||
}
|
||||
// Note: workaround for translations in listElements
|
||||
// ListElement: cannot use script for property value, so
|
||||
// code like this wont work:
|
||||
// ListElement { column1: qsTr("LOW") + translationManager.emptyString ; column2: ""; priority: PendingTransaction.Priority_Low }
|
||||
// For translations to work, the strings need to be listed in
|
||||
// the file components/StandardDropdown.qml too.
|
||||
|
||||
// Priorites after v5
|
||||
ListModel {
|
||||
id: priorityModelV5
|
||||
|
||||
ListElement { column1: qsTr("Automatic") ; column2: ""; priority: 0}
|
||||
ListElement { column1: qsTr("Slow (x0.2 fee)") ; column2: ""; priority: 1}
|
||||
ListElement { column1: qsTr("Normal (x1 fee)") ; column2: ""; priority: 2 }
|
||||
ListElement { column1: qsTr("Fast (x5 fee)") ; column2: ""; priority: 3 }
|
||||
ListElement { column1: qsTr("Fastest (x200 fee)") ; column2: ""; priority: 4 }
|
||||
}
|
||||
|
||||
StandardDropdown {
|
||||
Layout.preferredWidth: 200
|
||||
id: priorityDropdown
|
||||
Layout.topMargin: 5
|
||||
currentIndex: 0
|
||||
dataModel: priorityModelV5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.WarningBox {
|
||||
text: qsTr("Description field contents match long payment ID format. \
|
||||
@@ -492,21 +802,21 @@ Rectangle {
|
||||
rightIconInactive: "qrc:///images/rightArrowInactive.png"
|
||||
Layout.topMargin: 4
|
||||
text: qsTr("Send") + translationManager.emptyString
|
||||
enabled: !sendButtonWarningBox.visible && !warningContent && addressLine.text && !paymentIdWarningBox.visible
|
||||
enabled: !sendButtonWarningBox.visible && !warningContent && !recipientModel.hasEmptyAddress() && !paymentIdWarningBox.visible
|
||||
onClicked: {
|
||||
console.log("Transfer: paymentClicked")
|
||||
var priority = priorityModelV5.get(priorityDropdown.currentIndex).priority
|
||||
console.log("priority: " + priority)
|
||||
console.log("amount: " + amountLine.text)
|
||||
addressLine.text = addressLine.text.trim()
|
||||
setPaymentId(paymentIdLine.text.trim());
|
||||
root.paymentClicked(addressLine.text, paymentIdLine.text, amountLine.text, root.mixin, priority, descriptionLine.text)
|
||||
root.paymentClicked(recipientModel.getRecipients(), paymentIdLine.text, root.mixin, priority, descriptionLine.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkInformation(amount, address, nettype) {
|
||||
return amount.length > 0 && walletManager.amountFromString(amountLine.text) <= appWindow.getUnlockedBalance() && TxUtils.checkAddress(address, nettype)
|
||||
function checkInformation() {
|
||||
return !recipientModel.hasEmptyAmount() &&
|
||||
recipientModel.getAmountTotal() <= appWindow.getUnlockedBalance() &&
|
||||
!recipientModel.hasInvalidAddress();
|
||||
}
|
||||
|
||||
} // pageRoot
|
||||
@@ -566,15 +876,13 @@ Rectangle {
|
||||
visible: persistentSettings.transferShowAdvanced && appWindow.walletMode >= 2
|
||||
title: qsTr("Offline transaction signing") + translationManager.emptyString
|
||||
button1.text: qsTr("Create") + translationManager.emptyString
|
||||
button1.enabled: appWindow.viewOnly && pageRoot.checkInformation(amountLine.text, addressLine.text, appWindow.persistentSettings.nettype)
|
||||
button1.enabled: appWindow.viewOnly && pageRoot.checkInformation()
|
||||
button1.onClicked: {
|
||||
console.log("Transfer: saveTx Clicked")
|
||||
var priority = priorityModelV5.get(priorityDropdown.currentIndex).priority
|
||||
console.log("priority: " + priority)
|
||||
console.log("amount: " + amountLine.text)
|
||||
addressLine.text = addressLine.text.trim()
|
||||
setPaymentId(paymentIdLine.text.trim());
|
||||
root.paymentClicked(addressLine.text, paymentIdLine.text, amountLine.text, root.mixin, priority, descriptionLine.text)
|
||||
root.paymentClicked(recipientModel.getRecipients(), paymentIdLine.text, root.mixin, priority, descriptionLine.text)
|
||||
}
|
||||
button2.text: qsTr("Sign (offline)") + translationManager.emptyString
|
||||
button2.enabled: !appWindow.viewOnly
|
||||
@@ -591,7 +899,7 @@ Rectangle {
|
||||
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)){
|
||||
if (appWindow.viewOnly && !pageRoot.checkInformation()) {
|
||||
errorMessage = "<p class='orange'>" + qsTr("* To create a transaction file, please enter address and amount above") + "</p>";
|
||||
}
|
||||
return "<style type='text/css'>p{line-height:20px; margin-top:0px; margin-bottom:0px; color:" + MoneroComponents.Style.defaultFontColor +
|
||||
@@ -792,19 +1100,9 @@ Rectangle {
|
||||
}
|
||||
|
||||
// Popuplate fields from addressbook.
|
||||
function sendTo(address, paymentId, description, amount){
|
||||
function sendTo(address, paymentId, description, amount) {
|
||||
middlePanel.state = 'Transfer';
|
||||
|
||||
if(typeof address !== 'undefined')
|
||||
addressLine.text = address
|
||||
|
||||
if(typeof paymentId !== 'undefined')
|
||||
setPaymentId(paymentId);
|
||||
|
||||
if(typeof description !== 'undefined')
|
||||
setDescription(description);
|
||||
|
||||
if(typeof amount !== 'undefined')
|
||||
amountLine.text = amount;
|
||||
fillPaymentDetails(address, paymentId, amount, description);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ Rectangle {
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 40
|
||||
anchors.topMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
|
||||
@@ -1,423 +0,0 @@
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Dialogs 1.2
|
||||
import "../../js/Windows.js" as Windows
|
||||
import "../../js/Utils.js" as Utils
|
||||
import "../../components" as MoneroComponents
|
||||
import "../../pages"
|
||||
import "."
|
||||
import moneroComponents.Clipboard 1.0
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 96
|
||||
color: "transparent"
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
Layout.preferredHeight: 32
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
GridLayout {
|
||||
id: grid
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
columnSpacing: 0
|
||||
property string fontColorActive: MoneroComponents.Style.blackTheme ? "white" : "white"
|
||||
property string fontColorInActive: MoneroComponents.Style.blackTheme ? "white" : MoneroComponents.Style.dimmedFontColor
|
||||
property int fontSize: 15
|
||||
property bool fontBold: true
|
||||
property var fontFamily: MoneroComponents.Style.fontRegular.name
|
||||
property string borderColor: MoneroComponents.Style.blackTheme ? "#808080" : "#B9B9B9"
|
||||
property int textMargin: {
|
||||
// left-right margins for a given cell
|
||||
if(appWindow.width < 890){
|
||||
return 32;
|
||||
} else {
|
||||
return 64;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
// navbar left side border
|
||||
id: navBarLeft
|
||||
property bool isActive: settingsStateView.state === "Wallet"
|
||||
Layout.preferredWidth: 2
|
||||
Layout.preferredHeight: 32
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 1
|
||||
height: parent.height - 2
|
||||
color: grid.borderColor
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
width: 1
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredHeight: 1
|
||||
Layout.preferredWidth: 1
|
||||
color: grid.borderColor
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillHeight: true
|
||||
width: 1
|
||||
color: navBarLeft.isActive ? grid.borderColor : "transparent"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.preferredWidth: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
// WALLET
|
||||
id: navWallet
|
||||
property bool isActive: settingsStateView.state === "Wallet"
|
||||
Layout.preferredWidth: navWalletText.width + grid.textMargin
|
||||
Layout.minimumWidth: 72
|
||||
Layout.preferredHeight: 32
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: parent.isActive ? grid.borderColor : "transparent"
|
||||
height: 30
|
||||
Layout.fillWidth: true
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: navWalletText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.family: grid.fontFamily
|
||||
font.pixelSize: grid.fontSize
|
||||
font.bold: grid.fontBold
|
||||
text: qsTr("Wallet") + translationManager.emptyString
|
||||
color: navWallet.isActive ? grid.fontColorActive : grid.fontColorInActive
|
||||
themeTransition: false
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: { settingsStateView.state = "Wallet" }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
Layout.preferredWidth: 1
|
||||
Layout.preferredHeight: 32
|
||||
color: grid.borderColor
|
||||
}
|
||||
ColumnLayout {
|
||||
// UI
|
||||
id: navUI
|
||||
property bool isActive: settingsStateView.state === "UI"
|
||||
Layout.preferredWidth: navUIText.width + grid.textMargin
|
||||
Layout.preferredHeight: 32
|
||||
Layout.minimumWidth: 72
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: parent.isActive ? grid.borderColor : "transparent"
|
||||
height: 30
|
||||
Layout.fillWidth: true
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: navUIText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.family: grid.fontFamily
|
||||
font.pixelSize: grid.fontSize
|
||||
font.bold: grid.fontBold
|
||||
text: qsTr("Interface") + translationManager.emptyString
|
||||
color: navUI.isActive ? grid.fontColorActive : grid.fontColorInActive
|
||||
themeTransition: false
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: { settingsStateView.state = "UI" }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
Layout.preferredWidth: 1
|
||||
Layout.preferredHeight: 32
|
||||
color: grid.borderColor
|
||||
}
|
||||
ColumnLayout {
|
||||
// NODE
|
||||
id: navNode
|
||||
property bool isActive: settingsStateView.state === "Node"
|
||||
visible: appWindow.walletMode >= 2
|
||||
Layout.preferredWidth: navNodeText.width + grid.textMargin
|
||||
Layout.preferredHeight: 32
|
||||
Layout.minimumWidth: 72
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: parent.isActive ? grid.borderColor : "transparent"
|
||||
height: 30
|
||||
Layout.fillWidth: true
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: navNodeText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.family: grid.fontFamily
|
||||
font.pixelSize: grid.fontSize
|
||||
font.bold: grid.fontBold
|
||||
text: qsTr("Node") + translationManager.emptyString
|
||||
color: navNode.isActive ? grid.fontColorActive : grid.fontColorInActive
|
||||
themeTransition: false
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: { settingsStateView.state = "Node" }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
visible: appWindow.walletMode >= 2
|
||||
Layout.preferredWidth: 1
|
||||
Layout.preferredHeight: 32
|
||||
color: grid.borderColor
|
||||
}
|
||||
ColumnLayout {
|
||||
// LOG
|
||||
id: navLog
|
||||
property bool isActive: settingsStateView.state === "Log"
|
||||
Layout.preferredWidth: navLogText.width + grid.textMargin
|
||||
Layout.preferredHeight: 32
|
||||
Layout.minimumWidth: 72
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: parent.isActive ? grid.borderColor : "transparent"
|
||||
height: 30
|
||||
Layout.fillWidth: true
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: navLogText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.family: grid.fontFamily
|
||||
font.pixelSize: grid.fontSize
|
||||
font.bold: grid.fontBold
|
||||
text: qsTr("Log") + translationManager.emptyString
|
||||
color: navLog.isActive ? grid.fontColorActive : grid.fontColorInActive
|
||||
themeTransition: false
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: { settingsStateView.state = "Log" }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
visible: appWindow.walletMode >= 2
|
||||
Layout.preferredWidth: 1
|
||||
Layout.preferredHeight: 32
|
||||
color: grid.borderColor
|
||||
}
|
||||
ColumnLayout {
|
||||
// INFO
|
||||
id: navInfo
|
||||
property bool isActive: settingsStateView.state === "Info"
|
||||
Layout.preferredWidth: navInfoText.width + grid.textMargin
|
||||
Layout.preferredHeight: 32
|
||||
Layout.minimumWidth: 72
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: parent.isActive ? grid.borderColor : "transparent"
|
||||
height: 30
|
||||
Layout.fillWidth: true
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: navInfoText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.family: grid.fontFamily
|
||||
font.pixelSize: grid.fontSize
|
||||
font.bold: grid.fontBold
|
||||
text: qsTr("Info") + translationManager.emptyString
|
||||
color: navInfo.isActive ? grid.fontColorActive : grid.fontColorInActive
|
||||
themeTransition: false
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: { settingsStateView.state = "Info" }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
// navbar right side border
|
||||
id: navBarRight
|
||||
property bool isActive: settingsStateView.state === "Info"
|
||||
Layout.preferredWidth: 2
|
||||
Layout.preferredHeight: 32
|
||||
color: "transparent"
|
||||
rotation: 180
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 1
|
||||
height: parent.height - 2
|
||||
color: grid.borderColor
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
width: 1
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredHeight: 1
|
||||
Layout.preferredWidth: 1
|
||||
color: grid.borderColor
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillHeight: true
|
||||
width: 1
|
||||
color: navBarRight.isActive ? grid.borderColor : "transparent"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: grid.borderColor
|
||||
Layout.preferredHeight: 1
|
||||
Layout.preferredWidth: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: "transparent"
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,38 @@ ColumnLayout {
|
||||
property int settingsHeight: 900
|
||||
property alias settingsStateViewState: settingsStateView.state
|
||||
|
||||
Navbar{}
|
||||
MoneroComponents.Navbar {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: height
|
||||
Layout.bottomMargin: height
|
||||
|
||||
MoneroComponents.NavbarItem {
|
||||
active: settingsStateView.state == "Wallet"
|
||||
text: qsTr("Wallet") + translationManager.emptyString
|
||||
onSelected: settingsStateView.state = "Wallet"
|
||||
}
|
||||
MoneroComponents.NavbarItem {
|
||||
active: settingsStateView.state == "UI"
|
||||
text: qsTr("Interface") + translationManager.emptyString
|
||||
onSelected: settingsStateView.state = "UI"
|
||||
}
|
||||
MoneroComponents.NavbarItem {
|
||||
active: settingsStateView.state == "Node"
|
||||
text: qsTr("Node") + translationManager.emptyString
|
||||
visible: appWindow.walletMode >= 2
|
||||
onSelected: settingsStateView.state = "Node"
|
||||
}
|
||||
MoneroComponents.NavbarItem {
|
||||
active: settingsStateView.state == "Log"
|
||||
text: qsTr("Log") + translationManager.emptyString
|
||||
onSelected: settingsStateView.state = "Log"
|
||||
}
|
||||
MoneroComponents.NavbarItem {
|
||||
active: settingsStateView.state == "Info"
|
||||
text: qsTr("Info") + translationManager.emptyString
|
||||
onSelected: settingsStateView.state = "Info"
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle{
|
||||
id: settingsStateView
|
||||
|
||||
@@ -47,7 +47,7 @@ Rectangle {
|
||||
} else if(appWindow.walletMode === 1){
|
||||
return qsTr("Simple mode") + " (bootstrap)" + translationManager.emptyString;
|
||||
} else if(appWindow.walletMode === 2){
|
||||
return qsTr("Advanced mode") + translationManager.emptyString;
|
||||
return "%1 (%2)".arg(qsTr("Advanced mode")).arg(persistentSettings.useRemoteNode ? qsTr("Remote node") : qsTr("Local node")) + translationManager.emptyString;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,12 @@ Rectangle {
|
||||
text: qsTr("Check for updates periodically") + translationManager.emptyString
|
||||
}
|
||||
|
||||
MoneroComponents.CheckBox {
|
||||
checked: persistentSettings.displayWalletNameInTitleBar
|
||||
onClicked: persistentSettings.displayWalletNameInTitleBar = !persistentSettings.displayWalletNameInTitleBar
|
||||
text: qsTr("Display wallet name in title bar") + translationManager.emptyString
|
||||
}
|
||||
|
||||
MoneroComponents.CheckBox {
|
||||
id: hideBalanceCheckBox
|
||||
checked: persistentSettings.hideBalance
|
||||
|
||||
@@ -215,6 +215,7 @@ Rectangle {
|
||||
Layout.fillWidth: true
|
||||
property var lastCommands: []
|
||||
property int currentCommandIndex
|
||||
enabled: !persistentSettings.useRemoteNode
|
||||
fontBold: false
|
||||
placeholderText: qsTr("command + enter (e.g 'help' or 'status')") + translationManager.emptyString
|
||||
placeholderFontSize: 16
|
||||
|
||||
@@ -130,7 +130,7 @@ Rectangle{
|
||||
topPadding: 0
|
||||
text: qsTr("The blockchain is downloaded to your computer. Provides higher security and requires more local storage.") + translationManager.emptyString
|
||||
width: parent.width - (localNodeIcon.width + localNodeIcon.anchors.leftMargin + anchors.leftMargin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -262,80 +262,94 @@ Rectangle{
|
||||
text: qsTr("To find a remote node, type 'Monero remote node' into your favorite search engine. Please ensure the node is run by a trusted third-party.") + translationManager.emptyString
|
||||
}
|
||||
|
||||
MoneroComponents.RemoteNodeEdit {
|
||||
id: remoteNodeEdit
|
||||
Layout.minimumWidth: 100
|
||||
placeholderFontSize: 15
|
||||
|
||||
daemonAddrLabelText: qsTr("Address") + translationManager.emptyString
|
||||
daemonPortLabelText: qsTr("Port") + translationManager.emptyString
|
||||
|
||||
initialAddress: persistentSettings.remoteNodeAddress
|
||||
onEditingFinished: {
|
||||
persistentSettings.remoteNodeAddress = remoteNodeEdit.getAddress();
|
||||
console.log("setting remote node to " + persistentSettings.remoteNodeAddress);
|
||||
if (persistentSettings.is_trusted_daemon) {
|
||||
persistentSettings.is_trusted_daemon = !persistentSettings.is_trusted_daemon
|
||||
currentWallet.setTrustedDaemon(persistentSettings.is_trusted_daemon)
|
||||
setTrustedDaemonCheckBox.checked = !setTrustedDaemonCheckBox.checked
|
||||
appWindow.showStatusMessage(qsTr("Remote node updated. Trusted daemon has been reset. Mark again, if desired."), 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
columns: 2
|
||||
columnSpacing: 32
|
||||
|
||||
MoneroComponents.LineEdit {
|
||||
id: daemonUsername
|
||||
Layout.fillWidth: true
|
||||
labelText: qsTr("Daemon username") + translationManager.emptyString
|
||||
text: persistentSettings.daemonUsername
|
||||
placeholderText: qsTr("(optional)") + translationManager.emptyString
|
||||
placeholderFontSize: 15
|
||||
labelFontSize: 14
|
||||
fontSize: 15
|
||||
}
|
||||
|
||||
MoneroComponents.LineEdit {
|
||||
id: daemonPassword
|
||||
Layout.fillWidth: true
|
||||
labelText: qsTr("Daemon password") + translationManager.emptyString
|
||||
text: persistentSettings.daemonPassword
|
||||
placeholderText: qsTr("Password") + translationManager.emptyString
|
||||
password: true
|
||||
placeholderFontSize: 15
|
||||
labelFontSize: 14
|
||||
fontSize: 15
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.CheckBox {
|
||||
id: setTrustedDaemonCheckBox
|
||||
checked: persistentSettings.is_trusted_daemon
|
||||
onClicked: {
|
||||
persistentSettings.is_trusted_daemon = !persistentSettings.is_trusted_daemon
|
||||
currentWallet.setTrustedDaemon(persistentSettings.is_trusted_daemon)
|
||||
}
|
||||
text: qsTr("Mark as Trusted Daemon") + translationManager.emptyString
|
||||
border: false
|
||||
checkedIcon: FontAwesome.minusCircle
|
||||
uncheckedIcon: FontAwesome.plusCircle
|
||||
fontAwesomeIcons: true
|
||||
fontSize: 16
|
||||
iconOnTheLeft: true
|
||||
text: qsTr("Add remote node") + translationManager.emptyString
|
||||
toggleOnClick: false
|
||||
onClicked: remoteNodeDialog.add(remoteNodesModel.append)
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
id: btnConnectRemote
|
||||
enabled: remoteNodeEdit.isValid()
|
||||
small: true
|
||||
text: qsTr("Connect") + translationManager.emptyString
|
||||
onClicked: {
|
||||
// Update daemon login
|
||||
persistentSettings.remoteNodeAddress = remoteNodeEdit.getAddress();
|
||||
persistentSettings.daemonUsername = daemonUsername.text;
|
||||
persistentSettings.daemonPassword = daemonPassword.text;
|
||||
persistentSettings.useRemoteNode = true
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
currentWallet.setDaemonLogin(persistentSettings.daemonUsername, persistentSettings.daemonPassword);
|
||||
Repeater {
|
||||
model: remoteNodesModel
|
||||
|
||||
appWindow.connectRemoteNode()
|
||||
Rectangle {
|
||||
height: 30
|
||||
Layout.fillWidth: true
|
||||
color: itemMouseArea.containsMouse || index === remoteNodesModel.selected ? MoneroComponents.Style.titleBarButtonHoverColor : "transparent"
|
||||
|
||||
Rectangle {
|
||||
color: MoneroComponents.Style.appWindowBorderColor
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
height: 1
|
||||
visible: index > 0
|
||||
|
||||
MoneroEffects.ColorTransition {
|
||||
targetObj: parent
|
||||
blackColor: MoneroComponents.Style._b_appWindowBorderColor
|
||||
whiteColor: MoneroComponents.Style._w_appWindowBorderColor
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 80
|
||||
color: "transparent"
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
color: index === remoteNodesModel.selected ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 6
|
||||
font.pixelSize: 16
|
||||
text: address
|
||||
themeTransition: false
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: itemMouseArea
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: remoteNodesModel.applyRemoteNode(index)
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 6
|
||||
height: 30
|
||||
spacing: 10
|
||||
|
||||
MoneroComponents.InlineButton {
|
||||
buttonColor: "transparent"
|
||||
fontFamily: FontAwesome.fontFamily
|
||||
fontPixelSize: 18
|
||||
text: FontAwesome.edit
|
||||
onClicked: remoteNodeDialog.edit(remoteNodesModel.get(index), function (remoteNode) {
|
||||
remoteNodesModel.set(index, remoteNode)
|
||||
})
|
||||
}
|
||||
|
||||
MoneroComponents.InlineButton {
|
||||
buttonColor: "transparent"
|
||||
fontFamily: FontAwesome.fontFamily
|
||||
text: FontAwesome.times
|
||||
visible: remoteNodesModel.count > 1
|
||||
onClicked: remoteNodesModel.removeSelectNextIfNeeded(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -398,7 +412,7 @@ Rectangle{
|
||||
placeholderFontSize: 15
|
||||
text: persistentSettings.daemonFlags
|
||||
addressValidation: false
|
||||
error: text.match(/(^|\s)--(data-dir|bootstrap-daemon-address)/)
|
||||
error: text.match(/(^|\s)--(data-dir|bootstrap-daemon-address|non-interactive)/)
|
||||
onEditingFinished: {
|
||||
if (!daemonFlags.error) {
|
||||
persistentSettings.daemonFlags = daemonFlags.text;
|
||||
@@ -431,7 +445,7 @@ Rectangle{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ Rectangle {
|
||||
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
|
||||
visible: !appWindow.viewOnly && (currentWallet ? !currentWallet.isLedger() : true)
|
||||
|
||||
onClicked: {
|
||||
var newPath = currentWallet.path + "_viewonly";
|
||||
|
||||
8
qml.qrc
8
qml.qrc
@@ -3,7 +3,12 @@
|
||||
<file>main.qml</file>
|
||||
<file>LeftPanel.qml</file>
|
||||
<file>MiddlePanel.qml</file>
|
||||
<file>components/Dialog.qml</file>
|
||||
<file>components/Label.qml</file>
|
||||
<file>components/LanguageButton.qml</file>
|
||||
<file>components/Navbar.qml</file>
|
||||
<file>components/NavbarItem.qml</file>
|
||||
<file>components/RemoteNodeDialog.qml</file>
|
||||
<file>components/SettingsListItem.qml</file>
|
||||
<file>components/Slider.qml</file>
|
||||
<file>components/UpdateDialog.qml</file>
|
||||
@@ -14,6 +19,7 @@
|
||||
<file>monero/utils/gpg_keys/fluffypony.asc</file>
|
||||
<file>monero/utils/gpg_keys/luigi1111.asc</file>
|
||||
<file>pages/Account.qml</file>
|
||||
<file>pages/Advanced.qml</file>
|
||||
<file>pages/Transfer.qml</file>
|
||||
<file>pages/History.qml</file>
|
||||
<file>pages/AddressBook.qml</file>
|
||||
@@ -161,7 +167,6 @@
|
||||
<file>pages/settings/SettingsLog.qml</file>
|
||||
<file>pages/settings/SettingsLayout.qml</file>
|
||||
<file>pages/settings/SettingsInfo.qml</file>
|
||||
<file>pages/settings/Navbar.qml</file>
|
||||
<file>components/WarningBox.qml</file>
|
||||
<file>images/miningxmr.png</file>
|
||||
<file>images/miningxmr@2x.png</file>
|
||||
@@ -243,5 +248,6 @@
|
||||
<file>images/success.png</file>
|
||||
<file>images/success@2x.png</file>
|
||||
<file>components/SuccessfulTxDialog.qml</file>
|
||||
<file>components/TxConfirmationDialog.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -55,13 +55,6 @@ if(ENABLE_PASS_STRENGTH_METER)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_SCANNER)
|
||||
file(GLOB QR_CODE_FILES
|
||||
"QR-Code-scanner/*.h"
|
||||
"QR-Code-scanner/*.cpp"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(EXECUTABLE_FLAG)
|
||||
if(MINGW)
|
||||
set(EXECUTABLE_FLAG WIN32)
|
||||
@@ -81,13 +74,19 @@ if(APPLE)
|
||||
list(APPEND RESOURCES ${ICON})
|
||||
endif()
|
||||
|
||||
add_executable(monero-wallet-gui ${EXECUTABLE_FLAG} main/main.cpp
|
||||
set(monero_wallet_gui_sources
|
||||
${SOURCE_FILES}
|
||||
${PASS_STRENGTH_FILES}
|
||||
${QR_CODE_FILES}
|
||||
${RESOURCES}
|
||||
)
|
||||
|
||||
if(NOT ANDROID)
|
||||
add_executable(monero-wallet-gui ${EXECUTABLE_FLAG} ${monero_wallet_gui_sources})
|
||||
else()
|
||||
add_library(monero-wallet-gui SHARED ${monero_wallet_gui_sources})
|
||||
set_target_properties(monero-wallet-gui PROPERTIES COMPILE_DEFINITIONS "ANDROID")
|
||||
endif()
|
||||
|
||||
set_target_properties(monero-wallet-gui PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
MACOSX_BUNDLE TRUE
|
||||
@@ -121,7 +120,6 @@ target_include_directories(monero-wallet-gui PUBLIC
|
||||
${X11_INCLUDE_DIR}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
${ZBAR_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_compile_definitions(monero-wallet-gui
|
||||
@@ -130,6 +128,14 @@ target_compile_definitions(monero-wallet-gui
|
||||
${Qt5Qml_DEFINITIONS}
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
if(NOT ICU_ROOT)
|
||||
execute_process(COMMAND brew --prefix icu4c OUTPUT_VARIABLE ICU_ROOT OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
find_package(ICU REQUIRED COMPONENTS data i18n uc)
|
||||
target_link_directories(monero-wallet-gui PRIVATE ${ICU_ROOT}/lib)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
|
||||
|
||||
target_link_libraries(monero-wallet-gui
|
||||
@@ -152,6 +158,7 @@ target_link_libraries(monero-wallet-gui
|
||||
${EXTRA_LIBRARIES}
|
||||
${ICU_LIBRARIES}
|
||||
openpgp
|
||||
qrdecoder
|
||||
translations
|
||||
)
|
||||
|
||||
@@ -164,13 +171,15 @@ if(X11_FOUND)
|
||||
endif()
|
||||
|
||||
if(WITH_SCANNER)
|
||||
target_link_libraries(monero-wallet-gui
|
||||
${ZBAR_LIBRARIES}
|
||||
jpeg
|
||||
v4l2
|
||||
v4lconvert
|
||||
rt
|
||||
)
|
||||
target_link_libraries(monero-wallet-gui qrscanner)
|
||||
if(LINUX AND NOT ANDROID)
|
||||
target_link_libraries(monero-wallet-gui
|
||||
jpeg
|
||||
v4l2
|
||||
v4lconvert
|
||||
rt
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_custom_command(TARGET monero-wallet-gui POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:daemon> $<TARGET_FILE_DIR:monero-wallet-gui>)
|
||||
|
||||
@@ -1,4 +1,21 @@
|
||||
file(GLOB_RECURSE SRC_SOURCES *.cpp)
|
||||
file(GLOB_RECURSE SRC_HEADERS *.h)
|
||||
|
||||
add_library(qrdecoder STATIC
|
||||
Decoder.cpp
|
||||
)
|
||||
target_link_libraries(qrdecoder
|
||||
PUBLIC
|
||||
Qt5::Gui
|
||||
PRIVATE
|
||||
quirc
|
||||
)
|
||||
|
||||
if(WITH_SCANNER)
|
||||
add_library(qrscanner
|
||||
QrCodeScanner.cpp
|
||||
QrScanThread.cpp
|
||||
)
|
||||
target_link_libraries(qrscanner
|
||||
PUBLIC
|
||||
Qt5::Multimedia
|
||||
qrdecoder
|
||||
)
|
||||
endif()
|
||||
|
||||
99
src/QR-Code-scanner/Decoder.cpp
Normal file
99
src/QR-Code-scanner/Decoder.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2020, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "Decoder.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "quirc.h"
|
||||
|
||||
QrDecoder::QrDecoder()
|
||||
: m_qr(quirc_new())
|
||||
{
|
||||
if (m_qr == nullptr)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to allocate memory");
|
||||
}
|
||||
}
|
||||
|
||||
QrDecoder::~QrDecoder()
|
||||
{
|
||||
quirc_destroy(m_qr);
|
||||
}
|
||||
|
||||
std::vector<std::string> QrDecoder::decode(const QImage &image)
|
||||
{
|
||||
if (image.format() == QImage::Format_Grayscale8)
|
||||
{
|
||||
return decodeGrayscale8(image);
|
||||
}
|
||||
return decodeGrayscale8(image.convertToFormat(QImage::Format_Grayscale8));
|
||||
}
|
||||
|
||||
std::vector<std::string> QrDecoder::decodeGrayscale8(const QImage &image)
|
||||
{
|
||||
if (quirc_resize(m_qr, image.width(), image.height()) < 0)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to allocate video memory");
|
||||
}
|
||||
|
||||
uint8_t *rawImage = quirc_begin(m_qr, nullptr, nullptr);
|
||||
if (rawImage == nullptr)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to get image buffer");
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
std::copy(image.constBits(), image.constBits() + image.sizeInBytes(), rawImage);
|
||||
#else
|
||||
std::copy(image.constBits(), image.constBits() + image.byteCount(), rawImage);
|
||||
#endif
|
||||
quirc_end(m_qr);
|
||||
|
||||
const int count = quirc_count(m_qr);
|
||||
if (count < 0)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to get the number of recognized QR-codes");
|
||||
}
|
||||
|
||||
std::vector<std::string> result;
|
||||
result.reserve(static_cast<size_t>(count));
|
||||
for (int index = 0; index < count; ++index)
|
||||
{
|
||||
quirc_code code;
|
||||
quirc_extract(m_qr, index, &code);
|
||||
|
||||
quirc_data data;
|
||||
const quirc_decode_error_t err = quirc_decode(&code, &data);
|
||||
if (err == QUIRC_SUCCESS)
|
||||
{
|
||||
result.emplace_back(&data.payload[0], &data.payload[data.payload_len]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
49
src/QR-Code-scanner/Decoder.h
Normal file
49
src/QR-Code-scanner/Decoder.h
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2020, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <QImage>
|
||||
|
||||
struct quirc;
|
||||
|
||||
class QrDecoder
|
||||
{
|
||||
public:
|
||||
QrDecoder(const QrDecoder &) = delete;
|
||||
QrDecoder &operator=(const QrDecoder &) = delete;
|
||||
|
||||
QrDecoder();
|
||||
~QrDecoder();
|
||||
|
||||
std::vector<std::string> decode(const QImage &image);
|
||||
|
||||
private:
|
||||
std::vector<std::string> decodeGrayscale8(const QImage &image);
|
||||
|
||||
private:
|
||||
quirc *m_qr;
|
||||
};
|
||||
@@ -27,7 +27,6 @@
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "QrCodeScanner.h"
|
||||
#include <WalletManager.h>
|
||||
#include <QVideoProbe>
|
||||
#include <QCamera>
|
||||
|
||||
@@ -40,7 +39,7 @@ QrCodeScanner::QrCodeScanner(QObject *parent)
|
||||
m_probe = new QVideoProbe(this);
|
||||
m_thread = new QrScanThread(this);
|
||||
m_thread->start();
|
||||
QObject::connect(m_thread, SIGNAL(decoded(int, QString)), this, SIGNAL(decoded(int, QString)));
|
||||
QObject::connect(m_thread, SIGNAL(decoded(QString)), this, SIGNAL(decoded(QString)));
|
||||
QObject::connect(m_thread, SIGNAL(notifyError(const QString &, bool)), this, SIGNAL(notifyError(const QString &, bool)));
|
||||
connect(m_probe, SIGNAL(videoFrameProbed(QVideoFrame)), this, SLOT(processFrame(QVideoFrame)));
|
||||
}
|
||||
|
||||
@@ -56,8 +56,7 @@ public Q_SLOTS:
|
||||
Q_SIGNALS:
|
||||
void enabledChanged();
|
||||
|
||||
void decoded(int type, const QString &data);
|
||||
void decode(int type, const QString &data);
|
||||
void decoded(const QString &data);
|
||||
void notifyError(const QString &error, bool warning = false);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -38,62 +38,15 @@ QrScanThread::QrScanThread(QObject *parent)
|
||||
: QThread(parent)
|
||||
,m_running(true)
|
||||
{
|
||||
m_scanner.set_handler(*this);
|
||||
}
|
||||
|
||||
void QrScanThread::image_callback(zbar::Image &image)
|
||||
{
|
||||
qDebug() << "image_callback : Found Code ! " ;
|
||||
for(zbar::Image::SymbolIterator sym = image.symbol_begin();
|
||||
sym != image.symbol_end();
|
||||
++sym)
|
||||
if(!sym->get_count()) {
|
||||
QString data = QString::fromStdString(sym->get_data());
|
||||
emit decoded(sym->get_type(), data);
|
||||
}
|
||||
}
|
||||
|
||||
void QrScanThread::processZImage(zbar::Image &image)
|
||||
{
|
||||
m_scanner.recycle_image(image);
|
||||
zbar::Image tmp = image.convert(*(long*)"Y800");
|
||||
m_scanner.scan(tmp);
|
||||
image.set_symbols(tmp.get_symbols());
|
||||
}
|
||||
|
||||
bool QrScanThread::zimageFromQImage(const QImage &qimg, zbar::Image &dst)
|
||||
{
|
||||
switch( qimg.format() ){
|
||||
case QImage::Format_RGB32 :
|
||||
case QImage::Format_ARGB32 :
|
||||
case QImage::Format_ARGB32_Premultiplied :
|
||||
break;
|
||||
default :
|
||||
emit notifyError(QString("Invalid QImage Format !"));
|
||||
return false;
|
||||
}
|
||||
unsigned int bpl( qimg.bytesPerLine() ), width( bpl / 4), height( qimg.height());
|
||||
dst.set_size(width, height);
|
||||
dst.set_format("BGR4");
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
unsigned long datalen = qimg.sizeInBytes();
|
||||
#else
|
||||
unsigned long datalen = qimg.byteCount();
|
||||
#endif
|
||||
dst.set_data(qimg.bits(), datalen);
|
||||
if((width * 4 != bpl) || (width * height * 4 > datalen)){
|
||||
emit notifyError(QString("QImage to Zbar::Image failed !"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void QrScanThread::processQImage(const QImage &qimg)
|
||||
{
|
||||
try {
|
||||
m_image = QSharedPointer<zbar::Image>(new zbar::Image());
|
||||
if( ! zimageFromQImage(qimg, *m_image) )
|
||||
return;
|
||||
processZImage(*m_image);
|
||||
for (const std::string &code : m_decoder.decode(qimg))
|
||||
{
|
||||
emit decoded(QString::fromStdString(code));
|
||||
}
|
||||
}
|
||||
catch(std::exception &e) {
|
||||
qDebug() << "ERROR: " << e.what();
|
||||
|
||||
@@ -35,9 +35,10 @@
|
||||
#include <QEvent>
|
||||
#include <QVideoFrame>
|
||||
#include <QCamera>
|
||||
#include <zbar.h>
|
||||
|
||||
class QrScanThread : public QThread, public zbar::Image::Handler
|
||||
#include "Decoder.h"
|
||||
|
||||
class QrScanThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -47,20 +48,16 @@ public:
|
||||
virtual void stop();
|
||||
|
||||
Q_SIGNALS:
|
||||
void decoded(int type, const QString &data);
|
||||
void decoded(const QString &data);
|
||||
void notifyError(const QString &error, bool warning = false);
|
||||
|
||||
protected:
|
||||
virtual void run();
|
||||
void processVideoFrame(const QVideoFrame &);
|
||||
void processQImage(const QImage &);
|
||||
void processZImage(zbar::Image &image);
|
||||
virtual void image_callback(zbar::Image &image);
|
||||
bool zimageFromQImage(const QImage&, zbar::Image &);
|
||||
|
||||
private:
|
||||
zbar::ImageScanner m_scanner;
|
||||
QSharedPointer<zbar::Image> m_image;
|
||||
QrDecoder m_decoder;
|
||||
bool m_running;
|
||||
QMutex m_mutex;
|
||||
QWaitCondition m_waitCondition;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "DaemonManager.h"
|
||||
#include "common/util.h"
|
||||
#include <QElapsedTimer>
|
||||
#include <QFile>
|
||||
#include <QMutexLocker>
|
||||
@@ -47,24 +48,7 @@ namespace {
|
||||
static const int DAEMON_START_TIMEOUT_SECONDS = 120;
|
||||
}
|
||||
|
||||
DaemonManager * DaemonManager::m_instance = nullptr;
|
||||
QStringList DaemonManager::m_clArgs;
|
||||
|
||||
DaemonManager *DaemonManager::instance(const QStringList *args/* = nullptr*/)
|
||||
{
|
||||
if (!m_instance) {
|
||||
m_instance = new DaemonManager;
|
||||
// store command line arguments for later use
|
||||
if (args != nullptr)
|
||||
{
|
||||
m_clArgs = *args;
|
||||
}
|
||||
}
|
||||
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const QString &dataDir, const QString &bootstrapNodeAddress, bool noSync /* = false*/)
|
||||
bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const QString &dataDir, const QString &bootstrapNodeAddress, bool noSync /* = false*/, bool pruneBlockchain /* = false*/)
|
||||
{
|
||||
if (!QFileInfo(m_monerod).isFile())
|
||||
{
|
||||
@@ -85,12 +69,6 @@ bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const
|
||||
else if (nettype == NetworkType::STAGENET)
|
||||
arguments << "--stagenet";
|
||||
|
||||
foreach (const QString &str, m_clArgs) {
|
||||
qDebug() << QString(" [%1] ").arg(str);
|
||||
if (!str.isEmpty())
|
||||
arguments << str;
|
||||
}
|
||||
|
||||
// Custom startup flags for daemon
|
||||
foreach (const QString &str, flags.split(" ")) {
|
||||
qDebug() << QString(" [%1] ").arg(str);
|
||||
@@ -108,15 +86,18 @@ bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const
|
||||
arguments << "--bootstrap-daemon-address" << bootstrapNodeAddress;
|
||||
}
|
||||
|
||||
if (pruneBlockchain) {
|
||||
if (!checkLmdbExists(dataDir)) { // check that DB has not already been created
|
||||
arguments << "--prune-blockchain";
|
||||
}
|
||||
}
|
||||
|
||||
if (noSync) {
|
||||
arguments << "--no-sync";
|
||||
}
|
||||
|
||||
if (!flags.contains("--out-peers", Qt::CaseSensitive) && bootstrapNodeAddress == "auto") {
|
||||
arguments << "--out-peers" << "16";
|
||||
}
|
||||
|
||||
arguments << "--check-updates" << "disabled";
|
||||
arguments << "--non-interactive";
|
||||
|
||||
// --max-concurrency based on threads available.
|
||||
int32_t concurrency = qMax(1, QThread::idealThreadCount() / 2);
|
||||
@@ -349,6 +330,13 @@ QVariantMap DaemonManager::validateDataDir(const QString &dataDir) const
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DaemonManager::checkLmdbExists(QString datadir) {
|
||||
if (datadir.isEmpty() || datadir.isNull()) {
|
||||
datadir = QString::fromStdString(tools::get_default_data_dir());
|
||||
}
|
||||
return validateDataDir(datadir).value("lmdbExists").value<bool>();
|
||||
}
|
||||
|
||||
DaemonManager::DaemonManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_scheduler(this)
|
||||
|
||||
@@ -44,10 +44,10 @@ class DaemonManager : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DaemonManager(QObject *parent = 0);
|
||||
~DaemonManager();
|
||||
|
||||
static DaemonManager * instance(const QStringList *args = nullptr);
|
||||
|
||||
Q_INVOKABLE bool start(const QString &flags, NetworkType::Type nettype, const QString &dataDir = "", const QString &bootstrapNodeAddress = "", bool noSync = false);
|
||||
Q_INVOKABLE bool start(const QString &flags, NetworkType::Type nettype, const QString &dataDir = "", const QString &bootstrapNodeAddress = "", bool noSync = false, bool pruneBlockchain = false);
|
||||
Q_INVOKABLE void stopAsync(NetworkType::Type nettype, const QJSValue& callback);
|
||||
|
||||
Q_INVOKABLE bool noSync() const noexcept;
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
Q_INVOKABLE void sendCommandAsync(const QStringList &cmd, NetworkType::Type nettype, const QJSValue& callback) const;
|
||||
Q_INVOKABLE void exit();
|
||||
Q_INVOKABLE QVariantMap validateDataDir(const QString &dataDir) const;
|
||||
Q_INVOKABLE bool checkLmdbExists(QString datadir);
|
||||
|
||||
private:
|
||||
|
||||
@@ -76,11 +77,6 @@ public slots:
|
||||
void stateChanged(QProcess::ProcessState state);
|
||||
|
||||
private:
|
||||
explicit DaemonManager(QObject *parent = 0);
|
||||
~DaemonManager();
|
||||
|
||||
static DaemonManager * m_instance;
|
||||
static QStringList m_clArgs;
|
||||
std::unique_ptr<QProcess> m_daemon;
|
||||
QMutex m_daemonMutex;
|
||||
QString m_monerod;
|
||||
|
||||
@@ -78,7 +78,14 @@ void Subaddress::setLabel(quint32 accountIndex, quint32 addressIndex, const QStr
|
||||
|
||||
void Subaddress::refresh(quint32 accountIndex) const
|
||||
{
|
||||
m_subaddressImpl->refresh(accountIndex);
|
||||
try
|
||||
{
|
||||
m_subaddressImpl->refresh(accountIndex);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
qCritical() << "Failed to refresh account" << accountIndex << "subaddresses:" << e.what();
|
||||
}
|
||||
getAll();
|
||||
}
|
||||
|
||||
|
||||
@@ -104,10 +104,7 @@ void Wallet::updateConnectionStatusAsync()
|
||||
setConnectionStatus(ConnectionStatus_Connecting);
|
||||
}
|
||||
ConnectionStatus newStatus = static_cast<ConnectionStatus>(m_walletImpl->connected());
|
||||
if (newStatus != m_connectionStatus || !m_initialized) {
|
||||
m_initialized = true;
|
||||
setConnectionStatus(newStatus);
|
||||
}
|
||||
setConnectionStatus(newStatus);
|
||||
// Release lock
|
||||
m_connectionStatusRunning = false;
|
||||
});
|
||||
@@ -115,8 +112,13 @@ void Wallet::updateConnectionStatusAsync()
|
||||
|
||||
Wallet::ConnectionStatus Wallet::connected(bool forceCheck)
|
||||
{
|
||||
if (!m_initialized)
|
||||
{
|
||||
return ConnectionStatus_Connecting;
|
||||
}
|
||||
|
||||
// cache connection status
|
||||
if (forceCheck || !m_initialized || (m_connectionStatusTime.elapsed() / 1000 > m_connectionStatusTtl && !m_connectionStatusRunning) || m_connectionStatusTime.elapsed() > 30000) {
|
||||
if (forceCheck || (m_connectionStatusTime.elapsed() / 1000 > m_connectionStatusTtl && !m_connectionStatusRunning) || m_connectionStatusTime.elapsed() > 30000) {
|
||||
qDebug() << "Checking connection status";
|
||||
m_connectionStatusRunning = true;
|
||||
m_connectionStatusTime.restart();
|
||||
@@ -277,14 +279,25 @@ void Wallet::initAsync(
|
||||
{
|
||||
qDebug() << "initAsync: " + daemonAddress;
|
||||
const auto future = m_scheduler.run([this, daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight, proxyAddress] {
|
||||
bool success = init(daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight, proxyAddress);
|
||||
if (success)
|
||||
m_initialized = init(
|
||||
daemonAddress,
|
||||
trustedDaemon,
|
||||
upperTransactionLimit,
|
||||
isRecovering,
|
||||
isRecoveringFromDevice,
|
||||
restoreHeight,
|
||||
proxyAddress);
|
||||
if (m_initialized)
|
||||
{
|
||||
emit walletCreationHeightChanged();
|
||||
qDebug() << "init async finished - starting refresh";
|
||||
connected(true);
|
||||
startRefresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
qCritical() << "Failed to initialize the wallet";
|
||||
}
|
||||
});
|
||||
if (future.first)
|
||||
{
|
||||
@@ -519,25 +532,40 @@ void Wallet::pauseRefresh()
|
||||
m_refreshEnabled = false;
|
||||
}
|
||||
|
||||
PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QString &payment_id,
|
||||
quint64 amount, quint32 mixin_count,
|
||||
PendingTransaction::Priority priority)
|
||||
PendingTransaction *Wallet::createTransaction(
|
||||
const QVector<QString> &destinationAddresses,
|
||||
const QString &payment_id,
|
||||
const QVector<quint64> &amounts,
|
||||
quint32 mixin_count,
|
||||
PendingTransaction::Priority priority)
|
||||
{
|
||||
std::vector<std::string> destinations;
|
||||
for (const auto &address : destinationAddresses) {
|
||||
destinations.push_back(address.toStdString());
|
||||
}
|
||||
std::set<uint32_t> subaddr_indices;
|
||||
Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction(
|
||||
dst_addr.toStdString(), payment_id.toStdString(), amount, mixin_count,
|
||||
static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices);
|
||||
PendingTransaction * result = new PendingTransaction(ptImpl,0);
|
||||
Monero::PendingTransaction *ptImpl = m_walletImpl->createTransactionMultDest(
|
||||
destinations,
|
||||
payment_id.toStdString(),
|
||||
std::vector<uint64_t>(amounts.begin(), amounts.end()),
|
||||
mixin_count,
|
||||
static_cast<Monero::PendingTransaction::Priority>(priority),
|
||||
currentSubaddressAccount(),
|
||||
subaddr_indices);
|
||||
PendingTransaction *result = new PendingTransaction(ptImpl, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Wallet::createTransactionAsync(const QString &dst_addr, const QString &payment_id,
|
||||
quint64 amount, quint32 mixin_count,
|
||||
PendingTransaction::Priority priority)
|
||||
void Wallet::createTransactionAsync(
|
||||
const QVector<QString> &destinationAddresses,
|
||||
const QString &payment_id,
|
||||
const QVector<quint64> &amounts,
|
||||
quint32 mixin_count,
|
||||
PendingTransaction::Priority priority)
|
||||
{
|
||||
m_scheduler.run([this, dst_addr, payment_id, amount, mixin_count, priority] {
|
||||
PendingTransaction *tx = createTransaction(dst_addr, payment_id, amount, mixin_count, priority);
|
||||
emit transactionCreated(tx, dst_addr, payment_id, mixin_count);
|
||||
m_scheduler.run([this, destinationAddresses, payment_id, amounts, mixin_count, priority] {
|
||||
PendingTransaction *tx = createTransaction(destinationAddresses, payment_id, amounts, mixin_count, priority);
|
||||
emit transactionCreated(tx, destinationAddresses, payment_id, mixin_count);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -558,7 +586,7 @@ void Wallet::createTransactionAllAsync(const QString &dst_addr, const QString &p
|
||||
{
|
||||
m_scheduler.run([this, dst_addr, payment_id, mixin_count, priority] {
|
||||
PendingTransaction *tx = createTransactionAll(dst_addr, payment_id, mixin_count, priority);
|
||||
emit transactionCreated(tx, dst_addr, payment_id, mixin_count);
|
||||
emit transactionCreated(tx, {dst_addr}, payment_id, mixin_count);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -573,7 +601,7 @@ void Wallet::createSweepUnmixableTransactionAsync()
|
||||
{
|
||||
m_scheduler.run([this] {
|
||||
PendingTransaction *tx = createSweepUnmixableTransaction();
|
||||
emit transactionCreated(tx, "", "", 0);
|
||||
emit transactionCreated(tx, {""}, "", 0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -613,17 +641,32 @@ void Wallet::disposeTransaction(UnsignedTransaction *t)
|
||||
delete t;
|
||||
}
|
||||
|
||||
void Wallet::estimateTransactionFeeAsync(const QString &destination,
|
||||
quint64 amount,
|
||||
PendingTransaction::Priority priority,
|
||||
const QJSValue &callback)
|
||||
void Wallet::estimateTransactionFeeAsync(
|
||||
const QVector<QString> &destinationAddresses,
|
||||
const QVector<quint64> &amounts,
|
||||
PendingTransaction::Priority priority,
|
||||
const QJSValue &callback)
|
||||
{
|
||||
m_scheduler.run([this, destination, amount, priority] {
|
||||
const uint64_t fee = m_walletImpl->estimateTransactionFee(
|
||||
{std::make_pair(destination.toStdString(), amount)},
|
||||
static_cast<Monero::PendingTransaction::Priority>(priority));
|
||||
return QJSValueList({QString::fromStdString(Monero::Wallet::displayAmount(fee))});
|
||||
}, callback);
|
||||
m_scheduler.run(
|
||||
[this, destinationAddresses, amounts, priority] {
|
||||
if (destinationAddresses.size() != amounts.size())
|
||||
{
|
||||
return QJSValueList({""});
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, uint64_t>> destinations;
|
||||
destinations.reserve(destinationAddresses.size());
|
||||
for (size_t index = 0; index < destinationAddresses.size(); ++index)
|
||||
{
|
||||
destinations.emplace_back(std::make_pair(destinationAddresses[index].toStdString(), amounts[index]));
|
||||
}
|
||||
|
||||
const uint64_t fee = m_walletImpl->estimateTransactionFee(
|
||||
destinations,
|
||||
static_cast<Monero::PendingTransaction::Priority>(priority));
|
||||
return QJSValueList({QString::fromStdString(Monero::Wallet::displayAmount(fee))});
|
||||
},
|
||||
callback);
|
||||
}
|
||||
|
||||
TransactionHistory *Wallet::history() const
|
||||
@@ -1054,6 +1097,7 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
|
||||
, m_connectionStatus(Wallet::ConnectionStatus_Disconnected)
|
||||
, m_connectionStatusTtl(WALLET_CONNECTION_STATUS_CACHE_TTL_SECONDS)
|
||||
, m_disconnected(true)
|
||||
, m_initialized(false)
|
||||
, m_currentSubaddressAccount(0)
|
||||
, m_subaddress(nullptr)
|
||||
, m_subaddressModel(nullptr)
|
||||
@@ -1074,7 +1118,6 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
|
||||
m_connectionStatusTime.start();
|
||||
m_daemonBlockChainHeightTime.start();
|
||||
m_daemonBlockChainTargetHeightTime.start();
|
||||
m_initialized = false;
|
||||
m_connectionStatusRunning = false;
|
||||
m_daemonUsername = "";
|
||||
m_daemonPassword = "";
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#ifndef WALLET_H
|
||||
#define WALLET_H
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
@@ -214,15 +216,13 @@ public:
|
||||
Q_INVOKABLE void startRefresh();
|
||||
Q_INVOKABLE void pauseRefresh();
|
||||
|
||||
//! creates transaction
|
||||
Q_INVOKABLE PendingTransaction * createTransaction(const QString &dst_addr, const QString &payment_id,
|
||||
quint64 amount, quint32 mixin_count,
|
||||
PendingTransaction::Priority priority);
|
||||
|
||||
//! creates async transaction
|
||||
Q_INVOKABLE void createTransactionAsync(const QString &dst_addr, const QString &payment_id,
|
||||
quint64 amount, quint32 mixin_count,
|
||||
PendingTransaction::Priority priority);
|
||||
Q_INVOKABLE void createTransactionAsync(
|
||||
const QVector<QString> &destinationAddresses,
|
||||
const QString &payment_id,
|
||||
const QVector<quint64> &amounts,
|
||||
quint32 mixin_count,
|
||||
PendingTransaction::Priority priority);
|
||||
|
||||
//! creates transaction with all outputs
|
||||
Q_INVOKABLE PendingTransaction * createTransactionAll(const QString &dst_addr, const QString &payment_id,
|
||||
@@ -253,10 +253,11 @@ public:
|
||||
//! deletes unsigned transaction and frees memory
|
||||
Q_INVOKABLE void disposeTransaction(UnsignedTransaction * t);
|
||||
|
||||
Q_INVOKABLE void estimateTransactionFeeAsync(const QString &destination,
|
||||
quint64 amount,
|
||||
PendingTransaction::Priority priority,
|
||||
const QJSValue &callback);
|
||||
Q_INVOKABLE void estimateTransactionFeeAsync(
|
||||
const QVector<QString> &destinationAddresses,
|
||||
const QVector<quint64> &amounts,
|
||||
PendingTransaction::Priority priority,
|
||||
const QJSValue &callback);
|
||||
|
||||
//! returns transaction history
|
||||
TransactionHistory * history() const;
|
||||
@@ -380,7 +381,11 @@ signals:
|
||||
void deviceShowAddressShowed();
|
||||
|
||||
// emitted when transaction is created async
|
||||
void transactionCreated(PendingTransaction * transaction, QString address, QString paymentId, quint32 mixinCount);
|
||||
void transactionCreated(
|
||||
PendingTransaction *transaction,
|
||||
const QVector<QString> &addresses,
|
||||
const QString &paymentId,
|
||||
quint32 mixinCount);
|
||||
|
||||
void connectionStatusChanged(int status) const;
|
||||
void currentSubaddressAccountChanged() const;
|
||||
@@ -413,6 +418,13 @@ private:
|
||||
quint64 restoreHeight,
|
||||
const QString& proxyAddress);
|
||||
|
||||
PendingTransaction *createTransaction(
|
||||
const QVector<QString> &destinationAddresses,
|
||||
const QString &payment_id,
|
||||
const QVector<quint64> &amounts,
|
||||
quint32 mixin_count,
|
||||
PendingTransaction::Priority priority);
|
||||
|
||||
bool disconnected() const;
|
||||
bool refreshing() const;
|
||||
void refreshingSet(bool value);
|
||||
@@ -444,7 +456,7 @@ private:
|
||||
int m_connectionStatusTtl;
|
||||
mutable QElapsedTimer m_connectionStatusTime;
|
||||
bool m_disconnected;
|
||||
mutable bool m_initialized;
|
||||
std::atomic<bool> m_initialized;
|
||||
uint32_t m_currentSubaddressAccount;
|
||||
Subaddress * m_subaddress;
|
||||
mutable SubaddressModel * m_subaddressModel;
|
||||
|
||||
@@ -251,7 +251,7 @@ QString WalletManager::errorString() const
|
||||
return tr("Unknown error");
|
||||
}
|
||||
|
||||
quint64 WalletManager::maximumAllowedAmount() const
|
||||
quint64 WalletManager::maximumAllowedAmount()
|
||||
{
|
||||
return Monero::Wallet::maximumAllowedAmount();
|
||||
}
|
||||
@@ -266,7 +266,7 @@ QString WalletManager::displayAmount(quint64 amount)
|
||||
return QString::fromStdString(Monero::Wallet::displayAmount(amount));
|
||||
}
|
||||
|
||||
quint64 WalletManager::amountFromString(const QString &amount) const
|
||||
quint64 WalletManager::amountFromString(const QString &amount)
|
||||
{
|
||||
return Monero::Wallet::amountFromString(amount.toStdString());
|
||||
}
|
||||
@@ -276,6 +276,17 @@ quint64 WalletManager::amountFromDouble(double amount) const
|
||||
return Monero::Wallet::amountFromDouble(amount);
|
||||
}
|
||||
|
||||
QString WalletManager::amountsSumFromStrings(const QVector<QString> &amounts)
|
||||
{
|
||||
quint64 sum = 0;
|
||||
for (const auto &amountString : amounts)
|
||||
{
|
||||
const quint64 amount = amountFromString(amountString);
|
||||
sum = sum + std::min(maximumAllowedAmount() - sum, amount);
|
||||
}
|
||||
return QString::number(sum);
|
||||
}
|
||||
|
||||
bool WalletManager::paymentIdValid(const QString &payment_id) const
|
||||
{
|
||||
return Monero::Wallet::paymentIdValid(payment_id.toStdString());
|
||||
|
||||
@@ -133,9 +133,10 @@ public:
|
||||
|
||||
//! since we can't call static method from QML, move it to this class
|
||||
Q_INVOKABLE static QString displayAmount(quint64 amount);
|
||||
Q_INVOKABLE quint64 amountFromString(const QString &amount) const;
|
||||
Q_INVOKABLE static quint64 amountFromString(const QString &amount);
|
||||
Q_INVOKABLE quint64 amountFromDouble(double amount) const;
|
||||
Q_INVOKABLE quint64 maximumAllowedAmount() const;
|
||||
Q_INVOKABLE static QString amountsSumFromStrings(const QVector<QString> &amounts);
|
||||
Q_INVOKABLE static quint64 maximumAllowedAmount();
|
||||
|
||||
// QML JS engine doesn't support unsigned integers
|
||||
Q_INVOKABLE QString maximumAllowedAmountAsString() const;
|
||||
|
||||
@@ -117,13 +117,14 @@ Logger::Logger(QCoreApplication &parent, QString userDefinedLogFilePath)
|
||||
c.setGlobally(el::ConfigurationType::ToFile, "false");
|
||||
c.setGlobally(el::ConfigurationType::ToStandardOutput, "true");
|
||||
el::Loggers::setDefaultConfigurations(c, true);
|
||||
qInstallMessageHandler(messageHandler);
|
||||
}
|
||||
|
||||
void Logger::resetLogFilePath(bool portable)
|
||||
{
|
||||
m_logFilePath = QDir::toNativeSeparators(getLogPath(m_userDefinedLogFilePath, portable));
|
||||
Monero::Wallet::init(m_applicationFilePath.c_str(), "monero-wallet-gui", m_logFilePath.toStdString(), true);
|
||||
qInstallMessageHandler(messageHandler);
|
||||
qWarning() << "Logging to" << m_logFilePath;
|
||||
emit logFilePathChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -120,6 +120,10 @@ Q_IMPORT_PLUGIN(QQmlDebugServerFactory)
|
||||
Q_IMPORT_PLUGIN(QTcpServerConnectionFactory)
|
||||
Q_IMPORT_PLUGIN(QGenericEnginePlugin)
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
Q_IMPORT_PLUGIN(QtQmlPlugin)
|
||||
#endif
|
||||
Q_IMPORT_PLUGIN(QtQmlModelsPlugin)
|
||||
Q_IMPORT_PLUGIN(QtQuick2Plugin)
|
||||
Q_IMPORT_PLUGIN(QtQuickLayoutsPlugin)
|
||||
Q_IMPORT_PLUGIN(QtGraphicalEffectsPlugin)
|
||||
@@ -156,8 +160,6 @@ int main(int argc, char *argv[])
|
||||
// platform dependant settings
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
bool isDesktop = true;
|
||||
#elif defined(Q_OS_LINUX)
|
||||
bool isLinux = true;
|
||||
#elif defined(Q_OS_ANDROID)
|
||||
bool isAndroid = true;
|
||||
#elif defined(Q_OS_IOS)
|
||||
@@ -179,8 +181,8 @@ int main(int argc, char *argv[])
|
||||
// disable "QApplication: invalid style override passed" warning
|
||||
if (isDesktop) qputenv("QT_STYLE_OVERRIDE", "fusion");
|
||||
#ifdef Q_OS_LINUX
|
||||
// force platform xcb
|
||||
if (isDesktop) qputenv("QT_QPA_PLATFORM", "xcb");
|
||||
// platform xcb by default
|
||||
if (isDesktop && qEnvironmentVariableIsEmpty("QT_QPA_PLATFORM")) qputenv("QT_QPA_PLATFORM", "xcb");
|
||||
#endif
|
||||
|
||||
// enable High DPI scaling
|
||||
@@ -189,6 +191,12 @@ int main(int argc, char *argv[])
|
||||
// Turn off colors in monerod log output.
|
||||
qputenv("TERM", "goaway");
|
||||
|
||||
#if defined(Q_OS_MACOS)
|
||||
QDir::setCurrent(QDir(MacOSHelper::bundlePath() + QDir::separator() + "..").canonicalPath());
|
||||
#endif
|
||||
|
||||
qputenv("QML_DISABLE_DISK_CACHE", "1");
|
||||
|
||||
MainApp app(argc, argv);
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
@@ -277,7 +285,6 @@ Verify update binary using 'shasum'-compatible (SHA256 algo) output signed by tw
|
||||
if (logLevelOk && logLevel >= 0 && logLevel <= Monero::WalletManagerFactory::LogLevel_Max){
|
||||
Monero::WalletManagerFactory::setLogLevel(logLevel);
|
||||
}
|
||||
qWarning().noquote() << "app startd" << "(log: " + logger.logFilePath() + ")";
|
||||
|
||||
if (parser.isSet(verifyUpdateOption))
|
||||
{
|
||||
@@ -305,11 +312,6 @@ Verify update binary using 'shasum'-compatible (SHA256 algo) output signed by tw
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Desktop entry
|
||||
#ifdef Q_OS_LINUX
|
||||
registerXdgMime(app);
|
||||
#endif
|
||||
|
||||
IPC *ipc = new IPC(&app);
|
||||
QStringList posArgs = parser.positionalArguments();
|
||||
|
||||
@@ -326,10 +328,6 @@ Verify update binary using 'shasum'-compatible (SHA256 algo) output signed by tw
|
||||
// start listening
|
||||
QTimer::singleShot(0, ipc, SLOT(bind()));
|
||||
|
||||
#if defined(Q_OS_MACOS)
|
||||
QDir::setCurrent(QDir(MacOSHelper::bundlePath() + QDir::separator() + "..").canonicalPath());
|
||||
#endif
|
||||
|
||||
// screen settings
|
||||
// Mobile is designed on 128dpi
|
||||
qreal ref_dpi = 128;
|
||||
@@ -454,8 +452,8 @@ Verify update binary using 'shasum'-compatible (SHA256 algo) output signed by tw
|
||||
|
||||
// Exclude daemon manager from IOS
|
||||
#ifndef Q_OS_IOS
|
||||
DaemonManager * daemonManager = DaemonManager::instance();
|
||||
engine.rootContext()->setContextProperty("daemonManager", daemonManager);
|
||||
DaemonManager daemonManager;
|
||||
engine.rootContext()->setContextProperty("daemonManager", &daemonManager);
|
||||
#endif
|
||||
|
||||
engine.rootContext()->setContextProperty("isWindows", isWindows);
|
||||
|
||||
@@ -27,10 +27,16 @@
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "oshelper.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QGuiApplication>
|
||||
#include <QFileDialog>
|
||||
#include <QScreen>
|
||||
#include <QStandardPaths>
|
||||
#include <QTemporaryFile>
|
||||
#include <QWindow>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
@@ -46,13 +52,49 @@
|
||||
#endif
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
#include <X11/XKBlib.h>
|
||||
#undef Bool
|
||||
#undef KeyPress
|
||||
#undef KeyRelease
|
||||
#undef FocusIn
|
||||
#undef FocusOut
|
||||
// #undef those Xlib #defines that conflict with QEvent::Type enum
|
||||
#include "qt/utils.h"
|
||||
#endif
|
||||
|
||||
#include "QR-Code-scanner/Decoder.h"
|
||||
#include "qt/ScopeGuard.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
QPixmap screenshot()
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
return MacOSHelper::screenshot();
|
||||
#else
|
||||
std::unordered_set<QWindow *> hidden;
|
||||
const QWindowList windows = QGuiApplication::allWindows();
|
||||
for (QWindow *window : windows)
|
||||
{
|
||||
if (window->isVisible())
|
||||
{
|
||||
hidden.emplace(window);
|
||||
window->hide();
|
||||
}
|
||||
}
|
||||
const auto unhide = sg::make_scope_guard([&hidden]() {
|
||||
for (QWindow *window : hidden)
|
||||
{
|
||||
window->show();
|
||||
}
|
||||
});
|
||||
|
||||
return QGuiApplication::primaryScreen()->grabWindow(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
bool openFolderAndSelectItem(const QString &filePath)
|
||||
{
|
||||
@@ -85,11 +127,38 @@ OSHelper::OSHelper(QObject *parent) : QObject(parent)
|
||||
|
||||
}
|
||||
|
||||
void OSHelper::createDesktopEntry() const
|
||||
{
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
registerXdgMime();
|
||||
#endif
|
||||
}
|
||||
|
||||
QString OSHelper::downloadLocation() const
|
||||
{
|
||||
return QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
|
||||
}
|
||||
|
||||
QList<QString> OSHelper::grabQrCodesFromScreen() const
|
||||
{
|
||||
QList<QString> codes;
|
||||
|
||||
try
|
||||
{
|
||||
const QImage image = screenshot().toImage();
|
||||
const std::vector<std::string> decoded = QrDecoder().decode(image);
|
||||
std::for_each(decoded.begin(), decoded.end(), [&codes](const std::string &code) {
|
||||
codes.push_back(QString::fromStdString(code));
|
||||
});
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
qWarning() << e.what();
|
||||
}
|
||||
|
||||
return codes;
|
||||
}
|
||||
|
||||
bool OSHelper::openContainingFolder(const QString &filePath) const
|
||||
{
|
||||
QString canonicalFilePath = QFileInfo(filePath).canonicalFilePath();
|
||||
@@ -154,6 +223,7 @@ bool OSHelper::isCapsLock() const
|
||||
unsigned n;
|
||||
XkbGetIndicatorState(d, XkbUseCoreKbd, &n);
|
||||
caps_state = (n & 0x01) == 1;
|
||||
XCloseDisplay(d);
|
||||
}
|
||||
return caps_state;
|
||||
#elif defined(Q_OS_MAC)
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
#ifndef OSHELPER_H
|
||||
#define OSHELPER_H
|
||||
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
/**
|
||||
* @brief The OSHelper class - exports to QML some OS-related functions
|
||||
*/
|
||||
@@ -41,7 +43,9 @@ class OSHelper : public QObject
|
||||
public:
|
||||
explicit OSHelper(QObject *parent = 0);
|
||||
|
||||
Q_INVOKABLE void createDesktopEntry() const;
|
||||
Q_INVOKABLE QString downloadLocation() const;
|
||||
Q_INVOKABLE QList<QString> grabQrCodesFromScreen() const;
|
||||
Q_INVOKABLE bool openContainingFolder(const QString &filePath) const;
|
||||
Q_INVOKABLE QString openSaveFileDialog(const QString &title, const QString &folder, const QString &filename) const;
|
||||
Q_INVOKABLE QString temporaryFilename() const;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
file(GLOB_RECURSE SOURCES *.cpp)
|
||||
file(GLOB_RECURSE HEADERS *.h)
|
||||
|
||||
find_library(GCRYPT_LIBRARY gcrypt)
|
||||
find_library(GPG_ERROR_LIBRARY gpg-error)
|
||||
find_library(GCRYPT_LIBRARY gcrypt REQUIRED)
|
||||
find_path(GCRYPT_INCLUDE_DIR gcrypt.h REQUIRED)
|
||||
|
||||
find_library(GPG_ERROR_LIBRARY gpg-error REQUIRED)
|
||||
|
||||
add_library(openpgp
|
||||
${SOURCES}
|
||||
@@ -10,7 +12,8 @@ add_library(openpgp
|
||||
|
||||
target_include_directories(openpgp
|
||||
PUBLIC
|
||||
${CMAKE_SOURCE_DIR}/monero/contrib/epee/include)
|
||||
${CMAKE_SOURCE_DIR}/monero/contrib/epee/include
|
||||
${GCRYPT_INCLUDE_DIR})
|
||||
|
||||
target_link_libraries(openpgp
|
||||
PUBLIC
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
#include "FutureScheduler.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <QThreadPool>
|
||||
|
||||
FutureScheduler::FutureScheduler(QObject *parent)
|
||||
: QObject(parent), Alive(0), Stopping(false)
|
||||
{
|
||||
static std::once_flag once;
|
||||
std::call_once(once, []() {
|
||||
QThreadPool::globalInstance()->setMaxThreadCount(4);
|
||||
});
|
||||
}
|
||||
|
||||
FutureScheduler::~FutureScheduler()
|
||||
|
||||
@@ -179,13 +179,13 @@ bool MoneroSettings::portable() const
|
||||
return this->m_settings && this->m_settings->fileName() == portableFilePath();
|
||||
}
|
||||
|
||||
bool MoneroSettings::portableConfigExists() const
|
||||
bool MoneroSettings::portableConfigExists()
|
||||
{
|
||||
QFileInfo info(portableFilePath());
|
||||
return info.exists() && info.isFile();
|
||||
}
|
||||
|
||||
QString MoneroSettings::portableFilePath() const
|
||||
QString MoneroSettings::portableFilePath()
|
||||
{
|
||||
static QString filename(QDir(portableFolderName()).absoluteFilePath("settings.ini"));
|
||||
return filename;
|
||||
|
||||
@@ -64,6 +64,7 @@ public:
|
||||
Q_INVOKABLE void setWritable(bool enabled);
|
||||
|
||||
static QString portableFolderName();
|
||||
static bool portableConfigExists();
|
||||
|
||||
public slots:
|
||||
void _q_propertyChanged();
|
||||
@@ -84,8 +85,7 @@ private:
|
||||
void store();
|
||||
|
||||
bool portable() const;
|
||||
bool portableConfigExists() const;
|
||||
QString portableFilePath() const;
|
||||
static QString portableFilePath();
|
||||
std::unique_ptr<QSettings> portableSettings() const;
|
||||
std::unique_ptr<QSettings> unportableSettings() const;
|
||||
void swap(std::unique_ptr<QSettings> newSettings);
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#ifndef MACOSHELPER_H
|
||||
#define MACOSHELPER_H
|
||||
|
||||
#include <QPixmap>
|
||||
|
||||
class MacOSHelper
|
||||
{
|
||||
MacOSHelper() {}
|
||||
@@ -36,6 +38,7 @@ class MacOSHelper
|
||||
public:
|
||||
static bool isCapsLock();
|
||||
static bool openFolderAndSelectItem(const QUrl &path);
|
||||
static QPixmap screenshot();
|
||||
static QString bundlePath();
|
||||
};
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtGui>
|
||||
#include <QtMac>
|
||||
@@ -37,6 +39,8 @@
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include <Availability.h>
|
||||
|
||||
#include "ScopeGuard.h"
|
||||
|
||||
bool MacOSHelper::isCapsLock()
|
||||
{
|
||||
#ifdef __MAC_10_12
|
||||
@@ -56,6 +60,41 @@ bool MacOSHelper::openFolderAndSelectItem(const QUrl &path)
|
||||
return true;
|
||||
}
|
||||
|
||||
QPixmap MacOSHelper::screenshot()
|
||||
{
|
||||
std::unordered_set<uintptr_t> appWindowIds;
|
||||
for (NSWindow *window in [NSApp windows])
|
||||
{
|
||||
appWindowIds.insert((uintptr_t)[window windowNumber]);
|
||||
}
|
||||
|
||||
CFArrayRef onScreenWindows = CGWindowListCreate(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||
const auto onScreenWindowsClenaup = sg::make_scope_guard([&onScreenWindows]() {
|
||||
CFRelease(onScreenWindows);
|
||||
});
|
||||
|
||||
CFMutableArrayRef foreignWindows = CFArrayCreateMutable(NULL, CFArrayGetCount(onScreenWindows), NULL);
|
||||
const auto foreignWindowsClenaup = sg::make_scope_guard([&foreignWindows]() {
|
||||
CFRelease(foreignWindows);
|
||||
});
|
||||
|
||||
for (CFIndex index = 0, count = CFArrayGetCount(onScreenWindows); index < count; ++index)
|
||||
{
|
||||
const uintptr_t windowId = reinterpret_cast<const uintptr_t>(CFArrayGetValueAtIndex(onScreenWindows, index));
|
||||
if (appWindowIds.find(windowId) == appWindowIds.end())
|
||||
{
|
||||
CFArrayAppendValue(foreignWindows, reinterpret_cast<const void *>(windowId));
|
||||
}
|
||||
}
|
||||
|
||||
CGImageRef image = CGWindowListCreateImageFromArray(CGRectInfinite, foreignWindows, kCGWindowListOptionAll);
|
||||
const auto imageClenaup = sg::make_scope_guard([&image]() {
|
||||
CFRelease(image);
|
||||
});
|
||||
|
||||
return QtMac::fromCGImageRef(image);
|
||||
}
|
||||
|
||||
QString MacOSHelper::bundlePath()
|
||||
{
|
||||
NSBundle *main = [NSBundle mainBundle];
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <QtCore>
|
||||
#include <QApplication>
|
||||
#include <QCoreApplication>
|
||||
#include <QtGlobal>
|
||||
|
||||
#include "TailsOS.h"
|
||||
@@ -88,7 +88,7 @@ QString getAccountName(){
|
||||
}
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
QString xdgMime(QApplication &app){
|
||||
QString xdgMime(){
|
||||
return QString(
|
||||
"[Desktop Entry]\n"
|
||||
"Name=Monero GUI\n"
|
||||
@@ -105,32 +105,31 @@ QString xdgMime(QApplication &app){
|
||||
"StartupNotify=true\n"
|
||||
"X-GNOME-Bugzilla-Bugzilla=GNOME\n"
|
||||
"X-GNOME-UsesNotifications=true\n"
|
||||
).arg(app.applicationFilePath());
|
||||
).arg(QCoreApplication::applicationFilePath());
|
||||
}
|
||||
|
||||
void registerXdgMime(QApplication &app){
|
||||
void registerXdgMime(){
|
||||
// Register desktop entry
|
||||
// - MacOS handled via Info.plist
|
||||
// - Windows handled in the installer by rbrunner7
|
||||
// - Linux written to `QStandardPaths::ApplicationsLocation`
|
||||
// - Tails written to persistent dotfiles
|
||||
QString mime = xdgMime(app);
|
||||
QString mime = xdgMime();
|
||||
QString appPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
|
||||
QString filePath = QString("%1/monero-gui.desktop").arg(appPath);
|
||||
|
||||
if (TailsOS::detect() && TailsOS::detectDotPersistence() && TailsOS::usePersistence) {
|
||||
TailsOS::persistXdgMime(filePath, mime);
|
||||
return;
|
||||
if (TailsOS::detect())
|
||||
{
|
||||
if (TailsOS::detectDotPersistence() && TailsOS::usePersistence)
|
||||
{
|
||||
TailsOS::persistXdgMime(filePath, mime);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QDir().mkpath(QFileInfo(filePath).path());
|
||||
fileWrite(filePath, mime);
|
||||
}
|
||||
|
||||
QFileInfo file(filePath);
|
||||
QDir().mkpath(file.path()); // ensure directory exists
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
qDebug() << "Writing xdg mime: " << filePath;
|
||||
#endif
|
||||
|
||||
fileWrite(filePath, mime);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ QByteArray fileOpen(QString path);
|
||||
bool fileWrite(QString path, QString data);
|
||||
QString getAccountName();
|
||||
#ifdef Q_OS_LINUX
|
||||
QString xdgMime(QApplication &app);
|
||||
void registerXdgMime(QApplication &app);
|
||||
QString xdgMime();
|
||||
void registerXdgMime();
|
||||
#endif
|
||||
const static QRegExp reURI = QRegExp("^\\w+:\\/\\/([\\w+\\-?\\-_\\-=\\-&]+)");
|
||||
QString randomUserAgent();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3907
translations/monero-core_az.ts
Normal file
3907
translations/monero-core_az.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user