Add wifi setup, theme and translations

This commit is contained in:
Simon Stürz 2018-05-05 20:09:11 +02:00 committed by Michael Zanetti
parent f422d2b7ed
commit d52f983880
82 changed files with 5624 additions and 214 deletions

View File

@ -9,26 +9,27 @@ CONFIG += static
target.path = /usr/lib/$$system('dpkg-architecture -q DEB_HOST_MULTIARCH') target.path = /usr/lib/$$system('dpkg-architecture -q DEB_HOST_MULTIARCH')
INSTALLS += target INSTALLS += target
HEADERS += types/types.h \ HEADERS += \
types/vendor.h \ types/types.h \
types/vendors.h \ types/vendor.h \
types/deviceclass.h \ types/vendors.h \
types/device.h \ types/deviceclass.h \
types/param.h \ types/device.h \
types/params.h \ types/param.h \
types/paramtype.h \ types/params.h \
types/paramtypes.h \ types/paramtype.h \
types/statetype.h \ types/paramtypes.h \
types/statetypes.h \ types/statetype.h \
types/eventtype.h \ types/statetypes.h \
types/eventtypes.h \ types/eventtype.h \
types/actiontype.h \ types/eventtypes.h \
types/actiontypes.h \ types/actiontype.h \
types/state.h \ types/actiontypes.h \
types/states.h \ types/state.h \
types/statesproxy.h \ types/states.h \
types/plugin.h \ types/statesproxy.h \
types/plugins.h \ types/plugin.h \
types/plugins.h \
types/rules.h \ types/rules.h \
types/rule.h \ types/rule.h \
types/eventdescriptor.h \ types/eventdescriptor.h \
@ -51,25 +52,26 @@ HEADERS += types/types.h \
types/timeeventitems.h \ types/timeeventitems.h \
types/calendaritems.h types/calendaritems.h
SOURCES += types/vendor.cpp \ SOURCES += \
types/vendors.cpp \ types/vendor.cpp \
types/deviceclass.cpp \ types/vendors.cpp \
types/device.cpp \ types/deviceclass.cpp \
types/param.cpp \ types/device.cpp \
types/params.cpp \ types/param.cpp \
types/paramtype.cpp \ types/params.cpp \
types/paramtypes.cpp \ types/paramtype.cpp \
types/statetype.cpp \ types/paramtypes.cpp \
types/statetypes.cpp \ types/statetype.cpp \
types/eventtype.cpp \ types/statetypes.cpp \
types/eventtypes.cpp \ types/eventtype.cpp \
types/actiontype.cpp \ types/eventtypes.cpp \
types/actiontypes.cpp \ types/actiontype.cpp \
types/state.cpp \ types/actiontypes.cpp \
types/states.cpp \ types/state.cpp \
types/statesproxy.cpp \ types/states.cpp \
types/plugin.cpp \ types/statesproxy.cpp \
types/plugins.cpp \ types/plugin.cpp \
types/plugins.cpp \
types/rules.cpp \ types/rules.cpp \
types/rule.cpp \ types/rule.cpp \
types/eventdescriptor.cpp \ types/eventdescriptor.cpp \

View File

@ -14,6 +14,8 @@ int RuleActions::rowCount(const QModelIndex &parent) const
QVariant RuleActions::data(const QModelIndex &index, int role) const QVariant RuleActions::data(const QModelIndex &index, int role) const
{ {
Q_UNUSED(index)
Q_UNUSED(role)
return QVariant(); return QVariant();
} }

View File

@ -13,6 +13,8 @@ int StateEvaluators::rowCount(const QModelIndex &parent) const
QVariant StateEvaluators::data(const QModelIndex &index, int role) const QVariant StateEvaluators::data(const QModelIndex &index, int role) const
{ {
Q_UNUSED(index)
Q_UNUSED(role)
return QVariant(); return QVariant();
} }

View File

