diff --git a/src/contents/ui/AccountsOverview.qml b/src/contents/ui/AccountsOverview.qml new file mode 100644 index 0000000..1fa2bf4 --- /dev/null +++ b/src/contents/ui/AccountsOverview.qml @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2020 Johan Ouwerkerk + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as Controls +import org.kde.kirigami 2.8 as Kirigami + +import Keysmith.Application 1.0 +import Keysmith.Models 1.0 as Models + +Kirigami.ScrollablePage { + id: root + /* + * Explicitly opt-out of scroll-to-refresh/drag-to-refresh behaviour + * Underlying model implementations don't offer the hooks for that. + */ + supportsRefreshing: false + title: i18nc("@title:window", "Accounts") + + signal accountWanted + property bool addActionEnabled : true + property Models.AccountListModel accounts: Keysmith.accountListModel() + + Component { + id: mainListDelegate + AccountEntryView { + account: model.account + } + } + + ListView { + id: mainList + model: accounts + delegate: Kirigami.DelegateRecycler { + width: parent ? parent.width : implicitWidth + sourceComponent: mainListDelegate + } + } + + actions.main: Kirigami.Action { + id: addAction + text: i18n("Add") + iconName: "list-add" + visible: addActionEnabled + onTriggered: { + root.accountWanted(); + } + } +} diff --git a/src/contents/ui/AddAccount.qml b/src/contents/ui/AddAccount.qml new file mode 100644 index 0000000..cf8ab11 --- /dev/null +++ b/src/contents/ui/AddAccount.qml @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2020 Johan Ouwerkerk + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as Controls +import org.kde.kirigami 2.8 as Kirigami + +import Keysmith.Application 1.0 +import Keysmith.Models 1.0 as Models +import Keysmith.Validators 1.0 as Validators + +Kirigami.Page { + id: root + title: i18nc("@title:window", "Add new account") + signal dismissed + property Models.AccountListModel accounts: Keysmith.accountListModel() + + ColumnLayout { + anchors { + horizontalCenter: parent.horizontalCenter + } + Kirigami.FormLayout { + Controls.TextField { + id: accountName + Kirigami.FormData.label: i18nc("@label:textbox", "Account Name:") + validator: Validators.AccountNameValidator { + accounts: root.accounts + } + } + } + TokenDetailsForm { + id: tokenDetails + } + } + + actions.main: Kirigami.Action { + text: i18n("Add") + iconName: "answer-correct" + onTriggered: { + if (tokenDetails.isTotp) { + accounts.addTotp(accountName.text, tokenDetails.secret, parseInt(tokenDetails.timeStep), tokenDetails.tokenLength); + } + if (tokenDetails.isHotp) { + accounts.addHotp(accountName.text, tokenDetails.secret, parseInt(tokenDetails.counter), tokenDetails.tokenLength); + } + root.dismissed(); + } + } +} diff --git a/src/contents/ui/TokenDetailsForm.qml b/src/contents/ui/TokenDetailsForm.qml index 11d06dc..eb1c85e 100644 --- a/src/contents/ui/TokenDetailsForm.qml +++ b/src/contents/ui/TokenDetailsForm.qml @@ -1,25 +1,10 @@ /* - * Copyright 2019 Johan Ouwerkerk - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 3 of - * the License or any later version accepted by the membership of - * KDE e.V. (or its successor approved by the membership of KDE - * e.V.), which shall act as a proxy defined in Section 14 of - * version 3 of the license. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2019 Bhushan Shah + * SPDX-FileCopyrightText: 2019-2020 Johan Ouwerkerk */ -import Oath.Validators 1.0 as Validators +import Keysmith.Validators 1.0 as Validators import QtQuick 2.1 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.0 as Controls @@ -63,7 +48,9 @@ Kirigami.FormLayout { Kirigami.FormData.label: i18nc("@label:textbox", "Timer:") enabled: totpRadio.checked text: "30" - inputMask: "0009" + validator: IntValidator { + bottom: 1 + } inputMethodHints: Qt.ImhDigitsOnly } Controls.TextField { @@ -77,8 +64,9 @@ Kirigami.FormLayout { inputMethodHints: Qt.ImhDigitsOnly } /* - * The liboath API is documented to support tokens which are - * 6, 7 or 8 characters long only. + * OATH tokens are derived from a 32bit value, base-10 encoded. + * Meaning tokens should not be longer than 10 digits max. + * In addition tokens must be 6 digits long at minimum. * * Make a virtue of it by offering a spinner for better UX */ @@ -86,7 +74,7 @@ Kirigami.FormLayout { id: pinLengthField Kirigami.FormData.label: i18nc("@label:spinbox", "Token length:") from: 6 - to: 8 + to: 10 value: 6 } } diff --git a/src/contents/ui/main.qml b/src/contents/ui/main.qml index 778483f..61f8eae 100644 --- a/src/contents/ui/main.qml +++ b/src/contents/ui/main.qml @@ -1,27 +1,11 @@ /* - * Copyright 2019 Bhushan Shah - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 3 of - * the License or any later version accepted by the membership of - * KDE e.V. (or its successor approved by the membership of KDE - * e.V.), which shall act as a proxy defined in Section 14 of - * version 3 of the license. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2019 Bhushan Shah + * SPDX-FileCopyrightText: 2019-2020 Johan Ouwerkerk */ import Keysmith.Application 1.0 import Keysmith.Models 1.0 as Models -import Oath.Validators 1.0 as Validators import QtQuick 2.1 import QtQuick.Layouts 1.2 @@ -31,90 +15,30 @@ import org.kde.kirigami 2.4 as Kirigami Kirigami.ApplicationWindow { id: root - pageStack.initialPage: mainPageComponent + pageStack.initialPage: accountsOverviewPage property bool addActionEnabled: true - property Models.AccountListModel accounts: Keysmith.accountListModel() - Kirigami.Action { - id: addAction - text: i18n("Add") - iconName: "list-add" - visible: addActionEnabled - onTriggered: { - pageStack.push(addPageComponent); - addActionEnabled = false - } - } - Component { - id: mainListDelegate - AccountEntryView { - account: model.account - } - } - - Component { - id: mainPageComponent - Kirigami.ScrollablePage { - title: i18nc("@title:window", "Accounts") - actions.main: addAction - /* - * Explicitly opt-out of scroll-to-refresh/drag-to-refresh behaviour - * Underlying model implementations don't offer the hooks for that. - */ - supportsRefreshing: false - ListView { - id: mainList - model: accounts - delegate: Kirigami.DelegateRecycler { - width: parent ? parent.width : implicitWidth - sourceComponent: mainListDelegate - } + id: accountsOverviewPage + AccountsOverview { + accounts: root.accounts + addActionEnabled: root.addActionEnabled + onAccountWanted: { + pageStack.push(addPageComponent); + root.addActionEnabled = false; } } } Component { id: addPageComponent - Kirigami.Page { - title: i18nc("@title:window", "Add new account") - actions.main: Kirigami.Action { - text: i18n("Add") - iconName: "answer-correct" - onTriggered: { - if (tokenDetails.isTotp) { - accounts.addTotp(accountName.text, tokenDetails.secret, parseInt(tokenDetails.timeStep), tokenDetails.tokenLength); - } - if (tokenDetails.isHotp) { - accounts.addHotp(accountName.text, tokenDetails.secret, parseInt(tokenDetails.counter), tokenDetails.tokenLength); - } - - pageStack.pop(); - addActionEnabled = true; - } - } - - ColumnLayout { - id: addFormLayout - anchors { - horizontalCenter: parent.horizontalCenter - } - - Kirigami.FormLayout { - - Controls.TextField { - id: accountName - Kirigami.FormData.label: i18nc("@label:textbox", "Account Name:") - validator: Validators.AccountNameValidator { - id: nameValidator - } - } - } - TokenDetailsForm { - id: tokenDetails - } + AddAccount { + accounts: root.accounts + onDismissed: { + pageStack.pop(); + addActionEnabled = true; } } } diff --git a/src/main.cpp b/src/main.cpp index c104d35..edfa684 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,7 +29,8 @@ #include "app/keysmith.h" #include "model/accounts.h" -#include "../validators/qmlsupport.h" +#include "validators/countervalidator.h" +#include "validators/secretvalidator.h" Q_DECL_EXPORT int main(int argc, char *argv[]) { @@ -45,9 +46,11 @@ Q_DECL_EXPORT int main(int argc, char *argv[]) QQmlApplicationEngine engine; engine.rootContext()->setContextObject(new KLocalizedContext(&engine)); - validators::registerValidatorTypes(); qmlRegisterUncreatableType("Keysmith.Models", 1, 0, "AccountListModel", "Use the Keysmith singleton to obtain an AccountListModel"); qmlRegisterUncreatableType("Keysmith.Models", 1, 0, "Account", "Use an AccountListModel from the Keysmith singleton to obtain an Account"); + qmlRegisterType("Keysmith.Validators", 1, 0, "AccountNameValidator"); + qmlRegisterType("Keysmith.Validators", 1, 0, "Base32SecretValidator"); + qmlRegisterType("Keysmith.Validators", 1, 0, "HOTPCounterValidator"); qmlRegisterSingletonType("Keysmith.Application", 1, 0, "Keysmith", [](QQmlEngine *qml, QJSEngine *js) -> QObject * { Q_UNUSED(qml); diff --git a/src/resources.qrc b/src/resources.qrc index 6f6a238..a45ffb3 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -3,5 +3,7 @@ contents/ui/main.qml contents/ui/TokenDetailsForm.qml contents/ui/AccountEntryView.qml + contents/ui/AccountsOverview.qml + contents/ui/AddAccount.qml diff --git a/src/validators/CMakeLists.txt b/src/validators/CMakeLists.txt index 7ef4863..76a6238 100644 --- a/src/validators/CMakeLists.txt +++ b/src/validators/CMakeLists.txt @@ -2,12 +2,8 @@ # SPDX-License-Identifier: GPL-3.0-or-later # SPDX-FileCopyrightText: 2019-2020 Johan Ouwerkerk # -# This directory contains (custom) validators to support form field validation in the QML UI -# For the QML bindings see: qmlsupport.cpp -# set(validator_SRCS - qmlsupport.cpp countervalidator.cpp namevalidator.cpp secretvalidator.cpp @@ -15,4 +11,4 @@ set(validator_SRCS ) add_library(validator_lib STATIC ${validator_SRCS}) -target_link_libraries(validator_lib Qt5::Core Qt5::Qml Qt5::Gui base32_lib) +target_link_libraries(validator_lib Qt5::Core Qt5::Gui base32_lib) diff --git a/src/validators/qmlsupport.cpp b/src/validators/qmlsupport.cpp deleted file mode 100644 index a04a450..0000000 --- a/src/validators/qmlsupport.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/***************************************************************************** - * Copyright: 2019 Johan Ouwerkerk * - * * - * This project is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This project is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - * * - ****************************************************************************/ - -#include "qmlsupport.h" - -#include "countervalidator.h" -#include "namevalidator.h" -#include "secretvalidator.h" - -#include - -namespace validators -{ - void registerValidatorTypes(void) - { - qmlRegisterType("Oath.Validators", 1, 0, "AccountNameValidator"); - qmlRegisterType("Oath.Validators", 1, 0, "HOTPCounterValidator"); - qmlRegisterType("Oath.Validators", 1, 0, "Base32SecretValidator"); - } -} diff --git a/src/validators/qmlsupport.h b/src/validators/qmlsupport.h deleted file mode 100644 index c4b9423..0000000 --- a/src/validators/qmlsupport.h +++ /dev/null @@ -1,27 +0,0 @@ -/***************************************************************************** - * Copyright: 2019 Johan Ouwerkerk * - * * - * This project is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This project is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - * * - ****************************************************************************/ - -#ifndef VALIDATOR_QML_SUPPORT_H -#define VALIDATOR_QML_SUPPORT_H - -namespace validators -{ - void registerValidatorTypes(void); -} - -#endif