diff --git a/src/app/calladapter.cpp b/src/app/calladapter.cpp
index f5036a94707261b324fa30259f239b0939d55467..b3ba66b897b2d381e7539c33c46e2ee6f7a48005 100644
--- a/src/app/calladapter.cpp
+++ b/src/app/calladapter.cpp
@@ -26,23 +26,30 @@
 #include "calladapter.h"
 
 #include "systemtray.h"
-#include "utils.h"
 #include "qmlregister.h"
-
-#include <QApplication>
-#include <QTimer>
-#include <QJsonObject>
+#include "appsettingsmanager.h"
 
 #include <api/callmodel.h>
 #include <api/callparticipantsmodel.h>
 
 #include <media_const.h>
 
-CallAdapter::CallAdapter(SystemTray* systemTray, LRCInstance* instance, QObject* parent)
+#include <QApplication>
+#include <QTimer>
+#include <QJsonObject>
+
+CallAdapter::CallAdapter(AppSettingsManager* settingsManager,
+                         SystemTray* systemTray,
+                         LRCInstance* instance,
+                         QObject* parent)
     : QmlAdapterBase(instance, parent)
     , systemTray_(systemTray)
     , callInformationListModel_(std::make_unique<CallInformationListModel>())
+    , listener_(new PTTListener(settingsManager, this))
 {
+    // Expose the Push-to-talk listener to QML as a singleton
+    QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS, listener_, "PttListener");
+
     set_callInformationList(QVariant::fromValue(callInformationListModel_.get()));
 
     timer = new QTimer(this);
@@ -232,7 +239,7 @@ CallAdapter::onCallStarted(const QString& callId)
     // update call Information list by adding the new information related to the callId
     callInformationListModel_->addElement(
         qMakePair(callId, callModel->advancedInformationForCallId(callId)));