@ -68,6 +68,11 @@ BasicConfiguration *Engine::basicConfiguration() const
return m_basicConfiguration; return m_basicConfiguration;
} }
BluetoothDiscovery *Engine::bluetoothDiscovery() const
{
return m_bluetoothDiscovery;
}
NymeaConnection *Engine::connection() const NymeaConnection *Engine::connection() const
{ {
return m_connection; return m_connection;
@ -80,7 +85,8 @@ Engine::Engine(QObject *parent) :
m_deviceManager(new DeviceManager(m_jsonRpcClient, this)), m_deviceManager(new DeviceManager(m_jsonRpcClient, this)),
m_ruleManager(new RuleManager(m_jsonRpcClient, this)), m_ruleManager(new RuleManager(m_jsonRpcClient, this)),
m_logManager(new LogManager(m_jsonRpcClient, this)), m_logManager(new LogManager(m_jsonRpcClient, this)),
m_basicConfiguration(new BasicConfiguration(m_jsonRpcClient, this)) m_basicConfiguration(new BasicConfiguration(m_jsonRpcClient, this)),
m_bluetoothDiscovery(new BluetoothDiscovery(this))
{ {
connect(m_jsonRpcClient, &JsonRpcClient::connectedChanged, this, &Engine::onConnectedChanged); connect(m_jsonRpcClient, &JsonRpcClient::connectedChanged, this, &Engine::onConnectedChanged);
connect(m_jsonRpcClient, &JsonRpcClient::authenticationRequiredChanged, this, &Engine::onConnectedChanged); connect(m_jsonRpcClient, &JsonRpcClient::authenticationRequiredChanged, this, &Engine::onConnectedChanged);

View File

@ -28,6 +28,7 @@
#include "devicemanager.h" #include "devicemanager.h"
#include "nymeainterface.h" #include "nymeainterface.h"
#include "jsonrpc/jsonrpcclient.h" #include "jsonrpc/jsonrpcclient.h"
#include "wifisetup/bluetoothdiscovery.h"
class RuleManager; class RuleManager;
class LogManager; class LogManager;
@ -41,6 +42,7 @@ class Engine : public QObject
Q_PROPERTY(RuleManager* ruleManager READ ruleManager CONSTANT) Q_PROPERTY(RuleManager* ruleManager READ ruleManager CONSTANT)
Q_PROPERTY(JsonRpcClient* jsonRpcClient READ jsonRpcClient CONSTANT) Q_PROPERTY(JsonRpcClient* jsonRpcClient READ jsonRpcClient CONSTANT)
Q_PROPERTY(BasicConfiguration* basicConfiguration READ basicConfiguration CONSTANT) Q_PROPERTY(BasicConfiguration* basicConfiguration READ basicConfiguration CONSTANT)
Q_PROPERTY(BluetoothDiscovery* bluetoothDiscovery READ bluetoothDiscovery CONSTANT)
public: public:
static Engine *instance(); static Engine *instance();
@ -54,7 +56,8 @@ public:
RuleManager *ruleManager() const; RuleManager *ruleManager() const;
JsonRpcClient *jsonRpcClient() const; JsonRpcClient *jsonRpcClient() const;
LogManager *logManager() const; LogManager *logManager() const;
BasicConfiguration* basicConfiguration() const; BasicConfiguration *basicConfiguration() const;
BluetoothDiscovery *bluetoothDiscovery() const;
private: private:
explicit Engine(QObject *parent = 0); explicit Engine(QObject *parent = 0);
@ -66,6 +69,7 @@ private:
RuleManager *m_ruleManager; RuleManager *m_ruleManager;
LogManager *m_logManager; LogManager *m_logManager;
BasicConfiguration *m_basicConfiguration; BasicConfiguration *m_basicConfiguration;
BluetoothDiscovery *m_bluetoothDiscovery;
private slots: private slots:
void onConnectedChanged(); void onConnectedChanged();

View File

@ -52,6 +52,7 @@
#include "models/valuelogsproxymodel.h" #include "models/valuelogsproxymodel.h"
#include "models/eventdescriptorparamsfiltermodel.h" #include "models/eventdescriptorparamsfiltermodel.h"
#include "basicconfiguration.h" #include "basicconfiguration.h"
#include "wifisetup/networkmanagercontroler.h"
static QObject* interfacesModel_provider(QQmlEngine *engine, QJSEngine *scriptEngine) static QObject* interfacesModel_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
{ {
@ -156,6 +157,13 @@ int main(int argc, char *argv[])
qmlRegisterType<ValueLogsProxyModel>(uri, 1, 0, "ValueLogsProxyModel"); qmlRegisterType<ValueLogsProxyModel>(uri, 1, 0, "ValueLogsProxyModel");
qmlRegisterUncreatableType<LogEntry>(uri, 1, 0, "LogEntry", "Get them from LogsModel"); qmlRegisterUncreatableType<LogEntry>(uri, 1, 0, "LogEntry", "Get them from LogsModel");
qmlRegisterType<NetworkManagerControler>(uri, 1, 0, "NetworkManagerControler");
qmlRegisterUncreatableType<BluetoothDiscovery>(uri, 1, 0, "BluetoothDiscovery", "Can't create this in QML. Get it from the Engine instance.");
qmlRegisterUncreatableType<BluetoothDeviceInfo>(uri, 1, 0, "BluetoothDeviceInfo", "Can't create this in QML. Get it from the DeviceInfos.");
qmlRegisterUncreatableType<BluetoothDeviceInfos>(uri, 1, 0, "BluetoothDeviceInfos", "Can't create this in QML. Get it from the BluetoothDiscovery.");
qmlRegisterUncreatableType<WirelessSetupManager>(uri, 1, 0, "WirelessSetupManager", "Can't create this in QML. Get it from the NetworkManagerControler.");
qmlRegisterUncreatableType<WirelessAccesspoints>(uri, 1, 0, "WirelessAccesspoints", "Can't create this in QML. Get it from the Loop.");
Engine::instance(); Engine::instance();
QQmlApplicationEngine engine; QQmlApplicationEngine engine;

View File

@ -2,8 +2,7 @@ TEMPLATE=app
TARGET=mea TARGET=mea
include(../mea.pri) include(../mea.pri)
QT += qml quick quickcontrols2 websockets svg bluetooth
QT += qml quick quickcontrols2 websockets svg
INCLUDEPATH += $$top_srcdir/libnymea-common INCLUDEPATH += $$top_srcdir/libnymea-common
LIBS += -L$$top_builddir/libnymea-common/release -L$$top_builddir/libnymea-common/ -lnymea-common LIBS += -L$$top_builddir/libnymea-common/release -L$$top_builddir/libnymea-common/ -lnymea-common
@ -38,7 +37,15 @@ HEADERS += engine.h \
discovery/nymeadiscovery.h \ discovery/nymeadiscovery.h \
logmanager.h \ logmanager.h \
basicconfiguration.h \ basicconfiguration.h \
models/eventdescriptorparamsfiltermodel.h models/eventdescriptorparamsfiltermodel.h \
wifisetup/bluetoothdevice.h \
wifisetup/bluetoothdeviceinfo.h \
wifisetup/bluetoothdeviceinfos.h \
wifisetup/bluetoothdiscovery.h \
wifisetup/wirelessaccesspoint.h \
wifisetup/wirelessaccesspoints.h \
wifisetup/wirelesssetupmanager.h \
wifisetup/networkmanagercontroler.h
SOURCES += main.cpp \ SOURCES += main.cpp \
@ -72,7 +79,15 @@ SOURCES += main.cpp \
discovery/nymeadiscovery.cpp \ discovery/nymeadiscovery.cpp \
logmanager.cpp \ logmanager.cpp \
basicconfiguration.cpp \ basicconfiguration.cpp \
models/eventdescriptorparamsfiltermodel.cpp models/eventdescriptorparamsfiltermodel.cpp \
wifisetup/bluetoothdevice.cpp \
wifisetup/bluetoothdeviceinfo.cpp \
wifisetup/bluetoothdeviceinfos.cpp \
wifisetup/bluetoothdiscovery.cpp \
wifisetup/wirelessaccesspoint.cpp \
wifisetup/wirelessaccesspoints.cpp \
wifisetup/wirelesssetupmanager.cpp \
wifisetup/networkmanagercontroler.cpp
withavahi { withavahi {
DEFINES += WITH_AVAHI DEFINES += WITH_AVAHI

View File

@ -62,6 +62,11 @@ QString NymeaConnection::url() const
return m_currentUrl.toString(); return m_currentUrl.toString();
} }
QString NymeaConnection::hostAddress() const
{
return m_currentUrl.host();
}
void NymeaConnection::sendData(const QByteArray &data) void NymeaConnection::sendData(const QByteArray &data)
{ {
if (connected()) { if (connected()) {

View File

@ -14,6 +14,7 @@ class NymeaConnection : public QObject
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged) Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
Q_PROPERTY(QString url READ url NOTIFY connectedChanged) Q_PROPERTY(QString url READ url NOTIFY connectedChanged)
Q_PROPERTY(QString hostAddress READ hostAddress NOTIFY connectedChanged)
public: public:
explicit NymeaConnection(QObject *parent = nullptr); explicit NymeaConnection(QObject *parent = nullptr);
@ -23,7 +24,9 @@ public:
Q_INVOKABLE void acceptCertificate(const QByteArray &fingerprint); Q_INVOKABLE void acceptCertificate(const QByteArray &fingerprint);
bool connected(); bool connected();
QString url() const; QString url() const;
QString hostAddress() const;
void sendData(const QByteArray &data); void sendData(const QByteArray &data);

View File

@ -158,5 +158,21 @@
<file>styles/dark/Page.qml</file> <file>styles/dark/Page.qml</file>
<file>styles/marantec/ApplicationWindow.qml</file> <file>styles/marantec/ApplicationWindow.qml</file>
<file>styles/maveo/ApplicationWindow.qml</file> <file>styles/maveo/ApplicationWindow.qml</file>
<file>ui/BluetoothDiscoveryPage.qml</file>
<file>ui/images/bluetooth.svg</file>
<file>ui/images/refresh.svg</file>
<file>ui/WirelessControlerPage.qml</file>
<file>ui/BluetoothLoadingPage.qml</file>
<file>ui/images/nm-signal-00.svg</file>
<file>ui/images/nm-signal-00-secure.svg</file>
<file>ui/images/nm-signal-25.svg</file>
<file>ui/images/nm-signal-25-secure.svg</file>
<file>ui/images/nm-signal-50.svg</file>
<file>ui/images/nm-signal-50-secure.svg</file>
<file>ui/images/nm-signal-75.svg</file>
<file>ui/images/nm-signal-75-secure.svg</file>
<file>ui/images/nm-signal-100.svg</file>
<file>ui/images/nm-signal-100-secure.svg</file>
<file>ui/images/network-vpn.svg</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -259,6 +259,8 @@ void RuleManager::parseRuleExitActions(const QVariantList &ruleActions, Rule *ru
void RuleManager::parseTimeDescriptor(const QVariantMap &timeDescriptor, Rule *rule) void RuleManager::parseTimeDescriptor(const QVariantMap &timeDescriptor, Rule *rule)
{ {
Q_UNUSED(rule)
foreach (const QVariant &timeEventItemVariant, timeDescriptor.value("timeEventItems").toList()) { foreach (const QVariant &timeEventItemVariant, timeDescriptor.value("timeEventItems").toList()) {
TimeEventItem *timeEventItem = new TimeEventItem(); TimeEventItem *timeEventItem = new TimeEventItem();
timeEventItem->setDateTime(QDateTime::fromSecsSinceEpoch(timeEventItemVariant.toMap().value("datetime").toULongLong())); timeEventItem->setDateTime(QDateTime::fromSecsSinceEpoch(timeEventItemVariant.toMap().value("datetime").toULongLong()));

View File

@ -0,0 +1,81 @@
import QtQuick 2.4
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.2
import "components"
import Mea 1.0
Page {
id: root
header: GuhHeader {
text: qsTr("Bluetooth discovery")
onBackPressed: pageStack.pop()
HeaderButton {
imageSource: Qt.resolvedUrl("images/refresh.svg")
onClicked: Engine.bluetoothDiscovery.start()
}
}
Component.onCompleted: Engine.bluetoothDiscovery.start()
ColumnLayout {
anchors.fill: parent
BusyIndicator {
Layout.alignment: Qt.AlignHCenter
running: Engine.bluetoothDiscovery.discovering
}
ThinDivider { }
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
model: Engine.bluetoothDiscovery.deviceInfos
clip: true
delegate: ItemDelegate {
width: parent.width
height: app.delegateHeight
RowLayout {
anchors.verticalCenter: parent.verticalCenter
Item {
Layout.fillHeight: true
Layout.preferredWidth: height
ColorIcon {
id: image
name: Qt.resolvedUrl("images/bluetooth.svg")
anchors.fill: parent
anchors.margins: app.margins / 2
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
anchors.margins: app.margins
Label {
text: model.name
}
Label {
text: model.address
font.pixelSize: app.smallFont
}
}
}
onClicked: {
print("Start bluetooth connection to", model.name, " --> ", model.address)
Engine.bluetoothDiscovery.stop()
pageStack.push(Qt.resolvedUrl("BluetoothLoadingPage.qml"), { name: model.name, address: model.address } )
}
}
}
}
}

View File

@ -0,0 +1,67 @@
import QtQuick 2.4
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.2
import "components"
import Mea 1.0
Page {
id: root
property string name
property string address
NetworkManagerControler {
id: networkManger
name: root.name
address: root.address
Component.onCompleted: networkManger.connectDevice()
}
Connections {
target: networkManger.manager
onInitializedChanged: {
if (networkManger.manager.initialized) {
pageStack.push(Qt.resolvedUrl("WirelessControlerPage.qml"), { name: root.name, address: root.address, networkManger: networkManger } )
} else {
pageStack.pop()
}
}
onConnectedChanged: {
if (!networkManger.manager.connected) {
pageStack.pop()
}
}
}
ColumnLayout {
anchors.centerIn: parent
Label {
wrapMode: Text.WordWrap
font.pixelSize: app.largeFont
Layout.fillWidth: true
text: qsTr("Establish bluetooth LE connection")
}
BusyIndicator {
Layout.alignment: Qt.AlignHCenter
running: true
}
Label {
id: workingMessage
Layout.alignment: Qt.AlignHCenter
text: networkManger.manager.statusText
}
Label {
id: initializingMessage
Layout.alignment: Qt.AlignHCenter
text: networkManger.manager.initializing ? qsTr("Initialize services...") : ""
}
}
}

View File

@ -10,6 +10,35 @@ Page {
readonly property bool haveHosts: discovery.discoveryModel.count > 0 readonly property bool haveHosts: discovery.discoveryModel.count > 0
header: GuhHeader {
text: qsTr("Connect nymea")
backButtonVisible: false
menuButtonVisible: true
onMenuPressed: connectionMenu.open()
}
Menu {
id: connectionMenu
width: implicitWidth + app.margins
IconMenuItem {
iconSource: "../images/network-vpn.svg"
text: qsTr("Manual connect")
onTriggered: pageStack.push(manualConnectPage)
}
MenuSeparator {}
IconMenuItem {
iconSource: "../images/bluetooth.svg"
text: qsTr("Wireless setup")
onTriggered: pageStack.push(Qt.resolvedUrl("BluetoothDiscoveryPage.qml"))
}
}
Component.onCompleted: { Component.onCompleted: {
print("completed connectPage. last connected host:", settings.lastConnectedHost) print("completed connectPage. last connected host:", settings.lastConnectedHost)
if (settings.lastConnectedHost.length > 0) { if (settings.lastConnectedHost.length > 0) {
@ -43,8 +72,8 @@ Page {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: root.haveHosts ? "Oh, look!" : "Uh oh" text: root.haveHosts ? qsTr("Oh, look!") : qsTr("Uh oh")
color: "black" //color: "black"
font.pixelSize: app.largeFont font.pixelSize: app.largeFont
} }
@ -84,7 +113,7 @@ Page {
} }
} }
onClicked: { onClicked: {
print("should connect to", model.nymeaRpcUrl) print("Should connect to", model.nymeaRpcUrl)
Engine.connection.connect(model.nymeaRpcUrl) Engine.connection.connect(model.nymeaRpcUrl)
pageStack.push(connectingPage) pageStack.push(connectingPage)
} }
@ -119,10 +148,109 @@ Page {
visible: root.haveHosts visible: root.haveHosts
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Not the ones you're looking for? We're looking for more!" text: qsTr("Not the ones you're looking for? We're looking for more!")
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
} }
BusyIndicator {
BusyIndicator { }
}
}
Component {
id: manualConnectPage
Page {
header: GuhHeader {
text: qsTr("Manual connect to nymea")
onBackPressed: pageStack.pop()
}
ColumnLayout {
anchors.fill: parent
anchors.margins: app.margins
spacing: app.margins
GridLayout {
Layout.fillHeight: true
Layout.fillWidth: true
columns: 2
ComboBox {
id: connectionTypeComboBox
Layout.fillWidth: true
Layout.columnSpan: 2
model: [ qsTr("TCP"), qsTr("Websocket") ]
}
Label { text: qsTr("Address:") }
TextField {
id: addressTextInput
Layout.fillWidth: true
placeholderText: "127.0.0.1"
validator: RegExpValidator { regExp: /^((?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.){0,3}(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$/ }
}
Label { text: qsTr("Port:") }
TextField {
id: portTextInput
Layout.fillWidth: true
placeholderText: connectionTypeComboBox.currentIndex === 0 ? "2222" : "4444"
validator: IntValidator{bottom: 1; top: 65535;}
}
Label {
Layout.fillWidth: true
text: qsTr("Encrypted connection:")
}
CheckBox {
id: secureCheckBox
checked: true
}
}
Button {
text: qsTr("Connect")
Layout.fillWidth: true
onClicked: {
var rpcUrl
var hostAddress
var port
// Set default to placeholder
if (addressTextInput.text === "") {
hostAddress = addressTextInput.placeholderText
} else {
hostAddress = addressTextInput.text
}
if (portTextInput.text === "") {
port = portTextInput.placeholderText
} else {
port = portTextInput.text
}
if (connectionTypeComboBox.currentIndex == 0) {
if (secureCheckBox.checked) {
rpcUrl = "nymeas://" + hostAddress + ":" + port
} else {
rpcUrl = "nymea://" + hostAddress + ":" + port
}
} else if (connectionTypeComboBox.currentIndex == 1) {
if (secureCheckBox.checked) {
rpcUrl = "wss://" + hostAddress + ":" + port
} else {
rpcUrl = "ws://" + hostAddress + ":" + port
}
}
print("Try to connect ", rpcUrl)
Engine.connection.connect(rpcUrl)
pageStack.push(connectingPage)
}
}
} }
} }
} }
@ -143,7 +271,7 @@ Page {
} }
Button { Button {
text: "Cancel" text: qsTr("Cancel")
Layout.fillWidth: true Layout.fillWidth: true
onClicked: { onClicked: {
Engine.connection.disconnect() Engine.connection.disconnect()
@ -191,13 +319,13 @@ Page {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: "The authenticity of this nymea box cannot be verified." text: qsTr("The authenticity of this nymea box cannot be verified.")
} }
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: "If this is the first time you connect to this box, this is expected. Once you trust a box, you should never see this message again for that one. If you see this message multiple times for the same box, something suspicious is going on!" text: qsTr("If this is the first time you connect to this box, this is expected. Once you trust a box, you should never see this message again for that one. If you see this message multiple times for the same box, something suspicious is going on!")
} }
GridLayout { GridLayout {
@ -217,13 +345,13 @@ Page {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.WrapAtWordBoundaryOrAnywhere wrapMode: Text.WrapAtWordBoundaryOrAnywhere
text: "Fingerprint: " + certDialog.fingerprint text: qsTr("Fingerprint: ") + certDialog.fingerprint
} }
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: "Do you want to trust this device?" text: qsTr("Do you want to trust this device?")
font.bold: true font.bold: true
} }
} }

View File

@ -7,7 +7,7 @@ import Mea 1.0
Page { Page {
id: root id: root
header: GuhHeader { header: GuhHeader {
text: "Configure Things" text: qsTr("Configure Things")
onBackPressed: pageStack.pop() onBackPressed: pageStack.pop()
} }

View File

@ -9,7 +9,7 @@ Page {
signal backPressed(); signal backPressed();
header: GuhHeader { header: GuhHeader {
text: "Welcome to nymea!" text: qsTr("Welcome to nymea!")
backButtonVisible: true backButtonVisible: true
onBackPressed: root.backPressed() onBackPressed: root.backPressed()
} }
@ -49,8 +49,8 @@ Page {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: Engine.jsonRpcClient.initialSetupRequired ? text: Engine.jsonRpcClient.initialSetupRequired ?
"In order to use your nymea system, please enter your email address and set a password for your nymea box." qsTr("In order to use your nymea system, please enter your email address and set a password for your nymea box.")
: "In order to use your nymea system, please log in." : qsTr("In order to use your nymea system, please log in.")
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
} }
@ -58,7 +58,7 @@ Page {
Layout.fillWidth: true Layout.fillWidth: true
Label { Label {
text: "Your e-mail address:" text: qsTr("Your e-mail address:")
Layout.fillWidth: true Layout.fillWidth: true
} }
TextField { TextField {
@ -73,7 +73,7 @@ Page {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Password:" text: qsTr("Password:")
} }
TextField { TextField {
id: passwordTextField id: passwordTextField
@ -88,7 +88,7 @@ Page {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Confirm password:" text: qsTr("Confirm password:")
} }
TextField { TextField {
id: confirmPasswordTextField id: confirmPasswordTextField
@ -110,7 +110,7 @@ Page {
Button { Button {
Layout.fillWidth: true Layout.fillWidth: true
text: "OK" text: qsTr("OK")
enabled: usernameTextField.text.length >= 5 && passwordTextField.text.length >= 8 enabled: usernameTextField.text.length >= 5 && passwordTextField.text.length >= 8
&& (!Engine.jsonRpcClient.initialSetupRequired || confirmPasswordTextField.text == passwordTextField.text) && (!Engine.jsonRpcClient.initialSetupRequired || confirmPasswordTextField.text == passwordTextField.text)
onClicked: { onClicked: {

View File

@ -9,7 +9,7 @@ Page {
id: root id: root
header: GuhHeader { header: GuhHeader {
text: "My things" text: qsTr("My things")
backButtonVisible: false backButtonVisible: false
menuButtonVisible: true menuButtonVisible: true
onMenuPressed: mainMenu.open() onMenuPressed: mainMenu.open()
@ -40,30 +40,30 @@ Page {
width: implicitWidth + app.margins width: implicitWidth + app.margins
IconMenuItem { IconMenuItem {
iconSource: "../images/share.svg" iconSource: "../images/share.svg"
text: "Configure things" text: qsTr("Configure things")
onTriggered: pageStack.push(Qt.resolvedUrl("EditDevicesPage.qml")) onTriggered: pageStack.push(Qt.resolvedUrl("EditDevicesPage.qml"))
} }
IconMenuItem { IconMenuItem {
iconSource: "../images/add.svg" iconSource: "../images/add.svg"
text: "Add a new thing" text: qsTr("Add a new thing")
onTriggered: pageStack.push(Qt.resolvedUrl("NewDeviceWizard.qml")) onTriggered: pageStack.push(Qt.resolvedUrl("NewDeviceWizard.qml"))
} }
MenuSeparator {} MenuSeparator {}
IconMenuItem { IconMenuItem {
iconSource: "../images/magic.svg" iconSource: "../images/magic.svg"
text: "Magic" text: qsTr("Magic")
onTriggered: pageStack.push(Qt.resolvedUrl("MagicPage.qml")) onTriggered: pageStack.push(Qt.resolvedUrl("MagicPage.qml"))
} }
MenuSeparator {} MenuSeparator {}
IconMenuItem { IconMenuItem {
iconSource: "../images/settings.svg" iconSource: "../images/settings.svg"
text: "Settings" text: qsTr("Settings")
onTriggered: pageStack.push(Qt.resolvedUrl("SettingsPage.qml")) onTriggered: pageStack.push(Qt.resolvedUrl("SettingsPage.qml"))
} }
MenuSeparator {} MenuSeparator {}
IconMenuItem { IconMenuItem {
iconSource: "../images/info.svg" iconSource: "../images/info.svg"
text: "System information" text: qsTr("System information")
onTriggered: pageStack.push(Qt.resolvedUrl("SystemInfoPage.qml")) onTriggered: pageStack.push(Qt.resolvedUrl("SystemInfoPage.qml"))
} }
} }
@ -137,7 +137,7 @@ Page {
running: parent.visible running: parent.visible
} }
Label { Label {
text: "Loading data..." text: qsTr("Loading data...")
font.pixelSize: app.largeFont font.pixelSize: app.largeFont
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
@ -150,7 +150,7 @@ Page {
spacing: app.margins spacing: app.margins
visible: Engine.deviceManager.devices.count === 0 && !Engine.deviceManager.fetchingData visible: Engine.deviceManager.devices.count === 0 && !Engine.deviceManager.fetchingData
Label { Label {
text: "Welcome to nymea!" text: qsTr("Welcome to nymea!")
font.pixelSize: app.largeFont font.pixelSize: app.largeFont
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
@ -158,7 +158,7 @@ Page {
color: app.guhAccent color: app.guhAccent
} }
Label { Label {
text: "There are no things set up yet. You can start with adding your things by using the menu on the upper left and selecting \"Add a new thing\"." text: qsTr("There are no things set up yet. You can start with adding your things by using the menu on the upper left and selecting \"Add a new thing\".")
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter

View File

@ -9,7 +9,7 @@ Page {
id: root id: root
header: GuhHeader { header: GuhHeader {
text: "Set up new thing" text: qsTr("Set up new thing")
backButtonVisible: internalPageStack.depth > 1 backButtonVisible: internalPageStack.depth > 1
onBackPressed: { onBackPressed: {
internalPageStack.pop(); internalPageStack.pop();
@ -246,7 +246,7 @@ Page {
visible: discovery.busy visible: discovery.busy
spacing: app.margins * 2 spacing: app.margins * 2
Label { Label {
text: "Searching for things..." text: qsTr("Searching for things...")
Layout.fillWidth: true Layout.fillWidth: true
font.pixelSize: app.largeFont font.pixelSize: app.largeFont
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
@ -264,23 +264,23 @@ Page {
visible: !discovery.busy && discovery.count == 0 visible: !discovery.busy && discovery.count == 0
spacing: app.margins * 2 spacing: app.margins * 2
Label { Label {
text: "Too bad..." text: qsTr("Too bad...")
font.pixelSize: app.largeFont font.pixelSize: app.largeFont
Layout.fillWidth: true Layout.fillWidth: true
} }
Label { Label {
text: "No things of this kind could be found..." text: qsTr("No things of this kind could be found...")
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
} }
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Make sure your things are set up and connected, try searching again or go back and pick a different kind of thing." text: qsTr("Make sure your things are set up and connected, try searching again or go back and pick a different kind of thing.")
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
} }
Button { Button {
text: "Try again!" text: qsTr("Try again!")
Layout.fillWidth: true Layout.fillWidth: true
onClicked: { onClicked: {
discovery.discoverDevices(d.deviceClass.id, d.discoveryParams) discovery.discoverDevices(d.deviceClass.id, d.discoveryParams)

View File

@ -9,7 +9,7 @@ Page {
signal backPressed(); signal backPressed();
header: GuhHeader { header: GuhHeader {
text: "Welcome to nymea!" text: qsTr("Welcome to nymea!")
backButtonVisible: true backButtonVisible: true
onBackPressed: { onBackPressed: {
root.backPressed(); root.backPressed();
@ -58,7 +58,7 @@ Page {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Please press the button on your nymea box to authenticate this device." text: qsTr("Please press the button on your nymea box to authenticate this device.")
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
} }

View File

@ -8,7 +8,7 @@ import "components"
Page { Page {
id: root id: root
header: GuhHeader { header: GuhHeader {
text: "Settings" text: qsTr("Settings")
backButtonVisible: true backButtonVisible: true
onBackPressed: pageStack.pop() onBackPressed: pageStack.pop()
} }
@ -21,7 +21,7 @@ Page {
Layout.margins: app.margins Layout.margins: app.margins
Label { Label {
text: "Application".toUpperCase() text: qsTr("Application").toUpperCase()
color: app.guhAccent color: app.guhAccent
Layout.fillWidth: true Layout.fillWidth: true
} }
@ -30,10 +30,10 @@ Page {
Layout.fillWidth: true Layout.fillWidth: true
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "View mode" text: qsTr("View mode")
} }
ComboBox { ComboBox {
model: ["Windowed", "Maximized", "Fullscreen"] model: [qsTr("Windowed"), qsTr("Maximized"), qsTr("Fullscreen")]
currentIndex: { currentIndex: {
switch (settings.viewMode) { switch (settings.viewMode) {
case ApplicationWindow.Windowed: case ApplicationWindow.Windowed:
@ -90,7 +90,7 @@ Page {
Layout.fillWidth: true Layout.fillWidth: true
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Return to home on idle" text: qsTr("Return to home on idle")
} }
CheckBox { CheckBox {
checked: settings.returnToHome checked: settings.returnToHome
@ -101,16 +101,16 @@ Page {
Layout.fillWidth: true Layout.fillWidth: true
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Graph style" text: qsTr("Graph style")
} }
RadioButton { RadioButton {
checked: settings.graphStyle === "bars" checked: settings.graphStyle === "bars"
text: "Bars" text: qsTr("Bars")
onClicked: settings.graphStyle = "bars" onClicked: settings.graphStyle = "bars"
} }
RadioButton { RadioButton {
checked: settings.graphStyle === "bezier" checked: settings.graphStyle === "bezier"
text: "Lines" text: qsTr("Lines")
onClicked: settings.graphStyle = "bezier" onClicked: settings.graphStyle = "bezier"
} }
@ -125,7 +125,7 @@ Page {
Layout.leftMargin: app.margins Layout.leftMargin: app.margins
Layout.rightMargin: app.margins Layout.rightMargin: app.margins
Layout.topMargin: app.margins Layout.topMargin: app.margins
text: "System".toUpperCase() text: qsTr("System").toUpperCase()
color: app.guhAccent color: app.guhAccent
} }
@ -158,10 +158,20 @@ Page {
Layout.fillWidth: true Layout.fillWidth: true
} }
Switch { Switch {
id: debugServerEnabledSwitch
checked: Engine.basicConfiguration.debugServerEnabled checked: Engine.basicConfiguration.debugServerEnabled
onClicked: Engine.basicConfiguration.debugServerEnabled = checked onClicked: Engine.basicConfiguration.debugServerEnabled = checked
} }
} }
Button {
id: debugServerButton
Layout.fillWidth: true
visible: debugServerEnabledSwitch.checked
text: qsTr("Open debug interface")
onClicked: Qt.openUrlExternally("http://" + Engine.connection.hostAddress + "/debug")
}
} }
ItemDelegate { ItemDelegate {
@ -169,7 +179,7 @@ Page {
contentItem: RowLayout { contentItem: RowLayout {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Plugins" text: qsTr("Plugins")
} }
Image { Image {
source: "images/next.svg" source: "images/next.svg"

View File

@ -8,7 +8,7 @@ import Mea 1.0
Page { Page {
id: root id: root
header: GuhHeader { header: GuhHeader {
text: "System information" text: qsTr("System information")
backButtonVisible: true backButtonVisible: true
onBackPressed: pageStack.pop() onBackPressed: pageStack.pop()
} }
@ -22,7 +22,7 @@ Page {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Connected to:" text: qsTr("Connected to:")
color: Material.accent color: Material.accent
} }
RowLayout { RowLayout {
@ -33,7 +33,7 @@ Page {
text: Engine.connection.url text: Engine.connection.url
} }
Button { Button {
text: "Disconnect" text: qsTr("Disconnect")
onClicked: { onClicked: {
settings.lastConnectedHost = ""; settings.lastConnectedHost = "";
Engine.connection.disconnect(); Engine.connection.disconnect();
@ -48,7 +48,7 @@ Page {
Layout.fillWidth: true Layout.fillWidth: true
contentItem: RowLayout { contentItem: RowLayout {
Label { Label {
text: "Log viewer" text: qsTr("Log viewer")
Layout.fillWidth: true Layout.fillWidth: true
} }
Image { Image {

View File

@ -0,0 +1,310 @@
import QtQuick 2.4
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.2
import "components"
import Mea 1.0
Page {
id: root
property string name
property string address
property QtObject networkManger
header: GuhHeader {
text: qsTr("Wireless network")
onBackPressed: {
pageStack.pop()
pageStack.pop()
}
HeaderButton {
imageSource: Qt.resolvedUrl("images/refresh.svg")
onClicked: networkManger.manager.loadNetworks()
}
HeaderButton {
imageSource: Qt.resolvedUrl("images/settings.svg")
onClicked: pageStack.push(settingsPage)
}
}
Component.onCompleted: networkManger.manager.loadNetworks()
ColumnLayout {
anchors.fill: parent
visible: networkManger.manager.initialized
Label {
wrapMode: Text.WordWrap
Layout.fillWidth: true
text: qsTr("Network status: ") + networkManger.manager.networkStatus
}
Label {
wrapMode: Text.WordWrap
Layout.fillWidth: true
text: qsTr("Wireless status: ") + networkManger.manager.wirelessStatus
}
BusyIndicator {
Layout.alignment: Qt.AlignHCenter
running: networkManger.manager.working
}
ThinDivider { }
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
model: networkManger.manager.accessPoints
clip: true
delegate: ItemDelegate {
width: parent.width
height: app.delegateHeight
RowLayout {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: parent.right
Item {
Layout.fillHeight: true
Layout.preferredWidth: height
ColorIcon {
id: image
anchors.fill: parent
anchors.margins: app.margins / 2
name: {
if (model.protected) {
if (model.signalStrength <= 25)
return Qt.resolvedUrl("images/nm-signal-25-secure.svg")
if (model.signalStrength <= 50)
return Qt.resolvedUrl("images/nm-signal-50-secure.svg")
if (model.signalStrength <= 75)
return Qt.resolvedUrl("images/nm-signal-75-secure.svg")
if (model.signalStrength <= 100)
return Qt.resolvedUrl("images/nm-signal-100-secure.svg")
} else {
if (model.signalStrength <= 25)
return Qt.resolvedUrl("images/nm-signal-25.svg")
if (model.signalStrength <= 50)
return Qt.resolvedUrl("images/nm-signal-50.svg")
if (model.signalStrength <= 75)
return Qt.resolvedUrl("images/nm-signal-75.svg")
if (model.signalStrength <= 100)
return Qt.resolvedUrl("images/nm-signal-100.svg")
}
}
}
}
Label {
Layout.alignment: Qt.AlignVCenter
text: model.signalStrength + "%"
}
ColumnLayout {
Layout.fillWidth: true
Label {
text: model.ssid
}
Label {
text: model.macAddress
font.pixelSize: app.smallFont
}
}
}
onClicked: {
print("Connect to ", model.ssid, " --> ", model.macAddress)
pageStack.push(authenticationPage, { ssid: model.ssid, macAddress: model.macAddress })
}
}
}
}
Component {
id: authenticationPage
Page {
id: root
property string ssid
property string macAddress
header: GuhHeader {
text: qsTr("Wireless authentication")
onBackPressed: pageStack.pop()
}
ColumnLayout {
anchors.fill: parent
anchors.margins: app.margins
Label {
wrapMode: Text.WordWrap
font.pixelSize: app.largeFont
Layout.fillWidth: true
text: ssid + " (" + macAddress + ")"
}
Label {
wrapMode: Text.WordWrap
Layout.fillWidth: true
text: qsTr("Please enter the password for the Wifi network.")
}
TextField {
Layout.fillWidth: true
id: passwordTextField
echoMode: TextInput.Password
}
Button {
Layout.fillWidth: true
text: qsTr("Connect")
onPressed: {
networkManger.manager.connectWirelessNetwork(ssid, passwordTextField.text)
pageStack.pop()
}
}
}
}
}
Component {
id: settingsPage
Page {
id: root
header: GuhHeader {
text: qsTr("Network manager settings")
onBackPressed: pageStack.pop()
}
ColumnLayout {
anchors.fill: parent
anchors.margins: app.margins
RowLayout {
anchors.margins: app.margins
Layout.fillWidth: true
Label {
Layout.fillWidth: true
text: qsTr("Networking")
}
Switch {
id: networkingSwitch
checked: networkManger.manager.networkingEnabled
onCheckedChanged: networkManger.manager.enableNetworking(checked)
}
}
RowLayout {
anchors.margins: app.margins
Layout.fillWidth: true
Label {
Layout.fillWidth: true
text: qsTr("Wireless networking")
}
Switch {
id: wirelessNetworkingSwitch
checked: networkManger.manager.wirelessEnabled
onCheckedChanged: networkManger.manager.enableWireless(checked)
}
}
ThinDivider { }
RowLayout {
anchors.margins: app.margins
Layout.fillWidth: true
Label {
Layout.fillWidth: true
text: qsTr("System UUID")
}
Label {
text: networkManger.manager.modelNumber
}
}
RowLayout {
Layout.fillWidth: true
Label {
Layout.fillWidth: true
text: qsTr("Manufacturer")
}
Label {
text: networkManger.manager.manufacturer
}
}
RowLayout {
anchors.margins: app.margins
Layout.fillWidth: true
Label {
Layout.fillWidth: true
text: qsTr("Software revision")
}
Label {
text: networkManger.manager.softwareRevision
}
}
RowLayout {
anchors.margins: app.margins
Layout.fillWidth: true
Label {
Layout.fillWidth: true
text: qsTr("Firmware revision")
}
Label {
text: networkManger.manager.firmwareRevision
}
}
RowLayout {
anchors.margins: app.margins
Layout.fillWidth: true
Label {
Layout.fillWidth: true
text: qsTr("Hardware revision")
}
Label {
text: networkManger.manager.hardwareRevision
}
}
}
}
}
}

View File

@ -16,7 +16,7 @@ ActionDelegateBase {
} }
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Note: This action type has not been implemented yet" text: qsTr("Note: This action type has not been implemented yet")
font.pixelSize: app.smallFont font.pixelSize: app.smallFont
} }
} }

View File

@ -14,7 +14,7 @@ ActionDelegateBase {
Layout.fillWidth: true Layout.fillWidth: true
} }
Button { Button {
text: "Do it!" text: qsTr("Do it!")
onClicked: root.executeAction([]) onClicked: root.executeAction([])
} }
} }

View File

@ -18,7 +18,7 @@ ActionDelegateBase {
model: root.paramType.allowedValues model: root.paramType.allowedValues
currentIndex: root.paramType.allowedValues.indexOf(root.actionState) currentIndex: root.paramType.allowedValues.indexOf(root.actionState)
onActivated: { onActivated: {
if (root.actionState == root.paramType.allowedValues[index]) { if (root.actionState === root.paramType.allowedValues[index]) {
return; return;
} }

View File

@ -20,7 +20,7 @@ Item {
anchors.centerIn: parent anchors.centerIn: parent
width: parent.width - 2 * app.margins width: parent.width - 2 * app.margins
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: "Sorry, there isn't enough data to display a graph here yet!" text: qsTr("Sorry, there isn't enough data to display a graph here yet!")
visible: !root.model.busy && root.model.count <= 2 visible: !root.model.busy && root.model.count <= 2
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
font.pixelSize: app.largeFont font.pixelSize: app.largeFont

View File

@ -2,7 +2,7 @@ import QtQuick 2.0
Item { Item {
property ListModel eventTemplateModel: ListModel { property ListModel eventTemplateModel: ListModel {
ListElement { interfaceName: "battery"; stateName: "batteryLevel"; stateDisplayName: "Battery level"; eventDisplayName: "Battery level changed" } ListElement { interfaceName: "battery"; stateName: "batteryLevel"; stateDisplayName: qsTr("Battery level"); eventDisplayName: qsTr("Battery level changed") }
ListElement { interfaceName: "battery"; stateName: "batteryCritical"; stateDisplayName: "Battery critical"; eventDisplayName: "Battery critical changed" } ListElement { interfaceName: "battery"; stateName: "batteryCritical"; stateDisplayName: qsTr("Battery critical"); eventDisplayName: qsTr("Battery critical changed") }
} }
} }

View File

@ -91,7 +91,7 @@ Item {
var matching = true; var matching = true;
for (var k = 0; k < eventDescriptor.paramDescriptors.count; k++) { for (var k = 0; k < eventDescriptor.paramDescriptors.count; k++) {
var paramDescriptor = eventDescriptor.paramDescriptors.get(k); var paramDescriptor = eventDescriptor.paramDescriptors.get(k);
if (paramDescriptor.value == model.value) { if (paramDescriptor.value === model.value) {
return app.guhAccent; return app.guhAccent;
} }
} }

View File

@ -13,21 +13,21 @@ CustomViewBase {
anchors { left: parent.left; top: parent.top; right: parent.right; margins: app.margins } anchors { left: parent.left; top: parent.top; right: parent.right; margins: app.margins }
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Send a notification now:" text: qsTr("Send a notification now:")
} }
TextArea { TextArea {
id: titleTextArea id: titleTextArea
placeholderText: "Title" placeholderText: qsTr("Title")
Layout.fillWidth: true Layout.fillWidth: true
} }
TextArea { TextArea {
id: bodyTextArea id: bodyTextArea
placeholderText: "Text" placeholderText: qsTr("Text")
Layout.fillWidth: true Layout.fillWidth: true
} }
Button { Button {
Layout.fillWidth: true Layout.fillWidth: true
text: "Send" text: qsTr("Send")
onClicked: { onClicked: {
var params = [] var params = []

View File

@ -59,7 +59,7 @@ CustomViewBase {
id: zoomTabBar id: zoomTabBar
Layout.fillWidth: true Layout.fillWidth: true
TabButton { TabButton {
text: "6 h" text: qsTr("6 h")
property int avg: ValueLogsProxyModel.AverageQuarterHour property int avg: ValueLogsProxyModel.AverageQuarterHour
property date startTime: { property date startTime: {
var date = new Date(); var date = new Date();
@ -70,7 +70,7 @@ CustomViewBase {
} }
} }
TabButton { TabButton {
text: "24 h" text: qsTr("24 h")
property int avg: ValueLogsProxyModel.AverageHourly property int avg: ValueLogsProxyModel.AverageHourly
property date startTime: { property date startTime: {
var date = new Date(); var date = new Date();
@ -81,7 +81,7 @@ CustomViewBase {
} }
} }
TabButton { TabButton {
text: "7 d" text: qsTr("7 d")
property int avg: ValueLogsProxyModel.AverageDayTime property int avg: ValueLogsProxyModel.AverageDayTime
property date startTime: { property date startTime: {
var date = new Date(); var date = new Date();

View File

@ -7,7 +7,7 @@ import "../components"
Page { Page {
property alias filterInterface: devicesProxy.filterInterface property alias filterInterface: devicesProxy.filterInterface
header: GuhHeader { header: GuhHeader {
text: "Lights" text: qsTr("Lights")
onBackPressed: pageStack.pop() onBackPressed: pageStack.pop()
} }
ColumnLayout { ColumnLayout {
@ -16,11 +16,11 @@ Page {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: 10 Layout.margins: 10
Label { Label {
text: "All" text: qsTr("All")
Layout.fillWidth: true Layout.fillWidth: true
} }
Button { Button {
text: "off" text: qsTr("off")
onClicked: { onClicked: {
for (var i = 0; i < devicesProxy.count; i++) { for (var i = 0; i < devicesProxy.count; i++) {
var device = devicesProxy.get(i); var device = devicesProxy.get(i);

View File

@ -26,7 +26,7 @@ DevicePageBase {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
text: "When this switch is pressed..." text: qsTr("When this switch is pressed...")
visible: actionListView.count > 0 visible: actionListView.count > 0
} }
@ -42,15 +42,15 @@ DevicePageBase {
delegate: SwipeDelegate { delegate: SwipeDelegate {
width: parent.width width: parent.width
property var ruleActions: rulesFilterModel.get(index).actions property var ruleActions: rulesFilterModel.get(index).actions
property var ruleAction: ruleActions.count == 1 ? ruleActions.get(0) : null property var ruleAction: ruleActions.count === 1 ? ruleActions.get(0) : null
property var ruleActionType: ruleAction ? ruleActionDeviceClass.actionTypes.getActionType(ruleAction.actionTypeId) : null property var ruleActionType: ruleAction ? ruleActionDeviceClass.actionTypes.getActionType(ruleAction.actionTypeId) : null
property var ruleActionDevice: ruleAction ? Engine.deviceManager.devices.getDevice(ruleAction.deviceId) : null property var ruleActionDevice: ruleAction ? Engine.deviceManager.devices.getDevice(ruleAction.deviceId) : null
property var ruleActionDeviceClass: ruleActionDevice ? Engine.deviceManager.deviceClasses.getDeviceClass(ruleActionDevice.deviceClassId) : null property var ruleActionDeviceClass: ruleActionDevice ? Engine.deviceManager.deviceClasses.getDeviceClass(ruleActionDevice.deviceClassId) : null
property var ruleActionParams: ruleAction && ruleAction ? ruleAction.ruleActionParams : null property var ruleActionParams: ruleAction && ruleAction ? ruleAction.ruleActionParams : null
property var ruleActionParam: ruleActionParams.count == 1 ? ruleActionParams.get(0) : null property var ruleActionParam: ruleActionParams.count === 1 ? ruleActionParams.get(0) : null
text: { text: {
if (ruleActions && ruleActions.count > 1) { if (ruleActions && ruleActions.count > 1) {
return "Multiple actions"; return qsTr("Multiple actions");
} else if (ruleActionParam) { } else if (ruleActionParam) {
return qsTr("%1: Set %2 to %3").arg(ruleActionDevice.name).arg(ruleActionType.name).arg(ruleActionParam.value) return qsTr("%1: Set %2 to %3").arg(ruleActionDevice.name).arg(ruleActionType.name).arg(ruleActionParam.value)
} else { } else {
@ -79,7 +79,7 @@ DevicePageBase {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
anchors.centerIn: parent anchors.centerIn: parent
text: "No actions configured for this switch. You may add some actions for this switch by using the \"Add action\" button at the bottom." text: qsTr("No actions configured for this switch. You may add some actions for this switch by using the \"Add action\" button at the bottom.")
visible: actionListView.count == 0 visible: actionListView.count == 0
} }
} }
@ -87,9 +87,9 @@ DevicePageBase {
Button { Button {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
text: "Add an action" text: qsTr("Add an action")
onClicked: { onClicked: {
var page = pageStack.push(Qt.resolvedUrl("../magic/SelectActionPage.qml"), {text: "When this switch is pressed..."}); var page = pageStack.push(Qt.resolvedUrl("../magic/SelectActionPage.qml"), {text: qsTr("When this switch is pressed...")});
page.complete.connect(function() { page.complete.connect(function() {
print("have action:", page.device, page.actionType, page.params) print("have action:", page.device, page.actionType, page.params)
var rule = {}; var rule = {};

View File

@ -26,12 +26,12 @@ Page {
x: parent.width - width x: parent.width - width
IconMenuItem { IconMenuItem {
iconSource: "../images/delete.svg" iconSource: "../images/delete.svg"
text: "Delete Thing" text: qsTr("Delete Thing")
onTriggered: Engine.deviceManager.removeDevice(root.device.id) onTriggered: Engine.deviceManager.removeDevice(root.device.id)
} }
IconMenuItem { IconMenuItem {
iconSource: "../images/edit.svg" iconSource: "../images/edit.svg"
text: "Rename Thing" text: qsTr("Rename Thing")
onTriggered: { onTriggered: {
var popup = renameDialog.createObject(root); var popup = renameDialog.createObject(root);
popup.open(); popup.open();
@ -51,7 +51,7 @@ Page {
popup.open(); popup.open();
return; return;
default: default:
var popup = errorDialog.createObject(root, {text: "Remove device error: " + JSON.stringify(params.deviceError) }) var popup = errorDialog.createObject(root, {text: qsTr("Remove device error: %1").arg(JSON.stringify(params.deviceError)) })
popup.open(); popup.open();
} }
} }
@ -68,7 +68,7 @@ Page {
Layout.leftMargin: app.margins Layout.leftMargin: app.margins
Layout.rightMargin: app.margins Layout.rightMargin: app.margins
Layout.topMargin: app.margins Layout.topMargin: app.margins
text: "Thing parameters".toUpperCase() text: qsTr("Thing parameters").toUpperCase()
color: app.guhAccent color: app.guhAccent
} }

165
mea/ui/images/bluetooth.svg Normal file
View File

@ -0,0 +1,165 @@
<?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="bluetooth-active.svg">
<defs
id="defs4876" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4.4959994"
inkscape:cx="-67.515586"
inkscape:cy="75.155676"
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: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></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="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;opacity:1;fill:#808080;fill-opacity:1;stroke:none"
d="m 423.08053,395.36222 -4.94531,0 -24.47453,0 12.1044,12.10156 -2.95625,2.95703 -12.82343,-12.8164 -12.82343,12.8164 -2.95625,-2.95703 12.1044,-12.10156 -24.47257,0 -4.94532,0 3.46622,-3.53516 13.39983,-13.39258 1.48105,-1.41406 1.48692,1.41406 12.82343,12.81836 0.87144,0 12.82538,-12.81836 1.48301,-1.41406 1.48497,1.41406 13.39592,13.39258 3.47012,3.53516 z m -9.96097,-4.10938 -1.06683,-1.06836 -7.32321,-7.32031 -8.39003,8.38867 16.78007,0 z m -29.48823,0 -1.06682,-1.06836 -7.32517,-7.32031 -8.38808,8.38867 16.78007,0 z"
id="path4092"
inkscape:connector-curvature="0" />
<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:none;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;direction:ltr;block-progression:tb;writing-mode:lr-tb;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.00079155;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 355.96875,363.36133 c -2.6314,0 -4.71356,0.23788 -6.46875,0.89648 -1.75519,0.6586 -3.16115,1.84985 -3.99219,3.35547 -1.66208,3.01124 -1.48476,6.6938 -1.54297,11.72656 l 0,0.0117 0,28.02149 0,0.0117 c 0.0582,5.03276 -0.11911,8.71532 1.54297,11.72656 0.83104,1.50562 2.237,2.69686 3.99219,3.35547 1.75519,0.6586 3.83735,0.89648 6.46875,0.89648 l 68.02734,0 c 2.6314,0 4.71552,-0.23788 6.47071,-0.89648 1.75519,-0.65861 3.15919,-1.84985 3.99023,-3.35547 1.66208,-3.01124 1.48672,-6.6938 1.54492,-11.72656 l 0,-0.0117 0,-28.02149 0,-0.0117 c -0.0582,-5.03276 0.11716,-8.71532 -1.54492,-11.72656 -0.83104,-1.50562 -2.23504,-2.69687 -3.99023,-3.35547 -1.75519,-0.6586 -3.83931,-0.89648 -6.47071,-0.89648 l -68.02734,0 z m 0,4.00195 68.02734,0 c 2.37058,0 4.02426,0.25031 5.06446,0.64063 1.04019,0.39031 1.48966,0.80945 1.89453,1.54297 0.80823,1.46429 0.98613,4.77814 1.04492,9.8164 l 0,27.97656 c -0.0584,5.05418 -0.23518,8.37086 -1.04492,9.83789 -0.40487,0.73352 -0.85434,1.15266 -1.89453,1.54297 -1.0402,0.39032 -2.69388,0.64063 -5.06446,0.64063 l -68.02734,0 c -2.37058,0 -4.02426,-0.25031 -5.06445,-0.64063 -1.0402,-0.39031 -1.48771,-0.80945 -1.89258,-1.54297 -0.80836,-1.46451 -0.98616,-4.77682 -1.04492,-9.8164 l 0,-0.0215 0,-27.95312 0,-0.0234 c 0.0588,-5.03826 0.23669,-8.35211 1.04492,-9.8164 0.40487,-0.73352 0.85238,-1.15266 1.89258,-1.54297 1.04019,-0.39032 2.69387,-0.64063 5.06445,-0.64063 z"
id="path4180"
inkscape:connector-curvature="0" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.9 KiB

595
mea/ui/images/guh-logo.svg Normal file
View File

@ -0,0 +1,595 @@
<?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="500"
height="500"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="guh-logo.svg"
inkscape:export-filename="/home/timon/guh/guh/guh/icons/guh-logo-512x512.png"
inkscape:export-xdpi="92.160004"
inkscape:export-ydpi="92.160004">
<defs
id="defs4">
<linearGradient
id="SVGID_1_"
gradientUnits="userSpaceOnUse"
x1="369.02579"
y1="171.88429"
x2="441.68719"
y2="262.58051">
<stop
offset="0.1296"
style="stop-color:#7CC099"
id="stop46" />
<stop
offset="0.3785"
style="stop-color:#6FB594"
id="stop48" />
<stop
offset="0.835"
style="stop-color:#4E9688"
id="stop50" />
<stop
offset="1"
style="stop-color:#408A83"
id="stop52" />
</linearGradient>
<linearGradient
id="SVGID_2_"
gradientUnits="userSpaceOnUse"
x1="936.13898"
y1="154.45329"
x2="918.56207"
y2="154.45329"
gradientTransform="matrix(0.9669,0.2553,-0.2553,0.9669,-399.6603,-163.1002)">
<stop
offset="0"
style="stop-color:#DBE6E0"
id="stop61" />
<stop
offset="1"
style="stop-color:#BCDED3"
id="stop63" />
</linearGradient>
<linearGradient
id="SVGID_3_"
gradientUnits="userSpaceOnUse"
x1="451.01599"
y1="201.9489"
x2="442.73761"
y2="243.37801">
<stop
offset="0"
style="stop-color:#7CC099"
id="stop72" />
<stop
offset="0.2568"
style="stop-color:#78BC98"
id="stop74" />
<stop
offset="0.5165"
style="stop-color:#6CB193"
id="stop76" />
<stop
offset="0.7767"
style="stop-color:#589F8C"
id="stop78" />
<stop
offset="1"
style="stop-color:#408A83"
id="stop80" />
</linearGradient>
<linearGradient
id="SVGID_4_"
gradientUnits="userSpaceOnUse"
x1="457.62369"
y1="234.5722"
x2="457.47629"
y2="234.5722">
<stop
offset="0"
style="stop-color:#DBE6E0"
id="stop87" />
<stop
offset="1"
style="stop-color:#BCDED3"
id="stop89" />
</linearGradient>
<linearGradient
id="SVGID_5_"
gradientUnits="userSpaceOnUse"
x1="467.88159"
y1="223.4929"
x2="457.62369"
y2="223.4929">
<stop
offset="0"
style="stop-color:#DBE6E0"
id="stop96" />
<stop
offset="1"
style="stop-color:#BCDED3"
id="stop98" />
</linearGradient>
<linearGradient
id="SVGID_6_"
gradientUnits="userSpaceOnUse"
x1="457.47629"
y1="235.823"
x2="452.43719"
y2="235.823">
<stop
offset="0"
style="stop-color:#DBE6E0"
id="stop105" />
<stop
offset="1"
style="stop-color:#BCDED3"
id="stop107" />
</linearGradient>
<linearGradient
id="SVGID_7_"
gradientUnits="userSpaceOnUse"
x1="452.19159"
y1="227.27921"
x2="460.47461"
y2="227.27921">
<stop
offset="0"
style="stop-color:#6AA583"
id="stop112" />
<stop
offset="1"
style="stop-color:#4C9E96"
id="stop114" />
</linearGradient>
<linearGradient
id="SVGID_8_"
gradientUnits="userSpaceOnUse"
x1="473.17111"
y1="268.90411"
x2="455.23529"
y2="283.95389"
gradientTransform="matrix(0.9997,0.0227,-0.0227,0.9997,-36.4014,-7.9207)">
<stop
offset="0"
style="stop-color:#7CC099"
id="stop119" />
<stop
offset="1"
style="stop-color:#57BAAE"
id="stop121" />
</linearGradient>
<linearGradient
id="SVGID_9_"
gradientUnits="userSpaceOnUse"
x1="447.13129"
y1="274.66199"
x2="470.95151"
y2="274.66199"
gradientTransform="matrix(0.9997,0.0227,-0.0227,0.9997,-36.4014,-7.9207)">
<stop
offset="0"
style="stop-color:#7CC099"
id="stop126" />
<stop
offset="0.2327"
style="stop-color:#76BA97"
id="stop128" />
<stop
offset="0.5485"
style="stop-color:#65AB90"
id="stop130" />
<stop
offset="0.9106"
style="stop-color:#489186"
id="stop132" />
<stop
offset="1"
style="stop-color:#408A83"
id="stop134" />
</linearGradient>
<linearGradient
id="SVGID_10_"
gradientUnits="userSpaceOnUse"
x1="415.2153"
y1="260.93829"
x2="422.0509"
y2="252.7919">
<stop
offset="0"
style="stop-color:#4C9E96"
id="stop141" />
<stop
offset="0.4859"
style="stop-color:#489790"
id="stop143" />
<stop
offset="1"
style="stop-color:#408A83"
id="stop145" />
</linearGradient>
<linearGradient
id="SVGID_11_"
gradientUnits="userSpaceOnUse"
x1="425.60641"
y1="203.1666"
x2="393.7475"
y2="239.4308">
<stop
offset="0"
style="stop-color:#7CC099"
id="stop152" />
<stop
offset="0.3183"
style="stop-color:#77BF9C"
id="stop154" />
<stop
offset="0.6757"
style="stop-color:#6ABDA3"
id="stop156" />
<stop
offset="1"
style="stop-color:#57BAAE"
id="stop158" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="-124.12599"
inkscape:cy="202.52602"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="2880"
inkscape:window-height="1752"
inkscape:window-x="0"
inkscape:window-y="48"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<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></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-552.36215)">
<g
transform="matrix(2.2038606,0,0,2.2038606,-672.50331,283.61944)"
id="g41">
<g
id="g43">
<linearGradient
id="linearGradient3548"
gradientUnits="userSpaceOnUse"
x1="369.02579"
y1="171.88429"
x2="441.68719"
y2="262.58051">
<stop
offset="0.1296"
style="stop-color:#7CC099"
id="stop3550" />
<stop
offset="0.3785"
style="stop-color:#6FB594"
id="stop3552" />
<stop
offset="0.835"
style="stop-color:#4E9688"
id="stop3554" />
<stop
offset="1"
style="stop-color:#408A83"
id="stop3556" />
</linearGradient>
<path
style="fill:url(#SVGID_1_)"
inkscape:connector-curvature="0"
d="m 433.7,212.6 c -5.9,-10.1 -19,-17.9 -27.5,-21 -8.5,-3.2 -18,-10.1 -18,-10.1 -7.5,-5 -9.7,-9 -13.7,-14 -1.2,2.6 -2.2,5.8 -3,9.6 1.8,3.1 8.7,13.4 28.1,21.5 1.7,0.7 6.9,2.8 7,2.9 l 6.5,2.6 -6.7,-1.9 c -0.2,-0.1 -5.5,-1.6 -7.3,-2.2 -17.3,-6.3 -25,-15.1 -28,-19.9 -0.8,4.9 -1.1,10.6 -0.7,16.5 5.2,4.7 14,11 26.9,15.4 0.9,0.3 3.6,1.3 3.6,1.3 l 3.4,1.2 -3.5,-0.5 c -0.1,0 -3,-0.4 -4,-0.6 -12.1,-2.9 -20.5,-8.4 -26.1,-13.3 0.5,4.3 1.4,8.6 2.8,13 0.3,1 0.7,2.1 1.1,3 4.4,2 9.6,3.9 15.4,5.2 1.1,0.2 4.3,1.1 4.3,1.1 l 3.8,1 -4,-0.2 c -0.1,0 -3.4,-0.2 -4.5,-0.4 -5.1,-0.7 -9.8,-2 -13.9,-3.6 6.6,13.7 18.8,21.4 35.2,27.5 18.7,7 19.4,25 19.4,25 0,0 5.1,-3.8 9.6,-18.4 5.1,-16.2 -0.3,-30.6 -6.2,-40.7 z"
id="path54" />
</g>
<g
id="g56">
<g
id="g58">
<linearGradient
id="linearGradient3561"
gradientUnits="userSpaceOnUse"
x1="936.13898"
y1="154.45329"
x2="918.56207"
y2="154.45329"
gradientTransform="matrix(0.9669,0.2553,-0.2553,0.9669,-399.6603,-163.1002)">
<stop
offset="0"
style="stop-color:#DBE6E0"
id="stop3563" />
<stop
offset="1"
style="stop-color:#BCDED3"
id="stop3565" />
</linearGradient>
<path
style="fill:url(#SVGID_2_)"
inkscape:connector-curvature="0"
d="m 458.6,233.8 c 4.9,-3.6 6.9,-7.8 8.5,-12.5 0.7,-2.1 1.3,-5 0.3,-8.1 -0.8,-2.5 -6.5,-6.2 -11.2,-4.7 -5.1,1.7 -6.1,8.1 -6.5,10.9 -0.6,4.3 0.4,10.9 2.8,17.6 -0.1,0 2.1,-0.2 6.1,-3.2 z"
id="path65" />
</g>
<g
id="g67">
<g
id="g69">
<linearGradient
id="linearGradient3570"
gradientUnits="userSpaceOnUse"
x1="451.01599"
y1="201.9489"
x2="442.73761"
y2="243.37801">
<stop
offset="0"
style="stop-color:#7CC099"
id="stop3572" />
<stop
offset="0.2568"
style="stop-color:#78BC98"
id="stop3574" />
<stop
offset="0.5165"
style="stop-color:#6CB193"
id="stop3576" />
<stop
offset="0.7767"
style="stop-color:#589F8C"
id="stop3578" />
<stop
offset="1"
style="stop-color:#408A83"
id="stop3580" />
</linearGradient>
<path
style="fill:url(#SVGID_3_)"
inkscape:connector-curvature="0"
d="m 449.7,219.4 c 0.4,-2.8 1.4,-9.2 6.5,-10.9 4.2,-1.4 9.3,1.5 10.8,3.9 -1.5,-3.9 -5.6,-6.6 -9,-8.3 -4.8,-2.5 -10.8,-2.9 -15.7,-1.7 -4.6,1.1 -7,3.6 -10.9,6.9 0.8,1.1 1.6,2.2 2.2,3.3 4.6,8 9,18.6 8.2,30.6 3,-5 9.7,-6.1 10.6,-6.2 -2.4,-6.6 -3.4,-13.3 -2.7,-17.6 z"
id="path82" />
</g>
<g
id="g84">
<linearGradient
id="linearGradient3584"
gradientUnits="userSpaceOnUse"
x1="457.62369"
y1="234.5722"
x2="457.47629"
y2="234.5722">
<stop
offset="0"
style="stop-color:#DBE6E0"
id="stop3586" />
<stop
offset="1"
style="stop-color:#BCDED3"
id="stop3588" />
</linearGradient>
<path
style="fill:url(#SVGID_4_)"
inkscape:connector-curvature="0"
d="m 457.6,234.5 c -0.1,0 -0.1,0.1 -0.1,0.1 0,0 0.1,0 0.1,-0.1 z"
id="path91" />
</g>
<g
id="g93">
<linearGradient
id="linearGradient3592"
gradientUnits="userSpaceOnUse"
x1="467.88159"
y1="223.4929"
x2="457.62369"
y2="223.4929">
<stop
offset="0"
style="stop-color:#DBE6E0"
id="stop3594" />
<stop
offset="1"
style="stop-color:#BCDED3"
id="stop3596" />
</linearGradient>
<path
style="fill:url(#SVGID_5_)"
inkscape:connector-curvature="0"
d="m 467.4,213.2 c -0.1,-0.2 -0.2,-0.5 -0.4,-0.8 0.7,1.7 0.8,3.7 0.1,5.9 -1.5,4.9 -1.8,7.1 -6.1,12.9 -1,1.3 -2.2,2.4 -3.4,3.2 0.3,-0.2 0.6,-0.4 1,-0.7 4.9,-3.6 6.9,-7.8 8.5,-12.5 0.7,-2 1.2,-4.9 0.3,-8 z"
id="path100" />
</g>
<g
id="g102">
<linearGradient
id="linearGradient3600"
gradientUnits="userSpaceOnUse"
x1="457.47629"
y1="235.823"
x2="452.43719"
y2="235.823">
<stop
offset="0"
style="stop-color:#DBE6E0"
id="stop3602" />
<stop
offset="1"
style="stop-color:#BCDED3"
id="stop3604" />
</linearGradient>
<path
style="fill:url(#SVGID_6_)"
inkscape:connector-curvature="0"
d="m 452.4,237 c 0,0 0,0 0,0 0,0 1.8,-0.2 5,-2.4 -2.5,1.7 -4.9,2.4 -4.9,2.4 0,0 0,0 -0.1,0 z"
id="path109" />
</g>
</g>
<linearGradient
id="linearGradient3607"
gradientUnits="userSpaceOnUse"
x1="452.19159"
y1="227.27921"
x2="460.47461"
y2="227.27921">
<stop
offset="0"
style="stop-color:#6AA583"
id="stop3609" />
<stop
offset="1"
style="stop-color:#4C9E96"
id="stop3611" />
</linearGradient>
<path
style="fill:url(#SVGID_7_)"
inkscape:connector-curvature="0"
d="m 458.2,217.6 c -1,-0.3 -2,0 -2.8,0.6 -0.2,0.3 -0.3,0.6 -0.4,0.9 -0.4,1.6 0.5,3.3 2.2,3.7 0.7,0.2 1.3,0.1 1.9,-0.1 -0.9,6.9 -5.9,12.4 -6.9,13.5 0.1,0.4 0.2,0.5 0.2,0.7 0.3,0 0.4,-0.1 0.9,-0.2 1.7,-1.9 6.7,-7.9 7,-15.5 0.5,-1.5 -0.5,-3.1 -2.1,-3.6 z"
id="path116" />
</g>
<linearGradient
id="linearGradient3614"
gradientUnits="userSpaceOnUse"
x1="473.17111"
y1="268.90411"
x2="455.23529"
y2="283.95389"
gradientTransform="matrix(0.9997,0.0227,-0.0227,0.9997,-36.4014,-7.9207)">
<stop
offset="0"
style="stop-color:#7CC099"
id="stop3616" />
<stop
offset="1"
style="stop-color:#57BAAE"
id="stop3618" />
</linearGradient>
<path
style="fill:url(#SVGID_8_)"
inkscape:connector-curvature="0"
d="m 405.5,261.4 c 1.5,12.7 7.5,31.7 27.8,47.9 0,0 10.1,-15.4 0.4,-32.5 -9.7,-17.1 -23.8,-22.7 -28.8,-24.5 -0.2,3.6 0.4,6.8 0.6,9.1 z"
id="path123" />
<linearGradient
id="linearGradient3621"
gradientUnits="userSpaceOnUse"
x1="447.13129"
y1="274.66199"
x2="470.95151"
y2="274.66199"
gradientTransform="matrix(0.9997,0.0227,-0.0227,0.9997,-36.4014,-7.9207)">
<stop
offset="0"
style="stop-color:#7CC099"
id="stop3623" />
<stop
offset="0.2327"
style="stop-color:#76BA97"
id="stop3625" />
<stop
offset="0.5485"
style="stop-color:#65AB90"
id="stop3627" />
<stop
offset="0.9106"
style="stop-color:#489186"
id="stop3629" />
<stop
offset="1"
style="stop-color:#408A83"
id="stop3631" />
</linearGradient>
<path
style="fill:url(#SVGID_9_)"
inkscape:connector-curvature="0"
d="m 423.7,272.8 c -5.7,-10 -12.8,-16.8 -18.8,-20.5 -0.1,3.2 0.4,7 0.6,9.1 1.2,10.8 5.8,26.1 19.6,40.4 2.4,-5.5 5.5,-16.8 -1.4,-29 z"
id="path136" />
<g
id="g138">
<linearGradient
id="linearGradient3635"
gradientUnits="userSpaceOnUse"
x1="415.2153"
y1="260.93829"
x2="422.0509"
y2="252.7919">
<stop
offset="0"
style="stop-color:#4C9E96"
id="stop3637" />
<stop
offset="0.4859"
style="stop-color:#489790"
id="stop3639" />
<stop
offset="1"
style="stop-color:#408A83"
id="stop3641" />
</linearGradient>
<path
style="fill:url(#SVGID_10_)"
inkscape:connector-curvature="0"
d="m 411.9,246.7 c -2,-0.8 -4.9,-1.6 -6.8,-2.4 -0.3,2.5 -0.2,5.1 -0.2,8.1 4.4,1.6 16.1,6.2 25.5,19.3 0,-0.1 0,-0.2 0,-0.3 -0.2,-2.3 -1.1,-18.3 -18.5,-24.7 z"
id="path147" />
</g>
<g
id="g149">
<linearGradient
id="linearGradient3645"
gradientUnits="userSpaceOnUse"
x1="425.60641"
y1="203.1666"
x2="393.7475"
y2="239.4308">
<stop
offset="0"
style="stop-color:#7CC099"
id="stop3647" />
<stop
offset="0.3183"
style="stop-color:#77BF9C"
id="stop3649" />
<stop
offset="0.6757"
style="stop-color:#6ABDA3"
id="stop3651" />
<stop
offset="1"
style="stop-color:#57BAAE"
id="stop3653" />
</linearGradient>
<path
style="fill:url(#SVGID_11_)"
inkscape:connector-curvature="0"
d="m 433.7,212.6 c -5.9,-10.1 -19,-17.9 -27.5,-21 -8.5,-3.2 -18,-10.1 -18,-10.1 -2.1,-1.4 -3.8,-2.7 -5.2,-4 -0.4,3.6 -0.6,7.5 -0.4,11.6 4.2,3.2 9.7,6.5 16.9,9.5 1.7,0.7 6.9,2.8 7,2.9 l 6.5,2.6 -6.7,-1.9 c -0.2,-0.1 -5.5,-1.6 -7.3,-2.2 -6.8,-2.5 -12.1,-5.3 -16.2,-8.2 0.4,5 1.3,10.1 2.9,15.2 3.4,1.8 7.2,3.4 11.6,4.9 0.9,0.3 3.6,1.3 3.6,1.3 l 3.4,1.2 -3.5,-0.5 c -0.1,0 -3,-0.4 -4,-0.6 -3.7,-0.9 -7,-2 -10,-3.3 1.9,4.8 4.4,8.8 7.4,12.3 0.1,0 0.1,0 0.1,0 l 3.8,1 -3.2,-0.2 c 6.9,7.7 16.3,13.3 26.3,21.3 13.5,10.8 9.2,27.2 9.2,27.2 0,0 0.8,-0.6 1.5,-1.5 1.8,-2.1 5.1,-7 8.1,-16.9 5,-16.1 -0.4,-30.5 -6.3,-40.6 z"
id="path160" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" viewBox="0 0 96 96.000001" width="96" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<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 id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782-05" style="color:#000000;fill:none" transform="rotate(90)" height="96" width="96" y="-28.143" x="78.505"/>
<path id="path4205-0" d="m16.144 164.5h-72v-3.9984h72z" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;font-variant-ligatures:normal;isolation:auto;text-transform:none"/>
<path id="path4207" d="m-17.856 162.51h-4.002v-14h4.002z" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;font-variant-ligatures:normal;isolation:auto;text-transform:none"/>
<ellipse id="path4221" style="color:#000000;fill:#808080" rx="6" ry="6" cy="162.51" cx="-19.857"/>
<path id="path4179" d="m-47.881 88.506c-5.0328 0.0582-8.7136-0.12018-11.725 1.541-1.5055 0.83067-2.6968 2.2356-3.3555 3.9903-0.65866 1.7546-0.89647 3.8383-0.89647 6.4687v40c0 2.6304 0.23773 4.7122 0.89647 6.4668 0.65866 1.7546 1.85 3.1596 3.3555 3.9902 3.011 1.6613 6.6918 1.4848 11.725 1.543h56.045c5.0328-0.0582 8.7136 0.1183 11.725-1.543 1.5055-0.83066 2.6968-2.2356 3.3555-3.9902s0.89651-3.8364 0.89651-6.4668v-40c0-2.6304-0.23774-4.7141-0.89651-6.4687-0.65866-1.7547-1.85-3.1596-3.3555-3.9903-3.011-1.6612-6.6918-1.4828-11.725-1.541h-56.034zm0.02268 4h56c5.0382 0.0586 8.3518 0.23698 9.8164 1.0449 0.73365 0.40479 1.1527 0.85296 1.543 1.8926 0.39024 1.0396 0.64063 2.693 0.64063 5.0625v40c0 2.3696-0.25058 4.0229-0.64063 5.0625-0.39027 1.0396-0.80934 1.4878-1.543 1.8926-1.4645 0.80803-4.7782 0.98615-9.8164 1.0449h-56c-5.0383-0.0586-8.3519-0.23698-9.8164-1.0449-0.73364-0.40479-1.1508-0.85296-1.541-1.8926-0.39027-1.0396-0.6426-2.693-0.6426-5.0625v-40c0-2.3696 0.25247-4.0229 0.6426-5.0625 0.39024-1.0396 0.80734-1.4878 1.541-1.8926 1.4645-0.80803 4.7782-0.98616 9.8164-1.0449z" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;font-variant-ligatures:none;isolation:auto;text-transform:none"/>
<path id="path4122-16" d="m-1.1825 122.51h-36.674v-4.0004l36.675 0.002z" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;font-variant-ligatures:normal;isolation:auto;text-transform:none"/>
<path id="path5888" style="color:#000000;fill:#808080" d="m-35.858 110.51-0.0038 20c-2.9866-1.3906-6.0272-2.9466-9.1228-4.6656-3.0666-1.7232-6.0246-3.5004-8.8722-5.3336 2.8475-1.7965 5.8056-3.5567 8.8722-5.2798 3.0973-1.72 6.1396-3.2932 9.1278-4.721z"/>
<path id="path5900" style="color:#000000;fill:#808080" d="m-3.8559 110.51 0.0038 20c2.9866-1.3906 6.0272-2.9466 9.1228-4.6656 3.0666-1.7232 6.0246-3.5004 8.8722-5.3336-2.8475-1.7965-5.8056-3.5567-8.8722-5.2798-3.0973-1.72-6.1396-3.2932-9.1278-4.721z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" viewBox="0 0 96 96.000001" width="96" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<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 id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782" style="color:#000000;fill:none" transform="rotate(90)" height="96" width="96" y="-28.143" x="78.505"/>
<path id="path4171" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;block-progression:tb;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;font-variant-ligatures:none;isolation:auto;text-transform:none" d="m-19.84 90.506c-15.662-0.0038-31.324 5.0321-44.404 15.109l-1.5859 1.2227 1.2227 1.584 44.75 58.031 46.002-59.594-1.5859-1.2207c-13.076-10.085-28.737-15.13-44.399-15.134zm0 3.9922c14.153 0.0035 28.246 4.494 40.27 13.217l-40.285 52.191-40.26-52.211c12.028-8.7169 26.123-13.201 40.275-13.197z"/>
<path id="rect4174" style="color:#000000;fill:#808080" d="m13.143 138.51c-4.9514 0-9 4.0486-9 9v3h-2v16h11 11v-16h-2v-3c0-4.9514-4.0486-9-9-9zm0 4c2.8046 0 5 2.1954 5 5v3h-10v-3c0-2.8046 2.1954-5 5-5z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" viewBox="0 0 96 96.000001" width="96" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<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 id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782" style="color:#000000;fill:none" transform="rotate(90)" height="96" width="96" y="-28.143" x="78.505"/>
<path id="path4171" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;block-progression:tb;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;font-variant-ligatures:none;isolation:auto;text-transform:none" d="m-19.84 90.506c-15.662-0.0038-31.324 5.0321-44.404 15.109l-1.5859 1.2227 1.2227 1.584 44.75 58.031 46.002-59.594-1.5859-1.2207c-13.076-10.085-28.737-15.13-44.399-15.134zm0 3.9922c14.153 0.0035 28.246 4.494 40.27 13.217l-40.285 52.191-40.26-52.211c12.028-8.7169 26.123-13.201 40.275-13.197z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" viewBox="0 0 96 96.000001" width="96" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<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 id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782" style="color:#000000;fill:none" transform="rotate(90)" height="96" width="96" y="-28.143" x="78.505"/>
<path id="path4178" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;mix-blend-mode:normal;block-progression:tb;shape-padding:0;text-indent:0;image-rendering:auto;white-space:normal;text-decoration-style:solid;isolation:auto;text-transform:none" d="m-19.84 90.506c-15.662-0.0038-31.324 5.0321-44.404 15.109l-1.5859 1.2227 1.2227 1.584 44.75 58.031 46.002-59.594-1.5859-1.2207c-13.076-10.085-28.737-15.13-44.399-15.134z"/>
<path id="rect4174" style="color:#000000;fill:#808080" d="m81 60c-4.951 0-9 4.049-9 9v3h-2v16h11 11v-16h-2v-3c0-4.951-4.049-9-9-9zm0 4c2.805 0 5 2.195 5 5v3h-10v-3c0-2.805 2.195-5 5-5z" transform="translate(-67.857 78.505)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" viewBox="0 0 96 96.000001" width="96" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<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 id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782" style="color:#000000;fill:none" transform="rotate(90)" height="96" width="96" y="-28.143" x="78.505"/>
<path id="path4178" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;mix-blend-mode:normal;block-progression:tb;shape-padding:0;text-indent:0;image-rendering:auto;white-space:normal;text-decoration-style:solid;isolation:auto;text-transform:none" d="m-19.84 90.506c-15.662-0.0038-31.324 5.0321-44.404 15.109l-1.5859 1.2227 1.2227 1.584 44.75 58.031 46.002-59.594-1.5859-1.2207c-13.076-10.085-28.737-15.13-44.399-15.134z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" viewBox="0 0 96 96.000001" width="96" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<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 id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782" style="color:#000000;fill:none" transform="rotate(90)" height="96" width="96" y="-28.143" x="78.505"/>
<path id="path4171" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;block-progression:tb;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;font-variant-ligatures:none;isolation:auto;text-transform:none" d="m-19.84 90.506c-15.662-0.0038-31.324 5.0321-44.404 15.109l-1.5859 1.2227 1.2227 1.584 44.75 58.031 46.002-59.594-1.5859-1.2207c-13.076-10.085-28.737-15.13-44.399-15.134zm0 3.9922c14.153 0.0035 28.246 4.494 40.27 13.217l-40.285 52.191-40.26-52.211c12.028-8.7169 26.123-13.201 40.275-13.197z"/>
<path id="path4218" style="color:#000000;fill:#808080" d="m-35.056 143.68a24.897 24.886 0 0 1 30.408 0.007l-15.209 19.703z"/>
<path id="rect4174" style="color:#000000;fill:#808080" d="m13.143 138.51c-4.9514 0-9 4.0486-9 9v3h-2v16h11 11v-16h-2v-3c0-4.9514-4.0486-9-9-9zm0 4c2.8046 0 5 2.1954 5 5v3h-10v-3c0-2.8046 2.1954-5 5-5z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" viewBox="0 0 96 96.000001" width="96" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<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 id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782" style="color:#000000;fill:none" transform="rotate(90)" height="96" width="96" y="-28.143" x="78.505"/>
<path id="path4171" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;block-progression:tb;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;font-variant-ligatures:none;isolation:auto;text-transform:none" d="m-19.84 90.506c-15.662-0.0038-31.324 5.0321-44.404 15.109l-1.5859 1.2227 1.2227 1.584 44.75 58.031 46.002-59.594-1.5859-1.2207c-13.076-10.085-28.737-15.13-44.399-15.134zm0 3.9922c14.153 0.0035 28.246 4.494 40.27 13.217l-40.285 52.191-40.26-52.211c12.028-8.7169 26.123-13.201 40.275-13.197z"/>
<path id="path4218" style="color:#000000;fill:#808080" d="m-35.056 143.68a24.897 24.886 0 0 1 30.408 0.007l-15.209 19.703z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" viewBox="0 0 96 96.000001" width="96" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<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 id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782" style="color:#000000;fill:none" transform="rotate(90)" height="96" width="96" y="-28.143" x="78.505"/>
<path id="path4171" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;block-progression:tb;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;font-variant-ligatures:none;isolation:auto;text-transform:none" d="m-19.84 90.506c-15.662-0.0038-31.324 5.0321-44.404 15.109l-1.5859 1.2227 1.2227 1.584 44.75 58.031 46.002-59.594-1.5859-1.2207c-13.076-10.085-28.737-15.13-44.399-15.134zm0 3.9922c14.153 0.0035 28.246 4.494 40.27 13.217l-40.285 52.191-40.26-52.211c12.028-8.7169 26.123-13.201 40.275-13.197z"/>
<path id="path4218" style="color:#000000;fill:#808080" d="m-43.568 132.58a38.84 38.821 0 0 1 47.436 0.0116l-23.726 30.736z"/>
<path id="rect4174" style="color:#000000;fill:#808080" d="m13.143 138.51c-4.9514 0-9 4.0486-9 9v3h-2v16h11 11v-16h-2v-3c0-4.9514-4.0486-9-9-9zm0 4c2.8046 0 5 2.1954 5 5v3h-10v-3c0-2.8046 2.1954-5 5-5z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" viewBox="0 0 96 96.000001" width="96" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<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 id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782" style="color:#000000;fill:none" transform="rotate(90)" height="96" width="96" y="-28.143" x="78.505"/>
<path id="path4171" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;block-progression:tb;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;font-variant-ligatures:none;isolation:auto;text-transform:none" d="m-19.84 90.506c-15.662-0.0038-31.324 5.0321-44.404 15.109l-1.5859 1.2227 1.2227 1.584 44.75 58.031 46.002-59.594-1.5859-1.2207c-13.076-10.085-28.737-15.13-44.399-15.134zm0 3.9922c14.153 0.0035 28.246 4.494 40.27 13.217l-40.285 52.191-40.26-52.211c12.028-8.7169 26.123-13.201 40.275-13.197z"/>
<path id="path4218" style="color:#000000;fill:#808080" d="m-43.568 132.58a38.84 38.821 0 0 1 47.436 0.0116l-23.726 30.736z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" viewBox="0 0 96 96.000001" width="96" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<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 id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782" style="color:#000000;fill:none" transform="rotate(90)" height="96" width="96" y="-28.143" x="78.505"/>
<path id="path4171" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;block-progression:tb;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;font-variant-ligatures:none;isolation:auto;text-transform:none" d="m-19.84 90.506c-15.662-0.0038-31.324 5.0321-44.404 15.109l-1.5859 1.2227 1.2227 1.584 44.75 58.031 46.002-59.594-1.5859-1.2207c-13.076-10.085-28.737-15.13-44.399-15.134zm0 3.9922c14.153 0.0035 28.246 4.494 40.27 13.217l-40.285 52.191-40.26-52.211c12.028-8.7169 26.123-13.201 40.275-13.197z"/>
<path id="path4218" style="color:#000000;fill:#808080" d="m-53.295 119.89a54.774 54.748 0 0 1 66.897 0.0164l-33.459 43.346z"/>
<path id="rect4174" style="color:#000000;fill:#808080" d="m13.143 138.51c-4.9514 0-9 4.0486-9 9v3h-2v16h11 11v-16h-2v-3c0-4.9514-4.0486-9-9-9zm0 4c2.8046 0 5 2.1954 5 5v3h-10v-3c0-2.8046 2.1954-5 5-5z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" viewBox="0 0 96 96.000001" width="96" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<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 id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782" style="color:#000000;fill:none" transform="rotate(90)" height="96" width="96" y="-28.143" x="78.505"/>
<path id="path4171" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;block-progression:tb;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;font-variant-ligatures:none;isolation:auto;text-transform:none" d="m-19.84 90.506c-15.662-0.0038-31.324 5.0321-44.404 15.109l-1.5859 1.2227 1.2227 1.584 44.75 58.031 46.002-59.594-1.5859-1.2207c-13.076-10.085-28.737-15.13-44.399-15.134zm0 3.9922c14.153 0.0035 28.246 4.494 40.27 13.217l-40.285 52.191-40.26-52.211c12.028-8.7169 26.123-13.201 40.275-13.197z"/>
<path id="path4218" style="color:#000000;fill:#808080" d="m-53.295 119.89a54.774 54.748 0 0 1 66.897 0.0164l-33.459 43.346z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

18
mea/ui/images/refresh.svg Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" viewBox="0 0 96 96.000001" width="96" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<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 id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782-83" style="color:#000000;fill:none" transform="rotate(90)" height="96" width="96" y="-28.143" x="78.505"/>
<path id="path5588-9-2-96-57" style="color:#000000;fill:#808080" d="m15.073 88.463-16.966 16.977c3.761 1.401 7.7088 2.7082 11.843 3.9248 4.1122 1.1879 8.1765 2.2361 12.193 3.1414-0.93642-3.9851-1.9991-8.035-3.187-12.147-1.2172-4.136-2.5112-8.1001-3.8821-11.894z"/>
<path id="path4228" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;font-variant-numeric:normal;shape-rendering:auto;solid-color:#000000;text-decoration-line:none;fill:#808080;font-variant-position:normal;mix-blend-mode:normal;font-feature-settings:normal;shape-padding:0;font-variant-alternates:normal;text-indent:0;font-variant-ligatures:normal;dominant-baseline:auto;font-variant-caps:normal;image-rendering:auto;white-space:normal;text-decoration-style:solid;text-orientation:mixed;isolation:auto;text-transform:none" d="m-19.416 84.512c-6.4491-0.06917-12.962 1.3433-19.012 4.3262-16.133 7.9544-25.416 25.317-23.068 43.148 2.3479 17.831 15.809 32.202 33.451 35.711 17.642 3.5086 35.578-4.618 44.572-20.193l-3.4629-2c-8.1446 14.104-24.352 21.447-40.328 18.27-15.976-3.1774-28.139-16.162-30.266-32.309-2.1261-16.147 6.2596-31.836 20.869-39.039 14.61-7.2033 32.165-4.3052 43.684 7.2109l2.8281-2.8281c-7.9492-7.945-18.519-12.178-29.267-12.293z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -9,7 +9,7 @@ Page {
property var device: null property var device: null
header: GuhHeader { header: GuhHeader {
text: "Select event" text: qsTr("Select event")
} }
ColumnLayout { ColumnLayout {
@ -22,11 +22,11 @@ Page {
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
RadioButton { RadioButton {
text: "A specific thing" text: qsTr("A specific thing")
checked: true checked: true
} }
RadioButton { RadioButton {
text: "A group of things" text: qsTr("A group of things")
} }
} }

View File

@ -91,7 +91,7 @@ Page {
} }
header: GuhHeader { header: GuhHeader {
text: "New rule" text: qsTr("New rule")
onBackPressed: pageStack.pop() onBackPressed: pageStack.pop()
HeaderButton { HeaderButton {
imageSource: "../images/tick.svg" imageSource: "../images/tick.svg"
@ -115,7 +115,7 @@ Page {
Layout.margins: app.margins Layout.margins: app.margins
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Rule name" text: qsTr("Rule name")
} }
TextField { TextField {
Layout.fillWidth: true Layout.fillWidth: true
@ -146,7 +146,7 @@ Page {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
font.pixelSize: app.mediumFont font.pixelSize: app.mediumFont
text: "Events triggering this rule" text: qsTr("Events triggering this rule")
visible: !root.hasExitActions visible: !root.hasExitActions
} }
@ -224,7 +224,7 @@ Page {
Button { Button {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
text: eventsRepeater.count == 0 ? "Add an event..." : "Add another event..." text: eventsRepeater.count == 0 ? qsTr("Add an event...") : qsTr("Add another event...")
onClicked: root.addEventDescriptor(); onClicked: root.addEventDescriptor();
visible: !root.hasExitActions visible: !root.hasExitActions
} }
@ -232,7 +232,7 @@ Page {
ThinDivider {} ThinDivider {}
Label { Label {
text: "Conditions to be met" text: qsTr("Conditions to be met")
font.pixelSize: app.mediumFont font.pixelSize: app.mediumFont
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
@ -247,7 +247,7 @@ Page {
Button { Button {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
text: "Add a condition" text: qsTr("Add a condition")
visible: root.rule.stateEvaluator === null visible: root.rule.stateEvaluator === null
onClicked: { onClicked: {
root.rule.createStateEvaluator(); root.rule.createStateEvaluator();
@ -258,7 +258,7 @@ Page {
ThinDivider { visible: root.actionsVisible } ThinDivider { visible: root.actionsVisible }
Label { Label {
text: root.isStateBased ? "Active state enter actions" : "Actions to execute" text: root.isStateBased ? qsTr("Active state enter actions") : qsTr("Actions to execute")
font.pixelSize: app.mediumFont font.pixelSize: app.mediumFont
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
@ -290,7 +290,7 @@ Page {
model: actionDelegate.ruleAction.ruleActionParams model: actionDelegate.ruleAction.ruleActionParams
Label { Label {
text: actionDelegate.actionType.paramTypes.getParamType(model.paramTypeId).displayName + " -> " + text: actionDelegate.actionType.paramTypes.getParamType(model.paramTypeId).displayName + " -> " +
(model.eventParamTypeId.length > 0 ? "value from event" : model.value) (model.eventParamTypeId.length > 0 ? qsTr("value from event") : model.value)
font.pixelSize: app.smallFont font.pixelSize: app.smallFont
} }
} }
@ -314,7 +314,7 @@ Page {
Button { Button {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
text: actionsRepeater.count == 0 ? "Add an action..." : "Add another action..." text: actionsRepeater.count == 0 ? qsTr("Add an action...") : qsTr("Add another action...")
onClicked: root.addAction(); onClicked: root.addAction();
visible: root.actionsVisible visible: root.actionsVisible
} }
@ -322,7 +322,7 @@ Page {
ThinDivider { visible: root.exitActionsVisible } ThinDivider { visible: root.exitActionsVisible }
Label { Label {
text: "Active state exit actions" text: qsTr("Active state exit actions")
font.pixelSize: app.mediumFont font.pixelSize: app.mediumFont
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
@ -378,7 +378,7 @@ Page {
Button { Button {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
text: actionsRepeater.count == 0 ? "Add an action..." : "Add another action..." text: actionsRepeater.count == 0 ? qsTr("Add an action...") : qsTr("Add another action...")
onClicked: root.addExitAction(); onClicked: root.addExitAction();
visible: root.exitActionsVisible visible: root.exitActionsVisible
} }

View File

@ -7,7 +7,7 @@ import "../components"
Page { Page {
id: root id: root
header: GuhHeader { header: GuhHeader {
text: "Conditions" text: qsTr("Conditions")
onBackPressed: pageStack.pop() onBackPressed: pageStack.pop()
} }

View File

@ -16,23 +16,23 @@ Page {
ListModel { ListModel {
id: eventModel id: eventModel
ListElement { interfaceName: "temperaturesensor"; text: "When it's freezing..."; identifier: "freeze"} ListElement { interfaceName: "temperaturesensor"; text: qsTr("When it's freezing..."); identifier: "freeze"}
ListElement { interfaceName: "battery"; text: "When the device runs out of battery..."; identifier: "lowBattery"} ListElement { interfaceName: "battery"; text: qsTr("When the device runs out of battery..."); identifier: "lowBattery"}
ListElement { interfaceName: "weather"; text: "When it starts raining..."; identifier: "rain" } ListElement { interfaceName: "weather"; text: qsTr("When it starts raining..."); identifier: "rain" }
ListElement { interfaceName: "weather"; text: "When it's freezing..."; identifier: "freeze"} ListElement { interfaceName: "weather"; text: qsTr("When it's freezing..."); identifier: "freeze"}
} }
ListModel { ListModel {
id: actionModel id: actionModel
ListElement { interfaceName: "light"; text: "Switch light when..."; identifier: "switchLight"} ListElement { interfaceName: "light"; text: qsTr("Switch light when..."); identifier: "switchLight"}
ListElement { interfaceName: "dimmablelight"; text: "Dim light when..."; identifier: "dimLight"} ListElement { interfaceName: "dimmablelight"; text: qsTr("Dim light when..."); identifier: "dimLight"}
ListElement { interfaceName: "colorlight"; text: "Set light color when..."; identifier: "colorLight" } ListElement { interfaceName: "colorlight"; text: qsTr("Set light color when..."); identifier: "colorLight" }
ListElement { interfaceName: "mediacontroller"; text: "Pause playback when..."; identifier: "pausePlayback" } ListElement { interfaceName: "mediacontroller"; text: qsTr("Pause playback when..."); identifier: "pausePlayback" }
ListElement { interfaceName: "mediacontroller"; text: "Resume playback when..."; identifier: "resumePlayback" } ListElement { interfaceName: "mediacontroller"; text: qsTr("Resume playback when..."); identifier: "resumePlayback" }
ListElement { interfaceName: "extendedvolumecontroller"; text: "Set volume..."; identifier: "setVolume" } ListElement { interfaceName: "extendedvolumecontroller"; text: qsTr("Set volume..."); identifier: "setVolume" }
ListElement { interfaceName: "extendedvolumecontroller"; text: "Mute when..."; identifier: "mute" } ListElement { interfaceName: "extendedvolumecontroller"; text: qsTr("Mute when..."); identifier: "mute" }
ListElement { interfaceName: "extendedvolumecontroller"; text: "Unmute when..."; identifier: "unmute" } ListElement { interfaceName: "extendedvolumecontroller"; text: qsTr("Unmute when..."); identifier: "unmute" }
ListElement { interfaceName: "notifications"; text: "Notify me when..."; identifier: "notify" } ListElement { interfaceName: "notifications"; text: qsTr("Notify me when..."); identifier: "notify" }
} }
function entrySelected(identifier) { function entrySelected(identifier) {

View File

@ -22,11 +22,11 @@ Page {
ListModel { ListModel {
id: actionModel id: actionModel
ListElement { interfaceName: "light"; text: "Switch lights..."; identifier: "switchLights" } ListElement { interfaceName: "light"; text: qsTr("Switch lights..."); identifier: "switchLights" }
ListElement { interfaceName: "mediacontroller"; text: "Control media playback..."; identifier: "controlMedia" } ListElement { interfaceName: "mediacontroller"; text: qsTr("Control media playback..."); identifier: "controlMedia" }
ListElement { interfaceName: "extendedvolumecontroller"; text: "Mute media playback..."; identifier: "muteMedia" } ListElement { interfaceName: "extendedvolumecontroller"; text: qsTr("Mute media playback..."); identifier: "muteMedia" }
ListElement { interfaceName: "notifications"; text: "Notify me..."; identifier: "notify" } ListElement { interfaceName: "notifications"; text: qsTr("Notify me..."); identifier: "notify" }
ListElement { interfaceName: ""; text: "Manually configure an action..."; identifier: "manualAction" } ListElement { interfaceName: ""; text: qsTr("Manually configure an action..."); identifier: "manualAction" }
} }
DevicesProxy { DevicesProxy {
@ -91,7 +91,7 @@ Page {
id: selectDeviceComponent id: selectDeviceComponent
Page { Page {
header: GuhHeader { header: GuhHeader {
text: "Select device" text: qsTr("Select device")
onBackPressed: pageStack.pop() onBackPressed: pageStack.pop()
} }
@ -128,7 +128,7 @@ Page {
readonly property var deviceClass: Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) readonly property var deviceClass: Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId)
header: GuhHeader { header: GuhHeader {
text: "Select action" text: qsTr("Select action")
onBackPressed: pageStack.pop() onBackPressed: pageStack.pop()
} }
@ -150,7 +150,7 @@ Page {
onClicked: { onClicked: {
var actionType = page.deviceClass.actionTypes.get(index) var actionType = page.deviceClass.actionTypes.get(index)
if (page.deviceClass.actionTypes.get(index).paramTypes.count == 0) { if (page.deviceClass.actionTypes.get(index).paramTypes.count === 0) {
// We're all set. // We're all set.
var action = {} var action = {}
action["deviceId"] = page.device.id action["deviceId"] = page.device.id
@ -175,7 +175,7 @@ Page {
property var device property var device
property var actionType property var actionType
header: GuhHeader { header: GuhHeader {
text: "params" text: qsTr("params")
onBackPressed: pageStack.pop() onBackPressed: pageStack.pop()
} }
@ -195,7 +195,7 @@ Page {
Layout.fillHeight: true Layout.fillHeight: true
} }
Button { Button {
text: "OK" text: qsTr("OK")
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
onClicked: { onClicked: {
@ -223,7 +223,7 @@ Page {
id: switchLightsCompoent id: switchLightsCompoent
Page { Page {
header: GuhHeader { header: GuhHeader {
text: "Switch lights" text: qsTr("Switch lights")
onBackPressed: pageStack.pop() onBackPressed: pageStack.pop()
} }
@ -233,7 +233,7 @@ Page {
SwitchDelegate { SwitchDelegate {
id: switchDelegate id: switchDelegate
Layout.fillWidth: true Layout.fillWidth: true
text: "Set selected lights power to" text: qsTr("Set selected lights power to")
position: 0 position: 0
} }
ThinDivider {} ThinDivider {}
@ -266,7 +266,7 @@ Page {
Button { Button {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
text: "OK" text: qsTr("OK")
onClicked: { onClicked: {
for (var i = 0; i < lightsRepeater.count; i++) { for (var i = 0; i < lightsRepeater.count; i++) {
if (lightsRepeater.itemAt(i).checkState === Qt.Unchecked) { if (lightsRepeater.itemAt(i).checkState === Qt.Unchecked) {
@ -302,7 +302,7 @@ Page {
id: notificationActionComponent id: notificationActionComponent
Page { Page {
header: GuhHeader { header: GuhHeader {
text: "Send notification" text: qsTr("Send notification")
onBackPressed: pageStack.pop() onBackPressed: pageStack.pop()
} }
@ -311,7 +311,7 @@ Page {
spacing: app.margins spacing: app.margins
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: "Notification text" text: qsTr("Notification text")
Layout.topMargin: app.margins Layout.topMargin: app.margins
Layout.leftMargin: app.margins Layout.leftMargin: app.margins
Layout.rightMargin: app.margins Layout.rightMargin: app.margins
@ -351,7 +351,7 @@ Page {
Button { Button {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
text: "OK" text: qsTr("OK")
onClicked: { onClicked: {
var action = {} var action = {}
action["interface"] = "notifications"; action["interface"] = "notifications";

View File

@ -35,9 +35,9 @@ Page {
ListModel { ListModel {
id: eventTemplateModel id: eventTemplateModel
ListElement { interfaceName: "temperaturesensor"; text: "When it's freezing..."; event: "freeze"} ListElement { interfaceName: "temperaturesensor"; text: qsTr("When it's freezing..."); event: "freeze"}
ListElement { interfaceName: "battery"; text: "When the device runs out of battery..."; event: "lowBattery"} ListElement { interfaceName: "battery"; text: qsTr("When the device runs out of battery..."); event: "lowBattery"}
ListElement { interfaceName: "weather"; text: "When it starts raining..."; event: "rain" } ListElement { interfaceName: "weather"; text: qsTr("When it starts raining..."); event: "rain" }
} }
function buildInterface() { function buildInterface() {
@ -81,7 +81,7 @@ Page {
default: default:
console.warn("FIXME: Unhandled interface event"); console.warn("FIXME: Unhandled interface event");
} }
} else if (root.eventDescriptor.interfaceName != "") { } else if (root.eventDescriptor.interfaceName !== "") {
root.eventDescriptor.interfaceEvent = model.name; root.eventDescriptor.interfaceEvent = model.name;
if (listView.model.get(index).paramTypes.count > 0) { if (listView.model.get(index).paramTypes.count > 0) {
var paramsPage = pageStack.push(Qt.resolvedUrl("SelectEventDescriptorParamsPage.qml"), {eventDescriptor: root.eventDescriptor}) var paramsPage = pageStack.push(Qt.resolvedUrl("SelectEventDescriptorParamsPage.qml"), {eventDescriptor: root.eventDescriptor})

View File

@ -36,7 +36,7 @@ Page {
property alias operatorType: paramDescriptorDelegate.operatorType property alias operatorType: paramDescriptorDelegate.operatorType
CheckBox { CheckBox {
id: paramCheckBox id: paramCheckBox
text: "Only consider event if" text: qsTr("Only consider event if")
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: app.margins Layout.leftMargin: app.margins
Layout.rightMargin: app.margins Layout.rightMargin: app.margins

View File

@ -87,7 +87,7 @@ Page {
default: default:
console.warn("FIXME: Unhandled interface action"); console.warn("FIXME: Unhandled interface action");
} }
} else if (root.ruleAction.interfaceName != "") { } else if (root.ruleAction.interfaceName !== "") {
root.ruleAction.interfaceAction = model.name; root.ruleAction.interfaceAction = model.name;
if (listView.model.get(index).paramTypes.count > 0) { if (listView.model.get(index).paramTypes.count > 0) {
var paramsPage = pageStack.push(Qt.resolvedUrl("SelectRuleActionParamsPage.qml"), {ruleAction: root.ruleAction, rule: root.rule}) var paramsPage = pageStack.push(Qt.resolvedUrl("SelectRuleActionParamsPage.qml"), {ruleAction: root.ruleAction, rule: root.rule})

View File

@ -107,7 +107,7 @@ Page {
Layout.fillHeight: true Layout.fillHeight: true
} }
Button { Button {
text: "OK" text: qsTr("OK")
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
onClicked: { onClicked: {

View File

@ -17,7 +17,7 @@ Page {
signal completed(); signal completed();
header: GuhHeader { header: GuhHeader {
text: "params" text: qsTr("params")
onBackPressed: root.backPressed(); onBackPressed: root.backPressed();
} }
@ -30,7 +30,7 @@ Page {
value: paramType.defaultValue value: paramType.defaultValue
} }
Button { Button {
text: "OK" text: qsTr("OK")
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.margins: app.margins
onClicked: { onClicked: {

View File

@ -12,7 +12,7 @@ Page {
signal interfaceSelected(string interfaceName); signal interfaceSelected(string interfaceName);
header: GuhHeader { header: GuhHeader {
text: "Select a thing" text: qsTr("Select a thing")
onBackPressed: root.backPressed() onBackPressed: root.backPressed()
} }
ColumnLayout { ColumnLayout {
@ -22,12 +22,12 @@ Page {
Layout.fillWidth: true Layout.fillWidth: true
RadioButton { RadioButton {
id: thingButton id: thingButton
text: "A specific thing" text: qsTr("A specific thing")
checked: true checked: true
} }
RadioButton { RadioButton {
id: interfacesButton id: interfacesButton
text: "A group of things" text: qsTr("A group of things")
} }
} }

View File

@ -29,7 +29,7 @@ SwipeDelegate {
ComboBox { ComboBox {
Layout.fillWidth: true Layout.fillWidth: true
model: ["and all of those", "or any of those"] model: [qsTr("and all of those"), qsTr("or any of those")]
currentIndex: root.stateEvaluator && root.stateEvaluator.stateOperator === StateEvaluator.StateOperatorAnd ? 0 : 1 currentIndex: root.stateEvaluator && root.stateEvaluator.stateOperator === StateEvaluator.StateOperatorAnd ? 0 : 1
visible: root.stateEvaluator && root.stateEvaluator.childEvaluators.count > 0 visible: root.stateEvaluator && root.stateEvaluator.childEvaluators.count > 0
onActivated: { onActivated: {
@ -51,7 +51,7 @@ SwipeDelegate {
Button { Button {
Layout.fillWidth: true Layout.fillWidth: true
text: "Add a condition" text: qsTr("Add a condition")
onClicked: { onClicked: {
root.stateEvaluator.addChildEvaluator() root.stateEvaluator.addChildEvaluator()
// root.editStateEvaluator() // root.editStateEvaluator()

View File

@ -26,6 +26,7 @@ ApplicationWindow {
property string lastConnectedHost: "" property string lastConnectedHost: ""
property int viewMode: ApplicationWindow.Maximized property int viewMode: ApplicationWindow.Maximized
property bool returnToHome: false property bool returnToHome: false
property bool darkTheme: false
property string graphStyle: "bars" property string graphStyle: "bars"
property string style: "light" property string style: "light"
} }
@ -133,27 +134,27 @@ ApplicationWindow {
function interfaceToString(name) { function interfaceToString(name) {
switch(name) { switch(name) {
case "light": case "light":
return "Lighting" return qsTr("Lighting")
case "weather": case "weather":
return "Weather" return qsTr("Weather")
case "sensor": case "sensor":
return "Sensors" return qsTr("Sensors")
case "media": case "media":
return "Media" return qsTr("Media")
case "button": case "button":
return "Switches" return qsTr("Switches")
case "gateway": case "gateway":
return "Gateways" return qsTr("Gateways")
case "notifications": case "notifications":
return "Notifications" return qsTr("Notifications")
case "temperaturesensor": case "temperaturesensor":
return "Temperature"; return qsTr("Temperature");
case "humiditysensor": case "humiditysensor":
return "Humidity"; return qsTr("Humidity");
case "inputtrigger": case "inputtrigger":
return "Incoming Events"; return qsTr("Incoming Events");
case "outputtrigger": case "outputtrigger":
return "Events"; return qsTr("Events");
} }
} }
@ -233,7 +234,7 @@ ApplicationWindow {
anchors { left: parent.left; right: parent.right } anchors { left: parent.left; right: parent.right }
spacing: app.margins spacing: app.margins
Label { Label {
text: "Connection error" text: qsTr("Connection error")
Layout.fillWidth: true Layout.fillWidth: true
font.pixelSize: app.largeFont font.pixelSize: app.largeFont
} }
@ -244,7 +245,7 @@ ApplicationWindow {
} }
Button { Button {
Layout.fillWidth: true Layout.fillWidth: true
text: "OK" text: qsTr("OK")
onClicked: { onClicked: {
Engine.connection.disconnect(); Engine.connection.disconnect();
popup.close() popup.close()

View File

@ -26,7 +26,7 @@ ItemDelegate {
} }
Loader { Loader {
id: loader id: loader
Layout.fillWidth: sourceComponent == textFieldComponent Layout.fillWidth: sourceComponent === textFieldComponent
sourceComponent: { sourceComponent: {
if (!root.writable) { if (!root.writable) {
return stringComponent; return stringComponent;
@ -60,7 +60,7 @@ ItemDelegate {
switch (root.paramType.type.toLowerCase()) { switch (root.paramType.type.toLowerCase()) {
case "int": case "int":
case "double": case "double":
if (root.paramType.minValue != undefined && root.paramType.maxValue != undefined) { if (root.paramType.minValue !== undefined && root.paramType.maxValue !== undefined) {
return sliderComponent return sliderComponent
} }
break; break;

View File

@ -24,30 +24,30 @@ ItemDelegate {
case "bool": case "bool":
case "string": case "string":
case "qstring": case "qstring":
return ["is", "is not"]; return [qsTr("is"), qsTr("is not")];
case "int": case "int":
case "double": case "double":
return ["is", "is not", "is greater", "is smaller", "is greater or equal", "is smaller or equal"] return [qsTr("is"), qsTr("is not"), qsTr("is greater"), qsTr("is smaller"), qsTr("is greater or equal"), qsTr("is smaller or equal")]
} }
} }
onCurrentTextChanged: { onCurrentTextChanged: {
switch (currentText) { switch (currentText) {
case "is": case qsTr("is"):
root.operatorType = ParamDescriptor.ValueOperatorEquals; root.operatorType = ParamDescriptor.ValueOperatorEquals;
break; break;
case "is not": case qsTr("is not"):
root.operatorType = ParamDescriptor.ValueOperatorNotEquals; root.operatorType = ParamDescriptor.ValueOperatorNotEquals;
break; break;
case "is greater": case qsTr("is greater"):
root.operatorType = ParamDescriptor.ValueOperatorGreater; root.operatorType = ParamDescriptor.ValueOperatorGreater;
break; break;
case "is smaller": case qsTr("is smaller"):
root.operatorType = ParamDescriptor.ValueOperatorLess; root.operatorType = ParamDescriptor.ValueOperatorLess;
break; break;
case "is greater or equal": case qsTr("is greater or equal"):
root.operatorType = ParamDescriptor.ValueOperatorGreaterOrEqual; root.operatorType = ParamDescriptor.ValueOperatorGreaterOrEqual;
break; break;
case "is smaller or equal": case qsTr("is smaller or equal"):
root.operatorType = ParamDescriptor.ValueOperatorLessOrEqual; root.operatorType = ParamDescriptor.ValueOperatorLessOrEqual;
break; break;
} }

View File

@ -8,7 +8,7 @@ import "../components"
Page { Page {
id: root id: root
header: GuhHeader { header: GuhHeader {
text: "Log viewer" text: qsTr("Log viewer")
onBackPressed: pageStack.pop() onBackPressed: pageStack.pop()
HeaderButton { HeaderButton {
@ -66,24 +66,24 @@ Page {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
Label { Label {
width: listView.column0Width width: listView.column0Width
text: "Time" text: qsTr("Time")
} }
Label { Label {
text: "Type" text: qsTr("Type")
width: listView.column1Width width: listView.column1Width
} }
Label { Label {
width: listView.column2Width width: listView.column2Width
text: "Thing" text: qsTr("Thing")
} }
Label { Label {
width: listView.column3Width width: listView.column3Width
text: "Object" text: qsTr("Object")
} }
Label { Label {
width: listView.column4Width width: listView.column4Width
text: "Value" text: qsTr("Value")
} }
} }
ThinDivider { ThinDivider {
@ -134,7 +134,7 @@ Page {
Label { Label {
width: listView.column2Width width: listView.column2Width
text: model.source === LogEntry.LoggingSourceSystem ? "Nymea Server" : delegate.device.name text: model.source === LogEntry.LoggingSourceSystem ? qsTr("Nymea Server") : delegate.device.name
elide: Text.ElideRight elide: Text.ElideRight
} }
Label { Label {
@ -144,7 +144,7 @@ Page {
case LogEntry.LoggingSourceStates: case LogEntry.LoggingSourceStates:
return delegate.deviceClass.stateTypes.getStateType(model.typeId).displayName; return delegate.deviceClass.stateTypes.getStateType(model.typeId).displayName;
case LogEntry.LoggingSourceSystem: case LogEntry.LoggingSourceSystem:
return model.loggingEventType === LogEntry.LoggingEventTypeActiveChange ? "Active changed" : "FIXME" return model.loggingEventType === LogEntry.LoggingEventTypeActiveChange ? qsTr("Active changed") : "FIXME"
case LogEntry.LoggingSourceActions: case LogEntry.LoggingSourceActions:
return delegate.deviceClass.actionTypes.getActionType(model.typeId).displayName; return delegate.deviceClass.actionTypes.getActionType(model.typeId).displayName;
case LogEntry.LoggingSourceEvents: case LogEntry.LoggingSourceEvents:

View File

@ -26,11 +26,11 @@ Page {
Connections { Connections {
target: Engine.deviceManager target: Engine.deviceManager
onSavePluginConfigReply: { onSavePluginConfigReply: {
if (params.params.deviceError == "DeviceErrorNoError") { if (params.params.deviceError === "DeviceErrorNoError") {
pageStack.pop(); pageStack.pop();
} else { } else {
console.warn("Error saving plugin params:", JSON.stringify(params)) console.warn("Error saving plugin params:", JSON.stringify(params))
var dialog = errorDialog.createObject(root, {title: "Error", text: "Error saving params: " + JSON.stringify(params.params.deviceError)}); var dialog = errorDialog.createObject(root, {title: "Error", text: qsTr("Error saving params: ") + JSON.stringify(params.params.deviceError)});
dialog.open(); dialog.open();
} }
} }

View File

@ -8,7 +8,7 @@ import Mea 1.0
Page { Page {
id: root id: root
header: GuhHeader { header: GuhHeader {
text: "Plugins" text: qsTr("Plugins")
backButtonVisible: true backButtonVisible: true
onBackPressed: pageStack.pop() onBackPressed: pageStack.pop()
} }

View File

@ -0,0 +1,138 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "bluetoothdevice.h"
BluetoothDevice::BluetoothDevice(const QBluetoothDeviceInfo &deviceInfo, QObject *parent) :
QObject(parent),
m_deviceInfo(deviceInfo),
m_connected(false)
{
m_controller = new QLowEnergyController(deviceInfo.address(), this);
m_controller->setRemoteAddressType(QLowEnergyController::PublicAddress);
connect(m_controller, &QLowEnergyController::connected, this, &BluetoothDevice::onConnected);
connect(m_controller, &QLowEnergyController::disconnected, this, &BluetoothDevice::onDisconnected);
connect(m_controller, &QLowEnergyController::stateChanged, this, &BluetoothDevice::onDeviceStateChanged);
connect(m_controller, SIGNAL(error(QLowEnergyController::Error)), this, SLOT(onDeviceError(QLowEnergyController::Error)));
connect(m_controller, SIGNAL(discoveryFinished()), this, SIGNAL(serviceDiscoveryFinished()));
}
QString BluetoothDevice::name() const
{
return m_deviceInfo.name();
}
QBluetoothAddress BluetoothDevice::address() const
{
return m_deviceInfo.address();
}
bool BluetoothDevice::connected() const
{
return m_connected;
}
QString BluetoothDevice::statusText() const
{
return m_statusText;
}
void BluetoothDevice::connectDevice()
{
m_controller->connectToDevice();
}
void BluetoothDevice::disconnectDevice()
{
m_controller->disconnectFromDevice();
}
void BluetoothDevice::setConnected(const bool &connected)
{
m_connected = connected;
emit connectedChanged();
}
void BluetoothDevice::setStatusText(const QString &statusText)
{
m_statusText = statusText;
emit statusTextChanged();
}
QLowEnergyController *BluetoothDevice::controller()
{
return m_controller;
}
void BluetoothDevice::onConnected()
{
qDebug() << "BluetoothDevice: Connected to" << name() << address().toString();
m_controller->discoverServices();
}
void BluetoothDevice::onDisconnected()
{
qWarning() << "BluetoothDevice: Disconnected from" << name() << address().toString();
setConnected(false);
setStatusText("Disconnected from " + name());
}
void BluetoothDevice::onDeviceError(const QLowEnergyController::Error &error)
{
qWarning() << "BluetoothDevice: Error" << name() << address().toString() << ": " << error << m_controller->errorString();
setConnected(false);
}
void BluetoothDevice::onDeviceStateChanged(const QLowEnergyController::ControllerState &state)
{
switch (state) {
case QLowEnergyController::ConnectingState:
qDebug() << "BluetoothDevice: Connecting...";
setStatusText(QString(tr("Connecting to %1...").arg(name())));
break;
case QLowEnergyController::ConnectedState:
qDebug() << "BluetoothDevice: Connected!";
setStatusText(QString(tr("Connected to %1").arg(name())));
break;
case QLowEnergyController::ClosingState:
qDebug() << "BluetoothDevice: Connection: Closing...";
setStatusText(QString(tr("Disconnecting from %1...").arg(name())));
break;
case QLowEnergyController::DiscoveringState:
qDebug() << "BluetoothDevice: Discovering...";
setStatusText(QString(tr("Discovering services of %1...").arg(name())));
break;
case QLowEnergyController::DiscoveredState:
qDebug() << "BluetoothDevice: Discovered!";
setStatusText(QString(tr("%1 connected and discovered.").arg(name())));
setConnected(true);
break;
case QLowEnergyController::UnconnectedState:
qDebug() << "BluetoothDevice: Not connected.";
setStatusText(QString(tr("%1 disconnected.").arg(name())));
break;
default:
break;
}
}

View File

@ -0,0 +1,77 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef BLUETOOTHDEVICE_H
#define BLUETOOTHDEVICE_H
#include <QObject>
#include <QBluetoothUuid>
#include <QLowEnergyService>
#include <QBluetoothDeviceInfo>
#include <QLowEnergyController>
#include <QLowEnergyCharacteristic>
class BluetoothDevice : public QObject
{
Q_OBJECT
Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
Q_PROPERTY(QString statusText READ statusText NOTIFY statusTextChanged)
public:
explicit BluetoothDevice(const QBluetoothDeviceInfo &deviceInfo, QObject *parent = 0);
QString name() const;
QBluetoothAddress address() const;
bool connected() const;
QString statusText() const;
Q_INVOKABLE void connectDevice();
Q_INVOKABLE void disconnectDevice();
private:
QBluetoothDeviceInfo m_deviceInfo;
QLowEnergyController *m_controller;
bool m_connected;
QString m_statusText;
void setConnected(const bool &connected);
protected:
QLowEnergyController *controller();
void setStatusText(const QString &statusText);
signals:
void connectedChanged();
void serviceDiscoveryFinished();
void statusTextChanged();
private slots:
void onConnected();
void onDisconnected();
void onDeviceError(const QLowEnergyController::Error &error);
void onDeviceStateChanged(const QLowEnergyController::ControllerState &state);
};
#endif // BLUETOOTHDEVICE_H

View File

@ -0,0 +1,58 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "bluetoothdeviceinfo.h"
BluetoothDeviceInfo::BluetoothDeviceInfo()
{
}
BluetoothDeviceInfo::BluetoothDeviceInfo(const QBluetoothDeviceInfo &deviceInfo)
{
m_deviceInfo = deviceInfo;
}
QString BluetoothDeviceInfo::address() const
{
return m_deviceInfo.address().toString();
}
QString BluetoothDeviceInfo::name() const
{
return m_deviceInfo.name();
}
bool BluetoothDeviceInfo::isLowEnergy() const
{
return m_deviceInfo.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration;
}
QBluetoothDeviceInfo BluetoothDeviceInfo::getBluetoothDeviceInfo() const
{
return m_deviceInfo;
}
void BluetoothDeviceInfo::setBluetoothDeviceInfo(const QBluetoothDeviceInfo &deviceInfo)
{
m_deviceInfo = QBluetoothDeviceInfo(deviceInfo);
emit deviceChanged();
}

View File

@ -0,0 +1,56 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef BLUETOOTHDEVICEINFO_H
#define BLUETOOTHDEVICEINFO_H
#include <QList>
#include <QObject>
#include <QBluetoothAddress>
#include <QBluetoothDeviceInfo>
class BluetoothDeviceInfo : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name NOTIFY deviceChanged)
Q_PROPERTY(QString address READ address NOTIFY deviceChanged)
public:
BluetoothDeviceInfo();
BluetoothDeviceInfo(const QBluetoothDeviceInfo &deviceInfo);
QString address() const;
QString name() const;
bool isLowEnergy() const;
QBluetoothDeviceInfo getBluetoothDeviceInfo() const;
void setBluetoothDeviceInfo(const QBluetoothDeviceInfo &deviceInfo);
signals:
void deviceChanged();
private:
QBluetoothDeviceInfo m_deviceInfo;
};
#endif // BLUETOOTHDEVICEINFO_H

View File

@ -0,0 +1,93 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "bluetoothdeviceinfos.h"
BluetoothDeviceInfos::BluetoothDeviceInfos(QObject *parent) : QAbstractListModel(parent)
{
}
QList<BluetoothDeviceInfo *> BluetoothDeviceInfos::deviceInfos()
{
return m_deviceInfos;
}
int BluetoothDeviceInfos::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_deviceInfos.count();
}
QVariant BluetoothDeviceInfos::data(const QModelIndex &index, int role) const
{
if (index.row() < 0 || index.row() >= m_deviceInfos.count())
return QVariant();
BluetoothDeviceInfo *deviceInfo = m_deviceInfos.at(index.row());
if (role == BluetoothDeviceInfoRoleName) {
return deviceInfo->name();
} else if (role == BluetoothDeviceInfoRoleAddress) {
return deviceInfo->address();
} else if (role == BluetoothDeviceInfoRoleLe) {
return deviceInfo->isLowEnergy();
}
return QVariant();
}
int BluetoothDeviceInfos::count() const
{
return m_deviceInfos.count();
}
BluetoothDeviceInfo *BluetoothDeviceInfos::get(int index) const
{
if (index >= m_deviceInfos.count() || index < 0)
return Q_NULLPTR;
return m_deviceInfos.at(index);
}
void BluetoothDeviceInfos::addBluetoothDeviceInfo(BluetoothDeviceInfo *deviceInfo)
{
beginInsertRows(QModelIndex(), m_deviceInfos.count(), m_deviceInfos.count());
m_deviceInfos.append(deviceInfo);
endInsertRows();
}
void BluetoothDeviceInfos::clearModel()
{
beginResetModel();
qDeleteAll(m_deviceInfos);
m_deviceInfos.clear();
endResetModel();
}
QHash<int, QByteArray> BluetoothDeviceInfos::roleNames() const
{
QHash<int, QByteArray> roles;
roles[BluetoothDeviceInfoRoleName] = "name";
roles[BluetoothDeviceInfoRoleAddress] = "address";
roles[BluetoothDeviceInfoRoleLe] = "lowEnergy";
return roles;
}

View File

@ -0,0 +1,61 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef BLUETOOTHDEVICEINFOS_H
#define BLUETOOTHDEVICEINFOS_H
#include <QObject>
#include <QAbstractListModel>
#include "bluetoothdeviceinfo.h"
class BluetoothDeviceInfos : public QAbstractListModel
{
Q_OBJECT
public:
enum BluetoothDeviceInfoRole {
BluetoothDeviceInfoRoleName = Qt::DisplayRole,
BluetoothDeviceInfoRoleAddress,
BluetoothDeviceInfoRoleLe
};
explicit BluetoothDeviceInfos(QObject *parent = 0);
QList<BluetoothDeviceInfo *> deviceInfos();
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
Q_INVOKABLE int count() const;
Q_INVOKABLE BluetoothDeviceInfo *get(int index) const;
void addBluetoothDeviceInfo(BluetoothDeviceInfo *deviceInfo);
void clearModel();
protected:
QHash<int, QByteArray> roleNames() const;
private:
QList<BluetoothDeviceInfo *> m_deviceInfos;
};
#endif // BLUETOOTHDEVICEINFOS_H

View File

@ -0,0 +1,87 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "bluetoothdiscovery.h"
#include <QDebug>
BluetoothDiscovery::BluetoothDiscovery(QObject *parent) :
QObject(parent),
m_discoveryAgent(new QBluetoothDeviceDiscoveryAgent(this)),
m_deviceInfos(new BluetoothDeviceInfos(this)),
m_discovering(false)
{
connect(m_discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &BluetoothDiscovery::deviceDiscovered);
connect(m_discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &BluetoothDiscovery::discoveryFinished);
connect(m_discoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)), this, SLOT(onError(QBluetoothDeviceDiscoveryAgent::Error)));
}
bool BluetoothDiscovery::discovering() const
{
return m_discovering;
}
BluetoothDeviceInfos *BluetoothDiscovery::deviceInfos()
{
return m_deviceInfos;
}
void BluetoothDiscovery::setDiscovering(const bool &discovering)
{
m_discovering = discovering;
emit discoveringChanged();
}
void BluetoothDiscovery::deviceDiscovered(const QBluetoothDeviceInfo &deviceInfo)
{
qDebug() << "Discovery: [+]" << deviceInfo.name() << "(" << deviceInfo.address().toString() << ")" << (deviceInfo.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration ? "LE" : "");
m_deviceInfos->addBluetoothDeviceInfo(new BluetoothDeviceInfo(deviceInfo));
}
void BluetoothDiscovery::discoveryFinished()
{
qDebug() << "Discovery finished";
setDiscovering(false);
}
void BluetoothDiscovery::onError(const QBluetoothDeviceDiscoveryAgent::Error &error)
{
qWarning() << "Discovery error:" << error << m_discoveryAgent->errorString();
setDiscovering(false);
}
void BluetoothDiscovery::start()
{
if (m_discoveryAgent->isActive())
m_discoveryAgent->stop();
m_deviceInfos->clearModel();
m_discoveryAgent->start();
setDiscovering(true);
}
void BluetoothDiscovery::stop()
{
m_discoveryAgent->stop();
setDiscovering(false);
}

View File

@ -0,0 +1,66 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef BLUETOOTHDISCOVERY_H
#define BLUETOOTHDISCOVERY_H
#include <QObject>
#include <QBluetoothDeviceDiscoveryAgent>
#include "bluetoothdeviceinfos.h"
class BluetoothDiscovery : public QObject
{
Q_OBJECT
Q_PROPERTY(bool discovering READ discovering NOTIFY discoveringChanged)
Q_PROPERTY(BluetoothDeviceInfos *deviceInfos READ deviceInfos CONSTANT)
public:
explicit BluetoothDiscovery(QObject *parent = 0);
bool discovering() const;
BluetoothDeviceInfos *deviceInfos();
private:
QBluetoothDeviceDiscoveryAgent *m_discoveryAgent;
BluetoothDeviceInfos *m_deviceInfos;
bool m_discovering;
void setDiscovering(const bool &discovering);
signals:
void discoveringChanged();
private slots:
void deviceDiscovered(const QBluetoothDeviceInfo &deviceInfo);
void discoveryFinished();
void onError(const QBluetoothDeviceDiscoveryAgent::Error &error);
public slots:
Q_INVOKABLE void start();
Q_INVOKABLE void stop();
};
#endif // BLUETOOTHDISCOVERY_H

View File

@ -0,0 +1,68 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "networkmanagercontroler.h"
NetworkManagerControler::NetworkManagerControler(QObject *parent) : QObject(parent)
{
}
QString NetworkManagerControler::name() const
{
return m_name;
}
void NetworkManagerControler::setName(const QString &name)
{
m_name = name;
emit nameChanged();
}
QString NetworkManagerControler::address() const
{
return m_address;
}
void NetworkManagerControler::setAddress(const QString &address)
{
m_address = address;
}
WirelessSetupManager *NetworkManagerControler::manager()
{
return m_wirelessSetupManager;
}
void NetworkManagerControler::connectDevice()
{
if (m_wirelessSetupManager) {
delete m_wirelessSetupManager;
m_wirelessSetupManager = nullptr;
emit managerChanged();
}
m_wirelessSetupManager = new WirelessSetupManager(QBluetoothDeviceInfo(QBluetoothAddress(m_address), m_name, 0), this);
emit managerChanged();
m_wirelessSetupManager->connectDevice();
}

View File

@ -0,0 +1,64 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef NETWORKMANAGERCONTROLER_H
#define NETWORKMANAGERCONTROLER_H
#include <QObject>
#include <QBluetoothDeviceInfo>
#include "wirelesssetupmanager.h"
class NetworkManagerControler : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QString address READ address WRITE setAddress NOTIFY addressChanged)
Q_PROPERTY(WirelessSetupManager *manager READ manager NOTIFY managerChanged)
public:
explicit NetworkManagerControler(QObject *parent = nullptr);
QString name() const;
void setName(const QString &name);
QString address() const;
void setAddress(const QString &address);
WirelessSetupManager *manager();
Q_INVOKABLE void connectDevice();
private:
QString m_name;
QString m_address;
WirelessSetupManager *m_wirelessSetupManager = nullptr;
signals:
void managerChanged();
void nameChanged();
void addressChanged();
};
#endif // NETWORKMANAGERCONTROLER_H

View File

@ -0,0 +1,69 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "wirelessaccesspoint.h"
WirelessAccessPoint::WirelessAccessPoint(QObject *parent):
QObject(parent)
{
}
QString WirelessAccessPoint::ssid() const
{
return m_ssid;
}
void WirelessAccessPoint::setSsid(const QString ssid)
{
m_ssid = ssid;
}
QString WirelessAccessPoint::macAddress() const
{
return m_macAddress;
}
void WirelessAccessPoint::setMacAddress(const QString &macAddress)
{
m_macAddress = macAddress;
}
int WirelessAccessPoint::signalStrength() const
{
return m_signalStrength;
}
void WirelessAccessPoint::setSignalStrength(const int &signalStrength)
{
m_signalStrength = signalStrength;
}
bool WirelessAccessPoint::isProtected() const
{
return m_isProtected;
}
void WirelessAccessPoint::setProtected(const bool &isProtected)
{
m_isProtected = isProtected;
}

View File

@ -0,0 +1,56 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef WIRELESSACCESSPOINT_H
#define WIRELESSACCESSPOINT_H
#include <QObject>
#include <QString>
class WirelessAccessPoint : public QObject
{
Q_OBJECT
public:
WirelessAccessPoint(QObject *parent = 0);
QString ssid() const;
void setSsid(const QString ssid);
QString macAddress() const;
void setMacAddress(const QString &macAddress);
int signalStrength() const;
void setSignalStrength(const int &signalStrength);
bool isProtected() const;
void setProtected(const bool &isProtected);
private:
QString m_ssid;
QString m_macAddress;
int m_signalStrength;
bool m_isProtected;
};
#endif // WIRELESSACCESSPOINT_H

View File

@ -0,0 +1,112 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "wirelessaccesspoints.h"
WirelessAccesspoints::WirelessAccesspoints(QObject *parent) : QAbstractListModel(parent)
{
}
QList<WirelessAccessPoint *> WirelessAccesspoints::wirelessAccessPoints()
{
return m_wirelessAccessPoints;
}
void WirelessAccesspoints::setWirelessAccessPoints(QList<WirelessAccessPoint *> wirelessAccessPoints)
{
beginResetModel();
// Delete all
qDeleteAll(m_wirelessAccessPoints);
m_wirelessAccessPoints.clear();
qSort(wirelessAccessPoints.begin(), wirelessAccessPoints.end(), signalStrengthLessThan);
m_wirelessAccessPoints = wirelessAccessPoints;
endResetModel();
}
int WirelessAccesspoints::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_wirelessAccessPoints.count();
}
QVariant WirelessAccesspoints::data(const QModelIndex &index, int role) const
{
if (index.row() < 0 || index.row() >= m_wirelessAccessPoints.count())
return QVariant();
WirelessAccessPoint *accessPoint = m_wirelessAccessPoints.at(index.row());
if (role == WirelessAccesspointRoleSsid) {
return accessPoint->ssid();
} else if (role == WirelessAccesspointRoleMacAddress) {
return accessPoint->macAddress();
} else if (role == WirelessAccesspointRoleSignalStrength) {
return accessPoint->signalStrength();
} else if (role == WirelessAccesspointRoleProtected) {
return accessPoint->isProtected();
}
return QVariant();
}
int WirelessAccesspoints::count() const
{
return m_wirelessAccessPoints.count();
}
WirelessAccessPoint *WirelessAccesspoints::get(const QString &ssid) const
{
foreach (WirelessAccessPoint *accessPoint, m_wirelessAccessPoints) {
if (accessPoint->ssid() == ssid)
return accessPoint;
}
return Q_NULLPTR;
}
void WirelessAccesspoints::clearModel()
{
beginResetModel();
qDeleteAll(m_wirelessAccessPoints);
m_wirelessAccessPoints.clear();
endResetModel();
}
bool WirelessAccesspoints::signalStrengthLessThan(const WirelessAccessPoint *a, const WirelessAccessPoint *b)
{
return a->signalStrength() > b->signalStrength();
}
QHash<int, QByteArray> WirelessAccesspoints::roleNames() const
{
QHash<int, QByteArray> roles;
roles[WirelessAccesspointRoleSsid] = "ssid";
roles[WirelessAccesspointRoleMacAddress] = "macAddress";
roles[WirelessAccesspointRoleSignalStrength] = "signalStrength";
roles[WirelessAccesspointRoleProtected] = "protected";
return roles;
}

View File

@ -0,0 +1,66 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef WIRELESSACCESSPOINTS_H
#define WIRELESSACCESSPOINTS_H
#include <QObject>
#include <QAbstractListModel>
#include "wirelessaccesspoint.h"
class WirelessAccesspoints : public QAbstractListModel
{
Q_OBJECT
public:
enum BluetoothDeviceInfoRole {
WirelessAccesspointRoleSsid = Qt::DisplayRole,
WirelessAccesspointRoleMacAddress,
WirelessAccesspointRoleSignalStrength,
WirelessAccesspointRoleProtected
};
explicit WirelessAccesspoints(QObject *parent = 0);
QList<WirelessAccessPoint *> wirelessAccessPoints();
void setWirelessAccessPoints(QList<WirelessAccessPoint *> wirelessAccessPoints);
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
Q_INVOKABLE int count() const;
Q_INVOKABLE WirelessAccessPoint *get(const QString &ssid) const;
void clearModel();
static bool signalStrengthLessThan(const WirelessAccessPoint *a, const WirelessAccessPoint *b);
protected:
QHash<int, QByteArray> roleNames() const;
private:
QList<WirelessAccessPoint *> m_wirelessAccessPoints;
};
#endif // WIRELESSACCESSPOINTS_H

View File

@ -0,0 +1,961 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "wirelesssetupmanager.h"
#include <QJsonDocument>
static QBluetoothUuid wifiServiceUuid = QBluetoothUuid(QUuid("e081fec0-f757-4449-b9c9-bfa83133f7fc"));
static QBluetoothUuid wifiCommanderCharacteristicUuid = QBluetoothUuid(QUuid("e081fec1-f757-4449-b9c9-bfa83133f7fc"));
static QBluetoothUuid wifiResponseCharacteristicUuid = QBluetoothUuid(QUuid("e081fec2-f757-4449-b9c9-bfa83133f7fc"));
static QBluetoothUuid wifiStatusCharacteristicUuid = QBluetoothUuid(QUuid("e081fec3-f757-4449-b9c9-bfa83133f7fc"));
static QBluetoothUuid networkServiceUuid = QBluetoothUuid(QUuid("ef6d6610-b8af-49e0-9eca-ab343513641c"));
static QBluetoothUuid networkStatusCharacteristicUuid = QBluetoothUuid(QUuid("ef6d6611-b8af-49e0-9eca-ab343513641c"));
static QBluetoothUuid networkCommanderCharacteristicUuid = QBluetoothUuid(QUuid("ef6d6612-b8af-49e0-9eca-ab343513641c"));
static QBluetoothUuid networkResponseCharacteristicUuid = QBluetoothUuid(QUuid("ef6d6613-b8af-49e0-9eca-ab343513641c"));
static QBluetoothUuid networkingEnabledCharacteristicUuid = QBluetoothUuid(QUuid("ef6d6614-b8af-49e0-9eca-ab343513641c"));
static QBluetoothUuid wirelessEnabledCharacteristicUuid = QBluetoothUuid(QUuid("ef6d6615-b8af-49e0-9eca-ab343513641c"));
static QBluetoothUuid systemServiceUuid = QBluetoothUuid(QUuid("e081fed0-f757-4449-b9c9-bfa83133f7fc"));
static QBluetoothUuid systemCommanderCharacteristicUuid = QBluetoothUuid(QUuid("e081fed1-f757-4449-b9c9-bfa83133f7fc"));
static QBluetoothUuid systemResponseCharacteristicUuid = QBluetoothUuid(QUuid("e081fed2-f757-4449-b9c9-bfa83133f7fc"));
WirelessSetupManager::WirelessSetupManager(const QBluetoothDeviceInfo &deviceInfo, QObject *parent) :
BluetoothDevice(deviceInfo, parent),
m_accessPoints(new WirelessAccesspoints(this))
{
connect(this, &WirelessSetupManager::connectedChanged, this, &WirelessSetupManager::onConnectedChanged);
connect(this, &WirelessSetupManager::serviceDiscoveryFinished, this, &WirelessSetupManager::onServiceDiscoveryFinished);
}
QString WirelessSetupManager::modelNumber() const
{
return m_modelNumber;
}
QString WirelessSetupManager::manufacturer() const
{
return m_manufacturer;
}
QString WirelessSetupManager::softwareRevision() const
{
return m_softwareRevision;
}
QString WirelessSetupManager::firmwareRevision() const
{
return m_firmwareRevision;
}
QString WirelessSetupManager::hardwareRevision() const
{
return m_hardwareRevision;
}
bool WirelessSetupManager::initialized() const
{
return m_initialized;
}
bool WirelessSetupManager::initializing() const
{
return m_initializing;
}
bool WirelessSetupManager::working() const
{
return m_working;
}
QString WirelessSetupManager::networkStatus() const
{
return m_networkStatus;
}
QString WirelessSetupManager::wirelessStatus() const
{
return m_wirelessStatus;
}
bool WirelessSetupManager::networkingEnabled() const
{
return m_networkingEnabled;
}
bool WirelessSetupManager::wirelessEnabled() const
{
return m_wirelessEnabled;
}
WirelessAccesspoints *WirelessSetupManager::accessPoints()
{
return m_accessPoints;
}
void WirelessSetupManager::loadNetworks()
{
qDebug() << "WifiSetupManager: Start loading wifi networks";
if (!m_wifiService) {
qWarning() << "WifiSetupManager: Could not send command. Service not valid";
return;
}
QLowEnergyCharacteristic characteristic = m_wifiService->characteristic(wifiCommanderCharacteristicUuid);
if (!characteristic.isValid()) {
qWarning() << "WifiSetupManager: Could not send command. Characteristic is not valid";
return;
}
m_readingResponse = true;
m_inputDataStream.clear();
m_accessPoints->clearModel();
setStatusText("WifiSetupManager: Loading wifi network list...");
setWorking(true);
QVariantMap request;
request.insert("c", (int)WirelessServiceCommandGetNetworks);
streamData(request);
}
void WirelessSetupManager::loadCurrentConnection()
{
qDebug() << "WifiSetupManager: Start loading current connection data";
if (!m_wifiService) {
qWarning() << "WifiSetupManager: Could not send command. Service not valid";
return;
}
QLowEnergyCharacteristic characteristic = m_wifiService->characteristic(wifiCommanderCharacteristicUuid);
if (!characteristic.isValid()) {
qWarning() << "WifiSetupManager: Could not send command. Characteristic is not valid";
return;
}
m_readingResponse = false;
m_inputDataStream.clear();
setStatusText("WifiSetupManager: Loading current connection data");
setWorking(true);
QVariantMap request;
request.insert("c", (int)WirelessServiceCommandGetCurrentConnection);
streamData(request);
}
void WirelessSetupManager::performWifiScan()
{
qDebug() << "WifiSetupManager: Start loading wifi networks";
if (!m_wifiService) {
qWarning() << "WifiSetupManager: Could not send command. Service not valid";
return;
}
QLowEnergyCharacteristic characteristic = m_wifiService->characteristic(wifiCommanderCharacteristicUuid);
if (!characteristic.isValid()) {
qWarning() << "WifiSetupManager: Could not send command. Characteristic is not valid";
return;
}
setStatusText("WifiSetupManager: Perform refresh...");
setWorking(true);
QVariantMap request;
request.insert("c", (int)WirelessServiceCommandScan);
streamData(request);
}
void WirelessSetupManager::enableNetworking(bool enable)
{
qDebug() << "WifiSetupManager: Send networking" << enable;
if (!m_netwokService) {
qWarning() << "WifiSetupManager: Could not set networking. Service not valid";
return;
}
QLowEnergyCharacteristic characteristic = m_netwokService->characteristic(networkCommanderCharacteristicUuid);
if (!characteristic.isValid()) {
qWarning() << "WifiSetupManager: Could not set networking. Characteristic is not valid";
return;
}
m_netwokService->writeCharacteristic(characteristic, enable ? QByteArray::fromHex("00") : QByteArray::fromHex("01"));
}
void WirelessSetupManager::enableWireless(bool enable)
{
qDebug() << "WifiSetupManager: Send wireless networking" << enable;
if (!m_netwokService) {
qWarning() << "WifiSetupManager: Could not enable/disable wireless. Service not valid";
return;
}
QLowEnergyCharacteristic characteristic = m_netwokService->characteristic(networkCommanderCharacteristicUuid);
if (!characteristic.isValid()) {
qWarning() << "WifiSetupManager: Could not enable/disable wireless. Characteristic is not valid";
return;
}
m_netwokService->writeCharacteristic(characteristic, enable ? QByteArray::fromHex("02") : QByteArray::fromHex("03"));
}
void WirelessSetupManager::connectWirelessNetwork(const QString &ssid, const QString &password)
{
qDebug() << "WifiSetupManager: Connect wireless network" << ssid << password;
m_ssid = ssid;
m_password = password;
if (!m_wifiService) {
qWarning() << "WifiSetupManager: Could not set wireless network. Service not valid";
return;
}
QLowEnergyCharacteristic ssidCharacteristic = m_wifiService->characteristic(wifiCommanderCharacteristicUuid);
if (!ssidCharacteristic.isValid()) {
qWarning() << "WifiSetupManager: Could not connect. Characteristic is not valid";
return;
}
QVariantMap request;
request.insert("c", (int)WirelessServiceCommandConnect);
QVariantMap parameters;
parameters.insert("e", ssid);
parameters.insert("p", password);
request.insert("p", parameters);
streamData(request);
}
void WirelessSetupManager::disconnectWirelessNetwork()
{
qDebug() << "WifiSetupManager: Disconnect wireless network";
if (!m_wifiService) {
qWarning() << "WifiSetupManager: Could not disconnect wireless network. Service not valid";
return;
}
QLowEnergyCharacteristic ssidCharacteristic = m_wifiService->characteristic(wifiCommanderCharacteristicUuid);
if (!ssidCharacteristic.isValid()) {
qWarning() << "WifiSetupManager: Could not disconnect wireless ssid. Characteristic is not valid";
return;
}
QVariantMap request;
request.insert("c", (int)WirelessServiceCommandDisconnect);
streamData(request);
}
void WirelessSetupManager::pressPushButton()
{
qDebug() << "WifiSetupManager: Press push button";
if (!m_systemService) {
qWarning() << "WifiSetupManager: Could not press push button. Service not valid";
return;
}
QLowEnergyCharacteristic commanderCharacteristic = m_systemService->characteristic(systemCommanderCharacteristicUuid);
if (!commanderCharacteristic.isValid()) {
qWarning() << "WifiSetupManager: Could not press push button. Characteristic is not valid";
return;
}
QVariantMap request;
request.insert("c", (int)SystemServiceCommandPushAuthentication);
QByteArray data = QJsonDocument::fromVariant(request).toJson(QJsonDocument::Compact) + '\n';
qDebug() << "WifiSetupManager: SystemService: Start streaming response data:" << data.count() << "bytes";
int sentDataLength = 0;
QByteArray remainingData = data;
while (!remainingData.isEmpty()) {
QByteArray package = remainingData.left(20);
sentDataLength += package.count();
m_systemService->writeCharacteristic(commanderCharacteristic, package);
remainingData = remainingData.remove(0, package.count());
}
qDebug() << "WifiSetupManager: SystemService: Finished streaming request data";
}
void WirelessSetupManager::checkInitialized()
{
setInitialized(m_deviceInformationService->state() == QLowEnergyService::ServiceDiscovered
&& m_netwokService->state() == QLowEnergyService::ServiceDiscovered
&& m_wifiService->state() == QLowEnergyService::ServiceDiscovered
&& m_systemService->state() == QLowEnergyService::ServiceDiscovered);
}
void WirelessSetupManager::setModelNumber(const QString &modelNumber)
{
m_modelNumber = modelNumber;
emit modelNumberChanged();
}
void WirelessSetupManager::setManufacturer(const QString &manufacturer)
{
m_manufacturer = manufacturer;
emit manufacturerChanged();
}
void WirelessSetupManager::setSoftwareRevision(const QString &softwareRevision)
{
m_softwareRevision = softwareRevision;
emit softwareRevisionChanged();
}
void WirelessSetupManager::setFirmwareRevision(const QString &firmwareRevision)
{
m_firmwareRevision = firmwareRevision;
emit firmwareRevisionChanged();
}
void WirelessSetupManager::setHardwareRevision(const QString &hardwareRevision)
{
m_hardwareRevision = hardwareRevision;
emit hardwareRevisionChanged();
}
void WirelessSetupManager::setInitializing(bool initializing)
{
if (m_initializing == initializing)
return;
qDebug() << "WifiSetupManager:" << (initializing ? "initializing" : "not initializing");
m_initializing = initializing;
emit initializingChanged();
}
void WirelessSetupManager::setInitialized(bool initialized)
{
if (m_initialized == initialized)
return;
qDebug() << "WifiSetupManager:" << (initialized ? "initialized" : "not initialized");
m_initialized = initialized;
emit initializedChanged();
}
void WirelessSetupManager::setWorking(bool working)
{
if (m_working == working)
return;
qDebug() << "WifiSetupManager:" << (working ? "working" : "not working");
m_working = working;
emit workingChanged();
}
void WirelessSetupManager::setNetworkStatus(int networkStatus)
{
if (m_networkStatus == networkStatus)
return;
switch (networkStatus) {
case 0:
m_networkStatus = tr("Unknown");
break;
case 1:
m_networkStatus = tr("Asleep");
break;
case 2:
m_networkStatus = tr("Disconnected");
break;
case 3:
m_networkStatus = tr("Disconnecting...");
break;
case 4:
m_networkStatus = tr("Connecting...");
break;
case 5:
m_networkStatus = tr("Connected local.");
break;
case 6:
m_networkStatus = tr("Connected site.");
break;
case 7:
m_networkStatus = tr("Connected global.");
break;
default:
m_networkStatus = tr("-");
break;
}
emit networkStatusChanged();
}
void WirelessSetupManager::setWirelessStatus(int wirelessStatus)
{
if (m_wirelessStatus == wirelessStatus)
return;
switch (wirelessStatus) {
case 0:
m_wirelessStatus = tr("Unknown");
break;
case 1:
m_wirelessStatus = tr("Unmanaged");
break;
case 2:
m_wirelessStatus = tr("Unavailable");
break;
case 3:
m_wirelessStatus = tr("Disconnected");
break;
case 4:
m_wirelessStatus = tr("Prepare");
break;
case 5:
m_wirelessStatus = tr("Configure");
break;
case 6:
m_wirelessStatus = tr("Authentication needed");
break;
case 7:
m_wirelessStatus = tr("IP configuration");
break;
case 8:
m_wirelessStatus = tr("IP check");
break;
case 9:
m_wirelessStatus = tr("Secondaries");
break;
case 10:
m_wirelessStatus = tr("Connected");
break;
case 11:
m_wirelessStatus = tr("Deactivating");
break;
case 12:
m_wirelessStatus = tr("failed");
break;
default:
m_wirelessStatus = tr("-");
break;
}
emit wirelessStatusChanged();
}
void WirelessSetupManager::setNetworkingEnabled(bool networkingEnabled)
{
if (m_networkingEnabled == networkingEnabled)
return;
qDebug() << "WifiSetupManager: Networking enabled changed" << networkingEnabled;
m_networkingEnabled = networkingEnabled;
emit networkingEnabledChanged();
}
void WirelessSetupManager::setWirelessEnabled(bool wirelessEnabled)
{
if (m_wirelessEnabled == wirelessEnabled)
return;
qDebug() << "WifiSetupManager: Wireless enabled changed" << wirelessEnabled;
m_wirelessEnabled = wirelessEnabled;
emit wirelessEnabledChanged();
}
void WirelessSetupManager::streamData(const QVariantMap &request)
{
QLowEnergyCharacteristic characteristic = m_wifiService->characteristic(wifiCommanderCharacteristicUuid);
if (!characteristic.isValid()) {
qWarning() << "WifiSetupManager: WirelessService: Wireless commander characteristic not valid";
return;
}
QByteArray data = QJsonDocument::fromVariant(request).toJson(QJsonDocument::Compact) + '\n';
qDebug() << "WifiSetupManager: WirelessService: Start streaming response data:" << data.count() << "bytes";
int sentDataLength = 0;
QByteArray remainingData = data;
while (!remainingData.isEmpty()) {
QByteArray package = remainingData.left(20);
sentDataLength += package.count();
m_wifiService->writeCharacteristic(characteristic, package);
remainingData = remainingData.remove(0, package.count());
}
qDebug() << "WifiSetupManager: WirelessService: Finished streaming request data";
}
void WirelessSetupManager::processNetworkResponse(const QVariantMap &response)
{
setWorking(false);
if (!response.contains("c") || !response.contains("r")) {
qWarning() << "WifiSetupManager: Got invalid response map.";
return;
}
WirelessServiceCommand command = (WirelessServiceCommand)response.value("c").toInt();
WirelessServiceResponse responseCode = (WirelessServiceResponse)response.value("r").toInt();
if (responseCode != WirelessServiceResponseSuccess) {
qWarning() << "WifiSetupManager: Got error for command" << command << responseCode;
return;
}
qDebug() << "WifiSetupManager: Network command response" << command << responseCode;
}
void WirelessSetupManager::processWifiResponse(const QVariantMap &response)
{
setWorking(false);
if (!response.contains("c") || !response.contains("r")) {
qWarning() << "WifiSetupManager: Got invalid response map.";
return;
}
WirelessServiceCommand command = (WirelessServiceCommand)response.value("c").toInt();
WirelessServiceResponse responseCode = (WirelessServiceResponse)response.value("r").toInt();
if (responseCode != WirelessServiceResponseSuccess) {
qWarning() << "WifiSetupManager: Got error for command" << command << responseCode;
return;
}
switch (command) {
case WirelessServiceCommandGetNetworks: {
if (!response.contains("p")) {
qWarning() << "WifiSetupManager: Missing parameters in response.";
return;
}
QList<WirelessAccessPoint *> accessPointsList;
QVariantList accessPointsVariantList = response.value("p").toList();
foreach (const QVariant &accessPointVariant, accessPointsVariantList) {
QVariantMap accessPointVariantMap = accessPointVariant.toMap();
WirelessAccessPoint *accessPoint = new WirelessAccessPoint(this);
accessPoint->setSsid(accessPointVariantMap.value("e").toString());
accessPoint->setMacAddress(accessPointVariantMap.value("m").toString());
accessPoint->setSignalStrength(accessPointVariantMap.value("s").toInt());
accessPoint->setProtected(accessPointVariantMap.value("p").toBool());
accessPointsList.append(accessPoint);
}
m_accessPoints->setWirelessAccessPoints(accessPointsList);
break;
}
case WirelessServiceCommandConnect:
break;
case WirelessServiceCommandConnectHidden:
break;
case WirelessServiceCommandDisconnect:
break;
case WirelessServiceCommandGetCurrentConnection:
break;
default:
break;
}
}
void WirelessSetupManager::processSystemResponse(const QVariantMap &response)
{
setWorking(false);
if (!response.contains("c") || !response.contains("r")) {
qWarning() << "WifiSetupManager: Got invalid response map.";
return;
}
SystemServiceCommand command = (SystemServiceCommand)response.value("c").toInt();
SystemServiceResponse responseCode = (SystemServiceResponse)response.value("r").toInt();
if (responseCode != SystemServiceResponseSuccess) {
qWarning() << "WifiSetupManager: Got error for command" << command << responseCode;
return;
}
qDebug() << "WifiSetupManager: System command response" << command << responseCode;
}
void WirelessSetupManager::onConnectedChanged()
{
if (!connected()) {
// Clean up
qDebug() << "WifiSetupManager: Clean up services";
m_deviceInformationService->deleteLater();
m_netwokService->deleteLater();
m_wifiService->deleteLater();
m_systemService->deleteLater();
m_deviceInformationService = nullptr;
m_netwokService = nullptr;
m_wifiService = nullptr;
m_systemService = nullptr;
m_accessPoints->clearModel();
setInitialized(false);
setInitializing(false);
setWorking(false);
setManufacturer("");
setModelNumber("");
setSoftwareRevision("");
setFirmwareRevision("");
setHardwareRevision("");
}
}
void WirelessSetupManager::onServiceDiscoveryFinished()
{
setInitializing(true);
foreach (const QBluetoothUuid &serviceUuid, controller()->services()) {
qDebug() << "WifiSetupManager: -->" << serviceUuid.toString();
}
if (!controller()->services().contains(QBluetoothUuid::DeviceInformation)) {
qWarning() << "WifiSetupManager: Could not find device information service";
controller()->disconnectFromDevice();
return;
}
if (!controller()->services().contains(networkServiceUuid)) {
qWarning() << "WifiSetupManager: Could not find network service";
controller()->disconnectFromDevice();
return;
}
if (!controller()->services().contains(wifiServiceUuid)) {
qWarning() << "WifiSetupManager: Could not find wifi service";
controller()->disconnectFromDevice();
return;
}
// Device Informantion service
if (!m_deviceInformationService) {
m_deviceInformationService = controller()->createServiceObject(QBluetoothUuid::DeviceInformation, this);
if (!m_deviceInformationService) {
qWarning() << "WifiSetupManager: Could not create temperature service.";
controller()->disconnectFromDevice();
return;
}
connect(m_deviceInformationService, &QLowEnergyService::stateChanged, this, &WirelessSetupManager::onDeviceInformationStateChanged);
connect(m_deviceInformationService, &QLowEnergyService::characteristicChanged, this, &WirelessSetupManager::onDeviceInformationCharacteristicChanged);
connect(m_deviceInformationService, &QLowEnergyService::characteristicRead, this, &WirelessSetupManager::onDeviceInformationCharacteristicChanged);
if (m_deviceInformationService->state() == QLowEnergyService::DiscoveryRequired)
m_deviceInformationService->discoverDetails();
}
// Network service
if (!m_netwokService) {
m_netwokService = controller()->createServiceObject(networkServiceUuid, this);
if (!m_netwokService) {
qWarning() << "WifiSetupManager: Could not create network service.";
controller()->disconnectFromDevice();
return;
}
connect(m_netwokService, &QLowEnergyService::stateChanged, this, &WirelessSetupManager::onNetworkServiceStateChanged);
connect(m_netwokService, &QLowEnergyService::characteristicChanged, this, &WirelessSetupManager::onNetworkServiceCharacteristicChanged);
connect(m_netwokService, &QLowEnergyService::characteristicRead, this, &WirelessSetupManager::onNetworkServiceReadFinished);
if (m_netwokService->state() == QLowEnergyService::DiscoveryRequired)
m_netwokService->discoverDetails();
}
// Wifi service
if (!m_wifiService) {
m_wifiService = controller()->createServiceObject(wifiServiceUuid, this);
if (!m_wifiService) {
qWarning() << "WifiSetupManager: Could not create wifi service.";
controller()->disconnectFromDevice();
return;
}
connect(m_wifiService, &QLowEnergyService::stateChanged, this, &WirelessSetupManager::onWifiServiceStateChanged);
connect(m_wifiService, &QLowEnergyService::characteristicChanged, this, &WirelessSetupManager::onWifiServiceCharacteristicChanged);
connect(m_wifiService, &QLowEnergyService::characteristicRead, this, &WirelessSetupManager::onWifiServiceReadFinished);
if (m_wifiService->state() == QLowEnergyService::DiscoveryRequired)
m_wifiService->discoverDetails();
}
// System service
if (!m_systemService) {
m_systemService = controller()->createServiceObject(systemServiceUuid, this);
if (!m_systemService) {
qWarning() << "WifiSetupManager: Could not create system service.";
controller()->disconnectFromDevice();
return;
}
connect(m_systemService, &QLowEnergyService::stateChanged, this, &WirelessSetupManager::onWifiServiceStateChanged);
connect(m_systemService, &QLowEnergyService::characteristicChanged, this, &WirelessSetupManager::onWifiServiceCharacteristicChanged);
connect(m_systemService, &QLowEnergyService::characteristicRead, this, &WirelessSetupManager::onWifiServiceReadFinished);
if (m_systemService->state() == QLowEnergyService::DiscoveryRequired)
m_systemService->discoverDetails();
}
}
void WirelessSetupManager::onDeviceInformationStateChanged(const QLowEnergyService::ServiceState &state)
{
if (state != QLowEnergyService::ServiceDiscovered)
return;
qDebug() << "WifiSetupManager: Device information service discovered.";
foreach (const QLowEnergyCharacteristic &characteristic, m_deviceInformationService->characteristics()) {
qDebug() << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
foreach (const QLowEnergyDescriptor &descriptor, characteristic.descriptors()) {
qDebug() << " -->" << descriptor.name() << descriptor.uuid().toString() << descriptor.value();
}
}
setManufacturer(QString::fromUtf8(m_deviceInformationService->characteristic(QBluetoothUuid::ManufacturerNameString).value()));
setModelNumber(QString::fromUtf8(m_deviceInformationService->characteristic(QBluetoothUuid::ModelNumberString).value()));
setSoftwareRevision(QString::fromUtf8(m_deviceInformationService->characteristic(QBluetoothUuid::SoftwareRevisionString).value()));
setFirmwareRevision(QString::fromUtf8(m_deviceInformationService->characteristic(QBluetoothUuid::FirmwareRevisionString).value()));
setHardwareRevision(QString::fromUtf8(m_deviceInformationService->characteristic(QBluetoothUuid::HardwareRevisionString).value()));
checkInitialized();
}
void WirelessSetupManager::onDeviceInformationCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
Q_UNUSED(characteristic)
Q_UNUSED(value)
}
void WirelessSetupManager::onDeviceInformationReadFinished(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
Q_UNUSED(characteristic)
Q_UNUSED(value)
}
void WirelessSetupManager::onNetworkServiceStateChanged(const QLowEnergyService::ServiceState &state)
{
if (state != QLowEnergyService::ServiceDiscovered)
return;
qDebug() << "WifiSetupManager: Network service discovered.";
foreach (const QLowEnergyCharacteristic &characteristic, m_netwokService->characteristics()) {
qDebug() << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
foreach (const QLowEnergyDescriptor &descriptor, characteristic.descriptors()) {
qDebug() << " -->" << descriptor.name() << descriptor.uuid().toString() << descriptor.value();
}
}
QLowEnergyCharacteristic networkCharacteristic = m_netwokService->characteristic(networkStatusCharacteristicUuid);
// Enable notifications
m_netwokService->writeDescriptor(networkCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration), QByteArray::fromHex("0100"));
setStatusText("Connected and ready");
setWorking(false);
// Done with discovery
setNetworkStatus(m_netwokService->characteristic(networkStatusCharacteristicUuid).value().toHex().toUInt(0, 16));
setNetworkingEnabled((bool)m_netwokService->characteristic(networkingEnabledCharacteristicUuid).value().toHex().toUInt(0, 16));
setWirelessEnabled((bool)m_netwokService->characteristic(wirelessEnabledCharacteristicUuid).value().toHex().toUInt(0, 16));
checkInitialized();
}
void WirelessSetupManager::onNetworkServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
Q_UNUSED(characteristic)
// Check if currently reading
if (m_readingResponse) {
m_inputDataStream.append(value);
} else {
m_inputDataStream.clear();
m_readingResponse = true;
m_inputDataStream.append(value);
}
// If command finished
if (value.endsWith('\n')) {
QJsonParseError error;
QJsonDocument jsonDocument = QJsonDocument::fromJson(m_inputDataStream, &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "Got invalid json object" << m_inputDataStream;
m_inputDataStream.clear();
m_readingResponse = false;
return;
}
qDebug() << "Got command stream" << qUtf8Printable(jsonDocument.toJson());
processNetworkResponse(jsonDocument.toVariant().toMap());
m_inputDataStream.clear();
m_readingResponse = false;
}
}
void WirelessSetupManager::onNetworkServiceReadFinished(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
Q_UNUSED(characteristic)
Q_UNUSED(value)
}
void WirelessSetupManager::onWifiServiceStateChanged(const QLowEnergyService::ServiceState &state)
{
if (state != QLowEnergyService::ServiceDiscovered)
return;
qDebug() << "WifiSetupManager: Wifi service discovered.";
foreach (const QLowEnergyCharacteristic &characteristic, m_wifiService->characteristics()) {
qDebug() << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
foreach (const QLowEnergyDescriptor &descriptor, characteristic.descriptors()) {
qDebug() << " -->" << descriptor.name() << descriptor.uuid().toString() << descriptor.value();
}
}
// Enable notifications
m_wifiService->writeDescriptor(m_wifiService->characteristic(wifiResponseCharacteristicUuid).descriptor(QBluetoothUuid::ClientCharacteristicConfiguration), QByteArray::fromHex("0100"));
m_wifiService->writeDescriptor(m_wifiService->characteristic(wifiStatusCharacteristicUuid).descriptor(QBluetoothUuid::ClientCharacteristicConfiguration), QByteArray::fromHex("0100"));
setWirelessStatus(m_wifiService->characteristic(wifiStatusCharacteristicUuid).value().toHex().toUInt(0, 16));
checkInitialized();
}
void WirelessSetupManager::onWifiServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
Q_UNUSED(characteristic)
// Check if currently reading
if (m_readingResponse) {
m_inputDataStream.append(value);
} else {
m_inputDataStream.clear();
m_readingResponse = true;
m_inputDataStream.append(value);
}
// If command finished
if (value.endsWith('\n')) {
QJsonParseError error;
QJsonDocument jsonDocument = QJsonDocument::fromJson(m_inputDataStream, &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "Got invalid json object" << m_inputDataStream;
m_inputDataStream.clear();
m_readingResponse = false;
return;
}
qDebug() << "Got command stream" << qUtf8Printable(jsonDocument.toJson());
processWifiResponse(jsonDocument.toVariant().toMap());
m_inputDataStream.clear();
m_readingResponse = false;
}
}
void WirelessSetupManager::onWifiServiceReadFinished(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
Q_UNUSED(characteristic)
Q_UNUSED(value)
}
void WirelessSetupManager::onSystemServiceStateChanged(const QLowEnergyService::ServiceState &state)
{
if (state != QLowEnergyService::ServiceDiscovered)
return;
qDebug() << "WifiSetupManager: System service discovered.";
foreach (const QLowEnergyCharacteristic &characteristic, m_systemService->characteristics()) {
qDebug() << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
foreach (const QLowEnergyDescriptor &descriptor, characteristic.descriptors()) {
qDebug() << " -->" << descriptor.name() << descriptor.uuid().toString() << descriptor.value();
}
}
// Enable notifications
m_systemService->writeDescriptor(m_systemService->characteristic(systemResponseCharacteristicUuid).descriptor(QBluetoothUuid::ClientCharacteristicConfiguration), QByteArray::fromHex("0100"));
checkInitialized();
}
void WirelessSetupManager::onSystemServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
Q_UNUSED(characteristic)
// Check if currently reading
if (m_readingResponse) {
m_inputDataStream.append(value);
} else {
m_inputDataStream.clear();
m_readingResponse = true;
m_inputDataStream.append(value);
}
// If command finished
if (value.endsWith('\n')) {
QJsonParseError error;
QJsonDocument jsonDocument = QJsonDocument::fromJson(m_inputDataStream, &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "Got invalid json object" << m_inputDataStream;
m_inputDataStream.clear();
m_readingResponse = false;
return;
}
qDebug() << "Got command stream" << qUtf8Printable(jsonDocument.toJson());
processSystemResponse(jsonDocument.toVariant().toMap());
m_inputDataStream.clear();
m_readingResponse = false;
}
}
void WirelessSetupManager::onSystemServiceReadFinished(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
Q_UNUSED(characteristic)
Q_UNUSED(value)
}

View File

@ -0,0 +1,233 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Simon Stuerz <simon.stuerz@guh.io> *
* *
* This file is part of mea *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef WIRELESSSETUPMANAGER_H
#define WIRELESSSETUPMANAGER_H
#include <QObject>
#include <QBluetoothDeviceInfo>
#include "bluetoothdevice.h"
#include "wirelessaccesspoints.h"
class WirelessSetupManager : public BluetoothDevice
{
Q_OBJECT
Q_PROPERTY(bool working READ working NOTIFY workingChanged)
Q_PROPERTY(bool initializing READ initializing NOTIFY initializingChanged)
Q_PROPERTY(bool initialized READ initialized NOTIFY initializedChanged)
Q_PROPERTY(WirelessAccesspoints *accessPoints READ accessPoints CONSTANT)
Q_PROPERTY(QString modelNumber READ modelNumber NOTIFY modelNumberChanged)
Q_PROPERTY(QString manufacturer READ manufacturer NOTIFY manufacturerChanged)
Q_PROPERTY(QString softwareRevision READ softwareRevision NOTIFY softwareRevisionChanged)
Q_PROPERTY(QString firmwareRevision READ firmwareRevision NOTIFY firmwareRevisionChanged)
Q_PROPERTY(QString hardwareRevision READ hardwareRevision NOTIFY hardwareRevisionChanged)
Q_PROPERTY(QString networkStatus READ networkStatus NOTIFY networkStatusChanged)
Q_PROPERTY(QString wirelessStatus READ wirelessStatus NOTIFY wirelessStatusChanged)
Q_PROPERTY(bool networkingEnabled READ networkingEnabled NOTIFY networkingEnabledChanged)
Q_PROPERTY(bool wirelessEnabled READ wirelessEnabled NOTIFY wirelessEnabledChanged)
public:
enum WirelessServiceCommand {
WirelessServiceCommandInvalid = -1,
WirelessServiceCommandGetNetworks = 0x00,
WirelessServiceCommandConnect = 0x01,
WirelessServiceCommandConnectHidden = 0x02,
WirelessServiceCommandDisconnect = 0x03,
WirelessServiceCommandScan = 0x04,
WirelessServiceCommandGetCurrentConnection = 0x05
};
Q_ENUM(WirelessServiceCommand)
enum WirelessServiceResponse {
WirelessServiceResponseSuccess = 0x00,
WirelessServiceResponseIvalidCommand = 0x01,
WirelessServiceResponseIvalidParameters = 0x02,
WirelessServiceResponseNetworkManagerNotAvailable = 0x03,
WirelessServiceResponseWirelessNotAvailable = 0x04,
WirelessServiceResponseWirelessNotEnabled = 0x05,
WirelessServiceResponseNetworkingNotEnabled = 0x06,
WirelessServiceResponseUnknownError = 0x07
};
Q_ENUM(WirelessServiceResponse)
enum NetworkServiceCommand {
NetworkServiceCommandInvalid = -1,
NetworkServiceCommandEnableNetworking = 0x00,
NetworkServiceCommandDisableNetworking = 0x01,
NetworkServiceCommandEnableWireless = 0x02,
NetworkServiceCommandDisableWireless = 0x03
};
Q_ENUM(NetworkServiceCommand)
enum NetworkServiceResponse {
NetworkServiceResponseSuccess = 0x00,
NetworkServiceResponseIvalidValue = 0x01,
NetworkServiceResponseNetworkManagerNotAvailable = 0x02,
NetworkServiceResponseWirelessNotAvailable = 0x03,
NetworkServiceResponseUnknownError = 0x04,
};
Q_ENUM(NetworkServiceResponse)
enum SystemServiceCommand {
SystemServiceCommandInvalid = -1,
SystemServiceCommandPushAuthentication = 0x00
};
Q_ENUM(SystemServiceCommand)
enum SystemServiceResponse {
SystemServiceResponseSuccess = 0x00,
SystemServiceResponseUnknownError = 0x01,
SystemServiceResponseInvalidCommand = 0x02,
SystemServiceResponseInvalidValue = 0x03,
SystemServiceResponsePushServiceUnavailable = 0x04,
};
Q_ENUM(SystemServiceResponse)
explicit WirelessSetupManager(const QBluetoothDeviceInfo &deviceInfo, QObject *parent = nullptr);
QString modelNumber() const;
QString manufacturer() const;
QString softwareRevision() const;
QString firmwareRevision() const;
QString hardwareRevision() const;
bool initialized() const;
bool initializing() const;
bool working() const;
QString networkStatus() const;
QString wirelessStatus() const;
bool networkingEnabled() const;
bool wirelessEnabled() const;
WirelessAccesspoints *accessPoints();
// Wireless commands
Q_INVOKABLE void loadNetworks();
Q_INVOKABLE void loadCurrentConnection();
Q_INVOKABLE void performWifiScan();
Q_INVOKABLE void enableNetworking(bool enable);
Q_INVOKABLE void enableWireless(bool enable);
Q_INVOKABLE void connectWirelessNetwork(const QString &ssid, const QString &password = QString());
Q_INVOKABLE void disconnectWirelessNetwork();
Q_INVOKABLE void pressPushButton();
private:
QLowEnergyService *m_deviceInformationService = nullptr;
QLowEnergyService *m_netwokService = nullptr;
QLowEnergyService *m_wifiService = nullptr;
QLowEnergyService *m_systemService = nullptr;
WirelessAccesspoints *m_accessPoints = nullptr;
QString m_modelNumber;
QString m_manufacturer;
QString m_softwareRevision;
QString m_firmwareRevision;
QString m_hardwareRevision;
bool m_networkingEnabled = false;
bool m_wirelessEnabled = false;
bool m_working = false;
bool m_initialized = false;
bool m_initializing = false;
QString m_networkStatus;
QString m_wirelessStatus;
bool m_readingResponse;
QByteArray m_inputDataStream;
QString m_ssid;
QString m_password;
void checkInitialized();
// Private set methods for read only properties
void setModelNumber(const QString &modelNumber);
void setManufacturer(const QString &manufacturer);
void setSoftwareRevision(const QString &softwareRevision);
void setFirmwareRevision(const QString &firmwareRevision);
void setHardwareRevision(const QString &hardwareRevision);
void setInitializing(bool initializing);
void setInitialized(bool initialized);
void setWorking(bool working);
void setNetworkStatus(int networkStatus);
void setWirelessStatus(int wirelessStatus);
void setNetworkingEnabled(bool networkingEnabled);
void setWirelessEnabled(bool wirelessEnabled);
// Data methods
void streamData(const QVariantMap &request);
void processNetworkResponse(const QVariantMap &response);
void processWifiResponse(const QVariantMap &response);
void processSystemResponse(const QVariantMap &response);
signals:
void modelNumberChanged();
void manufacturerChanged();
void softwareRevisionChanged();
void firmwareRevisionChanged();
void hardwareRevisionChanged();
void initializingChanged();
void initializedChanged();
void workingChanged();
void networkStatusChanged();
void wirelessStatusChanged();
void networkingEnabledChanged();
void wirelessEnabledChanged();
private slots:
void onConnectedChanged();
void onServiceDiscoveryFinished();
void onDeviceInformationStateChanged(const QLowEnergyService::ServiceState &state);
void onDeviceInformationCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
void onDeviceInformationReadFinished(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
void onNetworkServiceStateChanged(const QLowEnergyService::ServiceState &state);
void onNetworkServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
void onNetworkServiceReadFinished(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
void onWifiServiceStateChanged(const QLowEnergyService::ServiceState &state);
void onWifiServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
void onWifiServiceReadFinished(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
void onSystemServiceStateChanged(const QLowEnergyService::ServiceState &state);
void onSystemServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
void onSystemServiceReadFinished(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
};
#endif // WIRELESSSETUPMANAGER_H

1501
translations/mea-en_US.ts Normal file

File diff suppressed because it is too large Load Diff