diff --git a/Linphone/core/chat/ChatList.cpp b/Linphone/core/chat/ChatList.cpp index fcf575f08..e5d9ee8b7 100644 --- a/Linphone/core/chat/ChatList.cpp +++ b/Linphone/core/chat/ChatList.cpp @@ -97,10 +97,12 @@ void ChatList::setSelf(QSharedPointer me) { std::find_if(list.begin(), list.end(), [chatRoom](const QSharedPointer &item) { return (item && item->getModel()->getMonitor() == chatRoom); }); - if (found != list.end()) { - qDebug() << "chat room created, add it to the list"; + if (found == list.end()) { auto model = createChatCore(chatRoom); - mModelConnection->invokeToCore([this, model]() { add(model); }); + mModelConnection->invokeToCore([this, model]() { + add(model); + emit chatAdded(); + }); } } } diff --git a/Linphone/core/chat/ChatList.hpp b/Linphone/core/chat/ChatList.hpp index 79c4a6741..963a3dcdb 100644 --- a/Linphone/core/chat/ChatList.hpp +++ b/Linphone/core/chat/ChatList.hpp @@ -47,6 +47,7 @@ signals: void lUpdate(); void filterChanged(QString filter); void chatRemoved(ChatGui *chat); + void chatAdded(); private: QString mFilter; diff --git a/Linphone/core/chat/ChatProxy.cpp b/Linphone/core/chat/ChatProxy.cpp index bcbc32dc8..1e802209e 100644 --- a/Linphone/core/chat/ChatProxy.cpp +++ b/Linphone/core/chat/ChatProxy.cpp @@ -28,6 +28,7 @@ DEFINE_ABSTRACT_OBJECT(ChatProxy) ChatProxy::ChatProxy(QObject *parent) : LimitProxy(parent) { mList = ChatList::create(); setSourceModel(mList.get()); + setDynamicSortFilter(true); } ChatProxy::~ChatProxy() { @@ -43,8 +44,10 @@ void ChatProxy::setSourceModel(QAbstractItemModel *model) { connect(this, &ChatProxy::filterTextChanged, newChatList, [this, newChatList] { emit newChatList->filterChanged(getFilterText()); }); connect(newChatList, &ChatList::chatRemoved, this, &ChatProxy::chatRemoved); + connect(newChatList, &ChatList::chatAdded, this, [this] { invalidate(); }); } - setSourceModels(new SortFilterList(model)); + auto firstList = new SortFilterList(model, Qt::AscendingOrder); + setSourceModels(firstList); sort(0); } diff --git a/Linphone/view/Control/Button/IconLabelButton.qml b/Linphone/view/Control/Button/IconLabelButton.qml index 520928dee..543eb67cd 100644 --- a/Linphone/view/Control/Button/IconLabelButton.qml +++ b/Linphone/view/Control/Button/IconLabelButton.qml @@ -13,9 +13,11 @@ Button { radius: Math.round(5 * DefaultStyle.dp) shadowEnabled: mainItem.activeFocus || hovered style: ButtonStyle.hoveredBackground + property bool inverseLayout: false contentItem: RowLayout { spacing: Math.round(5 * DefaultStyle.dp) + layoutDirection: mainItem.inverseLayout ? Qt.RightToLeft: Qt.LeftToRight EffectImage { imageSource: mainItem.icon.source imageWidth: mainItem.icon.width @@ -33,6 +35,7 @@ Button { horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter Layout.preferredWidth: textMetrics.advanceWidth + Layout.fillWidth: true wrapMode: Text.WrapAnywhere text: mainItem.text maximumLineCount: 1 diff --git a/Linphone/view/Control/Display/Chat/ChatMessage.qml b/Linphone/view/Control/Display/Chat/ChatMessage.qml index 1411decf6..7abb04314 100644 --- a/Linphone/view/Control/Display/Chat/ChatMessage.qml +++ b/Linphone/view/Control/Display/Chat/ChatMessage.qml @@ -8,137 +8,177 @@ import SettingsCpp import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils - -RowLayout { +Control.Control { id: mainItem property color backgroundColor property bool isFirstMessage property string imgUrl - spacing: 0 property ChatMessageGui chatMessage property string fromAddress: chatMessage? chatMessage.core.fromAddress : "" property bool isRemoteMessage: chatMessage? chatMessage.core.isRemoteMessage : false property bool isFromChatGroup: chatMessage? chatMessage.core.isFromChatGroup : false + hoverEnabled: true signal messageDeletionRequested() - Avatar { - id: avatar - visible: mainItem.isFromChatGroup - opacity: mainItem.isRemoteMessage && mainItem.isFirstMessage ? 1 : 0 - Layout.preferredWidth: 26 * DefaultStyle.dp - Layout.preferredHeight: 26 * DefaultStyle.dp - Layout.alignment: Qt.AlignTop - Layout.topMargin: isFirstMessage ? 16 * DefaultStyle.dp : 0 - _address: chatMessage ? chatMessage.core.fromAddress : "" - } - Control.Control { - Layout.topMargin: isFirstMessage ? 16 * DefaultStyle.dp : 0 - Layout.leftMargin: mainItem.isFromChatGroup ? Math.round(9 * DefaultStyle.dp) : 0 - Layout.preferredWidth: Math.min(implicitWidth, mainItem.maxWidth - avatar.implicitWidth) - // Layout.topMargin: name.visible ? Math.round(7 * DefaultStyle.dp) : 0 - topPadding: Math.round(12 * DefaultStyle.dp) - bottomPadding: Math.round(12 * DefaultStyle.dp) - leftPadding: Math.round(18 * DefaultStyle.dp) - rightPadding: Math.round(18 * DefaultStyle.dp) - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.RightButton - onClicked: (mouse) => { - console.log("message clicked") - if (mouse.button === Qt.RightButton) { - optionsMenu.x = mouse.x - optionsMenu.open() - } + background: Item { + anchors.fill: parent + Text { + id: fromNameText + visible: mainItem.isFromChatGroup && mainItem.isRemoteMessage && mainItem.isFirstMessage + anchors.top: parent.top + maximumLineCount: 1 + width: implicitWidth + x: chatBubble.x + text: mainItem.chatMessage.core.fromName + color: DefaultStyle.main2_500main + font { + pixelSize: Typography.p4.pixelSize + weight: Typography.p4.weight } } - Popup { - id: optionsMenu + } + + contentItem: RowLayout { + spacing: 0 + layoutDirection: mainItem.isRemoteMessage ? Qt.LeftToRight : Qt.RightToLeft + + Avatar { + id: avatar + visible: mainItem.isFromChatGroup + opacity: mainItem.isRemoteMessage && mainItem.isFirstMessage ? 1 : 0 + Layout.preferredWidth: 26 * DefaultStyle.dp + Layout.preferredHeight: 26 * DefaultStyle.dp + Layout.alignment: Qt.AlignTop + Layout.topMargin: isFirstMessage ? 16 * DefaultStyle.dp : 0 + _address: chatMessage ? chatMessage.core.fromAddress : "" + } + Control.Control { + id: chatBubble + Layout.topMargin: isFirstMessage ? 16 * DefaultStyle.dp : 0 + Layout.leftMargin: mainItem.isFromChatGroup ? Math.round(9 * DefaultStyle.dp) : 0 + Layout.preferredWidth: Math.min(implicitWidth, mainItem.maxWidth - avatar.implicitWidth) + spacing: Math.round(2 * DefaultStyle.dp) + topPadding: Math.round(12 * DefaultStyle.dp) + bottomPadding: Math.round(12 * DefaultStyle.dp) + leftPadding: Math.round(18 * DefaultStyle.dp) + rightPadding: Math.round(18 * DefaultStyle.dp) + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: (mouse) => { + if (mouse.button === Qt.RightButton) { + optionsMenu.open() + } + } + } + background: Item { anchors.fill: parent Rectangle { - id: popupBackground anchors.fill: parent - color: DefaultStyle.grey_0 + color: mainItem.backgroundColor radius: Math.round(16 * DefaultStyle.dp) } - MultiEffect { - source: popupBackground - anchors.fill: popupBackground - shadowEnabled: true - shadowBlur: 0.1 - shadowColor: DefaultStyle.grey_1000 - shadowOpacity: 0.4 + Rectangle { + visible: mainItem.isFirstMessage && mainItem.isRemoteMessage + anchors.top: parent.top + anchors.left: parent.left + width: Math.round(parent.width / 4) + height: Math.round(parent.height / 4) + color: mainItem.backgroundColor + } + Rectangle { + visible: mainItem.isFirstMessage && !mainItem.isRemoteMessage + anchors.bottom: parent.bottom + anchors.right: parent.right + width: Math.round(parent.width / 4) + height: Math.round(parent.height / 4) + color: mainItem.backgroundColor } } contentItem: ColumnLayout { - IconLabelButton { - //: "Supprimer" - text: qsTr("chat_message_delete") - icon.source: AppIcons.trashCan - spacing: Math.round(10 * DefaultStyle.dp) + id: contentLayout + Image { + visible: mainItem.imgUrl != undefined + id: contentimage + } + Text { + visible: modelData.core.text != undefined + text: modelData.core.text Layout.fillWidth: true - onClicked: { - mainItem.messageDeletionRequested() - optionsMenu.close() + color: DefaultStyle.main2_700 + font { + pixelSize: Typography.p1.pixelSize + weight: Typography.p1.weight + } + } + Text { + Layout.alignment: Qt.AlignRight + text: UtilsCpp.formatDate(modelData.core.timestamp, true, false) + color: DefaultStyle.main2_500main + font { + pixelSize: Typography.p3.pixelSize + weight: Typography.p3.weight } - style: ButtonStyle.noBackgroundRed } } } - - background: Item { - anchors.fill: parent - Rectangle { - anchors.fill: parent - color: mainItem.backgroundColor - radius: Math.round(16 * DefaultStyle.dp) - } - Rectangle { - visible: mainItem.isFirstMessage && mainItem.isRemoteMessage - anchors.top: parent.top - anchors.left: parent.left - width: Math.round(parent.width / 4) - height: Math.round(parent.height / 4) - color: mainItem.backgroundColor - } - Rectangle { - visible: mainItem.isFirstMessage && !mainItem.isRemoteMessage - anchors.bottom: parent.bottom - anchors.right: parent.right - width: Math.round(parent.width / 4) - height: Math.round(parent.height / 4) - color: mainItem.backgroundColor - } - } - contentItem: ColumnLayout { - id: contentLayout - Image { - visible: mainItem.imgUrl != undefined - id: contentimage - } - Text { - visible: modelData.core.text != undefined - text: modelData.core.text - Layout.fillWidth: true - color: DefaultStyle.main2_700 - font { - pixelSize: Typography.p1.pixelSize - weight: Typography.p1.weight + RowLayout { + id: actionsLayout + visible: mainItem.hovered || optionsMenu.hovered || optionsMenu.popup.opened || emojiButton.hovered + Layout.leftMargin: Math.round(8 * DefaultStyle.dp) + Layout.rightMargin: Math.round(8 * DefaultStyle.dp) + Layout.alignment: Qt.AlignVCenter + // Layout.fillWidth: true + spacing: Math.round(7 * DefaultStyle.dp) + layoutDirection: mainItem.isRemoteMessage ? Qt.LeftToRight : Qt.RightToLeft + PopupButton { + id: optionsMenu + popup.padding: 0 + popup.contentItem: ColumnLayout { + spacing: 0 + IconLabelButton { + inverseLayout: true + //: "Copy" + text: qsTr("chat_message_copy") + icon.source: AppIcons.copy + // spacing: Math.round(10 * DefaultStyle.dp) + Layout.fillWidth: true + Layout.preferredHeight: 45 * DefaultStyle.dp + onClicked: { + var success = UtilsCpp.copyToClipboard(modelData.core.text) + //: Copied + if (success) UtilsCpp.showInformationPopup(qsTr("chat_message_copied_to_clipboard_title"), + //: "in clipboard" + qsTr("chat_message_copied_to_clipboard_toast")) + } + } + IconLabelButton { + inverseLayout: true + //: "Delete" + text: qsTr("chat_message_delete") + icon.source: AppIcons.trashCan + // spacing: Math.round(10 * DefaultStyle.dp) + Layout.fillWidth: true + Layout.preferredHeight: 45 * DefaultStyle.dp + onClicked: { + mainItem.messageDeletionRequested() + optionsMenu.close() + } + style: ButtonStyle.hoveredBackgroundRed + } } } - Text { - Layout.alignment: Qt.AlignRight - text: UtilsCpp.formatDate(modelData.core.timestamp, true, false) - color: DefaultStyle.main2_500main - font { - pixelSize: Typography.p3.pixelSize - weight: Typography.p3.weight - } + BigButton { + id: emojiButton + style: ButtonStyle.noBackground + icon.source: AppIcons.smiley } } + Item{Layout.fillWidth: true} } } diff --git a/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml b/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml index 823d8e955..445d6339f 100644 --- a/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml +++ b/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml @@ -14,13 +14,41 @@ ListView { property color backgroundColor spacing: Math.round(4 * DefaultStyle.dp) - Component.onCompleted: positionViewAtEnd() + // Component.onCompleted: positionViewAtIndex(chatMessageProxy.findFirstUnreadIndex(), ListView.Visible) - onCountChanged: positionViewAtEnd() + onAtYEndChanged: if (atYEnd) chat.core.lMarkAsRead(); + + onChatChanged: if (visible) { + var index = chatMessageProxy.findFirstUnreadIndex() + console.log("visible, first unread at index", index) + mainItem.positionViewAtIndex(index, ListView.Visible) + } + + RoundButton { + icon.source: AppIcons.downArrow + // Layout.preferredWidth: 40 * DefaultStyle.dp + // Layout.preferredHeight: 40 * DefaultStyle.dp + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.bottomMargin: Math.round(18 * DefaultStyle.dp) + anchors.rightMargin: Math.round(18 * DefaultStyle.dp) + onClicked: { + var index = chatMessageProxy.findFirstUnreadIndex() + console.log("clicked, first unread at index", index) + mainItem.positionViewAtIndex(index, ListView.Visible) + // var chatMessage = chatMessageProxy.getChatMessageAtIndex(index) + // if (chatMessage && !chatMessage.core.isRead) chatMessage.core.lMarkAsRead() + } + } model: ChatMessageProxy { id: chatMessageProxy chatGui: mainItem.chat + onCountChanged: { + var indexToSelect = mainItem.currentIndex + mainItem.currentIndex = -1 + mainItem.currentIndex = indexToSelect + } } header: Item { @@ -31,7 +59,7 @@ ListView { chatMessage: modelData property real maxWidth: Math.round(mainItem.width * (3/4)) // height: childrenRect.height - // width: childrenRect.width + width: mainItem.width property var previousIndex: index - 1 property var previousFromAddress: chatMessageProxy.getChatMessageAtIndex(index-1)?.core.fromAddress backgroundColor: isRemoteMessage ? DefaultStyle.main2_100 : DefaultStyle.main1_100 @@ -52,7 +80,7 @@ ListView { bottomPadding: Math.round(5 * DefaultStyle.dp) background: Rectangle { anchors.fill: parent - color: mainItem.panelColor + color: mainItem.backgroundColor } contentItem: RowLayout { id: composeLayout diff --git a/Linphone/view/Page/Form/Chat/SelectedChatView.qml b/Linphone/view/Page/Form/Chat/SelectedChatView.qml index 37a7eff87..c85e6fcb7 100644 --- a/Linphone/view/Page/Form/Chat/SelectedChatView.qml +++ b/Linphone/view/Page/Form/Chat/SelectedChatView.qml @@ -80,7 +80,7 @@ RowLayout { ChatMessagesListView { id: chatMessagesListView height: contentHeight - backgroundColor: panelColor + backgroundColor: splitPanel.panelColor width: parent.width - anchors.leftMargin - anchors.rightMargin chat: mainItem.chat anchors.top: parent.top @@ -146,8 +146,8 @@ RowLayout { Layout.fillWidth: true leftPadding: Math.round(15 * DefaultStyle.dp) rightPadding: Math.round(15 * DefaultStyle.dp) - topPadding: Math.round(16 * DefaultStyle.dp) - bottomPadding: Math.round(16 * DefaultStyle.dp) + topPadding: Math.round(15 * DefaultStyle.dp) + bottomPadding: Math.round(15 * DefaultStyle.dp) background: Rectangle { id: inputBackground anchors.fill: parent @@ -188,9 +188,15 @@ RowLayout { height: sendingAreaFlickable.height anchors.left: parent.left anchors.right: parent.right + wrapMode: TextEdit.WordWrap //: Say something… : placeholder text for sending message text area placeholderText: qsTr("Dites quelque chose…") placeholderTextColor: DefaultStyle.main2_400 + color: DefaultStyle.main2_700 + font { + pixelSize: Typography.p1.pixelSize + weight: Typography.p1.weight + } onCursorRectangleChanged: sendingAreaFlickable.ensureVisible(cursorRectangle) property string previousText Component.onCompleted: previousText = text diff --git a/Linphone/view/Page/Main/Meeting/MeetingPage.qml b/Linphone/view/Page/Main/Meeting/MeetingPage.qml index 729181964..506946af0 100644 --- a/Linphone/view/Page/Main/Meeting/MeetingPage.qml +++ b/Linphone/view/Page/Main/Meeting/MeetingPage.qml @@ -684,8 +684,8 @@ AbstractMainPage { KeyNavigation.up: deletePopup KeyNavigation.down: joinButton onClicked: { - UtilsCpp.copyToClipboard(mainItem.selectedConference.core.uri) - UtilsCpp.showInformationPopup(qsTr("saved"), + var success = UtilsCpp.copyToClipboard(mainItem.selectedConference.core.uri) + if (success) UtilsCpp.showInformationPopup(qsTr("saved"), //: "Adresse de la réunion copiée" qsTr("meeting_address_copied_to_clipboard_toast")) } diff --git a/Linphone/view/Style/buttonStyle.js b/Linphone/view/Style/buttonStyle.js index b04b423ce..622a197c3 100644 --- a/Linphone/view/Style/buttonStyle.js +++ b/Linphone/view/Style/buttonStyle.js @@ -113,7 +113,8 @@ color: { normal: Linphone.DefaultStyle.grey_500, hovered: Linphone.DefaultStyle.grey_600, - pressed: Linphone.DefaultStyle.main2_400 + pressed: Linphone.DefaultStyle.main2_400, + hovered: Linphone.DefaultStyle.main2_400 }, text: { normal: Linphone.DefaultStyle.grey_0,