fix #LINQT-1282 autocomplete contact address

fix #LINQT-1285 fix call notif deletion

fix #LINQT-1283 : reset views when switching tab or creating new call

fix #LINQT-1287 pause logo on pause

fix #LINQT-1281 clear vertical tabbar index if in settings
This commit is contained in:
Gaelle Braud 2024-09-26 14:35:13 +02:00
parent a66528326f
commit 498777869e
18 changed files with 113 additions and 81 deletions

View file

@ -298,6 +298,8 @@ void App::setSelf(QSharedPointer<App>(me)) {
auto callGui = new CallGui(callCore);
auto win = getCallsWindow(QVariant::fromValue(callGui));
Utils::smartShowWindow(win);
auto mainwin = getMainWindow();
QMetaObject::invokeMethod(mainwin, "callCreated");
lDebug() << "App : call created" << callGui;
});
});

View file

@ -21,6 +21,7 @@
#include "CallHistoryCore.hpp"
#include "core/App.hpp"
#include "core/conference/ConferenceInfoCore.hpp"
#include "core/friend/FriendGui.hpp"
#include "model/call-history/CallHistoryModel.hpp"
#include "model/object/VariantObject.hpp"
#include "model/tool/ToolModel.hpp"
@ -61,6 +62,11 @@ CallHistoryCore::CallHistoryCore(const std::shared_ptr<linphone::CallLog> &callL
} else {
mRemoteAddress = Utils::coreStringToAppString(addr->asStringUriOnly());
mDisplayName = ToolModel::getDisplayName(Utils::coreStringToAppString(addr->asStringUriOnly()));
auto inFriend = Utils::findFriendByAddress(mRemoteAddress);
if (inFriend) {
auto friendGui = inFriend->getValue().value<FriendGui *>();
if (friendGui) mDisplayName = friendGui->getCore()->getDisplayName();
}
}
}

View file

