More work on NFC support

This commit is contained in:
Michael Zanetti 2020-10-02 23:50:59 +02:00
parent 3ea0ec1f9f
commit 2508e4dd8a
9 changed files with 386 additions and 15 deletions

View File

@ -29,6 +29,7 @@ SOURCES += \
nymeaappservice/androidbinder.cpp \
../nymea-app/stylecontroller.cpp \
../nymea-app/platformhelper.cpp \
../nymea-app/nfchelper.cpp \
../nymea-app/platformintegration/android/platformhelperandroid.cpp \
service_main.cpp
@ -38,6 +39,7 @@ HEADERS += \
nymeaappservice/androidbinder.h \
../nymea-app/stylecontroller.h \
../nymea-app/platformhelper.h \
../nymea-app/nfchelper.h \
../nymea-app/platformintegration/android/platformhelperandroid.h \
DISTFILES += \

View File

@ -6,6 +6,7 @@
#include "libnymea-app-core.h"
#include "../nymea-app/stylecontroller.h"
#include "../nymea-app/platformhelper.h"
#include "../nymea-app/nfchelper.h"
#include "../nymea-app/platformintegration/android/platformhelperandroid.h"
#include <QQmlApplicationEngine>
@ -54,20 +55,21 @@ DeviceControlApplication::DeviceControlApplication(int argc, char *argv[]) : QAp
qDebug() << "Connecting to:" << host;
qDebug() << "Creating QML view";
QQmlApplicationEngine *qmlEngine = new QQmlApplicationEngine(this);
m_qmlEngine = new QQmlApplicationEngine(this);
registerQmlTypes();
qmlRegisterSingletonType<PlatformHelper>("Nymea", 1, 0, "PlatformHelper", platformHelperProvider);
qmlRegisterSingletonType(QUrl("qrc:///ui/utils/NymeaUtils.qml"), "Nymea", 1, 0, "NymeaUtils" );
qmlRegisterType<NfcHelper>("Nymea", 1, 0, "NfcHelper");
StyleController styleController;
qmlEngine->rootContext()->setContextProperty("styleController", &styleController);
qmlEngine->rootContext()->setContextProperty("engine", m_engine);
qmlEngine->rootContext()->setContextProperty("_engine", m_engine);
qmlEngine->rootContext()->setContextProperty("controlledThingId", thingId);
m_qmlEngine->rootContext()->setContextProperty("styleController", &styleController);
m_qmlEngine->rootContext()->setContextProperty("engine", m_engine);
m_qmlEngine->rootContext()->setContextProperty("_engine", m_engine);
m_qmlEngine->rootContext()->setContextProperty("controlledThingId", thingId);
qmlEngine->load(QUrl(QLatin1String("qrc:/Main.qml")));
m_qmlEngine->load(QUrl(QLatin1String("qrc:/Main.qml")));
}
void DeviceControlApplication::handleNdefMessage(QNdefMessage message, QNearFieldTarget *target)
@ -88,8 +90,7 @@ void DeviceControlApplication::handleNdefMessage(QNdefMessage message, QNearFiel
NymeaHost *host = m_discovery->nymeaHosts()->find(nymeaId);
m_engine->jsonRpcClient()->connectToHost(host);
qmlEngine->rootContext()->setContextProperty("controlledThingId", thingId);
m_qmlEngine->rootContext()->setContextProperty("controlledThingId", thingId);
}
}

View File

@ -4,6 +4,7 @@
#include <QApplication>
#include <QNearFieldManager>
#include <QNdefMessage>
#include <QQmlApplicationEngine>
#include "connection/discovery/nymeadiscovery.h"
#include "engine.h"
@ -22,7 +23,7 @@ private slots:
private:
NymeaDiscovery *m_discovery = nullptr;
Engine *m_engine = nullptr;
QQmlApplicationEngine *m_qmlEngine = nullptr;
};
#endif // DEVICECONTROLAPPLICATION_H

View File

@ -237,5 +237,6 @@
<file>ui/images/connections/bluetooth.svg</file>
<file>ui/images/connections/network-wired-disabled.svg</file>
<file>ui/images/nfc.svg</file>
<file>ui/images/smartphone.svg</file>
</qresource>
</RCC>

View File

