Initial Android app proof-of-concept

This commit is contained in:
dsc 2021-04-20 00:03:56 +02:00
parent cfee938516
commit 8b5bdc4c6a
6 changed files with 280 additions and 3 deletions

View file

@ -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 \ apt install -y git cmake libqrencode-dev build-essential cmake libboost-all-dev \
miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-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 \ 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 ## 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 ./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.

45
src/mobile/README.md Normal file
View file

@ -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
```

102
src/mobile/main.cpp Normal file
View file

@ -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;
}
}

92
src/mobile/main.h Normal file
View file

@ -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

35
src/mobile/main.qml Normal file
View file

@ -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
}
}

5
src/mobile/qml.qrc Normal file
View file

@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file alias="main">main.qml</file>
</qresource>
</RCC>