269 lines
11 KiB
C++
269 lines
11 KiB
C++
/*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
* SPDX-FileCopyrightText: 2021 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
|
*/
|
|
|
|
#include "flows_p.h"
|
|
#include "cli.h"
|
|
#include "state_p.h"
|
|
#include "vms.h"
|
|
|
|
#include "../logging_p.h"
|
|
|
|
#include <KLocalizedString>
|
|
#include <QTimer>
|
|
|
|
KEYSMITH_LOGGER(logger, ".app.flows_p")
|
|
|
|
namespace app
|
|
{
|
|
accounts::AccountStorage * storageOf(Keysmith *app)
|
|
{
|
|
Q_ASSERT_X(app, Q_FUNC_INFO, "should have a Keysmith application instance");
|
|
|
|
auto accounts = app->store().accounts();
|
|
|
|
Q_ASSERT_X(accounts, Q_FUNC_INFO, "should have an AccountStorage instance");
|
|
return accounts;
|
|
}
|
|
|
|
Navigation * navigationFor(Keysmith *app)
|
|
{
|
|
auto nav = app->navigation();
|
|
Q_ASSERT_X(nav, Q_FUNC_INFO, "should have a Navigation instance");
|
|
return nav;
|
|
}
|
|
|
|
InitialFlow::InitialFlow(Keysmith *app) :
|
|
QObject(app), m_started(false), m_uriToAdd(false), m_uriParsed(false), m_passwordPromptResolved(false),
|
|
m_app(app), m_input(new model::AccountInput(this)),
|
|
m_passwordRequest(new model::PasswordRequest(storageOf(app)->secret(), this))
|
|
{
|
|
QObject::connect(m_passwordRequest, &model::PasswordRequest::passwordRequestChanged,
|
|
this, &InitialFlow::resume);
|
|
QObject::connect(m_passwordRequest, &model::PasswordRequest::passwordAccepted, this, &InitialFlow::resume);
|
|
QObject::connect(accountListOf(m_app), &model::SimpleAccountListModel::loadedChanged,
|
|
this, &InitialFlow::resume);
|
|
}
|
|
|
|
void InitialFlow::run(const QCommandLineParser &parser)
|
|
{
|
|
flowStateOf(m_app)->setFlowRunning(true);
|
|
overviewStateOf(m_app)->setActionsEnabled(false);
|
|
m_started = true;
|
|
|
|
const auto argv = parser.positionalArguments();
|
|
if (argv.isEmpty()) {
|
|
qCDebug(logger) << "No URIs to handle, moving on:" << this;
|
|
QTimer::singleShot(0, this, &InitialFlow::resume);
|
|
return;
|
|
}
|
|
|
|
qCDebug(logger) << "Will first parse given URI(s):" << this;
|
|
|
|
m_uriToAdd = true;
|
|
auto job = new CommandLineAccountJob(m_input);
|
|
QObject::connect(job, &CommandLineAccountJob::newAccountProcessed, this, &InitialFlow::onNewAccountProcessed);
|
|
QObject::connect(job, &CommandLineAccountJob::newAccountInvalid, this, &InitialFlow::onNewAccountInvalid);
|
|
job->run(argv[0]);
|
|
}
|
|
|
|
void InitialFlow::onNewAccountProcessed(void)
|
|
{
|
|
Q_ASSERT_X(m_started, Q_FUNC_INFO, "should have properly started the flow first");
|
|
|
|
m_uriParsed = true;
|
|
|
|
auto vm = new AddAccountViewModel(m_input, accountListOf(m_app), true, false);
|
|
QObject::connect(vm, &AddAccountViewModel::accepted, this, &InitialFlow::resume);
|
|
QObject::connect(vm, &AddAccountViewModel::cancelled, this, &InitialFlow::onNewAccountRejected);
|
|
navigationFor(m_app)->navigate(Navigation::Page::AddAccount, vm);
|
|
}
|
|
|
|
void InitialFlow::onNewAccountAccepted(void)
|
|
{
|
|
Q_ASSERT_X(m_started, Q_FUNC_INFO, "should have properly started the flow first");
|
|
Q_ASSERT_X(m_uriToAdd && m_uriParsed, Q_FUNC_INFO, "should have parsed URIs first");
|
|
|
|
accountListOf(m_app)->addAccount(m_input);
|
|
m_uriToAdd = false;
|
|
QTimer::singleShot(0, this, &InitialFlow::resume);
|
|
}
|
|
|
|
void InitialFlow::onNewAccountRejected(void)
|
|
{
|
|
Q_ASSERT_X(m_uriToAdd && m_uriParsed, Q_FUNC_INFO, "should have parsed URIs first");
|
|
m_uriToAdd = false;
|
|
QTimer::singleShot(0, this, &InitialFlow::resume);
|
|
}
|
|
|
|
void InitialFlow::onNewAccountInvalid(void)
|
|
{
|
|
Q_ASSERT_X(m_started, Q_FUNC_INFO, "should have properly started the flow first");
|
|
|
|
auto vm = new ErrorViewModel(
|
|
i18nc("@title:window", "Invalid account"),
|
|
i18nc("@info:label", "The account you are trying to add is invalid. You can either quit the app, or continue without adding the account."),
|
|
true
|
|
);
|
|
QObject::connect(vm, &ErrorViewModel::dismissed, this, &InitialFlow::onNewAccountRejected);
|
|
navigationFor(m_app)->navigate(Navigation::Page::Error, vm);
|
|
}
|
|
|
|
void InitialFlow::resume(void)
|
|
{
|
|
if (!m_started) {
|
|
qCDebug(logger) << "Blocking progress: flow has not been started yet:" << this;
|
|
return;
|
|
}
|
|
|
|
if (m_uriToAdd && !m_uriParsed) {
|
|
qCDebug(logger) << "Blocking progress: URI parsing has not completed yet:" << this;
|
|
return;
|
|
}
|
|
|
|
if (m_passwordRequest->keyAvailable()) {
|
|
if (m_uriToAdd) {
|
|
const auto accounts = accountListOf(m_app);
|
|
if (!accounts->isAccountStillAvailable(m_input->name(), m_input->issuer())) {
|
|
auto vm = new RenameAccountViewModel(m_input, accountListOf(m_app));
|
|
QObject::connect(vm, &RenameAccountViewModel::cancelled, this, &InitialFlow::onNewAccountRejected);
|
|
QObject::connect(vm, &RenameAccountViewModel::accepted, this, &InitialFlow::onNewAccountAccepted);
|
|
navigationFor(m_app)->navigate(Navigation::Page::RenameAccount, vm);
|
|
return;
|
|
}
|
|
if (accounts->loaded()) {
|
|
QTimer::singleShot(0, this, &InitialFlow::onNewAccountAccepted);
|
|
return;
|
|
}
|
|
|
|
qCDebug(logger)
|
|
<< "Blocking progress: accounts not fully loaded:"
|
|
<< "Waiting to see if new account remains available:" << this;
|
|
return;
|
|
}
|
|
|
|
auto vm = new AccountsOverviewViewModel(m_app);
|
|
navigationFor(m_app)->navigate(Navigation::Page::AccountsOverview, vm);
|
|
overviewStateOf(m_app)->setActionsEnabled(true);
|
|
auto flows = flowStateOf(m_app);
|
|
flows->setFlowRunning(false);
|
|
flows->setInitialFlowDone(true);
|
|
QTimer::singleShot(0, this, &QObject::deleteLater);
|
|
return;
|
|
}
|
|
|
|
if (!m_passwordPromptResolved) {
|
|
if (m_passwordRequest->firstRun()) {
|
|
m_passwordPromptResolved = true;
|
|
auto vm = new SetupPasswordViewModel(m_passwordRequest);
|
|
navigationFor(m_app)->navigate(Navigation::Page::SetupPassword, vm);
|
|
return;
|
|
}
|
|
if (m_passwordRequest->previouslyDefined()) {
|
|
m_passwordPromptResolved = true;
|
|
auto vm = new UnlockAccountsViewModel(m_passwordRequest);
|
|
navigationFor(m_app)->navigate(Navigation::Page::UnlockAccounts, vm);
|
|
return;
|
|
}
|
|
qCDebug(logger) << "Blocking progress: password request has not yet been resolved:" << this;
|
|
return;
|
|
}
|
|
|
|
qCDebug(logger) << "Blocking progress: waiting for the next event:" << this;
|
|
}
|
|
|
|
ManualAddAccountFlow::ManualAddAccountFlow(Keysmith *app) :
|
|
QObject(app), m_app(app), m_input(new model::AccountInput(this))
|
|
{
|
|
Q_ASSERT_X(app, Q_FUNC_INFO, "should have a Keysmith instance");
|
|
}
|
|
|
|
void ManualAddAccountFlow::run(void)
|
|
{
|
|
flowStateOf(m_app)->setFlowRunning(true);
|
|
overviewStateOf(m_app)->setActionsEnabled(false);
|
|
|
|
auto vm = new AddAccountViewModel(m_input, accountListOf(m_app), false, true);
|
|
QObject::connect(vm, &AddAccountViewModel::accepted, this, &ManualAddAccountFlow::onAccepted);
|
|
QObject::connect(vm, &AddAccountViewModel::cancelled, this, &ManualAddAccountFlow::back);
|
|
navigationFor(m_app)->push(Navigation::Page::AddAccount, vm);
|
|
}
|
|
|
|
void ManualAddAccountFlow::onAccepted(void)
|
|
{
|
|
accountListOf(m_app)->addAccount(m_input);
|
|
QTimer::singleShot(0, this, &ManualAddAccountFlow::back);
|
|
}
|
|
|
|
void ManualAddAccountFlow::back(void)
|
|
{
|
|
auto vm = new AccountsOverviewViewModel(m_app);
|
|
navigationFor(m_app)->navigate(Navigation::Page::AccountsOverview, vm);
|
|
overviewStateOf(m_app)->setActionsEnabled(true);
|
|
flowStateOf(m_app)->setFlowRunning(false);
|
|
QTimer::singleShot(0, this, &QObject::deleteLater);
|
|
}
|
|
|
|
ExternalCommandLineFlow::ExternalCommandLineFlow(Keysmith *app) :
|
|
QObject(app), m_app(app), m_input(new model::AccountInput(this))
|
|
{
|
|
Q_ASSERT_X(app, Q_FUNC_INFO, "should have a Keysmith instance");
|
|
}
|
|
|
|
void ExternalCommandLineFlow::run(const QCommandLineParser &parser)
|
|
{
|
|
const auto argv = parser.positionalArguments();
|
|
if (argv.isEmpty()) {
|
|
qCDebug(logger) << "No URIs to handle, nothing to do for external commandline:" << this;
|
|
QTimer::singleShot(0, this, &ExternalCommandLineFlow::deleteLater);
|
|
return;
|
|
}
|
|
|
|
flowStateOf(m_app)->setFlowRunning(true);
|
|
overviewStateOf(m_app)->setActionsEnabled(false);
|
|
qCDebug(logger) << "Will parse given URI(s) from external commandline:" << this;
|
|
|
|
auto job = new CommandLineAccountJob(m_input);
|
|
QObject::connect(job, &CommandLineAccountJob::newAccountProcessed,
|
|
this, &ExternalCommandLineFlow::onNewAccountProcessed);
|
|
QObject::connect(job, &CommandLineAccountJob::newAccountInvalid,
|
|
this, &ExternalCommandLineFlow::onNewAccountInvalid);
|
|
job->run(argv[0]);
|
|
}
|
|
|
|
void ExternalCommandLineFlow::onNewAccountProcessed(void)
|
|
{
|
|
auto vm = new AddAccountViewModel(m_input, accountListOf(m_app), false, true);
|
|
QObject::connect(vm, &AddAccountViewModel::accepted, this, &ExternalCommandLineFlow::onAccepted);
|
|
QObject::connect(vm, &AddAccountViewModel::cancelled, this, &ExternalCommandLineFlow::back);
|
|
navigationFor(m_app)->push(Navigation::Page::AddAccount, vm);
|
|
}
|
|
|
|
void ExternalCommandLineFlow::onNewAccountInvalid(void)
|
|
{
|
|
auto vm = new ErrorViewModel(
|
|
i18nc("@title:window", "Invalid account"),
|
|
i18nc("@info:label", "The account you are trying to add is invalid. Continue without adding the account."),
|
|
false
|
|
);
|
|
QObject::connect(vm, &ErrorViewModel::dismissed, this, &ExternalCommandLineFlow::back);
|
|
navigationFor(m_app)->navigate(Navigation::Page::Error, vm);
|
|
}
|
|
|
|
void ExternalCommandLineFlow::onAccepted(void)
|
|
{
|
|
accountListOf(m_app)->addAccount(m_input);
|
|
QTimer::singleShot(0, this, &ExternalCommandLineFlow::back);
|
|
}
|
|
|
|
void ExternalCommandLineFlow::back(void)
|
|
{
|
|
auto vm = new AccountsOverviewViewModel(m_app);
|
|
navigationFor(m_app)->navigate(Navigation::Page::AccountsOverview, vm);
|
|
overviewStateOf(m_app)->setActionsEnabled(true);
|
|
flowStateOf(m_app)->setFlowRunning(false);
|
|
QTimer::singleShot(0, this, &QObject::deleteLater);
|
|
}
|
|
}
|