summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCaroline Chao <caroline.chao@digia.com>2014-09-17 00:52:43 +0200
committerCaroline Chao <caroline.chao@digia.com>2014-09-17 14:38:10 +0200
commit85be990470e5fcd6baa973d83cf40f8ae8999814 (patch)
treededdf8660455add2d16d643d9de06b09c5ad15ae
parentccff7bb3878d24cccee00df04824cc0da4bccce4 (diff)
Refactor application to enable proper authentication
Use a single EnginioClient for all the application. Remove rssFeed not needed anymore. Change-Id: I0f5760abee0098aa0c99e4a65ccee716dca7a3fb Reviewed-by: Niels Weber <niels.weber@digia.com>
-rw-r--r--qml/components/ConferenceHeader.qml18
-rw-r--r--qml/components/DaySwitcher.qml2
-rw-r--r--qml/components/DayTracksModel.qml13
-rw-r--r--qml/components/HomeScreen.qml20
-rw-r--r--qml/components/ModelsSingleton.qml162
-rw-r--r--qml/components/Track.qml8
-rw-r--r--qml/components/TrackHeader.qml8
-rw-r--r--qml/components/TweetModel.qml2
-rw-r--r--qml/main.qml10
-rw-r--r--src/applicationclient.cpp174
-rw-r--r--src/applicationclient.h105
-rw-r--r--src/fileio.cpp10
-rw-r--r--src/fileio.h1
-rw-r--r--src/main.cpp6
-rw-r--r--src/model.cpp45
-rw-r--r--src/model.h16
-rw-r--r--talk-schedule.pro6
17 files changed, 409 insertions, 197 deletions
diff --git a/qml/components/ConferenceHeader.qml b/qml/components/ConferenceHeader.qml
index 0a454a3..914ee04 100644
--- a/qml/components/ConferenceHeader.qml
+++ b/qml/components/ConferenceHeader.qml
@@ -107,23 +107,17 @@ Item {
id: locationMenu
Instantiator {
id: menuConferenceRepeater
- model: ModelsSingleton.conferencesModel.rowCount()
+ model: applicationClient.conferencesModel.rowCount()
MenuItem {
- text: ModelsSingleton.conferencesModel.data(index, "title")
- onTriggered: {
- ModelsSingleton.conferenceId = ModelsSingleton.conferencesModel.data(index, "id")
- ModelsSingleton.conferenceLocation = ModelsSingleton.conferencesModel.data(index, "location")
- ModelsSingleton.conferenceTitle = ModelsSingleton.conferencesModel.data(index, "title")
- ModelsSingleton.conferenceTwitterTag = ModelsSingleton.conferencesModel.data(index, "TwitterTag")
- ModelsSingleton.rssFeed = ModelsSingleton.conferencesModel.data(index, "rssFeed")
- }
+ text: applicationClient.conferencesModel.data(index, "title")
+ onTriggered: applicationClient.setCurrentConferenceIndex(index)
}
onObjectAdded: locationMenu.insertItem(locationMenu.items.length, object)
}
Connections {
- target: ModelsSingleton.conferencesModel
- onDataReady: menuConferenceRepeater.model = ModelsSingleton.conferencesModel.rowCount()
+ target: applicationClient.conferencesModel
+ onDataReady: menuConferenceRepeater.model = applicationClient.conferencesModel.rowCount()
}
}
@@ -149,7 +143,7 @@ Item {
anchors.left: locationImage.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: Theme.margins.ten
- text: ModelsSingleton.conferenceLocation
+ text: applicationClient.currentConferenceDetails.location
font.pointSize: Theme.fonts.ten_pt
font.capitalization: Font.AllUppercase
font.weight: Font.DemiBold
diff --git a/qml/components/DaySwitcher.qml b/qml/components/DaySwitcher.qml
index 84ce6e7..2c485a0 100644
--- a/qml/components/DaySwitcher.qml
+++ b/qml/components/DaySwitcher.qml
@@ -61,7 +61,7 @@ Rectangle {
Item { Layout.fillWidth: true; width:Theme.margins.five; Layout.preferredHeight: 1 }
Label {
id: locationLabel
- text: ModelsSingleton.conferenceLocation
+ text: applicationClient.currentConferenceDetails.location
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.pointSize: Theme.fonts.seven_pt
diff --git a/qml/components/DayTracksModel.qml b/qml/components/DayTracksModel.qml
index 8b095ef..df28c55 100644
--- a/qml/components/DayTracksModel.qml
+++ b/qml/components/DayTracksModel.qml
@@ -53,16 +53,21 @@ QtObject {
property bool isEmpty: false
property var modelTracks: SortFilterModel {
+
property bool ready
+
+ function init()
+ {
+ isEmpty = modelTracks.rowCount() === 0
+ ready = Qt.binding(function() {return modelTracks.rowCount() > 0})
+ }
+
sortRole: "start"
filterRole: "track"
filterRegExp: new RegExp(dayId)
model: ModelsSingleton.eventModel
hide: true
- Component.onCompleted: {
- isEmpty = modelTracks.rowCount() === 0
- ready = Qt.binding(function() {return modelTracks.rowCount() > 0})
- }
+ Component.onCompleted: init()
onReadyChanged: {
// calculate number of rows needed for the current track
numberCollidingEvents = 0
diff --git a/qml/components/HomeScreen.qml b/qml/components/HomeScreen.qml
index 857b539..42988af 100644
--- a/qml/components/HomeScreen.qml
+++ b/qml/components/HomeScreen.qml
@@ -117,19 +117,31 @@ Rectangle {
SortFilterModel {
id: sortModelNextEvents
+
+ function init()
+ {
+ if (sortModelNextEvents.rowCount() > 0)
+ upcomingItem.visibleDate = Qt.formatDate(sortModelNextEvents.get(0, "start"), upcomingItem.formatDate)
+ }
+
sortRole: "start"
filterRole: "fromNow"
maximumCount: 7
model: ModelsSingleton.eventModel
- Component.onCompleted: {
- if (sortModelNextEvents.rowCount() > 0)
- upcomingItem.visibleDate = Qt.formatDate(sortModelNextEvents.get(0, "start"), upcomingItem.formatDate)
+ Component.onCompleted: init()
+ }
+
+ Connections {
+ target: ModelsSingleton.eventModel
+ onDataReady: {
+ sortModelNextEvents.model = ModelsSingleton.eventModel
+ sortModelNextEvents.init()
}
}
Text {
id: labelUpcoming
- text: Theme.text.upcoming.arg(ModelsSingleton.conferenceTitle).arg(upcomingItem.visibleDate)
+ text: Theme.text.upcoming.arg(applicationClient.currentConferenceDetails.title).arg(upcomingItem.visibleDate)
width: parent.width
height: Theme.sizes.homeTitleHeight
z: 1
diff --git a/qml/components/ModelsSingleton.qml b/qml/components/ModelsSingleton.qml
index cc7e1c6..e5f6e18 100644
--- a/qml/components/ModelsSingleton.qml
+++ b/qml/components/ModelsSingleton.qml
@@ -46,45 +46,14 @@ import TalkSchedule 1.0
QtObject {
id: object
property string conferenceId: ""
- property string currentUserId
- property string conferenceLocation
- property string conferenceTitle
- property string conferenceTwitterTag
- property string rssFeed
property var currentConferenceTracks: []
property var currentConferenceEvents: []
property var currentConferenceDays: []
property bool busy: false
property string errorMessage
property int conferenceIndex: 0
- property var conference
- property var client: EnginioClient {
- backendId: backId
- onError: {
- errorMessage = reply.errorString
- console.log("Enginio error " + reply.errorCode + ": " + reply.errorString)
- }
- Component.onCompleted: conferencesModel.query({"objectType": "objects.Conference"})
- }
-
- signal writeUserIdToFile(string userId)
-
- property var conferencesModel: Model {
- backendId: backId
- fileNameTag: "ConferencesObject"
- onDataReady: {
- if (conferencesModel.rowCount() > 0) {
- object.conferenceId = conferencesModel.data(0, "id")
- object.conferenceLocation = conferencesModel.data(0, "location")
- object.conferenceTitle = conferencesModel.data(0, "title")
- object.conferenceTwitterTag = conferencesModel.data(0, "TwitterTag")
- object.rssFeed = conferencesModel.data(0, "rssFeed")
- }
- }
- }
property var day: Model {
- backendId: backId
fileNameTag: "DayObject"
onDataReady: {
currentConferenceDays = []
@@ -95,7 +64,6 @@ QtObject {
}
property var trackModel: Model {
- backendId: backId
fileNameTag: "TrackObject"
onDataReady: {
currentConferenceTracks = []
@@ -107,7 +75,6 @@ QtObject {
property var eventModel: Model {
id: eventModel
- backendId: backId
fileNameTag: "EventObject"
onDataReady: queryFavorites()
function queryFavorites()
@@ -121,37 +88,39 @@ QtObject {
property var favoriteModel: Model {
// do not save favorite
- backendId: backId
onDataReady: getFavoriteIds()
}
property var breakModel: Model {
fileNameTag: "BreakObject"
- backendId: backId
}
property var timeListModel: Model {
// do not save time list
- backendId: backId
property var tracksTodayModel
onTracksTodayModelChanged: {
if (!!tracksTodayModel) {
var todaysTracks = []
for (var i = 0; i < tracksTodayModel.rowCount(); i++)
todaysTracks.push(tracksTodayModel.data(i, "id"))
- timeListModel.query({ "objectType": "objects.Event",
+ var timeQuery = applicationClient.client.query({ "objectType": "objects.Event",
"sort" : [{"sortBy": "start", "direction": "asc"}],
"query": { "track.id" : { "$in" : todaysTracks } }
})
+ timeQuery.finished.connect(function() {
+ timeListModel.onFinished(timeQuery)
+ })
}
}
}
function queryConferenceEvents()
{
- eventModel.query({
+ var eventQuery = applicationClient.client.query({
"objectType": "objects.Event",
"query": { "track.id" : { "$in" : currentConferenceTracks } },
+ "sort" : [{"sortBy": "start", "direction": "asc"}],
+ "limit": 200,
"include": {
"tracks": {
"objectType": "objects.Track",
@@ -160,14 +129,20 @@ QtObject {
}
}
})
+ eventQuery.finished.connect(function() {
+ eventModel.onFinished(eventQuery)
+ })
}
function queryConferenceBreaks()
{
- breakModel.query({
+ var breakQuery = applicationClient.client.query({
"objectType": "objects.Break",
"query": { "day.id" : { "$in" : currentConferenceDays } },
})
+ breakQuery.finished.connect(function() {
+ breakModel.onFinished(breakQuery)
+ })
}
function getFavoriteIds()
@@ -178,9 +153,8 @@ QtObject {
function queryUserConferenceFavorites()
{
- var favQuery = favoriteModel.query({ "objectType": "objects.Favorite",
+ var favQuery = applicationClient.client.query({ "objectType": "objects.Favorite",
"query": {
- "user.id": currentUserId,
"favoriteEvent.id" : { "$in" : currentConferenceEvents }
},
"include": {
@@ -198,58 +172,22 @@ QtObject {
}
}
})
- }
-
- function retrieveUser(userId)
- {
- currentUserId = userId
- if (currentUserId.length === 0)
- createUser()
- else
- getUser()
- }
-
- function createUser()
- {
- console.log("createUser")
- var reply = client.create({"objectType":"objects.User"})
- var userId = 0
- reply.finished.connect(function() {
- if (reply.errorType !== EnginioReply.NoError) {
- console.log("Failed to create an user:\n" + JSON.stringify(reply.data, undefined, 2) + "\n\n")
- } else {
- console.log("Account Created.")
- userId = reply.data.id
- writeUserIdToFile(userId)
- currentUserId = userId
- }
- })
- }
-
- function getUser()
- {
- console.log("get user")
- var queryUser = client.query({"objectType":"objects.User", "query" : { "id" : currentUserId }})
- queryUser.finished.connect(function() {
- if (queryUser.errorType !== EnginioReply.NoError || queryUser.data.results[0] === undefined) {
- // User not found. Create new one
- createUser()
- }
+ favQuery.finished.connect(function() {
+ favoriteModel.onFinished(favQuery)
})
}
function saveFeedback(fbtext, eventId, rating)
{
console.log("saveFeedback")
- var reply = client.create({
+ var reply = applicationClient.client.create({
"objectType": "objects.Feedback",
"event": {
"id": eventId,
"objectType": "objects.Event"
},
"rating": rating,
- "feedbackText": fbtext,
- "userId": currentUserId
+ "feedbackText": fbtext
})
reply.finished.connect(function() {
if (reply.errorType !== EnginioReply.NoError) {
@@ -268,15 +206,13 @@ QtObject {
}
busy = true
console.log("start saving favorite")
- var reply = client.create({
+ var reply = applicationClient.client.create({
"objectType": "objects.Favorite",
"favoriteEvent": {
"id": saveEventId,
"objectType": "objects.Event"
- },
- "user": {
- "id": currentUserId,
- "objectType": "objects.User"}})
+ }
+ })
reply.finished.connect(function() {
if (reply.errorType !== EnginioReply.NoError)
@@ -296,15 +232,13 @@ QtObject {
}
busy = true
console.log("start removing favorite. First get the favorite id which should be removed")
- var favoriteQuery = client.query({
+ var favoriteQuery = applicationClient.client.query({
"objectType": "objects.Favorite",
"query":{
"favoriteEvent": {
"id": removeEventId,
"objectType": "objects.Event"},
- "user": {
- "id": currentUserId ,
- "objectType": "objects.User"}}
+ }
})
favoriteQuery.finished.connect(function() {
@@ -314,8 +248,9 @@ QtObject {
else {
if (favoriteQuery.data.results.length > 0) {
// Now do the actual removal
- var reply = client.remove({ "objectType": "objects.Favorite",
- "id": favoriteQuery.data.results[0].id })
+ var reply = applicationClient.client.remove({ "objectType": "objects.Favorite",
+ "id": favoriteQuery.data.results[0].id
+ })
reply.finished.connect(function() {
if (favoriteQuery.errorType !== EnginioReply.NoError)
console.log("Failed to remove an Favorite:\n" + JSON.stringify(reply.data, undefined, 2) + "\n\n")
@@ -323,15 +258,15 @@ QtObject {
eventModel.removeFavorite(removeEventId)
})
}
+ console.log("favorite remove done")
}
- console.log("favorite remove done")
busy = false
})
}
onConferenceIdChanged: {
if (object.conferenceId === "")
- return
+ return
object.day.conferenceId = conferenceId
object.trackModel.conferenceId = conferenceId
@@ -340,21 +275,28 @@ QtObject {
object.breakModel.conferenceId = conferenceId
object.timeListModel.conferenceId = conferenceId
- day.query({ "objectType": "objects.Day",
- "query": {
- "conference": {
- "id": object.conferenceId,
- "objectType": "objects.Conference"
- }
- }
- })
- trackModel.query({"objectType": "objects.Track",
- "query": {
- "conference": {
- "id": object.conferenceId,
- "objectType": "objects.Conference"
- }
- }
- });
+ var dayQuery = applicationClient.client.query({ "objectType": "objects.Day",
+ "query": {
+ "conference": {
+ "id": object.conferenceId,
+ "objectType": "objects.Conference"
+ }
+ }
+ })
+ dayQuery.finished.connect(function() {
+ day.onFinished(dayQuery)
+ })
+
+ var tracksQuery = applicationClient.client.query({"objectType": "objects.Track",
+ "query": {
+ "conference": {
+ "id": object.conferenceId,
+ "objectType": "objects.Conference"
+ }
+ }
+ });
+ tracksQuery.finished.connect(function() {
+ trackModel.onFinished(tracksQuery)
+ })
}
}
diff --git a/qml/components/Track.qml b/qml/components/Track.qml
index fea4035..275f586 100644
--- a/qml/components/Track.qml
+++ b/qml/components/Track.qml
@@ -58,6 +58,14 @@ Row {
onIsReady: repeater1.model = rowsArray.length
}
+ Connections {
+ target: ModelsSingleton.eventModel
+ onDataReady: {
+ dayTracksModel.modelTracks.model = ModelsSingleton.eventModel
+ dayTracksModel.modelTracks.init()
+ }
+ }
+
Column {
id: column
width: parent.width
diff --git a/qml/components/TrackHeader.qml b/qml/components/TrackHeader.qml
index 65b7ec5..1e7fe13 100644
--- a/qml/components/TrackHeader.qml
+++ b/qml/components/TrackHeader.qml
@@ -68,6 +68,14 @@ ListView {
dayId: id
}
+ Connections {
+ target: ModelsSingleton.eventModel
+ onDataReady: {
+ dayTracksModel.modelTracks.model = ModelsSingleton.eventModel
+ dayTracksModel.modelTracks.init()
+ }
+ }
+
height: !dayTracksModel.isEmpty ? trackHeight * ( dayTracksModel.numberCollidingEvents + 1 ): 0
width: Theme.sizes.trackHeaderWidth
visible: !dayTracksModel.isEmpty
diff --git a/qml/components/TweetModel.qml b/qml/components/TweetModel.qml
index 78720ea..e9aec27 100644
--- a/qml/components/TweetModel.qml
+++ b/qml/components/TweetModel.qml
@@ -61,7 +61,7 @@ Item {
var req = new XMLHttpRequest;
req.open("GET", "https://api.twitter.com/1.1/search/tweets.json?" +
- "count=10&q=" + encodePhrase(ModelsSingleton.conferenceTwitterTag) + "-filter:retweets");
+ "count=10&q=" + encodePhrase(applicationClient.currentConferenceDetails.TwitterTag) + "-filter:retweets");
req.setRequestHeader("Authorization", "Bearer " + bearerToken);
req.onreadystatechange = function() {
status = req.readyState;
diff --git a/qml/main.qml b/qml/main.qml
index 6997bf7..b2245e6 100644
--- a/qml/main.qml
+++ b/qml/main.qml
@@ -53,14 +53,10 @@ ApplicationWindow {
color: Theme.colors.white
- FileIO {
- id: userIdFile
- Component.onCompleted: ModelsSingleton.retrieveUser(read())
- }
-
Connections {
- target: ModelsSingleton
- onWriteUserIdToFile: userIdFile.write(userId)
+ target: applicationClient
+ onCurrentConferenceIdChanged: ModelsSingleton.conferenceId = applicationClient.currentConferenceId
+ onError: ModelsSingleton.errorMessage = errorMessage
}
ConferenceHeader {
diff --git a/src/applicationclient.cpp b/src/applicationclient.cpp
new file mode 100644
index 0000000..3a2444d
--- /dev/null
+++ b/src/applicationclient.cpp
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "applicationclient.h"
+#include <Enginio/enginioclient.h>
+#include <Enginio/enginiomodel.h>
+#include <Enginio/enginioreply.h>
+#include <Enginio/enginiooauth2authentication.h>
+#include <QJsonObject>
+#include "fileio.h"
+#include "model.h"
+#include <QStringList>
+#include <QDebug>
+#include <QTimer>
+
+#define QUOTE_(x) #x
+#define QUOTE(x) QUOTE_(x)
+#define BACKEND_ID QUOTE(TALK_SCHEDULE_BACKEND_ID)
+
+ApplicationClient::ApplicationClient()
+{
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), this, SLOT(authenticate()));
+
+ m_userData = new FileIO(this);
+ authenticator = new EnginioOAuth2Authentication(this);
+ m_client = new EnginioClient(this);
+ const QByteArray backId = QByteArray(BACKEND_ID);
+ m_client->setBackendId(backId);
+
+ m_conferenceModel = new Model(this);
+ m_conferenceModel->setFileNameTag("ConferencesObject");
+
+ connect(m_client, SIGNAL(sessionAuthenticated(EnginioReply*)), this, SLOT(authenticationSuccess(EnginioReply*)));
+ connect(m_client, SIGNAL(sessionAuthenticationError(EnginioReply*)), this, SLOT(errorClient(EnginioReply*)));
+ connect(m_client, SIGNAL(error(EnginioReply*)), this, SLOT(errorClient(EnginioReply*)));
+ getUserCredentials();
+
+ m_details = new QQmlPropertyMap(this);
+ m_details->insert(QLatin1String("location"), QVariant(""));
+ m_details->insert(QLatin1String("title"), QVariant(""));
+ m_details->insert(QLatin1String("TwitterTag"), QVariant(""));
+}
+
+void ApplicationClient::errorClient(EnginioReply *reply)
+{
+ qDebug() << "Error" << reply->errorString() << m_client->authenticationState();
+ emit error(reply->errorString());
+ reply->deleteLater();
+}
+
+void ApplicationClient::getUserCredentials()
+{
+ qDebug() << "Get user credentials";
+ QString cachedUserData = m_userData->read();
+ QStringList splitData = cachedUserData.split(" ");
+ if (splitData.length() != 2) {
+ createUser();
+ } else {
+ currentUsername = splitData.at(0);
+ currentPassword = splitData.at(1);
+ authenticate();
+ }
+}
+
+void ApplicationClient::createUser()
+{
+ qDebug() << "Create User";
+ currentUsername = m_userData->createUUID();
+ currentPassword = m_userData->createUUID();
+ QJsonObject query;
+ query["objectType"] = QString::fromUtf8("users");
+ query["username"] = currentUsername;
+ query["password"] = currentPassword;
+ const EnginioReply *reply = m_client->create(query);
+ connect(reply, SIGNAL(finished(EnginioReply*)), this, SLOT(userCreationReply(EnginioReply*)));
+}
+
+void ApplicationClient::userCreationReply(EnginioReply *reply)
+{
+ if (reply->errorType() != Enginio::NoError) {
+ qDebug() << "Failed to create an user" << reply->errorString();
+ emit error(reply->errorString());
+ } else {
+ qDebug() << "User Created";
+ m_userData->write(QString("%1 %2").arg(currentUsername).arg(currentPassword));
+ authenticate();
+ }
+ reply->deleteLater();
+}
+
+void ApplicationClient::authenticate()
+{
+ qDebug() << "Authenticate" << currentUsername;
+ m_client->setIdentity(0);
+ authenticator->setUser(currentUsername);
+ authenticator->setPassword(currentPassword);
+ m_client->setIdentity(authenticator);
+}
+
+void ApplicationClient::authenticationSuccess(EnginioReply *reply)
+{
+ qDebug() << "Query the conference";
+ int timeout = (reply->data().value("expires_in").toInt() - 20*60)*1000;
+ timer->setSingleShot(true);
+ timer->start(timeout);
+ QJsonObject query;
+ query["objectType"] = QString::fromUtf8("objects.Conference");
+ const EnginioReply *replyConf = m_client->query(query);
+ connect(replyConf, SIGNAL(finished(EnginioReply*)), this, SLOT(queryConferenceReply(EnginioReply*)));
+}
+
+void ApplicationClient::setCurrentConferenceId(const QString &newConfId)
+{
+ if (m_currentConferenceId != newConfId) {
+ m_currentConferenceId = newConfId;
+ emit currentConferenceIdChanged();
+ }
+}
+
+void ApplicationClient::queryConferenceReply(EnginioReply *reply)
+{
+ m_conferenceModel->onFinished(reply);
+ emit conferencesModelChanged();
+ setCurrentConferenceIndex(0);
+}
+
+void ApplicationClient::setCurrentConferenceIndex(const int index)
+{
+ if (index > m_conferenceModel->rowCount() - 1)
+ return;
+ setCurrentConferenceId(m_conferenceModel->data(index, "id").toString());
+ m_details->insert(QLatin1String("location"),m_conferenceModel->data(index, "location"));
+ m_details->insert(QLatin1String("title"), m_conferenceModel->data(index, "title"));
+ m_details->insert(QLatin1String("TwitterTag"), m_conferenceModel->data(index, "TwitterTag"));
+ emit currentConferenceDetailsChanged();
+}
diff --git a/src/applicationclient.h b/src/applicationclient.h
new file mode 100644
index 0000000..a11bed3
--- /dev/null
+++ b/src/applicationclient.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef APPLICATIONCLIENT_H
+#define APPLICATIONCLIENT_H
+
+#include <QObject>
+#include <QString>
+#include <QtQml/QQmlPropertyMap>
+
+class EnginioClient;
+class EnginioModel;
+class EnginioOAuth2Authentication;
+class EnginioReply;
+class FileIO;
+class Model;
+class QTimer;
+
+class ApplicationClient: public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(EnginioClient *client READ client)
+ Q_PROPERTY(QString currentConferenceId READ currentConferenceId WRITE setCurrentConferenceId NOTIFY currentConferenceIdChanged)
+ Q_PROPERTY(Model *conferencesModel READ conferencesModel NOTIFY conferencesModelChanged())
+ Q_PROPERTY(QObject *currentConferenceDetails READ currentConferenceDetails NOTIFY currentConferenceDetailsChanged)
+public:
+ explicit ApplicationClient();
+ Model *conferencesModel() const { return m_conferenceModel; }
+ EnginioClient *client() { return m_client; }
+
+ QString currentConferenceId() const { return m_currentConferenceId; }
+ void setCurrentConferenceId(const QString &newConfId);
+
+ Q_INVOKABLE void setCurrentConferenceIndex(const int index);
+
+ QQmlPropertyMap *currentConferenceDetails() const { return m_details; }
+
+protected:
+ void getUserCredentials();
+ void createUser();
+
+signals:
+ void error(QString errorMessage);
+ void askQueryConferences();
+ void currentConferenceIdChanged();
+ void currentConferenceDetailsChanged();
+ void conferencesModelChanged();
+
+public slots:
+ void authenticationSuccess(EnginioReply *reply);
+ void errorClient(EnginioReply *reply);
+ void userCreationReply(EnginioReply *reply);
+ void queryConferenceReply(EnginioReply *reply);
+ void authenticate();
+
+private:
+ EnginioClient *m_client;
+ Model *m_conferenceModel;
+ FileIO *m_userData;
+ QString currentUsername;
+ QString currentPassword;
+ EnginioOAuth2Authentication *authenticator;
+ QString m_currentConferenceId;
+ QQmlPropertyMap *m_details;
+ QTimer *timer;
+};
+
+#endif // APPLICATIONCLIENT_H
diff --git a/src/fileio.cpp b/src/fileio.cpp
index 87fd174..2f18557 100644
--- a/src/fileio.cpp
+++ b/src/fileio.cpp
@@ -42,6 +42,7 @@
#include <QTextStream>
#include <QDir>
#include <QtCore/QStandardPaths>
+#include <QUuid>
#include <QDebug>
FileIO::FileIO(QObject *parent) :
@@ -97,3 +98,12 @@ bool FileIO::write(const QString &data)
return true;
}
+
+QString FileIO::createUUID()
+{
+ QString uuid = QUuid::createUuid().toString();
+ // Remove curly brackets
+ uuid.remove(0,1);
+ uuid.remove(uuid.length() - 1,1);
+ return uuid;
+}
diff --git a/src/fileio.h b/src/fileio.h
index e05bcb8..1af916b 100644
--- a/src/fileio.h
+++ b/src/fileio.h
@@ -52,6 +52,7 @@ public:
Q_INVOKABLE QString read();
Q_INVOKABLE bool write(const QString &data);
+ Q_INVOKABLE QString createUUID();
QString source() { return mSource; }
diff --git a/src/main.cpp b/src/main.cpp
index 8345eda..2f325ce 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -48,6 +48,7 @@
#include "model.h"
#include "sortfiltermodel.h"
#include "fileio.h"
+#include "applicationclient.h"
#define QUOTE_(x) #x
#define QUOTE(x) QUOTE_(x)
@@ -78,12 +79,13 @@ int main(int argc, char *argv[])
} else {
qWarning("Error: fail to load Open Sans font");
}
-
QQmlApplicationEngine engine;
- engine.rootContext()->setContextProperty("backId", QString(BACKEND_ID));
engine.rootContext()->setContextProperty("consumerKey", QString(CONSUMER_KEY));
engine.rootContext()->setContextProperty("consumerSecret", QString(CONSUMER_SECRET));
+ ApplicationClient *client = new ApplicationClient();
+ engine.rootContext()->setContextProperty("applicationClient", client);
+
const char *uri = "TalkSchedule";
// @uri TalkSchedule
qmlRegisterSingletonType<Theme>(uri, 1, 0, "Theme", systeminfo_provider);
diff --git a/src/model.cpp b/src/model.cpp
index 2ff33c9..70637b6 100644
--- a/src/model.cpp
+++ b/src/model.cpp
@@ -40,7 +40,6 @@
#include "model.h"
-#include <Enginio/enginioclient.h>
#include <Enginio/enginioreply.h>
#include <QtCore/QDebug>
#include <QtCore/QJsonValue>
@@ -54,8 +53,6 @@
Model::Model(QObject *parent)
: QAbstractListModel(parent)
{
- m_client = new EnginioClient(this);
- connect(m_client, SIGNAL(finished(EnginioReply*)), this, SLOT(onFinished(EnginioReply*)));
}
@@ -144,24 +141,12 @@ QHash<int, QByteArray> Model::roleNames() const
return m_roleNames;
}
-QString Model::backendId() const
-{
- return m_client ? m_client->backendId() : "";
-}
-
-void Model::setBackendId(const QString &id)
-{
- if (m_client && m_client->backendId() == id.toLatin1())
- return;
-
- m_client->setBackendId(id.toLatin1());
- Q_EMIT backendIdChanged();
-}
-
void Model::setConferenceId(const QString &id)
{
if (id != m_conferenceId) {
m_conferenceId = id;
+ // The file name tag has been declared before
+ load();
Q_EMIT conferenceIdChanged();
}
}
@@ -174,30 +159,6 @@ void Model::setFileNameTag(const QString &newTag)
}
}
-void Model::query(const QJSValue &query)
-{
- if (!query.hasProperty("objectType"))
- return;
-
- // Load data from file if available
- load();
-
- // Check for updates
- QJsonObject queryObject;
- queryObject["objectType"] = query.property("objectType").toString();
-
- if (query.hasProperty("query"))
- queryObject["query"] = QJsonObject::fromVariantMap(query.property("query").toVariant().toMap());
-
- if (query.hasProperty("sort"))
- queryObject["sort"] = QJsonObject::fromVariantMap(query.property("sort").toVariant().toMap());
-
- if (query.hasProperty("include"))
- queryObject["include"] = QJsonObject::fromVariantMap(query.property("include").toVariant().toMap());
-
- m_client->query(queryObject);
-}
-
QVariant Model::data(int index, const QString &role) const
{
return data(this->index(index, 0), m_roleNames.key(role.toLatin1()));
@@ -269,7 +230,7 @@ bool Model::parse(const QJsonObject &object)
{
bool dataHasChanged = true;
- dataHasChanged = fileNameTag().isEmpty() || object != currentModelObject[fileNameTag()] ;
+ dataHasChanged = fileNameTag().isEmpty() || object != currentModelObject[fileNameTag()];
if (dataHasChanged) {
beginResetModel();
diff --git a/src/model.h b/src/model.h
index 3936456..60b968a 100644
--- a/src/model.h
+++ b/src/model.h
@@ -45,18 +45,14 @@
#include <QtCore/QMap>
#include <QtCore/QList>
#include <QtQml/QJSValue>
-//#include <QtCore/QJsonDocument>
-#include <Enginio/enginioclient.h>
-//#include <Enginio/enginioreply.h>
+#include <QtCore/QJsonObject>
-QT_FORWARD_DECLARE_CLASS(EnginioClient)
-QT_FORWARD_DECLARE_CLASS(EnginioReply)
+class EnginioReply;
class Model : public QAbstractListModel
{
Q_OBJECT
- Q_PROPERTY(QString backendId READ backendId WRITE setBackendId NOTIFY backendIdChanged)
Q_PROPERTY(QString conferenceId READ conferenceId WRITE setConferenceId NOTIFY conferenceIdChanged)
Q_PROPERTY(QString fileNameTag READ fileNameTag WRITE setFileNameTag NOTIFY fileNameTagChanged)
@@ -68,15 +64,12 @@ public:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QHash<int, QByteArray> roleNames() const;
- QString backendId() const;
- void setBackendId(const QString &id);
QString conferenceId() const { return m_conferenceId; }
void setConferenceId(const QString &id);
QString fileNameTag() const { return m_fileNameTag; }
void setFileNameTag(const QString &newTag);
Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const;
- Q_INVOKABLE void query(const QJSValue &query);
Q_INVOKABLE QVariant data(int index, const QString &role) const;
Q_INVOKABLE void addFavorite(const QString &data);
Q_INVOKABLE void removeFavorite(const QString &data);
@@ -85,12 +78,12 @@ public:
Q_INVOKABLE QVariant indexOf(const QString &role, QVariant value);
Q_SIGNALS:
- void backendIdChanged();
+ void clientChanged();
void conferenceIdChanged();
void fileNameTagChanged();
void dataReady();
-private Q_SLOTS:
+public Q_SLOTS:
void onFinished(EnginioReply *reply);
private:
@@ -100,7 +93,6 @@ private:
QHash<int, QByteArray> m_roleNames;
QList<QMap<QString, QVariant> > m_data;
- EnginioClient *m_client;
QMap<QString, QJsonObject> currentModelObject;
QString m_conferenceId;
QString m_fileNameTag;
diff --git a/talk-schedule.pro b/talk-schedule.pro
index 563369b..ef2275e 100644
--- a/talk-schedule.pro
+++ b/talk-schedule.pro
@@ -14,7 +14,8 @@ SOURCES += src/main.cpp \
src/theme.cpp \
src/model.cpp \
src/sortfiltermodel.cpp \
- src/fileio.cpp
+ src/fileio.cpp \
+ src/applicationclient.cpp
OTHER_FILES += \
qml/main.qml \
@@ -45,7 +46,8 @@ HEADERS += \
src/theme.h \
src/model.h \
src/sortfiltermodel.h \
- src/fileio.h
+ src/fileio.h \
+ src/applicationclient.h
DEFINES += \
TALK_SCHEDULE_BACKEND_ID=$$TALK_SCHEDULE_BACKEND_ID \