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);
|
||||
|
||||
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]() {
|
||||
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);
|
||||
}
|
||||
if (role == IsWinnerRole) {
|
||||
return pollHandler->winningAnswerIds().contains(pollHandler->answerAtRow(row).id) && pollHandler->hasEnded();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -72,5 +75,6 @@ QHash<int, QByteArray> PollAnswerModel::roleNames() const
|
||||
{TextRole, "answerText"},
|
||||
{CountRole, "count"},
|
||||
{LocalChoiceRole, "localChoice"},
|
||||
{IsWinnerRole, "isWinner"},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
TextRole, /**< The answer text. */
|
||||
CountRole, /**< The number of people who gave this answer. */
|
||||
LocalChoiceRole, /**< Whether this option was selected by the local user */
|
||||
IsWinnerRole, /**< Whether this option was selected by the local user */
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <Quotient/events/roompowerlevelsevent.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <qcontainerfwd.h>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
@@ -133,6 +134,7 @@ void PollHandler::handleResponse(const Quotient::PollResponseEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
Q_EMIT totalCountChanged();
|
||||
Q_EMIT selectionsChanged();
|
||||
}
|
||||
|
||||
@@ -217,6 +219,44 @@ PollAnswerModel *PollHandler::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)
|
||||
{
|
||||
Q_ASSERT(eventId.length() > 0);
|
||||
|
||||
@@ -58,6 +58,11 @@ class PollHandler : public QObject
|
||||
*/
|
||||
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:
|
||||
PollHandler() = default;
|
||||
PollHandler(NeoChatRoom *room, const QString &pollStartId);
|
||||
@@ -89,6 +94,13 @@ public:
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -97,8 +109,8 @@ public:
|
||||
Q_SIGNALS:
|
||||
void questionChanged();
|
||||
void hasEndedChanged();
|
||||
|
||||
void answersChanged();
|
||||
void totalCountChanged();
|
||||
|
||||
/**
|
||||
* @brief Emitted when the selected answers to the poll change.
|
||||
@@ -113,7 +125,7 @@ private:
|
||||
void checkLoadRelations();
|
||||
void handleResponse(const Quotient::PollResponseEvent *event);
|
||||
QHash<QString, QDateTime> m_selectionTimestamps;
|
||||
QHash<QString, QList<QString>> m_selections;
|
||||
QHash<QString, QStringList> m_selections;
|
||||
|
||||
bool m_hasEnded = false;
|
||||
QDateTime m_endedTimestamp;
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.delegates as Delegates
|
||||
import org.kde.kirigamiaddons.formcard as FormCard
|
||||
|
||||
import Quotient
|
||||
@@ -34,50 +35,100 @@ ColumnLayout {
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: Message.maxContentWidth
|
||||
Layout.minimumWidth: Message.maxContentWidth
|
||||
|
||||
spacing: 0
|
||||
|
||||
Label {
|
||||
id: questionLabel
|
||||
text: root.pollHandler.question
|
||||
wrapMode: Text.Wrap
|
||||
RowLayout {
|
||||
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 {
|
||||
model: root.pollHandler.answerModel
|
||||
delegate: FormCard.FormCheckDelegate {
|
||||
delegate: Delegates.RoundedItemDelegate {
|
||||
id: answerDelegate
|
||||
|
||||
required property string id
|
||||
required property string answerText
|
||||
required property int count
|
||||
required property bool localChoice
|
||||
required property bool isWinner
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: -Kirigami.Units.largeSpacing - Kirigami.Units.smallSpacing
|
||||
Layout.rightMargin: -Kirigami.Units.largeSpacing - Kirigami.Units.smallSpacing
|
||||
|
||||
checked: answerDelegate.localChoice
|
||||
onClicked: root.pollHandler.sendPollAnswer(root.eventId, answerDelegate.id)
|
||||
enabled: !root.pollHandler.hasEnded
|
||||
highlighted: false
|
||||
|
||||
onClicked: {
|
||||
if (root.pollHandler.hasEnded) {
|
||||
return;
|
||||
}
|
||||
root.pollHandler.sendPollAnswer(root.eventId, answerDelegate.id);
|
||||
}
|
||||
text: answerDelegate.answerText
|
||||
|
||||
topPadding: Kirigami.Units.smallSpacing
|
||||
bottomPadding: Kirigami.Units.smallSpacing
|
||||
|
||||
trailing: Label {
|
||||
visible: root.pollHandler.kind == PollKind.Disclosed || pollHandler.hasEnded
|
||||
Layout.preferredWidth: contentWidth
|
||||
text: answerDelegate.count
|
||||
contentItem: ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
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 {
|
||||
visible: root.pollHandler.kind == "org.matrix.msc3381.poll.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)")) : "")
|
||||
QQC2.Label {
|
||||
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.totalCount) + (root.pollHandler.hasEnded ? (" " + i18nc("as in 'this vote has ended'", "(Ended)")) : "")
|
||||
font.pointSize: questionLabel.font.pointSize * 0.8
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user