Experimental ability to update read/unread status of messages.
This commit is contained in:
parent
0b5b75d3bd
commit
c8d4819270
@ -63,6 +63,6 @@ QString Enclosures::encodeEnclosuresToString(const QList<Enclosure> &enclosures)
|
||||
Message::Message() {
|
||||
m_title = m_url = m_author = m_contents = m_feedId = m_customId = "";
|
||||
m_enclosures = QList<Enclosure>();
|
||||
m_accountId = 0;
|
||||
m_accountId = m_id = 0;
|
||||
m_isRead = m_isImportant = false;
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ class Message {
|
||||
QDateTime m_created;
|
||||
QString m_feedId;
|
||||
int m_accountId;
|
||||
int m_id;
|
||||
QString m_customId;
|
||||
|
||||
bool m_isRead;
|
||||
|
@ -141,6 +141,7 @@ Message MessagesModel::messageAt(int row_index) const {
|
||||
message.m_url = rec.value(MSG_DB_URL_INDEX).toString();
|
||||
message.m_feedId = rec.value(MSG_DB_FEED_INDEX).toString();
|
||||
message.m_accountId = rec.value(MSG_DB_ACCOUNT_ID_INDEX).toInt();
|
||||
message.m_id = rec.value(MSG_DB_ID_INDEX).toInt();
|
||||
message.m_customId = rec.value(MSG_DB_CUSTOM_ID_INDEX).toString();
|
||||
message.m_created = TextFactory::parseDateTime(rec.value(MSG_DB_DCREATED_INDEX).value<qint64>()).toLocalTime();
|
||||
|
||||
@ -260,9 +261,9 @@ bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int message_id = messageId(row_index);
|
||||
Message message = messageAt(row_index);
|
||||
|
||||
if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, QList<int>() << message_id, read)) {
|
||||
if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, QList<Message>() << message, read)) {
|
||||
// Cannot change read status of the item. Abort.
|
||||
return false;
|
||||
}
|
||||
@ -284,11 +285,11 @@ bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) {
|
||||
return false;
|
||||
}
|
||||
|
||||
query_read_msg.bindValue(QSL(":id"), message_id);
|
||||
query_read_msg.bindValue(QSL(":id"), message.m_id);
|
||||
query_read_msg.bindValue(QSL(":read"), (int) read);
|
||||
|
||||
if (query_read_msg.exec()) {
|
||||
return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, QList<int>() << message_id, read);
|
||||
return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, QList<Message>() << message, read);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
@ -408,17 +409,17 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages) {
|
||||
|
||||
bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootItem::ReadStatus read) {
|
||||
QStringList message_ids;
|
||||
QList<int> message_ids_num;
|
||||
QList<Message> msgs;
|
||||
|
||||
// Obtain IDs of all desired messages.
|
||||
foreach (const QModelIndex &message, messages) {
|
||||
int message_id = messageId(message.row());
|
||||
Message msg = messageAt(message.row());
|
||||
|
||||
message_ids_num.append(message_id);
|
||||
message_ids.append(QString::number(message_id));
|
||||
msgs.append(msg);
|
||||
message_ids.append(QString::number(msg.m_id));
|
||||
}
|
||||
|
||||
if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, message_ids_num, read)) {
|
||||
if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, msgs, read)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -429,7 +430,7 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootIt
|
||||
.arg(message_ids.join(QSL(", ")), read == RootItem::Read ? QSL("1") : QSL("0")))) {
|
||||
fetchAllData();
|
||||
|
||||
return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, message_ids_num, read);
|
||||
return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, msgs, read);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
|
@ -233,7 +233,7 @@ void FeedMessageViewer::createConnections() {
|
||||
connect(qApp->feedUpdateLock(), SIGNAL(unlocked()), this, SLOT(updateFeedButtonsAvailability()));
|
||||
|
||||
// If user selects feeds, load their messages.
|
||||
connect(m_feedsView, SIGNAL(itemSelected(RootItem*)), m_messagesView, SLOT(loadFeeds(RootItem*)));
|
||||
connect(m_feedsView, SIGNAL(itemSelected(RootItem*)), m_messagesView, SLOT(loadItem(RootItem*)));
|
||||
|
||||
// State of many messages is changed, then we need
|
||||
// to reload selections.
|
||||
|
@ -227,7 +227,7 @@ void MessagesView::selectionChanged(const QItemSelection &selected, const QItemS
|
||||
QTreeView::selectionChanged(selected, deselected);
|
||||
}
|
||||
|
||||
void MessagesView::loadFeeds(RootItem *item) {
|
||||
void MessagesView::loadItem(RootItem *item) {
|
||||
m_sourceModel->loadMessages(item);
|
||||
|
||||
int col = qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortColumnMessages)).toInt();
|
||||
|
@ -57,7 +57,7 @@ class MessagesView : public QTreeView {
|
||||
void reloadSelections(bool mark_current_index_read);
|
||||
|
||||
// Loads un-deleted messages from selected feeds.
|
||||
void loadFeeds(RootItem *item);
|
||||
void loadItem(RootItem *item);
|
||||
|
||||
// Message manipulators.
|
||||
void openSelectedSourceMessagesExternally();
|
||||
|
@ -93,7 +93,7 @@ class ServiceRoot : public RootItem {
|
||||
// some ONLINE service or something.
|
||||
//
|
||||
// "read" is status which is ABOUT TO BE SET.
|
||||
virtual bool onBeforeSetMessagesRead(RootItem *selected_item, QList<int> message_db_ids, ReadStatus read) = 0;
|
||||
virtual bool onBeforeSetMessagesRead(RootItem *selected_item, const QList<Message> &messages, ReadStatus read) = 0;
|
||||
|
||||
// Called AFTER this read status update (triggered by user in message list) is stored in DB,
|
||||
// when false is returned, change is aborted.
|
||||
@ -101,7 +101,7 @@ class ServiceRoot : public RootItem {
|
||||
// which items are actually changed.
|
||||
//
|
||||
// "read" is status which is ABOUT TO BE SET.
|
||||
virtual bool onAfterSetMessagesRead(RootItem *selected_item, QList<int> message_db_ids, ReadStatus read) = 0;
|
||||
virtual bool onAfterSetMessagesRead(RootItem *selected_item, const QList<Message> &messages, ReadStatus read) = 0;
|
||||
|
||||
// Called BEFORE this importance switch update is stored in DB,
|
||||
// when false is returned, change is aborted.
|
||||
|
@ -135,7 +135,7 @@ QList<Message> StandardFeed::undeletedMessages() const {
|
||||
QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
|
||||
QSqlQuery query_read_msg(database);
|
||||
query_read_msg.setForwardOnly(true);
|
||||
query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures "
|
||||
query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, id "
|
||||
"FROM Messages "
|
||||
"WHERE is_deleted = 0 AND feed = :feed AND account_id = :account_id;");
|
||||
|
||||
@ -156,6 +156,7 @@ QList<Message> StandardFeed::undeletedMessages() const {
|
||||
message.m_contents = query_read_msg.value(4).toString();
|
||||
message.m_accountId = const_cast<StandardFeed*>(this)->serviceRoot()->accountId();
|
||||
message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString());
|
||||
message.m_id = query_read_msg.value(6).toInt();
|
||||
|
||||
messages.append(message);
|
||||
}
|
||||
|
@ -504,16 +504,16 @@ bool StandardServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *mo
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StandardServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, QList<int> message_db_ids, RootItem::ReadStatus read) {
|
||||
Q_UNUSED(message_db_ids)
|
||||
bool StandardServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, const QList<Message> &messages, RootItem::ReadStatus read) {
|
||||
Q_UNUSED(messages)
|
||||
Q_UNUSED(read)
|
||||
Q_UNUSED(selected_item)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StandardServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, QList<int> message_db_ids, RootItem::ReadStatus read) {
|
||||
Q_UNUSED(message_db_ids)
|
||||
bool StandardServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, const QList<Message> &messages, RootItem::ReadStatus read) {
|
||||
Q_UNUSED(messages)
|
||||
Q_UNUSED(read)
|
||||
|
||||
selected_item->updateCounts(false);
|
||||
|
@ -63,8 +63,8 @@ class StandardServiceRoot : public ServiceRoot {
|
||||
// Message stuff.
|
||||
bool loadMessagesForItem(RootItem *item, QSqlTableModel *model);
|
||||
|
||||
bool onBeforeSetMessagesRead(RootItem *selected_item, QList<int> message_db_ids, ReadStatus read);
|
||||
bool onAfterSetMessagesRead(RootItem *selected_item, QList<int> message_db_ids, ReadStatus read);
|
||||
bool onBeforeSetMessagesRead(RootItem *selected_item, const QList<Message> &messages, ReadStatus read);
|
||||
bool onAfterSetMessagesRead(RootItem *selected_item, const QList<Message> &messages, ReadStatus read);
|
||||
|
||||
bool onBeforeSwitchMessageImportance(RootItem *selected_item, QList<QPair<int,RootItem::Importance> > changes);
|
||||
bool onAfterSwitchMessageImportance(RootItem *selected_item, QList<QPair<int,RootItem::Importance> > changes);
|
||||
|
@ -171,6 +171,44 @@ TtRssGetHeadlinesResponse TtRssNetworkFactory::getHeadlines(int feed_id, bool fo
|
||||
return result;
|
||||
}
|
||||
|
||||
TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QList<int> &ids,
|
||||
UpdateArticle::OperatingField field,
|
||||
UpdateArticle::Mode mode,
|
||||
QNetworkReply::NetworkError &error) {
|
||||
QtJson::JsonObject json;
|
||||
json["op"] = "updateArticle";
|
||||
json["sid"] = m_sessionId;
|
||||
json["article_ids"] = encodeArticleIds(ids);
|
||||
json["mode"] = (int) mode;
|
||||
json["field"] = (int) field;
|
||||
|
||||
QByteArray result_raw;
|
||||
NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw);
|
||||
TtRssUpdateArticleResponse result(QString::fromUtf8(result_raw));
|
||||
|
||||
if (result.isNotLoggedIn()) {
|
||||
// We are not logged in.
|
||||
login(error);
|
||||
json["sid"] = m_sessionId;
|
||||
|
||||
network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw);
|
||||
result = TtRssUpdateArticleResponse(QString::fromUtf8(result_raw));
|
||||
}
|
||||
|
||||
error = network_reply.first;
|
||||
return result;
|
||||
}
|
||||
|
||||
QString TtRssNetworkFactory::encodeArticleIds(const QList<int> &ids) {
|
||||
QStringList strings;
|
||||
|
||||
foreach (int id, ids) {
|
||||
strings.append(QString::number(id));
|
||||
}
|
||||
|
||||
return strings.join(QL1C(','));
|
||||
}
|
||||
|
||||
TtRssResponse::TtRssResponse(const QString &raw_content) {
|
||||
m_rawContent = QtJson::parse(raw_content).toMap();
|
||||
}
|
||||
@ -255,7 +293,7 @@ TtRssGetFeedsCategoriesResponse::TtRssGetFeedsCategoriesResponse(const QString &
|
||||
TtRssGetFeedsCategoriesResponse::~TtRssGetFeedsCategoriesResponse() {
|
||||
}
|
||||
|
||||
RootItem *TtRssGetFeedsCategoriesResponse::feedsCategories(bool obtain_icons, QString base_address) {
|
||||
RootItem *TtRssGetFeedsCategoriesResponse::feedsCategories(bool obtain_icons, QString base_address) const {
|
||||
RootItem *parent = new RootItem();
|
||||
|
||||
// Chop the "api/" from the end of the address.
|
||||
@ -342,7 +380,7 @@ TtRssGetHeadlinesResponse::TtRssGetHeadlinesResponse(const QString &raw_content)
|
||||
TtRssGetHeadlinesResponse::~TtRssGetHeadlinesResponse() {
|
||||
}
|
||||
|
||||
QList<Message> TtRssGetHeadlinesResponse::messages() {
|
||||
QList<Message> TtRssGetHeadlinesResponse::messages() const {
|
||||
QList<Message> messages;
|
||||
|
||||
foreach (QVariant item, m_rawContent["content"].toList()) {
|
||||
@ -380,3 +418,28 @@ QList<Message> TtRssGetHeadlinesResponse::messages() {
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
|
||||
TtRssUpdateArticleResponse::TtRssUpdateArticleResponse(const QString &raw_content) : TtRssResponse(raw_content) {
|
||||
}
|
||||
|
||||
TtRssUpdateArticleResponse::~TtRssUpdateArticleResponse() {
|
||||
}
|
||||
|
||||
QString TtRssUpdateArticleResponse::updateStatus() const {
|
||||
if (m_rawContent.contains(QSL("content"))) {
|
||||
return m_rawContent["content"].toMap()["status"].toString();
|
||||
}
|
||||
else {
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
int TtRssUpdateArticleResponse::articlesUpdated() const {
|
||||
if (m_rawContent.contains(QSL("content"))) {
|
||||
return m_rawContent["content"].toMap()["updated"].toInt();
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ class TtRssGetFeedsCategoriesResponse : public TtRssResponse {
|
||||
// Returns tree of feeds/categories.
|
||||
// Top-level root of the tree is not needed here.
|
||||
// Returned items do not have primary IDs assigned.
|
||||
RootItem *feedsCategories(bool obtain_icons, QString base_address = QString());
|
||||
RootItem *feedsCategories(bool obtain_icons, QString base_address = QString()) const;
|
||||
};
|
||||
|
||||
class TtRssGetHeadlinesResponse : public TtRssResponse {
|
||||
@ -71,9 +71,32 @@ class TtRssGetHeadlinesResponse : public TtRssResponse {
|
||||
explicit TtRssGetHeadlinesResponse(const QString &raw_content = QString());
|
||||
virtual ~TtRssGetHeadlinesResponse();
|
||||
|
||||
QList<Message> messages();
|
||||
QList<Message> messages() const;
|
||||
};
|
||||
|
||||
class TtRssUpdateArticleResponse : public TtRssResponse {
|
||||
public:
|
||||
explicit TtRssUpdateArticleResponse(const QString &raw_content = QString());
|
||||
virtual ~TtRssUpdateArticleResponse();
|
||||
|
||||
QString updateStatus() const;
|
||||
int articlesUpdated() const;
|
||||
};
|
||||
|
||||
namespace UpdateArticle {
|
||||
enum Mode {
|
||||
SetToFalse = 0,
|
||||
SetToTrue = 1,
|
||||
Togggle = 2
|
||||
};
|
||||
|
||||
enum OperatingField {
|
||||
Starred = 0,
|
||||
Published = 1,
|
||||
Unread = 2
|
||||
};
|
||||
}
|
||||
|
||||
class TtRssNetworkFactory {
|
||||
public:
|
||||
explicit TtRssNetworkFactory();
|
||||
@ -107,7 +130,12 @@ class TtRssNetworkFactory {
|
||||
bool show_content, bool include_attachments,
|
||||
bool sanitize, QNetworkReply::NetworkError &error);
|
||||
|
||||
private:
|
||||
TtRssUpdateArticleResponse updateArticles(const QList<int> &ids, UpdateArticle::OperatingField field,
|
||||
UpdateArticle::Mode mode, QNetworkReply::NetworkError &error);
|
||||
|
||||
private:
|
||||
QString encodeArticleIds(const QList<int> &ids);
|
||||
|
||||
QString m_url;
|
||||
QString m_username;
|
||||
QString m_password;
|
||||
|
@ -118,7 +118,7 @@ QList<Message> TtRssFeed::undeletedMessages() const {
|
||||
QSqlQuery query_read_msg(database);
|
||||
|
||||
query_read_msg.setForwardOnly(true);
|
||||
query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, custom_id "
|
||||
query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, custom_id, id "
|
||||
"FROM Messages "
|
||||
"WHERE is_deleted = 0 AND feed = :feed AND account_id = :account_id;");
|
||||
|
||||
@ -140,6 +140,7 @@ QList<Message> TtRssFeed::undeletedMessages() const {
|
||||
message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString());
|
||||
message.m_accountId = account_id;
|
||||
message.m_customId = query_read_msg.value(6).toString();
|
||||
message.m_id = query_read_msg.value(7).toInt();
|
||||
|
||||
messages.append(message);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "services/tt-rss/ttrssserviceentrypoint.h"
|
||||
#include "services/tt-rss/ttrssfeed.h"
|
||||
#include "services/tt-rss/ttrsscategory.h"
|
||||
#include "services/tt-rss/definitions.h"
|
||||
#include "services/tt-rss/network/ttrssnetworkfactory.h"
|
||||
#include "services/tt-rss/gui/formeditaccount.h"
|
||||
|
||||
@ -145,19 +146,25 @@ QList<QAction*> TtRssServiceRoot::contextMenu() {
|
||||
return serviceMenu();
|
||||
}
|
||||
|
||||
bool TtRssServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, QList<int> message_db_ids, RootItem::ReadStatus read) {
|
||||
// TODO: misto čísel primarnich zprav, vracet cele objekty zprav
|
||||
// tedy včetně custom ID, nemusi se tak znova tahat z DB asi?s
|
||||
bool TtRssServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, const QList<Message> &messages, RootItem::ReadStatus read) {
|
||||
Q_UNUSED(selected_item)
|
||||
|
||||
// OK, update the messages status online.
|
||||
QNetworkReply::NetworkError error;
|
||||
TtRssUpdateArticleResponse response = m_network->updateArticles(customIDsOfMessages(messages),
|
||||
UpdateArticle::Unread,
|
||||
read == RootItem::Unread ? UpdateArticle::SetToTrue : UpdateArticle::SetToFalse,
|
||||
error);
|
||||
|
||||
// First obtain, custom IDs of messages.
|
||||
|
||||
return false;
|
||||
if (error == QNetworkReply::NoError && response.updateStatus() == STATUS_OK && response.articlesUpdated() == messages.size()) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TtRssServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, QList<int> message_db_ids, RootItem::ReadStatus read) {
|
||||
Q_UNUSED(message_db_ids)
|
||||
bool TtRssServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, const QList<Message> &messages, RootItem::ReadStatus read) {
|
||||
Q_UNUSED(messages)
|
||||
Q_UNUSED(read)
|
||||
|
||||
selected_item->updateCounts(false);
|
||||
@ -338,6 +345,16 @@ void TtRssServiceRoot::syncIn() {
|
||||
}
|
||||
}
|
||||
|
||||
QList<int> TtRssServiceRoot::customIDsOfMessages(const QList<Message> &messages) {
|
||||
QList<int> list;
|
||||
|
||||
foreach (const Message &message, messages) {
|
||||
list.append(message.m_customId.toInt());
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
QStringList TtRssServiceRoot::textualFeedIds(const QList<Feed*> &feeds) {
|
||||
QStringList stringy_ids;
|
||||
stringy_ids.reserve(feeds.size());
|
||||
|
@ -54,8 +54,8 @@ class TtRssServiceRoot : public ServiceRoot {
|
||||
|
||||
bool loadMessagesForItem(RootItem *item, QSqlTableModel *model);
|
||||
|
||||
bool onBeforeSetMessagesRead(RootItem *selected_item, QList<int> message_db_ids, ReadStatus read);
|
||||
bool onAfterSetMessagesRead(RootItem *selected_item, QList<int> message_db_ids, ReadStatus read);
|
||||
bool onBeforeSetMessagesRead(RootItem *selected_item, const QList<Message> &messages, ReadStatus read);
|
||||
bool onAfterSetMessagesRead(RootItem *selected_item, const QList<Message> &messages, ReadStatus read);
|
||||
|
||||
bool onBeforeSwitchMessageImportance(RootItem *selected_item, QList<QPair<int,RootItem::Importance> > changes);
|
||||
bool onAfterSwitchMessageImportance(RootItem *selected_item, QList<QPair<int,RootItem::Importance> > changes);
|
||||
@ -77,6 +77,8 @@ class TtRssServiceRoot : public ServiceRoot {
|
||||
void syncIn();
|
||||
|
||||
private:
|
||||
QList<int> customIDsOfMessages(const QList<Message> &messages);
|
||||
|
||||
// Returns converted ids of given feeds
|
||||
// which are suitable as IN clause for SQL queries.
|
||||
QStringList textualFeedIds(const QList<Feed*> &feeds);
|
||||
|
Loading…
x
Reference in New Issue
Block a user