summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--message.h1
-rw-r--r--messageengine.cpp9
-rw-r--r--voice-capabilities/CMakeLists.txt2
-rw-r--r--voice-capabilities/guimetadata.cpp344
-rw-r--r--voice-capabilities/guimetadata.h174
-rw-r--r--voice-capabilities/guimetadatamessage.cpp30
-rw-r--r--voice-capabilities/guimetadatamessage.h38
8 files changed, 598 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2f576e9..bf1cba4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -57,6 +57,7 @@ set (SUBDIRS
signal-composer
telephony
voice
+ voice-capabilities
weather)
add_headers(message.h messageengine.h responsemessage.h)
diff --git a/message.h b/message.h
index df640ec..87cd461 100644
--- a/message.h
+++ b/message.h
@@ -44,6 +44,7 @@ enum MessageType {
NavigationEventMessage,
VoiceEventMessage,
SignalComposerEventMessage,
+ GuiMetadataCapabilityEventMessage,
};
class Message : public QObject
diff --git a/messageengine.cpp b/messageengine.cpp
index d2644e8..115dde7 100644
--- a/messageengine.cpp
+++ b/messageengine.cpp
@@ -17,6 +17,7 @@
#include "message.h"
#include "messageengine.h"
#include "bluetoothmessage.h"
+#include "guimetadatamessage.h"
#include "mapmessage.h"
#include "mediaplayermessage.h"
#include "navigationmessage.h"
@@ -24,10 +25,10 @@
#include "pbapmessage.h"
#include "radiomessage.h"
#include "responsemessage.h"
+#include "signalcomposermessage.h"
#include "telephonymessage.h"
#include "weathermessage.h"
#include "voicemessage.h"
-#include "signalcomposermessage.h"
#include <QJsonArray>
@@ -143,6 +144,12 @@ void MessageEngine::onTextMessageReceived(QString jsonStr)
} else if (api == "vshl-core" ) {
message = new VoiceMessage;
type = VoiceEventMessage;
+ } else if (api == "vshl-capabilities" ) {
+ // NOTE: Will need to look at event name to differentiate
+ // capabilities if more support (e.g. navigation or
+ // local media control) is added.
+ message = new GuiMetadataCapabilityMessage;
+ type = GuiMetadataCapabilityEventMessage;
} else if (api == "signal-composer") {
message = new SignalComposerMessage;
type = SignalComposerEventMessage;
diff --git a/voice-capabilities/CMakeLists.txt b/voice-capabilities/CMakeLists.txt
new file mode 100644
index 0000000..e1a6089
--- /dev/null
+++ b/voice-capabilities/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_headers(guimetadata.h guimetadatamessage.h)
+add_sources(guimetadata.cpp guimetadatamessage.cpp)
diff --git a/voice-capabilities/guimetadata.cpp b/voice-capabilities/guimetadata.cpp
new file mode 100644
index 0000000..2ab86c5
--- /dev/null
+++ b/voice-capabilities/guimetadata.cpp
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "message.h"
+#include "messageengine.h"
+#include "guimetadata.h"
+#include "guimetadatamessage.h"
+
+#include <QJsonArray>
+
+GuiMetadata::GuiMetadata(QUrl &url, QQmlContext *context, QObject * parent) :
+ QObject(parent),
+ m_mloop(nullptr)
+{
+ m_mloop = new MessageEngine(url);
+ m_context = context;
+ QObject::connect(m_mloop, &MessageEngine::connected, this, &GuiMetadata::onConnected);
+ QObject::connect(m_mloop, &MessageEngine::disconnected, this, &GuiMetadata::onDisconnected);
+ QObject::connect(m_mloop, &MessageEngine::messageReceived, this, &GuiMetadata::onMessageReceived);
+}
+
+GuiMetadata::~GuiMetadata()
+{
+ delete m_mloop;
+}
+
+// Qt UI Context
+
+void GuiMetadata::clearMetadata()
+{
+ m_type = "";
+ m_title = "";
+ m_subtitle = "";
+
+ m_bodyText = "";
+ m_bodyImageSmallUrl = "";
+ m_bodyImageMediumUrl = "";
+ m_bodyImageLargeUrl = "";
+
+ m_weatherCurrentTemperature = "";
+ m_weatherCurrentWeatherIconSmallUrl = "";
+ m_weatherCurrentWeatherIconSmallDarkBgUrl = "";
+ m_weatherCurrentWeatherIconMediumUrl = "";
+ m_weatherCurrentWeatherIconMediumDarkBgUrl = "";
+ m_weatherCurrentWeatherIconLargeUrl = "";
+ m_weatherCurrentWeatherIconLargeDarkBgUrl = "";
+
+ m_weatherLowTemperature = "";
+ m_weatherLowTemperatureArrowSmallUrl = "";
+ m_weatherLowTemperatureArrowSmallDarkBgUrl = "";
+ m_weatherLowTemperatureArrowMediumUrl = "";
+ m_weatherLowTemperatureArrowMediumDarkBgUrl = "";
+ m_weatherLowTemperatureArrowLargeUrl = "";
+ m_weatherLowTemperatureArrowLargeDarkBgUrl = "";
+
+ m_weatherHighTemperature = "";
+ m_weatherHighTemperatureArrowSmallUrl = "";
+ m_weatherHighTemperatureArrowSmallDarkBgUrl = "";
+ m_weatherHighTemperatureArrowMediumUrl = "";
+ m_weatherHighTemperatureArrowMediumDarkBgUrl = "";
+ m_weatherHighTemperatureArrowLargeUrl = "";
+ m_weatherHighTemperatureArrowLargeDarkBgUrl = "";
+}
+
+bool GuiMetadata::parseImageMetadata(QJsonObject &imageObj,
+ QUrl &smallUrl, QUrl &mediumUrl, QUrl &largeUrl,
+ QUrl *pSmallDarkBgUrl, QUrl *pMediumDarkBgUrl, QUrl *pLargeDarkBgUrl)
+{
+ if(!(imageObj.contains("sources") && imageObj["sources"].isArray())) {
+ // error
+ qWarning() << "Could not find image.sources parameter!";
+ return false;
+ }
+ QJsonArray sourcesObj = imageObj["sources"].toArray();
+ bool found = false;
+ for(QJsonArray::iterator it = sourcesObj.begin(); it != sourcesObj.end(); it++) {
+ if(!it->isObject()) {
+ // unexpected, skip
+ continue;
+ }
+ QJsonObject sourceObj = it->toObject();
+ if(!(sourceObj.contains("url") && sourceObj["url"].isString())) {
+ // error
+ qWarning() << "Missing image.sources.url parameter!";
+ continue;
+ }
+ QString url = sourceObj["url"].toString();
+ QString darkBackgroundUrl = "";
+ if(sourceObj.contains("darkBackgroundUrl") && sourceObj["darkBackgroundUrl"].isString()) {
+ darkBackgroundUrl = sourceObj["darkBackgroundUrl"].toString();
+ }
+ if(sourceObj.contains("size") && sourceObj["size"].isString()) {
+ QString size = sourceObj["size"].toString();
+ if(size == "SMALL") {
+ smallUrl = url;
+ if(pSmallDarkBgUrl)
+ pSmallDarkBgUrl->setUrl(darkBackgroundUrl);
+ found = true;
+ } else if(size == "MEDIUM") {
+ mediumUrl = url;
+ if(pMediumDarkBgUrl)
+ pMediumDarkBgUrl->setUrl(darkBackgroundUrl);
+ found = true;
+ } else if(size == "LARGE") {
+ largeUrl = url;
+ if(pLargeDarkBgUrl)
+ pLargeDarkBgUrl->setUrl(darkBackgroundUrl);
+ found = true;
+ }
+ // else ignore (X-SMALL, X-LARGE)
+ }
+ // FIXME: Should handle image sources w/o size fields,
+ // parse width/height if present
+ }
+ return found;
+}
+
+bool GuiMetadata::updateMetadata(QJsonObject data)
+{
+ if(!data.contains("type"))
+ return false;
+
+ clearMetadata();
+
+ QString type = data["type"].toString();
+ if(!(type == "BodyTemplate1" ||
+ type == "BodyTemplate2" ||
+ type == "WeatherTemplate")) {
+ // Show unsupported type message
+ m_type = "Unsupported";
+ return true;
+ }
+ m_type = type;
+
+ // All template types have title
+ if(data.contains("title") && data["title"].isObject()) {
+ QJsonObject titleObj = data["title"].toObject();
+ if(titleObj.contains("mainTitle")) {
+ m_title = titleObj["mainTitle"].toString();
+ } else {
+ qWarning() << "Could not find title.mainTitle parameter!";
+ return false;
+ }
+ // subTitle is apparently optional
+ if(titleObj.contains("subTitle"))
+ m_subtitle = titleObj["subTitle"].toString();
+ } else {
+ // error
+ qWarning() << "Could not find title parameter!";
+ return false;
+ }
+
+ if(type == "BodyTemplate1" || type == "BodyTemplate2")
+ return updateBodyMetadata(data);
+ else
+ return updateWeatherMetadata(data);
+}
+
+bool GuiMetadata::updateBodyMetadata(QJsonObject &data)
+{
+ if(!data.contains("type"))
+ return false;
+
+ QString type = data["type"].toString();
+ if(!(type == "BodyTemplate1" || type == "BodyTemplate2"))
+ return false;
+
+ // BodyTemplate1/2 have text field
+ if(data.contains("textField")) {
+ m_bodyText = data["textField"].toString();
+ } else {
+ // error
+ qWarning() << "Could not find textField parameter!";
+ return false;
+ }
+
+ // BodyTemplate2 has image
+ if(type == "BodyTemplate2") {
+ if(!(data.contains("image") && data["image"].isObject())) {
+ // error
+ qWarning() << "Could not find image parameter!";
+ return false;
+ }
+ QJsonObject imageObj = data["image"].toObject();
+ if(!parseImageMetadata(imageObj,
+ m_bodyImageSmallUrl,
+ m_bodyImageMediumUrl,
+ m_bodyImageLargeUrl)) {
+ qWarning() << "Could not parse image parameter!";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool GuiMetadata::updateWeatherMetadata(QJsonObject &data)
+{
+ if(!data.contains("type"))
+ return false;
+
+ QString type = data["type"].toString();
+ if(type != "WeatherTemplate")
+ return false;
+
+ if(data.contains("currentWeather")) {
+ m_weatherCurrentTemperature = data["currentWeather"].toString();
+ } else {
+ // error
+ qWarning() << "Could not find currentWeather parameter!";
+ return false;
+ }
+
+ if(!(data.contains("currentWeatherIcon") && data["currentWeatherIcon"].isObject())) {
+ // error
+ qWarning() << "Could not find currentWeatherIcon parameter!";
+ return false;
+ }
+ QJsonObject imageObj = data["currentWeatherIcon"].toObject();
+ if(!parseImageMetadata(imageObj,
+ m_weatherCurrentWeatherIconSmallUrl,
+ m_weatherCurrentWeatherIconMediumUrl,
+ m_weatherCurrentWeatherIconLargeUrl,
+ &m_weatherCurrentWeatherIconSmallDarkBgUrl,
+ &m_weatherCurrentWeatherIconMediumDarkBgUrl,
+ &m_weatherCurrentWeatherIconLargeDarkBgUrl)) {
+ qWarning() << "Could not parse currentWeatherIcon.image parameter!";
+ return false;
+ }
+
+ if(!(data.contains("lowTemperature") && data["lowTemperature"].isObject())) {
+ // error
+ qWarning() << "Could not find lowTemperature parameter!";
+ return false;
+ }
+ QJsonObject tempObj = data["lowTemperature"].toObject();
+ if(!(tempObj.contains("value") && tempObj["value"].isString())) {
+ // error
+ qWarning() << "Could not find lowTemperature.value parameter!";
+ return false;
+ }
+ m_weatherLowTemperature = tempObj["value"].toString();
+
+ if(!(tempObj.contains("arrow") && tempObj["arrow"].isObject())) {
+ // error
+ qWarning() << "Could not find lowTemperature.arrow parameter!";
+ return false;
+ }
+ imageObj = tempObj["arrow"].toObject();
+ if(!parseImageMetadata(imageObj,
+ m_weatherLowTemperatureArrowSmallUrl,
+ m_weatherLowTemperatureArrowMediumUrl,
+ m_weatherLowTemperatureArrowLargeUrl,
+ &m_weatherLowTemperatureArrowSmallDarkBgUrl,
+ &m_weatherLowTemperatureArrowMediumDarkBgUrl,
+ &m_weatherLowTemperatureArrowLargeDarkBgUrl)) {
+ qWarning() << "Could not parse lowTemperature.arrow parameter!";
+ return false;
+ }
+
+ if(!(data.contains("highTemperature") && data["highTemperature"].isObject())) {
+ // error
+ qWarning() << "Could not find highTemperature parameter!";
+ return false;
+ }
+ tempObj = data["highTemperature"].toObject();
+ if(!(tempObj.contains("value") && tempObj["value"].isString())) {
+ // error
+ qWarning() << "Could not find highTemperature.value parameter!";
+ return false;
+ }
+ m_weatherHighTemperature = tempObj["value"].toString();
+
+ if(!(tempObj.contains("arrow") && tempObj["arrow"].isObject())) {
+ // error
+ qWarning() << "Could not find highTemperature.arrow parameter!";
+ return false;
+ }
+ imageObj = tempObj["arrow"].toObject();
+ if(!parseImageMetadata(imageObj,
+ m_weatherHighTemperatureArrowSmallUrl,
+ m_weatherHighTemperatureArrowMediumUrl,
+ m_weatherHighTemperatureArrowLargeUrl,
+ &m_weatherHighTemperatureArrowSmallDarkBgUrl,
+ &m_weatherHighTemperatureArrowMediumDarkBgUrl,
+ &m_weatherHighTemperatureArrowLargeDarkBgUrl)) {
+ qWarning() << "Could not parse highTemperature.arrow parameter!";
+ return false;
+ }
+
+ return true;
+
+}
+
+void GuiMetadata::onConnected()
+{
+ QStringListIterator eventIterator(events);
+ GuiMetadataCapabilityMessage *tmsg;
+
+ tmsg = new GuiMetadataCapabilityMessage();
+ QJsonObject parameter;
+ QJsonArray actions;
+ while (eventIterator.hasNext()) {
+ actions.append(QJsonValue(eventIterator.next()));
+ }
+ parameter.insert("actions", actions);
+ tmsg->createRequest("guimetadata/subscribe", parameter);
+ m_mloop->sendMessage(tmsg);
+ delete tmsg;
+}
+
+void GuiMetadata::onDisconnected()
+{
+ // vshl-capabilities currently has no unsubscribe verb...
+}
+
+void GuiMetadata::onMessageReceived(MessageType type, Message *message)
+{
+ if (type == GuiMetadataCapabilityEventMessage) {
+ GuiMetadataCapabilityMessage *tmsg = qobject_cast<GuiMetadataCapabilityMessage*>(message);
+ if (tmsg->isEvent()) {
+ if (tmsg->isGuiMetadataRenderTemplateEvent()) {
+ if(updateMetadata(tmsg->eventData()))
+ emit renderTemplate();
+ } else if (tmsg->isGuiMetadataClearTemplateEvent()) {
+ emit clearTemplate();
+ }
+ }
+ }
+ message->deleteLater();
+}
diff --git a/voice-capabilities/guimetadata.h b/voice-capabilities/guimetadata.h
new file mode 100644
index 0000000..c4a551f
--- /dev/null
+++ b/voice-capabilities/guimetadata.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GUIMETADATA_H
+#define GUIMETADATA_H
+
+#include <QDebug>
+#include <QObject>
+
+#include <QtQml/QQmlContext>
+#include "messageengine.h"
+
+class GuiMetadata : public QObject
+{
+ Q_OBJECT
+
+ // Common to all template types
+ Q_PROPERTY(QString type READ type)
+ Q_PROPERTY(QString title READ title)
+ Q_PROPERTY(QString subtitle READ subtitle)
+
+ // BodyTemplate1/2
+ Q_PROPERTY(QString bodyText READ bodyText)
+
+ // BodyTemplate2
+ Q_PROPERTY(QUrl bodyImageSmallUrl READ bodyImageSmallUrl)
+ Q_PROPERTY(QUrl bodyImageMediumUrl READ bodyImageMediumUrl)
+ Q_PROPERTY(QUrl bodyImageLargeUrl READ bodyImageLargeUrl)
+
+ // WeatherTemplate
+ Q_PROPERTY(QString weatherCurrentTemperature READ weatherCurrentTemperature)
+ Q_PROPERTY(QUrl weatherCurrentWeatherIconSmallUrl READ weatherCurrentWeatherIconSmallUrl)
+ Q_PROPERTY(QUrl weatherCurrentWeatherIconSmallDarkBgUrl READ weatherCurrentWeatherIconSmallDarkBgUrl)
+ Q_PROPERTY(QUrl weatherCurrentWeatherIconMediumUrl READ weatherCurrentWeatherIconMediumUrl)
+ Q_PROPERTY(QUrl weatherCurrentWeatherIconMediumDarkBgUrl READ weatherCurrentWeatherIconMediumDarkBgUrl)
+ Q_PROPERTY(QUrl weatherCurrentWeatherIconLargeUrl READ weatherCurrentWeatherIconLargeUrl)
+ Q_PROPERTY(QUrl weatherCurrentWeatherIconLargeDarkBgUrl READ weatherCurrentWeatherIconLargeDarkBgUrl)
+
+ Q_PROPERTY(QString weatherLowTemperature READ weatherLowTemperature)
+ Q_PROPERTY(QUrl weatherLowTemperatureArrowSmallUrl READ weatherLowTemperatureArrowSmallUrl)
+ Q_PROPERTY(QUrl weatherLowTemperatureArrowSmallDarkBgUrl READ weatherLowTemperatureArrowSmallDarkBgUrl)
+ Q_PROPERTY(QUrl weatherLowTemperatureArrowMediumUrl READ weatherLowTemperatureArrowMediumUrl)
+ Q_PROPERTY(QUrl weatherLowTemperatureArrowMediumDarkBgUrl READ weatherLowTemperatureArrowMediumDarkBgUrl)
+ Q_PROPERTY(QUrl weatherLowTemperatureArrowLargeUrl READ weatherLowTemperatureArrowLargeUrl)
+ Q_PROPERTY(QUrl weatherLowTemperatureArrowLargeDarkBgUrl READ weatherLowTemperatureArrowLargeDarkBgUrl)
+
+ Q_PROPERTY(QString weatherHighTemperature READ weatherHighTemperature)
+ Q_PROPERTY(QUrl weatherHighTemperatureArrowSmallUrl READ weatherHighTemperatureArrowSmallUrl)
+ Q_PROPERTY(QUrl weatherHighTemperatureArrowSmallDarkBgUrl READ weatherHighTemperatureArrowSmallDarkBgUrl)
+ Q_PROPERTY(QUrl weatherHighTemperatureArrowMediumUrl READ weatherHighTemperatureArrowMediumUrl)
+ Q_PROPERTY(QUrl weatherHighTemperatureArrowMediumDarkBgUrl READ weatherHighTemperatureArrowMediumDarkBgUrl)
+ Q_PROPERTY(QUrl weatherHighTemperatureArrowLargeUrl READ weatherHighTemperatureArrowLargeUrl)
+ Q_PROPERTY(QUrl weatherHighTemperatureArrowLargeDarkBgUrl READ weatherHighTemperatureArrowLargeDarkBgUrl)
+ // weatherForecast array ignored for now
+
+public:
+ explicit GuiMetadata(QUrl &url, QQmlContext *context, QObject * parent = Q_NULLPTR);
+ virtual ~GuiMetadata();
+
+ QString type() { return m_type; }
+ QString title() { return m_title; }
+ QString subtitle() { return m_subtitle; }
+
+ // BodyTemplate1/2
+ QString bodyText() { return m_bodyText; }
+
+ // BodyTemplate2
+ QUrl bodyImageSmallUrl() { return m_bodyImageSmallUrl; }
+ QUrl bodyImageMediumUrl() { return m_bodyImageMediumUrl; }
+ QUrl bodyImageLargeUrl() { return m_bodyImageLargeUrl; }
+
+ // WeatherTemplate
+ QString weatherCurrentTemperature() { return m_weatherCurrentTemperature; }
+ QUrl weatherCurrentWeatherIconSmallUrl() { return m_weatherCurrentWeatherIconSmallUrl; }
+ QUrl weatherCurrentWeatherIconSmallDarkBgUrl() { return m_weatherCurrentWeatherIconSmallDarkBgUrl; }
+ QUrl weatherCurrentWeatherIconMediumUrl() { return m_weatherCurrentWeatherIconMediumUrl; }
+ QUrl weatherCurrentWeatherIconMediumDarkBgUrl() { return m_weatherCurrentWeatherIconMediumDarkBgUrl; }
+ QUrl weatherCurrentWeatherIconLargeUrl() { return m_weatherCurrentWeatherIconLargeUrl; }
+ QUrl weatherCurrentWeatherIconLargeDarkBgUrl() { return m_weatherCurrentWeatherIconLargeDarkBgUrl; }
+
+ QString weatherLowTemperature() { return m_weatherLowTemperature; }
+ QUrl weatherLowTemperatureArrowSmallUrl() { return m_weatherLowTemperatureArrowSmallUrl; }
+ QUrl weatherLowTemperatureArrowSmallDarkBgUrl() { return m_weatherLowTemperatureArrowSmallDarkBgUrl; }
+ QUrl weatherLowTemperatureArrowMediumUrl() { return m_weatherLowTemperatureArrowMediumUrl; }
+ QUrl weatherLowTemperatureArrowMediumDarkBgUrl() { return m_weatherLowTemperatureArrowMediumDarkBgUrl; }
+ QUrl weatherLowTemperatureArrowLargeUrl() { return m_weatherLowTemperatureArrowLargeUrl; }
+ QUrl weatherLowTemperatureArrowLargeDarkBgUrl() { return m_weatherLowTemperatureArrowLargeDarkBgUrl; }
+
+ QString weatherHighTemperature() { return m_weatherHighTemperature; }
+ QUrl weatherHighTemperatureArrowSmallUrl() { return m_weatherHighTemperatureArrowSmallUrl; }
+ QUrl weatherHighTemperatureArrowSmallDarkBgUrl() { return m_weatherHighTemperatureArrowSmallDarkBgUrl; }
+ QUrl weatherHighTemperatureArrowMediumUrl() { return m_weatherHighTemperatureArrowMediumUrl; }
+ QUrl weatherHighTemperatureArrowMediumDarkBgUrl() { return m_weatherHighTemperatureArrowMediumDarkBgUrl; }
+ QUrl weatherHighTemperatureArrowLargeUrl() { return m_weatherHighTemperatureArrowLargeUrl; }
+ QUrl weatherHighTemperatureArrowLargeDarkBgUrl() { return m_weatherHighTemperatureArrowLargeDarkBgUrl; }
+
+signals:
+ void renderTemplate();
+ void clearTemplate();
+
+private:
+ MessageEngine *m_mloop;
+ QQmlContext *m_context;
+
+ void clearMetadata();
+ bool parseImageMetadata(QJsonObject &imageObj,
+ QUrl &smallUrl, QUrl &mediumUrl, QUrl &largeUrl,
+ QUrl *pSmallDarkBgUrl = NULL, QUrl *pMediumDarkBgUrl = NULL, QUrl *pLargeDarkBgUrl = NULL);
+
+ bool updateMetadata(QJsonObject data);
+ bool updateBodyMetadata(QJsonObject &data);
+ bool updateWeatherMetadata(QJsonObject &data);
+
+ void onConnected();
+ void onDisconnected();
+ void onMessageReceived(MessageType, Message*);
+
+ const QStringList events {
+ "render_template",
+ "clear_template",
+ };
+
+ QString m_type = "";
+ QString m_title = "";
+ QString m_subtitle = "";
+
+ // BodyTemplate1/2
+ QString m_bodyText = "";
+
+ // BodyTemplate2
+ QUrl m_bodyImageSmallUrl = QString("");
+ QUrl m_bodyImageMediumUrl = QString("");
+ QUrl m_bodyImageLargeUrl = QString("");
+
+ // WeatherTemplate
+ QString m_weatherCurrentTemperature = "";
+ QUrl m_weatherCurrentWeatherIconSmallUrl = QString("");
+ QUrl m_weatherCurrentWeatherIconSmallDarkBgUrl = QString("");
+ QUrl m_weatherCurrentWeatherIconMediumUrl = QString("");
+ QUrl m_weatherCurrentWeatherIconMediumDarkBgUrl = QString("");
+ QUrl m_weatherCurrentWeatherIconLargeUrl = QString("");
+ QUrl m_weatherCurrentWeatherIconLargeDarkBgUrl = QString("");
+
+ QString m_weatherLowTemperature = "";
+ QUrl m_weatherLowTemperatureArrowSmallUrl = QString("");
+ QUrl m_weatherLowTemperatureArrowSmallDarkBgUrl = QString("");
+ QUrl m_weatherLowTemperatureArrowMediumUrl = QString("");
+ QUrl m_weatherLowTemperatureArrowMediumDarkBgUrl = QString("");
+ QUrl m_weatherLowTemperatureArrowLargeUrl = QString("");
+ QUrl m_weatherLowTemperatureArrowLargeDarkBgUrl = QString("");
+
+ QString m_weatherHighTemperature = "";
+ QUrl m_weatherHighTemperatureArrowSmallUrl = QString("");
+ QUrl m_weatherHighTemperatureArrowSmallDarkBgUrl = QString("");
+ QUrl m_weatherHighTemperatureArrowMediumUrl = QString("");
+ QUrl m_weatherHighTemperatureArrowMediumDarkBgUrl = QString("");
+ QUrl m_weatherHighTemperatureArrowLargeUrl = QString("");
+ QUrl m_weatherHighTemperatureArrowLargeDarkBgUrl = QString("");
+};
+
+#endif // GUIMETADATA_H
diff --git a/voice-capabilities/guimetadatamessage.cpp b/voice-capabilities/guimetadatamessage.cpp
new file mode 100644
index 0000000..1613c12
--- /dev/null
+++ b/voice-capabilities/guimetadatamessage.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QDebug>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+
+#include "guimetadatamessage.h"
+
+bool GuiMetadataCapabilityMessage::createRequest(QString verb, QJsonObject parameter)
+{
+ if (!verbs.contains(verb))
+ return false;
+
+ return Message::createRequest("vshl-capabilities", verb, parameter);
+}
diff --git a/voice-capabilities/guimetadatamessage.h b/voice-capabilities/guimetadatamessage.h
new file mode 100644
index 0000000..7f0854f
--- /dev/null
+++ b/voice-capabilities/guimetadatamessage.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GUIMETADATA_MESSAGE_H
+#define GUIMETADATA_MESSAGE_H
+
+#include "message.h"
+
+class GuiMetadataCapabilityMessage : public Message
+{
+ Q_OBJECT
+public:
+ bool isGuiMetadataRenderTemplateEvent() const {
+ return (this->eventName() == "render_template"); };
+ bool isGuiMetadataClearTemplateEvent() const {
+ return (this->eventName() == "clear_template"); };
+ bool createRequest(QString verb, QJsonObject parameter);
+
+private:
+ QStringList verbs {
+ "guimetadata/subscribe",
+ };
+};
+
+#endif // GUIMETADATA_MESSAGE_H