diff --git a/Linphone/core/App.cpp b/Linphone/core/App.cpp index a0fb5a40d..1ee7ee518 100644 --- a/Linphone/core/App.cpp +++ b/Linphone/core/App.cpp @@ -63,7 +63,7 @@ #include "core/conference/ConferenceGui.hpp" #include "core/conference/ConferenceInfoGui.hpp" #include "core/conference/ConferenceInfoProxy.hpp" -#include "core/emoji/EmojiModel.hpp" +#include "core/emoji/EmojiProxy.hpp" #include "core/fps-counter/FPSCounter.hpp" #include "core/friend/FriendCore.hpp" #include "core/friend/FriendGui.hpp" @@ -686,6 +686,7 @@ void App::initCppInterfaces() { qmlRegisterType(Constants::MainQmlUri, 1, 0, "CameraGui"); qmlRegisterType(Constants::MainQmlUri, 1, 0, "FPSCounter"); qmlRegisterType(Constants::MainQmlUri, 1, 0, "EmojiModel"); + qmlRegisterType(Constants::MainQmlUri, 1, 0, "EmojiProxy"); qmlRegisterType(Constants::MainQmlUri, 1, 0, "SoundPlayerGui"); qmlRegisterType(Constants::MainQmlUri, 1, 0, "RecorderGui"); diff --git a/Linphone/core/CMakeLists.txt b/Linphone/core/CMakeLists.txt index 45a0def9e..faa9368eb 100644 --- a/Linphone/core/CMakeLists.txt +++ b/Linphone/core/CMakeLists.txt @@ -33,7 +33,9 @@ list(APPEND _LINPHONEAPP_SOURCES core/chat/message/content/ChatMessageContentGui.cpp core/chat/message/content/ChatMessageContentList.cpp core/chat/message/content/ChatMessageContentProxy.cpp + core/emoji/EmojiList.cpp core/emoji/EmojiModel.cpp + core/emoji/EmojiProxy.cpp core/fps-counter/FPSCounter.cpp core/friend/FriendCore.cpp core/friend/FriendGui.cpp diff --git a/Linphone/core/chat/message/ChatMessageCore.cpp b/Linphone/core/chat/message/ChatMessageCore.cpp index 0f4eb923a..6325b2a6f 100644 --- a/Linphone/core/chat/message/ChatMessageCore.cpp +++ b/Linphone/core/chat/message/ChatMessageCore.cpp @@ -97,6 +97,8 @@ ChatMessageCore::ChatMessageCore(const std::shared_ptr &c mVoiceRecordingContent = contentCore; } } + //: "Reactions": all reactions for one message label + mTotalReactionsLabel = tr("all_reactions_label"); auto reac = chatmessage->getOwnReaction(); mOwnReaction = reac ? Utils::coreStringToAppString(reac->getBody()) : QString(); for (auto &reaction : chatmessage->getReactions()) { @@ -121,6 +123,8 @@ ChatMessageCore::ChatMessageCore(const std::shared_ptr &c ++count; map.remove("count"); map.insert("count", count); + mReactionsSingletonMap.erase(it); + mReactionsSingletonMap.push_back(map); } } } @@ -336,6 +340,10 @@ void ChatMessageCore::setOwnReaction(const QString &reaction) { } } +QString ChatMessageCore::getTotalReactionsLabel() const { + return mTotalReactionsLabel; +} + QList ChatMessageCore::getReactions() const { return mReactions; } @@ -344,6 +352,19 @@ QList ChatMessageCore::getReactionsSingleton() const { return mReactionsSingletonMap; } +QStringList ChatMessageCore::getReactionsSingletonAsStrings() const { + QStringList reacStringList; + int totalCount = 0; + for (auto &reac : mReactionsSingletonMap) { + auto map = reac.toMap(); + auto count = map["count"].toInt(); + totalCount += count; + reacStringList.append(QString("%1 %2").arg(map["body"].toString()).arg(count)); + } + reacStringList.prepend(QString("%1 %2").arg(mTotalReactionsLabel).arg(totalCount)); + return reacStringList; +} + QList> ChatMessageCore::getChatMessageContentList() const { return mChatMessageContentList; } diff --git a/Linphone/core/chat/message/ChatMessageCore.hpp b/Linphone/core/chat/message/ChatMessageCore.hpp index 64dfefd20..96db71a93 100644 --- a/Linphone/core/chat/message/ChatMessageCore.hpp +++ b/Linphone/core/chat/message/ChatMessageCore.hpp @@ -64,6 +64,7 @@ class ChatMessageCore : public QObject, public AbstractObject { Q_PROPERTY(QString toAddress READ getToAddress CONSTANT) Q_PROPERTY(QString peerName READ getPeerName CONSTANT) Q_PROPERTY(QString fromName READ getFromName CONSTANT) + Q_PROPERTY(QString totalReactionsLabel READ getTotalReactionsLabel CONSTANT) Q_PROPERTY(LinphoneEnums::ChatMessageState messageState READ getMessageState WRITE setMessageState NOTIFY messageStateChanged) Q_PROPERTY(bool isRemoteMessage READ isRemoteMessage CONSTANT) @@ -72,6 +73,8 @@ class ChatMessageCore : public QObject, public AbstractObject { Q_PROPERTY(QString ownReaction READ getOwnReaction WRITE setOwnReaction NOTIFY messageReactionChanged) Q_PROPERTY(QList reactions READ getReactions WRITE setReactions NOTIFY messageReactionChanged) Q_PROPERTY(QList reactionsSingleton READ getReactionsSingleton NOTIFY singletonReactionMapChanged) + Q_PROPERTY( + QStringList reactionsSingletonAsStrings READ getReactionsSingletonAsStrings NOTIFY singletonReactionMapChanged) Q_PROPERTY(bool isForward MEMBER mIsForward CONSTANT) Q_PROPERTY(bool isReply MEMBER mIsReply CONSTANT) Q_PROPERTY(bool hasFileContent MEMBER mHasFileContent CONSTANT) @@ -105,8 +108,10 @@ public: QString getOwnReaction() const; void setOwnReaction(const QString &reaction); + QString getTotalReactionsLabel() const; QList getReactions() const; QList getReactionsSingleton() const; + QStringList getReactionsSingletonAsStrings() const; QList> getChatMessageContentList() const; void removeOneReactionFromSingletonMap(const QString &body); void resetReactionsSingleton(); @@ -163,6 +168,7 @@ private: bool mIsVoiceRecording = false; bool mIsOutgoing = false; + QString mTotalReactionsLabel; LinphoneEnums::ChatMessageState mMessageState; QList> mChatMessageContentList; // for voice recording creation message diff --git a/Linphone/core/emoji/EmojiList.cpp b/Linphone/core/emoji/EmojiList.cpp new file mode 100644 index 000000000..2a5a98b43 --- /dev/null +++ b/Linphone/core/emoji/EmojiList.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * 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 . + */ + +#include "EmojiList.hpp" +#include "core/App.hpp" +#include "core/chat/ChatCore.hpp" +#include "core/chat/message/content/ChatMessageContentGui.hpp" + +#include +#include + +#include + +// ============================================================================= + +DEFINE_ABSTRACT_OBJECT(EmojiList) + +QSharedPointer EmojiList::create() { + auto model = QSharedPointer(new EmojiList(), &QObject::deleteLater); + model->moveToThread(App::getInstance()->thread()); + return model; +} + +EmojiList::EmojiList(QObject *parent) : AbstractListProxy(parent) { + mustBeInMainThread(getClassName()); + App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership); +} + +EmojiList::~EmojiList() { + mustBeInMainThread("~" + getClassName()); +} + +QList EmojiList::getReactions() { + return mList; +} + +void EmojiList::setReactions(QList reactions) { + resetData(reactions); +} + +QVariant EmojiList::data(const QModelIndex &index, int role) const { + int row = index.row(); + if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant(); + if (role == Qt::DisplayRole) return QVariant::fromValue(mList.at(row)); + return QVariant(); +} \ No newline at end of file diff --git a/Linphone/core/emoji/EmojiList.hpp b/Linphone/core/emoji/EmojiList.hpp new file mode 100644 index 000000000..8a2ad9de7 --- /dev/null +++ b/Linphone/core/emoji/EmojiList.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * 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 . + */ + +#ifndef EMOJI_LIST_H_ +#define EMOJI_LIST_H_ + +#include "core/chat/message/ChatMessageCore.hpp" +#include "core/proxy/AbstractListProxy.hpp" +#include "tool/AbstractObject.hpp" +#include "tool/thread/SafeConnection.hpp" +#include + +// ============================================================================= + +class EmojiList : public AbstractListProxy, public AbstractObject { + Q_OBJECT +public: + static QSharedPointer create(); + EmojiList(QObject *parent = Q_NULLPTR); + ~EmojiList(); + + QList getReactions(); + void setReactions(QList reactions); + + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + +signals: + void reactionsChanged(); + +private: + QList mReactions; + DECLARE_ABSTRACT_OBJECT +}; + +#endif diff --git a/Linphone/core/emoji/EmojiProxy.cpp b/Linphone/core/emoji/EmojiProxy.cpp new file mode 100644 index 000000000..cd904e1e2 --- /dev/null +++ b/Linphone/core/emoji/EmojiProxy.cpp @@ -0,0 +1,65 @@ + +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * 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 . + */ + +#include "EmojiProxy.hpp" +#include "EmojiList.hpp" +#include "core/App.hpp" +// #include "core/chat/message/ChatMessageGui.hpp" + +DEFINE_ABSTRACT_OBJECT(EmojiProxy) + +EmojiProxy::EmojiProxy(QObject *parent) : LimitProxy(parent) { + mList = EmojiList::create(); + setSourceModel(mList.get()); + connect(mList.get(), &EmojiList::reactionsChanged, this, &EmojiProxy::reactionsChanged); + connect(this, &EmojiProxy::filterChanged, this, [this] { invalidate(); }); +} + +EmojiProxy::~EmojiProxy() { +} + +QList EmojiProxy::getReactions() { + return mList->getReactions(); +} + +void EmojiProxy::setReactions(QList reactions) { + mList->setReactions(reactions); +} + +QString EmojiProxy::getFilter() const { + return mFilter; +} + +void EmojiProxy::setFilter(QString filter) { + if (mFilter != filter) { + mFilter = filter; + emit filterChanged(); + } +} + +bool EmojiProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { + auto emoji = mList->getAt(sourceRow); + return emoji.mBody.contains(mFilter); +} + +bool EmojiProxy::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const { + return true; +} diff --git a/Linphone/core/emoji/EmojiProxy.hpp b/Linphone/core/emoji/EmojiProxy.hpp new file mode 100644 index 000000000..5a90ea67f --- /dev/null +++ b/Linphone/core/emoji/EmojiProxy.hpp @@ -0,0 +1,62 @@ + +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * 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 . + */ + +#ifndef EMOJI_PROXY_H_ +#define EMOJI_PROXY_H_ + +#include "core/chat/message/ChatMessageCore.hpp" +#include "core/emoji/EmojiModel.hpp" +#include "core/proxy/LimitProxy.hpp" +#include "tool/AbstractObject.hpp" + +// ============================================================================= + +class EmojiList; + +class EmojiProxy : public LimitProxy, public AbstractObject { + Q_OBJECT + Q_PROPERTY(QList reactions READ getReactions WRITE setReactions NOTIFY reactionsChanged) + Q_PROPERTY(QString filter READ getFilter WRITE setFilter NOTIFY filterChanged) + +public: + EmojiProxy(QObject *parent = Q_NULLPTR); + ~EmojiProxy(); + + QList getReactions(); + void setReactions(QList reactions); + + QString getFilter() const; + void setFilter(QString filter); + + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; + bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override; + +signals: + void reactionsChanged(); + void filterChanged(); + +protected: + QString mFilter; + QSharedPointer mList; + DECLARE_ABSTRACT_OBJECT +}; + +#endif diff --git a/Linphone/data/languages/de.ts b/Linphone/data/languages/de.ts index d8cd16086..51642f759 100644 --- a/Linphone/data/languages/de.ts +++ b/Linphone/data/languages/de.ts @@ -1802,31 +1802,31 @@ ChatMessage - + chat_message_copy_selection "Copy selection" - + chat_message_copy "Copy" - + chat_message_copied_to_clipboard_title Copied - + chat_message_copied_to_clipboard_toast "to clipboard" - + chat_message_delete "Delete" @@ -1916,13 +1916,19 @@ Error ChatMessageCore - + + all_reactions_label + "Reactions": all reactions for one message label + + + + info_toast_deleted_title Deleted - + info_toast_deleted_message The message has been deleted @@ -1975,20 +1981,20 @@ Error ChatMessagesListView - + chat_message_list_encrypted_header_title End to end encrypted chat - + chat_message_list_encrypted_header_message Les messages de cette conversation sont chiffrés de bout en bout. Seul votre correspondant peut les déchiffrer. - + chat_message_is_writing_info %1 is writing… @@ -4016,6 +4022,21 @@ Error Wie Teilnehmer in Besprechungen angezeigt werden + + MessageReactionsInfos + + + message_details_status title + Message status + + + + + click_to_delete_reaction_info + Click to delete + + + MultimediaSettings @@ -4811,7 +4832,7 @@ Pour les activer dans un projet commercial, merci de nous contacter. SelectedChatView - + chat_view_group_call_toast_message Start a group call ? diff --git a/Linphone/data/languages/en.ts b/Linphone/data/languages/en.ts index d0b04d428..0a3108736 100644 --- a/Linphone/data/languages/en.ts +++ b/Linphone/data/languages/en.ts @@ -1764,31 +1764,31 @@ ChatMessage - + chat_message_copy_selection "Copy selection" Copy selection - + chat_message_copy "Copy" Copy - + chat_message_copied_to_clipboard_title Copied Copied - + chat_message_copied_to_clipboard_toast "to clipboard" in clipboard - + chat_message_delete "Delete" Delete @@ -1878,13 +1878,19 @@ Error ChatMessageCore - + + all_reactions_label + "Reactions": all reactions for one message label + Reactions + + + info_toast_deleted_title Deleted Deleted - + info_toast_deleted_message The message has been deleted The message has been deleted @@ -1937,13 +1943,13 @@ Error ChatMessagesListView - + chat_message_list_encrypted_header_title End to end encrypted chat End to end encrypted chat - + chat_message_list_encrypted_header_message Les messages de cette conversation sont chiffrés de bout en bout. Seul votre correspondant peut les déchiffrer. @@ -1951,7 +1957,7 @@ Error Only your correspondent can decrypt them. - + chat_message_is_writing_info %1 is writing… %1 is writing… @@ -3934,6 +3940,21 @@ Only your correspondent can decrypt them. How participants are displayed in meetings + + MessageReactionsInfos + + + message_details_status title + Message status + Message status + + + + click_to_delete_reaction_info + Click to delete + Click to delete + + MultimediaSettings @@ -4712,7 +4733,7 @@ To enable them in a commercial project, please contact us. SelectedChatView - + chat_view_group_call_toast_message Start a group call ? diff --git a/Linphone/data/languages/fr_FR.ts b/Linphone/data/languages/fr_FR.ts index 7c90e5463..883986fad 100644 --- a/Linphone/data/languages/fr_FR.ts +++ b/Linphone/data/languages/fr_FR.ts @@ -1764,31 +1764,31 @@ ChatMessage - + chat_message_copy_selection "Copy selection" Copier la sélection - + chat_message_copy "Copy" Copier - + chat_message_copied_to_clipboard_title Copied Copié - + chat_message_copied_to_clipboard_toast "to clipboard" dans le presse-papiers - + chat_message_delete "Delete" Supprimer @@ -1878,13 +1878,19 @@ Error ChatMessageCore - + + all_reactions_label + "Reactions": all reactions for one message label + Réactions + + + info_toast_deleted_title Deleted Supprimé - + info_toast_deleted_message The message has been deleted Le message a été supprimé @@ -1937,13 +1943,13 @@ Error ChatMessagesListView - + chat_message_list_encrypted_header_title End to end encrypted chat Conversation chiffrée de bout en bout - + chat_message_list_encrypted_header_message Les messages de cette conversation sont chiffrés de bout en bout. Seul votre correspondant peut les déchiffrer. @@ -1951,7 +1957,7 @@ Error en bout. Seul votre correspondant peut les déchiffrer. - + chat_message_is_writing_info %1 is writing… %1 est en train d'écrire… @@ -3934,6 +3940,21 @@ en bout. Seul votre correspondant peut les déchiffrer. Le mode d’affichage des participants en réunions + + MessageReactionsInfos + + + message_details_status title + Message status + Statut du message + + + + click_to_delete_reaction_info + Click to delete + Appuyez pour supprimer + + MultimediaSettings @@ -4712,7 +4733,7 @@ Pour les activer dans un projet commercial, merci de nous contacter. SelectedChatView - + chat_view_group_call_toast_message Démarrer un appel de groupe ? diff --git a/Linphone/view/CMakeLists.txt b/Linphone/view/CMakeLists.txt index 91dd629bf..40a8f3107 100644 --- a/Linphone/view/CMakeLists.txt +++ b/Linphone/view/CMakeLists.txt @@ -154,6 +154,7 @@ list(APPEND _LINPHONEAPP_QML_FILES view/Page/Layout/Settings/NetworkSettingsLayout.qml view/Page/Layout/Settings/AdvancedSettingsLayout.qml view/Page/Layout/Chat/GroupConversationInfos.qml + view/Page/Layout/Chat/MessageReactionsInfos.qml view/Page/Layout/Chat/OneOneConversationInfos.qml view/Page/Layout/Chat/ChatInfoActionsGroup.qml view/Page/Layout/Chat/GroupChatInfoParticipants.qml diff --git a/Linphone/view/Control/Button/Button.qml b/Linphone/view/Control/Button/Button.qml index 0203df5ff..c2cb4f954 100644 --- a/Linphone/view/Control/Button/Button.qml +++ b/Linphone/view/Control/Button/Button.qml @@ -42,6 +42,7 @@ Control.Button { icon.source: style?.iconSource || "" MouseArea { id: mouseArea + z: stacklayout.z + 1 anchors.fill: parent hoverEnabled: true cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor diff --git a/Linphone/view/Control/Container/TabBar.qml b/Linphone/view/Control/Container/TabBar.qml index c1e3f856d..1ae264c85 100644 --- a/Linphone/view/Control/Container/TabBar.qml +++ b/Linphone/view/Control/Container/TabBar.qml @@ -88,7 +88,6 @@ Control.TabBar { width: Math.min(implicitWidth, mainItem.width / mainItem.model.length) font.weight: mainItem.textWeight color: mainItem.currentIndex === index ? DefaultStyle.main2_600 : DefaultStyle.main2_400 - font.family: DefaultStyle.defaultFont font.pixelSize: mainItem.pixelSize elide: Text.ElideRight maximumLineCount: 1 diff --git a/Linphone/view/Control/Display/Chat/ChatListView.qml b/Linphone/view/Control/Display/Chat/ChatListView.qml index 0f93daa00..4ea746e5a 100644 --- a/Linphone/view/Control/Display/Chat/ChatListView.qml +++ b/Linphone/view/Control/Display/Chat/ChatListView.qml @@ -263,6 +263,7 @@ ListView { font { pixelSize: Typography.p3.pixelSize weight: Typography.p3.weight + italic: modelData.core.sendingText !== "" } //: %1 is writing… text: modelData.core.composingName !== "" diff --git a/Linphone/view/Control/Display/Chat/ChatMessage.qml b/Linphone/view/Control/Display/Chat/ChatMessage.qml index d1bd65d1c..b080c21f2 100644 --- a/Linphone/view/Control/Display/Chat/ChatMessage.qml +++ b/Linphone/view/Control/Display/Chat/ChatMessage.qml @@ -28,6 +28,7 @@ Control.Control { signal messageDeletionRequested() signal isFileHoveringChanged(bool isFileHovering) + signal showReactionsForMessageRequested() background: Item { anchors.fill: parent @@ -174,6 +175,7 @@ Control.Control { property: "anchors.right" value: chatBubble.right } + onClicked: mainItem.showReactionsForMessageRequested() anchors.topMargin: Math.round(-6 * DefaultStyle.dp) topPadding: Math.round(8 * DefaultStyle.dp) bottomPadding: Math.round(8 * DefaultStyle.dp) diff --git a/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml b/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml index e86af1c31..fd0f8ed0c 100644 --- a/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml +++ b/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml @@ -14,6 +14,7 @@ ListView { spacing: Math.round(4 * DefaultStyle.dp) property ChatGui chat property color backgroundColor + signal showReactionsForMessageRequested(ChatMessageGui chatMessage) Component.onCompleted: { var index = eventLogProxy.findFirstUnreadIndex() @@ -133,6 +134,7 @@ ListView { : undefined onMessageDeletionRequested: modelData.core.lDelete() + onShowReactionsForMessageRequested: mainItem.showReactionsForMessageRequested(modelData) } } diff --git a/Linphone/view/Control/Display/Chat/Emoji/EmojiPicker.qml b/Linphone/view/Control/Display/Chat/Emoji/EmojiPicker.qml index 93f0d8af1..174990a86 100644 --- a/Linphone/view/Control/Display/Chat/Emoji/EmojiPicker.qml +++ b/Linphone/view/Control/Display/Chat/Emoji/EmojiPicker.qml @@ -34,7 +34,7 @@ import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils ColumnLayout { id: mainItem property var editor - property EmojiModel model: EmojiModel{ + property EmojiModel model: EmojiModel { id: emojiModel iconsPath: "image://emoji/emojiSvgs/" iconsType: '.svg' diff --git a/Linphone/view/Control/Display/Contact/Avatar.qml b/Linphone/view/Control/Display/Contact/Avatar.qml index 5755854ae..ce96e1208 100644 --- a/Linphone/view/Control/Display/Contact/Avatar.qml +++ b/Linphone/view/Control/Display/Contact/Avatar.qml @@ -114,8 +114,13 @@ Loader{ anchors.right: parent.right anchors.rightMargin: stackView.width / 15 z: 1 - source: account ? (account.core?.registrationState != LinphoneEnums.RegistrationState.Ok ? account.core?.registrationStateIcon : account.core?.presenceIcon) - : (contact ? contact.core?.presenceIcon : "") + source: account + ? (account.core?.registrationState !== LinphoneEnums.RegistrationState.Ok + ? account.core?.registrationStateIcon + : account.core?.presenceIcon) + : (contact + ? contact.core?.presenceIcon + : "") } } diff --git a/Linphone/view/Page/Form/Chat/SelectedChatView.qml b/Linphone/view/Page/Form/Chat/SelectedChatView.qml index e177f7c63..5828c9074 100644 --- a/Linphone/view/Page/Form/Chat/SelectedChatView.qml +++ b/Linphone/view/Page/Form/Chat/SelectedChatView.qml @@ -12,6 +12,8 @@ import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle RowLayout { id: mainItem property ChatGui chat + // used to show chat message reactions in details panel + property ChatMessageGui chatMessage property var contactObj: chat ? UtilsCpp.findFriendByAddress(mainItem.chat.core.peerAddress) : null property var contact: contactObj?.value || null property CallGui call @@ -112,12 +114,14 @@ RowLayout { onPressed: mainItem.oneOneCall(true) } BigButton { + id: detailsPanelButton style: ButtonStyle.noBackground checkable: true checkedImageColor: DefaultStyle.main1_500_main icon.source: AppIcons.info + checked: detailsPanel.visible onCheckedChanged: { - detailsPanel.visible = !detailsPanel.visible + detailsPanel.visible = checked } } } @@ -147,6 +151,11 @@ RowLayout { anchors.leftMargin: Math.round(18 * DefaultStyle.dp) anchors.rightMargin: Math.round(18 * DefaultStyle.dp) Control.ScrollBar.vertical: scrollbar + onShowReactionsForMessageRequested: (chatMessage) => { + mainItem.chatMessage = chatMessage + contentLoader.showingMessageReactions = true + detailsPanel.visible = true + } Popup { id: emojiPickerPopup @@ -313,6 +322,7 @@ RowLayout { visible: false Layout.fillHeight: true Layout.preferredWidth: Math.round(387 * DefaultStyle.dp) + onVisibleChanged: if(!visible) contentLoader.showingMessageReactions = false background: Rectangle { color: DefaultStyle.grey_0 @@ -321,9 +331,14 @@ RowLayout { contentItem: Loader { id: contentLoader + property bool showingMessageReactions: false anchors.top: parent.top anchors.topMargin: Math.round(39 * DefaultStyle.dp) - sourceComponent: mainItem.chat.core.isGroupChat ? groupInfoComponent : oneToOneInfoComponent + sourceComponent: showingMessageReactions + ? messageReactionsComponent + : mainItem.chat.core.isGroupChat + ? groupInfoComponent + : oneToOneInfoComponent active: detailsPanel.visible onLoaded: { if (contentLoader.item) { @@ -345,6 +360,16 @@ RowLayout { chatGui: mainItem.chat } } - } -} + Component { + id: messageReactionsComponent + MessageReactionsInfos { + chatMessageGui: mainItem.chatMessage + onGoBackRequested: { + detailsPanel.visible = false + mainItem.chatMessage = null + } + } + } + } +} \ No newline at end of file diff --git a/Linphone/view/Page/Layout/Chat/MessageReactionsInfos.qml b/Linphone/view/Page/Layout/Chat/MessageReactionsInfos.qml new file mode 100644 index 000000000..6c87f2eef --- /dev/null +++ b/Linphone/view/Page/Layout/Chat/MessageReactionsInfos.qml @@ -0,0 +1,118 @@ +import QtCore +import QtQuick +import QtQuick.Controls.Basic as Control +import QtQuick.Dialogs +import QtQuick.Effects +import QtQuick.Layouts +import Linphone +import UtilsCpp +import SettingsCpp +import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle + +ColumnLayout { + id: mainItem + property ChatMessageGui chatMessageGui + property var parentView + spacing: Math.round(25 * DefaultStyle.dp) + + signal goBackRequested() + + RowLayout { + BigButton { + icon.source: AppIcons.leftArrow + style: ButtonStyle.noBackground + onClicked: mainItem.goBackRequested() + } + Text { + //: Message status + text: qsTr("message_details_status title") + font { + pixelSize: Typography.h4.pixelSize + weight: Typography.h4.weight + } + } + } + + ColumnLayout { + spacing: Math.round(11 * DefaultStyle.dp) + Layout.leftMargin: Math.round(16 * DefaultStyle.dp) + Layout.rightMargin: Math.round(16 * DefaultStyle.dp) + TabBar { + id: tabbar + Layout.fillWidth: true + model: mainItem.chatMessageGui ? mainItem.chatMessageGui.core.reactionsSingletonAsStrings : [] + pixelSize: Typography.h3m.pixelSize + textWeight: Typography.h3m.weight + } + + ListView { + id: reactionsList + Layout.fillWidth: true + Layout.fillHeight: true + spacing: Math.round(11 * DefaultStyle.dp) + model: EmojiProxy { + reactions: mainItem.chatMessageGui ? mainItem.chatMessageGui.core.reactions : [] + // First index of reactionsSingletonAsStrings list is all reactions combined which does not appear + // in reactionsSingleton list + filter: tabbar.currentIndex >=1 && mainItem.chatMessageGui && mainItem.chatMessageGui.core.reactionsSingleton[tabbar.currentIndex-1].body || "" + } + delegate: Item { + width: reactionsList.width + height: delegateIn.implicitHeight + property var contactObj: modelData ? UtilsCpp.findFriendByAddress(modelData.address) : null + property var nameObj: modelData ? UtilsCpp.getDisplayName(modelData.address) : null + property var isMeObj: modelData ? UtilsCpp.isMe(modelData.address) : null + MouseArea { + anchors.fill: parent + enabled: isMeObj && isMeObj.value + cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + hoverEnabled: true + onClicked: mainItem.chatMessageGui.core.lRemoveReaction() + } + RowLayout { + id: delegateIn + anchors.fill: parent + spacing: Math.round(16 * DefaultStyle.dp) + Avatar { + Layout.alignment: Qt.AlignHCenter + contact: contactObj?.value || null + displayNameVal: contact + ? "" + : nameObj + ? nameObj.value + : "" + Layout.preferredWidth: Math.round(45 * DefaultStyle.dp) + Layout.preferredHeight: Math.round(45 * DefaultStyle.dp) + } + ColumnLayout { + Text { + text: nameObj?.value || "" + font { + pixelSize: Typography.p1.pixelSize + weight: Typography.p1.weight + } + } + Text { + visible: isMeObj && isMeObj.value + //: Click to delete + text: qsTr("click_to_delete_reaction_info") + color: DefaultStyle.main2_400 + font { + pixelSize: Typography.p3.pixelSize + weight: Typography.p3.weight + } + } + } + Item{Layout.fillWidth: true} + Text { + text: UtilsCpp.encodeEmojiToQmlRichFormat(modelData.body) + font { + pixelSize: Typography.h3.pixelSize + weight: Typography.p3.weight + } + } + } + } + } + } +} diff --git a/Linphone/view/Page/Layout/Chat/OneOneConversationInfos.qml b/Linphone/view/Page/Layout/Chat/OneOneConversationInfos.qml index b1e3282f7..9b35fc65f 100644 --- a/Linphone/view/Page/Layout/Chat/OneOneConversationInfos.qml +++ b/Linphone/view/Page/Layout/Chat/OneOneConversationInfos.qml @@ -13,7 +13,7 @@ ColumnLayout { id: mainItem property ChatGui chatGui property var chatCore: chatGui.core - property var contactObj: chat ? UtilsCpp.findFriendByAddress(mainItem.chatCore.peerAddress) : null + property var contactObj: chatGui ? UtilsCpp.findFriendByAddress(mainItem.chatCore.peerAddress) : null property var parentView spacing: 0 @@ -42,7 +42,7 @@ ColumnLayout { } Text { - visible: contactObj?.value + visible: contactObj && contactObj.value || false font: Typography.p3 color: contactObj?.value != null ? contactObj?.value.core.presenceColor : "transparent" text: contactObj?.value != null ? contactObj?.value.core.presenceStatus : "" diff --git a/Linphone/view/Style/Typography.qml b/Linphone/view/Style/Typography.qml index 0bba93392..9651a8d85 100644 --- a/Linphone/view/Style/Typography.qml +++ b/Linphone/view/Style/Typography.qml @@ -9,6 +9,13 @@ QtObject { pixelSize: Math.round(16 * DefaultStyle.dp), weight: Math.min(Math.round(800 * DefaultStyle.dp), 1000) }) + + // Title/H3M - Bloc title + property font h3m: Qt.font( { + family: DefaultStyle.defaultFont, + pixelSize: Math.round(16 * DefaultStyle.dp), + weight: Math.min(Math.round(800 * DefaultStyle.dp), 1000) + }) // Title/H3 - Bloc title property font h3: Qt.font( {