Compare commits

..

8 commits

Author SHA1 Message Date
Sebastian Wolf
0ba3a8cd7f Trouble with usernames 2023-11-19 12:23:42 +03:00
Sebastian Wolf
0aeaf50c92 Some minor adjustments 2023-11-19 12:23:23 +03:00
Johannes Bachmann
a9947ff9f7 Always append last message content to notifications (#514)
* always append last message content to notifications

* make "always show notification" configurable

* add unfinished translations

* Fix spacing if no sender is printed
2023-11-19 12:22:22 +03:00
Peter G
c7324c020b Add option to suppress notification previews (#521)
* Add Switch in Settings

* Don't set notification preview body

* Support the setting in appSettings

* fixup! Add Switch in Settings

* Just show message count

* Also show only when notifications are enabled at all

---------

Co-authored-by: nephros <nemo@pgxperiiia10>
2023-11-19 12:22:13 +03:00
Peter G
46419b0960 Highlight unread Converstations (#513)
* Highlight unread conversations

See: #512

* make highlighting configurable

* more verbose variable names

* remove the rectangle gain, it is too annoying

* respect the setting

---------

Co-authored-by: nephros <nemo@pgxperiiia10>
2023-11-19 12:22:04 +03:00
Slava Monich
c1c8729023 Adapt to changes in reply message info (#525)
1.8.14:
https://github.com/tdlib/td/commit/fa94aba

1.8.21:
https://github.com/tdlib/td/commit/811a7c6
https://github.com/tdlib/td/commit/5216ea1
2023-11-19 12:21:17 +03:00
Sebastian Wolf
9bcc9ab690 Only expect chat partner information in private chats 2023-11-19 12:01:42 +03:00
Slava Monich
0b6a2db2f1 Adapt to changes in TdLib (#524)
* Adapt setTdlibParameters for TdLib > 1.8.5

For some reason tdlibParameters were inlined between 1.8.5 and 1.8.6
See https://github.com/tdlib/td/commit/f6a2ecd

* sponsoredMessage => sponsoredMessages in TdLib 1.8.8

See https://github.com/tdlib/td/commit/ec1310a

* Support another variant of messageReaction

The reaction field has changed from string to ReactionType somewhere
between 1.8.5 and 1.8.6

See https://github.com/tdlib/td/commit/b14708f

* Add support for new message reactions API

It has changed between 1.8.5 and 1.8.6

https://github.com/tdlib/td/commit/b14708f (ReactionType)
https://github.com/tdlib/td/commit/0b8e143 (ChatAvailableReactions)
https://github.com/tdlib/td/commit/6b2f6b4 (addMessageReaction)
https://github.com/tdlib/td/commit/d29d367 (updateActiveEmojiReactions)

etc.

* Highlight chosen reaction

* Support username in the new format

username attribute has been replaced with usernames in 1.8.8 and
now looks like this:

    "usernames": {
        "@type": "usernames",
        "active_usernames": [
            "whatever"
        ],
        "disabled_usernames": [
        ],
        "editable_username": "whatever"
    }

See https://github.com/tdlib/td/commit/897032e

* Support new reply_to message attribute

Since 1.8.15 it replaces reply_to_message_id and reply_in_chat_id.
Looks like this:

    "reply_to": {
        "@type": "messageReplyToMessage",
        "chat_id": -1001234567890,
        "is_quote_manual": false,
        "message_id": 234567890,
        "origin_send_date": 0
    },

See https://github.com/tdlib/td/commit/6116573

* Added support for MessageOrigin values

All of a sudden MessageForwardOrigin has been renamed into MessageOrigin
in TdLib 1.8.20 just because why not:

https://github.com/tdlib/td/commit/10c9e40
2023-11-19 12:01:27 +03:00
29 changed files with 708 additions and 207 deletions

View file

@ -64,6 +64,7 @@ ListItem {
readonly property bool showForwardMessageMenuItem: (baseContextMenuItemCount + 2) <= maxContextMenuItemCount readonly property bool showForwardMessageMenuItem: (baseContextMenuItemCount + 2) <= maxContextMenuItemCount
// And don't count "More Options..." for "Delete Message" if "Delete Message" is the only extra option // And don't count "More Options..." for "Delete Message" if "Delete Message" is the only extra option
readonly property bool haveSpaceForDeleteMessageMenuItem: (baseContextMenuItemCount + 3 - (deleteMessageIsOnlyExtraOption ? 1 : 0)) <= maxContextMenuItemCount readonly property bool haveSpaceForDeleteMessageMenuItem: (baseContextMenuItemCount + 3 - (deleteMessageIsOnlyExtraOption ? 1 : 0)) <= maxContextMenuItemCount
property var chatReactions
property var messageReactions property var messageReactions
highlighted: (down || isSelected || additionalOptionsOpened) && !menuOpen highlighted: (down || isSelected || additionalOptionsOpened) && !menuOpen
@ -94,15 +95,21 @@ ListItem {
} }
} }
function getInteractionText(viewCount, reactions) { function getInteractionText(viewCount, reactions, size, highlightColor) {
var interactionText = ""; var interactionText = "";
if (viewCount > 0) { if (viewCount > 0) {
interactionText = Emoji.emojify("👁️", Theme.fontSizeTiny) + Functions.getShortenedCount(viewCount); interactionText = Emoji.emojify("👁️ ", size) + Functions.getShortenedCount(viewCount);
} }
for (var i = 0; i < reactions.length; i++) { for (var i = 0; i < reactions.length; i++) {
interactionText += ( "&nbsp;" + Emoji.emojify(reactions[i].reaction, Theme.fontSizeTiny) ); var reaction = reactions[i]
var reactionText = reaction.reaction ? reaction.reaction : (reaction.type && reaction.type.emoji) ? reaction.type.emoji : ""
if (reactionText) {
interactionText += ( "&nbsp;" + Emoji.emojify(reactionText, size) );
if (!chatPage.isPrivateChat) { if (!chatPage.isPrivateChat) {
interactionText += ( " " + Functions.getShortenedCount(reactions[i].total_count) ); var count = Functions.getShortenedCount(reaction.total_count)
interactionText += " "
interactionText += (reaction.is_chosen ? ( "<font color='" + highlightColor + "'><b>" + count + "</b></font>" ) : count)
}
} }
} }
return interactionText; return interactionText;
@ -125,6 +132,8 @@ ListItem {
if (messageListItem.messageReactions) { if (messageListItem.messageReactions) {
messageListItem.messageReactions = null; messageListItem.messageReactions = null;
} else if (messageListItem.chatReactions) {
messageListItem.messageReactions = chatReactions
} else { } else {
tdLibWrapper.getMessageAvailableReactions(messageListItem.chatId, messageListItem.messageId); tdLibWrapper.getMessageAvailableReactions(messageListItem.chatId, messageListItem.messageId);
} }
@ -467,11 +476,12 @@ ListItem {
width: parent.width width: parent.width
Component.onCompleted: { Component.onCompleted: {
if (myMessage.forward_info.origin["@type"] === "messageForwardOriginChannel") { var originType = myMessage.forward_info.origin["@type"]
if (originType === "messageOriginChannel" || originType === "messageForwardOriginChannel") {
var otherChatInformation = tdLibWrapper.getChat(myMessage.forward_info.origin.chat_id); var otherChatInformation = tdLibWrapper.getChat(myMessage.forward_info.origin.chat_id);
forwardedThumbnail.photoData = (typeof otherChatInformation.photo !== "undefined") ? otherChatInformation.photo.small : {}; forwardedThumbnail.photoData = (typeof otherChatInformation.photo !== "undefined") ? otherChatInformation.photo.small : {};
forwardedChannelText.text = Emoji.emojify(otherChatInformation.title, Theme.fontSizeExtraSmall); forwardedChannelText.text = Emoji.emojify(otherChatInformation.title, Theme.fontSizeExtraSmall);
} else if (myMessage.forward_info.origin["@type"] === "messageForwardOriginUser") { } else if (originType === "messageOriginUser" || originType === "messageForwardOriginUser") {
var otherUserInformation = tdLibWrapper.getUserInformation(myMessage.forward_info.origin.sender_user_id); var otherUserInformation = tdLibWrapper.getUserInformation(myMessage.forward_info.origin.sender_user_id);
forwardedThumbnail.photoData = (typeof otherUserInformation.profile_photo !== "undefined") ? otherUserInformation.profile_photo.small : {}; forwardedThumbnail.photoData = (typeof otherUserInformation.profile_photo !== "undefined") ? otherUserInformation.profile_photo.small : {};
forwardedChannelText.text = Emoji.emojify(Functions.getUserName(otherUserInformation), Theme.fontSizeExtraSmall); forwardedChannelText.text = Emoji.emojify(Functions.getUserName(otherUserInformation), Theme.fontSizeExtraSmall);
@ -625,7 +635,7 @@ ListItem {
height: ( ( chatPage.isChannel && messageViewCount > 0 ) || reactions.length > 0 ) ? ( Theme.fontSizeExtraSmall + Theme.paddingSmall ) : 0 height: ( ( chatPage.isChannel && messageViewCount > 0 ) || reactions.length > 0 ) ? ( Theme.fontSizeExtraSmall + Theme.paddingSmall ) : 0
sourceComponent: Component { sourceComponent: Component {
Label { Label {
text: getInteractionText(messageViewCount, reactions) text: getInteractionText(messageViewCount, reactions, font.pixelSize, Theme.highlightColor)
width: parent.width width: parent.width
font.pixelSize: Theme.fontSizeTiny font.pixelSize: Theme.fontSizeTiny
color: messageListItem.isOwnMessage ? Theme.secondaryHighlightColor : Theme.secondaryColor color: messageListItem.isOwnMessage ? Theme.secondaryHighlightColor : Theme.secondaryColor

View file

@ -40,9 +40,11 @@ Flickable {
function getOriginalAuthor(forwardInformation, fontSize) { function getOriginalAuthor(forwardInformation, fontSize) {
switch (forwardInformation.origin["@type"]) { switch (forwardInformation.origin["@type"]) {
case "messageOriginChannel":
case "messageForwardOriginChannel": case "messageForwardOriginChannel":
var otherChatInformation = tdLibWrapper.getChat(forwardInformation.origin.chat_id); var otherChatInformation = tdLibWrapper.getChat(forwardInformation.origin.chat_id);
return Emoji.emojify(otherChatInformation.title, fontSize); return Emoji.emojify(otherChatInformation.title, fontSize);
case "messageOriginUser":
case "messageForwardOriginUser": case "messageForwardOriginUser":
var otherUserInformation = tdLibWrapper.getUserInformation(forwardInformation.origin.sender_id.user_id); var otherUserInformation = tdLibWrapper.getUserInformation(forwardInformation.origin.sender_id.user_id);
return Emoji.emojify(Functions.getUserName(otherUserInformation), fontSize); return Emoji.emojify(Functions.getUserName(otherUserInformation), fontSize);

View file

@ -151,6 +151,9 @@ ListItem {
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: Math.min(contentColumn.width - (verifiedImage.visible ? (verifiedImage.width + primaryTextRow.spacing) : 0) - (mutedImage.visible ? (mutedImage.width + primaryTextRow.spacing) : 0), implicitWidth) width: Math.min(contentColumn.width - (verifiedImage.visible ? (verifiedImage.width + primaryTextRow.spacing) : 0) - (mutedImage.visible ? (mutedImage.width + primaryTextRow.spacing) : 0), implicitWidth)
font.bold: appSettings.highlightUnreadConversations && ( !chatListViewItem.isMuted && (chatListViewItem.unreadCount > 0 || chatListViewItem.isMarkedAsUnread) )
font.italic: appSettings.highlightUnreadConversations && (chatListViewItem.unreadReactionCount > 0)
color: (appSettings.highlightUnreadConversations && (chatListViewItem.unreadCount > 0)) ? Theme.highlightColor : Theme.primaryColor
} }
Image { Image {

View file

@ -79,7 +79,7 @@ ChatInformationTabItemBase {
// chat title // chat title
primaryText.text: Emoji.emojify(Functions.getUserName(user), primaryText.font.pixelSize) primaryText.text: Emoji.emojify(Functions.getUserName(user), primaryText.font.pixelSize)
// last user // last user
prologSecondaryText.text: "@"+(user.username !== "" ? user.username : member_id.user_id) + (member_id.user_id === chatInformationPage.myUserId ? " " + qsTr("You") : "") prologSecondaryText.text: "@"+(user.username ? user.username : member_id.user_id) + (member_id.user_id === chatInformationPage.myUserId ? " " + qsTr("You") : "")
secondaryText { secondaryText {
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
property string statusText: Functions.getChatMemberStatusText(model.status["@type"]) property string statusText: Functions.getChatMemberStatusText(model.status["@type"])
@ -180,6 +180,9 @@ ChatInformationTabItemBase {
for(var memberIndex in members) { for(var memberIndex in members) {
var memberData = members[memberIndex]; var memberData = members[memberIndex];
var userInfo = tdLibWrapper.getUserInformation(memberData.member_id.user_id) || {user:{}, bot_info:{}}; var userInfo = tdLibWrapper.getUserInformation(memberData.member_id.user_id) || {user:{}, bot_info:{}};
if (!userInfo.username && userInfo.usernames && userInfo.usernames.active_usernames) {
userInfo.username = userInfo.usernames.active_usernames[0]
}
memberData.user = userInfo; memberData.user = userInfo;
memberData.bot_info = memberData.bot_info || {}; memberData.bot_info = memberData.bot_info || {};
pageContent.membersList.append(memberData); pageContent.membersList.append(memberData);

View file

@ -70,6 +70,18 @@ AccordionItem {
} }
} }
TextSwitch {
width: parent.columnWidth
checked: appSettings.highlightUnreadConversations
text: qsTr("Highlight unread messages")
description: qsTr("Highlight Conversations with unread messages")
automaticCheck: false
onClicked: {
appSettings.highlightUnreadConversations = !checked
}
}
TextSwitch { TextSwitch {
width: parent.columnWidth width: parent.columnWidth
checked: appSettings.useOpenWith checked: appSettings.useOpenWith
@ -135,6 +147,20 @@ AccordionItem {
} }
} }
TextSwitch {
width: parent.columnWidth
checked: appSettings.notificationSuppressContent && enabled
text: qsTr("Hide content in Notifications")
enabled: appSettings.notificationFeedback !== AppSettings.NotificationFeedbackNone
clip: height < implicitHeight
visible: height > 0
automaticCheck: false
onClicked: {
appSettings.notificationSuppressContent = !checked
}
Behavior on height { SmoothedAnimation { duration: 200 } }
}
TextSwitch { TextSwitch {
width: parent.columnWidth width: parent.columnWidth
checked: appSettings.notificationTurnsDisplayOn && enabled checked: appSettings.notificationTurnsDisplayOn && enabled
@ -165,6 +191,17 @@ AccordionItem {
} }
Behavior on height { SmoothedAnimation { duration: 200 } } Behavior on height { SmoothedAnimation { duration: 200 } }
} }
TextSwitch {
width: parent.columnWidth
checked: appSettings.notificationAlwaysShowPreview
text: qsTr("Always append message preview to notifications")
description: qsTr("In addition to showing the number of unread messages, the latest message will also be appended to notifications.")
automaticCheck: false
onClicked: {
appSettings.notificationAlwaysShowPreview = !checked
}
}
} }
} }
} }

View file

@ -141,18 +141,6 @@ AccordionItem {
} }
} }
Label {
width: parent.width
text: qsTr("IP address: %1, origin: %2").arg(modelData.ip).arg(modelData.country)
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.secondaryColor
maximumLineCount: 1
truncationMode: TruncationMode.Fade
anchors {
horizontalCenter: parent.horizontalCenter
}
}
Label { Label {
width: parent.width width: parent.width
text: qsTr("Active since: %1, last online: %2").arg(Functions.getDateTimeTimepoint(modelData.log_in_date)).arg(Functions.getDateTimeElapsed(modelData.last_active_date)) text: qsTr("Active since: %1, last online: %2").arg(Functions.getDateTimeTimepoint(modelData.log_in_date)).arg(Functions.getDateTimeElapsed(modelData.last_active_date))

View file

@ -143,7 +143,7 @@ AccordionItem {
visible: true visible: true
canEdit: true canEdit: true
headerText: qsTr("Username", "user name of the logged-in profile - header") headerText: qsTr("Username", "user name of the logged-in profile - header")
text: userInformation.username text: userInformation.usernames.editable_username
width: parent.columnWidth width: parent.columnWidth
headerLeftAligned: true headerLeftAligned: true

View file

@ -66,6 +66,7 @@ Page {
readonly property bool canSendMessages: hasSendPrivilege("can_send_messages") readonly property bool canSendMessages: hasSendPrivilege("can_send_messages")
property bool doSendBotStartMessage property bool doSendBotStartMessage
property string sendBotStartMessageParameter property string sendBotStartMessageParameter
property var availableReactions
states: [ states: [
State { State {
@ -184,7 +185,7 @@ Page {
} }
tdLibWrapper.getChatPinnedMessage(chatInformation.id); tdLibWrapper.getChatPinnedMessage(chatInformation.id);
tdLibWrapper.toggleChatIsMarkedAsUnread(chatInformation.id, false); tdLibWrapper.toggleChatIsMarkedAsUnread(chatInformation.id, false);
availableReactions = tdLibWrapper.getChatReactions(chatInformation.id);
} }
function getMessageStatusText(message, listItemIndex, lastReadSentIndex, useElapsed) { function getMessageStatusText(message, listItemIndex, lastReadSentIndex, useElapsed) {
@ -439,7 +440,8 @@ Page {
Component.onDestruction: { Component.onDestruction: {
if (chatPage.canSendMessages && !chatPage.isDeletedUser) { if (chatPage.canSendMessages && !chatPage.isDeletedUser) {
tdLibWrapper.setChatDraftMessage(chatInformation.id, 0, newMessageColumn.replyToMessageId, newMessageTextField.text); tdLibWrapper.setChatDraftMessage(chatInformation.id, 0, newMessageColumn.replyToMessageId, newMessageTextField.text,
newMessageInReplyToRow.inReplyToMessage ? newMessageInReplyToRow.inReplyToMessage.id : 0);
} }
fernschreiberUtils.stopGeoLocationUpdates(); fernschreiberUtils.stopGeoLocationUpdates();
tdLibWrapper.closeChat(chatInformation.id); tdLibWrapper.closeChat(chatInformation.id);
@ -562,12 +564,12 @@ Page {
} }
} }
onUserFullInfoReceived: { onUserFullInfoReceived: {
if(userFullInfo["@extra"] === chatPartnerInformation.id.toString()) { if ((isPrivateChat || isSecretChat) && userFullInfo["@extra"] === chatPartnerInformation.id.toString()) {
chatPage.botInformation = userFullInfo; chatPage.botInformation = userFullInfo;
} }
} }
onUserFullInfoUpdated: { onUserFullInfoUpdated: {
if(userId === chatPartnerInformation.id) { if ((isPrivateChat || isSecretChat) && userId === chatPartnerInformation.id) {
chatPage.botInformation = userFullInfo; chatPage.botInformation = userFullInfo;
} }
} }
@ -1348,6 +1350,7 @@ Page {
messageId: model.message_id messageId: model.message_id
messageViewCount: model.view_count messageViewCount: model.view_count
reactions: model.reactions reactions: model.reactions
chatReactions: availableReactions
messageIndex: model.index messageIndex: model.index
hasContentComponent: !!myMessage.content && chatView.delegateMessagesContent.indexOf(model.content_type) > -1 hasContentComponent: !!myMessage.content && chatView.delegateMessagesContent.indexOf(model.content_type) > -1
canReplyToMessage: chatPage.canSendMessages canReplyToMessage: chatPage.canSendMessages

View file

@ -29,7 +29,9 @@ namespace {
const QString KEY_ANIMATE_STICKERS("animateStickers"); const QString KEY_ANIMATE_STICKERS("animateStickers");
const QString KEY_NOTIFICATION_TURNS_DISPLAY_ON("notificationTurnsDisplayOn"); const QString KEY_NOTIFICATION_TURNS_DISPLAY_ON("notificationTurnsDisplayOn");
const QString KEY_NOTIFICATION_SOUNDS_ENABLED("notificationSoundsEnabled"); const QString KEY_NOTIFICATION_SOUNDS_ENABLED("notificationSoundsEnabled");
const QString KEY_NOTIFICATION_SUPPRESS_ENABLED("notificationSuppressContent");
const QString KEY_NOTIFICATION_FEEDBACK("notificationFeedback"); const QString KEY_NOTIFICATION_FEEDBACK("notificationFeedback");
const QString KEY_NOTIFICATION_ALWAYS_SHOW_PREVIEW("notificationAlwaysShowPreview");
const QString KEY_STORAGE_OPTIMIZER("useStorageOptimizer"); const QString KEY_STORAGE_OPTIMIZER("useStorageOptimizer");
const QString KEY_INLINEBOT_LOCATION_ACCESS("allowInlineBotLocationAccess"); const QString KEY_INLINEBOT_LOCATION_ACCESS("allowInlineBotLocationAccess");
const QString KEY_REMAINING_INTERACTION_HINTS("remainingInteractionHints"); const QString KEY_REMAINING_INTERACTION_HINTS("remainingInteractionHints");
@ -37,6 +39,7 @@ namespace {
const QString KEY_DELAY_MESSAGE_READ("delayMessageRead"); const QString KEY_DELAY_MESSAGE_READ("delayMessageRead");
const QString KEY_FOCUS_TEXTAREA_ON_CHAT_OPEN("focusTextAreaOnChatOpen"); const QString KEY_FOCUS_TEXTAREA_ON_CHAT_OPEN("focusTextAreaOnChatOpen");
const QString KEY_SPONSORED_MESS("sponsoredMess"); const QString KEY_SPONSORED_MESS("sponsoredMess");
const QString KEY_HIGHLIGHT_UNREADCONVS("highlightUnreadConversations");
} }
AppSettings::AppSettings(QObject *parent) : QObject(parent), settings(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/de.ygriega/fernschreiber/settings.conf", QSettings::NativeFormat) AppSettings::AppSettings(QObject *parent) : QObject(parent), settings(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/de.ygriega/fernschreiber/settings.conf", QSettings::NativeFormat)
@ -155,6 +158,20 @@ void AppSettings::setNotificationSoundsEnabled(bool enable)
} }
} }
bool AppSettings::notificationSuppressContent() const
{
return settings.value(KEY_NOTIFICATION_SUPPRESS_ENABLED, false).toBool();
}
void AppSettings::setNotificationSuppressContent(bool enable)
{
if (notificationSuppressContent() != enable) {
LOG(KEY_NOTIFICATION_SUPPRESS_ENABLED << enable);
settings.setValue(KEY_NOTIFICATION_SUPPRESS_ENABLED, enable);
emit notificationSuppressContentChanged();
}
}
AppSettings::NotificationFeedback AppSettings::notificationFeedback() const AppSettings::NotificationFeedback AppSettings::notificationFeedback() const
{ {
return (NotificationFeedback) settings.value(KEY_NOTIFICATION_FEEDBACK, (int) NotificationFeedbackAll).toInt(); return (NotificationFeedback) settings.value(KEY_NOTIFICATION_FEEDBACK, (int) NotificationFeedbackAll).toInt();
@ -169,6 +186,20 @@ void AppSettings::setNotificationFeedback(NotificationFeedback feedback)
} }
} }
bool AppSettings::notificationAlwaysShowPreview() const
{
return settings.value(KEY_NOTIFICATION_ALWAYS_SHOW_PREVIEW, false).toBool();
}
void AppSettings::setNotificationAlwaysShowPreview(bool enable)
{
if (notificationAlwaysShowPreview() != enable) {
LOG(KEY_NOTIFICATION_ALWAYS_SHOW_PREVIEW << enable);
settings.setValue(KEY_NOTIFICATION_ALWAYS_SHOW_PREVIEW, enable);
emit notificationAlwaysShowPreviewChanged();
}
}
bool AppSettings::storageOptimizer() const bool AppSettings::storageOptimizer() const
{ {
return settings.value(KEY_STORAGE_OPTIMIZER, true).toBool(); return settings.value(KEY_STORAGE_OPTIMIZER, true).toBool();
@ -240,6 +271,20 @@ void AppSettings::setDelayMessageRead(bool enable)
} }
} }
bool AppSettings::highlightUnreadConversations() const
{
return settings.value(KEY_HIGHLIGHT_UNREADCONVS, true).toBool();
}
void AppSettings::setHighlightUnreadConversations(bool enable)
{
if (highlightUnreadConversations() != enable) {
LOG(KEY_HIGHLIGHT_UNREADCONVS << enable);
settings.setValue(KEY_HIGHLIGHT_UNREADCONVS, enable);
emit highlightUnreadConversationsChanged();
}
}
bool AppSettings::getFocusTextAreaOnChatOpen() const bool AppSettings::getFocusTextAreaOnChatOpen() const
{ {
return settings.value(KEY_FOCUS_TEXTAREA_ON_CHAT_OPEN, false).toBool(); return settings.value(KEY_FOCUS_TEXTAREA_ON_CHAT_OPEN, false).toBool();

View file

@ -32,7 +32,9 @@ class AppSettings : public QObject {
Q_PROPERTY(bool animateStickers READ animateStickers WRITE setAnimateStickers NOTIFY animateStickersChanged) Q_PROPERTY(bool animateStickers READ animateStickers WRITE setAnimateStickers NOTIFY animateStickersChanged)
Q_PROPERTY(bool notificationTurnsDisplayOn READ notificationTurnsDisplayOn WRITE setNotificationTurnsDisplayOn NOTIFY notificationTurnsDisplayOnChanged) Q_PROPERTY(bool notificationTurnsDisplayOn READ notificationTurnsDisplayOn WRITE setNotificationTurnsDisplayOn NOTIFY notificationTurnsDisplayOnChanged)
Q_PROPERTY(bool notificationSoundsEnabled READ notificationSoundsEnabled WRITE setNotificationSoundsEnabled NOTIFY notificationSoundsEnabledChanged) Q_PROPERTY(bool notificationSoundsEnabled READ notificationSoundsEnabled WRITE setNotificationSoundsEnabled NOTIFY notificationSoundsEnabledChanged)
Q_PROPERTY(bool notificationSuppressContent READ notificationSuppressContent WRITE setNotificationSuppressContent NOTIFY notificationSuppressContentChanged)
Q_PROPERTY(NotificationFeedback notificationFeedback READ notificationFeedback WRITE setNotificationFeedback NOTIFY notificationFeedbackChanged) Q_PROPERTY(NotificationFeedback notificationFeedback READ notificationFeedback WRITE setNotificationFeedback NOTIFY notificationFeedbackChanged)
Q_PROPERTY(bool notificationAlwaysShowPreview READ notificationAlwaysShowPreview WRITE setNotificationAlwaysShowPreview NOTIFY notificationAlwaysShowPreviewChanged)
Q_PROPERTY(bool storageOptimizer READ storageOptimizer WRITE setStorageOptimizer NOTIFY storageOptimizerChanged) Q_PROPERTY(bool storageOptimizer READ storageOptimizer WRITE setStorageOptimizer NOTIFY storageOptimizerChanged)
Q_PROPERTY(bool allowInlineBotLocationAccess READ allowInlineBotLocationAccess WRITE setAllowInlineBotLocationAccess NOTIFY allowInlineBotLocationAccessChanged) Q_PROPERTY(bool allowInlineBotLocationAccess READ allowInlineBotLocationAccess WRITE setAllowInlineBotLocationAccess NOTIFY allowInlineBotLocationAccessChanged)
Q_PROPERTY(int remainingInteractionHints READ remainingInteractionHints WRITE setRemainingInteractionHints NOTIFY remainingInteractionHintsChanged) Q_PROPERTY(int remainingInteractionHints READ remainingInteractionHints WRITE setRemainingInteractionHints NOTIFY remainingInteractionHintsChanged)
@ -40,6 +42,7 @@ class AppSettings : public QObject {
Q_PROPERTY(bool delayMessageRead READ delayMessageRead WRITE setDelayMessageRead NOTIFY delayMessageReadChanged) Q_PROPERTY(bool delayMessageRead READ delayMessageRead WRITE setDelayMessageRead NOTIFY delayMessageReadChanged)
Q_PROPERTY(bool focusTextAreaOnChatOpen READ getFocusTextAreaOnChatOpen WRITE setFocusTextAreaOnChatOpen NOTIFY focusTextAreaOnChatOpenChanged) Q_PROPERTY(bool focusTextAreaOnChatOpen READ getFocusTextAreaOnChatOpen WRITE setFocusTextAreaOnChatOpen NOTIFY focusTextAreaOnChatOpenChanged)
Q_PROPERTY(SponsoredMess sponsoredMess READ getSponsoredMess WRITE setSponsoredMess NOTIFY sponsoredMessChanged) Q_PROPERTY(SponsoredMess sponsoredMess READ getSponsoredMess WRITE setSponsoredMess NOTIFY sponsoredMessChanged)
Q_PROPERTY(bool highlightUnreadConversations READ highlightUnreadConversations WRITE setHighlightUnreadConversations NOTIFY highlightUnreadConversationsChanged)
public: public:
enum SponsoredMess { enum SponsoredMess {
@ -83,9 +86,15 @@ public:
bool notificationSoundsEnabled() const; bool notificationSoundsEnabled() const;
void setNotificationSoundsEnabled(bool enable); void setNotificationSoundsEnabled(bool enable);
bool notificationSuppressContent() const;
void setNotificationSuppressContent(bool enable);
NotificationFeedback notificationFeedback() const; NotificationFeedback notificationFeedback() const;
void setNotificationFeedback(NotificationFeedback feedback); void setNotificationFeedback(NotificationFeedback feedback);
bool notificationAlwaysShowPreview() const;
void setNotificationAlwaysShowPreview(bool enable);
bool storageOptimizer() const; bool storageOptimizer() const;
void setStorageOptimizer(bool enable); void setStorageOptimizer(bool enable);
@ -107,6 +116,9 @@ public:
SponsoredMess getSponsoredMess() const; SponsoredMess getSponsoredMess() const;
void setSponsoredMess(SponsoredMess sponsoredMess); void setSponsoredMess(SponsoredMess sponsoredMess);
bool highlightUnreadConversations() const;
void setHighlightUnreadConversations(bool enable);
signals: signals:
void sendByEnterChanged(); void sendByEnterChanged();
void focusTextAreaAfterSendChanged(); void focusTextAreaAfterSendChanged();
@ -116,7 +128,9 @@ signals:
void animateStickersChanged(); void animateStickersChanged();
void notificationTurnsDisplayOnChanged(); void notificationTurnsDisplayOnChanged();
void notificationSoundsEnabledChanged(); void notificationSoundsEnabledChanged();
void notificationSuppressContentChanged();
void notificationFeedbackChanged(); void notificationFeedbackChanged();
void notificationAlwaysShowPreviewChanged();
void storageOptimizerChanged(); void storageOptimizerChanged();
void allowInlineBotLocationAccessChanged(); void allowInlineBotLocationAccessChanged();
void remainingInteractionHintsChanged(); void remainingInteractionHintsChanged();
@ -124,6 +138,7 @@ signals:
void delayMessageReadChanged(); void delayMessageReadChanged();
void focusTextAreaOnChatOpenChanged(); void focusTextAreaOnChatOpenChanged();
void sponsoredMessChanged(); void sponsoredMessChanged();
void highlightUnreadConversationsChanged();
private: private:
QSettings settings; QSettings settings;

View file

@ -68,7 +68,7 @@ QVariant ContactsModel::data(const QModelIndex &index, int role) const
case ContactRole::RoleDisplay: return requestedContact; case ContactRole::RoleDisplay: return requestedContact;
case ContactRole::RoleTitle: return QString(requestedContact.value("first_name").toString() + " " + requestedContact.value("last_name").toString()).trimmed(); case ContactRole::RoleTitle: return QString(requestedContact.value("first_name").toString() + " " + requestedContact.value("last_name").toString()).trimmed();
case ContactRole::RoleUserId: return requestedContact.value("id"); case ContactRole::RoleUserId: return requestedContact.value("id");
case ContactRole::RoleUsername: return requestedContact.value("username"); case ContactRole::RoleUsername: return requestedContact.value("usernames").toMap().value("editable_username").toString();
case ContactRole::RolePhotoSmall: return requestedContact.value("profile_photo").toMap().value("small"); case ContactRole::RolePhotoSmall: return requestedContact.value("profile_photo").toMap().value("small");
case ContactRole::RoleUserStatus: return requestedContact.value("status").toMap().value("@type"); case ContactRole::RoleUserStatus: return requestedContact.value("status").toMap().value("@type");
case ContactRole::RoleUserLastOnline: return requestedContact.value("status").toMap().value("was_online"); case ContactRole::RoleUserLastOnline: return requestedContact.value("status").toMap().value("was_online");

View file

@ -341,8 +341,18 @@ void NotificationManager::publishNotification(const NotificationGroup *notificat
QString notificationBody; QString notificationBody;
const QVariantMap senderInformation = messageMap.value(SENDER_ID).toMap(); const QVariantMap senderInformation = messageMap.value(SENDER_ID).toMap();
if (notificationGroup->totalCount == 1 && !messageMap.isEmpty()) { bool outputMessageCount = notificationGroup->totalCount > 1;
bool messageIsEmpty = messageMap.isEmpty();
if (outputMessageCount || messageIsEmpty) {
// Either we have more than one notification or we have no content to display
LOG("Group" << notificationGroup->notificationGroupId << "has" << notificationGroup->totalCount << "notifications");
notificationBody = tr("%Ln unread messages", "", notificationGroup->totalCount);
}
if ((!outputMessageCount || appSettings->notificationAlwaysShowPreview()) && !messageIsEmpty) {
LOG("Group" << notificationGroup->notificationGroupId << "has 1 notification"); LOG("Group" << notificationGroup->notificationGroupId << "has 1 notification");
if (outputMessageCount) {
notificationBody += "; ";
}
if (chatInformation && (chatInformation->type == TDLibWrapper::ChatTypeBasicGroup || if (chatInformation && (chatInformation->type == TDLibWrapper::ChatTypeBasicGroup ||
(chatInformation->type == TDLibWrapper::ChatTypeSupergroup && !chatInformation->isChannel))) { (chatInformation->type == TDLibWrapper::ChatTypeSupergroup && !chatInformation->isChannel))) {
// Add author // Add author
@ -352,15 +362,9 @@ void NotificationManager::publishNotification(const NotificationGroup *notificat
} else { } else {
fullName = FernschreiberUtils::getUserName(tdLibWrapper->getUserInformation(senderInformation.value(USER_ID).toString())); fullName = FernschreiberUtils::getUserName(tdLibWrapper->getUserInformation(senderInformation.value(USER_ID).toString()));
} }
notificationBody += fullName.trimmed() + ": ";
notificationBody = notificationBody + fullName.trimmed() + ": ";
} }
notificationBody += FernschreiberUtils::getMessageShortText(tdLibWrapper, messageMap.value(CONTENT).toMap(), (chatInformation ? chatInformation->isChannel : false), tdLibWrapper->getUserInformation().value(ID).toLongLong(), senderInformation ); notificationBody += FernschreiberUtils::getMessageShortText(tdLibWrapper, messageMap.value(CONTENT).toMap(), (chatInformation ? chatInformation->isChannel : false), tdLibWrapper->getUserInformation().value(ID).toLongLong(), senderInformation );
nemoNotification->setBody(notificationBody);
} else {
// Either we have more than one notification or we have no content to display
LOG("Group" << notificationGroup->notificationGroupId << "has" << notificationGroup->totalCount << "notifications");
notificationBody = tr("%Ln unread messages", "", notificationGroup->totalCount);
} }
const QString summary(chatInformation ? chatInformation->title : QString()); const QString summary(chatInformation ? chatInformation->title : QString());
@ -377,7 +381,11 @@ void NotificationManager::publishNotification(const NotificationGroup *notificat
nemoNotification->setHintValue(HINT_VISIBILITY, QString()); nemoNotification->setHintValue(HINT_VISIBILITY, QString());
nemoNotification->setUrgency(Notification::Low); nemoNotification->setUrgency(Notification::Low);
} else { } else {
if (!appSettings->notificationSuppressContent()) {
nemoNotification->setPreviewBody(notificationBody); nemoNotification->setPreviewBody(notificationBody);
} else {
nemoNotification->setPreviewBody(tr("%Ln unread messages", "", notificationGroup->totalCount));
}
nemoNotification->setPreviewSummary(summary); nemoNotification->setPreviewSummary(summary);
nemoNotification->setHintValue(HINT_SUPPRESS_SOUND, !appSettings->notificationSoundsEnabled()); nemoNotification->setHintValue(HINT_SUPPRESS_SOUND, !appSettings->notificationSoundsEnabled());
nemoNotification->setHintValue(HINT_DISPLAY_ON, appSettings->notificationTurnsDisplayOn()); nemoNotification->setHintValue(HINT_DISPLAY_ON, appSettings->notificationTurnsDisplayOn());

View file

@ -60,6 +60,11 @@ namespace {
const QString CONTENT("content"); const QString CONTENT("content");
const QString NEW_CONTENT("new_content"); const QString NEW_CONTENT("new_content");
const QString SETS("sets"); const QString SETS("sets");
const QString EMOJIS("emojis");
const QString REPLY_TO("reply_to");
const QString REPLY_IN_CHAT_ID("reply_in_chat_id");
const QString REPLY_TO_MESSAGE_ID("reply_to_message_id");
const QString DRAFT_MESSAGE("draft_message");
const QString _TYPE("@type"); const QString _TYPE("@type");
const QString _EXTRA("@extra"); const QString _EXTRA("@extra");
@ -70,8 +75,11 @@ namespace {
const QString TYPE_MESSAGE("message"); const QString TYPE_MESSAGE("message");
const QString TYPE_STICKER("sticker"); const QString TYPE_STICKER("sticker");
const QString TYPE_MESSAGE_STICKER("messageSticker"); const QString TYPE_MESSAGE_STICKER("messageSticker");
const QString TYPE_MESSAGE_REPLY_TO_MESSAGE("messageReplyToMessage");
const QString TYPE_MESSAGE_ANIMATED_EMOJI("messageAnimatedEmoji"); const QString TYPE_MESSAGE_ANIMATED_EMOJI("messageAnimatedEmoji");
const QString TYPE_ANIMATED_EMOJI("animatedEmoji"); const QString TYPE_ANIMATED_EMOJI("animatedEmoji");
const QString TYPE_INPUT_MESSAGE_REPLY_TO_MESSAGE("inputMessageReplyToMessage");
const QString TYPE_DRAFT_MESSAGE("draftMessage");
} }
static QString getChatPositionOrder(const QVariantMap &position) static QString getChatPositionOrder(const QVariantMap &position)
@ -119,7 +127,8 @@ TDLibReceiver::TDLibReceiver(void *tdLibClient, QObject *parent) : QThread(paren
handlers.insert("updateSupergroup", &TDLibReceiver::processUpdateSuperGroup); handlers.insert("updateSupergroup", &TDLibReceiver::processUpdateSuperGroup);
handlers.insert("updateChatOnlineMemberCount", &TDLibReceiver::processChatOnlineMemberCountUpdated); handlers.insert("updateChatOnlineMemberCount", &TDLibReceiver::processChatOnlineMemberCountUpdated);
handlers.insert("messages", &TDLibReceiver::processMessages); handlers.insert("messages", &TDLibReceiver::processMessages);
handlers.insert("sponsoredMessage", &TDLibReceiver::processSponsoredMessage); handlers.insert("sponsoredMessage", &TDLibReceiver::processSponsoredMessage); // TdLib <= 1.8.7
handlers.insert("sponsoredMessages", &TDLibReceiver::processSponsoredMessages); // TdLib >= 1.8.8
handlers.insert("updateNewMessage", &TDLibReceiver::processUpdateNewMessage); handlers.insert("updateNewMessage", &TDLibReceiver::processUpdateNewMessage);
handlers.insert("message", &TDLibReceiver::processMessage); handlers.insert("message", &TDLibReceiver::processMessage);
handlers.insert("messageLinkInfo", &TDLibReceiver::processMessageLinkInfo); handlers.insert("messageLinkInfo", &TDLibReceiver::processMessageLinkInfo);
@ -167,6 +176,7 @@ TDLibReceiver::TDLibReceiver(void *tdLibClient, QObject *parent) : QThread(paren
handlers.insert("availableReactions", &TDLibReceiver::processAvailableReactions); handlers.insert("availableReactions", &TDLibReceiver::processAvailableReactions);
handlers.insert("updateChatUnreadMentionCount", &TDLibReceiver::processUpdateChatUnreadMentionCount); handlers.insert("updateChatUnreadMentionCount", &TDLibReceiver::processUpdateChatUnreadMentionCount);
handlers.insert("updateChatUnreadReactionCount", &TDLibReceiver::processUpdateChatUnreadReactionCount); handlers.insert("updateChatUnreadReactionCount", &TDLibReceiver::processUpdateChatUnreadReactionCount);
handlers.insert("updateActiveEmojiReactions", &TDLibReceiver::processUpdateActiveEmojiReactions);
} }
void TDLibReceiver::setActive(bool active) void TDLibReceiver::setActive(bool active)
@ -382,11 +392,24 @@ void TDLibReceiver::processMessages(const QVariantMap &receivedInformation)
void TDLibReceiver::processSponsoredMessage(const QVariantMap &receivedInformation) void TDLibReceiver::processSponsoredMessage(const QVariantMap &receivedInformation)
{ {
// TdLib <= 1.8.7
const qlonglong chatId = receivedInformation.value(_EXTRA).toLongLong(); // See TDLibWrapper::getChatSponsoredMessage const qlonglong chatId = receivedInformation.value(_EXTRA).toLongLong(); // See TDLibWrapper::getChatSponsoredMessage
LOG("Received sponsored message for chat" << chatId); LOG("Received sponsored message for chat" << chatId);
emit sponsoredMessageReceived(chatId, receivedInformation); emit sponsoredMessageReceived(chatId, receivedInformation);
} }
void TDLibReceiver::processSponsoredMessages(const QVariantMap &receivedInformation)
{
// TdLib >= 1.8.8
const qlonglong chatId = receivedInformation.value(_EXTRA).toLongLong(); // See TDLibWrapper::getChatSponsoredMessage
const QVariantList messages(receivedInformation.value(MESSAGES).toList());
LOG("Received" << messages.count() << "sponsored messages for chat" << chatId);
QListIterator<QVariant> it(messages);
while (it.hasNext()) {
emit sponsoredMessageReceived(chatId, it.next().toMap());
}
}
void TDLibReceiver::processUpdateNewMessage(const QVariantMap &receivedInformation) void TDLibReceiver::processUpdateNewMessage(const QVariantMap &receivedInformation)
{ {
const QVariantMap message = receivedInformation.value(MESSAGE).toMap(); const QVariantMap message = receivedInformation.value(MESSAGE).toMap();
@ -400,7 +423,7 @@ void TDLibReceiver::processMessage(const QVariantMap &receivedInformation)
const qlonglong chatId = receivedInformation.value(CHAT_ID).toLongLong(); const qlonglong chatId = receivedInformation.value(CHAT_ID).toLongLong();
const qlonglong messageId = receivedInformation.value(ID).toLongLong(); const qlonglong messageId = receivedInformation.value(ID).toLongLong();
LOG("Received message " << chatId << messageId); LOG("Received message " << chatId << messageId);
emit messageInformation(chatId, messageId, receivedInformation); emit messageInformation(chatId, messageId, cleanupMap(receivedInformation));
} }
void TDLibReceiver::processMessageLinkInfo(const QVariantMap &receivedInformation) void TDLibReceiver::processMessageLinkInfo(const QVariantMap &receivedInformation)
@ -425,7 +448,7 @@ void TDLibReceiver::processMessageSendSucceeded(const QVariantMap &receivedInfor
const QVariantMap message = receivedInformation.value(MESSAGE).toMap(); const QVariantMap message = receivedInformation.value(MESSAGE).toMap();
const qlonglong messageId = message.value(ID).toLongLong(); const qlonglong messageId = message.value(ID).toLongLong();
LOG("Message send succeeded" << messageId << oldMessageId); LOG("Message send succeeded" << messageId << oldMessageId);
emit messageSendSucceeded(messageId, oldMessageId, message); emit messageSendSucceeded(messageId, oldMessageId, cleanupMap(message));
} }
void TDLibReceiver::processUpdateActiveNotifications(const QVariantMap &receivedInformation) void TDLibReceiver::processUpdateActiveNotifications(const QVariantMap &receivedInformation)
@ -652,7 +675,7 @@ void TDLibReceiver::processUpdateChatIsMarkedAsUnread(const QVariantMap &receive
void TDLibReceiver::processUpdateChatDraftMessage(const QVariantMap &receivedInformation) void TDLibReceiver::processUpdateChatDraftMessage(const QVariantMap &receivedInformation)
{ {
LOG("Draft message was updated"); LOG("Draft message was updated");
emit chatDraftMessageUpdated(receivedInformation.value(CHAT_ID).toLongLong(), receivedInformation.value("draft_message").toMap(), findChatPositionOrder(receivedInformation.value(POSITIONS).toList())); emit chatDraftMessageUpdated(receivedInformation.value(CHAT_ID).toLongLong(), cleanupMap(receivedInformation.value(DRAFT_MESSAGE).toMap()), findChatPositionOrder(receivedInformation.value(POSITIONS).toList()));
} }
void TDLibReceiver::processInlineQueryResults(const QVariantMap &receivedInformation) void TDLibReceiver::processInlineQueryResults(const QVariantMap &receivedInformation)
@ -718,6 +741,13 @@ void TDLibReceiver::processUpdateChatUnreadReactionCount(const QVariantMap &rece
emit chatUnreadReactionCountUpdated(chatId, unreadReactionCount); emit chatUnreadReactionCountUpdated(chatId, unreadReactionCount);
} }
void TDLibReceiver::processUpdateActiveEmojiReactions(const QVariantMap &receivedInformation)
{
// updateActiveEmojiReactions was introduced between 1.8.5 and 1.8.6
// See https://github.com/tdlib/td/commit/d29d367
emit activeEmojiReactionsUpdated(receivedInformation.value(EMOJIS).toStringList());
}
// Recursively removes (some) unused entries from QVariantMaps to reduce // Recursively removes (some) unused entries from QVariantMaps to reduce
// memory usage. QStrings allocated by QVariantMaps are the top consumers // memory usage. QStrings allocated by QVariantMaps are the top consumers
// of memory. The biggest saving is achieved by removing "outline" from // of memory. The biggest saving is achieved by removing "outline" from
@ -747,17 +777,65 @@ const QVariantMap TDLibReceiver::cleanupMap(const QVariantMap& map, bool *update
return animated_emoji; return animated_emoji;
} }
} else if (type == TYPE_MESSAGE) { } else if (type == TYPE_MESSAGE) {
bool cleaned = false;
const QVariantMap content(cleanupMap(map.value(CONTENT).toMap(), &cleaned));
if (cleaned) {
QVariantMap message(map); QVariantMap message(map);
bool messageChanged = false;
const QVariantMap content(cleanupMap(map.value(CONTENT).toMap(), &messageChanged));
if (messageChanged) {
message.remove(CONTENT); message.remove(CONTENT);
message.insert(CONTENT, content); message.insert(CONTENT, content);
}
if (map.contains(REPLY_TO)) {
// In TdLib 1.8.15 reply_to_message_id and reply_in_chat_id attributes
// had been replaced with reply_to structure, e.g:
//
// "reply_to": {
// "@type": "messageReplyToMessage",
// "chat_id": -1001234567890,
// "is_quote_manual": false,
// "message_id": 234567890,
// "origin_send_date": 0
// }
//
QVariantMap reply_to(message.value(REPLY_TO).toMap());
if (reply_to.value(_TYPE).toString() == TYPE_MESSAGE_REPLY_TO_MESSAGE) {
if (reply_to.contains(MESSAGE_ID) &&
!message.contains(REPLY_TO_MESSAGE_ID)) {
message.insert(REPLY_TO_MESSAGE_ID, reply_to.value(MESSAGE_ID));
}
if (reply_to.contains(CHAT_ID) &&
!message.contains(REPLY_IN_CHAT_ID)) {
message.insert(REPLY_IN_CHAT_ID, reply_to.value(CHAT_ID));
}
reply_to.remove(_TYPE);
reply_to.insert(_TYPE, TYPE_MESSAGE_REPLY_TO_MESSAGE);
message.insert(REPLY_TO, reply_to);
messageChanged = true;
}
}
if (messageChanged) {
message.remove(_TYPE); message.remove(_TYPE);
message.insert(_TYPE, TYPE_MESSAGE); // Replace with a shared value message.insert(_TYPE, TYPE_MESSAGE); // Replace with a shared value
if (updated) *updated = true; if (updated) *updated = true;
return message; return message;
} }
} else if (type == TYPE_DRAFT_MESSAGE) {
QVariantMap draftMessage(map);
QVariantMap reply_to(draftMessage.value(REPLY_TO).toMap());
// In TdLib 1.8.21 reply_to_message_id has been replaced with reply_to
if (reply_to.value(_TYPE).toString() == TYPE_INPUT_MESSAGE_REPLY_TO_MESSAGE) {
if (reply_to.contains(MESSAGE_ID) &&
!draftMessage.contains(REPLY_TO_MESSAGE_ID)) {
// reply_to_message_id is what QML (still) expects
draftMessage.insert(REPLY_TO_MESSAGE_ID, reply_to.value(MESSAGE_ID));
}
reply_to.remove(_TYPE);
reply_to.insert(_TYPE, TYPE_INPUT_MESSAGE_REPLY_TO_MESSAGE); // Shared value
draftMessage.insert(REPLY_TO, reply_to);
draftMessage.remove(_TYPE);
draftMessage.insert(_TYPE, DRAFT_MESSAGE); // Shared value
if (updated) *updated = true;
return draftMessage;
}
} else if (type == TYPE_MESSAGE_STICKER) { } else if (type == TYPE_MESSAGE_STICKER) {
bool cleaned = false; bool cleaned = false;
const QVariantMap content(cleanupMap(map.value(CONTENT).toMap(), &cleaned)); const QVariantMap content(cleanupMap(map.value(CONTENT).toMap(), &cleaned));

View file

@ -105,6 +105,7 @@ signals:
void availableReactionsReceived(qlonglong messageId, const QStringList &reactions); void availableReactionsReceived(qlonglong messageId, const QStringList &reactions);
void chatUnreadMentionCountUpdated(qlonglong chatId, int unreadMentionCount); void chatUnreadMentionCountUpdated(qlonglong chatId, int unreadMentionCount);
void chatUnreadReactionCountUpdated(qlonglong chatId, int unreadReactionCount); void chatUnreadReactionCountUpdated(qlonglong chatId, int unreadReactionCount);
void activeEmojiReactionsUpdated(const QStringList& emojis);
private: private:
typedef void (TDLibReceiver::*Handler)(const QVariantMap &); typedef void (TDLibReceiver::*Handler)(const QVariantMap &);
@ -139,6 +140,7 @@ private:
void processChatOnlineMemberCountUpdated(const QVariantMap &receivedInformation); void processChatOnlineMemberCountUpdated(const QVariantMap &receivedInformation);
void processMessages(const QVariantMap &receivedInformation); void processMessages(const QVariantMap &receivedInformation);
void processSponsoredMessage(const QVariantMap &receivedInformation); void processSponsoredMessage(const QVariantMap &receivedInformation);
void processSponsoredMessages(const QVariantMap &receivedInformation);
void processUpdateNewMessage(const QVariantMap &receivedInformation); void processUpdateNewMessage(const QVariantMap &receivedInformation);
void processMessage(const QVariantMap &receivedInformation); void processMessage(const QVariantMap &receivedInformation);
void processMessageLinkInfo(const QVariantMap &receivedInformation); void processMessageLinkInfo(const QVariantMap &receivedInformation);
@ -186,6 +188,7 @@ private:
void processAvailableReactions(const QVariantMap &receivedInformation); void processAvailableReactions(const QVariantMap &receivedInformation);
void processUpdateChatUnreadMentionCount(const QVariantMap &receivedInformation); void processUpdateChatUnreadMentionCount(const QVariantMap &receivedInformation);
void processUpdateChatUnreadReactionCount(const QVariantMap &receivedInformation); void processUpdateChatUnreadReactionCount(const QVariantMap &receivedInformation);
void processUpdateActiveEmojiReactions(const QVariantMap &receivedInformation);
}; };
#endif // TDLIBRECEIVER_H #endif // TDLIBRECEIVER_H

View file

@ -36,6 +36,9 @@
#define DEBUG_MODULE TDLibWrapper #define DEBUG_MODULE TDLibWrapper
#include "debuglog.h" #include "debuglog.h"
#define VERSION_NUMBER(x,y,z) \
((((x) & 0x3ff) << 20) | (((y) & 0x3ff) << 10) | ((z) & 0x3ff))
namespace { namespace {
const QString STATUS("status"); const QString STATUS("status");
const QString ID("id"); const QString ID("id");
@ -48,23 +51,35 @@ namespace {
const QString THREAD_ID("thread_id"); const QString THREAD_ID("thread_id");
const QString VALUE("value"); const QString VALUE("value");
const QString CHAT_LIST_TYPE("chat_list_type"); const QString CHAT_LIST_TYPE("chat_list_type");
const QString REPLY_TO_MESSAGE_ID("reply_to_message_id");
const QString REPLY_TO("reply_to");
const QString _TYPE("@type"); const QString _TYPE("@type");
const QString _EXTRA("@extra"); const QString _EXTRA("@extra");
const QString CHAT_LIST_MAIN("chatListMain"); const QString CHAT_LIST_MAIN("chatListMain");
const QString CHAT_AVAILABLE_REACTIONS("available_reactions");
const QString CHAT_AVAILABLE_REACTIONS_ALL("chatAvailableReactionsAll");
const QString CHAT_AVAILABLE_REACTIONS_SOME("chatAvailableReactionsSome");
const QString REACTIONS("reactions");
const QString REACTION_TYPE("reaction_type");
const QString REACTION_TYPE_EMOJI("reactionTypeEmoji");
const QString EMOJI("emoji");
const QString TYPE_MESSAGE_REPLY_TO_MESSAGE("messageReplyToMessage");
const QString TYPE_INPUT_MESSAGE_REPLY_TO_MESSAGE("inputMessageReplyToMessage");
} }
TDLibWrapper::TDLibWrapper(AppSettings *appSettings, MceInterface *mceInterface, QObject *parent) TDLibWrapper::TDLibWrapper(AppSettings *settings, MceInterface *mce, QObject *parent)
: QObject(parent) : QObject(parent)
, tdLibClient(td_json_client_create())
, manager(new QNetworkAccessManager(this)) , manager(new QNetworkAccessManager(this))
, networkConfigurationManager(new QNetworkConfigurationManager(this)) , networkConfigurationManager(new QNetworkConfigurationManager(this))
, appSettings(settings)
, mceInterface(mce)
, authorizationState(AuthorizationState::Closed)
, versionNumber(0)
, joinChatRequested(false) , joinChatRequested(false)
, isLoggingOut(false)
{ {
LOG("Initializing TD Lib..."); LOG("Initializing TD Lib...");
this->appSettings = appSettings;
this->mceInterface = mceInterface;
this->tdLibClient = td_json_client_create();
this->authorizationState = AuthorizationState::Closed;
this->isLoggingOut = false;
initializeTDLibReceiver(); initializeTDLibReceiver();
@ -174,6 +189,7 @@ void TDLibWrapper::initializeTDLibReceiver() {
connect(this->tdLibReceiver, SIGNAL(availableReactionsReceived(qlonglong, QStringList)), this, SIGNAL(availableReactionsReceived(qlonglong, QStringList))); connect(this->tdLibReceiver, SIGNAL(availableReactionsReceived(qlonglong, QStringList)), this, SIGNAL(availableReactionsReceived(qlonglong, QStringList)));
connect(this->tdLibReceiver, SIGNAL(chatUnreadMentionCountUpdated(qlonglong, int)), this, SIGNAL(chatUnreadMentionCountUpdated(qlonglong, int))); connect(this->tdLibReceiver, SIGNAL(chatUnreadMentionCountUpdated(qlonglong, int)), this, SIGNAL(chatUnreadMentionCountUpdated(qlonglong, int)));
connect(this->tdLibReceiver, SIGNAL(chatUnreadReactionCountUpdated(qlonglong, int)), this, SIGNAL(chatUnreadReactionCountUpdated(qlonglong, int))); connect(this->tdLibReceiver, SIGNAL(chatUnreadReactionCountUpdated(qlonglong, int)), this, SIGNAL(chatUnreadReactionCountUpdated(qlonglong, int)));
connect(this->tdLibReceiver, SIGNAL(activeEmojiReactionsUpdated(QStringList)), this, SLOT(handleActiveEmojiReactionsUpdated(QStringList)));
this->tdLibReceiver->start(); this->tdLibReceiver->start();
} }
@ -192,7 +208,7 @@ void TDLibWrapper::sendRequest(const QVariantMap &requestObject)
QString TDLibWrapper::getVersion() QString TDLibWrapper::getVersion()
{ {
return this->version; return this->versionString;
} }
TDLibWrapper::AuthorizationState TDLibWrapper::getAuthorizationState() TDLibWrapper::AuthorizationState TDLibWrapper::getAuthorizationState()
@ -255,7 +271,7 @@ void TDLibWrapper::logout()
{ {
LOG("Logging out"); LOG("Logging out");
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert("@type", "logOut"); requestObject.insert(_TYPE, "logOut");
this->sendRequest(requestObject); this->sendRequest(requestObject);
this->isLoggingOut = true; this->isLoggingOut = true;
@ -389,15 +405,33 @@ static bool compareReplacements(const QVariant &replacement1, const QVariant &re
} }
} }
void TDLibWrapper::sendTextMessage(const QString &chatId, const QString &message, const QString &replyToMessageId) QVariantMap TDLibWrapper::newSendMessageRequest(qlonglong chatId, qlonglong replyToMessageId)
{
QVariantMap request;
request.insert(_TYPE, "sendMessage");
request.insert(CHAT_ID, chatId);
if (replyToMessageId) {
if (versionNumber > VERSION_NUMBER(1,8,14)) {
QVariantMap replyTo;
if (versionNumber > VERSION_NUMBER(1,8,20)) {
replyTo.insert(_TYPE, TYPE_INPUT_MESSAGE_REPLY_TO_MESSAGE);
} else {
replyTo.insert(_TYPE, TYPE_MESSAGE_REPLY_TO_MESSAGE);
}
replyTo.insert(CHAT_ID, chatId);
replyTo.insert(MESSAGE_ID, replyToMessageId);
request.insert(REPLY_TO, replyTo);
} else {
request.insert(REPLY_TO_MESSAGE_ID, replyToMessageId);
}
}
return request;
}
void TDLibWrapper::sendTextMessage(qlonglong chatId, const QString &message, qlonglong replyToMessageId)
{ {
LOG("Sending text message" << chatId << message << replyToMessageId); LOG("Sending text message" << chatId << message << replyToMessageId);
QVariantMap requestObject; QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId));
requestObject.insert(_TYPE, "sendMessage");
requestObject.insert(CHAT_ID, chatId);
if (replyToMessageId != "0") {
requestObject.insert("reply_to_message_id", replyToMessageId);
}
QVariantMap inputMessageContent; QVariantMap inputMessageContent;
inputMessageContent.insert(_TYPE, "inputMessageText"); inputMessageContent.insert(_TYPE, "inputMessageText");
@ -436,7 +470,7 @@ void TDLibWrapper::sendTextMessage(const QString &chatId, const QString &message
QVariantMap entityType; QVariantMap entityType;
entityType.insert(_TYPE, "textEntityTypeMentionName"); entityType.insert(_TYPE, "textEntityTypeMentionName");
entityType.insert("user_id", nextReplacement.value("userId").toString()); entityType.insert("user_id", nextReplacement.value("userId").toString());
entity.insert("type", entityType); entity.insert(TYPE, entityType);
entities.append(entity); entities.append(entity);
offsetCorrection += replacementLength - replacementPlainText.length(); offsetCorrection += replacementLength - replacementPlainText.length();
} }
@ -450,17 +484,13 @@ void TDLibWrapper::sendTextMessage(const QString &chatId, const QString &message
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::sendPhotoMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId) void TDLibWrapper::sendPhotoMessage(qlonglong chatId, const QString &filePath, const QString &message, qlonglong replyToMessageId)
{ {
LOG("Sending photo message" << chatId << filePath << message << replyToMessageId); LOG("Sending photo message" << chatId << filePath << message << replyToMessageId);
QVariantMap requestObject; QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId));
requestObject.insert(_TYPE, "sendMessage");
requestObject.insert(CHAT_ID, chatId);
if (replyToMessageId != "0") {
requestObject.insert("reply_to_message_id", replyToMessageId);
}
QVariantMap inputMessageContent; QVariantMap inputMessageContent;
inputMessageContent.insert(_TYPE, "inputMessagePhoto"); inputMessageContent.insert(_TYPE, "inputMessagePhoto");
QVariantMap formattedText; QVariantMap formattedText;
formattedText.insert("text", message); formattedText.insert("text", message);
formattedText.insert(_TYPE, "formattedText"); formattedText.insert(_TYPE, "formattedText");
@ -474,17 +504,13 @@ void TDLibWrapper::sendPhotoMessage(const QString &chatId, const QString &filePa
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::sendVideoMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId) void TDLibWrapper::sendVideoMessage(qlonglong chatId, const QString &filePath, const QString &message, qlonglong replyToMessageId)
{ {
LOG("Sending video message" << chatId << filePath << message << replyToMessageId); LOG("Sending video message" << chatId << filePath << message << replyToMessageId);
QVariantMap requestObject; QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId));
requestObject.insert(_TYPE, "sendMessage");
requestObject.insert(CHAT_ID, chatId);
if (replyToMessageId != "0") {
requestObject.insert("reply_to_message_id", replyToMessageId);
}
QVariantMap inputMessageContent; QVariantMap inputMessageContent;
inputMessageContent.insert(_TYPE, "inputMessageVideo"); inputMessageContent.insert(_TYPE, "inputMessageVideo");
QVariantMap formattedText; QVariantMap formattedText;
formattedText.insert("text", message); formattedText.insert("text", message);
formattedText.insert(_TYPE, "formattedText"); formattedText.insert(_TYPE, "formattedText");
@ -498,17 +524,13 @@ void TDLibWrapper::sendVideoMessage(const QString &chatId, const QString &filePa
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::sendDocumentMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId) void TDLibWrapper::sendDocumentMessage(qlonglong chatId, const QString &filePath, const QString &message, qlonglong replyToMessageId)
{ {
LOG("Sending document message" << chatId << filePath << message << replyToMessageId); LOG("Sending document message" << chatId << filePath << message << replyToMessageId);
QVariantMap requestObject; QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId));
requestObject.insert(_TYPE, "sendMessage");
requestObject.insert(CHAT_ID, chatId);
if (replyToMessageId != "0") {
requestObject.insert("reply_to_message_id", replyToMessageId);
}
QVariantMap inputMessageContent; QVariantMap inputMessageContent;
inputMessageContent.insert(_TYPE, "inputMessageDocument"); inputMessageContent.insert(_TYPE, "inputMessageDocument");
QVariantMap formattedText; QVariantMap formattedText;
formattedText.insert("text", message); formattedText.insert("text", message);
formattedText.insert(_TYPE, "formattedText"); formattedText.insert(_TYPE, "formattedText");
@ -522,17 +544,13 @@ void TDLibWrapper::sendDocumentMessage(const QString &chatId, const QString &fil
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::sendVoiceNoteMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId) void TDLibWrapper::sendVoiceNoteMessage(qlonglong chatId, const QString &filePath, const QString &message, qlonglong replyToMessageId)
{ {
LOG("Sending voice note message" << chatId << filePath << message << replyToMessageId); LOG("Sending voice note message" << chatId << filePath << message << replyToMessageId);
QVariantMap requestObject; QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId));
requestObject.insert(_TYPE, "sendMessage");
requestObject.insert(CHAT_ID, chatId);
if (replyToMessageId != "0") {
requestObject.insert("reply_to_message_id", replyToMessageId);
}
QVariantMap inputMessageContent; QVariantMap inputMessageContent;
inputMessageContent.insert(_TYPE, "inputMessageVoiceNote"); inputMessageContent.insert(_TYPE, "inputMessageVoiceNote");
QVariantMap formattedText; QVariantMap formattedText;
formattedText.insert("text", message); formattedText.insert("text", message);
formattedText.insert(_TYPE, "formattedText"); formattedText.insert(_TYPE, "formattedText");
@ -546,24 +564,19 @@ void TDLibWrapper::sendVoiceNoteMessage(const QString &chatId, const QString &fi
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::sendLocationMessage(const QString &chatId, double latitude, double longitude, double horizontalAccuracy, const QString &replyToMessageId) void TDLibWrapper::sendLocationMessage(qlonglong chatId, double latitude, double longitude, double horizontalAccuracy, qlonglong replyToMessageId)
{ {
LOG("Sending location message" << chatId << latitude << longitude << horizontalAccuracy << replyToMessageId); LOG("Sending location message" << chatId << latitude << longitude << horizontalAccuracy << replyToMessageId);
QVariantMap requestObject; QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId));
requestObject.insert(_TYPE, "sendMessage");
requestObject.insert(CHAT_ID, chatId);
if (replyToMessageId != "0") {
requestObject.insert("reply_to_message_id", replyToMessageId);
}
QVariantMap inputMessageContent; QVariantMap inputMessageContent;
inputMessageContent.insert(_TYPE, "inputMessageLocation"); inputMessageContent.insert(_TYPE, "inputMessageLocation");
QVariantMap location; QVariantMap location;
location.insert("latitude", latitude); location.insert("latitude", latitude);
location.insert("longitude", longitude); location.insert("longitude", longitude);
location.insert("horizontal_accuracy", horizontalAccuracy); location.insert("horizontal_accuracy", horizontalAccuracy);
location.insert(_TYPE, "location"); location.insert(_TYPE, "location");
inputMessageContent.insert("location", location); inputMessageContent.insert("location", location);
inputMessageContent.insert("live_period", 0); inputMessageContent.insert("live_period", 0);
inputMessageContent.insert("heading", 0); inputMessageContent.insert("heading", 0);
inputMessageContent.insert("proximity_alert_radius", 0); inputMessageContent.insert("proximity_alert_radius", 0);
@ -572,21 +585,16 @@ void TDLibWrapper::sendLocationMessage(const QString &chatId, double latitude, d
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::sendStickerMessage(const QString &chatId, const QString &fileId, const QString &replyToMessageId) void TDLibWrapper::sendStickerMessage(qlonglong chatId, const QString &fileId, qlonglong replyToMessageId)
{ {
LOG("Sending sticker message" << chatId << fileId << replyToMessageId); LOG("Sending sticker message" << chatId << fileId << replyToMessageId);
QVariantMap requestObject; QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId));
requestObject.insert(_TYPE, "sendMessage");
requestObject.insert(CHAT_ID, chatId);
if (replyToMessageId != "0") {
requestObject.insert("reply_to_message_id", replyToMessageId);
}
QVariantMap inputMessageContent; QVariantMap inputMessageContent;
inputMessageContent.insert(_TYPE, "inputMessageSticker"); inputMessageContent.insert(_TYPE, "inputMessageSticker");
QVariantMap stickerInputFile; QVariantMap stickerInputFile;
stickerInputFile.insert(_TYPE, "inputFileRemote"); stickerInputFile.insert(_TYPE, "inputFileRemote");
stickerInputFile.insert("id", fileId); stickerInputFile.insert(ID, fileId);
inputMessageContent.insert("sticker", stickerInputFile); inputMessageContent.insert("sticker", stickerInputFile);
@ -594,15 +602,10 @@ void TDLibWrapper::sendStickerMessage(const QString &chatId, const QString &file
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::sendPollMessage(const QString &chatId, const QString &question, const QVariantList &options, bool anonymous, int correctOption, bool multiple, const QString &explanation, const QString &replyToMessageId) void TDLibWrapper::sendPollMessage(qlonglong chatId, const QString &question, const QVariantList &options, bool anonymous, int correctOption, bool multiple, const QString &explanation, qlonglong replyToMessageId)
{ {
LOG("Sending poll message" << chatId << question << replyToMessageId); LOG("Sending poll message" << chatId << question << replyToMessageId);
QVariantMap requestObject; QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId));
requestObject.insert(_TYPE, "sendMessage");
requestObject.insert(CHAT_ID, chatId);
if (replyToMessageId != "0") {
requestObject.insert("reply_to_message_id", replyToMessageId);
}
QVariantMap inputMessageContent; QVariantMap inputMessageContent;
inputMessageContent.insert(_TYPE, "inputMessagePoll"); inputMessageContent.insert(_TYPE, "inputMessagePoll");
@ -620,7 +623,7 @@ void TDLibWrapper::sendPollMessage(const QString &chatId, const QString &questio
pollType.insert("allow_multiple_answers", multiple); pollType.insert("allow_multiple_answers", multiple);
} }
inputMessageContent.insert("type", pollType); inputMessageContent.insert(TYPE, pollType);
inputMessageContent.insert("question", question); inputMessageContent.insert("question", question);
inputMessageContent.insert("options", options); inputMessageContent.insert("options", options);
inputMessageContent.insert("is_anonymous", anonymous); inputMessageContent.insert("is_anonymous", anonymous);
@ -709,7 +712,11 @@ void TDLibWrapper::getChatSponsoredMessage(qlonglong chatId)
{ {
LOG("Retrieving sponsored message" << chatId); LOG("Retrieving sponsored message" << chatId);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert(_TYPE, "getChatSponsoredMessage"); // getChatSponsoredMessage has been replaced with getChatSponsoredMessages
// between 1.8.7 and 1.8.8
// See https://github.com/tdlib/td/commit/ec1310a
requestObject.insert(_TYPE, QString((versionNumber > VERSION_NUMBER(1,8,7)) ?
"getChatSponsoredMessages" : "getChatSponsoredMessage"));
requestObject.insert(CHAT_ID, chatId); requestObject.insert(CHAT_ID, chatId);
requestObject.insert(_EXTRA, chatId); // see TDLibReceiver::processSponsoredMessage requestObject.insert(_EXTRA, chatId); // see TDLibReceiver::processSponsoredMessage
this->sendRequest(requestObject); this->sendRequest(requestObject);
@ -1171,9 +1178,18 @@ void TDLibWrapper::setChatDraftMessage(qlonglong chatId, qlonglong threadId, qlo
inputMessageContent.insert(_TYPE, "inputMessageText"); inputMessageContent.insert(_TYPE, "inputMessageText");
inputMessageContent.insert("text", formattedText); inputMessageContent.insert("text", formattedText);
draftMessage.insert(_TYPE, "draftMessage"); draftMessage.insert(_TYPE, "draftMessage");
draftMessage.insert("reply_to_message_id", replyToMessageId);
draftMessage.insert("input_message_text", inputMessageContent); draftMessage.insert("input_message_text", inputMessageContent);
if (versionNumber > VERSION_NUMBER(1,8,20)) {
QVariantMap replyTo;
replyTo.insert(_TYPE, TYPE_INPUT_MESSAGE_REPLY_TO_MESSAGE);
replyTo.insert(CHAT_ID, chatId);
replyTo.insert(MESSAGE_ID, replyToMessageId);
draftMessage.insert(REPLY_TO, replyTo);
} else {
draftMessage.insert(REPLY_TO_MESSAGE_ID, replyToMessageId);
}
requestObject.insert("draft_message", draftMessage); requestObject.insert("draft_message", draftMessage);
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
@ -1433,8 +1449,8 @@ void TDLibWrapper::getMessageAvailableReactions(qlonglong chatId, qlonglong mess
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert(_TYPE, "getMessageAvailableReactions"); requestObject.insert(_TYPE, "getMessageAvailableReactions");
requestObject.insert(_EXTRA, QString::number(messageId)); requestObject.insert(_EXTRA, QString::number(messageId));
requestObject.insert("chat_id", chatId); requestObject.insert(CHAT_ID, chatId);
requestObject.insert("message_id", messageId); requestObject.insert(MESSAGE_ID, messageId);
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
@ -1457,11 +1473,23 @@ void TDLibWrapper::setMessageReaction(qlonglong chatId, qlonglong messageId, con
{ {
LOG("Set message reaction" << chatId << messageId << reaction); LOG("Set message reaction" << chatId << messageId << reaction);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert(_TYPE, "setMessageReaction"); requestObject.insert(CHAT_ID, chatId);
requestObject.insert("chat_id", chatId); requestObject.insert(MESSAGE_ID, messageId);
requestObject.insert("message_id", messageId);
requestObject.insert("reaction", reaction);
requestObject.insert("is_big", false); requestObject.insert("is_big", false);
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, "addMessageReaction");
} else {
requestObject.insert("reaction", reaction);
requestObject.insert(_TYPE, "setMessageReaction");
}
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
@ -1494,7 +1522,7 @@ void TDLibWrapper::setNetworkType(NetworkType networkType)
break; break;
} }
requestObject.insert("type", networkTypeObject); requestObject.insert(TYPE, networkTypeObject);
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
@ -1575,6 +1603,43 @@ QVariantMap TDLibWrapper::getChat(const QString &chatId)
return this->chats.value(chatId).toMap(); return this->chats.value(chatId).toMap();
} }
QStringList TDLibWrapper::getChatReactions(const QString &chatId)
{
const QVariant available_reactions(chats.value(chatId).toMap().value(CHAT_AVAILABLE_REACTIONS));
const QVariantMap map(available_reactions.toMap());
const QString reactions_type(map.value(_TYPE).toString());
if (reactions_type == CHAT_AVAILABLE_REACTIONS_ALL) {
return activeEmojiReactions;
} else if (reactions_type == CHAT_AVAILABLE_REACTIONS_SOME) {
const QVariantList reactions(map.value(REACTIONS).toList());
const int n = reactions.count();
QStringList emojis;
// "available_reactions": {
// "@type": "chatAvailableReactionsSome",
// "reactions": [
// {
// "@type": "reactionTypeEmoji",
// "emoji": "..."
// },
emojis.reserve(n);
for (int i = 0; i < n; i++) {
const QVariantMap reaction(reactions.at(i).toMap());
if (reaction.value(_TYPE).toString() == REACTION_TYPE_EMOJI) {
const QString emoji(reaction.value(EMOJI).toString());
if (!emoji.isEmpty()) {
emojis.append(emoji);
}
}
}
return emojis;
} else if (reactions_type.isEmpty()) {
return available_reactions.toStringList();
} else {
return QStringList();
}
}
QVariantMap TDLibWrapper::getSecretChatFromCache(qlonglong secretChatId) QVariantMap TDLibWrapper::getSecretChatFromCache(qlonglong secretChatId)
{ {
return this->secretChats.value(secretChatId); return this->secretChats.value(secretChatId);
@ -1645,7 +1710,16 @@ DBusAdaptor *TDLibWrapper::getDBusAdaptor()
void TDLibWrapper::handleVersionDetected(const QString &version) void TDLibWrapper::handleVersionDetected(const QString &version)
{ {
this->version = version; this->versionString = version;
const QStringList parts(version.split('.'));
uint major, minor, release;
bool ok;
if (parts.count() >= 3 &&
(major = parts.at(0).toInt(&ok), ok) &&
(minor = parts.at(1).toInt(&ok), ok) &&
(release = parts.at(2).toInt(&ok), ok)) {
versionNumber = VERSION_NUMBER(major, minor, release);
}
emit versionDetected(version); emit versionDetected(version);
} }
@ -1758,7 +1832,7 @@ void TDLibWrapper::handleConnectionStateChanged(const QString &connectionState)
void TDLibWrapper::handleUserUpdated(const QVariantMap &userInformation) void TDLibWrapper::handleUserUpdated(const QVariantMap &userInformation)
{ {
QString updatedUserId = userInformation.value("id").toString(); QString updatedUserId = userInformation.value(ID).toString();
if (updatedUserId == this->options.value("my_id").toString()) { if (updatedUserId == this->options.value("my_id").toString()) {
LOG("Own user information updated :)"); LOG("Own user information updated :)");
this->userInformation = userInformation; this->userInformation = userInformation;
@ -1774,11 +1848,11 @@ void TDLibWrapper::handleUserStatusUpdated(const QString &userId, const QVariant
{ {
if (userId == this->options.value("my_id").toString()) { if (userId == this->options.value("my_id").toString()) {
LOG("Own user status information updated :)"); LOG("Own user status information updated :)");
this->userInformation.insert("status", userStatusInformation); this->userInformation.insert(STATUS, userStatusInformation);
} }
LOG("User status information updated:" << userId << userStatusInformation.value(_TYPE).toString()); LOG("User status information updated:" << userId << userStatusInformation.value(_TYPE).toString());
QVariantMap updatedUserInformation = this->allUsers.value(userId).toMap(); QVariantMap updatedUserInformation = this->allUsers.value(userId).toMap();
updatedUserInformation.insert("status", userStatusInformation); updatedUserInformation.insert(STATUS, userStatusInformation);
this->allUsers.insert(userId, updatedUserInformation); this->allUsers.insert(userId, updatedUserInformation);
this->allUserNames.insert(userInformation.value(USERNAME).toString(), userInformation); this->allUserNames.insert(userInformation.value(USERNAME).toString(), userInformation);
emit userUpdated(userId, updatedUserInformation); emit userUpdated(userId, updatedUserInformation);
@ -1786,12 +1860,12 @@ void TDLibWrapper::handleUserStatusUpdated(const QString &userId, const QVariant
void TDLibWrapper::handleFileUpdated(const QVariantMap &fileInformation) void TDLibWrapper::handleFileUpdated(const QVariantMap &fileInformation)
{ {
emit fileUpdated(fileInformation.value("id").toInt(), fileInformation); emit fileUpdated(fileInformation.value(ID).toInt(), fileInformation);
} }
void TDLibWrapper::handleNewChatDiscovered(const QVariantMap &chatInformation) void TDLibWrapper::handleNewChatDiscovered(const QVariantMap &chatInformation)
{ {
QString chatId = chatInformation.value("id").toString(); QString chatId = chatInformation.value(ID).toString();
this->chats.insert(chatId, chatInformation); this->chats.insert(chatId, chatInformation);
emit newChatDiscovered(chatId, chatInformation); emit newChatDiscovered(chatId, chatInformation);
} }
@ -1856,7 +1930,7 @@ void TDLibWrapper::handleStickerSets(const QVariantList &stickerSets)
QListIterator<QVariant> stickerSetIterator(stickerSets); QListIterator<QVariant> stickerSetIterator(stickerSets);
while (stickerSetIterator.hasNext()) { while (stickerSetIterator.hasNext()) {
QVariantMap stickerSet = stickerSetIterator.next().toMap(); QVariantMap stickerSet = stickerSetIterator.next().toMap();
this->getStickerSet(stickerSet.value("id").toString()); this->getStickerSet(stickerSet.value(ID).toString());
} }
emit this->stickerSetsReceived(stickerSets); emit this->stickerSetsReceived(stickerSets);
} }
@ -1988,6 +2062,13 @@ void TDLibWrapper::handleSponsoredMessage(qlonglong chatId, const QVariantMap &m
} }
} }
void TDLibWrapper::handleActiveEmojiReactionsUpdated(const QStringList& emojis)
{
if (activeEmojiReactions != emojis) {
activeEmojiReactions = emojis;
LOG(emojis.count() << "reaction(s) available");
}
}
void TDLibWrapper::handleNetworkConfigurationChanged(const QNetworkConfiguration &config) void TDLibWrapper::handleNetworkConfigurationChanged(const QNetworkConfiguration &config)
{ {
@ -2077,28 +2158,40 @@ void TDLibWrapper::handleGetPageSourceFinished()
} }
} }
QVariantMap& TDLibWrapper::fillTdlibParameters(QVariantMap& parameters)
{
parameters.insert("api_id", TDLIB_API_ID);
parameters.insert("api_hash", TDLIB_API_HASH);
parameters.insert("database_directory", QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tdlib");
bool onlineOnlyMode = this->appSettings->onlineOnlyMode();
parameters.insert("use_file_database", !onlineOnlyMode);
parameters.insert("use_chat_info_database", !onlineOnlyMode);
parameters.insert("use_message_database", !onlineOnlyMode);
parameters.insert("use_secret_chats", true);
parameters.insert("system_language_code", QLocale::system().name());
QSettings hardwareSettings("/etc/hw-release", QSettings::NativeFormat);
parameters.insert("device_model", hardwareSettings.value("NAME", "Unknown Mobile Device").toString());
parameters.insert("system_version", QSysInfo::prettyProductName());
parameters.insert("application_version", "0.17");
parameters.insert("enable_storage_optimizer", appSettings->storageOptimizer());
// parameters.insert("use_test_dc", true);
return parameters;
}
void TDLibWrapper::setInitialParameters() void TDLibWrapper::setInitialParameters()
{ {
LOG("Sending initial parameters to TD Lib"); LOG("Sending initial parameters to TD Lib");
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert(_TYPE, "setTdlibParameters"); requestObject.insert(_TYPE, "setTdlibParameters");
// tdlibParameters were inlined between 1.8.5 and 1.8.6
// See https://github.com/tdlib/td/commit/f6a2ecd
if (versionNumber > VERSION_NUMBER(1,8,5)) {
fillTdlibParameters(requestObject);
} else {
QVariantMap initialParameters; QVariantMap initialParameters;
initialParameters.insert("api_id", TDLIB_API_ID); fillTdlibParameters(initialParameters);
initialParameters.insert("api_hash", TDLIB_API_HASH);
initialParameters.insert("database_directory", QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tdlib");
bool onlineOnlyMode = this->appSettings->onlineOnlyMode();
initialParameters.insert("use_file_database", !onlineOnlyMode);
initialParameters.insert("use_chat_info_database", !onlineOnlyMode);
initialParameters.insert("use_message_database", !onlineOnlyMode);
initialParameters.insert("use_secret_chats", true);
initialParameters.insert("system_language_code", QLocale::system().name());
QSettings hardwareSettings("/etc/hw-release", QSettings::NativeFormat);
initialParameters.insert("device_model", hardwareSettings.value("NAME", "Unknown Mobile Device").toString());
initialParameters.insert("system_version", QSysInfo::prettyProductName());
initialParameters.insert("application_version", "0.17");
initialParameters.insert("enable_storage_optimizer", appSettings->storageOptimizer());
// initialParameters.insert("use_test_dc", true);
requestObject.insert("parameters", initialParameters); requestObject.insert("parameters", initialParameters);
}
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }

View file

@ -148,6 +148,7 @@ public:
Q_INVOKABLE QVariantMap getSuperGroup(qlonglong groupId) const; Q_INVOKABLE QVariantMap getSuperGroup(qlonglong groupId) const;
Q_INVOKABLE QVariantMap getChat(const QString &chatId); Q_INVOKABLE QVariantMap getChat(const QString &chatId);
Q_INVOKABLE QVariantMap getSecretChatFromCache(qlonglong secretChatId); Q_INVOKABLE QVariantMap getSecretChatFromCache(qlonglong secretChatId);
Q_INVOKABLE QStringList getChatReactions(const QString &chatId);
Q_INVOKABLE QString getOptionString(const QString &optionName); Q_INVOKABLE QString getOptionString(const QString &optionName);
Q_INVOKABLE void copyFileToDownloads(const QString &filePath, bool openAfterCopy = false); Q_INVOKABLE void copyFileToDownloads(const QString &filePath, bool openAfterCopy = false);
Q_INVOKABLE void openFileOnDevice(const QString &filePath); Q_INVOKABLE void openFileOnDevice(const QString &filePath);
@ -175,14 +176,14 @@ public:
Q_INVOKABLE void viewMessage(qlonglong chatId, qlonglong messageId, bool force); Q_INVOKABLE void viewMessage(qlonglong chatId, qlonglong messageId, bool force);
Q_INVOKABLE void pinMessage(const QString &chatId, const QString &messageId, bool disableNotification = false); Q_INVOKABLE void pinMessage(const QString &chatId, const QString &messageId, bool disableNotification = false);
Q_INVOKABLE void unpinMessage(const QString &chatId, const QString &messageId); Q_INVOKABLE void unpinMessage(const QString &chatId, const QString &messageId);
Q_INVOKABLE void sendTextMessage(const QString &chatId, const QString &message, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendTextMessage(qlonglong chatId, const QString &message, qlonglong replyToMessageId = 0);
Q_INVOKABLE void sendPhotoMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendPhotoMessage(qlonglong chatId, const QString &filePath, const QString &message, qlonglong replyToMessageId = 0);
Q_INVOKABLE void sendVideoMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendVideoMessage(qlonglong chatId, const QString &filePath, const QString &message, qlonglong replyToMessageId = 0);
Q_INVOKABLE void sendDocumentMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendDocumentMessage(qlonglong chatId, const QString &filePath, const QString &message, qlonglong replyToMessageId = 0);
Q_INVOKABLE void sendVoiceNoteMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendVoiceNoteMessage(qlonglong chatId, const QString &filePath, const QString &message, qlonglong replyToMessageId = 0);
Q_INVOKABLE void sendLocationMessage(const QString &chatId, double latitude, double longitude, double horizontalAccuracy, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendLocationMessage(qlonglong chatId, double latitude, double longitude, double horizontalAccuracy, qlonglong replyToMessageId = 0);
Q_INVOKABLE void sendStickerMessage(const QString &chatId, const QString &fileId, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendStickerMessage(qlonglong chatId, const QString &fileId, qlonglong replyToMessageId = 0);
Q_INVOKABLE void sendPollMessage(const QString &chatId, const QString &question, const QVariantList &options, bool anonymous, int correctOption, bool multiple, const QString &explanation, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendPollMessage(qlonglong chatId, const QString &question, const QVariantList &options, bool anonymous, int correctOption, bool multiple, const QString &explanation, qlonglong replyToMessageId = 0);
Q_INVOKABLE void forwardMessages(const QString &chatId, const QString &fromChatId, const QVariantList &messageIds, bool sendCopy, bool removeCaption); Q_INVOKABLE void forwardMessages(const QString &chatId, const QString &fromChatId, const QVariantList &messageIds, bool sendCopy, bool removeCaption);
Q_INVOKABLE void getMessage(qlonglong chatId, qlonglong messageId); Q_INVOKABLE void getMessage(qlonglong chatId, qlonglong messageId);
Q_INVOKABLE void getMessageLinkInfo(const QString &url, const QString &extra = ""); Q_INVOKABLE void getMessageLinkInfo(const QString &url, const QString &extra = "");
@ -364,7 +365,7 @@ public slots:
void handleUpdatedUserPrivacySettingRules(const QVariantMap &updatedRules); void handleUpdatedUserPrivacySettingRules(const QVariantMap &updatedRules);
void handleSponsoredMessage(qlonglong chatId, const QVariantMap &message); void handleSponsoredMessage(qlonglong chatId, const QVariantMap &message);
void handleNetworkConfigurationChanged(const QNetworkConfiguration &config); void handleNetworkConfigurationChanged(const QNetworkConfiguration &config);
void handleActiveEmojiReactionsUpdated(const QStringList& emojis);
void handleGetPageSourceFinished(); void handleGetPageSourceFinished();
private: private:
@ -372,7 +373,9 @@ private:
void setInitialParameters(); void setInitialParameters();
void setEncryptionKey(); void setEncryptionKey();
void setLogVerbosityLevel(); void setLogVerbosityLevel();
QVariantMap &fillTdlibParameters(QVariantMap &parameters);
const Group *updateGroup(qlonglong groupId, const QVariantMap &groupInfo, QHash<qlonglong,Group*> *groups); const Group *updateGroup(qlonglong groupId, const QVariantMap &groupInfo, QHash<qlonglong,Group*> *groups);
QVariantMap newSendMessageRequest(qlonglong chatId, qlonglong replyToMessageId);
void initializeTDLibReceiver(); void initializeTDLibReceiver();
private: private:
@ -383,7 +386,7 @@ private:
MceInterface *mceInterface; MceInterface *mceInterface;
TDLibReceiver *tdLibReceiver; TDLibReceiver *tdLibReceiver;
DBusInterface *dbusInterface; DBusInterface *dbusInterface;
QString version; QString versionString;
TDLibWrapper::AuthorizationState authorizationState; TDLibWrapper::AuthorizationState authorizationState;
QVariantMap authorizationStateData; QVariantMap authorizationStateData;
TDLibWrapper::ConnectionState connectionState; TDLibWrapper::ConnectionState connectionState;
@ -399,7 +402,9 @@ private:
QHash<qlonglong,Group*> basicGroups; QHash<qlonglong,Group*> basicGroups;
QHash<qlonglong,Group*> superGroups; QHash<qlonglong,Group*> superGroups;
EmojiSearchWorker emojiSearchWorker; EmojiSearchWorker emojiSearchWorker;
QStringList activeEmojiReactions;
int versionNumber;
QString activeChatSearchName; QString activeChatSearchName;
bool joinChatRequested; bool joinChatRequested;
bool isLoggingOut; bool isLoggingOut;

View file

@ -1575,6 +1575,26 @@
<source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source> <source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source>
<translation>Wenn Töne eingeschaltet sind, wird Fernschreiber den aktuellen Sailfish OS-Hinweiston für Chats verwenden, der in den Systemeinstellungen konfiguriert werden kann.</translation> <translation>Wenn Töne eingeschaltet sind, wird Fernschreiber den aktuellen Sailfish OS-Hinweiston für Chats verwenden, der in den Systemeinstellungen konfiguriert werden kann.</translation>
</message> </message>
<message>
<source>Always append message preview to notifications</source>
<translation>Immer bei Hinweisen die Nachricht ausgeben</translation>
</message>
<message>
<source>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</source>
<translation>Zusätzlich zur Anzahl der ungelesenen Nachrichten wird immer die neuste Nachricht an Hinweise angefügt.</translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation>Ungelesene Nachrichten hervorheben</translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation>Unterhaltungen mit ungelesenen Nachrichten hervorheben</translation>
</message>
<message>
<source>Hide content in Notifications</source>
<translation>Inhalte in Hinweisen verbergen</translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1672,10 +1692,6 @@
<source>This app</source> <source>This app</source>
<translation>Diese App</translation> <translation>Diese App</translation>
</message> </message>
<message>
<source>IP address: %1, origin: %2</source>
<translation>IP-Adresse: %1, Herkunft: %2</translation>
</message>
<message> <message>
<source>Active since: %1, last online: %2</source> <source>Active since: %1, last online: %2</source>
<translation>Aktiv seit: %1, zuletzt online: %2</translation> <translation>Aktiv seit: %1, zuletzt online: %2</translation>

View file

@ -1577,6 +1577,26 @@ messages</numerusform>
<source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source> <source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source>
<translation>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</translation> <translation>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</translation>
</message> </message>
<message>
<source>Always append message preview to notifications</source>
<translation>Always append message preview to notifications</translation>
</message>
<message>
<source>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</source>
<translation>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide content in Notifications</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1682,10 +1702,6 @@ messages</numerusform>
<source>This app</source> <source>This app</source>
<translation>This app</translation> <translation>This app</translation>
</message> </message>
<message>
<source>IP address: %1, origin: %2</source>
<translation>IP address: %1, origin: %2</translation>
</message>
<message> <message>
<source>Active since: %1, last online: %2</source> <source>Active since: %1, last online: %2</source>
<translation>Active since: %1, last online: %2</translation> <translation>Active since: %1, last online: %2</translation>

View file

@ -1575,6 +1575,26 @@
<source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source> <source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source>
<translation>Cuando los sonidos están habilitados, Fernschreiber utilizará el sonido de notificación actual de Sailfish OS para los grupos, que se puede configurar en la configuración del sistema.</translation> <translation>Cuando los sonidos están habilitados, Fernschreiber utilizará el sonido de notificación actual de Sailfish OS para los grupos, que se puede configurar en la configuración del sistema.</translation>
</message> </message>
<message>
<source>Always append message preview to notifications</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide content in Notifications</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1680,10 +1700,6 @@
<source>This app</source> <source>This app</source>
<translation>Esta apl</translation> <translation>Esta apl</translation>
</message> </message>
<message>
<source>IP address: %1, origin: %2</source>
<translation>Dirección IP: %1, origen: %2</translation>
</message>
<message> <message>
<source>Active since: %1, last online: %2</source> <source>Active since: %1, last online: %2</source>
<translation>Activo desde: %1, último en línea: %2</translation> <translation>Activo desde: %1, último en línea: %2</translation>

View file

@ -1576,6 +1576,26 @@
<source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source> <source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source>
<translation>Kun äänet ovat käytössä, Fernschreiber käyttää Sailfish OS:n ilmoitusääniä keskusteluille, jotia voit muuttaa järjestelmäasetuksista.</translation> <translation>Kun äänet ovat käytössä, Fernschreiber käyttää Sailfish OS:n ilmoitusääniä keskusteluille, jotia voit muuttaa järjestelmäasetuksista.</translation>
</message> </message>
<message>
<source>Always append message preview to notifications</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide content in Notifications</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1681,10 +1701,6 @@
<source>This app</source> <source>This app</source>
<translation>Tämä sovellus</translation> <translation>Tämä sovellus</translation>
</message> </message>
<message>
<source>IP address: %1, origin: %2</source>
<translation>IP-osoite: %1, sijainti: %2</translation>
</message>
<message> <message>
<source>Active since: %1, last online: %2</source> <source>Active since: %1, last online: %2</source>
<translation>Aktiivinen %1 alkaen, viimeksi paikalla: %2</translation> <translation>Aktiivinen %1 alkaen, viimeksi paikalla: %2</translation>

View file

@ -1575,6 +1575,26 @@
<source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source> <source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source>
<translation>Lorsque le son est activé, Fernschreiber utilisera le réglage de Sailfish OS. Celui-ci est paramétrable depuis les paramètres du système.</translation> <translation>Lorsque le son est activé, Fernschreiber utilisera le réglage de Sailfish OS. Celui-ci est paramétrable depuis les paramètres du système.</translation>
</message> </message>
<message>
<source>Always append message preview to notifications</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide content in Notifications</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1680,10 +1700,6 @@
<source>This app</source> <source>This app</source>
<translation>Cette app</translation> <translation>Cette app</translation>
</message> </message>
<message>
<source>IP address: %1, origin: %2</source>
<translation>Adresse IP : %1, origine : %2</translation>
</message>
<message> <message>
<source>Active since: %1, last online: %2</source> <source>Active since: %1, last online: %2</source>
<translation>Actif depuis : %1, en ligne : %2</translation> <translation>Actif depuis : %1, en ligne : %2</translation>

View file

@ -1548,6 +1548,26 @@
<source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source> <source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Always append message preview to notifications</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide content in Notifications</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1653,10 +1673,6 @@
<source>This app</source> <source>This app</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>IP address: %1, origin: %2</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Active since: %1, last online: %2</source> <source>Active since: %1, last online: %2</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>

View file

@ -1575,6 +1575,26 @@
<source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source> <source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source>
<translation>Quando i suoni di notifica sono attivi, Fernschreiber utilizza l&apos;attuale suono di notifica per i messaggi scelto per Sailfish OS, il quale può essere modificato dalle impostazioni di sistema.</translation> <translation>Quando i suoni di notifica sono attivi, Fernschreiber utilizza l&apos;attuale suono di notifica per i messaggi scelto per Sailfish OS, il quale può essere modificato dalle impostazioni di sistema.</translation>
</message> </message>
<message>
<source>Always append message preview to notifications</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide content in Notifications</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1680,10 +1700,6 @@
<source>This app</source> <source>This app</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>IP address: %1, origin: %2</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Active since: %1, last online: %2</source> <source>Active since: %1, last online: %2</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>

View file

@ -1602,6 +1602,26 @@
<source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source> <source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source>
<translation>Gdy dźwięki włączone, Fernschreiber użyje bieżącego dźwięku powiadomienia Sailfish OS do czatów, które można skonfigurować w ustawieniach systemu.</translation> <translation>Gdy dźwięki włączone, Fernschreiber użyje bieżącego dźwięku powiadomienia Sailfish OS do czatów, które można skonfigurować w ustawieniach systemu.</translation>
</message> </message>
<message>
<source>Always append message preview to notifications</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide content in Notifications</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1707,10 +1727,6 @@
<source>This app</source> <source>This app</source>
<translation>Ta aplikacja</translation> <translation>Ta aplikacja</translation>
</message> </message>
<message>
<source>IP address: %1, origin: %2</source>
<translation>Adres IP: %1, oryginalny: %2</translation>
</message>
<message> <message>
<source>Active since: %1, last online: %2</source> <source>Active since: %1, last online: %2</source>
<translation>Aktywny od: %1, ostatnio aktywny: %2</translation> <translation>Aktywny od: %1, ostatnio aktywny: %2</translation>

View file

@ -1605,6 +1605,26 @@
<source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source> <source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source>
<translation>Если звуки разрешены, Fernschreiber использует звук, выбранный для чатов в настройках Sailfish OS.</translation> <translation>Если звуки разрешены, Fernschreiber использует звук, выбранный для чатов в настройках Sailfish OS.</translation>
</message> </message>
<message>
<source>Always append message preview to notifications</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide content in Notifications</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1710,10 +1730,6 @@
<source>This app</source> <source>This app</source>
<translation>Это приложение</translation> <translation>Это приложение</translation>
</message> </message>
<message>
<source>IP address: %1, origin: %2</source>
<translation>IP-адрес: %1, регион: %2</translation>
</message>
<message> <message>
<source>Active since: %1, last online: %2</source> <source>Active since: %1, last online: %2</source>
<translation>Активен с: %1, был онлайн: %2</translation> <translation>Активен с: %1, был онлайн: %2</translation>

View file

@ -1602,6 +1602,26 @@
<source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source> <source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source>
<translation>Keď povolené zvukové upozornenia, Fernschreiber použije aktuálne zvukové upozornenia Sailfish OS pre čety, ktoré môžu byť upravené v nastaveniach systému.</translation> <translation>Keď povolené zvukové upozornenia, Fernschreiber použije aktuálne zvukové upozornenia Sailfish OS pre čety, ktoré môžu byť upravené v nastaveniach systému.</translation>
</message> </message>
<message>
<source>Always append message preview to notifications</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide content in Notifications</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1707,10 +1727,6 @@
<source>This app</source> <source>This app</source>
<translation>Táto aplikácia</translation> <translation>Táto aplikácia</translation>
</message> </message>
<message>
<source>IP address: %1, origin: %2</source>
<translation>IP adresa: %1, pôvod: %2</translation>
</message>
<message> <message>
<source>Active since: %1, last online: %2</source> <source>Active since: %1, last online: %2</source>
<translation>Aktívna od: %1, naposledy pripojená: %2</translation> <translation>Aktívna od: %1, naposledy pripojená: %2</translation>

View file

@ -1575,6 +1575,26 @@
<source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source> <source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source>
<translation>När ljud är aktiverat, använder Fernschreiber aktuell Sailfish-signal för chatt-avisering, vilken kan ställas in i systemets ljudinställningar.</translation> <translation>När ljud är aktiverat, använder Fernschreiber aktuell Sailfish-signal för chatt-avisering, vilken kan ställas in i systemets ljudinställningar.</translation>
</message> </message>
<message>
<source>Always append message preview to notifications</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide content in Notifications</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1680,10 +1700,6 @@
<source>This app</source> <source>This app</source>
<translation>Denna app</translation> <translation>Denna app</translation>
</message> </message>
<message>
<source>IP address: %1, origin: %2</source>
<translation>IP-adress: %1, ursprung: %2</translation>
</message>
<message> <message>
<source>Active since: %1, last online: %2</source> <source>Active since: %1, last online: %2</source>
<translation>Aktiv sedan: %1, senast online: %2</translation> <translation>Aktiv sedan: %1, senast online: %2</translation>

View file

@ -1549,6 +1549,26 @@
<source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source> <source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source>
<translation>Fernschreiber </translation> <translation>Fernschreiber </translation>
</message> </message>
<message>
<source>Always append message preview to notifications</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide content in Notifications</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1654,10 +1674,6 @@
<source>This app</source> <source>This app</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>IP address: %1, origin: %2</source>
<translation>IP : %1, : %2</translation>
</message>
<message> <message>
<source>Active since: %1, last online: %2</source> <source>Active since: %1, last online: %2</source>
<translation>: %1, 线: %2</translation> <translation>: %1, 线: %2</translation>

View file

@ -1575,6 +1575,26 @@
<source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source> <source>When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Always append message preview to notifications</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide content in Notifications</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1680,10 +1700,6 @@
<source>This app</source> <source>This app</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>IP address: %1, origin: %2</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Active since: %1, last online: %2</source> <source>Active since: %1, last online: %2</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>