diff --git a/microblogs/pumpio/pumpiomicroblog.cpp b/microblogs/pumpio/pumpiomicroblog.cpp index b25f4c8f..19c5149e 100644 --- a/microblogs/pumpio/pumpiomicroblog.cpp +++ b/microblogs/pumpio/pumpiomicroblog.cpp @@ -1,554 +1,611 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2013 Andrea Scarpino This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "pumpiomicroblog.h" #include #include #include #include #include #include #include "accountmanager.h" #include "application.h" #include "choqokbehaviorsettings.h" #include "notifymanager.h" #include "pumpioaccount.h" #include "pumpioeditaccountwidget.h" #include "pumpiopostwidget.h" K_PLUGIN_FACTORY( MyPluginFactory, registerPlugin < PumpIOMicroBlog > (); ) K_EXPORT_PLUGIN( MyPluginFactory( "choqok_pumpio" ) ) PumpIOMicroBlog::PumpIOMicroBlog(QObject* parent, const QVariantList& args): MicroBlog(MyPluginFactory::componentData(), parent) { Q_UNUSED(args) setServiceName("Pump.io"); setServiceHomepageUrl("http://pump.io"); QStringList timelineNames; timelineNames << "Activity"; setTimelineNames(timelineNames); setTimelinesInfo(); } PumpIOMicroBlog::~PumpIOMicroBlog() { } void PumpIOMicroBlog::abortAllJobs(Choqok::Account* theAccount) { Q_FOREACH (KJob *job, m_accountJobs.keys(theAccount)) { job->kill(KJob::EmitResult); } } void PumpIOMicroBlog::abortCreatePost(Choqok::Account* theAccount, Choqok::Post* post) { if (m_createPostJobs.isEmpty()) { return; } if (post) { m_createPostJobs.key(post)->kill(KJob::EmitResult); return; } Q_FOREACH (KJob *job, m_createPostJobs.keys()){ if( m_accountJobs[job] == theAccount) { job->kill(KJob::EmitResult); } } } void PumpIOMicroBlog::aboutToUnload() { emit saveTimelines(); } ChoqokEditAccountWidget* PumpIOMicroBlog::createEditAccountWidget(Choqok::Account* account, QWidget* parent) { PumpIOAccount *acc = qobject_cast(account); if (acc || !account) { return new PumpIOEditAccountWidget(this, acc, parent); } else { kDebug() << "Account passed here was not a valid PumpIOAccount!"; return 0; } } Choqok::Account* PumpIOMicroBlog::createNewAccount(const QString& alias) { PumpIOAccount *acc = qobject_cast( Choqok::AccountManager::self()->findAccount(alias) ); if (!acc) { return new PumpIOAccount(this, alias); } else { kDebug() << "Cannot create a new PumpIOAccount!"; return 0; } } void PumpIOMicroBlog::createPost(Choqok::Account* theAccount, Choqok::Post* post) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { QVariantMap object; object.insert("objectType", "note"); object.insert("content", QUrl::toPercentEncoding(post->content)); QVariantList to; QVariantMap thePublic; thePublic.insert("objectType", "collection"); thePublic.insert("id", "http://activityschema.org/collection/public"); to.prepend(thePublic); QVariantMap item; item.insert("verb", "post"); item.insert("object", object); item.insert("to", to); QJson::Serializer serializer; const QByteArray data = serializer.serialize(item); KUrl url(acc->host()); url.addPath("/api/user/" + acc->username() + "/feed"); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); job->addMetaData("content-type", "Content-Type: application/json"); job->addMetaData("customHTTPHeader", authorizationMetaData(acc, url, QOAuth::POST)); if (!job) { kDebug() << "Cannot create an http POST request!"; return; } m_accountJobs[job] = acc; m_createPostJobs[job] = post; connect(job, SIGNAL(result(KJob*)), this, SLOT(slotCreatePost(KJob*))); job->start(); } else { kDebug() << "theAccount is not a PumpIOAccount!"; } } Choqok::UI::PostWidget* PumpIOMicroBlog::createPostWidget(Choqok::Account* account, Choqok::Post* post, QWidget* parent) { return new PumpIOPostWidget(account, post, parent); } void PumpIOMicroBlog::fetchPost(Choqok::Account* theAccount, Choqok::Post* post) { //TODO Choqok::MicroBlog::fetchPost(theAccount, post); } void PumpIOMicroBlog::removePost(Choqok::Account* theAccount, Choqok::Post* post) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { QVariantMap object; object.insert("id", post->postId.toString()); object.insert("objectType", post->type); QVariantMap item; item.insert("verb", "delete"); item.insert("object", object); QJson::Serializer serializer; const QByteArray data = serializer.serialize(item); KUrl url(acc->host()); url.addPath("/api/user/" + acc->username() + "/feed"); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); job->addMetaData("content-type", "Content-Type: application/json"); job->addMetaData("customHTTPHeader", authorizationMetaData(acc, url, QOAuth::POST)); if (!job) { kDebug() << "Cannot create an http POST request!"; return; } m_accountJobs[job] = acc; m_removePostJobs[job] = post; connect(job, SIGNAL(result(KJob*)), this, SLOT(slotRemovePost(KJob*))); job->start(); } else { kDebug() << "theAccount is not a PumpIOAccount!"; } } QList< Choqok::Post* > PumpIOMicroBlog::loadTimeline(Choqok::Account* account, const QString& timelineName) { QList< Choqok::Post* > list; const QString fileName = Choqok::AccountManager::generatePostBackupFileName(account->alias(), timelineName); const KConfig postsBackup( "choqok/" + fileName, KConfig::NoGlobals, "data" ); const QStringList tmpList = postsBackup.groupList(); // don't load old archives if (tmpList.isEmpty() || !(QDateTime::fromString(tmpList.first()).isValid())) { return list; } QList groupList; Q_FOREACH (const QString& str, tmpList) { groupList.append(QDateTime::fromString(str)); } qSort(groupList); Choqok::Post *st; Q_FOREACH (const QDateTime& datetime, groupList) { st = new Choqok::Post; KConfigGroup grp(&postsBackup, datetime.toString()); st->creationDateTime = grp.readEntry("creationDateTime", QDateTime::currentDateTime()); st->postId = grp.readEntry("postId", QString()); st->link = grp.readEntry("link", QString()); st->content = grp.readEntry("content", QString()); st->source = grp.readEntry("source", QString()); st->isFavorited = grp.readEntry("favorited", false); st->author.userId = grp.readEntry("authorId", QString()); st->author.userName = grp.readEntry("authorUserName", QString()); st->author.realName = grp.readEntry("authorRealName", QString()); st->author.location = grp.readEntry("authorLocation", QString()); st->author.description = grp.readEntry("authorDescription" , QString()); st->author.profileImageUrl = grp.readEntry("authorProfileImageUrl", QString()); st->author.homePageUrl = grp.readEntry("authorHomePageUrl", QString()); st->type = grp.readEntry("type", QString()); st->isRead = grp.readEntry("isRead", true); st->conversationId = grp.readEntry("conversationId", QString()); st->replyToPostId = grp.readEntry("replyToPostId", QString()); st->replyToUserId = grp.readEntry("replyToUserId", QString()); st->replyToUserName = grp.readEntry("replyToUserName", QString()); list.append(st); } setLastTimelineId(account, timelineName, st->conversationId.toString()); return list; } QString PumpIOMicroBlog::postUrl(Choqok::Account* account, const QString& username, const QString& postId) const { Q_UNUSED(account); return QString(postId).replace("/api/", '/' + username + '/'); } QString PumpIOMicroBlog::profileUrl(Choqok::Account* account, const QString& username) const { Q_UNUSED(account) if (username.contains("acct:")) { return QString("https://%1/%2").arg(hostFromAcct(username)).arg(userNameFromAcct(username)); } else { return username; } } void PumpIOMicroBlog::saveTimeline(Choqok::Account* account, const QString& timelineName, const QList< Choqok::UI::PostWidget* >& timeline) { const QString fileName = Choqok::AccountManager::generatePostBackupFileName(account->alias(), timelineName); KConfig postsBackup("choqok/" + fileName, KConfig::NoGlobals, "data"); ///Clear previous data: Q_FOREACH (const QString& group, postsBackup.groupList()) { postsBackup.deleteGroup(group); } QList< Choqok::UI::PostWidget *>::const_iterator it, endIt = timeline.constEnd(); for (it = timeline.constBegin(); it != endIt; ++it) { const Choqok::Post *post = ((*it)->currentPost()); KConfigGroup grp(&postsBackup, post->creationDateTime.toString()); grp.writeEntry("creationDateTime", post->creationDateTime); grp.writeEntry("postId", post->postId.toString()); grp.writeEntry("link", post->link); grp.writeEntry("content", post->content); grp.writeEntry("source", post->source); grp.writeEntry("favorited", post->isFavorited); grp.writeEntry("authorId", post->author.userId.toString()); grp.writeEntry("authorRealName", post->author.realName); grp.writeEntry("authorUserName", post->author.userName); grp.writeEntry("authorLocation" , post->author.location); grp.writeEntry("authorDescription" , post->author.description); grp.writeEntry("authorProfileImageUrl", post->author.profileImageUrl); grp.writeEntry("authorHomePageUrl" , post->author.homePageUrl); grp.writeEntry("type" , post->type); grp.writeEntry("isRead", post->isRead); grp.writeEntry("conversationId", post->conversationId.toString()); grp.writeEntry("replyToPostId", post->replyToPostId.toString()); grp.writeEntry("replyToUserId", post->replyToUserId.toString()); grp.writeEntry("replyToUserName", post->replyToUserName); } postsBackup.sync(); emit readyForUnload(); } Choqok::TimelineInfo* PumpIOMicroBlog::timelineInfo(const QString& timelineName) { return m_timelinesInfos.value(timelineName); } void PumpIOMicroBlog::updateTimelines(Choqok::Account* theAccount) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { Q_FOREACH (const QString timeline, acc->timelineNames()) { KUrl url(acc->host()); url.addPath(m_timelinesPaths[timeline].arg(acc->username())); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { kDebug() << "Cannot create an http GET request!"; continue; } QOAuth::ParamMap oAuthParams; const ChoqokId lastActivityId = lastTimelineId(theAccount, timeline); if (!lastActivityId.isNull()) { oAuthParams.insert("count", QByteArray::number(200)); oAuthParams.insert("since", lastActivityId.toLocal8Bit()); } else { oAuthParams.insert("count", QByteArray::number(Choqok::BehaviorSettings::countOfPosts())); } job->addMetaData("customHTTPHeader", authorizationMetaData(acc, url, QOAuth::GET, oAuthParams)); m_timelinesRequests[job] = timeline; m_accountJobs[job] = acc; connect(job, SIGNAL(result(KJob*)), this, SLOT(slotUpdateTimeline(KJob*))); job->start(); } } else { kDebug() << "theAccount is not a PumpIOAccount!"; } } +void PumpIOMicroBlog::toggleFavorite(Choqok::Account* theAccount, Choqok::Post* post) +{ + PumpIOAccount *acc = qobject_cast(theAccount); + if (acc) { + QVariantMap object; + object.insert("objectType", post->type); + object.insert("id", post->postId.toString()); + + QVariantMap item; + item.insert("verb", post->isFavorited ? "unfavorite" : "favorite"); + item.insert("object", object); + + QJson::Serializer serializer; + const QByteArray data = serializer.serialize(item); + + KUrl url(acc->host()); + url.addPath("/api/user/" + acc->username() + "/feed"); + KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); + job->addMetaData("content-type", "Content-Type: application/json"); + job->addMetaData("customHTTPHeader", authorizationMetaData(acc, url, QOAuth::POST)); + if (!job) { + kDebug() << "Cannot create an http POST request!"; + return; + } + m_accountJobs[job] = acc; + m_favoriteJobs[job] = post; + connect(job, SIGNAL(result(KJob*)), this, SLOT(slotFavorite(KJob*))); + job->start(); + } else { + kDebug() << "theAccount is not a PumpIOAccount!"; + } +} + void PumpIOMicroBlog::slotCreatePost(KJob* job) { if (!job) { kDebug() << "Job is null pointer"; return; } Choqok::Post *post = m_createPostJobs.take(job); Choqok::Account *theAccount = m_accountJobs.take(job); - if(!post || !theAccount) { + if (!post || !theAccount) { kDebug() << "Account or Post is NULL pointer"; return; } int ret = 0; if (job->error()) { ret = 1; } else { KIO::StoredTransferJob* j = qobject_cast(job); QJson::Parser parser; const QVariantMap reply = parser.parse(j->data()).toMap(); if (!reply["object"].toMap().take("id").toString().isEmpty()) { Choqok::NotifyManager::success(i18n("New post submitted successfully")); emit postCreated(theAccount, post); } else { ret = 1; } } if (ret) { kDebug() << "Job Error: " << job->errorString(); emit errorPost(theAccount, post, Choqok::MicroBlog::CommunicationError, i18n("Creating the new post failed. %1", job->errorString()), MicroBlog::Critical); } } +void PumpIOMicroBlog::slotFavorite(KJob* job) +{ + if (!job) { + kDebug() << "Job is null pointer"; + return; + } + Choqok::Post *post = m_favoriteJobs.take(job); + Choqok::Account *theAccount = m_accountJobs.take(job); + if (!post || !theAccount) { + kDebug() << "Account or Post is NULL pointer"; + return; + } + if (job->error()) { + kDebug() << "Job Error: " << job->errorString(); + emit error(theAccount, Choqok::MicroBlog::CommunicationError, + i18n("Cannot set the post as (un)favorite. %1", job->errorString())); + } else { + post->isFavorited = !post->isFavorited; + emit favorite(theAccount, post); + } +} + void PumpIOMicroBlog::slotRemovePost(KJob* job) { if (!job) { kDebug() << "Job is null pointer"; return; } Choqok::Post *post = m_removePostJobs.take(job); Choqok::Account *theAccount = m_accountJobs.take(job); - if(!post || !theAccount) { + if (!post || !theAccount) { kDebug() << "Account or Post is NULL pointer"; return; } if (job->error()) { kDebug() << "Job Error: " << job->errorString(); emit errorPost(theAccount, post, Choqok::MicroBlog::CommunicationError, i18n("Removing the post failed. %1", job->errorString()), MicroBlog::Critical); } else { KIO::StoredTransferJob* j = qobject_cast(job); QJson::Parser parser; const QVariantMap object = parser.parse(j->data()).toMap().take("object").toMap(); if (!object["deleted"].toString().isEmpty()) { Choqok::NotifyManager::success(i18n("Post removed successfully")); emit postRemoved(theAccount, post); } } } void PumpIOMicroBlog::slotUpdateTimeline(KJob* job) { Choqok::Account *account = m_accountJobs.take(job); if (job->error()) { kDebug() << "Job Error: " << job->errorString(); emit error(account, Choqok::MicroBlog::CommunicationError, i18n("An error occurred when fetching the timeline")); return; } KIO::StoredTransferJob* j = qobject_cast(job); QList list = readTimeline(j->data()); emit timelineDataReceived(account, m_timelinesRequests.take(job), list); } QString PumpIOMicroBlog::authorizationMetaData(Choqok::Account* theAccount, const KUrl& url, const QOAuth::HttpMethod& method, const QOAuth::ParamMap& paramMap) const { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { const QByteArray authorization = acc->oAuth()->createParametersString(url.url(), method, acc->token().toLocal8Bit(), acc->tokenSecret().toLocal8Bit(), QOAuth::HMAC_SHA1, paramMap, QOAuth::ParseForHeaderArguments); return "Authorization: " + authorization; } else { kDebug() << "theAccount is not a PumpIOAccount!"; return QString(); } } QString PumpIOMicroBlog::hostFromAcct(const QString& acct) const { if (acct.contains("acct:")) { return acct.split(':')[1].split('@')[1]; } return acct; } ChoqokId PumpIOMicroBlog::lastTimelineId(Choqok::Account* theAccount, const QString& timeline) const { return m_timelinesLatestIds[theAccount][timeline]; } Choqok::Post* PumpIOMicroBlog::readComment(const QVariantMap& var, const QString& conversationId, Choqok::Post* post) { QTextDocument content; content.setHtml(var["content"].toString()); post->content = content.toPlainText(); post->postId = var["id"].toString(); const QVariantMap replyTo = var["inReplyTo"].toMap(); post->replyToPostId = replyTo["id"].toString(); const QVariantMap replyToAuthor = replyTo["author"].toMap(); post->replyToUserId = replyToAuthor["id"].toString(); post->replyToUserName = userNameFromAcct(post->replyToUserId.toString()); post->link = var["url"].toString(); post->type = var["objectType"].toString(); + post->isFavorited = var["liked"].toBool(); post->creationDateTime = QDateTime::fromString(var["published"].toString(), "yyyy-MM-dd'T'hh:mm:ss'Z'"); const QVariantMap author = var["author"].toMap(); post->author.userId = author["id"].toString(); post->author.userName = author["preferredUsername"].toString(); post->author.realName = author["displayName"].toString(); post->author.homePageUrl = author["url"].toString(); post->author.location = author["location"].toMap().take("displayName").toString(); post->author.description = author["summary"].toString(); post->author.profileImageUrl = author["image"].toMap().take("url").toString(); post->conversationId = conversationId; return post; } Choqok::Post* PumpIOMicroBlog::readPost(const QVariantMap& var, Choqok::Post* post) { const QVariantMap object = var["object"].toMap(); QTextDocument content; content.setHtml(object["content"].toString()); if (object["displayName"].toString().isEmpty()) { post->content = content.toPlainText(); } else { post->content = object["displayName"].toString() + '\n' + content.toPlainText(); } if (!object["fullImage"].toMap().isEmpty()) { const QString imagePath = object["fullImage"].toMap().take("url").toString(); if (!imagePath.isEmpty()) { post->content += '\n' + imagePath; } } post->creationDateTime = QDateTime::fromString(var["published"].toString(), "yyyy-MM-dd'T'hh:mm:ss'Z'"); post->postId = object["id"].toString(); post->link = object["url"].toString(); post->type = object["objectType"].toString(); + post->isFavorited = object["liked"].toBool(); const QVariantMap actor = var["actor"].toMap(); post->author.userId = actor["id"].toString(); post->author.userName = actor["preferredUsername"].toString(); post->author.realName = actor["displayName"].toString(); post->author.homePageUrl = actor["url"].toString(); post->author.location = actor["location"].toMap().take("displayName").toString(); post->author.description = actor["summary"].toString(); post->author.profileImageUrl = actor["image"].toMap().take("url").toString(); post->source = var["generator"].toMap().take("displayName").toString(); post->conversationId = var["id"].toString(); return post; } QList< Choqok::Post* > PumpIOMicroBlog::readTimeline(const QByteArray& buffer) { QList posts; QJson::Parser parser; const QVariantList list = parser.parse(buffer).toMap().take("items").toList(); Q_FOREACH (const QVariant element, list) { const QVariantMap elementMap = element.toMap(); const QVariantMap object = elementMap["object"].toMap(); if (!object["deleted"].toString().isEmpty()) { // Skip deleted posts continue; } const QVariantList replies = object["replies"].toMap().take("items").toList(); Q_FOREACH (const QVariant reply, replies) { posts.prepend(readComment(reply.toMap(), elementMap["id"].toString(), new Choqok::Post)); } posts.prepend(readPost(elementMap, new Choqok::Post)); } return posts; } void PumpIOMicroBlog::setLastTimelineId(Choqok::Account* theAccount, const QString& timeline, const ChoqokId& id) { m_timelinesLatestIds[theAccount][timeline] = id; } void PumpIOMicroBlog::setTimelinesInfo() { Choqok::TimelineInfo *t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Activity"); t->description = i18nc("Timeline description", "You and your friends"); t->icon = "user-home"; m_timelinesInfos["Activity"] = t; m_timelinesPaths["Activity"] = "/api/user/%1/inbox/major"; } QString PumpIOMicroBlog::userNameFromAcct(const QString& acct) const { if (acct.contains("acct:")) { return acct.split(':')[1].split('@')[0]; } return acct; } diff --git a/microblogs/pumpio/pumpiomicroblog.h b/microblogs/pumpio/pumpiomicroblog.h index cd7bbe61..48393c5f 100644 --- a/microblogs/pumpio/pumpiomicroblog.h +++ b/microblogs/pumpio/pumpiomicroblog.h @@ -1,84 +1,91 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2013 Andrea Scarpino This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #ifndef PUMPIOMICROBLOG_H #define PUMPIOMICROBLOG_H #include "QtOAuth/qoauth_namespace.h" #include "microblog.h" class KJob; class KUrl; class PumpIOMicroBlog : public Choqok::MicroBlog { Q_OBJECT public: explicit PumpIOMicroBlog(QObject* parent, const QVariantList& args); virtual ~PumpIOMicroBlog(); virtual void abortAllJobs(Choqok::Account* theAccount); virtual void abortCreatePost(Choqok::Account* theAccount, Choqok::Post* post = 0); virtual void aboutToUnload(); virtual ChoqokEditAccountWidget* createEditAccountWidget(Choqok::Account* account, QWidget* parent); virtual Choqok::Account* createNewAccount(const QString& alias); virtual void createPost(Choqok::Account* theAccount, Choqok::Post* post); virtual Choqok::UI::PostWidget* createPostWidget(Choqok::Account* account, Choqok::Post* post, QWidget* parent); virtual void fetchPost(Choqok::Account* theAccount, Choqok::Post* post); virtual QList loadTimeline(Choqok::Account* account, const QString& timelineName); virtual void removePost(Choqok::Account* theAccount, Choqok::Post* post); virtual QString postUrl(Choqok::Account* account, const QString& username, const QString& postId) const; virtual QString profileUrl(Choqok::Account* account, const QString& username) const; virtual void saveTimeline(Choqok::Account* account, const QString& timelineName, const QList< Choqok::UI::PostWidget* >& timeline); virtual Choqok::TimelineInfo* timelineInfo(const QString& timelineName); virtual void updateTimelines(Choqok::Account* theAccount); -private Q_SLOTS: + void toggleFavorite(Choqok::Account* theAccount, Choqok::Post* post); + +Q_SIGNALS: + void favorite(Choqok::Account*, Choqok::Post*); + +protected Q_SLOTS: void slotCreatePost(KJob* job); + void slotFavorite(KJob* job); void slotRemovePost(KJob* job); void slotUpdateTimeline(KJob* job); private: QString authorizationMetaData(Choqok::Account* theAccount, const KUrl& url, const QOAuth::HttpMethod& method, const QOAuth::ParamMap& map = QOAuth::ParamMap()) const; QString hostFromAcct(const QString& acct) const; ChoqokId lastTimelineId(Choqok::Account* theAccount, const QString& timeline) const; Choqok::Post* readComment(const QVariantMap& var, const QString& conversationId, Choqok::Post* post); Choqok::Post* readPost(const QVariantMap& var, Choqok::Post* post); QList readTimeline(const QByteArray& buffer); void setLastTimelineId(Choqok::Account* theAccount, const QString& timeline, const ChoqokId& id); void setTimelinesInfo(); QString userNameFromAcct(const QString& acct) const; QMap m_accountJobs; QMap m_createPostJobs; + QMap m_favoriteJobs; QMap m_removePostJobs; QMap m_timelinesInfos; QHash > m_timelinesLatestIds; QHash m_timelinesPaths; QMap m_timelinesRequests; }; #endif // PUMPIOMICROBLOG_H \ No newline at end of file diff --git a/microblogs/pumpio/pumpiopostwidget.cpp b/microblogs/pumpio/pumpiopostwidget.cpp index 0ce823c2..93d9d0d4 100644 --- a/microblogs/pumpio/pumpiopostwidget.cpp +++ b/microblogs/pumpio/pumpiopostwidget.cpp @@ -1,77 +1,129 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2013 Andrea Scarpino This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "pumpiopostwidget.h" #include #include +#include + +#include "mediamanager.h" + +#include "pumpiomicroblog.h" + +const KIcon PumpIOPostWidget::unFavIcon(Choqok::MediaManager::convertToGrayScale(KIcon("rating").pixmap(16))); + +class PumpIOPostWidget::Private +{ +public: + Private() + { + } + + KPushButton *btnFav; +}; PumpIOPostWidget::PumpIOPostWidget(Choqok::Account* account, Choqok::Post* post, QWidget* parent): - PostWidget(account, post, parent) + PostWidget(account, post, parent), d(new Private()) { } PumpIOPostWidget::~PumpIOPostWidget() { + delete d; } QString PumpIOPostWidget::generateSign() { QString ss; ss = "author.description + "\">" + currentPost()->author.userName + " - "; ss += "link + "\" title=\"" + currentPost()->creationDateTime.toString(Qt::DefaultLocaleLongDate) + "\">%1"; if( !currentPost()->source.isEmpty() ) ss += " - " + currentPost()->source; if (!currentPost()->replyToPostId.isEmpty()) { const QString link = currentAccount()->microblog()->postUrl(currentAccount(), currentPost()->replyToUserName, currentPost()->replyToPostId ); ss += " - "; ss += i18n("in reply to @%3", link, currentAccount()->microblog()->profileUrl(currentAccount(), currentPost()->replyToUserId), currentPost()->replyToUserName); } return ss; } +void PumpIOPostWidget::initUi() +{ + Choqok::UI::PostWidget::initUi(); + + d->btnFav = addButton("btnFavorite", i18nc("@info:tooltip", "Favorite"), "rating"); + d->btnFav->setCheckable(true); + connect(d->btnFav, SIGNAL(clicked(bool)), this, SLOT(toggleFavorite())); + updateFavStat(); +} + +void PumpIOPostWidget::toggleFavorite() +{ + setReadWithSignal(); + PumpIOMicroBlog* microBlog = qobject_cast(currentAccount()->microblog()); + connect(microBlog, SIGNAL(favorite(Choqok::Account*, Choqok::Post*)), + this, SLOT(slotToggleFavorite(Choqok::Account*, Choqok::Post*))); + microBlog->toggleFavorite(currentAccount(), currentPost()); +} + +void PumpIOPostWidget::slotToggleFavorite(Choqok::Account*, Choqok::Post*) +{ + updateFavStat(); +} + void PumpIOPostWidget::slotPostError(Choqok::Account* theAccount, Choqok::Post* post, Choqok::MicroBlog::ErrorType error, const QString& errorMessage) { Q_UNUSED(error) if (theAccount == currentAccount() && post == currentPost()) { kDebug() << errorMessage; disconnect(currentAccount()->microblog(), SIGNAL(postRemoved(Choqok::Account*,Choqok::Post*)), this, SLOT(slotCurrentPostRemoved(Choqok::Account*,Choqok::Post*)) ); disconnect(currentAccount()->microblog(), SIGNAL(errorPost(Choqok::Account*,Choqok::Post*,Choqok::MicroBlog::ErrorType,QString,Choqok::MicroBlog::ErrorLevel)), this, SLOT(slotPostError(Choqok::Account*,Choqok::Post*,Choqok::MicroBlog::ErrorType,QString))); } } + +void PumpIOPostWidget::updateFavStat() +{ + d->btnFav->setChecked(currentPost()->isFavorited); + if (currentPost()->isFavorited){ + d->btnFav->setIcon(KIcon("rating")); + } else { + d->btnFav->setIcon(unFavIcon); + } +} \ No newline at end of file diff --git a/microblogs/pumpio/pumpiopostwidget.h b/microblogs/pumpio/pumpiopostwidget.h index 236aa2f6..1ed6d023 100644 --- a/microblogs/pumpio/pumpiopostwidget.h +++ b/microblogs/pumpio/pumpiopostwidget.h @@ -1,43 +1,56 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2013 Andrea Scarpino This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #ifndef PUMPIOPOSTWIDGET_H #define PUMPIOPOSTWIDGET_H #include "postwidget.h" class PumpIOPostWidget : public Choqok::UI::PostWidget { Q_OBJECT public: explicit PumpIOPostWidget(Choqok::Account* account, Choqok::Post* post, QWidget* parent = 0); virtual ~PumpIOPostWidget(); virtual QString generateSign(); + virtual void initUi(); protected Q_SLOTS: virtual void slotPostError(Choqok::Account* theAccount, Choqok::Post* post, Choqok::MicroBlog::ErrorType error, const QString& errorMessage); + virtual void toggleFavorite(); + virtual void slotToggleFavorite(Choqok::Account*, Choqok::Post*); + +protected: + static const KIcon unFavIcon; + +private: + void updateFavStat(); + + class Private; + Private * const d; + }; #endif // PUMPIOPOSTWIDGET_H \ No newline at end of file