Rework the appearance of poll delegate
{width=541 height=269}
This commit is contained in:
@@ -12,7 +12,7 @@ PollAnswerModel::PollAnswerModel(PollHandler *parent)
|
|||||||
Q_ASSERT(parent != nullptr);
|
Q_ASSERT(parent != nullptr);
|
||||||
|
|
||||||
connect(parent, &PollHandler::selectionsChanged, this, [this]() {
|
connect(parent, &PollHandler::selectionsChanged, this, [this]() {
|
||||||
dataChanged(index(0), index(rowCount() - 1), {CountRole, LocalChoiceRole});
|
dataChanged(index(0), index(rowCount() - 1), {CountRole, LocalChoiceRole, IsWinnerRole});
|
||||||
});
|
});
|
||||||
connect(parent, &PollHandler::answersChanged, this, [this]() {
|
connect(parent, &PollHandler::answersChanged, this, [this]() {
|
||||||
dataChanged(index(0), index(rowCount() - 1), {TextRole});
|
dataChanged(index(0), index(rowCount() - 1), {TextRole});
|
||||||
@@ -50,6 +50,9 @@ QVariant PollAnswerModel::data(const QModelIndex &index, int role) const
|
|||||||
}
|
}
|
||||||
return pollHandler->checkMemberSelectedId(room->localMember().id(), pollHandler->answerAtRow(row).id);
|
return pollHandler->checkMemberSelectedId(room->localMember().id(), pollHandler->answerAtRow(row).id);
|
||||||
}
|
}
|
||||||
|
if (role == IsWinnerRole) {
|
||||||
|
return pollHandler->winningAnswerIds().contains(pollHandler->answerAtRow(row).id) && pollHandler->hasEnded();
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,5 +75,6 @@ QHash<int, QByteArray> PollAnswerModel::roleNames() const
|
|||||||
{TextRole, "answerText"},
|
{TextRole, "answerText"},
|
||||||
{CountRole, "count"},
|
{CountRole, "count"},
|
||||||
{LocalChoiceRole, "localChoice"},
|
{LocalChoiceRole, "localChoice"},
|
||||||
|
{IsWinnerRole, "isWinner"},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public:
|
|||||||
TextRole, /**< The answer text. */
|
TextRole, /**< The answer text. */
|
||||||
CountRole, /**< The number of people who gave this answer. */
|
CountRole, /**< The number of people who gave this answer. */
|
||||||
LocalChoiceRole, /**< Whether this option was selected by the local user */
|
LocalChoiceRole, /**< Whether this option was selected by the local user */
|
||||||
|
IsWinnerRole, /**< Whether this option was selected by the local user */
|
||||||
};
|
};
|
||||||
Q_ENUM(Roles)
|
Q_ENUM(Roles)
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <Quotient/events/roompowerlevelsevent.h>
|
#include <Quotient/events/roompowerlevelsevent.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <qcontainerfwd.h>
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
@@ -133,6 +134,7 @@ void PollHandler::handleResponse(const Quotient::PollResponseEvent *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Q_EMIT totalCountChanged();
|
||||||
Q_EMIT selectionsChanged();
|
Q_EMIT selectionsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,6 +219,44 @@ PollAnswerModel *PollHandler::answerModel()
|
|||||||
return m_answerModel;
|
return m_answerModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int PollHandler::totalCount() const
|
||||||
|
{
|
||||||
|
int votes = 0;
|
||||||
|
for (const auto &selection : m_selections) {
|
||||||
|
votes += selection.size();
|
||||||
|
}
|
||||||
|
return votes;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList PollHandler::winningAnswerIds() 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 {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList currentWinners;
|
||||||
|
for (const auto &answer : pollStartEvent->answers()) {
|
||||||
|
if (currentWinners.isEmpty()) {
|
||||||
|
currentWinners += answer.id;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (answerCountAtId(currentWinners.first()) < answerCountAtId(answer.id)) {
|
||||||
|
currentWinners.clear();
|
||||||
|
currentWinners += answer.id;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (answerCountAtId(currentWinners.first()) == answerCountAtId(answer.id)) {
|
||||||
|
currentWinners += answer.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return currentWinners;
|
||||||
|
}
|
||||||
|
|
||||||
void PollHandler::sendPollAnswer(const QString &eventId, const QString &answerId)
|
void PollHandler::sendPollAnswer(const QString &eventId, const QString &answerId)
|
||||||
{
|
{
|
||||||
Q_ASSERT(eventId.length() > 0);
|
Q_ASSERT(eventId.length() > 0);
|
||||||
|
|||||||
@@ -58,6 +58,11 @@ class PollHandler : public QObject
|
|||||||
*/
|
*/
|
||||||
Q_PROPERTY(PollAnswerModel *answerModel READ answerModel CONSTANT)
|
Q_PROPERTY(PollAnswerModel *answerModel READ answerModel CONSTANT)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The total number of vote responses to the poll.
|
||||||
|
*/
|
||||||
|
Q_PROPERTY(int totalCount READ totalCount NOTIFY totalCountChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PollHandler() = default;
|
PollHandler() = default;
|
||||||
PollHandler(NeoChatRoom *room, const QString &pollStartId);
|
PollHandler(NeoChatRoom *room, const QString &pollStartId);
|
||||||
@@ -89,6 +94,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool checkMemberSelectedId(const QString &memberId, const QString &id) const;
|
bool checkMemberSelectedId(const QString &memberId, const QString &id) const;
|
||||||
|
|
||||||
|
int totalCount() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The current answer IDs with the most votes.
|
||||||
|
*/
|
||||||
|
QStringList winningAnswerIds() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send an answer to the poll.
|
* @brief Send an answer to the poll.
|
||||||
*/
|
*/
|
||||||
@@ -97,8 +109,8 @@ public:
|
|||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void questionChanged();
|
void questionChanged();
|
||||||
void hasEndedChanged();
|
void hasEndedChanged();
|
||||||
|
|
||||||
void answersChanged();
|
void answersChanged();
|
||||||
|
void totalCountChanged();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Emitted when the selected answers to the poll change.
|
* @brief Emitted when the selected answers to the poll change.
|
||||||
@@ -113,7 +125,7 @@ private:
|
|||||||
void checkLoadRelations();
|
void checkLoadRelations();
|
||||||
void handleResponse(const Quotient::PollResponseEvent *event);
|
void handleResponse(const Quotient::PollResponseEvent *event);
|
||||||
QHash<QString, QDateTime> m_selectionTimestamps;
|
QHash<QString, QDateTime> m_selectionTimestamps;
|
||||||
QHash<QString, QList<QString>> m_selections;
|
QHash<QString, QStringList> m_selections;
|
||||||
|
|
||||||
bool m_hasEnded = false;
|
bool m_hasEnded = false;
|
||||||
QDateTime m_endedTimestamp;
|
QDateTime m_endedTimestamp;
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls as QQC2
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
|
import org.kde.kirigamiaddons.delegates as Delegates
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
import org.kde.kirigamiaddons.formcard as FormCard
|
||||||
|
|
||||||
import Quotient
|
import Quotient
|
||||||
@@ -34,50 +35,100 @@ ColumnLayout {
|
|||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.maximumWidth: Message.maxContentWidth
|
Layout.maximumWidth: Message.maxContentWidth
|
||||||
|
Layout.minimumWidth: Message.maxContentWidth
|
||||||
|
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Label {
|
RowLayout {
|
||||||
id: questionLabel
|
|
||||||
text: root.pollHandler.question
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
visible: text.length > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Kirigami.Icon {
|
||||||
|
implicitWidth: Kirigami.Units.iconSizes.smallMedium
|
||||||
|
implicitHeight: implicitWidth
|
||||||
|
source: "amarok_playcount"
|
||||||
|
}
|
||||||
|
QQC2.Label {
|
||||||
|
id: questionLabel
|
||||||
|
Layout.fillWidth: true
|
||||||
|
topPadding: Kirigami.Units.largeSpacing
|
||||||
|
bottomPadding: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
|
text: root.pollHandler.question
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
visible: text.length > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
Repeater {
|
Repeater {
|
||||||
model: root.pollHandler.answerModel
|
model: root.pollHandler.answerModel
|
||||||
delegate: FormCard.FormCheckDelegate {
|
delegate: Delegates.RoundedItemDelegate {
|
||||||
id: answerDelegate
|
id: answerDelegate
|
||||||
|
|
||||||
required property string id
|
required property string id
|
||||||
required property string answerText
|
required property string answerText
|
||||||
required property int count
|
required property int count
|
||||||
required property bool localChoice
|
required property bool localChoice
|
||||||
|
required property bool isWinner
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: -Kirigami.Units.largeSpacing - Kirigami.Units.smallSpacing
|
Layout.leftMargin: -Kirigami.Units.largeSpacing - Kirigami.Units.smallSpacing
|
||||||
Layout.rightMargin: -Kirigami.Units.largeSpacing - Kirigami.Units.smallSpacing
|
Layout.rightMargin: -Kirigami.Units.largeSpacing - Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
checked: answerDelegate.localChoice
|
highlighted: false
|
||||||
onClicked: root.pollHandler.sendPollAnswer(root.eventId, answerDelegate.id)
|
|
||||||
enabled: !root.pollHandler.hasEnded
|
onClicked: {
|
||||||
|
if (root.pollHandler.hasEnded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
root.pollHandler.sendPollAnswer(root.eventId, answerDelegate.id);
|
||||||
|
}
|
||||||
text: answerDelegate.answerText
|
text: answerDelegate.answerText
|
||||||
|
|
||||||
topPadding: Kirigami.Units.smallSpacing
|
topPadding: Kirigami.Units.smallSpacing
|
||||||
bottomPadding: Kirigami.Units.smallSpacing
|
bottomPadding: Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
trailing: Label {
|
contentItem: ColumnLayout {
|
||||||
visible: root.pollHandler.kind == PollKind.Disclosed || pollHandler.hasEnded
|
Layout.fillWidth: true
|
||||||
Layout.preferredWidth: contentWidth
|
|
||||||
text: answerDelegate.count
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
QQC2.CheckBox {
|
||||||
|
enabled: !root.pollHandler.hasEnded
|
||||||
|
checked: answerDelegate.localChoice
|
||||||
|
|
||||||
|
onClicked: answerDelegate.clicked()
|
||||||
|
}
|
||||||
|
QQC2.Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: answerDelegate.answerText
|
||||||
|
}
|
||||||
|
Kirigami.Icon {
|
||||||
|
implicitWidth: Kirigami.Units.iconSizes.small
|
||||||
|
implicitHeight: implicitWidth
|
||||||
|
visible: answerDelegate.isWinner
|
||||||
|
source: "favorite-favorited"
|
||||||
|
}
|
||||||
|
QQC2.Label {
|
||||||
|
visible: root.pollHandler.kind == PollKind.Disclosed || pollHandler.hasEnded
|
||||||
|
horizontalAlignment: Text.AlignRight
|
||||||
|
text: i18np("%1 Vote", "%1 Votes", answerDelegate.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QQC2.ProgressBar {
|
||||||
|
id: voteProgress
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
to: root.pollHandler.totalCount
|
||||||
|
value: root.pollHandler.kind == PollKind.Disclosed || pollHandler.hasEnded ? answerDelegate.count : 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
QQC2.Label {
|
||||||
visible: root.pollHandler.kind == "org.matrix.msc3381.poll.disclosed" || root.pollHandler.hasEnded
|
visible: root.pollHandler.kind == PollKind.Disclosed || root.pollHandler.hasEnded
|
||||||
text: i18np("Based on votes by %1 user", "Based on votes by %1 users", root.pollHandler.answerCount) + (root.pollHandler.hasEnded ? (" " + i18nc("as in 'this vote has ended'", "(Ended)")) : "")
|
text: i18np("Based on votes by %1 user", "Based on votes by %1 users", root.pollHandler.totalCount) + (root.pollHandler.hasEnded ? (" " + i18nc("as in 'this vote has ended'", "(Ended)")) : "")
|
||||||
font.pointSize: questionLabel.font.pointSize * 0.8
|
font.pointSize: questionLabel.font.pointSize * 0.8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user