Files
neochat/src/controller.h
Tobias Leupold c1604a9c4f Trayicon tweaks
This fixes two minor inconveniences:

- When closing the chat window and re-showing it from the systray icon, the geometry was not properly restored. The window was always shown in the middle of the screen. Now, one gets the window back with it's actual last position and size.
- It is now possible to not only show the window from the systray icon, but also to close it. This is the way other chat programs do it (Kopete back in the day, Konversation, Quassel IRC etc.)
2023-08-22 20:58:04 +00:00

286 lines
8.5 KiB
C++

// SPDX-FileCopyrightText: 2018-2019 Black Hat <bhat@encom.eu.org>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include "models/pushrulemodel.h"
#include <QObject>
#include <QQuickItem>
#include <KFormat>
#include <Quotient/accountregistry.h>
#include <Quotient/jobs/basejob.h>
#include <Quotient/settings.h>
class NeoChatRoom;
class TrayIcon;
class QWindow;
class QQuickTextDocument;
namespace Quotient
{
class Connection;
class Room;
class User;
}
namespace QKeychain
{
class ReadPasswordJob;
}
/**
* @class Controller
*
* A singleton class designed to help manage the application.
*
* There are also a bunch of helper functions that currently don't fit anywhere
* else.
*/
class Controller : public QObject
{
Q_OBJECT
/**
* @brief The number of logged in accounts.
*/
Q_PROPERTY(int accountCount READ accountCount NOTIFY accountCountChanged)
/**
* @brief The current connection for the rest of NeoChat to use.
*/
Q_PROPERTY(Quotient::Connection *activeConnection READ activeConnection WRITE setActiveConnection NOTIFY activeConnectionChanged)
/**
* @brief The PushRuleModel that has the active connection's push rules.
*/
Q_PROPERTY(PushRuleModel *pushRuleModel READ pushRuleModel CONSTANT)
/**
* @brief The row number in the accounts directory of the active connection.
*/
Q_PROPERTY(int activeConnectionIndex READ activeConnectionIndex NOTIFY activeConnectionIndexChanged)
/**
* @brief The account label for the active account.
*
* Account labels are a concept specific to NeoChat, allowing accounts to be
* labelled, e.g. for "Work", "Private", etc.
*
* Set to an empty string to remove the label.
*/
Q_PROPERTY(QString activeAccountLabel READ activeAccountLabel WRITE setActiveAccountLabel NOTIFY activeAccountLabelChanged)
/**
* @brief Whether the OS NeoChat is running on supports sytem tray icons.
*/
Q_PROPERTY(bool supportSystemTray READ supportSystemTray CONSTANT)
/**
* @brief Whether KWindowSystem specific features are available.
*/
Q_PROPERTY(bool hasWindowSystem READ hasWindowSystem CONSTANT)
/**
* @brief Whether NeoChat is currently able to connect to the server.
*/
Q_PROPERTY(bool isOnline READ isOnline NOTIFY isOnlineChanged)
/**
* @brief Whether NeoChat is running as a flatpak.
*
* This is the only way to gate NeoChat features in flatpaks in QML.
*/
Q_PROPERTY(bool isFlatpak READ isFlatpak CONSTANT)
public:
/**
* @brief Defines the status after an attempt to change the password on an account.
*/
enum PasswordStatus {
Success, /**< The password was successfully changed. */
Wrong, /**< The current password entered was wrong. */
Other, /**< An unknown problem occurred. */
};
Q_ENUM(PasswordStatus)
static Controller &instance();
[[nodiscard]] int accountCount() const;
void setActiveConnection(Quotient::Connection *connection);
[[nodiscard]] Quotient::Connection *activeConnection() const;
[[nodiscard]] PushRuleModel *pushRuleModel() const;
/**
* @brief Add a new connection to the account registry.
*/
void addConnection(Quotient::Connection *c);
/**
* @brief Drop a connection from the account registry.
*/
void dropConnection(Quotient::Connection *c);
int activeConnectionIndex() const;
[[nodiscard]] QString activeAccountLabel() const;
void setActiveAccountLabel(const QString &label);
/**
* @brief Save an access token to the keychain for the given account.
*/
bool saveAccessTokenToKeyChain(const Quotient::AccountSettings &account, const QByteArray &accessToken);
/**
* @brief Change the password for an account.
*
* The function emits a passwordStatus signal with a PasswordStatus value when
* complete.
*
* @sa PasswordStatus, passwordStatus
*/
Q_INVOKABLE void changePassword(Quotient::Connection *connection, const QString &currentPassword, const QString &newPassword);
/**
* @brief Change the avatar for an account.
*/
Q_INVOKABLE bool setAvatar(Quotient::Connection *connection, const QUrl &avatarSource);
/**
* @brief Create new room for a group chat.
*/
Q_INVOKABLE void createRoom(const QString &name, const QString &topic);
/**
* @brief Create new space.
*/
Q_INVOKABLE void createSpace(const QString &name, const QString &topic);
/**
* @brief Join a room.
*/
Q_INVOKABLE void joinRoom(const QString &alias);
/**
* @brief Join a direct chat with the given user.
*
* If a direct chat with the user doesn't exist one is created and then joined.
*/
Q_INVOKABLE void openOrCreateDirectChat(Quotient::User *user);
[[nodiscard]] bool supportSystemTray() const;
/**
* @brief Set the background blur status of the given item.
*/
Q_INVOKABLE void setBlur(QQuickItem *item, bool blur);
bool isOnline() const;
/**
* @brief Sets the QNetworkProxy for the application.
*
* @sa QNetworkProxy::setApplicationProxy
*/
Q_INVOKABLE void setApplicationProxy();
bool isFlatpak() const;
/**
* @brief Return a string for the input timestamp.
*
* The output format depends on the KFormat::DurationFormatOptions chosen.
*
* @sa KFormat::DurationFormatOptions
*/
Q_INVOKABLE QString formatDuration(quint64 msecs, KFormat::DurationFormatOptions options = KFormat::DefaultDuration) const;
/**
* @brief Return a human readable string for a given input number of bytes.
*/
Q_INVOKABLE QString formatByteSize(double size, int precision = 1) const;
/**
* @brief Force a QQuickTextDocument to refresh when images are loaded.
*
* HACK: This is a workaround for QTBUG 93281.
*/
Q_INVOKABLE void forceRefreshTextDocument(QQuickTextDocument *textDocument, QQuickItem *item);
Q_INVOKABLE QVariantList getSupportedRoomVersions(Quotient::Connection *connection);
Quotient::AccountRegistry &accounts();
private:
explicit Controller(QObject *parent = nullptr);
QPointer<Quotient::Connection> m_connection;
TrayIcon *m_trayIcon = nullptr;
QKeychain::ReadPasswordJob *loadAccessTokenFromKeyChain(const Quotient::AccountSettings &account);
void loadSettings();
void saveSettings() const;
bool m_isOnline = true;
QMap<Quotient::Room *, int> m_notificationCounts;
bool hasWindowSystem() const;
QPointer<PushRuleModel> m_pushRuleModel;
Quotient::AccountRegistry m_accountRegistry;
private Q_SLOTS:
void invokeLogin();
void toggleWindow();
void setQuitOnLastWindowClosed();
Q_SIGNALS:
/// Error occurred because of user inputs
void errorOccured(const QString &error);
/// Error occurred because of server or bug in NeoChat
void globalErrorOccured(QString error, QString detail);
void syncDone();
void connectionAdded(Quotient::Connection *_t1);
void connectionDropped(Quotient::Connection *_t1);
void accountCountChanged();
void initiated();
void notificationClicked(const QString &_t1, const QString &_t2);
void quitOnLastWindowClosedChanged();
void unreadCountChanged();
void activeConnectionChanged();
void passwordStatus(Controller::PasswordStatus _t1);
void userConsentRequired(QUrl url);
void testConnectionResult(const QString &connection, bool usable);
void isOnlineChanged(bool isOnline);
void keyVerificationRequest(int timeLeft, Quotient::Connection *connection, const QString &transactionId, const QString &deviceId);
void keyVerificationStart();
void keyVerificationAccept(const QString &commitment);
void keyVerificationKey(const QString &sas);
void activeConnectionIndexChanged();
void roomAdded(NeoChatRoom *room);
void activeAccountLabelChanged();
public Q_SLOTS:
void logout(Quotient::Connection *conn, bool serverSideLogout);
void changeAvatar(Quotient::Connection *conn, const QUrl &localFile);
static void markAllMessagesAsRead(Quotient::Connection *conn);
void saveWindowGeometry();
};
// TODO libQuotient 0.7: Drop
class NeochatChangePasswordJob : public Quotient::BaseJob
{
public:
explicit NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const Quotient::Omittable<QJsonObject> &auth = Quotient::none);
};
class NeochatDeleteDeviceJob : public Quotient::BaseJob
{
public:
explicit NeochatDeleteDeviceJob(const QString &deviceId, const Quotient::Omittable<QJsonObject> &auth = Quotient::none);
};