From cb820fa02315cbf5ecc7f87435bc724460104f19 Mon Sep 17 00:00:00 2001 From: "Javier S. Pedro" Date: Sat, 6 Apr 2013 20:34:56 +0200 Subject: support replying to posts --- board.cpp | 40 +++++++++++++++++++++++---------- board.h | 8 ++++++- newpostaction.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++ newpostaction.h | 28 +++++++++++++++++++++++ qml/ForumPage.qml | 6 +++++ qml/NewPostSheet.qml | 38 +++++++++++++++++++++++++++++++ qml/TopicPage.qml | 18 +++++++++++++++ tapasboard.pro | 6 +++-- 8 files changed, 192 insertions(+), 15 deletions(-) create mode 100644 newpostaction.cpp create mode 100644 newpostaction.h create mode 100644 qml/NewPostSheet.qml diff --git a/board.cpp b/board.cpp index 5878475..7e734cb 100644 --- a/board.cpp +++ b/board.cpp @@ -9,6 +9,7 @@ #include "fetchconfigaction.h" #include "fetchforumsaction.h" #include "loginaction.h" +#include "newpostaction.h" #include "xmlrpcinterface.h" #include "board.h" @@ -150,6 +151,29 @@ void Board::logout() // TODO } +int Board::getTopicForumId(int topicId) +{ + QSqlQuery q(_db); + q.prepare("SELECT forum_id FROM topics WHERE topic_id = ?"); + q.bindValue(0, topicId); + if (q.exec()) { + if (q.next()) { + return q.value(0).toInt(); + } else { + qWarning() << "Could not get forum of topic"; + } + } else { + qWarning() << "Could not get forum of topic:" << q.lastError().text(); + } + + return -1; +} + +void Board::replyToTopic(int topicId, const QString &text) +{ + enqueueAction(new NewPostAction(topicId, text, this)); +} + QString Board::removeHtml(QString text) const { static const QRegExp regexp("<[a-zA-Z\\/][^>]*>"); @@ -322,18 +346,10 @@ void Board::markTopicAsRead(int topicId) q.bindValue(0, topicId); if (q.exec()) { if (q.numRowsAffected() > 0) { - q.prepare("SELECT forum_id FROM topics WHERE topic_id = ?"); - q.bindValue(0, topicId); - if (q.exec()) { - if (q.next()) { - int forum_id = q.value(0).toInt(); - notifyForumTopicChanged(forum_id, topicId); - updateForumReadState(forum_id); - } else { - qWarning() << "Could not get forum of topic"; - } - } else { - qWarning() << "Could not get forum of topic:" << q.lastError().text(); + int forum_id = getTopicForumId(topicId); + if (forum_id >= 0) { + notifyForumTopicChanged(forum_id, topicId); + updateForumReadState(forum_id); } } } else { diff --git a/board.h b/board.h index 7e8fb97..e48dd6f 100644 --- a/board.h +++ b/board.h @@ -48,7 +48,13 @@ public: void login(const QString& username, const QString& password); void logout(); - // Some helper functions + // Other functions that query the database + int getTopicForumId(int topicId); + + // Posting stuff + Q_INVOKABLE void replyToTopic(int topicId, const QString& text); + + // BBCode-related helper functions QString removeHtml(QString text) const; QString removeBbcode(QString text) const; QString bbcodeToRichText(QString text) const; diff --git a/newpostaction.cpp b/newpostaction.cpp new file mode 100644 index 0000000..4ad6244 --- /dev/null +++ b/newpostaction.cpp @@ -0,0 +1,63 @@ +#include +#include +#include + +#include "global.h" +#include "board.h" +#include "xmlrpcinterface.h" +#include "xmlrpcreply.h" +#include "newpostaction.h" +#include "fetchpostsaction.h" + +NewPostAction::NewPostAction(int topicId, const QString &text, Board *board) + : Action(board), _topicId(topicId), _text(text) +{ +} + +bool NewPostAction::isSupersetOf(Action *action) const +{ + return false; +} + +void NewPostAction::execute() +{ + int forum_id = _board->getTopicForumId(_topicId); + + _call = _board->service()->asyncCall("reply_post", + QString::number(forum_id), + QString::number(_topicId), + QByteArray(), // Empty subject + _text.toUtf8() + ); + _call->setParent(this); + connect(_call, SIGNAL(finished(XmlRpcPendingCall*)), SLOT(handleFinishedCall())); +} + +void NewPostAction::handleFinishedCall() +{ + XmlRpcReply result(_call); + if (result.isValid()) { + QVariantMap map = result; + bool post_ok = map["result"].toBool(); + if (post_ok) { + int state = map["state"].toInt(); + if (state == 1) { + // Awaiting moderation + // TODO + } else { + // Refresh posts + _board->enqueueAction(new FetchPostsAction(_topicId, + FetchPostsAction::FetchUnreadPosts, + TOPIC_PAGE_SIZE, + _board)); + } + } else { + qWarning() << "Could not submit post:" << map["result_text"].toString(); + } + } else { + qWarning() << "Could not submit post"; + // TODO emit error ... + } + emit finished(this); + _call->deleteLater(); +} diff --git a/newpostaction.h b/newpostaction.h new file mode 100644 index 0000000..27896df --- /dev/null +++ b/newpostaction.h @@ -0,0 +1,28 @@ +#ifndef NEWPOSTACTION_H +#define NEWPOSTACTION_H + +#include "action.h" + +class XmlRpcPendingCall; + +class NewPostAction : public Action +{ + Q_OBJECT +public: + explicit NewPostAction(int topicId, const QString& text, Board *board); + + bool isSupersetOf(Action *action) const; + + void execute(); + +private slots: + void handleFinishedCall(); + +private: + XmlRpcPendingCall *_call; + int _topicId; + QString _text; +}; + + +#endif // NEWPOSTACTION_H diff --git a/qml/ForumPage.qml b/qml/ForumPage.qml index ee04e43..4f2b64f 100644 --- a/qml/ForumPage.qml +++ b/qml/ForumPage.qml @@ -17,6 +17,9 @@ Page { platformIconId: "toolbar-back" onClicked: pageStack.pop() } + ToolIcon { + platformIconId: "toolbar-add" + } ToolIcon { platformIconId: board.busy ? "toolbar-cancle" : "toolbar-refresh" onClicked: { @@ -27,6 +30,9 @@ Page { } } } + ToolIcon { + platformIconId: "toolbar-view-menu" + } } ListView { diff --git a/qml/NewPostSheet.qml b/qml/NewPostSheet.qml new file mode 100644 index 0000000..96de9bc --- /dev/null +++ b/qml/NewPostSheet.qml @@ -0,0 +1,38 @@ +import QtQuick 1.1 +import com.nokia.meego 1.1 +import com.nokia.extras 1.1 +import com.javispedro.tapasboard 1.0 + +Sheet { + id: newPostSheet + + property Board board; + property int topicId; + + anchors.leftMargin: UiConstants.DefaultMargin + anchors.rightMargin: UiConstants.DefaultMargin + + acceptButtonText: qsTr("Submit") + rejectButtonText: qsTr("Cancel") + + content: TextArea { + id: postText + anchors { + fill: parent + } + + platformStyle: TextAreaStyle { + background: "image://theme/meegotouch-sheet-inputfield-background" + backgroundSelected: background + backgroundDisabled: "" + } + + placeholderText: qsTr("Write your reply here") + focus: true + wrapMode: TextEdit.Wrap + } + + onAccepted: { + board.replyToTopic(topicId, postText.text) + } +} diff --git a/qml/TopicPage.qml b/qml/TopicPage.qml index ebaa2c6..32a86ec 100644 --- a/qml/TopicPage.qml +++ b/qml/TopicPage.qml @@ -17,6 +17,19 @@ Page { platformIconId: "toolbar-back" onClicked: pageStack.pop() } + ToolIcon { + platformIconId: "toolbar-add" + onClicked: { + var component = Qt.createComponent("NewPostSheet.qml"); + if (component.status === Component.Ready) { + var sheet = component.createObject(topicPage, { + "board": board, + "topicId": topicId + }); + sheet.open(); + } + } + } ToolIcon { platformIconId: board.busy ? "toolbar-cancle" : "toolbar-refresh" onClicked: { @@ -27,6 +40,9 @@ Page { } } } + ToolIcon { + platformIconId: "toolbar-view-menu" + } } ListView { @@ -49,6 +65,8 @@ Page { text: section } + cacheBuffer: 200 + delegate: Item { id: postItem diff --git a/tapasboard.pro b/tapasboard.pro index 5d9bd08..4772169 100644 --- a/tapasboard.pro +++ b/tapasboard.pro @@ -51,7 +51,8 @@ SOURCES += main.cpp \ imagecache.cpp \ imagenetworkaccessmanager.cpp \ loginaction.cpp \ - markforumreadaction.cpp + markforumreadaction.cpp \ + newpostaction.cpp HEADERS += \ action.h \ @@ -72,7 +73,8 @@ HEADERS += \ imagecache.h \ imagenetworkaccessmanager.h \ loginaction.h \ - markforumreadaction.h + markforumreadaction.h \ + newpostaction.h TRANSLATIONS += i18n/en.ts i18n/es.ts -- cgit v1.2.3