1
0
Fork 0
mirror of https://git.jami.net/savoirfairelinux/jami-client-qt.git synced 2025-03-28 14:56:19 +01:00

injection: remove the remaining c++ singleton classes

- refactor qml object registration
- inject AppSettingsManager and SystemTray

Gitlab: #320
Change-Id: Ic8232a290003245d09ad9452c9f5518fd260af78
This commit is contained in:
Andreas Traczyk 2021-03-30 15:15:36 -04:00
parent 552c445c8d
commit 4ce208ec33
27 changed files with 362 additions and 249 deletions

View file

@ -69,7 +69,9 @@ set(COMMON_SOURCES
${SRC_DIR}/dbuserrorhandler.cpp
${SRC_DIR}/xrectsel.c
${SRC_DIR}/moderatorlistmodel.cpp
${SRC_DIR}/screensaver.cpp)
${SRC_DIR}/screensaver.cpp
${SRC_DIR}/systemtray.cpp
${SRC_DIR}/appsettingsmanager.cpp)
set(COMMON_HEADERS
${SRC_DIR}/avatarimageprovider.h
@ -82,8 +84,6 @@ set(COMMON_HEADERS
${SRC_DIR}/accountlistmodel.h
${SRC_DIR}/runguard.h
${SRC_DIR}/lrcinstance.h
${SRC_DIR}/globalsystemtray.h
${SRC_DIR}/appsettingsmanager.h
${SRC_DIR}/webchathelpers.h
${SRC_DIR}/rendermanager.h
${SRC_DIR}/connectivitymonitor.h
@ -122,7 +122,9 @@ set(COMMON_HEADERS
${SRC_DIR}/dbuserrorhandler.h
${SRC_DIR}/xrectsel.h
${SRC_DIR}/moderatorlistmodel.h
${SRC_DIR}/screensaver.h)
${SRC_DIR}/screensaver.h
${SRC_DIR}/systemtray.h
${SRC_DIR}/appsettingsmanager.h)
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBNM libnm)

View file

@ -92,7 +92,7 @@ Variables `QT5_VER` and `QT5_PATH` are used to specify version and path for a cu
If lrc library is installed in a custom directory you can set its path with the variable LRC. Additionally you can specify built library location with `LRCLIB` (otherwise it will seach inside LRC with the suffixes `/lib`, `/build` and `/build-local`).
After the build has finished, you are finally ready to launch jami-qt in your build directory.
After the build has finished, you are finally ready to launch jami-qt in your build directory.
If you want to install it to the path provided by `CMAKE_INSTALL_PREFIX` you can run:
@ -162,7 +162,7 @@ Only 64-bit MSVC build can be compiled.
> By default: ```toolset=v141```, ```sdk=10.0.16299.0```, ```qtver=5.9.4``` <br>
> For example:
```sh
python make-ring.py --install --toolset v142 --sdk 10.0.18362.0 --qtver 5.12.0
python make-ring.py --install --toolset v142 --sdk 10.0.18362.0 --qtver 5.14.0
```
### Build Module individually

View file

@ -176,8 +176,6 @@ HEADERS += \
src/accountlistmodel.h \
src/runguard.h \
src/lrcinstance.h \
src/globalsystemtray.h \
src/appsettingsmanager.h \
src/webchathelpers.h \
src/rendermanager.h \
src/connectivitymonitor.h \
@ -210,7 +208,9 @@ HEADERS += \
src/audiomanagerlistmodel.h \
src/qmlregister.h \
src/qtutils.h \
src/utilsadapter.h
src/utilsadapter.h \
src/systemtray.h \
src/appsettingsmanager.h
SOURCES += \
src/bannedlistmodel.cpp \
@ -250,7 +250,9 @@ SOURCES += \
src/videoformatresolutionmodel.cpp \
src/audiomanagerlistmodel.cpp \
src/qmlregister.cpp \
src/utilsadapter.cpp
src/utilsadapter.cpp \
src/systemtray.cpp \
src/appsettingsmanager.cpp
RESOURCES += \
resources.qrc \

View file

