Browse Source

Prepare Wowlet codebase for an Android app

pull/48/head
dsc 3 months ago
parent
commit
cfee938516
  1. 119
      src/appcontext.cpp
  2. 11
      src/appcontext.h
  3. 2
      src/libwalletqt/Wallet.cpp
  4. 42
      src/main.cpp
  5. 30
      src/utils/utils.cpp
  6. 10
      src/utils/utils.h

119
src/appcontext.cpp

@ -30,77 +30,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;
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");
this->isTails = TailsOS::detect();
this->isWhonix = WhonixOS::detect();
//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);
@ -558,12 +550,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 +943,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;
}
}

11
src/appcontext.h

@ -39,7 +39,12 @@ public:
~AppContext() override;
bool isTails = false;
bool isWhonix = false;
bool isAndroid = false;
bool isLinux = false;
bool isMac = false;
bool isWindows = false;
bool isDebug = false;
bool androidDebug = false;
// Donation config
const QString donationAddress = "Wo3MWeKwtA918DU4c69hVSNgejdWFCRCuWjShRY66mJkU2Hv58eygJWDJS1MNa2Ge5M1WjUkGHuLqHkweDxwZZU42d16v94mP";
@ -50,6 +55,7 @@ public:
QString coinName = "wownero";
bool isTorSocks = false;
QString pathGenericData;
QString homeDir;
QString accountName;
QString configRoot;
@ -215,6 +221,11 @@ private:
WalletKeysFilesModel *m_walletKeysFilesModel;
const int m_donationBoundary = 15;
QTimer m_storeTimer;
void setupPathsUnix();
void setupPathsWindows();
void setupPathsAndroid();
void setupPathsTails();
};
#endif //WOWLET_APPCONTEXT_H

2
src/libwalletqt/Wallet.cpp

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

42
src/main.cpp

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

30
src/utils/utils.cpp

@ -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;
}
@ -454,4 +457,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

10
src/utils/utils.h

@ -8,6 +8,9 @@
#include <QStandardItemModel>
#include <QApplication>
#include <QTextCharFormat>
#ifdef __ANDROID__
#include <QtAndroid>
#endif
#include <monero_seed/monero_seed.hpp>
@ -80,10 +83,13 @@ public:
static QTextCharFormat addressTextFormat(const SubaddressIndex &index);
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

Loading…
Cancel
Save