diff --git a/Linphone/core/chat/ChatCore.cpp b/Linphone/core/chat/ChatCore.cpp index 7aacb0ade..9426f703b 100644 --- a/Linphone/core/chat/ChatCore.cpp +++ b/Linphone/core/chat/ChatCore.cpp @@ -23,6 +23,8 @@ #include "core/chat/message/content/ChatMessageContentGui.hpp" #include "core/friend/FriendCore.hpp" #include "core/setting/SettingsCore.hpp" +#include "model/core/CoreModel.hpp" +#include "model/friend/FriendModel.hpp" #include "model/tool/ToolModel.hpp" #include "tool/Utils.hpp" @@ -38,7 +40,7 @@ QSharedPointer ChatCore::create(const std::shared_ptr &chatRoom) : QObject(nullptr) { - lDebug() << "[ChatCore] new" << this; + // lDebug() << "[ChatCore] new" << this; mustBeInLinphoneThread(getClassName()); App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership); mLastUpdatedTime = QDateTime::fromSecsSinceEpoch(chatRoom->getLastUpdateTime()); @@ -373,6 +375,15 @@ void ChatCore::setSelf(QSharedPointer me) { mChatModelConnection->invokeToModel( [this, index]() { mChatModel->toggleParticipantAdminStatusAtIndex(index); }); }); + + mCoreModelConnection = SafeConnection::create(me, CoreModel::getInstance()); + if (!ToolModel::findFriendByAddress(mPeerAddress)) + mCoreModelConnection->makeConnectToModel(&CoreModel::friendCreated, + [this](std::shared_ptr f) { updateInfo(f); }); + mCoreModelConnection->makeConnectToModel(&CoreModel::friendUpdated, + [this](std::shared_ptr f) { updateInfo(f); }); + mCoreModelConnection->makeConnectToModel(&CoreModel::friendRemoved, + [this](std::shared_ptr f) { updateInfo(f, true); }); } QDateTime ChatCore::getLastUpdatedTime() const { @@ -644,3 +655,47 @@ ChatCore::buildParticipants(const std::shared_ptr &chatRoom) QList> ChatCore::getParticipants() const { return mParticipants; } + +void ChatCore::updateInfo(const std::shared_ptr &updatedFriend, bool isRemoval) { + mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); + auto fAddress = ToolModel::interpretUrl(mPeerAddress); + bool isThisFriend = mFriendModel && updatedFriend == mFriendModel->getFriend(); + if (!isThisFriend) + for (auto f : updatedFriend->getAddresses()) { + if (f->weakEqual(fAddress)) { + isThisFriend = true; + break; + } + } + if (isThisFriend) { + if (isRemoval) { + mFriendModel = nullptr; + mFriendModelConnection = nullptr; + } + int capabilities = mChatModel->getCapabilities(); + auto chatroom = mChatModel->getMonitor(); + auto chatRoomAddress = chatroom->getPeerAddress()->clone(); + if (mChatModel->hasCapability((int)linphone::ChatRoom::Capabilities::Basic)) { + mTitle = ToolModel::getDisplayName(chatRoomAddress); + mAvatarUri = ToolModel::getDisplayName(chatRoomAddress); + emit titleChanged(mTitle); + emit avatarUriChanged(); + } else { + if (mChatModel->hasCapability((int)linphone::ChatRoom::Capabilities::OneToOne)) { + auto participants = chatroom->getParticipants(); + if (participants.size() > 0) { + auto peer = participants.front(); + if (peer) mTitle = ToolModel::getDisplayName(peer->getAddress()->clone()); + mAvatarUri = ToolModel::getDisplayName(peer->getAddress()->clone()); + if (participants.size() == 1) { + auto peerAddress = peer->getAddress(); + if (peerAddress) mPeerAddress = Utils::coreStringToAppString(peerAddress->asStringUriOnly()); + } + } + } else if (mChatModel->hasCapability((int)linphone::ChatRoom::Capabilities::Conference)) { + mTitle = Utils::coreStringToAppString(chatroom->getSubject()); + mAvatarUri = Utils::coreStringToAppString(chatroom->getSubject()); + } + } + } +} \ No newline at end of file diff --git a/Linphone/core/chat/ChatCore.hpp b/Linphone/core/chat/ChatCore.hpp index f17348c82..9e93c8ece 100644 --- a/Linphone/core/chat/ChatCore.hpp +++ b/Linphone/core/chat/ChatCore.hpp @@ -33,6 +33,7 @@ #include class EventLogCore; +class FriendModel; class ChatCore : public QObject, public AbstractObject { Q_OBJECT @@ -140,6 +141,8 @@ public: QVariantList getParticipantsGui() const; QStringList getParticipantsAddresses() const; + void updateInfo(const std::shared_ptr &updatedFriend, bool isRemoval = false); + signals: // used to close all the notifications when one is clicked void messageOpen(); @@ -208,7 +211,10 @@ private: std::shared_ptr mChatModel; QSharedPointer mLastMessage; QList> mEventLogList; + std::shared_ptr mFriendModel; QSharedPointer> mChatModelConnection; + QSharedPointer> mCoreModelConnection; + QSharedPointer> mFriendModelConnection; DECLARE_ABSTRACT_OBJECT }; diff --git a/Linphone/core/notifier/Notifier.cpp b/Linphone/core/notifier/Notifier.cpp index 7ab8df069..dbb81ec8c 100644 --- a/Linphone/core/notifier/Notifier.cpp +++ b/Linphone/core/notifier/Notifier.cpp @@ -212,8 +212,6 @@ bool Notifier::createNotification(Notifier::NotificationType type, QVariantMap d void Notifier::showNotification(QObject *notification, int timeout) { // Display notification. - QMetaObject::invokeMethod(notification, NotificationShowMethodName, Qt::DirectConnection); - QTimer *timer = new QTimer(notification); timer->setInterval(timeout); timer->setSingleShot(true); diff --git a/Linphone/model/chat/ChatModel.cpp b/Linphone/model/chat/ChatModel.cpp index 815cf132c..c96cca920 100644 --- a/Linphone/model/chat/ChatModel.cpp +++ b/Linphone/model/chat/ChatModel.cpp @@ -32,7 +32,7 @@ DEFINE_ABSTRACT_OBJECT(ChatModel) ChatModel::ChatModel(const std::shared_ptr &chatroom, QObject *parent) : ::Listener(chatroom, parent) { - lDebug() << "[ChatModel] new" << this << " / SDKModel=" << chatroom.get(); + // lDebug() << "[ChatModel] new" << this << " / SDKModel=" << chatroom.get(); mustBeInLinphoneThread(getClassName()); auto coreModel = CoreModel::getInstance(); if (coreModel) @@ -88,6 +88,14 @@ QString ChatModel::getPeerAddress() const { return Utils::coreStringToAppString(mMonitor->getPeerAddress()->asStringUriOnly()); } +int ChatModel::getCapabilities() const { + return mMonitor->getCapabilities(); +} + +bool ChatModel::hasCapability(int capability) const { + return mMonitor->hasCapability(capability); +} + std::shared_ptr ChatModel::getLastChatMessage() { return mMonitor->getLastMessageInHistory(); } diff --git a/Linphone/model/chat/ChatModel.hpp b/Linphone/model/chat/ChatModel.hpp index 47988722b..61f9042b4 100644 --- a/Linphone/model/chat/ChatModel.hpp +++ b/Linphone/model/chat/ChatModel.hpp @@ -42,6 +42,8 @@ public: QString getTitle(); QString getPeerAddress() const; std::shared_ptr getLastChatMessage(); + int getCapabilities() const; + bool hasCapability(int capability) const; int getUnreadMessagesCount() const; void markAsRead(); std::list> getHistory() const; diff --git a/Linphone/tool/Utils.cpp b/Linphone/tool/Utils.cpp index 759168807..7c21595b3 100644 --- a/Linphone/tool/Utils.cpp +++ b/Linphone/tool/Utils.cpp @@ -254,7 +254,7 @@ VariantObject *Utils::haveAccount() { void Utils::smartShowWindow(QQuickWindow *window) { if (!window) return; if (window->visibility() == QWindow::Maximized) // Avoid to change visibility mode - window->showNormal(); + window->showMaximized(); else window->show(); App::getInstance()->setLastActiveWindow(window); window->raise(); // Raise ensure to get focus on Mac diff --git a/Linphone/view/Control/Container/Contact/PresenceNoteLayout.qml b/Linphone/view/Control/Container/Contact/PresenceNoteLayout.qml index 2218c8677..a0155a77f 100644 --- a/Linphone/view/Control/Container/Contact/PresenceNoteLayout.qml +++ b/Linphone/view/Control/Container/Contact/PresenceNoteLayout.qml @@ -44,7 +44,7 @@ Rectangle { Text { font: Typography.p3 color: DefaultStyle.main2_500main - text: mainItem.friendCore.presenceNote + text: mainItem.friendCore?.presenceNote || "" wrapMode: Text.Wrap Layout.fillWidth: true } diff --git a/Linphone/view/Control/Display/Chat/ChatListView.qml b/Linphone/view/Control/Display/Chat/ChatListView.qml index 3f098486b..bb6a80a43 100644 --- a/Linphone/view/Control/Display/Chat/ChatListView.qml +++ b/Linphone/view/Control/Display/Chat/ChatListView.qml @@ -175,7 +175,7 @@ ListView { id: historyAvatar property var contactObj: UtilsCpp.findFriendByAddress(modelData.core.peerAddress) contact: contactObj?.value || null - displayNameVal: contact ? "" : modelData.core.avatarUri + displayNameVal: contact ? undefined : modelData.core.avatarUri secured: modelData.core.isEncrypted Layout.preferredWidth: Math.round(45 * DefaultStyle.dp) Layout.preferredHeight: Math.round(45 * DefaultStyle.dp) diff --git a/Linphone/view/Control/Display/Chat/ChatMessage.qml b/Linphone/view/Control/Display/Chat/ChatMessage.qml index d531a6fda..915f7f91f 100644 --- a/Linphone/view/Control/Display/Chat/ChatMessage.qml +++ b/Linphone/view/Control/Display/Chat/ChatMessage.qml @@ -148,7 +148,7 @@ Control.Control { bottomPadding: Math.round(19 * DefaultStyle.dp) leftPadding: Math.round(18 * DefaultStyle.dp) rightPadding: Math.round(18 * DefaultStyle.dp) - width: Math.min(implicitWidth, mainItem.maxWidth - avatar.implicitWidth) + Layout.preferredWidth: Math.min(implicitWidth, mainItem.maxWidth - avatar.implicitWidth) background: Rectangle { anchors.fill: parent color: DefaultStyle.grey_200 diff --git a/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml b/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml index 73ea41e11..d43cb2f4b 100644 --- a/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml +++ b/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml @@ -63,6 +63,7 @@ ListView { onCountChanged: if (atYEnd) { positionViewAtEnd() } + onChatChanged: lastItemVisible = false Button { visible: !mainItem.lastItemVisible @@ -95,6 +96,10 @@ ListView { if (!mainItem.visible) return mainItem.positionViewAtIndex(index, ListView.End) } + onModelReset: Qt.callLater(function() { + var index = eventLogProxy.findFirstUnreadIndex() + positionViewAtIndex(index, ListView.End) + }) } header: Item { @@ -262,7 +267,7 @@ ListView { footerPositioning: ListView.OverlayFooter footer: Control.Control { - visible: composeLayout.composingName !== "" + visible: composeLayout.composingName !== "" && composeLayout.composingName !== undefined width: mainItem.width z: mainItem.z + 2 topPadding: Math.round(5 * DefaultStyle.dp) @@ -273,11 +278,11 @@ ListView { } contentItem: RowLayout { id: composeLayout - property string composingName: mainItem.chat.core.composingName + property var composingName: mainItem.chat?.core.composingName Avatar { Layout.preferredWidth: Math.round(20 * DefaultStyle.dp) Layout.preferredHeight: Math.round(20 * DefaultStyle.dp) - _address: mainItem.chat.core.composingAddress + _address: mainItem.chat?.core.composingAddress } Text { Layout.fillWidth: true diff --git a/Linphone/view/Control/Display/Contact/Avatar.qml b/Linphone/view/Control/Display/Contact/Avatar.qml index ce96e1208..bdfdf059c 100644 --- a/Linphone/view/Control/Display/Contact/Avatar.qml +++ b/Linphone/view/Control/Display/Contact/Avatar.qml @@ -17,7 +17,7 @@ Loader{ property CallGui call: null property bool isConference: false property bool shadowEnabled: true - property string _address: account + property var _address: account ? account.core?.identityAddress || "" : call ? call.core.remoteAddress @@ -26,7 +26,7 @@ Loader{ : '' readonly property string address: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(_address) : _address property var displayNameObj: UtilsCpp.getDisplayName(_address) - property string displayNameVal: account && account.core.displayName + property var displayNameVal: account && account.core.displayName ? account.core.displayName : contact && contact.core.fullName ? contact.core.fullName @@ -152,7 +152,7 @@ Loader{ } EffectImage { id: initialImg - visible: initialItem.initials == '' + visible: initialItem.initials === "" width: stackView.width/2 height: width colorizationColor: DefaultStyle.main2_600 diff --git a/Linphone/view/Control/Popup/DesktopPopup.qml b/Linphone/view/Control/Popup/DesktopPopup.qml index 81f37524e..1363172b2 100644 --- a/Linphone/view/Control/Popup/DesktopPopup.qml +++ b/Linphone/view/Control/Popup/DesktopPopup.qml @@ -37,10 +37,10 @@ Window { // --------------------------------------------------------------------------- objectName: '__internalWindow' - property bool isFrameLess : false; property bool showAsTool : false // Don't use Popup for flags : it could lead to error in geometry. On Mac, Using Tool ensure to have the Window on Top and fullscreen independant - flags: Qt.BypassWindowManagerHint | (showAsTool?Qt.Tool:Qt.WindowStaysOnTopHint) | Qt.Window | Qt.FramelessWindowHint; + // flags: Qt.WindowDoesNotAcceptFocus | Qt.BypassWindowManagerHint | (showAsTool?Qt.Tool:Qt.WindowStaysOnTopHint) | Qt.Window | Qt.FramelessWindowHint; + flags: Qt.WindowDoesNotAcceptFocus | Qt.FramelessWindowHint opacity: 1.0 height: _content[0] != null ? _content[0].height : 0 width: _content[0] != null ? _content[0].width : 0 @@ -48,6 +48,7 @@ Window { Item { id: content anchors.fill:parent + focus: false property var $parent: mainItem } diff --git a/Linphone/view/Page/Form/Chat/SelectedChatView.qml b/Linphone/view/Page/Form/Chat/SelectedChatView.qml index 0a9c52daa..fc59a9c49 100644 --- a/Linphone/view/Page/Form/Chat/SelectedChatView.qml +++ b/Linphone/view/Page/Form/Chat/SelectedChatView.qml @@ -81,7 +81,7 @@ RowLayout { Avatar { property var contactObj: mainItem.chat ? UtilsCpp.findFriendByAddress(mainItem.chat?.core.peerAddress) : null contact: contactObj?.value || null - displayNameVal: contact ? "" : mainItem.chat.core.avatarUri + displayNameVal: contact ? "" : mainItem.chat?.core.avatarUri Layout.preferredWidth: Math.round(45 * DefaultStyle.dp) Layout.preferredHeight: Math.round(45 * DefaultStyle.dp) } @@ -97,7 +97,7 @@ RowLayout { } } EffectImage { - visible: mainItem.chat?.core.muted + visible: mainItem.chat?.core.muted || false Layout.preferredWidth: 20 * DefaultStyle.dp Layout.alignment: Qt.AlignVCenter Layout.preferredHeight: 20 * DefaultStyle.dp @@ -122,7 +122,7 @@ RowLayout { RoundButton { style: ButtonStyle.noBackground icon.source: AppIcons.videoCamera - visible: !mainItem.chat.core.isGroupChat + visible: !mainItem.chat?.core.isGroupChat || false onPressed: mainItem.oneOneCall(true) } RoundButton { @@ -443,8 +443,8 @@ RowLayout { } ChatDroppableTextArea { id: messageSender - Control.SplitView.preferredHeight: mainItem.chat.core.isReadOnly ? 0 : height - Control.SplitView.minimumHeight: mainItem.chat.core.isReadOnly ? 0 : Math.round(79 * DefaultStyle.dp) + Control.SplitView.preferredHeight: mainItem.chat?.core.isReadOnly ? 0 : height + Control.SplitView.minimumHeight: mainItem.chat?.core.isReadOnly ? 0 : Math.round(79 * DefaultStyle.dp) chat: mainItem.chat onChatChanged: { if (chat) messageSender.text = mainItem.chat.core.sendingText @@ -513,7 +513,7 @@ RowLayout { ? forwardToListsComponent : panelType === SelectedChatView.PanelType.ManageParticipants ? manageParticipantsComponent - : mainItem.chat.core.isGroupChat + : mainItem.chat?.core.isGroupChat ? groupInfoComponent : oneToOneInfoComponent active: detailsPanel.visible diff --git a/Linphone/view/Page/Main/AbstractMainPage.qml b/Linphone/view/Page/Main/AbstractMainPage.qml index 4b87df181..3c0ac1515 100644 --- a/Linphone/view/Page/Main/AbstractMainPage.qml +++ b/Linphone/view/Page/Main/AbstractMainPage.qml @@ -192,6 +192,7 @@ FocusScope { id: rightPanelStackView Layout.fillWidth: true Layout.fillHeight: true + visible: false } } } diff --git a/Linphone/view/Page/Main/Chat/ChatPage.qml b/Linphone/view/Page/Main/Chat/ChatPage.qml index 9b56f3c45..af2e02be4 100644 --- a/Linphone/view/Page/Main/Chat/ChatPage.qml +++ b/Linphone/view/Page/Main/Chat/ChatPage.qml @@ -25,7 +25,7 @@ AbstractMainPage { property bool isRegistered: account ? account.core?.registrationState == LinphoneEnums.RegistrationState.Ok : false - property var selectedChatGui + property var selectedChatGui: null property string remoteAddress onRemoteAddressChanged: console.log("ChatPage : remote address changed :", remoteAddress) property var remoteChatObj: UtilsCpp.getChatForAddress(remoteAddress) @@ -40,17 +40,14 @@ AbstractMainPage { listStackView.popToIndex(0) if (listStackView.depth === 0 || listStackView.currentItem.objectName !== "chatListItem") listStackView.push(chatListItem) } - rightPanelStackView.replace(currentChatComp, - Control.StackView.Immediate) - } - else { - rightPanelStackView.replace(emptySelection, - Control.StackView.Immediate) } } - rightPanelStackView.initialItem: emptySelection - rightPanelStackView.visible: listStackView.currentItem && listStackView.currentItem.objectName === "chatListItem" + rightPanelStackView.initialItem: currentChatComp + // Only play on the visible property of the right panel as there is only one item pushed + // and the sending TextArea must be instantiated only once, otherwise it looses focus + // when the chat list order is updated + rightPanelStackView.visible: false//listStackView.currentItem && listStackView.currentItem.objectName === "chatListItem" && selectedChatGui !== null onNoItemButtonPressed: goToNewChat() @@ -334,10 +331,11 @@ AbstractMainPage { id: currentChatComp FocusScope { SelectedChatView { + visible: chat != undefined && chat != null anchors.fill: parent chat: mainItem.selectedChatGui || null onChatChanged: if (mainItem.selectedChatGui !== chat) mainItem.selectedChatGui = chat } } } -} +} \ No newline at end of file diff --git a/Linphone/view/Page/Window/Main/MainWindow.qml b/Linphone/view/Page/Window/Main/MainWindow.qml index 4fb57e01a..b2d8ef389 100644 --- a/Linphone/view/Page/Window/Main/MainWindow.qml +++ b/Linphone/view/Page/Window/Main/MainWindow.qml @@ -28,7 +28,7 @@ AbstractWindow { property var accountProxy // TODO : use this to make the border transparent - // flags: Qt.Window | Qt.FramelessWindowHint | Qt.WindowTitleHint + flags: Qt.Window | Qt.WindowTitleHint // menuBar: Rectangle { // width: parent.width // height: Math.round(40 * DefaultStyle.dp)