feat(@desktop/cpp-app): base structure for new cpp app
- applied new project structure - new cmake scripts organizations - conan script for adding gtest and boost::di - boost::di introduced - gtest introduced Fixes #4894 #4834
This commit is contained in:
parent
75a3ff858c
commit
922a38108d
|
@ -90,3 +90,9 @@ build/
|
|||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Cpp App
|
||||
*build-src-cpp-structure*
|
||||
src-cpp-structure/projects/App/translations.qrc
|
||||
src-cpp-structure/projects/App/i18n/*
|
||||
src-cpp-structure/projects/App/translations/*
|
|
@ -0,0 +1,27 @@
|
|||
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
|
||||
|
||||
project(Status DESCRIPTION "Status project" LANGUAGES CXX)
|
||||
|
||||
include("${CMAKE_SOURCE_DIR}/cmake/project-config.cmake")
|
||||
include("${CMAKE_SOURCE_DIR}/cmake/conan.cmake")
|
||||
|
||||
find_package(Qt5 REQUIRED COMPONENTS
|
||||
Core
|
||||
Gui
|
||||
Quick
|
||||
Widgets
|
||||
Qml
|
||||
Quick
|
||||
QuickControls2
|
||||
QuickTemplates2
|
||||
Multimedia
|
||||
Concurrent
|
||||
LinguistTools)
|
||||
|
||||
# The following should be moved to conan.
|
||||
# But so far we're just adding libs from the vendor folder this way.
|
||||
# statusgo lib is registered globaly - /vendor/status-go/CMakeLists.txt
|
||||
SET(STATUS_GO_LIB statusgo_shared)
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/../vendor/status-go bin/status-go)
|
||||
|
||||
add_subdirectory(projects)
|
|
@ -0,0 +1,22 @@
|
|||
add_executable(${PROJECT_NAME})
|
||||
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Widgets
|
||||
Qt5::Quick
|
||||
Qt5::Qml
|
||||
Qt5::Quick
|
||||
Qt5::QuickControls2
|
||||
Qt5::QuickTemplates2
|
||||
Qt5::Multimedia
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE SOURCES
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
${STATUS_RCC}
|
||||
${STATUS_RESOURCES_QRC}
|
||||
${STATUS_QRC}
|
||||
)
|
|
@ -0,0 +1,30 @@
|
|||
add_executable(${PROJECT_NAME} MACOSX_BUNDLE)
|
||||
|
||||
find_library(FOUNDATION_FRAMEWORK Foundation)
|
||||
find_library(IO_KIT_FRAMEWORK IOKit)
|
||||
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Widgets
|
||||
Qt5::Quick
|
||||
Qt5::Qml
|
||||
Qt5::Quick
|
||||
Qt5::QuickControls2
|
||||
Qt5::QuickTemplates2
|
||||
Qt5::Multimedia
|
||||
Qt5::Concurrent
|
||||
${FOUNDATION_FRAMEWORK}
|
||||
${IO_KIT_FRAMEWORK}
|
||||
Status.Services
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE SOURCES
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
"*.mm"
|
||||
${STATUS_RCC}
|
||||
${STATUS_RESOURCES_QRC}
|
||||
${STATUS_QRC}
|
||||
)
|
|
@ -0,0 +1,22 @@
|
|||
add_executable(${PROJECT_NAME} WIN32)
|
||||
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Widgets
|
||||
Qt5::Quick
|
||||
Qt5::Qml
|
||||
Qt5::Quick
|
||||
Qt5::QuickControls2
|
||||
Qt5::QuickTemplates2
|
||||
Qt5::Multimedia
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE SOURCES
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
${STATUS_RCC}
|
||||
${STATUS_RESOURCES_QRC}
|
||||
${STATUS_QRC}
|
||||
)
|
|
@ -0,0 +1,27 @@
|
|||
set(CONAN_WORKING_DIR ${CMAKE_BINARY_DIR}/conan)
|
||||
|
||||
if (EXISTS ${CONAN_WORKING_DIR})
|
||||
file(REMOVE_RECURSE ${CONAN_WORKING_DIR})
|
||||
endif ()
|
||||
|
||||
file(MAKE_DIRECTORY ${CONAN_WORKING_DIR})
|
||||
|
||||
if (${CMAKE_BUILD_TYPE} STREQUAL Debug)
|
||||
set(CONAN_PROFILE ${PROJECT_SOURCE_DIR}/conan-debug-profile)
|
||||
else ()
|
||||
set(CONAN_PROFILE ${PROJECT_SOURCE_DIR}/conan-release-profile)
|
||||
endif ()
|
||||
|
||||
execute_process(
|
||||
COMMAND conan install ${PROJECT_SOURCE_DIR} -pr=${CONAN_PROFILE}
|
||||
WORKING_DIRECTORY ${CONAN_WORKING_DIR}
|
||||
RESULT_VARIABLE CONAN_RESULT
|
||||
)
|
||||
|
||||
if (NOT ${CONAN_RESULT} EQUAL 0)
|
||||
message(FATAL_ERROR "Conan failed: ${CONAN_RESULT}.")
|
||||
endif ()
|
||||
|
||||
include(${CONAN_WORKING_DIR}/conanbuildinfo.cmake)
|
||||
|
||||
conan_basic_setup(KEEP_RPATHS)
|
|
@ -0,0 +1,16 @@
|
|||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
#set(CMAKE_AUTORCC ON) This is disabled because of `/ui/generate-rcc.go` script usage for generating .qrc and cmake command for .rcc
|
||||
|
||||
# Set this to TRUE if you want to create .ts files and translations.qrc
|
||||
set(UPDATE_TRANSLATIONS FALSE)
|
||||
|
||||
if ($ENV{QTDIR} LESS_EQUAL "")
|
||||
message(FATAL_ERROR "Please set the path to your Qt dir as `QTDIR` variable in your ENV. Example: QTDIR=/Qt/Qt5.14.2/5.14.2/clang_64")
|
||||
endif()
|
||||
|
||||
add_definitions(-DSTATUS_SOURCE_DIR="${CMAKE_SOURCE_DIR}")
|
||||
add_definitions(-DSTATUS_DEVELOPMENT=true)
|
|
@ -0,0 +1,10 @@
|
|||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
Qt5::Core
|
||||
Status.Backend
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE SOURCES
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
)
|
|
@ -0,0 +1,22 @@
|
|||
find_library(FOUNDATION_FRAMEWORK Foundation)
|
||||
find_library(IO_KIT_FRAMEWORK IOKit)
|
||||
find_library(SECURITY_FRAMEWORK Security)
|
||||
find_library(CORE_SERVICES_FRAMEWORK CoreServices)
|
||||
find_library(LOCAL_AUTHENTICATION_FRAMEWORK LocalAuthentication)
|
||||
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
Qt5::Core
|
||||
${FOUNDATION_FRAMEWORK}
|
||||
${IO_KIT_FRAMEWORK}
|
||||
${SECURITY_FRAMEWORK}
|
||||
${CORE_SERVICES_FRAMEWORK}
|
||||
${LOCAL_AUTHENTICATION_FRAMEWORK}
|
||||
Status.Backend
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE SOURCES
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
"*.mm"
|
||||
)
|
|
@ -0,0 +1,10 @@
|
|||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
Qt5::Core
|
||||
Status.Backend
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE SOURCES
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
)
|
|
@ -0,0 +1,36 @@
|
|||
function(check_translations)
|
||||
set(TRANSLATION_DIR "translations")
|
||||
set(TRANSLATION_BASE_FILE "app_en_US.ts")
|
||||
set(QM_RESOURCE_FILE "translations.qrc")
|
||||
set(QM_FILES_FOLDER_NAME "i18n")
|
||||
|
||||
if(NOT UPDATE_TRANSLATIONS)
|
||||
file(REMOVE ${QM_RESOURCE_FILE})
|
||||
else()
|
||||
# New translations will be added just here
|
||||
set(TS_FILES
|
||||
${TRANSLATION_DIR}/${TRANSLATION_BASE_FILE}
|
||||
${TRANSLATION_DIR}/app_es_ES.ts
|
||||
)
|
||||
|
||||
if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${TRANSLATION_DIR}/${TRANSLATION_BASE_FILE})
|
||||
|
||||
set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/${QM_FILES_FOLDER_NAME})
|
||||
qt5_create_translation(QM_FILES ${TS_FILES} ${SOURCES})
|
||||
|
||||
endif ()
|
||||
|
||||
if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${QM_RESOURCE_FILE})
|
||||
|
||||
file(WRITE ${QM_RESOURCE_FILE} "<RCC>\n <qresource prefix=\"/${QM_FILES_FOLDER_NAME}\">\n")
|
||||
|
||||
foreach(qm_file ${QM_FILES})
|
||||
get_filename_component(qm_name ${qm_file} NAME)
|
||||
file(APPEND ${QM_RESOURCE_FILE} " <file alias=\"${qm_name}\">${QM_FILES_FOLDER_NAME}/${qm_name}</file>\n")
|
||||
endforeach(qm_file)
|
||||
|
||||
file(APPEND ${QM_RESOURCE_FILE} " </qresource>\n</RCC>\n")
|
||||
|
||||
endif ()
|
||||
endif ()
|
||||
endfunction()
|
|
@ -0,0 +1,4 @@
|
|||
include(default)
|
||||
|
||||
[settings]
|
||||
build_type=Debug
|
|
@ -0,0 +1,4 @@
|
|||
include(default)
|
||||
|
||||
[settings]
|
||||
build_type=Release
|
|
@ -0,0 +1,10 @@
|
|||
from conans import ConanFile
|
||||
|
||||
class StatusConan(ConanFile):
|
||||
name = "status-desktop"
|
||||
settings = "os", "compiler", "build_type"
|
||||
generators = "cmake"
|
||||
|
||||
def requirements(self):
|
||||
self.requires("di/1.2.0")
|
||||
self.requires("gtest/1.10.0")
|
|
@ -0,0 +1,100 @@
|
|||
#include "AppController.h"
|
||||
|
||||
#include "DI.h"
|
||||
#include "../Core/Engine.h"
|
||||
#include "../Common/Utils.h"
|
||||
#include "../Global/LocalAppSettings.h"
|
||||
#include "../Global/LocalAccountSettings.h"
|
||||
|
||||
#include "AppWindow.h"
|
||||
#include "../Modules/ModuleBuilder.h"
|
||||
|
||||
#include <QtGui>
|
||||
#include <QtQml>
|
||||
//#include <QtCore> <- include for QTranslator
|
||||
|
||||
using namespace Status;
|
||||
|
||||
AppController::AppController()
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#endif
|
||||
|
||||
QGuiApplication::setOrganizationName("Status");
|
||||
QGuiApplication::setOrganizationDomain("status.im");
|
||||
QGuiApplication::setApplicationName("Status Desktop");
|
||||
|
||||
Status::Logger::init();
|
||||
Utils::ensureDirectories();
|
||||
}
|
||||
|
||||
void registerResources()
|
||||
{
|
||||
Engine::instance()->addImportPath("qrc:/./StatusQ/src");
|
||||
Engine::instance()->addImportPath("qrc:/./imports");
|
||||
Engine::instance()->addImportPath("qrc:/./app");
|
||||
|
||||
// This will be removed once we completely move to c++, it's here to align with the current qml code.
|
||||
Engine::instance()->rootContext()->setContextProperty("cppApp", true);
|
||||
Engine::instance()->rootContext()->setContextProperty("production", STATUS_DEVELOPMENT);
|
||||
|
||||
Engine::instance()->rootContext()->setContextProperty("localAppSettings", &LocalAppSettings::instance());
|
||||
Engine::instance()->rootContext()->setContextProperty("localAccountSettings", &LocalAccountSettings::instance());
|
||||
|
||||
QString statusSourceDir(STATUS_SOURCE_DIR);
|
||||
QResource::registerResource(statusSourceDir + "/../resources.rcc");
|
||||
}
|
||||
|
||||
int AppController::exec(int& argc, char** argv)
|
||||
{
|
||||
int code;
|
||||
|
||||
// Once we fully move to c++ we should include the following line instead the line below it (it's here just to align with the current qml files).
|
||||
// qmlRegisterType<AppWindow>("AppWindow", 0 , 1, "AppWindow");
|
||||
qmlRegisterType<AppWindow>("DotherSide", 0 , 1, "StatusWindow");
|
||||
|
||||
try
|
||||
{
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
// This is here just to check loading translation on the cmake side,
|
||||
// will be handled much better later.
|
||||
//
|
||||
// QTranslator translator;
|
||||
// const QString baseName = "app_es_ES";
|
||||
// if (translator.load(baseName, QLatin1String(":/i18n"))){
|
||||
// app.installTranslator(&translator);
|
||||
// }
|
||||
|
||||
auto rootModule = Injector.create<Modules::ModuleBuilder>()();
|
||||
rootModule->load();
|
||||
|
||||
registerResources();
|
||||
|
||||
QString qmlFile = QStringLiteral("qrc:/main.qml");
|
||||
Engine::create(qmlFile);
|
||||
QObject::connect(Engine::instance(), &Engine::objectCreated, &app,
|
||||
[url = qmlFile](QObject* obj, const QUrl& objUrl) {
|
||||
if(!obj && url == objUrl.toString())
|
||||
{
|
||||
auto err = "Failed to create: " + url;
|
||||
throw std::runtime_error(err.toStdString());
|
||||
}
|
||||
});
|
||||
|
||||
code = app.exec();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
fprintf(stderr, "error: %s\n", e.what());
|
||||
code = -1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
fprintf(stderr, "unknown error\n");
|
||||
code = -1;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
namespace Status
|
||||
{
|
||||
class AppController final
|
||||
{
|
||||
public:
|
||||
|
||||
AppController();
|
||||
int exec(int& argc, char** argv);
|
||||
};
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
#include "AppWindow.h"
|
||||
|
||||
using namespace Status;
|
||||
|
||||
AppWindow::AppWindow(QWindow *parent)
|
||||
: QQuickWindow(parent),
|
||||
m_isFullScreen(false)
|
||||
{
|
||||
removeTitleBar();
|
||||
|
||||
connect(this, &QQuickWindow::windowStateChanged, [&](Qt::WindowState windowState) {
|
||||
if (windowState == Qt::WindowNoState) {
|
||||
removeTitleBar();
|
||||
m_isFullScreen = false;
|
||||
emit isFullScreenChanged();
|
||||
} else if (windowState == Qt::WindowFullScreen) {
|
||||
m_isFullScreen = true;
|
||||
emit isFullScreenChanged();
|
||||
showTitleBar();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void AppWindow::toggleFullScreen()
|
||||
{
|
||||
if (m_isFullScreen) {
|
||||
showNormal();
|
||||
} else {
|
||||
showFullScreen();
|
||||
}
|
||||
}
|
||||
|
||||
bool AppWindow::isFullScreen() const
|
||||
{
|
||||
return m_isFullScreen;
|
||||
}
|
||||
|
||||
void AppWindow::removeTitleBar()
|
||||
{
|
||||
#ifdef Q_OS_MACOS
|
||||
removeTitleBarMacOs();
|
||||
#endif
|
||||
}
|
||||
|
||||
void AppWindow::showTitleBar()
|
||||
{
|
||||
#ifdef Q_OS_MACOS
|
||||
showTitleBarMacOs();
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtQuick>
|
||||
|
||||
namespace Status
|
||||
{
|
||||
class AppWindow: public QQuickWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/***********************************************
|
||||
* Not Refactored, Just Taken From DOtherSide
|
||||
***********************************************/
|
||||
|
||||
Q_PROPERTY(bool isFullScreen READ isFullScreen NOTIFY isFullScreenChanged)
|
||||
|
||||
public:
|
||||
|
||||
explicit AppWindow(QWindow *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void toggleFullScreen();
|
||||
|
||||
bool isFullScreen() const;
|
||||
|
||||
Q_INVOKABLE void updatePosition() {
|
||||
auto point = QPoint(screen()->geometry().center().x() - geometry().width() / 2,
|
||||
screen()->geometry().center().y() - geometry().height() / 2);
|
||||
if (point != this->position()) {
|
||||
this->setPosition(point);
|
||||
}
|
||||
}
|
||||
|
||||
signals:
|
||||
void isFullScreenChanged();
|
||||
void secondInstanceDetected();
|
||||
|
||||
private:
|
||||
void initCallbacks();
|
||||
void removeTitleBar();
|
||||
void showTitleBar();
|
||||
#ifdef Q_OS_MACOS
|
||||
void removeTitleBarMacOs();
|
||||
void showTitleBarMacOs();
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool m_isFullScreen;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#include "AppWindow.h"
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <AppKit/NSView.h>
|
||||
#include <AppKit/NSWindow.h>
|
||||
#include <AppKit/NSColor.h>
|
||||
#include <AppKit/NSToolbar.h>
|
||||
#include <AppKit/NSButton.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
|
||||
using namespace Status;
|
||||
|
||||
void AppWindow::removeTitleBarMacOs()
|
||||
{
|
||||
NSView *nsView = reinterpret_cast<NSView*>(this->winId());
|
||||
NSWindow *window = [nsView window];
|
||||
|
||||
window.titlebarAppearsTransparent = true;
|
||||
window.titleVisibility = NSWindowTitleHidden;
|
||||
window.styleMask |= NSWindowStyleMaskFullSizeContentView;
|
||||
NSButton* close = [window standardWindowButton:NSWindowCloseButton];
|
||||
NSView* titleBarContainerView = close.superview.superview;
|
||||
[titleBarContainerView setHidden:YES];
|
||||
}
|
||||
|
||||
void AppWindow::showTitleBarMacOs()
|
||||
{
|
||||
NSView *nsView = reinterpret_cast<NSView*>(this->winId());
|
||||
NSWindow *window = [nsView window];
|
||||
|
||||
window.titlebarAppearsTransparent = true;
|
||||
window.titleVisibility = NSWindowTitleHidden;
|
||||
window.styleMask |= NSWindowStyleMaskFullSizeContentView;
|
||||
NSButton* close = [window standardWindowButton:NSWindowCloseButton];
|
||||
NSView* titleBarContainerView = close.superview.superview;
|
||||
[titleBarContainerView setHidden:NO];
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <StatusServices/Accounts/Service.h>
|
||||
#include <StatusServices/WalletAccounts/Service.h>
|
||||
#include <StatusServices/Keychain/Service.h>
|
||||
|
||||
#include <boost/di.hpp>
|
||||
|
||||
namespace Status
|
||||
{
|
||||
using namespace boost::di;
|
||||
|
||||
const auto Injector = make_injector(
|
||||
bind<Accounts::ServiceInterface>.to<Accounts::Service>(),
|
||||
bind<WalletAccount::ServiceInterface>.to<WalletAccount::Service>(),
|
||||
bind<Keychain::ServiceInterface>.to<Keychain::Service>()
|
||||
);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#include "AppController.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return Status::AppController().exec(argc, argv);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
|
||||
|
||||
project(Status.App DESCRIPTION "Main Status App Project")
|
||||
|
||||
include("${CMAKE_SOURCE_DIR}/cmake/translation.cmake")
|
||||
|
||||
# Building resource.rcc from multiple .qrc files
|
||||
SET(STATUS_RCC ${CMAKE_SOURCE_DIR}/../resources.rcc)
|
||||
SET(STATUS_QRC_SOURCE ${CMAKE_SOURCE_DIR}/../ui)
|
||||
SET(STATUS_QRC ${STATUS_QRC_SOURCE}/resources.qrc)
|
||||
SET(STATUS_RESOURCES_QRC ${CMAKE_SOURCE_DIR}/../resources/resources.qrc)
|
||||
|
||||
add_custom_target(rcc ALL DEPENDS resources.rcc)
|
||||
add_custom_command(
|
||||
OUTPUT resources.rcc
|
||||
COMMENT "Building resources.rcc"
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -f ${STATUS_RCC}
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -f ${STATUS_QRC}
|
||||
COMMAND go run ${CMAKE_SOURCE_DIR}/../ui/generate-rcc.go -source=${STATUS_QRC_SOURCE} -output=${STATUS_QRC}
|
||||
COMMAND rcc -binary --no-compress ${STATUS_QRC} ${STATUS_RESOURCES_QRC} -o ${STATUS_RCC}
|
||||
VERBATIM
|
||||
USES_TERMINAL
|
||||
PRE_BUILD
|
||||
)
|
||||
|
||||
# Platform specific stuff are place in the corresponding .cmake file.
|
||||
if (WIN32)
|
||||
include("${CMAKE_SOURCE_DIR}/cmake/app-win.cmake")
|
||||
elseif (APPLE)
|
||||
include("${CMAKE_SOURCE_DIR}/cmake/app-mac.cmake")
|
||||
elseif(UNIX)
|
||||
include("${CMAKE_SOURCE_DIR}/cmake/app-linux.cmake")
|
||||
endif ()
|
||||
|
||||
check_translations()
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::Constants
|
||||
{
|
||||
const QString UserDataDirName = "Status";
|
||||
const QString StatusGoDataDirName = "data";
|
||||
const QString TmpDataDirName = "tmp";
|
||||
const QString LogsDataDirName = "logs";
|
||||
const QString QtDataDirName = "qt";
|
||||
const QString KeystoreDataDirName = "keystore";
|
||||
const QString GlobalSettingsFileName = "global";
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
#pragma once
|
||||
|
||||
#include "Constants.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtGui>
|
||||
|
||||
namespace Status
|
||||
{
|
||||
class Utils final {
|
||||
public:
|
||||
static QString applicationDir()
|
||||
{
|
||||
return qGuiApp->applicationDirPath();
|
||||
}
|
||||
|
||||
static QString defaultDataDir()
|
||||
{
|
||||
auto d = QDir();
|
||||
if(STATUS_DEVELOPMENT){
|
||||
d = QDir(STATUS_SOURCE_DIR);
|
||||
d.cdUp();
|
||||
}
|
||||
else {
|
||||
// We should handle paths for different platforms here in case of non development
|
||||
}
|
||||
|
||||
return d.absolutePath() + QDir::separator() + Constants::UserDataDirName;
|
||||
}
|
||||
|
||||
static QString statusGoDataDir()
|
||||
{
|
||||
return defaultDataDir() + QDir::separator() + Constants::StatusGoDataDirName;
|
||||
}
|
||||
|
||||
static QString keystoreDataDir()
|
||||
{
|
||||
return statusGoDataDir() + QDir::separator() + Constants::KeystoreDataDirName;
|
||||
}
|
||||
|
||||
static QString tmpDataDir()
|
||||
{
|
||||
return defaultDataDir() + QDir::separator() + Constants::TmpDataDirName;
|
||||
}
|
||||
|
||||
static QString logsDataDir()
|
||||
{
|
||||
return defaultDataDir() + QDir::separator() + Constants::LogsDataDirName;
|
||||
}
|
||||
|
||||
static QString qtDataDir()
|
||||
{
|
||||
return defaultDataDir() + QDir::separator() + Constants::QtDataDirName;
|
||||
}
|
||||
|
||||
static void ensureDirectories()
|
||||
{
|
||||
QDir d;
|
||||
d.mkpath(defaultDataDir());
|
||||
d.mkpath(statusGoDataDir());
|
||||
d.mkpath(keystoreDataDir());
|
||||
d.mkpath(tmpDataDir());
|
||||
d.mkpath(logsDataDir());
|
||||
d.mkpath(qtDataDir());
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
#include "Engine.h"
|
||||
|
||||
using namespace Status;
|
||||
|
||||
Engine* Engine::instance()
|
||||
{
|
||||
static auto* engine = new Engine();
|
||||
return engine;
|
||||
}
|
||||
|
||||
Engine::Engine()
|
||||
: QQmlApplicationEngine(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Engine::~Engine()
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<QQmlComponent> Engine::load(const QString& qmlFile)
|
||||
{
|
||||
return std::shared_ptr<QQmlComponent>(new QQmlComponent(instance(), qmlFile, QQmlComponent::Asynchronous));
|
||||
}
|
||||
|
||||
void Engine::create(const QString& qmlFile, QQmlContext* context)
|
||||
{
|
||||
QObject* createdObj = nullptr;
|
||||
auto component = Engine::load(qmlFile);
|
||||
const auto status = component->status();
|
||||
|
||||
if (status == QQmlComponent::Ready)
|
||||
{
|
||||
createdObj = component->create();
|
||||
emit instance()->objectCreated(createdObj, qmlFile);
|
||||
}
|
||||
else if (status == QQmlComponent::Loading)
|
||||
{
|
||||
const auto create = [c = component, f = qmlFile](const QQmlComponent::Status status) mutable
|
||||
{
|
||||
if (status == QQmlComponent::Loading)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (status == QQmlComponent::Ready)
|
||||
{
|
||||
emit instance()->objectCreated(c->create(), f);
|
||||
}
|
||||
else if (status == QQmlComponent::Null || status == QQmlComponent::Error)
|
||||
{
|
||||
emit instance()->objectCreated(nullptr, f);
|
||||
}
|
||||
};
|
||||
QObject::connect(component.get(), &QQmlComponent::statusChanged, create);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit instance()->objectCreated(createdObj, qmlFile);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtQml>
|
||||
|
||||
namespace Status
|
||||
{
|
||||
class Engine final : public QQmlApplicationEngine
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
static Engine* instance();
|
||||
|
||||
// Methos here are just a concept how we can have a single engine instance shared accross the app
|
||||
// and use it for async instantiation for all qml files over the app. Also we can this way register
|
||||
// context only within a certain file, not globally.
|
||||
static std::shared_ptr<QQmlComponent> load(const QString& qmlFile);
|
||||
static void create(const QString& qmlFile, QQmlContext *context = nullptr);
|
||||
|
||||
private:
|
||||
explicit Engine();
|
||||
~Engine();
|
||||
};
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include "GlobalEvents.h"
|
||||
|
||||
using namespace Status;
|
||||
|
||||
GlobalEvents& GlobalEvents::instance()
|
||||
{
|
||||
static GlobalEvents events;
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
GlobalEvents::GlobalEvents()
|
||||
{
|
||||
}
|
||||
|
||||
GlobalEvents::~GlobalEvents()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status
|
||||
{
|
||||
class GlobalEvents final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
static GlobalEvents& instance();
|
||||
|
||||
private:
|
||||
explicit GlobalEvents();
|
||||
~GlobalEvents();
|
||||
|
||||
signals:
|
||||
void nodeReady(const QString& error);
|
||||
void nodeStarted(const QString& error);
|
||||
void nodeStopped(const QString& error);
|
||||
void nodeLogin(const QString& error);
|
||||
void nodeCrashed(const QString& error);
|
||||
};
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
#include "SignalsManager.h"
|
||||
|
||||
#include "GlobalEvents.h"
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include "libstatus.h"
|
||||
|
||||
using namespace Status;
|
||||
|
||||
std::map<QString, SignalType> SignalsManager::signalMap;
|
||||
|
||||
SignalsManager* SignalsManager::instance()
|
||||
{
|
||||
static auto* manager = new SignalsManager();
|
||||
return manager;
|
||||
}
|
||||
|
||||
SignalsManager::SignalsManager()
|
||||
: QObject(nullptr)
|
||||
{
|
||||
SetSignalEventCallback((void*)&SignalsManager::signalCallback);
|
||||
|
||||
signalMap = {
|
||||
{"node.ready", SignalType::NodeReady},
|
||||
{"node.started", SignalType::NodeStarted},
|
||||
{"node.stopped", SignalType::NodeStopped},
|
||||
{"node.login", SignalType::NodeLogin},
|
||||
{"node.crashed", SignalType::NodeCrashed}
|
||||
};
|
||||
}
|
||||
|
||||
SignalsManager::~SignalsManager()
|
||||
{
|
||||
}
|
||||
|
||||
void SignalsManager::processSignal(const QString& statusSignal)
|
||||
{
|
||||
try
|
||||
{
|
||||
QJsonParseError json_error;
|
||||
const QJsonDocument signalEventDoc(QJsonDocument::fromJson(statusSignal.toUtf8(), &json_error));
|
||||
if(json_error.error != QJsonParseError::NoError)
|
||||
{
|
||||
qWarning() << "Invalid signal received";
|
||||
return;
|
||||
}
|
||||
decode(signalEventDoc.object());
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
qWarning() << "Error decoding signal, err: ", e.what();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void SignalsManager::decode(const QJsonObject& signalEvent)
|
||||
{
|
||||
SignalType signalType(Unknown);
|
||||
if(!signalMap.count(signalEvent["type"].toString()))
|
||||
{
|
||||
qWarning() << "Unknown signal received: " << signalEvent["type"].toString();
|
||||
return;
|
||||
}
|
||||
|
||||
signalType = signalMap[signalEvent["type"].toString()];
|
||||
auto signalError = signalEvent["event"]["error"].toString();
|
||||
|
||||
switch(signalType)
|
||||
{
|
||||
// TODO: create extractor functions like in nim
|
||||
case NodeLogin:
|
||||
emit GlobalEvents::instance().nodeLogin(signalError);
|
||||
break;
|
||||
case NodeReady:
|
||||
emit GlobalEvents::instance().nodeReady(signalError);
|
||||
break;
|
||||
case NodeStarted:
|
||||
emit GlobalEvents::instance().nodeStarted(signalError);
|
||||
break;
|
||||
case NodeStopped:
|
||||
emit GlobalEvents::instance().nodeStopped(signalError);
|
||||
break;
|
||||
case NodeCrashed: {
|
||||
qWarning() << "node.crashed, error: " << signalError;
|
||||
emit GlobalEvents::instance().nodeCrashed(signalError);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qWarning() << "Signal decoding not implemented: " << signalEvent;
|
||||
}
|
||||
}
|
||||
|
||||
void SignalsManager::signalCallback(const char* data)
|
||||
{
|
||||
QtConcurrent::run(instance(), &SignalsManager::processSignal, QString(data));
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status
|
||||
{
|
||||
enum SignalType
|
||||
{
|
||||
Unknown,
|
||||
NodeLogin,
|
||||
NodeReady,
|
||||
NodeStarted,
|
||||
NodeStopped,
|
||||
NodeCrashed
|
||||
};
|
||||
|
||||
class SignalsManager final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
static SignalsManager* instance();
|
||||
|
||||
private:
|
||||
explicit SignalsManager();
|
||||
~SignalsManager();
|
||||
|
||||
private:
|
||||
static std::map<QString, SignalType> signalMap;
|
||||
static void signalCallback(const char* data);
|
||||
void processSignal(const QString& ev);
|
||||
void decode(const QJsonObject& signalEvent);
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#include "LocalAccountSettings.h"
|
||||
|
||||
#include "../Common/Utils.h"
|
||||
|
||||
using namespace Status;
|
||||
|
||||
LocalAccountSettings& LocalAccountSettings::instance()
|
||||
{
|
||||
static LocalAccountSettings laSettings;
|
||||
|
||||
return laSettings;
|
||||
}
|
||||
|
||||
LocalAccountSettings::LocalAccountSettings()
|
||||
{
|
||||
}
|
||||
|
||||
LocalAccountSettings::~LocalAccountSettings()
|
||||
{
|
||||
}
|
||||
|
||||
void LocalAccountSettings::setFileName(const QString& fileName)
|
||||
{
|
||||
auto filePath = Utils::qtDataDir() + QDir::separator() + fileName;
|
||||
LocalAccountSettings::instance().settings.reset(new QSettings(filePath, QSettings::IniFormat));
|
||||
}
|
||||
|
||||
bool LocalAccountSettings::containsKey(const QString& key)
|
||||
{
|
||||
return LocalAccountSettings::instance().settings->contains(key);
|
||||
}
|
||||
|
||||
void LocalAccountSettings::removeKey(const QString& key)
|
||||
{
|
||||
LocalAccountSettings::instance().settings->remove(key);
|
||||
}
|
||||
|
||||
QVariant LocalAccountSettingsKeys::getDefaultValue(const QString& key) {
|
||||
static QMap<QString, QVariant> defaults;
|
||||
if (defaults.isEmpty())
|
||||
{
|
||||
defaults.insert(storeToKeychain, LocalAccountSettingsPossibleValues::StoreToKeychain::NotNow);
|
||||
defaults.insert(isKeycardEnabled, false);
|
||||
}
|
||||
|
||||
return defaults.value(key);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include "SettingsProperties.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status
|
||||
{
|
||||
namespace LocalAccountSettingsKeys {
|
||||
const QString storeToKeychain = "storeToKeychain";
|
||||
const QString isKeycardEnabled = "isKeycardEnabled";
|
||||
|
||||
QVariant getDefaultValue(const QString& key);
|
||||
}
|
||||
|
||||
namespace LocalAccountSettingsPossibleValues {
|
||||
namespace StoreToKeychain {
|
||||
const QString Store = "store";
|
||||
const QString NotNow = "notNow";
|
||||
const QString Never = "never";
|
||||
}
|
||||
}
|
||||
|
||||
class LocalAccountSettings final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
static LocalAccountSettings& instance();
|
||||
|
||||
void setFileName(const QString& fileName);
|
||||
bool containsKey(const QString& key);
|
||||
void removeKey(const QString& key);
|
||||
|
||||
REGISTER_RW_PROPERTY(LocalAccountSettings, LocalAccountSettingsKeys, isKeycardEnabled, bool)
|
||||
REGISTER_RW_PROPERTY(LocalAccountSettings, LocalAccountSettingsKeys, storeToKeychain, QString)
|
||||
|
||||
private:
|
||||
explicit LocalAccountSettings();
|
||||
~LocalAccountSettings();
|
||||
|
||||
std::unique_ptr<QSettings> settings;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
#include "LocalAppSettings.h"
|
||||
|
||||
#include "../Common/Utils.h"
|
||||
#include "../Common/Constants.h"
|
||||
|
||||
using namespace Status;
|
||||
|
||||
LocalAppSettings& LocalAppSettings::instance()
|
||||
{
|
||||
static LocalAppSettings laSettings;
|
||||
|
||||
return laSettings;
|
||||
}
|
||||
|
||||
LocalAppSettings::LocalAppSettings()
|
||||
{
|
||||
if(!settings)
|
||||
{
|
||||
auto filePath = Utils::qtDataDir() + QDir::separator() + Constants::GlobalSettingsFileName;
|
||||
settings.reset(new QSettings(filePath, QSettings::IniFormat));
|
||||
}
|
||||
}
|
||||
|
||||
LocalAppSettings::~LocalAppSettings()
|
||||
{
|
||||
}
|
||||
|
||||
bool LocalAppSettings::containsKey(const QString& key)
|
||||
{
|
||||
return LocalAppSettings::instance().settings->contains(key);
|
||||
}
|
||||
|
||||
void LocalAppSettings::removeKey(const QString& key)
|
||||
{
|
||||
LocalAppSettings::instance().settings->remove(key);
|
||||
}
|
||||
|
||||
QVariant LocalAppSettingsKeys::getDefaultValue(const QString& key) {
|
||||
static QMap<QString, QVariant> defaults;
|
||||
if (defaults.isEmpty())
|
||||
{
|
||||
defaults.insert(locale, "en");
|
||||
defaults.insert(theme, 2);
|
||||
defaults.insert(appWidth, 1232);
|
||||
defaults.insert(appHeight, 770);
|
||||
defaults.insert(appSizeInitialized, false);
|
||||
}
|
||||
|
||||
return defaults.value(key);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include "SettingsProperties.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status
|
||||
{
|
||||
namespace LocalAppSettingsKeys {
|
||||
const QString locale = "global/locale";
|
||||
const QString theme = "global/theme";
|
||||
const QString appWidth = "global/app_width";
|
||||
const QString appHeight = "global/app_height";
|
||||
const QString appSizeInitialized = "global/app_size_initialized";
|
||||
|
||||
QVariant getDefaultValue(const QString& key);
|
||||
}
|
||||
|
||||
class LocalAppSettings final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
static LocalAppSettings& instance();
|
||||
|
||||
bool containsKey(const QString& key);
|
||||
void removeKey(const QString& key);
|
||||
|
||||
REGISTER_RW_PROPERTY(LocalAppSettings, LocalAppSettingsKeys, locale, QString)
|
||||
REGISTER_RW_PROPERTY(LocalAppSettings, LocalAppSettingsKeys, theme, int)
|
||||
REGISTER_RW_PROPERTY(LocalAppSettings, LocalAppSettingsKeys, appWidth, int)
|
||||
REGISTER_RW_PROPERTY(LocalAppSettings, LocalAppSettingsKeys, appHeight, int)
|
||||
REGISTER_RW_PROPERTY(LocalAppSettings, LocalAppSettingsKeys, appSizeInitialized, bool)
|
||||
|
||||
private:
|
||||
explicit LocalAppSettings();
|
||||
~LocalAppSettings();
|
||||
|
||||
std::unique_ptr<QSettings> settings;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
template<class T>
|
||||
[[nodiscard]] T extractValue(const QVariant& value)
|
||||
{
|
||||
if constexpr (std::is_same_v<bool, T>)
|
||||
return value.toBool();
|
||||
else if constexpr (std::is_same_v<QString, T>)
|
||||
return value.toString();
|
||||
else if constexpr (std::is_same_v<int, T>)
|
||||
return value.toInt();
|
||||
else if constexpr (std::is_same_v<float, T>)
|
||||
return value.toFloat();
|
||||
return T();
|
||||
}
|
||||
|
||||
#define REGISTER_RW_PROPERTY(class, nspace, key, type) \
|
||||
Q_SIGNALS: \
|
||||
void key##Changed(); \
|
||||
public: \
|
||||
Q_PROPERTY(type key READ get_##key WRITE set_##key NOTIFY key##Changed) \
|
||||
[[nodiscard]] type get_##key() const \
|
||||
{ \
|
||||
if(!class::instance().settings || \
|
||||
class::instance().settings->fileName().isEmpty()) \
|
||||
{ \
|
||||
qFatal("Please set settings file name first"); \
|
||||
return type(); \
|
||||
} \
|
||||
auto def = nspace::getDefaultValue(nspace::key); \
|
||||
return extractValue<type>(class::instance().settings->value(nspace::key, def)); \
|
||||
} \
|
||||
void set_##key(const type& value) \
|
||||
{ \
|
||||
if(!class::instance().settings || \
|
||||
class::instance().settings->fileName().isEmpty()) \
|
||||
{ \
|
||||
qFatal("Please set settings file name first"); \
|
||||
return; \
|
||||
} \
|
||||
class::instance().settings->setValue(nspace::key, value); \
|
||||
emit key##Changed(); \
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#include "Module.h"
|
||||
|
||||
#include "Startup/Module.h"
|
||||
|
||||
using namespace Status::Modules;
|
||||
|
||||
RootModule::RootModule(Startup::ModuleBuilder moduleBuilder)
|
||||
: m_startupModuleBuilder(std::move(moduleBuilder))
|
||||
{
|
||||
}
|
||||
|
||||
void RootModule::load()
|
||||
{
|
||||
m_startupModule = m_startupModuleBuilder(shared_from_this());
|
||||
m_startupModule->load();
|
||||
}
|
||||
|
||||
void RootModule::startupDidLoad()
|
||||
{
|
||||
m_startupModule->emitStartUpUIRaisedSignal();
|
||||
}
|
||||
|
||||
void RootModule::userLoggedIn()
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include "ModuleInterface.h"
|
||||
#include "Startup/ModuleBuilder.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Status::Modules
|
||||
{
|
||||
|
||||
class RootModule final : public ModuleAccessInterface
|
||||
, public Startup::ModuleDelegateInterface
|
||||
, public std::enable_shared_from_this<RootModule>
|
||||
{
|
||||
public:
|
||||
RootModule(Startup::ModuleBuilder moduleBuilder);
|
||||
|
||||
void load() override;
|
||||
void startupDidLoad() override;
|
||||
void userLoggedIn() override;
|
||||
|
||||
private:
|
||||
|
||||
Startup::ModuleBuilder m_startupModuleBuilder;
|
||||
std::shared_ptr<Startup::ModuleAccessInterface> m_startupModule;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#include "ModuleBuilder.h"
|
||||
|
||||
#include "Module.h"
|
||||
|
||||
using namespace Status::Modules;
|
||||
|
||||
ModuleBuilder::ModuleBuilder(Startup::ModuleBuilder moduleBuilder)
|
||||
: m_startupModuleBuilder(std::move(moduleBuilder))
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<ModuleAccessInterface> ModuleBuilder::operator()()
|
||||
{
|
||||
return std::make_shared<RootModule>(m_startupModuleBuilder);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "ModuleInterface.h"
|
||||
#include "Startup/ModuleBuilder.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Status::Modules
|
||||
{
|
||||
|
||||
class ModuleBuilder final
|
||||
{
|
||||
public:
|
||||
ModuleBuilder(Startup::ModuleBuilder moduleBuilder);
|
||||
|
||||
[[nodiscard]] std::shared_ptr<ModuleAccessInterface> operator()();
|
||||
|
||||
private:
|
||||
Startup::ModuleBuilder m_startupModuleBuilder;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
namespace Status::Modules
|
||||
{
|
||||
class ModuleAccessInterface
|
||||
{
|
||||
public:
|
||||
virtual ~ModuleAccessInterface() = default;
|
||||
|
||||
virtual void load() = 0;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
#include <QDebug>
|
||||
|
||||
#include "SectionItem.h"
|
||||
|
||||
using namespace Status::Shared::Models;
|
||||
|
||||
SectionItem::SectionItem(QObject* parent,
|
||||
const QString& id,
|
||||
SectionType sectionType,
|
||||
const QString& name,
|
||||
const QString& description,
|
||||
const QString& image,
|
||||
const QString& icon,
|
||||
const QString& color,
|
||||
bool active,
|
||||
bool enabled,
|
||||
bool amISectionAdmin,
|
||||
bool hasNotification,
|
||||
int notificationsCount,
|
||||
bool isMember,
|
||||
bool joined,
|
||||
bool canJoin,
|
||||
bool canManageUsers,
|
||||
bool canRequestAccess,
|
||||
int access,
|
||||
bool ensOnly)
|
||||
: QObject(parent)
|
||||
, m_id(id)
|
||||
, m_sectionType(sectionType)
|
||||
, m_name(name)
|
||||
, m_amISectionAdmin(amISectionAdmin)
|
||||
, m_description(description)
|
||||
, m_image(image)
|
||||
, m_icon(icon)
|
||||
, m_color(color)
|
||||
, m_hasNotification(hasNotification)
|
||||
, m_notificationsCount(notificationsCount)
|
||||
, m_active(active)
|
||||
, m_enabled(enabled)
|
||||
, m_isMember(isMember)
|
||||
, m_joined(joined)
|
||||
, m_canJoin(canJoin)
|
||||
, m_canManageUsers(canManageUsers)
|
||||
, m_canRequestAccess(canRequestAccess)
|
||||
, m_access(access)
|
||||
, m_ensOnly(ensOnly)
|
||||
{ }
|
||||
|
||||
SectionType SectionItem::getSectionType() const
|
||||
{
|
||||
return m_sectionType;
|
||||
}
|
||||
|
||||
const QString& SectionItem::getId() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
const QString& SectionItem::getName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
bool SectionItem::getAmISectionAdmin() const
|
||||
{
|
||||
return m_amISectionAdmin;
|
||||
}
|
||||
|
||||
const QString& SectionItem::getDescription() const
|
||||
{
|
||||
return m_description;
|
||||
}
|
||||
|
||||
const QString& SectionItem::getImage() const
|
||||
{
|
||||
return m_image;
|
||||
}
|
||||
|
||||
const QString& SectionItem::getIcon() const
|
||||
{
|
||||
return m_icon;
|
||||
}
|
||||
|
||||
const QString& SectionItem::getColor() const
|
||||
{
|
||||
return m_color;
|
||||
}
|
||||
|
||||
bool SectionItem::getHasNotification() const
|
||||
{
|
||||
return m_hasNotification;
|
||||
}
|
||||
|
||||
int SectionItem::getNotificationsCount() const
|
||||
{
|
||||
return m_notificationsCount;
|
||||
}
|
||||
|
||||
bool SectionItem::getIsActive() const
|
||||
{
|
||||
return m_active;
|
||||
}
|
||||
|
||||
bool SectionItem::getIsEnabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
bool SectionItem::getIsMember() const
|
||||
{
|
||||
return m_isMember;
|
||||
}
|
||||
|
||||
bool SectionItem::getHasJoined() const
|
||||
{
|
||||
return m_joined;
|
||||
}
|
||||
|
||||
bool SectionItem::getCanJoin() const
|
||||
{
|
||||
return m_canJoin;
|
||||
}
|
||||
|
||||
bool SectionItem::getCanManageUsers() const
|
||||
{
|
||||
return m_canManageUsers;
|
||||
}
|
||||
|
||||
bool SectionItem::getCanRequestAccess() const
|
||||
{
|
||||
return m_canRequestAccess;
|
||||
}
|
||||
|
||||
int SectionItem::getAccess() const
|
||||
{
|
||||
return m_access;
|
||||
}
|
||||
|
||||
bool SectionItem::getIsEnsOnly() const
|
||||
{
|
||||
return m_ensOnly;
|
||||
}
|
||||
|
||||
void SectionItem::setIsActive(bool isActive)
|
||||
{
|
||||
if(m_active != isActive)
|
||||
{
|
||||
m_active = isActive;
|
||||
activeChanged();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::Shared::Models
|
||||
{
|
||||
enum SectionType
|
||||
{
|
||||
Unkown = -1,
|
||||
Chat,
|
||||
Community,
|
||||
Wallet,
|
||||
Browser,
|
||||
ProfileSettings,
|
||||
NodeManagement
|
||||
};
|
||||
class SectionItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString id READ getId)
|
||||
Q_PROPERTY(int sectionType READ getSectionType)
|
||||
Q_PROPERTY(QString name READ getName)
|
||||
Q_PROPERTY(bool amISectionAdmin READ getAmISectionAdmin)
|
||||
Q_PROPERTY(QString description READ getDescription)
|
||||
Q_PROPERTY(QString image READ getImage)
|
||||
Q_PROPERTY(QString icon READ getIcon)
|
||||
Q_PROPERTY(QString color READ getColor)
|
||||
Q_PROPERTY(bool hasNotification READ getHasNotification)
|
||||
Q_PROPERTY(int notificationsCount READ getNotificationsCount)
|
||||
Q_PROPERTY(bool active READ getIsActive NOTIFY activeChanged)
|
||||
Q_PROPERTY(bool enabled READ getIsEnabled)
|
||||
Q_PROPERTY(bool joined READ getHasJoined)
|
||||
Q_PROPERTY(bool isMember READ getIsMember)
|
||||
Q_PROPERTY(bool canJoin READ getCanJoin)
|
||||
Q_PROPERTY(bool canManageUsers READ getCanManageUsers)
|
||||
Q_PROPERTY(bool canRequestAccess READ getCanRequestAccess)
|
||||
Q_PROPERTY(int access READ getAccess)
|
||||
Q_PROPERTY(bool ensOnly READ getIsEnsOnly)
|
||||
|
||||
public:
|
||||
SectionItem(QObject* parent = nullptr,
|
||||
const QString& id = "",
|
||||
SectionType sectionType = SectionType::Unkown,
|
||||
const QString& name = "",
|
||||
const QString& description = "",
|
||||
const QString& image = "",
|
||||
const QString& icon = "",
|
||||
const QString& color = "",
|
||||
bool active = false,
|
||||
bool enabled = false,
|
||||
bool amISectionAdmin = false,
|
||||
bool hasNotification = false,
|
||||
int notificationsCount = 0,
|
||||
bool isMember = false,
|
||||
bool joined = false,
|
||||
bool canJoin = false,
|
||||
bool canManageUsers = false,
|
||||
bool canRequestAccess = false,
|
||||
int access = 0,
|
||||
bool ensOnly = false);
|
||||
~SectionItem() = default;
|
||||
|
||||
// Getters
|
||||
SectionType getSectionType() const;
|
||||
const QString& getId() const;
|
||||
const QString& getName() const;
|
||||
bool getAmISectionAdmin() const;
|
||||
const QString& getDescription() const;
|
||||
const QString& getImage() const;
|
||||
const QString& getIcon() const;
|
||||
const QString& getColor() const;
|
||||
bool getHasNotification() const;
|
||||
int getNotificationsCount() const;
|
||||
bool getIsActive() const;
|
||||
bool getIsEnabled() const;
|
||||
bool getIsMember() const;
|
||||
bool getHasJoined() const;
|
||||
bool getCanJoin() const;
|
||||
bool getCanManageUsers() const;
|
||||
bool getCanRequestAccess() const;
|
||||
int getAccess() const;
|
||||
bool getIsEnsOnly() const;
|
||||
|
||||
// Setters
|
||||
void setIsActive(bool isActive);
|
||||
|
||||
signals:
|
||||
void activeChanged();
|
||||
|
||||
private:
|
||||
SectionType m_sectionType;
|
||||
QString m_id;
|
||||
QString m_name;
|
||||
bool m_amISectionAdmin;
|
||||
QString m_description;
|
||||
QString m_image;
|
||||
QString m_icon;
|
||||
QString m_color;
|
||||
bool m_hasNotification;
|
||||
int m_notificationsCount;
|
||||
bool m_active;
|
||||
bool m_enabled;
|
||||
bool m_isMember;
|
||||
bool m_joined;
|
||||
bool m_canJoin;
|
||||
bool m_canManageUsers;
|
||||
bool m_canRequestAccess;
|
||||
int m_access;
|
||||
bool m_ensOnly;
|
||||
// membersModel: user_model.Model
|
||||
// pendingRequestsToJoinModel: PendingRequestModel
|
||||
};
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
#include "SectionModel.h"
|
||||
|
||||
using namespace Status::Shared::Models;
|
||||
|
||||
SectionModel::SectionModel(QObject* parent)
|
||||
: QAbstractListModel(parent)
|
||||
{ }
|
||||
|
||||
QHash<int, QByteArray> SectionModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
|
||||
roles[Id] = "id";
|
||||
roles[SectionType] = "sectionType";
|
||||
roles[Name] = "name";
|
||||
roles[AmISectionAdmin] = "amISectionAdmin";
|
||||
roles[Description] = "description";
|
||||
roles[Image] = "image";
|
||||
roles[Icon] = "icon";
|
||||
roles[Color] = "color";
|
||||
roles[HasNotification] = "hasNotification";
|
||||
roles[NotificationsCount] = "notificationsCount";
|
||||
roles[Active] = "active";
|
||||
roles[Enabled] = "enabled";
|
||||
roles[Joined] = "joined";
|
||||
roles[IsMember] = "isMember";
|
||||
roles[CanJoin] = "canJoin";
|
||||
roles[CanManageUsers] = "canManageUsers";
|
||||
roles[CanRequestAccess] = "canRequestAccess";
|
||||
roles[Access] = "access";
|
||||
roles[EnsOnly] = "ensOnly";
|
||||
roles[MembersModel] = "members";
|
||||
roles[PendingRequestsToJoinModel] = "pendingRequestsToJoin";
|
||||
return roles;
|
||||
}
|
||||
|
||||
int SectionModel::rowCount(const QModelIndex& parent = QModelIndex()) const
|
||||
{
|
||||
return m_items.size();
|
||||
}
|
||||
|
||||
QVariant SectionModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if(!index.isValid())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if(index.row() < 0 || index.row() >= m_items.size())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
SectionItem* item = m_items.at(index.row());
|
||||
|
||||
switch(role)
|
||||
{
|
||||
case Id: return item->getId();
|
||||
case SectionType: return item->getSectionType();
|
||||
case Name: return item->getName();
|
||||
case AmISectionAdmin: return item->getAmISectionAdmin();
|
||||
case Description: return item->getDescription();
|
||||
case Image: return item->getImage();
|
||||
case Icon: return item->getIcon();
|
||||
case Color: return item->getColor();
|
||||
case HasNotification: return item->getHasNotification();
|
||||
case NotificationsCount: return item->getNotificationsCount();
|
||||
case Active: return item->getIsActive();
|
||||
case Enabled: return item->getIsEnabled();
|
||||
case Joined: return item->getHasJoined();
|
||||
case IsMember: return item->getIsMember();
|
||||
case CanJoin: return item->getCanJoin();
|
||||
case CanManageUsers: return item->getCanManageUsers();
|
||||
case CanRequestAccess: return item->getCanRequestAccess();
|
||||
case Access: return item->getAccess();
|
||||
case EnsOnly: return item->getIsEnsOnly();
|
||||
// To Do
|
||||
case MembersModel: return QVariant();
|
||||
case PendingRequestsToJoinModel: return QVariant();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void SectionModel::addItem(SectionItem* item)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), m_items.size(), m_items.size());
|
||||
m_items.append(item);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void SectionModel::setActiveSection(const QString& Id)
|
||||
{
|
||||
|
||||
for(int i = 0; i < m_items.size(); ++i)
|
||||
{
|
||||
auto newIndex = createIndex(i, 0, nullptr);
|
||||
if(m_items.at(i)->getIsActive())
|
||||
{
|
||||
m_items.at(i)->setIsActive(false);
|
||||
dataChanged(newIndex, newIndex, QVector<int>(ModelRole::Active));
|
||||
}
|
||||
if(m_items.at(i)->getId() == Id)
|
||||
{
|
||||
m_items.at(i)->setIsActive(true);
|
||||
dataChanged(newIndex, newIndex, QVector<int>(ModelRole::Active));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QPointer<SectionItem> SectionModel::getActiveItem()
|
||||
{
|
||||
SectionItem* activeItem = nullptr;
|
||||
for(auto item : m_items)
|
||||
{
|
||||
if(item->getIsActive())
|
||||
{
|
||||
activeItem = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return activeItem;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
#pragma once
|
||||
|
||||
#include "SectionItem.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::Shared::Models
|
||||
{
|
||||
class SectionModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ModelRole
|
||||
{
|
||||
Id = Qt::UserRole + 1,
|
||||
SectionType,
|
||||
Name,
|
||||
AmISectionAdmin,
|
||||
Description,
|
||||
Image,
|
||||
Icon,
|
||||
Color,
|
||||
HasNotification,
|
||||
NotificationsCount,
|
||||
Active,
|
||||
Enabled,
|
||||
Joined,
|
||||
IsMember,
|
||||
CanJoin,
|
||||
CanManageUsers,
|
||||
CanRequestAccess,
|
||||
Access,
|
||||
EnsOnly,
|
||||
MembersModel,
|
||||
PendingRequestsToJoinModel
|
||||
};
|
||||
|
||||
explicit SectionModel(QObject* parent = nullptr);
|
||||
~SectionModel() = default;
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
int rowCount(const QModelIndex&) const override;
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
|
||||
void addItem(SectionItem* item);
|
||||
void setActiveSection(const QString& Id);
|
||||
QPointer<SectionItem> getActiveItem();
|
||||
|
||||
// To add other api's later as needed
|
||||
|
||||
private:
|
||||
QVector<SectionItem*> m_items;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
#include "Controller.h"
|
||||
|
||||
#include "../../Core/GlobalEvents.h"
|
||||
#include "../../Common/Utils.h"
|
||||
|
||||
#include <StatusServices/CommonService>
|
||||
|
||||
using namespace Status::Modules::Startup;
|
||||
|
||||
Controller::Controller(std::shared_ptr<Accounts::ServiceInterface> accountsService)
|
||||
: QObject(nullptr)
|
||||
, m_delegate(nullptr)
|
||||
, m_accountsService(std::move(accountsService))
|
||||
{
|
||||
}
|
||||
|
||||
void Controller::setDelegate(std::shared_ptr<ControllerDelegateInterface> delegate)
|
||||
{
|
||||
m_delegate = std::move(delegate);
|
||||
}
|
||||
|
||||
void Controller::init()
|
||||
{
|
||||
m_accountsService->init(Utils::statusGoDataDir());
|
||||
|
||||
QObject::connect(&GlobalEvents::instance(), &GlobalEvents::nodeLogin, this, &Controller::onLogin);
|
||||
QObject::connect(&GlobalEvents::instance(), &GlobalEvents::nodeStopped, this, &Controller::onNodeStopped);
|
||||
QObject::connect(&GlobalEvents::instance(), &GlobalEvents::nodeReady, this, &Controller::onNodeReady);
|
||||
}
|
||||
|
||||
bool Controller::shouldStartWithOnboardingScreen()
|
||||
{
|
||||
return m_accountsService->openedAccounts().isEmpty();
|
||||
}
|
||||
|
||||
void Controller::onLogin(const QString& error)
|
||||
{
|
||||
if(!error.isEmpty())
|
||||
{
|
||||
qWarning() << error;
|
||||
return;
|
||||
}
|
||||
|
||||
m_delegate->userLoggedIn();
|
||||
}
|
||||
|
||||
void Controller::onNodeStopped(const QString& error)
|
||||
{
|
||||
if(!error.isEmpty())
|
||||
{
|
||||
qWarning() << error;
|
||||
}
|
||||
|
||||
m_accountsService->clear();
|
||||
m_delegate->emitLogOutSignal();
|
||||
}
|
||||
|
||||
void Controller::onNodeReady(const QString& error)
|
||||
{
|
||||
if(!error.isEmpty())
|
||||
{
|
||||
qWarning() << error;
|
||||
return;
|
||||
}
|
||||
|
||||
// In case of ready node we can do something here if needed.
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "ControllerInterface.h"
|
||||
|
||||
#include <StatusServices/AccountsService>
|
||||
|
||||
namespace Status::Modules::Startup
|
||||
{
|
||||
class Controller : public QObject,
|
||||
public ControllerInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Controller(std::shared_ptr<Accounts::ServiceInterface> accountsService);
|
||||
void setDelegate(std::shared_ptr<ControllerDelegateInterface> delegate);
|
||||
|
||||
// Controller Interface
|
||||
void init() override;
|
||||
bool shouldStartWithOnboardingScreen() override;
|
||||
|
||||
private slots:
|
||||
void onLogin(const QString& error);
|
||||
void onNodeStopped(const QString& error);
|
||||
void onNodeReady(const QString& error);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Accounts::ServiceInterface> m_accountsService;
|
||||
std::shared_ptr<ControllerDelegateInterface> m_delegate;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::Modules::Startup
|
||||
{
|
||||
class ControllerInterface
|
||||
{
|
||||
public:
|
||||
virtual ~ControllerInterface() = default;
|
||||
|
||||
virtual void init() = 0;
|
||||
virtual bool shouldStartWithOnboardingScreen() = 0;
|
||||
};
|
||||
|
||||
class ControllerDelegateInterface
|
||||
{
|
||||
public:
|
||||
virtual void userLoggedIn() = 0;
|
||||
virtual void emitLogOutSignal() = 0;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
#include "Controller.h"
|
||||
|
||||
#include "../../../Core/GlobalEvents.h"
|
||||
#include "../../../Global/LocalAccountSettings.h"
|
||||
|
||||
using namespace Status::Modules::Startup::Login;
|
||||
|
||||
Controller::Controller(std::shared_ptr<Accounts::ServiceInterface> accountsService,
|
||||
std::shared_ptr<Keychain::ServiceInterface> keychainService)
|
||||
: QObject(nullptr)
|
||||
, m_delegate(nullptr)
|
||||
, m_accountsService(std::move(accountsService))
|
||||
, m_keychainService(std::move(keychainService))
|
||||
{
|
||||
}
|
||||
|
||||
void Controller::setDelegate(std::shared_ptr<ControllerDelegateInterface> delegate)
|
||||
{
|
||||
m_delegate = std::move(delegate);
|
||||
}
|
||||
|
||||
void Controller::init()
|
||||
{
|
||||
m_keychainService->subscribe(shared_from_this());
|
||||
|
||||
QObject::connect(&GlobalEvents::instance(), &GlobalEvents::nodeLogin, this, &Controller::onLogin);
|
||||
}
|
||||
|
||||
void Controller::onLogin(const QString& error)
|
||||
{
|
||||
if(!error.isEmpty())
|
||||
{
|
||||
m_delegate->emitAccountLoginError(error);
|
||||
}
|
||||
}
|
||||
|
||||
QVector<Status::Accounts::AccountDto> Controller::getOpenedAccounts() const
|
||||
{
|
||||
return m_accountsService->openedAccounts();
|
||||
}
|
||||
|
||||
Status::Accounts::AccountDto Controller::getSelectedAccount() const
|
||||
{
|
||||
auto openedAccounts = getOpenedAccounts();
|
||||
foreach(const auto& acc, openedAccounts)
|
||||
{
|
||||
if(acc.keyUid == m_selectedAccountKeyUid)
|
||||
{
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: For situations like this, should be better to return a std::optional instead?
|
||||
return Accounts::AccountDto();
|
||||
}
|
||||
|
||||
void Controller::setSelectedAccountKeyUid(const QString& keyUid)
|
||||
{
|
||||
m_selectedAccountKeyUid = keyUid;
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
// Dealing with Keychain is the MacOS only feature
|
||||
|
||||
auto selectedAccount = getSelectedAccount();
|
||||
LocalAccountSettings::instance().setFileName(selectedAccount.name);
|
||||
|
||||
auto value = LocalAccountSettings::instance().get_storeToKeychain();
|
||||
if (value != LocalAccountSettingsPossibleValues::StoreToKeychain::Store)
|
||||
return;
|
||||
|
||||
m_keychainService->tryToObtainPassword(selectedAccount.name);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Controller::login(const QString& password)
|
||||
{
|
||||
auto selectedAccount = Controller::getSelectedAccount();
|
||||
auto error = m_accountsService->login(selectedAccount, password);
|
||||
if(!error.isEmpty())
|
||||
{
|
||||
m_delegate->emitAccountLoginError(error);
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::onKeychainManagerError(const QString& errorType, const int errorCode, const QString& errorDescription)
|
||||
{
|
||||
// We are notifying user only about keychain errors.
|
||||
if (errorType == Keychain::ErrorTypeAuthentication)
|
||||
return;
|
||||
|
||||
LocalAccountSettings::instance().removeKey(LocalAccountSettingsKeys::storeToKeychain);
|
||||
m_delegate->emitObtainingPasswordError(errorDescription);
|
||||
}
|
||||
|
||||
void Controller::onKeychainManagerSuccess(const QString& data)
|
||||
{
|
||||
m_delegate->emitObtainingPasswordSuccess(data);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include "ControllerInterface.h"
|
||||
|
||||
namespace Status::Modules::Startup::Login
|
||||
{
|
||||
class Controller : public QObject
|
||||
, public ControllerInterface
|
||||
, public Keychain::Listener
|
||||
, public std::enable_shared_from_this<Controller>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Controller(std::shared_ptr<Accounts::ServiceInterface> accountsService,
|
||||
std::shared_ptr<Keychain::ServiceInterface> keychainService);
|
||||
void setDelegate(std::shared_ptr<ControllerDelegateInterface> delegate);
|
||||
|
||||
// Controller Interface
|
||||
void init() override;
|
||||
QVector<Accounts::AccountDto> getOpenedAccounts() const override;
|
||||
void setSelectedAccountKeyUid(const QString& keyUid) override;
|
||||
void login(const QString& password) override;
|
||||
|
||||
// Listener Interface
|
||||
void onKeychainManagerError(const QString& errorType, const int errorCode,
|
||||
const QString& errorDescription) override;
|
||||
void onKeychainManagerSuccess(const QString& data) override;
|
||||
|
||||
private slots:
|
||||
void onLogin(const QString& error);
|
||||
|
||||
private:
|
||||
Accounts::AccountDto getSelectedAccount() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Accounts::ServiceInterface> m_accountsService;
|
||||
std::shared_ptr<Keychain::ServiceInterface> m_keychainService;
|
||||
std::shared_ptr<ControllerDelegateInterface> m_delegate;
|
||||
QString m_selectedAccountKeyUid;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include <StatusServices/AccountsService>
|
||||
#include <StatusServices/KeychainService>
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::Modules::Startup::Login
|
||||
{
|
||||
class ControllerInterface
|
||||
{
|
||||
public:
|
||||
virtual ~ControllerInterface() = default;
|
||||
|
||||
virtual void init() = 0;
|
||||
virtual QVector<Accounts::AccountDto> getOpenedAccounts() const = 0;
|
||||
virtual void setSelectedAccountKeyUid(const QString& keyUid) = 0;
|
||||
virtual void login(const QString& password) = 0;
|
||||
};
|
||||
|
||||
class ControllerDelegateInterface
|
||||
{
|
||||
public:
|
||||
virtual void emitAccountLoginError(const QString& error) = 0;
|
||||
virtual void emitObtainingPasswordError(const QString& errorDescription) = 0;
|
||||
virtual void emitObtainingPasswordSuccess(const QString& password) = 0;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#include "Item.h"
|
||||
|
||||
using namespace Status::Modules::Startup::Login;
|
||||
|
||||
Item::Item(const QString& name, const QString& identicon, const QString& thumbnailImage, const QString& largeImage,
|
||||
const QString& keyUid)
|
||||
: m_name(name)
|
||||
, m_identicon(identicon)
|
||||
, m_thumbnailImage(thumbnailImage)
|
||||
, m_largeImage(largeImage)
|
||||
, m_keyUid(keyUid)
|
||||
{
|
||||
}
|
||||
|
||||
QString Item::getName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
QString Item::getIdenticon() const
|
||||
{
|
||||
return m_identicon;
|
||||
}
|
||||
QString Item::getThumbnailImage() const
|
||||
{
|
||||
return m_thumbnailImage;
|
||||
}
|
||||
QString Item::getLargeImage() const
|
||||
{
|
||||
return m_largeImage;
|
||||
}
|
||||
QString Item::getKeyUid() const
|
||||
{
|
||||
return m_keyUid;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::Modules::Startup::Login
|
||||
{
|
||||
class Item
|
||||
{
|
||||
public:
|
||||
Item() {}
|
||||
Item(const QString& name, const QString& identicon, const QString& thumbnailImage, const QString& largeImage,
|
||||
const QString& keyUid);
|
||||
QString getName() const;
|
||||
QString getIdenticon() const;
|
||||
QString getThumbnailImage() const;
|
||||
QString getLargeImage() const;
|
||||
QString getKeyUid() const;
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
QString m_identicon;
|
||||
QString m_thumbnailImage;
|
||||
QString m_largeImage;
|
||||
QString m_keyUid;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
#include "Model.h"
|
||||
|
||||
using namespace Status::Modules::Startup::Login;
|
||||
|
||||
Model::Model(QObject* parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> Model::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[Name] = "username";
|
||||
roles[Identicon] = "identicon";
|
||||
roles[ThumbnailImage] = "thumbnailImage";
|
||||
roles[LargeImage] = "largeImage";
|
||||
roles[KeyUid] = "keyUid";
|
||||
return roles;
|
||||
}
|
||||
|
||||
int Model::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return m_items.size();
|
||||
}
|
||||
|
||||
QVariant Model::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if(!index.isValid())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if(index.row() < 0 || index.row() > m_items.size())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Item item = m_items[index.row()];
|
||||
|
||||
switch(role)
|
||||
{
|
||||
case Name:
|
||||
return item.getName();
|
||||
case Identicon:
|
||||
return item.getIdenticon();
|
||||
case ThumbnailImage:
|
||||
return item.getThumbnailImage();
|
||||
case LargeImage:
|
||||
return item.getLargeImage();
|
||||
case KeyUid:
|
||||
return item.getKeyUid();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void Model::setItems(QVector<Item> items)
|
||||
{
|
||||
beginResetModel();
|
||||
m_items = std::move(items);
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
Item Model::getItemAtIndex(const int index) const
|
||||
{
|
||||
if(index < 0 || index >= m_items.size())
|
||||
{
|
||||
return Item();
|
||||
}
|
||||
|
||||
return m_items[index];
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "Item.h"
|
||||
|
||||
namespace Status::Modules::Startup::Login
|
||||
{
|
||||
class Model : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ModelRole
|
||||
{
|
||||
Name = Qt::UserRole + 1,
|
||||
Identicon,
|
||||
ThumbnailImage,
|
||||
LargeImage,
|
||||
KeyUid
|
||||
};
|
||||
|
||||
explicit Model(QObject* parent = nullptr);
|
||||
QHash<int, QByteArray> roleNames() const;
|
||||
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||
virtual QVariant data(const QModelIndex& index, int role) const;
|
||||
void setItems(QVector<Item> items);
|
||||
Item getItemAtIndex(const int index) const;
|
||||
|
||||
private:
|
||||
QVector<Item> m_items;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
#include "Module.h"
|
||||
|
||||
#include "Controller.h"
|
||||
#include "View.h"
|
||||
|
||||
#include "../../../Core/Engine.h"
|
||||
|
||||
using namespace Status::Modules::Startup::Login;
|
||||
|
||||
Module::Module(std::shared_ptr<ModuleDelegateInterface> delegate,
|
||||
std::shared_ptr<ControllerInterface> controller,
|
||||
std::shared_ptr<ViewInterface> view)
|
||||
: m_delegate(std::move(delegate))
|
||||
, m_controller(std::move(controller))
|
||||
, m_view(std::move(view))
|
||||
{
|
||||
}
|
||||
|
||||
void Module::load()
|
||||
{
|
||||
Engine::instance()->rootContext()->setContextProperty("loginModule", m_view->getQObject());
|
||||
m_controller->init();
|
||||
m_view->load();
|
||||
|
||||
const QVector<Accounts::AccountDto> openedAccounts = m_controller->getOpenedAccounts();
|
||||
if(openedAccounts.size() > 0)
|
||||
{
|
||||
QVector<Item> items;
|
||||
foreach(const Accounts::AccountDto& acc, openedAccounts)
|
||||
{
|
||||
QString thumbnailImage;
|
||||
QString largeImage;
|
||||
extractImages(acc, thumbnailImage, largeImage);
|
||||
items << Item(acc.name, acc.identicon, thumbnailImage, largeImage, acc.keyUid);
|
||||
}
|
||||
|
||||
m_view->setModelItems(items);
|
||||
|
||||
// set the first account as selected one
|
||||
m_controller->setSelectedAccountKeyUid(items[0].getKeyUid());
|
||||
setSelectedAccount(items[0]);
|
||||
}
|
||||
}
|
||||
|
||||
bool Module::isLoaded()
|
||||
{
|
||||
return m_moduleLoaded;
|
||||
}
|
||||
|
||||
void Module::viewDidLoad()
|
||||
{
|
||||
m_moduleLoaded = true;
|
||||
m_delegate->loginDidLoad();
|
||||
}
|
||||
|
||||
void Module::extractImages(const Accounts::AccountDto& account, QString& thumbnailImage, QString& largeImage)
|
||||
{
|
||||
foreach(const Accounts::Image& img, account.images)
|
||||
{
|
||||
if(img.imgType == "thumbnail")
|
||||
{
|
||||
thumbnailImage = img.uri;
|
||||
}
|
||||
else if(img.imgType == "large")
|
||||
{
|
||||
largeImage = img.uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Module::setSelectedAccount(const Item& item)
|
||||
{
|
||||
m_controller->setSelectedAccountKeyUid(item.getKeyUid());
|
||||
m_view->setSelectedAccount(item);
|
||||
}
|
||||
|
||||
void Module::login(const QString& password)
|
||||
{
|
||||
m_controller->login(password);
|
||||
}
|
||||
|
||||
void Module::emitAccountLoginError(const QString& error)
|
||||
{
|
||||
m_view->emitAccountLoginError(error);
|
||||
}
|
||||
|
||||
void Module::emitObtainingPasswordError(const QString& errorDescription)
|
||||
{
|
||||
m_view->emitObtainingPasswordError(errorDescription);
|
||||
}
|
||||
|
||||
void Module::emitObtainingPasswordSuccess(const QString& password)
|
||||
{
|
||||
m_view->emitObtainingPasswordSuccess(password);
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include "ModuleInterface.h"
|
||||
#include "ControllerInterface.h"
|
||||
#include "ViewInterface.h"
|
||||
|
||||
namespace Status::Modules::Startup::Login
|
||||
{
|
||||
|
||||
class Module final : public ModuleAccessInterface
|
||||
, public ControllerDelegateInterface
|
||||
, public ViewDelegateInterface
|
||||
, public std::enable_shared_from_this<Module>
|
||||
{
|
||||
public:
|
||||
Module(std::shared_ptr<ModuleDelegateInterface> delegate,
|
||||
std::shared_ptr<ControllerInterface> controller,
|
||||
std::shared_ptr<ViewInterface> view);
|
||||
|
||||
// Module Access
|
||||
void load() override;
|
||||
bool isLoaded() override;
|
||||
|
||||
// Controller Delegate
|
||||
void emitAccountLoginError(const QString& error) override;
|
||||
void emitObtainingPasswordError(const QString& errorDescription) override;
|
||||
void emitObtainingPasswordSuccess(const QString& password) override;
|
||||
|
||||
// View Delegate
|
||||
void viewDidLoad() override;
|
||||
void setSelectedAccount(const Item& item) override;
|
||||
void login(const QString& password) override;
|
||||
|
||||
private:
|
||||
void checkIfModuleDidLoad();
|
||||
void extractImages(const Accounts::AccountDto& account, QString& thumbnailImage, QString& largeImage);
|
||||
|
||||
private:
|
||||
std::shared_ptr<ModuleDelegateInterface> m_delegate;
|
||||
std::shared_ptr<ControllerInterface> m_controller;
|
||||
std::shared_ptr<ViewInterface> m_view;
|
||||
bool m_moduleLoaded {false};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#include "ModuleBuilder.h"
|
||||
|
||||
#include "Module.h"
|
||||
#include "Controller.h"
|
||||
#include "View.h"
|
||||
|
||||
using namespace Status::Modules::Startup::Login;
|
||||
|
||||
ModuleBuilder::ModuleBuilder(std::shared_ptr<Accounts::ServiceInterface> accountsService,
|
||||
std::shared_ptr<Keychain::ServiceInterface> keychainService)
|
||||
: m_accountsService(std::move(accountsService))
|
||||
, m_keychainService(std::move(keychainService))
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<ModuleAccessInterface> ModuleBuilder::operator()(std::shared_ptr<ModuleDelegateInterface> delegate) {
|
||||
|
||||
auto controller = std::make_shared<Controller>(m_accountsService, m_keychainService);
|
||||
auto view = std::make_shared<View>();
|
||||
|
||||
auto module = std::make_shared<Module>(delegate, controller, view);
|
||||
|
||||
controller->setDelegate(module);
|
||||
view->setDelegate(module);
|
||||
|
||||
return module;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "ModuleInterface.h"
|
||||
|
||||
#include <StatusServices/AccountsService>
|
||||
#include <StatusServices/KeychainService>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Status::Modules::Startup::Login
|
||||
{
|
||||
class ModuleBuilder final
|
||||
{
|
||||
public:
|
||||
ModuleBuilder(std::shared_ptr<Accounts::ServiceInterface> accountsService,
|
||||
std::shared_ptr<Keychain::ServiceInterface> keychainService);
|
||||
|
||||
[[nodiscard]] std::shared_ptr<ModuleAccessInterface> operator()(std::shared_ptr<ModuleDelegateInterface> delegate);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Accounts::ServiceInterface> m_accountsService;
|
||||
std::shared_ptr<Keychain::ServiceInterface> m_keychainService;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
namespace Status::Modules::Startup::Login
|
||||
{
|
||||
class ModuleAccessInterface
|
||||
{
|
||||
public:
|
||||
virtual ~ModuleAccessInterface() = default;
|
||||
|
||||
virtual void load() = 0;
|
||||
virtual bool isLoaded() = 0;
|
||||
};
|
||||
|
||||
class ModuleDelegateInterface
|
||||
{
|
||||
public:
|
||||
virtual void loginDidLoad() = 0;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#include "SelectedAccount.h"
|
||||
|
||||
using namespace Status::Modules::Startup::Login;
|
||||
|
||||
SelectedAccount::SelectedAccount(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void SelectedAccount::setSelectedAccountData(const Item& item)
|
||||
{
|
||||
m_item = item;
|
||||
}
|
||||
|
||||
QString SelectedAccount::getName()
|
||||
{
|
||||
return m_item.getName();
|
||||
}
|
||||
|
||||
QString SelectedAccount::getIdenticon()
|
||||
{
|
||||
return m_item.getIdenticon();
|
||||
}
|
||||
|
||||
QString SelectedAccount::getKeyUid()
|
||||
{
|
||||
return m_item.getKeyUid();
|
||||
}
|
||||
|
||||
QString SelectedAccount::getThumbnailImage()
|
||||
{
|
||||
return m_item.getThumbnailImage();
|
||||
}
|
||||
|
||||
QString SelectedAccount::getLargeImage()
|
||||
{
|
||||
return m_item.getLargeImage();
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include "Item.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::Modules::Startup::Login
|
||||
{
|
||||
class SelectedAccount : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString username READ getName CONSTANT)
|
||||
Q_PROPERTY(QString identicon READ getIdenticon CONSTANT)
|
||||
Q_PROPERTY(QString keyUid READ getKeyUid CONSTANT)
|
||||
Q_PROPERTY(QString thumbnailImage READ getThumbnailImage CONSTANT)
|
||||
Q_PROPERTY(QString largeImage READ getLargeImage CONSTANT)
|
||||
|
||||
public:
|
||||
explicit SelectedAccount(QObject* parent = nullptr);
|
||||
|
||||
void setSelectedAccountData(const Item& item);
|
||||
|
||||
QString getName();
|
||||
QString getIdenticon();
|
||||
QString getKeyUid();
|
||||
QString getThumbnailImage();
|
||||
QString getLargeImage();
|
||||
|
||||
private:
|
||||
Item m_item;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
#include "View.h"
|
||||
|
||||
#include "../../../Core/Engine.h"
|
||||
|
||||
using namespace Status::Modules::Startup::Login;
|
||||
|
||||
View::View() : QObject(nullptr)
|
||||
, m_model(new Model(this))
|
||||
, m_selectedAccount(new SelectedAccount(this))
|
||||
{
|
||||
}
|
||||
|
||||
void View::setDelegate(std::shared_ptr<ViewDelegateInterface> delegate)
|
||||
{
|
||||
m_delegate = std::move(delegate);
|
||||
}
|
||||
|
||||
QObject* View::getQObject()
|
||||
{
|
||||
Engine::instance()->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
return this;
|
||||
}
|
||||
|
||||
void View::load()
|
||||
{
|
||||
m_delegate->viewDidLoad();
|
||||
}
|
||||
|
||||
Model* View::getModel()
|
||||
{
|
||||
Engine::instance()->setObjectOwnership(m_model, QQmlEngine::CppOwnership);
|
||||
return m_model;
|
||||
}
|
||||
|
||||
SelectedAccount* View::getSelectedAccount()
|
||||
{
|
||||
Engine::instance()->setObjectOwnership(m_selectedAccount, QQmlEngine::CppOwnership);
|
||||
return m_selectedAccount;
|
||||
}
|
||||
|
||||
void View::setModelItems(QVector<Item> accounts)
|
||||
{
|
||||
m_model->setItems(std::move(accounts));
|
||||
emit modelChanged();
|
||||
}
|
||||
|
||||
void View::setSelectedAccount(const Item& item)
|
||||
{
|
||||
m_selectedAccount->setSelectedAccountData(item);
|
||||
emit selectedAccountChanged();
|
||||
}
|
||||
|
||||
void View::emitAccountLoginError(const QString& error)
|
||||
{
|
||||
emit accountLoginError(error);
|
||||
}
|
||||
|
||||
void View::emitObtainingPasswordError(const QString& errorDescription)
|
||||
{
|
||||
emit obtainingPasswordError(errorDescription);
|
||||
}
|
||||
|
||||
void View::emitObtainingPasswordSuccess(const QString& password)
|
||||
{
|
||||
emit obtainingPasswordSuccess(password);
|
||||
}
|
||||
|
||||
void View::setSelectedAccountByIndex(const int index)
|
||||
{
|
||||
Item item = m_model->getItemAtIndex(index);
|
||||
m_delegate->setSelectedAccount(item);
|
||||
}
|
||||
|
||||
void View::login(const QString& password)
|
||||
{
|
||||
m_delegate->login(password);
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include "ViewInterface.h"
|
||||
|
||||
namespace Status::Modules::Startup::Login
|
||||
{
|
||||
class View final : public QObject
|
||||
, public ViewInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(SelectedAccount* selectedAccount READ getSelectedAccount NOTIFY selectedAccountChanged)
|
||||
Q_PROPERTY(Model* accountsModel READ getModel NOTIFY modelChanged)
|
||||
|
||||
public:
|
||||
explicit View();
|
||||
void setDelegate(std::shared_ptr<ViewDelegateInterface> delegate);
|
||||
|
||||
// View Interface
|
||||
QObject* getQObject() override;
|
||||
void load() override;
|
||||
Model* getModel() override;
|
||||
void setModelItems(QVector<Item> accounts) override;
|
||||
void setSelectedAccount(const Item& item) override;
|
||||
void emitAccountLoginError(const QString& error) override;
|
||||
void emitObtainingPasswordError(const QString& errorDescription) override;
|
||||
void emitObtainingPasswordSuccess(const QString& password) override;
|
||||
|
||||
Q_INVOKABLE void setSelectedAccountByIndex(const int index);
|
||||
Q_INVOKABLE void login(const QString& password);
|
||||
|
||||
signals:
|
||||
void selectedAccountChanged();
|
||||
void modelChanged();
|
||||
void accountLoginError(const QString& error);
|
||||
void obtainingPasswordError(const QString& errorDescription);
|
||||
void obtainingPasswordSuccess(const QString& password);
|
||||
|
||||
private:
|
||||
SelectedAccount* getSelectedAccount();
|
||||
|
||||
private:
|
||||
std::shared_ptr<ViewDelegateInterface> m_delegate;
|
||||
Model* m_model {nullptr};
|
||||
SelectedAccount* m_selectedAccount {nullptr};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include "Model.h"
|
||||
#include "SelectedAccount.h"
|
||||
|
||||
#include <StatusServices/AccountsService>
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::Modules::Startup::Login
|
||||
{
|
||||
class ViewInterface
|
||||
{
|
||||
public:
|
||||
virtual ~ViewInterface() = default;
|
||||
|
||||
virtual QObject* getQObject() = 0;
|
||||
virtual void load() = 0;
|
||||
virtual Model* getModel() = 0;
|
||||
virtual void setModelItems(QVector<Item> accounts) = 0;
|
||||
virtual void setSelectedAccount(const Item& item) = 0;
|
||||
virtual void emitAccountLoginError(const QString& error) = 0;
|
||||
virtual void emitObtainingPasswordError(const QString& errorDescription) = 0;
|
||||
virtual void emitObtainingPasswordSuccess(const QString& password) = 0;
|
||||
};
|
||||
|
||||
class ViewDelegateInterface
|
||||
{
|
||||
public:
|
||||
virtual void viewDidLoad() = 0;
|
||||
virtual void setSelectedAccount(const Item& item) = 0;
|
||||
virtual void login(const QString& password) = 0;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
#include "Module.h"
|
||||
|
||||
#include "Controller.h"
|
||||
#include "View.h"
|
||||
|
||||
#include "../../Core/Engine.h"
|
||||
|
||||
using namespace Status::Modules::Startup;
|
||||
|
||||
Module::Module(std::shared_ptr<Startup::ModuleDelegateInterface> delegate,
|
||||
std::shared_ptr<ControllerInterface> controller,
|
||||
std::shared_ptr<ViewInterface> view,
|
||||
Onboarding::ModuleBuilder onboardingModuleBuilder,
|
||||
Login::ModuleBuilder loginModuleBuilder)
|
||||
: m_delegate(std::move(delegate))
|
||||
, m_controller(std::move(controller))
|
||||
, m_view(std::move(view))
|
||||
, m_onboardingModuleBuilder(std::move(onboardingModuleBuilder))
|
||||
, m_loginModuleBuilder(std::move(loginModuleBuilder))
|
||||
{
|
||||
}
|
||||
|
||||
void Module::load()
|
||||
{
|
||||
Engine::instance()->rootContext()->setContextProperty("startupModule", m_view->getQObject());
|
||||
m_controller->init();
|
||||
m_view->load();
|
||||
}
|
||||
|
||||
void Module::checkIfModuleDidLoad()
|
||||
{
|
||||
if(!m_onboardingModule->isLoaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(!m_loginModule->isLoaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_delegate->startupDidLoad();
|
||||
}
|
||||
|
||||
void Module::viewDidLoad()
|
||||
{
|
||||
AppState initialAppState(AppState::OnboardingState);
|
||||
if(!m_controller->shouldStartWithOnboardingScreen())
|
||||
{
|
||||
initialAppState = AppState::LoginState;
|
||||
}
|
||||
|
||||
m_view->setAppState(initialAppState);
|
||||
|
||||
|
||||
m_onboardingModule = m_onboardingModuleBuilder(shared_from_this());
|
||||
m_loginModule = m_loginModuleBuilder(shared_from_this());
|
||||
|
||||
m_onboardingModule->load();
|
||||
m_loginModule->load();
|
||||
|
||||
checkIfModuleDidLoad();
|
||||
}
|
||||
|
||||
void Module::onboardingDidLoad()
|
||||
{
|
||||
checkIfModuleDidLoad();
|
||||
}
|
||||
|
||||
void Module::loginDidLoad()
|
||||
{
|
||||
checkIfModuleDidLoad();
|
||||
}
|
||||
|
||||
void Module::userLoggedIn()
|
||||
{
|
||||
m_delegate->userLoggedIn();
|
||||
}
|
||||
|
||||
void Module::moveToAppState()
|
||||
{
|
||||
m_view->setAppState(AppState::MainAppState);
|
||||
}
|
||||
|
||||
void Module::emitLogOutSignal()
|
||||
{
|
||||
m_view->emitLogOut();
|
||||
}
|
||||
|
||||
void Module::emitStartUpUIRaisedSignal()
|
||||
{
|
||||
m_view->emitStartUpUIRaised();
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
|
||||
#include "ModuleInterface.h"
|
||||
#include "ControllerInterface.h"
|
||||
#include "ViewInterface.h"
|
||||
|
||||
#include "Onboarding/ModuleBuilder.h"
|
||||
#include "Onboarding/ModuleInterface.h"
|
||||
#include "Login/ModuleBuilder.h"
|
||||
#include "Login/ModuleInterface.h"
|
||||
|
||||
#include <StatusServices/AccountsService>
|
||||
|
||||
namespace Status::Modules::Startup
|
||||
{
|
||||
|
||||
class Module final : public ModuleAccessInterface
|
||||
, public ControllerDelegateInterface
|
||||
, public ViewDelegateInterface
|
||||
, public std::enable_shared_from_this<Module>
|
||||
, public Onboarding::ModuleDelegateInterface
|
||||
, public Login::ModuleDelegateInterface
|
||||
{
|
||||
public:
|
||||
Module(std::shared_ptr<Startup::ModuleDelegateInterface> delegate,
|
||||
std::shared_ptr<ControllerInterface> controller,
|
||||
std::shared_ptr<ViewInterface> view,
|
||||
Onboarding::ModuleBuilder onboardingModuleBuilder,
|
||||
Login::ModuleBuilder loginModuleBuilder);
|
||||
|
||||
// Module Access
|
||||
void load() override;
|
||||
void moveToAppState() override;
|
||||
void emitStartUpUIRaisedSignal() override;
|
||||
|
||||
// Controller Delegate
|
||||
void userLoggedIn() override;
|
||||
void emitLogOutSignal() override;
|
||||
|
||||
// View Delegate
|
||||
void viewDidLoad() override;
|
||||
|
||||
// Onboarding Module Delegate
|
||||
void onboardingDidLoad() override;
|
||||
|
||||
// Login Module Delegate
|
||||
void loginDidLoad() override;
|
||||
|
||||
private:
|
||||
void checkIfModuleDidLoad();
|
||||
|
||||
private:
|
||||
std::shared_ptr<Startup::ModuleDelegateInterface> m_delegate;
|
||||
std::shared_ptr<ControllerInterface> m_controller;
|
||||
std::shared_ptr<ViewInterface> m_view;
|
||||
|
||||
Onboarding::ModuleBuilder m_onboardingModuleBuilder;
|
||||
std::shared_ptr<Onboarding::ModuleAccessInterface> m_onboardingModule;
|
||||
|
||||
Login::ModuleBuilder m_loginModuleBuilder;
|
||||
std::shared_ptr<Login::ModuleAccessInterface> m_loginModule;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#include "ModuleBuilder.h"
|
||||
|
||||
#include "Module.h"
|
||||
#include "Controller.h"
|
||||
#include "View.h"
|
||||
|
||||
using namespace Status::Modules::Startup;
|
||||
|
||||
ModuleBuilder::ModuleBuilder(std::shared_ptr<Accounts::ServiceInterface> accountsService,
|
||||
Onboarding::ModuleBuilder onboardingModuleBuilder,
|
||||
Login::ModuleBuilder loginModuleBuilder)
|
||||
: m_accountsService(std::move(accountsService))
|
||||
, m_onboardingModuleBuilder(std::move(onboardingModuleBuilder))
|
||||
, m_loginModuleBuilder(std::move(loginModuleBuilder))
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<ModuleAccessInterface> ModuleBuilder::operator()(std::shared_ptr<ModuleDelegateInterface> delegate) {
|
||||
|
||||
auto controller = std::make_shared<Controller>(m_accountsService);
|
||||
auto view = std::make_shared<View>();
|
||||
|
||||
auto module = std::make_shared<Module>(delegate, controller, view,
|
||||
m_onboardingModuleBuilder, m_loginModuleBuilder);
|
||||
|
||||
controller->setDelegate(module);
|
||||
view->setDelegate(module);
|
||||
|
||||
return module;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include "ModuleInterface.h"
|
||||
#include "Onboarding/ModuleBuilder.h"
|
||||
#include "Login/ModuleBuilder.h"
|
||||
|
||||
#include <StatusServices/Accounts/ServiceInterface.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Status::Modules::Startup
|
||||
{
|
||||
class ModuleBuilder final
|
||||
{
|
||||
public:
|
||||
ModuleBuilder(std::shared_ptr<Accounts::ServiceInterface> accountsService,
|
||||
Onboarding::ModuleBuilder onboardingModuleBuilder,
|
||||
Login::ModuleBuilder loginModuleBuilder);
|
||||
|
||||
[[nodiscard]] std::shared_ptr<ModuleAccessInterface> operator()(std::shared_ptr<ModuleDelegateInterface> delegate);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Accounts::ServiceInterface> m_accountsService;
|
||||
Onboarding::ModuleBuilder m_onboardingModuleBuilder;
|
||||
Login::ModuleBuilder m_loginModuleBuilder;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
namespace Status::Modules::Startup
|
||||
{
|
||||
class ModuleAccessInterface
|
||||
{
|
||||
public:
|
||||
virtual ~ModuleAccessInterface() = default;
|
||||
|
||||
virtual void load() = 0;
|
||||
virtual void moveToAppState() = 0;
|
||||
virtual void emitStartUpUIRaisedSignal() = 0;
|
||||
};
|
||||
|
||||
class ModuleDelegateInterface
|
||||
{
|
||||
public:
|
||||
virtual void startupDidLoad() = 0;
|
||||
virtual void userLoggedIn() = 0;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
#include "Controller.h"
|
||||
|
||||
#include "../../../Core/GlobalEvents.h"
|
||||
|
||||
using namespace Status::Modules::Startup::Onboarding;
|
||||
|
||||
Controller::Controller(std::shared_ptr<Accounts::ServiceInterface> accountsService)
|
||||
: QObject(nullptr)
|
||||
, m_delegate(nullptr)
|
||||
, m_accountsService(std::move(accountsService))
|
||||
{
|
||||
}
|
||||
|
||||
void Controller::setDelegate(std::shared_ptr<ControllerDelegateInterface> delegate)
|
||||
{
|
||||
m_delegate = std::move(delegate);
|
||||
}
|
||||
|
||||
void Controller::init()
|
||||
{
|
||||
QObject::connect(&GlobalEvents::instance(), &GlobalEvents::nodeLogin, this, &Controller::onLogin);
|
||||
}
|
||||
|
||||
void Controller::onLogin(const QString& error)
|
||||
{
|
||||
if(!error.isEmpty())
|
||||
{
|
||||
m_delegate->setupAccountError();
|
||||
}
|
||||
}
|
||||
|
||||
const QVector<Status::Accounts::GeneratedAccountDto>& Controller::getGeneratedAccounts() const
|
||||
{
|
||||
return m_accountsService->generatedAccounts();
|
||||
}
|
||||
|
||||
const Status::Accounts::GeneratedAccountDto& Controller::getImportedAccount() const
|
||||
{
|
||||
return m_accountsService->getImportedAccount();
|
||||
}
|
||||
|
||||
void Controller::setSelectedAccountByIndex(const int index)
|
||||
{
|
||||
auto accounts = getGeneratedAccounts();
|
||||
m_selectedAccountId = accounts[index].id;
|
||||
}
|
||||
|
||||
void Controller::storeSelectedAccountAndLogin(const QString& password)
|
||||
{
|
||||
if(!m_accountsService->setupAccount(m_selectedAccountId, password))
|
||||
{
|
||||
m_delegate->setupAccountError();
|
||||
}
|
||||
}
|
||||
|
||||
QString Controller::validateMnemonic(const QString& mnemonic)
|
||||
{
|
||||
return m_accountsService->validateMnemonic(mnemonic);
|
||||
}
|
||||
|
||||
void Controller::importMnemonic(const QString& mnemonic)
|
||||
{
|
||||
if(m_accountsService->importMnemonic(mnemonic))
|
||||
{
|
||||
m_selectedAccountId = getImportedAccount().id;
|
||||
m_delegate->importAccountSuccess();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_delegate->importAccountError();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include "ControllerInterface.h"
|
||||
|
||||
namespace Status::Modules::Startup::Onboarding
|
||||
{
|
||||
class Controller : public QObject,
|
||||
public ControllerInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Controller(std::shared_ptr<Accounts::ServiceInterface> accountsService);
|
||||
void setDelegate(std::shared_ptr<ControllerDelegateInterface> delegate);
|
||||
|
||||
// Controller Interface
|
||||
void init() override;
|
||||
const QVector<Accounts::GeneratedAccountDto>& getGeneratedAccounts() const override;
|
||||
const Accounts::GeneratedAccountDto& getImportedAccount() const override;
|
||||
void setSelectedAccountByIndex(const int index) override;
|
||||
void storeSelectedAccountAndLogin(const QString& password) override;
|
||||
QString validateMnemonic(const QString& mnemonic) override;
|
||||
void importMnemonic(const QString& mnemonic) override;
|
||||
|
||||
private slots:
|
||||
void onLogin(const QString& error);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Accounts::ServiceInterface> m_accountsService;
|
||||
std::shared_ptr<ControllerDelegateInterface> m_delegate;
|
||||
QString m_selectedAccountId;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <StatusServices/AccountsService>
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::Modules::Startup::Onboarding
|
||||
{
|
||||
class ControllerInterface
|
||||
{
|
||||
public:
|
||||
virtual ~ControllerInterface() = default;
|
||||
|
||||
virtual void init() = 0;
|
||||
virtual const QVector<Accounts::GeneratedAccountDto>& getGeneratedAccounts() const = 0;
|
||||
virtual void setSelectedAccountByIndex(const int index) = 0;
|
||||
virtual void storeSelectedAccountAndLogin(const QString& password) = 0;
|
||||
virtual const Accounts::GeneratedAccountDto& getImportedAccount() const = 0;
|
||||
virtual QString validateMnemonic(const QString& mnemonic) = 0;
|
||||
virtual void importMnemonic(const QString& mnemonic) = 0;
|
||||
};
|
||||
|
||||
class ControllerDelegateInterface
|
||||
{
|
||||
public:
|
||||
virtual void importAccountError() = 0;
|
||||
virtual void setupAccountError() = 0;
|
||||
virtual void importAccountSuccess() = 0;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#include "Item.h"
|
||||
|
||||
using namespace Status::Modules::Startup::Onboarding;
|
||||
|
||||
Item::Item(const QString& id, const QString& alias, const QString& identicon, const QString& address,
|
||||
const QString& keyUid)
|
||||
: m_id(id)
|
||||
, m_alias(alias)
|
||||
, m_identicon(identicon)
|
||||
, m_address(address)
|
||||
, m_keyUid(keyUid)
|
||||
{
|
||||
}
|
||||
|
||||
QString Item::getId() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
QString Item::getAlias() const
|
||||
{
|
||||
return m_alias;
|
||||
}
|
||||
|
||||
QString Item::getIdenticon() const
|
||||
{
|
||||
return m_identicon;
|
||||
}
|
||||
|
||||
QString Item::getAddress() const
|
||||
{
|
||||
return m_address;
|
||||
}
|
||||
|
||||
QString Item::getKeyUid() const
|
||||
{
|
||||
return m_keyUid;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::Modules::Startup::Onboarding
|
||||
{
|
||||
class Item
|
||||
{
|
||||
public:
|
||||
Item(const QString& id, const QString& alias, const QString& identicon, const QString& address,
|
||||
const QString& keyUid);
|
||||
|
||||
QString getId() const;
|
||||
QString getAlias() const;
|
||||
QString getIdenticon() const;
|
||||
QString getAddress() const;
|
||||
QString getKeyUid() const;
|
||||
|
||||
private:
|
||||
QString m_id;
|
||||
QString m_alias;
|
||||
QString m_identicon;
|
||||
QString m_address;
|
||||
QString m_keyUid;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
#include "Model.h"
|
||||
|
||||
using namespace Status::Modules::Startup::Onboarding;
|
||||
|
||||
Model::Model(QObject* parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> Model::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[Id] = "accountId";
|
||||
roles[Alias] = "username";
|
||||
roles[Identicon] = "identicon";
|
||||
roles[Address] = "address";
|
||||
roles[KeyUid] = "keyUid";
|
||||
return roles;
|
||||
}
|
||||
|
||||
int Model::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return m_items.size();
|
||||
}
|
||||
|
||||
QVariant Model::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if(!index.isValid())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if(index.row() < 0 || index.row() > m_items.size())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Item item = m_items[index.row()];
|
||||
|
||||
switch(role)
|
||||
{
|
||||
case Id:
|
||||
return item.getId();
|
||||
case Alias:
|
||||
return item.getAlias();
|
||||
case Identicon:
|
||||
return item.getIdenticon();
|
||||
case Address:
|
||||
return item.getAddress();
|
||||
case KeyUid:
|
||||
return item.getKeyUid();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void Model::setItems(QVector<Item> items)
|
||||
{
|
||||
beginResetModel();
|
||||
m_items = std::move(items);
|
||||
endResetModel();
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "Item.h"
|
||||
|
||||
namespace Status::Modules::Startup::Onboarding
|
||||
{
|
||||
class Model : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ModelRole
|
||||
{
|
||||
Id = Qt::UserRole + 1,
|
||||
Alias,
|
||||
Identicon,
|
||||
Address,
|
||||
KeyUid
|
||||
};
|
||||
|
||||
explicit Model(QObject* parent = nullptr);
|
||||
QHash<int, QByteArray> roleNames() const;
|
||||
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||
virtual QVariant data(const QModelIndex& index, int role) const;
|
||||
void setItems(QVector<Item> items);
|
||||
|
||||
private:
|
||||
QVector<Item> m_items;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
#include "Module.h"
|
||||
|
||||
#include "Controller.h"
|
||||
#include "View.h"
|
||||
|
||||
#include "../../../Core/Engine.h"
|
||||
|
||||
using namespace Status::Modules::Startup::Onboarding;
|
||||
|
||||
Module::Module(std::shared_ptr<ModuleDelegateInterface> delegate,
|
||||
std::shared_ptr<ControllerInterface> controller,
|
||||
std::shared_ptr<ViewInterface> view)
|
||||
: m_delegate(std::move(delegate))
|
||||
, m_controller(std::move(controller))
|
||||
, m_view(std::move(view))
|
||||
{
|
||||
}
|
||||
|
||||
void Module::load()
|
||||
{
|
||||
Engine::instance()->rootContext()->setContextProperty("onboardingModule", m_view->getQObject());
|
||||
m_controller->init();
|
||||
m_view->load();
|
||||
|
||||
const QVector<Accounts::GeneratedAccountDto>& gAcc = m_controller->getGeneratedAccounts();
|
||||
QVector<Item> accounts;
|
||||
foreach(const Accounts::GeneratedAccountDto& acc, gAcc)
|
||||
{
|
||||
accounts << Item(acc.id, acc.alias, acc.identicon, acc.address, acc.keyUid);
|
||||
}
|
||||
|
||||
m_view->setAccountList(accounts);
|
||||
}
|
||||
|
||||
bool Module::isLoaded()
|
||||
{
|
||||
return m_moduleLoaded;
|
||||
}
|
||||
|
||||
void Module::viewDidLoad()
|
||||
{
|
||||
m_moduleLoaded = true;
|
||||
m_delegate->onboardingDidLoad();
|
||||
}
|
||||
|
||||
void Module::setSelectedAccountByIndex(const int index)
|
||||
{
|
||||
m_controller->setSelectedAccountByIndex(index);
|
||||
}
|
||||
|
||||
void Module::storeSelectedAccountAndLogin(const QString& password)
|
||||
{
|
||||
m_controller->storeSelectedAccountAndLogin(password);
|
||||
}
|
||||
void Module::setupAccountError()
|
||||
{
|
||||
m_view->setupAccountError();
|
||||
}
|
||||
|
||||
const Status::Accounts::GeneratedAccountDto& Module::getImportedAccount() const
|
||||
{
|
||||
return m_controller->getImportedAccount();
|
||||
}
|
||||
|
||||
QString Module::validateMnemonic(const QString& mnemonic)
|
||||
{
|
||||
return m_controller->validateMnemonic(mnemonic);
|
||||
}
|
||||
|
||||
void Module::importMnemonic(const QString& mnemonic)
|
||||
{
|
||||
m_controller->importMnemonic(mnemonic);
|
||||
}
|
||||
|
||||
void Module::importAccountError()
|
||||
{
|
||||
m_view->importAccountError();
|
||||
}
|
||||
|
||||
void Module::importAccountSuccess()
|
||||
{
|
||||
m_view->importAccountSuccess();
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include "ModuleInterface.h"
|
||||
#include "ControllerInterface.h"
|
||||
#include "ViewInterface.h"
|
||||
|
||||
namespace Status::Modules::Startup::Onboarding
|
||||
{
|
||||
|
||||
class Module final : public ModuleAccessInterface
|
||||
, public ControllerDelegateInterface
|
||||
, public ViewDelegateInterface
|
||||
, public std::enable_shared_from_this<Module>
|
||||
{
|
||||
public:
|
||||
Module(std::shared_ptr<ModuleDelegateInterface> delegate,
|
||||
std::shared_ptr<ControllerInterface> controller,
|
||||
std::shared_ptr<ViewInterface> view);
|
||||
|
||||
// Module Access
|
||||
void load() override;
|
||||
bool isLoaded() override;
|
||||
|
||||
// Controller Delegate
|
||||
void importAccountError() override;
|
||||
void setupAccountError() override;
|
||||
void importAccountSuccess() override;
|
||||
|
||||
// View Delegate
|
||||
void viewDidLoad() override;
|
||||
void setSelectedAccountByIndex(const int index) override;
|
||||
void storeSelectedAccountAndLogin(const QString& password) override;
|
||||
const Accounts::GeneratedAccountDto& getImportedAccount() const override;
|
||||
QString validateMnemonic(const QString& mnemonic) override;
|
||||
void importMnemonic(const QString& mnemonic) override;
|
||||
|
||||
private:
|
||||
void checkIfModuleDidLoad();
|
||||
|
||||
private:
|
||||
std::shared_ptr<ModuleDelegateInterface> m_delegate;
|
||||
std::shared_ptr<ControllerInterface> m_controller;
|
||||
std::shared_ptr<ViewInterface> m_view;
|
||||
bool m_moduleLoaded {false};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#include "ModuleBuilder.h"
|
||||
|
||||
#include "Module.h"
|
||||
#include "Controller.h"
|
||||
#include "View.h"
|
||||
|
||||
using namespace Status::Modules::Startup::Onboarding;
|
||||
|
||||
ModuleBuilder::ModuleBuilder(std::shared_ptr<Accounts::ServiceInterface> accountsService)
|
||||
: m_accountsService(std::move(accountsService))
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<ModuleAccessInterface> ModuleBuilder::operator()(std::shared_ptr<ModuleDelegateInterface> delegate) {
|
||||
|
||||
auto controller = std::make_shared<Controller>(m_accountsService);
|
||||
auto view = std::make_shared<View>();
|
||||
|
||||
auto module = std::make_shared<Module>(delegate, controller, view);
|
||||
|
||||
controller->setDelegate(module);
|
||||
view->setDelegate(module);
|
||||
|
||||
return module;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "ModuleInterface.h"
|
||||
|
||||
#include <StatusServices/AccountsService>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Status::Modules::Startup::Onboarding
|
||||
{
|
||||
class ModuleBuilder final
|
||||
{
|
||||
public:
|
||||
ModuleBuilder(std::shared_ptr<Accounts::ServiceInterface> accountsService);
|
||||
|
||||
[[nodiscard]] std::shared_ptr<ModuleAccessInterface> operator()(std::shared_ptr<ModuleDelegateInterface> delegate);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Accounts::ServiceInterface> m_accountsService;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
namespace Status::Modules::Startup::Onboarding
|
||||
{
|
||||
class ModuleAccessInterface
|
||||
{
|
||||
public:
|
||||
virtual ~ModuleAccessInterface() = default;
|
||||
|
||||
virtual void load() = 0;
|
||||
virtual bool isLoaded() = 0;
|
||||
};
|
||||
|
||||
class ModuleDelegateInterface
|
||||
{
|
||||
public:
|
||||
virtual void onboardingDidLoad() = 0;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
#include "View.h"
|
||||
|
||||
#include "../../../Core/Engine.h"
|
||||
|
||||
using namespace Status::Modules::Startup::Onboarding;
|
||||
|
||||
View::View() : QObject(nullptr)
|
||||
, m_model(new Model(this))
|
||||
{
|
||||
}
|
||||
|
||||
void View::setDelegate(std::shared_ptr<ViewDelegateInterface> delegate)
|
||||
{
|
||||
m_delegate = std::move(delegate);
|
||||
}
|
||||
|
||||
QObject* View::getQObject()
|
||||
{
|
||||
Engine::instance()->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
return this;
|
||||
}
|
||||
|
||||
void View::load()
|
||||
{
|
||||
m_delegate->viewDidLoad();
|
||||
}
|
||||
|
||||
Model* View::getModel()
|
||||
{
|
||||
Engine::instance()->setObjectOwnership(m_model, QQmlEngine::CppOwnership);
|
||||
return m_model;
|
||||
}
|
||||
|
||||
void View::setAccountList(QVector<Item> accounts)
|
||||
{
|
||||
m_model->setItems(std::move(accounts));
|
||||
emit modelChanged();
|
||||
}
|
||||
|
||||
QString View::getImportedAccountIdenticon() const
|
||||
{
|
||||
return m_delegate->getImportedAccount().identicon;
|
||||
}
|
||||
|
||||
QString View::getImportedAccountAlias() const
|
||||
{
|
||||
return m_delegate->getImportedAccount().alias;
|
||||
}
|
||||
|
||||
QString View::getImportedAccountAddress() const
|
||||
{
|
||||
return m_delegate->getImportedAccount().address;
|
||||
}
|
||||
|
||||
void View::setSelectedAccountByIndex(const int index)
|
||||
{
|
||||
m_delegate->setSelectedAccountByIndex(index);
|
||||
}
|
||||
|
||||
void View::storeSelectedAccountAndLogin(const QString& password)
|
||||
{
|
||||
m_delegate->storeSelectedAccountAndLogin(password);
|
||||
}
|
||||
|
||||
void View::setupAccountError()
|
||||
{
|
||||
emit accountSetupError();
|
||||
}
|
||||
|
||||
QString View::validateMnemonic(const QString& mnemonic)
|
||||
{
|
||||
return m_delegate->validateMnemonic(mnemonic);
|
||||
}
|
||||
|
||||
void View::importMnemonic(const QString& mnemonic)
|
||||
{
|
||||
m_delegate->importMnemonic(mnemonic);
|
||||
}
|
||||
|
||||
void View::importAccountError()
|
||||
{
|
||||
// In QML we can connect to this signal and notify a user
|
||||
// before refactoring we didn't have this signal
|
||||
emit accountImportError();
|
||||
}
|
||||
|
||||
void View::importAccountSuccess()
|
||||
{
|
||||
emit importedAccountChanged();
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
|
||||
#include "ViewInterface.h"
|
||||
|
||||
namespace Status::Modules::Startup::Onboarding
|
||||
{
|
||||
class View final : public QObject
|
||||
, public ViewInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(Model* accountsModel READ getModel NOTIFY modelChanged)
|
||||
Q_PROPERTY(QString importedAccountIdenticon READ getImportedAccountIdenticon NOTIFY importedAccountChanged)
|
||||
Q_PROPERTY(QString importedAccountAlias READ getImportedAccountAlias NOTIFY importedAccountChanged)
|
||||
Q_PROPERTY(QString importedAccountAddress READ getImportedAccountAddress NOTIFY importedAccountChanged)
|
||||
|
||||
public:
|
||||
explicit View();
|
||||
void setDelegate(std::shared_ptr<ViewDelegateInterface> delegate);
|
||||
|
||||
// View Interface
|
||||
QObject* getQObject() override;
|
||||
void load() override;
|
||||
Model* getModel() override;
|
||||
void setAccountList(QVector<Item> accounts) override;
|
||||
void importAccountError() override;
|
||||
void setupAccountError() override;
|
||||
void importAccountSuccess() override;
|
||||
|
||||
QString getImportedAccountIdenticon() const;
|
||||
QString getImportedAccountAlias() const;
|
||||
QString getImportedAccountAddress() const;
|
||||
|
||||
Q_INVOKABLE void setSelectedAccountByIndex(const int index);
|
||||
Q_INVOKABLE void storeSelectedAccountAndLogin(const QString& password);
|
||||
Q_INVOKABLE QString validateMnemonic(const QString& mnemonic);
|
||||
Q_INVOKABLE void importMnemonic(const QString& mnemonic);
|
||||
|
||||
signals:
|
||||
void modelChanged();
|
||||
void importedAccountChanged();
|
||||
void accountSetupError();
|
||||
void accountImportError();
|
||||
|
||||
private:
|
||||
std::shared_ptr<ViewDelegateInterface> m_delegate;
|
||||
Model* m_model {nullptr};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include "Model.h"
|
||||
|
||||
#include <StatusServices/AccountsService>
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::Modules::Startup::Onboarding
|
||||
{
|
||||
class ViewInterface
|
||||
{
|
||||
public:
|
||||
virtual ~ViewInterface() = default;
|
||||
|
||||
virtual QObject* getQObject() = 0;
|
||||
virtual void load() = 0;
|
||||
virtual Model* getModel() = 0;
|
||||
virtual void setAccountList(QVector<Item> accounts) = 0;
|
||||
virtual void importAccountError() = 0;
|
||||
virtual void setupAccountError() = 0;
|
||||
virtual void importAccountSuccess() = 0;
|
||||
};
|
||||
|
||||
class ViewDelegateInterface
|
||||
{
|
||||
public:
|
||||
virtual void viewDidLoad() = 0;
|
||||
virtual void setSelectedAccountByIndex(const int index) = 0;
|
||||
virtual void storeSelectedAccountAndLogin(const QString& password) = 0;
|
||||
virtual const Accounts::GeneratedAccountDto& getImportedAccount() const = 0;
|
||||
virtual QString validateMnemonic(const QString& mnemonic) = 0;
|
||||
virtual void importMnemonic(const QString& mnemonic) = 0;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
#include "View.h"
|
||||
|
||||
#include "../../Core/Engine.h"
|
||||
|
||||
using namespace Status::Modules::Startup;
|
||||
|
||||
View::View() : QObject(nullptr)
|
||||
, m_appState(AppState::OnboardingState)
|
||||
{
|
||||
}
|
||||
|
||||
void View::setDelegate(std::shared_ptr<ViewDelegateInterface> delegate)
|
||||
{
|
||||
m_delegate = std::move(delegate);
|
||||
}
|
||||
|
||||
QObject* View::getQObject()
|
||||
{
|
||||
Engine::instance()->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
return this;
|
||||
}
|
||||
|
||||
void View::load()
|
||||
{
|
||||
m_delegate->viewDidLoad();
|
||||
}
|
||||
|
||||
int View::getAppState()
|
||||
{
|
||||
return static_cast<int>(m_appState);
|
||||
}
|
||||
|
||||
void View::setAppState(AppState state)
|
||||
{
|
||||
if(m_appState == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_appState = state;
|
||||
emit appStateChanged(m_appState);
|
||||
}
|
||||
|
||||
void View::emitLogOut()
|
||||
{
|
||||
emit logOut();
|
||||
}
|
||||
|
||||
void View::emitStartUpUIRaised()
|
||||
{
|
||||
emit startUpUIRaised();
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "ViewInterface.h"
|
||||
|
||||
namespace Status::Modules::Startup
|
||||
{
|
||||
class View final : public QObject
|
||||
, public ViewInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(int appState READ getAppState NOTIFY appStateChanged)
|
||||
|
||||
public:
|
||||
explicit View();
|
||||
void setDelegate(std::shared_ptr<ViewDelegateInterface> delegate);
|
||||
|
||||
// View Interface
|
||||
QObject* getQObject() override;
|
||||
void emitLogOut() override;
|
||||
void emitStartUpUIRaised() override;
|
||||
void setAppState(AppState state) override;
|
||||
void load() override;
|
||||
|
||||
public slots:
|
||||
int getAppState();
|
||||
|
||||
signals:
|
||||
void appStateChanged(int state);
|
||||
void logOut();
|
||||
void startUpUIRaised();
|
||||
|
||||
private:
|
||||
std::shared_ptr<ViewDelegateInterface> m_delegate;
|
||||
AppState m_appState;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::Modules::Startup
|
||||
{
|
||||
enum AppState
|
||||
{
|
||||
OnboardingState = 0,
|
||||
LoginState = 1,
|
||||
MainAppState = 2
|
||||
// TODO: is Pending
|
||||
};
|
||||
|
||||
class ViewInterface
|
||||
{
|
||||
public:
|
||||
virtual ~ViewInterface() = default;
|
||||
|
||||
virtual QObject* getQObject() = 0;
|
||||
virtual void emitLogOut() = 0;
|
||||
virtual void emitStartUpUIRaised() = 0;
|
||||
virtual void setAppState(AppState state) = 0;
|
||||
virtual void load() = 0;
|
||||
};
|
||||
|
||||
class ViewDelegateInterface
|
||||
{
|
||||
public:
|
||||
virtual void viewDidLoad() = 0;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
|
||||
|
||||
project(Status.Backend DESCRIPTION "Status project used to integrate with status-go")
|
||||
|
||||
set(CMAKE_DEBUG_POSTFIX d)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
add_library(${PROJECT_NAME} SHARED)
|
||||
|
||||
file(
|
||||
GLOB_RECURSE SOURCES
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
)
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC include)
|
||||
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
Qt5::Core
|
||||
${STATUS_GO_LIB}
|
||||
)
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Backend::Accounts
|
||||
{
|
||||
RpcResponse<QJsonArray> generateAddresses(const QVector<QString>& paths);
|
||||
|
||||
RpcResponse<QString> generateIdenticon(const QString& publicKey);
|
||||
|
||||
RpcResponse<QString> generateAlias(const QString& publicKey);
|
||||
|
||||
RpcResponse<QJsonObject> storeDerivedAccounts(const QString& accountId, const QString& hashedPassword,
|
||||
const QVector<QString>& paths);
|
||||
|
||||
RpcResponse<QJsonObject> saveAccountAndLogin(const QString& hashedPassword, const QJsonObject& account,
|
||||
const QJsonArray& subaccounts, const QJsonObject& settings,
|
||||
const QJsonObject& nodeConfig);
|
||||
|
||||
RpcResponse<QJsonArray> openAccounts(const QString& path);
|
||||
|
||||
RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const QString& hashedPassword,
|
||||
const QString& identicon, const QString& thumbnail, const QString& large);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Backend
|
||||
{
|
||||
// Used in calls where we don't have version and id returned from `status-go`
|
||||
static QString DefaultVersion = "2.0";
|
||||
static constexpr int DefaultId = 0;
|
||||
|
||||
struct RpcError
|
||||
{
|
||||
int code;
|
||||
QString message;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct RpcResponse
|
||||
{
|
||||
T result;
|
||||
QString jsonRpcVersion;
|
||||
int id;
|
||||
RpcError error;
|
||||
|
||||
RpcResponse(T result, QString version = DefaultVersion, int id = DefaultId,
|
||||
RpcError error = RpcError{-1, QString()})
|
||||
: result(result)
|
||||
, jsonRpcVersion(version)
|
||||
, id(id)
|
||||
, error(error)
|
||||
{ }
|
||||
|
||||
bool containsError() const {
|
||||
return !error.message.isEmpty();
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
#include "libstatus.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Backend
|
||||
{
|
||||
namespace Param {
|
||||
const QString Id = "id";
|
||||
const QString JsonRpc = "jsonrpc";
|
||||
const QString Result = "result";
|
||||
const QString Error = "error";
|
||||
const QString ErrorMessage = "message";
|
||||
const QString ErrorCode = "code";
|
||||
}
|
||||
|
||||
class Utils
|
||||
{
|
||||
public:
|
||||
template<class T> static QByteArray jsonToByteArray(const T& json){
|
||||
if constexpr (std::is_same_v<T, QJsonObject> ||
|
||||
std::is_same_v<T, QJsonArray>)
|
||||
{
|
||||
return QJsonDocument(json).toJson(QJsonDocument::Compact);
|
||||
}
|
||||
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
static QJsonArray toJsonArray(const QVector<QString>& value){
|
||||
QJsonArray array;
|
||||
for(auto& v : value)
|
||||
array << v;
|
||||
return array;
|
||||
}
|
||||
|
||||
template<class T> static bool checkReceivedResponse(const QString& response, T& json)
|
||||
{
|
||||
QJsonParseError error;
|
||||
auto jsonDocument = QJsonDocument::fromJson(response.toUtf8(), &error);
|
||||
|
||||
if (error.error != QJsonParseError::NoError)
|
||||
return false;
|
||||
|
||||
if constexpr (std::is_same_v<T, QJsonObject>)
|
||||
{
|
||||
json = jsonDocument.object();
|
||||
return true;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, QJsonArray>)
|
||||
{
|
||||
json = jsonDocument.array();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T> static RpcResponse<T> buildJsonRpcResponse(const T& json) {
|
||||
auto response = RpcResponse<T>(T());
|
||||
|
||||
if constexpr (std::is_same_v<T, QJsonObject>)
|
||||
{
|
||||
if (!json[Param::Id].isNull() && !json[Param::Id].isUndefined())
|
||||
response.id = json[Param::Id].toInt();
|
||||
|
||||
if (!json[Param::JsonRpc].isNull() && !json[Param::JsonRpc].isUndefined())
|
||||
response.jsonRpcVersion = json[Param::JsonRpc].toString();
|
||||
|
||||
if (!json[Param::Error].isNull() && !json[Param::Error].isUndefined())
|
||||
{
|
||||
auto errObj = json[Param::Id].toObject();
|
||||
if (!errObj[Param::ErrorCode].isNull() && !errObj[Param::ErrorCode].isUndefined())
|
||||
response.error.code = errObj[Param::ErrorCode].toInt();
|
||||
if (!errObj[Param::ErrorMessage].isNull() && !errObj[Param::ErrorMessage].isUndefined())
|
||||
response.error.message = errObj[Param::ErrorMessage].toString();
|
||||
}
|
||||
|
||||
if (!json[Param::Result].isNull() && !json[Param::Result].isUndefined())
|
||||
response.result = json[Param::Result].toObject();
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, QJsonArray>)
|
||||
{
|
||||
response.result = json;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
template<class T> static RpcResponse<T> callPrivateRpc(const QByteArray& payload)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto result = CallPrivateRPC(const_cast<QByteArray&>(payload).data());
|
||||
T jsonResult;
|
||||
if(!Utils::checkReceivedResponse(result, jsonResult))
|
||||
{
|
||||
auto msg = QObject::tr("parsing response failed");
|
||||
throw std::domain_error(msg.toStdString());
|
||||
}
|
||||
|
||||
return Utils::buildJsonRpcResponse(jsonResult);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
auto response = RpcResponse<T>(T());
|
||||
response.error.message = QObject::tr("an error executing rpc call occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
auto response = RpcResponse<T>(T());
|
||||
response.error.message = QObject::tr("an error executing rpc call");
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
static QString hashString(QString str) {
|
||||
return "0x" + QString::fromUtf8(QCryptographicHash::hash(str.toUtf8(),
|
||||
QCryptographicHash::Keccak_256).toHex());
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Backend::Wallet::Accounts
|
||||
{
|
||||
RpcResponse<QJsonArray> getAccounts();
|
||||
|
||||
RpcResponse<QJsonObject> generateNewAccount(const QString& password, const QString& accountName,
|
||||
const QString& color);
|
||||
|
||||
RpcResponse<QJsonObject> addAccountsFromPrivateKey(const QString& privateKey, const QString& password,
|
||||
const QString& accountName, const QString& color);
|
||||
|
||||
RpcResponse<QJsonObject> addAccountsFromSeed(const QString& seedPhrase, const QString& password,
|
||||
const QString& accountName, const QString& color);
|
||||
|
||||
RpcResponse<QJsonObject> addWatchOnlyAccount(const QString& address, const QString& accountName,
|
||||
const QString& color);
|
||||
|
||||
RpcResponse<QJsonObject> deleteAccount(const QString& address);
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
#include "StatusBackend/Accounts.h"
|
||||
|
||||
#include "StatusBackend/Utils.h"
|
||||
#include "libstatus.h"
|
||||
|
||||
const int NUMBER_OF_ADDRESSES_TO_GENERATE = 5;
|
||||
const int MNEMONIC_PHRASE_LENGTH = 12;
|
||||
|
||||
using namespace Backend;
|
||||
|
||||
RpcResponse<QJsonArray> Accounts::generateAddresses(const QVector<QString>& paths)
|
||||
{
|
||||
QJsonObject payload{
|
||||
{"n", NUMBER_OF_ADDRESSES_TO_GENERATE},
|
||||
{"mnemonicPhraseLength", MNEMONIC_PHRASE_LENGTH},
|
||||
{"bip32Passphrase", ""},
|
||||
{"paths", Utils::toJsonArray(paths)}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
auto result = MultiAccountGenerateAndDeriveAddresses(Utils::jsonToByteArray(std::move(payload)).data());
|
||||
QJsonArray jsonResult;
|
||||
if(!Utils::checkReceivedResponse(result, jsonResult))
|
||||
{
|
||||
auto msg = QObject::tr("parsing response failed");
|
||||
throw std::domain_error(msg.toStdString());
|
||||
}
|
||||
|
||||
return Utils::buildJsonRpcResponse(jsonResult);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
auto response = RpcResponse<QJsonArray>(QJsonArray());
|
||||
response.error.message = QObject::tr("an error generating address occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
auto response = RpcResponse<QJsonArray>(QJsonArray());
|
||||
response.error.message = QObject::tr("an error generating address occurred");
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
RpcResponse<QString> Accounts::generateIdenticon(const QString& publicKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
QString identicon;
|
||||
if(!publicKey.isEmpty())
|
||||
{
|
||||
identicon = Identicon(publicKey.toUtf8().data());
|
||||
}
|
||||
return Utils::buildJsonRpcResponse(identicon);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
auto response = RpcResponse<QString>(QString());
|
||||
response.error.message = QObject::tr("an error generating identicon occurred");
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
RpcResponse<QString> Accounts::generateAlias(const QString& publicKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
QString alias;
|
||||
if(!publicKey.isEmpty())
|
||||
{
|
||||
alias = GenerateAlias(publicKey.toUtf8().data());
|
||||
}
|
||||
|
||||
return Utils::buildJsonRpcResponse(alias);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
auto response = RpcResponse<QString>(QString());
|
||||
response.error.message = QObject::tr("an error generating alias occurred");
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> Accounts::storeDerivedAccounts(const QString& id, const QString& hashedPassword,
|
||||
const QVector<QString>& paths)
|
||||
{
|
||||
QJsonObject payload{
|
||||
{"accountID", id},
|
||||
{"paths", Utils::toJsonArray(paths)},
|
||||
{"password", hashedPassword}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
auto result = MultiAccountStoreDerivedAccounts(Utils::jsonToByteArray(std::move(payload)).data());
|
||||
QJsonObject jsonResult;
|
||||
if(!Utils::checkReceivedResponse(result, jsonResult))
|
||||
{
|
||||
auto msg = QObject::tr("parsing response failed");
|
||||
throw std::domain_error(msg.toStdString());
|
||||
}
|
||||
|
||||
return Utils::buildJsonRpcResponse(jsonResult);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error storing derived accounts occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error storing derived accounts occurred");
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> Accounts::saveAccountAndLogin(const QString& hashedPassword, const QJsonObject& account,
|
||||
const QJsonArray& subaccounts, const QJsonObject& settings,
|
||||
const QJsonObject& nodeConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto result = SaveAccountAndLogin(Utils::jsonToByteArray(std::move(account)).data(),
|
||||
hashedPassword.toUtf8().data(),
|
||||
Utils::jsonToByteArray(std::move(settings)).data(),
|
||||
Utils::jsonToByteArray(std::move(nodeConfig)).data(),
|
||||
Utils::jsonToByteArray(std::move(subaccounts)).data());
|
||||
QJsonObject jsonResult;
|
||||
if(!Utils::checkReceivedResponse(result, jsonResult))
|
||||
{
|
||||
auto msg = QObject::tr("parsing response failed");
|
||||
throw std::domain_error(msg.toStdString());
|
||||
}
|
||||
|
||||
return Utils::buildJsonRpcResponse(jsonResult);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error saving account and login occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error saving account and login occurred");
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
Backend::RpcResponse<QJsonArray> Backend::Accounts::openAccounts(const QString& path)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto result = OpenAccounts(path.toUtf8().data());
|
||||
QJsonArray jsonResult;
|
||||
if(!Utils::checkReceivedResponse(result, jsonResult))
|
||||
{
|
||||
auto msg = QObject::tr("parsing response failed");
|
||||
throw std::domain_error(msg.toStdString());
|
||||
}
|
||||
|
||||
return Utils::buildJsonRpcResponse(jsonResult);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
auto response = RpcResponse<QJsonArray>(QJsonArray());
|
||||
response.error.message = QObject::tr("an error opening accounts occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
auto response = RpcResponse<QJsonArray>(QJsonArray());
|
||||
response.error.message = QObject::tr("an error opening accounts occurred");
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> Accounts::login(const QString& name, const QString& keyUid, const QString& hashedPassword,
|
||||
const QString& identicon, const QString& thumbnail, const QString& large)
|
||||
{
|
||||
QJsonObject payload{
|
||||
{"name", name},
|
||||
{"key-uid", keyUid},
|
||||
{"identityImage", QJsonValue()},
|
||||
{"identicon", identicon}
|
||||
};
|
||||
|
||||
if(!thumbnail.isEmpty() && !large.isEmpty())
|
||||
{
|
||||
payload["identityImage"] = QJsonObject{{"thumbnail", thumbnail}, {"large", large}};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto result = Login(Utils::jsonToByteArray(std::move(payload)).data(), hashedPassword.toUtf8().data());
|
||||
QJsonObject jsonResult;
|
||||
if(!Utils::checkReceivedResponse(result, jsonResult))
|
||||
{
|
||||
auto msg = QObject::tr("parsing response failed");
|
||||
throw std::domain_error(msg.toStdString());
|
||||
}
|
||||
|
||||
return Utils::buildJsonRpcResponse(jsonResult);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error logining in account occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error logining in account occurred");
|
||||
return response;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
#include "StatusBackend/WalletAccounts.h"
|
||||
|
||||
#include "StatusBackend/Utils.h"
|
||||
|
||||
using namespace Backend;
|
||||
|
||||
RpcResponse<QJsonArray> Wallet::Accounts::getAccounts()
|
||||
{
|
||||
QJsonObject payload{
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "accounts_getAccounts"},
|
||||
{"params", QJsonValue()}
|
||||
};
|
||||
|
||||
return Utils::callPrivateRpc<QJsonArray>(Utils::jsonToByteArray(std::move(payload)));
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> Wallet::Accounts::generateNewAccount(const QString& password, const QString& accountName, const QString& color)
|
||||
{
|
||||
QString hashedPassword(Utils::hashString(password));
|
||||
QJsonArray params = {
|
||||
hashedPassword,
|
||||
accountName,
|
||||
color
|
||||
};
|
||||
|
||||
QJsonObject payload{
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "accounts_generateAccount"},
|
||||
{"params", params}
|
||||
};
|
||||
|
||||
return Utils::callPrivateRpc<QJsonObject>(Utils::jsonToByteArray(std::move(payload)));
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> Wallet::Accounts::addAccountsFromPrivateKey(const QString& privateKey, const QString& password,
|
||||
const QString& accountName, const QString& color)
|
||||
{
|
||||
QString hashedPassword(Utils::hashString(password));
|
||||
QJsonArray params = {
|
||||
privateKey,
|
||||
hashedPassword,
|
||||
accountName,
|
||||
color
|
||||
};
|
||||
|
||||
QJsonObject payload{
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "accounts_addAccountWithMnemonic"},
|
||||
{"params", params}
|
||||
};
|
||||
|
||||
return Utils::callPrivateRpc<QJsonObject>(Utils::jsonToByteArray(std::move(payload)));
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> Wallet::Accounts::addAccountsFromSeed(const QString& seedPhrase, const QString& password, const QString& accountName, const QString& color)
|
||||
{
|
||||
QString hashedPassword(Utils::hashString(password));
|
||||
|
||||
QJsonArray params = {
|
||||
seedPhrase,
|
||||
hashedPassword,
|
||||
accountName,
|
||||
color
|
||||
};
|
||||
|
||||
QJsonObject payload {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "accounts_addAccountWithPrivateKey"},
|
||||
{"params", params}
|
||||
};
|
||||
|
||||
return Utils::callPrivateRpc<QJsonObject>(Utils::jsonToByteArray(std::move(payload)));
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> Wallet::Accounts::addWatchOnlyAccount(const QString& address, const QString& accountName , const QString& color)
|
||||
{
|
||||
QJsonArray params = {
|
||||
address,
|
||||
accountName,
|
||||
color
|
||||
};
|
||||
|
||||
QJsonObject payload {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "accounts_addAccountWatch"},
|
||||
{"params", params}
|
||||
};
|
||||
|
||||
return Utils::callPrivateRpc<QJsonObject>(Utils::jsonToByteArray(std::move(payload)));
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> Wallet::Accounts::deleteAccount(const QString& address)
|
||||
{
|
||||
QJsonArray params = {
|
||||
address
|
||||
};
|
||||
|
||||
QJsonObject payload {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "accounts_deleteAccount"},
|
||||
{"params", params}
|
||||
};
|
||||
|
||||
return Utils::callPrivateRpc<QJsonObject>(Utils::jsonToByteArray(std::move(payload)));
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
|
||||
|
||||
add_subdirectory(App)
|
||||
add_subdirectory(Services)
|
||||
add_subdirectory(Backend)
|
||||
add_subdirectory(ServicesTest)
|
|
@ -0,0 +1,35 @@
|
|||
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
|
||||
|
||||
project(Status.Services DESCRIPTION "Status services")
|
||||
|
||||
set(CMAKE_DEBUG_POSTFIX d)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
add_library(${PROJECT_NAME} SHARED)
|
||||
|
||||
# Platform specific stuff are place in the corresponding .cmake file.
|
||||
if (WIN32)
|
||||
include("${CMAKE_SOURCE_DIR}/cmake/services-win.cmake")
|
||||
elseif (APPLE)
|
||||
include("${CMAKE_SOURCE_DIR}/cmake/services-mac.cmake")
|
||||
elseif(UNIX)
|
||||
include("${CMAKE_SOURCE_DIR}/cmake/services-linux.cmake")
|
||||
endif ()
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC include)
|
||||
|
||||
# default token is a free-tier token with limited capabilities and usage
|
||||
# limits; setup your own infura key with
|
||||
# cmake -DINFURA_KEY=infura_key_goes_here ..
|
||||
if( "${INFURA_KEY}" STREQUAL "")
|
||||
message("-- Using default Infura key")
|
||||
file (STRINGS ${CMAKE_SOURCE_DIR}/../resources/infura_key INFURA_KEY)
|
||||
else()
|
||||
message("-- Using custom Infura key")
|
||||
endif()
|
||||
|
||||
# Build constants
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE INFURA_KEY="${INFURA_KEY}")
|
|
@ -0,0 +1,86 @@
|
|||
#pragma once
|
||||
|
||||
#include <StatusServices/CommonService>
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::Accounts
|
||||
{
|
||||
struct Image
|
||||
{
|
||||
QString keyUid;
|
||||
QString imgType;
|
||||
QString uri;
|
||||
int width;
|
||||
int height;
|
||||
int fileSize;
|
||||
int resizeTarget;
|
||||
|
||||
static Image toImage(const QJsonObject& jsonObj)
|
||||
{
|
||||
auto result = Image();
|
||||
|
||||
try
|
||||
{
|
||||
result.keyUid = Json::getProp(jsonObj, "keyUid")->toString();
|
||||
result.imgType = Json::getProp(jsonObj, "type")->toString();
|
||||
result.uri = Json::getProp(jsonObj, "uri")->toString();
|
||||
result.width = Json::getProp(jsonObj, "width")->toInt();
|
||||
result.height = Json::getProp(jsonObj, "height")->toInt();
|
||||
result.fileSize = Json::getProp(jsonObj, "fileSize")->toInt();
|
||||
result.resizeTarget = Json::getProp(jsonObj, "resizeTarget")->toInt();
|
||||
}
|
||||
catch (std::exception e)
|
||||
{
|
||||
qWarning() << QObject::tr("Mapping Image failed: %1").arg(e.what());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct AccountDto
|
||||
{
|
||||
QString name;
|
||||
long timestamp;
|
||||
QString identicon;
|
||||
QString keycardPairing;
|
||||
QString keyUid;
|
||||
QVector<Image> images;
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return !(name.isEmpty() || keyUid.isEmpty());
|
||||
}
|
||||
|
||||
static AccountDto toAccountDto(const QJsonObject& jsonObj)
|
||||
{
|
||||
auto result = AccountDto();
|
||||
|
||||
try
|
||||
{
|
||||
result.name = Json::getMandatoryProp(jsonObj, "name")->toString();
|
||||
bool ok;
|
||||
result.timestamp = Json::getMandatoryProp(jsonObj, "timestamp")->toString().toLong(&ok);
|
||||
result.identicon = Json::getMandatoryProp(jsonObj, "identicon")->toString();
|
||||
result.keycardPairing = Json::getMandatoryProp(jsonObj, "keycard-pairing")->toString();
|
||||
result.keyUid = Json::getMandatoryProp(jsonObj, "key-uid")->toString();
|
||||
|
||||
foreach(const auto& value, jsonObj["images"].toArray())
|
||||
{
|
||||
result.images << Image::toImage(value.toObject());
|
||||
}
|
||||
}
|
||||
catch (std::exception e)
|
||||
{
|
||||
qWarning() << QObject::tr("Mapping AccountDto failed: %1").arg(e.what());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
#pragma once
|
||||
|
||||
#include <StatusServices/CommonService>
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::Accounts
|
||||
{
|
||||
struct DerivedAccountDetails
|
||||
{
|
||||
QString publicKey;
|
||||
QString address;
|
||||
QString derivationPath;
|
||||
|
||||
static DerivedAccountDetails toDerivedAccountDetails(const QJsonObject& jsonObj, const QString& derivationPath)
|
||||
{
|
||||
// Mapping this DTO is not strightforward since only keys are used for id. We
|
||||
// handle it a bit different.
|
||||
auto result = DerivedAccountDetails();
|
||||
|
||||
try
|
||||
{
|
||||
result.derivationPath = derivationPath;
|
||||
result.publicKey = Json::getMandatoryProp(jsonObj, "publicKey")->toString();
|
||||
result.address = Json::getMandatoryProp(jsonObj, "address")->toString();
|
||||
}
|
||||
catch (std::exception e)
|
||||
{
|
||||
qWarning() << QObject::tr("Mapping DerivedAccountDetails failed: %1").arg(e.what());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct DerivedAccounts
|
||||
{
|
||||
DerivedAccountDetails whisper;
|
||||
DerivedAccountDetails walletRoot;
|
||||
DerivedAccountDetails defaultWallet;
|
||||
DerivedAccountDetails eip1581;
|
||||
|
||||
static DerivedAccounts toDerivedAccounts(const QJsonObject& jsonObj)
|
||||
{
|
||||
auto result = DerivedAccounts();
|
||||
|
||||
foreach(const auto& derivationPath, jsonObj.keys())
|
||||
{
|
||||
auto derivedObj = jsonObj.value(derivationPath).toObject();
|
||||
if(derivationPath == Constants::General::PathWhisper)
|
||||
{
|
||||
result.whisper = DerivedAccountDetails::toDerivedAccountDetails(derivedObj, derivationPath);
|
||||
}
|
||||
else if(derivationPath == Constants::General::PathWalletRoot)
|
||||
{
|
||||
result.walletRoot = DerivedAccountDetails::toDerivedAccountDetails(derivedObj, derivationPath);
|
||||
}
|
||||
else if(derivationPath == Constants::General::PathDefaultWallet)
|
||||
{
|
||||
result.defaultWallet = DerivedAccountDetails::toDerivedAccountDetails(derivedObj, derivationPath);
|
||||
}
|
||||
else if(derivationPath == Constants::General::PathEIP1581)
|
||||
{
|
||||
result.eip1581 = DerivedAccountDetails::toDerivedAccountDetails(derivedObj, derivationPath);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct GeneratedAccountDto
|
||||
{
|
||||
QString id;
|
||||
QString publicKey;
|
||||
QString address;
|
||||
QString keyUid;
|
||||
QString mnemonic;
|
||||
DerivedAccounts derivedAccounts;
|
||||
|
||||
// The following two are set additionally.
|
||||
QString alias;
|
||||
QString identicon;
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return !(id.isEmpty() || publicKey.isEmpty() || address.isEmpty() || keyUid.isEmpty());
|
||||
}
|
||||
|
||||
static GeneratedAccountDto toGeneratedAccountDto(const QJsonObject& jsonObj)
|
||||
{
|
||||
auto result = GeneratedAccountDto();
|
||||
|
||||
try
|
||||
{
|
||||
result.id = Json::getMandatoryProp(jsonObj, "id")->toString();
|
||||
result.address = Json::getMandatoryProp(jsonObj, "address")->toString();
|
||||
result.keyUid = Json::getMandatoryProp(jsonObj, "keyUid")->toString();
|
||||
result.mnemonic = Json::getMandatoryProp(jsonObj, "mnemonic")->toString();
|
||||
result.publicKey = Json::getMandatoryProp(jsonObj, "publicKey")->toString();
|
||||
|
||||
auto derivedObj = Json::getProp(jsonObj, "derived")->toObject();
|
||||
if(!derivedObj.isEmpty())
|
||||
{
|
||||
result.derivedAccounts = DerivedAccounts::toDerivedAccounts(derivedObj);
|
||||
}
|
||||
}
|
||||
catch (std::exception e)
|
||||
{
|
||||
qWarning() << QObject::tr("Mapping GeneratedAccountDto failed: %1").arg(e.what());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
#pragma once
|
||||
|
||||
#include "ServiceInterface.h"
|
||||
|
||||
namespace Status::Accounts
|
||||
{
|
||||
|
||||
class Service : public ServiceInterface
|
||||
{
|
||||
public:
|
||||
Service();
|
||||
|
||||
void init(const QString& statusgoDataDir) override;
|
||||
|
||||
[[nodiscard]] QVector<AccountDto> openedAccounts() override;
|
||||
|
||||
[[nodiscard]] const QVector<GeneratedAccountDto>& generatedAccounts() const override;
|
||||
|
||||
bool setupAccount(const QString& accountId, const QString& password) override;
|
||||
|
||||
[[nodiscard]] const AccountDto& getLoggedInAccount() const override;
|
||||
|
||||
[[nodiscard]] const GeneratedAccountDto& getImportedAccount() const override;
|
||||
|
||||
[[nodiscard]] bool isFirstTimeAccountLogin() const override;
|
||||
|
||||
QString validateMnemonic(const QString& mnemonic) override;
|
||||
|
||||
bool importMnemonic(const QString& mnemonic) override;
|
||||
|
||||
QString login(AccountDto account, const QString& password) override;
|
||||
|
||||
void clear() override;
|
||||
|
||||
QString generateAlias(const QString& publicKey) override;
|
||||
|
||||
QString generateIdenticon(const QString& publicKey) override;
|
||||
|
||||
bool verifyAccountPassword(const QString& account, const QString& password) override;
|
||||
|
||||
private:
|
||||
QJsonObject prepareAccountJsonObject(const GeneratedAccountDto& account) const;
|
||||
|
||||
DerivedAccounts storeDerivedAccounts(const QString& accountId, const QString& hashedPassword,
|
||||
const QVector<QString>& paths);
|
||||
|
||||
AccountDto saveAccountAndLogin(const QString& hashedPassword, const QJsonObject& account,
|
||||
const QJsonArray& subaccounts, const QJsonObject& settings,
|
||||
const QJsonObject& config);
|
||||
|
||||
QJsonObject getAccountDataForAccountId(const QString& accountId) const;
|
||||
|
||||
QJsonArray prepareSubaccountJsonObject(const GeneratedAccountDto& account) const;
|
||||
|
||||
QJsonArray getSubaccountDataForAccountId(const QString& accountId) const;
|
||||
|
||||
QString generateSigningPhrase(const int count) const;
|
||||
|
||||
QJsonObject prepareAccountSettingsJsonObject(const GeneratedAccountDto& account,
|
||||
const QString& installationId) const;
|
||||
|
||||
QJsonObject getAccountSettings(const QString& accountId, const QString& installationId) const;
|
||||
|
||||
QJsonObject getDefaultNodeConfig(const QString& installationId) const;
|
||||
|
||||
private:
|
||||
QVector<GeneratedAccountDto> m_generatedAccounts;
|
||||
|
||||
QString m_statusgoDataDir;
|
||||
bool m_isFirstTimeAccountLogin;
|
||||
AccountDto m_loggedInAccount;
|
||||
GeneratedAccountDto m_importedAccount;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include "AccountDto.h"
|
||||
#include "GeneratedAccountDto.h"
|
||||
|
||||
namespace Status::Accounts
|
||||
{
|
||||
class ServiceInterface
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~ServiceInterface() = default;
|
||||
|
||||
virtual void init(const QString& statusgoDataDir) = 0;
|
||||
|
||||
[[nodiscard]] virtual QVector<AccountDto> openedAccounts() = 0;
|
||||
|
||||
[[nodiscard]] virtual const QVector<GeneratedAccountDto>& generatedAccounts() const = 0;
|
||||
|
||||
virtual bool setupAccount(const QString& accountId, const QString& password) = 0;
|
||||
|
||||
[[nodiscard]] virtual const AccountDto& getLoggedInAccount() const = 0;
|
||||
|
||||
[[nodiscard]] virtual const GeneratedAccountDto& getImportedAccount() const = 0;
|
||||
|
||||
[[nodiscard]] virtual bool isFirstTimeAccountLogin() const = 0;
|
||||
|
||||
virtual QString validateMnemonic(const QString& mnemonic) = 0;
|
||||
|
||||
virtual bool importMnemonic(const QString& mnemonic) = 0;
|
||||
|
||||
virtual QString login(AccountDto account, const QString& password) = 0;
|
||||
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual QString generateAlias(const QString& publicKey) = 0;
|
||||
|
||||
virtual QString generateIdenticon(const QString& publicKey) = 0;
|
||||
|
||||
virtual bool verifyAccountPassword(const QString& account, const QString& password) = 0;
|
||||
};
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue