From 798b6879fdc8f224c606aa77c293d1a76dfabf29 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Tue, 2 Oct 2018 22:41:20 +0200 Subject: [PATCH] intermediate commit --- libnymea-app-core/devicemanager.cpp | 3 +- libnymea-app-core/jsonrpc/jsonrpcclient.cpp | 2 +- libnymea-app-core/models/logsmodel.cpp | 3 + nymea-app/resources.qrc | 3 + nymea-app/ui/Nymea.qml | 11 +- .../FingerprintReaderDevicePage.qml | 295 ++++++++++++++++++ .../GenericDeviceStateDetailsPage.qml | 1 + .../devicepages/NotificationsDevicePage.qml | 1 + nymea-app/ui/images/account.svg | 188 +++++++++++ nymea-app/ui/images/contact-new.svg | 188 +++++++++++ 10 files changed, 692 insertions(+), 3 deletions(-) create mode 100644 nymea-app/ui/devicepages/FingerprintReaderDevicePage.qml create mode 100644 nymea-app/ui/images/account.svg create mode 100644 nymea-app/ui/images/contact-new.svg diff --git a/libnymea-app-core/devicemanager.cpp b/libnymea-app-core/devicemanager.cpp index bbb9933b..b9222cb3 100644 --- a/libnymea-app-core/devicemanager.cpp +++ b/libnymea-app-core/devicemanager.cpp @@ -155,7 +155,7 @@ void DeviceManager::getVendorsResponse(const QVariantMap ¶ms) void DeviceManager::getSupportedDevicesResponse(const QVariantMap ¶ms) { -// qDebug() << "DeviceClass received:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); + qDebug() << "DeviceClass received:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); if (params.value("params").toMap().keys().contains("deviceClasses")) { QVariantList deviceClassList = params.value("params").toMap().value("deviceClasses").toList(); foreach (QVariant deviceClassVariant, deviceClassList) { @@ -238,6 +238,7 @@ void DeviceManager::getConfiguredDevicesResponse(const QVariantMap ¶ms) value.convert(QVariant::Int); } device->setStateValue(stateTypeId, value); + qDebug() << "Set device state value:" << device->stateValue(stateTypeId) << value; } devices()->addDevice(device); } diff --git a/libnymea-app-core/jsonrpc/jsonrpcclient.cpp b/libnymea-app-core/jsonrpc/jsonrpcclient.cpp index ef2b07a7..31a293d8 100644 --- a/libnymea-app-core/jsonrpc/jsonrpcclient.cpp +++ b/libnymea-app-core/jsonrpc/jsonrpcclient.cpp @@ -303,7 +303,7 @@ void JsonRpcClient::sendRequest(const QVariantMap &request) { QVariantMap newRequest = request; newRequest.insert("token", m_token); - qDebug() << "Sending request" << qUtf8Printable(QJsonDocument::fromVariant(newRequest).toJson()); +// qDebug() << "Sending request" << qUtf8Printable(QJsonDocument::fromVariant(newRequest).toJson()); m_connection->sendData(QJsonDocument::fromVariant(newRequest).toJson(QJsonDocument::Compact) + "\n"); } diff --git a/libnymea-app-core/models/logsmodel.cpp b/libnymea-app-core/models/logsmodel.cpp index 6a2f0601..3e08301c 100644 --- a/libnymea-app-core/models/logsmodel.cpp +++ b/libnymea-app-core/models/logsmodel.cpp @@ -179,6 +179,9 @@ void LogsModel::update() void LogsModel::fetchEarlier(int hours) { + if (!m_engine) { + return; + } if (m_busy) { return; } diff --git a/nymea-app/resources.qrc b/nymea-app/resources.qrc index b4d7f4bb..6a377420 100644 --- a/nymea-app/resources.qrc +++ b/nymea-app/resources.qrc @@ -254,5 +254,8 @@ ui/devicelistpages/DeviceListPageBase.qml ui/MainPage.qml ui/RootItem.qml + ui/devicepages/FingerprintReaderDevicePage.qml + ui/images/account.svg + ui/images/contact-new.svg diff --git a/nymea-app/ui/Nymea.qml b/nymea-app/ui/Nymea.qml index b12048fc..3ae2e51d 100644 --- a/nymea-app/ui/Nymea.qml +++ b/nymea-app/ui/Nymea.qml @@ -53,7 +53,7 @@ ApplicationWindow { rootItem.handleCloseEvent(close) } - property var supportedInterfaces: ["light", "weather", "sensor", "media", "garagegate", "extendedawning", "extendedshutter", "extendedblind", "button", "notifications", "inputtrigger", "outputtrigger", "gateway"] + property var supportedInterfaces: ["light", "weather", "sensor", "media", "garagegate", "extendedawning", "extendedshutter", "extendedblind", "accesscontrol", "button", "notifications", "inputtrigger", "outputtrigger", "gateway"] function interfaceToString(name) { switch(name) { case "light": @@ -91,9 +91,14 @@ ApplicationWindow { return qsTr("Awnings"); case "garagegate": return qsTr("Garage gates"); + case "accesscontrol": + return qsTr("Access control"); case "uncategorized": return qsTr("Uncategorized") + default: + console.warn("interfaceToString unhandled interface:", name) } + return "" } function interfacesToIcon(interfaces) { @@ -166,6 +171,8 @@ ApplicationWindow { return Qt.resolvedUrl("images/select-none.svg") case "simpleclosable": return Qt.resolvedUrl("images/sort-listitem.svg") + case "accesscontrol": + return Qt.resolvedUrl("images/network-secure.svg"); default: console.warn("InterfaceToIcon: Unhandled interface", name) } @@ -233,6 +240,8 @@ ApplicationWindow { page = "AwningDevicePage.qml"; } else if (interfaceList.indexOf("notifications") >= 0) { page = "NotificationsDevicePage.qml"; + } else if (interfaceList.indexOf("fingerprintreader") >= 0) { + page = "FingerprintReaderDevicePage.qml"; } else { page = "GenericDevicePage.qml"; } diff --git a/nymea-app/ui/devicepages/FingerprintReaderDevicePage.qml b/nymea-app/ui/devicepages/FingerprintReaderDevicePage.qml new file mode 100644 index 00000000..b248a147 --- /dev/null +++ b/nymea-app/ui/devicepages/FingerprintReaderDevicePage.qml @@ -0,0 +1,295 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.1 +import Nymea 1.0 +import "../components" +import "../customviews" + +DevicePageBase { + id: root + + readonly property var usersStateType: deviceClass.stateTypes.findByName("users") + readonly property var usersState: device.states.getState(usersStateType.id) + + readonly property var accessGrantedEventType: deviceClass.eventTypes.findByName("accessGranted") + readonly property var accessDeniedEventType: deviceClass.eventTypes.findByName("accessDenied") + + ColumnLayout { + anchors.fill: parent + +// Item { +// Layout.fillWidth: true +// Layout.preferredHeight: root.inputVisible ? inputColumn.implicitHeight : 0 +// Behavior on Layout.preferredHeight { NumberAnimation { duration: 130; easing.type: Easing.InOutQuad } } + +// ColumnLayout { +// id: inputColumn +// anchors { left: parent.left; bottom: parent.bottom; right: parent.right } + +// TextField { +// id: titleTextField +// Layout.fillWidth: true +// Layout.topMargin: app.margins +// Layout.leftMargin: app.margins; Layout.rightMargin: app.margins +// placeholderText: qsTr("Title") +// } + +// TextArea { +// id: bodyTextField +// Layout.fillWidth: true +// Layout.leftMargin: app.margins; Layout.rightMargin: app.margins +// placeholderText: qsTr("Text") +// wrapMode: Text.WordWrap +// } +// } +// } + + + + + Button { + Layout.fillWidth: true + Layout.margins: app.margins + text: qsTr("Manage access") + onClicked: { + pageStack.push(manageUsersComponent) + } + } + +// ThinDivider {} + + GenericTypeLogView { + Layout.fillHeight: true + Layout.fillWidth: true + text: qsTr("%1 fingerprints recognized on this device in the last %2 days.") + + logsModel: LogsModel { + deviceId: root.device.id + engine: _engine + live: true + Component.onCompleted: update() + typeIds: [root.accessGrantedEventType.id, root.accessDeniedEventType.id]; + + } + + delegate: MeaListItemDelegate { + width: parent.width + iconName: "../images/notification.svg" + text: model.typeId === root.accessGrantedEventType.id ? qsTr("Access granted for user %1").arg(model.value) : qsTr("Access denied") + subText: Qt.formatDateTime(model.timestamp) + progressive: false + + onClicked: { + var parts = model.value.trim().split(', ') + var popup = detailsPopup.createObject(root, {timestamp: model.timestamp, notificationTitle: parts[1], notificationBody: parts[0]}); + popup.open(); + } + } + } + } + + Component { + id: manageUsersComponent + Page { + header: GuhHeader { + text: qsTr("Manage users") + onBackPressed: pageStack.pop() + + HeaderButton { + imageSource: "../images/contact-new.svg" + onClicked: pageStack.push(addUserComponent) + } + } + + ColumnLayout { + anchors.fill: parent + Label { + Layout.fillWidth: true + Layout.margins: app.margins + wrapMode: Text.WordWrap + text: root.usersState.value.length === 0 ? + qsTr("There are no fingerprints registered with this lock") + : qsTr("The following users have valid fingerprints for this lock") + } + ThinDivider {} + ListView { + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + model: root.usersState.value + + delegate: MeaListItemDelegate { + text: modelData + width: parent.width + progressive: false + iconName: "../images/account.svg" + canDelete: true + onDeleteClicked: { + var actionType = root.deviceClass.actionTypes.findByName("removeUser") + var params = [] + var titleParam = {} + titleParam["paramTypeId"] = actionType.paramTypes.findByName("userId").id + titleParam["value"] = modelData + params.push(titleParam) + engine.deviceManager.executeAction(root.device.id, actionType.id, params) + } + } + } + } + } + } + + Component { + id: addUserComponent + Page { + id: addUserPage + header: GuhHeader { + text: qsTr("Add a new fingerprint") + onBackPressed: pageStack.pop() + } + + property bool error: false + + Connections { + target: engine.deviceManager + onExecuteActionReply: { + addUserPage.error = params["deviceError"] !== DeviceManager.DeviceErrorNoError + print("Execute action reply:", params); + addUserSwipeView.currentIndex++ + } + } + + ColumnLayout { + anchors.fill: parent + SwipeView { + id: addUserSwipeView + Layout.fillWidth: true + Layout.preferredHeight: 200 + Layout.alignment: Qt.AlignTop + Item { + width: addUserSwipeView.width + height: addUserSwipeView.height + + ColumnLayout { + anchors.fill: parent + anchors.margins: app.margins + Label { + Layout.fillWidth: true + text: qsTr("Username") + } + + TextField { + id: userIdTextField + Layout.fillWidth: true + } + Button { + text: qsTr("Add user") + Layout.fillWidth: true + onClicked: { + var actionType = root.deviceClass.actionTypes.findByName("addUser") + var params = [] + var titleParam = {} + titleParam["paramTypeId"] = actionType.paramTypes.findByName("userId").id + titleParam["value"] = userIdTextField.displayText + params.push(titleParam) + engine.deviceManager.executeAction(root.device.id, actionType.id, params) + addUserSwipeView.currentIndex++ + } + } + } + } + + Item { + width: addUserSwipeView.width + height: addUserSwipeView.height + + ColumnLayout { + anchors.fill: parent + anchors.margins: app.margins + Label { + text: qsTr("Please scan the fingerprint now") + Layout.fillWidth: true + } + } + } + + Item { + width: addUserSwipeView.width + height: addUserSwipeView.height + + ColumnLayout { + anchors.fill: parent + anchors.margins: app.margins + spacing: app.margins * 2 + Label { + Layout.fillWidth: true + font.pixelSize: app.largeFont + color: app.accentColor + text: addUserPage.error ? qsTr("Uh oh") : + qsTr("All done!") + horizontalAlignment: Text.AlignHCenter + } + Label { + text: addUserPage.error ? qsTr("Fingerprint could not be read.\nPlease try again.") : + qsTr("Fingerprint added!") + Layout.fillWidth: true + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + } + Button { + Layout.fillWidth: true + text: qsTr("OK") + onClicked: pageStack.pop() + } + } + } + } + } + } + } + + Component { + id: detailsPopup + MeaDialog { + id: detailsDialog + property string timestamp + property string notificationTitle + property string notificationBody + title: qsTr("Notification details") + Label { + Layout.fillWidth: true + text: qsTr("Date sent") + font.bold: true + } + + Label { + Layout.fillWidth: true + text: Qt.formatDateTime(detailsDialog.timestamp) + } + Label { + Layout.topMargin: app.margins + Layout.fillWidth: true + text: qsTr("Title") + font.bold: true + } + + Label { + Layout.fillWidth: true + text: detailsDialog.notificationTitle + wrapMode: Text.WordWrap + } + Label { + Layout.topMargin: app.margins + Layout.fillWidth: true + text: qsTr("Text") + font.bold: true + } + + Label { + Layout.fillWidth: true + text: detailsDialog.notificationBody + wrapMode: Text.WordWrap + } + } + } +} diff --git a/nymea-app/ui/devicepages/GenericDeviceStateDetailsPage.qml b/nymea-app/ui/devicepages/GenericDeviceStateDetailsPage.qml index 72d42b9c..9b65946c 100644 --- a/nymea-app/ui/devicepages/GenericDeviceStateDetailsPage.qml +++ b/nymea-app/ui/devicepages/GenericDeviceStateDetailsPage.qml @@ -118,6 +118,7 @@ Page { property var unitString: deviceClass.stateTypes.getStateType(stateTypeId).unitString text: unitString === "datetime" ? Qt.formatDateTime(new Date(value * 1000), Qt.DefaultLocaleShortDate) : value + " " + unitString horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight } } diff --git a/nymea-app/ui/devicepages/NotificationsDevicePage.qml b/nymea-app/ui/devicepages/NotificationsDevicePage.qml index 7a65782b..5ac06f94 100644 --- a/nymea-app/ui/devicepages/NotificationsDevicePage.qml +++ b/nymea-app/ui/devicepages/NotificationsDevicePage.qml @@ -79,6 +79,7 @@ DevicePageBase { logsModel: LogsModel { deviceId: root.device.id live: true + engine: _engine Component.onCompleted: update() typeIds: [root.deviceClass.actionTypes.findByName("notify").id]; diff --git a/nymea-app/ui/images/account.svg b/nymea-app/ui/images/account.svg new file mode 100644 index 00000000..f432ac97 --- /dev/null +++ b/nymea-app/ui/images/account.svg @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/contact-new.svg b/nymea-app/ui/images/contact-new.svg new file mode 100644 index 00000000..67dd7616 --- /dev/null +++ b/nymea-app/ui/images/contact-new.svg @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + +