Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e5cac9fa3 | ||
|
|
b61b2b1630 | ||
|
|
1b1d1db14d | ||
|
|
81ec0183ea | ||
|
|
f5046cea54 | ||
|
|
624f13b2d9 | ||
|
|
0d502f0e45 | ||
|
|
6549ca4e1d | ||
|
|
37578dde7b | ||
|
|
225ae1233e | ||
|
|
d8cb29c4d4 | ||
|
|
502785f233 | ||
|
|
e3cf87906b | ||
|
|
5c3821007d | ||
|
|
c02e084dcf | ||
|
|
85d4e0ac6d | ||
|
|
fbca9c9340 | ||
|
|
d9d0ac1830 | ||
|
|
3adb2a6fe7 | ||
|
|
742ad82b88 | ||
|
|
a1ce8f866a | ||
|
|
24e8942ac5 | ||
|
|
3163d68e9e | ||
|
|
a6e1a6877f | ||
|
|
ac1ed1873a | ||
|
|
2ccefe0883 | ||
|
|
06f09e1f2e | ||
|
|
c3e9fbb25a | ||
|
|
096b28318c | ||
|
|
562d071c62 | ||
|
|
474d4b1994 | ||
|
|
49b55768f7 | ||
|
|
640a4d72e0 | ||
|
|
0e37f97aa2 | ||
|
|
499ad4a3aa | ||
|
|
8b5bdc4c6a | ||
|
|
cfee938516 | ||
|
|
c024323eab | ||
|
|
a2ad4692a3 |
@@ -4,18 +4,20 @@ project(wowlet)
|
||||
message(STATUS "Initiating compile using CMake ${CMAKE_VERSION}")
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
set(VERSION_MAJOR "0")
|
||||
set(VERSION_MINOR "2")
|
||||
set(VERSION_MAJOR "2")
|
||||
set(VERSION_MINOR "0")
|
||||
set(VERSION_REVISION "0")
|
||||
set(VERSION "beta-2")
|
||||
|
||||
option(FETCH_DEPS "Download dependencies if they are not found" ON)
|
||||
option(XMRIG "Include XMRig module" ON)
|
||||
option(OPENVR "Include OpenVR support" OFF)
|
||||
option(QML "Include QtQuick (QML)" OFF)
|
||||
option(TOR_BIN "Path to Tor binary to embed inside WOWlet" OFF)
|
||||
option(OPENVR "Include OpenVR support")
|
||||
option(QML "Include QtQuick (QML)")
|
||||
option(ANDROID "Android deployment")
|
||||
option(ANDROID_DEBUG "View the Android app on desktop")
|
||||
option(TOR_BIN "Path to Tor binary to embed inside WOWlet")
|
||||
option(STATIC "Link libraries statically, requires static Qt")
|
||||
option(USE_DEVICE_TREZOR "Trezor support compilation" OFF)
|
||||
option(USE_DEVICE_TREZOR "Trezor support compilation")
|
||||
option(DONATE_BEG "Prompt donation window every once in a while" ON)
|
||||
list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake")
|
||||
include(CheckCCompilerFlag)
|
||||
@@ -28,11 +30,10 @@ include(CheckSymbolExists)
|
||||
|
||||
set(WOWNERO_HEAD "f611d5c9e32bc62f1735f6571b0bdb95cc020531")
|
||||
set(BUILD_GUI_DEPS ON)
|
||||
set(ARCH "x86-64")
|
||||
set(BUILD_64 ON)
|
||||
set(BUILD_64 ON CACHE BOOL "Build 64-bit binaries")
|
||||
set(INSTALL_VENDORED_LIBUNBOUND ${STATIC})
|
||||
set(USE_SINGLE_BUILDDIR ON)
|
||||
if(OPENVR)
|
||||
if(OPENVR OR ANDROID_DEBUG)
|
||||
set(QML ON)
|
||||
endif()
|
||||
|
||||
@@ -41,10 +42,7 @@ set(_CMAKE_BUILD_TYPE "")
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" _CMAKE_BUILD_TYPE)
|
||||
if("${_CMAKE_BUILD_TYPE}" STREQUAL "DEBUG")
|
||||
set(DEBUG ON)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
message(STATUS "OPENVR: ${OPENVR}")
|
||||
message(STATUS "QML: ${QML}")
|
||||
endif()
|
||||
|
||||
check_include_file(sys/prctl.h HAVE_SYS_PRCTL_H)
|
||||
@@ -173,7 +171,7 @@ find_package(Boost 1.58 REQUIRED COMPONENTS
|
||||
program_options
|
||||
locale)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
# https://github.com/monero-project/monero-gui/issues/3142#issuecomment-705940446
|
||||
set(CMAKE_SKIP_RPATH ON)
|
||||
@@ -195,6 +193,17 @@ if("$ENV{DRONE}" STREQUAL "true")
|
||||
message(STATUS "We are inside a static compile with Drone CI")
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
if(NOT CMAKE_PREFIX_PATH AND DEFINED ENV{CMAKE_PREFIX_PATH})
|
||||
message(STATUS "Using CMAKE_PREFIX_PATH environment variable: '$ENV{CMAKE_PREFIX_PATH}'")
|
||||
set(CMAKE_PREFIX_PATH $ENV{CMAKE_PREFIX_PATH})
|
||||
endif()
|
||||
if(APPLE AND NOT CMAKE_PREFIX_PATH)
|
||||
execute_process(COMMAND brew --prefix qt5 OUTPUT_VARIABLE QT5_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
list(APPEND CMAKE_PREFIX_PATH ${QT5_DIR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# To build WOWlet with embedded (and static) Tor, pass CMake -DTOR_BIN=/path/to/tor
|
||||
if(TOR_BIN)
|
||||
if(APPLE)
|
||||
@@ -249,7 +258,7 @@ if(MINGW)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wa,-mbig-obj")
|
||||
set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi;crypt32;bcrypt)
|
||||
if(DEPENDS)
|
||||
set(ICU_LIBRARIES iconv)
|
||||
set(ICU_LIBRARIES iconv)
|
||||
else()
|
||||
set(ICU_LIBRARIES icuio icuin icuuc icudt icutu iconv)
|
||||
endif()
|
||||
@@ -264,7 +273,7 @@ elseif(DRAGONFLY)
|
||||
set(EXTRA_LIBRARIES execinfo ${COMPAT})
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "(SunOS|Solaris)")
|
||||
set(EXTRA_LIBRARIES socket nsl resolv)
|
||||
elseif(NOT MSVC AND NOT DEPENDS)
|
||||
elseif(NOT MSVC AND NOT DEPENDS AND NOT ANDROID)
|
||||
find_library(RT rt)
|
||||
set(EXTRA_LIBRARIES ${RT})
|
||||
endif()
|
||||
@@ -384,10 +393,6 @@ if(OPENVR)
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/contrib/openvr")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/contrib/KDMacTouchBar")
|
||||
endif()
|
||||
|
||||
if(WITH_SCANNER)
|
||||
add_library(quirc STATIC
|
||||
contrib/quirc/lib/decode.c
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
FROM debian:stretch
|
||||
|
||||
ARG THREADS=1
|
||||
ARG ANDROID_NDK_REVISION=21d
|
||||
ARG ANDROID_NDK_HASH=bcf4023eb8cb6976a4c7cff0a8a8f145f162bf4d
|
||||
ARG ANDROID_SDK_REVISION=4333796
|
||||
ARG ANDROID_SDK_HASH=92ffee5a1d98d856634e8b71132e8a95d96c83a63fde1099be3d86df3106def9
|
||||
ARG QT_VERSION=5.15.2
|
||||
|
||||
WORKDIR /opt/android
|
||||
ENV WORKDIR=/opt/android
|
||||
|
||||
ENV ANDROID_NATIVE_API_LEVEL=28
|
||||
ENV ANDROID_API=android-${ANDROID_NATIVE_API_LEVEL}
|
||||
ENV ANDROID_CLANG=aarch64-linux-android${ANDROID_NATIVE_API_LEVEL}-clang
|
||||
ENV ANDROID_CLANGPP=aarch64-linux-android${ANDROID_NATIVE_API_LEVEL}-clang++
|
||||
ENV ANDROID_NDK_ROOT=${WORKDIR}/android-ndk-r${ANDROID_NDK_REVISION}
|
||||
ENV ANDROID_SDK_ROOT=${WORKDIR}/tools
|
||||
ENV JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
|
||||
ENV PATH=${JAVA_HOME}/bin:${PATH}
|
||||
ENV PREFIX=${WORKDIR}/prefix
|
||||
ENV TOOLCHAIN_DIR=${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y ant automake build-essential ca-certificates-java file gettext git libc6 libncurses5 \
|
||||
libssl-dev libstdc++6 libtinfo5 libtool libz1 openjdk-8-jdk-headless openjdk-8-jre-headless pkg-config python3 \
|
||||
unzip wget
|
||||
|
||||
RUN wget -q https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_REVISION}.zip \
|
||||
&& unzip -q sdk-tools-linux-${ANDROID_SDK_REVISION}.zip \
|
||||
&& rm -f sdk-tools-linux-${ANDROID_SDK_REVISION}.zip
|
||||
|
||||
RUN wget -q https://dl.google.com/android/repository/android-ndk-r${ANDROID_NDK_REVISION}-linux-x86_64.zip \
|
||||
&& unzip -q android-ndk-r${ANDROID_NDK_REVISION}-linux-x86_64.zip \
|
||||
&& rm -f android-ndk-r${ANDROID_NDK_REVISION}-linux-x86_64.zip
|
||||
|
||||
RUN cd ${ANDROID_SDK_ROOT} && echo y | ./bin/sdkmanager "platform-tools" "platforms;${ANDROID_API}" "tools" > /dev/null
|
||||
RUN cp -r ${WORKDIR}/platforms ${WORKDIR}/platform-tools ${ANDROID_SDK_ROOT}
|
||||
|
||||
ENV HOST_PATH=${PATH}
|
||||
ENV PATH=${TOOLCHAIN_DIR}/aarch64-linux-android/bin:${TOOLCHAIN_DIR}/bin:${PATH}
|
||||
|
||||
ARG ZLIB_VERSION=1.2.11
|
||||
ARG ZLIB_HASH=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1
|
||||
RUN wget -q https://zlib.net/zlib-${ZLIB_VERSION}.tar.gz \
|
||||
&& tar -xzf zlib-${ZLIB_VERSION}.tar.gz \
|
||||
&& rm zlib-${ZLIB_VERSION}.tar.gz \
|
||||
&& cd zlib-${ZLIB_VERSION} \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --prefix=${PREFIX} --static \
|
||||
&& make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
RUN git clone git://code.qt.io/qt/qt5.git -b ${QT_VERSION} --depth 1 \
|
||||
&& cd qt5 \
|
||||
&& perl init-repository --module-subset=default,-qtwebengine \
|
||||
&& PATH=${HOST_PATH} ./configure -v -developer-build -release \
|
||||
-xplatform android-clang \
|
||||
-android-ndk-platform ${ANDROID_API} \
|
||||
-android-ndk ${ANDROID_NDK_ROOT} \
|
||||
-android-sdk ${ANDROID_SDK_ROOT} \
|
||||
-android-ndk-host linux-x86_64 \
|
||||
-no-dbus \
|
||||
-opengl es2 \
|
||||
-no-use-gold-linker \
|
||||
-no-sql-mysql \
|
||||
-opensource -confirm-license \
|
||||
-android-arch arm64-v8a \
|
||||
-prefix ${PREFIX} \
|
||||
-nomake tools -nomake tests -nomake examples \
|
||||
-skip qtwebengine \
|
||||
-skip qtserialport \
|
||||
-skip qtconnectivity \
|
||||
-skip qttranslations \
|
||||
-skip qtpurchasing \
|
||||
-skip qtgamepad -skip qtscript -skip qtdoc \
|
||||
-no-warnings-are-errors \
|
||||
&& sed -i '213,215d' qtbase/src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} install \
|
||||
&& cd qttools/src/linguist/lrelease \
|
||||
&& ../../../../qtbase/bin/qmake \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} install \
|
||||
&& cd ../../../.. \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
ARG ICONV_VERSION=1.16
|
||||
ARG ICONV_HASH=e6a1b1b589654277ee790cce3734f07876ac4ccfaecbee8afa0b649cf529cc04
|
||||
RUN wget -q http://ftp.gnu.org/pub/gnu/libiconv/libiconv-${ICONV_VERSION}.tar.gz \
|
||||
&& echo "${ICONV_HASH} libiconv-${ICONV_VERSION}.tar.gz" | sha256sum -c \
|
||||
&& tar -xzf libiconv-${ICONV_VERSION}.tar.gz \
|
||||
&& rm -f libiconv-${ICONV_VERSION}.tar.gz \
|
||||
&& cd libiconv-${ICONV_VERSION} \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --build=x86_64-linux-gnu --host=aarch64 --prefix=${PREFIX} --disable-rpath \
|
||||
&& make -j${THREADS} \
|
||||
&& make -j${THREADS} install
|
||||
|
||||
ARG BOOST_VERSION=1_74_0
|
||||
ARG BOOST_VERSION_DOT=1.74.0
|
||||
ARG BOOST_HASH=83bfc1507731a0906e387fc28b7ef5417d591429e51e788417fe9ff025e116b1
|
||||
RUN wget -q https://dl.bintray.com/boostorg/release/${BOOST_VERSION_DOT}/source/boost_${BOOST_VERSION}.tar.bz2 \
|
||||
&& echo "${BOOST_HASH} boost_${BOOST_VERSION}.tar.bz2" | sha256sum -c \
|
||||
&& tar -xf boost_${BOOST_VERSION}.tar.bz2 \
|
||||
&& rm -f boost_${BOOST_VERSION}.tar.bz2 \
|
||||
&& cd boost_${BOOST_VERSION} \
|
||||
&& PATH=${HOST_PATH} ./bootstrap.sh --prefix=${PREFIX} \
|
||||
&& PATH=${TOOLCHAIN_DIR}/bin:${HOST_PATH} ./b2 --build-type=minimal link=static runtime-link=static \
|
||||
--with-chrono --with-date_time --with-filesystem --with-program_options --with-regex --with-serialization \
|
||||
--with-system --with-thread --with-locale --build-dir=android --stagedir=android toolset=clang threading=multi \
|
||||
threadapi=pthread target-os=android -sICONV_PATH=${PREFIX} \
|
||||
cflags='--target=aarch64-linux-android' \
|
||||
cxxflags='--target=aarch64-linux-android' \
|
||||
linkflags='--target=aarch64-linux-android --sysroot=${ANDROID_NDK_ROOT}/platforms/${ANDROID_API}/arch-arm64 ${ANDROID_NDK_ROOT}/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so -nostdlib++' \
|
||||
install -j${THREADS} \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
ARG OPENSSL_VERSION=1.1.1g
|
||||
ARG OPENSSL_HASH=ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46
|
||||
RUN wget -q https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz \
|
||||
&& tar -xzf openssl-${OPENSSL_VERSION}.tar.gz \
|
||||
&& rm openssl-${OPENSSL_VERSION}.tar.gz \
|
||||
&& cd openssl-${OPENSSL_VERSION} \
|
||||
&& ANDROID_NDK_HOME=${ANDROID_NDK_ROOT} ./Configure CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} \
|
||||
android-arm64 no-asm no-shared --static \
|
||||
--with-zlib-include=${PREFIX}/include --with-zlib-lib=${PREFIX}/lib \
|
||||
--prefix=${PREFIX} --openssldir=${PREFIX} \
|
||||
&& sed -i 's/CNF_EX_LIBS=-ldl -pthread//g;s/BIN_CFLAGS=-pie $(CNF_CFLAGS) $(CFLAGS)//g' Makefile \
|
||||
&& ANDROID_NDK_HOME=${ANDROID_NDK_ROOT} make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
ARG ZMQ_VERSION=v4.3.3
|
||||
ARG ZMQ_HASH=04f5bbedee58c538934374dc45182d8fc5926fa3
|
||||
RUN git clone https://github.com/zeromq/libzmq.git -b ${ZMQ_VERSION} --depth 1 \
|
||||
&& cd libzmq \
|
||||
&& git checkout ${ZMQ_HASH} \
|
||||
&& ./autogen.sh \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --prefix=${PREFIX} --host=aarch64-linux-android \
|
||||
--enable-static --disable-shared \
|
||||
&& make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
ARG SODIUM_VERSION=1.0.18
|
||||
ARG SODIUM_HASH=4f5e89fa84ce1d178a6765b8b46f2b6f91216677
|
||||
RUN set -ex \
|
||||
&& git clone https://github.com/jedisct1/libsodium.git -b ${SODIUM_VERSION} --depth 1 \
|
||||
&& cd libsodium \
|
||||
&& test `git rev-parse HEAD` = ${SODIUM_HASH} || exit 1 \
|
||||
&& ./autogen.sh \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --prefix=${PREFIX} --host=aarch64-linux-android --enable-static --disable-shared \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b libgpg-error-1.38 --depth 1 git://git.gnupg.org/libgpg-error.git \
|
||||
&& cd libgpg-error \
|
||||
&& git reset --hard 71d278824c5fe61865f7927a2ed1aa3115f9e439 \
|
||||
&& ./autogen.sh \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --host=aarch64-linux-android --prefix=${PREFIX} --disable-rpath --disable-shared --enable-static --disable-doc --disable-tests \
|
||||
&& PATH=${TOOLCHAIN_DIR}/bin:${HOST_PATH} make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b libgcrypt-1.8.5 --depth 1 git://git.gnupg.org/libgcrypt.git \
|
||||
&& cd libgcrypt \
|
||||
&& git reset --hard 56606331bc2a80536db9fc11ad53695126007298 \
|
||||
&& ./autogen.sh \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --host=aarch64-linux-android --prefix=${PREFIX} --with-gpg-error-prefix=${PREFIX} --disable-shared --enable-static --disable-doc --disable-tests \
|
||||
&& PATH=${TOOLCHAIN_DIR}/bin:${HOST_PATH} make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
RUN cd tools \
|
||||
&& wget -q http://dl-ssl.google.com/android/repository/tools_r25.2.5-linux.zip \
|
||||
&& unzip -q tools_r25.2.5-linux.zip \
|
||||
&& rm -f tools_r25.2.5-linux.zip \
|
||||
&& echo y | ${ANDROID_SDK_ROOT}/tools/android update sdk --no-ui --all --filter build-tools-28.0.3
|
||||
|
||||
RUN git clone -b v3.19.7 --depth 1 https://github.com/Kitware/CMake \
|
||||
&& cd CMake \
|
||||
&& git reset --hard 22612dd53a46c7f9b4c3f4b7dbe5c78f9afd9581 \
|
||||
&& PATH=${HOST_PATH} ./bootstrap \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} \
|
||||
&& PATH=${HOST_PATH} make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b v1.6.35 --depth 1 https://github.com/glennrp/libpng.git && \
|
||||
cd libpng && \
|
||||
git reset --hard c17d164b4467f099b4484dfd4a279da0bc1dbd4a \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ./configure --with-zlib-prefix="${PREFIX}" --host=aarch64-linux-android --prefix=${PREFIX} --disable-shared --enable-static \
|
||||
&& PATH=${TOOLCHAIN_DIR}/bin:${HOST_PATH} make -j${THREADS} \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
# @TODO: don't hardcode ANDROID_PLATFORM
|
||||
RUN git clone -b v4.0.2 --depth 1 https://github.com/fukuchi/libqrencode.git && \
|
||||
cd libqrencode && \
|
||||
git reset --hard 59ee597f913fcfda7a010a6e106fbee2595f68e4 && \
|
||||
CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" \
|
||||
-DANDROID_PLATFORM="28" \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DARCH="armv8-a" \
|
||||
-DANDROID_ABI="arm64-v8a" \
|
||||
-DANDROID_TOOLCHAIN=clang \
|
||||
-DCMAKE_PREFIX_PATH="${PREFIX}" \
|
||||
-DPNG_PNG_INCLUDE_DIR="${PREFIX}/include/libpng16/" \
|
||||
-DPNG_LIBRARY="${PREFIX}/lib/libqtlibpng_arm64-v8a.a" \
|
||||
-DICONV_LIBRARY=/opt/android/prefix/lib/libiconv.a \
|
||||
-DICONV_INCLUDE_DIR=/opt/android/prefix/include/ \
|
||||
-DCMAKE_INSTALL_PREFIX="${PREFIX}" && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN ls -al && uname -a
|
||||
|
||||
# @TODO: switch to Release
|
||||
CMD set -ex \
|
||||
&& cd /wowlet \
|
||||
&& mkdir -p build/Android/release \
|
||||
&& cd build/Android/release \
|
||||
&& E=1 cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" \
|
||||
-DCMAKE_PREFIX_PATH="${PREFIX}" \
|
||||
-DCMAKE_FIND_ROOT_PATH="${PREFIX}" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DARCH="armv8-a" \
|
||||
-DANDROID_NATIVE_API_LEVEL=${ANDROID_NATIVE_API_LEVEL} \
|
||||
-DANDROID_ABI="arm64-v8a" \
|
||||
-DANDROID_TOOLCHAIN=clang \
|
||||
-DBoost_USE_STATIC_RUNTIME=ON \
|
||||
-DLRELEASE_PATH="${PREFIX}/bin" \
|
||||
-DQT_ANDROID_APPLICATION_BINARY="wowlet" \
|
||||
-DWITH_SCANNER=ON \
|
||||
-DUSE_DEVICE_TREZOR=OFF \
|
||||
-DUSE_SINGLE_BUILDDIR=ON \
|
||||
-DMANUAL_SUBMODULES=1 \
|
||||
-DUSE_SINGLE_BUILDDIR=ON \
|
||||
-DQML=ON \
|
||||
-DANDROID=ON \
|
||||
../../.. \
|
||||
&& PATH=${HOST_PATH} make generate_translations_header \
|
||||
&& make -j${THREADS} -C src \
|
||||
&& make -j${THREADS} apk
|
||||
@@ -43,6 +43,7 @@ CMAKEFLAGS = \
|
||||
$(CMAKEFLAGS_EXTRA)
|
||||
|
||||
release-static: CMAKEFLAGS += -DBUILD_TAG="linux-x64"
|
||||
release-static: CMAKEFLAGS += -DXMRIG=ON
|
||||
release-static: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
|
||||
release-static: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release
|
||||
release-static: CMAKEFLAGS += -DREPRODUCIBLE=$(or ${SOURCE_DATE_EPOCH},OFF)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#define WOWLET_VERSION "@VERSION@"
|
||||
#define WOWLET_BRANCH "@WOWLET_BRANCH@"
|
||||
#define WOWLET_VERSION_SEMVER "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_REVISION@"
|
||||
|
||||
#define MONERO_VERSION "@MONERO_VERSION@"
|
||||
#define MONERO_BRANCH "@MONERO_BRANCH@"
|
||||
|
||||
@@ -22,13 +22,13 @@ mkdir -p "$DEBDIR/usr/share/icons/hicolor/256x256/apps/"
|
||||
|
||||
# Copy over assets
|
||||
|
||||
cp "$PWD/src/assets/control" "$DEBDIR/DEBIAN/control"
|
||||
cp "$PWD/src/assets/copyright" "$DEBDIR/debian/copyright"
|
||||
cp "$PWD/src/assets/copyright" "$DEBDIR/usr/share/doc/wowlet/copyright"
|
||||
cp "$PWD/src/assets/changelog.gz" "$DEBDIR/usr/share/doc/wowlet/changelog.gz"
|
||||
cp "$PWD/contrib/debian/control" "$DEBDIR/DEBIAN/control"
|
||||
cp "$PWD/contrib/debian/copyright" "$DEBDIR/debian/copyright"
|
||||
cp "$PWD/contrib/debian/copyright" "$DEBDIR/usr/share/doc/wowlet/copyright"
|
||||
cp "$PWD/contrib/debian/changelog.gz" "$DEBDIR/usr/share/doc/wowlet/changelog.gz"
|
||||
cp "$PWD/src/assets/org.wowlet.wowlet.metainfo.xml" "$DEBDIR/usr/share/metainfo/org.wowlet.wowlet.metainfo.xml"
|
||||
cp "$PWD/README.md" "$DEBDIR/usr/share/doc/wowlet/README"
|
||||
cp "$PWD/SECURITY.md" "$DEBDIR/usr/share/doc/wowlet/SECURITY"
|
||||
cp "$PWD/docs/SECURITY.md" "$DEBDIR/usr/share/doc/wowlet/SECURITY"
|
||||
cp "$PWD/build/bin/wowlet" "$DEBDIR/usr/bin/wowlet"
|
||||
cp "$PWD/src/assets/org.wowlet.wowlet.desktop" "$DEBDIR/usr/share/applications/org.wowlet.wowlet.desktop"
|
||||
cp "$PWD/src/assets/wowlet.1.gz" "$DEBDIR/usr/share/man/man1/wowlet.1.gz"
|
||||
@@ -43,4 +43,4 @@ cp "$PWD/src/assets/images/appicons/256x256.png" "$DEBDIR/usr/share/icons/hicolo
|
||||
# Build deb package
|
||||
|
||||
dpkg-deb --build $DEBDIR
|
||||
mv wowlet.DebDir.deb wowlet_1.0_amd64.deb
|
||||
mv wowlet.DebDir.deb wowlet_2.0_amd64.deb
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Package: wowlet
|
||||
Version: 1.0
|
||||
Version: 2.0
|
||||
Section: net
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
|
||||
@@ -28,7 +28,7 @@ by running this command: `pandoc wowlet.1.md -s -t man -o wowlet.1 && gzip wowle
|
||||
apt install -y git cmake libqrencode-dev build-essential cmake libboost-all-dev \
|
||||
miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev \
|
||||
libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev \
|
||||
libprotobuf-dev protobuf-compiler libgcrypt20-dev
|
||||
libprotobuf-dev protobuf-compiler libgcrypt20-dev libpng-dev
|
||||
```
|
||||
|
||||
## Mac OS
|
||||
@@ -107,6 +107,4 @@ To skip the wizards and open a wallet directly use `--wallet-file`:
|
||||
./wowlet --use-local-tor --wallet-file /home/user/Wownero/wallets/bla.keys
|
||||
```
|
||||
|
||||
It is recommended that you use `--stagenet` for development. Testnet is also possible,
|
||||
but you'll have to provide Wownero a testnet node of your own.
|
||||
|
||||
|
||||
@@ -57,6 +57,15 @@ if(OPENVR)
|
||||
list(APPEND SOURCE_FILES ${SOURCE_FILES_QML})
|
||||
endif()
|
||||
|
||||
if(ANDROID OR ANDROID_DEBUG)
|
||||
qt5_add_resources(RESOURCES mobile/qml.qrc)
|
||||
file(GLOB SOURCE_FILES_QML
|
||||
"mobile/*.h"
|
||||
"mobile/*.cpp"
|
||||
)
|
||||
list(APPEND SOURCE_FILES ${SOURCE_FILES_QML})
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wno-deprecated-declarations") # @TODO: removeme
|
||||
|
||||
add_subdirectory(libwalletqt)
|
||||
@@ -98,11 +107,16 @@ if(APPLE)
|
||||
list(APPEND RESOURCES ${ICON})
|
||||
endif()
|
||||
|
||||
add_executable(wowlet ${EXECUTABLE_FLAG} main.cpp
|
||||
${SOURCE_FILES}
|
||||
${RESOURCES}
|
||||
${ASSETS_TOR}
|
||||
)
|
||||
if(NOT ANDROID)
|
||||
add_executable(wowlet ${EXECUTABLE_FLAG} main.cpp
|
||||
${SOURCE_FILES}
|
||||
${RESOURCES}
|
||||
${ASSETS_TOR}
|
||||
)
|
||||
else()
|
||||
add_library(wowlet SHARED ${SOURCE_FILES} ${RESOURCES})
|
||||
set_target_properties(wowlet PROPERTIES COMPILE_DEFINITIONS "ANDROID")
|
||||
endif()
|
||||
|
||||
# mac os bundle
|
||||
set_target_properties(wowlet PROPERTIES
|
||||
@@ -162,6 +176,14 @@ if(XMRIG)
|
||||
target_compile_definitions(wowlet PRIVATE HAS_XMRIG=1)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
target_compile_definitions(wowlet PRIVATE HAS_ANDROID=1)
|
||||
endif()
|
||||
|
||||
if(ANDROID_DEBUG)
|
||||
target_compile_definitions(wowlet PRIVATE HAS_ANDROID_DEBUG=1)
|
||||
endif()
|
||||
|
||||
if(OPENVR)
|
||||
target_compile_definitions(wowlet PRIVATE HAS_OPENVR=1)
|
||||
target_compile_definitions(wowlet PUBLIC VR_API_PUBLIC)
|
||||
@@ -220,6 +242,13 @@ else()
|
||||
target_link_libraries(wowlet PUBLIC monero-seed::monero-seed)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
# yolo some hardcoded paths
|
||||
target_include_directories(wowlet PUBLIC
|
||||
/opt/android/prefix/include/QtAndroidExtras/
|
||||
)
|
||||
endif()
|
||||
|
||||
# Link Wownero core libraries
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
wallet_merged
|
||||
@@ -261,6 +290,33 @@ else()
|
||||
Qt5::WebSockets)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
# yolo some hardcoded paths
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
/opt/android/prefix/lib/libQt5QuickTemplates2_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Quick_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5QmlModels_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Qml_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Svg_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Widgets_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Gui_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Xml_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5XmlPatterns_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Network_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5Core_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5VirtualKeyboard_arm64-v8a.so
|
||||
/opt/android/prefix/lib/libQt5AndroidExtras_arm64-v8a.so
|
||||
/opt/android/prefix/plugins/bearer/libplugins_bearer_qandroidbearer_arm64-v8a.so
|
||||
GLESv2
|
||||
log
|
||||
z
|
||||
jnigraphics
|
||||
android
|
||||
EGL
|
||||
c++_shared
|
||||
)
|
||||
endif()
|
||||
|
||||
# Link random other stuff
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
${ICU_LIBRARIES}
|
||||
@@ -294,7 +350,7 @@ if(OPENVR)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
target_link_libraries(wowlet
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
KDMacTouchBar
|
||||
)
|
||||
target_include_directories(wowlet
|
||||
@@ -329,3 +385,19 @@ endif()
|
||||
install(TARGETS wowlet
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}
|
||||
)
|
||||
|
||||
|
||||
message(STATUS "=============================================")
|
||||
message(STATUS "VERSION_MAJOR: ${VERSION_MAJOR}")
|
||||
message(STATUS "VERSION_MINOR: ${VERSION_MINOR}")
|
||||
message(STATUS "VERSION_REVISION: ${VERSION_REVISION}")
|
||||
message(STATUS "STATIC: ${STATIC}")
|
||||
message(STATUS "Include QtQuick (QML): ${QML}")
|
||||
message(STATUS "VERSION: ${VERSION}")
|
||||
message(STATUS "Include the XMRIG tab: ${XMRIG}")
|
||||
message(STATUS "Include Valve's OpenVR library: ${OPENVR}")
|
||||
message(STATUS "This build is for Android: ${ANDROID}")
|
||||
message(STATUS "This build is for testing the Android app on desktop: ${ANDROID_DEBUG}")
|
||||
message(STATUS "TOR_BIN: ${TOR_BIN}")
|
||||
message(STATUS "DONATE_BEG: ${DONATE_BEG}")
|
||||
message(STATUS "=============================================")
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "appcontext.h"
|
||||
#include "globals.h"
|
||||
#include "config-wowlet.h"
|
||||
|
||||
// libwalletqt
|
||||
#include "libwalletqt/TransactionHistory.h"
|
||||
@@ -30,77 +31,69 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
|
||||
this->cmdargs = cmdargs;
|
||||
AppContext::isQML = false;
|
||||
|
||||
// OS & env
|
||||
#if defined(Q_OS_MAC)
|
||||
this->isMac = true;
|
||||
this->isTorSocks = qgetenv("DYLD_INSERT_LIBRARIES").indexOf("libtorsocks") >= 0;
|
||||
#elif __ANDROID__
|
||||
this->isAndroid = true;
|
||||
#elif defined(Q_OS_LINUX)
|
||||
this->isLinux = true;
|
||||
this->isTorSocks = qgetenv("LD_PRELOAD").indexOf("libtorsocks") >= 0;
|
||||
#elif defined(Q_OS_WIN)
|
||||
this->isTorSocks = false;
|
||||
#endif
|
||||
|
||||
this->isTails = TailsOS::detect();
|
||||
this->isWhonix = WhonixOS::detect();
|
||||
#elif defined(Q_OS_WIN)
|
||||
this->isWindows = true;
|
||||
this->isTorSocks = false;
|
||||
#endif
|
||||
this->androidDebug = cmdargs->isSet("android-debug");
|
||||
|
||||
//Paths
|
||||
// Paths
|
||||
this->pathGenericData = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
|
||||
this->configRoot = QDir::homePath();
|
||||
if (isTails) { // #if defined(PORTABLE)
|
||||
QString portablePath = []{
|
||||
QString appImagePath = qgetenv("APPIMAGE");
|
||||
if (appImagePath.isEmpty()) {
|
||||
qDebug() << "Not an appimage, using currentPath()";
|
||||
return QDir::currentPath() + "/.wowlet";
|
||||
}
|
||||
|
||||
QFileInfo appImageDir(appImagePath);
|
||||
return appImageDir.absoluteDir().path() + "/.wowlet";
|
||||
}();
|
||||
|
||||
|
||||
if (QDir().mkpath(portablePath)) {
|
||||
this->configRoot = portablePath;
|
||||
} else {
|
||||
qCritical() << "Unable to create portable directory: " << portablePath;
|
||||
}
|
||||
}
|
||||
|
||||
this->accountName = Utils::getUnixAccountName();
|
||||
this->homeDir = QDir::homePath();
|
||||
|
||||
this->configDirectory = QString("%1/.config/wowlet/").arg(this->configRoot);
|
||||
this->configDirectoryVR = QString("%1%2").arg(this->configDirectory, "vr");
|
||||
|
||||
if (isTails) this->setupPathsTails();
|
||||
|
||||
QString walletDir = config()->get(Config::walletDirectory).toString();
|
||||
if (walletDir.isEmpty()) {
|
||||
#if defined(Q_OS_LINUX) or defined(Q_OS_MAC)
|
||||
this->defaultWalletDir = QString("%1/Wownero/wallets").arg(this->configRoot);
|
||||
this->defaultWalletDirRoot = QString("%1/Wownero").arg(this->configRoot);
|
||||
#elif defined(Q_OS_WIN)
|
||||
this->defaultWalletDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/Wownero";
|
||||
this->defaultWalletDirRoot = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
#endif
|
||||
if(walletDir.isEmpty()) {
|
||||
if (isAndroid && !androidDebug) setupPathsAndroid();
|
||||
else if (isWindows) setupPathsWindows();
|
||||
else if (isLinux || isMac) setupPathsUnix();
|
||||
} else {
|
||||
this->defaultWalletDir = walletDir;
|
||||
this->defaultWalletDirRoot = walletDir;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// can haz disk I/O?
|
||||
QVector<QString> perms = {
|
||||
"android.permission.WRITE_EXTERNAL_STORAGE",
|
||||
"android.permission.READ_EXTERNAL_STORAGE"
|
||||
};
|
||||
Utils::androidAskPermissions(perms);
|
||||
#endif
|
||||
|
||||
// Create wallet dirs
|
||||
qDebug() << "creating " << defaultWalletDir;
|
||||
if (!QDir().mkpath(defaultWalletDir))
|
||||
qCritical() << "Unable to create dir: " << defaultWalletDir;
|
||||
|
||||
this->configDirectory = QString("%1/.config/wowlet/").arg(this->configRoot);
|
||||
#if defined(Q_OS_UNIX)
|
||||
if(!this->configDirectory.endsWith('/'))
|
||||
this->configDirectory = QString("%1/").arg(this->configDirectory);
|
||||
#endif
|
||||
this->configDirectoryVR = QString("%1%2").arg(this->configDirectory, "vr");
|
||||
|
||||
// Create some directories
|
||||
createConfigDirectory(this->configDirectory);
|
||||
|
||||
// if(this->cmdargs->isSet("stagenet"))
|
||||
// this->networkType = NetworkType::STAGENET;
|
||||
// else if(this->cmdargs->isSet("testnet"))
|
||||
// this->networkType = NetworkType::TESTNET;
|
||||
// else
|
||||
this->networkType = NetworkType::MAINNET;
|
||||
|
||||
qDebug() << "configRoot: " << this->configRoot;
|
||||
qDebug() << "homeDir: " << this->homeDir;
|
||||
qDebug() << "customWalletDir: " << walletDir;
|
||||
qDebug() << "defaultWalletDir: " << this->defaultWalletDir;
|
||||
qDebug() << "defaultWalletDirRoot: " << this->defaultWalletDirRoot;
|
||||
qDebug() << "configDirectory: " << this->configDirectory;
|
||||
|
||||
// auto nodeSourceUInt = config()->get(Config::nodeSource).toUInt();
|
||||
// AppContext::nodeSource = static_cast<NodeSource>(nodeSourceUInt);
|
||||
this->nodes = new Nodes(this, this->networkClearnet);
|
||||
@@ -119,6 +112,24 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
|
||||
this->storeWallet();
|
||||
});
|
||||
|
||||
// If system clock skewed for >= 300 seconds, assume a wake-up from hibernate and reload the websocket connection
|
||||
if(!this->isAndroid)
|
||||
m_hibernateTimer.start(3 * 1000);
|
||||
|
||||
m_hibernatePreviousTime = std::chrono::steady_clock::now();
|
||||
connect(&m_hibernateTimer, &QTimer::timeout, [this]() {
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
const auto elapsed = now - m_hibernatePreviousTime;
|
||||
|
||||
if(elapsed >= m_hibernateDetectInterval) {
|
||||
qCritical() << "Clock skew detected, resetting websocket connection";
|
||||
this->ws->webSocket.abort();
|
||||
this->ws->start();
|
||||
}
|
||||
|
||||
m_hibernatePreviousTime = now;
|
||||
});
|
||||
|
||||
// restore height lookup
|
||||
this->initRestoreHeights();
|
||||
|
||||
@@ -423,7 +434,6 @@ void AppContext::onWSMessage(const QJsonObject &msg) {
|
||||
QJsonArray crypto_rates = msg.value("data").toArray();
|
||||
AppContext::prices->cryptoPricesReceived(crypto_rates);
|
||||
}
|
||||
|
||||
else if(cmd == "fiat_rates") {
|
||||
QJsonObject fiat_rates = msg.value("data").toObject();
|
||||
AppContext::prices->fiatPricesReceived(fiat_rates);
|
||||
@@ -432,21 +442,35 @@ void AppContext::onWSMessage(const QJsonObject &msg) {
|
||||
QJsonArray reddit_data = msg.value("data").toArray();
|
||||
this->onWSReddit(reddit_data);
|
||||
}
|
||||
|
||||
else if(cmd == "forum") {
|
||||
QJsonArray forum_data = msg.value("data").toArray();
|
||||
this->onWSForum(forum_data);
|
||||
}
|
||||
else if(cmd == "funding_proposals") {
|
||||
auto ccs_data = msg.value("data").toArray();
|
||||
this->onWSCCS(ccs_data);
|
||||
}
|
||||
|
||||
else if(cmd == "suchwow") {
|
||||
QJsonArray such_data = msg.value("data").toArray();
|
||||
emit suchWowUpdated(such_data);
|
||||
}
|
||||
|
||||
else if(cmd == "txFiatHistory") {
|
||||
auto txFiatHistory_data = msg.value("data").toObject();
|
||||
AppContext::txFiatHistory->onWSData(txFiatHistory_data);
|
||||
}
|
||||
else if(cmd == "wowlet_releases") {
|
||||
versionPending = msg.value("data").toObject();
|
||||
auto version_str = versionPending.value("version").toString();
|
||||
|
||||
if(Utils::versionOutdated(WOWLET_VERSION_SEMVER, version_str))
|
||||
emit versionOutdated(version_str, versionPending);
|
||||
}
|
||||
else if(cmd == "kill") {
|
||||
// used *only* in dire emergencies
|
||||
auto killme = msg.value("data").toBool();
|
||||
if(killme)
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
#if defined(HAS_OPENVR)
|
||||
else if(cmd == "requestPIN") {
|
||||
auto pin = msg.value("data").toString();
|
||||
@@ -497,6 +521,23 @@ void AppContext::onWSNodes(const QJsonArray &nodes) {
|
||||
this->nodes->onWSNodesReceived(l);
|
||||
}
|
||||
|
||||
void AppContext::onWSForum(const QJsonArray& forum_data) {
|
||||
QList<QSharedPointer<ForumPost>> l;
|
||||
|
||||
for (auto &&entry: forum_data) {
|
||||
auto obj = entry.toObject();
|
||||
auto forumPost = new ForumPost(
|
||||
obj.value("title").toString(),
|
||||
obj.value("author").toString(),
|
||||
obj.value("permalink").toString(),
|
||||
obj.value("comments").toInt());
|
||||
QSharedPointer<ForumPost> r = QSharedPointer<ForumPost>(forumPost);
|
||||
l.append(r);
|
||||
}
|
||||
|
||||
emit forumUpdated(l);
|
||||
}
|
||||
|
||||
void AppContext::onWSReddit(const QJsonArray& reddit_data) {
|
||||
QList<QSharedPointer<RedditPost>> l;
|
||||
|
||||
@@ -558,12 +599,14 @@ void AppContext::createConfigDirectory(const QString &dir) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAS_OPENVR
|
||||
auto config_dir_vr = QString("%1%2").arg(dir, "vr");
|
||||
if(!Utils::dirExists(config_dir_vr)) {
|
||||
qDebug() << QString("Creating directory: %1").arg(config_dir_vr);
|
||||
if (!QDir().mkpath(config_dir_vr))
|
||||
throw std::runtime_error("Could not create directory " + config_dir_vr.toStdString());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void AppContext::createWalletWithoutSpecifyingSeed(const QString &name, const QString &password) {
|
||||
@@ -949,3 +992,38 @@ void AppContext::refreshModels() {
|
||||
this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount());
|
||||
// Todo: set timer for refreshes
|
||||
}
|
||||
|
||||
void AppContext::setupPathsUnix() {
|
||||
this->defaultWalletDir = QString("%1/Wownero/wallets").arg(this->configRoot);
|
||||
this->defaultWalletDirRoot = QString("%1/Wownero").arg(this->configRoot);
|
||||
}
|
||||
|
||||
void AppContext::setupPathsWindows() {
|
||||
this->defaultWalletDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/Wownero";
|
||||
this->defaultWalletDirRoot = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
}
|
||||
|
||||
void AppContext::setupPathsAndroid() {
|
||||
this->defaultWalletDir = QString("%1/Wownero/wallets").arg(this->pathGenericData);
|
||||
this->defaultWalletDirRoot = QString("%1/Wownero").arg(this->pathGenericData);
|
||||
}
|
||||
|
||||
void AppContext::setupPathsTails() {
|
||||
QString portablePath = []{
|
||||
QString appImagePath = qgetenv("APPIMAGE");
|
||||
if (appImagePath.isEmpty()) {
|
||||
qDebug() << "Not an appimage, using currentPath()";
|
||||
return QDir::currentPath() + "/.wowlet";
|
||||
}
|
||||
|
||||
QFileInfo appImageDir(appImagePath);
|
||||
return appImageDir.absoluteDir().path() + "/.wowlet";
|
||||
}();
|
||||
|
||||
if (QDir().mkpath(portablePath)) {
|
||||
this->configRoot = portablePath;
|
||||
} else {
|
||||
qCritical() << "Unable to create portable directory: " << portablePath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "utils/txfiathistory.h"
|
||||
#include "utils/WowletSeed.h"
|
||||
#include "widgets/RedditPost.h"
|
||||
#include "widgets/ForumPost.h"
|
||||
#include "widgets/CCSEntry.h"
|
||||
#include "utils/RestoreHeightLookup.h"
|
||||
#include "utils/nodes.h"
|
||||
@@ -39,7 +40,13 @@ public:
|
||||
~AppContext() override;
|
||||
bool isTails = false;
|
||||
bool isWhonix = false;
|
||||
bool isAndroid = false;
|
||||
bool isLinux = false;
|
||||
bool isMac = false;
|
||||
bool isWindows = false;
|
||||
bool isDebug = false;
|
||||
static bool isQML;
|
||||
bool androidDebug = false;
|
||||
|
||||
// Donation config
|
||||
const QString donationAddress = "Wo3MWeKwtA918DU4c69hVSNgejdWFCRCuWjShRY66mJkU2Hv58eygJWDJS1MNa2Ge5M1WjUkGHuLqHkweDxwZZU42d16v94mP";
|
||||
@@ -50,6 +57,7 @@ public:
|
||||
|
||||
QString coinName = "wownero";
|
||||
bool isTorSocks = false;
|
||||
QString pathGenericData;
|
||||
QString homeDir;
|
||||
QString accountName;
|
||||
QString configRoot;
|
||||
@@ -98,7 +106,7 @@ public:
|
||||
static QMap<QString, QString> txDescriptionCache;
|
||||
static QMap<QString, QString> txCache;
|
||||
static TxFiatHistory *txFiatHistory;
|
||||
static bool isQML;
|
||||
QJsonObject versionPending;
|
||||
|
||||
// libwalletqt
|
||||
bool refreshed = false;
|
||||
@@ -154,6 +162,7 @@ private slots:
|
||||
void onWSMessage(const QJsonObject& msg);
|
||||
void onWSCCS(const QJsonArray &ccs_data);
|
||||
void onWSReddit(const QJsonArray& reddit_data);
|
||||
void onWSForum(const QJsonArray& forum_data);
|
||||
|
||||
void onMoneySpent(const QString &txId, quint64 amount);
|
||||
void onMoneyReceived(const QString &txId, quint64 amount);
|
||||
@@ -192,6 +201,7 @@ signals:
|
||||
void wsConnected();
|
||||
void wsDisconnected();
|
||||
void redditUpdated(QList<QSharedPointer<RedditPost>> &posts);
|
||||
void forumUpdated(QList<QSharedPointer<ForumPost>> &posts);
|
||||
void nodesUpdated(QList<QSharedPointer<WowletNode>> &nodes);
|
||||
void ccsUpdated(QList<QSharedPointer<CCSEntry>> &entries);
|
||||
void suchWowUpdated(const QJsonArray &such_data);
|
||||
@@ -210,11 +220,20 @@ signals:
|
||||
void initiateTransaction();
|
||||
void endTransaction();
|
||||
void setTitle(const QString &title); // set window title
|
||||
void versionOutdated(QString version_string, QJsonObject data);
|
||||
|
||||
private:
|
||||
WalletKeysFilesModel *m_walletKeysFilesModel;
|
||||
const int m_donationBoundary = 15;
|
||||
QTimer m_storeTimer;
|
||||
QTimer m_hibernateTimer;
|
||||
std::chrono::seconds m_hibernateDetectInterval{300};
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_hibernatePreviousTime;
|
||||
|
||||
void setupPathsUnix();
|
||||
void setupPathsWindows();
|
||||
void setupPathsAndroid();
|
||||
void setupPathsTails();
|
||||
};
|
||||
|
||||
#endif //WOWLET_APPCONTEXT_H
|
||||
|
||||
@@ -129,8 +129,56 @@
|
||||
<file>assets/images/welcome/wow74.png</file>
|
||||
<file>assets/images/welcome/wow75.png</file>
|
||||
<file>assets/images/welcome/wow76.png</file>
|
||||
<file>assets/images/welcome/wow77.png</file>
|
||||
<file>assets/images/welcome/wow78.png</file>
|
||||
<file>assets/images/welcome/wow79.png</file>
|
||||
<file>assets/images/welcome/wow80.png</file>
|
||||
<file>assets/images/welcome/wow81.png</file>
|
||||
<file>assets/images/welcome/wow82.png</file>
|
||||
<file>assets/images/welcome/wow83.png</file>
|
||||
<file>assets/images/welcome/wow84.png</file>
|
||||
<file>assets/images/welcome/wow85.png</file>
|
||||
<file>assets/images/welcome/wow86.png</file>
|
||||
<file>assets/images/welcome/wow87.png</file>
|
||||
<file>assets/images/welcome/wow88.png</file>
|
||||
<file>assets/images/welcome/wow89.png</file>
|
||||
<file>assets/images/welcome/wow90.png</file>
|
||||
<file>assets/images/welcome/wow91.png</file>
|
||||
<file>assets/images/welcome/wow92.png</file>
|
||||
<file>assets/images/welcome/wow93.png</file>
|
||||
<file>assets/images/welcome/wow94.png</file>
|
||||
<file>assets/images/welcome/wow95.png</file>
|
||||
<file>assets/images/welcome/wow96.png</file>
|
||||
<file>assets/images/welcome/wow97.png</file>
|
||||
<file>assets/images/welcome/wow98.png</file>
|
||||
<file>assets/images/welcome/wow99.png</file>
|
||||
<file>assets/images/welcome/wow100.png</file>
|
||||
<file>assets/images/welcome/wow101.png</file>
|
||||
<file>assets/images/welcome/wow102.png</file>
|
||||
<file>assets/images/welcome/wow103.png</file>
|
||||
<file>assets/images/welcome/wow104.png</file>
|
||||
<file>assets/images/welcome/wow105.png</file>
|
||||
<file>assets/images/welcome/wow106.png</file>
|
||||
<file>assets/images/welcome/wow107.png</file>
|
||||
<file>assets/images/welcome/wow108.png</file>
|
||||
<file>assets/images/welcome/wow109.png</file>
|
||||
<file>assets/images/welcome/wow110.png</file>
|
||||
<file>assets/images/welcome/wow111.png</file>
|
||||
<file>assets/images/welcome/wow112.png</file>
|
||||
<file>assets/images/welcome/wow113.png</file>
|
||||
<file>assets/images/welcome/wow114.png</file>
|
||||
<file>assets/images/welcome/wow115.png</file>
|
||||
<file>assets/images/welcome/wow116.png</file>
|
||||
<file>assets/images/welcome/wow117.png</file>
|
||||
<file>assets/images/welcome/wow118.png</file>
|
||||
<file>assets/images/welcome/wow119.png</file>
|
||||
<file>assets/images/welcome/wow120.png</file>
|
||||
<file>assets/images/welcome/wow121.png</file>
|
||||
<file>assets/images/welcome/wow122.png</file>
|
||||
<file>assets/images/welcome/wow123.png</file>
|
||||
<file>assets/images/preferences.png</file>
|
||||
<file>assets/images/preferences.svg</file>
|
||||
<file>assets/images/credits.jpg</file>
|
||||
<file>assets/images/qrcode.png</file>
|
||||
<file>assets/images/qrcode_white.png</file>
|
||||
<file>assets/images/revealer_c.png</file>
|
||||
@@ -138,6 +186,7 @@
|
||||
<file>assets/images/seal.png</file>
|
||||
<file>assets/images/seed.png</file>
|
||||
<file>assets/images/speaker.png</file>
|
||||
<file>assets/images/pls_update.jpg</file>
|
||||
<file>assets/images/status_connected_fork.png</file>
|
||||
<file>assets/images/status_connected.png</file>
|
||||
<file>assets/images/status_connected_proxy_fork.png</file>
|
||||
|
||||
|
After Width: | Height: | Size: 227 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 102 KiB |
|
After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 145 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 115 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 20 KiB |
@@ -13,8 +13,8 @@ AboutDialog::AboutDialog(QWidget *parent)
|
||||
ui->setupUi(this);
|
||||
this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png"));
|
||||
|
||||
QPixmap p(":assets/images/illiterate_illuminati.png");
|
||||
ui->aboutImage->setPixmap(p.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
QPixmap p(":assets/images/credits.jpg");
|
||||
ui->aboutImage->setPixmap(p.scaled(800, 600, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
auto about = Utils::fileOpenQRC(":assets/about.txt");
|
||||
auto about_text = Utils::barrayToString(about);
|
||||
about_text = about_text.replace("<wowlet_version>", WOWLET_VERSION);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#include <QObject>
|
||||
#include "updatedialog.h"
|
||||
#include "ui_updatedialog.h"
|
||||
|
||||
#include "config-wowlet.h"
|
||||
|
||||
UpdateDialog::UpdateDialog(AppContext *ctx, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ctx(ctx),
|
||||
ui(new Ui::UpdateDialog) {
|
||||
ui->setupUi(this);
|
||||
this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png"));
|
||||
|
||||
auto version_str = ctx->versionPending.value("version").toString();
|
||||
|
||||
QPixmap p(":assets/images/pls_update.jpg");
|
||||
ui->label_image->setPixmap(p.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
|
||||
ui->info_label->setText("Current version: " + QString(WOWLET_VERSION_SEMVER) + "\n"
|
||||
"New version: " + version_str);
|
||||
|
||||
ui->label_download->setText("Download: <a href=\"https://git.wownero.com/wowlet/wowlet/releases\">git.wownero.com</a>");
|
||||
ui->label_download->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
ui->label_download->setOpenExternalLinks(true);
|
||||
|
||||
// checkbox
|
||||
connect(ui->checkbox_ignore, &QCheckBox::clicked, this, &UpdateDialog::checkboxIgnoreWarning);
|
||||
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
void UpdateDialog::checkboxIgnoreWarning(bool checked) {
|
||||
if(checked)
|
||||
config()->set(Config::ignoreUpdateWarning, WOWLET_VERSION_SEMVER);
|
||||
else
|
||||
config()->set(Config::ignoreUpdateWarning, "");
|
||||
}
|
||||
|
||||
UpdateDialog::~UpdateDialog() {
|
||||
delete ui;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#ifndef WOWLET_UPDATEDIALOG_H
|
||||
#define WOWLET_UPDATEDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "appcontext.h"
|
||||
|
||||
namespace Ui {
|
||||
class UpdateDialog;
|
||||
}
|
||||
|
||||
class UpdateDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UpdateDialog(AppContext *ctx, QWidget *parent = nullptr);
|
||||
~UpdateDialog() override;
|
||||
|
||||
private slots:
|
||||
void checkboxIgnoreWarning(bool checked);
|
||||
|
||||
private:
|
||||
AppContext *ctx = nullptr;
|
||||
Ui::UpdateDialog *ui;
|
||||
};
|
||||
|
||||
|
||||
#endif //WOWLET_UPDATEDIALOG_H
|
||||
@@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>UpdateDialog</class>
|
||||
<widget class="QDialog" name="UpdateDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>349</width>
|
||||
<height>189</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Pls update</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_image">
|
||||
<property name="text">
|
||||
<string>image</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="info_label">
|
||||
<property name="text">
|
||||
<string>info_label</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_download">
|
||||
<property name="text">
|
||||
<string>download_label</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkbox_ignore">
|
||||
<property name="text">
|
||||
<string>Ignore for now</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>UpdateDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>UpdateDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -1,6 +1,8 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2014-2021, The Monero Project.
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "Wallet.h"
|
||||
|
||||
#include "TransactionHistory.h"
|
||||
|
||||
@@ -14,6 +14,12 @@
|
||||
#include "vr/main.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAS_ANDROID_DEBUG
|
||||
#include "mobile/main.h"
|
||||
#elif HAS_ANDROID
|
||||
#include "mobile/main.h"
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
@@ -44,6 +50,10 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||
argv_ << QString::fromStdString(argv[i]);
|
||||
}
|
||||
|
||||
QCoreApplication::setApplicationName("wowlet");
|
||||
QCoreApplication::setOrganizationDomain("wownero.org");
|
||||
QCoreApplication::setOrganizationName("wownero.org");
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("wowlet");
|
||||
parser.addHelpOption();
|
||||
@@ -91,9 +101,12 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||
QCommandLineOption openVROption(QStringList() << "openvr", "Start Wowlet OpenVR");
|
||||
parser.addOption(openVROption);
|
||||
|
||||
QCommandLineOption openVRDebugOption(QStringList() << "openvr-debug", "Start the Wowlet VR interface without initializing OpenVR - for debugging purposes.");
|
||||
QCommandLineOption openVRDebugOption(QStringList() << "openvr-debug", "Start the Wowlet VR interface without initializing OpenVR - for debugging purposes. Requires -DOPENVR=ON CMake definition.");
|
||||
parser.addOption(openVRDebugOption);
|
||||
|
||||
QCommandLineOption androidDebugOption(QStringList() << "android-debug", "Start the Android interface without actually running on Android - for debugging purposes. Requires -DANDROID_DEBUG=ON CMake definition.");
|
||||
parser.addOption(androidDebugOption);
|
||||
|
||||
auto parsed = parser.parse(argv_);
|
||||
if(!parsed) {
|
||||
qCritical() << parser.errorText();
|
||||
@@ -111,13 +124,29 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||
bool backgroundAddressEnabled = parser.isSet(backgroundOption);
|
||||
bool openVREnabled = parser.isSet(openVROption);
|
||||
bool cliMode = exportContacts || exportTxHistory || backgroundAddressEnabled;
|
||||
|
||||
bool androidDebug = parser.isSet(androidDebugOption);
|
||||
bool android = false;
|
||||
#ifdef __ANDROID__
|
||||
android = true;
|
||||
#endif
|
||||
qRegisterMetaType<QVector<QString>>();
|
||||
|
||||
#ifdef HAS_QML
|
||||
qputenv("QML_DISABLE_DISK_CACHE", "1");
|
||||
#endif
|
||||
|
||||
if(android || androidDebug) {
|
||||
#ifndef HAS_QML
|
||||
qCritical() << "Wowlet compiled without QML support. Try -DQML=ON";
|
||||
return 1;
|
||||
#endif
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QGuiApplication mobile_app(argc, argv);
|
||||
auto *ctx = new AppContext(&parser);
|
||||
auto *mobile = new mobile::Mobile(ctx, &parser, &mobile_app);
|
||||
return mobile_app.exec();
|
||||
}
|
||||
|
||||
if(openVREnabled) {
|
||||
#ifdef HAS_OPENVR
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
@@ -138,9 +167,6 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||
if(cliMode) {
|
||||
auto *ctx = new AppContext(&parser);
|
||||
QCoreApplication cli_app(argc, argv);
|
||||
QCoreApplication::setApplicationName("wowlet");
|
||||
QCoreApplication::setOrganizationDomain("wownero.org");
|
||||
QCoreApplication::setOrganizationName("wownero.org");
|
||||
|
||||
ctx->applicationPath = QString(argv[0]);
|
||||
ctx->isDebug = debugMode;
|
||||
@@ -191,10 +217,6 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
QApplication::setApplicationName("wowlet");
|
||||
QApplication::setOrganizationDomain("wownero.org");
|
||||
QApplication::setOrganizationName("wownero.org");
|
||||
|
||||
parser.process(app); // Parse again for --help and --version
|
||||
|
||||
if(!quiet) {
|
||||
@@ -204,8 +226,10 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||
if (stagenet) info["Mode"] = "Stagenet";
|
||||
else if (testnet) info["Mode"] = "Testnet";
|
||||
else info["Mode"] = "Mainnet";
|
||||
#ifndef QT_NO_SSL
|
||||
info["SSL"] = QSslSocket::sslLibraryVersionString();
|
||||
info["SSL build"] = QSslSocket::sslLibraryBuildVersionString();
|
||||
#endif
|
||||
for (const auto &k: info.keys())
|
||||
qWarning().nospace().noquote() << QString("%1: %2").arg(k).arg(info[k]);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QMessageBox>
|
||||
#include <QGroupBox>
|
||||
#include <QFileDialog>
|
||||
|
||||
#include "mainwindow.h"
|
||||
@@ -18,11 +19,13 @@
|
||||
#include "dialog/viewonlydialog.h"
|
||||
#include "dialog/broadcasttxdialog.h"
|
||||
#include "dialog/tximportdialog.h"
|
||||
#include "dialog/updatedialog.h"
|
||||
#include "dialog/passworddialog.h"
|
||||
#include "dialog/balancedialog.h"
|
||||
#include "dialog/WalletCacheDebugDialog.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include "globals.h"
|
||||
#include "config-wowlet.h"
|
||||
#include "utils/ColorScheme.h"
|
||||
|
||||
// libwalletqt
|
||||
@@ -38,6 +41,8 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
|
||||
pMainWindow = this;
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->label_outdated->setVisible(false);
|
||||
|
||||
m_windowSettings = new Settings(this);
|
||||
m_aboutDialog = new AboutDialog(this);
|
||||
m_windowCalc = new CalcWindow(this);
|
||||
@@ -129,15 +134,29 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
|
||||
#endif
|
||||
|
||||
// ticker widgets
|
||||
m_tickerWidgets.append(new TickerWidget(this, "WOW"));
|
||||
m_tickerWidgets.append(new TickerWidget(this, "BTC"));
|
||||
for(auto tickerWidget: m_tickerWidgets) {
|
||||
ui->tickerLayout->addWidget(tickerWidget);
|
||||
}
|
||||
m_tickerWOW = new TickerWidget(this, "WOW");
|
||||
ui->tickerLayout->addWidget(m_tickerWOW);
|
||||
|
||||
m_balanceWidget = new TickerWidget(this, "WOW", "Balance", true, true);
|
||||
m_tickerSAT = new TickerWidget(this, "Satoshi");
|
||||
m_tickerSAT->hidePct(true);
|
||||
ui->tickerLayout->addWidget(m_tickerSAT);
|
||||
|
||||
m_tickerBTC = new TickerWidget(this, "BTC");
|
||||
ui->tickerLayout->addWidget(m_tickerBTC);
|
||||
|
||||
m_tickerXMR = new TickerWidget(this, "XMR");
|
||||
ui->tickerLayout->addWidget(m_tickerXMR);
|
||||
|
||||
m_balanceWidget = new TickerWidget(this, "Balance");
|
||||
m_balanceWidget->hidePct(true);
|
||||
ui->fiatTickerLayout->addWidget(m_balanceWidget);
|
||||
|
||||
connect(m_tickerWOW, &TickerWidget::reload, this, &MainWindow::onUpdateWowWidget);
|
||||
connect(m_tickerBTC, &TickerWidget::reload, this, &MainWindow::onUpdateBTCWidget);
|
||||
connect(m_tickerSAT, &TickerWidget::reload, this, &MainWindow::onUpdateSATWidget);
|
||||
connect(m_tickerSAT, &TickerWidget::reload, this, &MainWindow::onUpdateXMRWidget);
|
||||
connect(m_balanceWidget, &TickerWidget::reload, this, &MainWindow::onUpdateFiatBalanceWidget);
|
||||
|
||||
// Send widget
|
||||
connect(ui->sendWidget, &SendWidget::createTransaction, m_ctx, QOverload<const QString, quint64, const QString, bool>::of(&AppContext::onCreateTransaction));
|
||||
connect(ui->sendWidget, &SendWidget::createTransactionMultiDest, m_ctx, &AppContext::onCreateTransactionMultiDest);
|
||||
@@ -167,6 +186,7 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
|
||||
connect(ui->ccsWidget, &CCSWidget::selected, this, &MainWindow::showSendScreen);
|
||||
connect(m_ctx, &AppContext::ccsUpdated, ui->ccsWidget->model(), &CCSModel::updateEntries);
|
||||
connect(m_ctx, &AppContext::redditUpdated, ui->redditWidget->model(), &RedditModel::updatePosts);
|
||||
connect(m_ctx, &AppContext::forumUpdated, ui->forumWidget->model(), &ForumModel::updatePosts);
|
||||
connect(m_ctx, &AppContext::suchWowUpdated, ui->suchWowWidget, &SuchWowWidget::onWS);
|
||||
connect(ui->suchWowWidget, &SuchWowWidget::donate, this, &MainWindow::suchDonate);
|
||||
|
||||
@@ -252,11 +272,9 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
|
||||
}
|
||||
|
||||
// settings connects
|
||||
// Update ticker widget(s) on home tab when settings preferred fiat currency is changed
|
||||
for(auto tickerWidget: m_tickerWidgets)
|
||||
connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, tickerWidget, &TickerWidget::init);
|
||||
connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_balanceWidget, &TickerWidget::init);
|
||||
connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, this, &MainWindow::onUpdateFiatBalanceWidget);
|
||||
connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_ctx, &AppContext::onPreferredFiatCurrencyChanged);
|
||||
connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, ui->suchWowWidget, &SuchWowWidget::onPreferredFiatCurrencyChanged);
|
||||
connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, ui->sendWidget, QOverload<>::of(&SendWidget::onPreferredFiatCurrencyChanged));
|
||||
|
||||
// Skin
|
||||
@@ -324,6 +342,9 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
|
||||
// window title
|
||||
connect(m_ctx, &AppContext::setTitle, this, &QMainWindow::setWindowTitle);
|
||||
|
||||
// Version warning
|
||||
connect(m_ctx, &AppContext::versionOutdated, this, &MainWindow::onVersionWarning);
|
||||
|
||||
// init touchbar
|
||||
#ifdef Q_OS_MAC
|
||||
m_touchbar = new KDMacTouchBar(this);
|
||||
@@ -365,6 +386,7 @@ void MainWindow::initMain() {
|
||||
this->setEnabled(false);
|
||||
this->show();
|
||||
m_wizard = this->createWizard(WalletWizard::Page_Menu);
|
||||
m_wizard->randomBanner();
|
||||
m_wizard->show();
|
||||
this->touchbarShowWizard();
|
||||
}
|
||||
@@ -414,6 +436,7 @@ void MainWindow::initMenu() {
|
||||
connect(ui->actionSeed, &QAction::triggered, this, &MainWindow::showSeedDialog);
|
||||
connect(ui->actionPassword, &QAction::triggered, this, &MainWindow::showPasswordDialog);
|
||||
connect(ui->actionKeys, &QAction::triggered, this, &MainWindow::showKeysDialog);
|
||||
connect(this, &MainWindow::updateDialog, this, &MainWindow::showUpdateDialog);
|
||||
connect(ui->actionViewOnly, &QAction::triggered, this, &MainWindow::showViewOnlyDialog);
|
||||
connect(ui->actionStore_wallet, &QAction::triggered, [this]{
|
||||
m_ctx->currentWallet->store();
|
||||
@@ -518,6 +541,7 @@ void MainWindow::showWizard(WalletWizard::Page startPage) {
|
||||
m_wizard->setStartId(startPage);
|
||||
m_wizard->restart();
|
||||
m_wizard->setEnabled(true);
|
||||
m_wizard->randomBanner();
|
||||
m_wizard->show();
|
||||
}
|
||||
|
||||
@@ -617,6 +641,8 @@ void MainWindow::onWalletOpened(Wallet *wallet) {
|
||||
this->updatePasswordIcon();
|
||||
|
||||
m_updateBytes.start(100);
|
||||
|
||||
if(m_showUpdateWarning == 1) emit updateDialog();
|
||||
}
|
||||
|
||||
void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) {
|
||||
@@ -632,7 +658,6 @@ void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) {
|
||||
|
||||
m_statusLabelBalance->setToolTip("Click for details");
|
||||
m_statusLabelBalance->setText(label_str);
|
||||
m_balanceWidget->setHidden(hide);
|
||||
}
|
||||
|
||||
void MainWindow::setStatusText(const QString &text, bool override, int timeout) {
|
||||
@@ -872,6 +897,12 @@ void MainWindow::updatePasswordIcon() {
|
||||
m_statusBtnPassword->setIcon(icon);
|
||||
}
|
||||
|
||||
void MainWindow::onVersionWarning(QString current_string, QJsonObject version_data) {
|
||||
if(m_showUpdateWarning != -1)
|
||||
m_showUpdateWarning = 1;
|
||||
ui->label_outdated->setVisible(true);
|
||||
}
|
||||
|
||||
void MainWindow::showRestoreHeightDialog() {
|
||||
// settings custom restore height is only available for 25 word seeds
|
||||
auto seed = m_ctx->currentWallet->getCacheAttribute("wowlet.seed");
|
||||
@@ -897,6 +928,17 @@ void MainWindow::showRestoreHeightDialog() {
|
||||
});
|
||||
}
|
||||
|
||||
void MainWindow::showUpdateDialog() {
|
||||
if(config()->get(Config::ignoreUpdateWarning).toString() == WOWLET_VERSION_SEMVER) {
|
||||
m_showUpdateWarning = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
auto *dialog = new UpdateDialog(m_ctx, this);
|
||||
dialog->show();
|
||||
m_showUpdateWarning = -1;
|
||||
}
|
||||
|
||||
void MainWindow::showKeysDialog() {
|
||||
auto *dialog = new KeysDialog(m_ctx, this);
|
||||
dialog->exec();
|
||||
@@ -1037,7 +1079,9 @@ void MainWindow::showSendScreen(const CCSEntry &entry) {
|
||||
}
|
||||
|
||||
void MainWindow::suchDonate(const QString address) {
|
||||
double donation = AppContext::prices->convert("EUR", "WOW", 2);
|
||||
double tipAmount = config()->get(Config::suchWowTipAmount).toDouble();
|
||||
QString preferredCurrency = config()->get(Config::preferredFiatCurrency).toString();
|
||||
double donation = AppContext::prices->convert(preferredCurrency, "WOW", tipAmount);
|
||||
ui->sendWidget->fill(address, "SuchWow contribution :-)", donation);
|
||||
ui->tabWidget->setCurrentIndex(Tabs::SEND);
|
||||
}
|
||||
@@ -1322,6 +1366,85 @@ void MainWindow::showBalanceDialog() {
|
||||
dialog->deleteLater();
|
||||
}
|
||||
|
||||
void MainWindow::onUpdateSATWidget() {
|
||||
if(!AppContext::prices->markets.count() || !AppContext::prices->rates.count())
|
||||
return;
|
||||
auto wowObj = AppContext::prices->markets["WOW"];
|
||||
QString satStr = QString::number(wowObj.price_sat);
|
||||
m_tickerSAT->setFiatText(satStr);
|
||||
}
|
||||
|
||||
void MainWindow::onUpdateWowWidget() {
|
||||
if(!AppContext::prices->markets.count() || !AppContext::prices->rates.count())
|
||||
return;
|
||||
QString fiatCurrency = config()->get(Config::preferredFiatCurrency).toString();
|
||||
if(!AppContext::prices->rates.contains(fiatCurrency)){
|
||||
config()->set(Config::preferredFiatCurrency, "USD");
|
||||
fiatCurrency = "USD";
|
||||
}
|
||||
|
||||
auto wowObj = AppContext::prices->markets["WOW"];
|
||||
auto currencyText = Utils::amountToCurrencyString(wowObj.price_usd, fiatCurrency);
|
||||
m_tickerWOW->setFiatText(currencyText);
|
||||
|
||||
auto pct24h = AppContext::prices->markets["WOW"].price_usd_change_pct_24h;
|
||||
auto pct24hText = QString::number(pct24h, 'f', 2);
|
||||
this->m_tickerWOW->setPctText(pct24hText, pct24h >= 0.0);
|
||||
}
|
||||
|
||||
void MainWindow::onUpdateBTCWidget() {
|
||||
if(!AppContext::prices->markets.count() || !AppContext::prices->rates.count())
|
||||
return;
|
||||
QString fiatCurrency = config()->get(Config::preferredFiatCurrency).toString();
|
||||
if(!AppContext::prices->rates.contains(fiatCurrency)){
|
||||
config()->set(Config::preferredFiatCurrency, "USD");
|
||||
fiatCurrency = "USD";
|
||||
}
|
||||
|
||||
double conversion = AppContext::prices->convert("BTC", fiatCurrency, 1.0);
|
||||
auto conversionText = Utils::amountToCurrencyString(conversion, fiatCurrency);
|
||||
m_tickerBTC->setFiatText(conversionText);
|
||||
|
||||
auto pct24h = AppContext::prices->markets["BTC"].price_usd_change_pct_24h;
|
||||
auto pct24hText = QString::number(pct24h, 'f', 2);
|
||||
this->m_tickerBTC->setPctText(pct24hText, pct24h >= 0.0);
|
||||
}
|
||||
|
||||
void MainWindow::onUpdateXMRWidget() {
|
||||
if(!AppContext::prices->markets.count() || !AppContext::prices->rates.count())
|
||||
return;
|
||||
QString fiatCurrency = config()->get(Config::preferredFiatCurrency).toString();
|
||||
if(!AppContext::prices->rates.contains(fiatCurrency)){
|
||||
config()->set(Config::preferredFiatCurrency, "USD");
|
||||
fiatCurrency = "USD";
|
||||
}
|
||||
|
||||
double conversion = AppContext::prices->convert("XMR", fiatCurrency, 1.0);
|
||||
auto conversionText = Utils::amountToCurrencyString(conversion, fiatCurrency);
|
||||
m_tickerXMR->setFiatText(conversionText);
|
||||
|
||||
auto pct24h = AppContext::prices->markets["XMR"].price_usd_change_pct_24h;
|
||||
auto pct24hText = QString::number(pct24h, 'f', 2);
|
||||
this->m_tickerXMR->setPctText(pct24hText, pct24h >= 0.0);
|
||||
}
|
||||
|
||||
void MainWindow::onUpdateFiatBalanceWidget() {
|
||||
bool hide = config()->get(Config::hideBalance).toBool() || config()->get(Config::hideFiatBalance).toBool();
|
||||
m_balanceWidget->setHidden(hide);
|
||||
|
||||
if(!AppContext::prices->markets.count() || !AppContext::prices->rates.count())
|
||||
return;
|
||||
QString fiatCurrency = config()->get(Config::preferredFiatCurrency).toString();
|
||||
if(!AppContext::prices->rates.contains(fiatCurrency)){
|
||||
config()->set(Config::preferredFiatCurrency, "USD");
|
||||
fiatCurrency = "USD";
|
||||
}
|
||||
|
||||
double conversion = AppContext::prices->convert("WOW", fiatCurrency, AppContext::balance);
|
||||
auto conversionText = Utils::amountToCurrencyString(conversion, fiatCurrency);
|
||||
m_balanceWidget->setFiatText(conversionText);
|
||||
}
|
||||
|
||||
QString MainWindow::statusDots() {
|
||||
m_statusDots++;
|
||||
m_statusDots = m_statusDots % 4;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include "src/kdmactouchbar.h"
|
||||
#endif
|
||||
@@ -23,6 +25,7 @@
|
||||
#include "calcwindow.h"
|
||||
#include "widgets/ccswidget.h"
|
||||
#include "widgets/redditwidget.h"
|
||||
#include "widgets/forumwidget.h"
|
||||
#include "widgets/tickerwidget.h"
|
||||
#include "widgets/xmrigwidget.h"
|
||||
#include "utils/networking.h"
|
||||
@@ -35,6 +38,7 @@
|
||||
#include "dialog/verifyproofdialog.h"
|
||||
#include "dialog/seeddialog.h"
|
||||
#include "dialog/passwordchangedialog.h"
|
||||
#include "dialog/updatedialog.h"
|
||||
#include "dialog/keysdialog.h"
|
||||
#include "dialog/aboutdialog.h"
|
||||
#include "dialog/restoredialog.h"
|
||||
@@ -81,8 +85,10 @@ public:
|
||||
};
|
||||
|
||||
enum TabsHome {
|
||||
CCS,
|
||||
REDDIT
|
||||
FORUM,
|
||||
REDDIT,
|
||||
SUCHWOW,
|
||||
WFS
|
||||
};
|
||||
|
||||
public slots:
|
||||
@@ -110,6 +116,7 @@ public slots:
|
||||
void showSendScreen(const CCSEntry &entry);
|
||||
void suchDonate(const QString address);
|
||||
void skinChanged(const QString &skinName);
|
||||
void onVersionWarning(QString current_string, QJsonObject data);
|
||||
void menuTorClicked();
|
||||
void onBlockchainSync(int height, int target);
|
||||
void onRefreshSync(int height, int target);
|
||||
@@ -145,7 +152,15 @@ public slots:
|
||||
void onCreateTransactionSuccess(PendingTransaction *tx, const QVector<QString> &address);
|
||||
void onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid);
|
||||
|
||||
// tickers
|
||||
void onUpdateWowWidget();
|
||||
void onUpdateFiatBalanceWidget();
|
||||
void onUpdateBTCWidget();
|
||||
void onUpdateSATWidget();
|
||||
void onUpdateXMRWidget();
|
||||
|
||||
signals:
|
||||
void updateDialog();
|
||||
void closed();
|
||||
|
||||
private:
|
||||
@@ -161,6 +176,7 @@ private:
|
||||
void saveGeo();
|
||||
void restoreGeo();
|
||||
void showDebugInfo();
|
||||
void showUpdateDialog();
|
||||
void showNodeExhaustedMessage();
|
||||
void showWSNodeExhaustedMessage();
|
||||
void createUnsignedTxDialog(UnsignedTransaction *tx);
|
||||
@@ -189,7 +205,10 @@ private:
|
||||
QAction *m_trayActionSend;
|
||||
QAction *m_trayActionHistory;
|
||||
|
||||
QList<TickerWidget*> m_tickerWidgets;
|
||||
TickerWidget *m_tickerWOW;
|
||||
TickerWidget *m_tickerBTC;
|
||||
TickerWidget *m_tickerSAT;
|
||||
TickerWidget *m_tickerXMR;
|
||||
TickerWidget *m_balanceWidget;
|
||||
|
||||
// lower status bar
|
||||
@@ -221,6 +240,7 @@ private:
|
||||
bool m_constructingTransaction = false;
|
||||
bool m_statusOverrideActive = false;
|
||||
QTimer m_txTimer;
|
||||
int m_showUpdateWarning = 0;
|
||||
|
||||
private slots:
|
||||
void menuToggleTabVisible(const QString &key);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1156</width>
|
||||
<height>502</height>
|
||||
<height>506</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -86,6 +86,13 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_outdated">
|
||||
<property name="text">
|
||||
<string>Warning: outdated wowlet version</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
@@ -101,9 +108,31 @@
|
||||
<property name="documentMode">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_4">
|
||||
<attribute name="title">
|
||||
<string>Forum</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<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="ForumWidget" name="forumWidget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>/r/Wownero</string>
|
||||
<string>Reddit</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<property name="leftMargin">
|
||||
@@ -326,7 +355,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1156</width>
|
||||
<height>20</height>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
@@ -755,6 +784,12 @@
|
||||
<header>widgets/suchwowwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ForumWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>widgets/forumwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="assets.qrc"/>
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# Wowlet Mobile (Android)
|
||||
|
||||
This directory contains an unfinished QML application that will show:
|
||||
|
||||

|
||||
|
||||
## Building
|
||||
|
||||
Credits go to Monero GUI team for providing the initial work on Qt5+Android.
|
||||
|
||||
Build a Docker image:
|
||||
|
||||
```bash
|
||||
docker build --tag wowlet:android --build-arg THREADS=14 --file Dockerfile.android .
|
||||
```
|
||||
|
||||
Building Wowlet for arm64-v8a:
|
||||
|
||||
```Bash
|
||||
docker run --rm -it -v $PWD:/wowlet -w /wowlet -e THREADS=6 wowlet:android
|
||||
```
|
||||
|
||||
Installing the resulting `.apk` on your device:
|
||||
|
||||
```bash
|
||||
adb install build/Android/release/android-build//build/outputs/apk/debug/android-build-debug.apk
|
||||
```
|
||||
|
||||
Viewing debug logs:
|
||||
|
||||
```bash
|
||||
adb logcat | grep --line-buffered "D wowlet"
|
||||
```
|
||||
|
||||
# Development
|
||||
|
||||
To show this on desktop, you will need the following CMake definitions:
|
||||
|
||||
`-DANDROID_DEBUG=ON -DWITH_SCANNER=ON`
|
||||
|
||||
Start wowlet with the `--android-debug` flag:
|
||||
|
||||
```bash
|
||||
./wowlet --android-debug
|
||||
```
|
||||
@@ -0,0 +1,102 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#include <iostream>
|
||||
#include <QResource>
|
||||
#include <QApplication>
|
||||
#include <QCoreApplication>
|
||||
#include <QQmlComponent>
|
||||
#include <QObject>
|
||||
#include <QtCore>
|
||||
#include <QtGui>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QtQml>
|
||||
#include <QFileInfo>
|
||||
#include <QQuickView>
|
||||
#include <QQuickItem>
|
||||
|
||||
#include "libwalletqt/TransactionInfo.h"
|
||||
#include "libwalletqt/TransactionHistory.h"
|
||||
#include "model/TransactionHistoryModel.h"
|
||||
#include "model/TransactionHistoryProxyModel.h"
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
|
||||
#include "utils/keysfiles.h"
|
||||
#include "mobile/main.h"
|
||||
|
||||
namespace mobile {
|
||||
|
||||
Mobile::Mobile(AppContext *ctx, QCommandLineParser *parser, QObject *parent) :
|
||||
QObject(parent), ctx(ctx), m_parser(parser) {
|
||||
AppContext::isQML = true;
|
||||
m_pClipboard = QGuiApplication::clipboard();
|
||||
desktopMode = true;
|
||||
|
||||
// turn on auto tx commits
|
||||
ctx->autoCommitTx = true;
|
||||
|
||||
// QR code scanning from screenshots
|
||||
m_qrScreenshotPreviewPath = ctx->configDirectoryVR + "/screenshot_preview";
|
||||
m_qrScreenshotImagePath = ctx->configDirectoryVR + "/screenshot";
|
||||
m_qrScreenshotTimer.setSingleShot(true);
|
||||
|
||||
qDebug() << "QMLSCENE_DEVICE: " << qgetenv("QMLSCENE_DEVICE");
|
||||
|
||||
m_engine.rootContext()->setContextProperty("homePath", QDir::homePath());
|
||||
m_engine.rootContext()->setContextProperty("applicationDirectory", QApplication::applicationDirPath());
|
||||
m_engine.rootContext()->setContextProperty("idealThreadCount", QThread::idealThreadCount());
|
||||
m_engine.rootContext()->setContextProperty("qtRuntimeVersion", qVersion());
|
||||
m_engine.rootContext()->setContextProperty("ctx", ctx);
|
||||
|
||||
m_engine.rootContext()->setContextProperty("Mobile", this);
|
||||
qRegisterMetaType<NetworkType::Type>();
|
||||
qmlRegisterType<NetworkType>("wowlet.NetworkType", 1, 0, "NetworkType");
|
||||
|
||||
qmlRegisterUncreatableType<WalletKeysFiles>("wowlet.WalletKeysFiles", 1, 0, "WalletKeysFiles", "WalletKeysFiles can't be instantiated directly");
|
||||
qmlRegisterUncreatableType<Wallet>("wowlet.Wallet", 1, 0, "Wallet", "Wallet can't be instantiated directly");
|
||||
qmlRegisterType<WalletManager>("wowlet.WalletManager", 1, 0, "WalletManager");
|
||||
|
||||
qmlRegisterUncreatableType<TransactionHistoryProxyModel>("wowlet.TransactionHistoryProxyModel", 1, 0, "TransactionHistoryProxyModel", "TransactionHistoryProxyModel can't be instantiated directly");
|
||||
qmlRegisterUncreatableType<TransactionHistoryModel>("wowlet.TransactionHistoryModel", 1, 0, "TransactionHistoryModel", "TransactionHistoryModel can't be instantiated directly");
|
||||
qmlRegisterUncreatableType<TransactionInfo>("wowlet.TransactionInfo", 1, 0, "TransactionInfo", "TransactionHistory can't be instantiated directly");
|
||||
qmlRegisterUncreatableType<TransactionHistory>("wowlet.TransactionHistory", 1, 0, "TransactionHistory", "TransactionHistory can't be instantiated directly");
|
||||
|
||||
qRegisterMetaType<PendingTransaction::Priority>();
|
||||
qRegisterMetaType<TransactionInfo::Direction>();
|
||||
qRegisterMetaType<TransactionHistoryModel::TransactionInfoRole>();
|
||||
|
||||
auto widgetUrl = QUrl(QStringLiteral("qrc:///main"));
|
||||
m_engine.load(widgetUrl);
|
||||
if (m_engine.rootObjects().isEmpty())
|
||||
{
|
||||
qCritical() << "Error: no root objects";
|
||||
return;
|
||||
}
|
||||
QObject *rootObject = m_engine.rootObjects().first();
|
||||
if (!rootObject)
|
||||
{
|
||||
qCritical() << "Error: no root objects";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int wege = 1;
|
||||
}
|
||||
|
||||
void Mobile::takeQRScreenshot() {
|
||||
|
||||
}
|
||||
|
||||
void Mobile::onCheckQRScreenshot() {
|
||||
|
||||
}
|
||||
|
||||
QString Mobile::checkQRScreenshotResults(std::vector<std::string> results) {
|
||||
|
||||
}
|
||||
|
||||
Mobile::~Mobile() {
|
||||
// bla
|
||||
int wegeg = 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#ifndef WOWLET_MAIN_H
|
||||
#define WOWLET_MAIN_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QQmlError>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QtQml>
|
||||
#include <QGuiApplication>
|
||||
#include <QClipboard>
|
||||
#include <QTimer>
|
||||
#include <globals.h>
|
||||
|
||||
#include "appcontext.h"
|
||||
#include "utils/config.h"
|
||||
#include "QR-Code-scanner/Decoder.h"
|
||||
|
||||
namespace mobile {
|
||||
|
||||
class Mobile : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Mobile(AppContext *ctx, QCommandLineParser *cmdargs, QObject *parent = nullptr);
|
||||
~Mobile() override;
|
||||
|
||||
QList<QQmlError> errors;
|
||||
|
||||
Q_INVOKABLE double cdiv(double amount) { return amount / globals::cdiv; }
|
||||
Q_INVOKABLE double add(double x, double y) const { return Utils::roundUp(x + y, 4); } // round ceil 4 decimals
|
||||
Q_INVOKABLE double sub(double x, double y) const { return Utils::roundUp(x - y, 4); } // round ceil 4 decimals
|
||||
|
||||
Q_INVOKABLE void onCreateTransaction(const QString &address, const QString &amount_str, const QString description, bool all) {
|
||||
auto amount = WalletManager::amountFromString(amount_str);
|
||||
ctx->onCreateTransaction(address, amount, description, false);
|
||||
}
|
||||
|
||||
Q_INVOKABLE void setClipboard(const QString &text) {
|
||||
m_pClipboard->setText(text, QClipboard::Clipboard);
|
||||
m_pClipboard->setText(text, QClipboard::Selection);
|
||||
}
|
||||
|
||||
Q_INVOKABLE QString preferredFiat() {
|
||||
return config()->get(Config::preferredFiatCurrency).toString();
|
||||
}
|
||||
|
||||
Q_INVOKABLE QString fiatToWow(double amount) {
|
||||
auto preferredFiatCurrency = config()->get(Config::preferredFiatCurrency).toString();
|
||||
if (amount <= 0) return QString("0.00");
|
||||
|
||||
double conversionAmount = AppContext::prices->convert(preferredFiatCurrency, "WOW", amount);
|
||||
return QString("%1").arg(QString::number(conversionAmount, 'f', 2));
|
||||
}
|
||||
|
||||
Q_INVOKABLE QString wowToFiat(double amount) {
|
||||
auto preferredFiatCurrency = config()->get(Config::preferredFiatCurrency).toString();
|
||||
if (amount <= 0) return QString("0.00");
|
||||
|
||||
double conversionAmount = AppContext::prices->convert("WOW", preferredFiatCurrency, amount);
|
||||
if(conversionAmount <= 0) return QString("0.00");
|
||||
return QString("~%1").arg(QString::number(conversionAmount, 'f', 2));
|
||||
}
|
||||
|
||||
Q_INVOKABLE void takeQRScreenshot();
|
||||
|
||||
signals:
|
||||
void qrScreenshotFailed(QString error);
|
||||
void qrScreenshotSuccess(QString address);
|
||||
|
||||
private slots:
|
||||
void onCheckQRScreenshot();
|
||||
|
||||
private:
|
||||
AppContext *ctx;
|
||||
QQmlApplicationEngine m_engine;
|
||||
|
||||
bool desktopMode = false;
|
||||
QString m_qrScreenshotPreviewPath;
|
||||
QString m_qrScreenshotImagePath;
|
||||
|
||||
QCommandLineParser *m_parser;
|
||||
QClipboard *m_pClipboard;
|
||||
QTimer m_qrScreenshotTimer;
|
||||
QrDecoder m_qrDecoder;
|
||||
|
||||
static QString checkQRScreenshotResults(std::vector<std::string> results);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //WOWLET_MAIN_H
|
||||
@@ -0,0 +1,35 @@
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Window 2.0
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Dialogs 1.2
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import "."
|
||||
|
||||
import wowlet.Wallet 1.0
|
||||
import wowlet.WalletManager 1.0
|
||||
|
||||
ApplicationWindow {
|
||||
visible: true
|
||||
id: appWindow
|
||||
width: 1080
|
||||
height: 2400
|
||||
color: "#2C3539"
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
Qt.quit();
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Wowlet"
|
||||
color: "white"
|
||||
anchors.centerIn: parent
|
||||
font.pointSize: 62
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/">
|
||||
<file alias="main">main.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -0,0 +1,104 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#include "ForumModel.h"
|
||||
|
||||
ForumModel::ForumModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ForumModel::clear() {
|
||||
beginResetModel();
|
||||
|
||||
m_posts.clear();
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void ForumModel::updatePosts(const QList<QSharedPointer<ForumPost>>& posts) {
|
||||
beginResetModel();
|
||||
|
||||
m_posts.clear();
|
||||
for (const auto& post : posts) {
|
||||
m_posts.push_back(post);
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int ForumModel::rowCount(const QModelIndex &parent) const{
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
return m_posts.count();
|
||||
}
|
||||
|
||||
int ForumModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
return ModelColumn::COUNT;
|
||||
}
|
||||
|
||||
QVariant ForumModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() < 0 || index.row() >= m_posts.count())
|
||||
return QVariant();
|
||||
|
||||
QSharedPointer<ForumPost> post = m_posts.at(index.row());
|
||||
|
||||
if(role == Qt::DisplayRole) {
|
||||
switch(index.column()) {
|
||||
case Title:
|
||||
return post->title;
|
||||
case Author:
|
||||
return post->author;
|
||||
case Comments:
|
||||
return QString::number(post->comments);
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
else if (role == Qt::TextAlignmentRole) {
|
||||
switch(index.column()) {
|
||||
case Comments:
|
||||
return Qt::AlignRight;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant ForumModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole) {
|
||||
return QVariant();
|
||||
}
|
||||
if (orientation == Qt::Horizontal)
|
||||
{
|
||||
switch(section) {
|
||||
case Title:
|
||||
return QString("Forum Post");
|
||||
case Author:
|
||||
return QString("Author");
|
||||
case Comments:
|
||||
return QString("Comments");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QSharedPointer<ForumPost> ForumModel::post(int row) {
|
||||
if (row < 0 || row >= m_posts.size()) {
|
||||
qCritical("%s: no forum post for index %d", __FUNCTION__, row);
|
||||
return QSharedPointer<ForumPost>();
|
||||
}
|
||||
|
||||
return m_posts.at(row);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#ifndef WOWLET_FORUMMODEL_H
|
||||
#define WOWLET_FORUMMODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include "widgets/ForumPost.h"
|
||||
|
||||
class ForumModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ModelColumn
|
||||
{
|
||||
Title = 0,
|
||||
Author,
|
||||
Comments,
|
||||
COUNT
|
||||
};
|
||||
|
||||
explicit ForumModel(QObject *parent);
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
int columnCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
|
||||
void clear();
|
||||
void updatePosts(const QList<QSharedPointer<ForumPost>>& posts);
|
||||
|
||||
QSharedPointer<ForumPost> post(int row);
|
||||
|
||||
private:
|
||||
QList<QSharedPointer<ForumPost>> m_posts;
|
||||
};
|
||||
|
||||
#endif //WOWLET_FORUMMODEL_H
|
||||
@@ -64,8 +64,6 @@ void SendWidget::addressEdited() {
|
||||
if (outputs.size() > 0) {
|
||||
ui->lineAmount->setText(WalletManager::displayAmount(ui->lineAddress->getTotal()));
|
||||
ui->comboCurrencySelection->setCurrentIndex(0);
|
||||
} else {
|
||||
ui->lineAmount->setText("");
|
||||
}
|
||||
|
||||
ui->btn_openAlias->setVisible(ui->lineAddress->isOpenAlias());
|
||||
|
||||
@@ -21,6 +21,10 @@ Settings::Settings(QWidget *parent) :
|
||||
|
||||
connect(ui->btnCopyToClipboard, &QPushButton::clicked, this, &Settings::copyToClipboard);
|
||||
connect(ui->checkBox_externalLink, &QCheckBox::clicked, this, &Settings::checkboxExternalLinkWarn);
|
||||
connect(ui->checkBox_hideFiatBalance, &QCheckBox::toggled, [this](bool toggled){
|
||||
config()->set(Config::hideFiatBalance, toggled);
|
||||
m_ctx->updateBalance();
|
||||
});
|
||||
connect(ui->checkBox_hideBalance, &QCheckBox::toggled, [this](bool toggled){
|
||||
config()->set(Config::hideBalance, toggled);
|
||||
m_ctx->updateBalance();
|
||||
@@ -47,6 +51,9 @@ Settings::Settings(QWidget *parent) :
|
||||
connect(ui->comboBox_blockExplorer, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_blockExplorerChanged);
|
||||
connect(ui->comboBox_redditFrontend, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_redditFrontendChanged);
|
||||
|
||||
// setup reddit combobox
|
||||
ui->comboBox_redditFrontend->setCurrentText(config()->get(Config::redditFrontend).toString());
|
||||
|
||||
// setup preferred fiat currency combobox
|
||||
QStringList fiatCurrencies;
|
||||
for (int index = 0; index < ui->comboBox_fiatCurrency->count(); index++)
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_hideBalance">
|
||||
<property name="text">
|
||||
<string>Hide balance</string>
|
||||
<string>Hide balances</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -191,6 +191,13 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_hideFiatBalance">
|
||||
<property name="text">
|
||||
<string>Hide fiat balance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_node">
|
||||
|
||||
@@ -22,7 +22,7 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
|
||||
{Config::warnOnStagenet,{QS("warnOnStagenet"), true}},
|
||||
{Config::warnOnTestnet,{QS("warnOnTestnet"), true}},
|
||||
{Config::warnOnAlpha,{QS("warnOnAlpha"), true}},
|
||||
{Config::homeWidget,{QS("homeWidget"), "ccs"}},
|
||||
{Config::homeWidget,{QS("homeWidget"), 0}},
|
||||
{Config::donateBeg,{QS("donateBeg"), 1}},
|
||||
{Config::skin,{QS("skin"), "light"}},
|
||||
{Config::openVRSkin,{QS("openVRSkin"), "default"}},
|
||||
@@ -46,8 +46,11 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
|
||||
{Config::windowState, {QS("windowState"), {}}},
|
||||
{Config::firstRun,{QS("firstRun"), false}},
|
||||
{Config::hideBalance, {QS("hideBalance"), false}},
|
||||
{Config::hideFiatBalance, {QS("hideFiatBalance"), false}},
|
||||
{Config::redditFrontend, {QS("redditFrontend"), "old.reddit.com"}},
|
||||
{Config::showHistorySyncNotice, {QS("showHistorySyncNotice"), true}}
|
||||
{Config::showHistorySyncNotice, {QS("showHistorySyncNotice"), true}},
|
||||
{Config::ignoreUpdateWarning, {QS("ignoreUpdateWarning"), ""}},
|
||||
{Config::suchWowTipAmount, {QS("suchWowTipAmount"), 0.75}}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -48,8 +48,11 @@ public:
|
||||
windowState,
|
||||
firstRun,
|
||||
hideBalance,
|
||||
hideFiatBalance,
|
||||
redditFrontend,
|
||||
showHistorySyncNotice
|
||||
showHistorySyncNotice,
|
||||
ignoreUpdateWarning,
|
||||
suchWowTipAmount
|
||||
};
|
||||
|
||||
~Config() override;
|
||||
|
||||
@@ -16,6 +16,7 @@ void UtilsNetworking::setUserAgent(const QString &userAgent) {
|
||||
}
|
||||
|
||||
void UtilsNetworking::get(const QString &url) {
|
||||
busy = true;
|
||||
QNetworkRequest request;
|
||||
request.setUrl(QUrl(url));
|
||||
request.setRawHeader("User-Agent", m_userAgent.toUtf8());
|
||||
@@ -26,6 +27,7 @@ void UtilsNetworking::get(const QString &url) {
|
||||
}
|
||||
|
||||
QNetworkReply* UtilsNetworking::getJson(const QString &url) {
|
||||
busy = true;
|
||||
QNetworkRequest request;
|
||||
request.setUrl(QUrl(url));
|
||||
request.setRawHeader("User-Agent", m_userAgent.toUtf8());
|
||||
@@ -35,6 +37,7 @@ QNetworkReply* UtilsNetworking::getJson(const QString &url) {
|
||||
}
|
||||
|
||||
QNetworkReply* UtilsNetworking::postJson(const QString &url, const QJsonObject &data) {
|
||||
busy = true;
|
||||
QNetworkRequest request;
|
||||
request.setUrl(QUrl(url));
|
||||
request.setRawHeader("User-Agent", m_userAgent.toUtf8());
|
||||
@@ -61,6 +64,8 @@ void UtilsNetworking::webResponse(QNetworkReply *reply) {
|
||||
emit webErrorReceived(err);
|
||||
else
|
||||
emit webReceived(data);
|
||||
|
||||
busy = false;
|
||||
}
|
||||
|
||||
QString UtilsNetworking::validateJSON(QNetworkReply *reply){
|
||||
|
||||
@@ -26,6 +26,8 @@ public:
|
||||
void setUserAgent(const QString &userAgent);
|
||||
static QString validateJSON(QNetworkReply *reply);
|
||||
|
||||
bool busy = false;
|
||||
|
||||
private slots:
|
||||
void webResponse(QNetworkReply *reply);
|
||||
|
||||
|
||||
@@ -41,7 +41,9 @@ void Prices::cryptoPricesReceived(const QJsonArray &data) {
|
||||
ms.symbol = obj.value("symbol").toString().toUpper();
|
||||
ms.image = obj.value("image").toString();
|
||||
ms.name = obj.value("name").toString();
|
||||
ms.price_usd = obj.value("current_price").toDouble();
|
||||
ms.price_usd = obj.value("current_price").toDouble(0);
|
||||
ms.price_btc = obj.value("current_price_btc").toDouble(0.0);
|
||||
ms.price_sat = obj.value("current_price_satoshi").toInt(0);
|
||||
ms.price_usd_change_pct_24h = obj.value("price_change_percentage_24h").toDouble();
|
||||
|
||||
if(ms.price_usd <= 0) continue;
|
||||
|
||||
@@ -15,6 +15,8 @@ struct marketStruct {
|
||||
QString name;
|
||||
QString image;
|
||||
double price_usd;
|
||||
double price_btc;
|
||||
uint price_sat;
|
||||
double price_usd_change_pct_24h;
|
||||
};
|
||||
|
||||
|
||||
@@ -256,11 +256,14 @@ QStandardItem *Utils::qStandardItem(const QString& text, QFont &font) {
|
||||
}
|
||||
|
||||
QString Utils::getUnixAccountName() {
|
||||
#ifdef __ANDROID__
|
||||
return "";
|
||||
#endif
|
||||
QString accountName = qgetenv("USER"); // mac/linux
|
||||
if (accountName.isEmpty())
|
||||
accountName = qgetenv("USERNAME"); // Windows
|
||||
if (accountName.isEmpty())
|
||||
throw std::runtime_error("Could derive system account name from env vars: USER or USERNAME");
|
||||
throw std::runtime_error("Could not derive system account name from env vars: USER or USERNAME");
|
||||
return accountName;
|
||||
}
|
||||
|
||||
@@ -431,6 +434,16 @@ int Utils::maxLength(const QVector<QString> &array) {
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
bool Utils::versionOutdated(const QString ¤t_version, const QString &newest_version) {
|
||||
// True when major or minor version changed
|
||||
auto cver = current_version.split('.');
|
||||
auto nver = newest_version.split('.');
|
||||
int cverlist[] = {cver.at(0).toInt(), cver.at(1).toInt()};
|
||||
int nverlist[] = {nver.at(0).toInt(), nver.at(1).toInt()};
|
||||
if(cverlist[0] < nverlist[0] || cverlist[1] < nverlist[1]) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
QString Utils::balanceFormat(quint64 balance) {
|
||||
QString str = QString::number(balance / globals::cdiv, 'f', 4);
|
||||
|
||||
@@ -454,4 +467,27 @@ QTextCharFormat Utils::addressTextFormat(const SubaddressIndex &index) {
|
||||
return rec;
|
||||
}
|
||||
return QTextCharFormat();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
bool Utils::androidAskPermissions(const QVector<QString> &permissions) {
|
||||
bool rtn = true;
|
||||
if(QtAndroid::androidSdkVersion() >= 23) {
|
||||
for(const QString &permission : permissions) {
|
||||
auto result = QtAndroid::checkPermission(permission);
|
||||
if(result != QtAndroid::PermissionResult::Granted) {
|
||||
auto resultHash = QtAndroid::requestPermissionsSync(QStringList({permission}));
|
||||
if(resultHash[permission] != QtAndroid::PermissionResult::Granted) {
|
||||
qDebug() << "Fail to get permission" << permission;
|
||||
rtn = false;
|
||||
} else {
|
||||
qDebug() << "Permission" << permission << "granted!";
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Permission" << permission << "already granted!";
|
||||
}
|
||||
}
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
#endif
|
||||
@@ -8,6 +8,9 @@
|
||||
#include <QStandardItemModel>
|
||||
#include <QApplication>
|
||||
#include <QTextCharFormat>
|
||||
#ifdef __ANDROID__
|
||||
#include <QtAndroid>
|
||||
#endif
|
||||
|
||||
#include <monero_seed/monero_seed.hpp>
|
||||
|
||||
@@ -78,12 +81,16 @@ public:
|
||||
static QMap<QString, QLocale> localeCache;
|
||||
static QString balanceFormat(quint64 balance);
|
||||
static QTextCharFormat addressTextFormat(const SubaddressIndex &index);
|
||||
static bool versionOutdated(const QString ¤t_version, const QString &newest_version);
|
||||
|
||||
template<typename QEnum>
|
||||
static QString QtEnumToString (const QEnum value)
|
||||
{
|
||||
static QString QtEnumToString (const QEnum value) {
|
||||
return QString::fromStdString(std::string(QMetaEnum::fromType<QEnum>().valueToKey(value)));
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
static bool androidAskPermissions(const QVector<QString> &permissions);
|
||||
#endif
|
||||
};
|
||||
|
||||
class AppContext; // forward declaration
|
||||
|
||||
@@ -184,31 +184,33 @@ namespace wowletvr {
|
||||
|
||||
auto results = m_qrDecoder.decodePNG(path);
|
||||
auto result = wowletvr::WowletVR::checkQRScreenshotResults(results);
|
||||
qDebug() << "no initial results";
|
||||
qDebug() << "QR code try #1: " << result;
|
||||
if(result.isEmpty()) {
|
||||
qDebug() << "trying to invert the image";
|
||||
// lets try to invert the image
|
||||
QImage image(path);
|
||||
image.invertPixels();
|
||||
image.save(pathPreview);
|
||||
results = m_qrDecoder.decodePNG(pathPreview);
|
||||
result = wowletvr::WowletVR::checkQRScreenshotResults(results);
|
||||
if(!result.isEmpty()) {
|
||||
qDebug() << "Found QR code after inverting the image.";
|
||||
qDebug() << "QR code try #2: " << result;
|
||||
}
|
||||
|
||||
if(!result.isEmpty()) {
|
||||
qDebug() << "QR code decoded, trying address validation.";
|
||||
|
||||
if(result.toLower().startsWith("wownero:"))
|
||||
result = result.remove(0, 8);
|
||||
|
||||
if(WalletManager::addressValid(result, NetworkType::MAINNET)) {
|
||||
qDebug() << "QR code appears valid.";
|
||||
emit qrScreenshotSuccess(result);
|
||||
QFile file (path);
|
||||
QFile file(path);
|
||||
file.remove();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "QR code found.";
|
||||
emit qrScreenshotSuccess(result);
|
||||
QFile file (path);
|
||||
file.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
emit qrScreenshotSuccess("No QR code could be detected.");
|
||||
emit qrScreenshotFailed("No QR code could be detected.");
|
||||
}
|
||||
|
||||
QString WowletVR::checkQRScreenshotResults(std::vector<std::string> results) {
|
||||
|
||||
@@ -51,13 +51,9 @@ ColumnLayout {
|
||||
function onQrScreenshotSuccess(address) {
|
||||
root.takingScreenshot = false;
|
||||
console.log("onPinLookupReceived", address);
|
||||
if(!address.startsWith("wownero:")) {
|
||||
messagePopup.showMessage("Invalid QR code", "QR data did not start with \"wownero:\"");
|
||||
return;
|
||||
}
|
||||
|
||||
if(sendStateView.currentView === sendStateView.qrPage) {
|
||||
sendStateController.destinationAddress = address.slice(8);
|
||||
sendStateController.destinationAddress = address;
|
||||
sendStateView.state = "transferPage";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#ifndef WOWLET_FORUMPOST_H
|
||||
#define WOWLET_FORUMPOST_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
struct ForumPost {
|
||||
ForumPost(const QString &title, const QString &author, const QString &permalink, int comments)
|
||||
: title(title), author(author), permalink(permalink), comments(comments){};
|
||||
|
||||
QString title;
|
||||
QString author;
|
||||
QString permalink;
|
||||
int comments;
|
||||
};
|
||||
|
||||
#endif //WOWLET_FORUMPOST_H
|
||||
@@ -0,0 +1,74 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#include <QStandardItemModel>
|
||||
#include <QTableWidget>
|
||||
#include <QDesktopServices>
|
||||
|
||||
#include "model/ForumModel.h"
|
||||
#include "forumwidget.h"
|
||||
#include "ui_forumwidget.h"
|
||||
#include "utils/utils.h"
|
||||
#include "utils/config.h"
|
||||
|
||||
ForumWidget::ForumWidget(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::ForumWidget),
|
||||
m_model(new ForumModel(this)),
|
||||
m_contextMenu(new QMenu(this))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->tableView->setModel(m_model);
|
||||
this->setupTable();
|
||||
|
||||
m_contextMenu->addAction("View thread", this, &ForumWidget::linkClicked);
|
||||
m_contextMenu->addAction("Copy link", this, &ForumWidget::copyUrl);
|
||||
connect(ui->tableView, &QHeaderView::customContextMenuRequested, this, &ForumWidget::showContextMenu);
|
||||
|
||||
connect(ui->tableView, &QTableView::doubleClicked, this, &ForumWidget::linkClicked);
|
||||
|
||||
ui->tableView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
}
|
||||
|
||||
ForumModel* ForumWidget::model() {
|
||||
return m_model;
|
||||
}
|
||||
|
||||
void ForumWidget::linkClicked() {
|
||||
QModelIndex index = ui->tableView->currentIndex();
|
||||
auto post = m_model->post(index.row());
|
||||
|
||||
if (post)
|
||||
Utils::externalLinkWarning(this, post->permalink);
|
||||
}
|
||||
|
||||
void ForumWidget::copyUrl() {
|
||||
QModelIndex index = ui->tableView->currentIndex();
|
||||
auto post = m_model->post(index.row());
|
||||
|
||||
if (post) {
|
||||
Utils::copyToClipboard(post->permalink);
|
||||
emit setStatusText("Link copied to clipboard", true, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
void ForumWidget::setupTable() {
|
||||
ui->tableView->verticalHeader()->setVisible(false);
|
||||
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
|
||||
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
ui->tableView->horizontalHeader()->setSectionResizeMode( 0, QHeaderView::Stretch);
|
||||
}
|
||||
|
||||
void ForumWidget::showContextMenu(const QPoint &pos) {
|
||||
QModelIndex index = ui->tableView->indexAt(pos);
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_contextMenu->exec(ui->tableView->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
ForumWidget::~ForumWidget() {
|
||||
delete ui;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#ifndef FORUMWIDGET_H
|
||||
#define FORUMWIDGET_H
|
||||
|
||||
#include <QMenu>
|
||||
#include <QWidget>
|
||||
#include <QItemSelection>
|
||||
|
||||
#include "model/ForumModel.h"
|
||||
|
||||
namespace Ui {
|
||||
class ForumWidget;
|
||||
}
|
||||
|
||||
class ForumWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ForumWidget(QWidget *parent = nullptr);
|
||||
~ForumWidget();
|
||||
ForumModel* model();
|
||||
|
||||
public slots:
|
||||
void linkClicked();
|
||||
|
||||
signals:
|
||||
void setStatusText(const QString &msg, bool override, int timeout);
|
||||
|
||||
private:
|
||||
void setupTable();
|
||||
void showContextMenu(const QPoint &pos);
|
||||
void copyUrl();
|
||||
|
||||
Ui::ForumWidget *ui;
|
||||
ForumModel* const m_model;
|
||||
QMenu *m_contextMenu;
|
||||
};
|
||||
|
||||
#endif // FORUMWIDGET_H
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ForumWidget</class>
|
||||
<widget class="QWidget" name="ForumWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>492</width>
|
||||
<height>409</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<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="QTableView" name="tableView">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<slots>
|
||||
<slot>linkClicked()</slot>
|
||||
</slots>
|
||||
</ui>
|
||||
@@ -80,12 +80,7 @@ void NodeWidget::showContextMenu(const QPoint &pos, const WowletNode &node) {
|
||||
}
|
||||
|
||||
void NodeWidget::onContextConnect() {
|
||||
QObject *obj = sender();
|
||||
if (obj == ui->customView)
|
||||
m_activeView = ui->customView;
|
||||
else
|
||||
m_activeView = ui->wsView;
|
||||
|
||||
//QObject *obj = sender();
|
||||
WowletNode node = this->selectedNode();
|
||||
if (!node.full.isEmpty())
|
||||
emit connectToNode(node);
|
||||
|
||||
@@ -47,6 +47,16 @@ SuchWowWidget::SuchWowWidget(QWidget *parent) :
|
||||
m_contextMenu->addAction("Donate", this, &SuchWowWidget::suchDonate);
|
||||
|
||||
connect(ui->listWidget, &QListWidget::customContextMenuRequested, this, &SuchWowWidget::showContextMenu);
|
||||
|
||||
// tip amount slider
|
||||
ui->slider_tipAmount->setMinimum(1);
|
||||
ui->slider_tipAmount->setMaximum(60);
|
||||
ui->slider_tipAmount->setTickInterval(1);
|
||||
ui->slider_tipAmount->setSingleStep(1);
|
||||
double tipAmount = config()->get(Config::suchWowTipAmount).toDouble();
|
||||
ui->slider_tipAmount->setValue((int)(tipAmount * 10));
|
||||
connect(ui->slider_tipAmount, &QSlider::valueChanged, this, &SuchWowWidget::onTipSliderChanged);
|
||||
this->setTipAmountLabel();
|
||||
}
|
||||
|
||||
void SuchWowWidget::setupTable() {
|
||||
@@ -57,31 +67,33 @@ void SuchWowWidget::setupTable() {
|
||||
}
|
||||
|
||||
void SuchWowWidget::onWS(QJsonArray such_data) {
|
||||
if(this->m_rendered) return; // only draw once
|
||||
if(this->m_ctx == nullptr) {
|
||||
if(this->m_ctx == nullptr)
|
||||
m_ctx = MainWindow::getContext();
|
||||
}
|
||||
|
||||
for (auto &&such_post: such_data) {
|
||||
auto obj = such_post.toObject();
|
||||
auto s = new SuchWowPost(m_ctx, this);
|
||||
s->added_by = obj.value("added_by").toString();
|
||||
s->addy = obj.value("addy").toString();
|
||||
s->title = obj.value("title").toString();
|
||||
s->img = obj.value("img").toString();
|
||||
s->thumb = obj.value("thumb").toString();
|
||||
s->href = obj.value("href").toString();
|
||||
m_posts.push_back(s);
|
||||
auto uid = obj.value("id").toInt();
|
||||
if(m_lookup.contains(uid)) continue;
|
||||
|
||||
connect(s, &SuchWowPost::thumbReceived, this, &SuchWowWidget::addThumb);
|
||||
s->download_thumb();
|
||||
s->download_img();
|
||||
auto post = new SuchWowPost(m_ctx, this);
|
||||
post->added_by = obj.value("added_by").toString();
|
||||
post->addy = obj.value("addy").toString();
|
||||
post->title = obj.value("title").toString();
|
||||
post->img = obj.value("img").toString();
|
||||
post->thumb = obj.value("thumb").toString();
|
||||
post->href = obj.value("href").toString();;
|
||||
post->uid = uid;
|
||||
|
||||
m_lookup[post->uid] = post;
|
||||
connect(post, &SuchWowPost::thumbReceived, this, &SuchWowWidget::addThumb);
|
||||
post->download_thumb();
|
||||
}
|
||||
}
|
||||
|
||||
void SuchWowWidget::addThumb(SuchWowPost *test) {
|
||||
auto *item = new QListWidgetItem(QIcon(test->thumb_data), test->title);
|
||||
void SuchWowWidget::addThumb(SuchWowPost *post) {
|
||||
auto *item = new SuchWidgetItem(QIcon(post->thumb_data), post->title, post);
|
||||
ui->listWidget->addItem(item);
|
||||
ui->listWidget->sortItems();
|
||||
}
|
||||
|
||||
void SuchWowWidget::showContextMenu(const QPoint &pos) {
|
||||
@@ -95,12 +107,18 @@ void SuchWowWidget::suchImage() {
|
||||
auto *post = this->itemToPost();
|
||||
if(post == nullptr)
|
||||
return;
|
||||
if(!post->img_data) {
|
||||
QMessageBox::warning(this, "wh00pz", "Image not dowloaded yet.");
|
||||
|
||||
if(!post->img_data && !post->isFetchingImage()) {
|
||||
connect(post, &SuchWowPost::imgReceived, this, &SuchWowWidget::showImage);
|
||||
post->download_img();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto title = QString("%1 - %2").arg(post->title).arg(post->added_by);
|
||||
this->showImage(post);
|
||||
}
|
||||
|
||||
void SuchWowWidget::showImage(SuchWowPost *post) {
|
||||
const auto title = QString("%1 - %2").arg(post->title, post->added_by);
|
||||
QMessageBox mb(title, "",
|
||||
QMessageBox::NoIcon,
|
||||
QMessageBox::Ok,
|
||||
@@ -119,14 +137,33 @@ void SuchWowWidget::suchDonate() {
|
||||
SuchWowPost *SuchWowWidget::itemToPost() {
|
||||
QListWidgetItem *item = ui->listWidget->currentItem();
|
||||
QString title = item->text();
|
||||
for(auto &post: m_posts){
|
||||
if(post->title == title) {
|
||||
return post;
|
||||
}
|
||||
|
||||
for(const auto &such_key: m_lookup.keys()) {
|
||||
if(m_lookup[such_key]->title == title)
|
||||
return m_lookup[such_key];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SuchWowWidget::setTipAmountLabel(double tipAmount) {
|
||||
if(tipAmount == 0.0)
|
||||
tipAmount = config()->get(Config::suchWowTipAmount).toDouble();
|
||||
|
||||
QString amount_fmt = Utils::amountToCurrencyString(tipAmount, config()->get(Config::preferredFiatCurrency).toString());
|
||||
ui->label_tipAmount->setText(QString("Default tip amount (%1)").arg(amount_fmt));
|
||||
}
|
||||
|
||||
void SuchWowWidget::onTipSliderChanged(int value) {
|
||||
double amount = (double)value / 10;
|
||||
config()->set(Config::suchWowTipAmount, amount);
|
||||
setTipAmountLabel(amount);
|
||||
}
|
||||
|
||||
void SuchWowWidget::onPreferredFiatCurrencyChanged(const QString &symbol) {
|
||||
this->setTipAmountLabel();
|
||||
}
|
||||
|
||||
SuchWowWidget::~SuchWowWidget() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
#ifndef SUCHWOWWIDGET_H
|
||||
#define SUCHWOWWIDGET_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QMenu>
|
||||
#include <QWidget>
|
||||
#include <QItemSelection>
|
||||
#include <QListWidgetItem>
|
||||
|
||||
#include "utils/networking.h"
|
||||
#include "appcontext.h"
|
||||
@@ -15,7 +17,6 @@ namespace Ui {
|
||||
class SuchWowWidget;
|
||||
}
|
||||
|
||||
|
||||
class SuchWowPost : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -30,31 +31,33 @@ public:
|
||||
QString img;
|
||||
QString addy;
|
||||
QString href;
|
||||
uint uid;
|
||||
|
||||
QPixmap thumb_data;
|
||||
QPixmap img_data;
|
||||
|
||||
void download_thumb() {
|
||||
const QString url = QString("%1/%2").arg(m_weburl).arg(this->thumb);
|
||||
qDebug() << url;
|
||||
const QString url = QString("%1/%2").arg(m_weburl, this->thumb);
|
||||
connect(m_networkThumb, &UtilsNetworking::webReceived, this, &SuchWowPost::onThumbReceived);
|
||||
m_networkThumb->get(url);
|
||||
}
|
||||
|
||||
void download_img() {
|
||||
const QString url = QString("%1/%2").arg(m_weburl).arg(this->img);
|
||||
qDebug() << url;
|
||||
const QString url = QString("%1/%2").arg(m_weburl, this->img);
|
||||
connect(m_networkImg, &UtilsNetworking::webReceived, this, &SuchWowPost::onImgReceived);
|
||||
m_networkImg->get(url);
|
||||
}
|
||||
|
||||
bool isFetchingImage() { return m_networkImg->busy; }
|
||||
bool isFetchingThumb() { return m_networkThumb->busy; }
|
||||
|
||||
private slots:
|
||||
void onThumbReceived(QByteArray data);
|
||||
void onImgReceived(QByteArray data);
|
||||
|
||||
signals:
|
||||
void imgReceived(SuchWowPost *test);
|
||||
void thumbReceived(SuchWowPost *test);
|
||||
void imgReceived(SuchWowPost *post);
|
||||
void thumbReceived(SuchWowPost *post);
|
||||
|
||||
private:
|
||||
QString m_weburl;
|
||||
@@ -73,26 +76,47 @@ public:
|
||||
|
||||
public slots:
|
||||
void onWS(QJsonArray such_data);
|
||||
void onPreferredFiatCurrencyChanged(const QString &symbol);
|
||||
|
||||
private slots:
|
||||
void addThumb(SuchWowPost *test);
|
||||
void addThumb(SuchWowPost *post);
|
||||
void showImage(SuchWowPost *post);
|
||||
void onTipSliderChanged(int value);
|
||||
|
||||
signals:
|
||||
void donate(QString donate);
|
||||
void openImage(SuchWowPost *test);
|
||||
void openImage(SuchWowPost *post);
|
||||
|
||||
private:
|
||||
void setupTable();
|
||||
void suchDonate();
|
||||
void suchImage();
|
||||
void setTipAmountLabel(double tipAmount = 0.0);
|
||||
SuchWowPost* itemToPost();
|
||||
void showContextMenu(const QPoint &pos);
|
||||
|
||||
bool m_rendered = false; // because we're too lazy to re-render on changes.
|
||||
QMap<uint, SuchWowPost*> m_lookup;
|
||||
Ui::SuchWowWidget *ui;
|
||||
QList<SuchWowPost*> m_posts;
|
||||
AppContext *m_ctx = nullptr;
|
||||
QMenu *m_contextMenu;
|
||||
};
|
||||
|
||||
#endif // SUCHWOWWIDGET_H
|
||||
class SuchWidgetItem : public QListWidgetItem
|
||||
{
|
||||
public:
|
||||
explicit SuchWidgetItem(const QIcon &icon, const QString &text, SuchWowPost *post, QListWidget *parent = nullptr, int type = Type) {
|
||||
this->setIcon(icon);
|
||||
this->setText(text);
|
||||
this->post = post;
|
||||
}
|
||||
|
||||
SuchWowPost *post;
|
||||
|
||||
// sort
|
||||
virtual bool operator< (const QListWidgetItem &other) const {
|
||||
auto const *_other = dynamic_cast<const SuchWidgetItem *>(&other);
|
||||
return this->post->uid > _other->post->uid;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SUCHWOWWIDGET_H
|
||||
@@ -14,24 +14,33 @@
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<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="QListWidget" name="listWidget"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_tipAmount">
|
||||
<property name="text">
|
||||
<string>Default tip amount</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSlider" name="slider_tipAmount">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>280</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
||||