@ -373,11 +373,12 @@ void FriendCore::removeAddress(int index) {
void FriendCore::appendAddress(const QString &addr) {
if (addr.isEmpty()) return;
auto linAddr = linphone::Factory::get()->createAddress(Utils::appStringToCoreString(addr));
QString interpretedAddress = Utils::interpretUrl(addr);
auto linAddr = linphone::Factory::get()->createAddress(Utils::appStringToCoreString(interpretedAddress));
if (!linAddr) Utils::showInformationPopup(tr("Erreur"), tr("Adresse invalide"), false);
else {
mAddressList.append(createFriendAddressVariant(addressLabel, addr));
if (mDefaultAddress.isEmpty()) mDefaultAddress = addr;
mAddressList.append(createFriendAddressVariant(addressLabel, interpretedAddress));
if (mDefaultAddress.isEmpty()) mDefaultAddress = interpretedAddress;
emit addressChanged();
}
}

View file

@ -125,19 +125,17 @@ Notifier::~Notifier() {
// -----------------------------------------------------------------------------
QObject *Notifier::createNotification(Notifier::NotificationType type, QVariantMap data) {
QQuickItem *wrapperItem = nullptr;
bool Notifier::createNotification(Notifier::NotificationType type, QVariantMap data) {
mMutex->lock();
Q_ASSERT(mInstancesNumber <= MaxNotificationsNumber);
if (mInstancesNumber == MaxNotificationsNumber) { // Check existing instances.
qWarning() << QStringLiteral("Unable to create another notification.");
mMutex->unlock();
return nullptr;
return false;
}
QList<QScreen *> allScreens = QGuiApplication::screens();
if (allScreens.size() > 0) { // Ensure to have a screen to avoid errors
QQuickItem *previousWrapper = nullptr;
++mInstancesNumber;
bool showAsTool = false;
#ifdef Q_OS_MACOS
for (auto w : QGuiApplication::topLevelWindows()) {
@ -151,6 +149,7 @@ QObject *Notifier::createNotification(Notifier::NotificationType type, QVariantM
#endif
for (int i = 0; i < allScreens.size(); ++i) {
++mInstancesNumber;
// Use QQuickView to create a visual root object that is
// independant from current application Window
QScreen *screen = allScreens[i];
@ -167,7 +166,7 @@ QObject *Notifier::createNotification(Notifier::NotificationType type, QVariantM
const QUrl url(QString(NotificationsPath) + Notifier::Notifications[type].filename);
QObject::connect(
engine, &QQmlApplicationEngine::objectCreated, this,
[this, url, screen, engine](QObject *obj, const QUrl &objUrl) {
[this, url, screen, engine, type](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl) {
lCritical() << "[App] Notifier.qml couldn't be load.";
engine->deleteLater();
@ -188,18 +187,21 @@ QObject *Notifier::createNotification(Notifier::NotificationType type, QVariantM
window->property("width")
.toInt())); //*screen->devicePixelRatio()); when using manual scaler
window->setY(heightOffset - (*screenHeightOffset % heightOffset));
lDebug() << window->geometry();
const int timeout = Notifications[type].getTimeout() * 1000;
QObject::connect(window, &QQuickWindow::closing, window,
[this, window] { deleteNotification(QVariant::fromValue(window)); });
showNotification(window, timeout);
lInfo() << QStringLiteral("Create notification:") << QVariant::fromValue(window);
}
}
},
Qt::QueuedConnection);
engine->load(url);
}
lInfo() << QStringLiteral("Create notifications:") << wrapperItem;
}
mMutex->unlock();
return wrapperItem;
return true;
}
// -----------------------------------------------------------------------------
@ -246,12 +248,12 @@ void Notifier::deleteNotification(QVariant notification) {
return;
}
lInfo() << QStringLiteral("Delete notification:") << instance;
lInfo() << QStringLiteral("Delete notification:") << instance << --mInstancesNumber;
instance->setProperty("__valid", true);
instance->property(NotificationPropertyTimer).value<QTimer *>()->stop();
auto timerProperty = instance->property(NotificationPropertyTimer).value<QTimer *>();
if (timerProperty) timerProperty->stop();
mInstancesNumber--;
Q_ASSERT(mInstancesNumber >= 0);
if (mInstancesNumber == 0) mScreenHeightOffset.clear();
@ -266,10 +268,7 @@ void Notifier::deleteNotification(QVariant notification) {
#define CREATE_NOTIFICATION(TYPE, DATA) \
auto settings = App::getInstance()->getSettings(); \
if (settings && settings->dndEnabled()) return; \
QObject *notification = createNotification(TYPE, DATA); \
if (!notification) return; \
const int timeout = Notifications[TYPE].getTimeout() * 1000; \
showNotification(notification, timeout);
createNotification(TYPE, DATA);
// -----------------------------------------------------------------------------
// Notification functions.
@ -299,15 +298,6 @@ void Notifier::notifyReceivedCall(const shared_ptr<linphone::Call> &call) {
map["call"].setValue(gui);
CREATE_NOTIFICATION(Notifier::ReceivedCall, map)
QObject::connect(
gui->getCore(), &CallCore::statusChanged, notification,
[this, notification](LinphoneEnums::CallStatus status) {
lInfo() << log().arg("Delete notification on call status : %1").arg(LinphoneEnums::toString(status));
deleteNotification(QVariant::fromValue(notification));
});
QObject::connect(gui->getCore(), &CallCore::destroyed, notification,
[this, notification]() { deleteNotification(QVariant::fromValue(notification)); });
});
}

View file

@ -41,12 +41,12 @@ public:
~Notifier();
enum NotificationType {
//ReceivedMessage,
//ReceivedFileMessage,
// ReceivedMessage,
// ReceivedFileMessage,
ReceivedCall,
//NewVersionAvailable,
//SnapshotWasTaken,
//RecordingCompleted
// NewVersionAvailable,
// SnapshotWasTaken,
// RecordingCompleted
};
// void notifyReceivedCall(Call *call);
@ -88,14 +88,14 @@ private:
int type;
};
QObject *createNotification(NotificationType type, QVariantMap data);
bool createNotification(NotificationType type, QVariantMap data);
void showNotification(QObject *notification, int timeout);
QHash<QString, int> mScreenHeightOffset;
int mInstancesNumber = 0;
QMutex *mMutex = nullptr;
//QQmlComponent **mComponents = nullptr;
// QQmlComponent **mComponents = nullptr;
QVector<QQmlComponent *> mComponents;
static const QHash<int, Notification> Notifications;

View file

@ -89,14 +89,14 @@ void MagicSearchProxy::setSourceFlags(int flags) {
}
}
bool MagicSearchProxy::showFavouritesOnly() const {
return mShowFavouritesOnly;
bool MagicSearchProxy::showFavoritesOnly() const {
return mShowFavoritesOnly;
}
void MagicSearchProxy::setShowFavouritesOnly(bool show) {
if (mShowFavouritesOnly != show) {
mShowFavouritesOnly = show;
emit showFavouriteOnlyChanged();
void MagicSearchProxy::setShowFavoritesOnly(bool show) {
if (mShowFavoritesOnly != show) {
mShowFavoritesOnly = show;
emit showFavoriteOnlyChanged();
}
}
@ -117,7 +117,7 @@ bool MagicSearchProxy::filterAcceptsRow(int sourceRow, const QModelIndex &source
auto friendGui = model.value<FriendGui *>();
auto friendCore = friendGui->getCore();
if (friendCore) {
return !mShowFavouritesOnly || friendCore->getStarred();
return !mShowFavoritesOnly || friendCore->getStarred();
}
return false;
}

View file

@ -34,8 +34,7 @@ class MagicSearchProxy : public SortFilterProxy {
Q_PROPERTY(int sourceFlags READ getSourceFlags WRITE setSourceFlags NOTIFY sourceFlagsChanged)
Q_PROPERTY(LinphoneEnums::MagicSearchAggregation aggregationFlag READ getAggregationFlag WRITE setAggregationFlag
NOTIFY aggregationFlagChanged)
Q_PROPERTY(
bool showFavouritesOnly READ showFavouritesOnly WRITE setShowFavouritesOnly NOTIFY showFavouriteOnlyChanged)
Q_PROPERTY(bool showFavoritesOnly READ showFavoritesOnly WRITE setShowFavoritesOnly NOTIFY showFavoriteOnlyChanged)
public:
MagicSearchProxy(QObject *parent = Q_NULLPTR);
@ -50,8 +49,8 @@ public:
LinphoneEnums::MagicSearchAggregation getAggregationFlag() const;
void setAggregationFlag(LinphoneEnums::MagicSearchAggregation flag);
bool showFavouritesOnly() const;
void setShowFavouritesOnly(bool show);
bool showFavoritesOnly() const;
void setShowFavoritesOnly(bool show);
void setSourceModel(QAbstractItemModel *sourceModel) override;
@ -64,12 +63,12 @@ signals:
void aggregationFlagChanged(LinphoneEnums::MagicSearchAggregation aggregationFlag);
void forceUpdate();
void friendCreated(int index);
void showFavouriteOnlyChanged();
void showFavoriteOnlyChanged();
protected:
QString mSearchText;
int mSourceFlags;
bool mShowFavouritesOnly = false;
bool mShowFavoritesOnly = false;
LinphoneEnums::MagicSearchAggregation mAggregationFlag;
QSharedPointer<MagicSearchList> mList;
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;

View file

@ -23,7 +23,7 @@ ListView {
property bool actionLayoutVisible: false
property bool initialHeadersVisible: true
property bool displayNameCapitalization: true
property bool showFavouritesOnly: false
property bool showFavoritesOnly: false
property bool showDefaultAddress: false
property var sourceModel: MagicSearchList{}
@ -82,10 +82,8 @@ ListView {
}
}
onActiveFocusChanged: if(activeFocus && (!footerItem || !footerItem.activeFocus)) {
currentIndex = 0
}else {
currentIndex = -1
}
currentIndex = 0
}
model: MagicSearchProxy {
id: magicSearchProxy
@ -93,7 +91,7 @@ ListView {
// This property is needed instead of playing on the delegate visibility
// considering its starred status. Otherwise, the row in the list still
// exists even if its delegate is not visible, and creates navigation issues
showFavouritesOnly: mainItem.showFavouritesOnly
showFavoritesOnly: mainItem.showFavoritesOnly
onFriendCreated: (index) => {
mainItem.currentIndex = index
}

View file

@ -25,7 +25,11 @@ Item {
property alias displayPresence: avatar.displayPresence
property color color: DefaultStyle.grey_600
property int radius: 15 * DefaultStyle.dp
property bool remoteIsPaused: participantDevice ? participantDevice.core.isPaused : false
property bool remoteIsPaused: participantDevice
? participantDevice.core.isPaused
: previewEnabled
? callState === LinphoneEnums.CallState.Paused
: callState === LinphoneEnums.CallState.PausedByRemote
property var peerAddressObj: previewEnabled && (call || account)
? UtilsCpp.getDisplayName(account ? account.core.identityAddress : call.core.localAddress)
: participantDevice && participantDevice.core
@ -202,7 +206,12 @@ Item {
triggeredOnStart: true
onTriggered: {cameraLoader.reset = !cameraLoader.reset}
}
active: mainItem.visible && mainItem.callState != LinphoneEnums.CallState.End && mainItem.callState != LinphoneEnums.CallState.Released && mainItem.videoEnabled && !cameraLoader.reset
active: mainItem.visible && !mainItem.remoteIsPaused
&& mainItem.callState != LinphoneEnums.CallState.End
&& mainItem.callState != LinphoneEnums.CallState.Released
&& mainItem.callState != LinphoneEnums.CallState.Paused
&& mainItem.callState != LinphoneEnums.CallState.PausedByRemote
&& mainItem.videoEnabled && !cameraLoader.reset
onActiveChanged: console.log("("+mainItem.qmlName+") Camera active " + active +", visible="+mainItem.visible +", videoEnabled="+mainItem.videoEnabled +", reset="+cameraLoader.reset)
sourceComponent: cameraComponent
}

View file

@ -20,7 +20,7 @@ DesktopPopup {
// Use as an intermediate between signal/slot without propagate the notification var : last signal parameter will be the last notification instance
function deleteNotificationSlot(){
deleteNotification(notification)
deleteNotification(mainItem)
}
function _close (cb) {
@ -29,7 +29,7 @@ DesktopPopup {
}
deleteNotificationSlot();
}
Rectangle {
id: background
color: DefaultStyle.grey_0

View file

@ -11,11 +11,15 @@ Notification {
overriddenHeight: content.implicitHeight//422 * DefaultStyle.dp
readonly property var call: notificationData && notificationData.call
property var state: call.core.state
property var status: call.core.status
onStateChanged:{
if (state != LinphoneEnums.CallState.IncomingReceived){
close()
}
}
onStatusChanged:{
console.log("status", status)
}
Popup {
id: content

View file

@ -319,10 +319,9 @@ MainRightPanel {
}
}
onEditingFinished: {
if (text != "sip:") mainItem.contact.core.appendAddress(text)
text = "sip:"
mainItem.contact.core.appendAddress(text)
newAddressTextField.clear()
}
Component.onCompleted: text = "sip:"
}
}
Item {

View file

@ -20,12 +20,14 @@ Item {
signal addAccountRequest()
signal openNewCallRequest()
signal callCreated()
signal openCallHistory()
signal openNumPadRequest()
signal displayContactRequested(string contactAddress)
signal createContactRequested(string name, string address)
signal accountRemoved()
function goToNewCall() {
tabbar.currentIndex = 0
mainItem.openNewCallRequest()
@ -138,6 +140,11 @@ Item {
Layout.preferredWidth: 82 * DefaultStyle.dp
defaultAccount: accountProxy.defaultAccount
currentIndex: SettingsCpp.getLastActiveTabIndex()
Binding on currentIndex {
when: mainItem.contextualMenuOpenedComponent != undefined
value: -1
restoreMode: Binding.RestoreBindingOrValue
}
model: [
{icon: AppIcons.phone, selectedIcon: AppIcons.phoneSelected, label: qsTr("Appels")},
{icon: AppIcons.adressBook, selectedIcon: AppIcons.adressBookSelected, label: qsTr("Contacts")},
@ -145,6 +152,7 @@ Item {
{icon: AppIcons.videoconference, selectedIcon: AppIcons.videoconferenceSelected, label: qsTr("Réunions"), visible: !SettingsCpp.disableMeetingsFeature}
]
onCurrentIndexChanged: {
if (currentIndex == -1) return
SettingsCpp.setLastActiveTabIndex(currentIndex)
if (currentIndex === 0 && accountProxy.defaultAccount) accountProxy.defaultAccount.core?.lResetMissedCalls()
if (mainItem.contextualMenuOpenedComponent) {
@ -580,12 +588,13 @@ Item {
StackLayout {
id: mainStackLayout
currentIndex: tabbar.currentIndex
onActiveFocusChanged: if(activeFocus) children[currentIndex].forceActiveFocus()
onActiveFocusChanged: if(activeFocus && currentIndex >= 0) children[currentIndex].forceActiveFocus()
CallPage {
id: callPage
Connections {
target: mainItem
function onOpenNewCallRequest(){ callPage.goToNewCall()}
function onCallCreated(){ callPage.resetLeftPanel()}
function onOpenCallHistory(){ callPage.goToCallHistory()}
function onOpenNumPadRequest(){ callPage.openNumPadRequest()}
}

View file

@ -11,19 +11,17 @@ AbstractSettingsLayout {
Component {
id: content
ColumnLayout {
width: parent.width
RowLayout {
ColumnLayout {
Layout.fillWidth: true
Item {
Layout.preferredWidth: 341 * DefaultStyle.dp
}
}
ColumnLayout {
Layout.rightMargin: 25 * DefaultStyle.dp
Layout.topMargin: 36 * DefaultStyle.dp
Layout.leftMargin: 64 * DefaultStyle.dp
Layout.fillWidth: true
spacing: 40 * DefaultStyle.dp
SwitchSetting {
titleText: qsTr("Annulateur d'écho")
@ -49,7 +47,6 @@ AbstractSettingsLayout {
}
RowLayout {
ColumnLayout {
Layout.fillWidth: true
ColumnLayout {
Layout.preferredWidth: 341 * DefaultStyle.dp
Text {
@ -72,17 +69,14 @@ AbstractSettingsLayout {
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 20 * DefaultStyle.dp
Layout.rightMargin: 44 * DefaultStyle.dp
Layout.topMargin: 20 * DefaultStyle.dp
Layout.leftMargin: 64 * DefaultStyle.dp
ColumnLayout {
Layout.fillWidth: true
spacing: 0
RowLayout {
Layout.fillWidth: true
EffectImage {
imageSource: AppIcons.speaker
colorizationColor: DefaultStyle.main1_500_main
@ -123,10 +117,8 @@ AbstractSettingsLayout {
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 0
RowLayout {
Layout.fillWidth: true
EffectImage {
imageSource: AppIcons.microphone
colorizationColor: DefaultStyle.main1_500_main
@ -205,7 +197,6 @@ AbstractSettingsLayout {
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 0
RowLayout {
EffectImage {

View file

@ -16,6 +16,10 @@ AbstractMainPage {
property var selectedRowHistoryGui
signal listViewUpdated()
onVisibleChanged: if (!visible) {
resetLeftPanel()
}
//Group call properties
property ConferenceInfoGui confInfoGui
property AccountProxy accounts: AccountProxy {id: accountProxy}
@ -47,13 +51,17 @@ AbstractMainPage {
onNoItemButtonPressed: goToNewCall()
showDefaultItem: listStackView.currentItem.listView && listStackView.currentItem.listView.count === 0 && listStackView.currentItem.listView.model.sourceModel.count === 0 || false
showDefaultItem: listStackView.currentItem && listStackView.currentItem.listView && listStackView.currentItem.listView.count === 0 && listStackView.currentItem.listView.model.sourceModel.count === 0 || false
function resetLeftPanel() {
listStackView.clear()
listStackView.push(listStackView.initialItem)
}
function goToNewCall() {
if (listStackView.currentItem.objectName != "newCallItem") listStackView.push(newCallItem)
if (listStackView.currentItem && listStackView.currentItem.objectName != "newCallItem") listStackView.push(newCallItem)
}
function goToCallHistory() {
if (listStackView.currentItem.objectName != "historyListItem") listStackView.replace(historyListItem)
if (listStackView.currentItem && listStackView.currentItem.objectName != "historyListItem") listStackView.replace(historyListItem)
}
Dialog {
@ -202,8 +210,6 @@ AbstractMainPage {
Component {
id: historyListItem
FocusScope{
width: parent.width
height: parent.height
Control.StackView.onActivated: titleLoader.sourceComponent = historyListTitle
ColumnLayout {
anchors.fill: parent
@ -315,6 +321,7 @@ AbstractMainPage {
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
capitalization: Font.Capitalize
}
}
RowLayout {
@ -500,14 +507,13 @@ AbstractMainPage {
searchBarColor: DefaultStyle.grey_100
//onSelectedContactChanged: mainWindow.startCallWithContact(selectedContact, false, callContactsList)
onCallSelectedContact: mainWindow.startCallWithContact(selectedContact, false, callContactsList)
onCallButtonPressed: mainItem.createCallFromSearchBarRequested()
onGroupCallCreationRequested: {
console.log("groupe call requetsed")
listStackView.push(groupCallItem)
}
Connections {
target: mainItem
function onCreateCallFromSearchBarRequested(){ UtilsCpp.createCall(callContactsList.searchBar.text)}
function onCreateCallFromSearchBarRequested(){ UtilsCpp.createCall(UtilsCpp.interpretUrl(callContactsList.searchBar.text))}
function onOpenNumPadRequest(){ if (!callContactsList.searchBar.numericPadButton.checked) callContactsList.searchBar.numericPadButton.checked = true}
}
Binding {

View file

@ -18,6 +18,12 @@ AbstractMainPage {
property FriendGui selectedContact
property string initialFriendToDisplay
onVisibleChanged: if (!visible) {
rightPanelStackView.clear()
contactList.currentIndex = -1
favoriteList.currentIndex = -1
}
onSelectedContactChanged: {
if (selectedContact) {
if (!rightPanelStackView.currentItem || rightPanelStackView.currentItem.objectName != "contactDetail") rightPanelStackView.push(contactDetail)
@ -272,7 +278,7 @@ AbstractMainPage {
Layout.fillWidth: true
Layout.preferredHeight: contentHeight
Control.ScrollBar.vertical.visible: false
showFavouritesOnly: true
showFavoritesOnly: true
contactMenuVisible: true
searchBarText: searchBar.text
sourceModel: allFriends
@ -703,7 +709,7 @@ AbstractMainPage {
Layout.preferredHeight: 50 * DefaultStyle.dp
iconSize: 24 * DefaultStyle.dp
iconSource: mainItem.selectedContact && mainItem.selectedContact.core.starred ? AppIcons.heartFill : AppIcons.heart
text: mainItem.selectedContact && mainItem.selectedContact.core.starred ? qsTr("Remove from favourites") : qsTr("Add to favourites")
text: mainItem.selectedContact && mainItem.selectedContact.core.starred ? qsTr("Remove from favorites") : qsTr("Add to favorites")
onClicked: if (mainItem.selectedContact) mainItem.selectedContact.core.lSetStarred(!mainItem.selectedContact.core.starred)
}
Rectangle {

View file

@ -21,6 +21,11 @@ AbstractMainPage {
Component.onCompleted: rightPanelStackView.push(overridenRightPanel, Control.StackView.Immediate)
showDefaultItem: false//leftPanelStackView.currentItem.objectName === "listLayout"
onVisibleChanged: if (!visible) {
leftPanelStackView.clear()
leftPanelStackView.push(leftPanelStackView.initialItem)
}
onSelectedConferenceChanged: {
overridenRightPanelStackView.clear()
if (selectedConference && selectedConference.core.haveModel) {
@ -125,7 +130,7 @@ AbstractMainPage {
}
Binding {
target: mainItem
when: leftPanelStackView.currentItem.objectName === "listLayout"
when: leftPanelStackView.currentItem && leftPanelStackView.currentItem.objectName === "listLayout"
property: "showDefaultItem"
value: conferenceList.count === 0
restoreMode: Binding.RestoreBindingOrValue

View file

@ -17,6 +17,8 @@ AbstractWindow {
color: "transparent"
signal callCreated()
// TODO : use this to make the border transparent
// flags: Qt.Window | Qt.FramelessWindowHint | Qt.WindowTitleHint
// menuBar: Rectangle {
@ -193,11 +195,16 @@ AbstractWindow {
Component {
id: mainPage
MainLayout {
id: mainLayout
objectName: "mainPage"
onAddAccountRequest: goToLogin()
onAccountRemoved: {
initStackViewItem()
}
Connections {
target: mainWindow
function onCallCreated(){ mainLayout.callCreated() }
}
// StackView.onActivated: connectionSecured(0) // TODO : connect to cpp part when ready
}
}