@ -23,12 +23,16 @@
#include "accountadapter.h"
#include "appsettingsmanager.h"
#include "qtutils.h"
#include <QtConcurrent/QtConcurrent>
AccountAdapter::AccountAdapter(LRCInstance* instance, QObject* parent)
AccountAdapter::AccountAdapter(AppSettingsManager* settingsManager,
LRCInstance* instance,
QObject* parent)
: QmlAdapterBase(instance, parent)
, settingsManager_(settingsManager)
{}
void
@ -100,7 +104,7 @@ AccountAdapter::createJamiAccount(QString registeredName,
lrcInstance_->accountModel().setAccountConfig(accountId, confProps);
auto showBackup = isCreating
&& !AppSettingsManager::getValue(Settings::Key::NeverShowMeAgain)
&& !settingsManager_->getValue(Settings::Key::NeverShowMeAgain)
.toBool();
if (!registeredName.isEmpty()) {
QObject::disconnect(registeredNameSavedConnection_);

View file

@ -27,6 +27,8 @@
#include "lrcinstance.h"
#include "utils.h"
class AppSettingsManager;
class AccountAdapter final : public QmlAdapterBase
{
Q_OBJECT
@ -50,7 +52,9 @@ signals:
void accountListSizeChanged();
public:
explicit AccountAdapter(LRCInstance* instance, QObject* parent = nullptr);
explicit AccountAdapter(AppSettingsManager* settingsManager,
LRCInstance* instance,
QObject* parent = nullptr);
~AccountAdapter() = default;
protected:
@ -132,5 +136,7 @@ private:
QMetaObject::Connection addedToConferenceConnection_;
QMetaObject::Connection contactUnbannedConnection_;
QMetaObject::Connection registeredNameSavedConnection_;
AppSettingsManager* settingsManager_;
};
Q_DECLARE_METATYPE(AccountAdapter*)

View file

@ -0,0 +1,50 @@
/*!
* Copyright (C) 2021 by Savoir-faire Linux
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.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 3 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* \file appsettingsmanager.cpp
*/
#include "appsettingsmanager.h"
AppSettingsManager::AppSettingsManager(QObject* parent)
: QObject(parent)
, settings_(new QSettings("jami.net", "Jami", this))
{
for (int i = 0; i < static_cast<int>(Settings::Key::COUNT__); ++i) {
auto key = static_cast<Settings::Key>(i);
if (!settings_->contains(Settings::toString(key)))
setValue(key, Settings::defaultValue(key));
}
}
QVariant
AppSettingsManager::getValue(const Settings::Key key)
{
auto value = settings_->value(Settings::toString(key), Settings::defaultValue(key));
if (QString(value.typeName()) == "QString"
&& (value.toString() == "false" || value.toString() == "true"))
return value.toBool();
return value;
}
void
AppSettingsManager::setValue(const Settings::Key key, const QVariant& value)
{
settings_->setValue(Settings::toString(key), value);
}

View file

@ -1,5 +1,5 @@
/*!
* Copyright (C) 2020 by Savoir-faire Linux
* Copyright (C) 2020-2021 by Savoir-faire Linux
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@ -84,51 +84,16 @@ private:
Q_DECLARE_METATYPE(Settings::Key)
// clang-format on
/*
* A singleton object to manage settings access.
*/
class AppSettingsManager : public QObject
{
Q_OBJECT
public:
virtual ~AppSettingsManager() = default;
explicit AppSettingsManager(QObject* parent = nullptr);
~AppSettingsManager() = default;
static AppSettingsManager& instance()
{
static AppSettingsManager* instance_ = new AppSettingsManager(nullptr);
return *instance_;
}
static QVariant getValue(const Settings::Key key)
{
auto settings = instance().settings_;
auto value = settings->value(Settings::toString(key), Settings::defaultValue(key));
if (QString(value.typeName()) == "QString"
&& (value.toString() == "false" || value.toString() == "true"))
return value.toBool();
return value;
}
static void setValue(const Settings::Key key, const QVariant& value)
{
instance().settings_->setValue(Settings::toString(key), value);
}
static void initValues()
{
for (int i = 0; i < static_cast<int>(Settings::Key::COUNT__); ++i) {
auto key = static_cast<Settings::Key>(i);
if (!instance().settings_->contains(Settings::toString(key)))
setValue(key, Settings::defaultValue(key));
}
}
QVariant getValue(const Settings::Key key);
void setValue(const Settings::Key key, const QVariant& value);
private:
explicit AppSettingsManager(QObject*)
: settings_(new QSettings("jami.net", "Jami", this))
{}
QSettings* settings_;
};

View file

@ -23,13 +23,16 @@
*/
#include "calladapter.h"
#include "systemtray.h"
#include "utils.h"
#include <QApplication>
CallAdapter::CallAdapter(LRCInstance* instance, QObject* parent)
CallAdapter::CallAdapter(SystemTray* systemTray, LRCInstance* instance, QObject* parent)
: QmlAdapterBase(instance, parent)
, oneSecondTimer_(new QTimer(this))
, systemTray_(systemTray)
{
accountId_ = lrcInstance_->getCurrAccId();
connectCallModel(accountId_);
@ -335,7 +338,7 @@ CallAdapter::showNotification(const QString& accountId, const QString& convUid)
emit callSetupMainViewRequired(convInfo.accountId, convInfo.uid);
};
emit lrcInstance_->updateSmartList();
Utils::showNotification(tr("is calling you"), from, accountId, convUid, onClicked);
systemTray_->showNotification(tr("is calling you"), from, onClicked);
}
void

View file

@ -28,6 +28,8 @@
#include <QVariant>
#include <QSystemTrayIcon>
class SystemTray;
class CallAdapter final : public QmlAdapterBase
{
Q_OBJECT
@ -36,7 +38,7 @@ public:
enum MuteStates { UNMUTED, LOCAL_MUTED, MODERATOR_MUTED, BOTH_MUTED };
Q_ENUM(MuteStates)
explicit CallAdapter(LRCInstance* instance, QObject* parent = nullptr);
explicit CallAdapter(SystemTray* systemTray, LRCInstance* instance, QObject* parent = nullptr);
~CallAdapter() = default;
protected:
@ -124,4 +126,6 @@ private:
ScreenSaver screenSaver;
void preventScreenSaver(bool state);
SystemTray* systemTray_;
};

View file

@ -56,11 +56,8 @@ public:
virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
{
// Accept all contacts in conversation list filtered with account type, except those in a call.
auto index = sourceModel()->index(source_row, 0, source_parent);
if (filterPredicate_) {
return filterPredicate_(index, filterRegExp());
}
return filterPredicate_ ? filterPredicate_(index, filterRegExp()) : false;
}
private:

View file

@ -25,11 +25,15 @@
#include "utils.h"
#include "qtutils.h"
#include "systemtray.h"
#include <QApplication>
ConversationsAdapter::ConversationsAdapter(LRCInstance* instance, QObject* parent)
ConversationsAdapter::ConversationsAdapter(SystemTray* systemTray,
LRCInstance* instance,
QObject* parent)
: QmlAdapterBase(instance, parent)
, systemTray_(systemTray)
{
connect(this, &ConversationsAdapter::currentTypeFilterChanged, [this]() {
lrcInstance_->getCurrentConversationModel()->setFilter(currentTypeFilter_);
@ -163,7 +167,7 @@ ConversationsAdapter::onNewUnreadInteraction(const QString& accountId,
}
};
Utils::showNotification(interaction.body, from, accountId, convUid, onClicked);
systemTray_->showNotification(interaction.body, from, onClicked);
return;
}
}

View file

@ -25,6 +25,8 @@
#include <QObject>
#include <QString>
class SystemTray;
class ConversationsAdapter final : public QmlAdapterBase
{
Q_OBJECT
@ -32,7 +34,9 @@ class ConversationsAdapter final : public QmlAdapterBase
Q_PROPERTY(lrc::api::profile::Type currentTypeFilter MEMBER currentTypeFilter_ NOTIFY
currentTypeFilterChanged)
public:
explicit ConversationsAdapter(LRCInstance* instance, QObject* parent = nullptr);
explicit ConversationsAdapter(SystemTray* systemTray,
LRCInstance* instance,
QObject* parent = nullptr);
~ConversationsAdapter() = default;
protected:
@ -86,4 +90,6 @@ private:
QMetaObject::Connection interactionRemovedConnection_;
QMetaObject::Connection searchStatusChangedConnection_;
QMetaObject::Connection searchResultUpdatedConnection_;
SystemTray* systemTray_;
};

View file

@ -26,7 +26,6 @@
#include "updatemanager.h"
#include "rendermanager.h"
#include "appsettingsmanager.h"
#include "utils.h"
#include "api/account.h"

View file

@ -21,15 +21,25 @@
#include "mainapplication.h"
#include "qmlregister.h"
#include "appsettingsmanager.h"
#include "connectivitymonitor.h"
#include "globalsystemtray.h"
#include "systemtray.h"
#include "namedirectory.h"
#include "qmlregister.h"
#include "qrimageprovider.h"
#include "tintedbuttonimageprovider.h"
#include "avatarimageprovider.h"
#include "accountadapter.h"
#include "avadapter.h"
#include "calladapter.h"
#include "contactadapter.h"
#include "pluginadapter.h"
#include "messagesadapter.h"
#include "settingsadapter.h"
#include "utilsadapter.h"
#include "conversationsadapter.h"
#include <QAction>
#include <QCommandLineParser>
#include <QCoreApplication>
@ -146,6 +156,8 @@ MainApplication::MainApplication(int& argc, char** argv)
: QApplication(argc, argv)
, engine_(new QQmlApplicationEngine())
, connectivityMonitor_(new ConnectivityMonitor(this))
, settingsManager_(new AppSettingsManager(this))
, systemTray_(new SystemTray(settingsManager_, this))
{
QObject::connect(this, &QApplication::aboutToQuit, [this] { cleanup(); });
}
@ -233,9 +245,11 @@ MainApplication::init()
vsConsoleDebug();
}
initSettings();
auto downloadPath = settingsManager_->getValue(Settings::Key::DownloadPath);
lrcInstance_->dataTransferModel().downloadDirectory = downloadPath.toString() + "/";
initQmlLayer();
initSystray();
initQmlEngine();
return true;
}
@ -394,9 +408,37 @@ MainApplication::setApplicationFont()
}
void
MainApplication::initQmlEngine()
MainApplication::initQmlLayer()
{
registerTypes(lrcInstance_.get());
// setup the adapters (their lifetimes are that of MainApplication)
auto callAdapter = new CallAdapter(systemTray_, lrcInstance_.data(), this);
auto messagesAdapter = new MessagesAdapter(settingsManager_, lrcInstance_.data(), this);
auto conversationsAdapter = new ConversationsAdapter(systemTray_, lrcInstance_.data(), this);
auto avAdapter = new AvAdapter(lrcInstance_.data(), this);
auto contactAdapter = new ContactAdapter(lrcInstance_.data(), this);
auto accountAdapter = new AccountAdapter(settingsManager_, lrcInstance_.data(), this);
auto utilsAdapter = new UtilsAdapter(systemTray_, lrcInstance_.data(), this);
auto settingsAdapter = new SettingsAdapter(settingsManager_, lrcInstance_.data(), this);
auto pluginAdapter = new PluginAdapter(lrcInstance_.data(), this);
// qml adapter registration
QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, callAdapter, "CallAdapter");
QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, messagesAdapter, "MessagesAdapter");
QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, conversationsAdapter, "ConversationsAdapter");
QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, avAdapter, "AvAdapter");
QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, contactAdapter, "ContactAdapter");
QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, accountAdapter, "AccountAdapter");
QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, utilsAdapter, "UtilsAdapter");
QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, settingsAdapter, "SettingsAdapter");
QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, pluginAdapter, "PluginAdapter");
// TODO: remove these
QML_REGISTERSINGLETONTYPE_CUSTOM(NS_MODELS, AVModel, &lrcInstance_->avModel())
QML_REGISTERSINGLETONTYPE_CUSTOM(NS_MODELS, PluginModel, &lrcInstance_->pluginModel())
QML_REGISTERSINGLETONTYPE_CUSTOM(NS_HELPERS, UpdateManager, lrcInstance_->getUpdateManager())
// register other types that don't require injection(e.g. uncreatables, c++/qml singletons)
Utils::registerTypes();
engine_->addImageProvider(QLatin1String("qrImage"), new QrImageProvider(lrcInstance_.get()));
engine_->addImageProvider(QLatin1String("tintedPixmap"),
@ -416,19 +458,10 @@ MainApplication::initQmlEngine()
engine_->load(QUrl(QStringLiteral("qrc:/src/MainApplicationWindow.qml")));
}
void
MainApplication::initSettings()
{
AppSettingsManager::instance().initValues();
auto downloadPath = AppSettingsManager::instance().getValue(Settings::Key::DownloadPath);
lrcInstance_->dataTransferModel().downloadDirectory = downloadPath.toString() + "/";
}
void
MainApplication::initSystray()
{
GlobalSystemTray& sysIcon = GlobalSystemTray::instance();
sysIcon.setIcon(QIcon(":images/jami.png"));
systemTray_->setIcon(QIcon(":images/jami.png"));
QMenu* systrayMenu = new QMenu();
@ -437,20 +470,21 @@ MainApplication::initSystray()
engine_->quit();
cleanup();
});
connect(&sysIcon, &QSystemTrayIcon::activated, [this](QSystemTrayIcon::ActivationReason reason) {
if (reason != QSystemTrayIcon::ActivationReason::Context)
restoreApp();
});
connect(systemTray_,
&QSystemTrayIcon::activated,
[this](QSystemTrayIcon::ActivationReason reason) {
if (reason != QSystemTrayIcon::ActivationReason::Context)
restoreApp();
});
systrayMenu->addAction(exitAction);
sysIcon.setContextMenu(systrayMenu);
sysIcon.show();
systemTray_->setContextMenu(systrayMenu);
systemTray_->show();
}
void
MainApplication::cleanup()
{
GlobalSystemTray::instance().hide();
#ifdef Q_OS_WIN
FreeConsole();
#endif

View file

@ -32,6 +32,8 @@
#include <memory>
class ConnectivityMonitor;
class AppSettingsManager;
class SystemTray;
// Provides information about the screen the app is displayed on
class ScreenInfo : public QObject
@ -81,16 +83,19 @@ private:
void initLrc(const QString& downloadUrl, ConnectivityMonitor* cm);
const QVariantMap parseArguments();
void setApplicationFont();
void initQmlEngine();
void initSettings();
void initQmlLayer();
void initSystray();
void cleanup();
private:
QScopedPointer<QFile> debugFile_;
QScopedPointer<QQmlApplicationEngine> engine_;
QScopedPointer<LRCInstance> lrcInstance_;
ConnectivityMonitor* connectivityMonitor_ {nullptr};
ConnectivityMonitor* connectivityMonitor_;
AppSettingsManager* settingsManager_;
SystemTray* systemTray_;
ScreenInfo screenInfo_;
};

