Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/desktop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Weilbach <felix.weilbach@nextcloud.com>2021-09-09 12:18:22 +0300
committerFelix Weilbach <felix.weilbach@nextcloud.com>2021-09-09 12:18:22 +0300
commit8a8d488454405356b5d11f63bebff2d69be43b02 (patch)
treeafa6c5a496561e6778227ece22a6c871622af926 /src/gui/userstatusselectormodel.cpp
parentf34d66302942ede371bf7bc5d5e213b6c41ea5d8 (diff)
Add dialog to set user status
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
Diffstat (limited to 'src/gui/userstatusselectormodel.cpp')
-rw-r--r--src/gui/userstatusselectormodel.cpp474
1 files changed, 474 insertions, 0 deletions
diff --git a/src/gui/userstatusselectormodel.cpp b/src/gui/userstatusselectormodel.cpp
new file mode 100644
index 000000000..c241474e0
--- /dev/null
+++ b/src/gui/userstatusselectormodel.cpp
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "userstatusselectormodel.h"
+#include "tray/UserModel.h"
+
+#include <ocsuserstatusconnector.h>
+#include <qnamespace.h>
+#include <userstatusconnector.h>
+#include <theme.h>
+
+#include <QDateTime>
+#include <QLoggingCategory>
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+
+namespace OCC {
+
+Q_LOGGING_CATEGORY(lcUserStatusDialogModel, "nextcloud.gui.userstatusdialogmodel", QtInfoMsg)
+
+UserStatusSelectorModel::UserStatusSelectorModel(QObject *parent)
+ : QObject(parent)
+ , _dateTimeProvider(new DateTimeProvider)
+{
+ _userStatus.setIcon("😀");
+}
+
+UserStatusSelectorModel::UserStatusSelectorModel(std::shared_ptr<UserStatusConnector> userStatusConnector, QObject *parent)
+ : QObject(parent)
+ , _userStatusConnector(userStatusConnector)
+ , _userStatus("no-id", "", "😀", UserStatus::OnlineStatus::Online, false, {})
+ , _dateTimeProvider(new DateTimeProvider)
+{
+ _userStatus.setIcon("😀");
+ init();
+}
+
+UserStatusSelectorModel::UserStatusSelectorModel(std::shared_ptr<UserStatusConnector> userStatusConnector,
+ std::unique_ptr<DateTimeProvider> dateTimeProvider,
+ QObject *parent)
+ : QObject(parent)
+ , _userStatusConnector(userStatusConnector)
+ , _dateTimeProvider(std::move(dateTimeProvider))
+{
+ _userStatus.setIcon("😀");
+ init();
+}
+
+UserStatusSelectorModel::UserStatusSelectorModel(const UserStatus &userStatus,
+ std::unique_ptr<DateTimeProvider> dateTimeProvider, QObject *parent)
+ : QObject(parent)
+ , _userStatus(userStatus)
+ , _dateTimeProvider(std::move(dateTimeProvider))
+{
+ _userStatus.setIcon("😀");
+}
+
+UserStatusSelectorModel::UserStatusSelectorModel(const UserStatus &userStatus,
+ QObject *parent)
+ : QObject(parent)
+ , _userStatus(userStatus)
+{
+ _userStatus.setIcon("😀");
+}
+
+void UserStatusSelectorModel::load(int id)
+{
+ reset();
+ _userStatusConnector = UserModel::instance()->userStatusConnector(id);
+ init();
+}
+
+void UserStatusSelectorModel::reset()
+{
+ if (_userStatusConnector) {
+ disconnect(_userStatusConnector.get(), &UserStatusConnector::userStatusFetched, this,
+ &UserStatusSelectorModel::onUserStatusFetched);
+ disconnect(_userStatusConnector.get(), &UserStatusConnector::predefinedStatusesFetched, this,
+ &UserStatusSelectorModel::onPredefinedStatusesFetched);
+ disconnect(_userStatusConnector.get(), &UserStatusConnector::error, this,
+ &UserStatusSelectorModel::onError);
+ disconnect(_userStatusConnector.get(), &UserStatusConnector::userStatusSet, this,
+ &UserStatusSelectorModel::onUserStatusSet);
+ disconnect(_userStatusConnector.get(), &UserStatusConnector::messageCleared, this,
+ &UserStatusSelectorModel::onMessageCleared);
+ }
+ _userStatusConnector = nullptr;
+}
+
+void UserStatusSelectorModel::init()
+{
+ if (!_userStatusConnector) {
+ return;
+ }
+
+ connect(_userStatusConnector.get(), &UserStatusConnector::userStatusFetched, this,
+ &UserStatusSelectorModel::onUserStatusFetched);
+ connect(_userStatusConnector.get(), &UserStatusConnector::predefinedStatusesFetched, this,
+ &UserStatusSelectorModel::onPredefinedStatusesFetched);
+ connect(_userStatusConnector.get(), &UserStatusConnector::error, this,
+ &UserStatusSelectorModel::onError);
+ connect(_userStatusConnector.get(), &UserStatusConnector::userStatusSet, this,
+ &UserStatusSelectorModel::onUserStatusSet);
+ connect(_userStatusConnector.get(), &UserStatusConnector::messageCleared, this,
+ &UserStatusSelectorModel::onMessageCleared);
+
+ _userStatusConnector->fetchUserStatus();
+ _userStatusConnector->fetchPredefinedStatuses();
+}
+
+UserStatusSelectorModel::~UserStatusSelectorModel()
+{
+ qCDebug(lcUserStatusDialogModel) << "Destroyed";
+}
+
+void UserStatusSelectorModel::onUserStatusSet()
+{
+ qCDebug(lcUserStatusDialogModel) << "Emit finished";
+ emit finished();
+}
+
+void UserStatusSelectorModel::onMessageCleared()
+{
+ emit finished();
+}
+
+void UserStatusSelectorModel::onError(UserStatusConnector::Error error)
+{
+ qCWarning(lcUserStatusDialogModel) << "Error:" << error;
+
+ switch (error) {
+ case UserStatusConnector::Error::CouldNotFetchPredefinedUserStatuses:
+ setError(tr("Could not fetch predefined statuses. Make sure you are connected to the server."));
+ return;
+
+ case UserStatusConnector::Error::CouldNotFetchUserStatus:
+ setError(tr("Could not fetch user status. Make sure you are connected to the server."));
+ return;
+
+ case UserStatusConnector::Error::UserStatusNotSupported:
+ setError(tr("User status feature is not supported. You will not be able to set your user status."));
+ return;
+
+ case UserStatusConnector::Error::EmojisNotSupported:
+ setError(tr("Emojis feature is not supported. Some user status functionality may not work."));
+ return;
+
+ case UserStatusConnector::Error::CouldNotSetUserStatus:
+ setError(tr("Could not set user status. Make sure you are connected to the server."));
+ return;
+
+ case UserStatusConnector::Error::CouldNotClearMessage:
+ setError(tr("Could not clear user status message. Make sure you are connected to the server."));
+ return;
+ }
+
+ Q_UNREACHABLE();
+}
+
+void UserStatusSelectorModel::setError(const QString &reason)
+{
+ _errorMessage = reason;
+ emit errorMessageChanged();
+}
+
+void UserStatusSelectorModel::clearError()
+{
+ setError("");
+}
+
+void UserStatusSelectorModel::setOnlineStatus(UserStatus::OnlineStatus status)
+{
+ if (status == _userStatus.state()) {
+ return;
+ }
+
+ _userStatus.setState(status);
+ emit onlineStatusChanged();
+}
+
+QUrl UserStatusSelectorModel::onlineIcon() const
+{
+ return Theme::instance()->statusOnlineImageSource();
+}
+
+QUrl UserStatusSelectorModel::awayIcon() const
+{
+ return Theme::instance()->statusAwayImageSource();
+}
+QUrl UserStatusSelectorModel::dndIcon() const
+{
+ return Theme::instance()->statusDoNotDisturbImageSource();
+}
+QUrl UserStatusSelectorModel::invisibleIcon() const
+{
+ return Theme::instance()->statusInvisibleImageSource();
+}
+
+UserStatus::OnlineStatus UserStatusSelectorModel::onlineStatus() const
+{
+ return _userStatus.state();
+}
+
+QString UserStatusSelectorModel::userStatusMessage() const
+{
+ return _userStatus.message();
+}
+
+void UserStatusSelectorModel::setUserStatusMessage(const QString &message)
+{
+ _userStatus.setMessage(message);
+ _userStatus.setMessagePredefined(false);
+ emit userStatusChanged();
+}
+
+void UserStatusSelectorModel::setUserStatusEmoji(const QString &emoji)
+{
+ _userStatus.setIcon(emoji);
+ _userStatus.setMessagePredefined(false);
+ emit userStatusChanged();
+}
+
+QString UserStatusSelectorModel::userStatusEmoji() const
+{
+ return _userStatus.icon();
+}
+
+void UserStatusSelectorModel::onUserStatusFetched(const UserStatus &userStatus)
+{
+ if (userStatus.state() != UserStatus::OnlineStatus::Offline) {
+ _userStatus.setState(userStatus.state());
+ }
+ _userStatus.setMessage(userStatus.message());
+ _userStatus.setMessagePredefined(userStatus.messagePredefined());
+ _userStatus.setId(userStatus.id());
+ _userStatus.setClearAt(userStatus.clearAt());
+
+ if (!userStatus.icon().isEmpty()) {
+ _userStatus.setIcon(userStatus.icon());
+ }
+
+ emit userStatusChanged();
+ emit onlineStatusChanged();
+ emit clearAtChanged();
+}
+
+Optional<ClearAt> UserStatusSelectorModel::clearStageTypeToDateTime(ClearStageType type) const
+{
+ switch (type) {
+ case ClearStageType::DontClear:
+ return {};
+
+ case ClearStageType::HalfHour: {
+ ClearAt clearAt;
+ clearAt._type = ClearAtType::Period;
+ clearAt._period = 60 * 30;
+ return clearAt;
+ }
+
+ case ClearStageType::OneHour: {
+ ClearAt clearAt;
+ clearAt._type = ClearAtType::Period;
+ clearAt._period = 60 * 60;
+ return clearAt;
+ }
+
+ case ClearStageType::FourHour: {
+ ClearAt clearAt;
+ clearAt._type = ClearAtType::Period;
+ clearAt._period = 60 * 60 * 4;
+ return clearAt;
+ }
+
+ case ClearStageType::Today: {
+ ClearAt clearAt;
+ clearAt._type = ClearAtType::EndOf;
+ clearAt._endof = "day";
+ return clearAt;
+ }
+
+ case ClearStageType::Week: {
+ ClearAt clearAt;
+ clearAt._type = ClearAtType::EndOf;
+ clearAt._endof = "week";
+ return clearAt;
+ }
+
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
+void UserStatusSelectorModel::setUserStatus()
+{
+ Q_ASSERT(_userStatusConnector);
+ if (!_userStatusConnector) {
+ return;
+ }
+
+ clearError();
+ _userStatusConnector->setUserStatus(_userStatus);
+}
+
+void UserStatusSelectorModel::clearUserStatus()
+{
+ Q_ASSERT(_userStatusConnector);
+ if (!_userStatusConnector) {
+ return;
+ }
+
+ clearError();
+ _userStatusConnector->clearMessage();
+}
+
+void UserStatusSelectorModel::onPredefinedStatusesFetched(const std::vector<UserStatus> &statuses)
+{
+ _predefinedStatuses = statuses;
+ emit predefinedStatusesChanged();
+}
+
+UserStatus UserStatusSelectorModel::predefinedStatus(int index) const
+{
+ Q_ASSERT(0 <= index && index < static_cast<int>(_predefinedStatuses.size()));
+ return _predefinedStatuses[index];
+}
+
+int UserStatusSelectorModel::predefinedStatusesCount() const
+{
+ 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();
+}
+
+QString UserStatusSelectorModel::clearAtStageToString(ClearStageType stage) const
+{
+ switch (stage) {
+ case ClearStageType::DontClear:
+ return tr("Don't clear");
+
+ case ClearStageType::HalfHour:
+ return tr("30 minutes");
+
+ case ClearStageType::OneHour:
+ return tr("1 hour");
+
+ case ClearStageType::FourHour:
+ return tr("4 hours");
+
+ case ClearStageType::Today:
+ return tr("Today");
+
+ case ClearStageType::Week:
+ return tr("This week");
+
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
+QStringList UserStatusSelectorModel::clearAtValues() const
+{
+ QStringList clearAtStages;
+ std::transform(_clearStages.begin(), _clearStages.end(),
+ std::back_inserter(clearAtStages),
+ [this](const ClearStageType &stage) { return clearAtStageToString(stage); });
+
+ return clearAtStages;
+}
+
+void UserStatusSelectorModel::setClearAt(int index)
+{
+ Q_ASSERT(0 <= index && index < static_cast<int>(_clearStages.size()));
+ _userStatus.setClearAt(clearStageTypeToDateTime(_clearStages[index]));
+ emit clearAtChanged();
+}
+
+QString UserStatusSelectorModel::errorMessage() const
+{
+ return _errorMessage;
+}
+
+QString UserStatusSelectorModel::timeDifferenceToString(int differenceSecs) const
+{
+ if (differenceSecs < 60) {
+ return tr("Less than a minute");
+ } else if (differenceSecs < 60 * 60) {
+ const auto minutesLeft = std::ceil(differenceSecs / 60.0);
+ if (minutesLeft == 1) {
+ return tr("1 minute");
+ } else {
+ return tr("%1 minutes").arg(minutesLeft);
+ }
+ } else if (differenceSecs < 60 * 60 * 24) {
+ const auto hoursLeft = std::ceil(differenceSecs / 60.0 / 60.0);
+ if (hoursLeft == 1) {
+ return tr("1 hour");
+ } else {
+ return tr("%1 hours").arg(hoursLeft);
+ }
+ } else {
+ const auto daysLeft = std::ceil(differenceSecs / 60.0 / 60.0 / 24.0);
+ if (daysLeft == 1) {
+ return tr("1 day");
+ } else {
+ return tr("%1 days").arg(daysLeft);
+ }
+ }
+}
+
+QString UserStatusSelectorModel::clearAtReadable(const Optional<ClearAt> &clearAt) const
+{
+ if (clearAt) {
+ switch (clearAt->_type) {
+ case ClearAtType::Period: {
+ return timeDifferenceToString(clearAt->_period);
+ }
+
+ case ClearAtType::Timestamp: {
+ const int difference = static_cast<int>(clearAt->_timestamp - _dateTimeProvider->currentDateTime().toTime_t());
+ return timeDifferenceToString(difference);
+ }
+
+ case ClearAtType::EndOf: {
+ if (clearAt->_endof == "day") {
+ return tr("Today");
+ } else if (clearAt->_endof == "week") {
+ return tr("This week");
+ }
+ Q_UNREACHABLE();
+ }
+
+ default:
+ Q_UNREACHABLE();
+ }
+ }
+ return tr("Don't clear");
+}
+
+QString UserStatusSelectorModel::predefinedStatusClearAt(int index) const
+{
+ return clearAtReadable(predefinedStatus(index).clearAt());
+}
+
+QString UserStatusSelectorModel::clearAt() const
+{
+ return clearAtReadable(_userStatus.clearAt());
+}
+}