diff --git a/qml/components/MessageListViewItem.qml b/qml/components/MessageListViewItem.qml index dcb5b47..cbc7865 100644 --- a/qml/components/MessageListViewItem.qml +++ b/qml/components/MessageListViewItem.qml @@ -115,6 +115,19 @@ ListItem { return interactionText; } + function openReactions() { + if (messageListItem.chatReactions) { + Debug.log("Using chat reactions") + messageListItem.messageReactions = chatReactions + showItemCompletelyTimer.requestedIndex = index; + showItemCompletelyTimer.start(); + } else { + Debug.log("Obtaining message reactions") + tdLibWrapper.getMessageAvailableReactions(messageListItem.chatId, messageListItem.messageId); + } + selectReactionBubble.visible = false; + } + onClicked: { if (messageListItem.precalculatedValues.pageIsSelecting) { page.toggleMessageSelection(myMessage); @@ -132,20 +145,17 @@ ListItem { if (messageListItem.messageReactions) { messageListItem.messageReactions = null; + selectReactionBubble.visible = false; + } else { + if (messageListItem.chatReactions) { + selectReactionBubble.visible = !selectReactionBubble.visible; + } } } } onDoubleClicked: { - if (messageListItem.chatReactions) { - Debug.log("Using chat reactions") - messageListItem.messageReactions = chatReactions - showItemCompletelyTimer.requestedIndex = index; - showItemCompletelyTimer.start(); - } else { - Debug.log("Obtaining message reactions") - tdLibWrapper.getMessageAvailableReactions(messageListItem.chatId, messageListItem.messageId); - } + openReactions(); } onPressAndHold: { @@ -652,12 +662,50 @@ ListItem { textFormat: Text.StyledText maximumLineCount: 1 elide: Text.ElideRight + MouseArea { + anchors.fill: parent + onClicked: { + if (messageListItem.messageReactions) { + messageListItem.messageReactions = null; + selectReactionBubble.visible = false; + } else { + openReactions(); + } + } + } } } } } + Rectangle { + id: selectReactionBubble + visible: false + opacity: visible ? 0.5 : 0.0 + Behavior on opacity { NumberAnimation {} } + anchors { + horizontalCenter: messageListItem.isOwnMessage ? messageBackground.left : messageBackground.right + verticalCenter: messageBackground.verticalCenter + } + height: Theme.itemSizeExtraSmall + width: Theme.itemSizeExtraSmall + color: Theme.primaryColor + radius: parent.width / 2 + } + + IconButton { + id: selectReactionButton + visible: selectReactionBubble.visible + opacity: visible ? 1.0 : 0.0 + Behavior on opacity { NumberAnimation {} } + icon.source: "image://theme/icon-s-favorite" + anchors.centerIn: selectReactionBubble + onClicked: { + openReactions(); + } + } + } } @@ -666,7 +714,7 @@ ListItem { id: reactionsColumn width: parent.width - ( 2 * Theme.horizontalPageMargin ) anchors.top: messageTextRow.bottom - anchors.topMargin: Theme.paddingSmall + anchors.topMargin: Theme.paddingMedium anchors.horizontalCenter: parent.horizontalCenter visible: messageListItem.messageReactions ? ( messageListItem.messageReactions.length > 0 ? true : false ) : false opacity: messageListItem.messageReactions ? ( messageListItem.messageReactions.length > 0 ? 1 : 0 ) : 0 @@ -675,7 +723,7 @@ ListItem { Flickable { width: parent.width - height: reactionsResultRow.height + Theme.paddingSmall + height: reactionsResultRow.height + 2 * Theme.paddingMedium anchors.horizontalCenter: parent.horizontalCenter contentWidth: reactionsResultRow.width clip: true @@ -691,13 +739,13 @@ ListItem { Row { id: singleReactionRow - spacing: Theme.paddingSmall + spacing: Theme.paddingMedium Image { id: emojiPicture source: Emoji.getEmojiPath(modelData) - width: status === Image.Ready ? Theme.fontSizeLarge : 0 - height: Theme.fontSizeLarge + width: status === Image.Ready ? Theme.fontSizeExtraLarge : 0 + height: Theme.fontSizeExtraLarge } } @@ -705,12 +753,26 @@ ListItem { MouseArea { anchors.fill: parent onClicked: { - tdLibWrapper.setMessageReaction(messageListItem.chatId, messageListItem.messageId, modelData); - messageListItem.messageReactions = null; + for (var i = 0; i < reactions.length; i++) { + var reaction = reactions[i] + var reactionText = reaction.reaction ? reaction.reaction : (reaction.type && reaction.type.emoji) ? reaction.type.emoji : "" + if (reactionText === modelData) { + if (reaction.is_chosen) { + // Reaction is already selected + tdLibWrapper.removeMessageReaction(chatId, messageId, reactionText) + messageReactions = null + return + } + break + } + } + // Reaction is not yet selected + tdLibWrapper.addMessageReaction(chatId, messageId, modelData) + messageReactions = null + selectReactionBubble.visible = false } } } - } } } diff --git a/qml/js/functions.js b/qml/js/functions.js index 7299b0d..b2e2ca7 100644 --- a/qml/js/functions.js +++ b/qml/js/functions.js @@ -448,7 +448,12 @@ function handleLink(link) { } else if (link.indexOf(tMePrefixHttp) === 0) { handleTMeLink(link, tMePrefixHttp); } else { - Qt.openUrlExternally(link); + Debug.log("Trying to open URL externally: " + link) + if (link.indexOf("://") === -1) { + Qt.openUrlExternally("https://" + link) + } else { + Qt.openUrlExternally(link); + } } } } diff --git a/qml/pages/ChatPage.qml b/qml/pages/ChatPage.qml index 993db38..b361923 100644 --- a/qml/pages/ChatPage.qml +++ b/qml/pages/ChatPage.qml @@ -576,6 +576,9 @@ Page { onSponsoredMessageReceived: { chatPage.containsSponsoredMessages = true; } + onReactionsUpdated: { + availableReactions = tdLibWrapper.getChatReactions(chatInformation.id); + } } Connections { @@ -610,6 +613,8 @@ Page { chatViewCooldownTimer.restart(); chatViewStartupReadTimer.restart(); + /* + // Double-tap for reactions is currently disabled, let's see if we'll ever need it again var remainingDoubleTapHints = appSettings.remainingDoubleTapHints; Debug.log("Remaining double tap hints: " + remainingDoubleTapHints); if (remainingDoubleTapHints > 0) { @@ -618,6 +623,8 @@ Page { tapHintLabel.visible = true; appSettings.remainingDoubleTapHints = remainingDoubleTapHints - 1; } + */ + } onNewMessageReceived: { if (( chatView.manuallyScrolledToBottom && Qt.application.state === Qt.ApplicationActive ) || message.sender_id.user_id === chatPage.myUserId) { diff --git a/rpm/harbour-fernschreiber.spec b/rpm/harbour-fernschreiber.spec index 4b6264a..51a5f21 100644 --- a/rpm/harbour-fernschreiber.spec +++ b/rpm/harbour-fernschreiber.spec @@ -12,7 +12,7 @@ Name: harbour-fernschreiber Summary: Fernschreiber is a Telegram client for Aurora OS Version: 0.17 -Release: 7 +Release: 8 Group: Qt/Qt License: LICENSE URL: http://werkwolf.eu/ @@ -70,7 +70,7 @@ desktop-file-install --delete-original \ %files %defattr(-,root,root,-) -%{_bindir} +%{_bindir}/%{name} %{_datadir}/%{name} %{_datadir}/applications/%{name}.desktop %{_datadir}/icons/hicolor/*/apps/%{name}.png diff --git a/src/tdlibwrapper.cpp b/src/tdlibwrapper.cpp index f815ccf..6b3e994 100644 --- a/src/tdlibwrapper.cpp +++ b/src/tdlibwrapper.cpp @@ -1462,9 +1462,8 @@ void TDLibWrapper::getPageSource(const QString &address) connect(reply, SIGNAL(finished()), this, SLOT(handleGetPageSourceFinished())); } -void TDLibWrapper::setMessageReaction(qlonglong chatId, qlonglong messageId, const QString &reaction) +void TDLibWrapper::addMessageReaction(qlonglong chatId, qlonglong messageId, const QString &reaction) { - LOG("Set message reaction" << chatId << messageId << reaction); QVariantMap requestObject; requestObject.insert(CHAT_ID, chatId); requestObject.insert(MESSAGE_ID, messageId); @@ -1479,9 +1478,35 @@ void TDLibWrapper::setMessageReaction(qlonglong chatId, qlonglong messageId, con reactionType.insert(EMOJI, reaction); requestObject.insert(REACTION_TYPE, reactionType); requestObject.insert(_TYPE, "addMessageReaction"); + LOG("Add message reaction" << chatId << messageId << reaction); } else { requestObject.insert("reaction", reaction); requestObject.insert(_TYPE, "setMessageReaction"); + LOG("Toggle message reaction" << chatId << messageId << reaction); + } + this->sendRequest(requestObject); +} + +void TDLibWrapper::removeMessageReaction(qlonglong chatId, qlonglong messageId, const QString &reaction) +{ + QVariantMap requestObject; + requestObject.insert(CHAT_ID, chatId); + requestObject.insert(MESSAGE_ID, messageId); + if (versionNumber > VERSION_NUMBER(1,8,5)) { + // "reaction_type": { + // "@type": "reactionTypeEmoji", + // "emoji": "..." + // } + QVariantMap reactionType; + reactionType.insert(_TYPE, REACTION_TYPE_EMOJI); + reactionType.insert(EMOJI, reaction); + requestObject.insert(REACTION_TYPE, reactionType); + requestObject.insert(_TYPE, "removeMessageReaction"); + LOG("Remove message reaction" << chatId << messageId << reaction); + } else { + requestObject.insert("reaction", reaction); + requestObject.insert(_TYPE, "setMessageReaction"); + LOG("Toggle message reaction" << chatId << messageId << reaction); } this->sendRequest(requestObject); } @@ -2068,6 +2093,7 @@ void TDLibWrapper::handleActiveEmojiReactionsUpdated(const QStringList& emojis) if (activeEmojiReactions != emojis) { activeEmojiReactions = emojis; LOG(emojis.count() << "reaction(s) available"); + emit reactionsUpdated(); } } diff --git a/src/tdlibwrapper.h b/src/tdlibwrapper.h index 17a0896..c4773e3 100644 --- a/src/tdlibwrapper.h +++ b/src/tdlibwrapper.h @@ -249,7 +249,8 @@ public: Q_INVOKABLE void terminateSession(const QString &sessionId); Q_INVOKABLE void getMessageAvailableReactions(qlonglong chatId, qlonglong messageId); Q_INVOKABLE void getPageSource(const QString &address); - Q_INVOKABLE void setMessageReaction(qlonglong chatId, qlonglong messageId, const QString &reaction); + Q_INVOKABLE void addMessageReaction(qlonglong chatId, qlonglong messageId, const QString &reaction); + Q_INVOKABLE void removeMessageReaction(qlonglong chatId, qlonglong messageId, const QString &reaction); Q_INVOKABLE void setNetworkType(NetworkType networkType); Q_INVOKABLE void setInactiveSessionTtl(int days); @@ -338,6 +339,7 @@ signals: void chatUnreadMentionCountUpdated(qlonglong chatId, int unreadMentionCount); void chatUnreadReactionCountUpdated(qlonglong chatId, int unreadReactionCount); void tgUrlFound(const QString &tgUrl); + void reactionsUpdated(); public slots: void handleVersionDetected(const QString &version);