From b072d41d8487460d81bba218930678b606a1305b Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 19 Oct 2017 10:43:34 +0200 Subject: [PATCH] Work on loading of gmail messages. --- src/core/feedsproxymodel.cpp | 8 ++- src/services/abstract/rootitem.cpp | 10 ++- src/services/abstract/rootitem.h | 5 ++ src/services/gmail/definitions.h | 1 + src/services/gmail/gmailfeed.cpp | 13 ++-- src/services/gmail/gmailserviceroot.cpp | 6 +- .../gmail/network/gmailnetworkfactory.cpp | 63 ++++++++++++++----- .../gmail/network/gmailnetworkfactory.h | 3 +- 8 files changed, 82 insertions(+), 27 deletions(-) diff --git a/src/core/feedsproxymodel.cpp b/src/core/feedsproxymodel.cpp index ba96664cb..40704fd31 100755 --- a/src/core/feedsproxymodel.cpp +++ b/src/core/feedsproxymodel.cpp @@ -136,7 +136,13 @@ bool FeedsProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right // Moreover, sort everything alphabetically or // by item counts, depending on the sort column. - if (left_item->kind() == right_item->kind()) { + if (left_item->keepOnTop()) { + return sortOrder() == Qt::AscendingOrder; + } + else if (right_item->keepOnTop()) { + return sortOrder() == Qt::DescendingOrder; + } + else if (left_item->kind() == right_item->kind()) { // Both items are feeds or both items are categories. if (left.column() == FDS_MODEL_COUNTS_INDEX) { // User wants to sort according to counts. diff --git a/src/services/abstract/rootitem.cpp b/src/services/abstract/rootitem.cpp index 1dcc8aee8..fafba324e 100755 --- a/src/services/abstract/rootitem.cpp +++ b/src/services/abstract/rootitem.cpp @@ -13,7 +13,7 @@ RootItem::RootItem(RootItem* parent_item) : QObject(nullptr), m_kind(RootItemKind::Root), m_id(NO_PARENT_CATEGORY), m_customId(QSL("")), m_title(QString()), m_description(QString()), m_icon(QIcon()), m_creationDate(QDateTime()), - m_childItems(QList()), m_parentItem(parent_item) {} + m_keepOnTop(false), m_childItems(QList()), m_parentItem(parent_item) {} RootItem::RootItem(const RootItem& other) : RootItem(nullptr) { setTitle(other.title()); @@ -438,6 +438,14 @@ ServiceRoot* RootItem::toServiceRoot() const { return static_cast(const_cast(this)); } +bool RootItem::keepOnTop() const { + return m_keepOnTop; +} + +void RootItem::setKeepOnTop(bool keep_on_top) { + m_keepOnTop = keep_on_top; +} + int RootItem::countOfUnreadMessages() const { int total_count = 0; diff --git a/src/services/abstract/rootitem.h b/src/services/abstract/rootitem.h index 78db08e0e..b75473439 100755 --- a/src/services/abstract/rootitem.h +++ b/src/services/abstract/rootitem.h @@ -54,6 +54,7 @@ class RootItem : public QObject { explicit RootItem(const RootItem& other); virtual ~RootItem(); + // Determines if this item should be kept always in the beginning of feeds list. virtual QString hashCode() const; virtual QString additionalTooltip() const; @@ -202,6 +203,9 @@ class RootItem : public QObject { Feed* toFeed() const; ServiceRoot* toServiceRoot() const; + bool keepOnTop() const; + void setKeepOnTop(bool keep_on_top); + private: RootItemKind::Kind m_kind; int m_id; @@ -210,6 +214,7 @@ class RootItem : public QObject { QString m_description; QIcon m_icon; QDateTime m_creationDate; + bool m_keepOnTop; QList m_childItems; RootItem* m_parentItem; diff --git a/src/services/gmail/definitions.h b/src/services/gmail/definitions.h index 1e3ab4b58..2e8a20bcd 100755 --- a/src/services/gmail/definitions.h +++ b/src/services/gmail/definitions.h @@ -8,6 +8,7 @@ #define GMAIL_OAUTH_SCOPE "https://mail.google.com/" #define GMAIL_API_LABELS_LIST "https://www.googleapis.com/gmail/v1/users/me/labels" +#define GMAIL_API_MSGS_LIST "https://www.googleapis.com/gmail/v1/users/me/messages" #define GMAIL_DEFAULT_BATCH_SIZE 100 #define GMAIL_MAX_BATCH_SIZE 999 diff --git a/src/services/gmail/gmailfeed.cpp b/src/services/gmail/gmailfeed.cpp index b910a4d06..66d868c39 100755 --- a/src/services/gmail/gmailfeed.cpp +++ b/src/services/gmail/gmailfeed.cpp @@ -23,15 +23,14 @@ GmailServiceRoot* GmailFeed::serviceRoot() const { QList GmailFeed::obtainNewMessages(bool* error_during_obtaining) { Feed::Status error; + QList messages = serviceRoot()->network()->messages(customId(), error); - // TODO: dodělat - QList messages;/* = serviceRoot()->network()->messages(customId(), error); + setStatus(error); - setStatus(error); - - if (error == Feed::Status::NetworkError || error == Feed::Status::AuthError) { - * error_during_obtaining = true; - }*/ + if (error == Feed::Status::NetworkError || error == Feed::Status::AuthError || + error == Feed::Status::ParsingError) { + *error_during_obtaining = true; + } return messages; } diff --git a/src/services/gmail/gmailserviceroot.cpp b/src/services/gmail/gmailserviceroot.cpp index 29ee64d2a..fe29c00ea 100755 --- a/src/services/gmail/gmailserviceroot.cpp +++ b/src/services/gmail/gmailserviceroot.cpp @@ -48,7 +48,11 @@ void GmailServiceRoot::updateTitle() { } void GmailServiceRoot::loadFromDatabase() { - appendChild(new GmailFeed(tr("Inbox"), QSL("INBOX"), qApp->icons()->fromTheme(QSL("mail-inbox")), this)); + GmailFeed* inbox = new GmailFeed(tr("Inbox"), QSL("INBOX"), qApp->icons()->fromTheme(QSL("mail-inbox")), this); + + inbox->setKeepOnTop(true); + + appendChild(inbox); appendChild(new GmailFeed(tr("Sent"), QSL("SENT"), qApp->icons()->fromTheme(QSL("mail-sent")), this)); appendChild(new GmailFeed(tr("Drafts"), QSL("DRAFT"), qApp->icons()->fromTheme(QSL("gtk-edit")), this)); appendChild(new GmailFeed(tr("Spam"), QSL("SPAM"), qApp->icons()->fromTheme(QSL("mail-mark-junk")), this)); diff --git a/src/services/gmail/network/gmailnetworkfactory.cpp b/src/services/gmail/network/gmailnetworkfactory.cpp index d1023a5e5..9146021ab 100755 --- a/src/services/gmail/network/gmailnetworkfactory.cpp +++ b/src/services/gmail/network/gmailnetworkfactory.cpp @@ -101,33 +101,60 @@ void GmailNetworkFactory::setUsername(const QString& username) { QList GmailNetworkFactory::messages(const QString& stream_id, Feed::Status& error) { Downloader downloader; QEventLoop loop; - QString target_url;// TODO: dodělat - // = INOREADER_API_FEED_CONTENTS; QString bearer = m_oauth2->bearer().toLocal8Bit(); + QString next_page_token; + + QList messages; if (bearer.isEmpty()) { error = Feed::Status::AuthError; return QList(); } - target_url += QSL("/") + QUrl::toPercentEncoding(stream_id) + QString("?n=%1").arg(batchSize()); - downloader.appendRawHeader(QString("Authorization").toLocal8Bit(), bearer.toLocal8Bit()); + downloader.appendRawHeader(QString(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(), bearer.toLocal8Bit()); // We need to quit event loop when the download finishes. connect(&downloader, &Downloader::completed, &loop, &QEventLoop::quit); - downloader.manipulateData(target_url, QNetworkAccessManager::Operation::GetOperation); - loop.exec(); + QString target_url; - if (downloader.lastOutputError() != QNetworkReply::NetworkError::NoError) { - error = Feed::Status::NetworkError; - return QList(); - } - else { - QString messages_data = downloader.lastOutputData(); + do { + target_url = GMAIL_API_MSGS_LIST; + target_url += QString("?labelIds=%1").arg(stream_id); - error = Feed::Status::Normal; - return decodeMessages(messages_data, stream_id); - } + if (batchSize() > 0) { + target_url += QString("&maxResults=%1").arg(batchSize()); + } + + if (!next_page_token.isEmpty()) { + target_url += QString("&pageToken=%1").arg(next_page_token); + } + + downloader.manipulateData(target_url, QNetworkAccessManager::Operation::GetOperation); + loop.exec(); + + if (downloader.lastOutputError() == QNetworkReply::NetworkError::NoError) { + // We parse this chunk. + QString messages_data = downloader.lastOutputData(); + + QList more_messages = decodeLiteMessages(messages_data, stream_id); + + // Now, we via batch HTTP request obtain full data for each message. + bool obtained = obtainAndDecodeFullMessages(more_messages); + + if (obtained) { + messages.append(more_messages); + error = Feed::Status::NetworkError; + return messages; + } + } + else { + error = Feed::Status::NetworkError; + return messages; + } + } while (!next_page_token.isEmpty()); + + error = Feed::Status::Normal; + return messages; } void GmailNetworkFactory::markMessagesRead(RootItem::ReadStatus status, const QStringList& custom_ids, bool async) { @@ -292,7 +319,11 @@ void GmailNetworkFactory::onAuthFailed() { }); } -QList GmailNetworkFactory::decodeMessages(const QString& messages_json_data, const QString& stream_id) { +bool GmailNetworkFactory::obtainAndDecodeFullMessages(const QList& lite_messages) { + return false; +} + +QList GmailNetworkFactory::decodeLiteMessages(const QString& messages_json_data, const QString& stream_id) { QList messages; QJsonArray json = QJsonDocument::fromJson(messages_json_data.toUtf8()).object()["items"].toArray(); diff --git a/src/services/gmail/network/gmailnetworkfactory.h b/src/services/gmail/network/gmailnetworkfactory.h index fa70a2d22..ebd76286e 100755 --- a/src/services/gmail/network/gmailnetworkfactory.h +++ b/src/services/gmail/network/gmailnetworkfactory.h @@ -47,7 +47,8 @@ class GmailNetworkFactory : public QObject { void onAuthFailed(); private: - QList decodeMessages(const QString& messages_json_data, const QString& stream_id); + bool obtainAndDecodeFullMessages(const QList& lite_messages); + QList decodeLiteMessages(const QString& messages_json_data, const QString& stream_id); //RootItem* decodeFeedCategoriesData(const QString& categories);