What changed, and why it matters
This commit is a large merge of pull request #4192 into the Monero GUI repository. The actual code change within that PR is a single, minor user-interface fix by contributor SNeedlewoods to prevent text overlap in certain languages. The rest of the diff is the initial population of the repository with the full Monero GUI source tree, build files, translations, images, and CI workflows. There is no security-relevant code change here.
No security action required. Treat as a routine UI fix and repository import.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The merge commit 7b286f48f995cb4ce2ccca7b24f45a0ef9e140c8 merges PR #4192. The only functional patch in the PR is 53b5fa1 by SNeedlewoods, titled ‘fix overlap in certain languages’. The surrounding diff shows 503 files being added because this appears to be an initial import or branch merge containing the entire monero-gui codebase (CMake, QML, C++, Dockerfiles, GitHub Actions, translations, assets). No cryptographic, wallet, network, or build-security logic is modified by the PR’s single commit.
Changed components
User interface layout/QML (minor overlap fix in PR #4192)Inspect captured patch +310381 / −0
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..72e8ffc
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1 @@
+*
diff --git a/.github/verify_p2pool.py b/.github/verify_p2pool.py
new file mode 100644
index 0000000..2c1de80
--- /dev/null
+++ b/.github/verify_p2pool.py
@@ -0,0 +1,107 @@
+import requests
+import subprocess
+from urllib.request import urlretrieve
+import difflib
+
+sech_key = "https://p2pool.io/SChernykh.asc"
+sech_key_backup = "https://raw.githubusercontent.com/monero-project/gitian.sigs/master/gitian-pubkeys/SChernykh.asc"
+sech_key_fp = "1FCA AB4D 3DC3 310D 16CB D508 C47F 82B5 4DA8 7ADF"
+
+p2pool_files = [{
+ "os": "WIN",
+ "filename": "windows-x64.zip",
+ },
+ {
+ "os": "LINUX",
+ "filename": "linux-x64.tar.gz"
+ },
+ {
+ "os": "MACOS_AARCH64",
+ "filename": "macos-aarch64.tar.gz",
+ },
+ {
+ "os": "MACOS",
+ "filename": "macos-x64.tar.gz",
+ }]
+
+def get_hash(fname):
+ fhash = subprocess.check_output(["sha256sum", fname]).decode("utf-8")
+ print(fhash.strip())
+ return fhash.split()[0]
+
+def main():
+ global p2pool_files, sech_key, sech_key_backup, sech_key_fp
+ p2pool_tag_api = "https://api.github.com/repos/SChernykh/p2pool/releases/latest"
+ data = requests.get(p2pool_tag_api).json()
+ tag = data["tag_name"]
+ head = f"p2pool-{tag}-"
+ url = f"https://github.com/SChernykh/p2pool/releases/download/{tag}/"
+
+ try:
+ urlretrieve(sech_key,"SChernykh.asc")
+ except:
+ urlretrieve(sech_key_backup,"SChernykh.asc")
+
+ urlretrieve(f"{url}sha256sums.txt.asc","sha256sums.txt.asc")
+
+ subprocess.check_call(["gpg", "--import", "SChernykh.asc"])
+ subprocess.check_call(["gpg", "--verify", "sha256sums.txt.asc"])
+ fingerprint = subprocess.check_output(["gpg","--fingerprint", "SChernykh"]).decode("utf-8").splitlines()[1].strip()
+
+ assert fingerprint == sech_key_fp
+
+ with open("sha256sums.txt.asc","r") as f:
+ lines = f.readlines()
+
+ signed_hashes = {}
+ for line in lines:
+ if "Name:" in line:
+ signed_fname = line.split()[1]
+ if "SHA256:" in line:
+ signed_hashes[signed_fname] = line.split()[1].lower()
+
+ expected = ""
+ for i in range(len(p2pool_files)):
+ fname = p2pool_files[i]["filename"]
+ str_os =p2pool_files[i]["os"]
+ dl = f"{url}{head}{fname}"
+ urlretrieve(dl,f"{head}{fname}")
+ fhash = get_hash(f"{head}{fname}")
+ assert signed_hashes[f"{head}{fname}"] == fhash
+ if i == 0:
+ expected += f" #ifdef Q_OS_{str_os}\n"
+ else:
+ expected += f" #elif defined(Q_OS_{str_os})\n"
+ expected += f" url = \"https://github.com/SChernykh/p2pool/releases/download/{tag}/{head}{fname}\";\n"
+ expected += f" fileName = m_p2poolPath + \"/{head}{fname}\";\n"
+ expected += f" validHash = \"{fhash}\";\n"
+ expected += " #endif\n"
+
+ print(f"Expected:\n{expected}")
+
+ with open("src/p2pool/P2PoolManager.cpp","r") as f:
+ p2pool_lines = f.readlines()
+
+ unexpected = ""
+ ignore = 1
+ for line in p2pool_lines:
+ if ignore == 0:
+ unexpected += line
+ if "QString validHash;" in line:
+ ignore = 0
+ if "#endif" in line and ignore == 0:
+ break
+
+ d = difflib.Differ()
+ diff = d.compare(str(unexpected).splitlines(True),str(expected).splitlines(True))
+
+ print("Unexpected:")
+ for i in diff:
+ if i.startswith("?"):
+ continue
+ print(i.replace("\n",""))
+
+ assert unexpected == expected
+
+if __name__ == "__main__":
+ main()
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..53cb0f3
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,198 @@
+name: ci/gh-actions/gui
+
+on: [push, pull_request]
+
+env:
+ FREE_DISKSPACE: |
+ sudo rm -rf /usr/local/.ghcup /usr/share/dotnet /usr/share/swift /usr/share/miniconda
+ QT_TAG: v5.15.17-lts-lgpl
+ QT_PREFIX: ${{ github.workspace }}/qt-install
+
+jobs:
+ build-macos:
+ 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 ninja openssl zmq libsodium unbound protobuf qt5 pkg-config
+ - name: build
+ run: DEV_MODE=ON make release
+ - name: test qml
+ run: build/release/bin/monero-wallet-gui.app/Contents/MacOS/monero-wallet-gui --test-qml
+
+ build-ubuntu:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v1
+ with:
+ submodules: recursive
+ - name: remove bundled boost
+ run: sudo rm -rf /usr/local/share/boost
+ - name: set apt conf
+ run: |
+ echo "Acquire::Retries \"3\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
+ echo "Acquire::http::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
+ echo "Acquire::ftp::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
+ - name: update apt
+ run: sudo apt update
+ - name: install monero dependencies
+ run: sudo apt -y install build-essential cmake ninja-build libboost-all-dev libunbound-dev graphviz doxygen 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 qtdeclarative5-dev qml-module-qtqml-models2 qml-module-qtquick-controls qml-module-qtquick-controls2 qml-module-qtquick-dialogs qml-module-qtquick-xmllistmodel qml-module-qt-labs-settings qml-module-qt-labs-platform qml-module-qt-labs-folderlistmodel qttools5-dev-tools qml-module-qtquick-templates2 libqt5svg5-dev libgcrypt20-dev xvfb
+ - name: build
+ run: DEV_MODE=ON make release
+ - name: test qml
+ run: xvfb-run -a build/release/bin/monero-wallet-gui --test-qml
+
+ build-windows:
+ runs-on: windows-latest
+ defaults:
+ run:
+ shell: msys2 {0}
+ steps:
+ - uses: actions/checkout@v1
+ with:
+ submodules: recursive
+ - uses: eine/setup-msys2@v2
+ with:
+ msystem: ucrt64
+ update: true
+ install: make
+ pacboy: toolchain:p pcre:p cmake:p ninja:p boost:p openssl:p zeromq:p libsodium:p hidapi:p protobuf-c:p libusb:p unbound:p git qt5:p libgcrypt:p angleproject:p
+ - name: add qmake.exe and windeployqt.exe
+ run: |
+ cp -f "$MSYSTEM_PREFIX/bin/qmake-qt5.exe" "$MSYSTEM_PREFIX/bin/qmake.exe"
+ cp -f "$MSYSTEM_PREFIX/bin/windeployqt-qt5.exe" "$MSYSTEM_PREFIX/bin/windeployqt.exe"
+ - name: build
+ run: DEV_MODE=ON make release-win64
+ - name: deploy
+ run: cmake --build . --target deploy
+ working-directory: build/release
+ - name: test qml
+ run: build/release/bin/monero-wallet-gui --test-qml
+
+ macos-bundle:
+ runs-on: macos-15
+ steps:
+ - uses: actions/checkout@v1
+ with:
+ submodules: recursive
+ - name: install dependencies
+ run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi ninja openssl zmq unbound protobuf pkg-config
+ - name: clone qt repo
+ run: git clone -b "${QT_TAG}" --recursive --depth 1 --shallow-submodules https://github.com/qt/qt5
+ - name: build qt from source
+ run: |
+ cd qt5
+ mkdir build && cd build
+ ../configure -prefix "${QT_PREFIX}" -opensource -confirm-license -release -nomake examples -nomake tests -no-rpath -skip qtwebengine -skip qt3d -skip qtandroidextras -skip qtcanvas3d -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdoc -skip qtgamepad -skip qtlocation -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 qtwebsockets -skip qtwebview -skip qtwinextras -skip qtx11extras -skip gamepad -skip serialbus -skip location -skip webengine
+ make -j"$(sysctl -n hw.ncpu)"
+ make install
+ cd ../qttools/src/linguist/lrelease
+ ../../../../build/qtbase/bin/qmake
+ make -j"$(sysctl -n hw.ncpu)"
+ make install
+ cd ../../../../qttools/src/macdeployqt/macdeployqt/
+ ../../../../build/qtbase/bin/qmake
+ make -j"$(sysctl -n hw.ncpu)"
+ make install
+ - name: build monero-gui
+ run: |
+ mkdir build && cd build
+ cmake -G Ninja -D CMAKE_BUILD_TYPE=Release -D ARCH=default -D CMAKE_PREFIX_PATH="${QT_PREFIX}" ..
+ cmake --build .
+ - name: deploy
+ run: cmake --build . --target deploy
+ working-directory: build
+ - name: test qml
+ run: build/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/bin
+ - uses: actions/upload-artifact@v4
+ with:
+ name: ${{ github.job }}
+ path: build/bin/monero-wallet-gui.tar
+
+ docker-linux-static:
+ runs-on: ubuntu-22.04
+ steps:
+ - uses: actions/checkout@v1
+ with:
+ submodules: recursive
+ - name: install dependencies
+ run: sudo apt -y install xvfb libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xkb1 libxcb-shape0 libxkbcommon-x11-0
+ - name: free up diskspace
+ run: ${{env.FREE_DISKSPACE}}
+ - name: prepare build environment
+ 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'
+ - 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@v4
+ 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-22.04
+ steps:
+ - uses: actions/checkout@v1
+ with:
+ submodules: recursive
+ - name: free up diskspace
+ run: ${{env.FREE_DISKSPACE}}
+ - name: prepare build environment
+ 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'
+ - 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@v4
+ 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-22.04
+ steps:
+ - uses: actions/checkout@v1
+ with:
+ submodules: recursive
+ - name: free up diskspace
+ run: ${{env.FREE_DISKSPACE}}
+ - name: prepare build environment
+ 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 monero:build-env-android
+ - uses: actions/upload-artifact@v4
+ 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-slim
+ 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@v4
+ with:
+ name: ${{ env.OUTPUT }}
+ path: /home/runner/work/monero-gui/monero-gui/${{ env.OUTPUT }}
diff --git a/.github/workflows/flatpak.yml b/.github/workflows/flatpak.yml
new file mode 100644
index 0000000..68ad21f
--- /dev/null
+++ b/.github/workflows/flatpak.yml
@@ -0,0 +1,174 @@
+name: Flatpak
+
+on:
+ release:
+ types: released
+
+jobs:
+ part1:
+ name: Part 1/3
+ if: github.repository == 'monero-project/monero-gui'
+ runs-on: ubuntu-latest
+ container:
+ image: bilelmoussaoui/flatpak-github-actions:kde-5.15-22.08
+ options: --privileged
+ strategy:
+ matrix:
+ arch: [x86_64, aarch64]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ submodules: recursive
+
+ - name: Install deps
+ run: dnf -y install docker
+
+ - name: Setup QEMU
+ uses: docker/setup-qemu-action@v2
+ with:
+ platforms: arm64
+
+ - name: Build flatpak
+ uses: flatpak/flatpak-github-actions/flatpak-builder@v6
+ env:
+ FLATPAK_BUILDER_N_JOBS: 3
+ with:
+ manifest-path: share/org.getmonero.Monero.yaml
+ arch: ${{ matrix.arch }}
+ cache: false
+ stop-at-module: boost
+
+ - name: Tar flatpak-builder
+ run: tar -cvf flatpak-builder.tar .flatpak-builder
+
+ - name: Save flatpak-builder
+ uses: actions/upload-artifact@v3
+ with:
+ name: flatpak-builder-${{ matrix.arch }}
+ path: flatpak-builder.tar
+
+ part2:
+ name: Part 2/3
+ if: github.repository == 'monero-project/monero-gui'
+ needs: part1
+ runs-on: ubuntu-latest
+ container:
+ image: bilelmoussaoui/flatpak-github-actions:kde-5.15-22.08
+ options: --privileged
+ strategy:
+ matrix:
+ arch: [x86_64, aarch64]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Install deps
+ run: dnf -y install docker
+
+ - name: Setup QEMU
+ uses: docker/setup-qemu-action@v2
+ with:
+ platforms: arm64
+
+ - name: Restore flatpak-builder
+ uses: actions/download-artifact@v4.1.7
+ with:
+ name: flatpak-builder-${{ matrix.arch }}
+
+ - name: Untar flatpak-builder
+ run: tar -xvf flatpak-builder.tar
+
+ - name: Build flatpak
+ uses: flatpak/flatpak-github-actions/flatpak-builder@v6
+ env:
+ FLATPAK_BUILDER_N_JOBS: 3
+ with:
+ manifest-path: share/org.getmonero.Monero.yaml
+ arch: ${{ matrix.arch }}
+ cache: false
+ stop-at-module: monero-gui
+
+ - name: Tar flatpak-builder
+ run: tar -cvf flatpak-builder.tar .flatpak-builder
+
+ - name: Save flatpak-builder
+ uses: actions/upload-artifact@v3
+ with:
+ name: flatpak-builder-${{ matrix.arch }}
+ path: flatpak-builder.tar
+
+ part3:
+ name: Part 3/3
+ if: github.repository == 'monero-project/monero-gui'
+ needs: [part1, part2]
+ runs-on: ubuntu-latest
+ container:
+ image: bilelmoussaoui/flatpak-github-actions:kde-5.15-22.08
+ options: --privileged
+ strategy:
+ matrix:
+ arch: [x86_64, aarch64]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ submodules: recursive
+
+ - name: Add version and date
+ run: |
+ sed -i 's/<version>/${{ github.event.release.tag_name }}/g' $GITHUB_WORKSPACE/share/org.getmonero.Monero.metainfo.xml
+ sed -i 's/<date>/'"$(date '+%F')"'/g' $GITHUB_WORKSPACE/share/org.getmonero.Monero.metainfo.xml
+
+ - name: Install deps
+ run: dnf -y install docker
+
+ - name: Setup QEMU
+ uses: docker/setup-qemu-action@v2
+ with:
+ platforms: arm64
+
+ - name: Restore flatpak-builder
+ uses: actions/download-artifact@v4.1.7
+ with:
+ name: flatpak-builder-${{ matrix.arch }}
+
+ - name: Untar flatpak-builder
+ run: tar -xvf flatpak-builder.tar
+
+ - name: Build flatpak
+ uses: flatpak/flatpak-github-actions/flatpak-builder@v6
+ env:
+ FLATPAK_BUILDER_N_JOBS: 3
+ with:
+ manifest-path: share/org.getmonero.Monero.yaml
+ arch: ${{ matrix.arch }}
+ cache: false
+
+ - name: Validate AppData
+ working-directory: flatpak_app/files/share/appdata
+ run: appstream-util validate org.getmonero.Monero.appdata.xml
+
+ - name: Delete flatpak-builder
+ uses: geekyeggo/delete-artifact@v2
+ with:
+ name: flatpak-builder-${{ matrix.arch }}
+
+ - name: Print hashes
+ working-directory: flatpak_app/files/bin
+ run: |
+ echo "Hashes of the ${{ matrix.arch }} binaries:" >> $GITHUB_STEP_SUMMARY
+ echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
+ for bin in monero-blockchain-ancestry monero-blockchain-depth monero-blockchain-export monero-blockchain-import monero-blockchain-mark-spent-outputs monero-blockchain-prune monero-blockchain-prune-known-spent-data monero-blockchain-stats monero-blockchain-usage monerod monero-gen-ssl-cert monero-gen-trusted-multisig monero-wallet-cli monero-wallet-gui monero-wallet-rpc p2pool; do sha256sum $bin; done >> $GITHUB_STEP_SUMMARY
+ echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
+ echo "An example command to check hashes:" >> $GITHUB_STEP_SUMMARY
+ echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
+ echo "$ flatpak run --command=sha256sum org.getmonero.Monero /app/bin/monero-wallet-gui" >> $GITHUB_STEP_SUMMARY
+ echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
+
+ - name: Publish to Flathub Beta
+ uses: flatpak/flatpak-github-actions/flat-manager@v6
+ with:
+ flat-manager-url: https://hub.flathub.org
+ repository: beta
+ token: ${{ secrets.FLATHUB_ }}
diff --git a/.github/workflows/verify_p2pool.yml b/.github/workflows/verify_p2pool.yml
new file mode 100644
index 0000000..2afa1fb
--- /dev/null
+++ b/.github/workflows/verify_p2pool.yml
@@ -0,0 +1,16 @@
+name: ci/gh-actions/verify
+on:
+ push:
+ paths:
+ - 'src/p2pool/P2PoolManager.cpp'
+ pull_request:
+ paths:
+ - 'src/p2pool/P2PoolManager.cpp'
+jobs:
+ p2pool-hashes:
+ runs-on: ubuntu-slim
+ steps:
+ - uses: actions/checkout@v1
+ - name: Verify Hashes
+ run: |
+ python3 .github/verify_p2pool.py
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e83dd75
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,36 @@
+*.user
+*.user.*
+translations/*.qm
+build
+version.js
+# IOS stuff below
+moc_*
+*.o
+*.mak
+*.build
+*.xcodeproj
+monero-wallet-gui_plugin_import.cpp
+monero-wallet-gui_qml_plugin_import.cpp
+*.qmlc
+*.jsc
+qml_qmlcache.qrc
+
+### Vim ###
+# Swap
+[._]*.s[a-v][a-z]
+[._]*.sw[a-p]
+[._]s[a-rt-v][a-z]
+[._]ss[a-gi-z]
+[._]sw[a-p]
+
+# Session
+Session.vim
+
+# Temporary
+.netrwhist
+*~
+*.autosave
+# Auto-generated tag files
+tags
+# Persistent undo
+[._]*.un~
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..ac846a0
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,7 @@
+[submodule "monero"]
+ path = monero
+ url = https://github.com/monero-project/monero
+ ignore = all
+[submodule "external/quirc"]
+ path = external/quirc
+ url = https://github.com/dlbeer/quirc/
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..876029d
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,443 @@
+cmake_minimum_required(VERSION 3.12)
+project(monero-gui)
+
+message(STATUS "Initiating compile using CMake ${CMAKE_VERSION}")
+
+set(VERSION_MAJOR "18")
+set(VERSION_MINOR "5")
+set(VERSION_REVISION "1")
+set(VERSION "0.${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}")
+
+option(STATIC "Link libraries statically, requires static Qt")
+
+option(USE_DEVICE_TREZOR "Trezor support compilation" ON)
+option(WITH_SCANNER "Enable webcam QR scanner" OFF)
+option(WITH_DESKTOP_ENTRY "Ask to install desktop entry on first startup" ON)
+option(WITH_UPDATER "Regularly check for new updates" ON)
+option(DEV_MODE "Checkout latest monero master on build" OFF)
+
+if(DEV_MODE)
+ # DEV_MODE checks out the monero submodule to master, which requires C++17.
+ set(CMAKE_CXX_STANDARD 17)
+else()
+ set(CMAKE_CXX_STANDARD 14)
+endif()
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake")
+include(CheckCCompilerFlag)
+include(CheckCXXCompilerFlag)
+include(CheckLinkerFlag)
+
+set(BUILD_GUI_DEPS ON)
+set(BUILD_64 ON CACHE BOOL "Build 64-bit binaries")
+
+if(NOT MANUAL_SUBMODULES)
+ find_package(Git)
+ if(GIT_FOUND)
+ if(NOT DEV_MODE)
+ function (check_submodule relative_path)
+ execute_process(COMMAND git rev-parse "HEAD" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${relative_path} OUTPUT_VARIABLE localHead)
+ execute_process(COMMAND git rev-parse "HEAD:${relative_path}" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE checkedHead)
+ string(COMPARE EQUAL "${localHead}" "${checkedHead}" upToDate)
+ if (upToDate)
+ message(STATUS "Submodule '${relative_path}' is up-to-date")
+ else()
+ message(FATAL_ERROR "Submodule '${relative_path}' is not using the checked head. Please update all submodules with\ngit submodule update --init --force --recursive\nor run cmake with -DMANUAL_SUBMODULES=1,\n or if you want to build from latest master run cmake with -DDEV_MODE=ON,\n or run make devmode")
+ endif()
+ endfunction ()
+ message(STATUS "Checking submodules")
+ check_submodule(monero)
+ else()
+ execute_process(COMMAND ${GIT_EXECUTABLE} fetch WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/monero RESULT_VARIABLE GIT_FETCH_RESULT)
+ execute_process(COMMAND ${GIT_EXECUTABLE} checkout -f origin/master WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/monero RESULT_VARIABLE GIT_CHECKOUT_MASTER_RESULT)
+ execute_process(COMMAND ${GIT_EXECUTABLE} submodule 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_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()
+ endif()
+endif()
+
+add_subdirectory(monero)
+add_subdirectory(external)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+get_directory_property(ARCH_WIDTH DIRECTORY "monero" DEFINITION ARCH_WIDTH)
+get_directory_property(Boost_VERSION_STRING DIRECTORY "monero" DEFINITION Boost_VERSION_STRING)
+
+if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
+ add_definitions(-DQT_NO_DEBUG)
+endif()
+
+if(STATIC)
+ message(STATUS "Initiating static build")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ add_definitions(-DMONERO_GUI_STATIC)
+endif()
+
+include(CMakePackageConfigHelpers)
+
+include_directories(${EASYLOGGING_INCLUDE})
+link_directories(${EASYLOGGING_LIBRARY_DIRS})
+
+include(VersionGui)
+
+message(STATUS "${CMAKE_MODULE_PATH}")
+
+if(WITH_SCANNER)
+ add_definitions(-DWITH_SCANNER)
+endif()
+
+if(WITH_DESKTOP_ENTRY)
+ add_definitions(-DWITH_DESKTOP_ENTRY)
+endif()
+
+if(WITH_UPDATER)
+ add_definitions(-DWITH_UPDATER)
+endif()
+
+# Sodium
+find_library(SODIUM_LIBRARY sodium)
+message(STATUS "libsodium: libraries at ${SODIUM_LIBRARY}")
+
+if(UNIX AND NOT APPLE AND NOT ANDROID)
+ set(CMAKE_SKIP_RPATH ON)
+ if(STATIC)
+ find_library(XCB_LIBRARY xcb)
+ message(STATUS "Found xcb library: ${XCB_LIBRARY}")
+ endif()
+endif()
+
+set(QT5_LIBRARIES
+ Qt5Core
+ Qt5Quick
+ Qt5Gui
+ Qt5Qml
+ Qt5Svg
+ Qt5Xml
+)
+
+if(WITH_SCANNER)
+ list(APPEND QT5_LIBRARIES Qt5Multimedia)
+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(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()
+endif()
+
+set(QT_MIN_VERSION "5.12")
+
+find_package(PkgConfig REQUIRED)
+
+# TODO: drop this once we switch to Qt 5.14+
+pkg_check_modules(Qt5QmlModels_PKG_CONFIG QUIET Qt5QmlModels)
+if(Qt5QmlModels_PKG_CONFIG_FOUND)
+ list(APPEND QT5_LIBRARIES Qt5QmlModels)
+endif()
+
+foreach(QT5_MODULE ${QT5_LIBRARIES})
+ find_package(${QT5_MODULE} ${QT_MIN_VERSION} REQUIRED)
+ include_directories(${${QT5_MODULE}_INCLUDE_DIRS})
+endforeach()
+
+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")
+ if(STATIC)
+ set(QT5_PKG_CONFIG "${QT5_PKG_CONFIG}_STATIC")
+ endif()
+
+ 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}" "${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})
+ include_directories(${${QT5_PKG_CONFIG}_INCLUDE_DIRS})
+ link_directories(${${QT5_PKG_CONFIG}_LIBRARY_DIRS})
+endif()
+
+list(APPEND QT5_LIBRARIES
+ ${Qt5Gui_PLUGINS}
+ ${Qt5Svg_PLUGINS}
+ ${Qt5Qml_PLUGINS}
+ ${Qt5Network_PLUGINS}
+)
+
+if(STATIC)
+ set(QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/Qt/labs/folderlistmodel)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/Qt/labs/settings)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/Qt/labs/platform)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtGraphicalEffects)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtGraphicalEffects/private)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtMultimedia)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQml)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQml/Models.2)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick.2)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Controls)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Controls.2)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Dialogs)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Dialogs/Private)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Layouts)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/PrivateWidgets)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Templates.2)
+ list(APPEND QT5_EXTRA_PATHS ${QT5_PKG_CONFIG_Qt5Qml_PREFIX}/qml/QtQuick/Window.2)
+
+ set(QT5_EXTRA_LIBRARIES_LIST
+ qtquicktemplates2plugin
+ Qt5QuickTemplates2
+ qtquickcontrols2plugin
+ Qt5QuickControls2
+ dialogplugin
+ dialogsprivateplugin
+ qmlfolderlistmodelplugin
+ qmlsettingsplugin
+ qtlabsplatformplugin
+ qquicklayoutsplugin
+ modelsplugin
+ )
+
+ if(WITH_SCANNER)
+ list(APPEND QT5_EXTRA_LIBRARIES_LIST
+ declarative_multimedia
+ Qt5MultimediaQuick
+ )
+ endif()
+
+ list(APPEND QT5_EXTRA_LIBRARIES_LIST
+ qtgraphicaleffectsplugin
+ qtgraphicaleffectsprivate
+ qtquick2plugin
+ qtquickcontrolsplugin
+ widgetsplugin
+ 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)
+ list(APPEND QT5_EXTRA_LIBRARIES ${${LIBRARY}_LIBRARY})
+ endforeach()
+
+ if(MINGW)
+ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ list(APPEND QT5_EXTRA_LIBRARIES D3D11 Dwrite D2d1)
+ endif()
+ endif()
+
+ set(QT5_LIBRARIES
+ ${QT5_EXTRA_LIBRARIES}
+ ${QT5_LIBRARIES}
+ )
+
+ set(QT5_INTEGRATION_LIBRARIES_LIST
+ Qt5EventDispatcherSupport
+ Qt5PacketProtocol
+ Qt5ThemeSupport
+ Qt5FontDatabaseSupport
+ )
+
+ if(UNIX AND NOT APPLE)
+ list(APPEND QT5_INTEGRATION_LIBRARIES_LIST
+ Qt5XcbQpa
+ Qt5ServiceSupport
+ Qt5GlxSupport
+ )
+ elseif(MINGW)
+ list(APPEND QT5_INTEGRATION_LIBRARIES_LIST qtfreetype)
+ endif()
+
+ foreach(LIBRARY ${QT5_INTEGRATION_LIBRARIES_LIST})
+ find_library(${LIBRARY}_LIBRARY ${LIBRARY} PATHS ${QT5_EXTRA_PATHS} REQUIRED)
+ list(APPEND QT5_LIBRARIES ${${LIBRARY}_LIBRARY})
+ endforeach()
+
+ if(UNIX AND NOT APPLE)
+ pkg_check_modules(X11XCB_XCBGLX 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()
+
+if(MINGW)
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wa,-mbig-obj")
+ set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi;crypt32;bcrypt)
+ if(DEPENDS)
+ set(ICU_LIBRARIES icuio icui18n icuuc icudata icutu iconv)
+ else()
+ set(ICU_LIBRARIES icuio icuin icuuc icudt icutu iconv)
+ endif()
+elseif(APPLE)
+ set(EXTRA_LIBRARIES "-framework AppKit")
+elseif(OPENBSD OR ANDROID)
+ set(EXTRA_LIBRARIES "")
+elseif(FREEBSD)
+ set(EXTRA_LIBRARIES execinfo)
+elseif(DRAGONFLY)
+ find_library(COMPAT compat)
+ set(EXTRA_LIBRARIES execinfo ${COMPAT})
+elseif(CMAKE_SYSTEM_NAME MATCHES "(SunOS|Solaris)")
+ set(EXTRA_LIBRARIES socket nsl resolv)
+elseif(NOT MSVC AND NOT DEPENDS)
+ find_library(RT rt)
+ set(EXTRA_LIBRARIES ${RT})
+endif()
+
+list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS})
+
+if(APPLE)
+ cmake_policy(SET CMP0042 NEW)
+endif()
+
+if (APPLE AND NOT IOS)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default")
+endif()
+
+if(APPLE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default -DGTEST_HAS_TR1_TUPLE=0")
+endif()
+
+# warnings
+add_c_flag_if_supported(-Wformat C_SECURITY_FLAGS)
+add_cxx_flag_if_supported(-Wformat CXX_SECURITY_FLAGS)
+add_c_flag_if_supported(-Wformat-security C_SECURITY_FLAGS)
+add_cxx_flag_if_supported(-Wformat-security CXX_SECURITY_FLAGS)
+
+# -fstack-protector
+if (NOT OPENBSD AND NOT (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1)))
+ add_c_flag_if_supported(-fstack-protector C_SECURITY_FLAGS)
+ add_cxx_flag_if_supported(-fstack-protector CXX_SECURITY_FLAGS)
+ add_c_flag_if_supported(-fstack-protector-strong C_SECURITY_FLAGS)
+ add_cxx_flag_if_supported(-fstack-protector-strong CXX_SECURITY_FLAGS)
+endif()
+
+# New in GCC 8.2
+if (NOT OPENBSD AND NOT (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1)))
+ add_c_flag_if_supported(-fcf-protection=full C_SECURITY_FLAGS)
+ add_cxx_flag_if_supported(-fcf-protection=full CXX_SECURITY_FLAGS)
+endif()
+if (NOT WIN32 AND NOT OPENBSD AND NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+ add_c_flag_if_supported(-fstack-clash-protection C_SECURITY_FLAGS)
+ add_cxx_flag_if_supported(-fstack-clash-protection CXX_SECURITY_FLAGS)
+endif()
+
+# Removed in GCC 9.1 (or before ?), but still accepted, so spams the output
+if (NOT (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1))
+ add_c_flag_if_supported(-mmitigate-rop C_SECURITY_FLAGS)
+ add_cxx_flag_if_supported(-mmitigate-rop CXX_SECURITY_FLAGS)
+endif()
+
+# linker
+if (APPLE)
+ add_linker_flag_if_supported(-Wl,-bind_at_load LD_SECURITY_FLAGS)
+ add_linker_flag_if_supported(-Wl,-dead_strip LD_SECURITY_FLAGS)
+ add_linker_flag_if_supported(-Wl,-dead_strip_dylibs LD_SECURITY_FLAGS)
+endif()
+if (NOT APPLE AND NOT (WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "GNU"))
+ # Windows binaries die on startup with PIE when compiled with GCC
+ add_linker_flag_if_supported(-pie LD_SECURITY_FLAGS)
+endif()
+add_linker_flag_if_supported(-Wl,-z,relro LD_SECURITY_FLAGS)
+add_linker_flag_if_supported(-Wl,-z,now LD_SECURITY_FLAGS)
+add_linker_flag_if_supported(-Wl,-z,noexecstack noexecstack_SUPPORTED)
+if (noexecstack_SUPPORTED)
+ set(LD_SECURITY_FLAGS "${LD_SECURITY_FLAGS} -Wl,-z,noexecstack")
+endif()
+add_linker_flag_if_supported(-Wl,-z,noexecheap noexecheap_SUPPORTED)
+if (noexecheap_SUPPORTED)
+ set(LD_SECURITY_FLAGS "${LD_SECURITY_FLAGS} -Wl,-z,noexecheap")
+endif()
+
+# some windows linker bits
+if (WIN32)
+ add_linker_flag_if_supported(-Wl,--dynamicbase LD_SECURITY_FLAGS)
+ add_linker_flag_if_supported(-Wl,--nxcompat LD_SECURITY_FLAGS)
+ add_linker_flag_if_supported(-Wl,--high-entropy-va LD_SECURITY_FLAGS)
+endif()
+
+if(STATIC)
+ add_linker_flag_if_supported(-static-libgcc STATIC_FLAGS)
+ add_linker_flag_if_supported(-static-libstdc++ STATIC_FLAGS)
+ if(MINGW)
+ add_linker_flag_if_supported(-static STATIC_FLAGS)
+ endif()
+endif()
+
+# With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that
+# is fixed in the code (Issue #847), force compiler to be conservative.
+add_c_flag_if_supported(-fno-strict-aliasing C_SECURITY_FLAGS)
+add_cxx_flag_if_supported(-fno-strict-aliasing CXX_SECURITY_FLAGS)
+
+add_c_flag_if_supported(-fPIC C_SECURITY_FLAGS)
+add_cxx_flag_if_supported(-fPIC CXX_SECURITY_FLAGS)
+
+message(STATUS "Using C security hardening flags: ${C_SECURITY_FLAGS}")
+message(STATUS "Using C++ security hardening flags: ${CXX_SECURITY_FLAGS}")
+message(STATUS "Using linker security hardening flags: ${LD_SECURITY_FLAGS}")
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 ${C_SECURITY_FLAGS}")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_SECURITY_FLAGS}")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LD_SECURITY_FLAGS} ${STATIC_FLAGS}")
+
+add_subdirectory(translations)
+add_subdirectory(src)
diff --git a/DEPLOY.md b/DEPLOY.md
new file mode 100644
index 0000000..660cd2c
--- /dev/null
+++ b/DEPLOY.md
@@ -0,0 +1,75 @@
+# macOS:
+
+Use macOS 10.12 - 10.13 for better backwards compability.
+
+1. `HOMEBREW_OPTFLAGS="-march=core2" HOMEBREW_OPTIMIZATION_LEVEL="O0" brew install boost zmq libpgm libsodium expat protobuf@21 libgcrypt hidapi libusb cmake pkg-config && brew link protobuf@21`
+
+2. 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. Compile `monero-wallet-gui.app`
+
+```bash
+mkdir build && cd build
+cmake -D CMAKE_BUILD_TYPE=Release -D ARCH=default -D CMAKE_PREFIX_PATH=/path/to/Qt5.12.8/5.12.8/clang_64 ..
+make
+make deploy
+```
+
+5. Replace the `monerod` binary inside `monero-wallet-gui.app/Contents/MacOS/` with one built using deterministic builds / gitian.
+
+## Codesigning and notarizing
+
+1. Save the following text as `entitlements.plist`
+
+```xml
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.cs.disable-executable-page-protection</key>
+ <true/>
+</dict>
+</plist>
+```
+
+2. `codesign --deep --force --verify --verbose --options runtime --timestamp --entitlements entitlements.plist --sign 'XXXXXXXXXX' monero-wallet-gui.app`
+
+You can check if this step worked by using `codesign -dvvv monero-wallet-gui.app`
+
+3. `hdiutil create -fs HFS+ -srcfolder monero-gui-v0.X.Y.Z -volname monero-wallet-gui monero-gui-mac-x64-v0.X.Y.Z.dmg`
+
+4. `xcrun notarytool submit monero-gui-mac-x64-v0.X.Y.Z.dmg --apple-id email@address.org --team-id XXXXXXXXXX`
+
+5. `xcrun notarytool info aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeee --apple-id email@address.org --team-id XXXXXXXXXX`
+
+6. `xcrun stapler staple -v monero-gui-mac-x64-v0.X.Y.Z.dmg`
+
+## Compile Qt for Apple Silicon
+
+Qt does not offer pre-built binaries for Apple Silicon, they have to be manually compiled.
+
+```bash
+git clone https://github.com/qt/qt5.git
+cd qt5
+git checkout v5.15.9-lts-lgpl
+./init-repository
+mkdir build
+cd build
+../configure -prefix /path/to/qt-build-dir/ -opensource -confirm-license -release -nomake examples -nomake tests -no-rpath -skip qtwebengine -skip qt3d -skip qtandroidextras -skip qtcanvas3d -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdoc -skip qtgamepad -skip qtlocation -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 qtwebsockets -skip qtwebview -skip qtwinextras -skip qtx11extras -skip gamepad -skip serialbus -skip location -skip webengine
+make
+make install
+cd ../qttools/src/linguist/lrelease
+../../../../build/qtbase/bin/qmake
+make
+make install
+cd ../../../../qttools/src/macdeployqt/macdeployqt/
+../../../../build/qtbase/bin/qmake
+make
+make install
+```
+
+For compilation with Xcode 15 the following patch has to be applied: https://raw.githubusercontent.com/Homebrew/formula-patches/086e8cf/qt5/qt5-qmake-xcode15.patch
+
+The `CMAKE_PREFIX_PATH` has to be set to `/path/to/qt-build-dir/` during monero-gui compilation.
diff --git a/Dockerfile.android b/Dockerfile.android
new file mode 100644
index 0000000..4dde3dd
--- /dev/null
+++ b/Dockerfile.android
@@ -0,0 +1,239 @@
+FROM ubuntu:20.04
+
+ARG THREADS=1
+ARG ANDROID_NDK_REVISION=23c
+ARG ANDROID_NDK_HASH=e5053c126a47e84726d9f7173a04686a71f9a67a
+ARG ANDROID_SDK_REVISION=7302050_latest
+ARG ANDROID_SDK_HASH=7a00faadc0864f78edd8f4908a629a46d622375cbe2e5814e82934aebecdb622
+ARG QT_VERSION=v5.15.19-lts-lgpl
+
+WORKDIR /opt/android
+ENV WORKDIR=/opt/android
+
+ENV ANDROID_NATIVE_API_LEVEL=31
+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}/cmdline-tools
+ENV JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
+ENV PATH=${JAVA_HOME}/bin:${PATH}
+ENV PREFIX=${WORKDIR}/prefix
+ENV TOOLCHAIN_DIR=${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64
+ENV DEBIAN_FRONTEND=noninteractive
+
+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 ninja-build openjdk-11-jdk-headless openjdk-11-jre-headless pkg-config python3 \
+ unzip wget
+
+RUN PACKAGE_NAME=commandlinetools-linux-${ANDROID_SDK_REVISION}.zip \
+ && wget -q https://dl.google.com/android/repository/${PACKAGE_NAME} \
+ && echo "${ANDROID_SDK_HASH} ${PACKAGE_NAME}" | sha256sum -c \
+ && unzip -q ${PACKAGE_NAME} \
+ && rm -f ${PACKAGE_NAME}
+
+RUN PACKAGE_NAME=android-ndk-r${ANDROID_NDK_REVISION}-linux.zip \
+ && wget -q https://dl.google.com/android/repository/${PACKAGE_NAME} \
+ && echo "${ANDROID_NDK_HASH} ${PACKAGE_NAME}" | sha1sum -c \
+ && unzip -q ${PACKAGE_NAME} \
+ && rm -f ${PACKAGE_NAME}
+
+RUN echo y | ${ANDROID_SDK_ROOT}/bin/sdkmanager --sdk_root=${ANDROID_SDK_ROOT} "build-tools;28.0.3" "platforms;${ANDROID_API}" "tools" > /dev/null
+
+ENV HOST_PATH=${PATH}
+ENV PATH=${TOOLCHAIN_DIR}/aarch64-linux-android/bin:${TOOLCHAIN_DIR}/bin:${PATH}
+
+ARG ZLIB_VERSION=1.3.1
+ARG ZLIB_HASH=9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23
+RUN wget -q https://github.com/madler/zlib/releases/download/v${ZLIB_VERSION}/zlib-${ZLIB_VERSION}.tar.gz \
+ && echo "${ZLIB_HASH} zlib-${ZLIB_VERSION}.tar.gz" | sha256sum -c \
+ && 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 https://code.qt.io/qt/qt5.git -b ${QT_VERSION} --depth 1 \
+ && cd qt5 \
+ && git reset --hard dc2ac680fa9d0ef7b0d9520859593d13951bedea \
+ && 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 \
+ && 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 https://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_85_0
+ARG BOOST_VERSION_DOT=1.85.0
+ARG BOOST_HASH=7009fe1faa1697476bdc7027703a2badb84e849b7b0baad5086b087b971f8617
+RUN wget -q https://archives.boost.io/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} \
+ && printf "using clang : arm : ${ANDROID_CLANGPP} :\n<cxxflags>\"-fPIC\"\n<cflags>\"-fPIC\" ;" > user.jam \
+ && 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-arm threading=multi \
+ threadapi=pthread target-os=android -sICONV_PATH=${PREFIX} --user-config=user.jam architecture=arm address-model=64 \
+ install -j${THREADS} \
+ && rm -rf $(pwd)
+
+ARG OPENSSL_VERSION=1.1.1w
+ARG OPENSSL_HASH=cf3098950cb4d853ad95c0841f1f9c6d3dc102dccfcacd521d93925208b76ac8
+RUN wget -q https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz \
+ && echo "${OPENSSL_HASH} openssl-${OPENSSL_VERSION}.tar.gz" | sha256sum -c \
+ && 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-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 EXPAT_VERSION=2.6.4
+ARG EXPAT_HASH=8dc480b796163d4436e6f1352e71800a774f73dbae213f1860b60607d2a83ada
+RUN wget https://github.com/libexpat/libexpat/releases/download/R_2_6_4/expat-${EXPAT_VERSION}.tar.bz2 && \
+ echo "${EXPAT_HASH} expat-${EXPAT_VERSION}.tar.bz2" | sha256sum -c && \
+ tar -xf expat-${EXPAT_VERSION}.tar.bz2 && \
+ rm expat-${EXPAT_VERSION}.tar.bz2 && \
+ cd expat-${EXPAT_VERSION} && \
+ CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --enable-static --disable-shared --prefix=${PREFIX} --host=aarch64-linux-android && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+ARG UNBOUND_VERSION=1.22.0
+ARG UNBOUND_HASH=c5dd1bdef5d5685b2cedb749158dd152c52d44f65529a34ac15cd88d4b1b3d43
+RUN wget https://www.nlnetlabs.nl/downloads/unbound/unbound-${UNBOUND_VERSION}.tar.gz && \
+ echo "${UNBOUND_HASH} unbound-${UNBOUND_VERSION}.tar.gz" | sha256sum -c && \
+ tar -xzf unbound-${UNBOUND_VERSION}.tar.gz && \
+ rm unbound-${UNBOUND_VERSION}.tar.gz && \
+ cd unbound-${UNBOUND_VERSION} && \
+ CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --disable-shared --enable-static --without-pyunbound --with-libexpat=${PREFIX} --with-ssl=${PREFIX} --with-libevent=no --without-pythonmodule --disable-flto --with-pthreads --with-libunbound-only --host=aarch64-linux-android --with-pic --prefix=${PREFIX} && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+ARG ZMQ_VERSION=v4.3.5
+ARG ZMQ_HASH=622fc6dde99ee172ebaa9c8628d85a7a1995a21d
+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.20-RELEASE
+ARG SODIUM_HASH=9511c982fb1d046470a8b42aa36556cdb7da15de
+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.41 --depth 1 https://github.com/gpg/libgpg-error \
+ && cd libgpg-error \
+ && git reset --hard 98032624ae89a67ee6fe3b1db5d95032e681d163 \
+ && ./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.10.1 --depth 1 https://github.com/gpg/libgcrypt \
+ && cd libgcrypt \
+ && git reset --hard ae0e567820c37f9640440b3cff77d7c185aa6742 \
+ && ./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 git clone -b v3.31.4 --depth 1 https://github.com/Kitware/CMake \
+ && cd CMake \
+ && git reset --hard 569b821a138a4d3f7f4cc42c0cf5ae5e68d56f96 \
+ && PATH=${HOST_PATH} ./bootstrap \
+ && PATH=${HOST_PATH} make -j${THREADS} \
+ && PATH=${HOST_PATH} make -j${THREADS} install \
+ && rm -rf $(pwd)
+
+# Workaround
+ENV NEW_SDK_ROOT=${WORKDIR}/sdk
+RUN mkdir ${NEW_SDK_ROOT} \
+ && cp -r ${ANDROID_SDK_ROOT}/licenses ${NEW_SDK_ROOT} \
+ && cp -r ${ANDROID_SDK_ROOT}/platforms ${NEW_SDK_ROOT} \
+ && cp -r ${ANDROID_SDK_ROOT}/build-tools ${NEW_SDK_ROOT}
+
+CMD set -ex \
+ && cd /monero-gui \
+ && mkdir -p build/Android/release \
+ && cd build/Android/release \
+ && cmake -G Ninja \
+ -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" \
+ -DANDROID_SDK="${NEW_SDK_ROOT}" \
+ -DWITH_SCANNER=ON \
+ -DWITH_DESKTOP_ENTRY=OFF \
+ ../../.. \
+ && PATH=${HOST_PATH} cmake --build . --target generate_translations_header \
+ && sed -i -e "/^build .*monero-wallet-gui.*:.*LINKER/,/^$/ { s#monero/external/randomx/librandomx.a##; s#-lm#-lm monero/external/randomx/librandomx.a#; }" build.ninja \
+ && cmake --build . --target monero-wallet-gui \
+ && cmake --build . --target apk
diff --git a/Dockerfile.linux b/Dockerfile.linux
new file mode 100644
index 0000000..0f82d4b
--- /dev/null
+++ b/Dockerfile.linux
@@ -0,0 +1,277 @@
+FROM ubuntu:18.04
+
+ARG THREADS=1
+ARG QT_VERSION=v5.15.19-lts-lgpl
+
+ENV CFLAGS="-fPIC"
+ENV CPPFLAGS="-fPIC"
+ENV CXXFLAGS="-fPIC"
+ENV SOURCE_DATE_EPOCH=1397818193
+
+RUN apt update && \
+ apt install -y automake autopoint bison gettext git gperf libgl1-mesa-dev libglib2.0-dev ninja-build \
+ libpng-dev libpthread-stubs0-dev libsodium-dev libtool-bin libudev-dev libusb-1.0-0-dev mesa-common-dev \
+ pkg-config python wget xutils-dev
+
+RUN git clone -b xorgproto-2020.1 --depth 1 https://gitlab.freedesktop.org/xorg/proto/xorgproto && \
+ cd xorgproto && \
+ git reset --hard c62e8203402cafafa5ba0357b6d1c019156c9f36 && \
+ ./autogen.sh && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN git clone -b 1.12 --depth 1 https://gitlab.freedesktop.org/xorg/proto/xcbproto && \
+ cd xcbproto && \
+ git reset --hard 6398e42131eedddde0d98759067dde933191f049 && \
+ ./autogen.sh && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN git clone -b libXau-1.0.9 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxau && \
+ cd libxau && \
+ git reset --hard d9443b2c57b512cfb250b35707378654d86c7dea && \
+ ./autogen.sh --enable-shared --disable-static && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN git clone -b 1.12 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb && \
+ cd libxcb && \
+ git reset --hard d34785a34f28fa6a00f8ce00d87e3132ff0f6467 && \
+ ./autogen.sh --enable-shared --disable-static && \
+ 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 c617eee22ae5c285e79e81ec39ce96862fd3262f && \
+ ./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 c617eee22ae5c285e79e81ec39ce96862fd3262f && \
+ ./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 c617eee22ae5c285e79e81ec39ce96862fd3262f && \
+ ./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 c617eee22ae5c285e79e81ec39ce96862fd3262f && \
+ ./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 c617eee22ae5c285e79e81ec39ce96862fd3262f && \
+ ./autogen.sh --enable-shared --disable-static && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN git clone -b xkbcommon-0.5.0 --depth 1 https://github.com/xkbcommon/libxkbcommon && \
+ cd libxkbcommon && \
+ git reset --hard c43c3c866eb9d52cd8f61e75cbef1c30d07f3a28 && \
+ ./autogen.sh --prefix=/usr --enable-shared --disable-static --enable-x11 --disable-docs && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN git clone -b v1.3 --depth 1 https://github.com/madler/zlib && \
+ cd zlib && \
+ git reset --hard 09155eaa2f9270dc4ed1fa13e2b4b2613e6e4851 && \
+ ./configure --static && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN git clone -b VER-2-10-2 --depth 1 https://gitlab.freedesktop.org/freetype/freetype.git && \
+ cd freetype && \
+ git reset --hard 132f19b779828b194b3fede187cee719785db4d8 && \
+ ./autogen.sh && \
+ ./configure --disable-shared --enable-static --with-zlib=no && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN wget https://github.com/libexpat/libexpat/releases/download/R_2_4_8/expat-2.4.8.tar.bz2 && \
+ echo "a247a7f6bbb21cf2ca81ea4cbb916bfb9717ca523631675f99b3d4a5678dcd16 expat-2.4.8.tar.bz2" | sha256sum -c && \
+ tar -xf expat-2.4.8.tar.bz2 && \
+ rm expat-2.4.8.tar.bz2 && \
+ cd expat-2.4.8 && \
+ ./configure --enable-static --disable-shared --prefix=/usr && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN git clone -b 2.13.92 --depth 1 https://gitlab.freedesktop.org/fontconfig/fontconfig && \
+ cd fontconfig && \
+ git reset --hard b1df1101a643ae16cdfa1d83b939de2497b1bf27 && \
+ ./autogen.sh --disable-shared --enable-static --sysconfdir=/etc --localstatedir=/var && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN git clone -b release-64-2 --depth 1 https://github.com/unicode-org/icu && \
+ cd icu/icu4c/source && \
+ git reset --hard e2d85306162d3a0691b070b4f0a73e4012433444 && \
+ ./configure --disable-shared --enable-static --disable-tests --disable-samples && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN wget https://archives.boost.io/release/1.80.0/source/boost_1_80_0.tar.gz && \
+ echo "4b2136f98bdd1f5857f1c3dea9ac2018effe65286cf251534b6ae20cc45e1847 boost_1_80_0.tar.gz" | sha256sum -c && \
+ tar -xzf boost_1_80_0.tar.gz && \
+ rm boost_1_80_0.tar.gz && \
+ cd boost_1_80_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="${CFLAGS}" cxxflags="${CXXFLAGS}" install -a --prefix=/usr && \
+ rm -rf $(pwd)
+
+RUN wget https://www.openssl.org/source/openssl-1.1.1u.tar.gz && \
+ echo "e2f8d84b523eecd06c7be7626830370300fbcc15386bf5142d72758f6963ebc6 openssl-1.1.1u.tar.gz" | sha256sum -c && \
+ tar -xzf openssl-1.1.1u.tar.gz && \
+ rm openssl-1.1.1u.tar.gz && \
+ cd openssl-1.1.1u && \
+ ./config no-shared no-zlib-dynamic --prefix=/usr --openssldir=/usr && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN wget https://www.nlnetlabs.nl/downloads/unbound/unbound-1.16.2.tar.gz && \
+ echo "2e32f283820c24c51ca1dd8afecfdb747c7385a137abe865c99db4b257403581 unbound-1.16.2.tar.gz" | sha256sum -c && \
+ tar -xzf unbound-1.16.2.tar.gz && \
+ rm unbound-1.16.2.tar.gz && \
+ cd unbound-1.16.2 && \
+ ./configure --disable-shared --enable-static --without-pyunbound --with-libexpat=/usr --with-ssl=/usr --with-libevent=no --without-pythonmodule --disable-flto --with-pthreads --with-libunbound-only --with-pic && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN rm /usr/lib/x86_64-linux-gnu/libX11.a && \
+ rm /usr/lib/x86_64-linux-gnu/libXext.a && \
+ rm /usr/lib/x86_64-linux-gnu/libX11-xcb.a && \
+ git clone https://code.qt.io/qt/qt5.git -b ${QT_VERSION} --depth 1 && \
+ cd qt5 && \
+ git reset --hard dc2ac680fa9d0ef7b0d9520859593d13951bedea && \
+ git submodule update --init --depth 1 qtbase qtdeclarative qtgraphicaleffects qtimageformats qtmultimedia qtquickcontrols qtquickcontrols2 qtsvg qttools qttranslations qtx11extras && \
+ 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 -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 \
+ -skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qttools \
+ -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview \
+ -skip qtwinextras -skip qtx11extras -skip gamepad -skip serialbus -skip location -skip webengine \
+ -nomake examples -nomake tests -nomake tools && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ cd qttools/src/linguist/lrelease && \
+ ../../../../qtbase/bin/qmake && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ cd ../../../.. && \
+ rm -rf $(pwd)
+
+RUN git clone -b v1.0.26 --depth 1 https://github.com/libusb/libusb && \
+ cd libusb && \
+ git reset --hard 4239bc3a50014b8e6a5a2a59df1fff3b7469543b && \
+ ./autogen.sh --disable-shared --enable-static && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN git clone -b hidapi-0.15.0 --depth 1 https://github.com/libusb/hidapi && \
+ cd hidapi && \
+ git reset --hard d6b2a974608dec3b76fb1e36c189f22b9cf3650c && \
+ ./bootstrap && \
+ ./configure --disable-shared --enable-static && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN git clone -b v4.3.4 --depth 1 https://github.com/zeromq/libzmq && \
+ cd libzmq && \
+ git reset --hard 4097855ddaaa65ed7b5e8cb86d143842a594eebd && \
+ ./autogen.sh && \
+ ./configure --disable-shared --enable-static --disable-libunwind --with-libsodium && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN git clone -b libgpg-error-1.45 --depth 1 https://github.com/gpg/libgpg-error && \
+ cd libgpg-error && \
+ git reset --hard dbac537e5e865fb6f3aa8596d213aa8c47a9dea1 && \
+ ./autogen.sh && \
+ ./configure --disable-shared --enable-static --disable-doc --disable-tests && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN git clone -b libgcrypt-1.10.1 --depth 1 https://github.com/gpg/libgcrypt && \
+ cd libgcrypt && \
+ git reset --hard ae0e567820c37f9640440b3cff77d7c185aa6742 && \
+ ./autogen.sh && \
+ ./configure --disable-shared --enable-static --disable-doc && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN git clone -b v21.5 --depth 1 https://github.com/protocolbuffers/protobuf && \
+ cd protobuf && \
+ git reset --hard ab840345966d0fa8e7100d771c92a73bfbadd25c && \
+ ./autogen.sh && \
+ ./configure --enable-static --disable-shared && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
+
+RUN git clone -b v3.24.0 --depth 1 https://github.com/Kitware/CMake && \
+ cd CMake && \
+ git reset --hard 4be24f031a4829db75b85062cc67125035d8831e && \
+ ./bootstrap && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ rm -rf $(pwd)
diff --git a/Dockerfile.windows b/Dockerfile.windows
new file mode 100644
index 0000000..3fde387
--- /dev/null
+++ b/Dockerfile.windows
@@ -0,0 +1,73 @@
+FROM ubuntu:20.04
+
+ARG THREADS=1
+ARG QT_VERSION=v5.15.19-lts-lgpl
+ENV SOURCE_DATE_EPOCH=1397818193
+
+RUN apt update && \
+ DEBIAN_FRONTEND=noninteractive apt install -y build-essential cmake g++-mingw-w64 gettext git libtool ninja-build pkg-config \
+ python && \
+ rm -rf /var/lib/apt/lists/*
+
+RUN update-alternatives --set x86_64-w64-mingw32-g++ $(which x86_64-w64-mingw32-g++-posix) && \
+ update-alternatives --set x86_64-w64-mingw32-gcc $(which x86_64-w64-mingw32-gcc-posix)
+
+RUN git clone -b v0.18.5.1 --depth 1 https://github.com/monero-project/monero && \
+ cd monero && \
+ git reset --hard 4f92268d7c16741cfb41e5bbe2aa46cc260a9ea5 && \
+ cp -a contrib/depends / && \
+ cd .. && \
+ rm -rf monero
+
+RUN make -j$THREADS -C /depends HOST=x86_64-w64-mingw32 NO_QT=1
+
+RUN git clone https://code.qt.io/qt/qt5.git -b ${QT_VERSION} --depth 1 && \
+ cd qt5 && \
+ git reset --hard dc2ac680fa9d0ef7b0d9520859593d13951bedea && \
+ git submodule update --init --depth 1 qtbase qtdeclarative qtgraphicaleffects qtimageformats qtmultimedia qtquickcontrols qtquickcontrols2 qtsvg qttools qttranslations && \
+ ./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 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 -j$THREADS && \
+ make -j$THREADS install && \
+ cd qttools/src/linguist/lrelease && \
+ ../../../../qtbase/bin/qmake && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ cd ../../../.. && \
+ rm -rf $(pwd)
+
+RUN git clone -b libgpg-error-1.38 --depth 1 https://github.com/gpg/libgpg-error && \
+ cd libgpg-error && \
+ git reset --hard 71d278824c5fe61865f7927a2ed1aa3115f9e439 && \
+ ./autogen.sh && \
+ ./configure --disable-shared --enable-static --disable-doc --disable-tests \
+ --host=x86_64-w64-mingw32 --prefix=/depends/x86_64-w64-mingw32 && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ cd .. && \
+ rm -rf libgpg-error
+
+RUN git clone -b libgcrypt-1.8.5 --depth 1 https://github.com/gpg/libgcrypt && \
+ cd libgcrypt && \
+ git reset --hard 56606331bc2a80536db9fc11ad53695126007298 && \
+ ./autogen.sh && \
+ ./configure --disable-shared --enable-static --disable-doc \
+ --host=x86_64-w64-mingw32 --prefix=/depends/x86_64-w64-mingw32 \
+ --with-gpg-error-prefix=/depends/x86_64-w64-mingw32 && \
+ make -j$THREADS && \
+ make -j$THREADS install && \
+ cd .. && \
+ rm -rf libgcrypt
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f5fccf9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,32 @@
+Copyright (c) 2014-2024, 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.
+
+Parts of the project are originally copyright (c) 2012-2013 The Cryptonote
+developers
+
diff --git a/LeftPanel.qml b/LeftPanel.qml
new file mode 100644
index 0000000..4365f99
--- /dev/null
+++ b/LeftPanel.qml
@@ -0,0 +1,556 @@
+// Copyright (c) 2014-2024, 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 QtGraphicalEffects 1.0
+import moneroComponents.Wallet 1.0
+import moneroComponents.NetworkType 1.0
+import moneroComponents.Clipboard 1.0
+import FontAwesome 1.0
+
+import "components" as MoneroComponents
+import "components/effects/" as MoneroEffects
+
+Rectangle {
+ id: panel
+
+ property int currentAccountIndex
+ property alias currentAccountLabel: accountLabel.text
+ property string balanceString: "?.??"
+ property string balanceUnlockedString: "?.??"
+ property string balanceFiatString: "?.??"
+ property string minutesToUnlock: ""
+ property bool isSyncing: false
+ property alias networkStatus : networkStatus
+ property alias progressBar : progressBar
+ property alias daemonProgressBar : daemonProgressBar
+
+ property int titleBarHeight: 50
+ property string copyValue: ""
+ Clipboard { id: clipboard }
+
+ signal historyClicked()
+ signal transferClicked()
+ signal receiveClicked()
+ signal advancedClicked()
+ signal settingsClicked()
+ signal addressBookClicked()
+ signal accountClicked()
+
+ function selectItem(pos) {
+ menuColumn.previousButton.checked = false
+ if(pos === "History") menuColumn.previousButton = historyButton
+ else if(pos === "Transfer") menuColumn.previousButton = transferButton
+ else if(pos === "Receive") menuColumn.previousButton = receiveButton
+ else if(pos === "AddressBook") menuColumn.previousButton = addressBookButton
+ else if(pos === "Settings") menuColumn.previousButton = settingsButton
+ else if(pos === "Advanced") menuColumn.previousButton = advancedButton
+ else if(pos === "Account") menuColumn.previousButton = accountButton
+ menuColumn.previousButton.checked = true
+ }
+
+ width: 300
+ color: "transparent"
+ anchors.bottom: parent.bottom
+ anchors.top: parent.top
+
+ MoneroEffects.GradientBackground {
+ anchors.fill: parent
+ fallBackColor: MoneroComponents.Style.middlePanelBackgroundColor
+ initialStartColor: MoneroComponents.Style.leftPanelBackgroundGradientStart
+ initialStopColor: MoneroComponents.Style.leftPanelBackgroundGradientStop
+ blackColorStart: MoneroComponents.Style._b_leftPanelBackgroundGradientStart
+ blackColorStop: MoneroComponents.Style._b_leftPanelBackgroundGradientStop
+ whiteColorStart: MoneroComponents.Style._w_leftPanelBackgroundGradientStart
+ whiteColorStop: MoneroComponents.Style._w_leftPanelBackgroundGradientStop
+ posStart: 0.6
+ start: Qt.point(0, 0)
+ end: Qt.point(height, width)
+ }
+
+ // card with monero logo
+ Column {
+ visible: true
+ z: 2
+ id: column1
+ height: 175
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.topMargin: (persistentSettings.customDecorations)? 50 : 0
+
+ Item {
+ Item {
+ anchors.left: parent.left
+ anchors.top: parent.top
+ anchors.topMargin: 20
+ anchors.leftMargin: 20
+ height: 490
+ width: 260
+
+ Image {
+ id: card
+ visible: !isOpenGL || MoneroComponents.Style.blackTheme
+ width: 260
+ height: 135
+ fillMode: Image.PreserveAspectFit
+ source: MoneroComponents.Style.blackTheme ? "qrc:///images/card-background-black" + (currentAccountIndex % MoneroComponents.Style.accountColors.length) + ".png" : "qrc:///images/card-background-white.png"
+ }
+
+ DropShadow {
+ visible: isOpenGL && !MoneroComponents.Style.blackTheme
+ anchors.fill: card
+ horizontalOffset: 3
+ verticalOffset: 3
+ radius: 10.0
+ samples: 15
+ color: "#3B000000"
+ source: card
+ cached: true
+ }
+
+ MoneroComponents.TextPlain {
+ id: testnetLabel
+ visible: persistentSettings.nettype != NetworkType.MAINNET
+ text: (persistentSettings.nettype == NetworkType.TESTNET ? qsTr("Testnet") : qsTr("Stagenet")) + translationManager.emptyString
+ anchors.top: parent.top
+ anchors.topMargin: 8
+ anchors.left: parent.left
+ anchors.leftMargin: 192
+ font.bold: true
+ font.pixelSize: 12
+ color: "#f33434"
+ themeTransition: false
+ }
+
+ MoneroComponents.TextPlain {
+ id: viewOnlyLabel
+ visible: viewOnly
+ text: qsTr("View Only") + translationManager.emptyString
+ anchors.top: parent.top
+ anchors.topMargin: 8
+ anchors.right: testnetLabel.visible ? testnetLabel.left : parent.right
+ anchors.rightMargin: 8
+ font.pixelSize: 12
+ font.bold: true
+ color: "#ff9323"
+ themeTransition: false
+ }
+ }
+
+ Item {
+ anchors.left: parent.left
+ anchors.top: parent.top
+ anchors.topMargin: 20
+ anchors.leftMargin: 20
+ height: 490
+ width: 50
+
+ MoneroComponents.Label {
+ fontSize: 12
+ id: accountIndex
+ text: qsTr("Account") + translationManager.emptyString + " #" + currentAccountIndex
+ color: MoneroComponents.Style.blackTheme ? "white" : "black"
+ anchors.left: parent.left
+ anchors.leftMargin: 60
+ anchors.top: parent.top
+ anchors.topMargin: 23
+ themeTransition: false
+
+ MouseArea{
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: appWindow.showPageRequest("Account")
+ }
+ }
+
+ MoneroComponents.Label {
+ fontSize: 16
+ id: accountLabel
+ textWidth: 170
+ color: MoneroComponents.Style.blackTheme ? "white" : "black"
+ anchors.left: parent.left
+ anchors.leftMargin: 60
+ anchors.top: parent.top
+ anchors.topMargin: 36
+ themeTransition: false
+ elide: Text.ElideRight
+
+ MouseArea {
+ hoverEnabled: true
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ onClicked: appWindow.showPageRequest("Account")
+ }
+ }
+
+ MoneroComponents.Label {
+ fontSize: 16
+ visible: isSyncing
+ text: qsTr("Syncing...") + translationManager.emptyString
+ color: MoneroComponents.Style.blackTheme ? "white" : "black"
+ anchors.left: parent.left
+ anchors.leftMargin: 20
+ anchors.bottom: currencyLabel.top
+ anchors.bottomMargin: 15
+ themeTransition: false
+ }
+
+ MoneroComponents.TextPlain {
+ id: currencyLabel
+ font.pixelSize: 16
+ text: {
+ if (persistentSettings.fiatPriceEnabled && persistentSettings.fiatPriceToggle) {
+ return appWindow.fiatApiCurrencySymbol();
+ } else {
+ return "XMR"
+ }
+ }
+ color: MoneroComponents.Style.blackTheme ? "white" : "black"
+ anchors.left: parent.left
+ anchors.leftMargin: 20
+ anchors.top: parent.top
+ anchors.topMargin: 100
+ themeTransition: false
+
+ MouseArea {
+ hoverEnabled: true
+ anchors.fill: parent
+ visible: persistentSettings.fiatPriceEnabled
+ cursorShape: Qt.PointingHandCursor
+ onClicked: persistentSettings.fiatPriceToggle = !persistentSettings.fiatPriceToggle
+ }
+ }
+
+ MoneroComponents.TextPlain {
+ id: balancePart1
+ themeTransition: false
+ anchors.left: parent.left
+ anchors.leftMargin: 58
+ anchors.baseline: currencyLabel.baseline
+ color: MoneroComponents.Style.blackTheme ? "white" : "black"
+ Binding on color {
+ when: balancePart1MouseArea.containsMouse || balancePart2MouseArea.containsMouse
+ value: MoneroComponents.Style.orange
+ }
+ text: {
+ if (persistentSettings.fiatPriceEnabled && persistentSettings.fiatPriceToggle) {
+ return balanceFiatString.split('.')[0] + "."
+ } else {
+ return balanceString.split('.')[0] + "."
+ }
+ }
+ font.pixelSize: {
+ var defaultSize = 29;
+ var digits = (balancePart1.text.length - 1)
+ if (digits > 2 && !(persistentSettings.fiatPriceEnabled && persistentSettings.fiatPriceToggle)) {
+ return defaultSize - 1.1 * digits
+ } else {
+ return defaultSize
+ }
+ }
+ MouseArea {
+ id: balancePart1MouseArea
+ hoverEnabled: true
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ console.log("Copied to clipboard");
+ clipboard.setText(balancePart1.text + balancePart2.text);
+ appWindow.showStatusMessage(qsTr("Copied to clipboard"),3)
+ }
+ }
+ }
+ MoneroComponents.TextPlain {
+ id: balancePart2
+ themeTransition: false
+ anchors.left: balancePart1.right
+ anchors.leftMargin: 2
+ anchors.baseline: currencyLabel.baseline
+ color: balancePart1.color
+ text: {
+ if (persistentSettings.fiatPriceEnabled && persistentSettings.fiatPriceToggle) {
+ return balanceFiatString.split('.')[1]
+ } else {
+ return balanceString.split('.')[1]
+ }
+ }
+ font.pixelSize: 16
+ MouseArea {
+ id: balancePart2MouseArea
+ hoverEnabled: true
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ onClicked: balancePart1MouseArea.clicked(mouse)
+ }
+ }
+
+ Item { //separator
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: 1
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ id: menuRect
+ z: 2
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.top: column1.bottom
+ color: "transparent"
+
+ Flickable {
+ id:flicker
+ contentHeight: menuColumn.height
+ anchors.top: parent.top
+ anchors.bottom: progressBar.visible ? progressBar.top : networkStatus.top
+ width: parent.width
+ boundsBehavior: isMac ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
+ clip: true
+
+ Column {
+ id: menuColumn
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ clip: true
+ property var previousButton: transferButton
+
+ // top border
+ MoneroComponents.MenuButtonDivider {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 20
+ }
+
+ // ------------- Account tab ---------------
+ MoneroComponents.MenuButton {
+ id: accountButton
+ anchors.left: parent.left
+ anchors.right: parent.right
+ text: qsTr("Account") + translationManager.emptyString
+ symbol: (isMac ? "⌃" : qsTr("Ctrl+")) + "T" + translationManager.emptyString
+
+ onClicked: {
+ parent.previousButton.checked = false
+ parent.previousButton = accountButton
+ panel.accountClicked()
+ }
+ }
+
+ MoneroComponents.MenuButtonDivider {
+ visible: accountButton.present
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 20
+ }
+
+ // ------------- Transfer tab ---------------
+ MoneroComponents.MenuButton {
+ id: transferButton
+ anchors.left: parent.left
+ anchors.right: parent.right
+ text: qsTr("Send") + translationManager.emptyString
+ symbol: (isMac ? "⌃" : qsTr("Ctrl+")) + "S" + translationManager.emptyString
+ onClicked: {
+ parent.previousButton.checked = false
+ parent.previousButton = transferButton
+ panel.transferClicked()
+ }
+ }
+
+ MoneroComponents.MenuButtonDivider {
+ visible: transferButton.present
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 20
+ }
+
+ // ------------- AddressBook tab ---------------
+
+ MoneroComponents.MenuButton {
+ id: addressBookButton
+ anchors.left: parent.left
+ anchors.right: parent.right
+ text: qsTr("Address book") + translationManager.emptyString
+ symbol: (isMac ? "⌃" : qsTr("Ctrl+")) + "B" + translationManager.emptyString
+ under: transferButton
+ onClicked: {
+ parent.previousButton.checked = false
+ parent.previousButton = addressBookButton
+ panel.addressBookClicked()
+ }
+ }
+
+ MoneroComponents.MenuButtonDivider {
+ visible: addressBookButton.present
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 20
+ }
+
+ // ------------- Receive tab ---------------
+ MoneroComponents.MenuButton {
+ id: receiveButton
+ anchors.left: parent.left
+ anchors.right: parent.right
+ text: qsTr("Receive") + translationManager.emptyString
+ symbol: (isMac ? "⌃" : qsTr("Ctrl+")) + "R" + translationManager.emptyString
+ onClicked: {
+ parent.previousButton.checked = false
+ parent.previousButton = receiveButton
+ panel.receiveClicked()
+ }
+ }
+
+ MoneroComponents.MenuButtonDivider {
+ visible: receiveButton.present
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 20
+ }
+
+ // ------------- History tab ---------------
+
+ MoneroComponents.MenuButton {
+ id: historyButton
+ anchors.left: parent.left
+ anchors.right: parent.right
+ text: qsTr("Transactions") + translationManager.emptyString
+ symbol: (isMac ? "⌃" : qsTr("Ctrl+")) + "H" + translationManager.emptyString
+ onClicked: {
+ parent.previousButton.checked = false
+ parent.previousButton = historyButton
+ panel.historyClicked()
+ }
+ }
+
+ MoneroComponents.MenuButtonDivider {
+ visible: historyButton.present
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 20
+ }
+
+ // ------------- Advanced tab ---------------
+ MoneroComponents.MenuButton {
+ id: advancedButton
+ visible: appWindow.walletMode >= 2
+ anchors.left: parent.left
+ anchors.right: parent.right
+ text: qsTr("Advanced") + translationManager.emptyString
+ symbol: (isMac ? "⌃" : qsTr("Ctrl+")) + "D" + translationManager.emptyString
+ onClicked: {
+ parent.previousButton.checked = false
+ parent.previousButton = advancedButton
+ panel.advancedClicked()
+ }
+ }
+
+ MoneroComponents.MenuButtonDivider {
+ visible: advancedButton.present && appWindow.walletMode >= 2
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 20
+ }
+
+ // ------------- Settings tab ---------------
+ MoneroComponents.MenuButton {
+ id: settingsButton
+ anchors.left: parent.left
+ anchors.right: parent.right
+ text: qsTr("Settings") + translationManager.emptyString
+ symbol: (isMac ? "⌃" : qsTr("Ctrl+")) + "E" + translationManager.emptyString
+ onClicked: {
+ parent.previousButton.checked = false
+ parent.previousButton = settingsButton
+ panel.settingsClicked()
+ }
+ }
+
+ MoneroComponents.MenuButtonDivider {
+ visible: settingsButton.present
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 20
+ }
+
+ } // Column
+
+ } // Flickable
+
+ Rectangle {
+ id: separator
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 0
+ anchors.rightMargin: 0
+ anchors.bottom: progressBar.visible ? progressBar.top : networkStatus.top
+ height: 10
+ color: "transparent"
+ }
+
+ MoneroComponents.ProgressBar {
+ id: progressBar
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: daemonProgressBar.top
+ height: 48
+ syncType: qsTr("Wallet") + translationManager.emptyString
+ visible: !appWindow.disconnected
+ }
+
+ MoneroComponents.ProgressBar {
+ id: daemonProgressBar
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: networkStatus.top
+ syncType: qsTr("Daemon") + translationManager.emptyString
+ visible: !appWindow.disconnected
+ height: 62
+ }
+
+ MoneroComponents.NetworkStatusItem {
+ id: networkStatus
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 5
+ anchors.rightMargin: 0
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 5
+ connected: Wallet.ConnectionStatus_Disconnected
+ height: 48
+ }
+ }
+}
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..7ed3f36
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,70 @@
+ANDROID_STANDALONE_TOOLCHAIN_PATH ?= /usr/local/toolchain
+MANUAL_SUBMODULES ?= OFF
+
+dotgit=$(shell ls -d .git/config)
+ifeq ($(dotgit), .git/config)
+ ifeq ($(shell git --version > /dev/null 2>&1 ; echo $$?), 0)
+ git = yes
+ else
+ $(warning git command not found)
+ endif
+endif
+
+builddir := build
+topdir := ../..
+ifeq ($(USE_SINGLE_BUILDDIR), OFF)
+ 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 -G Ninja -D DEV_MODE=$(or ${DEV_MODE},OFF) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release .. && cmake --build .
+debug:
+ mkdir -p build && cd build && cmake -G Ninja -D DEV_MODE=$(or ${DEV_MODE},ON) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -D CMAKE_BUILD_TYPE=Debug .. && cmake --build . --verbose
+
+depends:
+ mkdir -p build/$(target)/release
+ cd build/$(target)/release && cmake -G Ninja -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 ../../.. && cmake --build .
+
+devmode:
+ mkdir -p build && cd build && cmake -G Ninja -D DEV_MODE=$(or ${DEV_MODE},ON) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release .. && cmake --build .
+clean:
+ mkdir -p build && cd build && rm -rf *
+scanner:
+ mkdir -p build && cd build && cmake -G Ninja -D DEV_MODE=$(or ${DEV_MODE},ON) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -D WITH_SCANNER=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release .. && cmake --build .
+
+release:
+ mkdir -p $(builddir)/release && cd $(builddir)/release && cmake -G Ninja -D DEV_MODE=$(or ${DEV_MODE},OFF) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -D CMAKE_BUILD_TYPE=Release $(topdir) && cmake --build .
+
+release-linux-armv8:
+ mkdir -p $(builddir)/release && cd $(builddir)/release && cmake -G Ninja -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) && cmake --build .
+
+release-linux-ppc64le:
+ mkdir -p $(builddir)/release && cd $(builddir)/release && cmake -G Ninja -D DEV_MODE=$(or ${DEV_MODE},OFF) -DMANUAL_SUBMODULES=${MANUAL_SUBMODULES} -D ARCH="ppc64le" -D CMAKE_BUILD_TYPE=Release $(topdir) && cmake --build .
+
+release-static:
+ mkdir -p $(builddir)/release && cd $(builddir)/release && cmake -G Ninja -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) && cmake --build .
+
+debug-static-win64:
+ mkdir -p $(builddir)/debug && cd $(builddir)/debug && cmake -D STATIC=ON -G Ninja -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) && cmake --build .
+
+debug-static-mac64:
+ mkdir -p $(builddir)/debug
+ cd $(builddir)/debug && cmake -G Ninja -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=Debug -D BUILD_TAG="mac-x64" $(topdir) && cmake --build .
+
+release-static-win64:
+ mkdir -p $(builddir)/release && cd $(builddir)/release && cmake -D STATIC=ON -G Ninja -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" $(topdir) && cmake --build .
+
+release-win64:
+ mkdir -p $(builddir)/release && cd $(builddir)/release && cmake -D STATIC=OFF -G Ninja -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" $(topdir) && cmake --build .
diff --git a/MiddlePanel.qml b/MiddlePanel.qml
new file mode 100644
index 0000000..cd703a1
--- /dev/null
+++ b/MiddlePanel.qml
@@ -0,0 +1,257 @@
+// Copyright (c) 2014-2024, 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 QtQml 2.0
+import QtQuick 2.9
+import QtQuick.Controls 2.0
+import QtQuick.Controls 1.4
+import QtQuick.Layouts 1.1
+import QtGraphicalEffects 1.0
+import moneroComponents.Wallet 1.0
+
+import "./pages"
+import "./pages/settings"
+import "./pages/merchant"
+import "./components" as MoneroComponents
+import "./components/effects/" as MoneroEffects
+
+Rectangle {
+ id: root
+
+ property Item currentView
+ property Item previousView
+ property int minHeight: (appWindow.height > 800) ? appWindow.height : 800
+ property alias contentHeight: mainFlickable.contentHeight
+ property alias flickable: mainFlickable
+
+ property Transfer transferView: Transfer {
+ onPaymentClicked: root.paymentClicked(recipients, paymentId, mixinCount, priority, description)
+ onSweepUnmixableClicked: root.sweepUnmixableClicked()
+ }
+ property Receive receiveView: Receive { }
+ property Merchant merchantView: Merchant { }
+ property History historyView: History { }
+ property Advanced advancedView: Advanced { }
+ property Settings settingsView: Settings { }
+ property AddressBook addressBookView: AddressBook { }
+ property Keys keysView: Keys { }
+ property Account accountView: Account { }
+
+ signal paymentClicked(var recipients, string paymentId, int mixinCount, int priority, string description)
+ signal sweepUnmixableClicked()
+ signal generatePaymentIdInvoked()
+ signal getProofClicked(string txid, string address, string message, string amount);
+ signal checkProofClicked(string txid, string address, string message, string signature);
+
+ Rectangle {
+ // grey background on merchantView
+ visible: currentView === merchantView
+ color: MoneroComponents.Style.moneroGrey
+ anchors.fill: parent
+ }
+
+ MoneroEffects.GradientBackground {
+ visible: currentView !== merchantView
+ anchors.fill: parent
+ fallBackColor: MoneroComponents.Style.middlePanelBackgroundColor
+ initialStartColor: MoneroComponents.Style.middlePanelBackgroundGradientStart
+ initialStopColor: MoneroComponents.Style.middlePanelBackgroundGradientStop
+ blackColorStart: MoneroComponents.Style._b_middlePanelBackgroundGradientStart
+ blackColorStop: MoneroComponents.Style._b_middlePanelBackgroundGradientStop
+ whiteColorStart: MoneroComponents.Style._w_middlePanelBackgroundGradientStart
+ whiteColorStop: MoneroComponents.Style._w_middlePanelBackgroundGradientStop
+ start: Qt.point(0, 0)
+ end: Qt.point(height, width)
+ }
+
+ onCurrentViewChanged: {
+ if (previousView) {
+ if (typeof previousView.onPageClosed === "function") {
+ previousView.onPageClosed();
+ }
+ }
+ previousView = currentView
+ if (currentView) {
+ stackView.replace(currentView)
+ // Component.onCompleted is called before wallet is initilized
+ if (typeof currentView.onPageCompleted === "function") {
+ currentView.onPageCompleted();
+ }
+ }
+ }
+
+ function updateStatus(){
+ transferView.updateStatus();
+ }
+
+ // send from AddressBook
+ function sendTo(address, paymentId, description){
+ root.state = "Transfer";
+ transferView.sendTo(address, paymentId, description);
+ }
+
+ // open Transactions page with search term in search field
+ function searchInHistory(searchTerm){
+ root.state = "History";
+ historyView.searchInHistory(searchTerm);
+ }
+
+ states: [
+ State {
+ name: "History"
+ PropertyChanges { target: root; currentView: historyView }
+ PropertyChanges { target: mainFlickable; contentHeight: historyView.contentHeight + 80}
+ }, State {
+ name: "Transfer"
+ PropertyChanges { target: root; currentView: transferView }
+ PropertyChanges { target: mainFlickable; contentHeight: transferView.transferHeight1 + transferView.transferHeight2 + 80 }
+ }, State {
+ name: "Receive"
+ PropertyChanges { target: root; currentView: receiveView }
+ PropertyChanges { target: mainFlickable; contentHeight: receiveView.receiveHeight + 80 }
+ }, State {
+ name: "Merchant"
+ PropertyChanges { target: root; currentView: merchantView }
+ PropertyChanges { target: mainFlickable; contentHeight: merchantView.merchantHeight + 80 }
+ }, State {
+ name: "AddressBook"
+ PropertyChanges { target: root; currentView: addressBookView }
+ PropertyChanges { target: mainFlickable; contentHeight: addressBookView.addressbookHeight + 80 }
+ }, State {
+ 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: "Keys"
+ PropertyChanges { target: root; currentView: keysView }
+ PropertyChanges { target: mainFlickable; contentHeight: keysView.keysHeight + 80}
+ }, State {
+ name: "Account"
+ PropertyChanges { target: root; currentView: accountView }
+ PropertyChanges { target: mainFlickable; contentHeight: accountView.accountHeight + 80 }
+ }
+ ]
+
+ ColumnLayout {
+ anchors.fill: parent
+ anchors.margins: {
+ if(currentView === merchantView || currentView === historyView)
+ return 0;
+
+ return 20;
+ }
+
+ anchors.topMargin: appWindow.persistentSettings.customDecorations ? 50 : 0
+ anchors.bottomMargin: 0
+ spacing: 0
+
+ Flickable {
+ id: mainFlickable
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ clip: true
+ boundsBehavior: isMac ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
+
+ ScrollBar.vertical: ScrollBar {
+ parent: root
+ anchors.left: parent.right
+ anchors.leftMargin: -14 // 10 margin + 4 scrollbar width
+ anchors.top: parent.top
+ anchors.topMargin: persistentSettings.customDecorations ? 60 : 10
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: persistentSettings.customDecorations ? 15 : 10
+ onActiveChanged: if (!active && !isMac) active = true
+ }
+
+ onFlickingChanged: {
+ releaseFocus();
+ }
+
+ // Views container
+ StackView {
+ id: stackView
+ initialItem: transferView
+ anchors.fill:parent
+ clip: true // 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
+ }
+ }
+ }
+ }
+
+ }// flickable
+ }
+
+ // border
+ Rectangle {
+ id: borderLeft
+ visible: middlePanel.state !== "Merchant"
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ width: 1
+ color: MoneroComponents.Style.appWindowBorderColor
+
+ MoneroEffects.ColorTransition {
+ targetObj: parent
+ blackColor: MoneroComponents.Style._b_appWindowBorderColor
+ whiteColor: MoneroComponents.Style._w_appWindowBorderColor
+ }
+ }
+
+ // border shadow
+ Image {
+ source: "qrc:///images/middlePanelShadow.png"
+ width: 12
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.left: borderLeft.right
+ }
+}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5f74d72
--- /dev/null
+++ b/README.md
@@ -0,0 +1,349 @@
+# Monero GUI
+
+Copyright (c) 2014-2024, The Monero Project
+
+## Table of Contents
+ * [Development resources](#development-resources)
+ * [Vulnerability response](#vulnerability-response)
+ * [Introduction](#introduction)
+ * [About this project](#about-this-project)
+ * [Supporting the project](#supporting-the-project)
+ * [License](#license)
+ * [Translations](#translations)
+ * [Installing the Monero GUI from a package](#installing-the-monero-gui-from-a-package)
+ * [Compiling the Monero GUI from source](#compiling-the-monero-gui-from-source)
+ + [Building Reproducible Windows static binaries with Docker (any OS)](#building-reproducible-windows-static-binaries-with-docker-any-os)
+ + [Building Reproducible Linux static binaries with Docker (any OS)](#building-reproducible-linux-static-binaries-with-docker-any-os)
+ + [Building Android APK with Docker (any OS) *Experimental*](#building-android-apk-with-docker-any-os-experimental)
+ + [Building on Linux](#building-on-linux)
+ + [Building on OS X](#building-on-os-x)
+ + [Building on Windows](#building-on-windows)
+
+## Development resources
+
+- Web: [getmonero.org](https://getmonero.org)
+- Mail: [dev@getmonero.org](mailto:dev@getmonero.org)
+- Github: [https://github.com/monero-project/monero-gui](https://github.com/monero-project/monero-gui)
+- IRC: [#monero-gui on Libera](irc://irc.libera.chat/#monero-gui)
+- Translation platform (Weblate): [translate.getmonero.org](https://translate.getmonero.org)
+- UI Design: [Monero-GUI on Figma](https://www.figma.com/file/DplJ2DDQfIKiuRvolHX2hN/Monero-GUI)
+
+## Vulnerability response
+
+- Our [Vulnerability Response Process](https://github.com/monero-project/meta/blob/master/VULNERABILITY_RESPONSE_PROCESS.md) encourages responsible disclosure
+- We are also available via [HackerOne](https://hackerone.com/monero)
+
+## Introduction
+
+Monero is a private, secure, untraceable, decentralised digital currency. You are your bank, you control your funds, and nobody can trace your transfers unless you allow them to do so.
+
+**Privacy:** Monero uses a cryptographically sound system to allow you to send and receive funds without your transactions being easily revealed on the blockchain (the ledger of transactions that everyone has). This ensures that your purchases, receipts, and all transfers remain absolutely private by default.
+
+**Security:** Using the power of a distributed peer-to-peer consensus network, every transaction on the network is cryptographically secured. Individual wallets have a 25 word mnemonic seed that is only displayed once, and can be written down to backup the wallet. Wallet files are encrypted with a passphrase to ensure they are useless if stolen.
+
+**Untraceability:** By taking advantage of ring signatures, a special property of a certain type of cryptography, Monero is able to ensure that transactions are not only untraceable, but have an optional measure of ambiguity that ensures that transactions cannot easily be tied back to an individual user or computer.
+
+## About this project
+
+This is the GUI for the [core Monero implementation](https://github.com/monero-project/monero). It is open source and completely free to use without restrictions, except for those specified in the license agreement below. There are no restrictions on anyone creating an alternative implementation of Monero that uses the protocol and network in a compatible manner.
+
+As with many development projects, the repository on Github is considered to be the "staging" area for the latest changes. Before changes are merged into that branch on the main repository, they are tested by individual developers in their own branches, submitted as a pull request, and then subsequently tested by contributors who focus on testing and code reviews. That having been said, the repository should be carefully considered before using it in a production environment, unless there is a patch in the repository for a particular show-stopping issue you are experiencing. It is generally a better idea to use a tagged release for stability.
+
+## Supporting the project
+
+Monero is a 100% community-sponsored endeavor. If you want to join our efforts, the easiest thing you can do is support the project financially. Both Monero and Bitcoin donations can be made to **donate.getmonero.org** if using a client that supports the [OpenAlias](https://openalias.org) standard.
+
+The Monero donation address is: `888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H` (viewkey: `f359631075708155cc3d92a32b75a7d02a5dcf27756707b47a2b31b21c389501`)
+
+The Bitcoin donation address is: `1KTexdemPdxSBcG55heUuTjDRYqbC5ZL8H`
+
+GUI development funding and/or some supporting services are also graciously provided by [sponsors](https://www.getmonero.org/community/sponsorships/):
+
+[<img width="150" src="https://www.getmonero.org/img/sponsors/tarilabs.png"/>](https://tarilabs.com/)
+[<img width="150" src="https://www.getmonero.org/img/sponsors/symas.png"/>](https://symas.com/)
+[<img width="150" src="https://www.getmonero.org/img/sponsors/macstadium.png"/>](https://www.macstadium.com/)
+
+There are also several mining pools that kindly donate a portion of their fees, [a list of them can be found on our Bitcointalk post](https://bitcointalk.org/index.php?topic=583449.0).
+
+## License
+
+See [LICENSE](LICENSE).
+
+## Translations
+
+Do you speak a second language and would like to help translate the Monero GUI? Check out Weblate, our localization platform, at [translate.getmonero.org](https://translate.getmonero.org/). Choose the language and suggest a translation for a string or review an existing one. The Localization Workgroup made [a guide with step-by-step instructions](https://github.com/monero-ecosystem/monero-translations/blob/master/weblate.md) for Weblate.
+
+If you need help/support or any info you can contact the localization workgroup on the IRC channel #monero-translations (relayed on [Matrix](https://matrix.to/#/!BKMbQLMDzHKzmtrBfg:matrix.org?via=monero.social&via=matrix.org&via=libera.chat)) or by email at translate[at]getmonero[dot]org. For more info about the Localization workgroup: [github.com/monero-ecosystem/monero-translations](https://github.com/monero-ecosystem/monero-translations)
+
+Status of the translations:
+
+<a href="https://translate.getmonero.org/engage/monero/?utm_source=widget">
+<img src="https://translate.getmonero.org/widgets/monero/-/gui-wallet/horizontal-auto.svg" alt="Translation status" />
+</a>
+
+## Installing the Monero GUI from a package
+
+Packages are available for
+* Arch Linux: [monero-gui](https://archlinux.org/packages/extra/x86_64/monero-gui/)
+* NixOS: `nix-shell -p monero-gui`
+* Flatpak: [Monero GUI](https://flathub.org/apps/details/org.getmonero.Monero)
+* GuixSD: `guix package -i monero-gui`
+* macOS (homebrew): `brew install --cask monero-wallet`
+
+Packaging for your favorite distribution would be a welcome contribution!
+
+## Compiling the Monero GUI from source
+
+*Note*: Qt 5.12 is the minimum version required to build the GUI.
+
+*Note*: Official GUI releases use monero-wallet-gui from this process alongside the supporting binaries (monerod, etc) from the [CLI deterministic builds](https://github.com/monero-project/monero/blob/release-v0.18/contrib/gitian/README.md).
+
+*Note*: The convenience targets in the project Makefile require the Ninja build system. Other CMake generators can still be used by invoking CMake directly. Ninja builds in parallel by default. To limit or set the number of parallel build jobs, set `CMAKE_BUILD_PARALLEL_LEVEL`, for example `CMAKE_BUILD_PARALLEL_LEVEL=4 make release`.
+
+### 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 --branch master --recursive https://github.com/monero-project/monero-gui.git
+ ```
+ \* `master` - replace with the desired version tag (e.g. `v0.18.5.1`) to build the release binaries.
+3. Prepare build environment
+ ```
+ cd monero-gui
+ docker build --tag monero:build-env-windows --build-arg THREADS=4 --file Dockerfile.windows .
+ ```
+ \* `4` - number of CPU threads to use
+
+4. Build
+ ```
+ docker run --rm -it -v <MONERO_GUI_DIR_FULL_PATH>:/monero-gui -w /monero-gui monero:build-env-windows sh -c 'make depends root=/depends target=x86_64-w64-mingw32 tag=win-x64'
+ ```
+ \* `<MONERO_GUI_DIR_FULL_PATH>` - absolute path to `monero-gui` directory
+ \* Set `CMAKE_BUILD_PARALLEL_LEVEL` to control the number of parallel build jobs, e.g. add `-e CMAKE_BUILD_PARALLEL_LEVEL=4` to the `docker run` command
+5. Monero GUI Windows static binaries will be placed in `monero-gui/build/x86_64-w64-mingw32/release/bin` directory
+
+### 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 --branch master --recursive https://github.com/monero-project/monero-gui.git
+ ```
+ \* `master` - replace with the desired version tag (e.g. `v0.18.5.1`) to build the release binaries.
+3. Prepare build environment
+ ```
+ cd monero-gui
+ docker build --tag monero:build-env-linux --build-arg THREADS=4 --file Dockerfile.linux .
+ ```
+ \* `4` - number of CPU threads to use
+
+4. Build
+ ```
+ docker run --rm -it -v <MONERO_GUI_DIR_FULL_PATH>:/monero-gui -w /monero-gui monero:build-env-linux sh -c 'make release-static'
+ ```
+ \* `<MONERO_GUI_DIR_FULL_PATH>` - absolute path to `monero-gui` directory
+ \* Set `CMAKE_BUILD_PARALLEL_LEVEL` to control the number of parallel build jobs, e.g. add `-e CMAKE_BUILD_PARALLEL_LEVEL=4` to the `docker run` command
+5. Monero GUI Linux static binary will be placed in `monero-gui/build/release/bin` directory
+6. (*Note*) This process is only for building `monero-wallet-gui`, `monerod` has to be built separately according to the instructions in the `monero` repository.
+7. (*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 monero:build-env-android
+ ```
+ \* `<MONERO_GUI_DIR_FULL_PATH>` - absolute path to `monero-gui` directory
+ \* Set `CMAKE_BUILD_PARALLEL_LEVEL` to control the number of parallel build jobs, e.g. add `-e CMAKE_BUILD_PARALLEL_LEVEL=4` to the `docker run` command
+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
+ ```
+
+### Building on Linux
+
+(Tested on Ubuntu 17.10 x64, Ubuntu 18.04 x64 and Gentoo x64)
+
+1. Install Monero dependencies
+
+ - For Debian distributions (Debian, Ubuntu, Mint, Tails...)
+
+ `sudo apt install build-essential cmake ninja-build libunbound-dev graphviz doxygen pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev libprotobuf-dev protobuf-compiler libgcrypt20-dev libboost-chrono-dev libboost-date-time-dev libboost-filesystem-dev libboost-locale-dev libboost-program-options-dev libboost-regex-dev libboost-serialization-dev libboost-system-dev libboost-thread-dev`
+
+ - For Gentoo
+
+ `sudo emerge app-arch/xz-utils app-doc/doxygen dev-build/ninja dev-cpp/gtest dev-libs/boost dev-libs/expat dev-libs/openssl dev-util/cmake media-gfx/graphviz net-dns/unbound net-libs/zeromq dev-libs/libsodium dev-libs/hidapi dev-libs/libgcrypt`
+
+ - For Fedora
+
+ `sudo dnf install make automake cmake ninja gcc-c++ boost-devel graphviz doxygen unbound-devel pkgconfig openssl-devel libcurl-devel hidapi-devel libusb-devel zeromq-devel libgcrypt-devel`
+
+2. Install Qt:
+
+ *Note*: The Qt 5.12 or newer requirement makes **some** distributions (mostly based on Debian, like Ubuntu 16.x or Linux Mint 18.x) obsolete due to their repositories containing an older Qt version.
+
+ The recommended way is to install 5.12 or newer from the [official Qt installer](https://www.qt.io/download-qt-installer) or [compiling it yourself](https://wiki.qt.io/Install_Qt_5_on_Ubuntu). This ensures you have the correct version. Higher versions *can* work but as it differs from our production build target, slight differences may occur.
+
+The following instructions will fetch Qt from your distribution's repositories instead. Take note of what version it installs. Your mileage may vary.
+
+ - For Debian distributions (Debian, Ubuntu, Mint, Tails...)
+
+ `sudo apt install qtbase5-dev qtdeclarative5-dev qml-module-qtqml-models2 qml-module-qtquick-controls qml-module-qtquick-controls2 qml-module-qtquick-dialogs qml-module-qtquick-xmllistmodel qml-module-qt-labs-settings qml-module-qt-labs-platform qml-module-qt-labs-folderlistmodel qttools5-dev-tools qml-module-qtquick-templates2 libqt5svg5-dev`
+
+ - For Gentoo
+
+
+ The *qml* USE flag must be enabled.
+
+ `sudo emerge dev-qt/qtcore:5 dev-qt/qtdeclarative:5 dev-qt/qtquickcontrols:5 dev-qt/qtquickcontrols2:5 dev-qt/qtgraphicaleffects:5`
+
+ - Optional : To build the flag `WITH_SCANNER`
+
+ - For Debian distributions (Debian, Ubuntu, Mint, Tails...)
+
+ `sudo apt install qtmultimedia5-dev qml-module-qtmultimedia`
+
+ - For Gentoo
+
+ `emerge dev-qt/qtmultimedia:5`
+
+
+3. Clone repository
+
+ ```
+ git clone --recursive https://github.com/monero-project/monero-gui.git
+ cd monero-gui
+ ```
+
+4. Build
+
+ ```
+ make release
+ ```
+
+ \* Add `CMAKE_PREFIX_PATH` environment variable to set a custom Qt install directory, e.g. `CMAKE_PREFIX_PATH=$HOME/Qt/5.9.7/gcc_64 make release`
+ \* Set `CMAKE_BUILD_PARALLEL_LEVEL` to control the number of parallel build jobs, e.g. `CMAKE_BUILD_PARALLEL_LEVEL=4 make release`
+
+The executable can be found in the build/release/bin folder.
+
+### Building on OS X
+
+1. Install Xcode from AppStore
+
+2. Install [homebrew](http://brew.sh/)
+
+3. Install [monero](https://github.com/monero-project/monero) dependencies:
+
+ `brew install cmake ninja pkg-config openssl boost unbound hidapi zmq libpgm libsodium expat protobuf libgcrypt`
+
+4. Install Qt:
+
+ `brew install qt5` (or download QT 5.12+ from [qt.io](https://www.qt.io/download-open-source/))
+
+5. Grab an up-to-date copy of the monero-gui repository
+
+ ```
+ git clone --recursive https://github.com/monero-project/monero-gui.git
+ cd monero-gui
+ ```
+
+6. Start the build
+
+ ```
+ make release
+ ```
+ \* Add `CMAKE_PREFIX_PATH` environment variable to set a custom Qt install directory, e.g. `CMAKE_PREFIX_PATH=$HOME/Qt/5.9.7/clang_64 make release`
+ \* Set `CMAKE_BUILD_PARALLEL_LEVEL` to control the number of parallel build jobs, e.g. `CMAKE_BUILD_PARALLEL_LEVEL=4 make release`
+
+The executable can be found in the `build/release/bin` folder.
+
+For building an application bundle see `DEPLOY.md`.
+
+### Building on Windows
+
+The Monero GUI on Windows is 64 bits only; 32-bit Windows GUI builds are not officially supported anymore.
+
+1. Install [MSYS2](https://www.msys2.org/), follow the instructions on that page on how to update system and packages to the latest versions
+
+2. Open an 64-bit MSYS2 shell: Use the *MSYS2 MinGW 64-bit* shortcut, or use the `msys2_shell.cmd` batch file with a `-mingw64` parameter
+
+3. Install MSYS2 packages for Monero dependencies; the needed 64-bit packages have `x86_64` in their names
+
+ ```
+ pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja 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 mingw-w64-x86_64-unbound mingw-w64-x86_64-pcre mingw-w64-x86_64-angleproject
+ ```
+
+ 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
+
+ ```
+ pacman -S mingw-w64-x86_64-qt5
+ ```
+
+ There is no more need to download some special installer from the Qt website, the standard MSYS2 package for Qt will do in almost all circumstances.
+
+5. Install git
+
+ ```
+ pacman -S git
+ ```
+
+6. Clone repository
+
+ ```
+ git clone --recursive https://github.com/monero-project/monero-gui.git
+ cd monero-gui
+ ```
+
+7. Build
+
+ ```
+ make release-win64
+ cd build/release
+ cmake --build . --target deploy
+ ```
+ \* Set `CMAKE_BUILD_PARALLEL_LEVEL` to control the number of parallel build jobs, e.g. `CMAKE_BUILD_PARALLEL_LEVEL=4 make release-win64`
+
+The executable can be found in the `.\bin` directory.
diff --git a/cmake/CheckLinkerFlag.c b/cmake/CheckLinkerFlag.c
new file mode 100644
index 0000000..a0dcc16
--- /dev/null
+++ b/cmake/CheckLinkerFlag.c
@@ -0,0 +1,14 @@
+#ifdef __CLASSIC_C__
+int main()
+{
+ int ac;
+ char* av[];
+#else
+int main(int ac, char* av[])
+{
+#endif
+ if (ac > 1000) {
+ return *av[0];
+ }
+ return 0;
+}
diff --git a/cmake/CheckLinkerFlag.cmake b/cmake/CheckLinkerFlag.cmake
new file mode 100644
index 0000000..2b507ab
--- /dev/null
+++ b/cmake/CheckLinkerFlag.cmake
@@ -0,0 +1,47 @@
+include(CheckCCompilerFlag)
+
+macro(CHECK_LINKER_FLAG flag VARIABLE)
+ if(NOT DEFINED "${VARIABLE}")
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(STATUS "Looking for ${flag} linker flag")
+ endif()
+
+ set(_cle_source ${CMAKE_SOURCE_DIR}/cmake/CheckLinkerFlag.c)
+
+ set(saved_CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
+ set(CMAKE_C_FLAGS "${flag}")
+ try_compile(${VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${_cle_source}
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} ${flag}
+ CMAKE_FLAGS
+ OUTPUT_VARIABLE OUTPUT)
+ unset(_cle_source)
+ set(CMAKE_C_FLAGS ${saved_CMAKE_C_FLAGS})
+ unset(saved_CMAKE_C_FLAGS)
+
+ if ("${OUTPUT}" MATCHES "warning.*ignored")
+ set(${VARIABLE} 0)
+ endif()
+
+ if(${VARIABLE})
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(STATUS "Looking for ${flag} linker flag - found")
+ endif()
+ set(${VARIABLE} 1 CACHE INTERNAL "Have linker flag ${flag}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the ${flag} linker flag is supported "
+ "passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ else()
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(STATUS "Looking for ${flag} linker flag - not found")
+ endif()
+ set(${VARIABLE} "" CACHE INTERNAL "Have linker flag ${flag}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the ${flag} linker flag is supported "
+ "failed with the following output:\n"
+ "${OUTPUT}\n\n")
+ endif()
+ endif()
+endmacro()
diff --git a/cmake/Deploy.cmake b/cmake/Deploy.cmake
new file mode 100644
index 0000000..e5f147f
--- /dev/null
+++ b/cmake/Deploy.cmake
@@ -0,0 +1,125 @@
+if(APPLE OR (WIN32 AND NOT STATIC))
+ add_custom_target(deploy)
+ get_target_property(_qmake_executable Qt5::qmake IMPORTED_LOCATION)
+ get_filename_component(_qt_bin_dir "${_qmake_executable}" DIRECTORY)
+
+ if(APPLE AND NOT IOS)
+ find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${_qt_bin_dir}")
+ add_custom_command(TARGET deploy
+ POST_BUILD
+ COMMAND "${MACDEPLOYQT_EXECUTABLE}" "$<TARGET_FILE_DIR:monero-wallet-gui>/../.." -always-overwrite -qmldir="${CMAKE_SOURCE_DIR}"
+ COMMENT "Running macdeployqt..."
+ )
+
+ # workaround for a Qt bug that requires manually adding libqsvg.dylib to bundle
+ find_file(_qt_svg_dylib "libqsvg.dylib" PATHS "${CMAKE_PREFIX_PATH}/plugins/imageformats" NO_DEFAULT_PATH)
+ if(_qt_svg_dylib)
+ add_custom_command(TARGET deploy
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${_qt_svg_dylib} $<TARGET_FILE_DIR:monero-wallet-gui>/../PlugIns/imageformats/
+ COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtGui.framework/Versions/5/QtGui" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" $<TARGET_FILE_DIR:monero-wallet-gui>/../PlugIns/imageformats/libqsvg.dylib
+ COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtWidgets.framework/Versions/5/QtWidgets" "@executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets" $<TARGET_FILE_DIR:monero-wallet-gui>/../PlugIns/imageformats/libqsvg.dylib
+ COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtSvg.framework/Versions/5/QtSvg" "@executable_path/../Frameworks/QtSvg.framework/Versions/5/QtSvg" $<TARGET_FILE_DIR:monero-wallet-gui>/../PlugIns/imageformats/libqsvg.dylib
+ COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "${CMAKE_PREFIX_PATH}/lib/QtCore.framework/Versions/5/QtCore" "@executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore" $<TARGET_FILE_DIR:monero-wallet-gui>/../PlugIns/imageformats/libqsvg.dylib
+ COMMENT "Copying libqsvg.dylib, running install_name_tool"
+
+ )
+ endif()
+
+ # Copy Boost dylibs that macdeployqt doesn't pick up
+ find_package(Boost QUIET COMPONENTS atomic container date_time)
+ set(_boost_extras Boost::atomic Boost::container Boost::date_time)
+ foreach(_tgt IN LISTS _boost_extras)
+ if(TARGET ${_tgt})
+ add_custom_command(TARGET deploy POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy
+ "$<TARGET_FILE:${_tgt}>"
+ "$<TARGET_FILE_DIR:monero-wallet-gui>/../Frameworks/"
+ COMMENT "Copying $<TARGET_FILE_NAME:${_tgt}>"
+ )
+ endif()
+ endforeach()
+
+ # Apple Silicon requires all binaries to be codesigned
+ find_program(CODESIGN_EXECUTABLE NAMES codesign)
+ if(CODESIGN_EXECUTABLE)
+ add_custom_command(TARGET deploy
+ POST_BUILD
+ COMMAND "${CODESIGN_EXECUTABLE}" --force --deep --sign - "$<TARGET_FILE_DIR:monero-wallet-gui>/../.."
+ COMMENT "Running codesign..."
+ )
+ endif()
+
+ elseif(WIN32)
+ find_program(QMAKE_EXECUTABLE qmake HINTS "${_qt_bin_dir}")
+ find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${_qt_bin_dir}")
+ if(NOT QMAKE_EXECUTABLE OR NOT WINDEPLOYQT_EXECUTABLE)
+ message(WARNING "Deploy requires qmake.exe and windeployqt.exe (no -qt5 suffix) in ${_qt_bin_dir}")
+ endif()
+ add_custom_command(TARGET deploy POST_BUILD
+ COMMAND "${CMAKE_COMMAND}" -E env PATH="${_qt_bin_dir}" "${WINDEPLOYQT_EXECUTABLE}" "$<TARGET_FILE:monero-wallet-gui>" -no-translations -qmldir="${CMAKE_SOURCE_DIR}"
+ COMMENT "Running windeployqt..."
+ )
+ set(WIN_DEPLOY_DLLS
+ libboost_chrono-mt.dll
+ libboost_filesystem-mt.dll
+ libboost_locale-mt.dll
+ libboost_program_options-mt.dll
+ libboost_serialization-mt.dll
+ libboost_thread-mt.dll
+ libprotobuf.dll
+ libbrotlicommon.dll
+ libbrotlidec.dll
+ libusb-1.0.dll
+ zlib1.dll
+ libzstd.dll
+ libwinpthread-1.dll
+ libtiff-6.dll
+ libstdc++-6.dll
+ libpng16-16.dll
+ libpcre16-0.dll
+ libpcre-1.dll
+ libmng-2.dll
+ liblzma-5.dll
+ liblcms2-2.dll
+ libjpeg-8.dll
+ libintl-8.dll
+ libiconv-2.dll
+ libharfbuzz-0.dll
+ libgraphite2.dll
+ libglib-2.0-0.dll
+ libfreetype-6.dll
+ libbz2-1.dll
+ libpcre2-16-0.dll
+ libhidapi-0.dll
+ libdouble-conversion.dll
+ libgcrypt-20.dll
+ libgpg-error-0.dll
+ libsodium-26.dll
+ libzmq.dll
+ #platform files
+ libgcc_s_seh-1.dll
+ #openssl files
+ libssl-3-x64.dll
+ libcrypto-3-x64.dll
+ #icu
+ libicudt78.dll
+ libicuin78.dll
+ libicuio78.dll
+ libicutu78.dll
+ libicuuc78.dll
+ )
+
+ # Boost Regex is header-only since 1.77
+ if (Boost_VERSION_STRING VERSION_LESS 1.77.0)
+ list(APPEND WIN_DEPLOY_DLLS libboost_regex-mt.dll)
+ endif()
+
+ list(TRANSFORM WIN_DEPLOY_DLLS PREPEND "$ENV{MSYSTEM_PREFIX}/bin/")
+ add_custom_command(TARGET deploy
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${WIN_DEPLOY_DLLS} "$<TARGET_FILE_DIR:monero-wallet-gui>"
+ COMMENT "Copying DLLs to target folder"
+ )
+ endif()
+endif()
diff --git a/cmake/VersionGui.cmake b/cmake/VersionGui.cmake
new file mode 100644
index 0000000..4a554a8
--- /dev/null
+++ b/cmake/VersionGui.cmake
@@ -0,0 +1,47 @@
+# Copyright (c) 2014-2024, 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.
+
+function (write_static_version_header tag)
+ set(VERSION_TAG_GUI "${tag}" CACHE STRING "The tag portion of the Monero GUI software version" FORCE)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/version.js.in" "${CMAKE_CURRENT_SOURCE_DIR}/version.js")
+endfunction ()
+
+find_package(Git QUIET)
+if ("$Format:$" STREQUAL "")
+ # We're in a tarball; use hard-coded variables.
+ write_static_version_header("release")
+elseif (GIT_FOUND OR Git_FOUND)
+ message(STATUS "Found Git: ${GIT_EXECUTABLE}")
+ get_version_tag_from_git("${GIT_EXECUTABLE}")
+ write_static_version_header(${VERSIONTAG})
+else()
+ message(STATUS "WARNING: Git was not found!")
+ write_static_version_header("unknown")
+endif ()
+add_custom_target(genversiongui ALL
+ DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/version.js")
diff --git a/components/AdvancedOptionsItem.qml b/components/AdvancedOptionsItem.qml
new file mode 100644
index 0000000..d43944e
--- /dev/null
+++ b/components/AdvancedOptionsItem.qml
@@ -0,0 +1,68 @@
+import QtQuick 2.9
+import QtQuick.Layouts 1.1
+
+import "../components" as MoneroComponents
+
+RowLayout {
+ id: advancedOptionsItem
+
+ property alias title: title.text
+ property alias tooltip: title.tooltip
+ property alias button1: button1
+ property alias button2: button2
+ property alias button3: button3
+
+ RowLayout {
+ id: titlecolumn
+ Layout.alignment: Qt.AlignTop | Qt.AlignLeft
+ Layout.preferredWidth: 195
+ Layout.maximumWidth: 195
+ Layout.leftMargin: 10
+
+ MoneroComponents.Label {
+ id: title
+ fontSize: 14
+ tooltipIconVisible: true
+ }
+
+ Rectangle {
+ id: separator
+ Layout.fillWidth: true
+ height: 10
+ color: "transparent"
+ }
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: false
+ Layout.alignment: Qt.AlignTop | Qt.AlignLeft
+ spacing: 4
+
+ RowLayout {
+ Layout.fillWidth: false
+ spacing: 12
+ Layout.alignment: Qt.AlignTop | Qt.AlignLeft
+
+ StandardButton {
+ id: button1
+ small: true
+ primary: false
+ visible: button1.text
+ }
+
+ StandardButton {
+ id: button2
+ small: true
+ primary: false
+ visible: button2.text
+ }
+
+ StandardButton {
+ id: button3
+ small: true
+ primary: false
+ visible: button3.text
+ }
+ }
+ }
+}
diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt
new file mode 100644
index 0000000..2ae8e88
--- /dev/null
+++ b/components/CMakeLists.txt
@@ -0,0 +1,47 @@
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+###
+
+#configure_file(${CMAKE_CURRENT_SOURCE_DIR}/defines.h.cmake
+# ${CMAKE_CURRENT_BINARY_DIR}/defines.h)
+
+file(GLOB_RECURSE UI_FILES *.ui)
+file(GLOB_RECURSE CODE_FILES *.cpp)
+
+qt5_wrap_ui(UI_HEADERS ${UI_FILES})
+#qt5_add_resources(RESOURCE_FILES ../resources/resources.qrc)
+
+# Windows application icon
+if (WIN32)
+ set(WINDOWS_RES_FILE ${CMAKE_CURRENT_BINARY_DIR}/resources.obj)
+ if (MSVC)
+ add_custom_command(OUTPUT ${WINDOWS_RES_FILE}
+ COMMAND rc.exe /fo ${WINDOWS_RES_FILE} resources.rc
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/win
+ )
+ else()
+ add_custom_command(OUTPUT ${WINDOWS_RES_FILE}
+ COMMAND windres.exe resources.rc ${WINDOWS_RES_FILE}
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/win
+ )
+ endif()
+endif()
+
+add_executable(${CMAKE_PROJECT_NAME} WIN32
+ ${UI_HEADERS}
+ ${CODE_FILES}
+ ${RESOURCE_FILES}
+ ${WINDOWS_RES_FILE}
+)
+target_link_libraries(${CMAKE_PROJECT_NAME}
+ Qt5::Widgets
+)
+
+if (UNIX)
+ install(TARGETS ${CMAKE_PROJECT_NAME}
+ RUNTIME DESTINATION bin)
+elseif (WIN32)
+ install(TARGETS ${CMAKE_PROJECT_NAME}
+ DESTINATION .)
+endif()
diff --git a/components/CheckBox.qml b/components/CheckBox.qml
new file mode 100644
index 0000000..d0615e0
--- /dev/null
+++ b/components/CheckBox.qml
@@ -0,0 +1,134 @@
+// Copyright (c) 2014-2024, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import QtQuick 2.9
+import QtQuick.Layouts 1.1
+import FontAwesome 1.0
+
+import "." as MoneroComponents
+import "effects/" as MoneroEffects
+
+Item {
+ id: checkBox
+ property alias text: label.text
+ property string checkedIcon: "qrc:///images/check-white.svg"
+ property string uncheckedIcon
+ property bool fontAwesomeIcons: false
+ property int imgWidth: 13
+ property int imgHeight: 13
+ property bool toggleOnClick: true
+ property bool checked: false
+ property alias background: backgroundRect.color
+ property bool border: true
+ property int fontSize: 14
+ property alias fontColor: label.color
+ property bool iconOnTheLeft: true
+ property alias tooltipIconVisible: label.tooltipIconVisible
+ property alias tooltip: label.tooltip
+ 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) {
+ checkBox.checked = !checkBox.checked
+ }
+ checkBox.clicked()
+ }
+
+ RowLayout {
+ id: checkBoxLayout
+ layoutDirection: iconOnTheLeft ? Qt.LeftToRight : Qt.RightToLeft
+ spacing: 10
+
+ Item {
+ id: checkMark
+ height: checkBox.height
+ width: checkBox.height
+
+ Rectangle {
+ id: backgroundRect
+ visible: checkBox.border
+ anchors.fill: parent
+ radius: 3
+ color: checkBox.enabled ? "transparent" : MoneroComponents.Style.inputBoxBackgroundDisabled
+ border.color:
+ if (checkBox.activeFocus) {
+ return MoneroComponents.Style.inputBorderColorActive;
+ } else {
+ return MoneroComponents.Style.inputBorderColorInActive;
+ }
+ }
+
+ MoneroEffects.ImageMask {
+ id: img
+ visible: checkBox.checked || checkBox.uncheckedIcon != ""
+ anchors.centerIn: parent
+ width: checkBox.imgWidth
+ height: checkBox.imgHeight
+ color: MoneroComponents.Style.defaultFontColor
+ fontAwesomeFallbackIcon: checkBox.fontAwesomeIcons ? getIcon() : FontAwesome.plus
+ fontAwesomeFallbackSize: 14
+ image: checkBox.fontAwesomeIcons ? "" : getIcon()
+
+ function getIcon() {
+ if (checkBox.checked || checkBox.uncheckedIcon == "")
+ return checkBox.checkedIcon;
+ return checkBox.uncheckedIcon;
+ }
+ }
+ }
+
+ MoneroComponents.TextPlain {
+ id: label
+ font.family: MoneroComponents.Style.fontRegular.name
+ font.pixelSize: checkBox.fontSize
+ color: MoneroComponents.Style.defaultFontColor
+ textFormat: Text.RichText
+ wrapMode: Text.NoWrap
+ visible: text != ""
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onEntered: !label.tooltipIconVisible && label.tooltip ? label.tooltipPopup.open() : ""
+ onExited: !label.tooltipIconVisible && label.tooltip ? label.tooltipPopup.close() : ""
+ onClicked: {
+ toggle()
+ }
+ }
+}
diff --git a/components/CheckBox2.qml b/components/CheckBox2.qml
new file mode 100644
index 0000000..3764b99
--- /dev/null
+++ b/components/CheckBox2.qml
@@ -0,0 +1,110 @@
+// Copyright (c) 2014-2024, 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 QtGraphicalEffects 1.0
+import FontAwesome 1.0
+
+import "." 1.0
+import "." as MoneroComponents
+import "effects/" as MoneroEffects
+
+RowLayout {
+ id: checkBox
+ property alias text: label.text
+ property bool checked: false
+ property int fontSize: 14
+ property alias fontColor: label.color
+ property int textMargin: 8
+ signal clicked()
+ height: 25
+
+ function toggle(){
+ checkBox.checked = !checkBox.checked
+ checkBox.clicked()
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+
+ Rectangle{
+ height: label.height
+ width: (label.width + indicatorRect.width + checkBox.textMargin)
+ color: "transparent"
+
+ MoneroComponents.TextPlain {
+ id: label
+ font.family: Style.fontLight.name
+ font.pixelSize: checkBox.fontSize
+ color: Style.defaultFontColor
+ wrapMode: Text.Wrap
+ Layout.fillWidth: true
+ anchors.left: parent.left
+ }
+
+ Rectangle {
+ id: indicatorRect
+ width: indicatorImage.width
+ height: label.height
+ anchors.left: label.right
+ anchors.leftMargin: textMargin
+ color: "transparent"
+ rotation: checkBox.checked ? 180 : 0
+
+ MoneroEffects.ImageMask {
+ id: indicatorImage
+ anchors.centerIn: parent
+ width: 12
+ height: 8
+ image: "qrc:///images/whiteDropIndicator.png"
+ color: MoneroComponents.Style.defaultFontColor
+ opacity: MoneroComponents.Style.blackTheme ? 1 : 0.75
+ fontAwesomeFallbackIcon: FontAwesome.arrowDown
+ fontAwesomeFallbackSize: 14
+
+ MoneroEffects.ColorTransition {
+ targetObj: indicatorImage
+ blackColor: "white"
+ whiteColor: "black"
+ duration: 500
+ }
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ toggle();
+ }
+ }
+ }
+ }
+}
diff --git a/components/ContextMenu.qml b/components/ContextMenu.qml
new file mode 100644
index 0000000..efbd38a
--- /dev/null
+++ b/components/ContextMenu.qml
@@ -0,0 +1,78 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+
+import FontAwesome 1.0
+import "../components" as MoneroComponents
+
+MouseArea {
+ signal cut()
+ signal copy()
+ signal paste()
+ signal remove()
+ signal selectAll()
+
+ id: root
+ acceptedButtons: Qt.RightButton
+ anchors.fill: parent
+ onClicked: {
+ if (mouse.button === Qt.RightButton) {
+ root.parent.persistentSelection = true;
+ contextMenu.open()
+ root.parent.cursorVisible = true;
+ }
+ }
+
+ Menu {
+ id: contextMenu
+
+ background: Rectangle {
+ border.color: MoneroComponents.Style.buttonBackgroundColorDisabledHover
+ border.width: 1
+ radius: 2
+ color: MoneroComponents.Style.blackTheme ? MoneroComponents.Style.buttonBackgroundColorDisabled : "#E5E5E5"
+ }
+
+ padding: 1
+ width: 110
+ x: root.mouseX
+ y: root.mouseY
+
+ onClosed: {
+ if (!root.parent.activeFocus) {
+ root.parent.cursorVisible = false;
+ }
+ root.parent.persistentSelection = false;
+ root.parent.forceActiveFocus()
+ }
+
+ MoneroComponents.ContextMenuItem {
+ enabled: root.parent.selectedText != "" && !root.parent.readOnly
+ onTriggered: root.cut()
+ text: qsTr("Cut") + translationManager.emptyString
+ }
+
+ MoneroComponents.ContextMenuItem {
+ enabled: root.parent.selectedText != ""
+ onTriggered: root.copy()
+ text: qsTr("Copy") + translationManager.emptyString
+ }
+
+ MoneroComponents.ContextMenuItem {
+ enabled: root.parent.canPaste === true
+ onTriggered: root.paste()
+ text: qsTr("Paste") + translationManager.emptyString
+ }
+
+ MoneroComponents.ContextMenuItem {
+ enabled: root.parent.selectedText != "" && !root.parent.readOnly
+ onTriggered: root.remove()
+ text: qsTr("Delete") + translationManager.emptyString
+ }
+
+ MoneroComponents.ContextMenuItem {
+ enabled: root.parent.text != ""
+ onTriggered: root.selectAll()
+ text: qsTr("Select All") + translationManager.emptyString
+ }
+ }
+}
diff --git a/components/ContextMenuItem.qml b/components/ContextMenuItem.qml
new file mode 100644
index 0000000..c4e0f39
--- /dev/null
+++ b/components/ContextMenuItem.qml
@@ -0,0 +1,62 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.1
+
+import FontAwesome 1.0
+import "../components" as MoneroComponents
+
+MenuItem {
+ id: menuItem
+
+ property bool glyphIconSolid: true
+ property alias glyphIcon: glyphIcon.text
+
+ background: Rectangle {
+ color: MoneroComponents.Style.buttonBackgroundColorDisabledHover
+ opacity: 0
+
+ MouseArea {
+ id: mouse
+
+ anchors.fill: parent
+ hoverEnabled: true
+ onEntered: {
+ parent.opacity = 1;
+ }
+ onExited: {
+ parent.opacity = 0;
+ }
+ onClicked: {
+ if (menuItem.enabled) {
+ menuItem.triggered();
+ parent.opacity = 0;
+ }
+ }
+ }
+ }
+
+ contentItem: RowLayout {
+ anchors.fill: parent
+ anchors.leftMargin: 20
+ anchors.rightMargin: 10
+ opacity: menuItem.enabled ? 1 : 0.4
+ spacing: 8
+
+ Text {
+ id: glyphIcon
+
+ color: MoneroComponents.Style.buttonTextColor
+ font.family: glyphIconSolid ? FontAwesome.fontFamilySolid : FontAwesome.fontFamily
+ font.pixelSize: 14
+ font.styleName: glyphIconSolid ? "Solid" : "Regular"
+ }
+
+ Text {
+ color: MoneroComponents.Style.blackTheme ? MoneroComponents.Style.buttonTextColor : MoneroComponents.Style.defaultFontColor
+ font.family: MoneroComponents.Style.fontRegular.name
+ font.pixelSize: 14
+ Layout.fillWidth: true
+ text: menuItem.text
+ }
+ }
+}
diff --git a/components/DaemonManagerDialog.qml b/components/DaemonManagerDialog.qml
new file mode 100644
index 0000000..89e59f8
--- /dev/null
+++ b/components/DaemonManagerDialog.qml
@@ -0,0 +1,150 @@
+// Copyright (c) 2014-2024, 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.Dialogs 1.2
+import QtQuick.Layouts 1.1
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Window 2.0
+import moneroComponents.Wallet 1.0
+
+import "../components" as MoneroComponents
+
+Window {
+ id: root
+ modality: Qt.ApplicationModal
+ flags: Qt.Window | Qt.FramelessWindowHint
+ property int countDown: 10;
+ signal rejected()
+ signal started();
+
+ function open() {
+ countDown = 10;
+ timer.restart();
+ }
+
+ // TODO: implement without hardcoding sizes
+ width: 480
+ height: 200
+ color: MoneroComponents.Style.middlePanelBackgroundColor
+
+ // Make window draggable
+ MouseArea {
+ anchors.fill: parent
+ property point lastMousePos: Qt.point(0, 0)
+ onPressed: { lastMousePos = Qt.point(mouseX, mouseY); }
+ onMouseXChanged: root.x += (mouseX - lastMousePos.x)
+ onMouseYChanged: root.y += (mouseY - lastMousePos.y)
+ }
+
+ ColumnLayout {
+ id: mainLayout
+ spacing: 10
+ anchors { fill: parent; margins: 35 }
+
+ ColumnLayout {
+ id: column
+ //anchors {fill: parent; margins: 16 }
+ Layout.alignment: Qt.AlignHCenter
+
+ Timer {
+ id: timer
+ interval: 1000;
+ running: false;
+ repeat: true
+ onTriggered: {
+ if (currentWallet.connected() == Wallet.ConnectionStatus_Connected) {
+ timer.stop();
+ root.close();
+ return;
+ }
+
+ if (!root.visible) {
+ root.show();
+ }
+
+ countDown--;
+ if (countDown < 0) {
+ timer.stop();
+ // Start daemon
+ root.close()
+ appWindow.startDaemon(persistentSettings.daemonFlags);
+ root.started();
+ }
+ }
+ }
+
+ MoneroComponents.TextPlain {
+ text: qsTr("Starting local node in %1 seconds").arg(countDown) + translationManager.emptyString;
+ font.pixelSize: 18
+ Layout.alignment: Qt.AlignHCenter
+ Layout.fillWidth: true
+ horizontalAlignment: Text.AlignHCenter
+ themeTransition: false
+ color: MoneroComponents.Style.defaultFontColor
+ }
+
+ }
+
+ RowLayout {
+ id: buttons
+ spacing: 60
+ Layout.alignment: Qt.AlignHCenter
+
+ MoneroComponents.StandardButton {
+ id: okButton
+ visible:false
+ fontSize: 14
+ text: qsTr("Start daemon (%1)").arg(countDown) + translationManager.emptyString
+ KeyNavigation.tab: cancelButton
+ onClicked: {
+ timer.stop();
+ root.close()
+ appWindow.startDaemon(persistentSettings.daemonFlags);
+ root.started()
+ }
+ }
+
+ MoneroComponents.StandardButton {
+ id: cancelButton
+ fontSize: 14
+ text: qsTr("Use custom settings") + translationManager.emptyString
+
+ onClicked: {
+ timer.stop();
+ root.close()
+ root.rejected()
+ }
+ }
+ }
+ }
+}
+
+
+
diff --git a/components/DatePicker.qml b/components/DatePicker.qml
new file mode 100644
index 0000000..a9eba5f
--- /dev/null
+++ b/components/DatePicker.qml
@@ -0,0 +1,465 @@
+// Copyright (c) 2014-2024, 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.2
+import QtQuick.Controls 2.2 as QtQuickControls2
+import QtQuick.Layouts 1.2
+import QtGraphicalEffects 1.0
+import QtQuick.Controls.Styles 1.2
+import FontAwesome 1.0
+
+import "." as MoneroComponents
+import "effects/" as MoneroEffects
+
+Item {
+ id: datePicker
+ readonly property alias expanded: popup.visible
+ property date currentDate
+ property bool showCurrentDate: true
+ property color backgroundColor : MoneroComponents.Style.appWindowBorderColor
+ property color errorColor : "red"
+ property bool error: false
+ property alias inputLabel: inputLabel
+
+ signal dateChanged();
+
+ height: 50
+
+ onExpandedChanged: if(expanded) appWindow.currentItem = datePicker
+
+ Rectangle {
+ id: inputLabelRect
+ color: "transparent"
+ height: 22
+ width: parent.width
+
+ MoneroComponents.TextPlain {
+ id: inputLabel
+ anchors.top: parent.top
+ anchors.topMargin: 2
+ anchors.left: parent.left
+ font.family: MoneroComponents.Style.fontLight.name
+ font.pixelSize: 14
+ font.bold: false
+ textFormat: Text.RichText
+ color: MoneroComponents.Style.defaultFontColor
+ themeTransition: false
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.NoButton
+ cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
+ }
+ }
+ }
+
+ Item {
+ id: head
+ anchors.top: inputLabelRect.bottom
+ anchors.topMargin: 6
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: 28
+
+ Rectangle {
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: parent.height - 1
+ anchors.leftMargin: 0
+ anchors.rightMargin: 0
+ radius: 4
+ y: 1
+ color: datePicker.backgroundColor
+ }
+
+ RowLayout {
+ id: dateInput
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.leftMargin: 2
+ anchors.right: parent.right
+ property string headerFontColor: MoneroComponents.Style.blackTheme ? "#e6e6e6" : "#333333"
+ spacing: 0
+
+ function setDate(date) {
+ var day = date.getDate()
+ var month = date.getMonth() + 1
+ dayInput.text = day < 10 ? "0" + day : day
+ monthInput.text = month < 10 ? "0" + month : month
+ yearInput.text = date.getFullYear()
+ }
+
+ Connections {
+ target: datePicker
+ function onCurrentDateChanged() {
+ dateInput.setDate(datePicker.currentDate)
+ }
+ }
+
+ TextInput {
+ id: dayInput
+ readOnly: true
+ Layout.preferredWidth: childrenRect.width + 40
+ font.family: MoneroComponents.Style.fontRegular.name
+ font.pixelSize: 14
+ color: datePicker.error ? errorColor : parent.headerFontColor
+ selectionColor: MoneroComponents.Style.dimmedFontColor
+ selectByMouse: true
+ horizontalAlignment: TextInput.AlignHCenter
+ maximumLength: 2
+ validator: IntValidator{bottom: 01; top: 31;}
+ KeyNavigation.tab: monthInput
+
+ text: {
+ if(datePicker.showCurrentDate) {
+ var day = datePicker.currentDate.getDate()
+ return day < 10 ? "0" + day : day
+ }
+ }
+ onFocusChanged: {
+ if(focus === false) {
+ if(text.length === 0 || text === "0" || text === "00") text = "01"
+ else if(text.length === 1) text = "0" + text
+ }
+ }
+ }
+
+ MoneroComponents.TextPlain {
+ font.family: MoneroComponents.Style.fontRegular.name
+ font.pixelSize: 14
+ color: datePicker.error ? errorColor : MoneroComponents.Style.defaultFontColor
+ text: "-"
+ themeTransition: false
+ }
+
+ TextInput {
+ id: monthInput
+ readOnly: true
+ Layout.preferredWidth: childrenRect.width + 40
+ font.family: MoneroComponents.Style.fontRegular.name
+ font.pixelSize: 14
+ color: datePicker.error ? errorColor : parent.headerFontColor
+ selectionColor: MoneroComponents.Style.dimmedFontColor
+ selectByMouse: true
+ horizontalAlignment: TextInput.AlignHCenter
+ maximumLength: 2
+ validator: IntValidator{bottom: 01; top: 12;}
+ KeyNavigation.tab: yearInput
+ text: {
+ if(datePicker.showCurrentDate) {
+ var month = datePicker.currentDate.getMonth() + 1
+ return month < 10 ? "0" + month : month
+ }
+ }
+ onFocusChanged: {
+ if(focus === false) {
+ if(text.length === 0 || text === "0" || text === "00") text = "01"
+ else if(text.length === 1) text = "0" + text
+ }
+ }
+ }
+
+ MoneroComponents.TextPlain {
+ font.family: MoneroComponents.Style.fontRegular.name
+ font.pixelSize: 14
+ color: datePicker.error ? errorColor : MoneroComponents.Style.defaultFontColor
+ text: "-"
+ themeTransition: false
+ }
+
+ TextInput {
+ id: yearInput
+ Layout.preferredWidth: childrenRect.width + 60
+ font.family: MoneroComponents.Style.fontRegular.name
+ font.pixelSize: 14
+ color: datePicker.error ? errorColor : parent.headerFontColor
+ selectionColor: MoneroComponents.Style.dimmedFontColor
+ selectByMouse: true
+ horizontalAlignment: TextInput.AlignHCenter
+ maximumLength: 4
+ validator: IntValidator{bottom: 1000; top: 9999;}
+ text: if(datePicker.showCurrentDate) datePicker.currentDate.getFullYear()
+
+ onFocusChanged: {
+ if(focus === false) {
+ var d = new Date()
+ var y = d.getFullYear()
+ if(text.length != 4 || text[0] === "0")
+ text = y
+ }
+ }
+ }
+
+ Rectangle {
+ Layout.preferredHeight: parent.height
+ Layout.fillWidth: true
+ color: "transparent"
+
+ MoneroEffects.ImageMask {
+ id: button
+ anchors.right: parent.right
+ anchors.rightMargin: 10
+ anchors.verticalCenter: parent.verticalCenter
+ image: "qrc:///images/whiteDropIndicator.png"
+ height: 8
+ width: 12
+ fontAwesomeFallbackIcon: FontAwesome.arrowDown
+ fontAwesomeFallbackSize: 14
+ color: MoneroComponents.Style.defaultFontColor
+ rotation: datePicker.expanded ? 180 : 0
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: datePicker.expanded ? popup.close() : popup.open()
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ }
+ }
+ }
+ }
+
+ QtQuickControls2.Popup {
+ id: popup
+ padding: 0
+ closePolicy: QtQuickControls2.Popup.CloseOnEscape | QtQuickControls2.Popup.CloseOnPressOutsideParent
+ onOpened: {
+ calendar.visibleMonth = currentDate.getMonth();
+ calendar.visibleYear = currentDate.getFullYear();
+ }
+
+ Rectangle {
+ id: calendarRect
+ width: head.width
+ x: head.x
+ y: head.y + head.height - 2
+
+ color: MoneroComponents.Style.middlePanelBackgroundColor
+ border.width: 1
+ border.color: MoneroComponents.Style.appWindowBorderColor
+ height: datePicker.expanded ? calendar.height + 2 : 0
+ clip: true
+
+ Behavior on height {
+ NumberAnimation { duration: 150; easing.type: Easing.InQuad }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ scrollGestureEnabled: false
+ onWheel: {
+ if (wheel.angleDelta.y > 0) return calendar.showPreviousMonth();
+ if (wheel.angleDelta.y < 0) return calendar.showNextMonth();
+ }
+ }
+
+ Rectangle {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 1
+ anchors.rightMargin: 1
+ anchors.top: parent.top
+ color: MoneroComponents.Style.appWindowBorderColor
+ height: 1
+ }
+
+ Calendar {
+ id: calendar
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.margins: 1
+ anchors.bottomMargin: 10
+ height: 220
+ frameVisible: false
+
+ style: CalendarStyle {
+ gridVisible: false
+ background: Rectangle { color: MoneroComponents.Style.middlePanelBackgroundColor }
+ dayDelegate: Item {
+ z: parent.z + 1
+ implicitHeight: implicitWidth
+ implicitWidth: calendar.width / 7
+
+ Rectangle {
+ id: dayRect
+ anchors.fill: parent
+ radius: parent.implicitHeight / 2
+ }
+
+ MoneroComponents.TextPlain {
+ id: dayText
+ anchors.centerIn: parent
+ font.family: MoneroComponents.Style.fontMonoRegular.name
+ font.pixelSize: {
+ if(!styleData.visibleMonth) return 12
+ return 14
+ }
+ font.bold: {
+ if(dayArea.pressed || styleData.visibleMonth) return true;
+ return false;
+ }
+ text: styleData.date.getDate()
+ themeTransition: false
+ color: {
+ if (currentDate.toDateString() === styleData.date.toDateString()) {
+ if (dayArea.containsMouse) {
+ dayRect.color = MoneroComponents.Style.buttonBackgroundColorHover;
+ } else {
+ dayRect.color = MoneroComponents.Style.buttonBackgroundColor;
+ }
+ } else {
+ if (dayArea.containsMouse) {
+ dayRect.color = MoneroComponents.Style.blackTheme ? "#20FFFFFF" : "#10000000"
+ } else {
+ dayRect.color = "transparent";
+ }
+ }
+ if(!styleData.valid) return "transparent"
+ if(styleData.date.toDateString() === (new Date()).toDateString()) return "#FFFF00"
+ if(!styleData.visibleMonth) return MoneroComponents.Style.lightGreyFontColor
+ if(dayArea.pressed) return MoneroComponents.Style.defaultFontColor
+ return MoneroComponents.Style.defaultFontColor
+ }
+ }
+
+ MouseArea {
+ id: dayArea
+ anchors.fill: parent
+ visible: styleData.valid
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ if(styleData.visibleMonth) {
+ currentDate = styleData.date
+ popup.close()
+ } else {
+ var date = styleData.date
+ if(date.getMonth() > calendar.visibleMonth)
+ calendar.showNextMonth()
+ else calendar.showPreviousMonth()
+ }
+
+ datePicker.dateChanged();
+ }
+ }
+ }
+
+ dayOfWeekDelegate: Item {
+ implicitHeight: 20
+ implicitWidth: calendar.width / 7
+
+ MoneroComponents.TextPlain {
+ anchors.centerIn: parent
+ elide: Text.ElideRight
+ font.family: MoneroComponents.Style.fontMonoRegular.name
+ font.pixelSize: 12
+ color: MoneroComponents.Style.lightGreyFontColor
+ themeTransition: false
+ text: {
+ var locale = Qt.locale()
+ return locale.dayName(styleData.dayOfWeek, Locale.ShortFormat)
+ }
+ }
+ }
+
+ navigationBar: Rectangle {
+ color: MoneroComponents.Style.middlePanelBackgroundColor
+ implicitWidth: calendar.width
+ implicitHeight: 30
+
+ MoneroComponents.TextPlain {
+ anchors.centerIn: parent
+ font.family: MoneroComponents.Style.fontMonoRegular.name
+ font.pixelSize: 14
+ color: MoneroComponents.Style.dimmedFontColor
+ themeTransition: false
+ text: styleData.title
+ }
+
+
+ Item {
+ anchors.left: parent.left
+ anchors.leftMargin: 4
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ width: height
+
+ MoneroEffects.ImageMask {
+ id: prevMonthIcon
+ anchors.centerIn: parent
+ image: "qrc:///images/prevMonth.png"
+ height: 8
+ width: 12
+ fontAwesomeFallbackIcon: FontAwesome.arrowLeft
+ fontAwesomeFallbackSize: 14
+ color: MoneroComponents.Style.defaultFontColor
+ }
+
+ MouseArea {
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ anchors.fill: parent
+ onClicked: calendar.showPreviousMonth()
+ }
+ }
+
+ Item {
+ anchors.right: parent.right
+ anchors.rightMargin: 4
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ width: height
+
+ MoneroEffects.ImageMask {
+ id: nextMonthIcon
+ anchors.centerIn: parent
+ image: "qrc:///images/prevMonth.png"
+ height: 8
+ width: 12
+ rotation: 180
+ fontAwesomeFallbackIcon: FontAwesome.arrowLeft
+ fontAwesomeFallbackSize: 14
+ color: MoneroComponents.Style.defaultFontColor
+ }
+
+ MouseArea {
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ anchors.fill: parent
+ onClicked: calendar.showNextMonth()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/components/DevicePassphraseDialog.qml b/components/DevicePassphraseDialog.qml
new file mode 100644
index 0000000..75db398
--- /dev/null
+++ b/components/DevicePassphraseDialog.qml
@@ -0,0 +1,104 @@
+// Copyright (c) 2014-2024, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import QtQuick 2.9
+import "." as MoneroComponents
+
+Item {
+ id: root
+
+ property var onAcceptedCallback
+ property var onWalletEntryCallback
+ property var onRejectedCallback
+
+ function open(canEnterOnDevice_) {
+ var canEnterOnDevice = canEnterOnDevice_ !== null ? canEnterOnDevice_ : canEnterOnDevice
+ root.visible = true;
+
+ if (canEnterOnDevice) {
+ entryChooserDialog.okText = qsTr("Hardware wallet")
+ entryChooserDialog.cancelText = qsTr("Computer")
+ entryChooserDialog.open()
+ } else {
+ openPassphraseDialog()
+ }
+ }
+
+ function openPassphraseDialog() {
+ root.visible = true
+ passphraseDialog.openPassphraseDialog()
+ }
+
+ function close() {
+ root.visible = false;
+ if (entryChooserDialog.visible)
+ entryChooserDialog.close()
+ if (passphraseDialog.visible)
+ passphraseDialog.close()
+ }
+
+ StandardDialog {
+ id: entryChooserDialog
+ title: qsTr("Hardware wallet passphrase") + translationManager.emptyString
+ text: qsTr("Please select where you want to enter passphrase.\nIt is recommended to enter passphrase on the hardware wallet for better security.") + translationManager.emptyString
+
+ onAccepted: {
+ if (onWalletEntryCallback){
+ onWalletEntryCallback()
+ }
+ }
+
+ onRejected: {
+ openPassphraseDialog()
+ }
+
+ onCloseCallback: {
+ root.close()
+ }
+ }
+
+ PasswordDialog {
+ id: passphraseDialog
+ anchors.fill: parent
+ passphraseDialogMode: true
+
+ onAcceptedPassphrase: {
+ if (onAcceptedCallback)
+ onAcceptedCallback(passphraseDialog.password);
+ }
+
+ onRejectedPassphrase: {
+ if (onRejectedCallback)
+ onRejectedCallback();
+ }
+
+ onCloseCallback: {
+ root.close()
+ }
+ }
+}
diff --git a/components/Dialog.qml b/components/Dialog.qml
new file mode 100644
index 0000000..0cd712f
--- /dev/null
+++ b/components/Dialog.qml
@@ -0,0 +1,66 @@
+// Copyright (c) 2021-2024, 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 != ""
+ }
+ }
+}
diff --git a/components/IconButton.qml b/components/IconButton.qml
new file mode 100644
index 0000000..334f0da
--- /dev/null
+++ b/components/IconButton.qml
@@ -0,0 +1,67 @@
+// Copyright (c) 2014-2024, 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 "../components" as MoneroComponents
+import "../components/effects" as MoneroEffects
+
+MoneroEffects.ImageMask {
+ id: button
+ z: 666
+ color: MoneroComponents.Style.defaultFontColor
+ image: ""
+
+ property alias tooltip: tooltip.text
+ signal clicked(var mouse)
+
+ MoneroComponents.Tooltip {
+ id: tooltip
+ anchors.fill: parent
+ tooltipLeft: true
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+
+ onEntered: {
+ tooltip.text ? tooltip.tooltipPopup.open() : ""
+ button.width = button.width + 2
+ button.height = button.height + 2
+ }
+
+ onExited: {
+ tooltip.text ? tooltip.tooltipPopup.close() : ""
+ button.width = button.width - 2
+ button.height = button.height - 2
+ }
+
+ onClicked: button.clicked(mouse)
+ }
+}
diff --git a/components/InlineButton.qml b/components/InlineButton.qml
new file mode 100644
index 0000000..3fd7553
--- /dev/null
+++ b/components/InlineButton.qml
@@ -0,0 +1,127 @@
+// Copyright (c) 2014-2024, 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 QtGraphicalEffects 1.0
+
+import FontAwesome 1.0
+
+import "." as MoneroComponents
+import "./effects/" as MoneroEffects
+
+Item {
+ id: inlineButton
+
+ property bool small: false
+ property string textColor: MoneroComponents.Style.inlineButtonTextColor
+ property alias text: inlineText.text
+ property alias fontPixelSize: inlineText.font.pixelSize
+ property alias fontFamily: inlineText.font.family
+ property alias fontStyleName: inlineText.font.styleName
+ property bool isFontAwesomeIcon: fontFamily == FontAwesome.fontFamily || fontFamily == FontAwesome.fontFamilySolid
+ property alias buttonColor: rect.color
+ property alias tooltip: tooltip.text
+ property alias tooltipLeft: tooltip.tooltipLeft
+ property alias tooltipBottom: tooltip.tooltipBottom
+
+ height: isFontAwesomeIcon ? 30 : 24
+ width: isFontAwesomeIcon ? height : inlineText.width + 16
+
+ signal clicked()
+
+ function doClick() {
+ // Android workaround
+ releaseFocus();
+ clicked();
+ }
+
+ Rectangle{
+ id: rect
+ anchors.fill: parent
+ color: buttonArea.containsMouse ? MoneroComponents.Style.buttonInlineBackgroundColorHover : MoneroComponents.Style.buttonInlineBackgroundColor
+ radius: 4
+ border.width: parent.focus && parent.enabled ? 1 : 0
+
+ MoneroComponents.TextPlain {
+ id: inlineText
+ font.family: MoneroComponents.Style.fontBold.name
+ font.bold: true
+ font.pixelSize: inlineButton.isFontAwesomeIcon ? 22 : inlineButton.small ? 14 : 16
+ color: inlineButton.textColor
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ themeTransition: false
+
+ MoneroEffects.ColorTransition {
+ targetObj: inlineText
+ blackColor: MoneroComponents.Style._b_inlineButtonTextColor
+ whiteColor: MoneroComponents.Style._w_inlineButtonTextColor
+ }
+ }
+
+ MoneroComponents.Tooltip {
+ id: tooltip
+ anchors.fill: parent
+ }
+
+ MouseArea {
+ id: buttonArea
+ cursorShape: rect.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
+ hoverEnabled: true
+ anchors.fill: parent
+ onClicked: {
+ tooltip.text ? tooltip.tooltipPopup.close() : ""
+ doClick()
+ }
+ onEntered: {
+ tooltip.text ? tooltip.tooltipPopup.open() : ""
+ }
+ onExited: {
+ tooltip.text ? tooltip.tooltipPopup.close() : ""
+ }
+ }
+ }
+
+ DropShadow {
+ visible: !MoneroComponents.Style.blackTheme
+ anchors.fill: rect
+ horizontalOffset: 2
+ verticalOffset: 2
+ radius: 7.0
+ samples: 10
+ color: "#1B000000"
+ cached: true
+ source: rect
+ }
+
+ Keys.enabled: inlineButton.visible
+ Keys.onSpacePressed: doClick()
+ Keys.onEnterPressed: Keys.onReturnPressed(event)
+ Keys.onReturnPressed: doClick()
+}
diff --git a/components/Input.qml b/components/Input.qml
new file mode 100644
index 0000000..3fb83af
--- /dev/null
+++ b/components/Input.qml
@@ -0,0 +1,63 @@
+// Copyright (c) 2014-2024, 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.Controls 2.0
+import QtQuick 2.9
+
+import "../components" as MoneroComponents
+
+TextField {
+ id: textField
+ font.family: MoneroComponents.Style.fontRegular.name
+ font.pixelSize: 18
+ font.bold: true
+ horizontalAlignment: TextInput.AlignLeft
+ selectByMouse: true
+ color: MoneroComponents.Style.defaultFontColor
+ selectionColor: MoneroComponents.Style.textSelectionColor
+ selectedTextColor: MoneroComponents.Style.textSelectedColor
+
+ background: Rectangle {
+ color: "transparent"
+ }
+
+ MoneroComponents.ContextMenu {
+ cursorShape: Qt.IBeamCursor
+ onCut: textField.cut();
+ onCopy: textField.copy();
+ onPaste: {
+ var previoustextFieldLength = textField.length
+ var previousCursorPosition = textField.cursorPosition;
+ textField.paste();
+ textField.forceActiveFocus()
+ textField.cursorPosition = previousCursorPosition + (textField.length - previoustextFieldLength);
+ }
+ onRemove: textField.remove(selectionStart, selectionEnd);
+ onSelectAll: textField.selectAll();
+ }
+}
diff --git a/components/InputDialog.qml b/components/InputDialog.qml
new file mode 100644
index 0000000..40e3e44
--- /dev/null
+++ b/components/InputDialog.qml
@@ -0,0 +1,158 @@
+// Copyright (c) 2014-2024, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import QtQuick 2.9
+import QtQuick.Controls 2.0
+import QtQuick.Dialogs 1.2
+import QtQuick.Layouts 1.1
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Window 2.0
+
+import "../components" as MoneroComponents
+
+Item {
+ id: root
+ visible: false
+ property alias labelText: label.text
+ property alias inputText: input.text
+
+ // same signals as Dialog has
+ signal accepted()
+ signal rejected()
+
+ function open(prepopulate) {
+ leftPanel.enabled = false
+ middlePanel.enabled = false
+ titleBar.state = "essentials"
+ root.visible = true;
+ input.focus = true;
+ input.text = prepopulate ? prepopulate : "";
+ }
+
+ function close() {
+ leftPanel.enabled = true
+ middlePanel.enabled = true
+ titleBar.state = "default"
+ root.visible = false;
+ }
+
+ ColumnLayout {
+ z: parent.z + 1
+ id: mainLayout
+ spacing: 10
+ anchors { fill: parent; margins: 35 }
+
+ ColumnLayout {
+ id: column
+
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignHCenter
+ Layout.maximumWidth: 400
+
+ Label {
+ id: label
+ Layout.fillWidth: true
+
+ font.pixelSize: 16
+ font.family: MoneroComponents.Style.fontLight.name
+
+ color: MoneroComponents.Style.defaultFontColor
+ }
+
+ MoneroComponents.Input {
+ id : input
+ focus: true
+ Layout.topMargin: 6
+ Layout.fillWidth: true
+ horizontalAlignment: TextInput.AlignLeft
+ verticalAlignment: TextInput.AlignVCenter
+ font.family: MoneroComponents.Style.fontLight.name
+ font.pixelSize: 24
+ KeyNavigation.tab: okButton
+ bottomPadding: 10
+ leftPadding: 10
+ topPadding: 10
+ color: MoneroComponents.Style.defaultFontColor
+ selectionColor: MoneroComponents.Style.textSelectionColor
+ selectedTextColor: MoneroComponents.Style.textSelectedColor
+
+ background: Rectangle {
+ radius: 2
+ border.color: MoneroComponents.Style.inputBorderColorActive
+ border.width: 1
+ color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
+ }
+
+ Keys.enabled: root.visible
+ Keys.onEnterPressed: Keys.onReturnPressed(event)
+ Keys.onReturnPressed: {
+ root.close()
+ root.accepted()
+ }
+ Keys.onEscapePressed: {
+ root.close()
+ root.rejected()
+ }
+ }
+
+ // Ok/Cancel buttons
+ RowLayout {
+ id: buttons
+ spacing: 16
+ Layout.topMargin: 16
+ Layout.alignment: Qt.AlignRight
+
+ MoneroComponents.StandardButton {
+ id: cancelButton
+ primary: false
+ small: true
+ width: 120
+ fontSize: 14
+ text: qsTr("Cancel") + translationManager.emptyString
+ KeyNavigation.tab: input
+ onClicked: {
+ root.close()
+ root.rejected()
+ }
+ }
+ MoneroComponents.StandardButton {
+ id: okButton
+ small: true
+ width: 120
+ fontSize: 14
+ text: qsTr("Ok") + translationManager.emptyString
+ KeyNavigation.tab: cancelButton
+ onClicked: {
+ root.close()
+ root.accepted()
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/components/InputMulti.qml b/components/InputMulti.qml
new file mode 100644
index 0000000..6f07dd3
--- /dev/null
+++ b/components/InputMulti.qml
@@ -0,0 +1,86 @@
+// Copyright (c) 2014-2024, 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.Controls 2.0
+import QtQuick 2.9
+
+import "../js/TxUtils.js" as TxUtils
+import "../components" as MoneroComponents
+
+TextArea {
+ property int fontSize: 18
+ property bool fontBold: false
+ property string fontColor: MoneroComponents.Style.defaultFontColor
+
+ property bool mouseSelection: true
+ property bool error: false
+ property bool addressValidation: false
+
+ id: textArea
+ font.family: MoneroComponents.Style.fontRegular.name
+ color: fontColor
+ font.pixelSize: fontSize
+ font.bold: fontBold
+ horizontalAlignment: TextInput.AlignLeft
+ selectByMouse: mouseSelection
+ selectionColor: MoneroComponents.Style.textSelectionColor
+ selectedTextColor: MoneroComponents.Style.textSelectedColor
+
+ property int minimumHeight: 100
+ height: contentHeight > minimumHeight ? contentHeight : minimumHeight
+
+ onTextChanged: {
+ if(addressValidation){
+ // js replacement for `RegExpValidator { regExp: /[0-9A-Fa-f]{95}/g }`
+ if (textArea.text.startsWith("monero:")) {
+ error = false;
+ return;
+ }
+ textArea.text = textArea.text.replace(/[^a-z0-9.@\-]/gi,'');
+ var address_ok = TxUtils.checkAddress(textArea.text, appWindow.persistentSettings.nettype) || TxUtils.isValidOpenAliasAddress(textArea.text);
+ if(!address_ok) error = true;
+ else error = false;
+ TextArea.cursorPosition = textArea.text.length;
+ }
+ }
+
+ MoneroComponents.ContextMenu {
+ cursorShape: Qt.IBeamCursor
+ onCut: textArea.cut();
+ onCopy: textArea.copy();
+ onPaste: {
+ var previoustextFieldLength = textArea.length
+ var previousCursorPosition = textArea.cursorPosition;
+ textArea.paste();
+ textArea.forceActiveFocus()
+ textArea.cursorPosition = previousCursorPosition + (textArea.length - previoustextFieldLength);
+ }
+ onRemove: textArea.remove(selectionStart, selectionEnd);
+ onSelectAll: textArea.selectAll();
+ }
+}
diff --git a/components/Label.qml b/components/Label.qml
new file mode 100644
index 0000000..2277811
--- /dev/null
+++ b/components/Label.qml
@@ -0,0 +1,85 @@
+// Copyright (c) 2014-2024, 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 "../components" as MoneroComponents
+
+Item {
+ id: item
+ property alias text: label.text
+ property alias tooltip: label.tooltip
+ property alias tooltipIconVisible: label.tooltipIconVisible
+ property alias color: label.color
+ property alias labelMouseArea: labelMouseArea
+ property int textFormat: Text.PlainText
+ property string tipText: ""
+ property int fontSize: 16
+ property bool fontBold: false
+ property string fontColor: MoneroComponents.Style.defaultFontColor
+ property string fontFamily: ""
+ property alias wrapMode: label.wrapMode
+ property alias horizontalAlignment: label.horizontalAlignment
+ property alias elide: label.elide
+ property alias textWidth: label.width
+ property alias styleName: label.font.styleName
+ property alias themeTransition: label.themeTransition
+ signal linkActivated()
+ height: label.height
+ width: label.width
+ Layout.topMargin: 10
+
+ MoneroComponents.TextPlain {
+ id: label
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 2
+ anchors.left: parent.left
+ font.family: {
+ if(fontFamily){
+ return fontFamily;
+ } else {
+ return MoneroComponents.Style.fontRegular.name;
+ }
+ }
+ font.pixelSize: fontSize
+ font.bold: fontBold
+ color: fontColor
+ onLinkActivated: item.linkActivated()
+ textFormat: parent.textFormat
+ MouseArea {
+ id: labelMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ acceptedButtons: Qt.NoButton
+ cursorShape: parent.hoveredLink || (tooltip && !tooltipIconVisible) ? Qt.PointingHandCursor : Qt.ArrowCursor
+ onEntered: tooltip && !tooltipIconVisible ? parent.tooltipPopup.open() : undefined
+ onExited: tooltip && !tooltipIconVisible ? parent.tooltipPopup.close() : undefined
+ }
+ }
+}
diff --git a/components/LabelButton.qml b/components/LabelButton.qml
new file mode 100644
index 0000000..b7a4065
--- /dev/null
+++ b/components/LabelButton.qml
@@ -0,0 +1,73 @@
+// Copyright (c) 2014-2024, 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 "../components" as MoneroComponents
+
+
+Rectangle {
+ signal clicked();
+ property alias text: labelButtonText.text
+
+ id: labelButton
+ color: MoneroComponents.Style.buttonBackgroundColorDisabled
+ radius: 3
+ height: 20
+ width: labelButtonText.width + 14
+ anchors.right: copyButton.left
+ anchors.rightMargin: 6
+
+ MoneroComponents.TextPlain {
+ id: labelButtonText
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.family: MoneroComponents.Style.fontRegular.name
+ font.pixelSize: 12
+ font.bold: true
+ text: ""
+ color: MoneroComponents.Style.inlineButtonTextColor
+ }
+
+ MouseArea {
+ cursorShape: Qt.PointingHandCursor
+ anchors.fill: parent
+ hoverEnabled: true
+ onClicked: labelButton.clicked()
+ onEntered: {
+ labelButton.color = MoneroComponents.Style.buttonBackgroundColorDisabledHover;
+ labelButtonText.opacity = 0.8;
+ }
+ onExited: {
+ labelButton.color = MoneroComponents.Style.buttonBackgroundColorDisabled;
+ labelButtonText.opacity = 1.0;
+ }
+ }
+}
+
diff --git a/components/LabelSubheader.qml b/components/LabelSubheader.qml
new file mode 100644
index 0000000..a7432c5
--- /dev/null
+++ b/components/LabelSubheader.qml
@@ -0,0 +1,53 @@
+// Copyright (c) 2014-2024, 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 "../components" as MoneroComponents
+import "../components/effects/" as MoneroEffects
+
+Label {
+ id: item
+ fontSize: 18
+ tooltipIconVisible: true
+
+ Rectangle {
+ anchors.top: item.bottom
+ anchors.topMargin: 4
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: 2
+ color: MoneroComponents.Style.appWindowBorderColor
+
+ MoneroEffects.ColorTransition {
+ targetObj: parent
+ blackColor: MoneroComponents.Style._b_appWindowBorderColor
+ whiteColor: MoneroComponents.Style._w_appWindowBorderColor
+ }
+ }
+}
diff --git a/components/LanguageButton.qml b/components/LanguageButton.qml
new file mode 100644
index 0000000..aa33ea8
--- /dev/null
+++ b/components/LanguageButton.qml
@@ -0,0 +1,67 @@
+// Copyright (c) 2020-2024, 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()
+ }
+}
diff --git a/components/LanguageSidebar.qml b/components/LanguageSidebar.qml
new file mode 100644
index 0000000..20712a9
--- /dev/null
+++ b/components/LanguageSidebar.qml
@@ -0,0 +1,185 @@
+// Copyright (c) 2014-2024, 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 "../components" as MoneroComponents
+
+import QtQuick 2.9
+import QtQuick.Layouts 1.2
+import QtQuick.Controls 2.0
+import moneroComponents.LanguageModel 1.0
+
+
+Drawer {
+ id: sideBar
+
+ width: 240
+ height: parent.height - (persistentSettings.customDecorations ? 50 : 0)
+ y: titleBar.height
+
+ background: Rectangle {
+ color: MoneroComponents.Style.blackTheme ? "#0d0d0d" : "white"
+ width: parent.width
+ }
+
+ Rectangle {
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ color: "red"
+
+ ListView {
+ id: languagesListView
+ clip: true
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ boundsBehavior: Flickable.StopAtBounds
+ width: sideBar.width
+ height: sideBar.height
+ focus: true
+
+ model: langModel
+
+ Keys.onUpPressed: currentIndex !== 0 ? currentIndex = currentIndex - 1 : ""
+ Keys.onBacktabPressed: currentIndex !== 0 ? currentIndex = currentIndex - 1 : ""
+ Keys.onDownPressed: currentIndex + 1 !== count ? currentIndex = currentIndex + 1 : ""
+ Keys.onTabPressed: currentIndex + 1 !== count ? currentIndex = currentIndex + 1 : ""
+
+ delegate: Rectangle {
+ id: item
+ color: index == languagesListView.currentIndex ? MoneroComponents.Style.titleBarButtonHoverColor : "transparent"
+ width: sideBar.width
+ height: 32
+
+ Accessible.role: Accessible.ListItem
+ Accessible.name: display_name
+ Keys.onEnterPressed: setSelectedItemAsLanguage();
+ Keys.onReturnPressed: setSelectedItemAsLanguage();
+ Keys.onSpacePressed: setSelectedItemAsLanguage();
+
+ function setSelectedItemAsLanguage() {
+ var locale_spl = locale.split("_");
+
+ // reload active translations
+ console.log(locale_spl[0]);
+ translationManager.setLanguage(locale_spl[0]);
+
+ // set wizard language settings
+ persistentSettings.locale = locale;
+ persistentSettings.language = display_name;
+ persistentSettings.language_wallet = wallet_language;
+
+ appWindow.showStatusMessage(qsTr("Language changed."), 3);
+ appWindow.toggleLanguageView();
+ }
+
+ Rectangle {
+ id: selectedIndicator
+ anchors.left: parent.left
+ anchors.leftMargin: 0
+ height: parent.height
+ width: 2
+ color: index == languagesListView.currentIndex ? MoneroComponents.Style.buttonBackgroundColor : "transparent"
+ }
+
+ Rectangle {
+ id: flagRect
+ height: 24
+ width: 24
+ anchors.left: selectedIndicator.right
+ anchors.leftMargin: 4
+ anchors.verticalCenter: parent.verticalCenter
+ color: "transparent"
+
+ Image {
+ anchors.fill: parent
+ source: flag
+ }
+ }
+
+ MoneroComponents.TextPlain {
+ anchors.left: parent.left
+ anchors.leftMargin: 32
+ font.bold: languagesListView.currentIndex == index ? true : false
+ font.pixelSize: 14
+ color: MoneroComponents.Style.defaultFontColor
+ text: display_name
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Rectangle {
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ color: MoneroComponents.Style.dividerColor
+ opacity: MoneroComponents.Style.dividerOpacity
+ height: 1
+ }
+
+ // button gradient while checked
+ Image {
+ anchors.fill: parent
+ source: "qrc:///images/menuButtonGradient.png"
+ opacity: 0.65
+ visible: true
+
+ MouseArea {
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ onClicked: setSelectedItemAsLanguage();
+ hoverEnabled: true
+ onEntered: {
+ // item.color = "#26FFFFFF"
+ parent.opacity = 1
+ }
+ onExited: {
+ // item.color = "transparent"
+ parent.opacity = 0.65
+ }
+ }
+ }
+ }
+
+ ScrollBar.vertical: ScrollBar {
+ onActiveChanged: if (!active && !isMac) active = true
+ }
+ }
+ }
+
+ //Flags model
+ LanguageModel {
+ id: langModel
+ }
+
+ function selectCurrentLanguage() {
+ for (var i = 0; i < langModel.count; ++i) {
+ if (langModel.get(i).display_name === persistentSettings.language) {
+ languagesListView.currentIndex = i;
+ }
+ }
+ }
+}
diff --git a/components/LineEdit.qml b/components/LineEdit.qml
new file mode 100644
index 0000000..0274103
--- /dev/null
+++ b/components/LineEdit.qml
@@ -0,0 +1,307 @@
+// Copyright (c) 2014-2024, 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 FontAwesome 1.0
+import QtQuick 2.9
+import QtGraphicalEffects 1.0
+import QtQuick.Layouts 1.1
+
+import "../components" as MoneroComponents
+
+ColumnLayout {
+ id: item
+ Layout.fillWidth: true
+
+ default property alias content: inlineButtons.children
+
+ property alias input: input
+ property bool inputHasFocus: input.activeFocus
+ property bool tabNavigationEnabled: true
+ property alias text: input.text
+
+ property int inputPaddingLeft: 10
+ property int inputPaddingRight: 10
+ property int inputPaddingTop: 10
+ property int inputPaddingBottom: 10
+ property int inputRadius: 4
+
+ property bool password: false
+ property bool passwordHidden: true
+ property var passwordLinked: null
+
+ property alias placeholderText: placeholderLabel.text
+ property bool placeholderCenter: false
+ property string placeholderFontFamily: MoneroComponents.Style.fontRegular.name
+ property bool placeholderFontBold: false
+ property int placeholderFontSize: 18
+ property string placeholderColor: MoneroComponents.Style.defaultFontColor
+ property real placeholderOpacity: 0.35
+ property real placeholderLeftMargin: {
+ if (placeholderCenter) {
+ return undefined;
+ } else {
+ return inputPaddingLeft;
+ }
+ }
+
+ property alias acceptableInput: input.acceptableInput
+ property alias validator: input.validator
+ property alias readOnly : input.readOnly
+ property alias cursorPosition: input.cursorPosition
+ property bool copyButton: false
+ property bool pasteButton: false
+ property alias copyButtonText: copyButtonId.text
+ property alias copyButtonEnabled: copyButtonId.enabled
+
+ property bool borderDisabled: false
+ property string borderColor: {
+ if ((error && input.text !== "") || (errorWhenEmpty && input.text == "")) {
+ return MoneroComponents.Style.inputBorderColorInvalid;
+ } else if (input.activeFocus) {
+ return MoneroComponents.Style.inputBorderColorActive;
+ } else {
+ return MoneroComponents.Style.inputBorderColorInActive;
+ }
+ }
+
+ property string fontFamily: MoneroComponents.Style.fontRegular.name
+ property int fontSize: 18
+ property bool fontBold: false
+ property alias fontColor: input.color
+ property bool error: false
+ property bool errorWhenEmpty: false
+ property alias labelText: inputLabel.text
+ property alias labelColor: inputLabel.color
+ property alias labelTextFormat: inputLabel.textFormat
+ property string backgroundColor: "transparent"
+ property string tipText: ""
+ property int labelFontSize: 16
+ property bool labelFontBold: false
+ property alias labelWrapMode: inputLabel.wrapMode
+ property alias labelHorizontalAlignment: inputLabel.horizontalAlignment
+ property bool showingHeader: inputLabel.text !== "" || copyButton
+ property int inputHeight: 39
+
+ signal labelLinkActivated(); // input label, rich text <a> signal
+ signal editingFinished();
+ signal accepted();
+ signal textUpdated();
+ signal backtabPressed();
+ signal tabPressed();
+
+ onActiveFocusChanged: activeFocus && input.forceActiveFocus()
+ onTextUpdated: {
+ // check to remove placeholder text when there is content
+ if(item.isEmpty()){
+ placeholderLabel.visible = true;
+ } else {
+ placeholderLabel.visible = false;
+ }
+ }
+
+ function isEmpty(){
+ var val = input.text;
+ if(val === "") {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ function isPasswordHidden() {
+ if (password) {
+ return passwordHidden;
+ }
+ if (passwordLinked) {
+ return passwordLinked.passwordHidden;
+ }
+ return false;
+ }
+
+ function reset() {
+ text = "";
+ if (!passwordLinked) {
+ passwordHidden = true;
+ }
+ }
+
+ function passwordToggle() {
+ if (passwordLinked) {
+ passwordLinked.passwordHidden = !passwordLinked.passwordHidden;
+ } else {
+ passwordHidden = !passwordHidden;
+ }
+ }
+
+ spacing: 0
+ Rectangle {
+ id: inputLabelRect
+ color: "transparent"
+ Layout.fillWidth: true
+ height: (inputLabel.height + 10)
+ visible: showingHeader ? true : false
+
+ MoneroComponents.TextPlain {
+ id: inputLabel
+ anchors.top: parent.top
+ anchors.left: parent.left
+ font.family: MoneroComponents.Style.fontRegular.name
+ font.pixelSize: labelFontSize
+ font.bold: labelFontBold
+ textFormat: Text.RichText
+ color: MoneroComponents.Style.defaultFontColor
+ onLinkActivated: item.labelLinkActivated()
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.NoButton
+ cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
+ }
+ }
+
+ RowLayout {
+ anchors.right: parent.right
+ spacing: 16
+
+ MoneroComponents.LabelButton {
+ id: copyButtonId
+ text: qsTr("Copy") + translationManager.emptyString
+ onClicked: {
+ if (input.text.length > 0) {
+ console.log("Copied to clipboard");
+ clipboard.setText(input.text);
+ appWindow.showStatusMessage(qsTr("Copied to clipboard"), 3);
+ }
+ }
+ visible: copyButton && input.text !== ""
+ }
+
+ MoneroComponents.LabelButton {
+ id: pasteButtonId
+ onClicked: {
+ input.clear();
+ input.paste();
+ }
+ text: qsTr("Paste") + translationManager.emptyString
+ visible: pasteButton
+ }
+ }
+ }
+
+ MoneroComponents.Input {
+ id: input
+ Keys.onBacktabPressed: {
+ item.backtabPressed();
+ if (item.KeyNavigation.backtab) {
+ item.KeyNavigation.backtab.forceActiveFocus()
+ }
+ }
+ Keys.onTabPressed: {
+ item.tabPressed();
+ if (item.KeyNavigation.tab) {
+ item.KeyNavigation.tab.forceActiveFocus()
+ }
+ }
+ Layout.fillWidth: true
+ Layout.preferredHeight: inputHeight
+
+ leftPadding: item.inputPaddingLeft
+ rightPadding: (inlineButtons.width > 0 ? inlineButtons.width + inlineButtons.spacing : 0) + inputPaddingRight + (password || passwordLinked ? 45 : 0)
+ topPadding: item.inputPaddingTop
+ bottomPadding: item.inputPaddingBottom
+
+ font.family: item.fontFamily
+ font.pixelSize: item.fontSize
+ font.bold: item.fontBold
+ onEditingFinished: item.editingFinished()
+ onAccepted: item.accepted();
+ onTextChanged: item.textUpdated()
+ echoMode: isPasswordHidden() ? TextInput.Password : TextInput.Normal
+
+ MoneroComponents.Label {
+ visible: password || passwordLinked
+ fontSize: 20
+ text: isPasswordHidden() ? FontAwesome.eye : FontAwesome.eyeSlash
+ opacity: eyeMouseArea.containsMouse ? 0.9 : 0.7
+ fontFamily: FontAwesome.fontFamily
+ anchors.right: parent.right
+ anchors.rightMargin: 15
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.verticalCenterOffset: 1
+
+ MouseArea {
+ id: eyeMouseArea
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ hoverEnabled: true
+ onClicked: passwordToggle()
+ }
+ }
+
+ MoneroComponents.TextPlain {
+ id: placeholderLabel
+ visible: input.text ? false : true
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.horizontalCenter: placeholderCenter ? parent.horizontalCenter : undefined
+ anchors.left: placeholderCenter ? undefined : parent.left
+ anchors.leftMargin: placeholderLeftMargin
+
+ opacity: item.placeholderOpacity
+ color: item.placeholderColor
+ font.family: item.placeholderFontFamily
+ font.pixelSize: placeholderFontSize
+ font.bold: item.placeholderFontBold
+ text: ""
+ z: 3
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ anchors.topMargin: 1
+ color: item.enabled ? "transparent" : MoneroComponents.Style.inputBoxBackgroundDisabled
+ }
+
+ Rectangle {
+ id: inputFill
+ color: backgroundColor
+ anchors.fill: parent
+ border.width: borderDisabled ? 0 : 1
+ border.color: borderColor
+ radius: item.inputRadius
+ }
+
+ RowLayout {
+ id: inlineButtons
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ anchors.rightMargin: inputPaddingRight
+ spacing: 4
+ }
+ }
+}
diff --git a/components/LineEditMulti.qml b/components/LineEditMulti.qml
new file mode 100644
index 0000000..d937b6d
--- /dev/null
+++ b/components/LineEditMulti.qml
@@ -0,0 +1,217 @@
+// Copyright (c) 2014-2024, 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 "../components" as MoneroComponents
+
+ColumnLayout {
+ id: item
+
+ Layout.fillWidth: true
+
+ default property alias content: inlineButtons.children
+
+ property alias text: input.text
+ property alias labelText: inputLabel.text
+ property alias labelButtonText: labelButton.text
+ property alias placeholderText: placeholderLabel.text
+
+ property int inputPaddingLeft: 10
+ property int inputPaddingRight: 10
+ property int inputPaddingTop: 10
+ property int inputPaddingBottom: 10
+ property int inputRadius: 4
+
+ property bool placeholderCenter: false
+ property string placeholderFontFamily: MoneroComponents.Style.fontRegular.name
+ property bool placeholderFontBold: false
+ property int placeholderFontSize: 18
+ property string placeholderColor: MoneroComponents.Style.defaultFontColor
+ property real placeholderOpacity: 0.35
+
+ property bool borderDisabled: false
+ property string borderColor: {
+ if(input.error && input.text !== ""){
+ return MoneroComponents.Style.inputBorderColorInvalid;
+ } else if(input.activeFocus){
+ return MoneroComponents.Style.inputBorderColorActive;
+ } else {
+ return MoneroComponents.Style.inputBorderColorInActive;
+ }
+ }
+
+ property alias error: input.error
+ property alias cursorPosition: input.cursorPosition
+
+ property string labelFontColor: MoneroComponents.Style.defaultFontColor
+ property bool labelFontBold: false
+ property int labelFontSize: 16
+ 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
+
+ property bool mouseSelection: true
+ property alias readOnly: input.readOnly
+ property bool copyButton: false
+ property bool pasteButton: false
+ property bool showingHeader: labelText != "" || copyButton || pasteButton
+ property var wrapMode: Text.NoWrap
+ property alias addressValidation: input.addressValidation
+ property string backgroundColor: "" // mock
+
+ signal labelButtonClicked();
+ signal inputLabelLinkActivated();
+ signal editingFinished();
+ signal returnPressed();
+ signal enterPressed();
+
+ onActiveFocusChanged: activeFocus && input.forceActiveFocus()
+
+ spacing: 0
+ Rectangle {
+ id: inputLabelRect
+ color: "transparent"
+ Layout.fillWidth: true
+ height: (inputLabel.height + 10)
+ visible: showingHeader ? true : false
+
+ MoneroComponents.TextPlain {
+ id: inputLabel
+ anchors.top: parent.top
+ anchors.left: parent.left
+ font.family: MoneroComponents.Style.fontRegular.name
+ font.pixelSize: item.labelFontSize
+ font.bold: labelFontBold
+ textFormat: Text.RichText
+ color: item.labelFontColor
+ onLinkActivated: inputLabelLinkActivated()
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.NoButton
+ cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
+ }
+ }
+
+ RowLayout {
+ anchors.right: parent.right
+ spacing: 16
+
+ MoneroComponents.LabelButton {
+ id: labelButton
+ onClicked: labelButtonClicked()
+ visible: labelButtonVisible
+ }
+
+ MoneroComponents.LabelButton {
+ id: copyButtonId
+ visible: copyButton && input.text !== ""
+ text: qsTr("Copy") + translationManager.emptyString
+ onClicked: {
+ if (input.text.length > 0) {
+ console.log("Copied to clipboard");
+ clipboard.setText(input.text);
+ appWindow.showStatusMessage(qsTr("Copied to clipboard"), 3);
+ }
+ }
+ }
+
+ MoneroComponents.LabelButton {
+ id: pasteButtonId
+ onClicked: {
+ input.clear();
+ input.paste();
+ }
+ text: qsTr("Paste") + translationManager.emptyString
+ visible: pasteButton
+ }
+ }
+ }
+
+ MoneroComponents.InputMulti {
+ 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: (inlineButtons.width > 0 ? inlineButtons.width + inlineButtons.spacing : 0) + inputPaddingRight
+ topPadding: item.inputPaddingTop
+ bottomPadding: item.inputPaddingBottom
+
+ wrapMode: item.wrapMode
+ font.family: item.fontFamily
+ fontSize: item.fontSize
+ fontBold: item.fontBold
+ fontColor: item.fontColor
+ mouseSelection: item.mouseSelection
+ onEditingFinished: item.editingFinished()
+ Keys.onReturnPressed: item.returnPressed()
+ Keys.onEnterPressed: item.enterPressed()
+
+ MoneroComponents.TextPlain {
+ id: placeholderLabel
+ visible: input.text ? false : true
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.leftMargin: 10
+ opacity: item.placeholderOpacity
+ color: item.placeholderColor
+ font.family: item.placeholderFontFamily
+ font.bold: item.placeholderFontBold
+ font.pixelSize: item.placeholderFontSize
+ text: ""
+ z: 3
+ }
+
+ Rectangle {
+ color: "transparent"
+ border.width: 1
+ border.color: item.borderColor
+ radius: item.inputRadius
+ anchors.fill: parent
+ visible: !item.borderDisabled
+ }
+
+ RowLayout {
+ id: inlineButtons
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ anchors.rightMargin: inputPaddingRight
+ spacing: 4
+ }
+ }
+}
diff --git a/components/MenuBar.qml b/components/MenuBar.qml
new file mode 100644
index 0000000..e605f01
--- /dev/null
+++ b/components/MenuBar.qml
@@ -0,0 +1,55 @@
+// Copyright (c) 2014-2024, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import Qt.labs.platform 1.0 as PlatformLabs
+import "." as MoneroComponents
+
+PlatformLabs.MenuBar {
+ PlatformLabs.Menu {
+ title: qsTr("File")
+ PlatformLabs.MenuItem {
+ enabled: appWindow.viewState === "normal"
+ text: qsTr("Close Wallet")
+ onTriggered: appWindow.showWizard()
+ }
+ }
+ PlatformLabs.Menu {
+ title: qsTr("View")
+ PlatformLabs.MenuItem {
+ text: MoneroComponents.Style.blackTheme ? qsTr("Light Theme") : qsTr("Dark Theme")
+ onTriggered: {
+ MoneroComponents.Style.blackTheme = !MoneroComponents.Style.blackTheme;
+ }
+ }
+ PlatformLabs.MenuItem {
+ text: qsTr("Change Language")
+ onTriggered: appWindow.toggleLanguageView();
+ }
+ }
+}
+
diff --git a/components/MenuButton.qml b/components/MenuButton.qml
new file mode 100644
index 0000000..5f6381f
--- /dev/null
+++ b/components/MenuButton.qml
@@ -0,0 +1,167 @@
+/Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.