372 lines
15 KiB
QML
372 lines
15 KiB
QML
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
*
|
|
* Copyright 2013 - 2020, nymea GmbH
|
|
* Contact: contact@nymea.io
|
|
*
|
|
* This file is part of nymea.
|
|
* This project including source code and documentation is protected by
|
|
* copyright law, and remains the property of nymea GmbH. All rights, including
|
|
* reproduction, publication, editing and translation, are reserved. The use of
|
|
* this project is subject to the terms of a license agreement to be concluded
|
|
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
|
|
* under https://nymea.io/license
|
|
*
|
|
* GNU General Public License Usage
|
|
* Alternatively, this project may be redistributed and/or modified under the
|
|
* terms of the GNU General Public License as published by the Free Software
|
|
* Foundation, GNU version 3. 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 project. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
* For any further details and any questions please contact us under
|
|
* contact@nymea.io or see our FAQ/Licensing Information on
|
|
* https://nymea.io/license/faq
|
|
*
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
import QtQuick 2.5
|
|
import QtQuick.Controls 2.1
|
|
import QtQuick.Layouts 1.1
|
|
import Nymea 1.0
|
|
import "../components"
|
|
import "../customviews"
|
|
|
|
ThingPageBase {
|
|
id: root
|
|
|
|
readonly property State usersState: thing.stateByName("users")
|
|
|
|
readonly property EventType accessGrantedEventType: thing.thingClass.eventTypes.findByName("accessGranted")
|
|
readonly property EventType accessDeniedEventType: thing.thingClass.eventTypes.findByName("accessDenied")
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
|
|
Button {
|
|
Layout.fillWidth: true
|
|
Layout.leftMargin: app.margins; Layout.topMargin: app.margins; Layout.rightMargin: app.margins
|
|
text: qsTr("Manage access")
|
|
onClicked: {
|
|
pageStack.push(manageUsersComponent)
|
|
}
|
|
}
|
|
|
|
ThinDivider {}
|
|
|
|
Label {
|
|
Layout.fillWidth: true
|
|
Layout.margins: app.margins
|
|
text: qsTr("Access log:")
|
|
}
|
|
|
|
GenericTypeLogView {
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
|
|
logsModel: LogsModel {
|
|
id: logsModel
|
|
thingId: root.thing.id
|
|
engine: _engine
|
|
live: true
|
|
typeIds: [root.accessGrantedEventType.id, root.accessDeniedEventType.id];
|
|
}
|
|
|
|
delegate: NymeaSwipeDelegate {
|
|
width: parent.width
|
|
iconName: accessGranted ? "../images/tick.svg" : "../images/dialog-error-symbolic.svg"
|
|
iconColor: accessGranted ? "green" : "red"
|
|
text: accessGranted ? qsTr("Access granted for user %1").arg(model.value) : qsTr("Access denied")
|
|
subText: Qt.formatDateTime(model.timestamp)
|
|
progressive: false
|
|
|
|
property bool accessGranted: model.typeId === root.accessGrantedEventType.id
|
|
|
|
onClicked: {
|
|
var parts = model.value.trim().split(', ')
|
|
var popup = detailsPopup.createObject(root, {timestamp: model.timestamp, accessGranted: accessGranted, user: parts[0], finger: parts[1]});
|
|
popup.open();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: manageUsersComponent
|
|
Page {
|
|
header: NymeaHeader {
|
|
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: NymeaSwipeDelegate {
|
|
text: modelData
|
|
width: parent.width
|
|
progressive: false
|
|
iconName: "../images/account.svg"
|
|
canDelete: true
|
|
onClicked: {
|
|
pageStack.push(addUserComponent, {user: modelData})
|
|
}
|
|
|
|
onDeleteClicked: {
|
|
var actionType = root.thing.thingClass.actionTypes.findByName("removeUser")
|
|
var params = []
|
|
var titleParam = {}
|
|
titleParam["paramTypeId"] = actionType.paramTypes.findByName("userId").id
|
|
titleParam["value"] = modelData
|
|
params.push(titleParam)
|
|
engine.thingManager.executeAction(root.thing.id, actionType.id, params)
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.centerIn: parent
|
|
spacing: app.margins * 2
|
|
visible: parent.count === 0
|
|
width: parent.width - app.margins * 2
|
|
Item {
|
|
Layout.preferredWidth: 100
|
|
Layout.preferredHeight: width
|
|
Layout.alignment: Qt.AlignHCenter
|
|
ColorIcon {
|
|
name: "../images/fingerprint.svg"
|
|
anchors.centerIn: parent
|
|
height: Math.min(parent.width, parent.height)
|
|
width: height
|
|
}
|
|
}
|
|
|
|
Button {
|
|
text: qsTr("Add a fingerprint")
|
|
onClicked: pageStack.push(addUserComponent)
|
|
Layout.alignment: Qt.AlignHCenter
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: addUserComponent
|
|
Page {
|
|
id: addUserPage
|
|
header: NymeaHeader {
|
|
text: qsTr("Add a new fingerprint")
|
|
onBackPressed: pageStack.pop()
|
|
}
|
|
|
|
property string user: ""
|
|
|
|
property bool done: false
|
|
property bool error: false
|
|
|
|
Connections {
|
|
target: engine.thingManager
|
|
onExecuteActionReply: {
|
|
addUserPage.error = thingError !== Thing.ThingErrorNoError
|
|
var masks =[]
|
|
masks.push({x: 0, y: 0, width: 1, height: 1});
|
|
addUserPage.done = true
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
SwipeView {
|
|
id: addUserSwipeView
|
|
Layout.fillWidth: true
|
|
Layout.topMargin: app.margins
|
|
Layout.alignment: Qt.AlignTop
|
|
interactive: false
|
|
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
|
|
text: addUserPage.user
|
|
enabled: addUserPage.user.length === 0
|
|
}
|
|
Label {
|
|
Layout.fillWidth: true
|
|
text: qsTr("Finger")
|
|
}
|
|
ComboBox {
|
|
id: fingerComboBox
|
|
Layout.fillWidth: true
|
|
model: ListModel {
|
|
ListElement { modelData: qsTr("Left thumb"); enumValue: "ThumbLeft" }
|
|
ListElement { modelData: qsTr("Left index finger"); enumValue: "IndexFingerLeft" }
|
|
ListElement { modelData: qsTr("Left middle finger"); enumValue: "MiddleFingerLeft" }
|
|
ListElement { modelData: qsTr("Left ring finger"); enumValue: "RingFingerLeft" }
|
|
ListElement { modelData: qsTr("Left pinky finger"); enumValue: "PinkyLeft" }
|
|
ListElement { modelData: qsTr("Right thumb"); enumValue: "ThumbRight" }
|
|
ListElement { modelData: qsTr("Right index finger"); enumValue: "IndexFingerRight" }
|
|
ListElement { modelData: qsTr("Right middle finger"); enumValue: "MiddleFingerRight" }
|
|
ListElement { modelData: qsTr("Right ring finger"); enumValue: "RingFingerRight" }
|
|
ListElement { modelData: qsTr("Right pinky finger"); enumValue: "PinkyRight" }
|
|
}
|
|
}
|
|
|
|
Button {
|
|
text: qsTr("Add user")
|
|
Layout.fillWidth: true
|
|
onClicked: {
|
|
var actionType = root.thing.thingClass.actionTypes.findByName("addUser")
|
|
var params = []
|
|
var titleParam = {}
|
|
titleParam["paramTypeId"] = actionType.paramTypes.findByName("userId").id
|
|
titleParam["value"] = userIdTextField.displayText
|
|
params.push(titleParam)
|
|
var fingerParam = {}
|
|
fingerParam["paramTypeId"] = actionType.paramTypes.findByName("finger").id
|
|
fingerParam["value"] = fingerComboBox.model.get(fingerComboBox.currentIndex).enumValue
|
|
params.push(fingerParam)
|
|
engine.thingManager.executeAction(root.thing.id, actionType.id, params)
|
|
addUserSwipeView.currentIndex++
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
width: addUserSwipeView.width
|
|
height: addUserSwipeView.height
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
anchors.margins: app.margins
|
|
spacing: app.margins * 2
|
|
Label {
|
|
text: !addUserPage.done ? qsTr("Please scan the fingerprint now")
|
|
: addUserPage.error ? qsTr("Uh oh")
|
|
: qsTr("All done!")
|
|
Layout.fillWidth: true
|
|
font.pixelSize: app.largeFont
|
|
color: Style.accentColor
|
|
horizontalAlignment: Text.AlignHCenter
|
|
}
|
|
|
|
Item {
|
|
Layout.preferredWidth: 100
|
|
Layout.preferredHeight: 100
|
|
Layout.alignment: Qt.AlignCenter
|
|
|
|
ColorIcon {
|
|
name: "../images/fingerprint.svg"
|
|
height: Math.min(parent.width, parent.height)
|
|
width: height
|
|
anchors.centerIn: parent
|
|
color: addUserPage.done ?
|
|
(addUserPage.error ? "red" : Style.accentColor)
|
|
: Style.iconColor
|
|
}
|
|
}
|
|
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
|
|
visible: addUserPage.done
|
|
}
|
|
Button {
|
|
Layout.fillWidth: true
|
|
text: qsTr("OK")
|
|
onClicked: pageStack.pop()
|
|
visible: addUserPage.done
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: detailsPopup
|
|
MeaDialog {
|
|
id: detailsDialog
|
|
property string timestamp
|
|
property bool accessGranted
|
|
property string user
|
|
property string finger
|
|
title: qsTr("Access request details")
|
|
Label {
|
|
Layout.fillWidth: true
|
|
text: qsTr("Date/Time")
|
|
font.bold: true
|
|
}
|
|
|
|
Label {
|
|
Layout.fillWidth: true
|
|
text: Qt.formatDateTime(detailsDialog.timestamp)
|
|
}
|
|
Label {
|
|
Layout.topMargin: app.margins
|
|
Layout.fillWidth: true
|
|
text: detailsDialog.accessGranted ? qsTr("User") : qsTr("Access denied")
|
|
font.bold: true
|
|
}
|
|
|
|
Label {
|
|
Layout.fillWidth: true
|
|
text: detailsDialog.user
|
|
wrapMode: Text.WordWrap
|
|
visible: detailsDialog.accessGranted
|
|
}
|
|
|
|
Label {
|
|
Layout.topMargin: app.margins
|
|
Layout.fillWidth: true
|
|
text: qsTr("Fingerprint")
|
|
font.bold: true
|
|
visible: detailsDialog.accessGranted
|
|
}
|
|
|
|
Label {
|
|
Layout.fillWidth: true
|
|
text: detailsDialog.finger
|
|
wrapMode: Text.WordWrap
|
|
visible: detailsDialog.accessGranted
|
|
}
|
|
}
|
|
}
|
|
}
|