More improvements in the thing lists

This commit is contained in:
Michael Zanetti 2020-12-05 02:03:45 +01:00
parent 592e1021b6
commit aaa50ccdff
17 changed files with 352 additions and 209 deletions

View File

@ -235,5 +235,6 @@
<file>ui/components/ColorPicker.qml</file>
<file>ui/utils/ActionQueue.qml</file>
<file>ui/components/ColorTemperaturePicker.qml</file>
<file>ui/components/ThingContextMenu.qml</file>
</qresource>
</RCC>

View File

@ -32,6 +32,7 @@ import QtQuick 2.9
import QtQuick.Controls 2.2
Menu {
modal: true
function calculateWidth() {
var result = 0;
var i = 0;

View File

@ -3,7 +3,7 @@ import QtQuick.Layouts 1.2
import QtQuick.Controls 2.1
import Nymea 1.0
Item {
Item {
id: root
implicitHeight: layout.implicitHeight + app.margins
@ -18,6 +18,10 @@ Item {
property alias topPadding: content.topPadding
property alias bottomPadding: content.bottomPadding
readonly property State connectedState: thing.stateByName("connected")
readonly property bool isConnected: connectedState === null || connectedState.value === true
readonly property bool isEnabled: thing.setupStatus == Thing.ThingSetupStatusComplete && isConnected
signal clicked();
signal pressAndHold();
@ -25,6 +29,13 @@ Item {
wobbleAnimation.start();
}
onPressAndHold: {
var contextMenuComponent = Qt.createComponent("../components/ThingContextMenu.qml");
var contextMenu = contextMenuComponent.createObject(root, { thing: root.thing })
contextMenu.x = Qt.binding(function() { return (root.width - contextMenu.width) / 2 })
contextMenu.open()
}
transform: Translate { id: wobbleTransform }
SequentialAnimation {

View File

@ -0,0 +1,164 @@
import QtQuick 2.9
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import Nymea 1.0
AutoSizeMenu {
id: root
property Thing thing: null
property bool showDetails: true
property bool showLogs: true
Component.onCompleted: {
root.addItem(menuEntryComponent.createObject(root, {text: qsTr("Magic"), iconSource: "../images/magic.svg", functionName: "openThingMagicPage"}))
if (root.showDetails) {
root.addItem(menuEntryComponent.createObject(root, {text: qsTr("Details"), iconSource: "../images/info.svg", functionName: "openGenericThingPage"}))
}
// root.addItem(menuEntryComponent.createObject(root, {text: qsTr("Settings"), iconSource: "../images/configure.svg", functionName: "openThingSettingsPage"}))
if (root.showLogs) {
root.addItem(menuEntryComponent.createObject(root, {text: qsTr("Logs"), iconSource: "../images/logs.svg", functionName: "openThingLogPage"}))
}
if (engine.jsonRpcClient.ensureServerVersion("1.6")) {
root.addItem(menuEntryComponent.createObject(root,
{
text: Qt.binding(function() { return favoritesProxy.count === 0 ? qsTr("Mark as favorite") : qsTr("Remove from favorites")}),
iconSource: Qt.binding(function() { return favoritesProxy.count === 0 ? "../images/starred.svg" : "../images/non-starred.svg"}),
functionName: "toggleFavorite"
}))
root.addItem(menuEntryComponent.createObject(root,
{
text: qsTr("Grouping"),
iconSource: "../images/view-grid-symbolic.svg",
functionName: "addToGroup"
}))
}
print("*** creating menu")
print("NFC", NfcHelper.isAvailable)
if (NfcHelper.isAvailable) {
root.addItem(menuEntryComponent.createObject(root,
{
text: qsTr("Write NFC tag"),
iconSource: "../images/nfc.svg",
functionName: "writeNfcTag"
}));
}
}
function openThingMagicPage() {
pageStack.push(Qt.resolvedUrl("../magic/DeviceRulesPage.qml"), {thing: root.thing})
}
function openGenericThingPage() {
pageStack.push(Qt.resolvedUrl("../devicepages/GenericDevicePage.qml"), {thing: root.thing})
}
function toggleFavorite() {
if (favoritesProxy.count === 0) {
engine.tagsManager.tagDevice(root.thing.id, "favorites", 100000)
} else {
engine.tagsManager.untagDevice(root.thing.id, "favorites")
}
}
function addToGroup() {
var dialog = addToGroupDialog.createObject(root.parent)
dialog.open();
}
function openThingSettingsPage() {
pageStack.push(Qt.resolvedUrl("../thingconfiguration/ConfigureThingPage.qml"), {thing: root.thing})
}
function openThingLogPage() {
pageStack.push(Qt.resolvedUrl("../devicepages/DeviceLogPage.qml"), {thing: root.thing });
}
function writeNfcTag() {
pageStack.push(Qt.resolvedUrl("../magic/WriteNfcTagPage.qml"), {thing: root.thing})
}
TagsProxyModel {
id: favoritesProxy
tags: engine.tagsManager.tags
filterDeviceId: root.thing.id
filterTagId: "favorites"
}
Component {
id: menuEntryComponent
IconMenuItem {
width: parent.width
property string functionName: ""
onTriggered: root[functionName]()
}
}
Component {
id: addToGroupDialog
MeaDialog {
title: qsTr("Groups for %1").arg(root.thing.name)
headerIcon: "../images/view-grid-symbolic.svg"
// NOTE: If CloseOnPressOutside is active (default) it will break the QtVirtualKeyboard
// https://bugreports.qt.io/browse/QTBUG-56918
closePolicy: Popup.CloseOnEscape
RowLayout {
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
spacing: app.margins
TextField {
id: newGroupdTextField
Layout.fillWidth: true
placeholderText: qsTr("New group")
}
Button {
text: qsTr("OK")
enabled: newGroupdTextField.displayText.length > 0 && !groupTags.containsId("group-" + newGroupdTextField.displayText)
onClicked: {
engine.tagsManager.tagDevice(root.thing.id, "group-" + newGroupdTextField.text, 1000)
newGroupdTextField.text = ""
}
}
}
ListView {
Layout.fillWidth: true
height: 200
clip: true
ScrollIndicator.vertical: ScrollIndicator {}
model: TagListModel {
id: groupTags
tagsProxy: TagsProxyModel {
tags: engine.tagsManager.tags
filterTagId: "group-.*"
}
}
delegate: CheckDelegate {
width: parent.width
text: model.tagId.substring(6)
checked: innerProxy.count > 0
onClicked: {
if (innerProxy.count == 0) {
engine.tagsManager.tagDevice(root.thing.id, model.tagId, 1000)
} else {
engine.tagsManager.untagDevice(root.thing.id, model.tagId, model.value)
}
}
ThingsProxy {
id: innerProxy
engine: _engine
filterTagId: model.tagId
filterDeviceId: root.thing.id
}
}
}
}
}
}

View File

@ -1,23 +1,60 @@
import QtQuick 2.9
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import Nymea 1.0
RowLayout {
id: root
Layout.fillWidth: false
spacing: app.margins / 2
property Thing thing: null
property color color: keyColor
readonly property color keyColor: updateStatusIcon.keyColor
signal updateIconClicked();
signal batteryIconClicked();
signal connectionIconClicked();
signal setupIconClicked();
UpdateStatusIcon {
id: updateStatusIcon
Layout.preferredHeight: app.smallIconSize
Layout.preferredWidth: height
thing: root.thing
visible: updateAvailable || updateRunning
visible: setupStatusIcon.setupStatus == Thing.ThingSetupStatusComplete && connectionStatusIcon.isConnected && (updateAvailable || updateRunning)
Binding { target: updateStatusIcon; property: "color"; value: root.color; when: root.color !== root.keyColor }
MouseArea {
anchors.fill: parent
anchors.margins: -app.margins / 4
onClicked: {
var dialogComponent = Qt.createComponent("MeaDialog.qml")
var currentVersionState = root.thing.stateByName("currentVersion")
var availableVersionState = root.thing.stateByName("availableVersion")
var text = qsTr("An update for %1 is available. Do you want to start the update now?").arg(root.thing.name)
if (currentVersionState) {
text += "\n\n" + qsTr("Current version: %1").arg(currentVersionState.value)
}
if (availableVersionState) {
text += "\n\n" + qsTr("Available version: %1").arg(availableVersionState.value)
}
var dialog = dialogComponent.createObject(app,
{
headerIcon: "../images/system-update.svg",
title: qsTr("Update"),
text: text,
standardButtons: Dialog.Ok | Dialog.Cancel
})
dialog.accepted.connect(function() {
print("starting update")
engine.thingManager.executeAction(root.thing.id, root.thing.thingClass.actionTypes.findByName("performUpdate").id)
})
dialog.open();
root.updateIconClicked()
}
}
}
BatteryStatusIcon {
id: batteryStatusIcon
@ -26,6 +63,27 @@ RowLayout {
thing: root.thing
visible: root.thing.setupStatus == Thing.ThingSetupStatusComplete && (hasBatteryLevel || isCritical)
Binding { target: batteryStatusIcon; property: "color"; value: root.color; when: root.color !== root.keyColor }
MouseArea {
anchors.fill: parent
anchors.margins: -app.margins / 4
onClicked: {
root.batteryIconClicked()
var levelStateType = root.thing.thingClass.stateTypes.findByName("batteryLevel");
var criticalStateType = root.thing.thingClass.stateTypes.findByName("batteryCritical");
var stateTypes = []
if (levelStateType) {
stateTypes.push(levelStateType.id)
}
if (criticalStateType) {
stateTypes.push(criticalStateType.id)
}
pageStack.push("../devicepages/DeviceLogPage.qml",
{
thing: root.thing,
filterTypeIds: stateTypes
});
}
}
}
ConnectionStatusIcon {
id: connectionStatusIcon
@ -34,6 +92,27 @@ RowLayout {
thing: root.thing
visible: root.thing.setupStatus == Thing.ThingSetupStatusComplete && (hasSignalStrength || !isConnected)
Binding { target: connectionStatusIcon; property: "color"; value: root.color; when: root.color !== root.keyColor }
MouseArea {
anchors.fill: parent
anchors.margins: -app.margins / 4
onClicked: {
root.connectionIconClicked()
var signalStateType = root.thing.thingClass.stateTypes.findByName("signalStrength")
var connectedStateType = root.thing.thingClass.stateTypes.findByName("connected")
var stateTypes = []
if (signalStateType) {
stateTypes.push(signalStateType.id)
}
if (connectedStateType) {
stateTypes.push(connectedStateType.id)
}
pageStack.push("../devicepages/DeviceLogPage.qml",
{
thing: root.thing,
filterTypeIds: stateTypes
});
}
}
}
SetupStatusIcon {
id: setupStatusIcon
@ -42,5 +121,13 @@ RowLayout {
thing: root.thing
visible: setupFailed || setupInProgress
Binding { target: setupStatusIcon; property: "color"; value: root.color; when: root.color !== root.keyColor }
MouseArea {
anchors.fill: parent
anchors.margins: -app.margins / 4
onClicked: {
root.setupIconClicked()
pageStack.push("../thingconfiguration/ConfigureThingPage.qml", { thing: root.thing });
}
}
}
}

View File

@ -103,13 +103,17 @@ DeviceListPageBase {
Layout.preferredWidth: contentGrid.width / contentGrid.columns
thing: root.thingsProxy.getThing(model.id)
showHeader: false
enabled: connectedState == null || connectedState.value === true
topPadding: 0
bottomPadding: 0
onClicked: root.enterPage(index)
onClicked: {
if (isEnabled) {
root.enterPage(index)
} else {
itemDelegate.wobble()
}
}
property State connectedState: thing.stateByName("connected")
property State movingState: thing.stateByName("moving")
property State percentageState: thing.stateByName("percentage")
@ -131,6 +135,7 @@ DeviceListPageBase {
Layout.fillWidth: true
text: itemDelegate.thing.name
elide: Text.ElideRight
enabled: itemDelegate.isEnabled
}
ThingStatusIcons {
@ -143,6 +148,7 @@ DeviceListPageBase {
height: parent.height
device: itemDelegate.thing
invert: root.invertControls
enabled: itemDelegate.isEnabled
}
}
}

View File

@ -67,13 +67,17 @@ DeviceListPageBase {
Layout.preferredWidth: contentGrid.width / contentGrid.columns
thing: root.thingsProxy.getThing(model.id)
showHeader: false
enabled: connectedState == null || connectedState.value === true
topPadding: 0
bottomPadding: 0
onClicked: root.enterPage(index)
onClicked: {
if (isEnabled) {
root.enterPage(index)
} else {
itemDelegate.wobble()
}
}
property State connectedState: thing.stateByName("connected")
property State movingState: thing.stateByName("moving")
property State percentageState: thing.stateByName("percentage")
@ -97,6 +101,7 @@ DeviceListPageBase {
Layout.fillWidth: true
text: itemDelegate.thing.name
elide: Text.ElideRight
enabled: itemDelegate.isEnabled
}
ThingStatusIcons {
@ -110,6 +115,7 @@ DeviceListPageBase {
device: itemDelegate.thing
invert: root.invertControls
visible: !itemDelegate.isImpulseBased
enabled: itemDelegate.isEnabled
}
ProgressButton {
Layout.preferredHeight: app.iconSize
@ -117,6 +123,7 @@ DeviceListPageBase {
longpressEnabled: false
imageSource: "../images/closable-move.svg"
visible: itemDelegate.isImpulseBased
enabled: itemDelegate.isEnabled
onClicked: {
var actionTypeId = itemDelegate.thing.thingClass.actionTypes.findByName("triggerImpulse").id
print("Triggering impulse", actionTypeId)

View File

@ -73,11 +73,16 @@ DeviceListPageBase {
Layout.preferredWidth: contentGrid.width / contentGrid.columns
thing: root.thingsProxy.getThing(model.id)
showHeader: false
enabled: connectedState == null || connectedState.value === true
topPadding: 0
bottomPadding: 0
onClicked: root.enterPage(index)
onClicked: {
if (isEnabled) {
root.enterPage(index)
} else {
itemDelegate.wobble()
}
}
property State connectedState: thing.stateByName("connected")
property State powerState: thing.stateByName("power")
@ -96,6 +101,7 @@ DeviceListPageBase {
Layout.fillWidth: true
text: itemDelegate.thing.name
elide: Text.ElideRight
enabled: itemDelegate.isEnabled
}
ThingStatusIcons {
@ -104,7 +110,8 @@ DeviceListPageBase {
Switch {
visible: itemDelegate.powerState !== null
checked: itemDelegate.powerState.value === true
checked: itemDelegate.powerState && itemDelegate.powerState.value === true
enabled: itemDelegate.isEnabled
onClicked: {
var params = [];
var param1 = {};

View File

@ -97,18 +97,16 @@ DeviceListPageBase {
leftPadding: 0
rightPadding: 0
property State connectedState: thing.stateByName("connected")
property State powerState: thing.stateByName("power")
property State brightnessState: thing.stateByName("brightness")
property State colorState: thing.stateByName("color")
property State colorTemperatureState: thing.stateByName("colorTemperature")
property bool tileColored: isConnected && colorState && powerState.value === true
property bool tileColored: isEnabled && colorState && powerState.value === true
property bool colorInverted: tileColored && NymeaUtils.isDark(app.foregroundColor) === NymeaUtils.isDark(colorState.value)
property bool isConnected: connectedState === null || connectedState.value === true
onClicked: {
if (isConnected) {
if (isEnabled && (colorState || colorTemperatureState)) {
root.enterPage(index)
} else {
itemDelegate.wobble()
@ -126,7 +124,6 @@ DeviceListPageBase {
implicitHeight: contentColumn.implicitHeight
Behavior on implicitHeight { NumberAnimation { duration: 100 } }
radius: 6
enabled: itemDelegate.isConnected
ColumnLayout {
id: contentColumn
@ -156,6 +153,7 @@ DeviceListPageBase {
Layout.fillWidth: true
text: itemDelegate.thing.name
elide: Text.ElideRight
enabled: itemDelegate.isEnabled
Binding {
target: nameLabel
@ -172,6 +170,7 @@ DeviceListPageBase {
Switch {
id: lightSwitch
checked: itemDelegate.powerState.value === true
enabled: itemDelegate.isEnabled
onClicked: {
var params = [];
var param1 = {};
@ -256,6 +255,7 @@ DeviceListPageBase {
visible: itemDelegate.powerState.value === true && itemDelegate.brightnessState != null
radius: 6
color: Qt.tint(app.backgroundColor, Qt.rgba(app.foregroundColor.r, app.foregroundColor.g, app.foregroundColor.b, .1))
enabled: itemDelegate.isEnabled
Rectangle {
height: knob.x + knob.width / 2

View File

@ -68,9 +68,6 @@ DeviceListPageBase {
bottomPadding: 0
leftPadding: 0
rightPadding: 0
enabled: connectedState == null || connectedState.value === true
property State connectedState: thing.stateByName("connected")
readonly property StateType playbackStateType: thing.thingClass.stateTypes.findByName("playbackStatus")
readonly property State playbackState: thing.stateByName("playbackStatus")
@ -79,10 +76,15 @@ DeviceListPageBase {
readonly property State playerTypeState: thing.stateByName("playerType")
onClicked: {
enterPage(index)
if (isEnabled) {
enterPage(index)
} else {
itemDelegate.wobble();
}
}
contentItem: RowLayout {
enabled: itemDelegate.isEnabled
ColumnLayout {
id: leftColummn
Layout.margins: app.margins
@ -183,7 +185,6 @@ DeviceListPageBase {
}
}
}
}
}
}

View File

@ -67,11 +67,16 @@ DeviceListPageBase {
Layout.preferredWidth: contentGrid.width / contentGrid.columns
thing: root.thingsProxy.getThing(model.id)
showHeader: false
enabled: connectedState == null || connectedState.value === true
topPadding: 0
bottomPadding: 0
onClicked: root.enterPage(index)
onClicked: {
if (isEnabled) {
root.enterPage(index)
} else {
itemDelegate.wobble();
}
}
property State connectedState: thing.stateByName("connected")
property State powerState: thing.stateByName("power")
@ -90,6 +95,7 @@ DeviceListPageBase {
Layout.fillWidth: true
text: itemDelegate.thing.name
elide: Text.ElideRight
enabled: itemDelegate.isEnabled
}
ThingStatusIcons {
@ -98,6 +104,7 @@ DeviceListPageBase {
Switch {
checked: itemDelegate.powerState.value === true
enabled: itemDelegate.isEnabled
onClicked: {
var params = [];
var param1 = {};

View File

@ -64,9 +64,7 @@ DeviceListPageBase {
Layout.preferredWidth: contentGrid.width / contentGrid.columns
thing: root.thingsProxy.getThing(model.id)
onClicked: {
enterPage(index)
}
onClicked: enterPage(index)
contentItem: GridLayout {
id: dataGrid

View File

@ -39,11 +39,12 @@ import "../customviews"
Page {
id: root
property Device device: null
property Thing thing: null
property alias device: root.thing
property var filterTypeIds: []
header: NymeaHeader {
text: qsTr("History for %1").arg(root.device.name)
text: qsTr("History for %1").arg(root.thing.name)
onBackPressed: pageStack.pop()
HeaderButton {
@ -57,7 +58,7 @@ Page {
LogsModelNg {
id: logsModelNg
engine: _engine
deviceId: root.device.id
deviceId: root.thing.id
typeIds: root.filterTypeIds.length > 0
? root.filterTypeIds
: filterEnabled
@ -70,7 +71,7 @@ Page {
DeviceModel {
id: filterDeviceModel
device: root.device
device: root.thing
}
Pane {
@ -111,7 +112,7 @@ Page {
right: parent.right
}
readonly property StateType stateType: root.device.deviceClass.stateTypes.getStateType(root.filterTypeIds[0])
readonly property StateType stateType: root.thing.thingClass.stateTypes.getStateType(root.filterTypeIds[0])
readonly property bool canShowGraph: {
if (stateType === null) {
@ -122,14 +123,15 @@ Page {
return false;
}
switch (stateType.type) {
case "Int":
case "Double":
switch (stateType.type.toLowerCase()) {
case "uint":
case "int":
case "double":
return true;
case "Bool":
case "bool":
return engine.jsonRpcClient.ensureServerVersion("1.10")
}
print("not showing graph for", root.stateType.type)
print("not showing graph for", stateType.type)
return false;
}
@ -142,7 +144,7 @@ Page {
}
var source = Qt.resolvedUrl("../customviews/GenericTypeGraph.qml");
setSource(source, {device: root.device, stateType: stateType})
setSource(source, {device: root.thing, stateType: stateType})
}
}
@ -162,9 +164,9 @@ Page {
id: entryDelegate
width: parent.width
property StateType stateType: model.source === LogEntry.LoggingSourceStates ? root.device.deviceClass.stateTypes.getStateType(model.typeId) : null
property EventType eventType: model.source === LogEntry.LoggingSourceEvents || model.source === LogEntry.LoggingSourceStates ? root.device.deviceClass.eventTypes.getEventType(model.typeId) : null
property ActionType actionType: model.source === LogEntry.LoggingSourceActions ? root.device.deviceClass.actionTypes.getActionType(model.typeId) : null
property StateType stateType: model.source === LogEntry.LoggingSourceStates ? root.thing.thingClass.stateTypes.getStateType(model.typeId) : null
property EventType eventType: model.source === LogEntry.LoggingSourceEvents || model.source === LogEntry.LoggingSourceStates ? root.thing.thingClass.eventTypes.getEventType(model.typeId) : null
property ActionType actionType: model.source === LogEntry.LoggingSourceActions ? root.thing.thingClass.actionTypes.getActionType(model.typeId) : null
contentItem: RowLayout {
ColorIcon {

View File

@ -74,171 +74,21 @@ Page {
}
}
TagsProxyModel {
id: favoritesProxy
tags: engine.tagsManager.tags
filterDeviceId: root.device.id
filterTagId: "favorites"
}
AutoSizeMenu {
ThingContextMenu {
id: thingMenu
x: parent.width - width
thing: root.thing
showDetails: root.showDetailsButton
showLogs: root.showLogsButton
}
Component.onCompleted: {
thingMenu.addItem(menuEntryComponent.createObject(thingMenu, {text: qsTr("Magic"), iconSource: "../images/magic.svg", functionName: "openDeviceMagicPage"}))
if (root.showDetailsButton) {
thingMenu.addItem(menuEntryComponent.createObject(thingMenu, {text: qsTr("Details"), iconSource: "../images/info.svg", functionName: "openGenericDevicePage"}))
Connections {
target: engine.deviceManager.devices
onThingRemoved:{
if (device == root.device) {
print("Device destroyed")
pageStack.pop()
}
// thingMenu.addItem(menuEntryComponent.createObject(thingMenu, {text: qsTr("Settings"), iconSource: "../images/configure.svg", functionName: "openThingSettingsPage"}))
if (root.showLogsButton) {
thingMenu.addItem(menuEntryComponent.createObject(thingMenu, {text: qsTr("Logs"), iconSource: "../images/logs.svg", functionName: "openDeviceLogPage"}))
}
if (engine.jsonRpcClient.ensureServerVersion("1.6")) {
thingMenu.addItem(menuEntryComponent.createObject(thingMenu,
{
text: Qt.binding(function() { return favoritesProxy.count === 0 ? qsTr("Mark as favorite") : qsTr("Remove from favorites")}),
iconSource: Qt.binding(function() { return favoritesProxy.count === 0 ? "../images/starred.svg" : "../images/non-starred.svg"}),
functionName: "toggleFavorite"
}))
thingMenu.addItem(menuEntryComponent.createObject(thingMenu,
{
text: qsTr("Grouping"),
iconSource: "../images/view-grid-symbolic.svg",
functionName: "addToGroup"
}))
}
print("*** creating menu")
print("NFC", NfcHelper.isAvailable)
if (NfcHelper.isAvailable) {
thingMenu.addItem(menuEntryComponent.createObject(thingMenu,
{
text: qsTr("Write NFC tag"),
iconSource: "../images/nfc.svg",
functionName: "writeNfcTag"
}));
}
}
function openDeviceMagicPage() {
pageStack.push(Qt.resolvedUrl("../magic/DeviceRulesPage.qml"), {device: root.device})
}
function openGenericDevicePage() {
pageStack.push(Qt.resolvedUrl("GenericDevicePage.qml"), {device: root.device})
}
function toggleFavorite() {
if (favoritesProxy.count === 0) {
engine.tagsManager.tagDevice(root.device.id, "favorites", 100000)
} else {
engine.tagsManager.untagDevice(root.device.id, "favorites")
}
}
function addToGroup() {
var dialog = addToGroupDialog.createObject(root)
dialog.open();
}
function openThingSettingsPage() {
pageStack.push(Qt.resolvedUrl("../thingconfiguration/ConfigureThingPage.qml"), {device: root.device})
}
function openDeviceLogPage() {
pageStack.push(Qt.resolvedUrl("DeviceLogPage.qml"), {device: root.device });
}
function writeNfcTag() {
pageStack.push(Qt.resolvedUrl("../magic/WriteNfcTagPage.qml"), {thing: root.thing})
}
Component {
id: menuEntryComponent
IconMenuItem {
width: parent.width
property string functionName: ""
onTriggered: thingMenu[functionName]()
}
}
Connections {
target: engine.deviceManager.devices
onThingRemoved:{
if (device == root.device) {
print("Device destroyed")
pageStack.pop()
}
}
}
Component {
id: addToGroupDialog
MeaDialog {
title: qsTr("Groups for %1").arg(root.device.name)
headerIcon: "../images/view-grid-symbolic.svg"
// NOTE: If CloseOnPressOutside is active (default) it will break the QtVirtualKeyboard
// https://bugreports.qt.io/browse/QTBUG-56918
closePolicy: Popup.CloseOnEscape
RowLayout {
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
spacing: app.margins
TextField {
id: newGroupdTextField
Layout.fillWidth: true
placeholderText: qsTr("New group")
}
Button {
text: qsTr("OK")
enabled: newGroupdTextField.displayText.length > 0 && !groupTags.containsId("group-" + newGroupdTextField.displayText)
onClicked: {
engine.tagsManager.tagDevice(root.device.id, "group-" + newGroupdTextField.text, 1000)
newGroupdTextField.text = ""
}
}
}
ListView {
Layout.fillWidth: true
height: 200
clip: true
ScrollIndicator.vertical: ScrollIndicator {}
model: TagListModel {
id: groupTags
tagsProxy: TagsProxyModel {
tags: engine.tagsManager.tags
filterTagId: "group-.*"
}
}
delegate: CheckDelegate {
width: parent.width
text: model.tagId.substring(6)
checked: innerProxy.count > 0
onClicked: {
if (innerProxy.count == 0) {
engine.tagsManager.tagDevice(root.device.id, model.tagId, 1000)
} else {
engine.tagsManager.untagDevice(root.device.id, model.tagId, model.value)
}
}
DevicesProxy {
id: innerProxy
engine: _engine
filterTagId: model.tagId
filterDeviceId: root.device.id
}
}
}
}
}
}

View File

@ -42,7 +42,7 @@ DevicePageBase {
function executeAction(actionTypeId, params) {
print("executing", actionTypeId)
return engine.deviceManager.executeAction(root.device.id, actionTypeId, params)
return engine.thingManager.executeAction(root.thing.id, actionTypeId, params)
}
ListView {

View File

@ -47,9 +47,9 @@ DevicePageBase {
readonly property StateType movingStateType: isExtended ? deviceClass.stateTypes.findByName("moving") : null
readonly property StateType angleStateType: isVenetian ? deviceClass.stateTypes.findByName("angle") : null
readonly property State movingState: isExtended ? device.states.getState(movingStateType.id) : 0
readonly property State percentageState: isExtended ? device.states.getState(deviceClass.stateTypes.findByName("percentage").id) : 0
readonly property State angleState: isVenetian ? device.states.getState(angleStateType.id) : 0
readonly property State movingState: isExtended ? device.states.getState(movingStateType.id) : null
readonly property State percentageState: isExtended ? device.states.getState(deviceClass.stateTypes.findByName("percentage").id) : null
readonly property State angleState: isVenetian ? device.states.getState(angleStateType.id) : null
readonly property bool moving: movingState ? movingState.value === true : false
@ -212,8 +212,8 @@ DevicePageBase {
id: angleMouseArea
anchors.fill: parent
// angle : totalAngle = mouseY : height
property int totalAngle: root.angleStateType.maxValue - root.angleStateType.minValue
property int angle: totalAngle * mouseY / height + root.angleStateType.minValue
property int totalAngle: root.angleState ? root.angleStateType.maxValue - root.angleStateType.minValue : 0
property int angle: root.angleState ? totalAngle * mouseY / height + root.angleStateType.minValue : 0
hoverEnabled: true
property int startY: 0

View File

@ -37,7 +37,8 @@ import Nymea 1.0
Page {
id: root
property var device: null
property Thing thing: null
property alias device: root.thing
Component.onCompleted: print("+++ created devicerulespage")
Component.onDestruction: print("--- destroying devicerulespage")