File indexing completed on 2024-09-29 10:12:40
0001 // SPDX-FileCopyrightText: 2018-2019 Black Hat <bhat@encom.eu.org> 0002 // SPDX-License-Identifier: GPL-3.0-only 0003 0004 #pragma once 0005 0006 #include "models/pushrulemodel.h" 0007 #include <QObject> 0008 #include <QQuickItem> 0009 0010 #include <KFormat> 0011 0012 #include <Quotient/accountregistry.h> 0013 #include <Quotient/jobs/basejob.h> 0014 #include <Quotient/settings.h> 0015 0016 class NeoChatRoom; 0017 class NeoChatUser; 0018 class TrayIcon; 0019 class QWindow; 0020 class QQuickTextDocument; 0021 0022 namespace Quotient 0023 { 0024 class Connection; 0025 class Room; 0026 } 0027 0028 namespace QKeychain 0029 { 0030 class ReadPasswordJob; 0031 } 0032 0033 /** 0034 * @class Controller 0035 * 0036 * A singleton class designed to help manage the application. 0037 * 0038 * There are also a bunch of helper functions that currently don't fit anywhere 0039 * else. 0040 */ 0041 class Controller : public QObject 0042 { 0043 Q_OBJECT 0044 0045 /** 0046 * @brief The number of logged in accounts. 0047 */ 0048 Q_PROPERTY(int accountCount READ accountCount NOTIFY accountCountChanged) 0049 0050 /** 0051 * @brief The current connection for the rest of NeoChat to use. 0052 */ 0053 Q_PROPERTY(Quotient::Connection *activeConnection READ activeConnection WRITE setActiveConnection NOTIFY activeConnectionChanged) 0054 0055 /** 0056 * @brief The PushRuleModel that has the active connection's push rules. 0057 */ 0058 Q_PROPERTY(PushRuleModel *pushRuleModel READ pushRuleModel CONSTANT) 0059 0060 /** 0061 * @brief The row number in the accounts directory of the active connection. 0062 */ 0063 Q_PROPERTY(int activeConnectionIndex READ activeConnectionIndex NOTIFY activeConnectionIndexChanged) 0064 0065 /** 0066 * @brief The account label for the active account. 0067 * 0068 * Account labels are a concept specific to NeoChat, allowing accounts to be 0069 * labelled, e.g. for "Work", "Private", etc. 0070 * 0071 * Set to an empty string to remove the label. 0072 */ 0073 Q_PROPERTY(QString activeAccountLabel READ activeAccountLabel WRITE setActiveAccountLabel NOTIFY activeAccountLabelChanged) 0074 0075 /** 0076 * @brief Whether the OS NeoChat is running on supports sytem tray icons. 0077 */ 0078 Q_PROPERTY(bool supportSystemTray READ supportSystemTray CONSTANT) 0079 0080 /** 0081 * @brief Whether KWindowSystem specific features are available. 0082 */ 0083 Q_PROPERTY(bool hasWindowSystem READ hasWindowSystem CONSTANT) 0084 0085 /** 0086 * @brief Whether NeoChat is currently able to connect to the server. 0087 */ 0088 Q_PROPERTY(bool isOnline READ isOnline NOTIFY isOnlineChanged) 0089 0090 /** 0091 * @brief Whether the ecryption support has been enabled. 0092 */ 0093 Q_PROPERTY(bool encryptionSupported READ encryptionSupported CONSTANT) 0094 0095 /** 0096 * @brief The current minor version number of libQuotient being used. 0097 * 0098 * This is the only way to gate NeoChat features by libQuotient version in QML. 0099 * 0100 * @note No major version because libQuotient doesn't have any; All are 0.x. 0101 */ 0102 Q_PROPERTY(int quotientMinorVersion READ quotientMinorVersion CONSTANT) 0103 0104 /** 0105 * @brief Whether NeoChat is running as a flatpak. 0106 * 0107 * This is the only way to gate NeoChat features in flatpaks in QML. 0108 */ 0109 Q_PROPERTY(bool isFlatpak READ isFlatpak CONSTANT) 0110 0111 public: 0112 /** 0113 * @brief Defines the status after an attempt to change the password on an account. 0114 */ 0115 enum PasswordStatus { 0116 Success, /**< The password was successfully changed. */ 0117 Wrong, /**< The current password entered was wrong. */ 0118 Other, /**< An unknown problem occurred. */ 0119 }; 0120 Q_ENUM(PasswordStatus) 0121 0122 static Controller &instance(); 0123 0124 [[nodiscard]] int accountCount() const; 0125 0126 void setActiveConnection(Quotient::Connection *connection); 0127 [[nodiscard]] Quotient::Connection *activeConnection() const; 0128 0129 [[nodiscard]] PushRuleModel *pushRuleModel() const; 0130 0131 /** 0132 * @brief Add a new connection to the account registry. 0133 */ 0134 void addConnection(Quotient::Connection *c); 0135 0136 /** 0137 * @brief Drop a connection from the account registry. 0138 */ 0139 void dropConnection(Quotient::Connection *c); 0140 0141 int activeConnectionIndex() const; 0142 0143 [[nodiscard]] QString activeAccountLabel() const; 0144 void setActiveAccountLabel(const QString &label); 0145 0146 /** 0147 * @brief Save an access token to the keychain for the given account. 0148 */ 0149 bool saveAccessTokenToKeyChain(const Quotient::AccountSettings &account, const QByteArray &accessToken); 0150 0151 /** 0152 * @brief Change the password for an account. 0153 * 0154 * The function emits a passwordStatus signal with a PasswordStatus value when 0155 * complete. 0156 * 0157 * @sa PasswordStatus, passwordStatus 0158 */ 0159 Q_INVOKABLE void changePassword(Quotient::Connection *connection, const QString ¤tPassword, const QString &newPassword); 0160 0161 /** 0162 * @brief Change the avatar for an account. 0163 */ 0164 Q_INVOKABLE bool setAvatar(Quotient::Connection *connection, const QUrl &avatarSource); 0165 0166 /** 0167 * @brief Create new room for a group chat. 0168 */ 0169 Q_INVOKABLE void createRoom(const QString &name, const QString &topic); 0170 0171 /** 0172 * @brief Create new space. 0173 */ 0174 Q_INVOKABLE void createSpace(const QString &name, const QString &topic); 0175 0176 /** 0177 * @brief Join a room. 0178 */ 0179 Q_INVOKABLE void joinRoom(const QString &alias); 0180 0181 /** 0182 * @brief Join a direct chat with the given user. 0183 * 0184 * If a direct chat with the user doesn't exist one is created and then joined. 0185 */ 0186 Q_INVOKABLE void openOrCreateDirectChat(NeoChatUser *user); 0187 0188 [[nodiscard]] bool supportSystemTray() const; 0189 0190 /** 0191 * @brief Set the background blur status of the given item. 0192 */ 0193 Q_INVOKABLE void setBlur(QQuickItem *item, bool blur); 0194 0195 bool isOnline() const; 0196 0197 bool encryptionSupported() const; 0198 0199 /** 0200 * @brief Sets the QNetworkProxy for the application. 0201 * 0202 * @sa QNetworkProxy::setApplicationProxy 0203 */ 0204 Q_INVOKABLE void setApplicationProxy(); 0205 0206 int quotientMinorVersion() const; 0207 0208 bool isFlatpak() const; 0209 0210 /** 0211 * @brief Return a string for the input timestamp. 0212 * 0213 * The output format depends on the KFormat::DurationFormatOptions chosen. 0214 * 0215 * @sa KFormat::DurationFormatOptions 0216 */ 0217 Q_INVOKABLE QString formatDuration(quint64 msecs, KFormat::DurationFormatOptions options = KFormat::DefaultDuration) const; 0218 0219 /** 0220 * @brief Return a human readable string for a given input number of bytes. 0221 */ 0222 Q_INVOKABLE QString formatByteSize(double size, int precision = 1) const; 0223 0224 /** 0225 * @brief Force a QQuickTextDocument to refresh when images are loaded. 0226 * 0227 * HACK: This is a workaround for QTBUG 93281. 0228 */ 0229 Q_INVOKABLE void forceRefreshTextDocument(QQuickTextDocument *textDocument, QQuickItem *item); 0230 0231 Q_INVOKABLE QVariantList getSupportedRoomVersions(Quotient::Connection *connection); 0232 0233 Quotient::AccountRegistry &accounts(); 0234 0235 private: 0236 explicit Controller(QObject *parent = nullptr); 0237 0238 QPointer<Quotient::Connection> m_connection; 0239 TrayIcon *m_trayIcon = nullptr; 0240 0241 QKeychain::ReadPasswordJob *loadAccessTokenFromKeyChain(const Quotient::AccountSettings &account); 0242 0243 void loadSettings(); 0244 void saveSettings() const; 0245 bool m_isOnline = true; 0246 QMap<Quotient::Room *, int> m_notificationCounts; 0247 0248 bool hasWindowSystem() const; 0249 0250 QPointer<PushRuleModel> m_pushRuleModel; 0251 Quotient::AccountRegistry m_accountRegistry; 0252 0253 private Q_SLOTS: 0254 void invokeLogin(); 0255 void showWindow(); 0256 void setQuitOnLastWindowClosed(); 0257 0258 Q_SIGNALS: 0259 /// Error occurred because of user inputs 0260 void errorOccured(const QString &error); 0261 0262 /// Error occurred because of server or bug in NeoChat 0263 void globalErrorOccured(QString error, QString detail); 0264 void syncDone(); 0265 void connectionAdded(Quotient::Connection *_t1); 0266 void connectionDropped(Quotient::Connection *_t1); 0267 void accountCountChanged(); 0268 void initiated(); 0269 void notificationClicked(const QString &_t1, const QString &_t2); 0270 void quitOnLastWindowClosedChanged(); 0271 void unreadCountChanged(); 0272 void activeConnectionChanged(); 0273 void passwordStatus(Controller::PasswordStatus _t1); 0274 void userConsentRequired(QUrl url); 0275 void testConnectionResult(const QString &connection, bool usable); 0276 void isOnlineChanged(bool isOnline); 0277 void keyVerificationRequest(int timeLeft, Quotient::Connection *connection, const QString &transactionId, const QString &deviceId); 0278 void keyVerificationStart(); 0279 void keyVerificationAccept(const QString &commitment); 0280 void keyVerificationKey(const QString &sas); 0281 void activeConnectionIndexChanged(); 0282 void roomAdded(NeoChatRoom *room); 0283 void activeAccountLabelChanged(); 0284 0285 public Q_SLOTS: 0286 void logout(Quotient::Connection *conn, bool serverSideLogout); 0287 void changeAvatar(Quotient::Connection *conn, const QUrl &localFile); 0288 static void markAllMessagesAsRead(Quotient::Connection *conn); 0289 void saveWindowGeometry(); 0290 }; 0291 0292 // TODO libQuotient 0.7: Drop 0293 class NeochatChangePasswordJob : public Quotient::BaseJob 0294 { 0295 public: 0296 explicit NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const Quotient::Omittable<QJsonObject> &auth = Quotient::none); 0297 }; 0298 0299 class NeochatDeleteDeviceJob : public Quotient::BaseJob 0300 { 0301 public: 0302 explicit NeochatDeleteDeviceJob(const QString &deviceId, const Quotient::Omittable<QJsonObject> &auth = Quotient::none); 0303 };