@ -165,4 +165,10 @@ BR=$$BRANDING
target.path = /usr/bin
INSTALLS += target
ANDROID_ABIS = armeabi-v7a arm64-v8a
ANDROID_ABIS = armeabi-v7a
contains(ANDROID_TARGET_ARCH,) {
ANDROID_ABIS = \
armeabi-v7a \
arm64-v8a
}

View File

@ -223,5 +223,6 @@
<file>ui/components/BatteryStatusIcon.qml</file>
<file>ui/components/SetupStatusIcon.qml</file>
<file>ui/components/UpdateStatusIcon.qml</file>
<file>ui/magic/WriteNfcTagPage.qml</file>
</qresource>
</RCC>

View File

@ -146,12 +146,8 @@ Page {
pageStack.push(Qt.resolvedUrl("DeviceLogPage.qml"), {device: root.device });
}
NfcHelper {
id: nfcHelper
}
function writeNfcTag() {
nfcHelper.writeThingStates(engine, root.thing)
pageStack.push(Qt.resolvedUrl("../magic/WriteNfcTagPage.qml"), {thing: root.thing})
}
Component {

View File

@ -0,0 +1,166 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="96"
height="96"
id="svg4874"
version="1.1"
inkscape:version="0.91+devel r"
viewBox="0 0 96 96.000001"
sodipodi:docname="phone-smartphone-symbolic.svg">
<defs
id="defs4876" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="8.7812488"
inkscape:cx="15.954447"
inkscape:cy="64.905333"
inkscape:document-units="px"
inkscape:current-layer="g4780"
showgrid="true"
showborder="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="true"
inkscape:object-nodes="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-midpoints="true"
inkscape:snap-object-midpoints="true"
inkscape:snap-center="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-global="true">
<inkscape:grid
type="xygrid"
id="grid5451"
empspacing="8" />
<sodipodi:guide
orientation="1,0"
position="8,-8.0000001"
id="guide4063" />
<sodipodi:guide
orientation="1,0"
position="4,-8.0000001"
id="guide4065" />
<sodipodi:guide
orientation="0,1"
position="-8,88.000001"
id="guide4067" />
<sodipodi:guide
orientation="0,1"
position="-8,92.000001"
id="guide4069" />
<sodipodi:guide
orientation="0,1"
position="104,4"
id="guide4071" />
<sodipodi:guide
orientation="0,1"
position="-5,8.0000001"
id="guide4073" />
<sodipodi:guide
orientation="1,0"
position="88,-8.0000001"
id="guide4077" />
<sodipodi:guide
orientation="0,1"
position="-8,84.000001"
id="guide4074" />
<sodipodi:guide
orientation="1,0"
position="12,-8.0000001"
id="guide4076" />
<sodipodi:guide
orientation="1,0"
position="84,-8.0000001"
id="guide4080" />
<sodipodi:guide
position="48,-8.0000001"
orientation="1,0"
id="guide4170" />
<sodipodi:guide
position="-8,48"
orientation="0,1"
id="guide4172" />
<sodipodi:guide
position="92,-8.0000001"
orientation="1,0"
id="guide4760" />
<sodipodi:guide
position="108,12"
orientation="0,1"
id="guide4182" />
</sodipodi:namedview>
<metadata
id="metadata4879">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(67.857146,-78.50504)">
<g
transform="matrix(0,-1,-1,0,373.50506,516.50504)"
id="g4845"
style="display:inline">
<g
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="next01.png"
transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
id="g4778"
inkscape:label="Layer 1">
<g
transform="matrix(-1,0,0,1,575.99999,611)"
id="g4780"
style="display:inline">
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
id="rect4782"
width="96.037987"
height="96"
x="-438.00244"
y="345.36221"
transform="scale(-1,1)" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00000048;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 35.976562,2.0000001 C 30.943803,2.0581871 27.26124,1.881546 24.25,3.5429689 22.74438,4.3736802 21.553141,5.7767541 20.894531,7.5312501 20.235931,9.2857461 19.998047,11.369641 19.998047,14 v 68 c 0,2.630359 0.237884,4.714254 0.896484,6.46875 0.65861,1.754496 1.849849,3.15757 3.355469,3.988281 3.01124,1.661433 6.693803,1.484792 11.726562,1.542969 h 0.01172 24.021485 0.01172 c 5.03276,-0.05818 8.715323,0.118464 11.726563,-1.542969 1.50562,-0.830711 2.696869,-2.233785 3.355469,-3.988281 C 75.762116,86.714254 76,84.630359 76,82 V 14 C 76,11.369641 75.762116,9.2857461 75.103516,7.5312501 74.444916,5.7767541 73.253667,4.3736802 71.748047,3.5429689 68.736807,1.881546 65.054244,2.0581771 60.021484,2.0000001 H 60.009766 35.988281 Z M 24.080078,12 h 47.839844 c 0.04599,0.606222 0.07813,1.255513 0.07813,2 V 82 H 24 V 14 c 0,-0.744487 0.03408,-1.393778 0.08008,-2 z M 40,86 h 16 v 3.998047 H 40 Z"
transform="matrix(0,-1,-1.0003957,0,438.00245,441.36222)"
id="path4297"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscsscccccccsssssccccccsccscccccc" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -0,0 +1,197 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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"
Page {
id: root
property Thing thing: null
readonly property ThingClass thingClass: thing.thingClass
header: NymeaHeader {
text: qsTr("Write NFC tag")
onBackPressed: {
root.backPressed();
}
}
NfcHelper {
id: nfcHelper
}
// nfcHelper.writeThingStates(engine, root.thing)
GridLayout {
anchors.fill: parent
columns: app.landscape ? 2 : 1
Item {
Layout.preferredWidth: Math.min(root.width / parent.columns, root.height)
Layout.preferredHeight: app.iconSize * 8
SequentialAnimation {
loops: Animation.Infinite
running: true
PropertyAction { target: phoneIcon; property: "anchors.horizontalCenterOffset"; value: app.iconSize * 2 }
PropertyAction { target: phoneIcon; property: "scale"; value: 1.3 }
NumberAnimation {
target: phoneIcon
property: "opacity"
duration: 500
to: 1
}
PauseAnimation { duration: 500 }
ParallelAnimation {
NumberAnimation {
target: phoneIcon
property: "anchors.horizontalCenterOffset"
from: app.iconSize * 2
to: -app.iconSize * 2
duration: 1500
easing.type: Easing.OutQuad
}
NumberAnimation {
target: phoneIcon
property: "scale"
duration: 1500
from: 1.3
to: 1
easing.type: Easing.InOutQuad
}
}
ParallelAnimation {
loops: 2
NumberAnimation {
duration: 250
target: vibrateCircle
property: "scale"
from: .8
to: 1.5
}
NumberAnimation {
duration: 250
target: vibrateCircle
property: "opacity"
from: 1
to: 0
}
}
PauseAnimation {
duration: 500
}
NumberAnimation {
target: phoneIcon
property: "opacity"
duration: 500
to: 0
}
}
ColorIcon {
id: nfcIcon
name: "../images/nfc.svg"
height: app.iconSize * 2
width: app.iconSize * 2
anchors.centerIn: parent
anchors.horizontalCenterOffset: - app.iconSize * 2
}
Item {
id: phoneIcon
height: app.iconSize * 5
width: app.iconSize * 5
scale: 1.5
anchors.centerIn: parent
anchors.horizontalCenterOffset: app.iconSize * 2
Rectangle {
id: vibrateCircle
anchors.centerIn: parent
anchors.fill: parent
radius: width / 2
color: "transparent"
// border.color: nfcIcon.keyColor
border.color: app.accentColor
border.width: 2
scale: .8
opacity: 0
}
Rectangle {
anchors.fill: parent
anchors.leftMargin: phoneIcon.width * .21
anchors.rightMargin: phoneIcon.width * .21
anchors.topMargin: phoneIcon.height * .1
anchors.bottomMargin: phoneIcon.height * .1
color: app.backgroundColor
}
ColorIcon {
name: "../images/smartphone.svg"
anchors.fill: parent
}
}
}
ColumnLayout {
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
text: qsTr("Select the wanted states and tap an NFC tag to store them. When tapping this tag later, they will be restored.").arg(root.thing.name)
wrapMode: Text.WordWrap
font.pixelSize: app.smallFont
}
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
model: root.thingClass.stateTypes
clip: true
delegate: CheckDelegate {
width: parent.width
text: model.displayName
checked: true
}
}
}
}
}