save current code and try to fix #453
This commit is contained in:
parent
68be51b99f
commit
843b4312b2
@ -30,7 +30,7 @@
|
|||||||
<url type="donation">https://martinrotter.github.io/donate/</url>
|
<url type="donation">https://martinrotter.github.io/donate/</url>
|
||||||
<content_rating type="oars-1.1" />
|
<content_rating type="oars-1.1" />
|
||||||
<releases>
|
<releases>
|
||||||
<release version="3.9.2" date="2021-07-26"/>
|
<release version="3.9.2" date="2021-07-27"/>
|
||||||
</releases>
|
</releases>
|
||||||
<content_rating type="oars-1.0">
|
<content_rating type="oars-1.0">
|
||||||
<content_attribute id="violence-cartoon">none</content_attribute>
|
<content_attribute id="violence-cartoon">none</content_attribute>
|
||||||
|
@ -127,27 +127,27 @@ void FeedDownloader::updateOneFeed(Feed* feed) {
|
|||||||
QSqlDatabase database = is_main_thread ?
|
QSqlDatabase database = is_main_thread ?
|
||||||
qApp->database()->driver()->connection(metaObject()->className()) :
|
qApp->database()->driver()->connection(metaObject()->className()) :
|
||||||
qApp->database()->driver()->connection(QSL("feed_upd"));
|
qApp->database()->driver()->connection(QSL("feed_upd"));
|
||||||
QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>> stated_messages;
|
QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>> stated_messages;
|
||||||
QHash<QString, QStringList> tagged_messages;
|
QHash<QString, QStringList> tagged_messages;
|
||||||
|
|
||||||
if (feed->getParentServiceRoot()->wantsBaggedIdsOfExistingMessages()) {
|
if (feed->getParentServiceRoot()->wantsBaggedIdsOfExistingMessages()) {
|
||||||
// This account has activated intelligent downloading of messages.
|
// This account has activated intelligent downloading of messages.
|
||||||
// Prepare bags.
|
// Prepare bags.
|
||||||
stated_messages.insert(feed->customId(),
|
QHash<ServiceRoot::BagOfMessages, QStringList> per_feed_states;
|
||||||
{ ServiceRoot::BagOfMessages::Read,
|
|
||||||
DatabaseQueries::bagOfMessages(database,
|
per_feed_states.insert(ServiceRoot::BagOfMessages::Read,
|
||||||
ServiceRoot::BagOfMessages::Read,
|
DatabaseQueries::bagOfMessages(database,
|
||||||
feed) });
|
ServiceRoot::BagOfMessages::Read,
|
||||||
stated_messages.insert(feed->customId(),
|
feed));
|
||||||
{ ServiceRoot::BagOfMessages::Unread,
|
per_feed_states.insert(ServiceRoot::BagOfMessages::Unread,
|
||||||
DatabaseQueries::bagOfMessages(database,
|
DatabaseQueries::bagOfMessages(database,
|
||||||
ServiceRoot::BagOfMessages::Unread,
|
ServiceRoot::BagOfMessages::Unread,
|
||||||
feed) });
|
feed));
|
||||||
stated_messages.insert(feed->customId(),
|
per_feed_states.insert(ServiceRoot::BagOfMessages::Starred,
|
||||||
{ ServiceRoot::BagOfMessages::Starred,
|
DatabaseQueries::bagOfMessages(database,
|
||||||
DatabaseQueries::bagOfMessages(database,
|
ServiceRoot::BagOfMessages::Starred,
|
||||||
ServiceRoot::BagOfMessages::Starred,
|
feed));
|
||||||
feed) });
|
stated_messages.insert(feed->customId(), per_feed_states);
|
||||||
|
|
||||||
tagged_messages = DatabaseQueries::bagsOfMessages(database,
|
tagged_messages = DatabaseQueries::bagsOfMessages(database,
|
||||||
feed->getParentServiceRoot()->labelsNode()->labels());
|
feed->getParentServiceRoot()->labelsNode()->labels());
|
||||||
|
@ -39,9 +39,10 @@ MessagesModelSqlLayer::MessagesModelSqlLayer()
|
|||||||
<< MSG_DB_SCORE_INDEX;
|
<< MSG_DB_SCORE_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessagesModelSqlLayer::addSortState(int column, Qt::SortOrder order) {
|
void MessagesModelSqlLayer::addSortState(int column, Qt::SortOrder order, bool ignore_multicolumn_sorting) {
|
||||||
int existing = m_sortColumns.indexOf(column);
|
int existing = m_sortColumns.indexOf(column);
|
||||||
bool is_ctrl_pressed = (QApplication::queryKeyboardModifiers() & Qt::ControlModifier) == Qt::ControlModifier;
|
bool is_ctrl_pressed = (QApplication::queryKeyboardModifiers() &
|
||||||
|
Qt::KeyboardModifier::ControlModifier) == Qt::KeyboardModifier::ControlModifier;
|
||||||
|
|
||||||
if (existing >= 0) {
|
if (existing >= 0) {
|
||||||
m_sortColumns.removeAt(existing);
|
m_sortColumns.removeAt(existing);
|
||||||
@ -55,14 +56,18 @@ void MessagesModelSqlLayer::addSortState(int column, Qt::SortOrder order) {
|
|||||||
m_sortOrders.removeAt(0);
|
m_sortOrders.removeAt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_ctrl_pressed) {
|
if (is_ctrl_pressed && !ignore_multicolumn_sorting) {
|
||||||
// User is activating the multicolumn sort mode.
|
// User is activating the multicolumn sort mode.
|
||||||
m_sortColumns.append(column);
|
m_sortColumns.append(column);
|
||||||
m_sortOrders.append(order);
|
m_sortOrders.append(order);
|
||||||
|
|
||||||
|
qDebugNN << "CTRL is pressed while sorting articles - sorting with multicolumn mode.";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_sortColumns.prepend(column);
|
m_sortColumns.prepend(column);
|
||||||
m_sortOrders.prepend(order);
|
m_sortOrders.prepend(order);
|
||||||
|
|
||||||
|
qDebugNN << "CTRL is NOT pressed while sorting articles - sorting with standard mode.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ class MessagesModelSqlLayer {
|
|||||||
explicit MessagesModelSqlLayer();
|
explicit MessagesModelSqlLayer();
|
||||||
|
|
||||||
// Adds this new state to queue of sort states.
|
// Adds this new state to queue of sort states.
|
||||||
void addSortState(int column, Qt::SortOrder order);
|
void addSortState(int column, Qt::SortOrder order, bool ignore_multicolumn_sorting);
|
||||||
|
|
||||||
// Sets SQL WHERE clause, without "WHERE" keyword.
|
// Sets SQL WHERE clause, without "WHERE" keyword.
|
||||||
void setFilter(const QString& filter);
|
void setFilter(const QString& filter);
|
||||||
|
@ -982,9 +982,10 @@ QStringList DatabaseQueries::bagOfMessages(const QSqlDatabase& db, ServiceRoot::
|
|||||||
|
|
||||||
q.prepare(QSL("SELECT custom_id "
|
q.prepare(QSL("SELECT custom_id "
|
||||||
"FROM Messages "
|
"FROM Messages "
|
||||||
"WHERE %1 AND account_id = :account_id;").arg(query));
|
"WHERE %1 AND feed = :feed AND account_id = :account_id;").arg(query));
|
||||||
|
|
||||||
q.bindValue(QSL(":account_id"), feed->getParentServiceRoot()->accountId());
|
q.bindValue(QSL(":account_id"), feed->getParentServiceRoot()->accountId());
|
||||||
|
q.bindValue(QSL(":feed"), feed->customId());
|
||||||
q.exec();
|
q.exec();
|
||||||
|
|
||||||
while (q.next()) {
|
while (q.next()) {
|
||||||
@ -1277,22 +1278,20 @@ QPair<int, int> DatabaseQueries::updateMessages(QSqlDatabase db,
|
|||||||
//
|
//
|
||||||
// 4) FOR ALL SERVICES: Message update is forced, we want to overwrite message as some arbitrary atribute was changed,
|
// 4) FOR ALL SERVICES: Message update is forced, we want to overwrite message as some arbitrary atribute was changed,
|
||||||
// this particularly happens when manual message filter execution happens.
|
// this particularly happens when manual message filter execution happens.
|
||||||
if (/* 1 */ (!message.m_customId.isEmpty() && feed->getParentServiceRoot()->isSyncable() &&
|
bool cond_1 = !message.m_customId.isEmpty() && feed->getParentServiceRoot()->isSyncable() &&
|
||||||
(message.m_created.toMSecsSinceEpoch() != date_existing_message ||
|
(message.m_created.toMSecsSinceEpoch() != date_existing_message ||
|
||||||
message.m_isRead != is_read_existing_message ||
|
message.m_isRead != is_read_existing_message ||
|
||||||
message.m_isImportant != is_important_existing_message ||
|
message.m_isImportant != is_important_existing_message ||
|
||||||
message.m_feedId != feed_id_existing_message ||
|
message.m_feedId != feed_id_existing_message ||
|
||||||
message.m_title != title_existing_message ||
|
message.m_title != title_existing_message ||
|
||||||
message.m_contents != contents_existing_message)) ||
|
message.m_contents != contents_existing_message);
|
||||||
|
bool cond_2 = !message.m_customId.isEmpty() && !feed->getParentServiceRoot()->isSyncable() &&
|
||||||
|
(message.m_title != title_existing_message ||
|
||||||
|
message.m_contents != contents_existing_message);
|
||||||
|
bool cond_3 = message.m_createdFromFeed && message.m_created.toMSecsSinceEpoch() != date_existing_message &&
|
||||||
|
message.m_contents != contents_existing_message;
|
||||||
|
|
||||||
/* 2 */ (!message.m_customId.isEmpty() && !feed->getParentServiceRoot()->isSyncable() &&
|
if (cond_1 || cond_2 || cond_3 || force_update) {
|
||||||
(message.m_title != title_existing_message ||
|
|
||||||
message.m_contents != contents_existing_message)) ||
|
|
||||||
|
|
||||||
/* 3 */ (message.m_createdFromFeed && message.m_created.toMSecsSinceEpoch() != date_existing_message &&
|
|
||||||
message.m_contents != contents_existing_message) ||
|
|
||||||
|
|
||||||
/* 4 */ force_update) {
|
|
||||||
// Message exists and is changed, update it.
|
// Message exists and is changed, update it.
|
||||||
query_update.bindValue(QSL(":title"), unnulifyString(message.m_title));
|
query_update.bindValue(QSL(":title"), unnulifyString(message.m_title));
|
||||||
query_update.bindValue(QSL(":is_read"), int(message.m_isRead));
|
query_update.bindValue(QSL(":is_read"), int(message.m_isRead));
|
||||||
|
@ -52,12 +52,15 @@ void MessagesView::reloadFontSettings() {
|
|||||||
m_sourceModel->setupFonts();
|
m_sourceModel->setupFonts();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessagesView::sort(int column, Qt::SortOrder order, bool repopulate_data, bool change_header, bool emit_changed_from_header) {
|
void MessagesView::sort(int column, Qt::SortOrder order,
|
||||||
|
bool repopulate_data, bool change_header,
|
||||||
|
bool emit_changed_from_header,
|
||||||
|
bool ignore_multicolumn_sorting) {
|
||||||
if (change_header && !emit_changed_from_header) {
|
if (change_header && !emit_changed_from_header) {
|
||||||
header()->blockSignals(true);
|
header()->blockSignals(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_sourceModel->addSortState(column, order);
|
m_sourceModel->addSortState(column, order, ignore_multicolumn_sorting);
|
||||||
|
|
||||||
if (repopulate_data) {
|
if (repopulate_data) {
|
||||||
m_sourceModel->repopulate();
|
m_sourceModel->repopulate();
|
||||||
@ -94,7 +97,7 @@ void MessagesView::reloadSelections() {
|
|||||||
const Qt::SortOrder ord = header()->sortIndicatorOrder();
|
const Qt::SortOrder ord = header()->sortIndicatorOrder();
|
||||||
|
|
||||||
// Reload the model now.
|
// Reload the model now.
|
||||||
sort(col, ord, true, false, false);
|
sort(col, ord, true, false, false, true);
|
||||||
|
|
||||||
// Now, we must find the same previously focused message.
|
// Now, we must find the same previously focused message.
|
||||||
if (selected_message.m_id > 0) {
|
if (selected_message.m_id > 0) {
|
||||||
@ -363,7 +366,7 @@ void MessagesView::loadItem(RootItem* item) {
|
|||||||
const Qt::SortOrder ord = header()->sortIndicatorOrder();
|
const Qt::SortOrder ord = header()->sortIndicatorOrder();
|
||||||
|
|
||||||
scrollToTop();
|
scrollToTop();
|
||||||
sort(col, ord, false, true, false);
|
sort(col, ord, false, true, false, true);
|
||||||
m_sourceModel->loadMessages(item);
|
m_sourceModel->loadMessages(item);
|
||||||
|
|
||||||
// Messages are loaded, make sure that previously
|
// Messages are loaded, make sure that previously
|
||||||
@ -679,7 +682,7 @@ void MessagesView::adjustColumns() {
|
|||||||
|
|
||||||
void MessagesView::onSortIndicatorChanged(int column, Qt::SortOrder order) {
|
void MessagesView::onSortIndicatorChanged(int column, Qt::SortOrder order) {
|
||||||
// Repopulate the shit.
|
// Repopulate the shit.
|
||||||
sort(column, order, true, false, false);
|
sort(column, order, true, false, false, false);
|
||||||
|
|
||||||
emit currentMessageRemoved();
|
emit currentMessageRemoved();
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,8 @@ class MessagesView : public QTreeView {
|
|||||||
void willReselectSameMessage();
|
void willReselectSameMessage();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void sort(int column, Qt::SortOrder order, bool repopulate_data, bool change_header, bool emit_changed_from_header);
|
void sort(int column, Qt::SortOrder order, bool repopulate_data,
|
||||||
|
bool change_header, bool emit_changed_from_header, bool ignore_multicolumn_sorting);
|
||||||
|
|
||||||
// Creates needed connections.
|
// Creates needed connections.
|
||||||
void createConnections();
|
void createConnections();
|
||||||
|
@ -102,7 +102,7 @@ class ServiceRoot : public RootItem {
|
|||||||
// Throws exception subclassed from ApplicationException, preferably FeedFetchException
|
// Throws exception subclassed from ApplicationException, preferably FeedFetchException
|
||||||
// if any problems arise.
|
// if any problems arise.
|
||||||
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages) = 0;
|
const QHash<QString, QStringList>& tagged_messages) = 0;
|
||||||
|
|
||||||
// This method should prepare messages for given "item" (download them maybe?)
|
// This method should prepare messages for given "item" (download them maybe?)
|
||||||
|
@ -73,7 +73,7 @@ void FeedlyServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QList<Message> FeedlyServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
QList<Message> FeedlyServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages) {
|
const QHash<QString, QStringList>& tagged_messages) {
|
||||||
Q_UNUSED(stated_messages)
|
Q_UNUSED(stated_messages)
|
||||||
Q_UNUSED(tagged_messages)
|
Q_UNUSED(tagged_messages)
|
||||||
|
@ -24,7 +24,7 @@ class FeedlyServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
|||||||
virtual QVariantHash customDatabaseData() const;
|
virtual QVariantHash customDatabaseData() const;
|
||||||
virtual void setCustomDatabaseData(const QVariantHash& data);
|
virtual void setCustomDatabaseData(const QVariantHash& data);
|
||||||
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages);
|
const QHash<QString, QStringList>& tagged_messages);
|
||||||
|
|
||||||
FeedlyNetwork* network() const;
|
FeedlyNetwork* network() const;
|
||||||
|
@ -75,7 +75,7 @@ void GmailServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QList<Message> GmailServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
QList<Message> GmailServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages) {
|
const QHash<QString, QStringList>& tagged_messages) {
|
||||||
Q_UNUSED(stated_messages)
|
Q_UNUSED(stated_messages)
|
||||||
Q_UNUSED(tagged_messages)
|
Q_UNUSED(tagged_messages)
|
||||||
|
@ -32,7 +32,7 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
|||||||
virtual QVariantHash customDatabaseData() const;
|
virtual QVariantHash customDatabaseData() const;
|
||||||
virtual void setCustomDatabaseData(const QVariantHash& data);
|
virtual void setCustomDatabaseData(const QVariantHash& data);
|
||||||
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages);
|
const QHash<QString, QStringList>& tagged_messages);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#define GREADER_API_SUBSCRIPTION_LIST "reader/api/0/subscription/list?output=json"
|
#define GREADER_API_SUBSCRIPTION_LIST "reader/api/0/subscription/list?output=json"
|
||||||
#define GREADER_API_STREAM_CONTENTS "reader/api/0/stream/contents/%1?output=json&n=%2"
|
#define GREADER_API_STREAM_CONTENTS "reader/api/0/stream/contents/%1?output=json&n=%2"
|
||||||
#define GREADER_API_EDIT_TAG "reader/api/0/edit-tag"
|
#define GREADER_API_EDIT_TAG "reader/api/0/edit-tag"
|
||||||
|
#define GREADER_API_ITEM_IDS "reader/api/0/stream/items/ids?output=json&s=%1"
|
||||||
|
#define GREADER_API_ITEM_CONTENTS "reader/api/0/stream/items/contents?output=json&n=%1"
|
||||||
#define GREADER_API_TOKEN "reader/api/0/token"
|
#define GREADER_API_TOKEN "reader/api/0/token"
|
||||||
#define GREADER_API_USER_INFO "reader/api/0/user-info?output=json"
|
#define GREADER_API_USER_INFO "reader/api/0/user-info?output=json"
|
||||||
|
|
||||||
|
@ -120,6 +120,41 @@ QVariantHash GreaderNetwork::userInfo(const QNetworkProxy& proxy) {
|
|||||||
return QJsonDocument::fromJson(output).object().toVariantHash();
|
return QJsonDocument::fromJson(output).object().toVariantHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<Message> GreaderNetwork::getMessagesIntelligently(ServiceRoot* root,
|
||||||
|
const QString& stream_id,
|
||||||
|
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
|
||||||
|
const QHash<QString, QStringList>& tagged_messages,
|
||||||
|
Feed::Status& error,
|
||||||
|
const QNetworkProxy& proxy) {
|
||||||
|
// 1. Get unread IDs for a feed.
|
||||||
|
// 2. Get read IDs for a feed.
|
||||||
|
// 3. Download messages/contents for missing or changed IDs.
|
||||||
|
// 4. Download all starred messages and append those belonging to this feed.
|
||||||
|
|
||||||
|
auto remote_all_ids_list = itemIds(stream_id, false, proxy);
|
||||||
|
auto remote_unread_ids_list = itemIds(stream_id, true, proxy);
|
||||||
|
QSet<QString> remote_all_ids(remote_all_ids_list.begin(), remote_all_ids_list.end());
|
||||||
|
|
||||||
|
// 1.
|
||||||
|
auto local_unread_ids_list = stated_messages.value(ServiceRoot::BagOfMessages::Unread);
|
||||||
|
QSet<QString> remote_unread_ids(remote_unread_ids_list.begin(), remote_unread_ids_list.end());
|
||||||
|
QSet<QString> local_unread_ids(local_unread_ids_list.begin(),
|
||||||
|
local_unread_ids_list.end());
|
||||||
|
|
||||||
|
// 2.
|
||||||
|
auto local_read_ids_list = stated_messages.value(ServiceRoot::BagOfMessages::Read);
|
||||||
|
QSet<QString> remote_read_ids = remote_all_ids - remote_unread_ids;
|
||||||
|
QSet<QString> local_read_ids(local_read_ids_list.begin(),
|
||||||
|
local_read_ids_list.end());
|
||||||
|
auto not_downloaded = remote_all_ids - local_read_ids - local_unread_ids;
|
||||||
|
auto moved_unread = local_unread_ids.intersect(remote_read_ids);
|
||||||
|
auto moved_read = local_read_ids.intersect(remote_unread_ids);
|
||||||
|
auto to_download = not_downloaded + moved_read + moved_unread;
|
||||||
|
QList<QString> to_download_list(to_download.begin(), to_download.end());
|
||||||
|
|
||||||
|
return itemContents(root, to_download_list, error, proxy);
|
||||||
|
}
|
||||||
|
|
||||||
QNetworkReply::NetworkError GreaderNetwork::markMessagesRead(RootItem::ReadStatus status,
|
QNetworkReply::NetworkError GreaderNetwork::markMessagesRead(RootItem::ReadStatus status,
|
||||||
const QStringList& msg_custom_ids,
|
const QStringList& msg_custom_ids,
|
||||||
const QNetworkProxy& proxy) {
|
const QNetworkProxy& proxy) {
|
||||||
@ -132,6 +167,115 @@ QNetworkReply::NetworkError GreaderNetwork::markMessagesStarred(RootItem::Import
|
|||||||
return editLabels(GREADER_API_FULL_STATE_IMPORTANT, importance == RootItem::Importance::Important, msg_custom_ids, proxy);
|
return editLabels(GREADER_API_FULL_STATE_IMPORTANT, importance == RootItem::Importance::Important, msg_custom_ids, proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList GreaderNetwork::itemIds(const QString& stream_id, bool unread_only, const QNetworkProxy& proxy) {
|
||||||
|
QString continuation;
|
||||||
|
|
||||||
|
if (!ensureLogin(proxy)) {
|
||||||
|
throw ApplicationException(tr("login failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList ids;
|
||||||
|
|
||||||
|
do {
|
||||||
|
QString full_url = generateFullUrl(Operations::ItemIds).arg(m_service == GreaderServiceRoot::Service::TheOldReader
|
||||||
|
? stream_id
|
||||||
|
: QUrl::toPercentEncoding(stream_id));
|
||||||
|
auto timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||||
|
|
||||||
|
if (unread_only) {
|
||||||
|
full_url += QSL("&xt=%1").arg(GREADER_API_FULL_STATE_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!continuation.isEmpty()) {
|
||||||
|
full_url += QSL("&c=%1").arg(continuation);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray output_stream;
|
||||||
|
auto result_stream = NetworkFactory::performNetworkOperation(full_url,
|
||||||
|
timeout,
|
||||||
|
{},
|
||||||
|
output_stream,
|
||||||
|
QNetworkAccessManager::Operation::GetOperation,
|
||||||
|
{ authHeader() },
|
||||||
|
false,
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
proxy);
|
||||||
|
|
||||||
|
if (result_stream.first != QNetworkReply::NetworkError::NoError) {
|
||||||
|
qCriticalNN << LOGSEC_GREADER
|
||||||
|
<< "Cannot download item IDs for "
|
||||||
|
<< QUOTE_NO_SPACE(stream_id)
|
||||||
|
<< ", network error:"
|
||||||
|
<< QUOTE_W_SPACE_DOT(result_stream.first);
|
||||||
|
throw NetworkException(result_stream.first);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ids.append(decodeItemIds(output_stream, continuation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!continuation.isEmpty());
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Message> GreaderNetwork::itemContents(ServiceRoot* root, const QList<QString>& stream_ids,
|
||||||
|
Feed::Status& error, const QNetworkProxy& proxy) {
|
||||||
|
QString continuation;
|
||||||
|
|
||||||
|
if (!ensureLogin(proxy)) {
|
||||||
|
error = Feed::Status::AuthError;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Message> msgs;
|
||||||
|
int target_msgs_size = 999;
|
||||||
|
|
||||||
|
do {
|
||||||
|
QString full_url = generateFullUrl(Operations::ItemContents).arg(QString::number(target_msgs_size));
|
||||||
|
auto timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||||
|
|
||||||
|
if (!continuation.isEmpty()) {
|
||||||
|
full_url += QSL("&c=%1").arg(continuation);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list inp = boolinq::from(stream_ids).select([this](const QString& id) {
|
||||||
|
return QSL("i=%1").arg(m_service == GreaderServiceRoot::Service::TheOldReader
|
||||||
|
? id
|
||||||
|
: QUrl::toPercentEncoding(id));
|
||||||
|
}).toStdList();
|
||||||
|
QByteArray input = FROM_STD_LIST(QStringList, inp).join(QSL("&")).toUtf8();
|
||||||
|
QByteArray output_stream;
|
||||||
|
auto result_stream = NetworkFactory::performNetworkOperation(full_url,
|
||||||
|
timeout,
|
||||||
|
input,
|
||||||
|
output_stream,
|
||||||
|
QNetworkAccessManager::Operation::PostOperation,
|
||||||
|
{ authHeader() },
|
||||||
|
false,
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
proxy);
|
||||||
|
|
||||||
|
if (result_stream.first != QNetworkReply::NetworkError::NoError) {
|
||||||
|
qCriticalNN << LOGSEC_GREADER
|
||||||
|
<< "Cannot download messages for "
|
||||||
|
<< stream_ids
|
||||||
|
<< ", network error:"
|
||||||
|
<< QUOTE_W_SPACE_DOT(result_stream.first);
|
||||||
|
error = Feed::Status::NetworkError;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
msgs.append(decodeStreamContents(root, output_stream, "", continuation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!continuation.isEmpty());
|
||||||
|
|
||||||
|
error = Feed::Status::Normal;
|
||||||
|
return msgs;
|
||||||
|
}
|
||||||
|
|
||||||
QList<Message> GreaderNetwork::streamContents(ServiceRoot* root, const QString& stream_id,
|
QList<Message> GreaderNetwork::streamContents(ServiceRoot* root, const QString& stream_id,
|
||||||
Feed::Status& error, const QNetworkProxy& proxy) {
|
Feed::Status& error, const QNetworkProxy& proxy) {
|
||||||
QString continuation;
|
QString continuation;
|
||||||
@ -548,6 +692,21 @@ QString GreaderNetwork::simplifyStreamId(const QString& stream_id) const {
|
|||||||
return QString(stream_id).replace(QRegularExpression("\\/\\d+\\/"), QSL("/-/"));
|
return QString(stream_id).replace(QRegularExpression("\\/\\d+\\/"), QSL("/-/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList GreaderNetwork::decodeItemIds(const QString& stream_json_data, QString& continuation) {
|
||||||
|
QStringList ids;
|
||||||
|
QJsonDocument json_doc = QJsonDocument::fromJson(stream_json_data.toUtf8());
|
||||||
|
QJsonArray json = json_doc.object()["itemRefs"].toArray();
|
||||||
|
|
||||||
|
continuation = json_doc.object()["continuation"].toString();
|
||||||
|
ids.reserve(json.count());
|
||||||
|
|
||||||
|
for (const QJsonValue& id : json) {
|
||||||
|
ids.append(id.toObject()["id"].toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
QList<Message> GreaderNetwork::decodeStreamContents(ServiceRoot* root,
|
QList<Message> GreaderNetwork::decodeStreamContents(ServiceRoot* root,
|
||||||
const QString& stream_json_data,
|
const QString& stream_json_data,
|
||||||
const QString& stream_id,
|
const QString& stream_id,
|
||||||
@ -618,7 +777,9 @@ QList<Message> GreaderNetwork::decodeStreamContents(ServiceRoot* root,
|
|||||||
|
|
||||||
message.m_contents = message_obj["summary"].toObject()["content"].toString();
|
message.m_contents = message_obj["summary"].toObject()["content"].toString();
|
||||||
message.m_rawContents = QJsonDocument(message_obj).toJson(QJsonDocument::JsonFormat::Compact);
|
message.m_rawContents = QJsonDocument(message_obj).toJson(QJsonDocument::JsonFormat::Compact);
|
||||||
message.m_feedId = stream_id;
|
message.m_feedId = stream_id.isEmpty()
|
||||||
|
? message_obj["origin"].toObject()["streamId"].toString()
|
||||||
|
: stream_id;
|
||||||
|
|
||||||
messages.append(message);
|
messages.append(message);
|
||||||
}
|
}
|
||||||
@ -680,6 +841,12 @@ QString GreaderNetwork::generateFullUrl(GreaderNetwork::Operations operation) co
|
|||||||
case Operations::EditTag:
|
case Operations::EditTag:
|
||||||
return sanitizedBaseUrl() + GREADER_API_EDIT_TAG;
|
return sanitizedBaseUrl() + GREADER_API_EDIT_TAG;
|
||||||
|
|
||||||
|
case Operations::ItemIds:
|
||||||
|
return sanitizedBaseUrl() + GREADER_API_ITEM_IDS;
|
||||||
|
|
||||||
|
case Operations::ItemContents:
|
||||||
|
return sanitizedBaseUrl() + GREADER_API_ITEM_CONTENTS;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return sanitizedBaseUrl();
|
return sanitizedBaseUrl();
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,9 @@ class GreaderNetwork : public QObject {
|
|||||||
StreamContents,
|
StreamContents,
|
||||||
EditTag,
|
EditTag,
|
||||||
Token,
|
Token,
|
||||||
UserInfo
|
UserInfo,
|
||||||
|
ItemIds,
|
||||||
|
ItemContents
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit GreaderNetwork(QObject* parent = nullptr);
|
explicit GreaderNetwork(QObject* parent = nullptr);
|
||||||
@ -38,7 +40,19 @@ class GreaderNetwork : public QObject {
|
|||||||
|
|
||||||
QVariantHash userInfo(const QNetworkProxy& proxy);
|
QVariantHash userInfo(const QNetworkProxy& proxy);
|
||||||
|
|
||||||
|
QList<Message> getMessagesIntelligently(ServiceRoot* root,
|
||||||
|
const QString& stream_id,
|
||||||
|
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
|
||||||
|
const QHash<QString, QStringList>& tagged_messages,
|
||||||
|
Feed::Status& error,
|
||||||
|
const QNetworkProxy& proxy);
|
||||||
|
|
||||||
|
QStringList itemIds(const QString& stream_id, bool unread_only, const QNetworkProxy& proxy);
|
||||||
|
|
||||||
// Stream contents for a feed/label/etc.
|
// Stream contents for a feed/label/etc.
|
||||||
|
QList<Message> itemContents(ServiceRoot* root, const QList<QString>& stream_ids,
|
||||||
|
Feed::Status& error, const QNetworkProxy& proxy);
|
||||||
|
|
||||||
QList<Message> streamContents(ServiceRoot* root, const QString& stream_id,
|
QList<Message> streamContents(ServiceRoot* root, const QString& stream_id,
|
||||||
Feed::Status& error, const QNetworkProxy& proxy);
|
Feed::Status& error, const QNetworkProxy& proxy);
|
||||||
|
|
||||||
@ -78,6 +92,7 @@ class GreaderNetwork : public QObject {
|
|||||||
bool ensureLogin(const QNetworkProxy& proxy, QNetworkReply::NetworkError* output = nullptr);
|
bool ensureLogin(const QNetworkProxy& proxy, QNetworkReply::NetworkError* output = nullptr);
|
||||||
|
|
||||||
QString simplifyStreamId(const QString& stream_id) const;
|
QString simplifyStreamId(const QString& stream_id) const;
|
||||||
|
QStringList decodeItemIds(const QString& stream_json_data, QString& continuation);
|
||||||
QList<Message> decodeStreamContents(ServiceRoot* root, const QString& stream_json_data, const QString& stream_id, QString& continuation);
|
QList<Message> decodeStreamContents(ServiceRoot* root, const QString& stream_json_data, const QString& stream_id, QString& continuation);
|
||||||
RootItem* decodeTagsSubscriptions(const QString& categories, const QString& feeds, bool obtain_icons, const QNetworkProxy& proxy);
|
RootItem* decodeTagsSubscriptions(const QString& categories, const QString& feeds, bool obtain_icons, const QNetworkProxy& proxy);
|
||||||
QString sanitizedBaseUrl() const;
|
QString sanitizedBaseUrl() const;
|
||||||
|
@ -58,7 +58,7 @@ void GreaderServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QList<Message> GreaderServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
QList<Message> GreaderServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages) {
|
const QHash<QString, QStringList>& tagged_messages) {
|
||||||
Q_UNUSED(stated_messages)
|
Q_UNUSED(stated_messages)
|
||||||
Q_UNUSED(tagged_messages)
|
Q_UNUSED(tagged_messages)
|
||||||
@ -68,7 +68,17 @@ QList<Message> GreaderServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
|||||||
for (Feed* feed : feeds) {
|
for (Feed* feed : feeds) {
|
||||||
Feed::Status error = Feed::Status::Normal;
|
Feed::Status error = Feed::Status::Normal;
|
||||||
|
|
||||||
messages << network()->streamContents(this, feed->customId(), error, networkProxy());
|
if (true /* intelligent downloading */ ) {
|
||||||
|
messages << network()->getMessagesIntelligently(this,
|
||||||
|
feed->customId(),
|
||||||
|
stated_messages.value(feed->customId()),
|
||||||
|
tagged_messages,
|
||||||
|
error,
|
||||||
|
networkProxy());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
messages << network()->streamContents(this, feed->customId(), error, networkProxy());
|
||||||
|
}
|
||||||
|
|
||||||
if (error == Feed::Status::NetworkError || error == Feed::Status::AuthError) {
|
if (error == Feed::Status::NetworkError || error == Feed::Status::AuthError) {
|
||||||
throw FeedFetchException(error);
|
throw FeedFetchException(error);
|
||||||
|
@ -32,7 +32,7 @@ class GreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
|||||||
virtual QVariantHash customDatabaseData() const;
|
virtual QVariantHash customDatabaseData() const;
|
||||||
virtual void setCustomDatabaseData(const QVariantHash& data);
|
virtual void setCustomDatabaseData(const QVariantHash& data);
|
||||||
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages);
|
const QHash<QString, QStringList>& tagged_messages);
|
||||||
virtual bool wantsBaggedIdsOfExistingMessages() const;
|
virtual bool wantsBaggedIdsOfExistingMessages() const;
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ void InoreaderServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QList<Message> InoreaderServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
QList<Message> InoreaderServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages) {
|
const QHash<QString, QStringList>& tagged_messages) {
|
||||||
Q_UNUSED(stated_messages)
|
Q_UNUSED(stated_messages)
|
||||||
Q_UNUSED(tagged_messages)
|
Q_UNUSED(tagged_messages)
|
||||||
|
@ -30,7 +30,7 @@ class InoreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
|||||||
virtual QVariantHash customDatabaseData() const;
|
virtual QVariantHash customDatabaseData() const;
|
||||||
virtual void setCustomDatabaseData(const QVariantHash& data);
|
virtual void setCustomDatabaseData(const QVariantHash& data);
|
||||||
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages);
|
const QHash<QString, QStringList>& tagged_messages);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -151,7 +151,7 @@ void OwnCloudServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QList<Message> OwnCloudServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
QList<Message> OwnCloudServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages) {
|
const QHash<QString, QStringList>& tagged_messages) {
|
||||||
Q_UNUSED(stated_messages)
|
Q_UNUSED(stated_messages)
|
||||||
Q_UNUSED(tagged_messages)
|
Q_UNUSED(tagged_messages)
|
||||||
|
@ -29,7 +29,7 @@ class OwnCloudServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
|||||||
virtual QVariantHash customDatabaseData() const;
|
virtual QVariantHash customDatabaseData() const;
|
||||||
virtual void setCustomDatabaseData(const QVariantHash& data);
|
virtual void setCustomDatabaseData(const QVariantHash& data);
|
||||||
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages);
|
const QHash<QString, QStringList>& tagged_messages);
|
||||||
|
|
||||||
OwnCloudNetworkFactory* network() const;
|
OwnCloudNetworkFactory* network() const;
|
||||||
|
@ -145,7 +145,7 @@ Qt::ItemFlags StandardServiceRoot::additionalFlags() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QList<Message> StandardServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
QList<Message> StandardServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages) {
|
const QHash<QString, QStringList>& tagged_messages) {
|
||||||
Q_UNUSED(stated_messages)
|
Q_UNUSED(stated_messages)
|
||||||
Q_UNUSED(tagged_messages)
|
Q_UNUSED(tagged_messages)
|
||||||
|
@ -33,7 +33,7 @@ class StandardServiceRoot : public ServiceRoot {
|
|||||||
virtual bool supportsCategoryAdding() const;
|
virtual bool supportsCategoryAdding() const;
|
||||||
virtual Qt::ItemFlags additionalFlags() const;
|
virtual Qt::ItemFlags additionalFlags() const;
|
||||||
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages);
|
const QHash<QString, QStringList>& tagged_messages);
|
||||||
|
|
||||||
QList<QAction*> serviceMenu();
|
QList<QAction*> serviceMenu();
|
||||||
|
@ -215,7 +215,7 @@ void TtRssServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QList<Message> TtRssServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
QList<Message> TtRssServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages) {
|
const QHash<QString, QStringList>& tagged_messages) {
|
||||||
Q_UNUSED(stated_messages)
|
Q_UNUSED(stated_messages)
|
||||||
Q_UNUSED(tagged_messages)
|
Q_UNUSED(tagged_messages)
|
||||||
|
@ -34,7 +34,7 @@ class TtRssServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
|||||||
virtual QVariantHash customDatabaseData() const;
|
virtual QVariantHash customDatabaseData() const;
|
||||||
virtual void setCustomDatabaseData(const QVariantHash& data);
|
virtual void setCustomDatabaseData(const QVariantHash& data);
|
||||||
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
|
||||||
const QHash<QString, QPair<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||||
const QHash<QString, QStringList>& tagged_messages);
|
const QHash<QString, QStringList>& tagged_messages);
|
||||||
|
|
||||||
// Access to network.
|
// Access to network.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user