Compare commits

..
54 Commits
Author SHA1 Message Date
tobtoht 8c197f26ea Merge pull request 'build: prepare beta-2' (#224) from tobtoht/feather:beta-2 into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/224
2020-12-14 23:06:10 +00:00
tobtoht 6f17a1dfaa Merge pull request 'Update OpenSSL to 1.1.1i' (#223) from tobtoht/feather:openssl_1.1.1i into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/223
2020-12-14 23:04:58 +00:00
tobtoht 2217ae602a Merge pull request 'Allow resending failed transactions' (#212) from tobtoht/feather:black_holed_no_more into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/212
2020-12-14 22:27:12 +00:00
tobtoht 75743e8897 build: prepare beta-2 2020-12-14 23:10:54 +01:00
tobtoht 169d14ab3a Allow resending failed transactions 2020-12-14 23:07:50 +01:00
tobtoht 710556a580 Update OpenSSL to 1.1.1i 2020-12-14 21:55:52 +01:00
tobtoht 15211ce5fa Merge pull request 'Menu: add rescan spent' (#221) from tobtoht/feather:rescan_spent into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/221
2020-12-14 19:45:26 +00:00
tobtoht 66f53d865e Menu: add rescan spent 2020-12-14 20:44:37 +01:00
tobtoht ea81b308f7 Merge pull request 'TxInfoDialog: set blockheight to unconfirmed for mempool txs' (#220) from tobtoht/feather:tx_info_blockheight into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/220
2020-12-14 19:31:01 +00:00
tobtoht 9016fa13dc TxInfoDialog: set blockheight to unconfirmed for mempool txs 2020-12-14 20:30:15 +01:00
tobtoht cee70a997d Merge pull request 'TickerWidget: don't show percentage on balance' (#219) from tobtoht/feather:ticker_widget_no_perc into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/219
2020-12-14 19:19:40 +00:00
tobtoht 041c11f618 TickerWidget: don't show percentage on balance 2020-12-14 20:17:22 +01:00
tobtoht c5f0962e40 Merge pull request 'Replace showMessageBox with Qt builtin' (#218) from tobtoht/feather:messagebox_cleanup into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/218
2020-12-14 02:25:11 +00:00
tobtoht 85a06007a1 Replace showMessageBox with Qt builtin 2020-12-14 03:23:19 +01:00
tobtoht b6459d1b64 Merge pull request 'Remove user_agents.txt' (#217) from tobtoht/feather:remove_user_agents into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/217
2020-12-14 01:49:06 +00:00
tobtoht 653e59f5ec Remove user_agents.txt 2020-12-14 02:47:51 +01:00
tobtoht 71e28831d8 Merge pull request 'Coins: copy label' (#216) from tobtoht/feather:coins_copy_label into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/216
2020-12-14 01:33:29 +00:00
tobtoht 874748ea7f Coins: copy label 2020-12-14 02:30:30 +01:00
tobtoht d3e55c4510 Merge pull request 'Store wallet immediately after sending tx' (#215) from tobtoht/feather:store_on_send into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/215
2020-12-14 01:18:08 +00:00
tobtoht 147ee8ef8b Store wallet immediately after sending tx 2020-12-14 02:15:56 +01:00
tobtoht 5ec641bc6f Merge pull request 'Update fiat conversion label on donate' (#214) from tobtoht/feather:donation_fix into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/214
2020-12-14 01:01:00 +00:00
tobtoht 4a37be1ce7 Update fiat conversion label on donate 2020-12-14 01:59:32 +01:00
tobtoht d1b4db2be4 Merge pull request 'Core: rebase to v0.17.1.7' (#213) from tobtoht/feather:v0.17.1.7 into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/213
2020-12-13 13:21:29 +00:00
tobtoht 1e2fa51b98 Core: rebase to v0.17.1.7 2020-12-13 14:19:17 +01:00
tobtoht 743c5fa9a4 Merge pull request 'DebugInfoDialog: improve Tor status on Tails' (#211) from tobtoht/feather:tails_debug_info into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/211
2020-12-12 16:34:58 +00:00
tobtoht ae1d6a2d1c DebugInfoDialog: improve Tor status on Tails 2020-12-12 17:33:33 +01:00
tobtoht 5e246519c2 Merge pull request 'SeedDialog: improve UI' (#210) from tobtoht/feather:seed_dialog_height into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/210
2020-12-12 16:23:24 +00:00
tobtoht 8b5cb8ba2c SeedDialog: improve UI 2020-12-12 17:19:37 +01:00
tobtoht 3ea7e5932e Merge pull request 'Menu: remove disabled open wallet item' (#209) from tobtoht/feather:remove_open_wallet into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/209
2020-12-12 16:07:29 +00:00
tobtoht 97b4fcb958 Menu: remove disable open wallet item 2020-12-12 16:59:44 +01:00
tobtoht 80c1c66bea Merge pull request 'MorphToken: add statustext for missing states' (#208) from tobtoht/feather:morphtoken_processing_delay into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/208
2020-12-12 15:37:26 +00:00
tobtoht be61c803bf MorphToken: add statustext for missing states 2020-12-12 16:35:44 +01:00
tobtoht a0a307f3bd Merge pull request 'Remove sorry()' (#207) from tobtoht/feather:no_sorry into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/207
2020-12-12 14:56:18 +00:00
tobtoht 1d8f4f0bfd Remove sorry() 2020-12-12 15:54:43 +01:00
tobtoht 7c288570b1 Merge pull request 'Update calc icon' (#206) from tobtoht/feather:calc_icon into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/206
2020-12-12 14:48:57 +00:00
tobtoht 02d71ebf02 Update calc icon 2020-12-12 15:46:41 +01:00
tobtoht 6ef4eaa39f Merge pull request 'Rename XMRig tab to Mining' (#205) from tobtoht/feather:xmrig_mining into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/205
2020-12-12 14:29:30 +00:00
tobtoht d3ee2744d4 Merge pull request 'XMRig: squish settings UI' (#204) from tobtoht/feather:xmrig_cleanup into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/204
2020-12-12 14:24:02 +00:00
tobtoht 61b54efb97 Rename XMRig tab to Mining 2020-12-12 15:22:31 +01:00
tobtoht 91b00da4af XMRig: squish settings UI 2020-12-12 14:39:13 +01:00
tobtoht 2b72624ec0 Merge pull request 'Consolidate exchanges to exchange tab' (#203) from tobtoht/feather:consolidate_exchanges into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/203
2020-12-12 13:03:06 +00:00
tobtoht 55bb304dc2 Merge pull request 'Drone: optimize builds' (#202) from tobtoht/feather:drone_optimize_builds into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/202
2020-12-12 12:18:18 +00:00
tobtoht 8ffd2293f4 Consolidate exchanges to exchange tab 2020-12-12 02:49:33 +01:00
tobtoht 3df2e591fe Drone: optimize builds 2020-12-12 01:54:04 +01:00
tobtoht 785771cb90 Merge pull request 'Do not bundle XMRig' (#201) from tobtoht/feather:xmrip into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/201
2020-12-12 00:51:55 +00:00
tobtoht aa14a2dcbb Do not bundle XMRig binary 2020-12-12 01:18:09 +01:00
tobtoht c9e2ce3770 Merge pull request 'Spell it backwards' (#200) from tobtoht/feather:tobtoht into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/200
2020-12-11 19:50:08 +00:00
tobtoht 835e4aaca3 Spell it backwards 2020-12-11 20:46:24 +01:00
tobtoht 97900bcbe6 Merge pull request 'Home: add tabs for home widgets' (#199) from tobtoht/feather:main_tab into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/199
2020-12-11 13:33:32 +00:00
tobtoht a9ec69afd0 Home: add tabs for home widgets 2020-12-11 14:32:14 +01:00
tobtoht a008f1f45f Merge pull request 'Add reproducible build instructions' (#198) from tobtoht/feather:update_building into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/198
2020-12-10 17:16:54 +00:00
tobtoht fbd6b8eb53 Add reproducible build instructions 2020-12-10 18:13:21 +01:00
tobtoht 855755fea3 Merge pull request 'Add release signing key' (#197) from tobtoht/feather:signing_key into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/197
2020-12-09 21:14:31 +00:00
tobtoht 302e585af4 Add release signing key 2020-12-09 22:12:55 +01:00
64 changed files with 606 additions and 8231 deletions
+4 -4
View File
@@ -16,8 +16,8 @@ steps:
- git config --global url."http://gitea:3000/".insteadOf https://github.com/ - git config --global url."http://gitea:3000/".insteadOf https://github.com/
- git config --global url."http://gitea:3000/".insteadOf https://git.wownero.com/ - git config --global url."http://gitea:3000/".insteadOf https://git.wownero.com/
- git submodule update --init monero - git submodule update --init monero
- git submodule update --init --recursive monero - git submodule update --init --depth 1 --recursive monero
- TOR="/usr/local/tor/bin/tor" XMRIG="/xmrig/xmrig" make -j8 release-static - TOR_BIN="/usr/local/tor/bin/tor" make -j8 release-static
environment: environment:
OPENSSL_ROOT_DIR: /usr/local/openssl/ OPENSSL_ROOT_DIR: /usr/local/openssl/
CMAKEFLAGS_EXTRA: -DFETCH_DEPS=Off CMAKEFLAGS_EXTRA: -DFETCH_DEPS=Off
@@ -97,8 +97,8 @@ steps:
- git config --global url."http://gitea:3000/".insteadOf https://github.com/ - git config --global url."http://gitea:3000/".insteadOf https://github.com/
- git config --global url."http://gitea:3000/".insteadOf https://git.wownero.com/ - git config --global url."http://gitea:3000/".insteadOf https://git.wownero.com/
- git submodule update --init monero - git submodule update --init monero
- git submodule update --init --recursive monero - git submodule update --init --depth 1 --recursive monero
- PATH="/mxe/usr/bin/:$PATH" TOR="/mxe/usr/x86_64-w64-mingw32.static/bin/tor.exe" XMRIG="/xmrig/xmrig.exe" make -j8 windows-mxe-release - PATH="/mxe/usr/bin/:$PATH" TOR_BIN="/mxe/usr/x86_64-w64-mingw32.static/bin/tor.exe" make -j8 windows-mxe-release
environment: environment:
CMAKEFLAGS_EXTRA: -DFETCH_DEPS=Off CMAKEFLAGS_EXTRA: -DFETCH_DEPS=Off
- name: deploy - name: deploy
+41 -36
View File
@@ -10,6 +10,44 @@ Static builds via Docker are done in 3 steps:
2. Creating a base Docker image 2. Creating a base Docker image
3. Using the base image to compile a build 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 ### 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), 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),
@@ -35,45 +73,12 @@ Note: You only need to build the base image once.
#### 3. Build #### 3. Build
```bash ```bash
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" TOR="/mxe/usr/x86_64-w64-mingw32.static/bin/tor.exe" XMRIG="/xmrig/xmrig.exe" make windows-mxe-release -j8' 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'
```
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 'TOR="/usr/local/tor/bin/tor" XMRIG="/xmrig/xmrig" make release-static -j8'
``` ```
Replace `PATH_TO_FEATHER` with the absolute path to Feather locally. Replace `PATH_TO_FEATHER` with the absolute path to Feather locally.
The resulting binary can be found in `build/bin/feather`. The resulting binary can be found in `build/bin/feather.exe`.
## macOS ## macOS
@@ -98,4 +103,4 @@ Build Feather.
CMAKE_PREFIX_PATH=~/Qt5.15.1/5.15.1/clang_64 make mac-release 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` and will **not** have Tor embedded.
+10 -28
View File
@@ -7,14 +7,14 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
set(VERSION_MAJOR "0") set(VERSION_MAJOR "0")
set(VERSION_MINOR "1") set(VERSION_MINOR "1")
set(VERSION_REVISION "0") set(VERSION_REVISION "0")
set(VERSION "beta-1") set(VERSION "beta-2")
option(FETCH_DEPS "Download dependencies if they are not found" ON) option(FETCH_DEPS "Download dependencies if they are not found" ON)
option(XMRTO "Include Xmr.To module" ON) option(XMRTO "Include Xmr.To module" ON)
option(MORPHTOKEN "Include MorphToken module" ON) option(MORPHTOKEN "Include MorphToken module" ON)
option(XMRIG "Path to XMRig binary to embed inside Feather" OFF) option(XMRIG "Include XMRig module" ON)
option(TOR "Path to Tor binary to embed inside Feather" OFF) option(TOR_BIN "Path to Tor binary to embed inside Feather" OFF)
option(TOR_VERSION "Optional git hash or tag of embedded Tor version" "tor-0.4.3.5")
option(STATIC "Link libraries statically, requires static Qt") option(STATIC "Link libraries statically, requires static Qt")
option(USE_DEVICE_TREZOR "Trezor support compilation" OFF) option(USE_DEVICE_TREZOR "Trezor support compilation" OFF)
option(DONATE_BEG "Prompt donation window every once in a while" ON) option(DONATE_BEG "Prompt donation window every once in a while" ON)
@@ -31,7 +31,7 @@ if(DEBUG)
set(CMAKE_VERBOSE_MAKEFILE ON) set(CMAKE_VERBOSE_MAKEFILE ON)
endif() endif()
set(MONERO_HEAD "1fffb4e27a317cdfaf58c7848c143eb7fc3110d9") set(MONERO_HEAD "85b0b4f73aa6114e3ff91207aa94ad2a15c939a2")
set(BUILD_GUI_DEPS ON) set(BUILD_GUI_DEPS ON)
set(ARCH "x86-64") set(ARCH "x86-64")
set(BUILD_64 ON) set(BUILD_64 ON)
@@ -181,8 +181,8 @@ if("$ENV{DRONE}" STREQUAL "true")
message(STATUS "We are inside a static compile with Drone CI") message(STATUS "We are inside a static compile with Drone CI")
endif() endif()
# To build Feather with embedded (and static) Tor, pass CMake -DTOR=/path/to/tor # To build Feather with embedded (and static) Tor, pass CMake -DTOR_BIN=/path/to/tor
if(TOR) if(TOR_BIN)
if(APPLE) if(APPLE)
execute_process(COMMAND bash -c "touch ${CMAKE_CURRENT_SOURCE_DIR}/src/tor/libevent-2.1.7.dylib") execute_process(COMMAND bash -c "touch ${CMAKE_CURRENT_SOURCE_DIR}/src/tor/libevent-2.1.7.dylib")
endif() endif()
@@ -191,34 +191,16 @@ if(TOR)
# - linux: See `Dockerfile` # - linux: See `Dockerfile`
# - windows: https://github.com/mxe/mxe/blob/1024dc7d2db5eb7d5d3c64a2c12b5f592572f1ce/plugins/apps/tor.mk # - windows: https://github.com/mxe/mxe/blob/1024dc7d2db5eb7d5d3c64a2c12b5f592572f1ce/plugins/apps/tor.mk
# - macos: taken from Tor Browser official release # - macos: taken from Tor Browser official release
set(TOR_COPY_CMD "cp ${TOR} ${CMAKE_CURRENT_SOURCE_DIR}/src/assets/exec/tor") set(TOR_COPY_CMD "cp ${TOR_BIN} ${CMAKE_CURRENT_SOURCE_DIR}/src/assets/exec/tor")
message(STATUS "${TOR_COPY_CMD}") message(STATUS "${TOR_COPY_CMD}")
execute_process(COMMAND bash -c "${TOR_COPY_CMD}" RESULT_VARIABLE ret) execute_process(COMMAND bash -c "${TOR_COPY_CMD}" RESULT_VARIABLE ret)
if(ret EQUAL "1") if(ret EQUAL "1")
message(FATAL_ERROR "Tor copy failure: ${TOR_COPY_CMD}") message(FATAL_ERROR "Tor copy failure: ${TOR_COPY_CMD}")
endif() endif()
message(STATUS "Embedding Tor binary at ${TOR}") message(STATUS "Embedding Tor binary at ${TOR_BIN}")
else() else()
message(STATUS "Skipping Tor inclusion because -DTOR=Off") message(STATUS "Skipping Tor inclusion because -DTOR_BIN=Off")
endif()
# To build Feather with embedded (and static) XMRig, pass CMake -DXMRIG=/path/to/xmrig
if(XMRIG)
# on the buildbot XMRig is baked into the image
# - linux: See `Dockerfile`
# - windows: See `Dockerfile_windows`
# - macos: manually downloaded an official release
set(XMRIG_COPY_CMD "cp ${XMRIG} ${CMAKE_CURRENT_SOURCE_DIR}/src/assets/exec/xmrig")
message(STATUS "${XMRIG_COPY_CMD}")
execute_process(COMMAND bash -c "${XMRIG_COPY_CMD}" RESULT_VARIABLE ret)
if(ret EQUAL "1")
message(FATAL_ERROR "XMRig copy failure: ${XMRIG_COPY_CMD}")
endif()
message(STATUS "Embedding XMRig binary at ${XMRIG}")
else()
message(STATUS "Skipping XMRig inclusion because -DXMRIG=Off")
endif() endif()
if(MINGW) if(MINGW)
+5 -10
View File
@@ -174,11 +174,11 @@ RUN apt install -y wget && \
./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 && \ ./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) rm -rf $(pwd)
RUN wget https://www.openssl.org/source/openssl-1.1.1g.tar.gz && \ RUN wget https://www.openssl.org/source/openssl-1.1.1i.tar.gz && \
echo "ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46 openssl-1.1.1g.tar.gz" | sha256sum -c && \ echo "e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242 openssl-1.1.1i.tar.gz" | sha256sum -c && \
tar -xzf openssl-1.1.1g.tar.gz && \ tar -xzf openssl-1.1.1i.tar.gz && \
rm openssl-1.1.1g.tar.gz && \ rm openssl-1.1.1i.tar.gz && \
cd openssl-1.1.1g && \ cd openssl-1.1.1i && \
./config no-shared no-zlib-dynamic --prefix=/usr/local/openssl && \ ./config no-shared no-zlib-dynamic --prefix=/usr/local/openssl && \
make -j$THREADS && \ make -j$THREADS && \
make -j$THREADS install && \ make -j$THREADS install && \
@@ -346,8 +346,3 @@ RUN git clone https://git.wownero.com/feather/monero-seed.git && \
make -Cbuild -j$THREADS && \ make -Cbuild -j$THREADS && \
make -Cbuild install && \ make -Cbuild install && \
rm -rf $(pwd) rm -rf $(pwd)
RUN apt install -y curl && \
curl -LO "https://github.com/xmrig/xmrig/releases/download/v6.3.5/xmrig-6.3.5-linux-static-x64.tar.gz" && \
echo "24d4f07cf5850f00ab513b228f95769a5a5ed68d35808d98f9959b58d97985a0 xmrig-6.3.5-linux-static-x64.tar.gz" | sha256sum -c && \
tar xvf xmrig-6.3.5-linux-static-x64.tar.gz --one-top-level=/xmrig --strip 1
-7
View File
@@ -72,10 +72,3 @@ RUN git clone https://git.wownero.com/feather/monero-seed.git && \
cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && \ cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && \
make -Cbuild -j$THREADS && \ make -Cbuild -j$THREADS && \
make -Cbuild install make -Cbuild install
RUN apt install -y curl && \
curl -LO "https://github.com/xmrig/xmrig/releases/download/v6.3.5/xmrig-6.3.5-gcc-win64.zip" && \
echo "e45915ada7e6e30f6ab40abf33831056449d5914307d7706bb0ad439b6d64c12 xmrig-6.3.5-gcc-win64.zip" > hashsum.txt && \
sha256sum -c hashsum.txt && \
unzip -q xmrig-6.3.5-gcc-win64.zip -d /xmrig && \
mv /xmrig/xmrig-6.3.5/* /xmrig/
+3 -3
View File
@@ -42,9 +42,9 @@ via the `CMAKE_PREFIX_PATH` definition. For me this is:
There are some Monero/Feather related options/definitions that you may pass: There are some Monero/Feather related options/definitions that you may pass:
- `-DXMRTO=OFF` - disable Xmr.To feature - `-DXMRTO=OFF` - disable Xmr.To feature
- `-DMORPHTOKEN=OFF` - diable MorphToken feature - `-DMORPHTOKEN=OFF` - disable MorphToken feature
- `-DTOR=/path/to/tor` - Embed a Tor executable inside Feather - `-DXMRIG=OFF` - disable XMRig feature
- `-DXMRIG=/path/to/xmrig` - Embed a XMRig executable inside Feather - `-DTOR_BIN=/path/to/tor` - Embed a Tor executable inside Feather
- `-DDONATE_BEG=OFF` - disable the dreaded donate requests - `-DDONATE_BEG=OFF` - disable the dreaded donate requests
And: And:
+8 -12
View File
@@ -30,10 +30,10 @@ CMAKEFLAGS = \
-DARCH=x86_64 \ -DARCH=x86_64 \
-DBUILD_64=On \ -DBUILD_64=On \
-DBUILD_TESTS=Off \ -DBUILD_TESTS=Off \
-DXMRTO=ON \ -DXMRTO=On \
-DMORPHTOKEN=ON \ -DMORPHTOKEN=On \
-DXMRIG=Off \ -DXMRIG=On \
-DTOR=Off \ -DTOR_BIN=Off \
-DCMAKE_CXX_STANDARD=11 \ -DCMAKE_CXX_STANDARD=11 \
-DCMAKE_VERBOSE_MAKEFILE=On \ -DCMAKE_VERBOSE_MAKEFILE=On \
-DINSTALL_VENDORED_LIBUNBOUND=Off \ -DINSTALL_VENDORED_LIBUNBOUND=Off \
@@ -43,32 +43,28 @@ CMAKEFLAGS = \
$(CMAKEFLAGS_EXTRA) $(CMAKEFLAGS_EXTRA)
release-static: CMAKEFLAGS += -DBUILD_TAG="linux-x64" release-static: CMAKEFLAGS += -DBUILD_TAG="linux-x64"
release-static: CMAKEFLAGS += -DTOR=$(or ${TOR},OFF) release-static: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
release-static: CMAKEFLAGS += -DXMRIG=$(or ${XMRIG},OFF)
release-static: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release release-static: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release
release-static: release-static:
cmake -Bbuild $(CMAKEFLAGS) cmake -Bbuild $(CMAKEFLAGS)
$(MAKE) -Cbuild $(MAKE) -Cbuild
windows-mxe-release: CMAKEFLAGS += -DBUILD_TAG="win-x64" windows-mxe-release: CMAKEFLAGS += -DBUILD_TAG="win-x64"
windows-mxe-release: CMAKEFLAGS += -DTOR=$(or ${TOR},OFF) windows-mxe-release: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
windows-mxe-release: CMAKEFLAGS += -DXMRIG=$(or ${XMRIG},OFF)
windows-mxe-release: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release windows-mxe-release: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release
windows-mxe-release: windows-mxe-release:
cmake -Bbuild $(CMAKEFLAGS) cmake -Bbuild $(CMAKEFLAGS)
$(MAKE) -Cbuild $(MAKE) -Cbuild
windows-mxe-debug: CMAKEFLAGS += -DBUILD_TAG="win-x64" windows-mxe-debug: CMAKEFLAGS += -DBUILD_TAG="win-x64"
windows-mxe-debug: CMAKEFLAGS += -DTOR=$(or ${TOR},OFF) windows-mxe-debug: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
windows-mxe-debug: CMAKEFLAGS += -DXMRIG=$(or ${XMRIG},OFF)
windows-mxe-debug: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Debug windows-mxe-debug: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Debug
windows-mxe-debug: windows-mxe-debug:
cmake -Bbuild $(CMAKEFLAGS) cmake -Bbuild $(CMAKEFLAGS)
$(MAKE) -Cbuild $(MAKE) -Cbuild
mac-release: CMAKEFLAGS += -DSTATIC=Off mac-release: CMAKEFLAGS += -DSTATIC=Off
mac-release: CMAKEFLAGS += -DTOR=$(or ${TOR},OFF) mac-release: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
mac-release: CMAKEFLAGS += -DXMRIG=$(or ${XMRIG},OFF)
mac-release: CMAKEFLAGS += -DBUILD_TAG="mac-x64" mac-release: CMAKEFLAGS += -DBUILD_TAG="mac-x64"
mac-release: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release mac-release: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release
mac-release: mac-release:
+1 -1
Submodule monero updated: 1fffb4e27a...85b0b4f73a
+5 -10
View File
@@ -42,7 +42,7 @@ file(GLOB SOURCE_FILES
"dialog/*.cpp" "dialog/*.cpp"
) )
if(TOR) if(TOR_BIN)
if(APPLE) if(APPLE)
set(ASSETS_TOR "assets_tor_macos.qrc") set(ASSETS_TOR "assets_tor_macos.qrc")
else() else()
@@ -50,10 +50,6 @@ if(TOR)
endif() endif()
endif() endif()
if(XMRIG)
set(ASSETS_XMRIG "assets_mining.qrc")
endif()
set(EXECUTABLE_FLAG) set(EXECUTABLE_FLAG)
if(MINGW) if(MINGW)
set(EXECUTABLE_FLAG WIN32) set(EXECUTABLE_FLAG WIN32)
@@ -77,8 +73,7 @@ add_executable(feather ${EXECUTABLE_FLAG} main.cpp
${SOURCE_FILES} ${SOURCE_FILES}
${RESOURCES} ${RESOURCES}
${ASSETS_TOR} ${ASSETS_TOR}
${ASSETS_XMRIG} )
)
# mac os bundle # mac os bundle
set_target_properties(feather PROPERTIES set_target_properties(feather PROPERTIES
@@ -126,15 +121,15 @@ if(DONATE_BEG)
endif() endif()
if(XMRTO) if(XMRTO)
target_compile_definitions(feather PRIVATE XMRTO=1) target_compile_definitions(feather PRIVATE HAS_XMRTO=1)
endif() endif()
if(MORPHTOKEN) if(MORPHTOKEN)
target_compile_definitions(feather PRIVATE HAS_MORPHTOKEN=1) target_compile_definitions(feather PRIVATE HAS_MORPHTOKEN=1)
endif() endif()
if(TOR) if(TOR_BIN)
target_compile_definitions(feather PRIVATE HAS_TOR=1) target_compile_definitions(feather PRIVATE HAS_TOR_BIN=1)
endif() endif()
if(XMRIG) if(XMRIG)
+4
View File
@@ -164,6 +164,10 @@ void MorphTokenWidget::onApiResponse(const MorphTokenApi::MorphTokenResponse &re
} }
} else if (state == "COMPLETE_WITHOUT_REFUND") { } else if (state == "COMPLETE_WITHOUT_REFUND") {
statusText += "Deposit amount below network fee, too small to refund."; statusText += "Deposit amount below network fee, too small to refund.";
} else if (state == "PROCESSING_DELAY") {
statusText += "Please enter in contact with support.\n\ncontact@morphtoken.com";
} else if (state == "CANCELLED") {
statusText += "The trade was cancelled. If this is unexpected, please contact support at contact@morphtoken.com";
} }
ui->label_status->setText(statusText); ui->label_status->setText(statusText);
+1 -1
View File
@@ -29,7 +29,7 @@
<item> <item>
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabWidget">
<property name="currentIndex"> <property name="currentIndex">
<number>1</number> <number>0</number>
</property> </property>
<widget class="QWidget" name="tabCreateTrade"> <widget class="QWidget" name="tabCreateTrade">
<attribute name="title"> <attribute name="title">
+12 -19
View File
@@ -37,6 +37,7 @@ WalletKeysFilesModel *AppContext::wallets = nullptr;
TxFiatHistory *AppContext::txFiatHistory = nullptr; TxFiatHistory *AppContext::txFiatHistory = nullptr;
double AppContext::balance = 0; double AppContext::balance = 0;
QMap<QString, QString> AppContext::txDescriptionCache; QMap<QString, QString> AppContext::txDescriptionCache;
QMap<QString, QString> AppContext::txCache;
AppContext::AppContext(QCommandLineParser *cmdargs) { AppContext::AppContext(QCommandLineParser *cmdargs) {
this->network = new QNetworkAccessManager(); this->network = new QNetworkAccessManager();
@@ -96,7 +97,6 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
if(!this->configDirectory.endsWith('/')) if(!this->configDirectory.endsWith('/'))
this->configDirectory = QString("%1/").arg(this->configDirectory); this->configDirectory = QString("%1/").arg(this->configDirectory);
#endif #endif
this->sorry();
// Config // Config
createConfigDirectory(this->configDirectory); createConfigDirectory(this->configDirectory);
@@ -147,7 +147,7 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
AppContext::prices = new Prices(); AppContext::prices = new Prices();
// xmr.to // xmr.to
#ifdef XMRTO #ifdef HAS_XMRTO
this->XMRTo = new XmrTo(this); this->XMRTo = new XmrTo(this);
#endif #endif
@@ -419,7 +419,7 @@ void AppContext::onWSMessage(const QJsonObject &msg) {
QJsonObject fiat_rates = msg.value("data").toObject(); QJsonObject fiat_rates = msg.value("data").toObject();
AppContext::prices->fiatPricesReceived(fiat_rates); AppContext::prices->fiatPricesReceived(fiat_rates);
} }
#if defined(XMRTO) #if defined(HAS_XMRTO)
else if(cmd == "xmrto_rates") { else if(cmd == "xmrto_rates") {
auto xmr_rates = msg.value("data").toObject(); auto xmr_rates = msg.value("data").toObject();
this->XMRTo->onRatesReceived(xmr_rates); this->XMRTo->onRatesReceived(xmr_rates);
@@ -526,9 +526,8 @@ void AppContext::onWSCCS(const QJsonArray &ccs_data) {
void AppContext::createConfigDirectory(const QString &dir) { void AppContext::createConfigDirectory(const QString &dir) {
QString config_dir_tor = QString("%1%2").arg(dir).arg("tor"); QString config_dir_tor = QString("%1%2").arg(dir).arg("tor");
QString config_dir_tordata = QString("%1%2").arg(dir).arg("tor/data"); QString config_dir_tordata = QString("%1%2").arg(dir).arg("tor/data");
QString config_dir_xmrig = QString("%1%2").arg(dir).arg("xmrig");
QStringList createDirs({dir, config_dir_tor, config_dir_tordata, config_dir_xmrig}); QStringList createDirs({dir, config_dir_tor, config_dir_tordata});
for(const auto &d: createDirs) { for(const auto &d: createDirs) {
if(!Utils::dirExists(d)) { if(!Utils::dirExists(d)) {
qDebug() << QString("Creating directory: %1").arg(d); qDebug() << QString("Creating directory: %1").arg(d);
@@ -681,15 +680,6 @@ void AppContext::donateBeg() {
config()->set(Config::donateBeg, donationCounter); 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() { AppContext::~AppContext() {
this->walletClose(false); this->walletClose(false);
} }
@@ -764,8 +754,8 @@ void AppContext::onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, q
} }
void AppContext::onTransactionCreated(PendingTransaction *tx, const QString &address, const QString &paymentId, quint32 mixin) { void AppContext::onTransactionCreated(PendingTransaction *tx, const QString &address, const QString &paymentId, quint32 mixin) {
if(address == this->featherDonationAddress) if(address == this->donationAddress)
this->featherDonationSending = true; this->donationSending = true;
// tx created, but not sent yet. ask user to verify first. // tx created, but not sent yet. ask user to verify first.
emit createTransactionSuccess(tx, address, mixin); emit createTransactionSuccess(tx, address, mixin);
@@ -775,12 +765,15 @@ void AppContext::onTransactionCreated(PendingTransaction *tx, const QString &add
void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid){ void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid){
this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount()); this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount());
this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount()); this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount());
this->storeWallet();
// Store wallet immediately so we don't risk losing tx key if wallet crashes
this->currentWallet->store();
emit transactionCommitted(status, tx, txid); emit transactionCommitted(status, tx, txid);
// this tx was a donation to Feather, stop our nagging // this tx was a donation to Feather, stop our nagging
if(this->featherDonationSending) { if(this->donationSending) {
this->featherDonationSending = false; this->donationSending = false;
config()->set(Config::donateBeg, -1); config()->set(Config::donateBeg, -1);
} }
} }
+6 -4
View File
@@ -39,9 +39,11 @@ public:
bool isTails = false; bool isTails = false;
bool isWhonix = false; bool isWhonix = false;
bool isDebug = false; bool isDebug = false;
const QString featherDonationAddress = "47ntfT2Z5384zku39pTM6hGcnLnvpRYW2Azm87GiAAH2bcTidtq278TL6HmwyL8yjMeERqGEBs3cqC8vvHPJd1cWQrGC65f";
const int featherDonationAmount = 50; // euro // Donation config
bool featherDonationSending = false; const QString donationAddress = "47ntfT2Z5384zku39pTM6hGcnLnvpRYW2Azm87GiAAH2bcTidtq278TL6HmwyL8yjMeERqGEBs3cqC8vvHPJd1cWQrGC65f";
const int donationAmount = 25; // euro
bool donationSending = false;
QCommandLineParser *cmdargs; QCommandLineParser *cmdargs;
@@ -84,6 +86,7 @@ public:
static WalletKeysFilesModel *wallets; static WalletKeysFilesModel *wallets;
static double balance; static double balance;
static QMap<QString, QString> txDescriptionCache; static QMap<QString, QString> txDescriptionCache;
static QMap<QString, QString> txCache;
static TxFiatHistory *txFiatHistory; static TxFiatHistory *txFiatHistory;
// libwalletqt // libwalletqt
@@ -170,7 +173,6 @@ signals:
void setTitle(const QString &title); // set window title void setTitle(const QString &title); // set window title
private: private:
void sorry();
const unsigned int m_donationBoundary = 15; const unsigned int m_donationBoundary = 15;
UtilsNetworking *m_utilsNetworkingNodes; UtilsNetworking *m_utilsNetworkingNodes;
QTimer *m_storeTimer = new QTimer(this); QTimer *m_storeTimer = new QTimer(this);
+2 -3
View File
@@ -36,8 +36,7 @@
<file>assets/images/eye_blind.png</file> <file>assets/images/eye_blind.png</file>
<file>assets/images/feather.png</file> <file>assets/images/feather.png</file>
<file>assets/images/file.png</file> <file>assets/images/file.png</file>
<file>assets/images/ghost.png</file> <file>assets/images/gnome-calc.png</file>
<file>assets/images/ghost_icon.png</file>
<file>assets/images/history.png</file> <file>assets/images/history.png</file>
<file>assets/images/info.png</file> <file>assets/images/info.png</file>
<file>assets/images/key.png</file> <file>assets/images/key.png</file>
@@ -48,6 +47,7 @@
<file>assets/images/lock_icon.png</file> <file>assets/images/lock_icon.png</file>
<file>assets/images/lock.svg</file> <file>assets/images/lock.svg</file>
<file>assets/images/microphone.png</file> <file>assets/images/microphone.png</file>
<file>assets/images/mining.png</file>
<file>assets/images/morphtoken.png</file> <file>assets/images/morphtoken.png</file>
<file>assets/images/network.png</file> <file>assets/images/network.png</file>
<file>assets/images/offline_tx.png</file> <file>assets/images/offline_tx.png</file>
@@ -103,6 +103,5 @@
<file>assets/mnemonic_25_english.txt</file> <file>assets/mnemonic_25_english.txt</file>
<file>assets/restore_heights_monero_mainnet.txt</file> <file>assets/restore_heights_monero_mainnet.txt</file>
<file>assets/restore_heights_monero_stagenet.txt</file> <file>assets/restore_heights_monero_stagenet.txt</file>
<file>assets/user_agents.txt</file>
</qresource> </qresource>
</RCC> </RCC>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because it is too large Load Diff
-5
View File
@@ -1,5 +0,0 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>assets/exec/xmrig</file>
</qresource>
</RCC>
+6 -1
View File
@@ -14,6 +14,7 @@
#include <QKeyEvent> #include <QKeyEvent>
#include <QMenu> #include <QMenu>
#include <QAction> #include <QAction>
#include <QMessageBox>
CoinsWidget::CoinsWidget(QWidget *parent) CoinsWidget::CoinsWidget(QWidget *parent)
: QWidget(parent) : QWidget(parent)
@@ -36,6 +37,7 @@ CoinsWidget::CoinsWidget(QWidget *parent)
m_copyMenu->addAction("Key Image", this, [this]{copy(copyField::KeyImage);}); m_copyMenu->addAction("Key Image", this, [this]{copy(copyField::KeyImage);});
m_copyMenu->addAction("Transaction ID", this, [this]{copy(copyField::TxID);}); m_copyMenu->addAction("Transaction ID", this, [this]{copy(copyField::TxID);});
m_copyMenu->addAction("Address", this, [this]{copy(copyField::Address);}); 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("Height", this, [this]{copy(copyField::Height);});
m_copyMenu->addAction("Amount", this, [this]{copy(copyField::Amount);}); m_copyMenu->addAction("Amount", this, [this]{copy(copyField::Amount);});
@@ -196,7 +198,7 @@ void CoinsWidget::onSweepOutput() {
qCritical() << "key image: " << keyImage; qCritical() << "key image: " << keyImage;
if (!keyImageKnown) { if (!keyImageKnown) {
Utils::showMessageBox("Unable to sweep output", "Unable to sweep output: key image unknown", true); QMessageBox::warning(this, "Unable to sweep output", "Unable to sweep output: key image unknown");
return; return;
} }
@@ -229,6 +231,9 @@ void CoinsWidget::copy(copyField field) {
case Address: case Address:
data = c.address(); data = c.address();
break; break;
case Label:
data = c.addressLabel();
break;
case Height: case Height:
data = QString::number(c.blockHeight()); data = QString::number(c.blockHeight());
break; break;
+1
View File
@@ -48,6 +48,7 @@ private:
KeyImage, KeyImage,
TxID, TxID,
Address, Address,
Label,
Height, Height,
Amount Amount
}; };
+7 -2
View File
@@ -3,10 +3,11 @@
#include "broadcasttxdialog.h" #include "broadcasttxdialog.h"
#include "ui_broadcasttxdialog.h" #include "ui_broadcasttxdialog.h"
#include "utils/nodes.h"
#include <QMessageBox> #include <QMessageBox>
BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, AppContext *ctx) BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, AppContext *ctx, const QString &transactionHex)
: QDialog(parent) : QDialog(parent)
, m_ctx(ctx) , m_ctx(ctx)
, ui(new Ui::BroadcastTxDialog) , ui(new Ui::BroadcastTxDialog)
@@ -23,6 +24,10 @@ BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, AppContext *ctx)
connect(m_rpc, &DaemonRpc::ApiResponse, this, &BroadcastTxDialog::onApiResponse); connect(m_rpc, &DaemonRpc::ApiResponse, this, &BroadcastTxDialog::onApiResponse);
if (!transactionHex.isEmpty()) {
ui->transaction->setPlainText(transactionHex);
}
this->adjustSize(); this->adjustSize();
} }
@@ -33,7 +38,7 @@ void BroadcastTxDialog::broadcastTx() {
QString node; QString node;
if (ui->radio_useCustom->isChecked()) if (ui->radio_useCustom->isChecked())
node = ui->customNode->text(); node = ui->customNode->text();
else else if (ui->radio_useDefault->isChecked())
node = m_ctx->nodes->connection().full; node = m_ctx->nodes->connection().full;
if (!node.startsWith("http://")) if (!node.startsWith("http://"))
+1 -1
View File
@@ -17,7 +17,7 @@ class BroadcastTxDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit BroadcastTxDialog(QWidget *parent, AppContext *ctx); explicit BroadcastTxDialog(QWidget *parent, AppContext *ctx, const QString &transactionHex = "");
~BroadcastTxDialog() override; ~BroadcastTxDialog() override;
private slots: private slots:
-10
View File
@@ -63,16 +63,6 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="label_2">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>All transactions are broadcast over Tor</string>
</property>
</widget>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
+9 -1
View File
@@ -27,7 +27,15 @@ DebugInfoDialog::DebugInfoDialog(AppContext *ctx, QWidget *parent)
void DebugInfoDialog::updateInfo() { void DebugInfoDialog::updateInfo() {
QString torStatus; QString torStatus;
if(m_ctx->isTorSocks)
// 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)
torStatus = "Torsocks"; torStatus = "Torsocks";
else if(m_ctx->tor->localTor) else if(m_ctx->tor->localTor)
torStatus = "Local (assumed to be running)"; torStatus = "Local (assumed to be running)";
+2 -2
View File
@@ -21,12 +21,12 @@ SeedDialog::SeedDialog(Wallet *wallet, QWidget *parent)
this->setSeed(seed_25_words); this->setSeed(seed_25_words);
} else { } else {
this->setSeed(seed_14_words); this->setSeed(seed_14_words);
ui->widgetRestoreHeight->setVisible(false); ui->frameRestoreHeight->setVisible(false);
} }
connect(ui->check_toggleSeedType, &QCheckBox::toggled, [this, seed_25_words, seed_14_words](bool toggled){ connect(ui->check_toggleSeedType, &QCheckBox::toggled, [this, seed_25_words, seed_14_words](bool toggled){
this->setSeed(toggled ? seed_25_words : seed_14_words); this->setSeed(toggled ? seed_25_words : seed_14_words);
ui->widgetRestoreHeight->setVisible(toggled); ui->frameRestoreHeight->setVisible(toggled);
}); });
ui->label_restoreHeightHelp->setHelpText("Should you restore your wallet in the future, " ui->label_restoreHeightHelp->setHelpText("Should you restore your wallet in the future, "
+33 -17
View File
@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>590</width> <width>519</width>
<height>346</height> <height>330</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -49,7 +49,7 @@
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>0</width>
<height>125</height> <height>100</height>
</size> </size>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
@@ -64,20 +64,14 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QWidget" name="widgetRestoreHeight" native="true"> <widget class="QFrame" name="frameRestoreHeight">
<layout class="QHBoxLayout" name="horizontalLayout_4"> <property name="frameShape">
<property name="leftMargin"> <enum>QFrame::StyledPanel</enum>
<number>0</number> </property>
</property> <property name="frameShadow">
<property name="topMargin"> <enum>QFrame::Raised</enum>
<number>0</number> </property>
</property> <layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item> <item>
<widget class="HelpLabel" name="label_restoreHeightHelp"> <widget class="HelpLabel" name="label_restoreHeightHelp">
<property name="text"> <property name="text">
@@ -124,14 +118,36 @@
</item> </item>
<item> <item>
<widget class="QLabel" name="label_warning"> <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"> <property name="text">
<string>warning</string> <string>warning</string>
</property> </property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </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> <item>
<widget class="QDialogButtonBox" name="buttonBox"> <widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation"> <property name="orientation">
+5 -1
View File
@@ -30,9 +30,13 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx
ui->label_txKey->setText(txKey); ui->label_txKey->setText(txKey);
} }
QString blockHeight = QString::number(txInfo->blockHeight());
if (blockHeight == "0")
blockHeight = "Unconfirmed";
ui->label_status->setText(QString("Status: %1 confirmations").arg(txInfo->confirmations())); 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_date->setText(QString("Date: %1").arg(txInfo->timestamp().toString("yyyy-MM-dd HH:mm")));
ui->label_blockHeight->setText(QString("Block height: %1").arg(txInfo->blockHeight())); ui->label_blockHeight->setText(QString("Block height: %1").arg(blockHeight));
QString direction = txInfo->direction() == TransactionInfo::Direction_In ? "received" : "sent"; QString direction = txInfo->direction() == TransactionInfo::Direction_In ? "received" : "sent";
ui->label_amount->setText(QString("Amount %1: %2").arg(direction, txInfo->displayAmount())); ui->label_amount->setText(QString("Amount %1: %2").arg(direction, txInfo->displayAmount()));
+1
View File
@@ -51,6 +51,7 @@ TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QStrin
connect(ui->btn_Advanced, &QPushButton::clicked, this, &TxConfDialog::setShowAdvanced); connect(ui->btn_Advanced, &QPushButton::clicked, this, &TxConfDialog::setShowAdvanced);
AppContext::txCache[tx->txid()[0]] = tx->signedTxToHex(0);
this->adjustSize(); this->adjustSize();
} }
+38 -20
View File
@@ -25,20 +25,9 @@ HistoryWidget::HistoryWidget(QWidget *parent)
m_copyMenu->addAction("Transaction ID", this, [this]{copy(copyField::TxID);}); m_copyMenu->addAction("Transaction ID", this, [this]{copy(copyField::TxID);});
m_copyMenu->addAction("Date", this, [this]{copy(copyField::Date);}); m_copyMenu->addAction("Date", this, [this]{copy(copyField::Date);});
m_copyMenu->addAction("Amount", this, [this]{copy(copyField::Amount);}); m_copyMenu->addAction("Amount", this, [this]{copy(copyField::Amount);});
auto spendProof = m_copyMenu->addAction("Spend proof", this, &HistoryWidget::getSpendProof);
ui->history->setContextMenuPolicy(Qt::CustomContextMenu); ui->history->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->history, &QTreeView::customContextMenuRequested, [=](const QPoint & point){ connect(ui->history, &QTreeView::customContextMenuRequested, this, &HistoryWidget::showContextMenu);
QModelIndex index = ui->history->indexAt(point);
if (index.isValid()) {
TransactionInfo::Direction direction;
m_txHistory->transaction(m_model->mapToSource(index).row(), [&direction](TransactionInfo &tInfo) {
direction = tInfo.direction();
});
spendProof->setVisible(direction == TransactionInfo::Direction_Out);
m_contextMenu->exec(ui->history->viewport()->mapToGlobal(point));
}
});
connect(ui->search, &QLineEdit::textChanged, this, &HistoryWidget::setSearchFilter); connect(ui->search, &QLineEdit::textChanged, this, &HistoryWidget::setSearchFilter);
connect(ui->history, &QTreeView::doubleClicked, [this](QModelIndex index){ connect(ui->history, &QTreeView::doubleClicked, [this](QModelIndex index){
@@ -50,6 +39,43 @@ 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) {
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(TransactionHistoryProxyModel *model, Wallet *wallet)
{ {
m_model = model; m_model = model;
@@ -86,14 +112,6 @@ void HistoryWidget::onViewOnBlockExplorer() {
emit viewOnBlockExplorer(txid); 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) { void HistoryWidget::setSearchText(const QString &text) {
ui->search->setText(text); ui->search->setText(text);
} }
+3 -2
View File
@@ -29,14 +29,14 @@ public slots:
void setSearchText(const QString &text); void setSearchText(const QString &text);
signals: signals:
void spendProof(QString txid);
void viewOnBlockExplorer(QString txid); void viewOnBlockExplorer(QString txid);
void resendTransaction(QString txid);
private slots: private slots:
void showTxDetails(); void showTxDetails();
void onViewOnBlockExplorer(); void onViewOnBlockExplorer();
void getSpendProof();
void setSearchFilter(const QString &filter); void setSearchFilter(const QString &filter);
void onResendTransaction();
private: private:
enum copyField { enum copyField {
@@ -46,6 +46,7 @@ private:
}; };
void copy(copyField field); void copy(copyField field);
void showContextMenu(const QPoint &point);
Ui::HistoryWidget *ui; Ui::HistoryWidget *ui;
QMenu *m_contextMenu; QMenu *m_contextMenu;
+4
View File
@@ -76,6 +76,10 @@ QString CoinsInfo::address() const {
} }
QString CoinsInfo::addressLabel() const { QString CoinsInfo::addressLabel() const {
if (m_subaddrIndex == 0) {
return m_coinbase ? "Coinbase" : "Change";
}
return m_addressLabel; return m_addressLabel;
} }
+2 -6
View File
@@ -26,16 +26,12 @@ int main(int argc, char *argv[])
{ {
Q_INIT_RESOURCE(assets); Q_INIT_RESOURCE(assets);
#if defined(Q_OS_MAC) && defined(HAS_TOR) #if defined(Q_OS_MAC) && defined(HAS_TOR_BIN)
Q_INIT_RESOURCE(assets_tor_macos); Q_INIT_RESOURCE(assets_tor_macos);
#elif defined(HAS_TOR) #elif defined(HAS_TOR_BIN)
Q_INIT_RESOURCE(assets_tor); Q_INIT_RESOURCE(assets_tor);
#endif #endif
#if defined(HAS_XMRIG)
Q_INIT_RESOURCE(assets_mining);
#endif
#ifdef _WIN32 #ifdef _WIN32
if (AttachConsole(ATTACH_PARENT_PROCESS)) { if (AttachConsole(ATTACH_PARENT_PROCESS)) {
freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stdout);
+63 -85
View File
@@ -104,9 +104,9 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
"Try to explain not only what the bug is, but how it occurs.</body>"); "Try to explain not only what the bug is, but how it occurs.</body>");
}); });
connect(ui->actionShow_debug_info, &QAction::triggered, this, &MainWindow::showDebugInfo); connect(ui->actionShow_debug_info, &QAction::triggered, this, &MainWindow::showDebugInfo);
connect(ui->actionOfficialWebsite, &QAction::triggered, [=] { Utils::externalLinkWarning("https://featherwallet.org"); }); connect(ui->actionOfficialWebsite, &QAction::triggered, [=] { Utils::externalLinkWarning(this, "https://featherwallet.org"); });
#if defined(XMRTO) #if defined(HAS_XMRTO)
// xmr.to connects/widget // xmr.to connects/widget
connect(ui->xmrToWidget, &XMRToWidget::viewOrder, m_ctx->XMRTo, &XmrTo::onViewOrder); connect(ui->xmrToWidget, &XMRToWidget::viewOrder, m_ctx->XMRTo, &XmrTo::onViewOrder);
connect(ui->xmrToWidget, &XMRToWidget::getRates, m_ctx->XMRTo, &XmrTo::onGetRates); connect(ui->xmrToWidget, &XMRToWidget::getRates, m_ctx->XMRTo, &XmrTo::onGetRates);
@@ -115,14 +115,14 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
connect(m_ctx->XMRTo, &XmrTo::connectionError, ui->xmrToWidget, &XMRToWidget::onConnectionError); connect(m_ctx->XMRTo, &XmrTo::connectionError, ui->xmrToWidget, &XMRToWidget::onConnectionError);
connect(m_ctx->XMRTo, &XmrTo::connectionSuccess, ui->xmrToWidget, &XMRToWidget::onConnectionSuccess); connect(m_ctx->XMRTo, &XmrTo::connectionSuccess, ui->xmrToWidget, &XMRToWidget::onConnectionSuccess);
connect(m_ctx, &AppContext::balanceUpdated, ui->xmrToWidget, &XMRToWidget::onBalanceUpdated); connect(m_ctx, &AppContext::balanceUpdated, ui->xmrToWidget, &XMRToWidget::onBalanceUpdated);
connect(m_ctx->XMRTo, &XmrTo::openURL, this, [=](const QString &url){ Utils::externalLinkWarning(url); }); connect(m_ctx->XMRTo, &XmrTo::openURL, this, [=](const QString &url){ Utils::externalLinkWarning(this, url); });
ui->xmrToWidget->setHistoryModel(m_ctx->XMRTo->tableModel); ui->xmrToWidget->setHistoryModel(m_ctx->XMRTo->tableModel);
#else #else
ui->tabWidget->setTabVisible(Tabs::XMR_TO, false); ui->tabExchanges->setTabVisible(0, false);
#endif #endif
#ifndef HAS_MORPHTOKEN #ifndef HAS_MORPHTOKEN
ui->tabWidget->setTabVisible(Tabs::MORPHTOKEN, false); ui->tabExchanges->setTabVisible(1, false);
#endif #endif
#if defined(Q_OS_LINUX) #if defined(Q_OS_LINUX)
@@ -162,7 +162,7 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
ui->tickerLayout->addWidget(tickerWidget); ui->tickerLayout->addWidget(tickerWidget);
} }
m_balanceWidget = new TickerWidget(this, "XMR", "Balance", true); m_balanceWidget = new TickerWidget(this, "XMR", "Balance", true, true);
ui->fiatTickerLayout->addWidget(m_balanceWidget); ui->fiatTickerLayout->addWidget(m_balanceWidget);
// Send widget // Send widget
@@ -190,26 +190,13 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
ui->tabWidget->setTabVisible(Tabs::XMRIG, false); ui->tabWidget->setTabVisible(Tabs::XMRIG, false);
#endif #endif
// CCS/Reddit widget connect(ui->ccsWidget, &CCSWidget::selected, this, &MainWindow::showSendScreen);
m_ccsWidget = new CCSWidget(this); connect(m_ctx, &AppContext::ccsUpdated, ui->ccsWidget->model(), &CCSModel::updateEntries);
m_redditWidget = new RedditWidget(this); connect(m_ctx, &AppContext::redditUpdated, ui->redditWidget->model(), &RedditModel::updatePosts);
m_ccsWidget->hide(); connect(ui->tabHomeWidget, &QTabWidget::currentChanged, [](int index){
m_redditWidget->hide(); config()->set(Config::homeWidget, TabsHome(index));
ui->coolLayout->addWidget(m_ccsWidget);
ui->coolLayout->addWidget(m_redditWidget);
connect(m_ctx, &AppContext::ccsEmpty, [=] {
if(m_ccsWidget->isVisible()) {
// display Reddit widget instead
m_ccsWidget->show();
m_redditWidget->show();
}
}); });
connect(m_ctx, &AppContext::ccsUpdated, m_ccsWidget->model(), &CCSModel::updateEntries);
connect(m_ctx, &AppContext::redditUpdated, m_redditWidget->model(), &RedditModel::updatePosts);
connect(m_ccsWidget, &CCSWidget::selected, this, &MainWindow::showSendScreen);
connect(m_ctx, &AppContext::donationNag, [=]{ connect(m_ctx, &AppContext::donationNag, [=]{
auto msg = "Feather is a 100% community-sponsored endeavor. Please consider supporting " auto msg = "Feather is a 100% community-sponsored endeavor. Please consider supporting "
@@ -256,13 +243,13 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
"for developers only. Your coins are WORTHLESS."); "for developers only. Your coins are WORTHLESS.");
if(m_ctx->networkType == NetworkType::STAGENET) { if(m_ctx->networkType == NetworkType::STAGENET) {
if (config()->get(Config::warnOnStagenet).toBool()) { if (config()->get(Config::warnOnStagenet).toBool()) {
Utils::showMessageBox("Warning", worthlessWarning.arg("stagenet"), true); QMessageBox::warning(this, "Warning", worthlessWarning.arg("stagenet"));
config()->set(Config::warnOnStagenet, false); config()->set(Config::warnOnStagenet, false);
} }
} }
else if(m_ctx->networkType == NetworkType::TESTNET){ else if(m_ctx->networkType == NetworkType::TESTNET){
if (config()->get(Config::warnOnTestnet).toBool()) { if (config()->get(Config::warnOnTestnet).toBool()) {
Utils::showMessageBox("Warning", worthlessWarning.arg("testnet"), true); QMessageBox::warning(this, "Warning", worthlessWarning.arg("testnet"));
config()->set(Config::warnOnTestnet, false); config()->set(Config::warnOnTestnet, false);
} }
} }
@@ -282,9 +269,6 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_ctx, &AppContext::onPreferredFiatCurrencyChanged); connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_ctx, &AppContext::onPreferredFiatCurrencyChanged);
connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, ui->sendWidget, QOverload<>::of(&SendWidget::onPreferredFiatCurrencyChanged)); connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, ui->sendWidget, QOverload<>::of(&SendWidget::onPreferredFiatCurrencyChanged));
// CCS/Reddit widget
connect(m_windowSettings, &Settings::homeWidgetChanged, this, &MainWindow::homeWidgetChanged);
// Skin // Skin
connect(m_windowSettings, &Settings::skinChanged, this, &MainWindow::skinChanged); connect(m_windowSettings, &Settings::skinChanged, this, &MainWindow::skinChanged);
@@ -305,11 +289,8 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
}); });
// History // History
connect(ui->historyWidget, &HistoryWidget::spendProof, [&](const QString &txid){
TxProof txproof = m_ctx->currentWallet->getSpendProof(txid, "");
Utils::copyToClipboard(txproof.proof);
});
connect(ui->historyWidget, &HistoryWidget::viewOnBlockExplorer, this, &MainWindow::onViewOnBlockExplorer); connect(ui->historyWidget, &HistoryWidget::viewOnBlockExplorer, this, &MainWindow::onViewOnBlockExplorer);
connect(ui->historyWidget, &HistoryWidget::resendTransaction, this, &MainWindow::onResendTransaction);
// Contacts // Contacts
connect(ui->contactWidget, &ContactsWidget::addContact, this, &MainWindow::onAddContact); connect(ui->contactWidget, &ContactsWidget::addContact, this, &MainWindow::onAddContact);
@@ -419,26 +400,18 @@ void MainWindow::initMenu() {
m_tabShowHideMapper["Calc"] = new ToggleTab(ui->tabCalc, "Calc", "Calc", ui->actionShow_calc, Config::showTabCalc); m_tabShowHideMapper["Calc"] = new ToggleTab(ui->tabCalc, "Calc", "Calc", ui->actionShow_calc, Config::showTabCalc);
m_tabShowHideSignalMapper->setMapping(ui->actionShow_calc, "Calc"); m_tabShowHideSignalMapper->setMapping(ui->actionShow_calc, "Calc");
#if defined(HAS_MORPHTOKEN) #if defined(HAS_XMRTO) || defined(HAS_MORPHTOKEN)
connect(ui->actionShow_MorphToken, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map)); connect(ui->actionShow_Exchange, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map));
m_tabShowHideMapper["MorphToken"] = new ToggleTab(ui->tabMorphToken, "MorphToken", "MorphToken", ui->actionShow_MorphToken, Config::showTabMorphToken); m_tabShowHideMapper["Exchange"] = new ToggleTab(ui->tabExchange, "Exchange", "Exchange", ui->actionShow_Exchange, Config::showTabExchange);
m_tabShowHideSignalMapper->setMapping(ui->actionShow_MorphToken, "MorphToken"); m_tabShowHideSignalMapper->setMapping(ui->actionShow_Exchange, "Exchange");
#else #else
ui->actionShow_MorphToken->setVisible(false); ui->actionShow_Exchanges->setVisible(false);
#endif
#if defined(XMRTO)
connect(ui->actionShow_xmr_to, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map));
m_tabShowHideMapper["XMRto"] = new ToggleTab(ui->tabXmrTo, "XMRto", "XMR.to", ui->actionShow_xmr_to, Config::showTabXMRto);
m_tabShowHideSignalMapper->setMapping(ui->actionShow_xmr_to, "XMRto");
#else
ui->actionShow_xmr_to->setVisible(false);
#endif #endif
#if defined(HAS_XMRIG) #if defined(HAS_XMRIG)
connect(ui->actionShow_XMRig, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map)); connect(ui->actionShow_XMRig, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map));
m_tabShowHideMapper["XMRig"] = new ToggleTab(ui->tabXmrRig, "XMRig", "XMRig", ui->actionShow_XMRig, Config::showTabXMRig); m_tabShowHideMapper["Mining"] = new ToggleTab(ui->tabXmrRig, "Mining", "Mining", ui->actionShow_XMRig, Config::showTabXMRig);
m_tabShowHideSignalMapper->setMapping(ui->actionShow_XMRig, "XMRig"); m_tabShowHideSignalMapper->setMapping(ui->actionShow_XMRig, "Mining");
#else #else
ui->actionShow_XMRig->setVisible(false); ui->actionShow_XMRig->setVisible(false);
#endif #endif
@@ -457,15 +430,16 @@ void MainWindow::initMenu() {
connect(ui->actionPassword, &QAction::triggered, this, &MainWindow::showPasswordDialog); connect(ui->actionPassword, &QAction::triggered, this, &MainWindow::showPasswordDialog);
connect(ui->actionKeys, &QAction::triggered, this, &MainWindow::showKeysDialog); connect(ui->actionKeys, &QAction::triggered, this, &MainWindow::showKeysDialog);
connect(ui->actionViewOnly, &QAction::triggered, this, &MainWindow::showViewOnlyDialog); connect(ui->actionViewOnly, &QAction::triggered, this, &MainWindow::showViewOnlyDialog);
connect(ui->actionStore_wallet, &QAction::triggered, [&]{ connect(ui->actionStore_wallet, &QAction::triggered, [this]{
m_ctx->currentWallet->store(); m_ctx->currentWallet->store();
}); });
connect(ui->actionRefresh_tabs, &QAction::triggered, [&]{ connect(ui->actionRefresh_tabs, &QAction::triggered, [this]{
m_ctx->refreshModels(); m_ctx->refreshModels();
}); });
connect(ui->actionUpdate_balance, &QAction::triggered, [&]{ connect(ui->actionUpdate_balance, &QAction::triggered, [this]{
m_ctx->updateBalance(); m_ctx->updateBalance();
}); });
connect(ui->actionRescan_spent, &QAction::triggered, this, &MainWindow::rescanSpent);
connect(ui->actionExportKeyImages, &QAction::triggered, this, &MainWindow::exportKeyImages); connect(ui->actionExportKeyImages, &QAction::triggered, this, &MainWindow::exportKeyImages);
connect(ui->actionImportKeyImages, &QAction::triggered, this, &MainWindow::importKeyImages); connect(ui->actionImportKeyImages, &QAction::triggered, this, &MainWindow::importKeyImages);
connect(ui->actionExportOutputs, &QAction::triggered, this, &MainWindow::exportOutputs); connect(ui->actionExportOutputs, &QAction::triggered, this, &MainWindow::exportOutputs);
@@ -487,7 +461,7 @@ void MainWindow::initMenu() {
if(fn.isEmpty()) return; if(fn.isEmpty()) return;
if(!fn.endsWith(".csv")) fn += ".csv"; if(!fn.endsWith(".csv")) fn += ".csv";
m_ctx->currentWallet->history()->writeCSV(fn); m_ctx->currentWallet->history()->writeCSV(fn);
Utils::showMessageBox("CSV export", QString("Transaction history exported to %1").arg(fn), false); QMessageBox::information(this, "CSV export", QString("Transaction history exported to %1").arg(fn));
}); });
// Contact widget // Contact widget
@@ -495,7 +469,7 @@ void MainWindow::initMenu() {
if(m_ctx->currentWallet == nullptr) return; if(m_ctx->currentWallet == nullptr) return;
auto *model = m_ctx->currentWallet->addressBookModel(); auto *model = m_ctx->currentWallet->addressBookModel();
if (model->rowCount() <= 0){ if (model->rowCount() <= 0){
Utils::showMessageBox("Error", "Addressbook empty", true); QMessageBox::warning(this, "Error", "Addressbook empty");
return; return;
} }
@@ -505,7 +479,7 @@ void MainWindow::initMenu() {
qint64 now = QDateTime::currentDateTime().currentMSecsSinceEpoch(); qint64 now = QDateTime::currentDateTime().currentMSecsSinceEpoch();
QString fn = QString("%1/monero-contacts_%2.csv").arg(targetDir, QString::number(now / 1000)); QString fn = QString("%1/monero-contacts_%2.csv").arg(targetDir, QString::number(now / 1000));
if(model->writeCSV(fn)) if(model->writeCSV(fn))
Utils::showMessageBox("Address book exported", QString("Address book exported to %1").arg(fn), false); QMessageBox::information(this, "Address book exported", QString("Address book exported to %1").arg(fn));
}); });
connect(ui->actionImportContactsCSV, &QAction::triggered, this, &MainWindow::importContacts); connect(ui->actionImportContactsCSV, &QAction::triggered, this, &MainWindow::importContacts);
@@ -523,9 +497,8 @@ void MainWindow::initMenu() {
connect(ui->actionAbout, &QAction::triggered, this, &MainWindow::menuAboutClicked); connect(ui->actionAbout, &QAction::triggered, this, &MainWindow::menuAboutClicked);
connect(ui->actionDonate_to_Feather, &QAction::triggered, this, &MainWindow::donateButtonClicked); connect(ui->actionDonate_to_Feather, &QAction::triggered, this, &MainWindow::donateButtonClicked);
// Close / Open // Close wallet
connect(ui->actionClose, &QAction::triggered, this, &MainWindow::menuWalletCloseClicked); connect(ui->actionClose, &QAction::triggered, this, &MainWindow::menuWalletCloseClicked);
connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::menuWalletOpenClicked);
} }
void MainWindow::menuToggleTabVisible(const QString &key){ void MainWindow::menuToggleTabVisible(const QString &key){
@@ -538,15 +511,8 @@ void MainWindow::menuToggleTabVisible(const QString &key){
} }
void MainWindow::initWidgets() { void MainWindow::initWidgets() {
auto homeWidget = config()->get(Config::homeWidget).toString(); int homeWidget = config()->get(Config::homeWidget).toInt();
if(homeWidget == QString("ccs")) { ui->tabHomeWidget->setCurrentIndex(TabsHome(homeWidget));
m_ccsWidget->show();
} else if (homeWidget == "reddit") {
m_redditWidget->show();
} else {
config()->set(Config::homeWidget, "ccs");
m_ccsWidget->show();
}
} }
WalletWizard *MainWindow::createWizard(WalletWizard::Page startPage){ WalletWizard *MainWindow::createWizard(WalletWizard::Page startPage){
@@ -592,7 +558,7 @@ void MainWindow::touchbarShowWallet() {
} }
void MainWindow::onWalletCreatedError(const QString &err) { void MainWindow::onWalletCreatedError(const QString &err) {
Utils::showMessageBox("Wallet creation error", err, true); QMessageBox::warning(this, "Wallet creation error", err);
this->showWizard(WalletWizard::Page_CreateWallet); this->showWizard(WalletWizard::Page_CreateWallet);
} }
@@ -769,12 +735,12 @@ void MainWindow::onCreateTransactionSuccess(PendingTransaction *tx, const QStrin
err = QString("%1 %2").arg(err).arg(tx_err); err = QString("%1 %2").arg(err).arg(tx_err);
qDebug() << Q_FUNC_INFO << err; qDebug() << Q_FUNC_INFO << err;
Utils::showMessageBox("Transaction error", err, true); QMessageBox::warning(this, "Transactions error", err);
m_ctx->currentWallet->disposeTransaction(tx); m_ctx->currentWallet->disposeTransaction(tx);
} else if (tx->txCount() == 0) { } else if (tx->txCount() == 0) {
err = QString("%1 %2").arg(err).arg("No unmixable outputs to sweep."); err = QString("%1 %2").arg(err).arg("No unmixable outputs to sweep.");
qDebug() << Q_FUNC_INFO << err; qDebug() << Q_FUNC_INFO << err;
Utils::showMessageBox("Transaction error", err, true); QMessageBox::warning(this, "Transaction error", err);
m_ctx->currentWallet->disposeTransaction(tx); m_ctx->currentWallet->disposeTransaction(tx);
} else { } else {
const auto &description = m_ctx->tmpTxDescription; const auto &description = m_ctx->tmpTxDescription;
@@ -1000,12 +966,12 @@ void MainWindow::menuWalletOpenClicked() {
QFileInfo infoPath(path); QFileInfo infoPath(path);
if(!infoPath.isReadable()) { if(!infoPath.isReadable()) {
Utils::showMessageBox("Cannot read wallet file", "Permission error.", true); QMessageBox::warning(this, "Cannot read wallet file", "Permission error.");
return; return;
} }
if(path == m_ctx->walletPath) { if(path == m_ctx->walletPath) {
Utils::showMessageBox("Wallet already opened", "Please open another wallet.", true); QMessageBox::warning(this, "Wallet already opened", "Please open another wallet.");
return; return;
} }
@@ -1047,16 +1013,6 @@ void MainWindow::skinChanged(const QString &skinName) {
qDebug() << QString("Skin changed to %1").arg(skinName); qDebug() << QString("Skin changed to %1").arg(skinName);
} }
void MainWindow::homeWidgetChanged(const QString &widgetName) {
if(widgetName == "ccs"){
m_ccsWidget->show();
m_redditWidget->hide();
} else if(widgetName == "reddit") {
m_ccsWidget->hide();
m_redditWidget->show();
}
}
void MainWindow::closeEvent(QCloseEvent *event) { void MainWindow::closeEvent(QCloseEvent *event) {
cleanupBeforeClose(); cleanupBeforeClose();
@@ -1064,11 +1020,11 @@ void MainWindow::closeEvent(QCloseEvent *event) {
} }
void MainWindow::donateButtonClicked() { void MainWindow::donateButtonClicked() {
double donation = AppContext::prices->convert("EUR", "XMR", m_ctx->featherDonationAmount); double donation = AppContext::prices->convert("EUR", "XMR", m_ctx->donationAmount);
if(donation <= 0) if (donation <= 0)
donation = 1.337; donation = 0.1337;
ui->sendWidget->fill(m_ctx->featherDonationAddress, "Donation to the Feather development team", donation); ui->sendWidget->fill(m_ctx->donationAddress, "Donation to the Feather development team", donation);
ui->tabWidget->setCurrentIndex(Tabs::SEND); ui->tabWidget->setCurrentIndex(Tabs::SEND);
} }
@@ -1093,7 +1049,21 @@ void MainWindow::showSendScreen(const CCSEntry &entry) {
void MainWindow::onViewOnBlockExplorer(const QString &txid) { void MainWindow::onViewOnBlockExplorer(const QString &txid) {
QString blockExplorerLink = Utils::blockExplorerLink(config()->get(Config::blockExplorer).toString(), m_ctx->networkType, txid); QString blockExplorerLink = Utils::blockExplorerLink(config()->get(Config::blockExplorer).toString(), m_ctx->networkType, txid);
Utils::externalLinkWarning(blockExplorerLink); Utils::externalLinkWarning(this, blockExplorerLink);
}
void MainWindow::onResendTransaction(const QString &txid) {
if (!AppContext::txCache.contains(txid)) {
QMessageBox::warning(this, "Unable to resend transaction", "Transaction was not found in transaction cache. Unable to resend.");
return;
}
// Connect to a different node so chances of successful relay are higher
m_ctx->nodes->autoConnect(true);
auto dialog = new BroadcastTxDialog(this, m_ctx, AppContext::txCache[txid]);
dialog->exec();
dialog->deleteLater();
} }
void MainWindow::onAddContact(const QString &address, const QString &name) { void MainWindow::onAddContact(const QString &address, const QString &name) {
@@ -1344,6 +1314,14 @@ void MainWindow::updateNetStats() {
m_statusLabelNetStats->setText(QString("(D: %1)").arg(Utils::formatBytes(m_ctx->currentWallet->getBytesReceived()))); m_statusLabelNetStats->setText(QString("(D: %1)").arg(Utils::formatBytes(m_ctx->currentWallet->getBytesReceived())));
} }
void MainWindow::rescanSpent() {
if (!m_ctx->currentWallet->rescanSpent()) {
QMessageBox::warning(this, "Rescan spent", m_ctx->currentWallet->errorString());
} else {
QMessageBox::information(this, "Rescan spent", "Successfully rescanned spent outputs.");
}
}
MainWindow::~MainWindow() { MainWindow::~MainWindow() {
delete ui; delete ui;
} }
+8 -6
View File
@@ -76,11 +76,15 @@ public:
RECEIVE, RECEIVE,
COINS, COINS,
CALC, CALC,
MORPHTOKEN, EXCHANGES,
XMR_TO,
XMRIG XMRIG
}; };
enum TabsHome {
CCS,
REDDIT
};
public slots: public slots:
void initWidgets(); void initWidgets();
void initMenu(); void initMenu();
@@ -102,7 +106,6 @@ public slots:
void showSendTab(); void showSendTab();
void showHistoryTab(); void showHistoryTab();
void showSendScreen(const CCSEntry &entry); void showSendScreen(const CCSEntry &entry);
void homeWidgetChanged(const QString &widgetName);
void skinChanged(const QString &skinName); void skinChanged(const QString &skinName);
void menuTorClicked(); void menuTorClicked();
void onBlockchainSync(int height, int target); void onBlockchainSync(int height, int target);
@@ -114,6 +117,7 @@ public slots:
void menuWalletOpenClicked(); void menuWalletOpenClicked();
void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path); void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path);
void onViewOnBlockExplorer(const QString &txid); void onViewOnBlockExplorer(const QString &txid);
void onResendTransaction(const QString &txid);
void onAddContact(const QString &address, const QString &name); void onAddContact(const QString &address, const QString &name);
void importContacts(); void importContacts();
void showRestoreHeightDialog(); void showRestoreHeightDialog();
@@ -164,6 +168,7 @@ private:
void touchbarShowWallet(); void touchbarShowWallet();
void updatePasswordIcon(); void updatePasswordIcon();
void updateNetStats(); void updateNetStats();
void rescanSpent();
WalletWizard *createWizard(WalletWizard::Page startPage); WalletWizard *createWizard(WalletWizard::Page startPage);
@@ -177,9 +182,6 @@ private:
bool m_windowSpawned = false; bool m_windowSpawned = false;
CCSWidget *m_ccsWidget = nullptr;
RedditWidget *m_redditWidget = nullptr;
QSystemTrayIcon *m_trayIcon; QSystemTrayIcon *m_trayIcon;
QMenu m_trayMenu; QMenu m_trayMenu;
QAction *m_trayActionCalc; QAction *m_trayActionCalc;
+136 -68
View File
@@ -87,31 +87,65 @@
</layout> </layout>
</item> </item>
<item> <item>
<widget class="Line" name="homeLine"> <widget class="Line" name="line">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="coolLayout"> <widget class="QTabWidget" name="tabHomeWidget">
<property name="spacing"> <property name="currentIndex">
<number>9</number> <number>0</number>
</property> </property>
<item> <property name="documentMode">
<spacer name="verticalSpacer"> <bool>true</bool>
<property name="orientation"> </property>
<enum>Qt::Vertical</enum> <widget class="QWidget" name="tab">
<attribute name="title">
<string>CCS</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="leftMargin">
<number>0</number>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="topMargin">
<size> <number>0</number>
<width>0</width>
<height>40</height>
</size>
</property> </property>
</spacer> <property name="rightMargin">
</item> <number>0</number>
</layout> </property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="CCSWidget" name="ccsWidget" native="true"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>/r/Monero</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
<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="RedditWidget" name="redditWidget" native="true"/>
</item>
</layout>
</widget>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
@@ -227,7 +261,7 @@
<widget class="QWidget" name="tabCalc"> <widget class="QWidget" name="tabCalc">
<attribute name="icon"> <attribute name="icon">
<iconset resource="assets.qrc"> <iconset resource="assets.qrc">
<normaloff>:/assets/images/coldcard.png</normaloff>:/assets/images/coldcard.png</iconset> <normaloff>:/assets/images/gnome-calc.png</normaloff>:/assets/images/gnome-calc.png</iconset>
</attribute> </attribute>
<attribute name="title"> <attribute name="title">
<string>Calc</string> <string>Calc</string>
@@ -238,29 +272,15 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tabMorphToken"> <widget class="QWidget" name="tabExchange">
<attribute name="icon"> <attribute name="icon">
<iconset resource="assets.qrc"> <iconset resource="assets.qrc">
<normaloff>:/assets/images/morphtoken.png</normaloff>:/assets/images/morphtoken.png</iconset> <normaloff>:/assets/images/update.png</normaloff>:/assets/images/update.png</iconset>
</attribute> </attribute>
<attribute name="title"> <attribute name="title">
<string>MorphToken</string> <string>Exchange</string>
</attribute> </attribute>
<layout class="QVBoxLayout" name="verticalLayout_5"> <layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="MorphTokenWidget" name="morphtokenWidget" native="true"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabXmrTo">
<attribute name="icon">
<iconset resource="assets.qrc">
<normaloff>:/assets/images/xmrto.png</normaloff>:/assets/images/xmrto.png</iconset>
</attribute>
<attribute name="title">
<string>XMR.to</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
@@ -271,36 +291,76 @@
<number>0</number> <number>0</number>
</property> </property>
<property name="bottomMargin"> <property name="bottomMargin">
<number>1</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="XMRToWidget" name="xmrToWidget" native="true"/> <widget class="QTabWidget" name="tabExchanges">
</item> <property name="currentIndex">
<item> <number>0</number>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property> </property>
<property name="sizeType"> <widget class="QWidget" name="tabXMRto">
<enum>QSizePolicy::Preferred</enum> <attribute name="icon">
</property> <iconset resource="assets.qrc">
<property name="sizeHint" stdset="0"> <normaloff>:/assets/images/xmrto.png</normaloff>:/assets/images/xmrto.png</iconset>
<size> </attribute>
<width>20</width> <attribute name="title">
<height>0</height> <string>XMR.to</string>
</size> </attribute>
</property> <layout class="QVBoxLayout" name="verticalLayout_10">
</spacer> <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="XMRToWidget" name="xmrToWidget" native="true"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabMorphToken">
<attribute name="icon">
<iconset resource="assets.qrc">
<normaloff>:/assets/images/morphtoken.png</normaloff>:/assets/images/morphtoken.png</iconset>
</attribute>
<attribute name="title">
<string>MorphToken</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_9">
<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="MorphTokenWidget" name="morphtokenWidget" native="true"/>
</item>
</layout>
</widget>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tabXmrRig"> <widget class="QWidget" name="tabXmrRig">
<attribute name="icon"> <attribute name="icon">
<iconset resource="assets.qrc"> <iconset resource="assets.qrc">
<normaloff>:/assets/images/xmrig.ico</normaloff>:/assets/images/xmrig.ico</iconset> <normaloff>:/assets/images/mining.png</normaloff>:/assets/images/mining.png</iconset>
</attribute> </attribute>
<attribute name="title"> <attribute name="title">
<string>XMRig</string> <string>Mining</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0"> <item row="0" column="0">
@@ -326,7 +386,6 @@
<property name="title"> <property name="title">
<string>File</string> <string>File</string>
</property> </property>
<addaction name="actionOpen"/>
<addaction name="actionClose"/> <addaction name="actionClose"/>
<addaction name="actionQuit"/> <addaction name="actionQuit"/>
<addaction name="separator"/> <addaction name="separator"/>
@@ -370,6 +429,7 @@
<addaction name="actionStore_wallet"/> <addaction name="actionStore_wallet"/>
<addaction name="actionUpdate_balance"/> <addaction name="actionUpdate_balance"/>
<addaction name="actionRefresh_tabs"/> <addaction name="actionRefresh_tabs"/>
<addaction name="actionRescan_spent"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionChange_restore_height"/> <addaction name="actionChange_restore_height"/>
<addaction name="menuExport"/> <addaction name="menuExport"/>
@@ -431,8 +491,7 @@
</property> </property>
<addaction name="actionShow_Coins"/> <addaction name="actionShow_Coins"/>
<addaction name="actionShow_calc"/> <addaction name="actionShow_calc"/>
<addaction name="actionShow_MorphToken"/> <addaction name="actionShow_Exchange"/>
<addaction name="actionShow_xmr_to"/>
<addaction name="actionShow_XMRig"/> <addaction name="actionShow_XMRig"/>
</widget> </widget>
<addaction name="menuFile"/> <addaction name="menuFile"/>
@@ -441,14 +500,6 @@
<addaction name="menuTools"/> <addaction name="menuTools"/>
<addaction name="menuHelp"/> <addaction name="menuHelp"/>
</widget> </widget>
<action name="actionOpen">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Open wallet</string>
</property>
</action>
<action name="actionQuit"> <action name="actionQuit">
<property name="text"> <property name="text">
<string>Quit application</string> <string>Quit application</string>
@@ -641,7 +692,7 @@
</action> </action>
<action name="actionShow_XMRig"> <action name="actionShow_XMRig">
<property name="text"> <property name="text">
<string>Show XMRig</string> <string>Show Mining</string>
</property> </property>
</action> </action>
<action name="actionImportTransaction"> <action name="actionImportTransaction">
@@ -679,9 +730,14 @@
<string>Import transaction</string> <string>Import transaction</string>
</property> </property>
</action> </action>
<action name="actionShow_MorphToken"> <action name="actionShow_Exchange">
<property name="text"> <property name="text">
<string>Show MorphToken</string> <string>Show Exchange</string>
</property>
</action>
<action name="actionRescan_spent">
<property name="text">
<string>Rescan spent</string>
</property> </property>
</action> </action>
</widget> </widget>
@@ -734,6 +790,18 @@
<header>MorphTokenWidget.h</header> <header>MorphTokenWidget.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>CCSWidget</class>
<extends>QWidget</extends>
<header>widgets/ccswidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>RedditWidget</class>
<extends>QWidget</extends>
<header>widgets/redditwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="assets.qrc"/> <include location="assets.qrc"/>
-5
View File
@@ -180,12 +180,7 @@ QVariant CoinsModel::parseTransactionInfo(const CoinsInfo &cInfo, int column, in
case Address: case Address:
return ModelUtils::displayAddress(cInfo.address(), 1, ""); return ModelUtils::displayAddress(cInfo.address(), 1, "");
case AddressLabel: case AddressLabel:
{
if (cInfo.subaddrIndex() == 0) {
return cInfo.coinbase() ? "Coinbase" : "Change";
}
return cInfo.addressLabel(); return cInfo.addressLabel();
}
case Spent: case Spent:
return cInfo.spent(); return cInfo.spent();
case SpentHeight: case SpentHeight:
+4 -8
View File
@@ -55,17 +55,13 @@ void SendWidget::fill(double amount) {
ui->lineAmount->setText(QString::number(amount)); ui->lineAmount->setText(QString::number(amount));
} }
void SendWidget::fill(const QString &address, const QString& description){
ui->lineDescription->setText(description);
ui->lineAddress->setText(address);
ui->lineAddress->setCursorPosition(0);
}
void SendWidget::fill(const QString &address, const QString &description, double amount) { void SendWidget::fill(const QString &address, const QString &description, double amount) {
ui->lineDescription->setText(description); ui->lineDescription->setText(description);
ui->lineAmount->setText(QString::number(amount));
ui->lineAddress->setText(address); ui->lineAddress->setText(address);
ui->lineAddress->setCursorPosition(0); ui->lineAddress->setCursorPosition(0);
if (amount > 0)
ui->lineAmount->setText(QString::number(amount));
this->updateConversionLabel();
} }
void SendWidget::fillAddress(const QString &address) { void SendWidget::fillAddress(const QString &address) {
@@ -74,7 +70,7 @@ void SendWidget::fillAddress(const QString &address) {
} }
void SendWidget::sendClicked() { void SendWidget::sendClicked() {
double amount = 0.0; double amount;
QString currency = ui->comboCurrencySelection->currentText(); QString currency = ui->comboCurrencySelection->currentText();
QString recipient = ui->lineAddress->text().simplified().remove(' '); QString recipient = ui->lineAddress->text().simplified().remove(' ');
QString description = ui->lineDescription->text(); QString description = ui->lineDescription->text();
+1 -2
View File
@@ -19,8 +19,7 @@ Q_OBJECT
public: public:
explicit SendWidget(QWidget *parent = nullptr); explicit SendWidget(QWidget *parent = nullptr);
void fill(const CCSEntry &entry); void fill(const CCSEntry &entry);
void fill(const QString &address, const QString& description); void fill(const QString &address, const QString& description, double amount = 0);
void fill(const QString &address, const QString& description, double amount);
void fill(double amount); void fill(double amount);
void clearFields(); void clearFields();
~SendWidget() override; ~SendWidget() override;
-11
View File
@@ -38,16 +38,11 @@ Settings::Settings(QWidget *parent) :
ui->checkBox_hideBalance->setChecked(config()->get(Config::hideBalance).toBool()); ui->checkBox_hideBalance->setChecked(config()->get(Config::hideBalance).toBool());
// setup comboboxes // setup comboboxes
auto settingsHomeWidget = config()->get(Config::homeWidget).toString();
if (m_homeWidgets.contains(settingsHomeWidget))
ui->comboBox_homeWidget->setCurrentIndex(m_homeWidgets.indexOf(settingsHomeWidget));
this->setupSkinCombobox(); this->setupSkinCombobox();
auto settingsSkin = config()->get(Config::skin).toString(); auto settingsSkin = config()->get(Config::skin).toString();
if (m_skins.contains(settingsSkin)) if (m_skins.contains(settingsSkin))
ui->comboBox_skin->setCurrentIndex(m_skins.indexOf(settingsSkin)); ui->comboBox_skin->setCurrentIndex(m_skins.indexOf(settingsSkin));
connect(ui->comboBox_homeWidget, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_homeWidgetChanged);
connect(ui->comboBox_skin, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_skinChanged); connect(ui->comboBox_skin, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_skinChanged);
connect(ui->comboBox_blockExplorer, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_blockExplorerChanged); connect(ui->comboBox_blockExplorer, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_blockExplorerChanged);
@@ -83,12 +78,6 @@ void Settings::comboBox_skinChanged(int pos) {
emit skinChanged(m_skins.at(pos)); emit skinChanged(m_skins.at(pos));
} }
void Settings::comboBox_homeWidgetChanged(int pos) {
config()->set(Config::homeWidget, m_homeWidgets.at(pos));
emit homeWidgetChanged(m_homeWidgets.at(pos));
}
void Settings::comboBox_blockExplorerChanged(int pos) { void Settings::comboBox_blockExplorerChanged(int pos) {
QString blockExplorer = ui->comboBox_blockExplorer->currentText(); QString blockExplorer = ui->comboBox_blockExplorer->currentText();
config()->set(Config::blockExplorer, blockExplorer); config()->set(Config::blockExplorer, blockExplorer);
-3
View File
@@ -26,7 +26,6 @@ public:
signals: signals:
void closed(); void closed();
void preferredFiatCurrencyChanged(QString currency); void preferredFiatCurrencyChanged(QString currency);
void homeWidgetChanged(QString widgetName);
void skinChanged(QString skinName); void skinChanged(QString skinName);
void showHomeCCS(bool); void showHomeCCS(bool);
void blockExplorerChanged(QString blockExplorer); void blockExplorerChanged(QString blockExplorer);
@@ -35,12 +34,10 @@ public slots:
void copyToClipboard(); void copyToClipboard();
void checkboxExternalLinkWarn(); void checkboxExternalLinkWarn();
void fiatCurrencySelected(int index); void fiatCurrencySelected(int index);
void comboBox_homeWidgetChanged(int pos);
void comboBox_skinChanged(int pos); void comboBox_skinChanged(int pos);
void comboBox_blockExplorerChanged(int post); void comboBox_blockExplorerChanged(int post);
private: private:
const QStringList m_homeWidgets{"ccs", "reddit"};
QStringList m_skins{"Native", "QDarkStyle", "Breeze/Dark", "Breeze/Light"}; QStringList m_skins{"Native", "QDarkStyle", "Breeze/Dark", "Breeze/Light"};
private: private:
+6 -27
View File
@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1019</width> <width>1019</width>
<height>358</height> <height>336</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -121,44 +121,23 @@
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Home screen widget:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBox_homeWidget">
<item>
<property name="text">
<string>CCS proposals</string>
</property>
</item>
<item>
<property name="text">
<string>/r/monero</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6"> <widget class="QLabel" name="label_6">
<property name="text"> <property name="text">
<string>Appearance:</string> <string>Appearance:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="1" column="1">
<widget class="QComboBox" name="comboBox_skin"/> <widget class="QComboBox" name="comboBox_skin"/>
</item> </item>
<item row="3" column="0"> <item row="2" column="0">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>Block explorer:</string> <string>Block explorer:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="2" column="1">
<widget class="QComboBox" name="comboBox_blockExplorer"> <widget class="QComboBox" name="comboBox_blockExplorer">
<item> <item>
<property name="text"> <property name="text">
@@ -182,14 +161,14 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="3" column="0">
<widget class="QCheckBox" name="checkBox_externalLink"> <widget class="QCheckBox" name="checkBox_externalLink">
<property name="text"> <property name="text">
<string>Warn before opening external link</string> <string>Warn before opening external link</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0"> <item row="4" column="0">
<widget class="QCheckBox" name="checkBox_hideBalance"> <widget class="QCheckBox" name="checkBox_hideBalance">
<property name="text"> <property name="text">
<string>Hide balance</string> <string>Hide balance</string>
+1 -2
View File
@@ -41,8 +41,7 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
{Config::nodeSource,{QS("nodeSource"), 0}}, {Config::nodeSource,{QS("nodeSource"), 0}},
{Config::useOnionNodes,{QS("useOnionNodes"), false}}, {Config::useOnionNodes,{QS("useOnionNodes"), false}},
{Config::showTabCoins,{QS("showTabCoins"), false}}, {Config::showTabCoins,{QS("showTabCoins"), false}},
{Config::showTabMorphToken, {QS("showTabMorphToken"), false}}, {Config::showTabExchange, {QS("showTabExchange"), true}},
{Config::showTabXMRto,{QS("showTabXMRto"), true}},
{Config::showTabXMRig,{QS("showTabXMRig"), false}}, {Config::showTabXMRig,{QS("showTabXMRig"), false}},
{Config::showTabCalc,{QS("showTabCalc"), true}}, {Config::showTabCalc,{QS("showTabCalc"), true}},
{Config::geometry, {QS("geometry"), {}}}, {Config::geometry, {QS("geometry"), {}}},
+1 -2
View File
@@ -39,8 +39,7 @@ public:
nodeSource, nodeSource,
useOnionNodes, useOnionNodes,
showTabCoins, showTabCoins,
showTabMorphToken, showTabExchange,
showTabXMRto,
showTabCalc, showTabCalc,
showTabXMRig, showTabXMRig,
geometry, geometry,
+1 -1
View File
@@ -43,7 +43,7 @@ Tor::Tor(AppContext *ctx, QObject *parent)
return; return;
} }
#ifndef HAS_TOR #ifndef HAS_TOR_BIN
qCritical() << "Feather built without embedded Tor. Assuming --use-local-tor"; qCritical() << "Feather built without embedded Tor. Assuming --use-local-tor";
this->localTor = true; this->localTor = true;
return; return;
+2 -22
View File
@@ -276,7 +276,7 @@ bool Utils::testSocks5(const QString &host, quint16 port){
return false; return false;
} }
void Utils::externalLinkWarning(const QString &url){ void Utils::externalLinkWarning(QWidget *parent, const QString &url){
if(!config()->get(Config::warnOnExternalLink).toBool()) { if(!config()->get(Config::warnOnExternalLink).toBool()) {
QDesktopServices::openUrl(QUrl(url)); QDesktopServices::openUrl(QUrl(url));
return; return;
@@ -286,7 +286,7 @@ void Utils::externalLinkWarning(const QString &url){
body += QString("%1\n\n").arg(url); body += QString("%1\n\n").arg(url);
body += "You will NOT be using Tor."; body += "You will NOT be using Tor.";
switch (Utils::showMessageBox("External link warning", body, true)) { switch (QMessageBox::warning(parent, "External link warning", body, QMessageBox::Cancel|QMessageBox::Ok)) {
case QMessageBox::Cancel: case QMessageBox::Cancel:
break; break;
default: default:
@@ -327,26 +327,6 @@ bool Utils::walletExists(QString name, const QString &path) {
return Utils::fileExists(walletPath); return Utils::fileExists(walletPath);
} }
int Utils::showMessageBox(const QString &windowTitle, const QString &body, bool warning){
QMessageBox msgBox(QApplication::activeWindow());
msgBox.setWindowTitle(windowTitle);
msgBox.setText(body);
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Ok);
if(warning) {
QPixmap iconWarning = QPixmap(":/assets/images/ghost_icon.png");
msgBox.setIconPixmap(iconWarning);
}
else {
QPixmap iconInfo = QPixmap(":/assets/images/info.png")
.scaled(QSize(48,48), Qt::KeepAspectRatio, Qt::SmoothTransformation);
msgBox.setIconPixmap(iconInfo);
}
return msgBox.exec();
}
void Utils::copyToClipboard(const QString &string){ void Utils::copyToClipboard(const QString &string){
QClipboard * clipboard = QApplication::clipboard(); QClipboard * clipboard = QApplication::clipboard();
if (!clipboard) { if (!clipboard) {
+1 -4
View File
@@ -75,8 +75,7 @@ public:
static QStringList readJsonStringToQStringList(const QString &input); static QStringList readJsonStringToQStringList(const QString &input);
static void applicationLogHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg); static void applicationLogHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
static void openWindow(QWidget *w); static void openWindow(QWidget *w);
static void externalLinkWarning(const QString &url); static void externalLinkWarning(QWidget *parent, const QString &url);
static int showMessageBox(const QString &windowTitle, const QString &body, bool warning);
static QList<processStruct> procList(); static QList<processStruct> procList();
static bool dirExists(const QString &path); static bool dirExists(const QString &path);
static QString barrayToString(const QByteArray &data); static QString barrayToString(const QByteArray &data);
@@ -98,8 +97,6 @@ public:
static QString formatBytes(quint64 bytes); static QString formatBytes(quint64 bytes);
static QString amountToCurrencyString(double amount, const QString &currencyCode); static QString amountToCurrencyString(double amount, const QString &currencyCode);
static QStringList randomHTTPAgents;
template<typename QEnum> template<typename QEnum>
static QString QtEnumToString (const QEnum value) static QString QtEnumToString (const QEnum value)
{ {
-35
View File
@@ -9,22 +9,13 @@
#include "utils/utils.h" #include "utils/utils.h"
#include "utils/xmrig.h" #include "utils/xmrig.h"
#include "appcontext.h" #include "appcontext.h"
XmRig::XmRig(const QString &configDir, QObject *parent) : QObject(parent) { XmRig::XmRig(const QString &configDir, QObject *parent) : QObject(parent) {
this->rigDir = QDir(configDir).filePath("xmrig"); this->rigDir = QDir(configDir).filePath("xmrig");
} }
void XmRig::prepare() { void XmRig::prepare() {
// unpack and set process signals
if(!this->unpackBins()) {
qCritical() << "failed to write XMRig to config directory";
return;
}
m_process.setProcessChannelMode(QProcess::MergedChannels); m_process.setProcessChannelMode(QProcess::MergedChannels);
connect(&m_process, &QProcess::readyReadStandardOutput, this, &XmRig::handleProcessOutput); connect(&m_process, &QProcess::readyReadStandardOutput, this, &XmRig::handleProcessOutput);
connect(&m_process, &QProcess::errorOccurred, this, &XmRig::handleProcessError); connect(&m_process, &QProcess::errorOccurred, this, &XmRig::handleProcessError);
@@ -110,29 +101,3 @@ void XmRig::handleProcessError(QProcess::ProcessError err) {
emit error(QString("XMRig binary failed to start: %1").arg(path)); emit error(QString("XMRig binary failed to start: %1").arg(path));
} }
} }
bool XmRig::unpackBins() {
QString rigFile;
rigFile = ":/assets/exec/xmrig";
if (!Utils::fileExists(rigFile))
return false;
// write to disk
QFile f(rigFile);
QFileInfo fileInfo(f);
this->rigPath = QDir(this->rigDir).filePath(fileInfo.fileName());
#if defined(Q_OS_WIN)
if(!this->rigPath.endsWith(".exe"))
this->rigPath += ".exe";
#endif
qDebug() << "Writing XMRig executable to " << this->rigPath;
f.copy(rigPath);
f.close();
#if defined(Q_OS_UNIX)
QFile rigBin(this->rigPath);
rigBin.setPermissions(QFile::ExeGroup | QFile::ExeOther | QFile::ExeOther | QFile::ExeUser);
#endif
return true;
}
+1 -1
View File
@@ -42,7 +42,7 @@ void CCSWidget::linkClicked() {
auto entry = m_model->entry(index.row()); auto entry = m_model->entry(index.row());
if (entry) if (entry)
Utils::externalLinkWarning(entry->url); Utils::externalLinkWarning(this, entry->url);
} }
void CCSWidget::donateClicked() { void CCSWidget::donateClicked() {
-33
View File
@@ -48,39 +48,6 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="warnLabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Powered by ccs.getmonero.org</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</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>
</item>
</layout> </layout>
</widget> </widget>
<resources/> <resources/>
+2 -2
View File
@@ -113,14 +113,14 @@ void NodeWidget::onContextWSStatusURL() {
QModelIndex index = ui->wsView->currentIndex(); QModelIndex index = ui->wsView->currentIndex();
if (!index.isValid()) return; if (!index.isValid()) return;
FeatherNode node = m_wsModel->node(index.row()); FeatherNode node = m_wsModel->node(index.row());
Utils::externalLinkWarning(node.as_url()); Utils::externalLinkWarning(this, node.as_url());
} }
void NodeWidget::onContextCustomStatusURL() { void NodeWidget::onContextCustomStatusURL() {
QModelIndex index = ui->customView->currentIndex(); QModelIndex index = ui->customView->currentIndex();
if (!index.isValid()) return; if (!index.isValid()) return;
FeatherNode node = m_customModel->node(index.row()); FeatherNode node = m_customModel->node(index.row());
Utils::externalLinkWarning(node.as_url()); Utils::externalLinkWarning(this, node.as_url());
} }
void NodeWidget::onContextDisconnect() { void NodeWidget::onContextDisconnect() {
+1 -1
View File
@@ -37,7 +37,7 @@ void RedditWidget::linkClicked() {
auto post = m_model->post(index.row()); auto post = m_model->post(index.row());
if (post) { if (post) {
Utils::externalLinkWarning(post->url); Utils::externalLinkWarning(this, post->url);
} }
} }
-30
View File
@@ -51,36 +51,6 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Powered by Reddit</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</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>
</item>
</layout> </layout>
</widget> </widget>
<resources/> <resources/>
+6 -7
View File
@@ -8,11 +8,12 @@
#include "utils/config.h" #include "utils/config.h"
#include "mainwindow.h" #include "mainwindow.h"
TickerWidget::TickerWidget(QWidget *parent, QString symbol, QString title, bool convertBalance) : TickerWidget::TickerWidget(QWidget *parent, QString symbol, QString title, bool convertBalance, bool hidePercent) :
QWidget(parent), QWidget(parent),
ui(new Ui::TickerWidget), ui(new Ui::TickerWidget),
m_symbol(std::move(symbol)), m_symbol(std::move(symbol)),
m_convertBalance(convertBalance) m_convertBalance(convertBalance),
m_hidePercent(hidePercent)
{ {
ui->setupUi(this); ui->setupUi(this);
m_ctx = MainWindow::getContext(); m_ctx = MainWindow::getContext();
@@ -27,6 +28,8 @@ TickerWidget::TickerWidget(QWidget *parent, QString symbol, QString title, bool
this->setPctText(defaultPct, true); this->setPctText(defaultPct, true);
this->setFiatText(defaultFiat, 0.0); this->setFiatText(defaultFiat, 0.0);
ui->tickerPct->setHidden(hidePercent);
connect(AppContext::prices, &Prices::fiatPricesUpdated, this, &TickerWidget::init); connect(AppContext::prices, &Prices::fiatPricesUpdated, this, &TickerWidget::init);
connect(AppContext::prices, &Prices::cryptoPricesUpdated, this, &TickerWidget::init); connect(AppContext::prices, &Prices::cryptoPricesUpdated, this, &TickerWidget::init);
if (convertBalance) if (convertBalance)
@@ -47,7 +50,7 @@ void TickerWidget::init() {
double amount = m_convertBalance ? AppContext::balance : 1.0; double amount = m_convertBalance ? AppContext::balance : 1.0;
double conversion = AppContext::prices->convert(m_symbol, fiatCurrency, amount); double conversion = AppContext::prices->convert(m_symbol, fiatCurrency, amount);
if (conversion < 0) return; if (conversion < 0) return;
setPercentHidden(conversion == 0); ui->tickerPct->setHidden(conversion == 0 || m_hidePercent);
auto markets = AppContext::prices->markets; auto markets = AppContext::prices->markets;
if(!markets.contains(m_symbol)) return; if(!markets.contains(m_symbol)) return;
@@ -85,10 +88,6 @@ void TickerWidget::removePctContainer() {
ui->tickerPct->deleteLater(); ui->tickerPct->deleteLater();
} }
void TickerWidget::setPercentHidden(bool hidden) {
ui->tickerPct->setVisible(!hidden);
}
TickerWidget::~TickerWidget() { TickerWidget::~TickerWidget() {
delete ui; delete ui;
} }
+2 -3
View File
@@ -17,7 +17,7 @@ class TickerWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit TickerWidget(QWidget *parent, QString symbol, QString title = "", bool convertBalance = false); explicit TickerWidget(QWidget *parent, QString symbol, QString title = "", bool convertBalance = false, bool hidePercent = false);
void removePctContainer(); void removePctContainer();
void setFiatText(QString &fiatCurrency, double amount); void setFiatText(QString &fiatCurrency, double amount);
void setPctText(QString &text, bool positive); void setPctText(QString &text, bool positive);
@@ -29,11 +29,10 @@ public slots:
void init(); void init();
private: private:
void setPercentHidden(bool hidden);
Ui::TickerWidget *ui; Ui::TickerWidget *ui;
QString m_symbol; QString m_symbol;
bool m_convertBalance; bool m_convertBalance;
bool m_hidePercent;
AppContext *m_ctx; AppContext *m_ctx;
}; };
+6 -25
View File
@@ -36,7 +36,7 @@ XMRigWidget::XMRigWidget(AppContext *ctx, QWidget *parent) :
// threads // threads
ui->threadSlider->setMinimum(1); ui->threadSlider->setMinimum(1);
int threads = QThread::idealThreadCount(); int threads = QThread::idealThreadCount();
m_threads = (unsigned int) threads / 2; m_threads = threads / 2;
ui->threadSlider->setMaximum(threads); ui->threadSlider->setMaximum(threads);
ui->threadSlider->setValue(m_threads); ui->threadSlider->setValue(m_threads);
ui->label_threads->setText(QString("CPU threads: %1").arg(m_threads)); ui->label_threads->setText(QString("CPU threads: %1").arg(m_threads));
@@ -55,15 +55,12 @@ XMRigWidget::XMRigWidget(AppContext *ctx, QWidget *parent) :
ui->check_tls->setChecked(true); ui->check_tls->setChecked(true);
ui->label_status->setTextInteractionFlags(Qt::TextSelectableByMouse); ui->label_status->setTextInteractionFlags(Qt::TextSelectableByMouse);
ui->label_status->hide(); ui->label_status->hide();
ui->pathFrame->hide();
ui->soloFrame->hide(); ui->soloFrame->hide();
ui->poolFrame->hide(); ui->poolFrame->hide();
// XMRig binary // XMRig binary
auto path = config()->get(Config::xmrigPath).toString(); auto path = config()->get(Config::xmrigPath).toString();
if(!path.isEmpty()) { if(!path.isEmpty()) {
ui->pathFrame->show();
ui->check_custompath->setChecked(true);
ui->lineEdit_path->setText(path); ui->lineEdit_path->setText(path);
} }
@@ -99,7 +96,6 @@ XMRigWidget::XMRigWidget(AppContext *ctx, QWidget *parent) :
}); });
// checkbox connects // checkbox connects
connect(ui->check_custompath, &QCheckBox::stateChanged, this, &XMRigWidget::onCustomPathChecked);
connect(ui->check_solo, &QCheckBox::stateChanged, this, &XMRigWidget::onSoloChecked); connect(ui->check_solo, &QCheckBox::stateChanged, this, &XMRigWidget::onSoloChecked);
} }
@@ -127,7 +123,7 @@ void XMRigWidget::onWalletOpened(){
} }
void XMRigWidget::onThreadsValueChanged(int threads) { void XMRigWidget::onThreadsValueChanged(int threads) {
m_threads = (unsigned int) threads; m_threads = threads;
ui->label_threads->setText(QString("CPU threads: %1").arg(m_threads)); ui->label_threads->setText(QString("CPU threads: %1").arg(m_threads));
} }
@@ -150,12 +146,7 @@ void XMRigWidget::onClearClicked() {
void XMRigWidget::onStartClicked() { void XMRigWidget::onStartClicked() {
QString xmrigPath; QString xmrigPath;
bool solo = ui->check_solo->isChecked(); bool solo = ui->check_solo->isChecked();
bool customBinary = ui->check_custompath->isChecked(); xmrigPath = config()->get(Config::xmrigPath).toString();
if(customBinary)
xmrigPath = config()->get(Config::xmrigPath).toString();
else
xmrigPath = m_ctx->XMRig->rigPath;
// username is receiving address usually // username is receiving address usually
auto username = m_ctx->currentWallet->getCacheAttribute("feather.xmrig_username"); auto username = m_ctx->currentWallet->getCacheAttribute("feather.xmrig_username");
@@ -164,7 +155,7 @@ void XMRigWidget::onStartClicked() {
if(username.isEmpty()) { if(username.isEmpty()) {
QString err = "Please specify a receiving address on the Settings screen"; QString err = "Please specify a receiving address on the Settings screen";
ui->console->appendPlainText(err); ui->console->appendPlainText(err);
Utils::showMessageBox("Error", err, true); QMessageBox::warning(this, "Error", err);
return; return;
} }
@@ -245,7 +236,7 @@ void XMRigWidget::onDownloads(const QJsonObject &data) {
os_assets = const_cast<QJsonArray *>(&_linux); os_assets = const_cast<QJsonArray *>(&_linux);
} }
unsigned int i = 0; int i = 0;
for(const auto &entry: *os_assets) { for(const auto &entry: *os_assets) {
auto _obj = entry.toObject(); auto _obj = entry.toObject();
auto _name = _obj.value("name").toString(); auto _name = _obj.value("name").toString();
@@ -280,16 +271,6 @@ void XMRigWidget::showContextMenu(const QPoint &pos) {
m_contextMenu->exec(ui->tableView->viewport()->mapToGlobal(pos)); m_contextMenu->exec(ui->tableView->viewport()->mapToGlobal(pos));
} }
void XMRigWidget::onCustomPathChecked(int state) {
if(state == 2) {
ui->pathFrame->show();
} else {
ui->lineEdit_path->setText("");
config()->set(Config::xmrigPath, "");
ui->pathFrame->hide();
}
}
void XMRigWidget::onSoloChecked(int state) { void XMRigWidget::onSoloChecked(int state) {
if(state == 2) { if(state == 2) {
ui->poolFrame->hide(); ui->poolFrame->hide();
@@ -305,7 +286,7 @@ void XMRigWidget::onSoloChecked(int state) {
void XMRigWidget::linkClicked() { void XMRigWidget::linkClicked() {
QModelIndex index = ui->tableView->currentIndex(); QModelIndex index = ui->tableView->currentIndex();
auto download_link = m_urls.at(index.row()); auto download_link = m_urls.at(index.row());
Utils::externalLinkWarning(download_link); Utils::externalLinkWarning(this, download_link);
} }
QStandardItemModel *XMRigWidget::model() { QStandardItemModel *XMRigWidget::model() {
+2 -3
View File
@@ -22,7 +22,7 @@ class XMRigWidget : public QWidget
public: public:
explicit XMRigWidget(AppContext *ctx, QWidget *parent = nullptr); explicit XMRigWidget(AppContext *ctx, QWidget *parent = nullptr);
~XMRigWidget(); ~XMRigWidget() override;
QStandardItemModel *model(); QStandardItemModel *model();
public slots: public slots:
@@ -36,7 +36,6 @@ public slots:
void onProcessError(const QString &msg); void onProcessError(const QString &msg);
void onProcessOutput(const QByteArray &msg); void onProcessOutput(const QByteArray &msg);
void onHashrate(const QString &hashrate); void onHashrate(const QString &hashrate);
void onCustomPathChecked(int state);
void onSoloChecked(int state); void onSoloChecked(int state);
private slots: private slots:
@@ -55,7 +54,7 @@ private:
Ui::XMRigWidget *ui; Ui::XMRigWidget *ui;
QStandardItemModel *m_model; QStandardItemModel *m_model;
QMenu *m_contextMenu; QMenu *m_contextMenu;
unsigned int m_threads; int m_threads;
QStringList m_urls; QStringList m_urls;
QStringList m_pools{"pool.xmr.pt:9000", "pool.supportxmr.com:9000", "mine.xmrpool.net:443", "xmrpool.eu:9999", "xmr-eu1.nanopool.org:14433", "pool.minexmr.com:6666", "us-west.minexmr.com:6666", "monerohash.com:9999", "cryptonote.social:5555", "cryptonote.social:5556"}; QStringList m_pools{"pool.xmr.pt:9000", "pool.supportxmr.com:9000", "mine.xmrpool.net:443", "xmrpool.eu:9999", "xmr-eu1.nanopool.org:14433", "pool.minexmr.com:6666", "us-west.minexmr.com:6666", "monerohash.com:9999", "cryptonote.social:5555", "cryptonote.social:5556"};
}; };
+89 -156
View File
@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>800</width> <width>1329</width>
<height>556</height> <height>540</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -161,38 +161,7 @@
</property> </property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>40</width> <width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QCheckBox" name="check_solo">
<property name="text">
<string>Solo mine</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="check_custompath">
<property name="text">
<string>Custom XMRig executable</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height> <height>20</height>
</size> </size>
</property> </property>
@@ -221,27 +190,47 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLineEdit" name="lineEdit_path">
<property name="placeholderText">
<string>/path/to/xmrig</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_browse">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="check_tls">
<property name="text">
<string>TLS</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="relayTor">
<property name="text">
<string>Tor</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="check_solo">
<property name="text">
<string>Solo mine</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>
</layout>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_12"> <layout class="QHBoxLayout" name="horizontalLayout_12">
<item> <item>
@@ -267,15 +256,15 @@
</property> </property>
<item row="0" column="0"> <item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_4"> <layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Pool</string>
</property>
</widget>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_4"> <layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Pool</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QComboBox" name="combo_pools"> <widget class="QComboBox" name="combo_pools">
<property name="sizePolicy"> <property name="sizePolicy">
@@ -329,15 +318,15 @@
</property> </property>
<item row="0" column="0"> <item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_8"> <layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Node address</string>
</property>
</widget>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_8"> <layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Node address</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QLineEdit" name="lineEdit_solo"> <widget class="QLineEdit" name="lineEdit_solo">
<property name="text"> <property name="text">
@@ -368,80 +357,54 @@
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QLabel" name="label_2"> <layout class="QFormLayout" name="formLayout">
<property name="text"> <item row="0" column="0">
<string>Receiving address</string> <widget class="QLabel" name="label_2">
</property> <property name="text">
</widget> <string>Receiving address</string>
</item> </property>
<item> </widget>
<widget class="QLineEdit" name="lineEdit_address"/> </item>
</item> <item row="0" column="1">
<item> <widget class="QLineEdit" name="lineEdit_address"/>
<layout class="QVBoxLayout" name="verticalLayout_7"> </item>
<item> <item row="1" column="0">
<widget class="QLabel" name="label_5"> <widget class="QLabel" name="label_5">
<property name="text"> <property name="text">
<string>Password (optional)</string> <string>Password (optional)</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_10"> <widget class="QLineEdit" name="lineEdit_password"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>XMRig executable</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item> <item>
<widget class="QLineEdit" name="lineEdit_password"/> <widget class="QLineEdit" name="lineEdit_path">
<property name="placeholderText">
<string>/path/to/xmrig</string>
</property>
</widget>
</item> </item>
<item> <item>
<spacer name="horizontalSpacer_6"> <widget class="QPushButton" name="btn_browse">
<property name="orientation"> <property name="text">
<enum>Qt::Horizontal</enum> <string>Browse</string>
</property> </property>
<property name="sizeType"> </widget>
<enum>QSizePolicy::Maximum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>60</width>
<height>20</height>
</size>
</property>
</spacer>
</item> </item>
</layout> </layout>
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_13">
<item>
<widget class="QCheckBox" name="check_tls">
<property name="text">
<string>TLS</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="relayTor">
<property name="text">
<string>Tor</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_9">
<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>
</item>
</layout> </layout>
</item> </item>
<item> <item>
@@ -494,7 +457,7 @@
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>20</width>
<height>2000</height> <height>0</height>
</size> </size>
</property> </property>
</spacer> </spacer>
@@ -552,36 +515,6 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Powered by Github API v3</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</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>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
+1 -1
View File
@@ -74,7 +74,7 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>by dsc &amp; thotbot</string> <string>by dsc &amp; tobtoht</string>
</property> </property>
</widget> </widget>
</item> </item>
+3 -2
View File
@@ -8,6 +8,7 @@
#include <QPushButton> #include <QPushButton>
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox>
// @TODO: rescan wallet dir on wizard open // @TODO: rescan wallet dir on wizard open
@@ -27,7 +28,7 @@ OpenWalletPage::OpenWalletPage(AppContext *ctx, QWidget *parent) :
QFileInfo infoPath(path); QFileInfo infoPath(path);
if(!infoPath.isReadable()) { if(!infoPath.isReadable()) {
Utils::showMessageBox("Cannot read wallet file", "Permission error.", true); QMessageBox::warning(this, "Cannot read wallet file", "Permission error.");
return; return;
} }
@@ -67,7 +68,7 @@ int OpenWalletPage::nextId() const {
bool OpenWalletPage::validatePage() { bool OpenWalletPage::validatePage() {
QModelIndex index = ui->walletTable->currentIndex(); QModelIndex index = ui->walletTable->currentIndex();
if(!index.isValid()) { if(!index.isValid()) {
Utils::showMessageBox("Wallet not selected", "Please select a wallet from the list.", true); QMessageBox::warning(this, "Wallet not selected", "Please select a wallet from the list.");
return false; return false;
} }
QString walletPath = index.model()->data(index.siblingAtColumn(WalletKeysFilesModel::ModelColumns::Path), Qt::UserRole).toString(); QString walletPath = index.model()->data(index.siblingAtColumn(WalletKeysFilesModel::ModelColumns::Path), Qt::UserRole).toString();
+2 -2
View File
@@ -86,7 +86,7 @@ void XMRToWidget::onCreateOrder() {
auto amount = ui->lineAmount->text(); auto amount = ui->lineAmount->text();
if(amount.isEmpty()) { if(amount.isEmpty()) {
Utils::showMessageBox("Cannot create XMR.To order", "Invalid amount", false); QMessageBox::warning(this, "Cannot create XMR.To order", "Invalid amount");
return; return;
} }
@@ -99,7 +99,7 @@ void XMRToWidget::onCreateOrder() {
auto available = m_unlockedBalance; auto available = m_unlockedBalance;
if(amount_xmr > available){ if(amount_xmr > available){
Utils::showMessageBox("Cannot create XMR.To order", "Not enough Monero to create order.", false); QMessageBox::warning(this, "Cannot create XMR.To order", "Not enough Monero to create order.");
return; return;
} }
+1 -1
View File
@@ -14,7 +14,7 @@ git submodule update --init --depth 120 monero
git submodule update --init --depth 120 --recursive monero git submodule update --init --depth 120 --recursive monero
cp "/Users/administrator/tor/libevent-2.1.7.dylib" "/Users/administrator/feather/src/assets/exec/libevent-2.1.7.dylib" cp "/Users/administrator/tor/libevent-2.1.7.dylib" "/Users/administrator/feather/src/assets/exec/libevent-2.1.7.dylib"
CMAKE_PREFIX_PATH="~/Qt/5.15.1/clang_64" TOR="/Users/administrator/tor/tor" XMRIG="/Users/administrator/xmrig/xmrig" make -j3 mac-release CMAKE_PREFIX_PATH="~/Qt/5.15.1/clang_64" TOR_BIN="/Users/administrator/tor/tor" make -j3 mac-release
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
echo "[+] Feather built OK" echo "[+] Feather built OK"
+52
View File
@@ -0,0 +1,52 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBF/HogkBEAChsjCJUsZhDxOx5FrnRA3X5/mJd2xdKskLSPFtnYiQUtKvpRW6
i/RVNMkTwFovzbXB6ucKJtY+OoEMu7xDhIkDWp//UlfHuP9AWAvqbhq6V5xVrZ41
9oQ7JNN4gwAI8+ZjcNq3IVFQQ9mZ3py9t1IUdgWtWM3P/SD7vWiPIjG0D3Bt3Ptl
/mZjIFZZWUtFBItJLkiTpW0Ue4t98XMP6mvQiQ/LhP82OtSyCZ6agj4Wa3ve5KjA
pdEqamBGytx2kmN+AQFgMt66yOvr+97zzuEzI6mlWYORzOc1CFMsmPd6bu/dtQ4Z
96T8PNI6i1Lv5VqvqC7RBErvD7hO36JZb8j+PnbE1YADTKrw0HmgpI6d3RLyVop3
n6ZQri0+nZ+TH0JG74MiihyZIz826zJO5OIwltexRcW0ZiRSpRCxZekU894lEs5Q
SxacRLeqM8ZVawB+9brqbeU3IJxmOCZgXLkkns0dBiSWGxtt+Tji+KXjogNfghmA
dVw9NQoBS+W5+pBtKEORD0YIGiUou9a7ukyMe2uvsl7rT+7BCOdvYtMBRbsfV5NP
s644wfJNIGa7OOjkWhuGwy6BVKTohDhJdKeZUpiTPKLV7ZLHjT4pkjuJgGQB7c+w
v7QYeUpwARwQNi8ZHuij2loG3Fb4l+3ejkcvivw0DLnDDhvUY57ezq53JwARAQAB
tCVGZWF0aGVyV2FsbGV0IDxkZXZAZmVhdGhlcndhbGxldC5vcmc+iQJOBBMBCgA4
FiEEgYXhWKMzMMf9YbwNH3bhVc77pxwFAl/HogkCGwMFCwkIBwMFFQoJCAsFFgID
AQACHgECF4AACgkQH3bhVc77pxzAxw/9GYXGm71lUlZl2yfBPmo91euSc3w/irEC
88X1kFBsdKwL19B8HUaksCOQJRG8fJQmKvJmFnRZg3NK/GLIHam+1WVObFZc1MTv
y2ERzX5ILr9sb7FptB0Wr9gk0y0Nv032ZKci3wn1j2nA87o40uopDoQTaadDTKXa
s3M2+y6zM4dCmCaV6ylJromTzIaL2Q+tWSHDD8EDF2GbnfSeeEV6TV4xj3vqfT5P
34rK4vuVNxEy/YvRQJVRYntveNMJu9C4KJvIpo8onauUHEgBu4m+qfFpixDLwQzq
bJiJQaCUrwJ3liKMolBKiPqjGNl5JRRDy+YR1Dgsj6CRobWg1fDNnrGXUwDLaBwx
zVdCB0VSmcjXpt+FKTxw1mbY+6i6trUfJSjaaawXJbktOkO6sl0bVX83oQxEgod1
aHwuo+eFCAW5zF0r+8R9Lk97Y5jkLWRKjXMFnMIyHaRhPdc24fOfojIQrXzQBMEO
lDhbWVd5vdOALhqvSOGYvjGjxBd9TE0pGzayNfPaee6kFEbxO3wZgF/QLPABl8i9
b6hHJewpY5W9mM9/yP4lHL2TRcEMzk6I7XxPQUGEb3fzTAEHRM+My4SLwaUBIFvM
L8+hRhbfNnLZPd0xDAmvH6wToL3qgK/xSl9SYwuZkzaynblmyXE4+dCFp+T2XTam
FIbphOl8Yt+5Ag0EX8eiCQEQAKv0XnHtGhWTaq/sQ4lulYWNRjBsFQRMqwSFIosO
PfzWwATQeHxxIgRlWkc25w8W0O//t8x0UcNA5rU4R+C7kVrchVSYYYl9PY0vBhKP
3efVtPgntl/VgGH8LAdShHEt3H8ZDMFjqT6gx4xnpgt3C5OdGOA3bIWuvSZ1P7qp
SYiFZakrDfPeCdI/ifucipd+EnZhFv7ivnaoIGs+jgaImQH/5uEEVxpA89Bpxoju
gXlEKSVkVAanZsUwQkc/xzhsh8dzuEF5yKomVbwTYmXDTYmpff02ycdUP7gHw0Qg
WrWaQ2M0Xq1qcZL3ZpoaWUa/A92OfuncCSDNq1pRLqwJrExqQUP9cHGwGbqeGl8K
n2tFds8Pnnv+57ZKiO8E1VTDyBey1J3/Y1hOzctfEz6BzrL52Vj4vPWh2WNNh5fL
u1ZEIdykflH/Kho0zQkRfBfD93FbN/nH1xL3V7pO/wXVGqHSD3HbFLIcJ9Ax+Jgc
Z9fm9Bvc2RkXC8lJU5+htQ+YwHPLDExvUKrBL8b8xksODCvJSWLKcTPooFQyKgbK
EnPW5kmn3eT0SHHHOArn6EHoQttkR0pV2Lrgpfg+uhy3LSTmKbtRWo7VgDY0kfVL
hsatIUqYAVdDTBzsuMhehaoWwtLAsJ01OqxAoc6+0velLddLBuLxtzGtsF0u2mEF
QJmBABEBAAGJAjYEGAEKACAWIQSBheFYozMwx/1hvA0fduFVzvunHAUCX8eiCQIb
DAAKCRAfduFVzvunHDx1D/45GVAtIP1X640PR6N8qa4Iysc/crKepgDqm8zzvpQ8
58MdeJZ9oPFEHDMkIMM8FGK9GbK4UE5mJzWJ2y5acMDOwvX4C9M206YaWQW9jPZt
fTfElP1KdAfTWz2/1UeOZKtOUuq9Wq+QlZGYg532JlX09TMyvINRM/w0+f4IBDlE
XIeRzRI6UQfz3BxpFpfWtMq/ayJnmJPrDsKQBPalai01OsbC+h4BUysZf1n7eTRF
DVaAKkSeOu+4gOVguE9PgKr11lDlKOI38tR6xBXzidBe3cPdun6vQbd1Bdfdmx3J
yFtlQo16kwwG2ZiVicXXugASBsrOFJa2/0lrtAPOnUWJsp2+1Ea6IzpRN8d1mNqr
6ND+CLxBsWj16UXq34GW6vt/QM7N1Br4/6SuPtv8OmDGRkRH7h2pz5yMf5GOwQFq
kgvOHt/x/sFPwk0GMgGn8aFr3vPH2YDg90mPn306Kv12e0JGkYVl4KqdL7u51gxT
3z5C/4+hhPVGHSPkf+g0VY/eY136kuuAZjV3P36M6UaBeCyqeD7b3fJ5IJcLwD9N
R0ustnn8IJ9zEwn+LY8kjRG8J3V57t2qAVGkMCiXnwFu3Vb+AYozOYi2ibu/N9QX
V4dTHarw64HUtLu/HEtcYuzuM5nGOXYvWPz3pQBtlqsyrhIfeaywQ+O55h5/KBo8
Ig==
=2rq8
-----END PGP PUBLIC KEY BLOCK-----