summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Sterna <tomek@xiaoka.com>2015-01-14 22:33:35 +0100
committerTomasz Sterna <tomek@xiaoka.com>2015-01-14 22:33:35 +0100
commita73ceae865428cdfcf7022677bad5f932379fbf6 (patch)
tree6f0b994923e1c1f3ce1b3b1c89301e69a7867997
parente8f9a4da6c486ee4da9ae300019856976ff0a760 (diff)
parent0da3325dcab2ebd419d1d0b1a59428f3201a5732 (diff)
Merge pull request #29 from smurfy/pebble-store
Pebble store support
-rw-r--r--app/app.pro11
-rw-r--r--app/pebble.cpp3
-rw-r--r--app/pebblestoreview.cpp149
-rw-r--r--app/pebblestoreview.h52
-rw-r--r--app/qml/pages/AppStorePage.qml101
-rw-r--r--app/qml/pages/InstallAppDialog.qml4
6 files changed, 316 insertions, 4 deletions
diff --git a/app/app.pro b/app/app.pro
index 97c6232..9600919 100644
--- a/app/app.pro
+++ b/app/app.pro
@@ -2,7 +2,7 @@ TARGET = pebble
CONFIG += sailfishapp
-QT += dbus
+QT += dbus webkit quick-private webkit-private
CONFIG += c++11
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
@@ -10,11 +10,13 @@ DEFINES += APP_VERSION=\\\"$$VERSION\\\"
SOURCES += \
pebble.cpp \
pebbledinterface.cpp \
- pebbleappiconprovider.cpp
+ pebbleappiconprovider.cpp \
+ pebblestoreview.cpp
HEADERS += \
pebbledinterface.h \
- pebbleappiconprovider.h
+ pebbleappiconprovider.h \
+ pebblestoreview.h
DBUS_INTERFACES += ../org.pebbled.Watch.xml
@@ -30,7 +32,8 @@ OTHER_FILES += \
qml/images/* \
translations/*.ts \
pebble.desktop \
- pebble.png
+ pebble.png \
+ qml/pages/AppStorePage.qml
CONFIG += sailfishapp_i18n
TRANSLATIONS += translations/pebble-es.ts
diff --git a/app/pebble.cpp b/app/pebble.cpp
index 22f6ac1..dd3c915 100644
--- a/app/pebble.cpp
+++ b/app/pebble.cpp
@@ -34,6 +34,7 @@
#include <sailfishapp.h>
#include "pebbledinterface.h"
#include "pebbleappiconprovider.h"
+#include "pebblestoreview.h"
int main(int argc, char *argv[])
{
@@ -48,6 +49,8 @@ int main(int argc, char *argv[])
qmlRegisterUncreatableType<PebbledInterface>("org.pebbled", 0, 1, "PebbledInterface",
"Please use pebbled context property");
+ qmlRegisterType<PebbleStoreView>("org.pebbled", 0, 1, "PebbleStoreView");
+
QScopedPointer<QQuickView> view(SailfishApp::createView());
QScopedPointer<PebbledInterface> pebbled(new PebbledInterface);
QScopedPointer<PebbleAppIconProvider> appicons(new PebbleAppIconProvider(pebbled.data()));
diff --git a/app/pebblestoreview.cpp b/app/pebblestoreview.cpp
new file mode 100644
index 0000000..0ea5c14
--- /dev/null
+++ b/app/pebblestoreview.cpp
@@ -0,0 +1,149 @@
+#include "pebblestoreview.h"
+#include <QUrlQuery>
+#include <QStandardPaths>
+#include <QDir>
+#include <QFile>
+
+PebbleStoreView::PebbleStoreView()
+ : QQuickWebView()
+{
+ connect(this, SIGNAL(navigationRequested(QWebNavigationRequest*)), this, SLOT(onNavigationRequested(QWebNavigationRequest*)));
+
+ this->m_networkManager = new QNetworkAccessManager(this);
+ connect(this->m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onNetworkReplyFinished(QNetworkReply*)));
+
+ this->m_configUrl = QUrl("https://boot.getpebble.com/api/config/android/v1/3");
+ this->m_downloadInProgress = false;
+ emit downloadInProgressChanged();
+
+ //Fetching urls to use by the store
+ fetchData(this->m_configUrl);
+}
+
+QString PebbleStoreView::accessToken() const
+{
+ return this->m_accessToken;
+}
+
+void PebbleStoreView::setAccessToken(const QString &accessToken)
+{
+ this->m_accessToken = accessToken;
+ emit accessTokenChanged(accessToken);
+}
+
+void PebbleStoreView::logout()
+{
+ setAccessToken("");
+ setUrl(prepareUrl(this->storeConfigObject.value("webviews").toObject().value("authentication").toString()));
+}
+
+bool PebbleStoreView::loggedin()
+{
+ return (!this->m_accessToken.isEmpty());
+}
+
+bool PebbleStoreView::downloadInProgress()
+{
+ return this->m_downloadInProgress;
+}
+
+void PebbleStoreView::gotoWatchFaces()
+{
+ setUrl(prepareUrl(this->storeConfigObject.value("webviews").toObject().value("appstore/watchfaces").toString()));
+}
+
+void PebbleStoreView::gotoWatchApps()
+{
+ setUrl(prepareUrl(this->storeConfigObject.value("webviews").toObject().value("appstore/watchapps").toString()));
+}
+
+void PebbleStoreView::fetchData(QUrl url)
+{
+ QNetworkRequest request;
+ request.setUrl(url);
+ request.setRawHeader("Cache-Control", "no-cache");
+ this->m_networkManager->get(request);
+}
+
+void PebbleStoreView::onNetworkReplyFinished(QNetworkReply* reply)
+{
+ qDebug()<<"Download finished";
+ if (reply->request().url() == this->m_configUrl) {
+ QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll());
+ QJsonObject jsonObject = jsonResponse.object();
+ this->storeConfigObject = jsonObject.value("config").toObject();
+
+ if (this->m_accessToken.isEmpty()) {
+ setUrl(prepareUrl(this->storeConfigObject.value("webviews").toObject().value("authentication").toString()));
+ } else {
+ setUrl(prepareUrl(this->storeConfigObject.value("webviews").toObject().value("onboarding/get_some_apps").toString()));
+ }
+ } else {
+ QDir dataDir(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
+ QFile file(dataDir.absoluteFilePath("apps") + "/" + this->downloadObject.value("uuid").toString() + ".pbw");
+ file.open(QIODevice::WriteOnly);
+ file.write(reply->readAll());
+ file.close();
+
+ qDebug()<<this->downloadObject;
+
+ this->m_downloadInProgress = false;
+ emit downloadInProgressChanged();
+ }
+}
+
+QUrl PebbleStoreView::prepareUrl(QString baseUrl)
+{
+ baseUrl = baseUrl.replace("$$user_id$$", "ZZZ");
+ baseUrl = baseUrl.replace("$$phone_id$$", "XXX");
+ baseUrl = baseUrl.replace("$$pebble_id$$", "YYY");
+ baseUrl = baseUrl.replace("$$access_token$$", this->m_accessToken);
+
+ qDebug()<<baseUrl;
+
+ return QUrl(baseUrl);
+}
+
+void PebbleStoreView::onNavigationRequested(QWebNavigationRequest* request)
+{
+ if (request->url().scheme() == "pebble") {
+ if (request->url().host() == "login") {
+ QUrlQuery *accessTokenFragment = new QUrlQuery(request->url().fragment());
+ this->m_accessToken = accessTokenFragment->queryItemValue("access_token");
+ emit accessTokenChanged(accessTokenFragment->queryItemValue("access_token"));
+ setUrl(prepareUrl(this->storeConfigObject.value("webviews").toObject().value("onboarding/get_some_apps").toString()));
+ }
+ }
+ if (request->url().scheme() == "pebble-method-call-js-frame") {
+ QString urlStr = "";
+
+ //Basic parse error string
+ QRegExp reg(".*; source was \"(.*)\";.*");
+ reg.setMinimal(true);
+ if (reg.indexIn(request->url().errorString()) > -1) {
+ urlStr = reg.cap(1);
+ reg.setPattern("method=(.*)&args=(.*)$");
+ reg.setMinimal(true);
+ if (reg.indexIn(urlStr) > -1) {
+ QString methodStr = reg.cap(1);
+ QString argsStr = QUrl::fromPercentEncoding(reg.cap(2).toUtf8());
+ emit call(methodStr, argsStr);
+ if (methodStr == "loadAppToDeviceAndLocker") {
+ QJsonDocument jsonResponse = QJsonDocument::fromJson(argsStr.toUtf8());
+ QJsonObject jsonObject = jsonResponse.object();
+ QJsonObject data = jsonObject.value("data").toObject();
+ qDebug()<<"download"<<data.value("title").toString()<<data.value("pbw_file").toString();
+ this->downloadObject = data;;
+ this->m_downloadInProgress = true;
+ emit downloadInProgressChanged();
+ fetchData(QUrl(data.value("pbw_file").toString()));
+ emit downloadPebbleApp(data.value("title").toString(), data.value("pbw_file").toString());
+ }
+ }
+ }
+ }
+}
+
+
+
+
diff --git a/app/pebblestoreview.h b/app/pebblestoreview.h
new file mode 100644
index 0000000..a19b43d
--- /dev/null
+++ b/app/pebblestoreview.h
@@ -0,0 +1,52 @@
+#ifndef PEBBLESTOREVIEW_H
+#define PEBBLESTOREVIEW_H
+
+#include <private/qquickwebview_p.h>
+#include <private/qwebnavigationrequest_p.h>
+#include <QNetworkReply>
+#include <QNetworkAccessManager>
+#include <QJsonDocument>
+#include <QJsonObject>
+
+class PebbleStoreView : public QQuickWebView
+{
+ Q_OBJECT
+public:
+ PebbleStoreView();
+ Q_PROPERTY(bool loggedin READ loggedin NOTIFY accessTokenChanged)
+ Q_PROPERTY(bool downloadInProgress READ downloadInProgress NOTIFY downloadInProgressChanged)
+ Q_PROPERTY(QString accessToken READ accessToken WRITE setAccessToken NOTIFY accessTokenChanged)
+
+ bool loggedin();
+ bool downloadInProgress();
+ QString accessToken() const;
+ void setAccessToken(const QString &accessToken);
+
+public slots:
+ void gotoWatchFaces();
+ void gotoWatchApps();
+ void logout();
+
+private slots:
+ void onNavigationRequested(QWebNavigationRequest* request);
+ void onNetworkReplyFinished(QNetworkReply* reply);
+
+signals:
+ void accessTokenChanged(const QString & accessToken);
+ void downloadPebbleApp(const QString & downloadTitle, const QString & downloadUrl);
+ void downloadInProgressChanged();
+ void call(const QString &, const QString &);
+
+private:
+ QNetworkAccessManager* m_networkManager;
+ QUrl m_configUrl;
+ QString m_accessToken;
+ QJsonObject downloadObject;
+ QJsonObject storeConfigObject;
+ bool m_downloadInProgress;
+
+ QUrl prepareUrl(QString baseUrl);
+ void fetchData(QUrl url);
+};
+
+#endif // PEBBLESTOREVIEW_H
diff --git a/app/qml/pages/AppStorePage.qml b/app/qml/pages/AppStorePage.qml
new file mode 100644
index 0000000..680ac50
--- /dev/null
+++ b/app/qml/pages/AppStorePage.qml
@@ -0,0 +1,101 @@
+import QtQuick 2.0
+import QtQml 2.1
+import Sailfish.Silica 1.0
+import org.pebbled 0.1
+import org.nemomobile.configuration 1.0
+
+Page {
+ id: page
+
+ ConfigurationGroup {
+ id: settings
+ path: "/org/pebbled/settings"
+ property string storeAccessToken: ""
+ }
+
+ SilicaFlickable {
+ id: flickable
+ anchors.fill: parent
+ contentHeight: column.height + webview.height
+
+ PullDownMenu {
+ visible: webview.loggedin;
+
+ MenuItem {
+ text: qsTr("Logout")
+ onClicked: {
+ webview.logout();
+ }
+ }
+ }
+
+ Column {
+ id: column
+ width: page.width
+ spacing: Theme.paddingLarge
+
+ PageHeader {
+ title: qsTr("Pebble Appstore")
+ }
+
+ Row {
+ anchors.horizontalCenter: parent.horizontalCenter
+ visible: webview.loggedin;
+ Button {
+ text: qsTr("WatchApps")
+ onClicked: {
+ webview.gotoWatchApps();
+ }
+ }
+ Button {
+ text: qsTr("WatchFaces")
+ onClicked: {
+ webview.gotoWatchFaces();
+ }
+ }
+ }
+
+ Column {
+ id: download
+ visible: webview.downloadInProgress
+ width: parent.width
+
+ Label {
+ anchors.horizontalCenter: parent.horizontalCenter
+ id: downloadLabel
+ text: qsTr("Downloading...")
+ }
+
+ BusyIndicator {
+ anchors.horizontalCenter: parent.horizontalCenter
+ running: true
+ size: BusyIndicatorSize.Large
+ }
+ }
+ }
+
+ PebbleStoreView {
+ id: webview
+ visible: !webview.downloadInProgress
+ width: page.width
+ height: page.height - column.height
+
+ anchors {
+ top: column.bottom
+ }
+
+ accessToken: settings.storeAccessToken
+
+ onAccessTokenChanged: {
+ settings.storeAccessToken = accessToken;
+ }
+
+ onDownloadPebbleApp: {
+ downloadLabel.text = qsTr("Downloading %1...").arg(downloadTitle)
+ }
+ }
+ }
+
+
+}
+
diff --git a/app/qml/pages/InstallAppDialog.qml b/app/qml/pages/InstallAppDialog.qml
index ecc3d78..4661cf0 100644
--- a/app/qml/pages/InstallAppDialog.qml
+++ b/app/qml/pages/InstallAppDialog.qml
@@ -84,6 +84,10 @@ Dialog {
}
}
+ MenuItem {
+ text: qsTr("Pebble Appstore")
+ onClicked: pageStack.push(Qt.resolvedUrl("AppStorePage.qml"))
+ }
}
currentIndex: -1