From e7598bef1eda8e0e755e0e63427c0041f9bfd85f Mon Sep 17 00:00:00 2001 From: Gaelle Braud Date: Fri, 6 Mar 2026 11:38:42 +0100 Subject: [PATCH] add chat history button in call list for meetings with chat #LINQT-2449 --- .../core/call-history/CallHistoryCore.cpp | 8 + .../core/call-history/CallHistoryCore.hpp | 6 + .../Container/Call/CallHistoryLayout.qml | 51 +++++- .../view/Control/Container/VerticalTabBar.qml | 2 +- Linphone/view/Control/Display/EffectImage.qml | 1 + Linphone/view/Control/Display/Text.qml | 14 ++ Linphone/view/Control/Display/ToolTip.qml | 13 +- .../view/Page/Form/Chat/SelectedChatView.qml | 27 +++- .../Page/Layout/Chat/ConversationInfos.qml | 4 +- Linphone/view/Page/Main/Call/CallPage.qml | 151 ++++++++++-------- 10 files changed, 195 insertions(+), 82 deletions(-) diff --git a/Linphone/core/call-history/CallHistoryCore.cpp b/Linphone/core/call-history/CallHistoryCore.cpp index 8994649dd..75a486304 100644 --- a/Linphone/core/call-history/CallHistoryCore.cpp +++ b/Linphone/core/call-history/CallHistoryCore.cpp @@ -20,6 +20,7 @@ #include "CallHistoryCore.hpp" #include "core/App.hpp" +#include "core/chat/ChatGui.hpp" #include "core/conference/ConferenceInfoCore.hpp" #include "core/friend/FriendGui.hpp" #include "model/call-history/CallHistoryModel.hpp" @@ -58,6 +59,9 @@ CallHistoryCore::CallHistoryCore(const std::shared_ptr &callL mConferenceInfo = ConferenceInfoCore::create(confinfo); mRemoteAddress = Utils::coreStringToAppString(confinfo->getUri()->asStringUriOnly()); mDisplayName = Utils::coreStringToAppString(confinfo->getSubject()); + if (auto chatroom = callLog->getChatRoom()) { + mChatCore = ChatCore::create(chatroom); + } } else { mRemoteAddress = Utils::coreStringToAppString(addr->asStringUriOnly()); auto linphoneFriend = ToolModel::findFriendByAddress(addr); @@ -156,6 +160,10 @@ void CallHistoryCore::setDuration(const QString &duration) { } } +ChatGui *CallHistoryCore::getChatGui() const { + return mChatCore ? new ChatGui(mChatCore) : nullptr; +} + void CallHistoryCore::remove() { mHistoryModelConnection->invokeToModel([this]() { mCallHistoryModel->removeCallHistory(); diff --git a/Linphone/core/call-history/CallHistoryCore.hpp b/Linphone/core/call-history/CallHistoryCore.hpp index b39364085..192069fe5 100644 --- a/Linphone/core/call-history/CallHistoryCore.hpp +++ b/Linphone/core/call-history/CallHistoryCore.hpp @@ -30,6 +30,8 @@ #include class CallHistoryModel; +class ChatCore; +class ChatGui; class FriendModel; class CallHistoryCore : public QObject, public AbstractObject { @@ -40,6 +42,7 @@ class CallHistoryCore : public QObject, public AbstractObject { Q_PROPERTY(bool isOutgoing MEMBER mIsOutgoing CONSTANT) Q_PROPERTY(bool isConference MEMBER mIsConference CONSTANT) Q_PROPERTY(ConferenceInfoGui *conferenceInfo READ getConferenceInfoGui CONSTANT) + Q_PROPERTY(ChatGui *chatGui READ getChatGui CONSTANT) Q_PROPERTY(QDateTime date MEMBER mDate CONSTANT) Q_PROPERTY(LinphoneEnums::CallStatus status MEMBER mStatus CONSTANT) Q_PROPERTY(QString duration READ getDuration WRITE setDuration NOTIFY durationChanged) @@ -55,6 +58,8 @@ public: QString getDuration() const; void setDuration(const QString &duration); + ChatGui *getChatGui() const; + void onRemoved(const std::shared_ptr &updatedFriend); Q_INVOKABLE void remove(); @@ -76,6 +81,7 @@ signals: private: QString mDuration; QSharedPointer mConferenceInfo = nullptr; + QSharedPointer mChatCore = nullptr; std::shared_ptr mCallHistoryModel; std::shared_ptr mFriendModel; QSharedPointer> mFriendModelConnection; diff --git a/Linphone/view/Control/Container/Call/CallHistoryLayout.qml b/Linphone/view/Control/Container/Call/CallHistoryLayout.qml index b2f849033..e74092dd7 100644 --- a/Linphone/view/Control/Container/Call/CallHistoryLayout.qml +++ b/Linphone/view/Control/Container/Call/CallHistoryLayout.qml @@ -16,6 +16,7 @@ ColumnLayout { property FriendGui contact property var conferenceInfo: callHistoryGui?.core.conferenceInfo + property var chatGui: callHistoryGui?.core.chatGui property bool isConference: conferenceInfo != undefined && conferenceInfo != null property string contactAddress: specificAddress != "" ? specificAddress : contact && contact.core.defaultAddress || "" property var computedContactNameObj: UtilsCpp.getDisplayName(contactAddress) @@ -33,8 +34,12 @@ ColumnLayout { property alias buttonContent: rightButton.data property alias detailContent: detailControl.data + signal conferenceChatDisplayRequested() + signal conferenceCallHistoryDisplayRequested() + ColumnLayout { spacing: Utils.getSizeWithScreenRatio(13) + Layout.alignment: Qt.AlignHCenter Item { Layout.preferredWidth: Utils.getSizeWithScreenRatio(360) Layout.preferredHeight: detailAvatar.height @@ -65,6 +70,7 @@ ColumnLayout { ColumnLayout { spacing: Utils.getSizeWithScreenRatio(2) + Layout.alignment: Qt.AlignHCenter Text { Layout.preferredWidth: implicitWidth Layout.alignment: Qt.AlignHCenter @@ -81,7 +87,7 @@ ColumnLayout { Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter - visible: mainItem.specificAddress != "" + visible: mainItem.specificAddress != "" && !mainItem.isConference text: SettingsCpp.hideSipAddresses ? UtilsCpp.getUsername(mainItem.specificAddress) : mainItem.specificAddress elide: Text.ElideMiddle maximumLineCount: 1 @@ -106,7 +112,7 @@ ColumnLayout { } } MediumButton { - visible: mainItem.isConference && !SettingsCpp.disableMeetingsFeature + visible: mainItem.isConference && !SettingsCpp.disableMeetingsFeature && !confWithChatLayout.visible Layout.alignment: Qt.AlignHCenter //: "Rejoindre la réunion" text: qsTr("meeting_info_join_title") @@ -119,6 +125,47 @@ ColumnLayout { } } } + RowLayout { + id: confWithChatLayout + visible: mainItem.isConference && !SettingsCpp.disableMeetingsFeature && mainItem.chatGui !== null + Layout.alignment: Qt.AlignHCenter + spacing: Utils.getSizeWithScreenRatio(72) + // Layout.fillWidth: true + Layout.preferredHeight: childrenRect.height + LabelButton { + visible: !SettingsCpp.disableChatFeature + width: Utils.getSizeWithScreenRatio(56) + height: Utils.getSizeWithScreenRatio(56) + button.icon.width: Utils.getSizeWithScreenRatio(24) + button.icon.height: Utils.getSizeWithScreenRatio(24) + button.icon.source: AppIcons.videoconference + //: "Join" + label: qsTr("meeting_info_join_title") + button.onClicked: if (mainItem.conferenceInfo) { + var callsWindow = UtilsCpp.getOrCreateCallsWindow() + callsWindow.setupConference(mainItem.conferenceInfo) + UtilsCpp.smartShowWindow(callsWindow) + } + } + LabelButton { + visible: !SettingsCpp.disableChatFeature + button.checkable: true + width: Utils.getSizeWithScreenRatio(56) + height: Utils.getSizeWithScreenRatio(56) + button.icon.width: Utils.getSizeWithScreenRatio(24) + button.icon.height: Utils.getSizeWithScreenRatio(24) + button.icon.source: button.checked ? AppIcons.callList : AppIcons.chatTeardropText + label: button.checked + //: "Call history" + ? qsTr("contact_call_history_action") + //: "Conversation" + : qsTr("contact_conversation_action") + button.onCheckedChanged: { + if (button.checked) mainItem.conferenceChatDisplayRequested() + else mainItem.conferenceCallHistoryDisplayRequested() + } + } + } RowLayout { Layout.alignment: Qt.AlignHCenter spacing: Utils.getSizeWithScreenRatio(72) diff --git a/Linphone/view/Control/Container/VerticalTabBar.qml b/Linphone/view/Control/Container/VerticalTabBar.qml index b51f01861..1d655251f 100644 --- a/Linphone/view/Control/Container/VerticalTabBar.qml +++ b/Linphone/view/Control/Container/VerticalTabBar.qml @@ -142,7 +142,7 @@ Control.TabBar { font { weight: mainItem.currentIndex === index ? Utils.getSizeWithScreenRatio(800) - : tabButton.hovered + : tabButton.hovered ? Utils.getSizeWithScreenRatio(600) : Utils.getSizeWithScreenRatio(400) pixelSize: Utils.getSizeWithScreenRatio(11) diff --git a/Linphone/view/Control/Display/EffectImage.qml b/Linphone/view/Control/Display/EffectImage.qml index 908238e60..16bb08fd2 100644 --- a/Linphone/view/Control/Display/EffectImage.qml +++ b/Linphone/view/Control/Display/EffectImage.qml @@ -18,6 +18,7 @@ Item { property bool shadowEnabled: false property bool isImageReady: false property bool retainWhileLoading: true + property alias status: image.status Image { id: image visible: !effect2.effectEnabled diff --git a/Linphone/view/Control/Display/Text.qml b/Linphone/view/Control/Display/Text.qml index 0307032ca..4674088bd 100644 --- a/Linphone/view/Control/Display/Text.qml +++ b/Linphone/view/Control/Display/Text.qml @@ -7,6 +7,20 @@ Quick.Text { id: mainItem property double scaleLettersFactor: 1. width: txtMeter.advanceWidth + property alias tooltip: tooltip + property alias mouseArea: mouseArea + Quick.MouseArea { + id: mouseArea + anchors.fill: parent + acceptedButtons: Qt.NoButton + hoverEnabled: true + onContainsMouseChanged: console.log("mouse area contains mouse", containsMouse) + } + ToolTip { + id: tooltip + visible: mainItem.visible && mouseArea.containsMouse && mainItem.truncated + text: mainItem.text + } font { family: DefaultStyle.defaultFont pixelSize: Utils.getSizeWithScreenRatio(10) diff --git a/Linphone/view/Control/Display/ToolTip.qml b/Linphone/view/Control/Display/ToolTip.qml index a866596ca..d0bafcbd4 100644 --- a/Linphone/view/Control/Display/ToolTip.qml +++ b/Linphone/view/Control/Display/ToolTip.qml @@ -1,23 +1,28 @@ -import QtQuick +import QtQuick as Quick import QtQuick.Controls.Basic as Control import Linphone import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils Control.ToolTip { id: mainItem - delay: 1000 + delay: 800 clip: true - background: Rectangle { + background: Quick.Rectangle { id: tooltipBackground opacity: 0.7 color: DefaultStyle.main2_200 radius: Utils.getSizeWithScreenRatio(15) } - contentItem: Text { + contentItem: Quick.Text { text: mainItem.text color: DefaultStyle.main2_600 width: tooltipBackground.width wrapMode: Text.Wrap elide: Text.ElideRight + font { + family: DefaultStyle.defaultFont + pixelSize: Utils.getSizeWithScreenRatio(10) + weight: Typography.p1.weight + } } } diff --git a/Linphone/view/Page/Form/Chat/SelectedChatView.qml b/Linphone/view/Page/Form/Chat/SelectedChatView.qml index 78c6d78a3..b74b14629 100644 --- a/Linphone/view/Page/Form/Chat/SelectedChatView.qml +++ b/Linphone/view/Page/Form/Chat/SelectedChatView.qml @@ -115,6 +115,7 @@ FocusScope { ColumnLayout { Text { Layout.fillWidth: true + Component.onCompleted: console.log(text, "width", width, "implicitWidth", implicitWidth, "advance", advance, contentWidth) text: UtilsCpp.encodeEmojiToQmlRichFormat(mainItem.chat?.core.title) || "" color: DefaultStyle.main2_600 maximumLineCount: 1 @@ -166,6 +167,7 @@ FocusScope { imageSource: AppIcons.bellSlash } } + Item{Layout.fillWidth: true} RowLayout { id: headerActionButtons spacing: Utils.getSizeWithScreenRatio(16) @@ -211,12 +213,17 @@ FocusScope { onCheckedChanged: { detailsPanel.visible = checked } + Connections { + target: detailsPanel + function onVisibleChanged() { + if (!detailsPanel.visible) detailsPanelButton.checked = false + } + } } } } RowLayout { id: searchBarLayout - visible: searchInHistoryButton.checked onVisibleChanged: { if(!visible) chatMessagesSearchBar.clearText() else chatMessagesSearchBar.forceActiveFocus() @@ -291,7 +298,14 @@ FocusScope { anchors.fill: parent orientation: Qt.Vertical handle: Rectangle { - visible: !mainItem.chat?.core.isReadOnly + id: splitViewHandle + visible: !mainItem.chat?.core.isReadOnly || false + // Hack for keeping handle unvisible in call history chat + // (It somehow becomes visible when switching from call history to chat + // history even if chat is read only) + onVisibleChanged: { + visible = !mainItem.chat?.core.isReadOnly || false + } enabled: visible implicitHeight: Utils.getSizeWithScreenRatio(8) color: Control.SplitHandle.hovered ? DefaultStyle.grey_200 : DefaultStyle.grey_100 @@ -574,7 +588,7 @@ FocusScope { } } Rectangle { - visible: detailsPanel.visible + visible: detailsPanel.visible && detailsPanel.width < mainItem.width color: DefaultStyle.main2_200 Layout.preferredWidth: Utils.getSizeWithScreenRatio(1) Layout.fillHeight: true @@ -583,7 +597,7 @@ FocusScope { id: detailsPanel visible: false Layout.fillHeight: true - Layout.preferredWidth: Utils.getSizeWithScreenRatio(387) + Layout.preferredWidth: Math.min(Utils.getSizeWithScreenRatio(387), mainItem.width) onVisibleChanged: if(!visible) { contentLoader.panelType = SelectedChatView.PanelType.None } @@ -591,6 +605,11 @@ FocusScope { background: Rectangle { color: DefaultStyle.grey_0 anchors.fill: parent + RoundButton { + style: ButtonStyle.noBackgroundOrange + icon.source: AppIcons.leftArrow + onClicked: detailsPanel.visible = false + } } contentItem: Loader { diff --git a/Linphone/view/Page/Layout/Chat/ConversationInfos.qml b/Linphone/view/Page/Layout/Chat/ConversationInfos.qml index dc595b9b3..71264a5ba 100644 --- a/Linphone/view/Page/Layout/Chat/ConversationInfos.qml +++ b/Linphone/view/Page/Layout/Chat/ConversationInfos.qml @@ -192,8 +192,8 @@ ColumnLayout { spacing: Utils.getSizeWithScreenRatio(10) Layout.alignment: Qt.AlignHCenter Layout.topMargin: Utils.getSizeWithScreenRatio(30) - Layout.preferredHeight: Utils.getSizeWithScreenRatio(110) - Layout.minimumHeight: Utils.getSizeWithScreenRatio(110) + Layout.preferredHeight: visible ? Utils.getSizeWithScreenRatio(110) : 0 + Layout.minimumHeight: visible ? Utils.getSizeWithScreenRatio(110) : 0 LabelButton { text.Layout.fillWidth: true text.horizontalAlignment: Text.AlignHCenter diff --git a/Linphone/view/Page/Main/Call/CallPage.qml b/Linphone/view/Page/Main/Call/CallPage.qml index b5a4bb4c1..372de87fa 100644 --- a/Linphone/view/Page/Main/Call/CallPage.qml +++ b/Linphone/view/Page/Main/Call/CallPage.qml @@ -580,14 +580,18 @@ AbstractMainPage { } } } + onConferenceChatDisplayRequested: detailContentStack.currentIndex = 1 + onConferenceCallHistoryDisplayRequested: detailContentStack.currentIndex = 0 detailContent: Item { Layout.preferredWidth: Utils.getSizeWithScreenRatio(360) Layout.fillHeight: true RoundedPane { id: detailControl - visible: detailListView.count > 0 + visible: detailContentStack.currentIndex !== 0 || detailListView.count > 0 width: parent.width - height: Math.min(parent.height, detailListView.contentHeight) + topPadding + bottomPadding + height: detailContentStack.currentIndex === 0 + ? Math.min(parent.height, detailListView.contentHeight) + topPadding + bottomPadding + : parent.height background: Rectangle { id: detailListBackground anchors.fill: parent @@ -595,92 +599,101 @@ AbstractMainPage { radius: Utils.getSizeWithScreenRatio(15) } - contentItem: Control.ScrollView { - id: historyScrollView - Control.ScrollBar.vertical: ScrollBar { - id: historyScrollBar - visible: historyScrollView.contentHeight > historyScrollView.height - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: parent.right - } - CallHistoryListView { - id: detailListView - Layout.fillWidth: true - Layout.fillHeight: true - Layout.rightMargin: historyScrollBar.width + Utils.getSizeWithScreenRatio(8) - spacing: Utils.getSizeWithScreenRatio(14) - clip: true - searchText: mainItem.selectedRowHistoryGui ? mainItem.selectedRowHistoryGui.core.remoteAddress : "" - busyIndicatorSize: Utils.getSizeWithScreenRatio(40) + contentItem: StackLayout { + id: detailContentStack + currentIndex: 0 + Control.ScrollView { + id: historyScrollView + Control.ScrollBar.vertical: ScrollBar { + id: historyScrollBar + visible: historyScrollView.contentHeight > historyScrollView.height + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + } + CallHistoryListView { + id: detailListView + Layout.fillWidth: true + Layout.fillHeight: true + Layout.rightMargin: historyScrollBar.width + Utils.getSizeWithScreenRatio(8) + spacing: Utils.getSizeWithScreenRatio(14) + clip: true + searchText: mainItem.selectedRowHistoryGui ? mainItem.selectedRowHistoryGui.core.remoteAddress : "" + busyIndicatorSize: Utils.getSizeWithScreenRatio(40) - delegate: Item { - width: detailListView.width - height: Utils.getSizeWithScreenRatio(56) - RowLayout { - anchors.fill: parent - anchors.leftMargin: Utils.getSizeWithScreenRatio(20) - anchors.rightMargin: Utils.getSizeWithScreenRatio(20) - anchors.verticalCenter: parent.verticalCenter - ColumnLayout { - Layout.alignment: Qt.AlignVCenter - RowLayout { - EffectImage { - id: statusIcon - imageSource: modelData.core.status - === LinphoneEnums.CallStatus.Declined - || modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere || modelData.core.status === LinphoneEnums.CallStatus.Aborted || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted ? AppIcons.arrowElbow : modelData.core.isOutgoing ? AppIcons.arrowUpRight : AppIcons.arrowDownLeft - colorizationColor: modelData.core.status === LinphoneEnums.CallStatus.Declined || modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere || modelData.core.status === LinphoneEnums.CallStatus.Aborted || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted || modelData.core.status === LinphoneEnums.CallStatus.Missed ? DefaultStyle.danger_500_main : modelData.core.isOutgoing ? DefaultStyle.info_500_main : DefaultStyle.success_500_main - Layout.preferredWidth: Utils.getSizeWithScreenRatio(16) - Layout.preferredHeight: Utils.getSizeWithScreenRatio(16) - transform: Rotation { - angle: modelData.core.isOutgoing - && (modelData.core.status === LinphoneEnums.CallStatus.Declined || modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere || modelData.core.status === LinphoneEnums.CallStatus.Aborted || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted) ? 180 : 0 - origin { - x: statusIcon.width / 2 - y: statusIcon.height / 2 + delegate: Item { + width: detailListView.width + height: Utils.getSizeWithScreenRatio(56) + RowLayout { + anchors.fill: parent + anchors.leftMargin: Utils.getSizeWithScreenRatio(20) + anchors.rightMargin: Utils.getSizeWithScreenRatio(20) + anchors.verticalCenter: parent.verticalCenter + ColumnLayout { + Layout.alignment: Qt.AlignVCenter + RowLayout { + EffectImage { + id: statusIcon + imageSource: modelData.core.status + === LinphoneEnums.CallStatus.Declined + || modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere || modelData.core.status === LinphoneEnums.CallStatus.Aborted || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted ? AppIcons.arrowElbow : modelData.core.isOutgoing ? AppIcons.arrowUpRight : AppIcons.arrowDownLeft + colorizationColor: modelData.core.status === LinphoneEnums.CallStatus.Declined || modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere || modelData.core.status === LinphoneEnums.CallStatus.Aborted || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted || modelData.core.status === LinphoneEnums.CallStatus.Missed ? DefaultStyle.danger_500_main : modelData.core.isOutgoing ? DefaultStyle.info_500_main : DefaultStyle.success_500_main + Layout.preferredWidth: Utils.getSizeWithScreenRatio(16) + Layout.preferredHeight: Utils.getSizeWithScreenRatio(16) + transform: Rotation { + angle: modelData.core.isOutgoing + && (modelData.core.status === LinphoneEnums.CallStatus.Declined || modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere || modelData.core.status === LinphoneEnums.CallStatus.Aborted || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted) ? 180 : 0 + origin { + x: statusIcon.width / 2 + y: statusIcon.height / 2 + } + } + } + Text { + //: "Appel manqué" + text: modelData.core.status === LinphoneEnums.CallStatus.Missed ? qsTr("notification_missed_call_title") + : modelData.core.isOutgoing + //: "Appel sortant" + ? qsTr("call_outgoing") + //: "Appel entrant" + : qsTr("call_audio_incoming") + font { + pixelSize: Typography.p1.pixelSize + weight: Typography.p1.weight } } } Text { - //: "Appel manqué" - text: modelData.core.status === LinphoneEnums.CallStatus.Missed ? qsTr("notification_missed_call_title") - : modelData.core.isOutgoing - //: "Appel sortant" - ? qsTr("call_outgoing") - //: "Appel entrant" - : qsTr("call_audio_incoming") + text: UtilsCpp.formatDate(modelData.core.date) + color: modelData.core.status === LinphoneEnums.CallStatus.Missed ? DefaultStyle.danger_500_main : DefaultStyle.main2_500_main font { - pixelSize: Typography.p1.pixelSize - weight: Typography.p1.weight + pixelSize: Utils.getSizeWithScreenRatio(12) + weight: Utils.getSizeWithScreenRatio(300) } } } + Item { + Layout.fillHeight: true + Layout.fillWidth: true + } Text { - text: UtilsCpp.formatDate(modelData.core.date) - color: modelData.core.status === LinphoneEnums.CallStatus.Missed ? DefaultStyle.danger_500_main : DefaultStyle.main2_500_main + text: UtilsCpp.formatElapsedTime( + modelData.core.duration, + false) font { pixelSize: Utils.getSizeWithScreenRatio(12) weight: Utils.getSizeWithScreenRatio(300) } } } - Item { - Layout.fillHeight: true - Layout.fillWidth: true - } - Text { - text: UtilsCpp.formatElapsedTime( - modelData.core.duration, - false) - font { - pixelSize: Utils.getSizeWithScreenRatio(12) - weight: Utils.getSizeWithScreenRatio(300) - } - } } } } + SelectedChatView { + Layout.fillWidth: true + Layout.fillHeight: true + chat: contactDetail.callHistoryGui.core.chatGui + } } } }