Enable ending polls
This commit is contained in:
@@ -58,6 +58,14 @@ PollEndEvent::PollEndEvent(const QJsonObject &obj)
|
||||
{
|
||||
}
|
||||
|
||||
PollEndEvent::PollEndEvent(const QString &pollStartEventId, const QString &endText)
|
||||
: RoomEvent(basicJson(TypeId,
|
||||
{{"org.matrix.msc1767.text"_L1, endText},
|
||||
{"org.matrix.msc3381.poll.end"_L1, QJsonObject{}},
|
||||
{"m.relates_to"_L1, QJsonObject{{"rel_type"_L1, "m.reference"_L1}, {"event_id"_L1, pollStartEventId}}}}))
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<EventRelation> PollEndEvent::relatesTo() const
|
||||
{
|
||||
return contentPart<std::optional<EventRelation>>(RelatesToKey);
|
||||
|
||||
@@ -225,6 +225,7 @@ class PollEndEvent : public RoomEvent
|
||||
public:
|
||||
QUO_EVENT(PollEndEvent, "org.matrix.msc3381.poll.end");
|
||||
explicit PollEndEvent(const QJsonObject &obj);
|
||||
explicit PollEndEvent(const QString &pollStartEventId, const QString &endText);
|
||||
|
||||
/**
|
||||
* @brief The EventRelation pointing to the PollStartEvent.
|
||||
|
||||
@@ -238,6 +238,10 @@ QVariant MessageModel::data(const QModelIndex &idx, int role) const
|
||||
return {};
|
||||
}
|
||||
|
||||
if (role == IsPollRole) {
|
||||
return event->get().is<PollStartEvent>();
|
||||
}
|
||||
|
||||
if (role == ShowSectionRole) {
|
||||
for (auto r = row + 1; r < rowCount(); ++r) {
|
||||
auto i = index(r);
|
||||
@@ -316,6 +320,7 @@ QHash<int, QByteArray> MessageModel::roleNames() const
|
||||
roles[ProgressInfoRole] = "progressInfo";
|
||||
roles[IsThreadedRole] = "isThreaded";
|
||||
roles[ThreadRootRole] = "threadRoot";
|
||||
roles[IsPollRole] = "isPoll";
|
||||
roles[ShowSectionRole] = "showSection";
|
||||
roles[ReadMarkersRole] = "readMarkers";
|
||||
roles[ShowReadMarkersRole] = "showReadMarkers";
|
||||
|
||||
@@ -72,6 +72,7 @@ public:
|
||||
|
||||
IsThreadedRole, /**< Whether the message is in a thread. */
|
||||
ThreadRootRole, /**< The Matrix ID of the thread root message, if any . */
|
||||
IsPollRole, /**< Whether the message is a poll. */
|
||||
|
||||
ShowSectionRole, /**< Whether the section header should be shown. */
|
||||
|
||||
|
||||
@@ -502,7 +502,7 @@ public:
|
||||
*
|
||||
* @sa PollHandler
|
||||
*/
|
||||
PollHandler *poll(const QString &eventId);
|
||||
Q_INVOKABLE PollHandler *poll(const QString &eventId);
|
||||
|
||||
Q_INVOKABLE void postPoll(PollKind::Kind kind, const QString &question, const QList<QString> &answers);
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "pollhandler.h"
|
||||
|
||||
#include <KLocalization>
|
||||
|
||||
#include "events/pollevent.h"
|
||||
#include "neochatroom.h"
|
||||
#include "pollanswermodel.h"
|
||||
@@ -24,6 +26,7 @@ PollHandler::PollHandler(NeoChatRoom *room, const QString &pollStartId)
|
||||
|
||||
if (room != nullptr) {
|
||||
connect(room, &NeoChatRoom::aboutToAddNewMessages, this, &PollHandler::updatePoll);
|
||||
connect(room, &NeoChatRoom::pendingEventAboutToAdd, this, &PollHandler::handleEvent);
|
||||
checkLoadRelations();
|
||||
}
|
||||
}
|
||||
@@ -37,34 +40,8 @@ void PollHandler::updatePoll(Quotient::RoomEventsRange events)
|
||||
if (pollStartEvent == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &event : events) {
|
||||
if (event->is<PollEndEvent>()) {
|
||||
const auto endEvent = eventCast<const PollEndEvent>(event);
|
||||
if (endEvent->relatesTo()->eventId != m_pollStartId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto plEvent = room->currentState().get<RoomPowerLevelsEvent>();
|
||||
if (!plEvent) {
|
||||
continue;
|
||||
}
|
||||
auto userPl = plEvent->powerLevelForUser(event->senderId());
|
||||
if (event->senderId() == pollStartEvent->senderId() || userPl >= plEvent->redact()) {
|
||||
m_hasEnded = true;
|
||||
m_endedTimestamp = event->originTimestamp();
|
||||
Q_EMIT hasEndedChanged();
|
||||
}
|
||||
}
|
||||
if (event->is<PollResponseEvent>()) {
|
||||
handleResponse(eventCast<const PollResponseEvent>(event));
|
||||
}
|
||||
if (event->contentPart<QJsonObject>("m.relates_to"_L1).contains("rel_type"_L1)
|
||||
&& event->contentPart<QJsonObject>("m.relates_to"_L1)["rel_type"_L1].toString() == "m.replace"_L1
|
||||
&& event->contentPart<QJsonObject>("m.relates_to"_L1)["event_id"_L1].toString() == pollStartEvent->id()) {
|
||||
Q_EMIT questionChanged();
|
||||
Q_EMIT answersChanged();
|
||||
}
|
||||
handleEvent(event.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,32 +56,51 @@ void PollHandler::checkLoadRelations()
|
||||
}
|
||||
|
||||
auto job = room->connection()->callApi<GetRelatingEventsJob>(room->id(), pollStartEvent->id());
|
||||
connect(job, &BaseJob::success, this, [this, job, room, pollStartEvent]() {
|
||||
connect(job, &BaseJob::success, this, [this, job]() {
|
||||
for (const auto &event : job->chunk()) {
|
||||
if (event->is<PollEndEvent>()) {
|
||||
const auto endEvent = eventCast<const PollEndEvent>(event);
|
||||
if (endEvent->relatesTo()->eventId != m_pollStartId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto plEvent = room->currentState().get<RoomPowerLevelsEvent>();
|
||||
if (!plEvent) {
|
||||
continue;
|
||||
}
|
||||
auto userPl = plEvent->powerLevelForUser(event->senderId());
|
||||
if (event->senderId() == pollStartEvent->senderId() || userPl >= plEvent->redact()) {
|
||||
m_hasEnded = true;
|
||||
m_endedTimestamp = event->originTimestamp();
|
||||
Q_EMIT hasEndedChanged();
|
||||
}
|
||||
}
|
||||
if (event->is<PollResponseEvent>()) {
|
||||
handleResponse(eventCast<const PollResponseEvent>(event));
|
||||
}
|
||||
handleEvent(event.get());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PollHandler::handleEvent(Quotient::RoomEvent *event)
|
||||
{
|
||||
// This function will never be called if the PollHandler was not initialized with
|
||||
// a NeoChatRoom as parent and a PollStartEvent so no need to null check.
|
||||
const auto room = dynamic_cast<NeoChatRoom *>(parent());
|
||||
auto pollStartEvent = eventCast<const PollStartEvent>(room->getEvent(m_pollStartId).first);
|
||||
if (pollStartEvent == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->is<PollEndEvent>()) {
|
||||
const auto endEvent = eventCast<const PollEndEvent>(event);
|
||||
if (endEvent->relatesTo()->eventId != m_pollStartId) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto plEvent = room->currentState().get<RoomPowerLevelsEvent>();
|
||||
if (!plEvent) {
|
||||
return;
|
||||
}
|
||||
auto userPl = plEvent->powerLevelForUser(event->senderId());
|
||||
if (event->senderId() == pollStartEvent->senderId() || userPl >= plEvent->redact()) {
|
||||
m_hasEnded = true;
|
||||
m_endedTimestamp = event->originTimestamp();
|
||||
Q_EMIT hasEndedChanged();
|
||||
}
|
||||
}
|
||||
if (event->is<PollResponseEvent>()) {
|
||||
handleResponse(eventCast<const PollResponseEvent>(event));
|
||||
}
|
||||
if (event->contentPart<QJsonObject>("m.relates_to"_L1).contains("rel_type"_L1)
|
||||
&& event->contentPart<QJsonObject>("m.relates_to"_L1)["rel_type"_L1].toString() == "m.replace"_L1
|
||||
&& event->contentPart<QJsonObject>("m.relates_to"_L1)["event_id"_L1].toString() == pollStartEvent->id()) {
|
||||
Q_EMIT questionChanged();
|
||||
Q_EMIT answersChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void PollHandler::handleResponse(const Quotient::PollResponseEvent *event)
|
||||
{
|
||||
if (event == nullptr) {
|
||||
@@ -292,4 +288,32 @@ bool PollHandler::hasEnded() const
|
||||
return m_hasEnded;
|
||||
}
|
||||
|
||||
void PollHandler::endPoll() const
|
||||
{
|
||||
room()->post<PollEndEvent>(m_pollStartId, endText());
|
||||
}
|
||||
|
||||
QString PollHandler::endText() const
|
||||
{
|
||||
auto room = dynamic_cast<NeoChatRoom *>(parent());
|
||||
if (room == nullptr) {
|
||||
return {};
|
||||
}
|
||||
auto pollStartEvent = eventCast<const PollStartEvent>(room->getEvent(m_pollStartId).first);
|
||||
if (pollStartEvent == nullptr) {
|
||||
return {};
|
||||
}
|
||||
int maxCount = 0;
|
||||
QString answerText = {};
|
||||
for (const auto &answer : pollStartEvent->answers()) {
|
||||
const auto currentCount = answerCountAtId(answer.id);
|
||||
if (currentCount > maxCount) {
|
||||
maxCount = currentCount;
|
||||
answerText = answer.text;
|
||||
}
|
||||
}
|
||||
|
||||
return i18nc("%1 is the poll answer that had the most votes", "The poll has ended. Top answer: %1", answerText);
|
||||
}
|
||||
|
||||
#include "moc_pollhandler.cpp"
|
||||
|
||||
@@ -106,6 +106,11 @@ public:
|
||||
*/
|
||||
Q_INVOKABLE void sendPollAnswer(const QString &eventId, const QString &answerId);
|
||||
|
||||
/**
|
||||
* @brief Send the PollEndEvent.
|
||||
*/
|
||||
Q_INVOKABLE void endPoll() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void questionChanged();
|
||||
void hasEndedChanged();
|
||||
@@ -123,12 +128,14 @@ private:
|
||||
void updatePoll(Quotient::RoomEventsRange events);
|
||||
|
||||
void checkLoadRelations();
|
||||
void handleEvent(Quotient::RoomEvent *event);
|
||||
void handleResponse(const Quotient::PollResponseEvent *event);
|
||||
QHash<QString, QDateTime> m_selectionTimestamps;
|
||||
QHash<QString, QStringList> m_selections;
|
||||
|
||||
bool m_hasEnded = false;
|
||||
QDateTime m_endedTimestamp;
|
||||
QString endText() const;
|
||||
|
||||
QPointer<PollAnswerModel> m_answerModel;
|
||||
};
|
||||
|
||||
@@ -136,7 +136,7 @@ QQC2.Control {
|
||||
}
|
||||
|
||||
QQC2.Button {
|
||||
visible: NeoChatConfig.threads && !root.currentRoom.readOnly
|
||||
visible: NeoChatConfig.threads && !root.currentRoom.readOnly && !root.delegate?.isPoll
|
||||
text: i18n("Reply in Thread")
|
||||
icon.name: "dialog-messages"
|
||||
display: QQC2.Button.IconOnly
|
||||
@@ -153,6 +153,18 @@ QQC2.Control {
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
|
||||
QQC2.Button {
|
||||
visible: (root.delegate?.isPoll ?? false) && !root.currentRoom.poll(root.delegate.eventId).hasEnded
|
||||
text: i18n("End Poll")
|
||||
icon.name: "gtk-stop"
|
||||
display: QQC2.ToolButton.IconOnly
|
||||
onClicked: root.currentRoom.poll(root.delegate.eventId).endPoll()
|
||||
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
|
||||
EmojiDialog {
|
||||
id: emojiDialog
|
||||
currentRoom: root.currentRoom
|
||||
|
||||
@@ -92,6 +92,11 @@ TimelineDelegate {
|
||||
*/
|
||||
required property string threadRoot
|
||||
|
||||
/**
|
||||
* @brief Whether the message in a poll.
|
||||
*/
|
||||
required property bool isPoll
|
||||
|
||||
/**
|
||||
* @brief Whether this message has a local user mention.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user