-    if (listener_->getPttState()){
+    if (listener_->getPttState()) {
 #ifdef HAVE_GLOBAL_PTT
         listener_->startListening();
         toMute += callId;
@@ -976,7 +983,8 @@ CallAdapter::muteCameraToggle()
             callModel->removeMedia(callId,
                                    libjami::Media::Details::MEDIA_TYPE_VIDEO,
                                    libjami::Media::VideoProtocolPrefix::CAMERA,
-                                   mute, false);
+                                   mute,
+                                   false);
         else
             callModel->addMedia(callId,
                                 lrcInstance_->avModel().getCurrentVideoCaptureDevice(),
diff --git a/src/app/calladapter.h b/src/app/calladapter.h
index 5086e7e84fdab1a9e8bc9e1ae7b1740af9174ca0..45e6553a01d035001c4b30da3eabc4eeb96be7cf 100644
--- a/src/app/calladapter.h
+++ b/src/app/calladapter.h
@@ -37,6 +37,7 @@
 #include "callInformationListModel.h"
 
 class SystemTray;
+class AppSettingsManager;
 
 class CallAdapter final : public QmlAdapterBase
 {
@@ -49,7 +50,10 @@ public:
     enum MuteStates { UNMUTED, LOCAL_MUTED, MODERATOR_MUTED, BOTH_MUTED };
     Q_ENUM(MuteStates)
 
-    explicit CallAdapter(SystemTray* systemTray, LRCInstance* instance, QObject* parent = nullptr);
+    explicit CallAdapter(AppSettingsManager* settingsManager,
+                         SystemTray* systemTray,
+                         LRCInstance* instance,
+                         QObject* parent = nullptr);
     ~CallAdapter();
 
 public:
@@ -131,7 +135,7 @@ private:
     VectorString currentConfSubcalls_;
     std::unique_ptr<CallInformationListModel> callInformationListModel_;
 
-    PTTListener* listener_ = new PTTListener(systemTray_->getSettingsManager());
+    PTTListener* listener_;
     bool isMicrophoneMuted_ = true;
     QSet<QString> toMute;
 };
diff --git a/src/app/commoncomponents/ChangePttKeyPopup.qml b/src/app/commoncomponents/ChangePttKeyPopup.qml
index 90078407a619e987b3c7b4c390d5ff82eca300d4..b785e6af0ef17511c1020a61d0122c15fb46271e 100644
--- a/src/app/commoncomponents/ChangePttKeyPopup.qml
+++ b/src/app/commoncomponents/ChangePttKeyPopup.qml
@@ -102,7 +102,7 @@ BaseModalDialog {
 
             onClicked: {
                 if (!(pressedKey === Qt.Key_unknown)){
-                    pttListener.setPttKey(pressedKey);
+                    PttListener.setPttKey(pressedKey);
                     choiceMade(pressedKey);
                 }
                 close();
@@ -113,7 +113,7 @@ BaseModalDialog {
             id: keyItem
 
             Keys.onPressed: (event)=>{
-                keyLabel.text = pttListener.keyToString(event.key);
+                keyLabel.text = PttListener.keyToString(event.key);
                 pressedKey = event.key;
             }
         }
diff --git a/src/app/mainapplication.cpp b/src/app/mainapplication.cpp
index 1aef171821d9455b33c221bcf5d3337b1e905e6e..94fcb6921af6ffd395571eb93d1ad74e50b6300b 100644
--- a/src/app/mainapplication.cpp
+++ b/src/app/mainapplication.cpp
@@ -20,7 +20,6 @@
  */
 
 #include "mainapplication.h"
-#include "pttlistener.h"
 
 #include "qmlregister.h"
 #include "appsettingsmanager.h"
@@ -131,12 +130,12 @@ MainApplication::init()
     // This 2-phase initialisation prevents ephemeral instances from
     // performing unnecessary tasks, like initializing the webengine.
     engine_.reset(new QQmlApplicationEngine(this));
-    connectivityMonitor_.reset(new ConnectivityMonitor(this));
-    settingsManager_.reset(new AppSettingsManager(this));
-    systemTray_.reset(new SystemTray(settingsManager_.get(), this));
-    listener_ = new PTTListener(settingsManager_.get(), this);
 
-    QObject::connect(settingsManager_.get(),
+    connectivityMonitor_ = new ConnectivityMonitor(this);
+    settingsManager_ = new AppSettingsManager(this);
+    systemTray_ = new SystemTray(settingsManager_, this);
+
+    QObject::connect(settingsManager_,
                      &AppSettingsManager::retranslate,
                      engine_.get(),
                      &QQmlApplicationEngine::retranslate);
@@ -149,7 +148,7 @@ MainApplication::init()
     setApplicationFont();
 
     initLrc(runOptions_[Option::UpdateUrl].toString(),
-            connectivityMonitor_.get(),
+            connectivityMonitor_,
             runOptions_[Option::Debug].toBool(),
             runOptions_[Option::MuteDaemon].toBool());
 
@@ -171,7 +170,7 @@ MainApplication::init()
     }
 #endif
 
-    connect(connectivityMonitor_.get(), &ConnectivityMonitor::connectivityChanged, this, [this] {
+    connect(connectivityMonitor_, &ConnectivityMonitor::connectivityChanged, this, [this] {
         QTimer::singleShot(500, this, [&]() { lrcInstance_->connectivityChanged(); });
     });
 
@@ -350,16 +349,15 @@ MainApplication::initQmlLayer()
 {
     // Expose custom types to the QML engine.
     Utils::registerTypes(engine_.get(),
-                         systemTray_.get(),
                          lrcInstance_.get(),
-                         settingsManager_.get(),
-                         connectivityMonitor_.get(),
+                         systemTray_,
+                         settingsManager_,
+                         connectivityMonitor_,
                          &screenInfo_,
                          this);
 
     auto videoProvider = new VideoProvider(lrcInstance_->avModel(), this);
     engine_->rootContext()->setContextProperty("videoProvider", videoProvider);
-    engine_->rootContext()->setContextProperty("pttListener", listener_);
 
     engine_->load(QUrl(QStringLiteral("qrc:/MainApplicationWindow.qml")));
     qWarning().noquote() << "Main window loaded using" << getRenderInterfaceString();
@@ -385,7 +383,7 @@ MainApplication::initSystray()
     QAction* restoreAction = new QAction(tr("&Show Jami"), this);
     connect(restoreAction, &QAction::triggered, this, &MainApplication::restoreApp);
 
-    connect(systemTray_.get(),
+    connect(systemTray_,
             &QSystemTrayIcon::activated,
             this,
             [this](QSystemTrayIcon::ActivationReason reason) {
@@ -424,4 +422,3 @@ MainApplication::setEventFilter()
 {
     installEventFilter(this);
 }
-
diff --git a/src/app/mainapplication.h b/src/app/mainapplication.h
index 41159fc5239e455e2e01d3aaf77505f90621517b..8f0f9952b16a9c11438b2a943ef348018601cb65 100644
--- a/src/app/mainapplication.h
+++ b/src/app/mainapplication.h
@@ -20,10 +20,8 @@
 
 #pragma once
 
-#include "imagedownloader.h"
 #include "lrcinstance.h"
 #include "qtutils.h"
-#include "pttlistener.h"
 
 #include <QFile>
 #include <QApplication>
@@ -37,7 +35,6 @@
 class ConnectivityMonitor;
 class AppSettingsManager;
 class SystemTray;
-class CallAdapter;
 
 // Provides information about the screen the app is displayed on
 class ScreenInfo : public QObject
@@ -116,15 +113,14 @@ private:
 private:
     std::map<Option, QVariant> runOptions_;
 
+    // We want to be explicit about the destruction order of these objects
     QScopedPointer<QQmlApplicationEngine> engine_;
     QScopedPointer<LRCInstance> lrcInstance_;
 
-    QScopedPointer<ConnectivityMonitor> connectivityMonitor_;
-    QScopedPointer<AppSettingsManager> settingsManager_;
-    QScopedPointer<SystemTray> systemTray_;
-    QScopedPointer<ImageDownloader> imageDownloader_;
-
-    PTTListener* listener_;
+    // These are injected into the QML layer along with our LRCInstance
+    ConnectivityMonitor* connectivityMonitor_;
+    SystemTray* systemTray_;
+    AppSettingsManager* settingsManager_;
 
     ScreenInfo screenInfo_;
 
diff --git a/src/app/platform/windows/pttlistener.cpp b/src/app/platform/windows/pttlistener.cpp
index 20c5b77cb43a4af3ec94a520a3e999ef5d8ab0d7..c6d6511b56afd26e8c32c8c88a6da6c6298940ec 100644
--- a/src/app/platform/windows/pttlistener.cpp
+++ b/src/app/platform/windows/pttlistener.cpp
@@ -80,13 +80,12 @@ public:
     HHOOK keyboardHook;
 
     static quint32 qtKeyToVKey(Qt::Key key);
-
 };
 
 PTTListener::PTTListener(AppSettingsManager* settingsManager, QObject* parent)
-    : settingsManager_(settingsManager)
-    , QObject(parent)
+    : QObject(parent)
     , pimpl_(std::make_unique<Impl>(this))
+    , settingsManager_(settingsManager)
 {}
 
 PTTListener::~PTTListener() = default;
@@ -294,7 +293,7 @@ PTTListener::Impl::qtKeyToVKey(Qt::Key key)
         return 'Z';
 
     default:
-        //Try to get virtual key from current keyboard layout or US.
+        // Try to get virtual key from current keyboard layout or US.
         const HKL layout = GetKeyboardLayout(0);
         int vk = VkKeyScanEx(key, layout);
         if (vk == -1) {
@@ -305,5 +304,4 @@ PTTListener::Impl::qtKeyToVKey(Qt::Key key)
     }
 }
 
-
-#include "pttlistener.moc"
\ No newline at end of file
+#include "pttlistener.moc"
diff --git a/src/app/pttlistener.h b/src/app/pttlistener.h
index 4f527896a5dd7d89ed306e6acd40cfe56ff920d6..71d773f5d814b821a6889e580762c60925c5146e 100644
--- a/src/app/pttlistener.h
+++ b/src/app/pttlistener.h
@@ -1,6 +1,5 @@
 #pragma once
 
-#include "systemtray.h"
 #include "appsettingsmanager.h"
 
 #include <QObject>
@@ -23,6 +22,7 @@ public:
     {
         return QKeySequence(key).toString();
     }
+
     Q_INVOKABLE void setPttKey(Qt::Key key)
     {
         settingsManager_->setValue(Settings::Key::pttKey, key);
@@ -48,5 +48,6 @@ public Q_SLOTS:
 private:
     class Impl;
     std::unique_ptr<Impl> pimpl_;
+
     AppSettingsManager* settingsManager_;
 };
diff --git a/src/app/settingsview/components/CallSettingsPage.qml b/src/app/settingsview/components/CallSettingsPage.qml
index a07fa7ea4002c585ad814cf1bd3ba08f0a316cce..7f0d8bed0895b12b95f9ec45f40bb616ebc01cc9 100644
--- a/src/app/settingsview/components/CallSettingsPage.qml
+++ b/src/app/settingsview/components/CallSettingsPage.qml
@@ -34,7 +34,7 @@ SettingsPageBase {
 
     property bool isSIP: CurrentAccount.type === Profile.Type.SIP
     property int itemWidth: 132
-    property string key: pttListener.keyToString(pttListener.getCurrentKey())
+    property string key: PttListener.keyToString(PttListener.getCurrentKey())
     title: JamiStrings.callSettingsTitle
 
     function updateAndShowModeratorsSlot() {
@@ -437,7 +437,7 @@ SettingsPageBase {
                     onClicked: {
                         var dlg = viewCoordinator.presentDialog(appWindow, "commoncomponents/ChangePttKeyPopup.qml");
                         dlg.choiceMade.connect(function (chosenKey) {
-                             keyLabel.text = pttListener.keyToString(chosenKey);
+                             keyLabel.text = PttListener.keyToString(chosenKey);
                         });
                     }
                 }
diff --git a/src/app/systemtray.h b/src/app/systemtray.h
index 5b8fc0dd8d3153ea6fe4e372d9e5e1eefcb22941..219ac94fbdf1937f20ba5393bf6b44f51e0c536f 100644
--- a/src/app/systemtray.h
+++ b/src/app/systemtray.h
@@ -37,11 +37,6 @@ public:
     explicit SystemTray(AppSettingsManager* settingsManager, QObject* parent = nullptr);
     ~SystemTray();
 
-    AppSettingsManager* getSettingsManager()
-    {
-        return settingsManager_;
-    }
-
     void onNotificationCountChanged(int count);
 #ifdef Q_OS_LINUX
     bool hideNotification(const QString& id);