View file

@ -23,6 +23,7 @@
#include "messagesadapter.h"
#include "appsettingsmanager.h"
#include "qtutils.h"
#include "utils.h"
#include "webchathelpers.h"
@ -35,8 +36,11 @@
#include <QList>
#include <QUrl>
MessagesAdapter::MessagesAdapter(LRCInstance* instance, QObject* parent)
MessagesAdapter::MessagesAdapter(AppSettingsManager* settingsManager,
LRCInstance* instance,
QObject* parent)
: QmlAdapterBase(instance, parent)
, settingsManager_(settingsManager)
{}
void
@ -94,7 +98,7 @@ MessagesAdapter::setupChatView(const QString& convUid)
connect(lrcInstance_->getCurrentConversationModel(),
&ConversationModel::composingStatusChanged,
[this](const QString& convUid, const QString& contactUri, bool isComposing) {
if (!AppSettingsManager::getValue(Settings::Key::EnableTypingIndicator).toBool()) {
if (!settingsManager_->getValue(Settings::Key::EnableTypingIndicator).toBool()) {
return;
}
contactIsComposing(convUid, contactUri, isComposing);
@ -438,7 +442,7 @@ MessagesAdapter::pasteKeyDetected()
void
MessagesAdapter::onComposing(bool isComposing)
{
if (!AppSettingsManager::getValue(Settings::Key::EnableTypingIndicator).toBool()) {
if (!settingsManager_->getValue(Settings::Key::EnableTypingIndicator).toBool()) {
return;
}
lrcInstance_->getCurrentConversationModel()->setIsComposing(lrcInstance_->getCurrentConvUid(),
@ -550,8 +554,7 @@ void
MessagesAdapter::setDisplayLinks()
{
QString s = QString::fromLatin1("setDisplayLinks(%1);")
.arg(
AppSettingsManager::getValue(Settings::Key::DisplayImagesChatview).toBool());
.arg(settingsManager_->getValue(Settings::Key::DisplayImagesChatview).toBool());
QMetaObject::invokeMethod(qmlObj_, "webViewRunJavaScript", Q_ARG(QVariant, s));
}

View file

@ -25,13 +25,17 @@
#include <QObject>
#include <QString>
class AppSettingsManager;
class MessagesAdapter final : public QmlAdapterBase
{
Q_OBJECT
Q_PROPERTY(QVariantMap chatviewTranslatedStrings MEMBER chatviewTranslatedStrings_ CONSTANT)
public:
explicit MessagesAdapter(LRCInstance* instance, QObject* parent = nullptr);
explicit MessagesAdapter(AppSettingsManager* settingsManager,
LRCInstance* instance,
QObject* parent = nullptr);
~MessagesAdapter() = default;
protected:
@ -115,4 +119,6 @@ private:
QMetaObject::Connection newInteractionConnection_;
QMetaObject::Connection interactionStatusUpdatedConnection_;
QMetaObject::Connection interactionRemovedConnection_;
AppSettingsManager* settingsManager_;
};

View file

@ -18,28 +18,22 @@
#include "qmlregister.h"
#include "accountadapter.h"
#include "accountlistmodel.h"
#include "accountstomigratelistmodel.h"
#include "mediacodeclistmodel.h"
#include "audiodevicemodel.h"
#include "audiomanagerlistmodel.h"
#include "avadapter.h"
#include "bannedlistmodel.h"
#include "moderatorlistmodel.h"
#include "calladapter.h"
#include "contactadapter.h"
#include "conversationsadapter.h"
#include "deviceitemlistmodel.h"
#include "smartlistmodel.h"
#include "appsettingsmanager.h"
#include "distantrenderer.h"
#include "pluginadapter.h"
#include "messagesadapter.h"
#include "namedirectory.h"
#include "updatemanager.h"
#include "pluginlistpreferencemodel.h"
#include "previewrenderer.h"
#include "settingsadapter.h"
#include "utilsadapter.h"
#include "version.h"
#include "videoformatfpsmodel.h"
#include "videoformatresolutionmodel.h"
@ -49,116 +43,91 @@
#include <QQmlEngine>
// clang-format off
#define QML_REGISTERSINGLETONTYPE_ADAPTER(N, T, MAJ, MIN) \
qmlRegisterSingletonType<T>(N, MAJ, MIN, #T, \
[instance](QQmlEngine* e, QJSEngine* se) -> QObject* { \
Q_UNUSED(e); Q_UNUSED(se); \
T* obj = new T(nullptr, instance); return obj; \
});
#define QML_REGISTERSINGLETONTYPE_WITH_INSTANCE(T, MAJ, MIN) \
qmlRegisterSingletonType<T>("net.jami.Models", MAJ, MIN, #T, \
// TODO: remove this
#define QML_REGISTERSINGLETONTYPE_WITH_INSTANCE(T) \
qmlRegisterSingletonType<T>(NS_MODELS, VER_MAJ, VER_MIN, #T, \
[](QQmlEngine* e, QJSEngine* se) -> QObject* { \
Q_UNUSED(e); Q_UNUSED(se); \
return &(T::instance()); \
});
#define QML_REGISTERSINGLETONTYPE_CUSTOM(N, T, MAJ, MIN, P) \
qmlRegisterSingletonType<T>(N, MAJ, MIN, #T, \
[instance](QQmlEngine* e, QJSEngine* se) -> QObject* { \
Q_UNUSED(e); Q_UNUSED(se); \
return P; \
});
#define QML_REGISTERSINGLETONTYPE_URL(NS, URL, T) \
qmlRegisterSingletonType(QUrl(QStringLiteral(URL)), NS, VER_MAJ, VER_MIN, #T);
#define QML_REGISTERSINGLETONTYPE_URL(N, URL, T, MAJ, MIN) \
qmlRegisterSingletonType(QUrl(QStringLiteral(URL)), N, MAJ, MIN, #T);
#define QML_REGISTERTYPE(NS, T) qmlRegisterType<T>(NS, VER_MAJ, VER_MIN, #T);
#define QML_REGISTERTYPE(N, T, MAJ, MIN) qmlRegisterType<T>(N, MAJ, MIN, #T);
#define QML_REGISTERNAMESPACE(T, NAME) \
qmlRegisterUncreatableMetaObject(T, NS_MODELS, VER_MAJ, VER_MIN, NAME, "")
#define QML_REGISTERNAMESPACE(T, NAME, MAJ, MIN) \
qmlRegisterUncreatableMetaObject(T, "net.jami.Models", MAJ, MIN, NAME, "")
#define QML_REGISTERUNCREATABLE(N, T) \
qmlRegisterUncreatableType<T>(N, VER_MAJ, VER_MIN, #T, "Don't try to add to a qml definition of " #T);
#define QML_REGISTERUNCREATABLE(N, T, MAJ, MIN) \
qmlRegisterUncreatableType<T>(N, MAJ, MIN, #T, "Don't try to add to a qml definition of " #T);
#define QML_REGISTERUNCREATABLE_IN_NAMESPACE(T, NAMESPACE, MAJ, MIN) \
qmlRegisterUncreatableType<NAMESPACE::T>("net.jami.Models", \
MAJ, MIN, #T, \
#define QML_REGISTERUNCREATABLE_IN_NAMESPACE(T, NAMESPACE) \
qmlRegisterUncreatableType<NAMESPACE::T>(NS_MODELS, \
VER_MAJ, VER_MIN, #T, \
"Don't try to add to a qml definition of " #T);
namespace Utils {
/*!
* This function will expose custom types to the QML engine.
*/
void
registerTypes(LRCInstance* instance)
registerTypes()
{
// QAbstractListModels
QML_REGISTERTYPE("net.jami.Models", AccountListModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", DeviceItemListModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", BannedListModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", ModeratorListModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", MediaCodecListModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", AccountsToMigrateListModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", AudioDeviceModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", AudioManagerListModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", VideoInputDeviceModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", VideoFormatResolutionModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", VideoFormatFpsModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", PluginListPreferenceModel, 1, 0);
QML_REGISTERTYPE("net.jami.Models", SmartListModel, 1, 0);
QML_REGISTERTYPE(NS_MODELS, AccountListModel);
QML_REGISTERTYPE(NS_MODELS, DeviceItemListModel);
QML_REGISTERTYPE(NS_MODELS, BannedListModel);
QML_REGISTERTYPE(NS_MODELS, ModeratorListModel);
QML_REGISTERTYPE(NS_MODELS, MediaCodecListModel);
QML_REGISTERTYPE(NS_MODELS, AccountsToMigrateListModel);
QML_REGISTERTYPE(NS_MODELS, AudioDeviceModel);
QML_REGISTERTYPE(NS_MODELS, AudioManagerListModel);
QML_REGISTERTYPE(NS_MODELS, VideoInputDeviceModel);
QML_REGISTERTYPE(NS_MODELS, VideoFormatResolutionModel);
QML_REGISTERTYPE(NS_MODELS, VideoFormatFpsModel);
QML_REGISTERTYPE(NS_MODELS, PluginListPreferenceModel);
QML_REGISTERTYPE(NS_MODELS, SmartListModel);
// QQuickItems
QML_REGISTERTYPE("net.jami.Models", PreviewRenderer, 1, 0);
QML_REGISTERTYPE("net.jami.Models", VideoCallPreviewRenderer, 1, 0);
QML_REGISTERTYPE("net.jami.Models", DistantRenderer, 1, 0);
QML_REGISTERTYPE("net.jami.Models", PhotoboothPreviewRender, 1, 0)
// Adaptors
QML_REGISTERSINGLETONTYPE_ADAPTER("net.jami.Adapters", CallAdapter, 1, 0);
QML_REGISTERSINGLETONTYPE_ADAPTER("net.jami.Adapters", MessagesAdapter, 1, 0);
QML_REGISTERSINGLETONTYPE_ADAPTER("net.jami.Adapters", ConversationsAdapter, 1, 0);
QML_REGISTERSINGLETONTYPE_ADAPTER("net.jami.Adapters", AvAdapter, 1, 0);
QML_REGISTERSINGLETONTYPE_ADAPTER("net.jami.Adapters", ContactAdapter, 1, 0);
QML_REGISTERSINGLETONTYPE_ADAPTER("net.jami.Adapters", PluginAdapter, 1, 0);
QML_REGISTERSINGLETONTYPE_ADAPTER("net.jami.Adapters", AccountAdapter, 1, 0);
QML_REGISTERSINGLETONTYPE_ADAPTER("net.jami.Adapters", UtilsAdapter, 1, 0);
QML_REGISTERSINGLETONTYPE_ADAPTER("net.jami.Adapters", SettingsAdapter, 1, 0);
QML_REGISTERSINGLETONTYPE_CUSTOM("net.jami.Models", AVModel, 1, 0, &instance->avModel())
QML_REGISTERSINGLETONTYPE_CUSTOM("net.jami.Models", PluginModel, 1, 0, &instance->pluginModel())
QML_REGISTERSINGLETONTYPE_CUSTOM("net.jami.Helpers", UpdateManager, 1, 0, instance->getUpdateManager())
QML_REGISTERTYPE(NS_MODELS, PreviewRenderer);
QML_REGISTERTYPE(NS_MODELS, VideoCallPreviewRenderer);
QML_REGISTERTYPE(NS_MODELS, DistantRenderer);
QML_REGISTERTYPE(NS_MODELS, PhotoboothPreviewRender)
// Qml singleton components
QML_REGISTERSINGLETONTYPE_URL("net.jami.Constants", "qrc:/src/constant/JamiTheme.qml", JamiTheme, 1, 0);
QML_REGISTERSINGLETONTYPE_URL("net.jami.Models", "qrc:/src/constant/JamiQmlUtils.qml", JamiQmlUtils, 1, 0);
QML_REGISTERSINGLETONTYPE_URL("net.jami.Constants", "qrc:/src/constant/JamiStrings.qml", JamiStrings, 1, 0);
QML_REGISTERSINGLETONTYPE_URL(NS_CONSTANTS, "qrc:/src/constant/JamiTheme.qml", JamiTheme);
QML_REGISTERSINGLETONTYPE_URL(NS_MODELS, "qrc:/src/constant/JamiQmlUtils.qml", JamiQmlUtils);
QML_REGISTERSINGLETONTYPE_URL(NS_CONSTANTS, "qrc:/src/constant/JamiStrings.qml", JamiStrings);
// C++ singletons
QML_REGISTERSINGLETONTYPE_WITH_INSTANCE(NameDirectory, 1, 0);
// TODO: remove this
QML_REGISTERSINGLETONTYPE_WITH_INSTANCE(NameDirectory);
// Lrc namespaces, models, and singletons
QML_REGISTERNAMESPACE(lrc::api::staticMetaObject, "Lrc", 1, 0);
QML_REGISTERNAMESPACE(lrc::api::account::staticMetaObject, "Account", 1, 0);
QML_REGISTERNAMESPACE(lrc::api::call::staticMetaObject, "Call", 1, 0);
QML_REGISTERNAMESPACE(lrc::api::datatransfer::staticMetaObject, "Datatransfer", 1, 0);
QML_REGISTERNAMESPACE(lrc::api::interaction::staticMetaObject, "Interaction", 1, 0);
QML_REGISTERNAMESPACE(lrc::api::video::staticMetaObject, "Video", 1, 0);
QML_REGISTERNAMESPACE(lrc::api::profile::staticMetaObject, "Profile", 1, 0);
QML_REGISTERNAMESPACE(lrc::api::staticMetaObject, "Lrc");
QML_REGISTERNAMESPACE(lrc::api::account::staticMetaObject, "Account");
QML_REGISTERNAMESPACE(lrc::api::call::staticMetaObject, "Call");
QML_REGISTERNAMESPACE(lrc::api::datatransfer::staticMetaObject, "Datatransfer");
QML_REGISTERNAMESPACE(lrc::api::interaction::staticMetaObject, "Interaction");
QML_REGISTERNAMESPACE(lrc::api::video::staticMetaObject, "Video");
QML_REGISTERNAMESPACE(lrc::api::profile::staticMetaObject, "Profile");
// Same as QML_REGISTERUNCREATABLE but omit the namespace in Qml
QML_REGISTERUNCREATABLE_IN_NAMESPACE(NewAccountModel, lrc::api, 1, 0);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(BehaviorController, lrc::api, 1, 0);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(DataTransferModel, lrc::api, 1, 0);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(ContactModel, lrc::api, 1, 0);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(ConversationModel, lrc::api, 1, 0);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(NewCallModel, lrc::api, 1, 0);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(NewDeviceModel, lrc::api, 1, 0);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(NewCodecModel, lrc::api, 1, 0);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(PeerDiscoveryModel, lrc::api, 1, 0);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(NewAccountModel, lrc::api);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(BehaviorController, lrc::api);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(DataTransferModel, lrc::api);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(ContactModel, lrc::api);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(ConversationModel, lrc::api);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(NewCallModel, lrc::api);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(NewDeviceModel, lrc::api);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(NewCodecModel, lrc::api);
QML_REGISTERUNCREATABLE_IN_NAMESPACE(PeerDiscoveryModel, lrc::api);
// Enums
QML_REGISTERUNCREATABLE("net.jami.Enums", Settings, 1, 0);
QML_REGISTERUNCREATABLE("net.jami.Enums", NetWorkManager, 1, 0);
QML_REGISTERUNCREATABLE(NS_ENUMS, Settings);
QML_REGISTERUNCREATABLE(NS_ENUMS, NetWorkManager);
}
// clang-format on
} // namespace Utils

View file

@ -18,6 +18,30 @@
#pragma once
class LRCInstance;
#define NS_MODELS "net.jami.Models"
#define NS_ADAPTERS "net.jami.Adapters"
#define NS_CONSTANTS "net.jami.Constants"
#define NS_HELPERS "net.jami.Helpers"
#define NS_ENUMS "net.jami.Enums"
#define VER_MAJ 1
#define VER_MIN 0
void registerTypes(LRCInstance* instance);
// clang-format off
#define QML_REGISTERSINGLETONTYPE_POBJECT(NS, I, N) \
QQmlEngine::setObjectOwnership(I, QQmlEngine::CppOwnership); \
{ using T = std::remove_reference<decltype(*I)>::type; \
qmlRegisterSingletonType<T>(NS, VER_MAJ, VER_MIN, N, \
[I](QQmlEngine*, QJSEngine*) -> QObject* { \
return I; }); }
#define QML_REGISTERSINGLETONTYPE_CUSTOM(NS, T, P) \
qmlRegisterSingletonType<T>(NS, VER_MAJ, VER_MIN, #T, \
[p=P](QQmlEngine* e, QJSEngine* se) -> QObject* { \
Q_UNUSED(e); Q_UNUSED(se); \
return p; \
});
// clang-format on
namespace Utils {
void registerTypes();
}

View file

@ -20,8 +20,11 @@
#include "api/newdevicemodel.h"
SettingsAdapter::SettingsAdapter(LRCInstance* instance, QObject* parent)
SettingsAdapter::SettingsAdapter(AppSettingsManager* settingsManager,
LRCInstance* instance,
QObject* parent)
: QmlAdapterBase(instance, parent)
, settingsManager_(settingsManager)
{}
QString
@ -54,13 +57,13 @@ SettingsAdapter::getDir_Download()
QVariant
SettingsAdapter::getAppValue(const Settings::Key key)
{
return AppSettingsManager::getValue(key);
return settingsManager_->getValue(key);
}
void
SettingsAdapter::setAppValue(const Settings::Key key, const QVariant& value)
{
AppSettingsManager::setValue(key, value);
settingsManager_->setValue(key, value);
}
void

View file

@ -19,7 +19,6 @@
#pragma once
#include <QObject>
#include <QSettings>
#include "api/account.h"
#include "api/datatransfermodel.h"
@ -27,12 +26,15 @@
#include "typedefs.h"
#include "utils.h"
#include "qmladapterbase.h"
#include "appsettingsmanager.h"
class SettingsAdapter : public QmlAdapterBase
{
Q_OBJECT
public:
explicit SettingsAdapter(LRCInstance* instance, QObject* parent = nullptr);
explicit SettingsAdapter(AppSettingsManager* settingsManager,
LRCInstance* instance,
QObject* parent = nullptr);
void safeInit() override {}
@ -225,5 +227,8 @@ public:
Q_INVOKABLE void enableLocalModerators(const QString& accountID, const bool& isModEnabled);
Q_INVOKABLE bool isLocalModeratorsEnabled(const QString& accountId);
Q_INVOKABLE bool isAllModeratorsEnabled(const QString& accountId);
private:
AppSettingsManager* settingsManager_;
};
Q_DECLARE_METATYPE(SettingsAdapter*)

57
src/systemtray.cpp Normal file
View file

@ -0,0 +1,57 @@
/*
* Copyright (C) 2021 by Savoir-faire Linux
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.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 3 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "systemtray.h"
#include "appsettingsmanager.h"
SystemTray::SystemTray(AppSettingsManager* settingsManager, QObject* parent)
: QSystemTrayIcon(parent)
, settingsManager_(settingsManager)
{}
SystemTray::~SystemTray()
{
hide();
}
void
SystemTray::showNotification(const QString& message,
const QString& from,
std::function<void()> const& onClickedCb)
{
if (!settingsManager_->getValue(Settings::Key::EnableNotifications).toBool()) {
qWarning() << "Notifications are disabled";
return;
}
setOnClickedCallback(std::move(onClickedCb));
if (from.isEmpty())
showMessage(message, "", QIcon(":images/jami.png"));
else
showMessage(from, message, QIcon(":images/jami.png"));
}
template<typename Func>
void
SystemTray::setOnClickedCallback(Func&& onClicked)
{
disconnect(messageClicked_);
messageClicked_ = connect(this, &QSystemTrayIcon::messageClicked, onClicked);
}

View file

@ -1,6 +1,6 @@
/*
* Copyright (C) 2015-2020 by Savoir-faire Linux
* Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>
* Copyright (C) 2021 by Savoir-faire Linux
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.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
@ -18,33 +18,26 @@
#pragma once
#include "lrcinstance.h"
#include <QSystemTrayIcon>
class GlobalSystemTray final : public QSystemTrayIcon
class AppSettingsManager;
class SystemTray final : public QSystemTrayIcon
{
Q_OBJECT
public:
~GlobalSystemTray() = default;
static GlobalSystemTray& instance()
{
static GlobalSystemTray* instance_ = new GlobalSystemTray();
return *instance_;
}
explicit SystemTray(AppSettingsManager* settingsManager, QObject* parent = nullptr);
~SystemTray();
void showNotification(const QString& message,
const QString& from,
std::function<void()> const& onClickedCb);
template<typename Func>
static void connectClicked(Func&& onClicked)
{
auto& instance_ = instance();
instance_.disconnect(instance_.messageClicked_);
instance_.connect(&instance_, &QSystemTrayIcon::messageClicked, onClicked);
}
void setOnClickedCallback(Func&& onClickedCb);
private:
explicit GlobalSystemTray()
: QSystemTrayIcon() {};
QMetaObject::Connection messageClicked_;
AppSettingsManager* settingsManager_;
};

View file

@ -22,7 +22,6 @@
#include "utils.h"
#include "globalsystemtray.h"
#include "jamiavatartheme.h"
#include "lrcinstance.h"
@ -395,31 +394,6 @@ Utils::getCirclePhoto(const QImage original, int sizePhoto)
return target;
}
void
Utils::showNotification(const QString& message,
const QString& from,
const QString& accountId,
const QString& convUid,
std::function<void()> const& onClicked)
{
if (accountId.isEmpty() || convUid.isEmpty()) {
// This should never happen.
qFatal("Invalid account or conversation.");
}
if (!AppSettingsManager::getValue(Settings::Key::EnableNotifications).toBool()) {
qWarning() << "Notifications are disabled";
return;
}
GlobalSystemTray::connectClicked(std::move(onClicked));
if (from.isEmpty())
GlobalSystemTray::instance().showMessage(message, "", QIcon(":images/jami.png"));
else
GlobalSystemTray::instance().showMessage(from, message, QIcon(":images/jami.png"));
}
QSize
Utils::getRealSize(QScreen* screen)
{

View file

@ -66,11 +66,6 @@ const char* WinGetEnv(const char* name);
QString GetRingtonePath();
QString GenGUID();
QString GetISODate();
void showNotification(const QString& message,
const QString& from,
const QString& accountId,
const QString& convUid,
std::function<void()> const& onClicked);
QSize getRealSize(QScreen* screen);
void forceDeleteAsync(const QString& path);
QString getProjectCredits();

View file

@ -22,8 +22,8 @@
#include "utilsadapter.h"
#include "globalsystemtray.h"
#include "lrcinstance.h"
#include "systemtray.h"
#include "utils.h"
#include "version.h"
@ -31,9 +31,10 @@
#include <QClipboard>
#include <QFileInfo>
UtilsAdapter::UtilsAdapter(LRCInstance* instance, QObject* parent)
UtilsAdapter::UtilsAdapter(SystemTray* systemTray, LRCInstance* instance, QObject* parent)
: QmlAdapterBase(instance, parent)
, clipboard_(QApplication::clipboard())
, systemTray_(systemTray)
{}
const QString
@ -360,5 +361,5 @@ UtilsAdapter::humanFileSize(qint64 fileSize)
void
UtilsAdapter::setSystemTrayIconVisible(bool visible)
{
GlobalSystemTray::instance().setVisible(visible);
systemTray_->setVisible(visible);
}

View file

@ -28,12 +28,13 @@
#include "qmladapterbase.h"
class QClipboard;
class SystemTray;
class UtilsAdapter final : public QmlAdapterBase
{
Q_OBJECT
public:
explicit UtilsAdapter(LRCInstance* instance, QObject* parent = nullptr);
explicit UtilsAdapter(SystemTray* systemTray, LRCInstance* instance, QObject* parent = nullptr);
~UtilsAdapter() = default;
void safeInit() override {}
@ -81,5 +82,6 @@ public:
private:
QClipboard* clipboard_;
SystemTray* systemTray_;
};
Q_DECLARE_METATYPE(UtilsAdapter*)