Finishing touches
This commit is contained in:
parent
3c41a7090b
commit
82454fc554
@ -79,6 +79,8 @@ QVariant LogsModel::data(const QModelIndex &index, int role) const
|
||||
return m_list.at(index.row())->source();
|
||||
case RoleLoggingEventType:
|
||||
return m_list.at(index.row())->loggingEventType();
|
||||
case RoleErrorCode:
|
||||
return m_list.at(index.row())->errorCode();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
@ -93,6 +95,7 @@ QHash<int, QByteArray> LogsModel::roleNames() const
|
||||
roles.insert(RoleTypeId, "typeId");
|
||||
roles.insert(RoleSource, "source");
|
||||
roles.insert(RoleLoggingEventType, "loggingEventType");
|
||||
roles.insert(RoleErrorCode, "errorCode");
|
||||
return roles;
|
||||
}
|
||||
|
||||
@ -229,7 +232,8 @@ void LogsModel::logsReply(int /*commandId*/, const QVariantMap &data)
|
||||
QMetaEnum loggingEventTypeEnum = QMetaEnum::fromType<LogEntry::LoggingEventType>();
|
||||
LogEntry::LoggingEventType loggingEventType = static_cast<LogEntry::LoggingEventType>(loggingEventTypeEnum.keyToValue(entryMap.value("eventType").toByteArray()));
|
||||
QVariant value = loggingEventType == LogEntry::LoggingEventTypeActiveChange ? entryMap.value("active").toBool() : entryMap.value("value");
|
||||
LogEntry *entry = new LogEntry(timeStamp, value, thingId, typeId, loggingSource, loggingEventType, this);
|
||||
QString errorCode = entryMap.value("errorCode").toString();
|
||||
LogEntry *entry = new LogEntry(timeStamp, value, thingId, typeId, loggingSource, loggingEventType, errorCode, this);
|
||||
newBlock.append(entry);
|
||||
}
|
||||
|
||||
@ -371,7 +375,7 @@ void LogsModel::newLogEntryReceived(const QVariantMap &data)
|
||||
QMetaEnum loggingEventTypeEnum = QMetaEnum::fromType<LogEntry::LoggingEventType>();
|
||||
LogEntry::LoggingEventType loggingEventType = static_cast<LogEntry::LoggingEventType>(loggingEventTypeEnum.keyToValue(entryMap.value("eventType").toByteArray()));
|
||||
QVariant value = loggingEventType == LogEntry::LoggingEventTypeActiveChange ? entryMap.value("active").toBool() : entryMap.value("value");
|
||||
LogEntry *entry = new LogEntry(timeStamp, value, thingId, typeId, loggingSource, loggingEventType, this);
|
||||
LogEntry *entry = new LogEntry(timeStamp, value, thingId, typeId, loggingSource, loggingEventType, entryMap.value("errorCode").toString(), this);
|
||||
m_list.prepend(entry);
|
||||
endInsertRows();
|
||||
emit countChanged();
|
||||
|
||||
@ -61,7 +61,8 @@ public:
|
||||
RoleDeviceId, // < JSONRPC 5.0
|
||||
RoleTypeId,
|
||||
RoleSource,
|
||||
RoleLoggingEventType
|
||||
RoleLoggingEventType,
|
||||
RoleErrorCode
|
||||
};
|
||||
explicit LogsModel(QObject *parent = nullptr);
|
||||
|
||||
|
||||
@ -261,7 +261,7 @@ void LogsModelNg::logsReply(int commandId, const QVariantMap &data)
|
||||
QMetaEnum loggingEventTypeEnum = QMetaEnum::fromType<LogEntry::LoggingEventType>();
|
||||
LogEntry::LoggingEventType loggingEventType = static_cast<LogEntry::LoggingEventType>(loggingEventTypeEnum.keyToValue(entryMap.value("eventType").toByteArray()));
|
||||
QVariant value = loggingEventType == LogEntry::LoggingEventTypeActiveChange ? entryMap.value("active").toBool() : entryMap.value("value");
|
||||
LogEntry *entry = new LogEntry(timeStamp, value, thingId, typeId, loggingSource, loggingEventType, this);
|
||||
LogEntry *entry = new LogEntry(timeStamp, value, thingId, typeId, loggingSource, loggingEventType, entryMap.value("errorCode").toString(), this);
|
||||
newBlock.append(entry);
|
||||
}
|
||||
|
||||
@ -461,7 +461,7 @@ void LogsModelNg::newLogEntryReceived(const QVariantMap &data)
|
||||
QMetaEnum loggingEventTypeEnum = QMetaEnum::fromType<LogEntry::LoggingEventType>();
|
||||
LogEntry::LoggingEventType loggingEventType = static_cast<LogEntry::LoggingEventType>(loggingEventTypeEnum.keyToValue(entryMap.value("eventType").toByteArray()));
|
||||
QVariant value = loggingEventType == LogEntry::LoggingEventTypeActiveChange ? entryMap.value("active").toBool() : entryMap.value("value");
|
||||
LogEntry *entry = new LogEntry(timeStamp, value, thingId, typeId, loggingSource, loggingEventType, this);
|
||||
LogEntry *entry = new LogEntry(timeStamp, value, thingId, typeId, loggingSource, loggingEventType, entryMap.value("errorCode").toString(), this);
|
||||
m_list.prepend(entry);
|
||||
if (m_graphSeries) {
|
||||
|
||||
|
||||
@ -167,12 +167,26 @@ State *Device::stateByName(const QString &stateName) const
|
||||
return m_states->getState(st->id());
|
||||
}
|
||||
|
||||
Param *Device::param(const QUuid ¶mTypeId) const
|
||||
{
|
||||
return m_params->getParam(paramTypeId);
|
||||
}
|
||||
|
||||
Param *Device::paramByName(const QString ¶mName) const
|
||||
{
|
||||
ParamType *paramType = m_thingClass->paramTypes()->findByName(paramName);
|
||||
if (!paramType) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_params->getParam(paramType->id());
|
||||
}
|
||||
|
||||
DeviceClass *Device::thingClass() const
|
||||
{
|
||||
return m_thingClass;
|
||||
}
|
||||
|
||||
bool Device::hasState(const QUuid &stateTypeId)
|
||||
bool Device::hasState(const QUuid &stateTypeId) const
|
||||
{
|
||||
foreach (State *state, states()->states()) {
|
||||
if (state->stateTypeId() == stateTypeId) {
|
||||
@ -182,7 +196,7 @@ bool Device::hasState(const QUuid &stateTypeId)
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant Device::stateValue(const QUuid &stateTypeId)
|
||||
QVariant Device::stateValue(const QUuid &stateTypeId) const
|
||||
{
|
||||
foreach (State *state, states()->states()) {
|
||||
if (state->stateTypeId() == stateTypeId) {
|
||||
|
||||
@ -92,15 +92,17 @@ public:
|
||||
|
||||
States *states() const;
|
||||
void setStates(States *states);
|
||||
void setStateValue(const QUuid &stateTypeId, const QVariant &value);
|
||||
|
||||
DeviceClass *thingClass() const;
|
||||
|
||||
Q_INVOKABLE bool hasState(const QUuid &stateTypeId);
|
||||
Q_INVOKABLE bool hasState(const QUuid &stateTypeId) const;
|
||||
Q_INVOKABLE State *state(const QUuid &stateTypeId) const;
|
||||
Q_INVOKABLE State *stateByName(const QString &stateName) const;
|
||||
Q_INVOKABLE QVariant stateValue(const QUuid &stateTypeId) const;
|
||||
|
||||
Q_INVOKABLE QVariant stateValue(const QUuid &stateTypeId);
|
||||
void setStateValue(const QUuid &stateTypeId, const QVariant &value);
|
||||
Q_INVOKABLE Param *param(const QUuid ¶mTypeId) const;
|
||||
Q_INVOKABLE Param *paramByName(const QString ¶mName) const;
|
||||
|
||||
Q_INVOKABLE virtual int executeAction(const QString &actionName, const QVariantList ¶ms);
|
||||
|
||||
@ -112,8 +114,6 @@ signals:
|
||||
void statesChanged();
|
||||
void eventTriggered(const QUuid &eventTypeId, const QVariantMap ¶ms);
|
||||
|
||||
private:
|
||||
|
||||
protected:
|
||||
DeviceManager *m_thingManager = nullptr;
|
||||
QString m_name;
|
||||
|
||||
@ -32,14 +32,15 @@
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
LogEntry::LogEntry(const QDateTime ×tamp, const QVariant &value, const QUuid &thingId, const QUuid &typeId, LoggingSource source, LoggingEventType loggingEventType, QObject *parent):
|
||||
LogEntry::LogEntry(const QDateTime ×tamp, const QVariant &value, const QUuid &thingId, const QUuid &typeId, LoggingSource source, LoggingEventType loggingEventType, const QString &errorCode, QObject *parent):
|
||||
QObject(parent),
|
||||
m_value(value),
|
||||
m_timeStamp(timestamp),
|
||||
m_thingId(thingId),
|
||||
m_typeId(typeId),
|
||||
m_source(source),
|
||||
m_loggingEventType(loggingEventType)
|
||||
m_loggingEventType(loggingEventType),
|
||||
m_errorCode(errorCode)
|
||||
{
|
||||
|
||||
}
|
||||
@ -104,3 +105,8 @@ QString LogEntry::dateString() const
|
||||
{
|
||||
return m_timeStamp.date().toString("dd.MM.");
|
||||
}
|
||||
|
||||
QString LogEntry::errorCode() const
|
||||
{
|
||||
return m_errorCode;
|
||||
}
|
||||
|
||||
@ -50,6 +50,7 @@ class LogEntry : public QObject
|
||||
Q_PROPERTY(QString timeString READ timeString CONSTANT)
|
||||
Q_PROPERTY(QString dayString READ dayString CONSTANT)
|
||||
Q_PROPERTY(QString dateString READ dateString CONSTANT)
|
||||
Q_PROPERTY(QString errorCode READ errorCode CONSTANT)
|
||||
|
||||
public:
|
||||
enum LoggingSource {
|
||||
@ -71,7 +72,7 @@ public:
|
||||
};
|
||||
Q_ENUM(LoggingEventType)
|
||||
|
||||
explicit LogEntry(const QDateTime ×tamp, const QVariant &value, const QUuid &thingId = QUuid(), const QUuid &typeId = QUuid(), LoggingSource source = LoggingSourceSystem, LoggingEventType loggingEventType = LoggingEventTypeTrigger, QObject *parent = nullptr);
|
||||
explicit LogEntry(const QDateTime ×tamp, const QVariant &value, const QUuid &thingId = QUuid(), const QUuid &typeId = QUuid(), LoggingSource source = LoggingSourceSystem, LoggingEventType loggingEventType = LoggingEventTypeTrigger, const QString &errorCode = QString(), QObject *parent = nullptr);
|
||||
|
||||
QVariant value() const;
|
||||
QDateTime timestamp() const;
|
||||
@ -83,6 +84,7 @@ public:
|
||||
QString timeString() const;
|
||||
QString dayString() const;
|
||||
QString dateString() const;
|
||||
QString errorCode() const;
|
||||
|
||||
private:
|
||||
QVariant m_value;
|
||||
@ -91,6 +93,7 @@ private:
|
||||
QUuid m_typeId;
|
||||
LoggingSource m_source;
|
||||
LoggingEventType m_loggingEventType;
|
||||
QString m_errorCode;
|
||||
};
|
||||
|
||||
#endif // LOGENTRY_H
|
||||
|
||||
@ -56,10 +56,10 @@ Param *Params::get(int index) const
|
||||
return m_params.at(index);
|
||||
}
|
||||
|
||||
Param *Params::getParam(QString paramTypeId) const
|
||||
Param *Params::getParam(const QUuid ¶mTypeId) const
|
||||
{
|
||||
foreach (Param *param, m_params) {
|
||||
if (QUuid(param->paramTypeId()) == QUuid(paramTypeId)) {
|
||||
if (param->paramTypeId() == paramTypeId) {
|
||||
return param;
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ public:
|
||||
|
||||
Q_INVOKABLE int count() const;
|
||||
Q_INVOKABLE Param *get(int index) const;
|
||||
Q_INVOKABLE Param *getParam(QString paramTypeId) const;
|
||||
Q_INVOKABLE Param *getParam(const QUuid ¶mTypeId) const;
|
||||
|
||||
Q_INVOKABLE int paramCount() const;
|
||||
|
||||
|
||||
@ -37,16 +37,6 @@
|
||||
#include <QCommandLineParser>
|
||||
#include <QCommandLineOption>
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include <QtAndroidExtras/QtAndroid>
|
||||
#include "platformintegration/android/platformhelperandroid.h"
|
||||
#elif defined(Q_OS_IOS)
|
||||
#include "platformintegration/ios/platformhelperios.h"
|
||||
#elif defined UBPORTS
|
||||
#include "platformintegration/ubports/platformhelperubports.h"
|
||||
#else
|
||||
#include "platformintegration/generic/platformhelpergeneric.h"
|
||||
#endif
|
||||
|
||||
#include "libnymea-app-core.h"
|
||||
|
||||
@ -56,21 +46,8 @@
|
||||
#include "ruletemplates/messages.h"
|
||||
#include "nfchelper.h"
|
||||
#include "nfcthingactionwriter.h"
|
||||
#include "platformhelper.h"
|
||||
|
||||
QObject *platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
|
||||
{
|
||||
Q_UNUSED(engine)
|
||||
Q_UNUSED(scriptEngine)
|
||||
#ifdef Q_OS_ANDROID
|
||||
return new PlatformHelperAndroid();
|
||||
#elif defined(Q_OS_IOS)
|
||||
return new PlatformHelperIOS();
|
||||
#elif defined UBPORTS
|
||||
return new PlatformHelperUBPorts();
|
||||
#else
|
||||
return new PlatformHelperGeneric();
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@ -159,7 +136,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
engine->rootContext()->setContextProperty("styleController", &styleController);
|
||||
|
||||
qmlRegisterSingletonType<PlatformHelper>("Nymea", 1, 0, "PlatformHelper", platformHelperProvider);
|
||||
qmlRegisterSingletonType<PlatformHelper>("Nymea", 1, 0, "PlatformHelper", PlatformHelper::platformHelperProvider);
|
||||
qmlRegisterSingletonType<NfcHelper>("Nymea", 1, 0, "NfcHelper", NfcHelper::nfcHelperProvider);
|
||||
qmlRegisterType<NfcThingActionWriter>("Nymea", 1, 0, "NfcThingActionWriter");
|
||||
|
||||
|
||||
@ -33,11 +33,40 @@
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
|
||||
#if defined Q_OS_ANDROID
|
||||
#include <QtAndroidExtras/QtAndroid>
|
||||
#include "platformintegration/android/platformhelperandroid.h"
|
||||
#elif defined Q_OS_IOS
|
||||
#include "platformintegration/ios/platformhelperios.h"
|
||||
#elif defined UBPORTS
|
||||
#include "platformintegration/ubports/platformhelperubports.h"
|
||||
#else
|
||||
#include "platformintegration/generic/platformhelpergeneric.h"
|
||||
#endif
|
||||
|
||||
PlatformHelper* PlatformHelper::s_instance = nullptr;
|
||||
|
||||
PlatformHelper::PlatformHelper(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PlatformHelper *PlatformHelper::instance()
|
||||
{
|
||||
if (!s_instance) {
|
||||
#ifdef Q_OS_ANDROID
|
||||
s_instance = new PlatformHelperAndroid();
|
||||
#elif defined(Q_OS_IOS)
|
||||
s_instance = new PlatformHelperIOS();
|
||||
#elif defined UBPORTS
|
||||
s_instance = new PlatformHelperUBPorts();
|
||||
#else
|
||||
s_instance = new PlatformHelperGeneric();
|
||||
#endif
|
||||
}
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
bool PlatformHelper::hasPermissions() const
|
||||
{
|
||||
return true;
|
||||
@ -153,3 +182,10 @@ QString PlatformHelper::fromClipBoard()
|
||||
{
|
||||
return QApplication::clipboard()->text();
|
||||
}
|
||||
|
||||
QObject *PlatformHelper::platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
|
||||
{
|
||||
Q_UNUSED(engine)
|
||||
Q_UNUSED(scriptEngine)
|
||||
return instance();
|
||||
}
|
||||
|
||||
@ -34,6 +34,9 @@
|
||||
#include <QObject>
|
||||
#include <QColor>
|
||||
|
||||
class QQmlEngine;
|
||||
class QJSEngine;
|
||||
|
||||
class PlatformHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -58,7 +61,7 @@ public:
|
||||
};
|
||||
Q_ENUM(HapticsFeedback)
|
||||
|
||||
explicit PlatformHelper(QObject *parent = nullptr);
|
||||
static PlatformHelper* instance();
|
||||
virtual ~PlatformHelper() = default;
|
||||
|
||||
virtual bool hasPermissions() const;
|
||||
@ -88,6 +91,7 @@ public:
|
||||
Q_INVOKABLE virtual void toClipBoard(const QString &text);
|
||||
Q_INVOKABLE virtual QString fromClipBoard();
|
||||
|
||||
static QObject *platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine);
|
||||
signals:
|
||||
void permissionsRequestFinished();
|
||||
void screenTimeoutChanged();
|
||||
@ -95,7 +99,12 @@ signals:
|
||||
void topPanelColorChanged();
|
||||
void bottomPanelColorChanged();
|
||||
|
||||
protected:
|
||||
explicit PlatformHelper(QObject *parent = nullptr);
|
||||
|
||||
private:
|
||||
static PlatformHelper *s_instance;
|
||||
|
||||
QColor m_topPanelColor = QColor("black");
|
||||
QColor m_bottomPanelColor = QColor("black");
|
||||
};
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
#include "platformhelperubports.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QUuid>
|
||||
|
||||
PlatformHelperUBPorts::PlatformHelperUBPorts(QObject *parent) : PlatformHelper(parent)
|
||||
{
|
||||
|
||||
@ -9,3 +12,9 @@ QString PlatformHelperUBPorts::platform() const
|
||||
{
|
||||
return "ubports";
|
||||
}
|
||||
|
||||
QString PlatformHelperUBPorts::deviceSerial() const
|
||||
{
|
||||
QSettings s;
|
||||
return s.value("deviceSerial", QUuid::createUuid()).toString();
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ public:
|
||||
explicit PlatformHelperUBPorts(QObject *parent = nullptr);
|
||||
|
||||
QString platform() const override;
|
||||
QString deviceSerial() const override;
|
||||
|
||||
signals:
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "pushnotifications.h"
|
||||
#include "platformhelper.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
@ -87,6 +88,27 @@ PushNotifications *PushNotifications::instance()
|
||||
return pushNotifications;
|
||||
}
|
||||
|
||||
QString PushNotifications::service() const
|
||||
{
|
||||
#if defined Q_OS_ANDROID
|
||||
return "FB-GCM";
|
||||
#elif defined Q_OS_IOS
|
||||
return "FB-APNs";
|
||||
#elif defined UBPORTS
|
||||
return "ubports";
|
||||
#endif
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString PushNotifications::clientId() const
|
||||
{
|
||||
QString branding;
|
||||
#if defined BRANDING
|
||||
branding = "-" + BRANDING;
|
||||
#endif
|
||||
return PlatformHelper::instance()->deviceSerial() + "+io.guh.nymeaapp" + branding;
|
||||
}
|
||||
|
||||
QString PushNotifications::token() const
|
||||
{
|
||||
return m_token;
|
||||
|
||||
@ -51,6 +51,8 @@ class PushNotifications : public QObject
|
||||
#endif
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString service READ service CONSTANT)
|
||||
Q_PROPERTY(QString clientId READ clientId CONSTANT)
|
||||
Q_PROPERTY(QString token READ token NOTIFY tokenChanged)
|
||||
|
||||
public:
|
||||
@ -60,6 +62,8 @@ public:
|
||||
static QObject* pushNotificationsProvider(QQmlEngine *engine, QJSEngine *scriptEngine);
|
||||
static PushNotifications* instance();
|
||||
|
||||
QString service() const;
|
||||
QString clientId() const;
|
||||
QString token() const;
|
||||
|
||||
// Called by Objective-C++
|
||||
|
||||
@ -232,5 +232,6 @@
|
||||
<file>ui/StyleBase.qml</file>
|
||||
<file>ui/customviews/ThermostatController.qml</file>
|
||||
<file>ui/devicepages/ThermostatDevicePage.qml</file>
|
||||
<file>ui/components/BigThingTile.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@ -32,8 +32,8 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Notify me when something runs dry",
|
||||
"ruleNameTemplate": "Notify %1 when %0 runs dry",
|
||||
"description": "Notify me when something dries ou",
|
||||
"ruleNameTemplate": "Notify %1 when %0 dries out",
|
||||
"stateEvaluatorTemplate": {
|
||||
"stateDescriptorTemplate": {
|
||||
"interfaceName": "moisturesensor",
|
||||
|
||||
@ -262,6 +262,7 @@ Item {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Old nymea:cloud based push notifications...
|
||||
function setupPushNotifications(askForPermissions) {
|
||||
if (askForPermissions === undefined) {
|
||||
askForPermissions = true;
|
||||
@ -296,6 +297,46 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// New, nymea thing based push notifactions
|
||||
function updatePushNotificationThings() {
|
||||
if (PushNotifications.service == "") {
|
||||
print("This platform does not support push notifications")
|
||||
return;
|
||||
}
|
||||
if (!PushNotifications.token) {
|
||||
print("No push notification token available at this time. Not updating...");
|
||||
return;
|
||||
}
|
||||
|
||||
print("Updating push notifications")
|
||||
print("Own push service:", PushNotifications.service);
|
||||
print("Own client ID:", PushNotifications.clientId);
|
||||
print("Current token:", PushNotifications.token);
|
||||
|
||||
for (var i = 0; i < engine.thingManager.things.count; i++) {
|
||||
var thing = engine.thingManager.things.get(i);
|
||||
if (thing.thingClass.id.toString().match(/\{?f0dd4c03-0aca-42cc-8f34-9902457b05de\}?/)) {
|
||||
var serviceParam = thing.paramByName("service");
|
||||
var clientIdParam = thing.paramByName("clientId")
|
||||
var tokenParam = thing.paramByName("token")
|
||||
print("Found a push notification thing for client id:", clientIdParam.value)
|
||||
if (clientIdParam.value === PushNotifications.clientId) {
|
||||
if (tokenParam.value !== PushNotifications.token) {
|
||||
var params = [
|
||||
{ "paramTypeId": serviceParam.paramTypeId, "value": PushNotifications.service },
|
||||
{ "paramTypeId": clientIdParam.paramTypeId, "value": PushNotifications.clientId },
|
||||
{ "paramTypeId": tokenParam.paramTypeId, "value": PushNotifications.token }
|
||||
];
|
||||
print("Reconfiguring PushNotifications for", thing.name)
|
||||
engine.thingManager.reconfigureDevice(thing.id, params);
|
||||
} else {
|
||||
print("Push notifications don't need to be updated. Token is valid.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: engine.jsonRpcClient
|
||||
onCurrentHostChanged: {
|
||||
@ -370,13 +411,22 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: engine.thingManager
|
||||
onFetchingDataChanged: {
|
||||
if (!engine.thingManager.fetchingData) {
|
||||
updatePushNotificationThings()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: invalidVersionComponent
|
||||
Popup {
|
||||
id: popup
|
||||
|
||||
property string actualVersion: "0.0"
|
||||
property string minimumVersion: "1.0"
|
||||
property string minimumVersion: "1.10"
|
||||
|
||||
width: app.width * .8
|
||||
height: col.childrenRect.height + app.margins * 2
|
||||
|
||||
36
nymea-app/ui/components/BigThingTile.qml
Normal file
36
nymea-app/ui/components/BigThingTile.qml
Normal file
@ -0,0 +1,36 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.1
|
||||
import Nymea 1.0
|
||||
|
||||
BigTile {
|
||||
id: root
|
||||
|
||||
property Thing thing: null
|
||||
|
||||
readonly property State connectedState: thing.stateByName("connected")
|
||||
readonly property bool isConnected: connectedState === null || connectedState.value === true
|
||||
readonly property bool isEnabled: thing.setupStatus == Thing.ThingSetupStatusComplete && isConnected
|
||||
|
||||
onPressAndHold: {
|
||||
var contextMenuComponent = Qt.createComponent("../components/ThingContextMenu.qml");
|
||||
var contextMenu = contextMenuComponent.createObject(root, { thing: root.thing })
|
||||
contextMenu.x = Qt.binding(function() { return (root.width - contextMenu.width) / 2 })
|
||||
contextMenu.open()
|
||||
}
|
||||
|
||||
header: RowLayout {
|
||||
id: headerRow
|
||||
visible: root.showHeader
|
||||
width: parent.width
|
||||
Layout.margins: app.margins / 2
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: root.thing.name
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
ThingStatusIcons {
|
||||
thing: root.thing
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,25 +4,20 @@ import QtQuick.Controls 2.1
|
||||
import QtQuick.Controls.Material 2.1
|
||||
import Nymea 1.0
|
||||
|
||||
Item {
|
||||
Item {
|
||||
id: root
|
||||
implicitHeight: layout.implicitHeight + app.margins
|
||||
|
||||
property Thing thing: null
|
||||
|
||||
property bool showHeader: true
|
||||
|
||||
property alias header: headerContainer.children
|
||||
property alias contentItem: content.contentItem
|
||||
|
||||
property alias showHeader: headerContainer.visible
|
||||
|
||||
property alias leftPadding: content.leftPadding
|
||||
property alias rightPadding: content.rightPadding
|
||||
property alias topPadding: content.topPadding
|
||||
property alias bottomPadding: content.bottomPadding
|
||||
|
||||
readonly property State connectedState: thing.stateByName("connected")
|
||||
readonly property bool isConnected: connectedState === null || connectedState.value === true
|
||||
readonly property bool isEnabled: thing.setupStatus == Thing.ThingSetupStatusComplete && isConnected
|
||||
|
||||
signal clicked();
|
||||
signal pressAndHold();
|
||||
|
||||
@ -73,12 +68,12 @@ import Nymea 1.0
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: (headerRow.height + app.margins) / background.height
|
||||
position: (headerContainer.height + app.margins) / background.height
|
||||
color: Style.tileBackgroundColor
|
||||
}
|
||||
GradientStop {
|
||||
position: (headerRow.height + app.margins) / background.height
|
||||
color:root.showHeader ?
|
||||
position: (headerContainer.height + app.margins) / background.height
|
||||
color: headerContainer.visible ?
|
||||
Style.tileOverlayColor
|
||||
: Style.tileBackgroundColor
|
||||
}
|
||||
@ -90,20 +85,12 @@ import Nymea 1.0
|
||||
spacing: 0
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right; margins: app.margins / 2 }
|
||||
|
||||
RowLayout {
|
||||
id: headerRow
|
||||
visible: root.showHeader
|
||||
Item {
|
||||
id: headerContainer
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins / 2
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: root.thing.name
|
||||
elide: Text.ElideRight
|
||||
color: Style.tileOverlayForegroundColor
|
||||
}
|
||||
ThingStatusIcons {
|
||||
thing: root.thing
|
||||
// color: Style.tileOverlayForegroundColor
|
||||
}
|
||||
visible: children.length > 0
|
||||
height: childrenRect.height
|
||||
}
|
||||
|
||||
ItemDelegate {
|
||||
|
||||
@ -98,7 +98,7 @@ DeviceListPageBase {
|
||||
Repeater {
|
||||
model: root.thingsProxy
|
||||
|
||||
delegate: BigTile {
|
||||
delegate: BigThingTile {
|
||||
id: itemDelegate
|
||||
Layout.preferredWidth: contentGrid.width / contentGrid.columns
|
||||
thing: root.thingsProxy.getThing(model.id)
|
||||
|
||||
@ -62,7 +62,7 @@ DeviceListPageBase {
|
||||
Repeater {
|
||||
model: root.thingsProxy
|
||||
|
||||
delegate: BigTile {
|
||||
delegate: BigThingTile {
|
||||
id: itemDelegate
|
||||
Layout.preferredWidth: contentGrid.width / contentGrid.columns
|
||||
thing: root.thingsProxy.getThing(model.id)
|
||||
|
||||
@ -68,7 +68,7 @@ DeviceListPageBase {
|
||||
Repeater {
|
||||
model: root.thingsProxy
|
||||
|
||||
delegate: BigTile {
|
||||
delegate: BigThingTile {
|
||||
id: itemDelegate
|
||||
Layout.preferredWidth: contentGrid.width / contentGrid.columns
|
||||
thing: root.thingsProxy.getThing(model.id)
|
||||
|
||||
@ -87,7 +87,7 @@ DeviceListPageBase {
|
||||
Repeater {
|
||||
model: root.thingsProxy
|
||||
|
||||
delegate: BigTile {
|
||||
delegate: BigThingTile {
|
||||
id: itemDelegate
|
||||
Layout.preferredWidth: contentGrid.width / contentGrid.columns
|
||||
thing: root.thingsProxy.getThing(model.id)
|
||||
@ -97,6 +97,7 @@ DeviceListPageBase {
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
|
||||
|
||||
property State powerState: thing.stateByName("power")
|
||||
property State brightnessState: thing.stateByName("brightness")
|
||||
property State colorState: thing.stateByName("color")
|
||||
|
||||
@ -59,7 +59,7 @@ DeviceListPageBase {
|
||||
Repeater {
|
||||
model: root.thingsProxy
|
||||
|
||||
delegate: BigTile {
|
||||
delegate: BigThingTile {
|
||||
id: itemDelegate
|
||||
Layout.preferredWidth: contentGrid.width / contentGrid.columns
|
||||
thing: thingsProxy.getThing(model.id)
|
||||
|
||||
@ -62,7 +62,7 @@ DeviceListPageBase {
|
||||
Repeater {
|
||||
model: root.thingsProxy
|
||||
|
||||
delegate: BigTile {
|
||||
delegate: BigThingTile {
|
||||
id: itemDelegate
|
||||
Layout.preferredWidth: contentGrid.width / contentGrid.columns
|
||||
thing: root.thingsProxy.getThing(model.id)
|
||||
|
||||
@ -59,7 +59,7 @@ DeviceListPageBase {
|
||||
Repeater {
|
||||
model: root.thingsProxy
|
||||
|
||||
delegate: BigTile {
|
||||
delegate: BigThingTile {
|
||||
id: itemDelegate
|
||||
Layout.preferredWidth: contentGrid.width / contentGrid.columns
|
||||
thing: root.thingsProxy.getThing(model.id)
|
||||
|
||||
@ -59,7 +59,7 @@ DeviceListPageBase {
|
||||
Repeater {
|
||||
model: root.thingsProxy
|
||||
|
||||
delegate: BigTile {
|
||||
delegate: BigThingTile {
|
||||
id: itemDelegate
|
||||
Layout.preferredWidth: contentGrid.width / contentGrid.columns
|
||||
thing: root.thingsProxy.getThing(model.id)
|
||||
|
||||
@ -60,7 +60,7 @@ DeviceListPageBase {
|
||||
Repeater {
|
||||
model: root.thingsProxy
|
||||
|
||||
delegate: BigTile {
|
||||
delegate: BigThingTile {
|
||||
id: itemDelegate
|
||||
Layout.preferredWidth: contentGrid.width / contentGrid.columns
|
||||
thing: root.thingsProxy.get(model.id)
|
||||
|
||||
@ -28,8 +28,8 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 2.1
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import Nymea 1.0
|
||||
import "../components"
|
||||
@ -52,19 +52,92 @@ DevicePageBase {
|
||||
}
|
||||
}
|
||||
|
||||
function sendMessage(title, text) {
|
||||
print("sending message", title, text)
|
||||
var actionType = root.deviceClass.actionTypes.findByName("notify")
|
||||
var params = []
|
||||
var titleParam = {}
|
||||
titleParam["paramTypeId"] = actionType.paramTypes.findByName("title").id
|
||||
titleParam["value"] = title
|
||||
params.push(titleParam)
|
||||
var bodyParam = {}
|
||||
bodyParam["paramTypeId"] = actionType.paramTypes.findByName("body").id
|
||||
bodyParam["value"] = text
|
||||
params.push(bodyParam)
|
||||
d.pendingAction = engine.deviceManager.executeAction(root.device.id, actionType.id, params)
|
||||
titleTextField.clear();
|
||||
bodyTextField.clear();
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
|
||||
Label {
|
||||
RowLayout {
|
||||
id: inputPane
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
wrapMode: Text.WordWrap
|
||||
text: qsTr("Sent notifications:")
|
||||
visible: logsModel.count > 0 && !logsModel.busy
|
||||
spacing: app.margins
|
||||
|
||||
ColumnLayout {
|
||||
id: inputColumn
|
||||
|
||||
TextField {
|
||||
id: titleTextField
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Title")
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
Layout.preferredWidth: inputPane.width - app.iconSize - inputPane.spacing
|
||||
Layout.maximumHeight: content.height - y - app.margins
|
||||
contentWidth: width
|
||||
|
||||
TextArea {
|
||||
id: bodyTextField
|
||||
placeholderText: qsTr("Text")
|
||||
wrapMode: TextArea.WrapAtWordBoundaryOrAnywhere
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: sendButton
|
||||
Layout.preferredWidth: app.iconSize
|
||||
Layout.preferredHeight: inputColumn.height
|
||||
ColorIcon {
|
||||
anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom; margins: app.margins }
|
||||
height: app.iconSize
|
||||
width: app.iconSize
|
||||
name: "../images/send.svg"
|
||||
color: titleTextField.displayText.length > 0 ? Style.accentColor : Style.iconColor
|
||||
visible: d.pendingAction == -1
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom; margins: app.margins }
|
||||
visible: d.pendingAction != -1
|
||||
running: visible
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
print("clicked!")
|
||||
bodyTextField.focus = false
|
||||
if (titleTextField.displayText.length > 0) {
|
||||
root.sendMessage(titleTextField.displayText, bodyTextField.text)
|
||||
titleTextField.clear();
|
||||
bodyTextField.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GenericTypeLogView {
|
||||
id: logView
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
@ -76,16 +149,65 @@ DevicePageBase {
|
||||
typeIds: [root.deviceClass.actionTypes.findByName("notify").id];
|
||||
}
|
||||
|
||||
delegate: NymeaSwipeDelegate {
|
||||
width: parent.width
|
||||
iconName: app.interfaceToIcon("notifications")
|
||||
text: model.value.trim()
|
||||
subText: Qt.formatDateTime(model.timestamp)
|
||||
progressive: false
|
||||
delegate: BigTile {
|
||||
id: itemDelegate
|
||||
showHeader: false
|
||||
width: logView.width - app.margins
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
// Note: This will go wrong if the title contains ", ". Known shortcoming of the log db
|
||||
readonly property string title: model.value.trim().replace(/, ?.*/, "")
|
||||
readonly property string text: model.value.trim().replace(/.*, ?/, "")
|
||||
|
||||
contentItem: RowLayout {
|
||||
ColumnLayout {
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: itemDelegate.title
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
GridLayout {
|
||||
Layout.fillWidth: true
|
||||
columns: textLabel.implicitWidth + dateLayout.implicitWidth < width ? 2 : 1
|
||||
|
||||
Label {
|
||||
id: textLabel
|
||||
Layout.fillWidth: true
|
||||
text: itemDelegate.text
|
||||
font.pixelSize: app.smallFont
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: dateLayout
|
||||
Layout.fillWidth: true
|
||||
spacing: app.margins / 2
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignRight
|
||||
text: Qt.formatDateTime(model.timestamp)
|
||||
font.pixelSize: app.extraSmallFont
|
||||
}
|
||||
ColorIcon {
|
||||
Layout.preferredWidth: app.smallIconSize
|
||||
Layout.preferredHeight: app.smallIconSize
|
||||
name: "../images/dialog-warning-symbolic.svg"
|
||||
color: "red"
|
||||
visible: model.errorCode !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
var parts = model.value.trim().split(', ')
|
||||
var popup = detailsPopup.createObject(root, {timestamp: model.timestamp, notificationTitle: parts[0], notificationBody: parts[1]});
|
||||
var popup = detailsPopup.createObject(root,
|
||||
{
|
||||
timestamp: model.timestamp,
|
||||
notificationTitle: itemDelegate.title,
|
||||
notificationBody: itemDelegate.text,
|
||||
errorCode: model.errorCode
|
||||
});
|
||||
popup.open();
|
||||
}
|
||||
}
|
||||
@ -100,73 +222,6 @@ DevicePageBase {
|
||||
visible: logsModel.count == 0 && !logsModel.busy
|
||||
}
|
||||
}
|
||||
|
||||
ThinDivider {}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
spacing: app.margins
|
||||
|
||||
ColumnLayout {
|
||||
id: inputColumn
|
||||
anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
|
||||
|
||||
TextField {
|
||||
id: titleTextField
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Title")
|
||||
}
|
||||
|
||||
TextArea {
|
||||
id: bodyTextField
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Text")
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: app.iconSize
|
||||
Layout.preferredHeight: inputColumn.height
|
||||
ColorIcon {
|
||||
anchors.centerIn: parent
|
||||
height: app.iconSize
|
||||
width: app.iconSize
|
||||
name: "../images/send.svg"
|
||||
color: titleTextField.displayText.length > 0 ? Style.accentColor : Style.iconColor
|
||||
visible: d.pendingAction == -1
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
anchors.centerIn: parent
|
||||
visible: d.pendingAction != -1
|
||||
running: visible
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
print("clicked!")
|
||||
if (titleTextField.displayText.length > 0) {
|
||||
var actionType = root.deviceClass.actionTypes.findByName("notify")
|
||||
var params = []
|
||||
var titleParam = {}
|
||||
titleParam["paramTypeId"] = actionType.paramTypes.findByName("title").id
|
||||
titleParam["value"] = titleTextField.displayText
|
||||
params.push(titleParam)
|
||||
var bodyParam = {}
|
||||
bodyParam["paramTypeId"] = actionType.paramTypes.findByName("body").id
|
||||
bodyParam["value"] = bodyTextField.text
|
||||
params.push(bodyParam)
|
||||
d.pendingAction = engine.deviceManager.executeAction(root.device.id, actionType.id, params)
|
||||
titleTextField.clear();
|
||||
bodyTextField.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
@ -177,22 +232,38 @@ DevicePageBase {
|
||||
|
||||
Component {
|
||||
id: detailsPopup
|
||||
|
||||
MeaDialog {
|
||||
id: detailsDialog
|
||||
standardButtons: Dialog.NoButton
|
||||
property string timestamp
|
||||
property string notificationTitle
|
||||
property string notificationBody
|
||||
property string errorCode
|
||||
title: qsTr("Notification details")
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Date sent")
|
||||
font.bold: true
|
||||
headerIcon: "../images/messaging-app-symbolic.svg"
|
||||
RowLayout {
|
||||
ColumnLayout {
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: detailsDialog.errorCode == "" ? qsTr("Date sent") : qsTr("Sending failed")
|
||||
font.bold: true
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: Qt.formatDateTime(detailsDialog.timestamp)
|
||||
}
|
||||
}
|
||||
ColorIcon {
|
||||
Layout.preferredWidth: app.largeIconSize
|
||||
Layout.preferredHeight: app.largeIconSize
|
||||
name: "../images/dialog-warning-symbolic.svg"
|
||||
color: "red"
|
||||
visible: detailsDialog.errorCode !== ""
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: Qt.formatDateTime(detailsDialog.timestamp)
|
||||
}
|
||||
Label {
|
||||
Layout.topMargin: app.margins
|
||||
Layout.fillWidth: true
|
||||
@ -217,6 +288,20 @@ DevicePageBase {
|
||||
text: detailsDialog.notificationBody
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Button {
|
||||
text: qsTr("Resend")
|
||||
onClicked: root.sendMessage(detailsDialog.notificationTitle, detailsDialog.notificationBody)
|
||||
}
|
||||
Button {
|
||||
text: qsTr("Close")
|
||||
onClicked: detailsDialog.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -401,21 +401,13 @@ Page {
|
||||
print("Setting up params for thing class:", root.thingClass.id, root.thingClass.name)
|
||||
if (root.thingClass.id.toString().match(/\{?f0dd4c03-0aca-42cc-8f34-9902457b05de\}?/)) {
|
||||
if (paramType.id.toString().match(/\{?3cb8e30e-2ec5-4b4b-8c8c-03eaf7876839\}?/)) {
|
||||
if (PlatformHelper.platform === "android") {
|
||||
return "FB-GCM";
|
||||
} else if (PlatformHelper.platform === "ios") {
|
||||
return "FB-APNs"
|
||||
} else if (PlatformHelper.platform === "ubports") {
|
||||
return "UBPorts";
|
||||
} else {
|
||||
print("Unsupported platform for push notifications:", PlatformHelper.platform)
|
||||
}
|
||||
return PushNotifications.service;
|
||||
}
|
||||
if (paramType.id.toString().match(/\{?12ec06b2-44e7-486a-9169-31c684b91c8f\}?/)) {
|
||||
return PushNotifications.token;
|
||||
}
|
||||
if (paramType.id.toString().match(/\{?d76da367-64e3-4b7d-aa84-c96b3acfb65e\}?/)) {
|
||||
return PlatformHelper.deviceSerial + "+io.guh.nymeaapp" + (appBranding.length > 0 ? "-" + appBranding : "");
|
||||
return PushNotifications.clientId;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
pragma Singleton
|
||||
import QtQuick 2.9
|
||||
import Nymea 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
@ -81,4 +82,5 @@ Item {
|
||||
|
||||
return ((r * 299 + g * 587 + b * 114) / 1000) < 128
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user