Skip to content

Commit

Permalink
Merge pull request #4650 from nextcloud/bugfix/userstatusselectormode…
Browse files Browse the repository at this point in the history
…l-refactor

Properly adapt the UserStatusSelectorModel to QML, eliminate hacks, make code more declarative
  • Loading branch information
claucambra authored Jul 12, 2022
2 parents 004d4e9 + cf372b4 commit 53aba48
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 163 deletions.
2 changes: 1 addition & 1 deletion src/gui/BasicComboBox.qml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ ComboBox {
id: clearStatusDelegate
width: clearComboBox.width
contentItem: Label {
text: modelData
text: modelData.display
color: Style.ncTextColor
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
Expand Down
34 changes: 18 additions & 16 deletions src/gui/UserStatusSelector.qml
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ ColumnLayout {
}

UserStatusSelectorButton {
checked: NC.UserStatus.Online == userStatusSelectorModel.onlineStatus
checked: NC.UserStatus.Online === userStatusSelectorModel.onlineStatus
checkable: true
icon.source: userStatusSelectorModel.onlineIcon
icon.color: "transparent"
text: qsTr("Online")
onClicked: userStatusSelectorModel.setOnlineStatus(NC.UserStatus.Online)
onClicked: userStatusSelectorModel.onlineStatus = NC.UserStatus.Online

Layout.fillWidth: true
implicitWidth: 200 // Pretty much a hack to ensure all the buttons are equal in width
Expand All @@ -67,12 +67,12 @@ ColumnLayout {
Component.onCompleted: topButtonsLayout.updateMaxButtonHeight(implicitHeight)
}
UserStatusSelectorButton {
checked: NC.UserStatus.Away == userStatusSelectorModel.onlineStatus
checked: NC.UserStatus.Away === userStatusSelectorModel.onlineStatus
checkable: true
icon.source: userStatusSelectorModel.awayIcon
icon.color: "transparent"
text: qsTr("Away")
onClicked: userStatusSelectorModel.setOnlineStatus(NC.UserStatus.Away)
onClicked: userStatusSelectorModel.onlineStatus = NC.UserStatus.Away

Layout.fillWidth: true
implicitWidth: 200 // Pretty much a hack to ensure all the buttons are equal in width
Expand All @@ -82,13 +82,13 @@ ColumnLayout {

}
UserStatusSelectorButton {
checked: NC.UserStatus.DoNotDisturb == userStatusSelectorModel.onlineStatus
checked: NC.UserStatus.DoNotDisturb === userStatusSelectorModel.onlineStatus
checkable: true
icon.source: userStatusSelectorModel.dndIcon
icon.color: "transparent"
text: qsTr("Do not disturb")
secondaryText: qsTr("Mute all notifications")
onClicked: userStatusSelectorModel.setOnlineStatus(NC.UserStatus.DoNotDisturb)
onClicked: userStatusSelectorModel.onlineStatus = NC.UserStatus.DoNotDisturb

Layout.fillWidth: true
implicitWidth: 200 // Pretty much a hack to ensure all the buttons are equal in width
Expand All @@ -97,13 +97,13 @@ ColumnLayout {
Component.onCompleted: topButtonsLayout.updateMaxButtonHeight(implicitHeight)
}
UserStatusSelectorButton {
checked: NC.UserStatus.Invisible == userStatusSelectorModel.onlineStatus
checked: NC.UserStatus.Invisible === userStatusSelectorModel.onlineStatus
checkable: true
icon.source: userStatusSelectorModel.invisibleIcon
icon.color: "transparent"
text: qsTr("Invisible")
secondaryText: qsTr("Appear offline")
onClicked: userStatusSelectorModel.setOnlineStatus(NC.UserStatus.Invisible)
onClicked: userStatusSelectorModel.onlineStatus = NC.UserStatus.Invisible

Layout.fillWidth: true
implicitWidth: 200 // Pretty much a hack to ensure all the buttons are equal in width
Expand Down Expand Up @@ -214,7 +214,7 @@ ColumnLayout {
text: userStatusSelectorModel.userStatusMessage
color: Style.ncTextColor
selectByMouse: true
onEditingFinished: userStatusSelectorModel.setUserStatusMessage(text)
onEditingFinished: userStatusSelectorModel.userStatusMessage = text

property color borderColor: activeFocus ? Style.ncBlue : Style.menuBorder

Expand Down Expand Up @@ -247,7 +247,7 @@ ColumnLayout {
}

Repeater {
model: userStatusSelectorModel.predefinedStatusesCount
model: userStatusSelectorModel.predefinedStatuses

PredefinedStatusButton {
id: control
Expand All @@ -256,9 +256,9 @@ ColumnLayout {
Layout.rightMargin: Style.standardSpacing
internalSpacing: Style.standardSpacing + fieldButton.padding + userStatusMessageTextField.padding

emoji: userStatusSelectorModel.predefinedStatus(index).icon
text: "<b>" + userStatusSelectorModel.predefinedStatus(index).message + "</b> – " + userStatusSelectorModel.predefinedStatusClearAt(index)
onClicked: userStatusSelectorModel.setPredefinedStatus(index)
emoji: modelData.icon
text: "<b>%1</b> – %2".arg(modelData.message).arg(userStatusSelectorModel.clearAtReadable(modelData))
onClicked: userStatusSelectorModel.setPredefinedStatus(modelData)
}
}

Expand All @@ -279,9 +279,11 @@ ColumnLayout {
id: clearComboBox

Layout.fillWidth: true
model: userStatusSelectorModel.clearAtValues
displayText: userStatusSelectorModel.clearAt
onActivated: userStatusSelectorModel.setClearAt(index)
model: userStatusSelectorModel.clearStageTypes
textRole: "display"
valueRole: "clearStageType"
displayText: userStatusSelectorModel.clearAtDisplayString
onActivated: userStatusSelectorModel.setClearAt(currentValue)
}
}

Expand Down
60 changes: 27 additions & 33 deletions src/gui/userstatusselectormodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
#include "userstatusselectormodel.h"
#include "tray/usermodel.h"

#include <ocsuserstatusconnector.h>
#include <qnamespace.h>
#include <userstatusconnector.h>
#include <theme.h>

#include <QDateTime>
Expand Down Expand Up @@ -250,7 +248,7 @@ void UserStatusSelectorModel::onUserStatusFetched(const UserStatus &userStatus)

emit userStatusChanged();
emit onlineStatusChanged();
emit clearAtChanged();
emit clearAtDisplayStringChanged();
}

Optional<ClearAt> UserStatusSelectorModel::clearStageTypeToDateTime(ClearStageType type) const
Expand Down Expand Up @@ -319,36 +317,27 @@ void UserStatusSelectorModel::clearUserStatus()
_userStatusConnector->clearMessage();
}

void UserStatusSelectorModel::onPredefinedStatusesFetched(const std::vector<UserStatus> &statuses)
void UserStatusSelectorModel::onPredefinedStatusesFetched(const QVector<UserStatus> &statuses)
{
_predefinedStatuses = statuses;
emit predefinedStatusesChanged();
}

UserStatus UserStatusSelectorModel::predefinedStatus(int index) const
QVector<UserStatus> UserStatusSelectorModel::predefinedStatuses() const
{
Q_ASSERT(0 <= index && index < static_cast<int>(_predefinedStatuses.size()));
return _predefinedStatuses[index];
return _predefinedStatuses;
}

int UserStatusSelectorModel::predefinedStatusesCount() const
void UserStatusSelectorModel::setPredefinedStatus(const UserStatus &predefinedStatus)
{
return static_cast<int>(_predefinedStatuses.size());
}

void UserStatusSelectorModel::setPredefinedStatus(int index)
{
Q_ASSERT(0 <= index && index < static_cast<int>(_predefinedStatuses.size()));

_userStatus.setMessagePredefined(true);
const auto predefinedStatus = _predefinedStatuses[index];
_userStatus.setId(predefinedStatus.id());
_userStatus.setMessage(predefinedStatus.message());
_userStatus.setIcon(predefinedStatus.icon());
_userStatus.setClearAt(predefinedStatus.clearAt());

emit userStatusChanged();
emit clearAtChanged();
emit clearAtDisplayStringChanged();
}

QString UserStatusSelectorModel::clearAtStageToString(ClearStageType stage) const
Expand Down Expand Up @@ -377,21 +366,24 @@ QString UserStatusSelectorModel::clearAtStageToString(ClearStageType stage) cons
}
}

QStringList UserStatusSelectorModel::clearAtValues() const
QVariantList UserStatusSelectorModel::clearStageTypes() const
{
QStringList clearAtStages;
std::transform(_clearStages.begin(), _clearStages.end(),
std::back_inserter(clearAtStages),
[this](const ClearStageType &stage) { return clearAtStageToString(stage); });
QVariantList clearStageTypes;

return clearAtStages;
for(const auto clearStageType : _clearStages) {
QVariantMap clearStageToAdd;
clearStageToAdd.insert(QStringLiteral("display"), clearAtStageToString(clearStageType));
clearStageToAdd.insert(QStringLiteral("clearStageType"), QVariant::fromValue(clearStageType));
clearStageTypes.append(clearStageToAdd);
}

return clearStageTypes;
}

void UserStatusSelectorModel::setClearAt(int index)
void UserStatusSelectorModel::setClearAt(const ClearStageType clearStageType)
{
Q_ASSERT(0 <= index && index < static_cast<int>(_clearStages.size()));
_userStatus.setClearAt(clearStageTypeToDateTime(_clearStages[index]));
emit clearAtChanged();
_userStatus.setClearAt(clearStageTypeToDateTime(clearStageType));
emit clearAtDisplayStringChanged();
}

QString UserStatusSelectorModel::errorMessage() const
Expand Down Expand Up @@ -427,6 +419,12 @@ QString UserStatusSelectorModel::timeDifferenceToString(int differenceSecs) cons
}
}

QString UserStatusSelectorModel::clearAtReadable(const UserStatus &status) const
{
const auto clearAt = status.clearAt();
return clearAtReadable(clearAt);
}

QString UserStatusSelectorModel::clearAtReadable(const Optional<ClearAt> &clearAt) const
{
if (clearAt) {
Expand Down Expand Up @@ -456,13 +454,9 @@ QString UserStatusSelectorModel::clearAtReadable(const Optional<ClearAt> &clearA
return tr("Don't clear");
}

QString UserStatusSelectorModel::predefinedStatusClearAt(int index) const
{
return clearAtReadable(predefinedStatus(index).clearAt());
}

QString UserStatusSelectorModel::clearAt() const
QString UserStatusSelectorModel::clearAtDisplayString() const
{
return clearAtReadable(_userStatus.clearAt());
}

}
65 changes: 33 additions & 32 deletions src/gui/userstatusselectormodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "common/result.h"

#include <userstatusconnector.h>
#include <ocsuserstatusconnector.h>
#include <datetimeprovider.h>

#include <QObject>
Expand All @@ -33,19 +34,29 @@ class UserStatusSelectorModel : public QObject
{
Q_OBJECT

Q_PROPERTY(QString userStatusMessage READ userStatusMessage NOTIFY userStatusChanged)
Q_PROPERTY(QString userStatusMessage READ userStatusMessage WRITE setUserStatusMessage NOTIFY userStatusChanged)
Q_PROPERTY(QString userStatusEmoji READ userStatusEmoji WRITE setUserStatusEmoji NOTIFY userStatusChanged)
Q_PROPERTY(OCC::UserStatus::OnlineStatus onlineStatus READ onlineStatus WRITE setOnlineStatus NOTIFY onlineStatusChanged)
Q_PROPERTY(int predefinedStatusesCount READ predefinedStatusesCount NOTIFY predefinedStatusesChanged)
Q_PROPERTY(QStringList clearAtValues READ clearAtValues CONSTANT)
Q_PROPERTY(QString clearAt READ clearAt NOTIFY clearAtChanged)
Q_PROPERTY(QVector<OCC::UserStatus> predefinedStatuses READ predefinedStatuses NOTIFY predefinedStatusesChanged)
Q_PROPERTY(QVariantList clearStageTypes READ clearStageTypes CONSTANT)
Q_PROPERTY(QString clearAtDisplayString READ clearAtDisplayString NOTIFY clearAtDisplayStringChanged)
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged)
Q_PROPERTY(QUrl onlineIcon READ onlineIcon CONSTANT)
Q_PROPERTY(QUrl awayIcon READ awayIcon CONSTANT)
Q_PROPERTY(QUrl dndIcon READ dndIcon CONSTANT)
Q_PROPERTY(QUrl invisibleIcon READ invisibleIcon CONSTANT)

public:
enum class ClearStageType {
DontClear,
HalfHour,
OneHour,
FourHour,
Today,
Week,
};
Q_ENUM(ClearStageType);

explicit UserStatusSelectorModel(QObject *parent = nullptr);

explicit UserStatusSelectorModel(std::shared_ptr<UserStatusConnector> userStatusConnector,
Expand All @@ -62,70 +73,60 @@ class UserStatusSelectorModel : public QObject
explicit UserStatusSelectorModel(const UserStatus &userStatus,
QObject *parent = nullptr);

Q_INVOKABLE void load(int id);

Q_REQUIRED_RESULT UserStatus::OnlineStatus onlineStatus() const;
Q_INVOKABLE void setOnlineStatus(OCC::UserStatus::OnlineStatus status);
void setOnlineStatus(UserStatus::OnlineStatus status);

Q_REQUIRED_RESULT QUrl onlineIcon() const;
Q_REQUIRED_RESULT QUrl awayIcon() const;
Q_REQUIRED_RESULT QUrl dndIcon() const;
Q_REQUIRED_RESULT QUrl invisibleIcon() const;

Q_REQUIRED_RESULT QString userStatusMessage() const;
Q_INVOKABLE void setUserStatusMessage(const QString &message);
void setUserStatusEmoji(const QString &emoji);
void setUserStatusMessage(const QString &message);
Q_REQUIRED_RESULT QString userStatusEmoji() const;
void setUserStatusEmoji(const QString &emoji);

Q_INVOKABLE void setUserStatus();
Q_INVOKABLE void clearUserStatus();

Q_REQUIRED_RESULT int predefinedStatusesCount() const;
Q_INVOKABLE UserStatus predefinedStatus(int index) const;
Q_INVOKABLE QString predefinedStatusClearAt(int index) const;
Q_INVOKABLE void setPredefinedStatus(int index);
QVector<UserStatus> predefinedStatuses() const;

Q_REQUIRED_RESULT QStringList clearAtValues() const;
Q_REQUIRED_RESULT QString clearAt() const;
Q_INVOKABLE void setClearAt(int index);
Q_REQUIRED_RESULT QVariantList clearStageTypes() const;
Q_REQUIRED_RESULT QString clearAtDisplayString() const;
Q_INVOKABLE QString clearAtReadable(const UserStatus &status) const;

Q_REQUIRED_RESULT QString errorMessage() const;

public slots:
void load(int id);
void setUserStatus();
void clearUserStatus();
void setClearAt(const ClearStageType clearStageType);
void setPredefinedStatus(const UserStatus &predefinedStatus);

signals:
void errorMessageChanged();
void userStatusChanged();
void onlineStatusChanged();
void clearAtChanged();
void clearAtDisplayStringChanged();
void predefinedStatusesChanged();
void finished();

private:
enum class ClearStageType {
DontClear,
HalfHour,
OneHour,
FourHour,
Today,
Week
};

void init();
void reset();
void onUserStatusFetched(const UserStatus &userStatus);
void onPredefinedStatusesFetched(const std::vector<UserStatus> &statuses);
void onPredefinedStatusesFetched(const QVector<UserStatus> &statuses);
void onUserStatusSet();
void onMessageCleared();
void onError(UserStatusConnector::Error error);

Q_REQUIRED_RESULT QString clearAtStageToString(ClearStageType stage) const;
Q_REQUIRED_RESULT QString clearAtReadable(const Optional<ClearAt> &clearAt) const;
Q_REQUIRED_RESULT QString clearAtStageToString(ClearStageType stage) const;
Q_REQUIRED_RESULT QString timeDifferenceToString(int differenceSecs) const;
Q_REQUIRED_RESULT Optional<ClearAt> clearStageTypeToDateTime(ClearStageType type) const;
void setError(const QString &reason);
void clearError();

std::shared_ptr<UserStatusConnector> _userStatusConnector {};
std::vector<UserStatus> _predefinedStatuses;
QVector<UserStatus> _predefinedStatuses;
UserStatus _userStatus;
std::unique_ptr<DateTimeProvider> _dateTimeProvider;

Expand Down
6 changes: 3 additions & 3 deletions src/libsync/ocsuserstatusconnector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,15 +191,15 @@ OCC::UserStatus jsonToUserStatus(QJsonObject jsonObject)
return userStatus;
}

std::vector<OCC::UserStatus> jsonToPredefinedStatuses(QJsonArray jsonDataArray)
QVector<OCC::UserStatus> jsonToPredefinedStatuses(QJsonArray jsonDataArray)
{
std::vector<OCC::UserStatus> statuses;
QVector<OCC::UserStatus> statuses;
for (const auto &jsonEntry : jsonDataArray) {
Q_ASSERT(jsonEntry.isObject());
if (!jsonEntry.isObject()) {
continue;
}
statuses.push_back(jsonToUserStatus(jsonEntry.toObject()));
statuses.append(jsonToUserStatus(jsonEntry.toObject()));
}

return statuses;
Expand Down
Loading

0 comments on commit 53aba48

Please sign in to comment.