diff --git a/src/app/LayoutManager.qml b/src/app/LayoutManager.qml
index 774389766e9de3a46cfc28c0489bd657c43801f0..cb2b7f7d9a7d65181fccbcb28a41db25529d437b 100644
--- a/src/app/LayoutManager.qml
+++ b/src/app/LayoutManager.qml
@@ -126,7 +126,7 @@ QtObject {
     // Adds an item to the fullscreen item stack. Automatically puts
     // the main window in fullscreen mode if needed. Callbacks should be used
     // to perform component-specific tasks upon successful transitions.
-    function pushFullScreenItem(item, originalParent, pushedCb, removedCb) {
+    function pushFullScreenItem(item, prevParent, pushedCb, removedCb) {
         if (item === null || item === undefined
                 || priv.fullScreenItems.length >= 3) {
             return
@@ -138,10 +138,12 @@ QtObject {
         // Add the item to our list and reparent it to appContainer.
         priv.fullScreenItems.push({
                                  "item": item,
-                                 "originalParent": originalParent,
+                                 "prevParent": prevParent,
+                                 "prevAnchorsFill": item.anchors.fill,
                                  "removedCb": removedCb
                              })
         item.parent = appContainer
+        item.anchors.fill = item.parent
         if (pushedCb) {
             pushedCb()
         }
@@ -164,7 +166,8 @@ QtObject {
         }
         if (obj !== undefined) {
             if (obj.item !== appWindow) {
-                obj.item.parent = obj.originalParent
+                obj.item.anchors.fill = obj.prevAnchorsFill
+                obj.item.parent = obj.prevParent
                 if (obj.removedCb) {
                     obj.removedCb()
                 }
diff --git a/src/app/MainApplicationWindow.qml b/src/app/MainApplicationWindow.qml
index a64ea58265fdcd654b9a1700f38dcab94a55ea88..74bba482895f603d16d9b514db75dcba6b0e4896 100644
--- a/src/app/MainApplicationWindow.qml
+++ b/src/app/MainApplicationWindow.qml
@@ -51,6 +51,16 @@ ApplicationWindow {
     property LayoutManager layoutManager: LayoutManager {
         appContainer: appContainer
     }
+    property ViewCoordinator viewCoordinator: ViewCoordinator {
+        resources: {
+            "WelcomePage": "mainview/components/WelcomePage.qml",
+            "SidePanel": "mainview/components/SidePanel.qml",
+            "ConversationView": "mainview/ConversationView.qml",
+            "NewSwarmPage": "mainview/components/NewSwarmPage.qml",
+            "WizardView": "wizardview/WizardView.qml",
+            "SettingsView": "settingsview/SettingsView.qml",
+        }
+    }
 
     property bool windowSettingsLoaded: false
     property bool allowVisibleWindow: true
@@ -85,6 +95,7 @@ ApplicationWindow {
                 !UtilsAdapter.getAccountListSize()) {
             // Save the window geometry and state before quitting.
             layoutManager.saveWindowSettings()
+            viewCoordinator.dismissAll()
             Qt.quit()
         } else {
             layoutManager.closeToTray()
@@ -105,10 +116,6 @@ ApplicationWindow {
         anchors.fill: parent
     }
 
-    DaemonReconnectPopup {
-        id: daemonReconnectPopup
-    }
-
     Loader {
         id: mainApplicationLoader
 
@@ -117,7 +124,14 @@ ApplicationWindow {
 
         asynchronous: true
         visible: status == Loader.Ready
-        source: ""
+
+        Connections {
+            target: viewCoordinator
+
+            function onRequestAppWindowWizardView() {
+                mainApplicationLoader.setSource(JamiQmlUtils.wizardViewLoadPath)
+            }
+        }
 
         Connections {
             target: mainApplicationLoader.item
@@ -149,6 +163,13 @@ ApplicationWindow {
                 // Main window, load any valid app settings, and allow the
                 // layoutManager to handle as much as possible.
                 layoutManager.restoreWindowSettings()
+
+                // Present the welcome view once the viewCoordinator is setup.
+                viewCoordinator.initialized.connect(function() {
+                    viewCoordinator.present("WelcomePage")
+                })
+                // Set the viewCoordinator's root item.
+                viewCoordinator.setRootView(item)
             }
             if (Qt.platform.os.toString() === "osx") {
                 MainApplication.setEventFilter()
@@ -206,14 +227,11 @@ ApplicationWindow {
         ignoreUnknownSignals: true
 
         function onShowDaemonReconnectPopup(visible) {
-            if (visible)
-                daemonReconnectPopup.open()
-            else
-                daemonReconnectPopup.close()
-        }
-
-        function onDaemonReconnectFailed() {
-            daemonReconnectPopup.connectionFailed = true
+            if (visible) {
+                viewCoordinator.presentDialog(
+                            appWindow,
+                            "commoncomponents/DaemonReconnectPopup.qml")
+            }
         }
     }
 
diff --git a/src/app/ViewCoordinator.qml b/src/app/ViewCoordinator.qml
new file mode 100644
index 0000000000000000000000000000000000000000..d924ccf9da16b34a6298a701907e2f3d906675c5
--- /dev/null
+++ b/src/app/ViewCoordinator.qml
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2023 Savoir-faire Linux Inc.
+ *
+ * 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/>.
+ */
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import net.jami.Constants 1.1
+import net.jami.Models 1.1
+
+// This object should be implemented as a QML singleton, or be instantiated
+// once in the main application window component. The top-level application window
+// contains a loader[mainview, wizardview] and "rootView" MUST parent a horizontal
+// SplitView with a StackView in each pane.
+QtObject {
+    id: root
+
+    signal requestAppWindowWizardView
+
+    // A map of view names to file paths for QML files that define each view.
+    required property variant resources
+
+    // Maybe this state needs to be toggled because the SidePanel content is replaced.
+    // This makes it so the state can't be inferred from loaded views in single pane mode.
+    property bool inSettings: viewManager.hasView("SettingsView")
+    property bool inNewSwarm: viewManager.hasView("NewSwarmPage")
+
+    property bool busy: false
+
+    // The `main` view of the application window.
+    property Item rootView: null
+
+    // HACKS.
+    property real mainViewWidth: rootView ? rootView.width : 0
+    property real previousWidth: mainViewWidth
+    property real mainViewSidePanelRectWidth: sv1 ? sv1.width : 0
+    property real lastSideBarSplitSize: mainViewSidePanelRectWidth
+    onMainViewWidthChanged: resolvePanes()
+
+    function resolvePanes(force=false) {
+        if (forceSinglePane) return
+        const isExpanding = previousWidth < mainViewWidth
+        if (mainViewWidth < JamiTheme.chatViewHeaderMinimumWidth + mainViewSidePanelRectWidth
+                && sv2.visible && (!isExpanding || force)) {
+            lastSideBarSplitSize = mainViewSidePanelRectWidth
+            singlePane = true
+        } else if (mainViewWidth >= lastSideBarSplitSize + JamiTheme.chatViewHeaderMinimumWidth
+                   && !sv2.visible && (isExpanding || force) && !layoutManager.isFullScreen) {
+            singlePane = false
+        }
+        previousWidth = mainViewWidth
+    }
+
+    // Must be the child of `rootView`.
+    property Item splitView: null
+
+    // StackView objects, which are children of `splitView`.
+    property StackView sv1: null
+    property StackView sv2: null
+
+    // The StackView object that is currently active, determined by the value
+    // of singlePane.
+    readonly property StackView activeStackView: singlePane ? sv1 : sv2
+
+    readonly property string currentViewName: {
+        if (activeStackView == null || activeStackView.depth === 0) return ''
+        return activeStackView.currentItem.objectName
+    }
+
+    readonly property var currentView: {
+        return activeStackView ? activeStackView.currentItem : null
+    }
+
+    // Handle single/dual pane mode.
+    property bool forceSinglePane: false
+    property bool singlePane
+    onForceSinglePaneChanged: {
+        if (forceSinglePane) singlePane = true
+        else resolvePanes(true)
+    }
+
+    onSinglePaneChanged: {
+        // Hiding sv2 before moving items from, and after moving
+        // items to, reduces stack item visibility change events.
+        if (singlePane) {
+            sv2.visible = false
+            if (forceSinglePane) Qt.callLater(move, sv2, sv1)
+            else move(sv2, sv1)
+        } else {
+            move(sv1, sv2)
+            sv2.visible = true
+        }
+    }
+
+    // Emitted once at the end of setRootView.
+    signal initialized()
+
+    // Create, present, and return a dialog object.
+    function presentDialog(parent, path, props={}) {
+        // Open the dialog once the object is created
+        return viewManager.createView(path, parent, function(obj) {
+            const doneCb = function() { viewManager.destroyView(path) }
+            if (obj.closed !== undefined) {
+                obj.closed.connect(doneCb)
+            } else {
+                if (obj.accepted !== undefined) { obj.accepted.connect(doneCb) }
+                if (obj.rejected !== undefined) { obj.rejected.connect(doneCb) }
+            }
+            obj.open()
+        }, props)
+    }
+
+    // Dismiss all views.
+    function dismissAll() {
+        for (var path in viewManager.views) {
+            viewManager.destroyView(path)
+        }
+    }
+
+    // Get a view regardless of whether it is currently active.
+    function getView(viewName) {
+        if (!viewManager.hasView(viewName)) {
+            return null
+        }
+        return viewManager.views[viewManager.viewPaths[viewName]]
+    }
+
+    // A private object used to manage the lifecycle of views.
+    property QtObject viewManager: QtObject {
+        id: viewManager
+
+        // A map of path strings to view objects.
+        property variant views: ({})
+        // A map of view names to path strings.
+        property variant viewPaths: ({})
+        // The number of views.
+        property int nViews: 0
+
+        function createView(path, parent=null, cb=null, props={}) {
+            if (views[path] !== undefined) {
+                // an instance of <path> already exists
+                return views[path]
+            }
+
+            const component = Qt.createComponent(Qt.resolvedUrl(path))
+            if (component.status === Component.Ready) {
+                const obj = component.createObject(parent, props)
+                if (obj === null) {
+                    print("error creating object")
+                    return null
+                }
+                views[path] = obj
+                // Set the view name to the object name if it has one.
+                const viewName = obj.objectName.toString() !== '' ?
+                            obj.objectName :
+                            path.replace(/^.*[\\\/]/, '').replace(/\.[^/.]+$/, "")
+                viewPaths[viewName] = path
+                nViews = Object.keys(views).length
+                if (cb !== null) {
+                    cb(obj)
+                }
+                return views[path]
+            }
+            print("error creating component", path)
+            console.error(component.errorString())
+            Qt.exit(1)
+            return null
+        }
+
+        function destroyView(path) {
+            if (views[path] === undefined) {
+                print(path, "instance does not exist", Object.keys(views))
+                return false
+            }
+            views[path].destroy()
+            views[path] = undefined
+            // QObject::destroy is queued, and we can't connect to its completion,
+            // so we queue the resulting mutation to our view storage.
+            Qt.callLater(function() {
+                delete views[path]
+                // Remove the view name from the viewPaths map.
+                for (var viewName in viewPaths) {
+                    if (viewPaths[viewName] === path) {
+                        delete viewPaths[viewName]
+                        break
+                    }
+                }
+                nViews = Object.keys(views).length
+            })
+            return true
+        }
+
+        function hasView(viewName) {
+            return nViews && viewPaths[viewName] !== undefined
+        }
+    }
+
+    // Sets object references, onInitialized is a good time to present views.
+    function setRootView(obj) {
+        rootView = obj
+        splitView = rootView.splitView
+        sv1 = rootView.sv1
+        sv1.parent = Qt.binding(() => singlePane ? rootView : splitView)
+        sv1.anchors.fill = Qt.binding(() => singlePane ? rootView : undefined)
+        sv2 = rootView.sv2
+
+        initialized()
+        resolvePanes()
+    }
+
+    // Finds a view and gets its index within the StackView it's in.
+    function getStackIndex(viewName) {
+        for (const [key, value] of Object.entries(viewManager.views)) {
+            if (value.objectName === viewName) {
+                return value.StackView.index
+            }
+        }
+        return -1
+    }
+
+    // This function presents the view with the given viewName in the
+    // specified StackView. Return the view if successful.
+    function present(viewName, sv=activeStackView) {
+        if (!rootView) return
+
+        // If the view already exists in the StackView, the function will attempt
+        // to navigate to its StackView position by dismissing elevated views.
+        if (sv.find(function(item) {
+            return item.objectName === viewName;
+        })) {
+            const viewIndex = getStackIndex(viewName)
+            if (viewIndex >= 0) {
+                for (var i = (sv.depth - 1); i > viewIndex; i--) {
+                    dismissObj(sv.get(i, StackView.DontLoad))
+                }
+                return true
+            }
+            return false
+        }
+
+        // If we are in single-pane mode and the view was previously forced into
+        // sv2, we can move it back to the top of sv1.
+        if (singlePane && sv === sv1) {
+            // See if the item is at the top of sv2
+            if (sv2.currentItem && sv2.currentItem.objectName === viewName) {
+                // Move it to the top of sv1
+                const view = sv2.pop(StackView.Immediate)
+                sv1.push(view, StackView.Immediate)
+                view.presented()
+                return view
+            }
+        }
+
+        const obj = viewManager.createView(resources[viewName], appWindow)
+        if (!obj) {
+            print("could not create view:", viewName)
+            return null
+        }
+        if (obj === currentView) {
+            print("view is current:", viewName)
+            return null
+        }
+
+        // If we are in single-pane mode and the view should start hidden
+        // (requiresIndex), we can push it into sv2.
+        if (singlePane && sv === sv1 && obj.requiresIndex) {
+            sv = sv2
+        } else {
+            forceSinglePane = obj.singlePaneOnly
+        }
+
+        const view = sv.push(obj, StackView.Immediate)
+        if (!view) {
+            return null
+        }
+        if (view.objectName === '') {
+            view.objectName = viewName
+        }
+        view.presented()
+        return view
+    }
+
+    // Dismiss by object.
+    function dismissObj(obj, sv=activeStackView) {
+        if (obj.StackView.view !== sv) {
+            print("view not in the stack:", obj)
+            return
+        }
+
+        // If we are dismissing a view that is not at the top of the stack,
+        // we need to store each of the views on top into a temporary stack
+        // and then restore them after the view is dismissed.
+        // So we get the index of the view we are dismissing.
+        const viewIndex = obj.StackView.index
+        var tempStack = []
+        for (var i = (sv.depth - 1); i > viewIndex; i--) {
+            var item = sv.pop(StackView.Immediate)
+            tempStack.push(item)
+        }
+        // And we define a function to restore and resolve the views.
+        var resolveStack = () => {
+            for (var i = 0; i < tempStack.length; i++) {
+                sv.push(tempStack[i], StackView.Immediate)
+            }
+
+            forceSinglePane = sv.currentItem.singlePaneOnly
+            sv.currentItem.presented()
+        }
+
+        // Now we can dismiss the view at the top of the stack.
+        const depth = sv.depth
+        if (obj === sv.get(depth - 1, StackView.DontLoad)) {
+            var view = sv.pop(StackView.Immediate)
+            if (!view) {
+                print("could not pop view:", obj.objectName)
+                resolveStack()
+                return
+            }
+
+            // If the view is managed, we can destroy it, otherwise, it can
+            // be reused and destroyed by it's parent.
+            if (view.managed) {
+                var objectName = view ? view.objectName : obj.objectName
+                if (!viewManager.destroyView(resources[objectName])) {
+                    print("could not destroy view:", objectName)
+                }
+            } else {
+                view.dismissed()
+            }
+        }
+        resolveStack()
+    }
+
+    // Dismiss by view name.
+    function dismiss(viewName) {
+        const depth = activeStackView.depth
+        for (var i = (depth - 1); i >= 0; i--) {
+            const view = activeStackView.get(i, StackView.DontLoad)
+            if (view.objectName === viewName) {
+                dismissObj(view)
+                return
+            }
+        }
+
+        // Check if the view is hidden on the top of sv2 (if in single-pane mode),
+        // and dismiss it in that case.
+        if (singlePane && sv2.currentItem && sv2.currentItem.objectName === viewName) {
+            dismissObj(sv2.currentItem, sv2)
+        }
+    }
+
+    // Move items from one stack to another. We avoid the recursive technique to
+    // avoid  visibility change events.
+    function move(from, to, depth=1) {
+        busy = true
+        var tempStack = []
+        while (from.depth > depth) {
+            var item = from.pop(StackView.Immediate)
+            tempStack.push(item)
+        }
+        while (tempStack.length) {
+            to.push(tempStack.pop(), StackView.Immediate)
+        }
+        busy = false
+    }
+
+    // Effectively hide the current view by moving it to the other StackView.
+    // This function only works when in single-pane mode.
+    function hideCurrentView() {
+        if (singlePane) move(sv1, sv2)
+    }
+}
diff --git a/src/app/accountadapter.cpp b/src/app/accountadapter.cpp
index 66ec7625971cb18ed7dea8fd33136b16e6c4d137..c48aac2f87d4995d1fec2314a6185c78d97835db 100644
--- a/src/app/accountadapter.cpp
+++ b/src/app/accountadapter.cpp
@@ -327,23 +327,6 @@ AccountAdapter::getDefaultModerators(const QString& accountId)
     return lrcInstance_->accountModel().getDefaultModerators(accountId);
 }
 
-bool
-AccountAdapter::hasPassword()
-{
-    auto confProps = lrcInstance_->accountModel().getAccountConfig(
-        lrcInstance_->get_currentAccountId());
-    return confProps.archiveHasPassword;
-}
-
-void
-AccountAdapter::setArchiveHasPassword(bool isHavePassword)
-{
-    auto confProps = lrcInstance_->accountModel().getAccountConfig(
-        lrcInstance_->get_currentAccountId());
-    confProps.archiveHasPassword = isHavePassword;
-    lrcInstance_->accountModel().setAccountConfig(lrcInstance_->get_currentAccountId(), confProps);
-}
-
 bool
 AccountAdapter::exportToFile(const QString& accountId,
                              const QString& path,
diff --git a/src/app/accountadapter.h b/src/app/accountadapter.h
index 8b141983555c2ae098602238097c36b3580a5f0a..8b474941677dcf80ee1b8b781e89345bdd9bb43d 100644
--- a/src/app/accountadapter.h
+++ b/src/app/accountadapter.h
@@ -50,8 +50,6 @@ public:
                             QObject* parent = nullptr);
     ~AccountAdapter() = default;
 
-    void safeInit() override {}
-
     // Change to account corresponding to combox box index.
     Q_INVOKABLE void changeAccount(int row);
 
@@ -64,8 +62,6 @@ public:
     Q_INVOKABLE void deleteCurrentAccount();
 
     // Conf property
-    Q_INVOKABLE bool hasPassword();
-    Q_INVOKABLE void setArchiveHasPassword(bool isHavePassword);
     Q_INVOKABLE bool exportToFile(const QString& accountId,
                                   const QString& path,
                                   const QString& password = {}) const;
diff --git a/src/app/avadapter.h b/src/app/avadapter.h
index 23fdd18a57b0d66c234afc715f33b67f20fb03c6..641dfc27ae82929c5f462f4673eb82571e7b297a 100644
--- a/src/app/avadapter.h
+++ b/src/app/avadapter.h
@@ -50,8 +50,6 @@ Q_SIGNALS:
     void audioDeviceListChanged(int inputs, int outputs);
 
 protected:
-    void safeInit() override {};
-
     /**
      * Check if user is sharing a media
      */
@@ -89,7 +87,9 @@ protected:
     Q_INVOKABLE void shareWindow(const QString& windowProcessId, const QString& windowId);
 
     // Returns the screensharing resource
-    Q_INVOKABLE QString getSharingResource(int screenId = -2, const QString& windowProcessId = "", const QString& key = "");
+    Q_INVOKABLE QString getSharingResource(int screenId = -2,
+                                           const QString& windowProcessId = "",
+                                           const QString& key = "");
 
     Q_INVOKABLE void getListWindows();
 
diff --git a/src/app/calladapter.h b/src/app/calladapter.h
index 84b93c94459fe76a306ac609f212427a69e6e039..ff1112bc99cd30f9184553ade9427bd071053066 100644
--- a/src/app/calladapter.h
+++ b/src/app/calladapter.h
@@ -49,9 +49,6 @@ public:
     explicit CallAdapter(SystemTray* systemTray, LRCInstance* instance, QObject* parent = nullptr);
     ~CallAdapter() = default;
 
-protected:
-    void safeInit() override {};
-
 public:
     Q_INVOKABLE void startTimerInformation();
     Q_INVOKABLE void stopTimerInformation();
diff --git a/src/app/calloverlaymodel.cpp b/src/app/calloverlaymodel.cpp
index ea7b04aa2521d5f78f9780538fa94950e71a22fa..dd1ee9c9e041fca6efa9107f7e7fd3eff2eda33b 100644
--- a/src/app/calloverlaymodel.cpp
+++ b/src/app/calloverlaymodel.cpp
@@ -54,7 +54,9 @@ PendingConferenceesListModel::PendingConferenceesListModel(LRCInstance* instance
     , lrcInstance_(instance)
 {
     connectSignals();
-    connect(lrcInstance_, &LRCInstance::currentAccountIdChanged, [this]() { connectSignals(); });
+    connect(lrcInstance_, &LRCInstance::currentAccountIdChanged, this, [this]() {
+        connectSignals();
+    });
 }
 
 int
@@ -128,10 +130,14 @@ PendingConferenceesListModel::connectSignals()
         return;
 
     using namespace PendingConferences;
-    callsStatusChanged_
-        = connect(currentCallModel, &CallModel::callStatusChanged, [this](const QString&, int) {
-              Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1), {Role::CallStatus});
-          });
+    callsStatusChanged_ = connect(currentCallModel,
+                                  &CallModel::callStatusChanged,
+                                  this,
+                                  [this](const QString&, int) {
+                                      Q_EMIT dataChanged(index(0, 0),
+                                                         index(rowCount() - 1),
+                                                         {Role::CallStatus});
+                                  });
 
     beginInsertPendingConferencesRows_ = connect(
         currentCallModel,
diff --git a/src/app/commoncomponents/BaseView.qml b/src/app/commoncomponents/BaseView.qml
new file mode 100644
index 0000000000000000000000000000000000000000..cdd51ce9ca91178f08fdf78d59b0f030068da3b0
--- /dev/null
+++ b/src/app/commoncomponents/BaseView.qml
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 Savoir-faire Linux Inc.
+ *
+ * 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/>.
+ */
+
+import QtQuick
+
+Rectangle {
+    id: viewNode
+
+    // True if this view is managed by the view coordinator.
+    // False if this view is managed by its parent view, and will
+    // only be destroyed when its parent is destroyed.
+    property bool managed: true
+
+    // True if this view functions in a single-pane context only.
+    property bool singlePaneOnly: false
+
+    // True if this view requires and initial selection from
+    // a group of menu options when in single-pane mode (e.g. settings).
+    property bool requiresIndex: false
+
+    function dismiss() { viewCoordinator.dismiss(objectName) }
+
+    signal presented
+    signal dismissed
+
+    Component.onCompleted: { if (managed) presented() }
+    Component.onDestruction: { if (managed) dismissed() }
+}
diff --git a/src/app/commoncomponents/ConfirmDialog.qml b/src/app/commoncomponents/ConfirmDialog.qml
index 535b11d205a8f0d7f6b74a751fc2d11de54d2186..2a2acb1e490c27fb0e9c5405c9ca0d1f7af4c708 100644
--- a/src/app/commoncomponents/ConfirmDialog.qml
+++ b/src/app/commoncomponents/ConfirmDialog.qml
@@ -29,11 +29,13 @@ BaseModalDialog {
 
     signal accepted
 
-    width: Math.min(mainView.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogWidth)
-    height: Math.min(mainView.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogHeight)
+    width: Math.min(appWindow.width - 2 * JamiTheme.preferredMarginSize,
+                    JamiTheme.preferredDialogWidth)
+    height: Math.min(appWindow.height - 2 * JamiTheme.preferredMarginSize,
+                     JamiTheme.preferredDialogHeight)
 
-    property var confirmLabel: ""
-    property var textLabel: ""
+    property string confirmLabel: ""
+    property string textLabel: ""
 
     popupContent: ColumnLayout {
         id: column
diff --git a/src/app/commoncomponents/DaemonReconnectPopup.qml b/src/app/commoncomponents/DaemonReconnectPopup.qml
index d777c27667c1bf112e57efb1ed46aa27546c3025..df4299b179d97d4e5d00e454373259e88a77bcf2 100644
--- a/src/app/commoncomponents/DaemonReconnectPopup.qml
+++ b/src/app/commoncomponents/DaemonReconnectPopup.qml
@@ -31,6 +31,26 @@ BaseModalDialog {
 
     autoClose: false
 
+    Connections {
+        target: {
+            if (Qt.platform.os.toString()  !== "windows" && Qt.platform.os.toString()  !== "osx")
+                return DBusErrorHandler
+            return null
+        }
+        ignoreUnknownSignals: true
+
+        function onShowDaemonReconnectPopup(visible) {
+            if (!visible) {
+                viewCoordinator.dismiss(this)
+            }
+        }
+
+        function onDaemonReconnectFailed() {
+            connectionFailed = true
+        }
+    }
+
+
     onPopupContentLoadStatusChanged: {
         if (popupContentLoadStatus === Loader.Ready) {
             root.height = Qt.binding(function() {
diff --git a/src/app/commoncomponents/DeleteAccountDialog.qml b/src/app/commoncomponents/DeleteAccountDialog.qml
index 987f719c2e1f3821fafa9c259c96f4948fea8e99..a4c2b54113002b96e0817f2b4e373824bb0422c3 100644
--- a/src/app/commoncomponents/DeleteAccountDialog.qml
+++ b/src/app/commoncomponents/DeleteAccountDialog.qml
@@ -35,8 +35,8 @@ BaseModalDialog {
 
     title: JamiStrings.deleteAccount
 
-    width: Math.min(mainView.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogWidth)
-    height: Math.min(mainView.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogHeight)
+    width: Math.min(appWindow.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogWidth)
+    height: Math.min(appWindow.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogHeight)
 
     popupContent: ColumnLayout {
         id: deleteAccountContentColumnLayout
diff --git a/src/app/commoncomponents/JamiFileDialog.qml b/src/app/commoncomponents/JamiFileDialog.qml
index 8306aace41fe8cbd2ef2f320259837a8a78cfe32..611dc765f419ff3eb50dc85f1345a29e46e01335 100644
--- a/src/app/commoncomponents/JamiFileDialog.qml
+++ b/src/app/commoncomponents/JamiFileDialog.qml
@@ -27,6 +27,17 @@ FileDialog {
     // Use enum to avoid importing Qt.labs.platform when using JamiFileDialog.
     property int mode: JamiFileDialog.Mode.OpenFile
 
+    signal fileAccepted(string file)
+    signal filesAccepted(var files)
+
+    onAccepted: {
+        switch(fileMode) {
+        case FileDialog.OpenFile: fileAccepted(file); break
+        case FileDialog.OpenFiles: filesAccepted(files); break
+        default: fileAccepted(file)
+        }
+    }
+
     enum Mode {
         OpenFile = 0,
         OpenFiles,
diff --git a/src/app/commoncomponents/LocalVideo.qml b/src/app/commoncomponents/LocalVideo.qml
index 2e7067fad87cb460c1aa4be35d7cf7639b48dc8a..d657b54e0cd82709a7e87ca49b6fc9389205c672 100644
--- a/src/app/commoncomponents/LocalVideo.qml
+++ b/src/app/commoncomponents/LocalVideo.qml
@@ -28,7 +28,7 @@ VideoView {
     crop: true
 
     function startWithId(id, force = false) {
-        if (id.length === 0) {
+        if (id !== undefined && id.length === 0) {
             VideoDevices.stopDevice(rendererId)
             rendererId = id
         } else {
diff --git a/src/app/commoncomponents/PasswordDialog.qml b/src/app/commoncomponents/PasswordDialog.qml
index 5fb05edd3cbaebb550239607b72e5d1e913855ce..b0451b5849a7e3b4432939d3f9046a599123266d 100644
--- a/src/app/commoncomponents/PasswordDialog.qml
+++ b/src/app/commoncomponents/PasswordDialog.qml
@@ -35,17 +35,10 @@ BaseModalDialog {
     property string path: ""
     property int purpose: PasswordDialog.ChangePassword
 
-    signal doneSignal(bool success, int currentPurpose)
+    signal done(bool success, int purpose)
 
-    function openDialog(purposeIn, exportPathIn = "") {
-        purpose = purposeIn
-        path = exportPathIn
-
-        open()
-    }
-
-    width: Math.min(mainView.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogWidth)
-    height: Math.min(mainView.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogHeight)
+    width: Math.min(appWindow.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogWidth)
+    height: Math.min(appWindow.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogHeight)
 
     title: {
         switch(purpose){
@@ -58,6 +51,32 @@ BaseModalDialog {
         }
     }
 
+    function reportStatus(success) {
+        const title = success ? JamiStrings.success : JamiStrings.error
+        var info
+        switch(purpose) {
+            case PasswordDialog.ExportAccount:
+                info = success ? JamiStrings.backupSuccessful : JamiStrings.backupFailed
+                break
+            case PasswordDialog.ChangePassword:
+                info = success ? JamiStrings.changePasswordSuccess : JamiStrings.changePasswordFailed
+                break
+            case PasswordDialog.SetPassword:
+                info = success ? JamiStrings.setPasswordSuccess : JamiStrings.setPasswordFailed
+                break
+        }
+        viewCoordinator.presentDialog(
+                    appWindow,
+                    "commoncomponents/SimpleMessageDialog.qml",
+                    {
+                        title: title,
+                        infoText: info,
+                        buttonTitles: [JamiStrings.optionOk],
+                        buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue]
+                    })
+        done(success, purpose)
+    }
+
     popupContent: ColumnLayout {
         id: popupContentColumnLayout
 
@@ -86,20 +105,17 @@ BaseModalDialog {
                             path,
                             currentPasswordEdit.text)
             }
-            doneSignal(success, purpose)
+            reportStatus(success)
+
             close()
         }
 
         function savePasswordQML() {
-            var success = false
-            success = AccountAdapter.savePassword(
+            var success = AccountAdapter.savePassword(
                         LRCInstance.currentAccountId,
                         currentPasswordEdit.text,
                         passwordEdit.text)
-            if (success) {
-                AccountAdapter.setArchiveHasPassword(passwordEdit.text.length !== 0)
-            }
-            doneSignal(success, purpose)
+            reportStatus(success)
             close()
         }
 
diff --git a/src/app/commoncomponents/PhotoboothView.qml b/src/app/commoncomponents/PhotoboothView.qml
index b76875131657433a52a54510a80d64ef13080653..85105c4ca68c183702097accab9610ee611100d9 100644
--- a/src/app/commoncomponents/PhotoboothView.qml
+++ b/src/app/commoncomponents/PhotoboothView.qml
@@ -84,47 +84,6 @@ Item {
         }
     }
 
-    JamiFileDialog {
-        id: importFromFileDialog
-
-        objectName: "photoboothImportFromFileDialog"
-
-        mode: JamiFileDialog.OpenFile
-        title: JamiStrings.chooseAvatarImage
-        folder: StandardPaths.writableLocation(StandardPaths.PicturesLocation)
-
-        nameFilters: [
-            JamiStrings.imageFiles,
-            JamiStrings.allFiles
-        ]
-
-        onVisibleChanged: {
-            if (!visible) {
-                rejected()
-            }
-        }
-
-        onAccepted: {
-            if (importButton.focusAfterFileDialogClosed) {
-                importButton.focusAfterFileDialogClosed = false
-                importButton.forceActiveFocus()
-            }
-
-            var filePath = UtilsAdapter.getAbsPath(file)
-            if (!root.newItem)
-                AccountAdapter.setCurrentAccountAvatarFile(filePath)
-            else
-                UtilsAdapter.setTempCreationImageFromFile(filePath, root.imageId)
-        }
-
-        onRejected: {
-            if (importButton.focusAfterFileDialogClosed) {
-                importButton.focusAfterFileDialogClosed = false
-                importButton.forceActiveFocus()
-            }
-        }
-    }
-
     Rectangle {
         id: imageLayer
 
@@ -246,8 +205,6 @@ Item {
 
             objectName: "photoboothViewImportButton"
 
-            property bool focusAfterFileDialogClosed: false
-
             Layout.alignment: Qt.AlignHCenter
             visible: parent.visible
 
@@ -267,7 +224,6 @@ Item {
             Keys.onPressed: function (keyEvent) {
                 if (keyEvent.key === Qt.Key_Enter ||
                         keyEvent.key === Qt.Key_Return) {
-                    focusAfterFileDialogClosed = true
                     clicked()
                     keyEvent.accepted = true
                 } else if (keyEvent.key === Qt.Key_Down ||
@@ -282,11 +238,28 @@ Item {
             onClicked: {
                 stopBooth()
                 buttonsRowLayout.backToAvatar()
-                importFromFileDialog.open()
+                var dlg = viewCoordinator.presentDialog(
+                            appWindow,
+                            "commoncomponents/JamiFileDialog.qml",
+                            {
+                                title: JamiStrings.chooseAvatarImage,
+                                fileMode: JamiFileDialog.OpenFile,
+                                folder: StandardPaths.writableLocation(
+                                            StandardPaths.PicturesLocation),
+                                nameFilters: [JamiStrings.imageFiles,
+                                    JamiStrings.allFiles]
+                            })
+                dlg.fileAccepted.connect(function(file) {
+                    var filePath = UtilsAdapter.getAbsPath(file)
+                    if (!root.newItem) {
+                        AccountAdapter.setCurrentAccountAvatarFile(filePath)
+                    } else {
+                        UtilsAdapter.setTempCreationImageFromFile(filePath, root.imageId)
+                    }
+                })
             }
         }
 
-
         PushButton {
             id: clearButton
 
diff --git a/src/app/commoncomponents/PreferenceItemDelegate.qml b/src/app/commoncomponents/PreferenceItemDelegate.qml
index 244c49e4fa10c18abc495be05e40d73fdff02e35..609e70b3e57657fa01664ea2d7258a8547bf1c78 100644
--- a/src/app/commoncomponents/PreferenceItemDelegate.qml
+++ b/src/app/commoncomponents/PreferenceItemDelegate.qml
@@ -19,6 +19,7 @@
 import QtQuick
 import QtQuick.Controls
 import QtQuick.Layouts
+import Qt.labs.platform
 
 import net.jami.Models 1.1
 import net.jami.Adapters 1.1
@@ -53,10 +54,20 @@ ItemDelegate {
                 break
             case PreferenceItemListModel.PATH:
                 if (index === 0) {
-                    preferenceFilePathDialog.title = JamiStrings.selectAnImage.arg(preferenceName)
-                    preferenceFilePathDialog.nameFilters = fileFilters
-                    preferenceFilePathDialog.selectedNameFilter.index = fileFilters.length - 1
-                    preferenceFilePathDialog.open()
+                    var dlg = viewCoordinator.presentDialog(
+                                appWindow,
+                                "commoncomponents/JamiFileDialog.qml",
+                                {
+                                    title: JamiStrings.selectAnImage.arg(preferenceName),
+                                    fileMode: JamiFileDialog.OpenFile,
+                                    folder: JamiQmlUtils.qmlFilePrefix + currentPath,
+                                    nameFilters: fileFilters
+                                })
+                    dlg.fileAccepted.connect(function (file) {
+                        var url = UtilsAdapter.getAbsPath(file.toString())
+                        preferenceNewValue = url
+                        btnPreferenceClicked()
+                    })
                 }
                 else
                     btnPreferenceClicked()
@@ -74,19 +85,6 @@ ItemDelegate {
         }
     }
 
-    JamiFileDialog {
-        id: preferenceFilePathDialog
-
-        title: JamiStrings.selectFile
-        folder: JamiQmlUtils.qmlFilePrefix + currentPath
-
-        onAccepted: {
-            var url = UtilsAdapter.getAbsPath(file.toString())
-            preferenceNewValue = url
-            btnPreferenceClicked()
-        }
-    }
-
     RowLayout{
         anchors.fill: parent
 
diff --git a/src/app/commoncomponents/SBSMessageBase.qml b/src/app/commoncomponents/SBSMessageBase.qml
index a7e45f32e51a7e72d15e20fb1fbefeb4877f82d9..1914ef0667eba65e92f71393462902c896110932 100644
--- a/src/app/commoncomponents/SBSMessageBase.qml
+++ b/src/app/commoncomponents/SBSMessageBase.qml
@@ -187,7 +187,6 @@ Control {
                             messageOptionPopup.open()
                             messageOptionPopup.x = messageOptionPopup.setXposition(messageOptionPopup.width)
                             messageOptionPopup.y = messageOptionPopup.setYposition(messageOptionPopup.height)
-
                         }
                     }
 
@@ -246,7 +245,6 @@ Control {
                             emojiPicker.x = setXposition(JamiTheme.emojiPickerWidth)
                         messageOptionPopup.x = setXposition(width)
                         messageOptionPopup.y = setYposition(height)
-
                     }
 
                     Connections {
@@ -268,8 +266,9 @@ Control {
                                                                                  x: setXposition(JamiTheme.emojiPickerWidth),
                                                                                  y: setYposition(JamiTheme.emojiPickerHeight)
                                                                                 });
-                        messageOptionPopup.emojiPicker.open()
-                        if (messageOptionPopup.emojiPicker === null) {
+                        if (messageOptionPopup.emojiPicker !== null) {
+                            messageOptionPopup.emojiPicker.open()
+                        } else {
                             console.log("Error creating emojiPicker in SBSMessageBase");
                         }
                     }
@@ -292,14 +291,22 @@ Control {
                     }
 
                     function setYposition(height) {
-                        var mappedCoord = bubble.mapToItem(appWindow.contentItem,0, 0)
-                        var distBottomScreen = appWindow.height - mappedCoord.y - height - JamiQmlUtils.messageBarButtonsRowObj.height
+                        var bottomOffset = 0
+                        if (JamiQmlUtils.messageBarButtonsRowObj) {
+                            bottomOffset = JamiQmlUtils.messageBarButtonsRowObj.height
+                        }
+                        var mappedCoord = bubble.mapToItem(appWindow.contentItem, 0, 0)
+                        var distBottomScreen = appWindow.height - mappedCoord.y - height - bottomOffset
                         if (distBottomScreen < 0) {
                             return distBottomScreen
                         }
-                        var distTopScreen = mappedCoord.y - JamiQmlUtils.messagingHeaderRectRowLayout.height
+                        var topOffset = 0
+                        if (JamiQmlUtils.messagingHeaderRectRowLayout) {
+                            topOffset = JamiQmlUtils.messagingHeaderRectRowLayout.height
+                        }
+                        var distTopScreen = mappedCoord.y - topOffset
                         if (distTopScreen < 0)
-                            return - distTopScreen
+                            return -distTopScreen
                         return 0
                     }
                 }
diff --git a/src/app/commoncomponents/TextMessageDelegate.qml b/src/app/commoncomponents/TextMessageDelegate.qml
index 84e8eb9c6eb77612f31ae5db0f57f3aaa343ccd4..7b3f756c5a72d209deb572d2f2210cceb264a98b 100644
--- a/src/app/commoncomponents/TextMessageDelegate.qml
+++ b/src/app/commoncomponents/TextMessageDelegate.qml
@@ -46,12 +46,6 @@ SBSMessageBase {
     extraHeight: extraContent.active && !isRemoteImage ? msgRadius : -isRemoteImage
     textHovered: textHoverhandler.hovered
 
-    EditedPopup {
-        id: editedPopup
-
-        previousBodies: PreviousBodies
-    }
-
     innerContent.children: [
         TextEdit {
             id: textEditId
@@ -155,7 +149,10 @@ SBSMessageBase {
                 TapHandler {
                     acceptedButtons: Qt.LeftButton
                     onTapped: {
-                        editedPopup.open()
+                        viewCoordinator.presentDialog(
+                                    appWindow,
+                                    "commoncomponents/EditedPopup.qml",
+                                    {previousBodies: PreviousBodies})
                     }
                 }
             }
diff --git a/src/app/constant/JamiQmlUtils.qml b/src/app/constant/JamiQmlUtils.qml
index 22f487b084cb17245f0f5383c2083966be1cb9d9..fff14ba4398285422bb3a89e74f7d3d9f6f5eec3 100644
--- a/src/app/constant/JamiQmlUtils.qml
+++ b/src/app/constant/JamiQmlUtils.qml
@@ -53,6 +53,8 @@ Item {
     property point videoRecordMessageButtonInMainViewPoint
     property var emojiPickerButtonInMainViewPoint
 
+    signal settingsPageRequested(int index)
+
     function updateMessageBarButtonsPoints() {
         if (messageBarButtonsRowObj && audioRecordMessageButtonObj && videoRecordMessageButtonObj) {
             audioRecordMessageButtonInMainViewPoint =
diff --git a/src/app/contactadapter.h b/src/app/contactadapter.h
index 5058c1e75175284208843b273bdba8c4d28c137c..ebe49a3e4fd9f7a5d55fe91ad7a22da297ecbab9 100644
--- a/src/app/contactadapter.h
+++ b/src/app/contactadapter.h
@@ -57,7 +57,7 @@ public:
         filterPredicate_ = filterPredicate;
     }
 
-    virtual bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override
+    bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override
     {
         // Accept all contacts in conversation list filtered with account type, except those in a call.
         auto index = sourceModel()->index(sourceRow, 0, sourceParent);
@@ -86,8 +86,6 @@ public:
 
     using Role = ConversationList::Role;
 
-    void safeInit() override {}
-
     Q_INVOKABLE QVariant getContactSelectableModel(int type);
     Q_INVOKABLE void setSearchFilter(const QString& filter);
     Q_INVOKABLE void contactSelected(int index);
diff --git a/src/app/conversationlistmodel.h b/src/app/conversationlistmodel.h
index 8320d7aca3e8870ee1a89b2eb24b94acd045595a..8fd672048663e6fab8b74a15292cbebc984de51d 100644
--- a/src/app/conversationlistmodel.h
+++ b/src/app/conversationlistmodel.h
@@ -22,8 +22,6 @@
 #include "conversationlistmodelbase.h"
 #include "selectablelistproxymodel.h"
 
-#include "api/profile.h"
-
 #include <QSortFilterProxyModel>
 
 // A wrapper view model around ConversationModel's underlying data
diff --git a/src/app/conversationsadapter.cpp b/src/app/conversationsadapter.cpp
index 4cdd3344d0e171485034874ccc51ad99a239501e..8f7e035c25b22a59009295a6e4e19304d306d70b 100644
--- a/src/app/conversationsadapter.cpp
+++ b/src/app/conversationsadapter.cpp
@@ -19,7 +19,6 @@
 
 #include "conversationsadapter.h"
 
-#include "utils.h"
 #include "qtutils.h"
 #include "systemtray.h"
 #include "qmlregister.h"
@@ -49,7 +48,7 @@ ConversationsAdapter::ConversationsAdapter(SystemTray* systemTray,
         convModel_->setFilterRequests(filterRequests_);
     });
 
-    connect(lrcInstance_, &LRCInstance::selectedConvUidChanged, [this]() {
+    connect(lrcInstance_, &LRCInstance::selectedConvUidChanged, this, [this]() {
         auto convId = lrcInstance_->get_selectedConvUid();
         if (convId.isEmpty()) {
             // deselected
@@ -76,7 +75,7 @@ ConversationsAdapter::ConversationsAdapter(SystemTray* systemTray,
         }
     });
 
-    connect(lrcInstance_, &LRCInstance::draftSaved, [this](const QString& convId) {
+    connect(lrcInstance_, &LRCInstance::draftSaved, this, [this](const QString& convId) {
         auto row = lrcInstance_->indexOf(convId);
         const auto index = convSrcModel_->index(row, 0);
         Q_EMIT convSrcModel_->dataChanged(index, index);
@@ -103,13 +102,7 @@ ConversationsAdapter::ConversationsAdapter(SystemTray* systemTray,
                 accInfo.conversationModel->removeConversation(convUid);
             });
 #endif
-}
 
-void
-ConversationsAdapter::safeInit()
-{
-    // TODO: remove these safeInits, they are possibly called
-    // multiple times during qml component inits
     connect(&lrcInstance_->behaviorController(),
             &BehaviorController::newUnreadInteraction,
             this,
@@ -580,11 +573,14 @@ ConversationsAdapter::openDialogConversationWith(const QString& peerUri)
     lrcInstance_->selectConversation(convInfo.uid);
 }
 
-bool
+void
 ConversationsAdapter::connectConversationModel()
 {
     // Signal connections
     auto currentConversationModel = lrcInstance_->getCurrentConversationModel();
+    if (currentConversationModel == nullptr) {
+        return;
+    }
 
     QObject::connect(currentConversationModel,
                      &ConversationModel::modelChanged,
@@ -657,8 +653,6 @@ ConversationsAdapter::connectConversationModel()
     searchModel_->bindSourceModel(searchSrcModel_.get());
 
     updateConversationFilterData();
-
-    return true;
 }
 
 void
@@ -672,4 +666,4 @@ ConversationsAdapter::createSwarm(const QString& title,
                                   {{"title", title},
                                    {"description", description},
                                    {"avatar", avatar}});
-}
\ No newline at end of file
+}
diff --git a/src/app/conversationsadapter.h b/src/app/conversationsadapter.h
index bb8fd82c5b30017978dc78b94e649defad6d7655..f05e39fbe854ba4b0a95a1e903f46f5b362819e0 100644
--- a/src/app/conversationsadapter.h
+++ b/src/app/conversationsadapter.h
@@ -21,7 +21,6 @@
 
 #include "lrcinstance.h"
 #include "qmladapterbase.h"
-#include "smartlistmodel.h"
 #include "conversationlistmodel.h"
 #include "searchresultslistmodel.h"
 
@@ -43,11 +42,9 @@ public:
                                   QObject* parent = nullptr);
     ~ConversationsAdapter() = default;
 
-protected:
-    void safeInit() override;
-
 public:
-    Q_INVOKABLE bool connectConversationModel();
+    void connectConversationModel();
+
     Q_INVOKABLE void createSwarm(const QString& title,
                                  const QString& description,
                                  const QString& avatar,
diff --git a/src/app/currentaccount.cpp b/src/app/currentaccount.cpp
index eb26e559e3a34129b818dbd3de6088cecb47e920..df68a6023582bb68467eccbf5a3ec4d768a24728 100644
--- a/src/app/currentaccount.cpp
+++ b/src/app/currentaccount.cpp
@@ -131,6 +131,8 @@ CurrentAccount::updateData()
         set_publishedPort(accConfig.publishedPort, true);
         set_registrationExpire(accConfig.registrationExpire, true);
 
+        set_hasArchivePassword(accConfig.archiveHasPassword);
+
         // DHT
         set_PublicInCallsDHT(accConfig.DHT.PublicInCalls, true);
 
diff --git a/src/app/currentaccount.h b/src/app/currentaccount.h
index 554450d2d1fa357555a83621087461ae513232b0..8b345e24ca32ab1b2d49627a4e5b20c5400f34f3 100644
--- a/src/app/currentaccount.h
+++ b/src/app/currentaccount.h
@@ -132,6 +132,8 @@ class CurrentAccount final : public QObject
     QML_ACCOUNT_CONFIG_SETTINGS_PROPERTY(int, publishedPort)
     QML_ACCOUNT_CONFIG_SETTINGS_PROPERTY(int, registrationExpire)
 
+    QML_RO_PROPERTY(bool, hasArchivePassword)
+
     // Moderator settings
     Q_PROPERTY(bool isAllModeratorsEnabled READ get_isAllModeratorsEnabled WRITE
                    set_isAllModeratorsEnabled NOTIFY isAllModeratorsEnabledChanged)
diff --git a/src/app/currentcall.cpp b/src/app/currentcall.cpp
index 6eb4fbd50920d7c890f5ed452f897b471551cbe0..c813ebafa4e066edd35c563c283067688844c6f5 100644
--- a/src/app/currentcall.cpp
+++ b/src/app/currentcall.cpp
@@ -33,6 +33,11 @@ CurrentCall::CurrentCall(LRCInstance* lrcInstance, QObject* parent)
             this,
             &CurrentCall::onCurrentConvIdChanged);
 
+    connect(&lrcInstance_->behaviorController(),
+            &BehaviorController::showIncomingCallView,
+            this,
+            &CurrentCall::onShowIncomingCallView);
+
     connectModel();
 }
 
@@ -57,9 +62,7 @@ CurrentCall::updateId(QString callId)
 
     // Set the current id_ if there is a call.
     auto& accInfo = lrcInstance_->getCurrentAccountInfo();
-    if (accInfo.callModel->hasCall(callId)) {
-        set_id(callId);
-    }
+    set_id((accInfo.callModel->hasCall(callId) ? callId : QString()));
 }
 
 void
@@ -102,6 +105,7 @@ CurrentCall::updateCallInfo()
 
     auto callInfo = callModel->getCall(id_);
 
+    set_isOutgoing(callInfo.isOutgoing);
     set_isGrid(callInfo.layout == call::Layout::GRID);
     set_isAudioOnly(callInfo.isAudioOnly);
 
@@ -181,41 +185,41 @@ CurrentCall::updateRecordingState(bool state)
 void
 CurrentCall::connectModel()
 {
-    try {
-        auto& accInfo = lrcInstance_->getCurrentAccountInfo();
-        connect(accInfo.callModel.get(),
-                &CallModel::callStatusChanged,
-                this,
-                &CurrentCall::onCallStatusChanged,
-                Qt::UniqueConnection);
-        connect(accInfo.callModel.get(),
-                &CallModel::callInfosChanged,
-                this,
-                &CurrentCall::onCallInfosChanged,
-                Qt::UniqueConnection);
-        connect(accInfo.callModel.get(),
-                &CallModel::currentCallChanged,
-                this,
-                &CurrentCall::onCurrentCallChanged,
-                Qt::UniqueConnection);
-        connect(accInfo.callModel.get(),
-                &CallModel::participantsChanged,
-                this,
-                &CurrentCall::onParticipantsChanged,
-                Qt::UniqueConnection);
-        connect(accInfo.callModel.get(),
-                &CallModel::remoteRecordersChanged,
-                this,
-                &CurrentCall::onRemoteRecordersChanged,
-                Qt::UniqueConnection);
-        connect(accInfo.callModel.get(),
-                &CallModel::recordingStateChanged,
-                this,
-                &CurrentCall::onRecordingStateChanged,
-                Qt::UniqueConnection);
-    } catch (const std::exception& e) {
-        qWarning() << "Exception getting account info." << e.what();
+    auto callModel = lrcInstance_->getCurrentCallModel();
+    if (callModel == nullptr) {
+        return;
     }
+
+    connect(callModel,
+            &CallModel::callStatusChanged,
+            this,
+            &CurrentCall::onCallStatusChanged,
+            Qt::UniqueConnection);
+    connect(callModel,
+            &CallModel::callInfosChanged,
+            this,
+            &CurrentCall::onCallInfosChanged,
+            Qt::UniqueConnection);
+    connect(callModel,
+            &CallModel::currentCallChanged,
+            this,
+            &CurrentCall::onCurrentCallChanged,
+            Qt::UniqueConnection);
+    connect(callModel,
+            &CallModel::participantsChanged,
+            this,
+            &CurrentCall::onParticipantsChanged,
+            Qt::UniqueConnection);
+    connect(callModel,
+            &CallModel::remoteRecordersChanged,
+            this,
+            &CurrentCall::onRemoteRecordersChanged,
+            Qt::UniqueConnection);
+    connect(callModel,
+            &CallModel::recordingStateChanged,
+            this,
+            &CurrentCall::onRecordingStateChanged,
+            Qt::UniqueConnection);
 }
 
 void
@@ -277,7 +281,7 @@ CurrentCall::onCurrentCallChanged(const QString& callId)
     // If this status change's callId is not the current, it's possible that
     // the current value of id_ is stale, and needs to be updated after checking
     // the current conversation's getCallId(). Other slots need not do this, as the
-    // id_ is updated here.
+    // id_ is updated in CurrentCall::updateId.
     if (id_ == callId) {
         return;
     }
@@ -317,3 +321,18 @@ CurrentCall::onRecordingStateChanged(const QString& callId, bool state)
 
     updateRecordingState(state);
 }
+
+void
+CurrentCall::onShowIncomingCallView(const QString& accountId, const QString& convUid)
+{
+    if (accountId != lrcInstance_->get_currentAccountId()
+        || convUid != lrcInstance_->get_selectedConvUid()) {
+        return;
+    }
+
+    // Update the id in case the current conversation now has a call
+    // that matches the current id.
+    updateId();
+    updateCallStatus();
+    updateCallInfo();
+}
diff --git a/src/app/currentcall.h b/src/app/currentcall.h
index 4b128b9b1443e9945e17a0555df98960222f03e7..622ba5c511ed326bacf4dab9ffd11c90e9705afb 100644
--- a/src/app/currentcall.h
+++ b/src/app/currentcall.h
@@ -47,9 +47,9 @@ class CurrentCall final : public QObject
     QML_RO_PROPERTY(bool, isHandRaised)
     QML_RO_PROPERTY(bool, isConference)
     QML_RO_PROPERTY(bool, isModerator)
-
     QML_PROPERTY(bool, hideSelf)
     QML_PROPERTY(bool, hideSpectators)
+    QML_RO_PROPERTY(bool, isOutgoing)
 
 public:
     explicit CurrentCall(LRCInstance* lrcInstance, QObject* parent = nullptr);
@@ -73,6 +73,7 @@ private Q_SLOTS:
     void onParticipantsChanged(const QString& callId);
     void onRemoteRecordersChanged(const QString& callId, const QStringList& recorders);
     void onRecordingStateChanged(const QString& callId, bool state);
+    void onShowIncomingCallView(const QString& accountId, const QString& convUid);
 
 private:
     LRCInstance* lrcInstance_;
diff --git a/src/app/currentconversation.cpp b/src/app/currentconversation.cpp
index 8a12636f7a3194a1649d47a72fef6a2b25401793..b4e4bb45be9343f8bc1f8a621ad91aed9615fc3d 100644
--- a/src/app/currentconversation.cpp
+++ b/src/app/currentconversation.cpp
@@ -17,7 +17,6 @@
  */
 
 #include "currentconversation.h"
-#include "qmlregister.h"
 
 #include <api/conversationmodel.h>
 
@@ -38,6 +37,12 @@ CurrentConversation::CurrentConversation(LRCInstance* lrcInstance, QObject* pare
             &LRCInstance::selectedConvUidChanged,
             this,
             &CurrentConversation::updateData);
+
+    connect(&lrcInstance_->behaviorController(),
+            &BehaviorController::showIncomingCallView,
+            this,
+            &CurrentConversation::onShowIncomingCallView);
+
     updateData();
 }
 
@@ -45,9 +50,9 @@ void
 CurrentConversation::updateData()
 {
     auto convId = lrcInstance_->get_selectedConvUid();
+    set_id(convId);
     if (convId.isEmpty())
         return;
-    set_id(convId);
     try {
         auto accountId = lrcInstance_->get_currentAccountId();
         const auto& accInfo = lrcInstance_->accountModel().getAccountInfo(accountId);
@@ -67,8 +72,10 @@ CurrentConversation::updateData()
             if (accInfo.callModel->hasCall(callId_)) {
                 auto call = accInfo.callModel->getCall(callId_);
                 set_callState(call.status);
+                set_hasCall(callState_ != call::Status::ENDED);
             } else {
                 set_callState(call::Status::INVALID);
+                set_hasCall(false);
             }
             set_inCall(callState_ == call::Status::CONNECTED
                        || callState_ == call::Status::IN_PROGRESS
@@ -93,7 +100,6 @@ CurrentConversation::updateData()
                 }
             set_isContact(isContact);
 
-            QString modeString;
             if (convInfo.mode == conversation::Mode::ONE_TO_ONE) {
                 set_modeString(tr("Private"));
             } else if (convInfo.mode == conversation::Mode::ADMIN_INVITES_ONLY) {
@@ -137,7 +143,7 @@ CurrentConversation::setPreference(const QString& key, const QString& value)
 QString
 CurrentConversation::getPreference(const QString& key) const
 {
-    return getPreferences()[key];
+    return getPreferences().value(key);
 }
 
 MapStringString
@@ -147,7 +153,6 @@ CurrentConversation::getPreferences() const
     const auto& accInfo = lrcInstance_->accountModel().getAccountInfo(accountId);
     auto convId = lrcInstance_->get_selectedConvUid();
     if (auto optConv = accInfo.conversationModel->getConversationForUid(convId)) {
-        auto& convInfo = optConv->get();
         auto preferences = accInfo.conversationModel->getConversationPreferences(convId);
         return preferences;
     }
@@ -212,7 +217,6 @@ CurrentConversation::updateConversationPreferences(const QString& convId)
     const auto& accInfo = lrcInstance_->accountModel().getAccountInfo(accountId);
     if (auto optConv = accInfo.conversationModel->getConversationForUid(convId)) {
         auto& convInfo = optConv->get();
-        auto preferences = convInfo.preferences;
         auto color = Utils::getAvatarColor(convId).name();
         if (convInfo.preferences.contains("color")) {
             color = convInfo.preferences["color"];
@@ -261,10 +265,15 @@ CurrentConversation::connectModel()
             this,
             &CurrentConversation::onNeedsHost,
             Qt::UniqueConnection);
+    connect(lrcInstance_->getCurrentCallModel(),
+            &CallModel::callStatusChanged,
+            this,
+            &CurrentConversation::onCallStatusChanged,
+            Qt::UniqueConnection);
 }
 
 void
-CurrentConversation::showSwarmDetails() const
+CurrentConversation::showSwarmDetails()
 {
     Q_EMIT showDetails();
 }
@@ -275,11 +284,11 @@ CurrentConversation::updateErrors(const QString& convId)
     if (convId != id_)
         return;
     try {
+        QStringList newErrors;
+        QStringList newBackendErr;
         const auto& convModel = lrcInstance_->getCurrentConversationModel();
         if (auto optConv = convModel->getConversationForUid(convId)) {
             auto& convInfo = optConv->get();
-            QStringList newErrors;
-            QStringList newBackendErr;
             for (const auto& [code, error] : convInfo.errors) {
                 if (code == 1) {
                     newErrors.append(tr("An error occurred while fetching this repository"));
@@ -295,9 +304,9 @@ CurrentConversation::updateErrors(const QString& convId)
                 }
                 newBackendErr.push_back(error);
             }
-            set_backendErrors(newBackendErr);
-            set_errors(newErrors);
         }
+        set_backendErrors(newBackendErr);
+        set_errors(newErrors);
     } catch (...) {
     }
 }
@@ -338,6 +347,32 @@ CurrentConversation::updateActiveCalls(const QString&, const QString& convId)
     }
 }
 
+void
+CurrentConversation::onCallStatusChanged(const QString& callId, int)
+{
+    if (callId != callId_) {
+        return;
+    }
+    auto callModel = lrcInstance_->getCurrentCallModel();
+    if (callModel->hasCall(callId_)) {
+        auto callInfo = callModel->getCall(callId_);
+        set_hasCall(callInfo.status != call::Status::ENDED);
+    }
+}
+
+void
+CurrentConversation::onShowIncomingCallView(const QString& accountId, const QString& convUid)
+{
+    if (accountId != lrcInstance_->get_currentAccountId()) {
+        return;
+    }
+    const auto& convModel = lrcInstance_->getCurrentConversationModel();
+    if (auto optConv = convModel->getConversationForUid(convUid)) {
+        auto& convInfo = optConv->get();
+        set_hasCall(!convInfo.getCallId().isEmpty());
+    }
+}
+
 void
 CurrentConversation::scrollToMsg(const QString& msg)
 {
diff --git a/src/app/currentconversation.h b/src/app/currentconversation.h
index 76054d94670f928e93f1533a970f4e18091ec1b5..84f640f64281b245d54fcb98474449afcd8babc4 100644
--- a/src/app/currentconversation.h
+++ b/src/app/currentconversation.h
@@ -55,12 +55,13 @@ class CurrentConversation final : public QObject
     QML_PROPERTY(QStringList, errors)
     QML_PROPERTY(QStringList, backendErrors)
     QML_PROPERTY(QString, lastSelfMessageId)
+    QML_RO_PROPERTY(bool, hasCall)
 
 public:
     explicit CurrentConversation(LRCInstance* lrcInstance, QObject* parent = nullptr);
     ~CurrentConversation() = default;
     Q_INVOKABLE void scrollToMsg(const QString& msgId);
-    Q_INVOKABLE void showSwarmDetails() const;
+    Q_INVOKABLE void showSwarmDetails();
     Q_INVOKABLE void setPreference(const QString& key, const QString& value);
     Q_INVOKABLE QString getPreference(const QString& key) const;
     Q_INVOKABLE MapStringString getPreferences() const;
@@ -68,7 +69,7 @@ public:
 
 Q_SIGNALS:
     void scrollTo(const QString& msgId);
-    void showDetails() const;
+    void showDetails();
 
 private Q_SLOTS:
     void updateData();
@@ -78,6 +79,8 @@ private Q_SLOTS:
     void updateErrors(const QString& convId);
     void updateConversationPreferences(const QString& convId);
     void updateActiveCalls(const QString&, const QString& convId);
+    void onCallStatusChanged(const QString& callId, int code);
+    void onShowIncomingCallView(const QString& accountId, const QString& convUid);
 
 Q_SIGNALS:
     void needsHost();
diff --git a/src/app/lrcinstance.cpp b/src/app/lrcinstance.cpp
index df4b25b927e53fc9f777394eb754754e5f7dba65..122fb1b05bbfac90e906bf508bc58e3c2a788cae 100644
--- a/src/app/lrcinstance.cpp
+++ b/src/app/lrcinstance.cpp
@@ -339,6 +339,10 @@ LRCInstance::setContentDraft(const QString& convUid,
                              const QString& accountId,
                              const QString& content)
 {
+    if (accountId.isEmpty() || convUid.isEmpty()) {
+        return;
+    }
+
     auto draftKey = accountId + "_" + convUid;
 
     // prevent a senseless dataChanged signal from the
@@ -359,6 +363,7 @@ LRCInstance::selectConversation(const QString& convId, const QString& accountId)
         Q_EMIT conversationUpdated(convId, accountId);
         return;
     }
+
     // if the account is not currently selected, do that first, then
     // proceed to select the conversation
     if (!accountId.isEmpty() && accountId != get_currentAccountId()) {
diff --git a/src/app/mainapplication.cpp b/src/app/mainapplication.cpp
index 1e7c115c2172b55daad54ac59b2d6bc234c312ea..64ad3b27f52f481368cadc2ed36b1ef56284281a 100644
--- a/src/app/mainapplication.cpp
+++ b/src/app/mainapplication.cpp
@@ -104,7 +104,7 @@ MainApplication::MainApplication(int& argc, char** argv)
     }
 
     parseArguments();
-    QObject::connect(this, &QApplication::aboutToQuit, [this] { cleanup(); });
+    QObject::connect(this, &QApplication::aboutToQuit, this, &MainApplication::cleanup);
 }
 
 MainApplication::~MainApplication()
@@ -158,7 +158,7 @@ MainApplication::init()
     }
 #endif
 
-    connect(connectivityMonitor_.get(), &ConnectivityMonitor::connectivityChanged, [this] {
+    connect(connectivityMonitor_.get(), &ConnectivityMonitor::connectivityChanged, this, [this] {
         QTimer::singleShot(500, this, [&]() { lrcInstance_->connectivityChanged(); });
     });
 
diff --git a/src/app/mainview/ConversationView.qml b/src/app/mainview/ConversationView.qml
new file mode 100644
index 0000000000000000000000000000000000000000..f8963ba69f89c0e5d8769a3fe98d290df357bcf0
--- /dev/null
+++ b/src/app/mainview/ConversationView.qml
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2023 Savoir-faire Linux Inc.
+ *
+ * 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/>.
+ */
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Qt5Compat.GraphicalEffects
+
+import net.jami.Models 1.1
+import net.jami.Adapters 1.1
+import net.jami.Constants 1.1
+
+import "../commoncomponents"
+import "components"
+
+BaseView {
+    id: root
+    objectName: "ConversationView"
+    managed: false
+
+    onPresented: {
+        if (!visible && viewCoordinator.singlePane &&
+                CurrentConversation.id !== '') {
+            viewCoordinator.present(objectName)
+        }
+    }
+
+    onDismissed: {
+        callStackView.needToCloseInCallConversationAndPotentialWindow()
+        LRCInstance.deselectConversation()
+    }
+
+    property string currentAccountId: CurrentAccount.id
+    onCurrentAccountIdChanged: dismiss()
+
+    onVisibleChanged: {
+        if (visible) return
+        UtilsAdapter.clearInteractionsCache(CurrentAccount.id, CurrentConversation.id)
+    }
+
+    color: JamiTheme.transparentColor
+
+    StackLayout {
+        currentIndex: !CurrentConversation.hasCall ? 0 : 1
+        onCurrentIndexChanged: chatView.parent = currentIndex == 1 ?
+                                   callStackView.chatViewContainer :
+                                   chatViewContainer
+
+        anchors.fill: root
+
+        Item {
+            id: chatViewContainer
+
+            Layout.fillWidth: true
+            Layout.fillHeight: true
+
+            ChatView {
+                id: chatView
+                anchors.fill: parent
+                inCallView: parent == callStackView.chatViewContainer
+
+                property string currentConvId: CurrentConversation.id
+                onCurrentConvIdChanged: {
+                    if (!CurrentConversation.hasCall) {
+                        resetPanels()
+                        Qt.callLater(focusChatView)
+                    }
+                }
+
+                onDismiss: {
+                    if (parent == chatViewContainer) {
+                        root.dismiss()
+                    } else {
+                        callStackView.chatViewContainer.visible = false
+                    }
+                }
+            }
+        }
+
+        CallStackView {
+            id: callStackView
+            Layout.fillWidth: true
+            Layout.fillHeight: true
+        }
+    }
+}
diff --git a/src/app/mainview/MainView.qml b/src/app/mainview/MainView.qml
index 31e17fd70b14ba3ed6824061fd38c44d876911cf..6f5717e171acddaf235d32b6ed97bb36ae7f6340 100644
--- a/src/app/mainview/MainView.qml
+++ b/src/app/mainview/MainView.qml
@@ -39,223 +39,39 @@ Rectangle {
 
     objectName: "mainView"
 
-    property int sidePanelViewStackCurrentWidth: 300
-    property int mainViewStackPreferredWidth: sidePanelViewStackCurrentWidth + JamiTheme.chatViewHeaderMinimumWidth
-    property int settingsViewPreferredWidth: 460
-    property int onWidthChangedTriggerDistance: 5
-    property int lastSideBarSplitSize: sidePanelViewStackCurrentWidth
-
-    property bool sidePanelOnly: (!mainViewStack.visible) && sidePanelViewStack.visible
-    property int previousWidth: width
-
     // To calculate tab bar bottom border hidden rect left margin.
     property int tabBarLeftMargin: 8
     property int tabButtonShrinkSize: 8
-    property bool inSettingsView: false
-
-    // For updating msgWebView
-    property string currentConvUID: ""
+    property bool inSettingsView: viewCoordinator.inSettings
 
     signal loaderSourceChangeRequested(int sourceToLoad)
 
-    property string currentAccountId: LRCInstance.currentAccountId
-    onCurrentAccountIdChanged: {
-        if (inSettingsView) {
-            settingsView.setSelected(settingsView.selectedMenu, true)
-        } else {
-            backToMainView(true)
-        }
-    }
-
-    function isPageInStack(objectName, stackView) {
-        var foundItem = stackView.find(function (item, index) {
-            return item.objectName === objectName
-        })
-
-        return foundItem ? true : false
-    }
-
-    function showWelcomeView() {
-        currentConvUID = ""
-        callStackView.needToCloseInCallConversationAndPotentialWindow()
-        LRCInstance.deselectConversation()
-        if (isPageInStack("callStackViewObject", sidePanelViewStack) ||
-                isPageInStack("chatView", sidePanelViewStack) ||
-                isPageInStack("chatView", mainViewStack) ||
-                isPageInStack("newSwarmPage", sidePanelViewStack) ||
-                isPageInStack("newSwarmPage", mainViewStack) ||
-                isPageInStack("callStackViewObject", mainViewStack)) {
-            sidePanelViewStack.pop(StackView.Immediate)
-            mainViewStack.pop(welcomePage, StackView.Immediate)
-        }
-    }
-
-    function pushCallStackView() {
-        chatView.inCallView = true
-        if (sidePanelOnly) {
-            sidePanelViewStack.pop(StackView.Immediate)
-            sidePanelViewStack.push(callStackView, StackView.Immediate)
-        } else {
-            sidePanelViewStack.pop(StackView.Immediate)
-            mainViewStack.pop(welcomePage, StackView.Immediate)
-            mainViewStack.push(callStackView, StackView.Immediate)
-        }
-    }
-
-    function pushCommunicationMessageWebView() {
-        chatView.inCallView = false
-        if (sidePanelOnly) {
-            sidePanelViewStack.pop(StackView.Immediate)
-            sidePanelViewStack.push(chatView, StackView.Immediate)
-        } else {
-            mainViewStack.pop(welcomePage, StackView.Immediate)
-            mainViewStack.push(chatView, StackView.Immediate)
-        }
-    }
-
-    function pushNewSwarmPage() {
-        if (sidePanelOnly) {
-            sidePanelViewStack.pop(StackView.Immediate)
-            sidePanelViewStack.push(newSwarmPage, StackView.Immediate)
-        } else {
-            mainViewStack.pop(welcomePage, StackView.Immediate)
-            mainViewStack.push(newSwarmPage, StackView.Immediate)
-        }
-    }
-
-    function startWizard() {
-        mainViewStackLayout.currentIndex = 1
-    }
-
-    function currentAccountIsCalling() {
-        return UtilsAdapter.hasCall(LRCInstance.currentAccountId)
-    }
-
-    // Only called onWidthChanged
-    function recursionStackViewItemMove(stackOne, stackTwo, depth=1) {
-        // Move all items (expect the bottom item) to stacktwo by the same order in stackone.
-        if (stackOne.depth === depth) {
-            return
-        }
-
-        var tempItem = stackOne.pop(StackView.Immediate)
-        recursionStackViewItemMove(stackOne, stackTwo, depth)
-        stackTwo.push(tempItem, StackView.Immediate)
-    }
-
-    // Back to WelcomeView required, but can also check, i. e., on account switch or
-    // settings exit, if there is need to switch to a current call
-    function backToMainView(checkCurrentCall = false) {
-        if (inSettingsView)
-            return
-        if (checkCurrentCall && currentAccountIsCalling()) {
-            var callConv = UtilsAdapter.getCallConvForAccount(
-                        LRCInstance.currentAccountId)
-            LRCInstance.selectConversation(callConv, currentAccountId)
-            CallAdapter.updateCall(callConv, currentAccountId)
-        } else {
-            showWelcomeView()
-        }
-    }
-
-    function toggleSettingsView() {
-        inSettingsView = !inSettingsView
-
-        if (inSettingsView) {
-            if (sidePanelOnly)
-                sidePanelViewStack.push(settingsMenu, StackView.Immediate)
-            else {
-                mainViewStack.pop(welcomePage, StackView.Immediate)
-                mainViewStack.push(settingsView, StackView.Immediate)
-                sidePanelViewStack.push(settingsMenu, StackView.Immediate)
-            }
+    property string currentConvId: CurrentConversation.id
+    onCurrentConvIdChanged: {
+        if (currentConvId !== '') {
+            viewCoordinator.present("ConversationView")
         } else {
-            sidePanelViewStack.pop(StackView.Immediate)
-            mainViewStack.pop(StackView.Immediate)
-            backToMainView(true)
-        }
-    }
-
-    function setMainView(convId) {
-        var item = ConversationsAdapter.getConvInfoMap(convId)
-        if (item.convId === undefined)
-            return
-        if (item.callStackViewShouldShow) {
-            if (inSettingsView) {
-                toggleSettingsView()
-            }
-            MessagesAdapter.setupChatView(item)
-            callStackView.setLinkedWebview(chatView)
-            callStackView.responsibleAccountId = LRCInstance.currentAccountId
-            callStackView.responsibleConvUid = convId
-            currentConvUID = convId
-
-            if (item.callState === Call.Status.IN_PROGRESS ||
-                    item.callState === Call.Status.PAUSED) {
-                CallAdapter.updateCall(convId, LRCInstance.currentAccountId)
-                callStackView.showOngoingCallPage()
-            } else {
-                callStackView.showInitialCallPage(item.callState, item.isAudioOnly)
-            }
-            pushCallStackView()
-
-        } else if (!inSettingsView) {
-            if (currentConvUID !== convId) {
-                callStackView.needToCloseInCallConversationAndPotentialWindow()
-                MessagesAdapter.setupChatView(item)
-                pushCommunicationMessageWebView()
-                chatView.focusChatView()
-                currentConvUID = convId
-            } else if (isPageInStack("callStackViewObject", sidePanelViewStack)
-                       || isPageInStack("callStackViewObject", mainViewStack)) {
-                callStackView.needToCloseInCallConversationAndPotentialWindow()
-                pushCommunicationMessageWebView()
-                chatView.focusChatView()
-            }
+            viewCoordinator.present("WelcomePage")
         }
     }
 
     color: JamiTheme.backgroundColor
 
-    Connections {
-        target: LRCInstance
-
-        function onSelectedConvUidChanged() {
-            mainView.setMainView(LRCInstance.selectedConvUid)
-        }
-
-        function onConversationUpdated(convUid, accountId) {
-            if (convUid === LRCInstance.selectedConvUid &&
-                    accountId === currentAccountId)
-                mainView.setMainView(convUid)
-        }
-    }
-
-    Connections {
-        target: WizardViewStepModel
+    onWidthChanged: Qt.callLater(JamiQmlUtils.updateMessageBarButtonsPoints)
+    onHeightChanged: Qt.callLater(JamiQmlUtils.updateMessageBarButtonsPoints)
 
-        function onCloseWizardView() {
-            mainViewStackLayout.currentIndex = 0
-            backToMainView()
-        }
-    }
-
-    StackLayout {
-        id: mainViewStackLayout
+    // Needed by ViewCoordinator.
+    property alias splitView: splitView
+    property alias sv1: sv1
+    property alias sv2: sv2
 
+    StackView {
+        id: mainStackView
         anchors.fill: parent
 
-        currentIndex: 0
-
-        SplitView {
+        initialItem: SplitView {
             id: splitView
 
-            Layout.fillWidth: true
-            Layout.fillHeight: true
-
-            width: mainView.width
-            height: mainView.height
-
             handle: Rectangle {
                 implicitWidth: JamiTheme.splitViewHandlePreferredWidth
                 implicitHeight: splitView.height
@@ -267,264 +83,33 @@ Rectangle {
                 }
             }
 
-            Rectangle {
-                id: mainViewSidePanelRect
-
-                SplitView.maximumWidth: splitView.width
-                SplitView.minimumWidth: sidePanelViewStackCurrentWidth
-                SplitView.preferredWidth: sidePanelViewStackCurrentWidth
+            StackView {
+                id: sv1
+                objectName: "sv1"
+                SplitView.minimumWidth: 300
+                SplitView.preferredWidth: 300
                 SplitView.fillHeight: true
-                color: JamiTheme.backgroundColor
-
-                // AccountComboBox is not a ComboBox
-                AccountComboBox {
-                    id: accountComboBox
-
-                    anchors.top: mainViewSidePanelRect.top
-                    width: mainViewSidePanelRect.width
-                    height: JamiTheme.accountListItemHeight
-
-                    visible: (mainViewSidePanel.visible || settingsMenu.visible)
-
-                    onSettingBtnClicked: {
-                        toggleSettingsView()
-                    }
-
-                    Component.onCompleted: {
-                        AccountAdapter.setQmlObject(this)
-                    }
-                }
-
-                StackView {
-                    id: sidePanelViewStack
-
-                    initialItem: mainViewSidePanel
-
-                    anchors.top: accountComboBox.visible ? accountComboBox.bottom :
-                                                           mainViewSidePanelRect.top
-                    width: mainViewSidePanelRect.width
-                    height: accountComboBox.visible ? mainViewSidePanelRect.height - accountComboBox.height :
-                                                      mainViewSidePanelRect.height
-
-                    clip: true
-                }
+                clip: true
+                initialItem: SidePanel {}
             }
 
             StackView {
-                id: mainViewStack
-
-                initialItem: welcomePage
-
-                SplitView.maximumWidth: splitView.width
-                SplitView.minimumWidth: JamiTheme.chatViewHeaderMinimumWidth
-                SplitView.preferredWidth: mainViewStackPreferredWidth
+                id: sv2
+                objectName: "sv2"
                 SplitView.fillHeight: true
-
                 clip: true
             }
         }
-
-        WizardView {
-            id: wizardView
-
-            Layout.fillWidth: true
-            Layout.fillHeight: true
-
-            onLoaderSourceChangeRequested: {
-                mainViewStackLayout.currentIndex = 0
-                backToMainView()
-            }
-        }
     }
 
-    SettingsMenu {
-        id: settingsMenu
-
-        objectName: "settingsMenu"
-
-        visible: false
-
-        width: mainViewSidePanelRect.width
-        height: mainViewSidePanelRect.height
-
-        onItemSelected: function (index) {
-            settingsView.setSelected(index)
-            if (sidePanelOnly)
-                sidePanelViewStack.push(settingsView, StackView.Immediate)
-        }
-    }
-
-    SidePanel {
-        id: mainViewSidePanel
-
-        Connections {
-            target: ConversationsAdapter
-
-            function onNavigateToWelcomePageRequested() {
-                backToMainView()
-            }
-
-        }
-
-        onCreateSwarmClicked: {
-            if (newSwarmPage.visible) {
-                backToMainView()
-                mainViewSidePanel.showSwarmListView(false)
-            } else {
-                pushNewSwarmPage()
-            }
-        }
-
-        onHighlightedMembersChanged: {
-            newSwarmPage.members = mainViewSidePanel.highlightedMembers
-        }
-    }
-
-    CallStackView {
-        id: callStackView
-
-        visible: false
-        objectName: "callStackViewObject"
-    }
-
-    WelcomePage {
-        id: welcomePage
-
-        visible: false
-    }
-
-    SettingsView {
-        id: settingsView
-
-        visible: false
-
-        onSettingsViewNeedToShowMainView: {
-            AccountAdapter.changeAccount(0)
-            toggleSettingsView()
-        }
-
-        onSettingsViewNeedToShowNewWizardWindow: loaderSourceChangeRequested(
-                                                     MainApplicationWindow.LoadedSource.WizardView)
-
-        onSettingsBackArrowClicked: sidePanelViewStack.pop(StackView.Immediate)
-    }
-
-    ChatView {
-        id: chatView
-
-        objectName: "chatView"
-        visible: false
-        inCallView: false
-        Component.onCompleted: {
-            MessagesAdapter.setQmlObject(this)
-            PositionManager.setQmlObject(this)
-        }
-    }
-
-    NewSwarmPage {
-        id: newSwarmPage
-
-        objectName: "newSwarmPage"
-        visible: false
-
-        onVisibleChanged: {
-            mainViewSidePanel.showSwarmListView(newSwarmPage.visible)
-        }
-
-        onRemoveMember: function(convId, member) {
-            mainViewSidePanel.removeMember(convId, member)
-        }
-
-        onCreateSwarmClicked: function(title, description, avatar) {
-            var uris = []
-            for (var idx in newSwarmPage.members) {
-                var uri = newSwarmPage.members[idx].uri
-                if (uris.indexOf(uri) === -1) {
-                    uris.push(uri)
-                }
-            }
-            ConversationsAdapter.createSwarm(title, description, avatar, uris)
-            backToMainView()
-        }
-    }
-
-    onWidthChanged: {
-        // Hide unnecessary stackview when width is changed.
-        var isExpanding = previousWidth < mainView.width
-
-        if (mainView.width < JamiTheme.chatViewHeaderMinimumWidth + mainViewSidePanelRect.width
-                && mainViewStack.visible && !isExpanding) {
-            lastSideBarSplitSize = mainViewSidePanelRect.width
-            mainViewStack.visible = false
-
-            // The find callback function is called for each item in the stack.
-            var inWelcomeViewStack = mainViewStack.find(
-                        function (item, index) {
-                            return index > 0
-                        })
-
-            if (inSettingsView) {
-                mainViewStack.pop(StackView.Immediate)
-                sidePanelViewStack.push(settingsView, StackView.Immediate)
-            }
-            else if (inWelcomeViewStack)
-                recursionStackViewItemMove(mainViewStack, sidePanelViewStack)
-        } else if (mainView.width >= lastSideBarSplitSize + JamiTheme.chatViewHeaderMinimumWidth
-                   && !mainViewStack.visible && isExpanding && !layoutManager.isFullScreen) {
-            mainViewStack.visible = true
-
-            var inSidePanelViewStack = sidePanelViewStack.find(
-                        function (item, index) {
-                            return index > 0
-                        })
-
-            if (inSettingsView) {
-                if (sidePanelViewStack.currentItem.objectName !== settingsMenu.objectName)
-                    sidePanelViewStack.pop(StackView.Immediate)
-                mainViewStack.push(settingsView, StackView.Immediate)
-            } else if (inSidePanelViewStack) {
-                recursionStackViewItemMove(sidePanelViewStack, mainViewStack)
-                if (currentAccountIsCalling())
-                    pushCallStackView()
-            }
-        }
-
-        previousWidth = mainView.width
-
-        JamiQmlUtils.updateMessageBarButtonsPoints()
-    }
-
-    onHeightChanged: JamiQmlUtils.updateMessageBarButtonsPoints()
-
     Component.onCompleted: {
         JamiQmlUtils.mainViewRectObj = mainView
     }
 
-    AboutPopUp {
-        id: aboutPopUpDialog
-        width: Math.min(mainView.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.secondaryDialogDimension)
-        height: Math.min(mainView.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.secondaryDialogDimension)
-    }
-
-    WelcomePageQrDialog {
-        id: qrDialog
-    }
-
-    UserProfile {
-        id: userProfile
-        width: Math.min(mainView.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.secondaryDialogDimension)
-        height: Math.min(mainView.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.secondaryDialogDimension)
-    }
-
     Shortcut {
         sequence: "Ctrl+M"
         context: Qt.ApplicationShortcut
-        onActivated: {
-            if (!inSettingsView) {
-                toggleSettingsView()
-            }
-            settingsMenu.buttonSelectedManually(SettingsView.Media)
-        }
+        onActivated: JamiQmlUtils.settingsPageRequested(SettingsView.Media)
     }
 
     WheelHandler {
@@ -571,42 +156,25 @@ Rectangle {
     Shortcut {
         sequence: "Ctrl+0"
         context: Qt.ApplicationShortcut
-        onActivated: {
-            UtilsAdapter.setAppValue(Settings.BaseZoom, 1.0)
-        }
+        onActivated: UtilsAdapter.setAppValue(Settings.BaseZoom, 1.0)
     }
 
     Shortcut {
         sequence: "Ctrl+G"
         context: Qt.ApplicationShortcut
-        onActivated: {
-            if (!inSettingsView) {
-                toggleSettingsView()
-            }
-            settingsMenu.buttonSelectedManually(SettingsView.General)
-        }
+        onActivated: JamiQmlUtils.settingsPageRequested(SettingsView.General)
     }
 
     Shortcut {
         sequence: "Ctrl+I"
         context: Qt.ApplicationShortcut
-        onActivated: {
-            if (!inSettingsView) {
-                toggleSettingsView()
-            }
-            settingsMenu.buttonSelectedManually(SettingsView.Account)
-        }
+        onActivated: JamiQmlUtils.settingsPageRequested(SettingsView.Account)
     }
 
     Shortcut {
         sequence: "Ctrl+P"
         context: Qt.ApplicationShortcut
-        onActivated: {
-            if (!inSettingsView) {
-                toggleSettingsView()
-            }
-            settingsMenu.buttonSelectedManually(SettingsView.Plugin)
-        }
+        onActivated: JamiQmlUtils.settingsPageRequested(SettingsView.Plugin)
     }
 
     Shortcut {
@@ -650,7 +218,7 @@ Rectangle {
     Shortcut {
         sequence: "Ctrl+Shift+N"
         context: Qt.ApplicationShortcut
-        onActivated: startWizard()
+        onActivated: viewCoordinator.present("WizardView")
     }
 
     Shortcut {
diff --git a/src/app/mainview/components/AboutPopUp.qml b/src/app/mainview/components/AboutPopUp.qml
index b58f4bf8bd4bf883f7bea6a529761652b2dd0866..bebd79718c6bc86e4083cd2e7f3dd0b59d2cda5c 100644
--- a/src/app/mainview/components/AboutPopUp.qml
+++ b/src/app/mainview/components/AboutPopUp.qml
@@ -31,6 +31,9 @@ import "../../commoncomponents"
 BaseModalDialog {
     id: root
 
+    width: Math.min(parent.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.secondaryDialogDimension)
+    height: Math.min(parent.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.secondaryDialogDimension)
+
     popupContentMargins: 14
 
     PushButton {
diff --git a/src/app/mainview/components/AccountComboBox.qml b/src/app/mainview/components/AccountComboBox.qml
index 1b8b1ff47b0d33409f84107a83ac277f99ad38a9..58f3a3f37a6e394c7b6bc62a835efb445232762b 100644
--- a/src/app/mainview/components/AccountComboBox.qml
+++ b/src/app/mainview/components/AccountComboBox.qml
@@ -33,6 +33,8 @@ Label {
     signal settingBtnClicked
     property alias popup: comboBoxPopup
 
+    property bool inSettingsView: viewCoordinator.inSettings
+
     // TODO: remove these refresh hacks use QAbstractItemModels correctly
     Connections {
         target: AccountAdapter
@@ -194,23 +196,22 @@ Label {
                 normalColor: JamiTheme.backgroundColor
                 imageColor: JamiTheme.textColor
 
-                onClicked: {
-                    if (visible)
-                        qrDialog.open()
-                }
+                onClicked: viewCoordinator.presentDialog(
+                               appWindow,
+                               "mainview/components/WelcomePageQrDialog.qml")
             }
 
             PushButton {
                 id: settingsButton
 
                 anchors.verticalCenter: parent.verticalCenter
-                source: !mainView.inSettingsView ?
+                source: !inSettingsView ?
                             JamiResources.settings_24dp_svg :
                             JamiResources.round_close_24dp_svg
 
                 normalColor: JamiTheme.backgroundColor
                 imageColor: JamiTheme.textColor
-                toolTipText: !mainView.inSettingsView ?
+                toolTipText: !inSettingsView ?
                                  JamiStrings.openSettings :
                                  JamiStrings.closeSettings
 
diff --git a/src/app/mainview/components/AccountComboBoxPopup.qml b/src/app/mainview/components/AccountComboBoxPopup.qml
index 80e5059b1fef57132b53504bec19daf207fd7d10..068ae75a565f1424afbe01276285cd3b94c42fee 100644
--- a/src/app/mainview/components/AccountComboBoxPopup.qml
+++ b/src/app/mainview/components/AccountComboBoxPopup.qml
@@ -39,7 +39,7 @@ Popup {
         return visible ? Math.min(
                              JamiTheme.accountListItemHeight * Math.min(
                                  5, listView.model.count + 1),
-                             mainViewSidePanelRect.height) : 0
+                             appWindow.height - parent.height) : 0
     }
     padding: 0
     modal: true
@@ -101,7 +101,7 @@ Popup {
 
             onClicked: {
                 root.close()
-                mainView.startWizard()
+                viewCoordinator.present("WizardView")
             }
         }
     }
diff --git a/src/app/mainview/components/BackupTipBox.qml b/src/app/mainview/components/BackupTipBox.qml
index 38012c15aa9eef2ad96233d20964c2b6926a560b..1dbe2b7ad0777b608e256cb413bb5499b076d401 100644
--- a/src/app/mainview/components/BackupTipBox.qml
+++ b/src/app/mainview/components/BackupTipBox.qml
@@ -33,50 +33,6 @@ Item {
 
     signal ignore
 
-    PasswordDialog {
-        id: passwordDialog
-
-        visible: false
-        purpose: PasswordDialog.ExportAccount
-
-        onDoneSignal: function (success) {
-            root.ignore()
-        }
-    }
-
-    // JamiFileDialog for exporting account
-    JamiFileDialog {
-        id: exportDialog
-
-        mode: JamiFileDialog.SaveFile
-
-        title: JamiStrings.backupAccountHere
-        folder: StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/Desktop"
-
-        nameFilters: [JamiStrings.jamiArchiveFiles, JamiStrings.allFiles]
-
-        onAccepted: {
-            // Is there password? If so, go to password dialog, else, go to following directly
-            if (AccountAdapter.hasPassword()) {
-                passwordDialog.path = UtilsAdapter.getAbsPath(file)
-                passwordDialog.open()
-            } else {
-                if (file.toString().length > 0)
-                    root.ignore()
-            }
-        }
-
-        onVisibleChanged: {
-            if (!visible) {
-                rejected()
-            }
-        }
-
-        onRejected: {
-            backupBtn.forceActiveFocus()
-        }
-    }
-
     ColumnLayout {
         id: backupLayout
 
@@ -156,7 +112,40 @@ Item {
             hoveredColor: JamiTheme.buttonTintedGreyHovered
             pressedColor: JamiTheme.buttonTintedGreyPressed
 
-            onClicked: exportDialog.open()
+            onClicked: {
+                var dlg = viewCoordinator.presentDialog(
+                            appWindow,
+                            "commoncomponents/JamiFileDialog.qml",
+                            {
+                                //objectName: "exportDialog",
+                                title: JamiStrings.backupAccountHere,
+                                fileMode: JamiFileDialog.SaveFile,
+                                folder: StandardPaths.writableLocation(
+                                            StandardPaths.HomeLocation) + "/Desktop",
+                                nameFilters: [JamiStrings.jamiArchiveFiles, JamiStrings.allFiles]
+                            })
+                dlg.fileAccepted.connect(function (file) {
+                    // Is there password? If so, go to password dialog, else, go to following directly
+                    if (CurrentAccount.hasArchivePassword) {
+                        var pwdDlg = viewCoordinator.presentDialog(
+                                    appWindow,
+                                    "commoncomponents/PasswordDialog.qml",
+                                    {
+                                        //objectName: "passwordDialog",
+                                        path: UtilsAdapter.getAbsPath(file),
+                                        purpose: PasswordDialog.ExportAccount
+                                    })
+                        pwdDlg.done.connect(function () { root.ignore() })
+                    } else {
+                        if (file.toString().length > 0) {
+                            root.ignore()
+                        }
+                    }
+                })
+                dlg.rejected.connect(function () {
+                    backupBtn.forceActiveFocus()
+                })
+            }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/app/mainview/components/CallActionBar.qml b/src/app/mainview/components/CallActionBar.qml
index 48c4f0c3bc21084db0f0c88ab8434fd30de0b851..2d6fb8060a7790551e24fc84bd9c026f23cadf32 100644
--- a/src/app/mainview/components/CallActionBar.qml
+++ b/src/app/mainview/components/CallActionBar.qml
@@ -473,6 +473,8 @@ Control {
             spacing: 0
 
             ListView {
+                id: itemListView
+
                 property bool centeredGroup: true
 
                 orientation: ListView.Horizontal
diff --git a/src/app/mainview/components/CallButtonDelegate.qml b/src/app/mainview/components/CallButtonDelegate.qml
index 054b7e0a7ffcb48a72142a973eb4bce813e303f0..5726555764639573c69922cba008ea2a893d8c00 100644
--- a/src/app/mainview/components/CallButtonDelegate.qml
+++ b/src/app/mainview/components/CallButtonDelegate.qml
@@ -299,8 +299,8 @@ ItemDelegate {
                 if (isVertical)
                     return -implicitWidth - 12
                 var xValue = -(implicitWidth - root.width) / 2 - 18
-                var mainPoint = mapToItem(mainView, xValue, y)
-                var diff = mainPoint.x + itemListView.implicitWidth - mainView.width
+                var mainPoint = mapToItem(viewCoordinator.rootView, xValue, y)
+                var diff = mainPoint.x + itemListView.implicitWidth - viewCoordinator.rootView.width
                 return diff > 0 ? xValue - diff - 24 : xValue
             }
 
diff --git a/src/app/mainview/components/CallOverlay.qml b/src/app/mainview/components/CallOverlay.qml
index 3e51c48cf407c049ed5f2f59f98be3e0777558b1..d6123739a13f0ff2a7a496b78df4974e1a4793c7 100644
--- a/src/app/mainview/components/CallOverlay.qml
+++ b/src/app/mainview/components/CallOverlay.qml
@@ -42,7 +42,6 @@ Item {
     signal closeClicked
 
     function closeContextMenuAndRelatedWindows() {
-        ContactPickerCreation.closeContactPicker()
         sipInputPanel.close()
         ScreenRubberBandCreation.destroyScreenRubberBandWindow()
         PluginHandlerPickerCreation.closePluginHandlerPicker()
@@ -91,14 +90,17 @@ Item {
         }
     }
 
-    JamiFileDialog {
-        id: jamiFileDialog
-
-        mode: JamiFileDialog.Mode.OpenFile
-
-        onAccepted: {
-            AvAdapter.shareFile(jamiFileDialog.file)
-        }
+    function openShareFileDialog() {
+        var dlg = viewCoordinator.presentDialog(
+                    appWindow,
+                    "commoncomponents/JamiFileDialog.qml",
+                    {
+                        fileMode: JamiFileDialog.OpenFile,
+                        nameFilters: [JamiStrings.allFiles]
+                    })
+        dlg.fileAccepted.connect(function(file) {
+            AvAdapter.shareFile(file)
+        })
     }
 
     ResponsiveImage {
@@ -116,8 +118,7 @@ Item {
     }
 
     function openContactPicker(type) {
-        ContactPickerCreation.createContactPickerObjects(type, root)
-        ContactPickerCreation.openContactPicker()
+        ContactPickerCreation.presentContactPickerPopup(type, root)
     }
 
     function openShareScreen() {
@@ -168,7 +169,7 @@ Item {
             function onStopSharingClicked() { AvAdapter.stopSharing(CurrentCall.sharingSource) }
             function onShareScreenAreaClicked() { openShareScreenArea() }
             function onRecordCallClicked() { CallAdapter.recordThisCallToggle() }
-            function onShareFileClicked() { jamiFileDialog.open() }
+            function onShareFileClicked() { openShareFileDialog() }
             function onPluginsClicked() { openPluginsMenu() }
             function onFullScreenClicked() { root.fullScreenClicked() }
         }
diff --git a/src/app/mainview/components/CallStackView.qml b/src/app/mainview/components/CallStackView.qml
index a9bc0178c46141db6d0a965ff23c71b545b7ab95..c5b4419fe1793489c3b0254e18fc254304a2c19e 100644
--- a/src/app/mainview/components/CallStackView.qml
+++ b/src/app/mainview/components/CallStackView.qml
@@ -18,6 +18,7 @@
 
 import QtQuick
 import QtQuick.Controls
+import QtQuick.Layouts
 
 import net.jami.Models 1.1
 import net.jami.Adapters 1.1
@@ -25,9 +26,11 @@ import net.jami.Constants 1.1
 
 import "../../commoncomponents"
 
-Rectangle {
+Item {
     id: root
 
+    property alias chatViewContainer: ongoingCallPage.chatViewContainer
+
     property var sipKeys: [
         "1", "2", "3", "A",
         "4", "5", "6", "B",
@@ -35,11 +38,6 @@ Rectangle {
         "*", "0", "#", "D"
     ]
 
-    enum StackNumber {
-        InitialPageStack,
-        OngoingPageStack
-    }
-
     Shortcut {
         sequence: "Ctrl+D"
         context: Qt.ApplicationShortcut
@@ -58,54 +56,13 @@ Rectangle {
         }
     }
 
-    // When selected conversation is changed,
-    // these values will also be changed.
-    property string responsibleConvUid: ""
-    property string responsibleAccountId: ""
-
     // TODO: this should all be done by listening to
     // parent visibility change or parent `Component.onDestruction`
     function needToCloseInCallConversationAndPotentialWindow() {
-        // Close potential window, context menu releated windows.
         ongoingCallPage.closeInCallConversation()
         ongoingCallPage.closeContextMenuAndRelatedWindows()
     }
 
-    function setLinkedWebview(webViewId) {
-        ongoingCallPage.setLinkedWebview(webViewId)
-    }
-
-    function getItemFromStack(itemNumber) {
-        return callStackMainView.find(function (item) {
-            return item.stackNumber === itemNumber
-        })
-    }
-
-    function showInitialCallPage(callState, isAudioOnly) {
-        var itemToFind = getItemFromStack(CallStackView.InitialPageStack)
-        if (!itemToFind) {
-            callStackMainView.push(initialCallPage, StackView.Immediate)
-        } else {
-            callStackMainView.pop(itemToFind, StackView.Immediate)
-        }
-        initialCallPage.callStatus = callState
-        initialCallPage.isAudioOnly = isAudioOnly
-        if (initialCallPage.callStatus === Call.Status.INCOMING_RINGING)
-            initialCallPage.isIncoming = true
-        else
-            initialCallPage.isIncoming = false
-    }
-
-    function showOngoingCallPage() {
-        var itemToFind = getItemFromStack(CallStackView.OngoingPageStack)
-        if (!itemToFind) {
-            callStackMainView.push(ongoingCallPage, StackView.Immediate)
-        } else {
-            callStackMainView.pop(itemToFind, StackView.Immediate)
-        }
-        ongoingCallPage.accountPeerPair = [responsibleAccountId, responsibleConvUid]
-    }
-
     function toggleFullScreen() {
         if (!layoutManager.isCallFullscreen) {
             layoutManager.pushFullScreenItem(
@@ -119,47 +76,29 @@ Rectangle {
         }
     }
 
-    Connections {
-        target: CallAdapter
-
-        function onCallStatusChanged(status, accountId, convUid) {
-            if (callStackMainView.currentItem.stackNumber === CallStackView.InitialPageStack
-                    && responsibleConvUid === convUid && responsibleAccountId === accountId) {
-                initialCallPage.callStatus = status
-            }
-        }
-    }
-
-    OngoingCallPage {
-        id: ongoingCallPage
-
-        property int stackNumber: CallStackView.OngoingPageStack
-
-        visible: callStackMainView.currentItem.stackNumber === stackNumber
-    }
-
-    InitialCallPage {
-        id: initialCallPage
-
-        property int stackNumber: CallStackView.InitialPageStack
-
-        onCallAccepted: {
-            CallAdapter.acceptACall(responsibleAccountId, responsibleConvUid)
-            mainViewSidePanel.selectTab(SidePanelTabBar.Conversations)
-        }
-
-        onCallCanceled: {
-            CallAdapter.hangUpACall(responsibleAccountId, responsibleConvUid)
-        }
-
-        visible: callStackMainView.currentItem.stackNumber === stackNumber
-    }
-
-    StackView {
+    StackLayout {
         id: callStackMainView
 
         anchors.fill: parent
 
-        initialItem: initialCallPage
+        property Item currentItem: itemAt(currentIndex)
+
+        currentIndex: {
+            switch (CurrentCall.status) {
+            case Call.Status.IN_PROGRESS:
+            case Call.Status.CONNECTED:
+            case Call.Status.PAUSED:
+                return 1
+            case Call.Status.SEARCHING:
+            case Call.Status.CONNECTING:
+            case Call.Status.INCOMING_RINGING:
+            case Call.Status.OUTGOING_RINGING:
+            default:
+                return 0
+            }
+        }
+
+        InitialCallPage {}
+        OngoingCallPage { id: ongoingCallPage }
     }
 }
diff --git a/src/app/mainview/components/ChatView.qml b/src/app/mainview/components/ChatView.qml
index f2a207035eb38c3c47d349754effcabedc859a4a..a56e328a1433c4440c0ab4ec727a619b65d0ae91 100644
--- a/src/app/mainview/components/ChatView.qml
+++ b/src/app/mainview/components/ChatView.qml
@@ -33,35 +33,26 @@ import "../js/pluginhandlerpickercreation.js" as PluginHandlerPickerCreation
 Rectangle {
     id: root
 
-    property bool allMessagesLoaded
+    color: JamiTheme.chatviewBgColor
+
     property var mapPositions: PositionManager.mapStatus
-    property var inCallView: false
 
     property int lastContentsSplitSize: JamiTheme.detailsPageMinWidth
     property int lastDetailsSplitSize: JamiTheme.detailsPageMinWidth
     property int previousWidth: width
+    required property bool inCallView
 
-    signal needToHideConversationInCall
-    signal messagesCleared
-    signal messagesLoaded
+    signal dismiss
 
-    onInCallViewChanged: {
-        notificationArea.visible = CurrentConversation.activeCalls.length > 0 && !root.inCallView
+    function focusChatView() {
+        chatViewFooter.updateMessageDraft()
+        chatViewFooter.textInput.forceActiveFocus()
     }
 
-    onVisibleChanged: {
-        if (visible)
-            return
+    function resetPanels() {
         swarmDetailsPanel.visible = false
         addMemberPanel.visible = false
         chatContents.visible = true
-        UtilsAdapter.clearInteractionsCache(CurrentAccount.id, CurrentConversation.id)
-    }
-
-    function focusChatView() {
-        chatViewFooter.textInput.forceActiveFocus()
-        swarmDetailsPanel.visible = false
-        addMemberPanel.visible = false
     }
 
     function instanceMapObject() {
@@ -75,20 +66,19 @@ Rectangle {
             }
         }
     }
+
     Connections {
         target: PositionManager
-
         function onOpenNewMap() {
             instanceMapObject()
         }
     }
 
-    color: JamiTheme.chatviewBgColor
-
-    property string currentConvId: CurrentConversation.id
-
-    HostPopup {
-        id: hostPopup
+    Connections {
+        target: CurrentConversation
+        function onIdChanged() {
+            MessagesAdapter.loadMoreMessages()
+        }
     }
 
     ColumnLayout {
@@ -110,13 +100,7 @@ Rectangle {
                 onDropped: chatViewFooter.setFilePathsToSend(drop.urls)
             }
 
-            onBackClicked: {
-                mainView.showWelcomeView()
-            }
-
-            onNeedToHideConversationInCall: {
-                root.needToHideConversationInCall()
-            }
+            onBackClicked: root.dismiss()
 
             onShowDetailsClicked: {
                 addMemberPanel.visible = false
@@ -130,15 +114,15 @@ Rectangle {
             }
 
             onWidthChanged: {
-                var isExpanding = previousWidth < width
-
+                const isExpanding = previousWidth < width
                 if (!swarmDetailsPanel.visible && !addMemberPanel.visible)
                     return
-
                 if (chatViewHeader.width < JamiTheme.detailsPageMinWidth + JamiTheme.chatViewHeaderMinimumWidth
                     && !isExpanding && chatContents.visible) {
                     lastContentsSplitSize = chatContents.width
-                    lastDetailsSplitSize = swarmDetailsPanel.visible ? swarmDetailsPanel.width : addMemberPanel.width
+                    lastDetailsSplitSize = Math.min(JamiTheme.detailsPageMinWidth, (swarmDetailsPanel.visible ?
+                                                                                        swarmDetailsPanel.width :
+                                                                                        addMemberPanel.width))
                     chatContents.visible = false
                 } else if (chatViewHeader.width >= JamiTheme.chatViewHeaderMinimumWidth + lastDetailsSplitSize
                          && isExpanding && !layoutManager.isFullScreen && !chatContents.visible) {
@@ -158,7 +142,9 @@ Rectangle {
                 }
 
                 function onNeedsHost() {
-                    hostPopup.open()
+                    viewCoordinator.presentDialog(
+                                appWindow,
+                                "mainview/components/HostPopup.qml")
                 }
             }
 
@@ -245,18 +231,18 @@ Rectangle {
 
             handle: Rectangle {
                 implicitWidth: JamiTheme.splitViewHandlePreferredWidth
-                implicitHeight: splitView.height
+                implicitHeight: viewCoordinator.splitView.height
                 color: JamiTheme.primaryBackgroundColor
                 Rectangle {
                     implicitWidth: 1
-                    implicitHeight: splitView.height
+                    implicitHeight: viewCoordinator.splitView.height
                     color: JamiTheme.tabbarBorderColor
                 }
             }
 
             ColumnLayout {
                 id: chatContents
-                SplitView.maximumWidth: splitView.width
+                SplitView.maximumWidth: viewCoordinator.splitView.width
                 SplitView.minimumWidth: JamiTheme.chatViewHeaderMinimumWidth
 
                 SplitView.preferredWidth: chatViewHeader.width -
@@ -333,7 +319,7 @@ Rectangle {
                 id: swarmDetailsPanel
                 visible: false
 
-                SplitView.maximumWidth: splitView.width
+                SplitView.maximumWidth: viewCoordinator.splitView.width
                 SplitView.preferredWidth: JamiTheme.detailsPageMinWidth
                 SplitView.minimumWidth: JamiTheme.detailsPageMinWidth
             }
@@ -342,7 +328,7 @@ Rectangle {
                 id: addMemberPanel
                 visible: false
 
-                SplitView.maximumWidth: splitView.width
+                SplitView.maximumWidth: viewCoordinator.splitView.width
                 SplitView.preferredWidth: JamiTheme.detailsPageMinWidth
                 SplitView.minimumWidth: JamiTheme.detailsPageMinWidth
             }
diff --git a/src/app/mainview/components/ChatViewFooter.qml b/src/app/mainview/components/ChatViewFooter.qml
index 5dcbe0f0138de55d556a681184acaf84835eef8b..ce840d554644b4ce8aaed7a2804c9b85ed5980d7 100644
--- a/src/app/mainview/components/ChatViewFooter.qml
+++ b/src/app/mainview/components/ChatViewFooter.qml
@@ -30,8 +30,8 @@ Rectangle {
     id: root
 
     property alias textInput: messageBar.textAreaObj
-    property string previousConvId: ""
-    property string previousAccountId: ""
+    property string previousConvId
+    property string previousAccountId
 
     function setFilePathsToSend(filePaths) {
         for (var index = 0; index < filePaths.length; ++index) {
@@ -44,39 +44,34 @@ Rectangle {
 
     color: JamiTheme.primaryBackgroundColor
 
-    Connections {
-        target: LRCInstance
+    function updateMessageDraft() {
+        LRCInstance.setContentDraft(previousConvId,
+                                    previousAccountId,
+                                    messageBar.text);
 
-        function onSelectedConvUidChanged() {
-            // Handle Draft
-            if (previousConvId !== "" && previousAccountId != "") {
-                LRCInstance.setContentDraft(previousConvId, previousAccountId,
-                                            messageBar.text);
-            }
+        previousConvId = CurrentConversation.id
+        previousAccountId = CurrentAccount.id
 
-            // turn off the button animations when switching convs
-            messageBar.animate = false
+        // turn off the button animations when switching convs
+        messageBar.animate = false
+        messageBar.textAreaObj.clearText()
 
-            messageBar.textAreaObj.clearText()
-            previousConvId = LRCInstance.selectedConvUid
-            previousAccountId = LRCInstance.currentAccountId
+        var restoredContent = LRCInstance.getContentDraft(CurrentConversation.id,
+                                                          CurrentAccount.id);
+        if (restoredContent) {
+            messageBar.textAreaObj.insertText(restoredContent)
+        }
+    }
 
-            var restoredContent = LRCInstance.getContentDraft(LRCInstance.selectedConvUid,
-                                                              LRCInstance.currentAccountId);
-            if (restoredContent)
-                messageBar.textAreaObj.insertText(restoredContent)
+    Connections {
+        target: CurrentConversation
 
-            messageBar.animate = true
-        }
+        function onIdChanged() { messageBar.animate = true }
     }
 
     Connections {
         target: MessagesAdapter
 
-        function onNewMessageBarPlaceholderText(placeholderText) {
-            messageBar.textAreaObj.placeholderText = JamiStrings.writeTo.arg(placeholderText)
-        }
-
         function onNewFilePasted(filePath) {
             dataTransferSendContainer.filesToSendListModel.addToPending(filePath)
         }
@@ -106,14 +101,6 @@ Rectangle {
         visible: false
     }
 
-    JamiFileDialog {
-        id: jamiFileDialog
-
-        mode: JamiFileDialog.Mode.OpenFiles
-
-        onAccepted: setFilePathsToSend(jamiFileDialog.files)
-    }
-
     ColumnLayout {
         id: footerColumnLayout
 
@@ -193,7 +180,19 @@ Rectangle {
                 PositionManager.setMapActive(CurrentAccount.id)
             }
 
-            onSendFileButtonClicked: jamiFileDialog.open()
+            onSendFileButtonClicked: {
+                var dlg = viewCoordinator.presentDialog(
+                            appWindow,
+                            "commoncomponents/JamiFileDialog.qml",
+                            {
+                                fileMode: JamiFileDialog.OpenFiles,
+                                nameFilters: [JamiStrings.allFiles]
+                            })
+                dlg.filesAccepted.connect(function(files) {
+                    setFilePathsToSend(files)
+                })
+            }
+
             onSendMessageButtonClicked: {
                 // Send text message
                 if (messageBar.text) {
diff --git a/src/app/mainview/components/ChatViewHeader.qml b/src/app/mainview/components/ChatViewHeader.qml
index dbb3b5c1a8c0809677821643455ab264dc68a869..66a820928f6981d19a6f7749b2552f2eb5224f08 100644
--- a/src/app/mainview/components/ChatViewHeader.qml
+++ b/src/app/mainview/components/ChatViewHeader.qml
@@ -31,7 +31,6 @@ Rectangle {
     id: root
 
     signal backClicked
-    signal needToHideConversationInCall
     signal addToConversationClicked
     signal pluginSelector
     signal showDetailsClicked
@@ -87,9 +86,7 @@ Rectangle {
             normalColor: JamiTheme.chatviewBgColor
             imageColor: JamiTheme.chatviewButtonColor
 
-            onClicked: CurrentConversation.inCall ?
-                           root.needToHideConversationInCall() :
-                           root.backClicked()
+            onClicked: root.backClicked()
         }
 
         Rectangle {
@@ -133,7 +130,7 @@ Rectangle {
                     Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
 
                     visible: text.length &&
-                             CurrentConversation.title != CurrentConversation.description
+                             CurrentConversation.title !== CurrentConversation.description
                     font.pointSize: JamiTheme.textFontSize
                     color: JamiTheme.faddedLastInteractionFontColor
 
diff --git a/src/app/mainview/components/ConversationListView.qml b/src/app/mainview/components/ConversationListView.qml
index 06a2421d64856664514473dd97103358f94d9f4e..363dff5d02e4ff61bf698d81e9583b7d15399cd9 100644
--- a/src/app/mainview/components/ConversationListView.qml
+++ b/src/app/mainview/components/ConversationListView.qml
@@ -75,11 +75,6 @@ JamiListView {
 
     onCountChanged: positionViewAtBeginning()
 
-    Component.onCompleted: {
-        // TODO: remove this
-        ConversationsAdapter.setQmlObject(this)
-    }
-
     add: Transition {
         NumberAnimation {
             property: "opacity"; from: 0; to: 1.0
@@ -113,42 +108,31 @@ JamiListView {
     ConversationSmartListContextMenu {
         id: contextMenu
 
-        property var index: -1
+        property int index: -1
 
         function openMenuAt(x, y) {
             contextMenu.x = x
             contextMenu.y = y
 
-            // TODO:
-            // - accountId, convId only
-            // - userProfile dialog should use a loader/popup
-
-            var row = root.indexAt(x, y + root.contentY)
-            index = row
-            var item = {
-                "convId": model.dataForRow(row, ConversationList.UID),
-                "displayId": model.dataForRow(row, ConversationList.BestId),
-                "title": model.dataForRow(row, ConversationList.Title),
-                "uri": model.dataForRow(row, ConversationList.URI),
-                "isBanned": model.dataForRow(row, ConversationList.IsBanned),
-                "mode": model.dataForRow(row, ConversationList.Mode),
-                "isCoreDialog": model.dataForRow(row, ConversationList.IsCoreDialog),
-                "isTemporary": model.dataForRow(row, ConversationList.ContactType) === Profile.Type.TEMPORARY,
-            }
+            index = root.indexAt(x, y + root.contentY)
 
+            // TODO: use accountId and convId only
             responsibleAccountId = LRCInstance.currentAccountId
-            responsibleConvUid = item.convId
-            isBanned = item.isBanned
-            mode = item.mode
-            isCoreDialog = item.isCoreDialog
+            responsibleConvUid = model.dataForRow(index, ConversationList.UID)
+            isBanned = model.dataForRow(index, ConversationList.IsBanned)
+            mode = model.dataForRow(index, ConversationList.Mode)
+            isCoreDialog = model.dataForRow(index, ConversationList.IsCoreDialog)
             contactType = LRCInstance.currentAccountType
-            readOnly = mode === Conversation.Mode.NON_SWARM && !item.isTemporary && CurrentAccount.type !== Profile.Type.SIP
-
-            if (model.dataForRow(row, ConversationList.IsCoreDialog)) {
-                userProfile.aliasText = item.title
-                userProfile.registeredNameText = item.displayId
-                userProfile.idText = item.uri
-                userProfile.convId = item.convId
+            readOnly = mode === Conversation.Mode.NON_SWARM &&
+                    (model.dataForRow(index, ConversationList.ContactType) !==
+                                                   Profile.Type.TEMPORARY) &&
+                    CurrentAccount.type !== Profile.Type.SIP
+
+            // For UserProfile dialog.
+            if (isCoreDialog) {
+                aliasText = model.dataForRow(index, ConversationList.Title)
+                registeredNameText = model.dataForRow(index, ConversationList.BestId)
+                idText = model.dataForRow(index, ConversationList.URI)
             }
 
             openMenu()
@@ -182,18 +166,16 @@ JamiListView {
         context: Qt.ApplicationShortcut
         enabled: root.visible
         onActivated: MessagesAdapter.clearConversationHistory(
-                         LRCInstance.currentAccountId,
-                         LRCInstance.selectedConvUid)
+                         CurrentAccount.id,
+                         CurrentConversation.id)
     }
 
     Shortcut {
         sequence: "Ctrl+Shift+B"
         context: Qt.ApplicationShortcut
         enabled: root.visible
-        onActivated: {
-            MessagesAdapter.blockConversation(
-                        LRCInstance.selectedConvUid)
-        }
+        onActivated: MessagesAdapter.blockConversation(
+                         CurrentConversation.id)
     }
 
     Shortcut {
diff --git a/src/app/mainview/components/ConversationSmartListContextMenu.qml b/src/app/mainview/components/ConversationSmartListContextMenu.qml
index ccaf083735f84e3fa462eb48ea93a54958c2d152..291c8b5786cfcf17d02a5a4212410439ec21a92c 100644
--- a/src/app/mainview/components/ConversationSmartListContextMenu.qml
+++ b/src/app/mainview/components/ConversationSmartListContextMenu.qml
@@ -30,29 +30,6 @@ ContextMenuAutoLoader {
 
     signal showSwarmDetails
 
-    ConfirmDialog {
-        id: rmDialog
-
-        title: JamiStrings.confirmAction
-        textLabel: JamiStrings.confirmRmConversation
-        confirmLabel: JamiStrings.optionRemove
-        onAccepted: {
-            if (!isCoreDialog)
-                MessagesAdapter.removeConversation(responsibleConvUid)
-            else
-                MessagesAdapter.removeContact(responsibleConvUid)
-        }
-    }
-
-    ConfirmDialog {
-        id: blockDialog
-
-        title: JamiStrings.confirmAction
-        textLabel: JamiStrings.confirmBlockConversation
-        confirmLabel: JamiStrings.optionBlock
-        onAccepted: MessagesAdapter.blockConversation(responsibleConvUid)
-    }
-
     property string responsibleAccountId: ""
     property string responsibleConvUid: ""
     property bool isBanned: false
@@ -67,6 +44,11 @@ ContextMenuAutoLoader {
     }
     property bool readOnly
 
+    // For UserProfile dialog.
+    property string aliasText
+    property string registeredNameText
+    property string idText
+
     property list<GeneralMenuItem> menuItems: [
         GeneralMenuItem {
             id: startVideoCallItem
@@ -114,7 +96,22 @@ ContextMenuAutoLoader {
                     return JamiStrings.removeContact
             }
             iconSource: JamiResources.ic_hangup_participant_24dp_svg
-            onClicked: rmDialog.open()
+            onClicked: {
+                var dlg = viewCoordinator.presentDialog(
+                            appWindow,
+                            "commoncomponents/ConfirmDialog.qml",
+                            {
+                                title: JamiStrings.confirmAction,
+                                textLabel: JamiStrings.confirmRmConversation,
+                                confirmLabel: JamiStrings.optionRemove
+                            })
+                dlg.accepted.connect(function() {
+                    if (!isCoreDialog)
+                        MessagesAdapter.removeConversation(responsibleConvUid)
+                    else
+                        MessagesAdapter.removeContact(responsibleConvUid)
+                })
+            }
         },
         GeneralMenuItem {
             id: hangup
@@ -151,7 +148,19 @@ ContextMenuAutoLoader {
             itemName: !(mode && isCoreDialog) ? JamiStrings.blockContact : JamiStrings.blockSwarm
             iconSource: JamiResources.block_black_24dp_svg
             addMenuSeparatorAfter: canTrigger
-            onClicked: blockDialog.open()
+            onClicked: {
+                var dlg = viewCoordinator.presentDialog(
+                            appWindow,
+                            "commoncomponents/ConfirmDialog.qml",
+                            {
+                                title: JamiStrings.confirmAction,
+                                textLabel: JamiStrings.confirmBlockConversation,
+                                confirmLabel: JamiStrings.optionBlock
+                            })
+                dlg.accepted.connect(function() {
+                    MessagesAdapter.blockConversation(responsibleConvUid)
+                })
+            }
         },
         GeneralMenuItem {
             id: unblockContact
@@ -169,10 +178,19 @@ ContextMenuAutoLoader {
             itemName: isCoreDialog ? JamiStrings.contactDetails : JamiStrings.convDetails
             iconSource: JamiResources.person_24dp_svg
             onClicked: {
-                if (isCoreDialog)
-                    userProfile.open()
-                else
+                if (isCoreDialog) {
+                    viewCoordinator.presentDialog(
+                                appWindow,
+                                "mainview/components/UserProfile.qml",
+                                {
+                                    aliasText: aliasText,
+                                    registeredNameText: registeredNameText,
+                                    idText: idText,
+                                    convId: responsibleConvUid
+                                })
+                } else {
                     root.showSwarmDetails()
+                }
             }
         }
     ]
diff --git a/src/app/mainview/components/FilterTabButton.qml b/src/app/mainview/components/FilterTabButton.qml
index a57872dd34892be672344c61d16b2485a3a365c3..caa40094c6cd1701c1c4ac6829e4062ba914152f 100644
--- a/src/app/mainview/components/FilterTabButton.qml
+++ b/src/app/mainview/components/FilterTabButton.qml
@@ -84,7 +84,9 @@ TabButton {
     }
 
     Rectangle {
-        width: underlineContentOnly ? informations.width + JamiTheme.menuBorderPreferredHeight : contentRect.width
+        width: underlineContentOnly ?
+                   informations.width + JamiTheme.menuBorderPreferredHeight :
+                   contentRect.width
         anchors.horizontalCenter: contentRect.horizontalCenter
         anchors.bottom: contentRect.bottom
         height: borderWidth
diff --git a/src/app/mainview/components/HostPopup.qml b/src/app/mainview/components/HostPopup.qml
index ec8593ec1c93691ce52b07f2e42fb575f9d1a6bc..ad65a86e5b0b0643316e64ab2e25ee02fcb36093 100644
--- a/src/app/mainview/components/HostPopup.qml
+++ b/src/app/mainview/components/HostPopup.qml
@@ -108,4 +108,4 @@ BaseModalDialog {
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/app/mainview/components/InitialCallPage.qml b/src/app/mainview/components/InitialCallPage.qml
index dac1050fc928fb195e2f9c4e0b2e0781d8521157..fb52052f319c20baf883a5086e1f6954b958c970 100644
--- a/src/app/mainview/components/InitialCallPage.qml
+++ b/src/app/mainview/components/InitialCallPage.qml
@@ -30,25 +30,24 @@ import "../../commoncomponents"
 Rectangle {
     id: root
 
-    property bool isIncoming: false
-    property bool isAudioOnly: CurrentCall.isAudioOnly
-    property int callStatus: 0
-
     signal callCanceled
     signal callAccepted
 
+    onCallAccepted: CallAdapter.acceptACall(CurrentAccount.id, CurrentConversation.id)
+    onCallCanceled: CallAdapter.hangUpACall(CurrentAccount.id, CurrentConversation.id)
+
     color: "black"
 
     LocalVideo {
         id: previewRenderer
         anchors.centerIn: parent
         anchors.fill: parent
-        visible: !root.isAudioOnly &&
+        visible: !CurrentCall.isAudioOnly &&
                  CurrentAccount.videoEnabled_Video &&
                  VideoDevices.listSize !== 0 &&
-                 ((callStatus >= Call.Status.INCOMING_RINGING
-                   && callStatus <= Call.Status.SEARCHING)
-                  || callStatus === Call.Status.CONNECTED)
+                 ((CurrentCall.status >= Call.Status.INCOMING_RINGING
+                   && CurrentCall.status <= Call.Status.SEARCHING)
+                  || CurrentCall.status === Call.Status.CONNECTED)
         opacity: 0.5
 
         // HACK: this is a workaround to the preview video starting
@@ -150,8 +149,8 @@ Rectangle {
             property string title: CurrentConversation.title
 
             text: {
-                if (root.isIncoming)
-                    return root.isAudioOnly ?
+                if (!CurrentCall.isOutgoing)
+                    return CurrentCall.isAudioOnly ?
                                 JamiStrings.incomingAudioCallFrom.replace("{}", title) :
                                 JamiStrings.incomingVideoCallFrom.replace("{}", title)
                 else
@@ -159,7 +158,7 @@ Rectangle {
             }
             wrapMode: Text.WordWrap
             elide: Text.ElideRight
-            maximumLineCount: root.isIncoming ? 2 : 1
+            maximumLineCount: !CurrentCall.isOutgoing ? 2 : 1
             color: "white"
         }
 
@@ -173,9 +172,9 @@ Rectangle {
             horizontalAlignment: Text.AlignHCenter
             verticalAlignment: Text.AlignVCenter
 
-            text: UtilsAdapter.getCallStatusStr(callStatus) + "…"
+            text: UtilsAdapter.getCallStatusStr(CurrentCall.status) + "…"
             color: JamiTheme.whiteColor
-            visible: !root.isIncoming
+            visible: CurrentCall.isOutgoing
         }
 
         RowLayout {
@@ -184,10 +183,10 @@ Rectangle {
 
             Repeater {
                 id: controlButtons
-                model: root.isIncoming ? incomingControlsModel : outgoingControlsModel
+                model: !CurrentCall.isOutgoing ? incomingControlsModel : outgoingControlsModel
 
                 delegate: ColumnLayout {
-                    visible: (type === "cam" && root.isAudioOnly) ? false : true;
+                    visible: (type === "cam" && CurrentCall.isAudioOnly) ? false : true
 
                     PushButton {
                         id: actionButton
@@ -223,7 +222,7 @@ Rectangle {
                                     acceptVideoMedia = true
                                 else if ( type === "mic" )
                                     acceptVideoMedia = false
-                                CallAdapter.setCallMedia(responsibleAccountId, responsibleConvUid, acceptVideoMedia)
+                                CallAdapter.setCallMedia(CurrentAccount.id, CurrentConversation.id, acceptVideoMedia)
                                 callAccepted()
                             } else {
                                 callCanceled()
@@ -248,7 +247,7 @@ Rectangle {
                             else if (type === "cam")
                                 return JamiStrings.acceptVideo
                             else if (type === "mic")
-                                return root.isAudioOnly ? JamiStrings.accept : JamiStrings.acceptAudio
+                                return CurrentCall.isAudioOnly ? JamiStrings.accept : JamiStrings.acceptAudio
                             else if (type === "cancel")
                                 return JamiStrings.endCall
                             return ""
diff --git a/src/app/mainview/components/JamiIdentifier.qml b/src/app/mainview/components/JamiIdentifier.qml
index 83f9fa950fc1468623de3ae2e8d35a4db5d6d217..a7664cf919c40edcd717d1c3d049e4afcf5267a0 100644
--- a/src/app/mainview/components/JamiIdentifier.qml
+++ b/src/app/mainview/components/JamiIdentifier.qml
@@ -30,12 +30,6 @@ import "../../settingsview/components"
 Item {
     id: root
 
-    NameRegistrationDialog {
-        id : nameRegistrationDialog
-        onAccepted: usernameTextEdit.nameRegistrationState =
-                    UsernameLineEdit.NameRegistrationState.BLANK
-    }
-
     width: childrenRect.width
     height: controlsLayout.height + usernameTextEdit.height
             + 2 * JamiTheme.preferredMarginSize
@@ -154,7 +148,19 @@ Item {
             Layout.rightMargin: JamiTheme.preferredMarginSize
             fontPointSize: JamiTheme.textFontSize + 1
 
-            onAccepted: nameRegistrationDialog.openNameRegistrationDialog(dynamicText)
+            onAccepted: {
+                if (dynamicText === '') {
+                    return
+                }
+                var dlg = viewCoordinator.presentDialog(
+                            appWindow,
+                            "settingsview/components/NameRegistrationDialog.qml",
+                            { registeredName: dynamicText })
+                dlg.accepted.connect(function() {
+                    currentRegisteredID.nameRegistrationState =
+                            UsernameLineEdit.NameRegistrationState.BLANK
+                })
+            }
         }
     }
 }
diff --git a/src/app/mainview/components/MainOverlay.qml b/src/app/mainview/components/MainOverlay.qml
index e5cd2cb38263449b0fefc9ad0d6ca75c5fea9184..86d6b282a71b5d59c58fee47e8abbe2d51cadfbd 100644
--- a/src/app/mainview/components/MainOverlay.qml
+++ b/src/app/mainview/components/MainOverlay.qml
@@ -68,10 +68,10 @@ Item {
 
     // (un)subscribe to an app-wide mouse move event trap filtered
     // for the overlay's geometry
-    onVisibleChanged: visible ? CallOverlayModel.registerFilter(
-                                    appWindow,
-                                    this) : CallOverlayModel.unregisterFilter(
-                                    appWindow, this)
+    onVisibleChanged: {
+        visible ? CallOverlayModel.registerFilter(appWindow, this) :
+                  CallOverlayModel.unregisterFilter(appWindow, this)
+    }
 
     Connections {
         target: CallOverlayModel
@@ -84,7 +84,6 @@ Item {
         }
     }
 
-
     Shortcut {
         sequence: "M"
         enabled: root.visible
@@ -129,7 +128,7 @@ Item {
             root.timeText = CallAdapter.getCallDurationTime(
                         LRCInstance.currentAccountId,
                         LRCInstance.selectedConvUid)
-            if (root.opacity === 0 && !CurrentCall.isRecordingRemotely)
+            if (!root.opacity && !CurrentCall.isRecordingRemotely)
                 root.remoteRecordingLabel = ""
         }
     }
diff --git a/src/app/mainview/components/MessageBar.qml b/src/app/mainview/components/MessageBar.qml
index a856ecb437834427605602f10abb6e8d3d1dea4b..3ca1e60313233f1405b615b7acbe39a259cea362 100644
--- a/src/app/mainview/components/MessageBar.qml
+++ b/src/app/mainview/components/MessageBar.qml
@@ -162,6 +162,8 @@ ColumnLayout {
                     textAreaObj.forceActiveFocus()
             }
 
+            placeholderText: JamiStrings.writeTo.arg(CurrentConversation.title)
+
             Layout.alignment: Qt.AlignVCenter
             Layout.fillWidth: true
             Layout.margins: marginSize / 2
diff --git a/src/app/mainview/components/MessageListView.qml b/src/app/mainview/components/MessageListView.qml
index 2e79c2f256dd5d4fab0cf5167eb7b105a06a3f64..ce5698d7c428ad2d0ce7affabd3fffc8730f55dc 100644
--- a/src/app/mainview/components/MessageListView.qml
+++ b/src/app/mainview/components/MessageListView.qml
@@ -168,9 +168,6 @@ JamiListView {
 
     topMargin: 12
     spacing: 2
-    anchors.centerIn: parent
-    height: parent.height
-    width: parent.width
     // this offscreen caching is pretty huge
     // displayMarginEnd may be removed
 
diff --git a/src/app/mainview/components/NewSwarmPage.qml b/src/app/mainview/components/NewSwarmPage.qml
index 20f195ffccf224d30cec45a2a3d54cb95382922f..a529cf1d580d09fbcdede5585cad99166b1a3539 100644
--- a/src/app/mainview/components/NewSwarmPage.qml
+++ b/src/app/mainview/components/NewSwarmPage.qml
@@ -26,8 +26,7 @@ import net.jami.Constants 1.1
 
 import "../../commoncomponents"
 
-
-Rectangle {
+BaseView {
     id: root
 
     color: JamiTheme.chatviewBgColor
@@ -217,9 +216,9 @@ Rectangle {
 
             text: JamiStrings.createTheSwarm
 
-            onClicked: {
-                createSwarmClicked(title.text, description.text, UtilsAdapter.tempCreationImage())
-            }
+            onClicked: createSwarmClicked(title.text,
+                                          description.text,
+                                          UtilsAdapter.tempCreationImage())
         }
     }
 }
diff --git a/src/app/mainview/components/OngoingCallPage.qml b/src/app/mainview/components/OngoingCallPage.qml
index 21c079fa4421d1fefff0c16c00fd5a0cd9c3160e..ebafe082312cc73d38f687d2aabee9d977efd2be 100644
--- a/src/app/mainview/components/OngoingCallPage.qml
+++ b/src/app/mainview/components/OngoingCallPage.qml
@@ -33,16 +33,13 @@ import "../../commoncomponents"
 Rectangle {
     id: root
 
-    anchors.fill: parent
-
-    property var accountPeerPair: ["", ""]
-    property variant clickPos: "1,1"
+    property point clickPos
     property int previewMargin: 15
     property int previewMarginYTop: previewMargin + 42
     property int previewMarginYBottom: previewMargin + 84
     property int previewToX: 0
     property int previewToY: 0
-    property var linkedWebview: null
+    property alias chatViewContainer: chatViewContainer
     property string callPreviewId
 
     onCallPreviewIdChanged: {
@@ -51,18 +48,11 @@ Rectangle {
 
     color: "black"
 
-    onAccountPeerPairChanged: {
-        if (accountPeerPair[0] === "" || accountPeerPair[1] === "")
-            return
-        contactImage.imageId = accountPeerPair[1]
-    }
-
-    function setLinkedWebview(webViewId) {
-        linkedWebview = webViewId
-        linkedWebview.needToHideConversationInCall.disconnect(
-                    closeInCallConversation)
-        linkedWebview.needToHideConversationInCall.connect(
-                    closeInCallConversation)
+    Connections {
+        target: CurrentConversation
+        function onIdChanged() {
+            if (CurrentConversation.id !== "") contactImage.imageId = CurrentConversation.id
+        }
     }
 
     Connections {
@@ -75,13 +65,11 @@ Rectangle {
 
     function openInCallConversation() {
         mainColumnLayout.isHorizontal = UtilsAdapter.getAppValue(Settings.Key.ShowChatviewHorizontally)
-        inCallMessageWebViewStack.visible = true
-        inCallMessageWebViewStack.push(linkedWebview)
+        chatViewContainer.visible = true
     }
 
     function closeInCallConversation() {
-        inCallMessageWebViewStack.visible = false
-        inCallMessageWebViewStack.clear()
+        chatViewContainer.visible = false
     }
 
     function closeContextMenuAndRelatedWindows() {
@@ -329,10 +317,12 @@ Rectangle {
 
                     function onNewInteraction(id, interactionType) {
                         // Ignore call notifications, as we are in the call.
-                        if (interactionType !== Interaction.Type.CALL && !inCallMessageWebViewStack.visible)
+                        if (interactionType !== Interaction.Type.CALL &&
+                                !chatViewContainer.visible)
                             openInCallConversation()
                     }
                 }
+
                 onCloseClicked: {
                     participantsLayer.hoveredOverlayUri = ""
                     participantsLayer.hoveredOverlaySinkId = ""
@@ -340,7 +330,7 @@ Rectangle {
                 }
 
                 onChatButtonClicked: {
-                    inCallMessageWebViewStack.visible ?
+                    chatViewContainer.visible ?
                                 closeInCallConversation() :
                                 openInCallConversation()
                 }
@@ -352,6 +342,7 @@ Rectangle {
 
             ColumnLayout {
                 id: audioCallPageRectCentralRect
+
                 anchors.centerIn: parent
                 anchors.left: parent.left
                 anchors.right: parent.right
@@ -390,15 +381,16 @@ Rectangle {
             color: "transparent"
         }
 
-        StackView {
-            id: inCallMessageWebViewStack
-
-            SplitView.preferredHeight: mainColumnLayout.isHorizontal ? root.height : root.height / 3
-            SplitView.preferredWidth: mainColumnLayout.isHorizontal ? root.width / 3 : root.width
-            SplitView.fillWidth: false
+        Item {
+            id: chatViewContainer
 
+            SplitView.preferredHeight: mainColumnLayout.isHorizontal ?
+                                           root.height :
+                                           root.height / 3
+            SplitView.preferredWidth: mainColumnLayout.isHorizontal ?
+                                          root.width / 3 :
+                                          root.width
             visible: false
-
             clip: true
         }
     }
diff --git a/src/app/mainview/components/SidePanel.qml b/src/app/mainview/components/SidePanel.qml
index 4a6e00a0acf4f7e47b6ac9d66e6c066ab014b218..dca69069cb8aa3bae6c2770313488c9b9bbfc963 100644
--- a/src/app/mainview/components/SidePanel.qml
+++ b/src/app/mainview/components/SidePanel.qml
@@ -27,14 +27,14 @@ import net.jami.Enums 1.1
 import net.jami.Models 1.1
 
 import "../../commoncomponents"
+import "../../settingsview/components"
 
-Rectangle {
+BaseView {
     id: root
+    objectName: "SidePanel"
 
     color: JamiTheme.backgroundColor
 
-    signal createSwarmClicked
-
     Connections {
         target: LRCInstance
 
@@ -52,6 +52,43 @@ Rectangle {
         }
     }
 
+    Connections {
+        target: ConversationsAdapter
+
+        function onShowSearchStatus(status) {
+            searchStatusText.text = status
+        }
+
+        function onTextFilterChanged(text) {
+            // In the swarm details, "Go to conversation" can
+            // change the search bar. Be sure to be synced
+            contactSearchBar.textContent = text
+        }
+    }
+
+    function toggleCreateSwarmView() {
+        if (!viewCoordinator.inNewSwarm) {
+            viewCoordinator.present("NewSwarmPage")
+            const newSwarmPage = viewCoordinator.currentView
+            newSwarmPage.removeMember.connect((convId, member) => {
+                removeMember(convId, member)
+            })
+            newSwarmPage.createSwarmClicked.connect((title, description, avatar) => {
+                var uris = []
+                for (var idx in newSwarmPage.members) {
+                    var uri = newSwarmPage.members[idx].uri
+                    if (uris.indexOf(uri) === -1) {
+                        uris.push(uri)
+                    }
+                }
+                ConversationsAdapter.createSwarm(title, description, avatar, uris)
+                viewCoordinator.dismiss("NewSwarmPage")
+            })
+        } else {
+            viewCoordinator.dismiss("NewSwarmPage")
+        }
+    }
+
     function clearContactSearchBar() {
         contactSearchBar.clearText()
     }
@@ -62,6 +99,12 @@ Rectangle {
 
     property var highlighted: []
     property var highlightedMembers: []
+    onHighlightedMembersChanged: {
+        if (viewCoordinator.inNewSwarm) {
+            const newSwarmPage = viewCoordinator.getView("NewSwarmPage")
+            newSwarmPage.members = highlightedMembers
+        }
+    }
 
     function refreshHighlighted(convId, highlightedStatus) {
         var newH = root.highlighted
@@ -72,7 +115,8 @@ Rectangle {
             var added = false
             for (var idx in item.uris) {
                 var uri = item.uris[idx]
-                if (!Array.from(newHm).find(r => r.uri === uri) && uri != CurrentAccount.uri) {
+                if (!Array.from(newHm).find(r => r.uri === uri) &&
+                        uri !== CurrentAccount.uri) {
                     newHm.push({"uri": uri, "convId": convId})
                     added = true
                 }
@@ -106,9 +150,9 @@ Rectangle {
         var newHm = []
         for (var hm in root.highlightedMembers) {
             var m = root.highlightedMembers[hm]
-            if (m.convId == convId && m.uri == member) {
+            if (m.convId === convId && m.uri === member) {
                 continue;
-            } else if (m.convId == convId) {
+            } else if (m.convId === convId) {
                 refreshHighlighted = false
             }
             newHm.push(m)
@@ -119,296 +163,318 @@ Rectangle {
             // Remove highlighted status if necessary
             for (var d in swarmCurrentConversationList.contentItem.children) {
                 var delegate = swarmCurrentConversationList.contentItem.children[d]
-                if (delegate.convId == convId)
+                if (delegate.convId === convId)
                     delegate.highlighted = false
             }
         }
     }
 
-    function showSwarmListView(v) {
-        smartListLayout.visible = !v
-        swarmMemberSearchList.visible = v
-    }
+    Page {
+        id: page
 
-    RowLayout {
-        id: titleBar
+        anchors.fill: parent
 
-        visible: swarmMemberSearchList.visible
-
-        height: 40
-        anchors.top: root.top
-        anchors.topMargin: 10
-        anchors.left: root.left
-        anchors.leftMargin: 15
-        anchors.right: root.right
-        anchors.rightMargin: 15
-
-        Label {
-            id: title
+        background: Rectangle {
+            color: JamiTheme.backgroundColor
+        }
 
-            height: parent.height
-            Layout.fillWidth: true
-            Layout.alignment: Qt.AlignVCenter
+        header: AccountComboBox {
+            width: parent.width
+            height: JamiTheme.accountListItemHeight
+            onSettingBtnClicked: {
+                !inSettingsView ?
+                            viewCoordinator.present("SettingsView") :
+                            viewCoordinator.dismiss("SettingsView")}
+        }
 
-            color: JamiTheme.textColor
+        StackLayout {
+            anchors.fill: parent
 
-            font.bold: true
-            font.pointSize: JamiTheme.contactEventPointSize
+            currentIndex: viewCoordinator.inSettings ? 0 : 1
 
-            text: JamiStrings.createSwarm
-        }
+            SettingsMenu {
+                id: settingsMenu
+                objectName: "settingsMenu"
 
-        PushButton {
-            radius: JamiTheme.primaryRadius
+                Layout.fillWidth: true
+                Layout.fillHeight: true
+            }
 
-            imageColor: JamiTheme.textColor
-            imagePadding: 8
-            normalColor: JamiTheme.secondaryBackgroundColor
+            Item {
+                Layout.fillWidth: true
+                Layout.fillHeight: true
 
-            preferredSize: titleBar.height
+                RowLayout {
+                    id: titleBar
 
-            source: JamiResources.round_close_24dp_svg
-            toolTipText: JamiStrings.cancel
+                    visible: swarmMemberSearchList.visible
 
-            onClicked: createSwarmClicked()
-        }
-    }
+                    height: 40
+                    anchors.top: parent.top
+                    anchors.topMargin: 10
+                    anchors.left: parent.left
+                    anchors.leftMargin: 15
+                    anchors.right: parent.right
+                    anchors.rightMargin: 15
 
-    RowLayout {
-        id: startBar
-
-        height: 40
-        anchors.top: titleBar.visible ? titleBar.bottom : root.top
-        anchors.topMargin: 10
-        anchors.left: root.left
-        anchors.leftMargin: 15
-        anchors.right: root.right
-        anchors.rightMargin: 15
-
-        ContactSearchBar {
-            id: contactSearchBar
-
-            Layout.fillHeight: true
-            Layout.fillWidth: true
-
-            onContactSearchBarTextChanged: function (text) {
-                // not calling positionViewAtBeginning will cause
-                // sort animation visual bugs
-                conversationListView.positionViewAtBeginning()
-                ConversationsAdapter.ignoreFiltering(root.highlighted)
-                ConversationsAdapter.setFilter(text)
-            }
+                    Label {
+                        id: title
 
-            onReturnPressedWhileSearching: {
-                var listView = searchResultsListView.count ?
-                            searchResultsListView :
-                            conversationListView
-                if (listView.count)
-                    listView.model.select(0)
-            }
-        }
+                        height: parent.height
+                        Layout.fillWidth: true
+                        Layout.alignment: Qt.AlignVCenter
 
-        PushButton {
-            id: startConversation
+                        color: JamiTheme.textColor
 
-            Layout.alignment: Qt.AlignLeft
-            radius: JamiTheme.primaryRadius
+                        font.bold: true
+                        font.pointSize: JamiTheme.contactEventPointSize
 
-            imageColor: JamiTheme.textColor
-            imagePadding: 8
-            normalColor: JamiTheme.secondaryBackgroundColor
+                        text: JamiStrings.createSwarm
+                    }
 
-            preferredSize: startBar.height
+                    PushButton {
+                        radius: JamiTheme.primaryRadius
 
-            visible: !swarmMemberSearchList.visible && CurrentAccount.type !== Profile.Type.SIP
+                        imageColor: JamiTheme.textColor
+                        imagePadding: 8
+                        normalColor: JamiTheme.secondaryBackgroundColor
 
-            source: smartListLayout.visible ? JamiResources.create_swarm_svg : JamiResources.round_close_24dp_svg
-            toolTipText: smartListLayout.visible ? JamiStrings.startSwarm : JamiStrings.cancel
+                        preferredSize: titleBar.height
 
-            onClicked: createSwarmClicked()
-        }
-    }
+                        source: JamiResources.round_close_24dp_svg
+                        toolTipText: JamiStrings.cancel
 
-    SidePanelTabBar {
-        id: sidePanelTabBar
+                        onClicked: toggleCreateSwarmView()
+                    }
+                }
 
-        visible: ConversationsAdapter.pendingRequestCount &&
-                 !contactSearchBar.textContent && smartListLayout.visible
-        anchors.top: startBar.bottom
-        anchors.topMargin: visible ? 10 : 0
-        width: root.width
-        height: visible ? 42 : 0
-        contentHeight: visible ? 42 : 0
-    }
+                RowLayout {
+                    id: startBar
+
+                    height: 40
+                    anchors.top: titleBar.visible ? titleBar.bottom : parent.top
+                    anchors.topMargin: 10
+                    anchors.left: parent.left
+                    anchors.leftMargin: 15
+                    anchors.right: parent.right
+                    anchors.rightMargin: 15
+
+                    ContactSearchBar {
+                        id: contactSearchBar
+
+                        Layout.fillHeight: true
+                        Layout.fillWidth: true
+
+                        onContactSearchBarTextChanged: function (text) {
+                            print(text)
+                            // not calling positionViewAtBeginning will cause
+                            // sort animation visual bugs
+                            conversationListView.positionViewAtBeginning()
+                            ConversationsAdapter.ignoreFiltering(root.highlighted)
+                            ConversationsAdapter.setFilter(text)
+                        }
+
+                        onReturnPressedWhileSearching: {
+                            var listView = searchResultsListView.count ?
+                                        searchResultsListView :
+                                        conversationListView
+                            if (listView.count)
+                                listView.model.select(0)
+                        }
+                    }
 
-    Rectangle {
-        id: searchStatusRect
+                    PushButton {
+                        id: startConversation
 
-        visible: searchStatusText.text !== "" && smartListLayout.visible
+                        Layout.alignment: Qt.AlignLeft
+                        radius: JamiTheme.primaryRadius
 
-        anchors.top: sidePanelTabBar.bottom
-        anchors.topMargin: visible ? 10 : 0
-        width: parent.width
-        height: visible ? 42 : 0
+                        imageColor: JamiTheme.textColor
+                        imagePadding: 8
+                        normalColor: JamiTheme.secondaryBackgroundColor
 
-        color: JamiTheme.backgroundColor
+                        preferredSize: startBar.height
 
-        Text {
-            id: searchStatusText
+                        visible: !swarmMemberSearchList.visible && CurrentAccount.type !== Profile.Type.SIP
 
-            anchors.verticalCenter: parent.verticalCenter
-            anchors.left: parent.left
-            anchors.leftMargin: 32
-            anchors.right: parent.right
-            anchors.rightMargin: 32
-            color: JamiTheme.textColor
-            wrapMode: Text.WordWrap
-            font.pointSize: JamiTheme.filterItemFontSize
-        }
-    }
+                        source: smartListLayout.visible ? JamiResources.create_swarm_svg : JamiResources.round_close_24dp_svg
+                        toolTipText: smartListLayout.visible ? JamiStrings.startSwarm : JamiStrings.cancel
 
-    Connections {
-        target: ConversationsAdapter
+                        onClicked: toggleCreateSwarmView()
+                    }
+                }
 
-        function onShowSearchStatus(status) {
-            searchStatusText.text = status
-        }
+                SidePanelTabBar {
+                    id: sidePanelTabBar
 
-        function onTextFilterChanged(text) {
-            // In the swarm details, "Go to conversation" can
-            // change the search bar. Be sure to be synced
-            contactSearchBar.textContent = text
-        }
-    }
+                    visible: ConversationsAdapter.pendingRequestCount &&
+                             !contactSearchBar.textContent && smartListLayout.visible
+                    anchors.top: startBar.bottom
+                    anchors.topMargin: visible ? 10 : 0
+                    width: page.width
+                    height: visible ? 42 : 0
+                    contentHeight: visible ? 42 : 0
+                }
 
-    ColumnLayout {
-        id: smartListLayout
-
-        width: parent.width
-        anchors.top: searchStatusRect.bottom
-        anchors.topMargin: (sidePanelTabBar.visible ||
-                            searchStatusRect.visible) ? 0 : 12
-        anchors.bottom: parent.bottom
-
-        spacing: 4
-
-        ConversationListView {
-            id: searchResultsListView
-
-            visible: count
-            opacity: visible ? 1 : 0
-
-            Layout.topMargin: 10
-            Layout.alignment: Qt.AlignTop
-            Layout.fillWidth: true
-            Layout.preferredHeight: visible ? contentHeight : 0
-            Layout.maximumHeight: {
-                var otherContentHeight = conversationListView.contentHeight + 16
-                if (conversationListView.visible)
-                    if (otherContentHeight < parent.height / 2)
-                        return parent.height - otherContentHeight
-                    else
-                        return parent.height / 2
-                else
-                    return parent.height
-            }
+                Rectangle {
+                    id: searchStatusRect
 
-            model: SearchResultsListModel
-            headerLabel: JamiStrings.searchResults
-            headerVisible: visible
-        }
+                    visible: searchStatusText.text !== "" && smartListLayout.visible
 
-        ConversationListView {
-            id: conversationListView
+                    anchors.top: sidePanelTabBar.bottom
+                    anchors.topMargin: visible ? 10 : 0
+                    width: parent.width
+                    height: visible ? 42 : 0
 
-            visible: count
+                    color: JamiTheme.backgroundColor
 
-            Layout.preferredWidth: parent.width
-            Layout.fillHeight: true
+                    Text {
+                        id: searchStatusText
 
-            model: ConversationListModel
-            headerLabel: JamiStrings.conversations
-            headerVisible: searchResultsListView.visible
-        }
-    }
+                        anchors.verticalCenter: parent.verticalCenter
+                        anchors.left: parent.left
+                        anchors.leftMargin: 32
+                        anchors.right: parent.right
+                        anchors.rightMargin: 32
+                        color: JamiTheme.textColor
+                        wrapMode: Text.WordWrap
+                        font.pointSize: JamiTheme.filterItemFontSize
+                    }
+                }
 
-    ColumnLayout {
-        id: swarmMemberSearchList
+                ColumnLayout {
+                    id: smartListLayout
+
+                    width: parent.width
+                    anchors.top: searchStatusRect.bottom
+                    anchors.topMargin: (sidePanelTabBar.visible ||
+                                        searchStatusRect.visible) ? 0 : 12
+                    anchors.bottom: parent.bottom
+
+                    spacing: 4
+
+                    visible: !swarmMemberSearchList.visible
+
+                    ConversationListView {
+                        id: searchResultsListView
+
+                        visible: count
+                        opacity: visible ? 1 : 0
+
+                        Layout.topMargin: 10
+                        Layout.alignment: Qt.AlignTop
+                        Layout.fillWidth: true
+                        Layout.preferredHeight: visible ? contentHeight : 0
+                        Layout.maximumHeight: {
+                            var otherContentHeight = conversationListView.contentHeight + 16
+                            if (conversationListView.visible)
+                                if (otherContentHeight < parent.height / 2)
+                                    return parent.height - otherContentHeight
+                                else
+                                    return parent.height / 2
+                            else
+                                return parent.height
+                        }
+
+                        model: SearchResultsListModel
+                        headerLabel: JamiStrings.searchResults
+                        headerVisible: visible
+                    }
 
-        visible: false
+                    ConversationListView {
+                        id: conversationListView
 
-        width: parent.width
-        anchors.top: searchStatusRect.bottom
-        anchors.topMargin: (sidePanelTabBar.visible ||
-                            searchStatusRect.visible) ? 0 : 12
-        anchors.bottom: parent.bottom
+                        visible: count
 
-        spacing: 4
+                        Layout.preferredWidth: parent.width
+                        Layout.fillHeight: true
 
-        Text {
-            font.bold: true
-            font.pointSize: JamiTheme.contactEventPointSize
+                        model: ConversationListModel
+                        headerLabel: JamiStrings.conversations
+                        headerVisible: searchResultsListView.visible
+                    }
+                }
 
-            Layout.margins: 16
-            Layout.maximumHeight: 24
-            Layout.alignment: Qt.AlignTop
-            Layout.fillWidth: true
+                ColumnLayout {
+                    id: swarmMemberSearchList
 
-            wrapMode: Text.Wrap
+                    visible: viewCoordinator.inNewSwarm
 
-            text: {
-                if (highlightedMembers.length === 0)
-                    return JamiStrings.youCanAdd7
-                return JamiStrings.youCanAddMore.arg(7 - Math.min(highlightedMembers.length, 7))
-            }
-            color: JamiTheme.textColor
-        }
+                    width: parent.width
+                    anchors.top: searchStatusRect.bottom
+                    anchors.topMargin: (sidePanelTabBar.visible ||
+                                        searchStatusRect.visible) ? 0 : 12
+                    anchors.bottom: parent.bottom
 
-        JamiListView {
-            id: swarmCurrentConversationList
+                    spacing: 4
 
-            Layout.preferredWidth: parent.width
-            Layout.fillHeight: true
+                    Text {
+                        font.bold: true
+                        font.pointSize: JamiTheme.contactEventPointSize
 
-            model: ConversationListModel
-            delegate: SmartListItemDelegate {
-                interactive: false
+                        Layout.margins: 16
+                        Layout.maximumHeight: 24
+                        Layout.alignment: Qt.AlignTop
+                        Layout.fillWidth: true
 
-                onVisibleChanged: {
-                    if (!swarmCurrentConversationList.visible) {
-                        highlighted = false
-                        root.clearHighlighted()
-                    }
-                }
+                        wrapMode: Text.Wrap
 
-                Component.onCompleted: {
-                    // Note: when scrolled down, this delegate will be
-                    // destroyed from the memory. So, re-add the highlighted
-                    // status if necessary
-                    if (Array.from(root.highlighted).find(r => r === UID)) {
-                        highlighted = true
+                        text: {
+                            if (highlightedMembers.length === 0)
+                                return JamiStrings.youCanAdd7
+                            return JamiStrings.youCanAddMore.arg(7 - Math.min(highlightedMembers.length, 7))
+                        }
+                        color: JamiTheme.textColor
                     }
-                }
 
-                onHighlightedChanged: function onHighlightedChanged() {
-                    if (highlighted && Array.from(root.highlighted).find(r => r === UID)) {
-                        // Due to scrolling destruction/reconstruction
-                        return
-                    }
-                    var currentHighlighted = root.highlighted
-                    if (!root.refreshHighlighted(UID, highlighted)) {
-                        highlighted = false
-                        return
-                    }
-                    if (highlighted) {
-                        root.highlighted.push(UID)
-                    } else {
-                        root.highlighted = Array.from(root.highlighted).filter(r => r !== UID)
+                    JamiListView {
+                        id: swarmCurrentConversationList
+
+                        Layout.preferredWidth: parent.width
+                        Layout.fillHeight: true
+
+                        model: ConversationListModel
+                        delegate: SmartListItemDelegate {
+                            interactive: false
+
+                            onVisibleChanged: {
+                                if (!swarmCurrentConversationList.visible) {
+                                    highlighted = false
+                                    root.clearHighlighted()
+                                }
+                            }
+
+                            Component.onCompleted: {
+                                // Note: when scrolled down, this delegate will be
+                                // destroyed from the memory. So, re-add the highlighted
+                                // status if necessary
+                                if (Array.from(root.highlighted).find(r => r === UID)) {
+                                    highlighted = true
+                                }
+                            }
+
+                            onHighlightedChanged: function onHighlightedChanged() {
+                                if (highlighted && Array.from(root.highlighted).find(r => r === UID)) {
+                                    // Due to scrolling destruction/reconstruction
+                                    return
+                                }
+                                var currentHighlighted = root.highlighted
+                                if (!root.refreshHighlighted(UID, highlighted)) {
+                                    highlighted = false
+                                    return
+                                }
+                                if (highlighted) {
+                                    root.highlighted.push(UID)
+                                } else {
+                                    root.highlighted = Array.from(root.highlighted).filter(r => r !== UID)
+                                }
+                                root.clearContactSearchBar()
+                            }
+                        }
+                        currentIndex: model.currentFilteredRow
                     }
-                    root.clearContactSearchBar()
                 }
             }
-            currentIndex: model.currentFilteredRow
         }
     }
 }
diff --git a/src/app/mainview/components/SwarmDetailsPanel.qml b/src/app/mainview/components/SwarmDetailsPanel.qml
index e6ad2053426a038aa3ff6c9befb9be720ecee17c..50db6f3156730ada657cabd59ecc32859f0760e8 100644
--- a/src/app/mainview/components/SwarmDetailsPanel.qml
+++ b/src/app/mainview/components/SwarmDetailsPanel.qml
@@ -34,12 +34,9 @@ Rectangle {
 
     color: CurrentConversation.color
     property var isAdmin: !CurrentConversation.isCoreDialog &&
-        UtilsAdapter.getParticipantRole(CurrentAccount.id, CurrentConversation.id, CurrentAccount.uri) === Member.Role.ADMIN
-
-
-    DevicesListPopup {
-        id: devicesListPopup
-    }
+        UtilsAdapter.getParticipantRole(CurrentAccount.id,
+                                        CurrentConversation.id,
+                                        CurrentAccount.uri) === Member.Role.ADMIN
 
     ColumnLayout {
         id: swarmProfileDetails
@@ -184,7 +181,8 @@ Rectangle {
 
                 onEditingFinished: {
                     if (text !== CurrentConversation.description)
-                        ConversationsAdapter.updateConversationDescription(LRCInstance.selectedConvUid, text)
+                        ConversationsAdapter.updateConversationDescription(
+                                    LRCInstance.selectedConvUid, text)
                 }
 
                 onSecondIcoClicked: {editable = !editable}
@@ -268,22 +266,16 @@ Rectangle {
             }
         }
 
-        ColorDialog {
-            id: colorDialog
-            title: JamiStrings.chooseAColor
-            onAccepted: {
-                CurrentConversation.setPreference("color", colorDialog.color)
-            }
-        }
-
-        ConfirmDialog {
-            id: rmDialog
-
-            title: JamiStrings.confirmAction
-            textLabel: JamiStrings.confirmRmConversation
-            confirmLabel: JamiStrings.optionRemove
-            onAccepted: {
-                MessagesAdapter.removeConversation(LRCInstance.selectedConvUid)
+        Component {
+            id: colorDialogComp
+            ColorDialog {
+                id: colorDialog
+                title: JamiStrings.chooseAColor
+                onAccepted: {
+                    CurrentConversation.setPreference("color", colorDialog.color)
+                    this.destroy()
+                }
+                onRejected: this.destroy()
             }
         }
 
@@ -354,7 +346,17 @@ Rectangle {
                             target: parent
                             enabled: parent.visible
                             onTapped: function onTapped(eventPoint) {
-                                rmDialog.open()
+                                var dlg = viewCoordinator.presentDialog(
+                                            appWindow,
+                                            "commoncomponents/ConfirmDialog.qml",
+                                            {
+                                                title: JamiStrings.confirmAction,
+                                                textLabel: JamiStrings.confirmRmConversation,
+                                                confirmLabel: JamiStrings.optionRemove
+                                            })
+                                dlg.accepted.connect(function() {
+                                    MessagesAdapter.removeConversation(LRCInstance.selectedConvUid)
+                                })
                             }
                         }
                     }
@@ -399,7 +401,7 @@ Rectangle {
                             target: parent
                             enabled: parent.visible
                             onTapped: function onTapped(eventPoint) {
-                                colorDialog.open()
+                                colorDialogComp.createObject(appWindow).open()
                             }
                         }
                     }
@@ -507,7 +509,9 @@ Rectangle {
 
                             enabled: parent.visible && root.isAdmin
                             onTapped: function onTapped(eventPoint) {
-                                devicesListPopup.open()
+                                viewCoordinator.presentDialog(
+                                            appWindow,
+                                            "mainview/components/DevicesListPopup.qml")
                             }
                         }
                     }
diff --git a/src/app/mainview/components/UserProfile.qml b/src/app/mainview/components/UserProfile.qml
index 4b05cf335b9d6deb28b4de50d69fda9a57f0332b..7f4562d3415dd8a8128f99c97214d9760b34c2d5 100644
--- a/src/app/mainview/components/UserProfile.qml
+++ b/src/app/mainview/components/UserProfile.qml
@@ -27,6 +27,9 @@ import "../../commoncomponents"
 BaseModalDialog {
     id: root
 
+    width: Math.min(appWindow.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.secondaryDialogDimension)
+    height: Math.min(appWindow.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.secondaryDialogDimension)
+
     property string convId
     property string aliasText
     property string registeredNameText
diff --git a/src/app/mainview/components/WelcomePage.qml b/src/app/mainview/components/WelcomePage.qml
index b609be8b7419c331c778cf3a4836f7cdcb7330f1..5edf09544c6986e69c417ad4cb8cecd20fc4d898 100644
--- a/src/app/mainview/components/WelcomePage.qml
+++ b/src/app/mainview/components/WelcomePage.qml
@@ -27,11 +27,10 @@ import net.jami.Models 1.1
 import "../../commoncomponents"
 import "../js/keyboardshortcuttablecreation.js" as KeyboardShortcutTableCreation
 
-Rectangle {
-
+BaseView {
     id: root
-    color: JamiTheme.secondaryBackgroundColor
 
+    color: JamiTheme.secondaryBackgroundColor
 
     JamiFlickable {
         id: welcomeView
@@ -136,8 +135,6 @@ Rectangle {
                         anchors.margins: JamiTheme.preferredMarginSize
                     }
 
-
-
                     Image {
                         id: welcomeLogo
 
@@ -203,7 +200,6 @@ Rectangle {
                 }
             }
 
-
             Item {
                 id: bottomRow
                 width: Math.max(300, root.width)
@@ -218,7 +214,9 @@ Rectangle {
                     preferredWidth: JamiTheme.aboutButtonPreferredWidthth
                     text: JamiStrings.aboutJami
 
-                    onClicked: aboutPopUpDialog.open()
+                    onClicked: viewCoordinator.presentDialog(
+                                   appWindow,
+                                   "mainview/components/AboutPopUp.qml")
                 }
 
                 PushButton {
diff --git a/src/app/mainview/js/contactpickercreation.js b/src/app/mainview/js/contactpickercreation.js
index 2de3ddf3c83e11f12adbaff69ba37a22dd76992f..a87cf687721a264c8d1a9a52e9557928589d380c 100644
--- a/src/app/mainview/js/contactpickercreation.js
+++ b/src/app/mainview/js/contactpickercreation.js
@@ -16,55 +16,20 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-
-/*
- * Global contact picker component, object variable for creation.
- */
-var contactPickerComponent
-var contactPickerObject
-
-function createContactPickerObjects(type, parent) {
-    if (contactPickerObject) {
-
-        /*
-         * If already created, reset parameters, since object cannot be destroyed.
-         */
-        contactPickerObject.parent = parent
-        contactPickerObject.type = type
-        return
-    }
-    contactPickerComponent = Qt.createComponent(
+function presentContactPickerPopup(type, parent) {
+    var comp = Qt.createComponent(
                 "../components/ContactPicker.qml")
-    if (contactPickerComponent.status === Component.Ready)
-        finishCreation(type, parent)
-    else if (contactPickerComponent.status === Component.Error)
-        console.log("Error loading component:",
-                    contactPickerComponent.errorString())
-}
-
-function finishCreation(type, parent) {
-    contactPickerObject = contactPickerComponent.createObject(parent, {
-                                                                  "type": type
-                                                              })
-    if (contactPickerObject === null) {
-        /*
-         * Error Handling.
-         */
-        console.log("Error creating object for contact picker")
-    } else {
-        contactPickerObject.x = Qt.binding(function(){
-            return parent.width/2 - contactPickerObject.width / 2})
-        contactPickerObject.y = Qt.binding(function(){
-            return parent.height/2 - contactPickerObject.height / 2})
+    if (comp.status === Component.Ready) {
+        var obj = comp.createObject(parent, { type: type })
+        if (obj === null) {
+            console.log("Error creating object for contact picker")
+        } else {
+            obj.x = Qt.binding(() => parent.width / 2 - obj.width / 2)
+            obj.y = Qt.binding(() => parent.height / 2 - obj.height / 2)
+            obj.closed.connect(() => obj.destroy())
+            obj.open()
+        }
+    } else if (comp.status === Component.Error) {
+        console.log("Error loading component:", comp.errorString())
     }
 }
-
-function openContactPicker() {
-    if (contactPickerObject)
-        contactPickerObject.open()
-}
-
-function closeContactPicker() {
-    if (contactPickerObject)
-        contactPickerObject.close()
-}
diff --git a/src/app/messagesadapter.cpp b/src/app/messagesadapter.cpp
index 053f73f99cf3ff408f4b54fbbab8181aa5fb7810..e10bf358368b5b54b1962a3641be1b1cecc788e4 100644
--- a/src/app/messagesadapter.cpp
+++ b/src/app/messagesadapter.cpp
@@ -53,7 +53,11 @@ MessagesAdapter::MessagesAdapter(AppSettingsManager* settingsManager,
     , mediaInteractions_(std::make_unique<MessageListModel>())
     , timestampTimer_(new QTimer(this))
 {
-    connect(lrcInstance_, &LRCInstance::selectedConvUidChanged, [this]() {
+    setObjectName(typeid(*this).name());
+
+    set_messageListModel(QVariant::fromValue(filteredMsgListModel_));
+
+    connect(lrcInstance_, &LRCInstance::selectedConvUidChanged, this, [this]() {
         set_replyToId("");
         set_editId("");
         const QString& convId = lrcInstance_->get_selectedConvUid();
@@ -61,7 +65,6 @@ MessagesAdapter::MessagesAdapter(AppSettingsManager* settingsManager,
 
         // Reset the source model for the proxy model.
         filteredMsgListModel_->setSourceModel(conversation.interactions.get());
-        set_messageListModel(QVariant::fromValue(filteredMsgListModel_));
 
         set_currentConvComposingList(conversationTypersUrlToName(conversation.typers));
     });
@@ -71,28 +74,12 @@ MessagesAdapter::MessagesAdapter(AppSettingsManager* settingsManager,
 
     connect(timestampTimer_, &QTimer::timeout, this, &MessagesAdapter::timestampUpdated);
     timestampTimer_->start(timestampUpdateIntervalMs_);
-}
 
-void
-MessagesAdapter::safeInit()
-{
-    connect(lrcInstance_, &LRCInstance::currentAccountIdChanged, [this]() {
+    connect(lrcInstance_, &LRCInstance::currentAccountIdChanged, this, [this]() {
         connectConversationModel();
     });
-    connectConversationModel();
-}
 
-void
-MessagesAdapter::setupChatView(const QVariantMap& convInfo)
-{
-    auto* convModel = lrcInstance_->getCurrentConversationModel();
-    auto convId = convInfo["convId"].toString();
-    if (convInfo["isSwarm"].toBool()) {
-        convModel->loadConversationMessages(convId, loadChunkSize_);
-    }
-
-    // TODO: current conv observe
-    Q_EMIT newMessageBarPlaceholderText(convInfo["title"].toString());
+    connectConversationModel();
 }
 
 void
@@ -136,6 +123,9 @@ void
 MessagesAdapter::connectConversationModel()
 {
     auto currentConversationModel = lrcInstance_->getCurrentConversationModel();
+    if (currentConversationModel == nullptr) {
+        return;
+    }
 
     QObject::connect(currentConversationModel,
                      &ConversationModel::newInteraction,
@@ -184,7 +174,6 @@ void
 MessagesAdapter::editMessage(const QString& convId, const QString& newBody, const QString& messageId)
 {
     try {
-        const auto convUid = lrcInstance_->get_selectedConvUid();
         auto editId = !messageId.isEmpty() ? messageId : editId_;
         if (editId.isEmpty()) {
             return;
@@ -202,7 +191,6 @@ MessagesAdapter::removeEmojiReaction(const QString& convId,
                                      const QString& messageId)
 {
     try {
-        const auto convUid = lrcInstance_->get_selectedConvUid();
         const auto authorUri = lrcInstance_->getCurrentAccountInfo().profileInfo.uri;
         // check if this emoji has already been added by this author
         auto emojiId = lrcInstance_->getConversationFromConvUid(convId)
diff --git a/src/app/messagesadapter.h b/src/app/messagesadapter.h
index afb299820cf889d36f97be5bb6da8fcad9e12fad..8356b4a51839fcb7ce0849a010bb5d43bb101707 100644
--- a/src/app/messagesadapter.h
+++ b/src/app/messagesadapter.h
@@ -70,7 +70,6 @@ public:
 
 Q_SIGNALS:
     void newInteraction(const QString& id, int type);
-    void newMessageBarPlaceholderText(QString placeholderText);
     void newFilePasted(QString filePath);
     void newTextPasted();
     void previewInformationToQML(QString messageId, QStringList previewInformation);
@@ -78,9 +77,6 @@ Q_SIGNALS:
     void timestampUpdated();
 
 protected:
-    void safeInit() override;
-
-    Q_INVOKABLE void setupChatView(const QVariantMap& convInfo);
     Q_INVOKABLE void loadMoreMessages();
     Q_INVOKABLE void loadConversationUntil(const QString& to);
     Q_INVOKABLE void connectConversationModel();
diff --git a/src/app/pluginadapter.h b/src/app/pluginadapter.h
index b60761fa5f37b97b8ad2b5aae3584f4c5e3249c2..cb640100cf78607fb7d700295d117922d55616e8 100644
--- a/src/app/pluginadapter.h
+++ b/src/app/pluginadapter.h
@@ -40,8 +40,6 @@ public:
     ~PluginAdapter() = default;
 
 protected:
-    void safeInit() override {};
-
     Q_INVOKABLE QVariant getMediaHandlerSelectableModel(const QString& callId);
     Q_INVOKABLE QVariant getChatHandlerSelectableModel(const QString& accountId,
                                                        const QString& peerId);
diff --git a/src/app/positionmanager.cpp b/src/app/positionmanager.cpp
index 3ba52cf92d075fc01ad1cd3365e916b1ff38b52b..7c1a204a3c1ef112a38f7fe76149275986ade06a 100644
--- a/src/app/positionmanager.cpp
+++ b/src/app/positionmanager.cpp
@@ -38,11 +38,7 @@ PositionManager::PositionManager(AppSettingsManager* settingsManager,
             onPositionReceived(accountId, peerId, body, -1, "");
         },
         Qt::QueuedConnection);
-}
 
-void
-PositionManager::safeInit()
-{
     localPositioning_.reset(new Positioning());
     connectAccountModel();
 }
diff --git a/src/app/positionmanager.h b/src/app/positionmanager.h
index 3c2e5cef48664ad1e5e017bf6c3e66e0355747e1..e54d0dac9bb9f39d5fa3588bb4aef99dfbfcf158 100644
--- a/src/app/positionmanager.h
+++ b/src/app/positionmanager.h
@@ -57,8 +57,6 @@ Q_SIGNALS:
     void sendCountdownUpdate(const QString& accountId, const int remainingTime);
 
 protected:
-    void safeInit() override;
-
     QString getAvatar(const QString& accountId, const QString& peerId);
     QVariantMap parseJsonPosition(const QString& accountId,
                                   const QString& peerId,
diff --git a/src/app/previewengine.cpp b/src/app/previewengine.cpp
index 3f3540b2ca08312374d49143af76707792b4b8cc..ab91116d9e6bb7210e8496f15024798b25e57a98 100644
--- a/src/app/previewengine.cpp
+++ b/src/app/previewengine.cpp
@@ -19,6 +19,8 @@
 
 #include "previewengine.h"
 
+#include "utils.h"
+
 #include <QWebEngineScript>
 #include <QWebEngineProfile>
 #include <QWebEngineSettings>
@@ -111,6 +113,3 @@ PreviewEngine::emitLinkified(const QString& messageId, const QString& linkifiedS
 {
     Q_EMIT linkified(messageId, linkifiedStr);
 }
-
-#include "moc_previewengine.cpp"
-#include "previewengine.moc"
diff --git a/src/app/previewengine.h b/src/app/previewengine.h
index c95d42ed8d795a49aaa3b2bba62bd2351f69dc27..be9e3f6b5c44ac6e239362ea66a40fdb4bf6d611 100644
--- a/src/app/previewengine.h
+++ b/src/app/previewengine.h
@@ -19,7 +19,7 @@
 
 #pragma once
 
-#include "utils.h"
+#include <QColor>
 #include <QObject>
 
 class PreviewEngine : public QObject
diff --git a/src/app/qmladapterbase.h b/src/app/qmladapterbase.h
index c0c77dc72e82bb8f087640b9ad8a35d9bfce9080..0ffc3cd59a35e19a2815d0e0e038eafcad3656a9 100644
--- a/src/app/qmladapterbase.h
+++ b/src/app/qmladapterbase.h
@@ -22,34 +22,18 @@
 
 class LRCInstance;
 
-// The main purpose of this class is to operate on qml objects,
-// or provide api calls to qml objects that cannot be done directly in qml.
+// Base class for adapters that need an LRC instance.
 class QmlAdapterBase : public QObject
 {
     Q_OBJECT
 public:
     explicit QmlAdapterBase(LRCInstance* instance, QObject* parent = nullptr)
         : QObject(parent)
-        , qmlObj_(nullptr)
         , lrcInstance_(instance) {};
 
     virtual ~QmlAdapterBase() = default;
 
-    // This function should be called in the Component.onCompleted slot
-    // in the qml component that this adapter should attach to.
-    Q_INVOKABLE void setQmlObject(QObject* obj)
-    {
-        qmlObj_ = obj;
-        safeInit();
-    };
-
 protected:
-    // Once the qml object is set, Qml method invokation can be done
-    virtual void safeInit() = 0;
-
-    // Object pointer.
-    QObject* qmlObj_;
-
     // LRCInstance pointer
     LRCInstance* lrcInstance_ {nullptr};
 };
diff --git a/src/app/qmlregister.cpp b/src/app/qmlregister.cpp
index f6937331784c5b90432319ccf3d4a1ca87810703..80faf8f8f257db7d7e7534c479c2accc6d351e0b 100644
--- a/src/app/qmlregister.cpp
+++ b/src/app/qmlregister.cpp
@@ -57,7 +57,6 @@
 #include "pluginlistmodel.h"
 #include "pluginlistpreferencemodel.h"
 #include "preferenceitemlistmodel.h"
-#include "version.h"
 #include "wizardviewstepmodel.h"
 
 #include "api/peerdiscoverymodel.h"
@@ -126,6 +125,8 @@ registerTypes(QQmlEngine* engine,
     auto tipsModel = new TipsModel(settingsManager, parent);
     auto videoDevices = new VideoDevices(lrcInstance, parent);
     auto currentAccountToMigrate = new CurrentAccountToMigrate(lrcInstance, parent);
+    auto avatarRegistry = new AvatarRegistry(lrcInstance, parent);
+    auto wizardViewStepModel = new WizardViewStepModel(lrcInstance, accountAdapter, settingsManager, parent);
 
     // qml adapter registration
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, callAdapter, "CallAdapter");
@@ -143,6 +144,8 @@ registerTypes(QQmlEngine* engine,
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, currentAccount, "CurrentAccount");
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, videoDevices, "VideoDevices");
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, currentAccountToMigrate, "CurrentAccountToMigrate")
+    QML_REGISTERSINGLETONTYPE_POBJECT(NS_HELPERS, avatarRegistry, "AvatarRegistry");
+    QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS, wizardViewStepModel, "WizardViewStepModel")
 
     // TODO: remove these
     QML_REGISTERSINGLETONTYPE_CUSTOM(NS_MODELS, AVModel, &lrcInstance->avModel())
@@ -174,7 +177,6 @@ registerTypes(QQmlEngine* engine,
     QML_REGISTERTYPE(NS_MODELS, CallInformationListModel);
     QML_REGISTERTYPE(NS_MODELS, RendererInformationListModel);
 
-
     // Roles & type enums for models
     QML_REGISTERNAMESPACE(NS_MODELS, AccountList::staticMetaObject, "AccountList");
     QML_REGISTERNAMESPACE(NS_MODELS, ConversationList::staticMetaObject, "ConversationList");
@@ -194,11 +196,6 @@ registerTypes(QQmlEngine* engine,
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_CONSTANTS, lrcInstance, "LRCInstance")
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_CONSTANTS, settingsManager, "AppSettingsManager")
 
-    auto avatarRegistry = new AvatarRegistry(lrcInstance, parent);
-    auto wizardViewStepModel = new WizardViewStepModel(lrcInstance, accountAdapter, settingsManager, parent);
-    QML_REGISTERSINGLETONTYPE_POBJECT(NS_HELPERS, avatarRegistry, "AvatarRegistry");
-    QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS, wizardViewStepModel, "WizardViewStepModel")
-
     // C++ singletons
     // TODO: remove this
     QML_REGISTERSINGLETONTYPE_WITH_INSTANCE(NameDirectory);
diff --git a/src/app/selectablelistproxymodel.cpp b/src/app/selectablelistproxymodel.cpp
index 7b6678355e44b514b814ac1b7d00bc3f44108f2e..51410fdb048f28ef4dae2a943f4f1ca936f6fce1 100644
--- a/src/app/selectablelistproxymodel.cpp
+++ b/src/app/selectablelistproxymodel.cpp
@@ -30,6 +30,9 @@ void
 SelectableListProxyModel::bindSourceModel(QAbstractListModel* model)
 {
     setSourceModel(model);
+    if (!model) {
+        return;
+    }
     connect(sourceModel(),
             &QAbstractListModel::dataChanged,
             this,
@@ -159,7 +162,7 @@ SelectableListProxyGroupModel::SelectableListProxyGroupModel(QList<SelectableLis
     , models_(models)
 {
     Q_FOREACH (auto* m, models_) {
-        connect(m, &SelectableListProxyModel::validSelectionChanged, [this, m] {
+        connect(m, &SelectableListProxyModel::validSelectionChanged, this, [this, m] {
             // deselct all other lists in the group
             Q_FOREACH (auto* otherM, models_) {
                 if (m != otherM) {
diff --git a/src/app/settingsview/SettingsView.qml b/src/app/settingsview/SettingsView.qml
index 4ecb7e5dddcf15f3a99bfbca236ec0d123b8e56f..c60b49a330604a863471e8da107681c6b61163da 100644
--- a/src/app/settingsview/SettingsView.qml
+++ b/src/app/settingsview/SettingsView.qml
@@ -29,8 +29,19 @@ import "components"
 import "../commoncomponents"
 import "../mainview/js/contactpickercreation.js" as ContactPickerCreation
 
-Rectangle {
+BaseView {
     id: root
+    objectName: "SettingsView"
+    requiresIndex: true
+
+    onDismissed: {
+        settingsViewRect.stopBooth()
+        if (UtilsAdapter.getAccountListSize() === 0) {
+            viewCoordinator.requestAppWindowWizardView()
+        } else {
+            AccountAdapter.changeAccount(0)
+        }
+    }
 
     enum SettingsMenu {
         Account,
@@ -39,50 +50,22 @@ Rectangle {
         Plugin
     }
 
-    onVisibleChanged: {
-        if(visible){
-            setSelected(selectedMenu,true)
-        }
-    }
+    onVisibleChanged: if(visible) setSelected(selectedMenu, true)
 
-    function setSelected(sel, recovery = false) {
-        if(selectedMenu === sel && (!recovery)) { return }
-        switch(sel) {
-            case SettingsView.Account:
-                selectedMenu = sel
-                pageIdCurrentAccountSettings.updateAccountInfoDisplayed()
-                break
-            case SettingsView.General:
-                selectedMenu = sel
-                break
-            case SettingsView.Media:
-                selectedMenu = sel
-                avSettings.populateAVSettings()
-                break
-            case SettingsView.Plugin:
-                selectedMenu = sel
-                break
+    property int selectedMenu: SettingsView.Account
+    onSelectedMenuChanged: {
+        if (selectedMenu === SettingsView.Account) {
+            pageIdCurrentAccountSettings.updateAccountInfoDisplayed()
+        } else if (selectedMenu === SettingsView.Media) {
+            avSettings.populateAVSettings()
         }
     }
 
-    // slots
-    function leaveSettingsSlot(showMainView) {
-        settingsViewRect.stopBooth()
-        if (showMainView)
-            settingsViewNeedToShowMainView()
-        else
-            settingsViewNeedToShowNewWizardWindow()
+    function setSelected(idx, recovery = false) {
+        if (selectedMenu === idx && !recovery) return
+        selectedMenu = idx
     }
 
-    property int selectedMenu: SettingsView.Account
-    // signal to redirect the page to main view
-    signal settingsViewNeedToShowMainView()
-    signal settingsViewNeedToShowNewWizardWindow
-
-    signal settingsBackArrowClicked
-
-    visible: true
-
     Rectangle {
         id: settingsViewRect
 
@@ -126,7 +109,7 @@ Rectangle {
                 }
             }
 
-            onBackArrowClicked: root.settingsBackArrowClicked()
+            onBackArrowClicked: viewCoordinator.hideCurrentView()
         }
 
         JamiFlickable {
@@ -182,13 +165,8 @@ Rectangle {
 
                     isSIP: settingsViewRect.isSIP
 
-                    onNavigateToMainView: {
-                        leaveSettingsSlot(true)
-                    }
-
-                    onNavigateToNewWizardView: {
-                        leaveSettingsSlot(false)
-                    }
+                    onNavigateToMainView: dismiss()
+                    onNavigateToNewWizardView: dismiss()
 
                     onAdvancedSettingsToggled: function (settingsVisible) {
                         if (settingsVisible)
diff --git a/src/app/settingsview/components/AdvancedCallSettings.qml b/src/app/settingsview/components/AdvancedCallSettings.qml
index aa5d4c0dd7b1c8f1e6bed674ca56f44f1130373b..324f270fd7408b13b10f4a5f8e34e9db5a121623 100644
--- a/src/app/settingsview/components/AdvancedCallSettings.qml
+++ b/src/app/settingsview/components/AdvancedCallSettings.qml
@@ -47,25 +47,6 @@ ColumnLayout {
         }
     }
 
-    JamiFileDialog {
-        id: ringtonePath_Dialog
-
-        mode: JamiFileDialog.OpenFile
-        title: JamiStrings.selectNewRingtone
-        folder: JamiQmlUtils.qmlFilePrefix + UtilsAdapter.toFileAbsolutepath(
-                    CurrentAccount.ringtonePath_Ringtone)
-
-        nameFilters: [JamiStrings.audioFile,
-            JamiStrings.allFiles]
-
-        onAccepted: {
-            var url = UtilsAdapter.getAbsPath(file.toString())
-
-            if(url.length !== 0)
-                CurrentAccount.ringtonePath_Ringtone = url
-        }
-    }
-
     ElidedTextLabel {
         Layout.fillWidth: true
 
@@ -125,7 +106,26 @@ ColumnLayout {
             titleField: JamiStrings.selectCustomRingtone
             source: JamiResources.round_folder_24dp_svg
             itemWidth: root.itemWidth
-            onClick: ringtonePath_Dialog.open()
+
+            onClick: {
+                var dlg = viewCoordinator.presentDialog(
+                            appWindow,
+                            "commoncomponents/JamiFileDialog.qml",
+                            {
+                                title: JamiStrings.selectNewRingtone,
+                                fileMode: JamiFileDialog.OpenFile,
+                                folder: JamiQmlUtils.qmlFilePrefix +
+                                        UtilsAdapter.toFileAbsolutepath(
+                                            CurrentAccount.ringtonePath_Ringtone),
+                                nameFilters: [JamiStrings.audioFile, JamiStrings.allFiles]
+                            })
+                dlg.fileAccepted.connect(function (file) {
+                    var url = UtilsAdapter.getAbsPath(file.toString())
+                    if(url.length !== 0) {
+                        CurrentAccount.ringtonePath_Ringtone = url
+                    }
+                })
+            }
         }
 
         ToggleSwitch {
@@ -213,10 +213,9 @@ ColumnLayout {
             text: JamiStrings.addDefaultModerator
 
             onClicked: {
-                ContactPickerCreation.createContactPickerObjects(
+                ContactPickerCreation.presentContactPickerPopup(
                             ContactList.CONVERSATION,
-                            mainView)
-                ContactPickerCreation.openContactPicker()
+                            appWindow)
             }
         }
 
diff --git a/src/app/settingsview/components/AdvancedJamiSecuritySettings.qml b/src/app/settingsview/components/AdvancedJamiSecuritySettings.qml
index 1c2af23c6e3bf43c4734709b48ebd396daa7014e..e3046345ac6bf626dae8a8d179bff697c5d00c7c 100644
--- a/src/app/settingsview/components/AdvancedJamiSecuritySettings.qml
+++ b/src/app/settingsview/components/AdvancedJamiSecuritySettings.qml
@@ -30,58 +30,20 @@ ColumnLayout {
 
     property int itemWidth
 
-    JamiFileDialog {
-        id: caCert_Dialog
-
-        property string oldPath: CurrentAccount.certificateListFile_TLS
-        property string openPath: oldPath === "" ?
-                                      (UtilsAdapter.getCurrentPath() + "/ringtones/") :
-                                      (UtilsAdapter.toFileAbsolutepath(oldPath))
-
-        mode: JamiFileDialog.OpenFile
-        title: JamiStrings.selectCACert
-        folder: openPath
-        nameFilters: [JamiStrings.certificateFile,
-            JamiStrings.allFiles]
-
-        onAccepted: CurrentAccount.certificateListFile_TLS =
-                    UtilsAdapter.getAbsPath(file.toString())
-    }
-
-    JamiFileDialog {
-        id: userCert_Dialog
-
-        property string oldPath: CurrentAccount.certificateFile_TLS
-        property string openPath: oldPath === "" ?
-                                      (UtilsAdapter.getCurrentPath() + "/ringtones/") :
-                                      (UtilsAdapter.toFileAbsolutepath(oldPath))
-
-        mode: JamiFileDialog.OpenFile
-        title: JamiStrings.selectUserCert
-        folder: openPath
-        nameFilters: [JamiStrings.certificateFile,
-            JamiStrings.allFiles]
-
-        onAccepted: CurrentAccount.certificateFile_TLS =
-                    UtilsAdapter.getAbsPath(file.toString())
-    }
-
-    JamiFileDialog {
-        id: privateKey_Dialog
-
-        property string oldPath: CurrentAccount.privateKeyFile_TLS
-        property string openPath: oldPath === "" ?
-                                      (UtilsAdapter.getCurrentPath() + "/ringtones/") :
-                                      (UtilsAdapter.toFileAbsolutepath(oldPath))
-
-        mode: JamiFileDialog.OpenFile
-        title: JamiStrings.selectPrivateKey
-        folder: openPath
-        nameFilters: [JamiStrings.keyFile,
-            JamiStrings.allFiles]
-
-        onAccepted: CurrentAccount.privateKeyFile_TLS =
-                    UtilsAdapter.getAbsPath(file.toString())
+    function openFileDialog(title, oldPath, fileType, onAcceptedCb) {
+        var openPath = oldPath === "" ?
+                    (UtilsAdapter.getCurrentPath() + "/ringtones/") :
+                    (UtilsAdapter.toFileAbsolutepath(oldPath))
+        var dlg = viewCoordinator.presentDialog(
+                    appWindow,
+                    "commoncomponents/JamiFileDialog.qml",
+                    {
+                        title: title,
+                        fileMode: JamiFileDialog.OpenFile,
+                        folder: openPath,
+                        nameFilters: [fileType, JamiStrings.allFiles]
+                    })
+        dlg.fileAccepted.connect(onAcceptedCb)
     }
 
     ElidedTextLabel {
@@ -109,7 +71,13 @@ ColumnLayout {
             source: JamiResources.round_folder_24dp_svg
             itemWidth: root.itemWidth
 
-            onClick: caCert_Dialog.open()
+            onClick: openFileDialog(JamiStrings.selectCACert,
+                                    CurrentAccount.certificateListFile_TLS,
+                                    JamiStrings.certificateFile,
+                                    function (file) {
+                                        CurrentAccount.certificateListFile_TLS =
+                                                UtilsAdapter.getAbsPath(file.toString())
+                                    })
         }
 
         SettingMaterialButton {
@@ -124,7 +92,13 @@ ColumnLayout {
             source: JamiResources.round_folder_24dp_svg
             itemWidth: root.itemWidth
 
-            onClick: userCert_Dialog.open()
+            onClick: openFileDialog(JamiStrings.selectUserCert,
+                                    CurrentAccount.certificateFile_TLS,
+                                    JamiStrings.certificateFile,
+                                    function (file) {
+                                        CurrentAccount.certificateFile_TLS =
+                                                UtilsAdapter.getAbsPath(file.toString())
+                                    })
         }
 
         SettingMaterialButton {
@@ -139,7 +113,13 @@ ColumnLayout {
             source: JamiResources.round_folder_24dp_svg
             itemWidth: root.itemWidth
 
-            onClick: privateKey_Dialog.open()
+            onClick: openFileDialog(JamiStrings.selectPrivateKey,
+                                    CurrentAccount.privateKeyFile_TLS,
+                                    JamiStrings.keyFile,
+                                    function (file) {
+                                        CurrentAccount.privateKeyFile_TLS =
+                                                UtilsAdapter.getAbsPath(file.toString())
+                                    })
         }
 
         SettingsMaterialLineEdit {
diff --git a/src/app/settingsview/components/AdvancedSIPSecuritySettings.qml b/src/app/settingsview/components/AdvancedSIPSecuritySettings.qml
index 685361bdcbfdb4e120c1543703c85d08b3f92f42..906324753ca8f9547179bd6f438e6707cedc7a3a 100644
--- a/src/app/settingsview/components/AdvancedSIPSecuritySettings.qml
+++ b/src/app/settingsview/components/AdvancedSIPSecuritySettings.qml
@@ -31,58 +31,20 @@ ColumnLayout {
 
     property int itemWidth
 
-    JamiFileDialog {
-        id: caCert_Dialog_SIP
-
-        property string oldPath: CurrentAccount.certificateListFile_TLS
-        property string openPath: oldPath === "" ?
-                                      (UtilsAdapter.getCurrentPath() + "/ringtones/") :
-                                      (UtilsAdapter.toFileAbsolutepath(oldPath))
-
-        mode: JamiFileDialog.OpenFile
-        title: JamiStrings.selectCACert
-        folder: openPath
-        nameFilters: [JamiStrings.certificateFile,
-            JamiStrings.allFiles]
-
-        onAccepted: CurrentAccount.certificateListFile_TLS =
-                    UtilsAdapter.getAbsPath(file.toString())
-    }
-
-    JamiFileDialog {
-        id: userCert_Dialog_SIP
-
-        property string oldPath: CurrentAccount.certificateFile_TLS
-        property string openPath: oldPath === "" ?
-                                      (UtilsAdapter.getCurrentPath() + "/ringtones/") :
-                                      (UtilsAdapter.toFileAbsolutepath(oldPath))
-
-        mode: JamiFileDialog.OpenFile
-        title: JamiStrings.selectUserCert
-        folder: openPath
-        nameFilters: [JamiStrings.certificateFile,
-            JamiStrings.allFiles]
-
-        onAccepted: CurrentAccount.certificateFile_TLS =
-                    UtilsAdapter.getAbsPath(file.toString())
-    }
-
-    JamiFileDialog {
-        id: privateKey_Dialog_SIP
-
-        property string oldPath: CurrentAccount.privateKeyFile_TLS
-        property string openPath: oldPath === "" ?
-                                      (UtilsAdapter.getCurrentPath() + "/ringtones/") :
-                                      (UtilsAdapter.toFileAbsolutepath(oldPath))
-
-        mode: JamiFileDialog.OpenFile
-        title: JamiStrings.selectPrivateKey
-        folder: openPath
-        nameFilters: [JamiStrings.keyFile,
-            JamiStrings.allFiles]
-
-        onAccepted: CurrentAccount.privateKeyFile_TLS =
-                    UtilsAdapter.getAbsPath(file.toString())
+    function openFileDialog(title, oldPath, fileType, onAcceptedCb) {
+        var openPath = oldPath === "" ?
+                    (UtilsAdapter.getCurrentPath() + "/ringtones/") :
+                    (UtilsAdapter.toFileAbsolutepath(oldPath))
+        var dlg = viewCoordinator.presentDialog(
+                    appWindow,
+                    "commoncomponents/JamiFileDialog.qml",
+                    {
+                        title: title,
+                        fileMode: JamiFileDialog.OpenFile,
+                        folder: openPath,
+                        nameFilters: [fileType, JamiStrings.allFiles]
+                    })
+        dlg.fileAccepted.connect(onAcceptedCb)
     }
 
     ElidedTextLabel {
@@ -160,7 +122,13 @@ ColumnLayout {
 
             textField: UtilsAdapter.toFileInfoName(CurrentAccount.certificateListFile_TLS)
 
-            onClick: caCert_Dialog_SIP.open()
+            onClick: openFileDialog(JamiStrings.selectCACert,
+                                    CurrentAccount.certificateListFile_TLS,
+                                    JamiStrings.certificateFile,
+                                    function (file) {
+                                        CurrentAccount.certificateListFile_TLS =
+                                                UtilsAdapter.getAbsPath(file.toString())
+                                    })
         }
 
         SettingMaterialButton {
@@ -177,7 +145,13 @@ ColumnLayout {
 
             textField: UtilsAdapter.toFileInfoName(CurrentAccount.certificateFile_TLS)
 
-            onClick: userCert_Dialog_SIP.open()
+            onClick: openFileDialog(JamiStrings.selectUserCert,
+                                    CurrentAccount.certificateFile_TLS,
+                                    JamiStrings.certificateFile,
+                                    function (file) {
+                                        CurrentAccount.certificateFile_TLS =
+                                                UtilsAdapter.getAbsPath(file.toString())
+                                    })
         }
 
         SettingMaterialButton {
@@ -194,7 +168,13 @@ ColumnLayout {
 
             textField: UtilsAdapter.toFileInfoName(CurrentAccount.privateKeyFile_TLS)
 
-            onClick: privateKey_Dialog_SIP.open()
+            onClick: openFileDialog(JamiStrings.selectPrivateKey,
+                                    CurrentAccount.privateKeyFile_TLS,
+                                    JamiStrings.keyFile,
+                                    function (file) {
+                                        CurrentAccount.privateKeyFile_TLS =
+                                                UtilsAdapter.getAbsPath(file.toString())
+                                    })
         }
 
         // Private key password
diff --git a/src/app/settingsview/components/CurrentAccountSettings.qml b/src/app/settingsview/components/CurrentAccountSettings.qml
index d1483e8d4d3b0429cd23155eaaa7e2c9f30f721e..219daace01b32c8dfcc90cd3f306989cb6af9ea6 100644
--- a/src/app/settingsview/components/CurrentAccountSettings.qml
+++ b/src/app/settingsview/components/CurrentAccountSettings.qml
@@ -42,118 +42,14 @@ Rectangle {
 
     function updateAccountInfoDisplayed() {
         bannedContacts.updateAndShowBannedContactsSlot()
-        setPasswordButtonText()
-    }
-
-    function passwordClicked() {
-        if (AccountAdapter.hasPassword()) {
-            passwordDialog.openDialog(PasswordDialog.ChangePassword)
-        } else {
-            passwordDialog.openDialog(PasswordDialog.SetPassword)
-        }
-    }
-
-    function exportAccountSlot() {
-        exportBtn_Dialog.open()
-    }
-
-    function delAccountSlot() {
-        deleteAccountDialog.isSIP = CurrentAccount.type === Profile.Type.SIP
-        deleteAccountDialog.bestName = CurrentAccount.bestName
-        deleteAccountDialog.accountId = CurrentAccount.uri
-        deleteAccountDialog.open()
     }
 
     function getAdvancedSettingsScrollPosition() {
         return advancedSettings.y
     }
 
-    function setPasswordButtonText() {
-        var hasPassword = AccountAdapter.hasPassword()
-        passwdPushButton.toolTipText = hasPassword ?
-                    JamiStrings.changeCurrentPassword :
-                    JamiStrings.setAPassword
-
-        passwdPushButton.text = hasPassword ?
-                    JamiStrings.changePassword :
-                    JamiStrings.setPassword
-    }
-
     color: JamiTheme.secondaryBackgroundColor
 
-    SimpleMessageDialog {
-        id: msgDialog
-
-        buttonTitles: [JamiStrings.optionOk]
-        buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue]
-        buttonCallBacks: [setPasswordButtonText]
-    }
-
-    DeleteAccountDialog {
-        id: deleteAccountDialog
-
-        onAccepted: {
-            if(UtilsAdapter.getAccountListSize() > 0) {
-                navigateToMainView()
-            } else {
-                navigateToNewWizardView()
-            }
-        }
-    }
-
-    PasswordDialog {
-        id: passwordDialog
-
-        onDoneSignal: function (success, currentPurpose) {
-            var title = success ? JamiStrings.success : JamiStrings.error
-
-            var info
-            switch(currentPurpose) {
-                case PasswordDialog.ExportAccount:
-                    info = success ? JamiStrings.backupSuccessful : JamiStrings.backupFailed
-                    break
-                case PasswordDialog.ChangePassword:
-                    info = success ? JamiStrings.changePasswordSuccess : JamiStrings.changePasswordFailed
-                    break
-                case PasswordDialog.SetPassword:
-                    info = success ? JamiStrings.setPasswordSuccess : JamiStrings.setPasswordFailed
-                    passwdPushButton.text = success ? JamiStrings.changePassword : JamiStrings.setPassword
-                    break
-            }
-
-            msgDialog.openWithParameters(title, info)
-        }
-    }
-
-    JamiFileDialog {
-        id: exportBtn_Dialog
-
-        mode: JamiFileDialog.SaveFile
-
-        title: JamiStrings.backupAccountHere
-        folder: StandardPaths.writableLocation(StandardPaths.DesktopLocation)
-
-        nameFilters: [JamiStrings.jamiArchiveFiles, JamiStrings.allFiles]
-
-        onAccepted: {
-            // is there password? If so, go to password dialog, else, go to following directly
-            var exportPath = UtilsAdapter.getAbsPath(file.toString())
-            if (AccountAdapter.hasPassword()) {
-                passwordDialog.openDialog(PasswordDialog.ExportAccount,exportPath)
-                return
-            } else {
-                if (exportPath.length > 0) {
-                    var isSuccessful = AccountAdapter.model.exportToFile(LRCInstance.currentAccountId,
-                                                                         exportPath, "")
-                    var title = isSuccessful ? JamiStrings.success : JamiStrings.error
-                    var info = isSuccessful ? JamiStrings.backupSuccessful : JamiStrings.backupFailed
-
-                    msgDialog.openWithParameters(title,info)
-                }
-            }
-        }
-    }
-
     ColumnLayout {
         id: currentAccountSettingsColumnLayout
 
@@ -212,16 +108,21 @@ Rectangle {
             pressedColor: JamiTheme.buttonTintedBlackPressed
             secondary: true
 
-            toolTipText: AccountAdapter.hasPassword() ?
+            toolTipText: CurrentAccount.hasArchivePassword ?
                              JamiStrings.changeCurrentPassword :
                              JamiStrings.setAPassword
-            text: AccountAdapter.hasPassword() ?
+            text: CurrentAccount.hasArchivePassword ?
                       JamiStrings.changePassword :
                       JamiStrings.setPassword
 
             iconSource: JamiResources.round_edit_24dp_svg
 
-            onClicked: passwordClicked()
+            onClicked: viewCoordinator.presentDialog(
+                                   appWindow,
+                                   "commoncomponents/PasswordDialog.qml",
+                                   { purpose: CurrentAccount.hasArchivePassword ?
+                                                  PasswordDialog.ChangePassword :
+                                                  PasswordDialog.SetPassword })
         }
 
         MaterialButton {
@@ -243,7 +144,42 @@ Rectangle {
 
             iconSource: JamiResources.round_save_alt_24dp_svg
 
-            onClicked: exportAccountSlot()
+            onClicked: {
+                var dlg = viewCoordinator.presentDialog(
+                            appWindow,
+                            "commoncomponents/JamiFileDialog.qml",
+                            {
+                                title: JamiStrings.backupAccountHere,
+                                fileMode: FileDialog.SaveFile,
+                                folder: StandardPaths.writableLocation(StandardPaths.DesktopLocation),
+                                nameFilters: [JamiStrings.jamiArchiveFiles, JamiStrings.allFiles]
+                            })
+                dlg.fileAccepted.connect(function (file) {
+                    // is there password? If so, go to password dialog, else, go to following directly
+                    var exportPath = UtilsAdapter.getAbsPath(file.toString())
+                    if (CurrentAccount.hasArchivePassword) {
+                        viewCoordinator.presentDialog(
+                                    appWindow,
+                                    "commoncomponents/PasswordDialog.qml",
+                                    {
+                                        purpose: PasswordDialog.ExportAccount,
+                                        path: exportPath
+                                    })
+                        return
+                    } else if (exportPath.length > 0) {
+                        var success = AccountAdapter.model.exportToFile(LRCInstance.currentAccountId, exportPath)
+                        viewCoordinator.presentDialog(
+                                    appWindow,
+                                    "commoncomponents/SimpleMessageDialog.qml",
+                                    {
+                                        title: success ? JamiStrings.success : JamiStrings.error,
+                                        infoText: success ? JamiStrings.backupSuccessful : JamiStrings.backupFailed,
+                                        buttonTitles: [JamiStrings.optionOk],
+                                        buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue]
+                                    })
+                    }
+                })
+            }
         }
 
         MaterialButton {
@@ -262,7 +198,17 @@ Rectangle {
 
             iconSource: JamiResources.delete_forever_24dp_svg
 
-            onClicked: delAccountSlot()
+            onClicked: {
+                var dlg = viewCoordinator.presentDialog(
+                        appWindow,
+                        "commoncomponents/DeleteAccountDialog.qml",
+                        {
+                            isSIP: CurrentAccount.type === Profile.Type.SIP,
+                            bestName: CurrentAccount.bestName,
+                            accountId: CurrentAccount.uri
+                        })
+                dlg.accepted.connect(navigateToMainView)
+            }
         }
 
         LinkedDevices {
diff --git a/src/app/settingsview/components/JamiUserIdentity.qml b/src/app/settingsview/components/JamiUserIdentity.qml
index 5032375d74b992253c3f497acf2eb59ffdd64c27..a3acde9503235bce31ebc0600496247a131b50af 100644
--- a/src/app/settingsview/components/JamiUserIdentity.qml
+++ b/src/app/settingsview/components/JamiUserIdentity.qml
@@ -31,13 +31,6 @@ ColumnLayout {
 
     property int itemWidth
 
-    NameRegistrationDialog {
-        id : nameRegistrationDialog
-
-        onAccepted: currentRegisteredID.nameRegistrationState =
-                    UsernameLineEdit.NameRegistrationState.BLANK
-    }
-
     // Identity
     Row {
         Layout.fillWidth: true
@@ -162,6 +155,18 @@ ColumnLayout {
         hoveredColor: JamiTheme.buttonTintedGreyHovered
         pressedColor: JamiTheme.buttonTintedGreyPressed
 
-        onClicked: nameRegistrationDialog.openNameRegistrationDialog(currentRegisteredID.text)
+        onClicked: {
+            if (currentRegisteredID.text === '') {
+                return
+            }
+            var dlg = viewCoordinator.presentDialog(
+                        appWindow,
+                        "settingsview/components/NameRegistrationDialog.qml",
+                        { registeredName: currentRegisteredID.text })
+            dlg.accepted.connect(function() {
+                currentRegisteredID.nameRegistrationState =
+                        UsernameLineEdit.NameRegistrationState.BLANK
+            })
+        }
     }
 }
diff --git a/src/app/settingsview/components/LinkDeviceDialog.qml b/src/app/settingsview/components/LinkDeviceDialog.qml
index 2211f155c740665370071d26a7cbde27aa4b30b5..cae0ded44b2ece38c6ce5644b71472347ed0c9ed 100644
--- a/src/app/settingsview/components/LinkDeviceDialog.qml
+++ b/src/app/settingsview/components/LinkDeviceDialog.qml
@@ -34,14 +34,14 @@ BaseModalDialog {
 
     title: JamiStrings.addDevice
 
-    width: Math.min(mainView.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogWidth)
-    height: Math.min(mainView.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogHeight)
+    width: Math.min(appWindow.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogWidth)
+    height: Math.min(appWindow.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogHeight)
 
     popupContent: StackLayout {
         id: stackedWidget
 
         function setGeneratingPage() {
-            if(passwordEdit.length === 0 && AccountAdapter.hasPassword()){
+            if(passwordEdit.length === 0 && CurrentAccount.hasArchivePassword){
                 setExportPage(NameDirectory.ExportOnRingStatus.WRONG_PASSWORD, "")
                 return
             }
@@ -102,7 +102,7 @@ BaseModalDialog {
                 infoLabel.text = JamiStrings.pinTimerInfos
                 passwordEdit.clear()
 
-                if(AccountAdapter.hasPassword()) {
+                if(CurrentAccount.hasArchivePassword) {
                     stackedWidget.currentIndex = enterPasswordPage.pageIndex
                     passwordEdit.forceActiveFocus()
                 } else {
diff --git a/src/app/settingsview/components/LinkedDevices.qml b/src/app/settingsview/components/LinkedDevices.qml
index 109b1945b91ee1dbd306d7b6db4b5a4b1f0afd3e..f59d1b84e32ff5925a36e1d3bf0993d311ba6885 100644
--- a/src/app/settingsview/components/LinkedDevices.qml
+++ b/src/app/settingsview/components/LinkedDevices.qml
@@ -33,44 +33,30 @@ ColumnLayout {
     id:root
 
     function removeDeviceSlot(index){
-        var idOfDevice = settingsListView.model.data(settingsListView.model.index(index,0),
+        var deviceId = settingsListView.model.data(settingsListView.model.index(index,0),
                                                      DeviceItemListModel.DeviceID)
-        if(AccountAdapter.hasPassword()){
-            revokeDevicePasswordDialog.openRevokeDeviceDialog(idOfDevice)
+        if(CurrentAccount.hasArchivePassword){
+            viewCoordinator.presentDialog(
+                        appWindow,
+                        "settingsview/components/RevokeDevicePasswordDialog.qml",
+                        { deviceId: deviceId })
         } else {
-            revokeDeviceMessageBox.idOfDev = idOfDevice
-            revokeDeviceMessageBox.open()
+            viewCoordinator.presentDialog(
+                        appWindow,
+                        "commoncomponents/SimpleMessageDialog.qml",
+                        {
+                            title: JamiStrings.removeDevice,
+                            infoText: JamiStrings.sureToRemoveDevice,
+                            buttonTitles: [JamiStrings.optionOk, JamiStrings.optionCancel],
+                            buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue,
+                                           SimpleMessageDialog.ButtonStyle.TintedBlack],
+                            buttonCallBacks: [
+                                function() { DeviceItemListModel.revokeDevice(deviceId, "") }
+                            ]
+                        })
         }
     }
 
-    LinkDeviceDialog {
-        id: linkDeviceDialog
-    }
-
-    RevokeDevicePasswordDialog{
-        id: revokeDevicePasswordDialog
-
-        onRevokeDeviceWithPassword: function(idOfDevice, password) {
-            DeviceItemListModel.revokeDevice(idOfDevice, password)
-        }
-    }
-
-    SimpleMessageDialog {
-        id: revokeDeviceMessageBox
-
-        property string idOfDev: ""
-
-        title: JamiStrings.removeDevice
-        infoText: JamiStrings.sureToRemoveDevice
-
-        buttonTitles: [JamiStrings.optionOk, JamiStrings.optionCancel]
-        buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue,
-                       SimpleMessageDialog.ButtonStyle.TintedBlack]
-        buttonCallBacks: [
-            function() { DeviceItemListModel.revokeDevice(idOfDev, "") }
-        ]
-    }
-
     Label {
         Layout.preferredHeight: JamiTheme.preferredFieldHeight
 
@@ -132,6 +118,8 @@ ColumnLayout {
 
         text: JamiStrings.linkAnotherDevice
 
-        onClicked: linkDeviceDialog.open()
+        onClicked: viewCoordinator.presentDialog(
+                                   appWindow,
+                                   "settingsview/components/LinkDeviceDialog.qml")
     }
 }
diff --git a/src/app/settingsview/components/NameRegistrationDialog.qml b/src/app/settingsview/components/NameRegistrationDialog.qml
index fc65042d26918271a1dec379ed04f89d0e238b41..d61125fb45bc5b0582182eb9bb6ac41e21a0bf00 100644
--- a/src/app/settingsview/components/NameRegistrationDialog.qml
+++ b/src/app/settingsview/components/NameRegistrationDialog.qml
@@ -30,19 +30,12 @@ import "../../commoncomponents"
 BaseModalDialog {
     id: root
 
-    property string registerdName : ""
+    property string registeredName : ""
 
     signal accepted
 
-    function openNameRegistrationDialog(registerNameIn) {
-        if (registerNameIn === '')
-            return
-        registerdName = registerNameIn
-        open()
-    }
-
-    width: Math.min(mainView.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogWidth)
-    height: Math.min(mainView.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogHeight)
+    width: Math.min(appWindow.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogWidth)
+    height: Math.min(appWindow.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogHeight)
 
     title: JamiStrings.setUsername
 
@@ -64,7 +57,7 @@ BaseModalDialog {
 
             onTriggered: {
                 AccountAdapter.model.registerName(LRCInstance.currentAccountId,
-                                                  passwordEdit.text, registerdName)
+                                                  passwordEdit.text, registeredName)
             }
         }
 
@@ -96,7 +89,7 @@ BaseModalDialog {
                 lblRegistrationError.text = JamiStrings.somethingWentWrong
                 passwordEdit.clear()
 
-                if (AccountAdapter.hasPassword()){
+                if (CurrentAccount.hasArchivePassword){
                     stackedWidget.currentIndex = nameRegisterEnterPasswordPage.pageIndex
                     passwordEdit.forceActiveFocus()
                 } else {
diff --git a/src/app/settingsview/components/PluginItemDelegate.qml b/src/app/settingsview/components/PluginItemDelegate.qml
index 21af2f5ea2a724154fd44531f3f458209883bdec..8c8886c8f8fd31779e3fd249ee72187b1a62e621 100644
--- a/src/app/settingsview/components/PluginItemDelegate.qml
+++ b/src/app/settingsview/components/PluginItemDelegate.qml
@@ -34,21 +34,15 @@ ItemDelegate {
     property string pluginIcon: ""
     property bool isLoaded: false
     property string activeId: ""
-    height: pluginPreferencesView.visible ? implicitHeight + pluginPreferencesView.childrenRect.height : implicitHeight
+    height: pluginPreferencesView.visible ?
+                implicitHeight + pluginPreferencesView.childrenRect.height :
+                implicitHeight
 
     signal settingsClicked
 
-    onActiveIdChanged: {
-        pluginPreferencesView.visible = activeId != pluginId ? false : !pluginPreferencesView.visible
-    }
-
-    SimpleMessageDialog {
-        id: msgDialog
-
-        buttonTitles: [JamiStrings.optionOk, JamiStrings.optionCancel]
-        buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue,
-                       SimpleMessageDialog.ButtonStyle.TintedBlack]
-    }
+    onActiveIdChanged: pluginPreferencesView.visible = activeId != pluginId ?
+                           false :
+                           !pluginPreferencesView.visible
 
     ColumnLayout {
         width: parent.width
diff --git a/src/app/settingsview/components/PluginListView.qml b/src/app/settingsview/components/PluginListView.qml
index 85afec4b6efa37da3ea57bddbef6a5815c1ca289..b130fc60f2f7b6edfa963e59851f7051935e2898 100644
--- a/src/app/settingsview/components/PluginListView.qml
+++ b/src/app/settingsview/components/PluginListView.qml
@@ -35,22 +35,6 @@ Rectangle {
     visible: false
     color: JamiTheme.secondaryBackgroundColor
 
-    JamiFileDialog {
-        id: pluginPathDialog
-
-        mode: JamiFileDialog.OpenFile
-        title: JamiStrings.selectPluginInstall
-        folder: StandardPaths.writableLocation(StandardPaths.DownloadLocation)
-
-        nameFilters: [JamiStrings.pluginFiles, JamiStrings.allFiles]
-
-        onAccepted: {
-            var url = UtilsAdapter.getAbsPath(file.toString())
-            PluginModel.installPlugin(url, true)
-            installedPluginsModel.addPlugin()
-        }
-    }
-
     ColumnLayout {
         anchors.left: root.left
         anchors.right: root.right
@@ -88,7 +72,22 @@ Rectangle {
 
             text: JamiStrings.installPlugin
 
-            onClicked: pluginPathDialog.open()
+            onClicked: {
+                var dlg = viewCoordinator.presentDialog(
+                            appWindow,
+                            "commoncomponents/JamiFileDialog.qml",
+                            {
+                                title: JamiStrings.selectPluginInstall,
+                                fileMode: JamiFileDialog.OpenFile,
+                                folder: StandardPaths.writableLocation(StandardPaths.DownloadLocation),
+                                nameFilters: [JamiStrings.pluginFiles, JamiStrings.allFiles]
+                            })
+                dlg.fileAccepted.connect(function (file) {
+                    var url = UtilsAdapter.getAbsPath(file.toString())
+                    PluginModel.installPlugin(url, true)
+                    installedPluginsModel.addPlugin()
+                })
+            }
         }
 
         ListView {
diff --git a/src/app/settingsview/components/PluginPreferencesListView.qml b/src/app/settingsview/components/PluginPreferencesListView.qml
index c833310ba7ab08360b99279fc59b5bbef95a44bb..3cefe4015d57bbfb5c13f19e4230583125ca64db 100644
--- a/src/app/settingsview/components/PluginPreferencesListView.qml
+++ b/src/app/settingsview/components/PluginPreferencesListView.qml
@@ -280,21 +280,27 @@ Rectangle {
 
             text: JamiStrings.reset
 
-            onClicked: {
-                msgDialog.buttonCallBacks = [function () {
-                    if (isLoaded) {
-                        PluginModel.unloadPlugin(pluginId)
-                        PluginModel.resetPluginPreferencesValues(pluginId, accountId)
-                        PluginModel.loadPlugin(pluginId)
-                    } else {
-                        PluginModel.resetPluginPreferencesValues(pluginId, accountId)
-                    }
-                    preferencesPerCategoryModel.reset()
-                    generalPreferencesModel.reset()
-                }]
-                msgDialog.openWithParameters(JamiStrings.resetPreferences,
-                                             JamiStrings.pluginResetConfirmation.arg(pluginName))
-            }
+            onClicked: viewCoordinator.presentDialog(
+                           appWindow,
+                           "commoncomponents/SimpleMessageDialog.qml",
+                           {
+                               title: JamiStrings.resetPreferences,
+                               infoText: JamiStrings.pluginResetConfirmation.arg(pluginName),
+                               buttonTitles: [JamiStrings.optionOk, JamiStrings.optionCancel],
+                               buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue,
+                                              SimpleMessageDialog.ButtonStyle.TintedBlack],
+                               buttonCallBacks: [function () {
+                                   if (isLoaded) {
+                                       PluginModel.unloadPlugin(pluginId)
+                                       PluginModel.resetPluginPreferencesValues(pluginId, accountId)
+                                       PluginModel.loadPlugin(pluginId)
+                                   } else {
+                                       PluginModel.resetPluginPreferencesValues(pluginId, accountId)
+                                   }
+                                   preferencesPerCategoryModel.reset()
+                                   generalPreferencesModel.reset()
+                               }]
+                           })
         }
     }
 }
diff --git a/src/app/settingsview/components/PluginPreferencesView.qml b/src/app/settingsview/components/PluginPreferencesView.qml
index 78021d267e592a7138ccde40bd24435789247574..33d267c5890a3cb209c2c10eaba8da00b89b1b7f 100644
--- a/src/app/settingsview/components/PluginPreferencesView.qml
+++ b/src/app/settingsview/components/PluginPreferencesView.qml
@@ -173,15 +173,21 @@ Rectangle {
 
             text: JamiStrings.uninstall
 
-            onClicked: {
-                msgDialog.buttonCallBacks = [function () {
-                    pluginPreferencesView.visible = false
-                    PluginModel.uninstallPlugin(pluginId)
-                    installedPluginsModel.removePlugin(index)
-                }]
-                msgDialog.openWithParameters(JamiStrings.uninstallPlugin,
-                                             JamiStrings.pluginUninstallConfirmation.arg(pluginName))
-            }
+            onClicked: viewCoordinator.presentDialog(
+                           appWindow,
+                           "commoncomponents/SimpleMessageDialog.qml",
+                           {
+                               title: JamiStrings.uninstallPlugin,
+                               infoText: JamiStrings.pluginUninstallConfirmation.arg(pluginName),
+                               buttonTitles: [JamiStrings.optionOk, JamiStrings.optionCancel],
+                               buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue,
+                                              SimpleMessageDialog.ButtonStyle.TintedBlack],
+                               buttonCallBacks: [function () {
+                                   pluginPreferencesView.visible = false
+                                   PluginModel.uninstallPlugin(pluginId)
+                                   installedPluginsModel.removePlugin(index)
+                               }]
+                           })
         }
 
         Rectangle {
diff --git a/src/app/settingsview/components/RevokeDevicePasswordDialog.qml b/src/app/settingsview/components/RevokeDevicePasswordDialog.qml
index 67fbe55b1dd9e6d0b07cac5f9de6ab3ae2c15bb9..c32f0742b5fc10b0aee45a6ac1b79f9873e6ea23 100644
--- a/src/app/settingsview/components/RevokeDevicePasswordDialog.qml
+++ b/src/app/settingsview/components/RevokeDevicePasswordDialog.qml
@@ -22,24 +22,17 @@ import QtQuick.Controls
 import QtQuick.Layouts
 
 import net.jami.Constants 1.1
+import net.jami.Models 1.1
 
 import "../../commoncomponents"
 
 BaseModalDialog {
     id: root
 
-    property string deviceId : ""
+    required property string deviceId
 
-    signal revokeDeviceWithPassword(string idOfDevice, string password)
-
-    function openRevokeDeviceDialog(deviceIdIn) {
-        deviceId = deviceIdIn
-
-        open()
-    }
-
-    width: Math.min(mainView.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogWidth)
-    height: Math.min(mainView.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogHeight)
+    width: Math.min(appWindow.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogWidth)
+    height: Math.min(appWindow.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.preferredDialogHeight)
 
     title: JamiStrings.removeDevice
 
@@ -106,7 +99,7 @@ BaseModalDialog {
                 text: JamiStrings.optionRemove
 
                 onClicked: {
-                    revokeDeviceWithPassword(deviceId, passwordEdit.text)
+                    DeviceItemListModel.revokeDevice(deviceId, passwordEdit.text)
                     close()
                 }
             }
@@ -130,6 +123,6 @@ BaseModalDialog {
 
                 onClicked: close()
             }
-    }
+        }
     }
 }
diff --git a/src/app/settingsview/components/SettingsHeader.qml b/src/app/settingsview/components/SettingsHeader.qml
index d48324782c01be1b81e806161356063eb7044cc8..2d299af07a693d44403433ef44a30dfdf6cad977 100644
--- a/src/app/settingsview/components/SettingsHeader.qml
+++ b/src/app/settingsview/components/SettingsHeader.qml
@@ -37,7 +37,7 @@ RowLayout {
         Layout.preferredWidth: JamiTheme.preferredFieldHeight
         Layout.preferredHeight: JamiTheme.preferredFieldHeight
 
-        visible: mainView.sidePanelOnly
+        visible: viewCoordinator.singlePane
 
         onClicked: backArrowClicked()
     }
diff --git a/src/app/settingsview/components/SettingsMenu.qml b/src/app/settingsview/components/SettingsMenu.qml
index 17533734eef94ff24fffb5c84683698792cca134..77910d9a44fc5a559703ffcac87b083f50879e31 100644
--- a/src/app/settingsview/components/SettingsMenu.qml
+++ b/src/app/settingsview/components/SettingsMenu.qml
@@ -22,96 +22,81 @@ import QtQuick.Controls
 import net.jami.Models 1.1
 import net.jami.Constants 1.1
 
-// TODO: these includes should generally be resource uris
 import "../../commoncomponents"
 import "../../settingsview"
 
 Rectangle {
     id: root
 
-    signal itemSelected(int index)
-    signal buttonSelectedManually(int index)
-
     color: JamiTheme.backgroundColor
 
+    // The following bindings provide the settings menu selection persistence behavior.
+    property bool singlePane: viewCoordinator.singlePane
+    onSinglePaneChanged: {
+        if (!viewCoordinator.singlePane && viewCoordinator.inSettings) {
+            const idx = viewCoordinator.currentView.selectedMenu
+            buttonGroup.checkedButton = buttonGroup.buttons[idx]
+        }
+    }
+    onVisibleChanged: buttonGroup.checkedButton = visible && !viewCoordinator.singlePane ?
+                        buttonGroup.buttons[0] :
+                        null
+
+    // Bind to requests for a settings page to be selected via shorcut.
+    Connections {
+        target: JamiQmlUtils
+        function onSettingsPageRequested(index) {
+            buttonGroup.checkedButton = buttonGroup.buttons[index]
+        }
+    }
+
     ButtonGroup {
         id: buttonGroup
-
-        buttons: buttons.children
-        onCheckedButtonChanged: itemSelected(checkedButton.menuType)
+        buttons: settingsButtons.children
+
+        // When the selection changes, we present the SettingsView at
+        // the selected index.
+        onCheckedButtonChanged: {
+            for (var i = 0; i < buttons.length; i++)
+                if (buttons[i] === checkedButton) {
+                    if (viewCoordinator.singlePane) {
+                        viewCoordinator.present("SettingsView").selectedMenu = i
+                    } else if (!viewCoordinator.busy) {
+                        var settingsView = viewCoordinator.getView("SettingsView")
+                        settingsView.selectedMenu = i
+                    }
+                }
+        }
     }
 
     Column {
-        id: buttons
+        id: settingsButtons
 
         spacing: 0
         anchors.left: parent.left
         anchors.right: parent.right
         height: childrenRect.height
 
-        SettingsMenuButton {
-            id: accountPushButton
-            property int menuType: SettingsView.Account
-            Connections {
-                target: root
+        component SMB: SettingsMenuButton { normalColor: root.color }
 
-                function onButtonSelectedManually(index) {
-                    if (accountPushButton.menuType === index)
-                        buttonGroup.checkedButton = accountPushButton
-                }
-            }
-            checked: true
+        SMB {
             buttonText: JamiStrings.accountSettingsMenuTitle
             source: JamiResources.account_24dp_svg
-            normalColor: root.color
         }
 
-        SettingsMenuButton {
-            id: generalPushButton
-            property int menuType: SettingsView.General
-            Connections {
-                target: root
-
-                function onButtonSelectedManually(index) {
-                    if (generalPushButton.menuType === index)
-                        buttonGroup.checkedButton = generalPushButton
-                }
-            }
+        SMB {
             buttonText: JamiStrings.generalSettingsTitle
             source: JamiResources.gear_black_24dp_svg
-            normalColor: root.color
         }
 
-        SettingsMenuButton {
-            id: mediaPushButton
-            property int menuType: SettingsView.Media
-            Connections {
-                target: root
-
-                function onButtonSelectedManually(index) {
-                    if (mediaPushButton.menuType === index)
-                        buttonGroup.checkedButton = mediaPushButton
-                }
-            }
+        SMB {
             buttonText: JamiStrings.avSettingsMenuTitle
             source: JamiResources.media_black_24dp_svg
-            normalColor: root.color
         }
 
-        SettingsMenuButton {
-            id: pluginPushButton
-            property int menuType: SettingsView.Plugin
-            Connections {
-                target: root
-
-                function onButtonSelectedManually(index) {
-                    if (pluginPushButton.menuType === index)
-                        buttonGroup.checkedButton = pluginPushButton
-                }
-            }
+        SMB {
             buttonText: JamiStrings.pluginSettingsTitle
             source: JamiResources.plugin_settings_black_24dp_svg
-            normalColor: root.color
         }
     }
 }
diff --git a/src/app/settingsview/components/UpdateDownloadDialog.qml b/src/app/settingsview/components/UpdateDownloadDialog.qml
new file mode 100644
index 0000000000000000000000000000000000000000..88cf9f351020f3f1b585c946d87ee82ea27a955a
--- /dev/null
+++ b/src/app/settingsview/components/UpdateDownloadDialog.qml
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2023 Savoir-faire Linux Inc.
+ *
+ * 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/>.
+ */
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import net.jami.Adapters 1.1
+import net.jami.Enums 1.1
+import net.jami.Models 1.1
+import net.jami.Helpers 1.1
+import net.jami.Constants 1.1
+
+import "../../commoncomponents"
+
+SimpleMessageDialog {
+    id: downloadDialog
+
+    property int bytesRead: 0
+    property int totalBytes: 0
+    property string hSizeRead:  UtilsAdapter.humanFileSize(bytesRead)
+    property string hTotalBytes: UtilsAdapter.humanFileSize(totalBytes)
+    property alias progressBarValue: progressBar.value
+
+    Connections {
+        target: UpdateManager
+
+        function onUpdateDownloadProgressChanged(bytesRead, totalBytes) {
+            downloadDialog.setDownloadProgress(bytesRead, totalBytes)
+        }
+
+        function onUpdateDownloadErrorOccurred(error) {
+            downloadDialog.close()
+        }
+
+        function onUpdateDownloadFinished() {
+            downloadDialog.close()
+        }
+    }
+
+    function setDownloadProgress(bytesRead, totalBytes) {
+        downloadDialog.bytesRead = bytesRead
+        downloadDialog.totalBytes = totalBytes
+    }
+
+    infoText: JamiStrings.updateDownloading +
+              " (%1 / %2)".arg(hSizeRead).arg(hTotalBytes)
+
+    innerContentData: ProgressBar {
+        id: progressBar
+
+        value: downloadDialog.bytesRead /
+               downloadDialog.totalBytes
+
+        anchors.left: parent.left
+        anchors.leftMargin: JamiTheme.preferredMarginSize
+        anchors.right: parent.right
+        anchors.rightMargin: JamiTheme.preferredMarginSize
+
+        background: Rectangle {
+            implicitWidth: parent.width
+            implicitHeight: 24
+            color: JamiTheme.darkGrey
+        }
+
+        contentItem: Item {
+            implicitWidth: parent.width
+            implicitHeight: 22
+
+            Rectangle {
+                width: progressBar.visualPosition * parent.width
+                height: parent.height
+                color: JamiTheme.selectionBlue
+            }
+            Label {
+                anchors.horizontalCenter: parent.horizontalCenter
+                anchors.verticalCenter: parent.verticalCenter
+
+                color: JamiTheme.whiteColor
+                font.bold: true
+                font.pointSize: JamiTheme.textFontSize + 1
+                horizontalAlignment: Text.AlignHCenter
+                verticalAlignment: Text.AlignVCenter
+                text: Math.ceil(progressBar.value * 100).toString() + "%"
+            }
+        }
+    }
+
+    buttonTitles: [JamiStrings.optionCancel]
+    buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue]
+    buttonCallBacks: [function() { UpdateManager.cancelUpdate() }]
+    onVisibleChanged: {
+        if (!visible)
+            UpdateManager.cancelUpdate()
+    }
+}
diff --git a/src/app/settingsview/components/UpdateSettings.qml b/src/app/settingsview/components/UpdateSettings.qml
index 1f198fe499a739bd259b18cc32868efbdda2a3cf..124e7e31c2272c294e73035d31d034640f38657c 100644
--- a/src/app/settingsview/components/UpdateSettings.qml
+++ b/src/app/settingsview/components/UpdateSettings.qml
@@ -103,11 +103,36 @@ ColumnLayout {
         toolTipText: JamiStrings.betaInstall
         text: JamiStrings.betaInstall
 
-        onClicked: {
-            confirmInstallDialog.beta = true
-            confirmInstallDialog.openWithParameters(JamiStrings.updateDialogTitle,
-                                                    JamiStrings.confirmBeta)
-        }
+        onClicked: presentConfirmInstallDialog(JamiStrings.confirmBeta, true)
+    }
+
+    function presentInfoDialog(infoText) {
+        viewCoordinator.presentDialog(
+            appWindow,
+            "commoncomponents/SimpleMessageDialog.qml",
+            {
+                title: JamiStrings.updateDialogTitle,
+                infoText: infoText,
+                buttonTitles: [JamiStrings.optionOk],
+                buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue],
+                buttonCallBacks: []
+            })
+    }
+
+    function presentConfirmInstallDialog(infoText, beta) {
+        viewCoordinator.presentDialog(
+            appWindow,
+            "commoncomponents/SimpleMessageDialog.qml",
+            {
+                title: JamiStrings.updateDialogTitle,
+                infoText: infoText,
+                buttonTitles: [JamiStrings.optionUpgrade, JamiStrings.optionLater],
+                buttonStyles: [
+                    SimpleMessageDialog.ButtonStyle.TintedBlue,
+                    SimpleMessageDialog.ButtonStyle.TintedBlue
+                ],
+                buttonCallBacks: [function() {UpdateManager.applyUpdates(beta)}]
+            })
     }
 
     Connections {
@@ -129,128 +154,31 @@ ColumnLayout {
             }
         }
 
+        function onUpdateDownloadStarted() {
+            viewCoordinator.presentDialog(
+                appWindow,
+                "settingsview/components/UpdateDownloadDialog.qml",
+                {title: JamiStrings.updateDialogTitle})
+        }
+
         function onUpdateCheckReplyReceived(ok, found) {
             if (!ok) {
-                issueDialog.openWithParameters(JamiStrings.updateDialogTitle,
-                                               JamiStrings.updateCheckError)
+                presentInfoDialog(JamiStrings.updateCheckError)
                 return
             }
             if (!found) {
-                issueDialog.openWithParameters(JamiStrings.updateDialogTitle,
-                                               JamiStrings.updateNotFound)
+                presentInfoDialog(JamiStrings.updateNotFound)
             } else {
-                confirmInstallDialog.openWithParameters(JamiStrings.updateDialogTitle,
-                                                        JamiStrings.updateFound)
+                presentConfirmInstallDialog(JamiStrings.confirmUpdate, false)
             }
         }
 
-        function onUpdateCheckErrorOccurred(error) {
-            issueDialog.openWithParameters(JamiStrings.updateDialogTitle,
-                                           errorToString(error))
-        }
-
-        function onUpdateDownloadStarted() {
-            downloadDialog.setDownloadProgress(0, 0)
-            downloadDialog.openWithParameters(JamiStrings.updateDialogTitle)
-        }
-
-        function onUpdateDownloadProgressChanged(bytesRead, totalBytes) {
-            downloadDialog.setDownloadProgress(bytesRead, totalBytes)
-        }
-
         function onUpdateDownloadErrorOccurred(error) {
-            downloadDialog.close()
-            issueDialog.openWithParameters(JamiStrings.updateDialogTitle,
-                                           errorToString(error))
+            presentInfoDialog(errorToString(error))
         }
 
-        function onUpdateDownloadFinished() { downloadDialog.close() }
-    }
-
-    SimpleMessageDialog {
-        id: confirmInstallDialog
-
-        property bool beta: false
-
-        buttonTitles: [JamiStrings.optionUpgrade, JamiStrings.optionLater]
-        buttonStyles: [
-            SimpleMessageDialog.ButtonStyle.TintedBlue,
-            SimpleMessageDialog.ButtonStyle.TintedBlue
-        ]
-        buttonCallBacks: [function() {UpdateManager.applyUpdates(beta)}]
-    }
-
-    SimpleMessageDialog {
-        id: issueDialog
-
-        buttonTitles: [JamiStrings.optionOk]
-        buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue]
-        buttonCallBacks: []
-    }
-
-    SimpleMessageDialog {
-        id: downloadDialog
-
-        property int bytesRead: 0
-        property int totalBytes: 0
-        property string hSizeRead:  UtilsAdapter.humanFileSize(bytesRead)
-        property string hTotalBytes: UtilsAdapter.humanFileSize(totalBytes)
-        property alias progressBarValue: progressBar.value
-
-        function setDownloadProgress(bytesRead, totalBytes) {
-            downloadDialog.bytesRead = bytesRead
-            downloadDialog.totalBytes = totalBytes
-        }
-
-        infoText: JamiStrings.updateDownloading +
-                  " (%1 / %2)".arg(hSizeRead).arg(hTotalBytes)
-
-        innerContentData: ProgressBar {
-            id: progressBar
-
-            value: downloadDialog.bytesRead /
-                   downloadDialog.totalBytes
-
-            anchors.left: parent.left
-            anchors.leftMargin: JamiTheme.preferredMarginSize
-            anchors.right: parent.right
-            anchors.rightMargin: JamiTheme.preferredMarginSize
-
-            background: Rectangle {
-                implicitWidth: parent.width
-                implicitHeight: 24
-                color: JamiTheme.darkGrey
-            }
-
-            contentItem: Item {
-                implicitWidth: parent.width
-                implicitHeight: 22
-
-                Rectangle {
-                    width: progressBar.visualPosition * parent.width
-                    height: parent.height
-                    color: JamiTheme.selectionBlue
-                }
-                Label {
-                    anchors.horizontalCenter: parent.horizontalCenter
-                    anchors.verticalCenter: parent.verticalCenter
-
-                    color: JamiTheme.whiteColor
-                    font.bold: true
-                    font.pointSize: JamiTheme.textFontSize + 1
-                    horizontalAlignment: Text.AlignHCenter
-                    verticalAlignment: Text.AlignVCenter
-                    text: Math.ceil(progressBar.value * 100).toString() + "%"
-                }
-            }
-        }
-
-        buttonTitles: [JamiStrings.optionCancel]
-        buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue]
-        buttonCallBacks: [function() {UpdateManager.cancelUpdate()}]
-        onVisibleChanged: {
-            if (!visible)
-                UpdateManager.cancelUpdate()
+        function onUpdateCheckErrorOccurred(error) {
+            presentInfoDialog(errorToString(error))
         }
     }
 }
diff --git a/src/app/updatemanager.cpp b/src/app/updatemanager.cpp
index 7e4f97f29915f63f8a0efa738b09e105401caac4..d81383ce70f1636295a9d1e72aeee1fbfa2fc7d9 100644
--- a/src/app/updatemanager.cpp
+++ b/src/app/updatemanager.cpp
@@ -48,7 +48,7 @@ struct UpdateManager::Impl : public QObject
         , tempPath_(QDir::tempPath())
         , updateTimer_(new QTimer(this))
     {
-        connect(updateTimer_, &QTimer::timeout, [this] {
+        connect(updateTimer_, &QTimer::timeout, this, [this] {
             // Quiet period update check.
             parent_.checkForUpdates(true);
         });
@@ -96,7 +96,7 @@ struct UpdateManager::Impl : public QObject
                 &NetWorkManager::errorOccured,
                 &parent_,
                 &UpdateManager::updateDownloadErrorOccurred);
-        connect(&parent_, &NetWorkManager::statusChanged, [this](GetStatus status) {
+        connect(&parent_, &NetWorkManager::statusChanged, this, [this](GetStatus status) {
             switch (status) {
             case GetStatus::STARTED:
                 connect(&parent_,
diff --git a/src/app/utilsadapter.h b/src/app/utilsadapter.h
index 4db0723c7df9b1a0a77c73a37ccd8a9aba8f6534..89fad25139d8d2ce09d162cab3e775fead1fc4e3 100644
--- a/src/app/utilsadapter.h
+++ b/src/app/utilsadapter.h
@@ -42,7 +42,6 @@ class SystemTray;
 
 #define LOGSLIMIT 10000
 
-
 #if defined(WIN32) && __has_include(<winrt/Windows.Foundation.h>)
 /**
  * @brief Read if "AppsUseLightTheme" registry exists and its value
@@ -66,8 +65,6 @@ public:
                           QObject* parent = nullptr);
     ~UtilsAdapter() = default;
 
-    void safeInit() override {}
-
     Q_INVOKABLE const QString getProjectCredits();
     Q_INVOKABLE const QString getVersionStr();
     Q_INVOKABLE void setClipboardText(QString text);
diff --git a/src/app/wizardview/WizardView.qml b/src/app/wizardview/WizardView.qml
index fded8ff5758ec8c16da4479d5c50fc3ac4522f0a..bd0d7514534a5389f2ff15b789e87b578736827b 100644
--- a/src/app/wizardview/WizardView.qml
+++ b/src/app/wizardview/WizardView.qml
@@ -30,8 +30,10 @@ import "../"
 import "../commoncomponents"
 import "components"
 
-Rectangle {
+BaseView {
     id: root
+    objectName: "WizardView"
+    singlePaneOnly: true
 
     // signal to redirect the page to main view
     signal loaderSourceChangeRequested(int sourceToLoad)
@@ -59,6 +61,7 @@ Rectangle {
 
         function onCloseWizardView() {
             loaderSourceChangeRequested(MainApplicationWindow.LoadedSource.MainView)
+            root.dismiss()
         }
     }
 
diff --git a/src/app/wizardview/components/ImportFromBackupPage.qml b/src/app/wizardview/components/ImportFromBackupPage.qml
index 191d76180ec89e11e3081717e0b5e8a2637a3d7b..534f3d6e1e8e11b65e6e858d55eed9e56f30848a 100644
--- a/src/app/wizardview/components/ImportFromBackupPage.qml
+++ b/src/app/wizardview/components/ImportFromBackupPage.qml
@@ -67,35 +67,6 @@ Rectangle {
 
     color: JamiTheme.secondaryBackgroundColor
 
-    JamiFileDialog {
-        id: importFromFileDialog
-
-        mode: JamiFileDialog.OpenFile
-        title: JamiStrings.openFile
-        folder: StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/Desktop"
-
-        nameFilters: [JamiStrings.jamiArchiveFiles, JamiStrings.allFiles]
-
-        onVisibleChanged: {
-            if (!visible) {
-                rejected()
-            }
-        }
-
-        onRejected: {
-            fileImportBtn.forceActiveFocus()
-        }
-
-        onAccepted: {
-            filePath = file
-            if (file.length !== "") {
-                fileImportBtnText = UtilsAdapter.toFileInfoName(file)
-            } else {
-                fileImportBtnText = JamiStrings.archive
-            }
-        }
-    }
-
     ColumnLayout {
         id: importFromBackupPageColumnLayout
 
@@ -157,7 +128,28 @@ Rectangle {
 
             onClicked: {
                 errorText = ""
-                importFromFileDialog.open()
+                var dlg = viewCoordinator.presentDialog(
+                            appWindow,
+                            "commoncomponents/JamiFileDialog.qml",
+                            {
+                                title: JamiStrings.openFile,
+                                fileMode: JamiFileDialog.OpenFile,
+                                folder: StandardPaths.writableLocation(
+                                            StandardPaths.HomeLocation) + "/Desktop",
+                                nameFilters: [JamiStrings.jamiArchiveFiles,
+                                    JamiStrings.allFiles]
+                            })
+                dlg.fileAccepted.connect(function(file) {
+                    filePath = file
+                    if (file.length !== "") {
+                        fileImportBtnText = UtilsAdapter.toFileInfoName(file)
+                    } else {
+                        fileImportBtnText = JamiStrings.archive
+                    }
+                })
+                dlg.rejected.connect(function() {
+                    fileImportBtn.forceActiveFocus()
+                })
             }
         }
 
diff --git a/src/app/wizardview/components/WelcomePage.qml b/src/app/wizardview/components/WelcomePage.qml
index 1dcb2dfcdf9af9e58d91d79ce9e580e8543de728..ee914f42dbbfc03e399820be8fd5711ce6e5d368 100644
--- a/src/app/wizardview/components/WelcomePage.qml
+++ b/src/app/wizardview/components/WelcomePage.qml
@@ -61,7 +61,6 @@ Rectangle {
     KeyNavigation.up: newAccountButton
     KeyNavigation.down: KeyNavigation.tab
 
-
     ColumnLayout {
         id: welcomePageColumnLayout
 
@@ -72,13 +71,6 @@ Rectangle {
         anchors.topMargin: JamiTheme.wizardViewLayoutTopMargin
         width: Math.max(508, root.width - 100)
 
-        AboutPopUp {
-            id: aboutPopUpDialog
-
-            width: Math.min(parent.width - 2 * JamiTheme.preferredMarginSize, JamiTheme.secondaryDialogDimension)
-            height: Math.min(parent.height - 2 * JamiTheme.preferredMarginSize, JamiTheme.secondaryDialogDimension)
-        }
-
         ResponsiveImage {
             id: welcomeLogo
 
@@ -231,7 +223,6 @@ Rectangle {
             onClicked: WizardViewStepModel.startAccountCreationFlow(WizardViewStepModel.AccountCreationOption.ImportFromBackup)
         }
 
-
         MaterialButton {
             id: showAdvancedButton
 
@@ -337,7 +328,6 @@ Rectangle {
                            WizardViewStepModel.AccountCreationOption.CreateSipAccount)
         }
 
-
         MaterialButton {
             id: btnAboutPopUp
 
@@ -355,7 +345,9 @@ Rectangle {
 
             text: JamiStrings.aboutJami
 
-            onClicked: aboutPopUpDialog.open()
+            onClicked: viewCoordinator.presentDialog(
+                           parent,
+                           "mainview/components/AboutPopUp.qml")
         }
     }
 
@@ -385,7 +377,5 @@ Rectangle {
         KeyNavigation.down: KeyNavigation.tab
 
         onClicked: WizardViewStepModel.previousStep()
-
     }
-
 }
diff --git a/src/libclient/callmodel.cpp b/src/libclient/callmodel.cpp
index ce0b779c9a69785255a0070cba90f6d670341873..c87311cf48c515ab392c13f12d175e051af1f119 100644
--- a/src/libclient/callmodel.cpp
+++ b/src/libclient/callmodel.cpp
@@ -400,7 +400,7 @@ CallModel::createCall(const QString& uri, bool isAudioOnly, VectorMapStringStrin
     }
 #ifdef ENABLE_LIBWRAP
     auto callId = CallManager::instance().placeCallWithMedia(owner.id, uri, mediaList);
-#else  // dbus
+#else // dbus
     // do not use auto here (QDBusPendingReply<QString>)
     QString callId = CallManager::instance().placeCallWithMedia(owner.id, uri, mediaList);
 #endif // ENABLE_LIBWRAP