Compare commits

..
Author SHA1 Message Date
dsc 6745f49e8f Commit cd1cd5cb75
introduced an issue for CMAKE_BUILD_TYPE=Debug:

  libringct.so => not found
  libcryptonote_basic.so => not found
  libcheckpoints.so => not found
  libdevice.so => not found
  libringct_basic.so => not found
  libcommon.so => not found
  libwallet-crypto.so => not found
  libcncrypto.so => not found
  libeasylogging.so => not found
  librandomx.so => not found
  libversion.so => not found

We'll only set `CMAKE_SKIP_RPATH` when in release.
2020-10-12 17:39:26 +02:00
201 changed files with 9745 additions and 7040 deletions
+27 -24
View File
@@ -14,10 +14,11 @@ steps:
commands:
- git config --global url."http://gitea:3000/tor/".insteadOf https://git.torproject.org/
- git config --global url."http://gitea:3000/".insteadOf https://github.com/
- git config --global url."http://gitea:3000/".insteadOf https://git.wownero.com/
- git submodule update --init monero
- git submodule update --init --depth 1 --recursive monero
- TOR_BIN="/usr/local/tor/bin/tor" make -j8 release-static
- git submodule update --init --depth 50 contrib/tor
- git submodule update --init --depth 50 contrib/torsocks
- git submodule update --init --depth 120 monero
- git submodule update --init --depth 120 --recursive monero
- make -j8 release-static
environment:
OPENSSL_ROOT_DIR: /usr/local/openssl/
CMAKEFLAGS_EXTRA: -DFETCH_DEPS=Off
@@ -29,7 +30,7 @@ steps:
- name: files_linux_release
path: /files
commands:
- export FN="feather-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
- export FN="feather-`git rev-parse --short HEAD`.zip"
- export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH"
- mkdir -p "$TARGET_DIR"
- echo "writing to $TARGET_DIR/$FN"
@@ -43,22 +44,20 @@ volumes:
path: /var/drone/ccache_linux_release/
- name: files_linux_release
host:
path: /build/feather_files/files/linux-release/
path: /mnt/storage1/feather_files/files/linux-release/
---
kind: pipeline
type: docker
name: linux-release-appimage
steps:
- name: build
image: feather:appimage
volumes:
- name: files_linux_release
path: /files
commands:
- export FN="feather-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
- export FN="feather-`git rev-parse --short HEAD`.zip"
- export BRANCH="$DRONE_SOURCE_BRANCH"
- cp /files/$BRANCH/$FN feather.zip
- bash ./contrib/build-appimage.sh
- name: deploy
image: feather:appimage
@@ -72,18 +71,18 @@ steps:
- echo "writing to $TARGET_DIR/$FN"
- mv "Feather-1.0-x86_64.AppImage" "$TARGET_DIR/$FN"
- echo "[*] written to https://build.featherwallet.org/files/linux-release-appimage/$DRONE_SOURCE_BRANCH/$FN"
volumes:
- name: files_linux_appimage
host:
path: /build/feather_files/files/linux-release-appimage/
- name: files_linux_release
host:
path: /build/feather_files/files/linux-release/
path: /mnt/storage1/feather_files/files/linux-release-appimage/
---
kind: pipeline
type: docker
name: windows-mxe-release
steps:
- name: build
image: feather:win
@@ -95,10 +94,11 @@ steps:
commands:
- git config --global url."http://gitea:3000/tor/".insteadOf https://git.torproject.org/
- git config --global url."http://gitea:3000/".insteadOf https://github.com/
- git config --global url."http://gitea:3000/".insteadOf https://git.wownero.com/
- git submodule update --init monero
- git submodule update --init --depth 1 --recursive monero
- PATH="/mxe/usr/bin/:$PATH" TOR_BIN="/mxe/usr/x86_64-w64-mingw32.static/bin/tor.exe" make -j8 windows-mxe-release
- git submodule update --init --depth 50 contrib/tor
- git submodule update --init --depth 50 contrib/torsocks
- git submodule update --init --depth 120 monero
- git submodule update --init --depth 120 --recursive monero
- PATH=/mxe/usr/bin/:$PATH make -j8 windows-mxe-release
environment:
CMAKEFLAGS_EXTRA: -DFETCH_DEPS=Off
- name: deploy
@@ -109,21 +109,23 @@ steps:
- name: files_win_release
path: /files
commands:
- export FN="feather-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
- export FN="feather-`git rev-parse --short HEAD`.zip"
- export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH"
- mkdir -p "$TARGET_DIR"
- echo "writing to $TARGET_DIR/$FN"
- zip -j "$TARGET_DIR/$FN" build/feather.log build/bin/feather.exe
- echo "[*] written to https://build.featherwallet.org/files/windows-mxe-release/$DRONE_SOURCE_BRANCH/$FN"
volumes:
- name: ccache_win_release
host:
path: /var/drone/ccache_win_release/
- name: files_win_release
host:
path: /build/feather_files/files/windows-mxe-release/
path: /mnt/storage1/feather_files/files/windows-mxe-release/
---
kind: pipeline
type: docker
name: mac-release
@@ -136,6 +138,7 @@ steps:
path: /files
commands:
- mkdir -p build
- scp -P22 utils/build_macos.sh administrator@steve.jobs.xmr.pm:build_macos.sh
- ssh administrator@steve.jobs.xmr.pm "chmod +x build_macos.sh && PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin ~/build_macos.sh $DRONE_COMMIT_SHA"
- scp -P22 administrator@steve.jobs.xmr.pm:feather.zip build/feather.zip
- name: deploy
@@ -144,7 +147,7 @@ steps:
- name: files_mac_release
path: /files
commands:
- export FN="feather-`echo $DRONE_COMMIT_AFTER | cut -c 1-7`.zip"
- export FN="feather-`git rev-parse --short HEAD`.zip"
- export TARGET_DIR="/files/$DRONE_SOURCE_BRANCH"
- mkdir -p "$TARGET_DIR"
- echo "writing to $TARGET_DIR/$FN"
@@ -154,9 +157,9 @@ steps:
volumes:
- name: files_mac_release
host:
path: /build/feather_files/files/mac-release/
path: /mnt/storage1/feather_files/files/mac-release/
---
kind: signature
hmac: f16a0379280e2e89987930d635ec6fb938d67732fdaf4ddc488f2a9db64bda2c
hmac: 91e773a27d27f29ea62f5df500664b733df641b7c31202c8e5558174fd046fba
...
+3 -3
View File
@@ -1,9 +1,9 @@
[submodule "monero"]
path = monero
url = https://git.wownero.com/feather/monero.git
[submodule "contrib/torsocks"]
path = contrib/torsocks
url = https://git.torproject.org/torsocks.git
[submodule "contrib/tor"]
path = contrib/tor
url = https://git.torproject.org/tor.git
[submodule "contrib/KDMacTouchBar"]
path = contrib/KDMacTouchBar
url = https://github.com/KDAB/KDMacTouchBar.git
+35 -40
View File
@@ -10,44 +10,6 @@ Static builds via Docker are done in 3 steps:
2. Creating a base Docker image
3. Using the base image to compile a build
### Linux (reproducible)
The docker image for reproducible Linux static builds uses Ubuntu 16.04 and compiles the required libraries statically
so that the resulting Feather binary is static. For more information, check the Dockerfile: `Dockerfile`.
#### 1. Clone
```bash
git clone --branch master --recursive https://git.wownero.com/feather/feather.git
cd feather
```
Replace `master` with the desired version tag (e.g. `beta-1`) to build the release binary.
#### 2. Base image
```bash
docker build --tag feather:linux --build-arg THREADS=4 .
```
Building the base image takes a while. You only need to build the base image once.
#### 3. Build
```bash
docker run --rm -it -v $PWD:/feather --env OPENSSL_ROOT_DIR=/usr/local/openssl/ -w /feather feather:linux sh -c 'TOR_BIN="/usr/local/tor/bin/tor" make release-static -j4'
```
If you're re-running a build make sure to `rm -rf build/` first.
The resulting binary can be found in `build/bin/feather`.
Hashes for tagged commits should match:
```
beta-1: d1a52e3bac1abbae4adda1fc88cb2a7a06fbd61085868421897c6a4f3f4eb091 feather
```
### Windows
The docker image for Windows static compiles uses Ubuntu 18.04 and installs [mxe](https://mxe.cc) from [our git](https://git.wownero.com/feather/mxe/src/branch/feather-patch),
@@ -73,13 +35,46 @@ Note: You only need to build the base image once.
#### 3. Build
```bash
docker run --rm -it -v /tmp/ccache:/root/.ccache -v PATH_TO_FEATHER:/feather -w /feather feather:win /bin/bash -c 'PATH="/mxe/usr/bin/:$PATH" TOR_BIN="/mxe/usr/x86_64-w64-mingw32.static/bin/tor.exe" make windows-mxe-release -j8'
docker run --rm -it -v /tmp/ccache:/root/.ccache -v /root/feather:/feather -w /feather feather:win /bin/bash -c 'PATH=/mxe/usr/bin/:$PATH make windows-mxe-release -j8'
```
Replace `PATH_TO_FEATHER` with the absolute path to Feather locally.
The resulting binary can be found in `build/bin/feather.exe`.
### Linux
The docker image for Linux static compiles uses Ubuntu 18.04 and compiles the required libraries statically so that
the resulting Feather binary is static. It comes with OpenSSL 1.1.1g, Qt 5.15.0 (OpenGL disabled). For more information,
check the Dockerfile: `Dockerfile`.
#### 1. Clone
```bash
git clone --recursive https://git.wownero.com/feather/feather.git
cd feather
```
#### 2. Base image
Warning: Building the base image takes a while, go prepare some dinner.
```bash
docker build --tag feather:linux --build-arg THREADS=8 .
```
Note: You only need to build the base image once.
#### 3. Build
```bash
docker run --env OPENSSL_ROOT_DIR=/usr/local/openssl/ --rm -it -v /tmp/ccache:/root/.ccache -v PATH_TO_FEATHER:/feather -w /feather feather:linux sh -c 'make release-static -j8'
```
Replace `PATH_TO_FEATHER` with the absolute path to Feather locally.
The resulting binary can be found in `build/bin/feather`.
## macOS
For MacOS it's easiest to leverage [brew](https://brew.sh) to install the required dependencies.
@@ -103,4 +98,4 @@ Build Feather.
CMAKE_PREFIX_PATH=~/Qt5.15.1/5.15.1/clang_64 make mac-release
```
The resulting Mac OS application can be found `build/bin/feather.app` and will **not** have Tor embedded.
The resulting Mac OS application can be found `build/bin/feather.app`.
+40 -30
View File
@@ -7,13 +7,11 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
set(VERSION_MAJOR "0")
set(VERSION_MINOR "1")
set(VERSION_REVISION "0")
set(VERSION "beta-3")
set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}")
option(FETCH_DEPS "Download dependencies if they are not found" ON)
option(XMRTO "Include Xmr.To module" ON)
option(XMRIG "Include XMRig module" ON)
option(TOR_BIN "Path to Tor binary to embed inside Feather" OFF)
option(BUILD_TOR "Build Tor" OFF)
option(STATIC "Link libraries statically, requires static Qt")
option(USE_DEVICE_TREZOR "Trezor support compilation" OFF)
option(DONATE_BEG "Prompt donation window every once in a while" ON)
@@ -30,7 +28,7 @@ if(DEBUG)
set(CMAKE_VERBOSE_MAKEFILE ON)
endif()
set(MONERO_HEAD "85b0b4f73aa6114e3ff91207aa94ad2a15c939a2")
set(MONERO_HEAD "a1404e92cb439ba0f120e7c4a579ed0b9a0372a4")
set(BUILD_GUI_DEPS ON)
set(ARCH "x86-64")
set(BUILD_64 ON)
@@ -160,7 +158,6 @@ find_package(Boost 1.58 REQUIRED COMPONENTS
if(UNIX AND NOT APPLE)
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
# https://github.com/monero-project/monero-gui/issues/3142#issuecomment-705940446
set(CMAKE_SKIP_RPATH ON)
endif()
@@ -176,30 +173,47 @@ if(UNIX AND NOT APPLE)
endif()
endif()
if("$ENV{DRONE}" STREQUAL "true")
message(STATUS "We are inside a static compile with Drone CI")
# Tor/torsocks
set(TOR_TAG "tor-0.4.3.5")
set(TOR_DIR "${CMAKE_SOURCE_DIR}/contrib/tor")
if(BUILD_TOR AND APPLE)
execute_process(COMMAND bash -c "touch ${CMAKE_SOURCE_DIR}/src/tor/libevent-2.1.7.dylib")
ENDIF()
if(UNIX AND NOT APPLE)
set(TOR_LIB "libtorsocks.so")
elseif(APPLE)
set(TOR_LIB "libtorsocks.dylib")
endif()
# To build Feather with embedded (and static) Tor, pass CMake -DTOR_BIN=/path/to/tor
if(TOR_BIN)
if(APPLE)
execute_process(COMMAND bash -c "touch ${CMAKE_CURRENT_SOURCE_DIR}/src/tor/libevent-2.1.7.dylib")
if("$ENV{DRONE}" STREQUAL "true" AND APPLE)
message(STATUS "We are inside a static compile with Drone CI")
# @TODO: taken from Tor Browser official release for now
execute_process(COMMAND bash -c "cp ~/tor/libevent-2.1.7.dylib ${CMAKE_SOURCE_DIR}/src/tor/libevent-2.1.7.dylib")
execute_process(COMMAND bash -c "cp ~/tor/tor ${CMAKE_SOURCE_DIR}/src/tor/tor")
elseif("$ENV{DRONE}" STREQUAL "true" AND BUILD_TOR)
message(STATUS "We are inside a static compile with Drone CI")
if(MINGW)
execute_process(COMMAND bash -c "cp /mxe/usr/x86_64-w64-mingw32.static/bin/tor.exe ${CMAKE_SOURCE_DIR}/src/tor/tor.exe")
elseif(UNIX AND NOT APPLE)
execute_process(COMMAND bash -c "cp /usr/local/tor/bin/tor ${CMAKE_SOURCE_DIR}/src/tor/tor")
execute_process(COMMAND bash -c "cp /usr/local/torsocks/lib/torsocks/* ${CMAKE_SOURCE_DIR}/src/tor/")
endif()
# on the buildbot Tor is baked into the image
# - linux: See `Dockerfile`
# - windows: https://github.com/mxe/mxe/blob/1024dc7d2db5eb7d5d3c64a2c12b5f592572f1ce/plugins/apps/tor.mk
# - macos: taken from Tor Browser official release
set(TOR_COPY_CMD "cp -u ${TOR_BIN} ${CMAKE_CURRENT_SOURCE_DIR}/src/assets/exec/tor")
message(STATUS "${TOR_COPY_CMD}")
execute_process(COMMAND bash -c "${TOR_COPY_CMD}" RESULT_VARIABLE ret)
if(ret EQUAL "1")
message(FATAL_ERROR "Tor copy failure: ${TOR_COPY_CMD}")
endif()
message(STATUS "Embedding Tor binary at ${TOR_BIN}")
else()
message(STATUS "Skipping Tor inclusion because -DTOR_BIN=Off")
if(BUILD_TOR)
if(UNIX OR APPLE)
execute_process(COMMAND bash -c "ls -al src/tor/${TOR_LIB} 2>/dev/null" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE TOR_FOUND OUTPUT_STRIP_TRAILING_WHITESPACE)
if(TOR_FOUND)
message(STATUS "${TOR_LIB} found, skipping Tor build")
else()
message(STATUS "${TOR_LIB} not found, building Tor")
execute_process(COMMAND bash -c "bash build_tor.sh ${TOR_TAG} ${CMAKE_SOURCE_DIR} 'ON'" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/contrib)
endif()
endif()
else()
message(STATUS "Skipping Tor build because -DBUILD_TOR=OFF")
endif()
endif()
if(MINGW)
@@ -347,8 +361,4 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 ${C_SECURITY_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${CXX_SECURITY_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LD_SECURITY_FLAGS} ${STATIC_FLAGS}")
if(APPLE)
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/contrib/KDMacTouchBar")
endif()
add_subdirectory(src)
+133 -174
View File
@@ -1,214 +1,188 @@
FROM ubuntu:16.04
FROM ubuntu:18.04
ARG THREADS=1
ARG QT_VERSION=5.15.2
ENV CFLAGS="-fPIC"
ENV CPPFLAGS="-fPIC"
ENV CXXFLAGS="-fPIC"
ENV SOURCE_DATE_EPOCH=1397818193
RUN apt clean && apt update
RUN apt install -y gnupg
RUN apt-get update
RUN apt-get install -y nano vim ccache software-properties-common
COPY utils/pubkeys/kitware.asc /kitware.asc
RUN cat /kitware.asc | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null
RUN apt install -y automake git pkg-config python wget python3.6-distutils software-properties-common
RUN apt-add-repository 'deb https://apt.kitware.com/ubuntu/ bionic main' && apt update
RUN add-apt-repository ppa:git-core/ppa
RUN apt-get update
ARG DEBIAN_FRONTEND=noninteractive
ENV TZ=Europe/Amsterdam
RUN apt install -y build-essential nano vim aptitude ccache libusb-1.0-0-dev tzdata
RUN apt install -y automake git pkg-config python xutils-dev && \
RUN apt install -y xutils-dev && \
git clone -b xorgproto-2020.1 --depth 1 https://gitlab.freedesktop.org/xorg/proto/xorgproto && \
cd xorgproto && \
git reset --hard c62e8203402cafafa5ba0357b6d1c019156c9f36 && \
./autogen.sh && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone -b 1.12 --depth 1 https://gitlab.freedesktop.org/xorg/proto/xcbproto && \
RUN git clone -b xcb-proto-1.13 --depth 1 https://gitlab.freedesktop.org/xorg/proto/xcbproto && \
cd xcbproto && \
git reset --hard 6398e42131eedddde0d98759067dde933191f049 && \
./autogen.sh && \
git reset --hard 94228cde97d9aecfda04a8e699d462ba2b89e3a0 && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN apt install -y libtool-bin && \
git clone -b libXau-1.0.9 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxau && \
cd libxau && \
git reset --hard d9443b2c57b512cfb250b35707378654d86c7dea && \
./autogen.sh --enable-shared --disable-static && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN apt install -y libpthread-stubs0-dev && \
git clone -b 1.12 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb && \
git clone -b 1.13.1 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb && \
cd libxcb && \
git reset --hard d34785a34f28fa6a00f8ce00d87e3132ff0f6467 && \
./autogen.sh --enable-shared --disable-static && \
git reset --hard 8287ebd7b752c33b0cabc4982606fe4831106f7e && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-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)
make -j$THREADS install
RUN git clone -b 0.4.0 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-util && \
RUN git clone -b 0.4.0 --depth 1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-util.git && \
cd libxcb-util && \
git reset --hard acf790d7752f36e450d476ad79807d4012ec863b && \
git submodule init && \
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
./autogen.sh --enable-shared --disable-static && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone -b 0.4.0 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-image && \
RUN git clone -b xtrans-1.3.5 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxtrans.git && \
cd libxtrans && \
git reset --hard 7cbad9fe2e61cd9d5caeaf361826a6f4bd320f03 && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install
RUN git clone -b 0.4.0 --depth 1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-image.git && \
cd libxcb-image && \
git reset --hard d882052fb2ce439c6483fce944ba8f16f7294639 && \
git submodule init && \
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
./autogen.sh --enable-shared --disable-static && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone -b 0.4.0 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-keysyms && \
RUN git clone -b 0.4.0 --depth 1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-keysyms.git && \
cd libxcb-keysyms && \
git reset --hard 0e51ee5570a6a80bdf98770b975dfe8a57f4eeb1 && \
git submodule init && \
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
./autogen.sh --enable-shared --disable-static && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone -b 0.3.9 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-render-util && \
RUN git clone -b 0.3.9 --depth 1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-render-util.git && \
cd libxcb-render-util && \
git reset --hard 0317caf63de532fd7a0493ed6afa871a67253747 && \
git submodule init && \
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
./autogen.sh --enable-shared --disable-static && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone -b 0.4.1 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxcb-wm && \
RUN git clone -b 0.4.1 --depth 1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-wm.git && \
cd libxcb-wm && \
git reset --hard 24eb17df2e1245885e72c9d4bbb0a0f69f0700f2 && \
git submodule init && \
git clone --depth 1 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 m4 && \
git -C m4 reset --hard f662e3a93ebdec3d1c9374382dcc070093a42fed && \
./autogen.sh --enable-shared --disable-static && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN apt install -y bison && \
git clone -b xkbcommon-0.5.0 --depth 1 https://github.com/xkbcommon/libxkbcommon && \
cd libxkbcommon && \
git reset --hard c43c3c866eb9d52cd8f61e75cbef1c30d07f3a28 && \
./autogen.sh --prefix=/usr --enable-shared --disable-static --enable-x11 --disable-docs && \
RUN git clone -b libX11-1.6.9 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libx11 && \
cd libx11 && \
git reset --hard db7cca17ad7807e92a928da9d4c68a00f4836da2 && \
ACLOCAL='aclocal -I /usr/local/share/aclocal/' CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone -b libXext-1.3.4 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxext && \
cd libxext && \
git reset --hard ebb167f34a3514783966775fb12573c4ed209625 && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install
RUN apt install -y libpthread-stubs0-dev && \
git clone -b libXinerama-1.1.4 --depth 1 https://gitlab.freedesktop.org/xorg/lib/libxinerama.git && \
cd libxinerama && \
git reset --hard c3ab2361f13154921df2992f9eacc1ea1b3f946b && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install
RUN git clone -b v1.2.11 --depth 1 https://github.com/madler/zlib && \
cd zlib && \
git reset --hard cacf7f1d4e3d44d871b605da3b647f07d718623f && \
./configure --static && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --static && \
make -j$THREADS && \
make -j$THREADS install && \
./configure --static --prefix=/usr/local/zlib && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --static --prefix=/usr/local/zlib && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone -b VER-2-10-2 --depth 1 https://git.savannah.gnu.org/git/freetype/freetype2.git && \
RUN git clone -b VER-2-10-2 https://git.sv.nongnu.org/r/freetype/freetype2.git && \
cd freetype2 && \
git reset --hard 132f19b779828b194b3fede187cee719785db4d8 && \
./autogen.sh && \
./configure --disable-shared --enable-static --with-zlib=no && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --with-zlib=no && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone -b R_2_2_9 --depth 1 https://github.com/libexpat/libexpat && \
cd libexpat/expat && \
git reset --hard a7bc26b69768f7fb24f0c7976fae24b157b85b13 && \
./buildconf.sh && \
./configure --disable-shared --enable-static && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN apt install -y autopoint gettext gperf libpng12-dev && \
RUN apt install -y autopoint gettext gperf libpng-dev && \
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 && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static --sysconfdir=/etc --localstatedir=/var && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
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 && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --disable-tests --disable-samples && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN apt install -y wget && \
wget https://dl.bintray.com/boostorg/release/1.73.0/source/boost_1_73_0.tar.gz && \
echo "9995e192e68528793755692917f9eb6422f3052a53c5e13ba278a228af6c7acf boost_1_73_0.tar.gz" | sha256sum -c && \
tar -xzf boost_1_73_0.tar.gz && \
rm boost_1_73_0.tar.gz && \
echo "9995e192e68528793755692917f9eb6422f3052a53c5e13ba278a228af6c7acf boost_1_73_0.tar.gz" > hashsum.txt && \
sha256sum -c hashsum.txt && \
tar -xvzf boost_1_73_0.tar.gz && \
cd boost_1_73_0 && \
./bootstrap.sh && \
./b2 --with-atomic --with-system --with-filesystem --with-thread --with-date_time --with-chrono --with-regex --with-serialization --with-program_options --with-locale variant=release link=static runtime-link=static cflags="${CFLAGS}" cxxflags="${CXXFLAGS}" install -a --prefix=/usr && \
rm -rf $(pwd)
./b2 --with-atomic --with-system --with-filesystem --with-thread --with-date_time --with-chrono --with-regex --with-serialization --with-program_options --with-locale variant=release link=static runtime-link=static cflags='-fPIC' cxxflags='-fPIC' install -a --prefix=/usr
RUN wget https://www.openssl.org/source/openssl-1.1.1i.tar.gz && \
echo "e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242 openssl-1.1.1i.tar.gz" | sha256sum -c && \
tar -xzf openssl-1.1.1i.tar.gz && \
rm openssl-1.1.1i.tar.gz && \
cd openssl-1.1.1i && \
./config no-shared no-zlib-dynamic --prefix=/usr/local/openssl && \
RUN wget https://www.openssl.org/source/openssl-1.1.1g.tar.gz && \
echo "ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46 openssl-1.1.1g.tar.gz" > hashsum.txt && \
sha256sum -c hashsum.txt && \
tar -xzf openssl-1.1.1g.tar.gz && \
cd openssl-1.1.1g && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./config no-shared no-zlib-dynamic --prefix=/usr/local/openssl && \
make -j$THREADS && \
make -j$THREADS install && \
./config no-shared no-zlib-dynamic --openssldir=/usr && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN apt install -y libgl1-mesa-dev libglib2.0-dev mesa-common-dev && \
rm /usr/lib/x86_64-linux-gnu/libX11.a && \
rm /usr/lib/x86_64-linux-gnu/libXext.a && \
rm /usr/lib/x86_64-linux-gnu/libX11-xcb.a && \
git clone git://code.qt.io/qt/qt5.git -b ${QT_VERSION} --depth 1 && \
cd qt5 && \
git clone git://code.qt.io/qt/qtbase.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qtimageformats.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qtmultimedia.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qtsvg.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qttools.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qttranslations.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qtx11extras.git -b ${QT_VERSION} --depth 1 && \
git clone git://code.qt.io/qt/qtwebsockets.git -b ${QT_VERSION} --depth 1 && \
RUN wget https://download.qt.io/archive/qt/5.15/5.15.0/single/qt-everywhere-src-5.15.0.tar.xz && \
echo "22b63d7a7a45183865cc4141124f12b673e7a17b1fe2b91e433f6547c5d548c3 qt-everywhere-src-5.15.0.tar.xz" > hashsum.txt && \
sha256sum -c hashsum.txt && \
tar -xf qt-everywhere-src-5.15.0.tar.xz
COPY contrib/Qt5.15_LinuxPatch.json /qt-everywhere-src-5.15.0/qtbase/src/gui/configure.json
RUN apt install -y libgl1-mesa-dev libglib2.0-dev libxkbcommon-dev libxkbcommon-x11-dev
RUN cd /qt-everywhere-src-5.15.0 && \
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 && \
OPENSSL_LIBS="-lssl -lcrypto -lpthread -ldl" \
./configure --prefix=/usr -platform linux-g++-64 -opensource -confirm-license -release -static -no-avx \
-no-opengl -qpa xcb --xcb -xcb-xlib -feature-xlib -openssl-linked -I /usr/local/openssl/include \
-L /usr/local/openssl/lib -system-freetype -fontconfig -glib \
-no-opengl -qpa xcb -openssl-linked -I /usr/local/openssl/include -L /usr/local/openssl/lib -system-freetype -fontconfig -glib \
-no-dbus -no-sql-sqlite -no-use-gold-linker -no-kms \
-qt-harfbuzz -qt-libjpeg -qt-libpng -qt-pcre -qt-zlib \
-skip qt3d -skip qtandroidextras -skip qtcanvas3d -skip qtcharts -skip qtconnectivity -skip qtdatavis3d \
@@ -217,103 +191,84 @@ RUN apt install -y libgl1-mesa-dev libglib2.0-dev mesa-common-dev && \
-skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qttools \
-skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebview \
-skip qtwinextras -skip qtx11extras -skip gamepad -skip serialbus -skip location -skip webengine \
-skip qtdeclarative \
-skip qtdeclarative -skip qtmultimedia \
-no-feature-cups -no-feature-ftp -no-feature-pdf -no-feature-animation \
-nomake examples -nomake tests -nomake tools && \
-nomake examples -nomake tests -nomake tools
RUN cd /qt-everywhere-src-5.15.0 && \
make -j$THREADS && \
make -j$THREADS install && \
cd qttools/src/linguist/lrelease && \
../../../../qtbase/bin/qmake && \
make -j$THREADS install
RUN cd qt-everywhere-src-5.15.0/qttools/src/linguist/lrelease && \
qmake && \
make -j$THREADS && \
make -j$THREADS install && \
cd ../../../.. && \
rm -rf $(pwd)
make -j$THREADS install
RUN apt install -y libudev-dev && \
git clone -b v1.0.23 --depth 1 https://github.com/libusb/libusb && \
cd libusb && \
git reset --hard e782eeb2514266f6738e242cdcb18e3ae1ed06fa && \
./autogen.sh --disable-shared --enable-static && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./autogen.sh --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone -b hidapi-0.9.0 --depth 1 https://github.com/libusb/hidapi && \
cd hidapi && \
git reset --hard 7da5cc91fc0d2dbe4df4f08cd31f6ca1a262418f && \
./bootstrap && \
./configure --disable-shared --enable-static && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN apt install -y libsodium-dev && \
git clone -b v4.3.2 --depth 1 https://github.com/zeromq/libzmq && \
cd libzmq && \
git reset --hard a84ffa12b2eb3569ced199660bac5ad128bff1f0 && \
./autogen.sh && \
./configure --disable-shared --enable-static --disable-libunwind --with-libsodium && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --disable-libunwind --with-libsodium && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone -b libgpg-error-1.38 --depth 1 git://git.gnupg.org/libgpg-error.git && \
cd libgpg-error && \
git reset --hard 71d278824c5fe61865f7927a2ed1aa3115f9e439 && \
./autogen.sh && \
./configure --disable-shared --enable-static --disable-doc --disable-tests && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --disable-doc --disable-tests && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone -b libgcrypt-1.8.5 --depth 1 git://git.gnupg.org/libgcrypt.git && \
cd libgcrypt && \
git reset --hard 56606331bc2a80536db9fc11ad53695126007298 && \
./autogen.sh && \
./configure --disable-shared --enable-static --disable-doc && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --disable-shared --enable-static --disable-doc && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone -b v3.10.0 --depth 1 https://github.com/protocolbuffers/protobuf && \
cd protobuf && \
git reset --hard 6d4e7fd7966c989e38024a8ea693db83758944f1 && \
./autogen.sh && \
./configure --enable-static --disable-shared && \
CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --enable-static --disable-shared && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone -b v3.18.4 --depth 1 https://github.com/Kitware/CMake && \
cd CMake && \
git reset --hard 3cc3d42aba879fff5e85b363ae8f21386a3f9f9b && \
./bootstrap && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
RUN apt install -y libusb-1.0-0-dev
RUN apt install -y zip && git clone -b v4.0.2 --depth 1 https://github.com/fukuchi/libqrencode.git && \
RUN apt install -y zip cmake && git clone -b v4.0.2 --depth 1 https://github.com/fukuchi/libqrencode.git && \
cd libqrencode && \
git reset --hard 59ee597f913fcfda7a010a6e106fbee2595f68e4 && \
cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=/usr . && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN apt install -y libmbedtls-dev && git clone -b release-2.1.12-stable --depth 1 https://github.com/libevent/libevent.git && \
cd libevent && \
git reset --hard 5df3037d10556bfcb675bc73e516978b75fc7bc7 && \
mkdir build && cd build && \
cmake -DEVENT_LIBRARY_STATIC=ON -DOPENSSL_ROOT_DIR=/usr/local/openssl -DCMAKE_INSTALL_PREFIX=/usr/local/libevent .. && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone -b tor-0.4.4.6 --depth 1 https://git.torproject.org/tor.git && \
RUN git clone -b tor-0.4.3.5 --depth 1 https://git.torproject.org/tor.git && \
cd tor && \
git reset --hard 2a8b789ea6f308d081f369d78fa7cfdc9d00bf90 && \
bash autogen.sh && \
LDFLAGS="-L/usr/local/openssl/lib/" LIBS="-lssl -lcrypto -lpthread -ldl" CPPFLAGS="-I/usr/local/openssl/include/" ./configure \
--enable-static-zlib \
@@ -336,13 +291,17 @@ RUN git clone -b tor-0.4.4.6 --depth 1 https://git.torproject.org/tor.git && \
--disable-system-torrc \
--prefix=/usr/local/tor && \
make -j$THREADS && \
make -j$THREADS install && \
rm -rf $(pwd)
make -j$THREADS install
RUN git clone https://git.torproject.org/torsocks.git && \
cd torsocks && \
bash autogen.sh && \
./configure --prefix=/usr/local/torsocks && \
make -j$THREADS && \
make -j$THREADS install
RUN git clone https://git.wownero.com/feather/monero-seed.git && \
cd monero-seed && \
git reset --hard 4674ef09b6faa6fe602ab5ae0b9ca8e1fd7d5e1b && \
cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && \
make -Cbuild -j$THREADS && \
make -Cbuild install && \
rm -rf $(pwd)
make -Cbuild install
+1 -1
View File
@@ -3,7 +3,7 @@ FROM ubuntu:20.04
ARG DEBIAN_FRONTEND=noninteractive
RUN apt clean && apt update
RUN apt install -y golang git build-essential wget curl ngrep unzip file squashfs-tools desktop-file-utils patchelf libxkbcommon-x11-dev libx11-xcb-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render0 libxcb-render-util0 libxcb-shape0 libxcb-sync1 libxcb-xfixes0 libxcb-shm0 libxcb-keysyms1 libxcb-xkb1
RUN apt install -y golang git build-essential wget curl ngrep unzip file squashfs-tools desktop-file-utils patchelf libxkbcommon-x11-dev
RUN go get github.com/probonopd/go-appimage/src/appimagetool
RUN go build -trimpath -ldflags="-s -w" github.com/probonopd/go-appimage/src/appimagetool
+1 -1
View File
@@ -50,7 +50,7 @@ RUN apt install -y \
RUN git clone -b feather-patch --depth 1 https://git.wownero.com/feather/mxe.git && \
cd mxe && \
make -j$THREADS MXE_TARGETS='x86_64-w64-mingw32.static' gcc libqrencode pkgconf libgpg_error libgcrypt cmake libsodium lzma readline libzmq boost qtbase qtsvg qtwebsockets qtimageformats qtmultimedia
make -j$THREADS MXE_TARGETS='x86_64-w64-mingw32.static' gcc libqrencode pkgconf libgpg_error libgcrypt cmake libsodium lzma readline libzmq boost qtbase qtsvg qtwebsockets qtimageformats
# plugins
RUN cd mxe && make -j$THREADS MXE_PLUGIN_DIRS='/mxe/plugins/apps/' MXE_TARGETS='x86_64-w64-mingw32.static' tor
+1 -2
View File
@@ -42,8 +42,7 @@ via the `CMAKE_PREFIX_PATH` definition. For me this is:
There are some Monero/Feather related options/definitions that you may pass:
- `-DXMRTO=OFF` - disable Xmr.To feature
- `-DXMRIG=OFF` - disable XMRig feature
- `-DTOR_BIN=/path/to/tor` - Embed a Tor executable inside Feather
- `-DBUILD_TOR=OFF` - disable embedded Tor
- `-DDONATE_BEG=OFF` - disable the dreaded donate requests
And:
+5 -7
View File
@@ -30,9 +30,7 @@ CMAKEFLAGS = \
-DARCH=x86_64 \
-DBUILD_64=On \
-DBUILD_TESTS=Off \
-DXMRTO=On \
-DXMRIG=On \
-DTOR_BIN=Off \
-DXMRTO=ON \
-DCMAKE_CXX_STANDARD=11 \
-DCMAKE_VERBOSE_MAKEFILE=On \
-DINSTALL_VENDORED_LIBUNBOUND=Off \
@@ -42,29 +40,29 @@ CMAKEFLAGS = \
$(CMAKEFLAGS_EXTRA)
release-static: CMAKEFLAGS += -DBUILD_TAG="linux-x64"
release-static: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
release-static: CMAKEFLAGS += -DBUILD_TOR=On
release-static: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release
release-static:
cmake -Bbuild $(CMAKEFLAGS)
$(MAKE) -Cbuild
windows-mxe-release: CMAKEFLAGS += -DBUILD_TAG="win-x64"
windows-mxe-release: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
windows-mxe-release: CMAKEFLAGS += -DBUILD_TOR=On
windows-mxe-release: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release
windows-mxe-release:
cmake -Bbuild $(CMAKEFLAGS)
$(MAKE) -Cbuild
windows-mxe-debug: CMAKEFLAGS += -DBUILD_TAG="win-x64"
windows-mxe-debug: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
windows-mxe-debug: CMAKEFLAGS += -DBUILD_TOR=Off
windows-mxe-debug: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Debug
windows-mxe-debug:
cmake -Bbuild $(CMAKEFLAGS)
$(MAKE) -Cbuild
mac-release: CMAKEFLAGS += -DSTATIC=Off
mac-release: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
mac-release: CMAKEFLAGS += -DBUILD_TAG="mac-x64"
mac-release: CMAKEFLAGS += -DBUILD_TOR=Off
mac-release: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release
mac-release:
cmake -Bbuild $(CMAKEFLAGS)
+11 -12
View File
@@ -1,35 +1,34 @@
# Maintainer: wowario <wowario[at]protonmail[dot]com>
# Contributor: wowario <wowario[at]protonmail[dot]com>
pkgname='monero-feather-git'
pkgver=0.1.0.925ef5683
pkgbase=('monero-feather-git')
pkgname=('monero-feather-git')
pkgver=v0.1.0.0.cd1cd5cb75
pkgrel=1
pkgdesc='a free Monero desktop wallet'
pkgdesc="a free Monero desktop wallet"
license=('BSD')
arch=('x86_64')
url="https://featherwallet.org"
depends=('boost-libs' 'libunwind' 'openssl' 'readline' 'pcsclite' 'hidapi' 'protobuf' 'miniupnpc' 'libgcrypt' 'qrencode' 'libsodium' 'libpgm' 'expat' 'qt5-base' 'qt5-websockets' 'tor')
depends=('boost-libs' 'libunwind' 'openssl' 'readline' 'zeromq' 'pcsclite' 'hidapi' 'protobuf' 'miniupnpc'
'libgcrypt' 'qrencode' 'ccache' 'libsodium' 'libpgm' 'expat' 'base-devel' 'qt5-base')
makedepends=('git' 'cmake' 'boost')
provides=('monero-feather-git')
source=("${pkgname}"::"git+https://git.wownero.com/feather/feather")
sha256sums=('SKIP')
pkgver() {
cd "${srcdir}/${pkgname}"
printf "%s.%s" "$(git describe --tags --abbrev=0)" "$(git rev-parse --short=9 HEAD)"
cd "$srcdir/$pkgname"
git describe --long --tags | sed 's/\([^-]*-\)g/r\1/;s/-/./g'
}
build() {
cd "${srcdir}/${pkgname}"
git submodule update --init --recursive
mkdir -p build
cd build
cmake ..
make
mkdir build && cd build && cmake .. && make release-static -j2
}
package_monero-feather-git() {
package_feather-git() {
install -Dm644 "${srcdir}/${pkgname}/LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
install -Dm755 "${srcdir}/${pkgname}/build/bin/feather" "${pkgdir}/usr/bin/feather"
}
+22
View File
@@ -2,11 +2,33 @@
set -e
function verify_hash() {
local file=$1 expected_hash=$2
actual_hash=$(sha256sum $file | awk '{print $1}')
if [ "$actual_hash" == "$expected_hash" ]; then
return 0
else
echo "$file $actual_hash (unexpected hash)" >&2
rm "$file"
exit 1
fi
}
function download_if_not_exist() {
local file_name=$1 url=$2
if [ ! -e $file_name ] ; then
wget -q -O $file_name "$url"
fi
}
APPDIR="$PWD/feather.AppDir"
mkdir -p "$APPDIR"
mkdir -p "$APPDIR/usr/share/applications/"
mkdir -p "$APPDIR/usr/bin"
echo "Downloading dependencies"
download_if_not_exist "feather.zip" "https://build.featherwallet.org/files/linux-release/$BRANCH/$FN"
unzip -q feather.zip
cp "$PWD/src/assets/feather.desktop" "$APPDIR/usr/share/applications/feather.desktop"
+126
View File
@@ -0,0 +1,126 @@
#!/usr/bin/env bash
# this file is used by feather's CMake
# arguments: ./build.tor $TAG $ROOT_FEATHER_DIR
set -ex
ERR_WIN="This script does not work on Windows"
if [[ "$OSTYPE" == "msys" ]]; then
echo "$ERR_WIN"
exit 1
elif [[ "$OSTYPE" == "win32" ]]; then
echo "$ERR_WIN"
exit 1
fi
TOR_TAG="$1"
ROOT_DIR="$2"
STATIC="$3"
TOR_DIR="$ROOT_DIR/contrib/tor"
TORSOCKS_DIR="$ROOT_DIR/contrib/torsocks"
TARGET_DIR="$ROOT_DIR/src/tor"
CPU_CORE_COUNT="$(nproc)"
#
### tor
#
pushd "$TOR_DIR"
rm -rf "$TOR_DIR/build"
mkdir -p "$TOR_DIR/build"
# configure
git -C "$TOR_DIR" fetch
git -C "$TOR_DIR" checkout tor-0.4.3.5
bash "$TOR_DIR/autogen.sh"
if [[ "$STATIC" = "ON" ]]; then
# static assumes that openssl has been compiled with:
# CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./config no-asm no-shared no-zlib-dynamic --prefix=/usr/local/openssl --openssldir=/usr/local/openssl
# and libevent with:
# cmake -DEVENT_LIBRARY_STATIC=ON -DOPENSSL_ROOT_DIR=/usr/local/openssl -DCMAKE_INSTALL_PREFIX=/usr/local/libevent
# and zlib with:
# CFLAGS='-fPIC' CXXFLAGS='-fPIC' ./configure --static --prefix=/usr/local/zlib
LDFLAGS="-L/usr/local/openssl/lib/" LIBS="-lssl -lcrypto -lpthread -ldl" CPPFLAGS="-I/usr/local/openssl/include/" ./configure \
--enable-static-zlib \
--enable-static-openssl \
--enable-static-libevent \
--disable-system-torrc \
--with-libevent-dir=/usr/local/libevent \
--with-openssl-dir=/usr/local/openssl/ \
--with-zlib-dir=/usr/local/zlib \
--disable-system-torrc \
--disable-tool-name-check \
--disable-systemd \
--disable-lzma \
--disable-unittests \
--disable-zstd \
--disable-seccomp \
--disable-asciidoc \
--disable-manpage \
--disable-html-manual \
--disable-system-torrc \
--prefix="$TOR_DIR/build"
else
bash "$TOR_DIR/configure" \
--disable-tool-name-check \
--disable-systemd \
--disable-lzma \
--disable-unittests \
--disable-zstd \
--disable-asciidoc \
--disable-manpage \
--disable-html-manual \
--prefix="$TOR_DIR/build"
fi
# build
make -j "$CPU_CORE_COUNT"
make install -j "$CPU_CORE_COUNT"
# copy to lib/tor
cp "$TOR_DIR/build/bin/tor" "$TARGET_DIR"
cp "$TOR_DIR/build/etc/tor/torrc.sample"* "$TARGET_DIR"
#
### torsocks
#
pushd "$TORSOCKS_DIR"
mkdir -p "$TORSOCKS_DIR/build"
# configure
bash "$TORSOCKS_DIR/autogen.sh"
bash "$TORSOCKS_DIR/configure" --prefix="$TORSOCKS_DIR/build"
# build
make -j "$CPU_CORE_COUNT"
make install -j "$CPU_CORE_COUNT"
# copy to lib/torsocks
cp "$TORSOCKS_DIR/build/lib/torsocks/"* "$TARGET_DIR"
cp "$TORSOCKS_DIR/build/bin/"* "$TARGET_DIR"
cp "$TORSOCKS_DIR/build/etc/tor/"* "$TARGET_DIR"
#
### verify installation
#
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
for fn in "$TARGET_DIR/libtorsocks.so" "$TARGET_DIR/tor"; do
if [[ ! -f "$fn" ]]; then
echo "[*] Failed to install tor or torsocks: no such file $fn"
exit 1
fi; done
elif [[ "$OSTYPE" == "darwin"* ]]; then
for fn in "$TARGET_DIR/libtorsocks.dylib" "$TARGET_DIR/tor"; do
if [[ ! -f "$fn" ]]; then
echo "[*] Failed to install tor or torsocks: no such file $fn"
exit 1
fi; done
fi
echo "[*] Compiled tor/torsocks into $TARGET_DIR"
+1
Submodule contrib/torsocks added at 4c00ec8773
+53
View File
@@ -0,0 +1,53 @@
From fc5eafeb2886605d4de1546846f06a12a18c87ef Mon Sep 17 00:00:00 2001
From: "J.W" <jakwings@gmail.com>
Date: Mon, 22 Apr 2019 05:19:32 +0100
Subject: [PATCH 1/2] Fix macros for accept4(2)
Both accept(2) and accept4(2) exist on linux but accept4(2) does not
exist on macos 10.11.6 (and maybe other distros).
---
src/lib/torsocks.c | 9 ++++++++-
src/lib/torsocks.h | 4 +++-
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/lib/torsocks.c b/src/lib/torsocks.c
index 16f2da0..9527513 100644
--- a/src/lib/torsocks.c
+++ b/src/lib/torsocks.c
@@ -234,9 +234,16 @@ static void init_libc_symbols(void)
tsocks_libc_socket = dlsym(libc_ptr, LIBC_SOCKET_NAME_STR);
tsocks_libc_syscall = dlsym(libc_ptr, LIBC_SYSCALL_NAME_STR);
tsocks_libc_execve = dlsym(libc_ptr, LIBC_EXECVE_NAME_STR);
+ tsocks_libc_accept = dlsym(libc_ptr, LIBC_ACCEPT_NAME_STR);
+#if (defined(__linux__))
tsocks_libc_accept4 = dlsym(libc_ptr, LIBC_ACCEPT4_NAME_STR);
+#endif
+
if (!tsocks_libc_connect || !tsocks_libc_close || !tsocks_libc_socket ||
- !tsocks_libc_syscall || !tsocks_libc_execve || ! tsocks_libc_accept4) {
+#if (defined(__linux__))
+ !tsocks_libc_accept4 ||
+#endif
+ !tsocks_libc_syscall || !tsocks_libc_execve || ! tsocks_libc_accept) {
ERR("Unable to lookup symbols in " LIBC_NAME "(%s)", dlerror());
goto error;
}
diff --git a/src/lib/torsocks.h b/src/lib/torsocks.h
index 33da526..bf9109d 100644
--- a/src/lib/torsocks.h
+++ b/src/lib/torsocks.h
@@ -30,8 +30,10 @@
* libc call outside of torsocks can be used. These are declared for each
* symbol torsocks hijacked.
*/
+#define TSOCKS_LIBC_FUNC(name) \
+ tsocks_libc_##name
#define TSOCKS_LIBC_DECL(name, type, sig) \
- type (*tsocks_libc_##name)(sig);
+ type (*TSOCKS_LIBC_FUNC(name))(sig);
#define TSOCKS_DECL(name, type, sig) \
extern type tsocks_##name(sig);
--
2.21.0
+1 -1
Submodule monero updated: 85b0b4f73a...a1404e92cb
+15 -25
View File
@@ -42,12 +42,14 @@ file(GLOB SOURCE_FILES
"dialog/*.cpp"
)
if(TOR_BIN)
if(APPLE)
set(ASSETS_TOR "assets_tor_macos.qrc")
else()
set(ASSETS_TOR "assets_tor.qrc")
endif()
if((APPLE AND BUILD_TOR) OR (APPLE AND "$ENV{DRONE}" STREQUAL "true"))
set(ASSETS_OS "assets_macos_tor.qrc")
elseif(UNIX AND NOT APPLE AND BUILD_TOR)
set(ASSETS_OS "assets_linux_tor.qrc")
elseif(MINGW AND BUILD_TOR)
set(ASSETS_OS "assets_windows_tor.qrc")
else()
message(STATUS "Building without embedded Tor")
endif()
set(EXECUTABLE_FLAG)
@@ -72,8 +74,8 @@ endif()
add_executable(feather ${EXECUTABLE_FLAG} main.cpp
${SOURCE_FILES}
${RESOURCES}
${ASSETS_TOR}
)
${ASSETS_OS}
)
# mac os bundle
set_target_properties(feather PROPERTIES
@@ -120,16 +122,12 @@ if(DONATE_BEG)
target_compile_definitions(feather PRIVATE DONATE_BEG=1)
endif()
if(BUILD_TOR)
target_compile_definitions(feather PRIVATE BUILD_TOR=1)
endif()
if(XMRTO)
target_compile_definitions(feather PRIVATE HAS_XMRTO=1)
endif()
if(TOR_BIN)
target_compile_definitions(feather PRIVATE HAS_TOR_BIN=1)
endif()
if(XMRIG)
target_compile_definitions(feather PRIVATE HAS_XMRIG=1)
target_compile_definitions(feather PRIVATE XMRTO=1)
endif()
if(HAVE_SYS_PRCTL_H)
@@ -196,14 +194,6 @@ target_link_libraries(feather
${QRENCODE_LIBRARY}
)
if(APPLE)
target_link_libraries(feather
KDMacTouchBar
)
target_include_directories(feather
PUBLIC ../contrib/KDMacTouchBar)
endif()
if(NOT APPLE)
target_link_libraries(feather
Qt5::QSvgIconPlugin
+83 -139
View File
@@ -9,14 +9,12 @@
#include <QDesktopWidget>
#include "appcontext.h"
#include "globals.h"
#include "utils/tails.h"
#include "utils/whonix.h"
#include "utils/utils.h"
#include "utils/prices.h"
#include "utils/networktype.h"
#include "utils/wsclient.h"
#include "utils/config.h"
// libwalletqt
#include "libwalletqt/WalletManager.h"
@@ -30,6 +28,7 @@
#include "model/SubaddressModel.h"
#include "utils/keysfiles.h"
#include "utils/networktype.h"
#include "utils/config.h"
Prices *AppContext::prices = nullptr;
@@ -37,7 +36,6 @@ WalletKeysFilesModel *AppContext::wallets = nullptr;
TxFiatHistory *AppContext::txFiatHistory = nullptr;
double AppContext::balance = 0;
QMap<QString, QString> AppContext::txDescriptionCache;
QMap<QString, QString> AppContext::txCache;
AppContext::AppContext(QCommandLineParser *cmdargs) {
this->network = new QNetworkAccessManager();
@@ -80,19 +78,13 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
this->accountName = Utils::getUnixAccountName();
this->homeDir = QDir::homePath();
QString walletDir = config()->get(Config::walletDirectory).toString();
if (walletDir.isEmpty()) {
#if defined(Q_OS_LINUX) or defined(Q_OS_MAC)
this->defaultWalletDir = QString("%1/Monero/wallets").arg(this->configRoot);
this->defaultWalletDirRoot = QString("%1/Monero").arg(this->configRoot);
this->defaultWalletDir = QString("%1/Monero/wallets").arg(this->configRoot);
this->defaultWalletDirRoot = QString("%1/Monero").arg(this->configRoot);
#elif defined(Q_OS_WIN)
this->defaultWalletDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/Monero";
this->defaultWalletDirRoot = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
this->defaultWalletDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/Monero";
this->defaultWalletDirRoot = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
#endif
} else {
this->defaultWalletDir = walletDir;
this->defaultWalletDirRoot = walletDir;
}
// Create wallet dirs
if (!QDir().mkpath(defaultWalletDir))
@@ -103,6 +95,7 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
if(!this->configDirectory.endsWith('/'))
this->configDirectory = QString("%1/").arg(this->configDirectory);
#endif
this->sorry();
// Config
createConfigDirectory(this->configDirectory);
@@ -119,6 +112,7 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
this->nodes = new Nodes(this, this->networkClearnet);
connect(this, &AppContext::nodeSourceChanged, this->nodes, &Nodes::onNodeSourceChanged);
connect(this, &AppContext::setCustomNodes, this->nodes, &Nodes::setCustomNodes);
connect(this, &AppContext::walletClosing, this->nodes, &Nodes::onWalletClosing);
// Tor & socks proxy
this->ws = new WSClient(this, m_wsUrl);
@@ -140,11 +134,11 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
auto genesis_timestamp = this->restoreHeights[NetworkType::Type::MAINNET]->data.firstKey();
AppContext::txFiatHistory = new TxFiatHistory(genesis_timestamp, this->configDirectory);
connect(this->ws, &WSClient::connectionEstablished, AppContext::txFiatHistory, &TxFiatHistory::onUpdateDatabase);
connect(AppContext::txFiatHistory, &TxFiatHistory::requestYear, [=](int year){
connect(AppContext::txFiatHistory, &TxFiatHistory::requestYear, [=](unsigned int year){
QByteArray data = QString(R"({"cmd": "txFiatHistory", "data": {"year": %1}})").arg(year).toUtf8();
this->ws->sendMsg(data);
});
connect(AppContext::txFiatHistory, &TxFiatHistory::requestYearMonth, [=](int year, int month) {
connect(AppContext::txFiatHistory, &TxFiatHistory::requestYearMonth, [=](unsigned int year, unsigned int month) {
QByteArray data = QString(R"({"cmd": "txFiatHistory", "data": {"year": %1, "month": %2}})").arg(year).arg(month).toUtf8();
this->ws->sendMsg(data);
});
@@ -153,16 +147,10 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
AppContext::prices = new Prices();
// xmr.to
#ifdef HAS_XMRTO
#if defined(XMRTO)
this->XMRTo = new XmrTo(this);
#endif
// XMRig
#ifdef HAS_XMRIG
this->XMRig = new XmRig(this->configDirectory, this);
this->XMRig->prepare();
#endif
this->walletManager = WalletManager::instance();
QString logPath = QString("%1/daemon.log").arg(configDirectory);
Monero::Utils::onStartup();
@@ -185,7 +173,7 @@ void AppContext::initTor() {
this->tor = new Tor(this, this);
this->tor->start();
if (!(isWhonix)) {
if (!(isTails || isWhonix)) {
auto networkProxy = new QNetworkProxy(QNetworkProxy::Socks5Proxy, Tor::torHost, Tor::torPort);
this->network->setProxy(*networkProxy);
if (m_wsUrl.host().endsWith(".onion"))
@@ -200,7 +188,7 @@ void AppContext::initWS() {
void AppContext::onCancelTransaction(PendingTransaction *tx, const QString &address) {
// tx cancelled by user
double amount = tx->amount() / globals::cdiv;
double amount = tx->amount() / AppContext::cdiv;
emit createTransactionCancelled(address, amount);
this->currentWallet->disposeTransaction(tx);
}
@@ -239,8 +227,8 @@ void AppContext::onCreateTransaction(const QString &address, const double amount
return;
}
auto balance = this->currentWallet->balance() / globals::cdiv;
auto unlocked_balance = this->currentWallet->unlockedBalance() / globals::cdiv;
auto balance = this->currentWallet->balance() / AppContext::cdiv;
auto unlocked_balance = this->currentWallet->unlockedBalance() / AppContext::cdiv;
if(!all && amount > unlocked_balance) {
emit createTransactionError("Not enough money to spend");
return;
@@ -249,7 +237,7 @@ void AppContext::onCreateTransaction(const QString &address, const double amount
return;
}
auto amount_num = static_cast<quint64>(amount * globals::cdiv);
auto amount_num = static_cast<quint64>(amount * AppContext::cdiv);
qDebug() << "creating tx";
if(all || amount == balance)
this->currentWallet->createTransactionAllAsync(address, "", this->tx_mixin, this->tx_priority);
@@ -265,6 +253,7 @@ void AppContext::onCreateTransactionError(const QString &msg) {
}
void AppContext::walletClose(bool emitClosedSignal) {
this->nodes->stopTimer();
if(this->currentWallet == nullptr) return;
emit walletClosing();
//ctx->currentWallet->store(); @TODO: uncomment to store on wallet close
@@ -287,10 +276,6 @@ void AppContext::onOpenWallet(const QString &path, const QString &password){
return;
}
if (password.isEmpty()) {
this->walletPassword = "";
}
config()->set(Config::firstRun, false);
this->walletPath = path;
@@ -325,14 +310,13 @@ void AppContext::onWalletOpened(Wallet *wallet) {
emit walletOpenedError(errMsg);
} else {
this->walletClose(false);
emit walletOpenPasswordNeeded(!this->walletPassword.isEmpty(), wallet->path());
emit walletOpenPasswordNeeded(this->walletPassword.isEmpty());
}
return;
}
this->currentWallet = wallet;
this->walletPath = this->currentWallet->path() + ".keys";
this->walletViewOnly = this->currentWallet->viewOnly();
config()->set(Config::walletPath, this->walletPath);
connect(this->currentWallet, &Wallet::moneySpent, this, &AppContext::onMoneySpent);
@@ -346,12 +330,9 @@ void AppContext::onWalletOpened(Wallet *wallet) {
connect(this->currentWallet, &Wallet::transactionCreated, this, &AppContext::onTransactionCreated);
connect(this->currentWallet, &Wallet::connectionStatusChanged, this, &AppContext::onConnectionStatusChanged);
emit walletOpened();
connect(this->currentWallet, &Wallet::connectionStatusChanged, [this]{
this->nodes->autoConnect();
});
this->nodes->connectToNode();
emit walletOpened();
this->updateBalance();
#ifdef DONATE_BEG
@@ -360,18 +341,6 @@ void AppContext::onWalletOpened(Wallet *wallet) {
// force trigger preferredFiat signal for history model
this->onPreferredFiatCurrencyChanged(config()->get(Config::preferredFiatCurrency).toString());
this->setWindowTitle();
}
void AppContext::setWindowTitle(bool mining) {
QFileInfo fileInfo(this->walletPath);
auto title = QString("Feather - [%1]").arg(fileInfo.fileName());
if(this->walletViewOnly)
title += " [view-only]";
if(mining)
title += " [mining]";
emit setTitle(title);
}
void AppContext::onWSMessage(const QJsonObject &msg) {
@@ -384,22 +353,22 @@ void AppContext::onWSMessage(const QJsonObject &msg) {
auto changed = false;
if(!this->heights.contains("mainnet")) {
this->heights["mainnet"] = mainnet;
this->heights["mainnet"] = (unsigned int) mainnet;
changed = true;
}
else {
if (mainnet > this->heights["mainnet"]) {
this->heights["mainnet"] = mainnet;
this->heights["mainnet"] = (unsigned int) mainnet;
changed = true;
}
}
if(!this->heights.contains("stagenet")) {
this->heights["stagenet"] = stagenet;
this->heights["stagenet"] = (unsigned int) stagenet;
changed = true;
}
else {
if (stagenet > this->heights["stagenet"]) {
this->heights["stagenet"] = stagenet;
this->heights["stagenet"] = (unsigned int) stagenet;
changed = true;
}
}
@@ -411,11 +380,7 @@ void AppContext::onWSMessage(const QJsonObject &msg) {
else if(cmd == "nodes") {
this->onWSNodes(msg.value("data").toArray());
}
#if defined(HAS_XMRIG)
else if(cmd == "xmrig") {
this->XMRigDownloads(msg.value("data").toObject());
}
#endif
else if(cmd == "crypto_rates") {
QJsonArray crypto_rates = msg.value("data").toArray();
AppContext::prices->cryptoPricesReceived(crypto_rates);
@@ -425,7 +390,7 @@ void AppContext::onWSMessage(const QJsonObject &msg) {
QJsonObject fiat_rates = msg.value("data").toObject();
AppContext::prices->fiatPricesReceived(fiat_rates);
}
#if defined(HAS_XMRTO)
#if defined(XMRTO)
else if(cmd == "xmrto_rates") {
auto xmr_rates = msg.value("data").toObject();
this->XMRTo->onRatesReceived(xmr_rates);
@@ -469,8 +434,7 @@ void AppContext::onWSNodes(const QJsonArray &nodes) {
auto node = new FeatherNode(
obj.value("address").toString(),
obj.value("height").toInt(),
obj.value("target_height").toInt(),
(unsigned int)obj.value("height").toInt(),
obj.value("online").toBool());
QSharedPointer<FeatherNode> r = QSharedPointer<FeatherNode>(node);
l.append(r);
@@ -530,16 +494,31 @@ void AppContext::onWSCCS(const QJsonArray &ccs_data) {
}
void AppContext::createConfigDirectory(const QString &dir) {
QString config_dir_tor = QString("%1%2").arg(dir).arg("tor");
QString config_dir_tordata = QString("%1%2").arg(dir).arg("tor/data");
if(!Utils::dirExists(dir)) {
qDebug() << QString("Creating directory: %1").arg(dir);
if(!QDir().mkpath(dir))
throw std::runtime_error("Could not create directory " + dir.toStdString());
}
QStringList createDirs({dir, config_dir_tor, config_dir_tordata});
for(const auto &d: createDirs) {
if(!Utils::dirExists(d)) {
qDebug() << QString("Creating directory: %1").arg(d);
if (!QDir().mkpath(d))
throw std::runtime_error("Could not create directory " + d.toStdString());
}
QString config_dir_tor = QString("%1%2").arg(dir).arg("tor");
if(!Utils::dirExists(config_dir_tor)) {
qDebug() << QString("Creating directory: %1").arg(config_dir_tor);
if (!QDir().mkpath(config_dir_tor))
throw std::runtime_error("Could not create directory " + config_dir_tor.toStdString());
}
QString config_dir_tordata = QString("%1%2").arg(dir).arg("tor/data");
if(!Utils::dirExists(config_dir_tordata)) {
qDebug() << QString("Creating directory: %1").arg(config_dir_tordata);
if (!QDir().mkpath(config_dir_tordata))
throw std::runtime_error("Could not create directory " + config_dir_tordata.toStdString());
}
QString config_dir_torsocks = QString("%1%2").arg(dir).arg("torsocks");
if(!Utils::dirExists(config_dir_torsocks)) {
qDebug() << QString("Creating directory: %1").arg(config_dir_torsocks);
if (!QDir().mkpath(config_dir_torsocks))
throw std::runtime_error("Could not create directory " + config_dir_torsocks.toStdString());
}
}
@@ -562,43 +541,6 @@ void AppContext::createWallet(FeatherSeed seed, const QString &path, const QStri
return;
}
this->createWalletFinish(password);
}
void AppContext::createWalletViewOnly(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight) {
if(Utils::fileExists(path)) {
auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path);
qCritical() << err;
emit walletCreatedError(err);
return;
}
if(!this->walletManager->addressValid(address, this->networkType)) {
auto err = QString("Failed to create wallet. Invalid address provided.").arg(path);
qCritical() << err;
emit walletCreatedError(err);
return;
}
if(!this->walletManager->keyValid(viewkey, address, true, this->networkType)) {
auto err = QString("Failed to create wallet. Invalid viewkey provided.").arg(path);
qCritical() << err;
emit walletCreatedError(err);
return;
}
if(!spendkey.isEmpty() && !this->walletManager->keyValid(spendkey, address, false, this->networkType)) {
auto err = QString("Failed to create wallet. Invalid spendkey provided.").arg(path);
qCritical() << err;
emit walletCreatedError(err);
return;
}
this->currentWallet = this->walletManager->createWalletFromKeys(path, this->seedLanguage, this->networkType, address, viewkey, spendkey, restoreHeight);
this->createWalletFinish(password);
}
void AppContext::createWalletFinish(const QString &password) {
this->currentWallet->setPassword(password);
this->currentWallet->store();
this->walletPassword = password;
@@ -611,7 +553,7 @@ void AppContext::initRestoreHeights() {
restoreHeights[NetworkType::MAINNET] = RestoreHeightLookup::fromFile(":/assets/restore_heights_monero_mainnet.txt", NetworkType::MAINNET);
}
void AppContext::onSetRestoreHeight(quint64 height){
void AppContext::onSetRestoreHeight(unsigned int height){
auto seed = this->currentWallet->getCacheAttribute("feather.seed");
if(!seed.isEmpty()) {
const auto msg = "This wallet has a 14 word mnemonic seed which has the restore height embedded.";
@@ -620,7 +562,7 @@ void AppContext::onSetRestoreHeight(quint64 height){
}
this->currentWallet->setWalletCreationHeight(height);
this->currentWallet->setPassword(this->currentWallet->getPassword()); // trigger .keys write
this->currentWallet->setPassword(this->walletPassword); // trigger .keys write
// nuke wallet cache
const auto fn = this->currentWallet->path();
@@ -672,9 +614,8 @@ void AppContext::onOpenAliasResolve(const QString &openAlias) {
}
void AppContext::donateBeg() {
if(this->currentWallet == nullptr) return;
if(this->networkType != NetworkType::Type::MAINNET) return;
if(this->currentWallet->viewOnly()) return;
if(this->networkType != NetworkType::Type::MAINNET)
return;
auto donationCounter = config()->get(Config::donateBeg).toInt();
if(donationCounter == -1)
@@ -686,6 +627,15 @@ void AppContext::donateBeg() {
config()->set(Config::donateBeg, donationCounter);
}
void AppContext::sorry() {
auto msg = "Unable to start Feather, error code 0xd34db33f. If this problem "
"persists, please contact Technical Support.";
QStringList paths = {"C:\\ProgramData\\ryo", this->homeDir + "/.ryo"};
for(const QString &ryo: paths)
if(Utils::dirExists(ryo))
throw std::runtime_error(msg);
}
AppContext::~AppContext() {
this->walletClose(false);
}
@@ -693,19 +643,19 @@ AppContext::~AppContext() {
// ############################################## LIBWALLET QT #########################################################
void AppContext::onMoneySpent(const QString &txId, quint64 amount) {
auto amount_num = amount / globals::cdiv;
auto amount_num = amount / AppContext::cdiv;
qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
}
void AppContext::onMoneyReceived(const QString &txId, quint64 amount) {
// Incoming tx included in a block.
auto amount_num = amount / globals::cdiv;
auto amount_num = amount / AppContext::cdiv;
qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
}
void AppContext::onUnconfirmedMoneyReceived(const QString &txId, quint64 amount) {
// Incoming transaction in pool
auto amount_num = amount / globals::cdiv;
auto amount_num = amount / AppContext::cdiv;
qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
if(this->currentWallet->synchronized()) {
@@ -723,16 +673,13 @@ void AppContext::onWalletUpdate() {
this->storeWallet();
}
void AppContext::onWalletRefreshed(bool success) {
void AppContext::onWalletRefreshed() {
if (!this->refreshed) {
refreshModels();
this->refreshed = true;
// store wallet immediately upon finishing synchronization
this->currentWallet->store();
this->storeWallet();
}
qDebug() << "Wallet refresh status: " << success;
this->currentWallet->refreshHeightAsync();
}
@@ -749,7 +696,7 @@ void AppContext::onWalletNewBlock(quint64 blockheight, quint64 targetHeight) {
void AppContext::onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) {
qDebug() << Q_FUNC_INFO << walletHeight << daemonHeight << targetHeight;
if (this->currentWallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected)
if (!this->currentWallet->connected())
return;
if (daemonHeight < targetHeight) {
@@ -761,28 +708,23 @@ void AppContext::onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, q
}
void AppContext::onTransactionCreated(PendingTransaction *tx, const QString &address, const QString &paymentId, quint32 mixin) {
if(address == this->donationAddress)
this->donationSending = true;
// Let UI know that the transaction was constructed
emit endTransaction();
if(address == this->featherDonationAddress)
this->featherDonationSending = true;
// tx created, but not sent yet. ask user to verify first.
emit createTransactionSuccess(tx, address, mixin);
emit endTransaction();
}
void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid){
this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount());
this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount());
// Store wallet immediately so we don't risk losing tx key if wallet crashes
this->currentWallet->store();
this->storeWallet();
emit transactionCommitted(status, tx, txid);
// this tx was a donation to Feather, stop our nagging
if(this->donationSending) {
this->donationSending = false;
if(this->featherDonationSending) {
this->featherDonationSending = false;
config()->set(Config::donateBeg, -1);
}
}
@@ -799,14 +741,16 @@ void AppContext::storeWallet() {
}
void AppContext::updateBalance() {
if (!this->currentWallet)
return;
if(!this->currentWallet)
throw std::runtime_error("this should not happen, ever");
quint64 balance_u = this->currentWallet->balance();
AppContext::balance = balance_u / globals::cdiv;
double spendable = this->currentWallet->unlockedBalance();
AppContext::balance = this->currentWallet->balance() / AppContext::cdiv;
auto balance_str = QString::number(balance, 'f');
emit balanceUpdated(balance_u, spendable);
double unlocked = this->currentWallet->unlockedBalance() / AppContext::cdiv;
auto unlocked_str = QString::number(unlocked, 'f');
emit balanceUpdated(balance, unlocked, balance_str, unlocked_str);
}
void AppContext::syncStatusUpdated(quint64 height, quint64 target) {
+16 -25
View File
@@ -14,7 +14,6 @@
#include "utils/networking.h"
#include "utils/tor.h"
#include "utils/xmrto.h"
#include "utils/xmrig.h"
#include "utils/wsclient.h"
#include "utils/txfiathistory.h"
#include "widgets/RedditPost.h"
@@ -39,11 +38,9 @@ public:
bool isTails = false;
bool isWhonix = false;
bool isDebug = false;
// Donation config
const QString donationAddress = "47ntfT2Z5384zku39pTM6hGcnLnvpRYW2Azm87GiAAH2bcTidtq278TL6HmwyL8yjMeERqGEBs3cqC8vvHPJd1cWQrGC65f";
const int donationAmount = 25; // euro
bool donationSending = false;
const QString featherDonationAddress = "47ntfT2Z5384zku39pTM6hGcnLnvpRYW2Azm87GiAAH2bcTidtq278TL6HmwyL8yjMeERqGEBs3cqC8vvHPJd1cWQrGC65f";
const int featherDonationAmount = 50; // euro
bool featherDonationSending = false;
QCommandLineParser *cmdargs;
@@ -59,19 +56,18 @@ public:
QString walletPath;
QString walletPassword = "";
bool walletViewOnly = false;
NetworkType::Type networkType;
QString applicationPath;
static void createConfigDirectory(const QString &dir) ;
QMap<QString, int> heights;
QMap<QString, unsigned int> heights;
QMap<NetworkType::Type, RestoreHeightLookup*> restoreHeights;
const quint64 kdfRounds = 1;
const unsigned int kdfRounds = 1;
PendingTransaction::Priority tx_priority = PendingTransaction::Priority::Priority_Low;
quint32 tx_mixin = static_cast<const quint32 &>(10);
QString seedLanguage = "English"; // 14 word `monero-seed` only has English
static constexpr const double cdiv = 1e12;
QNetworkAccessManager *network;
QNetworkAccessManager *networkClearnet;
@@ -80,22 +76,19 @@ public:
Tor *tor;
WSClient *ws;
XmrTo *XMRTo;
XmRig *XMRig;
Nodes *nodes;
static Prices *prices;
static WalletKeysFilesModel *wallets;
static double balance;
static QMap<QString, QString> txDescriptionCache;
static QMap<QString, QString> txCache;
static TxFiatHistory *txFiatHistory;
// libwalletqt
unsigned int blockHeight = 0;
bool refreshed = false;
WalletManager *walletManager;
Wallet *currentWallet = nullptr;
void createWallet(FeatherSeed seed, const QString &path, const QString &password);
void createWalletViewOnly(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight);
void createWalletFinish(const QString &password);
void syncStatusUpdated(quint64 height, quint64 target);
void updateBalance();
void initTor();
@@ -105,7 +98,6 @@ public:
void walletClose(bool emitClosedSignal = true);
void storeWallet();
void refreshModels();
void setWindowTitle(bool mining = false);
public slots:
void onOpenWallet(const QString& path, const QString &password);
@@ -115,7 +107,7 @@ public slots:
void onSweepOutput(const QString &keyImage, QString address, bool churn, int outputs) const;
void onCreateTransactionError(const QString &msg);
void onOpenAliasResolve(const QString &openAlias);
void onSetRestoreHeight(quint64 height);
void onSetRestoreHeight(unsigned int height);
void onPreferredFiatCurrencyChanged(const QString &symbol);
private slots:
@@ -128,7 +120,7 @@ private slots:
void onMoneyReceived(const QString &txId, quint64 amount);
void onUnconfirmedMoneyReceived(const QString &txId, quint64 amount);
void onWalletUpdate();
void onWalletRefreshed(bool success);
void onWalletRefreshed();
void onWalletOpened(Wallet *wallet);
void onWalletNewBlock(quint64 blockheight, quint64 targetHeight);
void onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight);
@@ -137,18 +129,18 @@ private slots:
void onConnectionStatusChanged(int status);
signals:
void balanceUpdated(quint64 balance, quint64 spendable);
void balanceUpdated(double balance, double unlocked, QString balance_str, QString unlocked_str);
void blockchainSync(int height, int target);
void refreshSync(int height, int target);
void synchronized();
void blockHeightWSUpdated(QMap<QString, int> heights);
void blockHeightWSUpdated(QMap<QString, unsigned int> heights);
void walletSynchronized();
void walletOpened();
void walletClosed();
void walletCreatedError(const QString &msg);
void walletCreated(Wallet *wallet);
void walletOpenedError(QString msg);
void walletOpenPasswordNeeded(bool invalidPassword, QString path);
void walletOpenPasswordNeeded(bool invalidPassword);
void transactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid);
void createTransactionError(QString message);
void createTransactionCancelled(QString address, double amount);
@@ -157,25 +149,24 @@ signals:
void nodesUpdated(QList<QSharedPointer<FeatherNode>> &nodes);
void ccsUpdated(QList<QSharedPointer<CCSEntry>> &entries);
void nodeSourceChanged(NodeSource nodeSource);
void XMRigDownloads(const QJsonObject &data);
void setCustomNodes(QList<FeatherNode> nodes);
void ccsEmpty();
void openAliasResolveError(const QString &msg);
void openAliasResolved(const QString &address, const QString &openAlias);
void setRestoreHeightError(const QString &msg);
void customRestoreHeightSet(int height);
void customRestoreHeightSet(unsigned int height);
void closeApplication();
void donationNag();
void initiateTransaction();
void endTransaction();
void walletClosing();
void setTitle(const QString &title); // set window title
private:
const int m_donationBoundary = 15;
void sorry();
const unsigned int m_donationBoundary = 15;
UtilsNetworking *m_utilsNetworkingNodes;
QTimer *m_storeTimer = new QTimer(this);
QUrl m_wsUrl = QUrl(QStringLiteral("ws://7e6egbawekbkxzkv4244pqeqgoo4axko2imgjbedwnn6s5yb6b7oliqd.onion/ws"));
QUrl m_wsUrl = QUrl(QStringLiteral("ws://dtg2clrd6iand4mwp2x6nhbqd3nqbxlbiw65f6vkwmmutxy2sijsnjyd.onion/ws"));
};
#endif //FEATHER_APPCONTEXT_H
+3 -11
View File
@@ -11,9 +11,6 @@
<file>assets/images/appicons/128x128.png</file>
<file>assets/images/appicons/256x256.png</file>
<file>assets/images/arrow.svg</file>
<file>assets/images/banners/1.png</file>
<file>assets/images/banners/2.png</file>
<file>assets/images/banners/3.png</file>
<file>assets/images/bitcoin.png</file>
<file>assets/images/camera_dark.png</file>
<file>assets/images/camera_white.png</file>
@@ -26,7 +23,6 @@
<file>assets/images/coldcard.png</file>
<file>assets/images/coldcard_unpaired.png</file>
<file>assets/images/confirmed.png</file>
<file>assets/images/confirmed_icon.png</file>
<file>assets/images/confirmed.svg</file>
<file>assets/images/connect.svg</file>
<file>assets/images/copy.png</file>
@@ -34,12 +30,10 @@
<file>assets/images/edit.png</file>
<file>assets/images/exchange.png</file>
<file>assets/images/expired.png</file>
<file>assets/images/expired_icon.png</file>
<file>assets/images/eye1.png</file>
<file>assets/images/eye_blind.png</file>
<file>assets/images/feather.png</file>
<file>assets/images/file.png</file>
<file>assets/images/gnome-calc.png</file>
<file>assets/images/ghost.png</file>
<file>assets/images/history.png</file>
<file>assets/images/info.png</file>
<file>assets/images/key.png</file>
@@ -47,13 +41,12 @@
<file>assets/images/ledger_unpaired.png</file>
<file>assets/images/lightning.png</file>
<file>assets/images/lock.png</file>
<file>assets/images/lock_icon.png</file>
<file>assets/images/lock.svg</file>
<file>assets/images/microphone.png</file>
<file>assets/images/mining.png</file>
<file>assets/images/network.png</file>
<file>assets/images/offline_tx.png</file>
<file>assets/images/person.svg</file>
<file>assets/images/photos/1.png</file>
<file>assets/images/preferences.png</file>
<file>assets/images/preferences.svg</file>
<file>assets/images/qrcode.png</file>
@@ -98,11 +91,10 @@
<file>assets/images/warning.png</file>
<file>assets/images/xmrto_big.png</file>
<file>assets/images/xmrto.png</file>
<file>assets/images/xmrig.ico</file>
<file>assets/images/xmrig.svg</file>
<file>assets/images/zoom.png</file>
<file>assets/mnemonic_25_english.txt</file>
<file>assets/restore_heights_monero_mainnet.txt</file>
<file>assets/restore_heights_monero_stagenet.txt</file>
<file>assets/user_agents.txt</file>
</qresource>
</RCC>
+2 -4
View File
@@ -1,11 +1,9 @@
The wallet UI is heavily inspired by Electrum. We would like to recognize Thomas Voegtlin for his pioneering work on Bitcoin.
Feather uses monero-seed written by Tevador, for 14 word mnemonic seeds.
Wizard banner art was adapted from a paper wallet design by the themonera (themonera.art).
Initial CMake support for the Monero GUI was coded by TheCharlatan/xiphon.
The wallet UI is heavily inspired by Electrum. We would like to recognize Thomas Voegtlin for his pioneering work on Bitcoin.
Huge thanks to nioc, fluffypony, wowario, thrmo for help during development.
Some more shoutouts for people for hosting nodes and/or having good ideas:
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 496.06 496.06"><title>XMRig</title><defs><style>.a{fill:none;}.b{clip-path:url(#a);}.c{fill:#ec671a;}.d{fill:#575756;}.e{fill:#fff;}</style><clipPath id="a" transform="translate(-106.3 -106.3)"><circle class="a" cx="354.33" cy="354.33" r="248.03"/></clipPath></defs><title>Xr_icon</title><g class="b"><rect class="c" width="496.06" height="496.06"/><polygon class="d" points="496.06 496.06 0 496.06 0 387.21 124.02 387.55 189.12 291.44 254.23 387.55 496.06 387.55 496.06 496.06"/><path class="e" d="M481.44,441.14c0-13.18,0-27,0-37.32,0-54.11,22.15-77.57,55.82-52.71-0.39.07,27.9-43.41,27.9-43.41-35.68-24.09-67.09-10.17-86.81,19.45V295.42H428.74V441.14H391.12l-61-91.46,89.91-134.87H351.85L296,298.52l-55.81-83.71H172l89.91,134.87-61,91.46H106.3v52.37l59.65,0.16-0.12.18H234l62-93,62,93H602.36V441.14H481.44Z" transform="translate(-106.3 -106.3)"/></g></svg>

Before

Width:  |  Height:  |  Size: 955 B

File diff suppressed because it is too large Load Diff
@@ -1,5 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>assets/exec/tor</file>
<file>tor/tor</file>
</qresource>
</RCC>
+6
View File
@@ -0,0 +1,6 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>tor/tor</file>
<file>tor/libevent-2.1.7.dylib</file>
</qresource>
</RCC>
-6
View File
@@ -1,6 +0,0 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>assets/exec/tor</file>
<file>assets/exec/libevent-2.1.7.dylib</file>
</qresource>
</RCC>
+5
View File
@@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>tor/tor.exe</file>
</qresource>
</RCC>
+1 -1
View File
@@ -58,7 +58,7 @@ void CLI::onWalletOpenedError(const QString &err) {
return this->finishedError(err);
}
void CLI::onWalletOpenPasswordRequired(bool invalidPassword, const QString &path) {
void CLI::onWalletOpenPasswordRequired(bool invalidPassword) {
if(mode == CLIMode::CLIModeExportContacts ||
mode == CLIMode::CLIModeExportTxHistory)
return this->finishedError("invalid password");
+1 -1
View File
@@ -26,7 +26,7 @@ public slots:
//libwalletqt
void onWalletOpened();
void onWalletOpenedError(const QString& err);
void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path);
void onWalletOpenPasswordRequired(bool invalidPassword);
private:
AppContext *ctx;
+11 -30
View File
@@ -7,14 +7,12 @@
#include "utils/utils.h"
#include "dialog/outputinfodialog.h"
#include "dialog/outputsweepdialog.h"
#include "mainwindow.h"
#include <QClipboard>
#include <QDebug>
#include <QKeyEvent>
#include <QMenu>
#include <QAction>
#include <QMessageBox>
CoinsWidget::CoinsWidget(QWidget *parent)
: QWidget(parent)
@@ -23,7 +21,6 @@ CoinsWidget::CoinsWidget(QWidget *parent)
, m_copyMenu(new QMenu("Copy",this))
{
ui->setupUi(this);
m_ctx = MainWindow::getContext();
// header context menu
ui->coins->header()->setContextMenuPolicy(Qt::CustomContextMenu);
@@ -37,21 +34,20 @@ CoinsWidget::CoinsWidget(QWidget *parent)
m_copyMenu->addAction("Key Image", this, [this]{copy(copyField::KeyImage);});
m_copyMenu->addAction("Transaction ID", this, [this]{copy(copyField::TxID);});
m_copyMenu->addAction("Address", this, [this]{copy(copyField::Address);});
m_copyMenu->addAction("Label", this, [this]{copy(copyField::Label);});
m_copyMenu->addAction("Height", this, [this]{copy(copyField::Height);});
m_copyMenu->addAction("Amount", this, [this]{copy(copyField::Amount);});
// context menu
ui->coins->setContextMenuPolicy(Qt::CustomContextMenu);
m_thawOutputAction = new QAction("Thaw output", this);
m_freezeOutputAction = new QAction("Freeze output", this);
m_thawOutputAction = new QAction("Thaw output");
m_freezeOutputAction = new QAction("Freeze output");
m_freezeAllSelectedAction = new QAction("Freeze selected", this);
m_thawAllSelectedAction = new QAction("Thaw selected", this);
m_freezeAllSelectedAction = new QAction("Freeze selected");
m_thawAllSelectedAction = new QAction("Thaw selected");
m_viewOutputAction = new QAction(QIcon(":/assets/images/info.png"), "Details", this);
m_sweepOutputAction = new QAction("Sweep output", this);
m_viewOutputAction = new QAction(QIcon(":/assets/images/info.png"), "Details");
m_sweepOutputAction = new QAction("Sweep output");
connect(m_freezeOutputAction, &QAction::triggered, this, &CoinsWidget::freezeOutput);
connect(m_thawOutputAction, &QAction::triggered, this, &CoinsWidget::thawOutput);
connect(m_viewOutputAction, &QAction::triggered, this, &CoinsWidget::viewOutput);
@@ -67,19 +63,13 @@ CoinsWidget::CoinsWidget(QWidget *parent)
void CoinsWidget::setModel(CoinsModel * model, Coins * coins) {
m_coins = coins;
m_model = model;
m_proxyModel = new CoinsProxyModel(this);
m_proxyModel = new CoinsProxyModel;
m_proxyModel->setSourceModel(m_model);
ui->coins->setModel(m_proxyModel);
ui->coins->setColumnHidden(CoinsModel::Spent, true);
ui->coins->setColumnHidden(CoinsModel::SpentHeight, true);
ui->coins->setColumnHidden(CoinsModel::Frozen, true);
if (!m_ctx->currentWallet->viewOnly()) {
ui->coins->setColumnHidden(CoinsModel::KeyImageKnown, true);
} else {
ui->coins->setColumnHidden(CoinsModel::KeyImageKnown, false);
}
ui->coins->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
ui->coins->header()->setSectionResizeMode(CoinsModel::AddressLabel, QHeaderView::Stretch);
ui->coins->header()->setSortIndicator(CoinsModel::BlockHeight, Qt::DescendingOrder);
@@ -113,15 +103,10 @@ void CoinsWidget::showContextMenu(const QPoint &point) {
if (!isSpent) {
isFrozen ? menu->addAction(m_thawOutputAction) : menu->addAction(m_freezeOutputAction);
menu->addAction(m_sweepOutputAction);
if (isFrozen || !isUnlocked) {
m_sweepOutputAction->setDisabled(true);
} else {
m_sweepOutputAction->setEnabled(true);
}
}
if (!isFrozen && isUnlocked) {
menu->addAction(m_sweepOutputAction);
}
menu->addAction(m_viewOutputAction);
}
@@ -198,7 +183,7 @@ void CoinsWidget::onSweepOutput() {
qCritical() << "key image: " << keyImage;
if (!keyImageKnown) {
QMessageBox::warning(this, "Unable to sweep output", "Unable to sweep output: key image unknown");
Utils::showMessageBox("Unable to sweep output", "Unable to sweep output: key image unknown", true);
return;
}
@@ -209,7 +194,6 @@ void CoinsWidget::onSweepOutput() {
qCritical() << "key image: " << keyImage;
emit sweepOutput(keyImage, dialog->address(), dialog->churn(), dialog->outputs());
dialog->deleteLater();
}
void CoinsWidget::copy(copyField field) {
@@ -231,9 +215,6 @@ void CoinsWidget::copy(copyField field) {
case Address:
data = c.address();
break;
case Label:
data = c.addressLabel();
break;
case Height:
data = QString::number(c.blockHeight());
break;
-2
View File
@@ -48,7 +48,6 @@ private:
KeyImage,
TxID,
Address,
Label,
Height,
Amount
};
@@ -68,7 +67,6 @@ private:
Coins *m_coins;
CoinsModel * m_model;
CoinsProxyModel * m_proxyModel;
AppContext *m_ctx;
void showContextMenu(const QPoint & point);
void copy(copyField field);
+3 -1
View File
@@ -68,7 +68,9 @@ HelpLabel::HelpLabel(QWidget *parent) : QLabel(parent)
void HelpLabel::mouseReleaseEvent(QMouseEvent *event)
{
Q_UNUSED(event)
QMessageBox::information(this, "Help", this->help_text);
QMessageBox msgBox(QApplication::activeWindow());
msgBox.setText(this->help_text);
msgBox.exec();
}
void HelpLabel::enterEvent(QEvent *event)
+13 -42
View File
@@ -5,17 +5,17 @@
#include "ui_contactswidget.h"
#include "dialog/contactsdialog.h"
#include "model/ModelUtils.h"
#include "mainwindow.h"
#include "libwalletqt/AddressBook.h"
#include "utils/utils.h"
#include <QMessageBox>
#include <QClipboard>
#include <QDebug>
#include <QKeyEvent>
ContactsWidget::ContactsWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ContactsWidget)
{
ui->setupUi(this);
m_ctx = MainWindow::getContext();
// header context menu
ui->contacts->header()->setContextMenuPolicy(Qt::CustomContextMenu);
@@ -28,16 +28,15 @@ ContactsWidget::ContactsWidget(QWidget *parent) :
// context menu
ui->contacts->setContextMenuPolicy(Qt::CustomContextMenu);
m_contextMenu = new QMenu(ui->contacts);
m_contextMenu->addAction(QIcon(":/assets/images/person.svg"), "New contact", [this]{
this->newContact();
});
m_contextMenu->addAction(QIcon(":/assets/images/person.svg"), "New contact", this, &ContactsWidget::newContact);
// row context menu
m_rowMenu = new QMenu(ui->contacts);
m_rowMenu->addAction(QIcon(":/assets/images/copy.png"), "Copy address", this, &ContactsWidget::copyAddress);
m_rowMenu->addAction(QIcon(":/assets/images/copy.png"), "Copy name", this, &ContactsWidget::copyName);
m_rowMenu->addAction("Pay to", this, &ContactsWidget::payTo);
m_rowMenu->addAction("Delete", this, &ContactsWidget::deleteContact);
m_rowMenu->addAction(QIcon(":/assets/images/appicons/128x128.png"), "Pay to", this, &ContactsWidget::payTo);
m_deleteEntryAction = m_rowMenu->addAction("Delete", this, &ContactsWidget::deleteContact);
connect(ui->contacts, &QTreeView::customContextMenuRequested, [=](const QPoint & point){
QModelIndex index = ui->contacts->indexAt(point);
@@ -96,44 +95,16 @@ void ContactsWidget::showHeaderMenu(const QPoint& position)
m_headerMenu->exec(QCursor::pos());
}
void ContactsWidget::newContact(QString address, QString name)
void ContactsWidget::newContact()
{
auto * dialog = new ContactsDialog(this, address, name);
auto * dialog = new ContactsDialog(this);
int ret = dialog->exec();
if (!ret) return;
address = dialog->getAddress();
name = dialog->getName();
QString address = dialog->getAddress();
QString name = dialog->getName();
bool addressValid = WalletManager::addressValid(address, m_ctx->currentWallet->nettype());
if (!addressValid) {
QMessageBox::warning(this, "Invalid address", "Invalid address");
return;
}
int num_addresses = m_ctx->currentWallet->addressBook()->count();
QString address_entry;
QString name_entry;
for (int i=0; i<num_addresses; i++) {
m_ctx->currentWallet->addressBook()->getRow(i, [&address_entry, &name_entry](const AddressBookInfo &entry){
address_entry = entry.address();
name_entry = entry.description();
});
if (address == address_entry) {
QMessageBox::warning(this, "Unable to add contact", "Duplicate address");
ui->contacts->setCurrentIndex(m_model->index(i,0)); // Highlight duplicate address
return;
}
if (name == name_entry) {
QMessageBox::warning(this, "Unable to add contact", "Duplicate label");
this->newContact(address, name);
return;
}
}
m_ctx->currentWallet->addressBook()->addRow(address, "", name);
m_ctx->storeWallet();
emit addContact(address, name);
}
void ContactsWidget::deleteContact()
+5 -5
View File
@@ -6,7 +6,6 @@
#include "model/AddressBookModel.h"
#include "model/AddressBookProxyModel.h"
#include "appcontext.h"
#include <QWidget>
#include <QMenu>
@@ -22,28 +21,29 @@ class ContactsWidget : public QWidget
public:
explicit ContactsWidget(QWidget *parent = nullptr);
void setModel(AddressBookModel * model);
~ContactsWidget() override;
~ContactsWidget();
public slots:
void copyAddress();
void copyName();
void payTo();
void newContact(QString address = "", QString name = "");
void newContact();
void deleteContact();
void setShowFullAddresses(bool show);
void setSearchFilter(const QString &filter);
signals:
void addContact(QString &address, QString &name);
void fillAddress(QString &address);
private slots:
void showHeaderMenu(const QPoint &position);
void showHeaderMenu(const QPoint& position);
private:
Ui::ContactsWidget *ui;
AppContext *m_ctx;
QAction *m_showFullAddressesAction;
QAction *m_deleteEntryAction;
QMenu *m_rowMenu;
QMenu *m_contextMenu;
QMenu *m_headerMenu;
+1 -1
View File
@@ -53,7 +53,7 @@
<item>
<widget class="QPlainTextEdit" name="copyrightText">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
-27
View File
@@ -1,27 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#include "balancedialog.h"
#include "ui_balancedialog.h"
#include "libwalletqt/WalletManager.h"
BalanceDialog::BalanceDialog(QWidget *parent, Wallet *wallet)
: QDialog(parent)
, ui(new Ui::BalanceDialog)
{
ui->setupUi(this);
ui->label_unconfirmed_help->setHelpText("Outputs require 10 confirmations before they become spendable. "
"This will take 20 minutes on average.");
ui->label_unconfirmed->setText(WalletManager::displayAmount(wallet->balance() - wallet->unlockedBalance()));
ui->label_spendable->setText(WalletManager::displayAmount(wallet->unlockedBalance()));
ui->label_total->setText(WalletManager::displayAmount(wallet->balance()));
this->adjustSize();
}
BalanceDialog::~BalanceDialog() {
delete ui;
}
-27
View File
@@ -1,27 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#ifndef FEATHER_BALANCEDIALOG_H
#define FEATHER_BALANCEDIALOG_H
#include "libwalletqt/Wallet.h"
#include <QDialog>
namespace Ui {
class BalanceDialog;
}
class BalanceDialog : public QDialog
{
Q_OBJECT
public:
explicit BalanceDialog(QWidget *parent, Wallet *wallet);
~BalanceDialog() override;
private:
Ui::BalanceDialog *ui;
};
#endif //FEATHER_BALANCEDIALOG_H
-142
View File
@@ -1,142 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BalanceDialog</class>
<widget class="QDialog" name="BalanceDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>405</width>
<height>162</height>
</rect>
</property>
<property name="windowTitle">
<string>Balance</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="HelpLabel" name="label_unconfirmed_help">
<property name="text">
<string>Unconfirmed</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_unconfirmed">
<property name="text">
<string>0.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_spendable_help">
<property name="text">
<string>Spendable</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_spendable">
<property name="text">
<string>0.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Total</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_total">
<property name="text">
<string>0.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>HelpLabel</class>
<extends>QLabel</extends>
<header>components.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>BalanceDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>BalanceDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
-67
View File
@@ -1,67 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#include "broadcasttxdialog.h"
#include "ui_broadcasttxdialog.h"
#include "utils/nodes.h"
#include <QMessageBox>
BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, AppContext *ctx, const QString &transactionHex)
: QDialog(parent)
, m_ctx(ctx)
, ui(new Ui::BroadcastTxDialog)
{
ui->setupUi(this);
m_network = new UtilsNetworking(m_ctx->network, this);
auto node = ctx->nodes->connection();
m_rpc = new DaemonRpc(this, m_network, node.full);
connect(ui->btn_Broadcast, &QPushButton::clicked, this, &BroadcastTxDialog::broadcastTx);
connect(ui->btn_Close, &QPushButton::clicked, this, &BroadcastTxDialog::reject);
connect(m_rpc, &DaemonRpc::ApiResponse, this, &BroadcastTxDialog::onApiResponse);
if (!transactionHex.isEmpty()) {
ui->transaction->setPlainText(transactionHex);
}
this->adjustSize();
}
void BroadcastTxDialog::broadcastTx() {
QString tx = ui->transaction->toPlainText();
QString node = [this]{
QString node;
if (ui->radio_useCustom->isChecked())
node = ui->customNode->text();
else if (ui->radio_useDefault->isChecked())
node = m_ctx->nodes->connection().full;
if (!node.startsWith("http://"))
node = QString("http://%1").arg(node);
return node;
}();
m_rpc->setDaemonAddress(node);
m_rpc->sendRawTransaction(tx);
}
void BroadcastTxDialog::onApiResponse(const DaemonRpc::DaemonResponse &resp) {
if (!resp.ok) {
QMessageBox::warning(this, "Transaction broadcast", resp.status);
return;
}
if (resp.endpoint == DaemonRpc::Endpoint::SEND_RAW_TRANSACTION) {
QMessageBox::information(this, "Transaction broadcast", "Transaction submitted successfully.\n\n"
"If the transaction belongs to this wallet it may take several minutes before it shows up in the history tab.");
}
}
BroadcastTxDialog::~BroadcastTxDialog() {
delete ui;
}
-35
View File
@@ -1,35 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#ifndef FEATHER_BROADCASTTXDIALOG_H
#define FEATHER_BROADCASTTXDIALOG_H
#include <QDialog>
#include "appcontext.h"
#include "utils/daemonrpc.h"
namespace Ui {
class BroadcastTxDialog;
}
class BroadcastTxDialog : public QDialog
{
Q_OBJECT
public:
explicit BroadcastTxDialog(QWidget *parent, AppContext *ctx, const QString &transactionHex = "");
~BroadcastTxDialog() override;
private slots:
void broadcastTx();
void onApiResponse(const DaemonRpc::DaemonResponse &resp);
private:
Ui::BroadcastTxDialog *ui;
UtilsNetworking *m_network;
AppContext *m_ctx;
DaemonRpc *m_rpc;
};
#endif //FEATHER_BROADCASTTXDIALOG_H
-101
View File
@@ -1,101 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BroadcastTxDialog</class>
<widget class="QDialog" name="BroadcastTxDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>797</width>
<height>575</height>
</rect>
</property>
<property name="windowTitle">
<string>Broadcast transaction</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Transaction:</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="transaction">
<property name="minimumSize">
<size>
<width>500</width>
<height>0</height>
</size>
</property>
<property name="placeholderText">
<string>Paste hex encoded signed tx string here</string>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Node</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QRadioButton" name="radio_useDefault">
<property name="text">
<string>Use currently connected node</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radio_useCustom">
<property name="text">
<string>Use custom node</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="customNode"/>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btn_Broadcast">
<property name="text">
<string>Broadcast</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_Close">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+1 -7
View File
@@ -4,19 +4,13 @@
#include "ui_contactsdialog.h"
#include "contactsdialog.h"
ContactsDialog::ContactsDialog(QWidget *parent, const QString &address, const QString &name)
ContactsDialog::ContactsDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::ContactsDialog)
{
ui->setupUi(this);
setMinimumWidth(400);
ui->lineEdit_address->setText(address);
ui->lineEdit_name->setText(name);
if (!name.isEmpty()) {
ui->lineEdit_name->setFocus();
}
connect(ui->buttonBox, &QDialogButtonBox::accepted, [&](){
m_address = ui->lineEdit_address->text();
m_name = ui->lineEdit_name->text();
+1 -1
View File
@@ -15,7 +15,7 @@ class ContactsDialog : public QDialog
Q_OBJECT
public:
explicit ContactsDialog(QWidget *parent = nullptr, const QString &address = "", const QString &name = "");
explicit ContactsDialog(QWidget *parent = nullptr);
~ContactsDialog() override;
QString getAddress();
+33 -56
View File
@@ -12,34 +12,15 @@
DebugInfoDialog::DebugInfoDialog(AppContext *ctx, QWidget *parent)
: QDialog(parent)
, ui(new Ui::DebugInfoDialog)
, m_ctx(ctx)
{
ui->setupUi(this);
connect(ui->btn_Copy, &QPushButton::clicked, this, &DebugInfoDialog::copyToClipboad);
m_updateTimer.start(5000);
connect(&m_updateTimer, &QTimer::timeout, this, &DebugInfoDialog::updateInfo);
this->updateInfo();
this->adjustSize();
}
void DebugInfoDialog::updateInfo() {
QString torStatus;
// Special case for Tails because we know the status of the daemon by polling tails-tor-has-bootstrapped.target
if(m_ctx->isTails) {
if(m_ctx->tor->torConnected)
torStatus = "Connected";
else
torStatus = "Disconnected";
}
else if(m_ctx->isTorSocks)
if(ctx->isTorSocks)
torStatus = "Torsocks";
else if(m_ctx->tor->localTor)
else if(ctx->tor->localTor)
torStatus = "Local (assumed to be running)";
else if(m_ctx->tor->torConnected)
else if(ctx->tor->torConnected)
torStatus = "Running";
else
torStatus = "Unknown";
@@ -47,29 +28,27 @@ void DebugInfoDialog::updateInfo() {
ui->label_featherVersion->setText(QString("%1-%2").arg(FEATHER_VERSION, FEATHER_BRANCH));
ui->label_moneroVersion->setText(QString("%1-%2").arg(MONERO_VERSION, MONERO_BRANCH));
ui->label_walletHeight->setText(QString::number(m_ctx->currentWallet->blockChainHeight()));
ui->label_daemonHeight->setText(QString::number(m_ctx->currentWallet->daemonBlockChainHeight()));
ui->label_targetHeight->setText(QString::number(m_ctx->currentWallet->daemonBlockChainTargetHeight()));
ui->label_restoreHeight->setText(QString::number(m_ctx->currentWallet->getWalletCreationHeight()));
ui->label_synchronized->setText(m_ctx->currentWallet->synchronized() ? "True" : "False");
ui->label_walletHeight->setText(QString::number(ctx->currentWallet->blockChainHeight()));
ui->label_daemonHeight->setText(QString::number(ctx->currentWallet->daemonBlockChainHeight()));
ui->label_restoreHeight->setText(QString::number(ctx->currentWallet->getWalletCreationHeight()));
ui->label_synchronized->setText(ctx->currentWallet->synchronized() ? "True" : "False");
auto node = m_ctx->nodes->connection();
auto node = ctx->nodes->connection();
ui->label_remoteNode->setText(node.full);
ui->label_walletStatus->setText(this->statusToString(m_ctx->currentWallet->connectionStatus()));
ui->label_walletStatus->setText(this->statusToString(ctx->currentWallet->connected()));
ui->label_torStatus->setText(torStatus);
ui->label_websocketStatus->setText(Utils::QtEnumToString(m_ctx->ws->webSocket.state()).remove("State"));
ui->label_websocketStatus->setText(Utils::QtEnumToString(ctx->ws->webSocket.state()));
ui->label_netType->setText(Utils::QtEnumToString(m_ctx->currentWallet->nettype()));
ui->label_seedType->setText(m_ctx->currentWallet->getCacheAttribute("feather.seed").isEmpty() ? "25 word" : "14 word");
ui->label_viewOnly->setText(m_ctx->currentWallet->viewOnly() ? "True" : "False");
ui->label_primaryOnly->setText(m_ctx->currentWallet->balance(0) == m_ctx->currentWallet->balanceAll() ? "True" : "False");
ui->label_netType->setText(Utils::QtEnumToString(ctx->currentWallet->nettype()));
ui->label_seedType->setText(ctx->currentWallet->getCacheAttribute("feather.seed").isEmpty() ? "25 word" : "14 word");
ui->label_viewOnly->setText(ctx->currentWallet->viewOnly() ? "True" : "False");
QString os = QSysInfo::prettyProductName();
if (m_ctx->isTails) {
os = QString("Tails %1").arg(TailsOS::version());
}
ui->label_OS->setText(os);
ui->label_OS->setText(QSysInfo::prettyProductName());
ui->label_timestamp->setText(QString::number(QDateTime::currentSecsSinceEpoch()));
connect(ui->btn_Copy, &QPushButton::clicked, this, &DebugInfoDialog::copyToClipboad);
this->adjustSize();
}
QString DebugInfoDialog::statusToString(Wallet::ConnectionStatus status) {
@@ -88,28 +67,26 @@ QString DebugInfoDialog::statusToString(Wallet::ConnectionStatus status) {
}
void DebugInfoDialog::copyToClipboad() {
// Two spaces at the end of each line are for newlines in Markdown
QString text = "";
text += QString("Feather version: %1 \n").arg(ui->label_featherVersion->text());
text += QString("Monero version: %1 \n").arg(ui->label_moneroVersion->text());
text += QString("Feather version: %1\n").arg(ui->label_featherVersion->text());
text += QString("Monero version: %1\n").arg(ui->label_moneroVersion->text());
text += QString("Wallet height: %1 \n").arg(ui->label_walletHeight->text());
text += QString("Daemon height: %1 \n").arg(ui->label_daemonHeight->text());
text += QString("Target height: %1 \n").arg(ui->label_targetHeight->text());
text += QString("Restore height: %1 \n").arg(ui->label_restoreHeight->text());
text += QString("Synchronized: %1 \n").arg(ui->label_synchronized->text());
text += QString("Wallet height: %1\n").arg(ui->label_walletHeight->text());
text += QString("Daemon height: %1\n").arg(ui->label_daemonHeight->text());
text += QString("Restore height: %1\n").arg(ui->label_restoreHeight->text());
text += QString("Synchronized: %1\n").arg(ui->label_synchronized->text());
text += QString("Remote node: %1 \n").arg(ui->label_remoteNode->text());
text += QString("Wallet status: %1 \n").arg(ui->label_walletStatus->text());
text += QString("Tor status: %1 \n").arg(ui->label_torStatus->text());
text += QString("Websocket status: %1 \n").arg(ui->label_websocketStatus->text());
text += QString("Remote node: %1\n").arg(ui->label_remoteNode->text());
text += QString("Wallet status: %1\n").arg(ui->label_walletStatus->text());
text += QString("Tor status: %1\n").arg(ui->label_torStatus->text());
text += QString("Websocket status: %1\n").arg(ui->label_websocketStatus->text());
text += QString("Network type: %1 \n").arg(ui->label_netType->text());
text += QString("Seed type: %1 \n").arg(ui->label_seedType->text());
text += QString("View only: %1 \n").arg(ui->label_viewOnly->text());
text += QString("Network type: %1\n").arg(ui->label_netType->text());
text += QString("Seed type: %1\n").arg(ui->label_seedType->text());
text += QString("View only: %1\n").arg(ui->label_viewOnly->text());
text += QString("Operating system: %1 \n").arg(ui->label_OS->text());
text += QString("Timestamp: %1 \n").arg(ui->label_timestamp->text());
text += QString("Operating system: %1\n").arg(ui->label_OS->text());
text += QString("Timestamp: %1\n").arg(ui->label_timestamp->text());
Utils::copyToClipboard(text);
}
-4
View File
@@ -23,10 +23,6 @@ public:
private:
QString statusToString(Wallet::ConnectionStatus status);
void copyToClipboad();
void updateInfo();
QTimer m_updateTimer;
AppContext *m_ctx;
Ui::DebugInfoDialog *ui;
};
+26 -60
View File
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>693</width>
<height>612</height>
<height>580</height>
</rect>
</property>
<property name="windowTitle">
@@ -91,14 +91,14 @@
</property>
</widget>
</item>
<item row="6" column="0">
<item row="5" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Restore height:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="5" column="1">
<widget class="QLabel" name="label_restoreHeight">
<property name="text">
<string>TextLabel</string>
@@ -108,14 +108,14 @@
</property>
</widget>
</item>
<item row="7" column="0">
<item row="6" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Synchronized:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<item row="6" column="1">
<widget class="QLabel" name="label_synchronized">
<property name="text">
<string>TextLabel</string>
@@ -125,21 +125,21 @@
</property>
</widget>
</item>
<item row="8" column="1">
<item row="7" column="1">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="9" column="0">
<item row="8" column="0">
<widget class="QLabel" name="label_27">
<property name="text">
<string>Remote node:</string>
</property>
</widget>
</item>
<item row="9" column="1">
<item row="8" column="1">
<widget class="QLabel" name="label_remoteNode">
<property name="text">
<string>TextLabel</string>
@@ -149,14 +149,14 @@
</property>
</widget>
</item>
<item row="10" column="0">
<item row="9" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Wallet status:</string>
</property>
</widget>
</item>
<item row="10" column="1">
<item row="9" column="1">
<widget class="QLabel" name="label_walletStatus">
<property name="text">
<string>TextLabel</string>
@@ -166,14 +166,14 @@
</property>
</widget>
</item>
<item row="11" column="0">
<item row="10" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Tor status:</string>
</property>
</widget>
</item>
<item row="11" column="1">
<item row="10" column="1">
<widget class="QLabel" name="label_torStatus">
<property name="text">
<string>TextLabel</string>
@@ -183,14 +183,14 @@
</property>
</widget>
</item>
<item row="12" column="0">
<item row="11" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Websocket status:</string>
</property>
</widget>
</item>
<item row="12" column="1">
<item row="11" column="1">
<widget class="QLabel" name="label_websocketStatus">
<property name="text">
<string>TextLabel</string>
@@ -200,21 +200,21 @@
</property>
</widget>
</item>
<item row="13" column="1">
<item row="12" column="1">
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="14" column="0">
<item row="13" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Network type:</string>
</property>
</widget>
</item>
<item row="14" column="1">
<item row="13" column="1">
<widget class="QLabel" name="label_netType">
<property name="text">
<string>TextLabel</string>
@@ -224,14 +224,14 @@
</property>
</widget>
</item>
<item row="15" column="0">
<item row="14" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Seed type:</string>
</property>
</widget>
</item>
<item row="15" column="1">
<item row="14" column="1">
<widget class="QLabel" name="label_seedType">
<property name="text">
<string>TextLabel</string>
@@ -241,14 +241,14 @@
</property>
</widget>
</item>
<item row="16" column="0">
<item row="15" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>View only:</string>
</property>
</widget>
</item>
<item row="16" column="1">
<item row="15" column="1">
<widget class="QLabel" name="label_viewOnly">
<property name="text">
<string>TextLabel</string>
@@ -258,14 +258,14 @@
</property>
</widget>
</item>
<item row="20" column="0">
<item row="18" column="0">
<widget class="QLabel" name="label_24">
<property name="text">
<string>Timestamp:</string>
</property>
</widget>
</item>
<item row="20" column="1">
<item row="18" column="1">
<widget class="QLabel" name="label_timestamp">
<property name="text">
<string>TextLabel</string>
@@ -275,61 +275,27 @@
</property>
</widget>
</item>
<item row="19" column="0">
<item row="17" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Operating system:</string>
</property>
</widget>
</item>
<item row="19" column="1">
<item row="17" column="1">
<widget class="QLabel" name="label_OS">
<property name="text">
<string>TextLabel</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="18" column="1">
<item row="16" column="1">
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Target height:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_targetHeight">
<property name="text">
<string>TextLabel</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="17" column="1">
<widget class="QLabel" name="label_primaryOnly">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="17" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Primary only:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
+11 -46
View File
@@ -5,39 +5,17 @@
#include "ui_passwordchangedialog.h"
#include <QPushButton>
#include <QMessageBox>
PasswordChangeDialog::PasswordChangeDialog(QWidget *parent, Wallet *wallet)
PasswordChangeDialog::PasswordChangeDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::PasswordChangeDialog)
, m_wallet(wallet)
{
ui->setupUi(this);
bool noPassword = wallet->getPassword().isEmpty();
QString warning_str = noPassword ? "Your wallet is not password protected. Use this dialog to add a password to your wallet." :
"Your wallet is password protected and encrypted. Use this dialog to change your password.";
ui->label_warning->setText(warning_str);
QPixmap pixmap = noPassword ? QPixmap(":/assets/images/unlock.png") : QPixmap(":/assets/images/lock.png");
ui->icon->setPixmap(pixmap.scaledToWidth(32, Qt::SmoothTransformation));
if (noPassword) {
ui->label_currentPassword->hide();
ui->lineEdit_currentPassword->hide();
}
ui->icon->setPixmap(QPixmap(":/assets/images/lock.png").scaledToWidth(32, Qt::SmoothTransformation));
connect(ui->lineEdit_newPassword, &QLineEdit::textChanged, this, &PasswordChangeDialog::passwordsMatch);
connect(ui->lineEdit_confirmPassword, &QLineEdit::textChanged, this, &PasswordChangeDialog::passwordsMatch);
connect(ui->btn_Cancel, &QPushButton::clicked, [this]{
this->reject();
});
connect(ui->btn_OK, &QPushButton::clicked, this, &PasswordChangeDialog::setPassword);
ui->label_match->setVisible(false);
this->adjustSize();
}
@@ -46,28 +24,15 @@ PasswordChangeDialog::~PasswordChangeDialog()
delete ui;
}
QString PasswordChangeDialog::getCurrentPassword() {
return ui->lineEdit_currentPassword->text();
}
QString PasswordChangeDialog::getNewPassword() {
return ui->lineEdit_newPassword->text();
}
void PasswordChangeDialog::passwordsMatch() {
bool match = ui->lineEdit_newPassword->text() == ui->lineEdit_confirmPassword->text();
ui->btn_OK->setEnabled(match);
ui->label_match->setHidden(match);
}
void PasswordChangeDialog::setPassword() {
QString currentPassword = ui->lineEdit_currentPassword->text();
QString newPassword = ui->lineEdit_newPassword->text();
if (currentPassword != m_wallet->getPassword()) {
QMessageBox::warning(this, "Error", "Incorrect password");
ui->lineEdit_currentPassword->setText("");
ui->lineEdit_currentPassword->setFocus();
return;
}
if (m_wallet->setPassword(newPassword)) {
QMessageBox::information(this, "Information", "Password changed successfully");
this->accept();
}
else {
QMessageBox::warning(this, "Error", QString("Error: %1").arg(m_wallet->errorString()));
}
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(match);
}
+4 -4
View File
@@ -5,7 +5,6 @@
#define FEATHER_PASSWORDCHANGEDIALOG_H
#include <QDialog>
#include "libwalletqt/Wallet.h"
namespace Ui {
class PasswordChangeDialog;
@@ -16,15 +15,16 @@ class PasswordChangeDialog : public QDialog
Q_OBJECT
public:
explicit PasswordChangeDialog(QWidget *parent, Wallet *wallet);
explicit PasswordChangeDialog(QWidget *parent = nullptr);
~PasswordChangeDialog() override;
QString getCurrentPassword();
QString getNewPassword();
private:
Ui::PasswordChangeDialog *ui;
Wallet *m_wallet;
void passwordsMatch();
void setPassword();
};
#endif //FEATHER_PASSWORDCHANGEDIALOG_H
+46 -60
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>556</width>
<height>309</height>
<width>500</width>
<height>237</height>
</rect>
</property>
<property name="sizePolicy">
@@ -30,7 +30,7 @@
</widget>
</item>
<item>
<widget class="QLabel" name="label_warning">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Your wallet is password protected and encrypted. Use this dialog to change your password.</string>
</property>
@@ -41,22 +41,6 @@
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
@@ -81,7 +65,7 @@
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_currentPassword">
<widget class="QLabel" name="label">
<property name="text">
<string>Current Password:</string>
</property>
@@ -104,45 +88,14 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_match">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Passwords do not match</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btn_Cancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_OK">
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
</layout>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
@@ -152,5 +105,38 @@
<tabstop>lineEdit_confirmPassword</tabstop>
</tabstops>
<resources/>
<connections/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PasswordChangeDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PasswordChangeDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
-26
View File
@@ -1,26 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#include "passworddialog.h"
#include "ui_passworddialog.h"
PasswordDialog::PasswordDialog(QWidget *parent, const QString &walletName, bool incorrectPassword)
: QDialog(parent)
, ui(new Ui::PasswordDialog)
{
ui->setupUi(this);
ui->label_wallet->setText(QString("Please enter password for wallet: %1").arg(walletName));
ui->label_incorrectPassword->setVisible(incorrectPassword);
connect(ui->buttonBox, &QDialogButtonBox::accepted, [this]{
password = ui->line_password->text();
});
this->adjustSize();
}
PasswordDialog::~PasswordDialog()
{
delete ui;
}
-27
View File
@@ -1,27 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#ifndef FEATHER_PASSWORDDIALOG_H
#define FEATHER_PASSWORDDIALOG_H
#include <QDialog>
namespace Ui {
class PasswordDialog;
}
class PasswordDialog : public QDialog
{
Q_OBJECT
public:
explicit PasswordDialog(QWidget *parent, const QString &walletName, bool incorrectPassword);
~PasswordDialog() override;
QString password = "";
private:
Ui::PasswordDialog *ui;
};
#endif //FEATHER_PASSWORDDIALOG_H
-85
View File
@@ -1,85 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PasswordDialog</class>
<widget class="QDialog" name="PasswordDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>832</width>
<height>158</height>
</rect>
</property>
<property name="windowTitle">
<string>Password required</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_wallet">
<property name="text">
<string>Please enter password for wallet: </string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_incorrectPassword">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; color:#a40000;&quot;&gt;Incorrect password, try again.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="line_password">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PasswordDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PasswordDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
+4 -7
View File
@@ -9,14 +9,15 @@
#include <QFileDialog>
#include <QMessageBox>
QrCodeDialog::QrCodeDialog(QWidget *parent, const QrCode &qrCode, const QString &title)
QrCodeDialog::QrCodeDialog(QWidget *parent, const QString &text, const QString &title)
: QDialog(parent)
, ui(new Ui::QrCodeDialog)
{
ui->setupUi(this);
this->setWindowTitle(title);
m_pixmap = qrCode.toPixmap(1).scaled(500, 500, Qt::KeepAspectRatio);
m_qrc = new QrCode(text, QrCode::Version::AUTO, QrCode::ErrorCorrectionLevel::HIGH);
m_pixmap = m_qrc->toPixmap(1).scaled(500, 500, Qt::KeepAspectRatio);
ui->QrCode->setPixmap(m_pixmap);
connect(ui->btn_CopyImage, &QPushButton::clicked, this, &QrCodeDialog::copyImage);
@@ -31,11 +32,7 @@ QrCodeDialog::QrCodeDialog(QWidget *parent, const QrCode &qrCode, const QString
QrCodeDialog::~QrCodeDialog()
{
delete ui;
}
void QrCodeDialog::setQrCode(const QrCode &qrCode) {
m_pixmap = qrCode.toPixmap(1).scaled(500, 500, Qt::KeepAspectRatio);
ui->QrCode->setPixmap(m_pixmap);
delete m_qrc;
}
void QrCodeDialog::copyImage() {
+2 -2
View File
@@ -16,15 +16,15 @@ class QrCodeDialog : public QDialog
Q_OBJECT
public:
explicit QrCodeDialog(QWidget *parent, const QrCode &qrCode, const QString &title = "Qr Code");
explicit QrCodeDialog(QWidget *parent, const QString &text, const QString &title = "Qr Code");
~QrCodeDialog() override;
void setQrCode(const QrCode &qrCode);
private:
void copyImage();
void saveImage();
Ui::QrCodeDialog *ui;
QrCode *m_qrc;
QPixmap m_pixmap;
};
+1 -1
View File
@@ -24,7 +24,7 @@ RestoreDialog::RestoreDialog(AppContext *ctx, QWidget *parent)
}
}
int RestoreDialog::getHeight() {
unsigned int RestoreDialog::getHeight() {
return ui->restoreHeightWidget->getHeight();
}
+1 -1
View File
@@ -24,7 +24,7 @@ Q_OBJECT
public:
explicit RestoreDialog(AppContext *ctx, QWidget *parent = nullptr);
void initRestoreHeights(RestoreHeightLookup *lookup);
int getHeight();
unsigned int getHeight();
~RestoreDialog() override;
signals:
+12 -36
View File
@@ -4,51 +4,27 @@
#include "ui_seeddialog.h"
#include "seeddialog.h"
SeedDialog::SeedDialog(Wallet *wallet, QWidget *parent)
SeedDialog::SeedDialog(const QString &seed, QWidget *parent)
: QDialog(parent)
, ui(new Ui::SeedDialog)
{
ui->setupUi(this);
ui->label_seedIcon->setPixmap(QPixmap(":/assets/images/seed.png").scaledToWidth(64, Qt::SmoothTransformation));
ui->label_restoreHeight->setText(QString::number(wallet->getWalletCreationHeight()));
QString seed_14_words = wallet->getCacheAttribute("feather.seed");
QString seed_25_words = wallet->getSeed();
if (seed_14_words.isEmpty()) {
ui->check_toggleSeedType->hide();
this->setSeed(seed_25_words);
} else {
this->setSeed(seed_14_words);
ui->frameRestoreHeight->setVisible(false);
}
connect(ui->check_toggleSeedType, &QCheckBox::toggled, [this, seed_25_words, seed_14_words](bool toggled){
this->setSeed(toggled ? seed_25_words : seed_14_words);
ui->frameRestoreHeight->setVisible(toggled);
});
ui->label_restoreHeightHelp->setHelpText("Should you restore your wallet in the future, "
"specifying this block number will recover your wallet quicker.");
this->adjustSize();
}
void SeedDialog::setSeed(const QString &seed) {
ui->seed->setPlainText(seed);
int words = seed.split(" ").size();
ui->label_warning->setText(QString("<p>Please save these %1 words on paper (order is important). "
"This seed will allow you to recover your wallet in case "
"of computer failure."
"</p>"
"<b>WARNING:</b>"
"<ul>"
"<li>Never disclose your seed.</li>"
"<li>Never type it on a website</li>"
"<li>Do not store it electronically</li>"
"</ul>").arg(words));
"This seed will allow you to recover your wallet in case "
"of computer failure."
"</p>"
"<b>WARNING:</b>"
"<ul>"
"<li>Never disclose your seed.</li>"
"<li>Never type it on a website</li>"
"<li>Do not store it electronically</li>"
"</ul>").arg(words));
this->adjustSize();
}
SeedDialog::~SeedDialog()
+1 -4
View File
@@ -5,7 +5,6 @@
#define FEATHER_SEEDDIALOG_H
#include <QDialog>
#include "libwalletqt/Wallet.h"
namespace Ui {
class SeedDialog;
@@ -16,12 +15,10 @@ class SeedDialog : public QDialog
Q_OBJECT
public:
explicit SeedDialog(Wallet *wallet, QWidget *parent = nullptr);
explicit SeedDialog(const QString& seed, QWidget *parent = nullptr);
~SeedDialog() override;
private:
void setSeed(const QString &seed);
Ui::SeedDialog *ui;
};
+22 -110
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>519</width>
<height>330</height>
<width>542</width>
<height>244</height>
</rect>
</property>
<property name="windowTitle">
@@ -34,120 +34,39 @@
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPlainTextEdit" name="seed">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>300</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frameRestoreHeight">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="HelpLabel" name="label_restoreHeightHelp">
<property name="text">
<string>Restore height:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_restoreHeight">
<property name="text">
<string>TextLabel</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
<widget class="QPlainTextEdit" name="seed">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>125</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="check_toggleSeedType">
<property name="text">
<string>Show 25 word seed</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_warning">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>warning</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
@@ -160,13 +79,6 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>HelpLabel</class>
<extends>QLabel</extends>
<header>components.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
+10 -25
View File
@@ -6,37 +6,22 @@
#include "libwalletqt/CoinsInfo.h"
#include "libwalletqt/WalletManager.h"
#include "utils.h"
#include <QDebug>
#include <QMessageBox>
TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent)
TransactionInfoDialog::TransactionInfoDialog(Coins *coins, TransactionInfo *txInfo, QWidget *parent)
: QDialog(parent)
, ui(new Ui::TransactionInfoDialog)
, m_wallet(wallet)
, m_coins(coins)
, m_txInfo(txInfo)
{
ui->setupUi(this);
m_txProofWidget = new TxProofWidget(this, wallet, txInfo);
ui->label_txid->setText(QString(txInfo->hash()));
if (txInfo->direction() == TransactionInfo::Direction_In) {
ui->txKey->hide();
} else {
QString txKey = m_wallet->getTxKey(txInfo->hash());
txKey = txKey.isEmpty() ? "unknown" : txKey;
ui->label_txKey->setText(txKey);
}
QString blockHeight = QString::number(txInfo->blockHeight());
if (blockHeight == "0")
blockHeight = "Unconfirmed";
ui->txid->setText(QString(txInfo->hash()));
ui->txid->setCursorPosition(0);
ui->label_status->setText(QString("Status: %1 confirmations").arg(txInfo->confirmations()));
ui->label_date->setText(QString("Date: %1").arg(txInfo->timestamp().toString("yyyy-MM-dd HH:mm")));
ui->label_blockHeight->setText(QString("Block height: %1").arg(blockHeight));
ui->label_blockHeight->setText(QString("Block height: %1").arg(txInfo->blockHeight()));
QString direction = txInfo->direction() == TransactionInfo::Direction_In ? "received" : "sent";
ui->label_amount->setText(QString("Amount %1: %2").arg(direction, txInfo->displayAmount()));
@@ -45,17 +30,17 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx
ui->label_fee->setText(QString("Fee: %1").arg(txInfo->isCoinbase() ? WalletManager::displayAmount(0) : fee));
ui->label_unlockTime->setText(QString("Unlock time: %1 (height)").arg(txInfo->unlockTime()));
qDebug() << m_wallet->coins()->coins_from_txid(txInfo->hash());
qDebug() << m_coins->coins_from_txid(txInfo->hash());
QString destinations = txInfo->destinations_formatted();
if (destinations.isEmpty()) {
ui->frameDestinations->hide();
ui->destinations->setHidden(true);
ui->label_destinations->setHidden(true);
ui->line_2->setHidden(true);
} else {
ui->destinations->setText(destinations);
}
ui->txProofWidget->addWidget(m_txProofWidget);
this->adjustSize();
}
+2 -5
View File
@@ -8,8 +8,6 @@
#include <QtSvg/QSvgWidget>
#include "libwalletqt/Coins.h"
#include "libwalletqt/TransactionInfo.h"
#include "libwalletqt/Wallet.h"
#include "widgets/txproofwidget.h"
namespace Ui {
class TransactionInfoDialog;
@@ -20,15 +18,14 @@ class TransactionInfoDialog : public QDialog
Q_OBJECT
public:
explicit TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent = nullptr);
explicit TransactionInfoDialog(Coins *coins, TransactionInfo *txInfo, QWidget *parent = nullptr);
~TransactionInfoDialog() override;
private:
Ui::TransactionInfoDialog *ui;
TransactionInfo *m_txInfo;
Wallet *m_wallet;
TxProofWidget *m_txProofWidget;
Coins *m_coins;
};
#endif //FEATHER_TRANSACTIONINFODIALOG_H
+41 -84
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>829</width>
<height>570</height>
<width>547</width>
<height>332</height>
</rect>
</property>
<property name="windowTitle">
@@ -15,41 +15,32 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<widget class="QLabel" name="label">
<property name="text">
<string>Transaction ID:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_txid">
<property name="text">
<string>txid</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="txKey">
<property name="title">
<string>Transaction key:</string>
<widget class="QLineEdit" name="txid">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>525</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>txid</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QLabel" name="label_txKey">
<property name="text">
<string>txKey</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
@@ -132,65 +123,31 @@
</layout>
</item>
<item>
<widget class="QFrame" name="frameDestinations">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_destinations">
<property name="text">
<string>Destinations:</string>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="destinations">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>100</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line_3">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="txProofWidget"/>
<widget class="QLabel" name="label_destinations">
<property name="text">
<string>Destinations:</string>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="destinations">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>100</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
-186
View File
@@ -1,186 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#include "txconfadvdialog.h"
#include "ui_txconfadvdialog.h"
#include "libwalletqt/WalletManager.h"
#include "qrcode/QrCode.h"
#include "dialog/qrcodedialog.h"
#include "utils/utils.h"
#include "libwalletqt/PendingTransactionInfo.h"
#include "libwalletqt/Transfer.h"
#include "libwalletqt/Input.h"
#include "model/ModelUtils.h"
#include <QFileDialog>
#include <QMessageBox>
TxConfAdvDialog::TxConfAdvDialog(AppContext *ctx, const QString &description, QWidget *parent)
: QDialog(parent)
, ui(new Ui::TxConfAdvDialog)
, m_ctx(ctx)
, m_exportUnsignedMenu(new QMenu(this))
, m_exportSignedMenu(new QMenu(this))
{
ui->setupUi(this);
m_exportUnsignedMenu->addAction("Copy to clipboard", this, &TxConfAdvDialog::unsignedCopy);
m_exportUnsignedMenu->addAction("Show as QR code", this, &TxConfAdvDialog::unsignedQrCode);
m_exportUnsignedMenu->addAction("Save to file", this, &TxConfAdvDialog::unsignedSaveFile);
ui->btn_exportUnsigned->setMenu(m_exportUnsignedMenu);
m_exportSignedMenu->addAction("Copy to clipboard", this, &TxConfAdvDialog::signedCopy);
m_exportSignedMenu->addAction("Save to file", this, &TxConfAdvDialog::signedSaveFile);
ui->btn_exportSigned->setMenu(m_exportSignedMenu);
if (m_ctx->currentWallet->viewOnly()) {
ui->btn_exportSigned->hide();
ui->btn_send->hide();
}
ui->label_description->setText(QString("Description: %1").arg(description));
connect(ui->btn_sign, &QPushButton::clicked, this, &TxConfAdvDialog::signTransaction);
connect(ui->btn_send, &QPushButton::clicked, this, &TxConfAdvDialog::broadcastTransaction);
connect(ui->btn_close, &QPushButton::clicked, this, &TxConfAdvDialog::closeDialog);
ui->inputs->setFont(ModelUtils::getMonospaceFont());
ui->outputs->setFont(ModelUtils::getMonospaceFont());
this->adjustSize();
}
void TxConfAdvDialog::setTransaction(PendingTransaction *tx) {
ui->btn_sign->hide();
m_tx = tx;
m_tx->refresh();
PendingTransactionInfo *ptx = m_tx->transaction(0);
ui->txid->setText(tx->txid().first());
ui->amount->setText(WalletManager::displayAmount(tx->amount()));
ui->fee->setText(WalletManager::displayAmount(ptx->fee()));
ui->total->setText(WalletManager::displayAmount(tx->amount() + ptx->fee()));
auto size_str = [this]{
if (m_ctx->currentWallet->viewOnly()) {
return QString("Size: %1 bytes (unsigned)").arg(QString::number(m_tx->unsignedTxToBin().size()));
} else {
auto size = m_tx->signedTxToHex(0).size() / 2;
return QString("Size: %1 bytes (%2 bytes unsigned)").arg(QString::number(size), QString::number(m_tx->unsignedTxToBin().size()));
}
}();
ui->label_size->setText(size_str);
this->setupConstructionData(ptx);
}
void TxConfAdvDialog::setUnsignedTransaction(UnsignedTransaction *utx) {
m_utx = utx;
m_utx->refresh();
ui->btn_exportUnsigned->hide();
ui->btn_exportSigned->hide();
ui->btn_sign->show();
ui->btn_send->hide();
ui->txid->setText("n/a");
ui->label_size->setText("Size: n/a");
ui->amount->setText(WalletManager::displayAmount(utx->amount(0)));
ui->fee->setText(WalletManager::displayAmount(utx->fee(0)));
ui->total->setText(WalletManager::displayAmount(utx->amount(0) + utx->fee(0)));
ConstructionInfo *ci = m_utx->constructionInfo(0);
this->setupConstructionData(ci);
}
void TxConfAdvDialog::setupConstructionData(ConstructionInfo *ci) {
QString inputs_str;
auto inputs = ci->inputs();
for (const auto& i: inputs) {
inputs_str += QString("%1 %2\n").arg(i->pubKey(), WalletManager::displayAmount(i->amount()));
}
ui->inputs->setText(inputs_str);
ui->label_inputs->setText(QString("Inputs (%1)").arg(QString::number(inputs.size())));
QString outputs_str;
auto outputs = ci->outputs();
for (const auto& o: outputs) {
outputs_str += QString("%1 %2\n").arg(o->address(), WalletManager::displayAmount(o->amount()));
}
ui->outputs->setText(outputs_str);
ui->label_outputs->setText(QString("Outputs (%1)").arg(QString::number(outputs.size())));
ui->label_ringSize->setText(QString("Ring size: %1").arg(QString::number(ci->minMixinCount() + 1)));
ui->label_unlockTime->setText(QString("Unlock time: %1 (height)").arg(QString::number(ci->unlockTime())));
}
void TxConfAdvDialog::signTransaction() {
QString defaultName = QString("%1_signed_monero_tx").arg(QString::number(QDateTime::currentSecsSinceEpoch()));
QString fn = QFileDialog::getSaveFileName(this, "Save signed transaction to file", QDir::home().filePath(defaultName), "Transaction (*signed_monero_tx)");
if(fn.isEmpty()) return;
m_utx->sign(fn) ? QMessageBox::information(this, "Sign transaction", "Transaction saved successfully")
: QMessageBox::warning(this, "Sign transaction", "Failes to save transaction to file.");
}
void TxConfAdvDialog::unsignedSaveFile() {
QString defaultName = QString("%1_unsigned_monero_tx").arg(QString::number(QDateTime::currentSecsSinceEpoch()));
QString fn = QFileDialog::getSaveFileName(this, "Save transaction to file", QDir::home().filePath(defaultName), "Transaction (*unsigned_monero_tx)");
if(fn.isEmpty()) return;
m_tx->saveToFile(fn) ? QMessageBox::information(this, "Transaction saved to file", "Transaction saved successfully")
: QMessageBox::warning(this, "Save transaction", "Failed to save transaction to file.");
}
void TxConfAdvDialog::signedSaveFile() {
QString defaultName = QString("%1_signed_monero_tx").arg(QString::number(QDateTime::currentSecsSinceEpoch()));
QString fn = QFileDialog::getSaveFileName(this, "Save transaction to file", QDir::home().filePath(defaultName), "Transaction (*signed_monero_tx)");
if(fn.isEmpty()) return;
m_tx->saveToFile(fn) ? QMessageBox::information(this, "Transaction saved to file", "Transaction saved successfully")
: QMessageBox::warning(this, "Save transaction", "Failed to save transaction to file.");
}
void TxConfAdvDialog::unsignedQrCode() {
if (m_tx->unsignedTxToBin().size() > 2953) {
QMessageBox::warning(this, "Unable to show QR code", "Transaction size exceeds the maximum size for QR codes (2953 bytes).");
return;
}
QrCode qr(m_tx->unsignedTxToBin(), QrCode::Version::AUTO, QrCode::ErrorCorrectionLevel::LOW);
auto *dialog = new QrCodeDialog(this, qr, "Unsigned Transaction");
dialog->exec();
dialog->deleteLater();
}
void TxConfAdvDialog::unsignedCopy() {
Utils::copyToClipboard(m_tx->unsignedTxToBase64());
}
void TxConfAdvDialog::signedCopy() {
Utils::copyToClipboard(m_tx->signedTxToHex(0));
}
void TxConfAdvDialog::signedQrCode() {
}
void TxConfAdvDialog::broadcastTransaction() {
if (m_tx == nullptr) return;
m_ctx->currentWallet->commitTransactionAsync(m_tx);
QDialog::accept();
}
void TxConfAdvDialog::closeDialog() {
if (m_tx != nullptr)
m_ctx->currentWallet->disposeTransaction(m_tx);
if (m_utx != nullptr)
m_ctx->currentWallet->disposeTransaction(m_utx);
QDialog::reject();
}
TxConfAdvDialog::~TxConfAdvDialog() {
delete ui;
}
-54
View File
@@ -1,54 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#ifndef FEATHER_TXCONFADVDIALOG_H
#define FEATHER_TXCONFADVDIALOG_H
#include <QDialog>
#include <QStandardItemModel>
#include <QAbstractButton>
#include <QMenu>
#include "libwalletqt/PendingTransaction.h"
#include "appcontext.h"
namespace Ui {
class TxConfAdvDialog;
}
class TxConfAdvDialog : public QDialog
{
Q_OBJECT
public:
explicit TxConfAdvDialog(AppContext *ctx, const QString &description, QWidget *parent = nullptr);
~TxConfAdvDialog() override;
void setTransaction(PendingTransaction *tx);
void setUnsignedTransaction(UnsignedTransaction *utx);
private:
void setupConstructionData(ConstructionInfo *ci);
void signTransaction();
void broadcastTransaction();
void closeDialog();
void unsignedCopy();
void unsignedQrCode();
void unsignedSaveFile();
void signedCopy();
void signedQrCode();
void signedSaveFile();
Ui::TxConfAdvDialog *ui;
AppContext *m_ctx;
PendingTransaction *m_tx = nullptr;
UnsignedTransaction *m_utx = nullptr;
QMenu *m_exportUnsignedMenu;
QMenu *m_exportSignedMenu;
};
#endif //FEATHER_TXCONFADVDIALOG_H
-279
View File
@@ -1,279 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TxConfAdvDialog</class>
<widget class="QDialog" name="TxConfAdvDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>542</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>800</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Transaction</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Transaction ID:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="txid">
<property name="text">
<string>txid</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_amount">
<property name="text">
<string>Amount: </string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="amount">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_fee">
<property name="text">
<string>Fee: </string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="fee">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Total:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="total">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_description">
<property name="text">
<string>Description:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_size">
<property name="text">
<string>Size: </string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_unlockTime">
<property name="text">
<string>Unlock time: </string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_ringSize">
<property name="text">
<string>Ringsize:</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_inputs">
<property name="text">
<string>Inputs</string>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="inputs">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>100</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_outputs">
<property name="text">
<string>Outputs</string>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="outputs">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>100</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="btn_exportUnsigned">
<property name="text">
<string>Export unsigned</string>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="btn_exportSigned">
<property name="text">
<string>Export signed</string>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btn_sign">
<property name="text">
<string>Sign</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_send">
<property name="text">
<string>Send</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_close">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+28 -26
View File
@@ -6,16 +6,12 @@
#include "appcontext.h"
#include "utils/config.h"
#include "model/ModelUtils.h"
#include "libwalletqt/WalletManager.h"
#include "txconfadvdialog.h"
#include "globals.h"
#include <QMessageBox>
TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QString &address, const QString &description, int mixin, QWidget *parent)
TxConfDialog::TxConfDialog(PendingTransaction *tx, const QString &address, const QString &description, int mixin, QWidget *parent)
: QDialog(parent)
, ui(new Ui::TxConfDialog)
, m_ctx(ctx)
, m_tx(tx)
, m_address(address)
, m_description(description)
@@ -32,38 +28,44 @@ TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QStrin
};
QString amount = WalletManager::displayAmount(tx->amount());
QString amount_fiat = convert(tx->amount() / AppContext::cdiv);
ui->label_amount->setText(QString("%1 (%2 %3)").arg(amount, amount_fiat, preferredCur));
QString fee = WalletManager::displayAmount(tx->fee());
QString fee_fiat = convert(tx->fee() / AppContext::cdiv);
ui->label_fee->setText(QString("%1 (%2 %3)").arg(fee, fee_fiat, preferredCur));
QString total = WalletManager::displayAmount(tx->amount() + tx->fee());
QVector<QString> amounts = {amount, fee, total};
int maxLength = Utils::maxLength(amounts);
std::for_each(amounts.begin(), amounts.end(), [maxLength](QString& amount){amount = amount.rightJustified(maxLength, ' ');});
QString amount_fiat = convert(tx->amount() / globals::cdiv);
QString fee_fiat = convert(tx->fee() / globals::cdiv);
QString total_fiat = convert((tx->amount() + tx->fee()) / globals::cdiv);
QVector<QString> amounts_fiat = {amount_fiat, fee_fiat, total_fiat};
int maxLengthFiat = Utils::maxLength(amounts_fiat);
std::for_each(amounts_fiat.begin(), amounts_fiat.end(), [maxLengthFiat](QString& amount){amount = amount.rightJustified(maxLengthFiat, ' ');});
ui->label_amount->setText(QString("%1 (%2 %3)").arg(amounts[0], amounts_fiat[0], preferredCur));
ui->label_fee->setText(QString("%1 (%2 %3)").arg(amounts[1], amounts_fiat[1], preferredCur));
ui->label_total->setText(QString("%1 (%2 %3)").arg(amounts[2], amounts_fiat[2], preferredCur));
QString total_fiat = convert((tx->amount() + tx->fee()) / AppContext::cdiv);
ui->label_total->setText(QString("%1 (%2 %3)").arg(total, total_fiat, preferredCur));
ui->label_address->setText(ModelUtils::displayAddress(address, 2));
ui->label_address->setFont(ModelUtils::getMonospaceFont());
ui->label_address->setToolTip(address);
ui->buttonBox->button(QDialogButtonBox::Ok)->setText("Send");
connect(ui->btn_Advanced, &QPushButton::clicked, this, &TxConfDialog::showAdvanced);
connect(ui->btn_Advanced, &QPushButton::clicked, this, &TxConfDialog::setShowAdvanced);
AppContext::txCache[tx->txid()[0]] = tx->signedTxToHex(0);
this->adjustSize();
}
void TxConfDialog::setShowAdvanced() {
this->showAdvanced = true;
QDialog::reject();
void TxConfDialog::showAdvanced() {
const auto amount = m_tx->amount() / AppContext::cdiv;
const auto fee = m_tx->fee() / AppContext::cdiv;
QString body = QString("Address: %2\n").arg(m_address.left(60));
body += m_address.mid(60) + "\n";
if(!m_description.isEmpty())
body = QString("%1Description: %2\n").arg(body, m_description);
body = QString("%1Amount: %2 XMR\n").arg(body, QString::number(amount));
body = QString("%1Fee: %2 XMR\n").arg(body, QString::number(fee));
body = QString("%1Ringsize: %2").arg(body, QString::number(m_mixin + 1));
auto subaddrIndices = m_tx->subaddrIndices();
for (int i = 0; i < subaddrIndices.count(); ++i){
body = QString("%1\nSpending address index: %2").arg(body, QString::number(subaddrIndices.at(i).toInt()));
}
QMessageBox::information(this, "Transaction information", body);
}
TxConfDialog::~TxConfDialog() {
+2 -8
View File
@@ -7,7 +7,6 @@
#include <QDialog>
#include "libwalletqt/PendingTransaction.h"
#include "libwalletqt/WalletManager.h"
#include "appcontext.h"
namespace Ui {
class TxConfDialog;
@@ -18,18 +17,13 @@ class TxConfDialog : public QDialog
Q_OBJECT
public:
explicit TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QString &address, const QString &description, int mixin, QWidget *parent = nullptr);
explicit TxConfDialog(PendingTransaction *tx, const QString &address, const QString &description, int mixin, QWidget *parent = nullptr);
~TxConfDialog() override;
bool showAdvanced = false;
private:
void setShowAdvanced();
void saveToFile();
void copyToClipboard();
void showAdvanced();
Ui::TxConfDialog *ui;
AppContext *m_ctx;
PendingTransaction *m_tx;
QString m_address;
QString m_description;
+1 -1
View File
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>844</width>
<width>655</width>
<height>248</height>
</rect>
</property>
-102
View File
@@ -1,102 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#include "tximportdialog.h"
#include "ui_tximportdialog.h"
#include <QMessageBox>
TxImportDialog::TxImportDialog(QWidget *parent, AppContext *ctx)
: QDialog(parent)
, m_ctx(ctx)
, m_loadTimer(new QTimer(this))
, ui(new Ui::TxImportDialog)
{
ui->setupUi(this);
ui->resp->hide();
ui->label_loading->hide();
m_network = new UtilsNetworking(m_ctx->network, this);
auto node = ctx->nodes->connection();
m_rpc = new DaemonRpc(this, m_network, node.full);
connect(ui->btn_load, &QPushButton::clicked, this, &TxImportDialog::loadTx);
connect(ui->btn_import, &QPushButton::clicked, this, &TxImportDialog::onImport);
connect(m_rpc, &DaemonRpc::ApiResponse, this, &TxImportDialog::onApiResponse);
connect(m_loadTimer, &QTimer::timeout, [this]{
ui->label_loading->setText(ui->label_loading->text() + ".");
});
this->adjustSize();
}
void TxImportDialog::loadTx() {
QString txid = ui->line_txid->text();
QString node = m_ctx->nodes->connection().full;
if (!node.startsWith("http://"))
node = QString("http://%1").arg(node);
m_rpc->setDaemonAddress(node);
m_rpc->getTransactions(QStringList() << txid, false, true);
ui->label_loading->setText("Loading transaction");
ui->label_loading->setHidden(false);
m_loadTimer->start(1000);
}
void TxImportDialog::onApiResponse(const DaemonRpc::DaemonResponse &resp) {
m_loadTimer->stop();
ui->label_loading->setHidden(true);
if (!resp.ok) {
QMessageBox::warning(this, "Import transaction", resp.status);
return;
}
if (resp.endpoint == DaemonRpc::Endpoint::GET_TRANSACTIONS) {
ui->resp->setVisible(true);
ui->resp->setPlainText(QJsonDocument(resp.obj).toJson(QJsonDocument::Indented));
this->adjustSize();
if (resp.obj.contains("missed_tx")) {
ui->btn_import->setEnabled(false);
QMessageBox::warning(this, "Load transaction", "Transaction could not be found. Make sure the txid is correct, or try connecting to a different node.");
return;
}
QMessageBox::information(this, "Load transaction", "Transaction loaded successfully.\n\nAfter closing this message box click the Import button to import the transaction into your wallet.");
m_transaction = resp.obj;
ui->btn_import->setEnabled(true);
}
}
void TxImportDialog::onImport() {
QJsonObject tx = m_transaction.value("txs").toArray().first().toObject();
QString txid = tx.value("tx_hash").toString();
QVector<quint64> output_indices;
for (const auto &o: tx.value("output_indices").toArray()) {
output_indices.push_back(o.toInt());
}
quint64 height = tx.value("block_height").toInt();
quint64 timestamp = tx.value("block_timestamp").toInt();
bool pool = tx.value("in_pool").toBool();
bool double_spend_seen = tx.value("double_spend_seen").toBool();
if (m_ctx->currentWallet->importTransaction(tx.value("tx_hash").toString(), output_indices, height, timestamp, false, pool, double_spend_seen)) {
QMessageBox::information(this, "Import transaction", "Transaction imported successfully.");
} else {
QMessageBox::warning(this, "Import transaction", "Transaction import failed.");
}
m_ctx->refreshModels();
}
TxImportDialog::~TxImportDialog() {
delete ui;
}
-39
View File
@@ -1,39 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#ifndef FEATHER_TXIMPORTDIALOG_H
#define FEATHER_TXIMPORTDIALOG_H
#include <QDialog>
#include "appcontext.h"
#include "utils/daemonrpc.h"
namespace Ui {
class TxImportDialog;
}
class TxImportDialog : public QDialog
{
Q_OBJECT
public:
explicit TxImportDialog(QWidget *parent, AppContext *ctx);
~TxImportDialog() override;
private slots:
void loadTx();
void onImport();
void onApiResponse(const DaemonRpc::DaemonResponse &resp);
private:
Ui::TxImportDialog *ui;
UtilsNetworking *m_network;
AppContext *m_ctx;
DaemonRpc *m_rpc;
QTimer *m_loadTimer;
QJsonObject m_transaction;
};
#endif //FEATHER_TXIMPORTDIALOG_H
-115
View File
@@ -1,115 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TxImportDialog</class>
<widget class="QDialog" name="TxImportDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>700</width>
<height>442</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>700</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Import Transaction</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLineEdit" name="line_txid">
<property name="placeholderText">
<string>Transaction ID</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="resp">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>Debug info..</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="btn_load">
<property name="text">
<string>Load</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_import">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Import</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_loading">
<property name="text">
<string>Loading transaction</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>TxImportDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>TxImportDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
+19 -35
View File
@@ -16,28 +16,26 @@ VerifyProofDialog::VerifyProofDialog(Wallet *wallet, QWidget *parent)
{
ui->setupUi(this);
connect(ui->btn_verify, &QPushButton::clicked, this, &VerifyProofDialog::checkProof);
connect(ui->btn_verifySpendProof, &QPushButton::clicked, this, &VerifyProofDialog::checkSpendProof);
connect(ui->btn_verifyOutProof, &QPushButton::clicked, this, &VerifyProofDialog::checkOutProof);
connect(ui->btn_verifyInProof, &QPushButton::clicked, this, &VerifyProofDialog::checkInProof);
connect(ui->btn_clear, &QPushButton::clicked, [this]{
switch (ui->tabWidget->currentIndex()) {
case 0:
ui->lineEdit_spendTxID->clear();
ui->lineEdit_spendMessage->clear();
ui->input_SpendProof->clear();
break;
case 1:
ui->lineEdit_outTxID->clear();
ui->lineEdit_outAddress->clear();
ui->lineEdit_outMessage->clear();
ui->input_OutProof->clear();
break;
case 2:
ui->lineEdit_inTxID->clear();
ui->lineEdit_inAddress->clear();
ui->lineEdit_inMessage->clear();
ui->input_InProof->clear();
break;
}
connect(ui->btn_spendClear, &QPushButton::clicked, [this](){
ui->lineEdit_spendTxID->clear();
ui->lineEdit_spendMessage->clear();
ui->input_SpendProof->clear();
});
connect(ui->btn_outClear, &QPushButton::clicked, [this](){
ui->lineEdit_outTxID->clear();
ui->lineEdit_outAddress->clear();
ui->lineEdit_outMessage->clear();
ui->input_OutProof->clear();
});
connect(ui->btn_inClear, &QPushButton::clicked, [this](){
ui->lineEdit_inTxID->clear();
ui->lineEdit_inAddress->clear();
ui->lineEdit_inMessage->clear();
ui->input_InProof->clear();
});
}
@@ -46,20 +44,6 @@ VerifyProofDialog::~VerifyProofDialog()
delete ui;
}
void VerifyProofDialog::checkProof() {
switch (ui->tabWidget->currentIndex()) {
case 0:
this->checkSpendProof();
break;
case 1:
this->checkOutProof();
break;
case 2:
this->checkInProof();
break;
}
}
void VerifyProofDialog::checkSpendProof() {
auto r = m_wallet->checkSpendProof(ui->lineEdit_spendTxID->text(), ui->lineEdit_spendMessage->text(), ui->input_SpendProof->toPlainText());
+3 -4
View File
@@ -20,14 +20,13 @@ public:
~VerifyProofDialog() override;
private slots:
void checkProof();
private:
void checkTxProof(const QString &txId, const QString &address, const QString &message, const QString &signature);
void checkSpendProof();
void checkOutProof();
void checkInProof();
private:
void checkTxProof(const QString &txId, const QString &address, const QString &message, const QString &signature);
Ui::VerifyProofDialog *ui;
Wallet *m_wallet;
};
+108 -49
View File
@@ -39,17 +39,7 @@
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Message:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_spendTxID"/>
</item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
@@ -57,10 +47,13 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_spendMessage">
<property name="placeholderText">
<string>Optional message against which the signature is signed</string>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_spendTxID"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Message:</string>
</property>
</widget>
</item>
@@ -71,6 +64,13 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_spendMessage">
<property name="placeholderText">
<string>Optional message against which the signature is signed</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPlainTextEdit" name="input_SpendProof">
<property name="overwriteMode">
@@ -96,6 +96,37 @@
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btn_spendClear">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_verifySpendProof">
<property name="text">
<string>Verify</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="OutProof">
@@ -182,6 +213,37 @@
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btn_outClear">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_verifyOutProof">
<property name="text">
<string>Verify</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="InProof">
@@ -269,44 +331,41 @@
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btn_inClear">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_verifyInProof">
<property name="text">
<string>Verify</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btn_clear">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_verify">
<property name="text">
<string>Verify</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
-59
View File
@@ -1,59 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#include <QFileDialog>
#include <QInputDialog>
#include <QMessageBox>
#include "viewonlydialog.h"
#include "ui_viewonlydialog.h"
ViewOnlyDialog::ViewOnlyDialog(AppContext *ctx, QWidget *parent)
: QDialog(parent)
, ui(new Ui::ViewOnlyDialog), m_ctx(ctx)
{
ui->setupUi(this);
ui->label_restoreHeight->setText(QString::number(ctx->currentWallet->getWalletCreationHeight()));
ui->label_primaryAddress->setText(ctx->currentWallet->address(0, 0));
ui->label_secretViewKey->setText(ctx->currentWallet->getSecretViewKey());
connect(ui->btn_Copy, &QPushButton::clicked, this, &ViewOnlyDialog::copyToClipboad);
connect(ui->btn_Save, &QPushButton::clicked, this, &ViewOnlyDialog::onWriteViewOnlyWallet);
ui->btn_Save->setEnabled(!m_ctx->currentWallet->viewOnly());
this->adjustSize();
}
void ViewOnlyDialog::onWriteViewOnlyWallet(){
QString fn = QFileDialog::getSaveFileName(this, "Save .keys wallet file", QDir::homePath(), "Monero wallet (*.keys)");
if(fn.isEmpty()) return;
if(!fn.endsWith(".keys")) fn += ".keys";
QString passwd;
QInputDialog passwordDialog(this);
passwordDialog.setInputMode(QInputDialog::TextInput);
passwordDialog.setTextEchoMode(QLineEdit::Password);
passwordDialog.setWindowTitle("View-Only wallet password");
passwordDialog.setLabelText("Protect this view-only wallet with a password?");
passwordDialog.resize(300, 100);
if((bool)passwordDialog.exec())
passwd = passwordDialog.textValue();
m_ctx->currentWallet->createViewOnly(fn, passwd);
QMessageBox::information(this, "Information", "View-only wallet successfully written to disk.");
}
void ViewOnlyDialog::copyToClipboad() {
QString text = "";
text += QString("Address: %1\n").arg(ui->label_primaryAddress->text());
text += QString("Secret view key: %1\n").arg(ui->label_secretViewKey->text());
text += QString("Restore height: %1\n").arg(ui->label_restoreHeight->text());
Utils::copyToClipboard(text);
}
ViewOnlyDialog::~ViewOnlyDialog()
{
delete ui;
}
-32
View File
@@ -1,32 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#ifndef FEATHER_VIEWONLYDIALOG_H
#define FEATHER_VIEWONLYDIALOG_H
#include <QDialog>
#include "appcontext.h"
namespace Ui {
class ViewOnlyDialog;
}
class ViewOnlyDialog : public QDialog
{
Q_OBJECT
public:
explicit ViewOnlyDialog(AppContext *ctx, QWidget *parent = nullptr);
~ViewOnlyDialog() override;
private slots:
void onWriteViewOnlyWallet();
private:
Ui::ViewOnlyDialog *ui;
AppContext *m_ctx = nullptr;
void copyToClipboad();
};
#endif //FEATHER_KEYSDIALOG_H
-139
View File
@@ -1,139 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ViewOnlyDialog</class>
<widget class="QDialog" name="ViewOnlyDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>659</width>
<height>254</height>
</rect>
</property>
<property name="windowTitle">
<string>View-Only</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox_6">
<property name="title">
<string>Restore height</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="label_restoreHeight">
<property name="text">
<string>TextLabel</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Primary address</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_primaryAddress">
<property name="text">
<string>TextLabel</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Secret view key</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_secretViewKey">
<property name="text">
<string>TextLabel</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="btn_Copy">
<property name="text">
<string>Copy</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_Save">
<property name="text">
<string>Create view-only wallet</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ViewOnlyDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ViewOnlyDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
+1 -1
View File
@@ -31,7 +31,7 @@ WalletInfoDialog::WalletInfoDialog(AppContext *ctx, QWidget *parent)
void WalletInfoDialog::openWalletDir() {
QFileInfo file(m_ctx->walletPath);
QDesktopServices::openUrl(QUrl(QString("file://%1").arg(file.absolutePath()), QUrl::TolerantMode));
QDesktopServices::openUrl(file.absolutePath());
}
WalletInfoDialog::~WalletInfoDialog() {
-14
View File
@@ -1,14 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020, The Monero Project.
#ifndef FEATHER_GLOBALS_H
#define FEATHER_GLOBALS_H
#include <QtGlobal>
namespace globals
{
const qreal cdiv = 1e12;
}
#endif //FEATHER_GLOBALS_H
+19 -42
View File
@@ -25,9 +25,15 @@ HistoryWidget::HistoryWidget(QWidget *parent)
m_copyMenu->addAction("Transaction ID", this, [this]{copy(copyField::TxID);});
m_copyMenu->addAction("Date", this, [this]{copy(copyField::Date);});
m_copyMenu->addAction("Amount", this, [this]{copy(copyField::Amount);});
m_copyMenu->addAction("Spend proof", this, &HistoryWidget::getSpendProof);
ui->history->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->history, &QTreeView::customContextMenuRequested, this, &HistoryWidget::showContextMenu);
connect(ui->history, &QTreeView::customContextMenuRequested, [=](const QPoint & point){
QModelIndex index = ui->history->indexAt(point);
if (index.isValid()) {
m_contextMenu->exec(ui->history->viewport()->mapToGlobal(point));
}
});
connect(ui->search, &QLineEdit::textChanged, this, &HistoryWidget::setSearchFilter);
connect(ui->history, &QTreeView::doubleClicked, [this](QModelIndex index){
@@ -39,48 +45,11 @@ HistoryWidget::HistoryWidget(QWidget *parent)
}
void HistoryWidget::showContextMenu(const QPoint &point) {
QModelIndex index = ui->history->indexAt(point);
if (!index.isValid()) {
return;
}
QMenu menu(this);
TransactionInfo::Direction direction;
QString txid;
bool unconfirmed;
m_txHistory->transaction(m_model->mapToSource(index).row(), [&direction, &txid, &unconfirmed](TransactionInfo &tInfo) {
direction = tInfo.direction();
txid = tInfo.hash();
unconfirmed = tInfo.isFailed() || tInfo.isPending();
});
if (AppContext::txCache.contains(txid) && unconfirmed && direction != TransactionInfo::Direction_In) {
menu.addAction(QIcon(":/assets/images/info.png"), "Resend transaction", this, &HistoryWidget::onResendTransaction);
}
menu.addMenu(m_copyMenu);
menu.addAction(QIcon(":/assets/images/info.png"), "Show details", this, &HistoryWidget::showTxDetails);
menu.addAction(QIcon(":/assets/images/network.png"), "View on block explorer", this, &HistoryWidget::onViewOnBlockExplorer);
menu.exec(ui->history->viewport()->mapToGlobal(point));
}
void HistoryWidget::onResendTransaction() {
QModelIndex index = ui->history->currentIndex();
QString txid;
m_txHistory->transaction(m_model->mapToSource(index).row(), [&txid](TransactionInfo &tInfo) {
txid = tInfo.hash();
});
emit resendTransaction(txid);
}
void HistoryWidget::setModel(TransactionHistoryProxyModel *model, Wallet *wallet)
void HistoryWidget::setModel(Coins *coins, TransactionHistoryProxyModel *model, TransactionHistory *txHistory)
{
m_coins = coins;
m_model = model;
m_wallet = wallet;
m_txHistory = m_wallet->history();
m_txHistory = txHistory;
ui->history->setModel(m_model);
ui->history->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
@@ -97,7 +66,7 @@ void HistoryWidget::showTxDetails() {
});
if (i != nullptr) {
auto * dialog = new TransactionInfoDialog(m_wallet, i, this);
auto * dialog = new TransactionInfoDialog(m_coins, i, this);
dialog->exec();
}
}
@@ -112,6 +81,14 @@ void HistoryWidget::onViewOnBlockExplorer() {
emit viewOnBlockExplorer(txid);
}
void HistoryWidget::getSpendProof() {
QModelIndex index = ui->history->currentIndex();
m_txHistory->transaction(m_model->mapToSource(index).row(), [this](TransactionInfo &tInfo) {
emit spendProof(tInfo.hash());
});
}
void HistoryWidget::setSearchText(const QString &text) {
ui->search->setText(text);
}
+4 -6
View File
@@ -7,7 +7,6 @@
#include "model/TransactionHistoryModel.h"
#include "model/TransactionHistoryProxyModel.h"
#include "libwalletqt/Coins.h"
#include "libwalletqt/Wallet.h"
#include <QWidget>
#include <QMenu>
@@ -22,21 +21,21 @@ Q_OBJECT
public:
explicit HistoryWidget(QWidget *parent = nullptr);
void setModel(TransactionHistoryProxyModel *model, Wallet *wallet);
void setModel(Coins * coins, TransactionHistoryProxyModel * model, TransactionHistory * txHistory);
~HistoryWidget() override;
public slots:
void setSearchText(const QString &text);
signals:
void spendProof(QString txid);
void viewOnBlockExplorer(QString txid);
void resendTransaction(QString txid);
private slots:
void showTxDetails();
void onViewOnBlockExplorer();
void getSpendProof();
void setSearchFilter(const QString &filter);
void onResendTransaction();
private:
enum copyField {
@@ -46,14 +45,13 @@ private:
};
void copy(copyField field);
void showContextMenu(const QPoint &point);
Ui::HistoryWidget *ui;
QMenu *m_contextMenu;
QMenu *m_copyMenu;
TransactionHistory *m_txHistory;
TransactionHistoryProxyModel *m_model;
Wallet *m_wallet = nullptr;
Coins *m_coins;
};
#endif //FEATHER_HISTORYWIDGET_H
-4
View File
@@ -76,10 +76,6 @@ QString CoinsInfo::address() const {
}
QString CoinsInfo::addressLabel() const {
if (m_subaddrIndex == 0) {
return m_coinbase ? "Coinbase" : "Change";
}
return m_addressLabel;
}
-53
View File
@@ -1,53 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2014-2020, The Monero Project.
#include "ConstructionInfo.h"
#include "Input.h"
#include "Transfer.h"
quint64 ConstructionInfo::unlockTime() const {
return m_unlockTime;
}
QSet<quint32> ConstructionInfo::subaddressIndices() const {
return m_subaddressIndices;
}
QVector<QString> ConstructionInfo::subaddresses() const {
return m_subaddresses;
}
quint64 ConstructionInfo::minMixinCount() const {
return m_minMixinCount;
}
QList<Input *> ConstructionInfo::inputs() const {
return m_inputs;
}
QList<Transfer *> ConstructionInfo::outputs() const {
return m_outputs;
}
ConstructionInfo::ConstructionInfo(const Monero::TransactionConstructionInfo *pimpl, QObject *parent)
: QObject(parent)
, m_unlockTime(pimpl->unlockTime())
, m_minMixinCount(pimpl->minMixinCount())
{
for (auto const &i : pimpl->inputs())
{
Input *input = new Input(i.amount, QString::fromStdString(i.pubkey), this);
m_inputs.append(input);
}
for (auto const &o : pimpl->outputs())
{
Transfer *output = new Transfer(o.amount, QString::fromStdString(o.address), this);
m_outputs.append(output);
}
for (uint32_t i : pimpl->subaddressIndices())
{
m_subaddressIndices.insert(i);
}
}
-46
View File
@@ -1,46 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2014-2020, The Monero Project.
#ifndef FEATHER_CONSTRUCTIONINFO_H
#define FEATHER_CONSTRUCTIONINFO_H
#include <wallet/api/wallet2_api.h>
#include <QObject>
#include <QSet>
class Input;
class Transfer;
class ConstructionInfo : public QObject
{
Q_OBJECT
Q_PROPERTY(quint64 unlockTime READ unlockTime)
Q_PROPERTY(QSet<quint32> subaddressIndices READ subaddressIndices)
Q_PROPERTY(QVector<QString> subaddresses READ subaddresses)
Q_PROPERTY(quint64 minMixinCount READ minMixinCount)
Q_PROPERTY(QList<Input*> inputs READ inputs)
Q_PROPERTY(QList<Transfer*> outputs READ outputs)
public:
quint64 unlockTime() const;
QSet<quint32> subaddressIndices() const;
QVector<QString> subaddresses() const;
quint64 minMixinCount() const;
QList<Input*> inputs() const;
QList<Transfer*> outputs() const;
private:
explicit ConstructionInfo(const Monero::TransactionConstructionInfo *pimpl, QObject *parent = nullptr);
friend class PendingTransactionInfo;
friend class UnsignedTransaction;
quint64 m_unlockTime;
QSet<quint32> m_subaddressIndices;
QVector<QString> m_subaddresses;
quint64 m_minMixinCount;
mutable QList<Input*> m_inputs;
mutable QList<Transfer*> m_outputs;
};
#endif //FEATHER_CONSTRUCTIONINFO_H
-29
View File
@@ -1,29 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2014-2020, The Monero Project.
#ifndef FEATHER_INPUT_H
#define FEATHER_INPUT_H
#include <wallet/api/wallet2_api.h>
#include <QObject>
#include <utility>
class Input : public QObject
{
Q_OBJECT
Q_PROPERTY(quint64 amount READ amount)
Q_PROPERTY(QString pubKey READ pubKey)
private:
explicit Input(uint64_t _amount, QString _address, QObject *parent = nullptr): QObject(parent), m_amount(_amount), m_pubkey(std::move(_address)) {};
friend class ConstructionInfo;
quint64 m_amount;
QString m_pubkey;
public:
quint64 amount() const { return m_amount; }
QString pubKey() const { return m_pubkey; }
};
#endif //FEATHER_INPUT_H
+7 -32
View File
@@ -16,12 +16,10 @@ QString PendingTransaction::errorString() const
bool PendingTransaction::commit()
{
return m_pimpl->commit();
}
bool PendingTransaction::saveToFile(const QString &fileName)
{
return m_pimpl->commit(fileName.toStdString());
// Save transaction to file if fileName is set.
if(!m_fileName.isEmpty())
return m_pimpl->commit(m_fileName.toStdString());
return m_pimpl->commit(m_fileName.toStdString());
}
quint64 PendingTransaction::amount() const
@@ -39,6 +37,7 @@ quint64 PendingTransaction::fee() const
return m_pimpl->fee();
}
QStringList PendingTransaction::txid() const
{
QStringList list;
@@ -64,33 +63,9 @@ QList<QVariant> PendingTransaction::subaddrIndices() const
return result;
}
QByteArray PendingTransaction::unsignedTxToBin() const {
return QByteArray::fromStdString(m_pimpl->unsignedTxToBin());
}
QString PendingTransaction::unsignedTxToBase64() const
void PendingTransaction::setFilename(const QString &fileName)
{
return QString::fromStdString(m_pimpl->unsignedTxToBase64());
}
QString PendingTransaction::signedTxToHex(int index) const
{
return QString::fromStdString(m_pimpl->signedTxToHex(index));
}
PendingTransactionInfo * PendingTransaction::transaction(int index) const {
return m_pending_tx_info[index];
}
void PendingTransaction::refresh()
{
qDeleteAll(m_pending_tx_info);
m_pending_tx_info.clear();
m_pimpl->refresh();
for (const auto i : m_pimpl->getAll()) {
m_pending_tx_info.append(new PendingTransactionInfo(i, this));
}
m_fileName = fileName;
}
PendingTransaction::PendingTransaction(Monero::PendingTransaction *pt, QObject *parent)
+4 -12
View File
@@ -9,8 +9,6 @@
#include <QVariant>
#include <wallet/api/wallet2_api.h>
#include "PendingTransactionInfo.h"
//namespace Monero {
//class PendingTransaction;
@@ -32,7 +30,7 @@ public:
enum Status {
Status_Ok = Monero::PendingTransaction::Status_Ok,
Status_Error = Monero::PendingTransaction::Status_Error,
Status_Critical = Monero::PendingTransaction::Status_Critical
Status_Critical = Monero::PendingTransaction::Status_Critical
};
Q_ENUM(Status)
@@ -47,27 +45,21 @@ public:
Status status() const;
QString errorString() const;
Q_INVOKABLE bool commit();
bool saveToFile(const QString &fileName);
quint64 amount() const;
quint64 dust() const;
quint64 fee() const;
QStringList txid() const;
quint64 txCount() const;
QList<QVariant> subaddrIndices() const;
QByteArray unsignedTxToBin() const;
QString unsignedTxToBase64() const;
QString signedTxToHex(int index) const;
void refresh();
PendingTransactionInfo * transaction(int index) const;
Q_INVOKABLE void setFilename(const QString &fileName);
private:
explicit PendingTransaction(Monero::PendingTransaction * pt, QObject *parent = nullptr);
explicit PendingTransaction(Monero::PendingTransaction * pt, QObject *parent = 0);
private:
friend class Wallet;
Monero::PendingTransaction * m_pimpl;
mutable QList<PendingTransactionInfo*> m_pending_tx_info;
QString m_fileName;
};
#endif // PENDINGTRANSACTION_H
@@ -1,32 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2014-2020, The Monero Project.
#include "PendingTransactionInfo.h"
#include "Input.h"
#include "Transfer.h"
quint64 PendingTransactionInfo::fee() const {
return m_fee;
}
quint64 PendingTransactionInfo::dust() const {
return m_dust;
}
bool PendingTransactionInfo::dustAddedToFee() const {
return m_dustAddedToFee;
}
QString PendingTransactionInfo::txKey() const {
return m_txKey;
}
PendingTransactionInfo::PendingTransactionInfo(const Monero::PendingTransactionInfo *pimpl, QObject *parent)
: ConstructionInfo(pimpl->constructionData(), parent)
, m_fee(pimpl->fee())
, m_dust(pimpl->dust())
, m_dustAddedToFee(pimpl->dustAddedToFee())
, m_txKey(QString::fromStdString(pimpl->txKey()))
{
}
-46
View File
@@ -1,46 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2014-2020, The Monero Project.
#ifndef FEATHER_PENDINGTRANSACTIONINFO_H
#define FEATHER_PENDINGTRANSACTIONINFO_H
#include <wallet/api/wallet2_api.h>
#include "ConstructionInfo.h"
#include <QObject>
#include <QSet>
class Input;
class Transfer;
class PendingTransactionInfo : public ConstructionInfo
{
Q_OBJECT
Q_PROPERTY(quint64 fee READ fee)
Q_PROPERTY(quint64 dust READ dust)
Q_PROPERTY(bool dustAddedToFee READ dustAddedToFee)
Q_PROPERTY(QString txKey READ txKey)
Q_PROPERTY(quint64 unlockTime READ unlockTime)
Q_PROPERTY(QSet<quint32> subaddressIndices READ subaddressIndices)
Q_PROPERTY(QVector<QString> subaddresses READ subaddresses)
Q_PROPERTY(quint64 minMixinCount READ minMixinCount)
Q_PROPERTY(QList<Input*> inputs READ inputs)
Q_PROPERTY(QList<Transfer*> outputs READ outputs)
public:
quint64 fee() const;
quint64 dust() const;
bool dustAddedToFee() const;
QString txKey() const;
private:
explicit PendingTransactionInfo(const Monero::PendingTransactionInfo *pimpl, QObject *parent = nullptr);
friend class PendingTransaction;
quint64 m_fee;
quint64 m_dust;
bool m_dustAddedToFee;
QString m_txKey;
};
#endif //FEATHER_PENDINGTRANSACTIONINFO_H

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