refactor: UI (page) navigation from C++ code
An app::Navigation class is introduced with an API very similar to the Kirigami.PageRouter in QML. This new class is responsible for pusing populated view model classes from C++ into QML ownership and triggering appropriate navigation events. On the QML side a signal handler forwards these calls to the Kirigami.PageRouter to perform the actual navigation in the UI. This construct paves the way for moving state transition and related logic out of QML and towards C++, since this logic is currently mostly concerned with page navigation in Keysmith. Ultimately that transition should make the QML (page) views more easily re-usable.master
parent
571afeacdf
commit
12e060923e
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
# SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
# SPDX-FileCopyrightText: 2020-2021 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
#
|
||||
|
||||
set(keysmith_SRCS
|
||||
|
@ -9,4 +9,4 @@ set(keysmith_SRCS
|
|||
)
|
||||
|
||||
add_library(keysmith_lib STATIC ${keysmith_SRCS})
|
||||
target_link_libraries(keysmith_lib Qt5::Core Qt5::Gui Qt5::Concurrent KF5::I18n model_lib account_lib)
|
||||
target_link_libraries(keysmith_lib Qt5::Core Qt5::Gui Qt5::Concurrent Qt5::Qml KF5::I18n model_lib account_lib)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2020-2021 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
*/
|
||||
#include "keysmith.h"
|
||||
#include "../logging_p.h"
|
||||
|
@ -12,7 +12,47 @@ KEYSMITH_LOGGER(logger, ".app.keysmith")
|
|||
|
||||
namespace app
|
||||
{
|
||||
Keysmith::Keysmith(QObject *parent): QObject(parent), m_storage(nullptr)
|
||||
|
||||
static QMetaEnum pagesEnum = QMetaEnum::fromType<Navigation::Page>();
|
||||
|
||||
Navigation::Navigation(QQmlEngine *engine) :
|
||||
QObject(engine), m_engine(engine)
|
||||
{
|
||||
Q_ASSERT_X(m_engine, Q_FUNC_INFO, "must have an engine to work with");
|
||||
}
|
||||
|
||||
QString Navigation::name(Navigation::Page page) const
|
||||
{
|
||||
const char *cname = pagesEnum.valueToKey(page);
|
||||
Q_ASSERT_X(cname, Q_FUNC_INFO, "must be able to lookup pages enum constant's name");
|
||||
QString result;
|
||||
result.append(cname);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Navigation::navigate(Navigation::Page page, QObject *modelToTransfer)
|
||||
{
|
||||
const QString route = name(page);
|
||||
if (modelToTransfer) {
|
||||
m_engine->setObjectOwnership(modelToTransfer, QQmlEngine::JavaScriptOwnership);
|
||||
}
|
||||
|
||||
qCDebug(logger) << "Requesting switch to route:" << route << "using (view) model:" << modelToTransfer;
|
||||
Q_EMIT routed(route, modelToTransfer);
|
||||
}
|
||||
|
||||
void Navigation::push(Navigation::Page page, QObject *modelToTransfer)
|
||||
{
|
||||
const QString route = name(page);
|
||||
if (modelToTransfer) {
|
||||
m_engine->setObjectOwnership(modelToTransfer, QQmlEngine::JavaScriptOwnership);
|
||||
}
|
||||
|
||||
qCDebug(logger) << "Requesting to push route:" << route << "using (view) model:" << modelToTransfer;
|
||||
Q_EMIT pushed(route, modelToTransfer);
|
||||
}
|
||||
|
||||
Keysmith::Keysmith(Navigation *navigation, QObject *parent): QObject(parent), m_navigation(navigation), m_storage(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -24,6 +64,11 @@ namespace app
|
|||
}
|
||||
}
|
||||
|
||||
Navigation * Keysmith::navigation(void) const
|
||||
{
|
||||
return m_navigation;
|
||||
}
|
||||
|
||||
void Keysmith::copyToClipboard(const QString &text)
|
||||
{
|
||||
QClipboard * clipboard = QGuiApplication::clipboard();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2020-2021 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
*/
|
||||
#ifndef APP_KEYSMITH_H
|
||||
#define APP_KEYSMITH_H
|
||||
|
@ -9,24 +9,58 @@
|
|||
#include "../model/accounts.h"
|
||||
#include "../model/password.h"
|
||||
|
||||
#include <QMetaEnum>
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
|
||||
namespace app
|
||||
{
|
||||
class Keysmith: public QObject
|
||||
class Navigation: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Keysmith(QObject *parent = nullptr);
|
||||
enum Page
|
||||
{
|
||||
Error,
|
||||
AddAccount,
|
||||
RenameAccount,
|
||||
AccountsOverview,
|
||||
SetupPassword,
|
||||
UnlockAccounts
|
||||
};
|
||||
Q_ENUM(Page)
|
||||
public:
|
||||
explicit Navigation(QQmlEngine * const engine);
|
||||
Q_INVOKABLE QString name(app::Navigation::Page page) const;
|
||||
public Q_SLOTS:
|
||||
void push(app::Navigation::Page page, QObject *modelToTransfer);
|
||||
void navigate(app::Navigation::Page page, QObject *modelToTransfer);
|
||||
Q_SIGNALS:
|
||||
void routed(const QString &route, QObject *transferred);
|
||||
void pushed(const QString &route, QObject *transferred);
|
||||
private:
|
||||
QQmlEngine * const m_engine;
|
||||
};
|
||||
|
||||
class Keysmith: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(app::Navigation * navigation READ navigation CONSTANT)
|
||||
public:
|
||||
explicit Keysmith(Navigation * const navigation, QObject *parent = nullptr);
|
||||
virtual ~Keysmith();
|
||||
Navigation * navigation(void) const;
|
||||
Q_INVOKABLE void copyToClipboard(const QString &text);
|
||||
Q_INVOKABLE model::SimpleAccountListModel * accountListModel(void);
|
||||
Q_INVOKABLE model::PasswordRequest * passwordRequest(void);
|
||||
private:
|
||||
accounts::AccountStorage * storage(void);
|
||||
private:
|
||||
Navigation * const m_navigation;
|
||||
accounts::AccountStorage *m_storage;
|
||||
};
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(app::Navigation *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -148,6 +148,16 @@ Kirigami.ApplicationWindow {
|
|||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Keysmith.navigation
|
||||
function onRouted (route, data) {
|
||||
root.router.navigateToRoute({route, data});
|
||||
}
|
||||
function onPushed(route, data) {
|
||||
root.router.pushRoute({route, data});
|
||||
}
|
||||
}
|
||||
|
||||
function autoAddNewAccountFromCommandLine() {
|
||||
// accounts not yet loaded, keep the user waiting...
|
||||
if (!accounts.loaded) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* SPDX-FileCopyrightText: 2019 Bhushan Shah <bshah@kde.org>
|
||||
* SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2020-2021 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
*/
|
||||
|
||||
#include <QApplication>
|
||||
|
@ -92,10 +92,9 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
|
|||
qmlRegisterType<validators::UnsignedLongValidator>("Keysmith.Validators", 1, 0, "HOTPCounterValidator");
|
||||
qmlRegisterSingletonType<app::Keysmith>("Keysmith.Application", 1, 0, "Keysmith", [](QQmlEngine *qml, QJSEngine *js) -> QObject *
|
||||
{
|
||||
Q_UNUSED(qml);
|
||||
Q_UNUSED(js);
|
||||
|
||||
return new app::Keysmith();
|
||||
return new app::Keysmith(new app::Navigation(qml));
|
||||
});
|
||||
qmlRegisterSingletonType<app::CommandLineOptions>("Keysmith.Application", 1, 0, "CommandLine", [parseOk, &cliParser](QQmlEngine *qml, QJSEngine *js) -> QObject *
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue