diff --git a/src/app/commoncomponents/DataTransferMessageDelegate.qml b/src/app/commoncomponents/DataTransferMessageDelegate.qml index d4dd426fa847f1262fa80b8de3d2dd95c4480049..6c0926274e15ff287632306a3cf95e3280fdcb80 100644 --- a/src/app/commoncomponents/DataTransferMessageDelegate.qml +++ b/src/app/commoncomponents/DataTransferMessageDelegate.qml @@ -326,8 +326,10 @@ Loader { Component { id: imageComp + Image { id: img + anchors.right: isOutgoing ? parent.right : undefined property real minSize: 192 property real maxSize: 256 @@ -346,6 +348,7 @@ Loader { innerContent.width - senderMargin)) width: adjustedWidth height: Math.ceil(adjustedWidth / aspectRatio) + Rectangle { color: JamiTheme.previewImageBackgroundColor z: -1 diff --git a/src/app/commoncomponents/SBSMessageBase.qml b/src/app/commoncomponents/SBSMessageBase.qml index a2d1bc3e1716f96c1b45f01f9ea94a98bba6fa63..343b4da434a3e78cddf8d32c4c7a5d398e65a139 100644 --- a/src/app/commoncomponents/SBSMessageBase.qml +++ b/src/app/commoncomponents/SBSMessageBase.qml @@ -32,7 +32,6 @@ Control { property alias avatarBlockWidth: avatarBlock.width property alias innerContent: innerContent property alias bubble: bubble - property alias selectAnimation: selectAnimation property real extraHeight: 0 // these MUST be set but we won't use the 'required' keyword yet @@ -145,6 +144,8 @@ Control { MessageBubble { id: bubble + + visible: !IsEmojiOnly z:-1 out: isOutgoing type: seq @@ -166,15 +167,48 @@ Control { height: innerContent.childrenRect.height + (visible ? root.extraHeight : 0) } + Rectangle { + id: bg + + color: bubble.getBaseColor() + anchors.fill: parent + visible: false + } + SequentialAnimation { id: selectAnimation - ColorAnimation { - target: bubble; property: "color" - to: Qt.darker(bubble.getBaseColor(), 1.5); duration: 240 + + PropertyAnimation { + properties: "opacity" + target: opacityMask + from: 0 + to: 1 + duration: JamiTheme.longFadeDuration } - ColorAnimation { - target: bubble; property: "color" - to: bubble.getBaseColor(); duration: 240 + PropertyAnimation { + properties: "opacity" + target: opacityMask + from: 1 + to: 0 + duration: JamiTheme.longFadeDuration + } + } + + OpacityMask { + id: opacityMask + + opacity: 0 + anchors.fill: bubble + source: bubble + maskSource: bg + } + + Connections { + target: CurrentConversation + function onScrollTo(id) { + if (id !== root.id) + return + selectAnimation.start() } } } diff --git a/src/app/commoncomponents/TextMessageDelegate.qml b/src/app/commoncomponents/TextMessageDelegate.qml index 0177699767b9c880086e776e1f97173272c64a09..0cbe4b0d54f9a69dddd7ff5381725fb5a71c21fd 100644 --- a/src/app/commoncomponents/TextMessageDelegate.qml +++ b/src/app/commoncomponents/TextMessageDelegate.qml @@ -21,6 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import Qt5Compat.GraphicalEffects + import net.jami.Models 1.1 import net.jami.Adapters 1.1 import net.jami.Constants 1.1 @@ -30,7 +31,9 @@ SBSMessageBase { id : root property bool isRemoteImage + property bool isEmojiOnly: IsEmojiOnly property real maxMsgWidth: root.width - senderMargin - 2 * hPadding - avatarBlockWidth + isOutgoing: Author === "" author: Author readers: Readers @@ -41,10 +44,15 @@ SBSMessageBase { innerContent.children: [ TextEdit { - padding: JamiTheme.preferredMarginSize + id: textEditId + + padding: isEmojiOnly ? 0 : JamiTheme.preferredMarginSize anchors.right: isOutgoing ? parent.right : undefined + text: Body - horizontalAlignment: Text.AlignLeft + + horizontalAlignment: isOutgoing ? Text.AlignLeft : Text.AlignRight + width: { if (extraContent.active) Math.max(extraContent.width, @@ -57,16 +65,31 @@ SBSMessageBase { height: implicitHeight wrapMode: Label.WrapAtWordBoundaryOrAnywhere selectByMouse: true - font.pixelSize: JamiTheme.chatviewFontSize + font.pixelSize: isEmojiOnly? JamiTheme.chatviewEmojiSize : JamiTheme.chatviewFontSize + font.hintingPreference: Font.PreferNoHinting renderType: Text.NativeRendering textFormat: Text.MarkdownText onLinkHovered: root.hoveredLink = hoveredLink onLinkActivated: Qt.openUrlExternally(hoveredLink) readOnly: true - color: UtilsAdapter.luma(bubble.color) ? - JamiTheme.chatviewTextColorLight : - JamiTheme.chatviewTextColorDark + color: getBaseColor() + + function getBaseColor() { + var baseColor + if (isEmojiOnly) { + if (JamiTheme.darkTheme) + baseColor = JamiTheme.chatviewTextColorLight + else + baseColor = JamiTheme.chatviewTextColorDark + } else { + if (UtilsAdapter.luma(bubble.color)) + baseColor = JamiTheme.chatviewTextColorLight + else + baseColor = JamiTheme.chatviewTextColorDark + } + return baseColor + } TapHandler { enabled: parent.selectedText.length > 0 @@ -104,6 +127,7 @@ SBSMessageBase { } AnimatedImage { id: img + cache: false source: isRemoteImage ? LinkPreviewInfo.url : diff --git a/src/app/constant/JamiTheme.qml b/src/app/constant/JamiTheme.qml index 0bccb0fef408e2b5b3c811af3e3d068bd51f1b0d..5267a12e9aca8c7c3c297bac7182db12a5292d58 100644 --- a/src/app/constant/JamiTheme.qml +++ b/src/app/constant/JamiTheme.qml @@ -188,6 +188,7 @@ Item { property color chatviewTextColorLight: "#f0f0f0" property color chatviewTextColorDark: "#353637" property real chatviewFontSize: calcSize(15) + property real chatviewEmojiSize: calcSize(60) property color timestampColor: darkTheme ? "#bbb" : "#777" property color messageOutTxtColor: "#000000" property color messageInBgColor: darkTheme ? "#28b1ed" : "#e5e5e5" diff --git a/src/app/mainview/components/MessageListView.qml b/src/app/mainview/components/MessageListView.qml index 0c4357035e22917a73793a72fb87890faffb24cf..ffc2c0125d299c533db8540cd29d346fbd6de3aa 100644 --- a/src/app/mainview/components/MessageListView.qml +++ b/src/app/mainview/components/MessageListView.qml @@ -166,9 +166,6 @@ JamiListView { } } positionViewAtIndex(idx, ListView.Center) - var delegate = root.itemAtIndex(idx) - if (delegate.selectAnimation) - delegate.selectAnimation.start() } } diff --git a/src/libclient/messagelistmodel.cpp b/src/libclient/messagelistmodel.cpp index f796f6fdc79b0e1ee198f6028e02789318047806..8e3f0b1cba0806950f4ca05081294cdfb9647eee 100644 --- a/src/libclient/messagelistmodel.cpp +++ b/src/libclient/messagelistmodel.cpp @@ -357,6 +357,29 @@ MessageListModel::roleNames() const return roles; } +bool +MessageListModel::isOnlyEmoji(const QString& text) const +{ + auto codepointList = text.toUcs4(); + for (QList<uint>::iterator it = codepointList.begin(); it != codepointList.end(); it++) { + auto cur = false; + if (*it == 20 or *it == 0x200D) { + cur = true; + } else if (0x1f000 <= *it && 0x1ffff >= *it) { + cur = true; + } else if (0x2600 <= *it && 0x27BF >= *it) { + cur = true; + } else if (0xFE00 <= *it && 0xFE0f >= *it) { + cur = true; + } else if (0xE0000 <= *it && 0xE007F >= *it) { + cur = true; + } + if (!cur) + return false; + } + return true; +} + QVariant MessageListModel::dataForItem(item_t item, int, int role) const { @@ -401,6 +424,8 @@ MessageListModel::dataForItem(item_t item, int, int role) const return QVariant(item.second.commit["displayName"]); case Role::Readers: return QVariant(messageToReaders_[item.first]); + case Role::IsEmojiOnly: + return QVariant(isOnlyEmoji(item.second.body)); default: return {}; } diff --git a/src/libclient/messagelistmodel.h b/src/libclient/messagelistmodel.h index 88028550fbeda72f5ede99c39c01dc7422602099..2613276b73d4e5efe37b0012e45ce5851e5a140b 100644 --- a/src/libclient/messagelistmodel.h +++ b/src/libclient/messagelistmodel.h @@ -50,7 +50,8 @@ struct Info; X(ReplyToAuthor) \ X(TotalSize) \ X(TransferName) \ - X(Readers) + X(Readers) \ + X(IsEmojiOnly) namespace MessageList { Q_NAMESPACE @@ -125,6 +126,7 @@ public: // these emission wrappers void emitDataChanged(iterator it, VectorInt roles = {}); void emitDataChanged(const QString& msgId, VectorInt roles = {}); + bool isOnlyEmoji(const QString& text) const; Q_SIGNAL void timestampUpdate();