diff --git a/docs/HACKING.md b/docs/HACKING.md index 6b8fe78..2b7c08e 100644 --- a/docs/HACKING.md +++ b/docs/HACKING.md @@ -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. diff --git a/src/mobile/README.md b/src/mobile/README.md new file mode 100644 index 0000000..250e21c --- /dev/null +++ b/src/mobile/README.md @@ -0,0 +1,45 @@ +# Wowlet Mobile (Android) + +This directory contains an unfinished QML application that will show: + +![https://i.imgur.com/yhCsSgj.jpg](https://i.imgur.com/yhCsSgj.jpg) + +## 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 +``` diff --git a/src/mobile/main.cpp b/src/mobile/main.cpp new file mode 100644 index 0000000..5c2a761 --- /dev/null +++ b/src/mobile/main.cpp @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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(); + qmlRegisterType("wowlet.NetworkType", 1, 0, "NetworkType"); + + qmlRegisterUncreatableType("wowlet.WalletKeysFiles", 1, 0, "WalletKeysFiles", "WalletKeysFiles can't be instantiated directly"); + qmlRegisterUncreatableType("wowlet.Wallet", 1, 0, "Wallet", "Wallet can't be instantiated directly"); + qmlRegisterType("wowlet.WalletManager", 1, 0, "WalletManager"); + + qmlRegisterUncreatableType("wowlet.TransactionHistoryProxyModel", 1, 0, "TransactionHistoryProxyModel", "TransactionHistoryProxyModel can't be instantiated directly"); + qmlRegisterUncreatableType("wowlet.TransactionHistoryModel", 1, 0, "TransactionHistoryModel", "TransactionHistoryModel can't be instantiated directly"); + qmlRegisterUncreatableType("wowlet.TransactionInfo", 1, 0, "TransactionInfo", "TransactionHistory can't be instantiated directly"); + qmlRegisterUncreatableType("wowlet.TransactionHistory", 1, 0, "TransactionHistory", "TransactionHistory can't be instantiated directly"); + + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + + 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 results) { + + } + + Mobile::~Mobile() { + // bla + int wegeg = 1; + } +} diff --git a/src/mobile/main.h b/src/mobile/main.h new file mode 100644 index 0000000..284d755 --- /dev/null +++ b/src/mobile/main.h @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#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 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 results); + }; + +} + +#endif //WOWLET_MAIN_H diff --git a/src/mobile/main.qml b/src/mobile/main.qml new file mode 100644 index 0000000..5e29737 --- /dev/null +++ b/src/mobile/main.qml @@ -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 + } +} diff --git a/src/mobile/qml.qrc b/src/mobile/qml.qrc new file mode 100644 index 0000000..5a38622 --- /dev/null +++ b/src/mobile/qml.qrc @@ -0,0 +1,5 @@ + + + main.qml + + \ No newline at end of file