Compare commits

..

No commits in common. "0236586e4454bc8f06dcf070fd440c1151577005" and "1ad324aa23c404667ca80c5a2284025d67d14c8d" have entirely different histories.

55 changed files with 2631 additions and 19500 deletions

View file

@ -84,7 +84,7 @@ jobs:
assets+=("-a" "$asset") assets+=("-a" "$asset")
done done
tag_name="${GITHUB_REF##*/}" tag_name="${GITHUB_REF##*/}"
gh release create "$tag_name" "${assets[@]}" hub release create "${assets[@]}" -m "$tag_name" "$tag_name"
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -97,6 +97,6 @@ jobs:
assets+=("-a" "$asset") assets+=("-a" "$asset")
done done
tag_name="${GITHUB_REF##*/}" tag_name="${GITHUB_REF##*/}"
gh release create "$tag_name" -p -n "This is a pre-release for testing purposes only. It may or may not be unstable." "${assets[@]}" hub release create -p "${assets[@]}" -m "$tag_name" -m "This is a pre-release for testing purposes only. It may or may not be unstable." -m "Join the Telegram group to help out: https://github.com/Wunderfitz/harbour-fernschreiber/issues/162" "$tag_name"
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

3
.gitignore vendored
View file

@ -53,6 +53,3 @@ compile_commands.json
# TDLib API Secrets # TDLib API Secrets
tdlibsecrets.h tdlibsecrets.h
#Convinience scripts
*.sh

View file

@ -14,11 +14,7 @@ Fernschreiber wouldn't be the same without all the people helping in making it b
- Chat info page, performance improvements to chat page, location support, app initialization/registration with Telegram, project dependencies, emoji handling, qml/js optimizations, multi-message actions, i18n fixes, chat permission handling, code reviews, logging categories, bot support, github build: [jgibbon](https://github.com/jgibbon) - Chat info page, performance improvements to chat page, location support, app initialization/registration with Telegram, project dependencies, emoji handling, qml/js optimizations, multi-message actions, i18n fixes, chat permission handling, code reviews, logging categories, bot support, github build: [jgibbon](https://github.com/jgibbon)
- Copy message to clipboard: [Christian Stemmle](https://github.com/chstem) - Copy message to clipboard: [Christian Stemmle](https://github.com/chstem)
- Hide send message button if send-by-enter is switched on, focus text input on entering a chat: [santhoshmanikandan](https://github.com/santhoshmanikandan) - Hide send message button if send-by-enter is switched on, focus text input on entering a chat: [santhoshmanikandan](https://github.com/santhoshmanikandan)
- Integration of logout and sesison options to settings page, search results optimization, highlight unread conversations: [Peter G.](https://github.com/nephros) - Integration of logout and sesison options to settings page: [Peter G.](https://github.com/nephros)
- Option to always append last message in notifications: [Johannes Bachmann](https://github.com/dscheinah)
- Option to jump to quoted message, widescreen UI adjustments: [Mikhail Barashkov](https://github.com/mbarashkov)
This list might not be complete. In case I forgot something/somebody, please let me know or create a PR, thanks! :)
### Logo/Icon ### Logo/Icon
- Designed by [Matteo](https://github.com/iamnomeutente), adjustments by [Slava Monich](https://github.com/monich) - Designed by [Matteo](https://github.com/iamnomeutente), adjustments by [Slava Monich](https://github.com/monich)
@ -52,7 +48,7 @@ const char TDLIB_API_HASH[] = "1234567890abcdef1234567890abcdef";
You get the Telegram API ID and hash as soon as you've registered your own application on [https://my.telegram.org](https://my.telegram.org). You get the Telegram API ID and hash as soon as you've registered your own application on [https://my.telegram.org](https://my.telegram.org).
Moreover, you need to have a compiled version of [TDLib 1.8.21](https://github.com/tdlib/td) or higher in the sub-directory `tdlib`. This sub-directory must contain another sub-directory that fits to the target device architecture (e.g. armv7hl, i486). Within this directory, there needs to be a folder called `lib` that contains at least `libtdjson.so`. For armv7hl the relative path would consequently be `tdlib/armv7hl/lib`. Moreover, you need to have a compiled version of [TDLib 1.8.3](https://github.com/tdlib/td) or higher in the sub-directory `tdlib`. This sub-directory must contain another sub-directory that fits to the target device architecture (e.g. armv7hl, i486). Within this directory, there needs to be a folder called `lib` that contains at least `libtdjson.so`. For armv7hl the relative path would consequently be `tdlib/armv7hl/lib`.
You may just want to download the [tdlib.zip from our fork](https://github.com/Wunderfitz/td/releases) to just use the exact version of the latest official Fernschreiber release. To use it, you need to extract it into your local `tdlib/` folder as described above. If so, you're done and can compile Fernschreiber using the Sailfish SDK. If you want to build TDLib for yourself, please keep on reading. You may just want to download the [tdlib.zip from our fork](https://github.com/Wunderfitz/td/releases) to just use the exact version of the latest official Fernschreiber release. To use it, you need to extract it into your local `tdlib/` folder as described above. If so, you're done and can compile Fernschreiber using the Sailfish SDK. If you want to build TDLib for yourself, please keep on reading.

View file

@ -1,6 +1,6 @@
[Desktop Entry] [Desktop Entry]
Type=Application Type=Application
X-Nemo-Application-Type=silica-qt5 X-Nemo-Application-Type=generic
Icon=harbour-fernschreiber Icon=harbour-fernschreiber
Exec=harbour-fernschreiber Exec=harbour-fernschreiber
Name=Fernschreiber Name=Fernschreiber

View file

@ -40,7 +40,7 @@ Loader {
property string chatId property string chatId
property string userName property string userName
property bool userNameIsValid: userName !== "" && inlineBotInformation && userName.toLowerCase() === inlineBotInformation.usernames.editable_username.toLowerCase() property bool userNameIsValid: userName !== "" && inlineBotInformation && userName.toLowerCase() === inlineBotInformation.username.toLowerCase()
property string query property string query
property int currentOffset: 0 property int currentOffset: 0
property string responseExtra: chatId+"|"+userName+"|"+query+"|"+currentOffset property string responseExtra: chatId+"|"+userName+"|"+query+"|"+currentOffset

View file

@ -47,7 +47,6 @@ ListItem {
readonly property bool canDeleteMessage: myMessage.can_be_deleted_for_all_users || (myMessage.can_be_deleted_only_for_self && myMessage.chat_id === page.myUserId) readonly property bool canDeleteMessage: myMessage.can_be_deleted_for_all_users || (myMessage.can_be_deleted_only_for_self && myMessage.chat_id === page.myUserId)
property bool hasContentComponent property bool hasContentComponent
property bool additionalOptionsOpened property bool additionalOptionsOpened
property bool wasNavigatedTo: false
readonly property var additionalItemsModel: (extraContentLoader.item && ("extraContextMenuItems" in extraContentLoader.item)) ? readonly property var additionalItemsModel: (extraContentLoader.item && ("extraContextMenuItems" in extraContentLoader.item)) ?
extraContentLoader.item.extraContextMenuItems : 0 extraContentLoader.item.extraContextMenuItems : 0
@ -65,10 +64,9 @@ 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 || wasNavigatedTo) && !menuOpen highlighted: (down || isSelected || additionalOptionsOpened) && !menuOpen
openMenuOnPressAndHold: !messageListItem.precalculatedValues.pageIsSelecting openMenuOnPressAndHold: !messageListItem.precalculatedValues.pageIsSelecting
signal replyToMessage() signal replyToMessage()
@ -96,43 +94,20 @@ ListItem {
} }
} }
function getInteractionText(viewCount, reactions, size, highlightColor) { function getInteractionText(viewCount, reactions) {
var interactionText = ""; var interactionText = "";
if (viewCount > 0) { if (viewCount > 0) {
interactionText = Emoji.emojify("👁️ ", size) + Functions.getShortenedCount(viewCount); interactionText = Emoji.emojify("👁️", Theme.fontSizeTiny) + Functions.getShortenedCount(viewCount);
} }
for (var i = 0; i < reactions.length; i++) { for (var i = 0; i < reactions.length; i++) {
var reaction = reactions[i] interactionText += ( "&nbsp;" + Emoji.emojify(reactions[i].reaction, Theme.fontSizeTiny) );
var reactionText = reaction.reaction ? reaction.reaction : (reaction.type && reaction.type.emoji) ? reaction.type.emoji : "" if (!chatPage.isPrivateChat) {
if (reactionText) { interactionText += ( " " + Functions.getShortenedCount(reactions[i].total_count) );
interactionText += ( "&nbsp;" + Emoji.emojify(reactionText, size) );
if (!chatPage.isPrivateChat) {
var count = Functions.getShortenedCount(reaction.total_count)
interactionText += " "
interactionText += (reaction.is_chosen ? ( "<font color='" + highlightColor + "'><b>" + count + "</b></font>" ) : count)
}
} }
} }
return interactionText; return interactionText;
} }
function openReactions() {
if (messageListItem.chatReactions) {
Debug.log("Using chat reactions")
messageListItem.messageReactions = chatReactions
showItemCompletelyTimer.requestedIndex = index;
showItemCompletelyTimer.start();
} else {
Debug.log("Obtaining message reactions")
tdLibWrapper.getMessageAvailableReactions(messageListItem.chatId, messageListItem.messageId);
}
selectReactionBubble.visible = false;
}
function getContentWidthMultiplier() {
return Functions.isWidescreen(appWindow) ? 0.4 : 1.0
}
onClicked: { onClicked: {
if (messageListItem.precalculatedValues.pageIsSelecting) { if (messageListItem.precalculatedValues.pageIsSelecting) {
page.toggleMessageSelection(myMessage); page.toggleMessageSelection(myMessage);
@ -150,26 +125,12 @@ ListItem {
if (messageListItem.messageReactions) { if (messageListItem.messageReactions) {
messageListItem.messageReactions = null; messageListItem.messageReactions = null;
selectReactionBubble.visible = false;
} else { } else {
selectReactionBubble.visible = !selectReactionBubble.visible; tdLibWrapper.getMessageAvailableReactions(messageListItem.chatId, messageListItem.messageId);
elementSelected(index);
} }
} }
} }
onDoubleClicked: {
if (messageListItem.chatReactions) {
Debug.log("Using chat reactions")
messageListItem.messageReactions = chatReactions
showItemCompletelyTimer.requestedIndex = index;
showItemCompletelyTimer.start();
} else {
Debug.log("Obtaining message reactions")
tdLibWrapper.getMessageAvailableReactions(messageListItem.chatId, messageListItem.messageId);
}
}
onPressAndHold: { onPressAndHold: {
if (openMenuOnPressAndHold) { if (openMenuOnPressAndHold) {
openContextMenu() openContextMenu()
@ -193,25 +154,6 @@ ListItem {
} }
} }
Connections {
target: chatPage
onResetElements: {
messageListItem.messageReactions = null;
selectReactionBubble.visible = false;
}
onElementSelected: {
if (elementIndex !== index) {
selectReactionBubble.visible = false;
}
}
onNavigatedTo: {
if (targetIndex === index) {
messageListItem.wasNavigatedTo = true;
restoreNormalityTimer.start();
}
}
}
Loader { Loader {
id: contextMenuLoader id: contextMenuLoader
active: false active: false
@ -316,9 +258,6 @@ ListItem {
messageListItem.messageReactions = null; messageListItem.messageReactions = null;
} }
} }
onReactionsUpdated: {
chatReactions = tdLibWrapper.getChatReactions(page.chatInformation.id);
}
} }
Timer { Timer {
@ -331,34 +270,16 @@ ListItem {
interval: 200 interval: 200
triggeredOnStart: false triggeredOnStart: false
onTriggered: { onTriggered: {
Debug.log("Show item completely timer triggered, requested index: " + requestedIndex + ", current index: " + index)
if (requestedIndex === index) { if (requestedIndex === index) {
var p = chatView.contentItem.mapFromItem(reactionsColumn, 0, 0) chatView.highlightMoveDuration = -1;
if (chatView.contentY > p.y || p.y + reactionsColumn.height > chatView.contentY + chatView.height) { chatView.highlightResizeDuration = -1;
Debug.log("Moving reactions for item at", requestedIndex, "info the view") chatView.scrollToIndex(requestedIndex);
chatView.highlightMoveDuration = -1 chatView.highlightMoveDuration = 0;
chatView.highlightResizeDuration = -1 chatView.highlightResizeDuration = 0;
chatView.scrollToIndex(requestedIndex, height <= chatView.height ? ListView.Contain : ListView.End)
chatView.highlightMoveDuration = 0
chatView.highlightResizeDuration = 0
}
} }
} }
} }
Timer {
id: restoreNormalityTimer
repeat: false
running: false
interval: 1000
triggeredOnStart: false
onTriggered: {
Debug.log("Restore normality for index " + index);
messageListItem.wasNavigatedTo = false;
}
}
Component.onCompleted: { Component.onCompleted: {
delegateComponentLoadingTimer.start(); delegateComponentLoadingTimer.start();
if (myMessage.reply_to_message_id) { if (myMessage.reply_to_message_id) {
@ -401,10 +322,8 @@ ListItem {
id: messageTextRow id: messageTextRow
spacing: Theme.paddingSmall spacing: Theme.paddingSmall
width: precalculatedValues.entryWidth width: precalculatedValues.entryWidth
anchors.horizontalCenter: Functions.isWidescreen(appWindow) ? undefined : parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.left: Functions.isWidescreen(appWindow) ? parent.left : undefined
y: Theme.paddingSmall y: Theme.paddingSmall
anchors.leftMargin: Functions.isWidescreen(appWindow) ? Theme.paddingMedium : undefined
Loader { Loader {
id: profileThumbnailLoader id: profileThumbnailLoader
@ -521,12 +440,8 @@ ListItem {
page.toggleMessageSelection(myMessage) page.toggleMessageSelection(myMessage)
} else { } else {
messageOptionsDrawer.open = false messageOptionsDrawer.open = false
if(appSettings.goToQuotedMessage) { messageOverlayLoader.overlayMessage = messageInReplyToRow.inReplyToMessage
chatPage.showMessage(messageInReplyToRow.inReplyToMessage.id, true) messageOverlayLoader.active = true
} else {
messageOverlayLoader.active = true
messageOverlayLoader.overlayMessage = messageInReplyToRow.inReplyToMessage
}
} }
} }
onPressAndHold: { onPressAndHold: {
@ -552,12 +467,11 @@ ListItem {
width: parent.width width: parent.width
Component.onCompleted: { Component.onCompleted: {
var originType = myMessage.forward_info.origin["@type"] if (myMessage.forward_info.origin["@type"] === "messageForwardOriginChannel") {
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 (originType === "messageOriginUser" || originType === "messageForwardOriginUser") { } else if (myMessage.forward_info.origin["@type"] === "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);
@ -638,7 +552,7 @@ ListItem {
id: webPagePreviewLoader id: webPagePreviewLoader
active: false active: false
asynchronous: true asynchronous: true
width: parent.width * getContentWidthMultiplier() width: parent.width
height: (status === Loader.Ready) ? item.implicitHeight : myMessage.content.web_page ? precalculatedValues.webPagePreviewHeight : 0 height: (status === Loader.Ready) ? item.implicitHeight : myMessage.content.web_page ? precalculatedValues.webPagePreviewHeight : 0
sourceComponent: Component { sourceComponent: Component {
@ -652,7 +566,7 @@ ListItem {
Loader { Loader {
id: extraContentLoader id: extraContentLoader
width: parent.width * getContentWidthMultiplier() width: parent.width
asynchronous: true asynchronous: true
height: item ? item.height : (messageListItem.hasContentComponent ? chatView.getContentComponentHeight(model.content_type, myMessage.content, width) : 0) height: item ? item.height : (messageListItem.hasContentComponent ? chatView.getContentComponentHeight(model.content_type, myMessage.content, width) : 0)
} }
@ -711,7 +625,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, font.pixelSize, Theme.highlightColor) text: getInteractionText(messageViewCount, reactions)
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
@ -763,7 +677,7 @@ ListItem {
Image { Image {
id: emojiPicture id: emojiPicture
source: Emoji.getEmojiPath(modelData) source: Emoji.getEmojiPath(modelData)
width: status === Image.Ready ? Theme.fontSizeLarge : 0 width: Theme.fontSizeLarge
height: Theme.fontSizeLarge height: Theme.fontSizeLarge
} }

View file

@ -40,11 +40,9 @@ 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

@ -31,12 +31,12 @@ Loader {
property var botUserInformation: tdLibWrapper.getUserInformation(message.via_bot_user_id) property var botUserInformation: tdLibWrapper.getUserInformation(message.via_bot_user_id)
color: Theme.secondaryColor color: Theme.secondaryColor
font.pixelSize: Theme.fontSizeExtraSmall font.pixelSize: Theme.fontSizeExtraSmall
text: qsTr("via %1", "message posted via bot user").arg("<a style=\"text-decoration: none; font-weight: bold; color:"+Theme.primaryColor+"\" href=\"userId://" + message.via_bot_user_id + "\">@" + Emoji.emojify(botUserInformation.usernames.editable_username, font.pixelSize)+"</a>") text: qsTr("via %1", "message posted via bot user").arg("<a style=\"text-decoration: none; font-weight: bold; color:"+Theme.primaryColor+"\" href=\"userId://" + message.via_bot_user_id + "\">@" + Emoji.emojify(botUserInformation.username, font.pixelSize)+"</a>")
textFormat: Text.RichText textFormat: Text.RichText
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
onLinkActivated: { onLinkActivated: {
if(link === "userId://" + message.via_bot_user_id && botUserInformation.type.is_inline) { if(link === "userId://" + message.via_bot_user_id && botUserInformation.type.is_inline) {
newMessageTextField.text = "@"+botUserInformation.usernames.editable_username+" " newMessageTextField.text = "@"+botUserInformation.username+" "
newMessageTextField.cursorPosition = newMessageTextField.text.length newMessageTextField.cursorPosition = newMessageTextField.text.length
lostFocusTimer.start(); lostFocusTimer.start();
} }

View file

@ -1,7 +1,6 @@
import QtQuick 2.6 import QtQuick 2.6
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0 import WerkWolf.Fernschreiber 1.0
import "../js/functions.js" as Functions
ListItem { ListItem {
id: chatListViewItem id: chatListViewItem
@ -104,42 +103,31 @@ ListItem {
anchors.centerIn: chatUnreadMessagesCountBackground anchors.centerIn: chatUnreadMessagesCountBackground
visible: chatListViewItem.unreadCount > 0 visible: chatListViewItem.unreadCount > 0
opacity: isMuted ? Theme.opacityHigh : 1.0 opacity: isMuted ? Theme.opacityHigh : 1.0
text: Functions.formatUnreadCount(chatListViewItem.unreadCount) text: chatListViewItem.unreadCount > 99 ? "99+" : chatListViewItem.unreadCount
} }
Rectangle { Rectangle {
id: chatUnreadReactionCountBackground
color: isMuted ? ((Theme.colorScheme === Theme.DarkOnLight) ? "lightgray" : "dimgray") : Theme.highlightBackgroundColor color: isMuted ? ((Theme.colorScheme === Theme.DarkOnLight) ? "lightgray" : "dimgray") : Theme.highlightBackgroundColor
width: Theme.fontSizeLarge width: Theme.fontSizeLarge
height: Theme.fontSizeLarge height: Theme.fontSizeLarge
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
radius: parent.width / 2 radius: parent.width / 2
visible: chatListViewItem.unreadReactionCount > 0 || chatListViewItem.unreadMentionCount > 0 visible: chatListViewItem.unreadReactionCount > 0
Icon {
source: "image://theme/icon-s-favorite"
height: Theme.iconSizeExtraSmall
width: Theme.iconSizeExtraSmall
highlighted: chatListViewItem.highlighted
anchors.centerIn: parent
visible: chatListViewItem.unreadReactionCount > 0 && !chatListViewItem.unreadMentionCount
}
Text {
font {
pixelSize: Theme.iconSizeExtraSmall
bold: true
}
color: Theme.primaryColor
anchors.centerIn: parent
visible: chatListViewItem.unreadMentionCount > 0
opacity: isMuted ? Theme.opacityHigh : 1.0
text: "@"
}
} }
Icon {
source: "image://theme/icon-s-favorite"
height: Theme.iconSizeExtraSmall
width: Theme.iconSizeExtraSmall
highlighted: chatListViewItem.highlighted
anchors.centerIn: chatUnreadReactionCountBackground
visible: chatListViewItem.unreadReactionCount > 0
}
} }
} }
Column { Column {
id: contentColumn id: contentColumn
anchors { anchors {
@ -162,9 +150,6 @@ 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

@ -60,12 +60,12 @@ Column {
}, },
inlineKeyboardButtonTypeSwitchInline: function() { inlineKeyboardButtonTypeSwitchInline: function() {
if(modelData.type.in_current_chat) { if(modelData.type.in_current_chat) {
chatPage.setMessageText("@" + userInformation.usernames.editable_username + " "+(modelData.type.query || "")) chatPage.setMessageText("@" + userInformation.username + " "+(modelData.type.query || ""))
} else { } else {
pageStack.push(Qt.resolvedUrl("../pages/ChatSelectionPage.qml"), { pageStack.push(Qt.resolvedUrl("../pages/ChatSelectionPage.qml"), {
myUserId: chatPage.myUserId, myUserId: chatPage.myUserId,
payload: { neededPermissions: ["can_send_other_messages"], text:"@" + userInformation.usernames.editable_username + " "+(modelData.type.query || "")}, payload: { neededPermissions: ["can_send_other_messages"], text:"@" + userInformation.username + " "+(modelData.type.query || "")},
state: "fillTextArea" state: "fillTextArea"
}) })
} }

View file

@ -300,8 +300,8 @@ SilicaFlickable {
} }
leftMargin: imageContainer.getEased((imageContainer.minDimension + Theme.paddingMedium), 0, imageContainer.tweenFactor) + Theme.horizontalPageMargin leftMargin: imageContainer.getEased((imageContainer.minDimension + Theme.paddingMedium), 0, imageContainer.tweenFactor) + Theme.horizontalPageMargin
title: chatInformationPage.chatInformation.title !== "" ? Emoji.emojify(chatInformationPage.chatInformation.title, Theme.fontSizeLarge) : qsTr("Unknown") title: chatInformationPage.chatInformation.title !== "" ? Emoji.emojify(chatInformationPage.chatInformation.title, Theme.fontSizeLarge) : qsTr("Unknown")
description: ((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && chatInformationPage.privateChatUserInformation.usernames.editable_username) description: ((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && chatInformationPage.privateChatUserInformation.username)
? ("@"+chatInformationPage.privateChatUserInformation.usernames.editable_username) : "" ? ("@"+chatInformationPage.privateChatUserInformation.username) : ""
} }
SilicaFlickable { SilicaFlickable {

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,9 +180,6 @@ 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

@ -27,7 +27,7 @@ MessageContentBase {
property var stickerData: messageListItem ? messageListItem.myMessage.content.sticker : overlayFlickable.overlayMessage.content.sticker; property var stickerData: messageListItem ? messageListItem.myMessage.content.sticker : overlayFlickable.overlayMessage.content.sticker;
readonly property bool asEmoji: appSettings.showStickersAsEmojis readonly property bool asEmoji: appSettings.showStickersAsEmojis
readonly property bool animated: stickerData.format["@type"] === "stickerFormatTgs" && appSettings.animateStickers readonly property bool animated: stickerData.type["@type"] === "stickerTypeAnimated" && appSettings.animateStickers
readonly property bool stickerVisible: staticStickerLoader.item ? staticStickerLoader.item.visible : readonly property bool stickerVisible: staticStickerLoader.item ? staticStickerLoader.item.visible :
animatedStickerLoader.item ? animatedStickerLoader.item.visible : false animatedStickerLoader.item ? animatedStickerLoader.item.visible : false
readonly property bool isOwnSticker : messageListItem ? messageListItem.isOwnMessage : overlayFlickable.isOwnMessage readonly property bool isOwnSticker : messageListItem ? messageListItem.isOwnMessage : overlayFlickable.isOwnMessage

View file

@ -19,10 +19,9 @@
import QtQuick 2.6 import QtQuick 2.6
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import "../../js/functions.js" as Functions
Grid { Grid {
width: parent.width - ( 2 * x ) width: parent.width - ( 2 * x )
columns: Functions.isWidescreen(appWindow) ? 2 : 1 columns: (appWindow.deviceOrientation & Orientation.LandscapeMask) || Screen.sizeCategory === Screen.Large || Screen.sizeCategory === Screen.ExtraLarge ? 2 : 1
readonly property real columnWidth: width/columns readonly property real columnWidth: width/columns
} }

View file

@ -70,17 +70,6 @@ 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
@ -92,28 +81,6 @@ AccordionItem {
} }
} }
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
}
}
TextSwitch {
width: parent.columnWidth
checked: appSettings.goToQuotedMessage
text: qsTr("Go to quoted message")
description: qsTr("When tapping a quoted message, open it in chat instead of showing it in an overlay.")
automaticCheck: false
onClicked: {
appSettings.goToQuotedMessage = !checked
}
}
ComboBox { ComboBox {
id: feedbackComboBox id: feedbackComboBox
width: parent.columnWidth width: parent.columnWidth
@ -168,53 +135,35 @@ AccordionItem {
} }
} }
Item { TextSwitch {
// Occupies one grid cell so that the column ends up under the combo box
// in the landscape layout
visible: parent.columns === 2
width: 1
height: 1
}
Column {
enabled: appSettings.notificationFeedback !== AppSettings.NotificationFeedbackNone
width: parent.columnWidth width: parent.columnWidth
checked: appSettings.notificationTurnsDisplayOn && enabled
text: qsTr("Notification turns on the display")
enabled: appSettings.notificationFeedback !== AppSettings.NotificationFeedbackNone
height: enabled ? implicitHeight: 0 height: enabled ? implicitHeight: 0
clip: height < implicitHeight clip: height < implicitHeight
visible: height > 0 visible: height > 0
automaticCheck: false
onClicked: {
appSettings.notificationTurnsDisplayOn = !checked
}
Behavior on height { SmoothedAnimation { duration: 200 } } Behavior on height { SmoothedAnimation { duration: 200 } }
}
TextSwitch { TextSwitch {
checked: appSettings.notificationSuppressContent && enabled width: parent.columnWidth
text: qsTr("Hide content in notifications") checked: appSettings.notificationSoundsEnabled && enabled
enabled: parent.enabled text: qsTr("Enable notification sounds")
automaticCheck: false description: qsTr("When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.")
onClicked: { enabled: appSettings.notificationFeedback !== AppSettings.NotificationFeedbackNone
appSettings.notificationSuppressContent = !checked height: enabled ? implicitHeight: 0
} clip: height < implicitHeight
} visible: height > 0
automaticCheck: false
TextSwitch { onClicked: {
checked: appSettings.notificationTurnsDisplayOn && enabled appSettings.notificationSoundsEnabled = !checked
text: qsTr("Notification turns on the display")
enabled: parent.enabled
automaticCheck: false
onClicked: {
appSettings.notificationTurnsDisplayOn = !checked
}
}
TextSwitch {
checked: appSettings.notificationSoundsEnabled && enabled
text: qsTr("Enable notification sounds")
description: qsTr("When sounds are enabled, Fernschreiber will use the current Sailfish OS notification sound for chats, which can be configured in the system settings.")
enabled: parent.enabled
automaticCheck: false
onClicked: {
appSettings.notificationSoundsEnabled = !checked
}
} }
Behavior on height { SmoothedAnimation { duration: 200 } }
} }
} }
} }

View file

@ -30,183 +30,153 @@ AccordionItem {
Column { Column {
id: activeSessionsItem id: activeSessionsItem
bottomPadding: Theme.paddingMedium bottomPadding: Theme.paddingMedium
property variant activeSessions property variant activeSessions;
property int inactiveSessionsTtlDays property bool loaded : false;
Component.onCompleted: { Component.onCompleted: {
if (!activeSessions) { if (!activeSessions) {
tdLibWrapper.getActiveSessions(); tdLibWrapper.getActiveSessions();
} else {
activeSessionsItem.loaded = true;
} }
} }
Connections { Connections {
target: tdLibWrapper target: tdLibWrapper
onSessionsReceived: { onSessionsReceived: {
activeSessionsItem.activeSessions = sessions activeSessionsItem.activeSessions = sessions;
activeSessionsItem.inactiveSessionsTtlDays = inactive_session_ttl_days activeSessionsItem.loaded = true;
} }
onOkReceived: { onOkReceived: {
if (request === "terminateSession") { if (request === "terminateSession") {
appNotification.show(qsTr("Session was terminated")); appNotification.show(qsTr("Session was terminated"));
activeSessionsItem.loaded = false;
tdLibWrapper.getActiveSessions(); tdLibWrapper.getActiveSessions();
} }
} }
} }
Loader { Loader {
id: sessionInformationLoader
active: tdLibWrapper.authorizationState === TelegramAPI.AuthorizationReady active: tdLibWrapper.authorizationState === TelegramAPI.AuthorizationReady
width: parent.width width: parent.width
sourceComponent: Component { sourceComponent: Component {
Column { SilicaListView {
BusyIndicator { id: activeSessionsListView
anchors.horizontalCenter: parent.horizontalCenter width: parent.width
running: !activeSessionsListView.count && !activeSessionsItem.inactiveSessionsTtlDays height: contentHeight
size: BusyIndicatorSize.Medium model: activeSessionsItem.activeSessions
visible: opacity > 0 headerPositioning: ListView.OverlayHeader
height: running ? implicitHeight : 0 header: Separator {
}
SilicaListView {
id: activeSessionsListView
width: parent.width width: parent.width
height: contentHeight color: Theme.primaryColor
model: activeSessionsItem.activeSessions horizontalAlignment: Qt.AlignHCenter
headerPositioning: ListView.OverlayHeader }
header: Separator { delegate: ListItem {
id: activeSessionListItem
width: parent.width
contentHeight: activeSessionColumn.height + ( 2 * Theme.paddingMedium )
menu: ContextMenu {
hasContent: !modelData.is_current
onHeightChanged: {
if (parent && flickable) {
// Make sure we are inside the screen area
var bottom = parent.mapToItem(flickable, x, y).y + height
if (bottom > flickable.height) {
flickable.contentY += bottom - flickable.height
}
}
}
MenuItem {
onClicked: {
var sessionId = modelData.id;
Remorse.itemAction(activeSessionListItem, qsTr("Terminating session"), function() { tdLibWrapper.terminateSession(sessionId); });
}
text: qsTr("Terminate Session")
}
}
Column {
id: activeSessionColumn
width: parent.width - ( 2 * Theme.horizontalPageMargin )
spacing: Theme.paddingSmall
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
Label {
width: parent.width
text: qsTr("This app")
font.pixelSize: Theme.fontSizeMedium
font.bold: true
visible: modelData.is_current
color: Theme.highlightColor
anchors {
horizontalCenter: parent.horizontalCenter
}
}
Label {
width: parent.width
text: modelData.application_name + " " + modelData.application_version
font.pixelSize: Theme.fontSizeMedium
font.bold: true
color: Theme.primaryColor
maximumLineCount: 1
elide: Text.ElideRight
anchors {
horizontalCenter: parent.horizontalCenter
}
}
Label {
width: parent.width
text: modelData.device_model + ", " + (modelData.platform + " " + modelData.system_version).trim()
font.pixelSize: Theme.fontSizeSmall
color: Theme.primaryColor
maximumLineCount: 1
truncationMode: TruncationMode.Fade
anchors {
horizontalCenter: parent.horizontalCenter
}
}
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 {
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))
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.primaryColor
maximumLineCount: 1
truncationMode: TruncationMode.Fade
anchors {
horizontalCenter: parent.horizontalCenter
}
}
}
Separator {
id: separator
anchors {
bottom: parent.bottom
}
width: parent.width width: parent.width
color: Theme.primaryColor color: Theme.primaryColor
horizontalAlignment: Qt.AlignHCenter horizontalAlignment: Qt.AlignHCenter
visible: activeSessionsListView.count > 0
}
delegate: ListItem {
id: activeSessionListItem
width: parent.width
contentHeight: activeSessionColumn.height + ( 2 * Theme.paddingMedium )
menu: ContextMenu {
hasContent: !modelData.is_current
onHeightChanged: {
if (parent && flickable) {
// Make sure we are inside the screen area
var bottom = parent.mapToItem(flickable, x, y).y + height
if (bottom > flickable.height) {
flickable.contentY += bottom - flickable.height
}
}
}
MenuItem {
onClicked: {
var sessionId = modelData.id;
Remorse.itemAction(activeSessionListItem, qsTr("Terminating session"), function() { tdLibWrapper.terminateSession(sessionId); });
}
text: qsTr("Terminate Session")
}
}
Column {
id: activeSessionColumn
width: parent.width - ( 2 * Theme.horizontalPageMargin )
spacing: Theme.paddingSmall
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
Label {
width: parent.width
text: qsTr("This app")
font.pixelSize: Theme.fontSizeMedium
font.bold: true
visible: modelData.is_current
color: Theme.highlightColor
}
Label {
width: parent.width
text: modelData.application_name + " " + modelData.application_version
font.pixelSize: Theme.fontSizeMedium
font.bold: true
maximumLineCount: 1
elide: Text.ElideRight
}
Label {
width: parent.width
text: modelData.device_model + ", " + (modelData.platform + " " + modelData.system_version).trim()
font.pixelSize: Theme.fontSizeSmall
maximumLineCount: 1
truncationMode: TruncationMode.Fade
}
Label {
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))
font.pixelSize: Theme.fontSizeExtraSmall
maximumLineCount: 1
truncationMode: TruncationMode.Fade
}
}
Separator {
anchors {
bottom: parent.bottom
}
width: parent.width
color: Theme.primaryColor
horizontalAlignment: Qt.AlignHCenter
}
}
}
ComboBox {
readonly property int ttl: activeSessionsItem.inactiveSessionsTtlDays
label: qsTr("Session Timeout")
description: qsTr("Inactive sessions will be terminated after this timeframe")
value: (currentItem && currentItem.text) ? currentItem.text : qsTr("%1 day(s)", "", ttl).arg(ttl)
visible: ttl > 0
menu: ContextMenu {
id: ttlMenu
MenuItem {
readonly property int days: 7
text: qsTr("1 week")
onClicked: tdLibWrapper.setInactiveSessionTtl(days)
}
MenuItem {
readonly property int days: 30
text: qsTr("1 month")
onClicked: tdLibWrapper.setInactiveSessionTtl(days)
}
MenuItem {
readonly property int days: 90
text: qsTr("3 months")
onClicked: tdLibWrapper.setInactiveSessionTtl(days)
}
MenuItem {
readonly property int days: 180
text: qsTr("6 months")
onClicked: tdLibWrapper.setInactiveSessionTtl(days)
}
MenuItem {
readonly property int days: 365
text: qsTr("1 year")
onClicked: tdLibWrapper.setInactiveSessionTtl(days)
}
} }
Component.onCompleted: updateSelection()
onTtlChanged: updateSelection()
function updateSelection() {
var menuItems = ttlMenu.children
var n = menuItems.length
for (var i = 0; i < n; i++) {
if (menuItems[i].days === ttl) {
currentIndex = i
return
}
}
currentIndex = -1
}
} }
} }
} }

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.usernames.editable_username text: userInformation.username
width: parent.columnWidth width: parent.columnWidth
headerLeftAligned: true headerLeftAligned: true

View file

@ -27,14 +27,6 @@ function setGlobals(globals) {
tdLibWrapper = globals.tdLibWrapper; tdLibWrapper = globals.tdLibWrapper;
appNotification = globals.appNotification; appNotification = globals.appNotification;
} }
function formatUnreadCount(value) {
if(value < 1000) {
return value;
} else if(value > 9000) {
return '9k+';
}
return ''+Math.floor(value / 1000)+'k'+((value % 1000)>0 ? '+' : '');
}
function getUserName(userInformation) { function getUserName(userInformation) {
return ((userInformation.first_name || "") + " " + (userInformation.last_name || "")).trim(); return ((userInformation.first_name || "") + " " + (userInformation.last_name || "")).trim();
@ -535,7 +527,3 @@ function getMessagesNeededForwardPermissions(messages) {
} }
return neededPermissions return neededPermissions
} }
function isWidescreen(appWindow) {
return (appWindow.deviceOrientation & Silica.Orientation.LandscapeMask) || Silica.Screen.sizeCategory === Silica.Screen.Large || Silica.Screen.sizeCategory === Silica.Screen.ExtraLarge
}

View file

@ -54,7 +54,6 @@ Page {
property bool iterativeInitialization: false; property bool iterativeInitialization: false;
property var messageToShow; property var messageToShow;
property string messageIdToShow; property string messageIdToShow;
property string messageIdToScrollTo;
readonly property bool userIsMember: ((isPrivateChat || isSecretChat) && chatInformation["@type"]) || // should be optimized readonly property bool userIsMember: ((isPrivateChat || isSecretChat) && chatInformation["@type"]) || // should be optimized
(isBasicGroup || isSuperGroup) && ( (isBasicGroup || isSuperGroup) && (
(chatGroupInformation.status["@type"] === "chatMemberStatusMember") (chatGroupInformation.status["@type"] === "chatMemberStatusMember")
@ -64,13 +63,9 @@ Page {
) )
property var selectedMessages: [] property var selectedMessages: []
readonly property bool isSelecting: selectedMessages.length > 0 readonly property bool isSelecting: selectedMessages.length > 0
readonly property bool canSendMessages: hasSendPrivilege("can_send_basic_messages") readonly property bool canSendMessages: hasSendPrivilege("can_send_messages")
property bool doSendBotStartMessage property bool doSendBotStartMessage
property string sendBotStartMessageParameter property string sendBotStartMessageParameter
property var availableReactions
signal resetElements()
signal elementSelected(int elementIndex)
signal navigatedTo(int targetIndex)
states: [ states: [
State { State {
@ -189,7 +184,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) {
@ -411,24 +406,6 @@ Page {
chatPage.focus = true; chatPage.focus = true;
} }
function showMessage(messageId, initialRun) {
// Means we tapped a quoted message and had to load it.
if(initialRun) {
chatPage.messageIdToScrollTo = messageId
}
if (chatPage.messageIdToScrollTo && chatPage.messageIdToScrollTo != "") {
var index = chatModel.getMessageIndex(chatPage.messageIdToScrollTo);
if(index !== -1) {
chatPage.messageIdToScrollTo = "";
chatView.scrollToIndex(index);
navigatedTo(index);
} else if(initialRun) {
// we only want to do this once.
chatModel.triggerLoadHistoryForMessage(chatPage.messageIdToScrollTo)
}
}
}
Timer { Timer {
id: forwardMessagesTimer id: forwardMessagesTimer
interval: 200 interval: 200
@ -462,8 +439,7 @@ 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);
@ -502,10 +478,7 @@ Page {
if (pageStack.depth === 1) { if (pageStack.depth === 1) {
// Only clear chat model if navigated back to overview page. In other cases we keep the information... // Only clear chat model if navigated back to overview page. In other cases we keep the information...
chatModel.clear(); chatModel.clear();
} else {
resetElements();
} }
break; break;
} }
} }
@ -589,12 +562,12 @@ Page {
} }
} }
onUserFullInfoReceived: { onUserFullInfoReceived: {
if ((isPrivateChat || isSecretChat) && userFullInfo["@extra"] === chatPartnerInformation.id.toString()) { if(userFullInfo["@extra"] === chatPartnerInformation.id.toString()) {
chatPage.botInformation = userFullInfo; chatPage.botInformation = userFullInfo;
} }
} }
onUserFullInfoUpdated: { onUserFullInfoUpdated: {
if ((isPrivateChat || isSecretChat) && userId === chatPartnerInformation.id) { if(userId === chatPartnerInformation.id) {
chatPage.botInformation = userFullInfo; chatPage.botInformation = userFullInfo;
} }
} }
@ -634,15 +607,6 @@ Page {
chatViewCooldownTimer.restart(); chatViewCooldownTimer.restart();
chatViewStartupReadTimer.restart(); chatViewStartupReadTimer.restart();
var remainingDoubleTapHints = appSettings.remainingDoubleTapHints;
Debug.log("Remaining double tap hints: " + remainingDoubleTapHints);
if (remainingDoubleTapHints > 0) {
doubleTapHintTimer.start();
tapHint.visible = true;
tapHintLabel.visible = true;
appSettings.remainingDoubleTapHints = remainingDoubleTapHints - 1;
}
} }
onNewMessageReceived: { onNewMessageReceived: {
if (( chatView.manuallyScrolledToBottom && Qt.application.state === Qt.ApplicationActive ) || message.sender_id.user_id === chatPage.myUserId) { if (( chatView.manuallyScrolledToBottom && Qt.application.state === Qt.ApplicationActive ) || message.sender_id.user_id === chatPage.myUserId) {
@ -654,8 +618,8 @@ Page {
onUnreadCountUpdated: { onUnreadCountUpdated: {
Debug.log("[ChatPage] Unread count updated, new count: ", unreadCount); Debug.log("[ChatPage] Unread count updated, new count: ", unreadCount);
chatInformation.unread_count = unreadCount; chatInformation.unread_count = unreadCount;
chatUnreadMessagesItem.visible = ( !chatPage.loading && unreadCount > 0 && chatOverviewItem.visible ); chatUnreadMessagesItem.visible = ( !chatPage.loading && chatInformation.unread_count > 0 && chatOverviewItem.visible );
chatUnreadMessagesCount.text = Functions.formatUnreadCount(unreadCount) chatUnreadMessagesCount.text = unreadCount > 99 ? "99+" : unreadCount;
} }
onLastReadSentMessageUpdated: { onLastReadSentMessageUpdated: {
Debug.log("[ChatPage] Updating last read sent index, new index: ", lastReadSentIndex); Debug.log("[ChatPage] Updating last read sent index, new index: ", lastReadSentIndex);
@ -670,8 +634,6 @@ Page {
if (chatView.height > chatView.contentHeight) { if (chatView.height > chatView.contentHeight) {
Debug.log("[ChatPage] Chat content quite small..."); Debug.log("[ChatPage] Chat content quite small...");
viewMessageTimer.queueViewMessage(chatView.count - 1); viewMessageTimer.queueViewMessage(chatView.count - 1);
} else if (chatPage.messageIdToScrollTo && chatPage.messageIdToScrollTo != "") {
showMessage(chatPage.messageIdToScrollTo, false)
} }
chatViewCooldownTimer.restart(); chatViewCooldownTimer.restart();
chatViewStartupReadTimer.restart(); chatViewStartupReadTimer.restart();
@ -1208,7 +1170,7 @@ Page {
readonly property int profileThumbnailDimensions: showUserInfo ? Theme.itemSizeSmall : 0 readonly property int profileThumbnailDimensions: showUserInfo ? Theme.itemSizeSmall : 0
readonly property int pageMarginDouble: 2 * Theme.horizontalPageMargin readonly property int pageMarginDouble: 2 * Theme.horizontalPageMargin
readonly property int paddingMediumDouble: 2 * Theme.paddingMedium readonly property int paddingMediumDouble: 2 * Theme.paddingMedium
readonly property int entryWidth: chatView.width - pageMarginDouble readonly property int entryWidth: chatView.width - pageMarginDouble //ширина полной строки сообщения вместе с аватаркой
readonly property int textItemWidth: entryWidth - profileThumbnailDimensions - Theme.paddingSmall readonly property int textItemWidth: entryWidth - profileThumbnailDimensions - Theme.paddingSmall
readonly property int backgroundWidth: page.isPrivateChat ? textItemWidth - pageMarginDouble : textItemWidth //уменьшенная ширина сообщений для приватных чатов readonly property int backgroundWidth: page.isPrivateChat ? textItemWidth - pageMarginDouble : textItemWidth //уменьшенная ширина сообщений для приватных чатов
readonly property int backgroundRadius: textItemWidth/50 readonly property int backgroundRadius: textItemWidth/50
@ -1234,9 +1196,10 @@ Page {
manuallyScrolledToBottom = chatView.atYEnd manuallyScrolledToBottom = chatView.atYEnd
} }
function scrollToIndex(index, mode) { function scrollToIndex(index) {
if(index > 0 && index < chatView.count) { if(index > 0 && index < chatView.count) {
positionViewAtIndex(index, (mode === undefined) ? ListView.Contain : mode) positionViewAtIndex(index, ListView.Contain)
// currentIndex = index;
if(index === chatView.count - 1) { if(index === chatView.count - 1) {
manuallyScrolledToBottom = true; manuallyScrolledToBottom = true;
} }
@ -1385,7 +1348,6 @@ 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
@ -1465,7 +1427,7 @@ Page {
color: Theme.primaryColor color: Theme.primaryColor
anchors.centerIn: chatUnreadMessagesCountBackground anchors.centerIn: chatUnreadMessagesCountBackground
visible: chatUnreadMessagesItem.visible visible: chatUnreadMessagesItem.visible
text: Functions.formatUnreadCount(chatInformation.unread_count) text: chatInformation.unread_count > 99 ? "99+" : chatInformation.unread_count
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
@ -1634,7 +1596,7 @@ Page {
IconButton { IconButton {
id: attachImageIconButton id: attachImageIconButton
visible: chatPage.hasSendPrivilege("can_send_photos") visible: chatPage.hasSendPrivilege("can_send_media_messages")
icon.source: "image://theme/icon-m-image" icon.source: "image://theme/icon-m-image"
onClicked: { onClicked: {
var picker = pageStack.push("Sailfish.Pickers.ImagePickerPage", { var picker = pageStack.push("Sailfish.Pickers.ImagePickerPage", {
@ -1650,7 +1612,7 @@ Page {
} }
} }
IconButton { IconButton {
visible: chatPage.hasSendPrivilege("can_send_videos") visible: chatPage.hasSendPrivilege("can_send_media_messages")
icon.source: "image://theme/icon-m-video" icon.source: "image://theme/icon-m-video"
onClicked: { onClicked: {
var picker = pageStack.push("Sailfish.Pickers.VideoPickerPage", { var picker = pageStack.push("Sailfish.Pickers.VideoPickerPage", {
@ -1666,7 +1628,7 @@ Page {
} }
} }
IconButton { IconButton {
visible: chatPage.hasSendPrivilege("can_send_voice_notes") visible: chatPage.hasSendPrivilege("can_send_media_messages")
icon.source: "image://theme/icon-m-mic" icon.source: "image://theme/icon-m-mic"
icon.sourceSize { icon.sourceSize {
width: Theme.iconSizeMedium width: Theme.iconSizeMedium
@ -1679,7 +1641,7 @@ Page {
} }
} }
IconButton { IconButton {
visible: chatPage.hasSendPrivilege("can_send_documents") visible: chatPage.hasSendPrivilege("can_send_media_messages")
icon.source: "image://theme/icon-m-document" icon.source: "image://theme/icon-m-document"
onClicked: { onClicked: {
var picker = pageStack.push("Sailfish.Pickers.FilePickerPage", { var picker = pageStack.push("Sailfish.Pickers.FilePickerPage", {
@ -2192,31 +2154,4 @@ Page {
} }
} }
} }
Timer {
id: doubleTapHintTimer
running: true
triggeredOnStart: false
repeat: false
interval: 6000
onTriggered: {
tapHint.visible = false;
tapHintLabel.visible = false;
}
}
TapInteractionHint {
id: tapHint
loops: Animation.Infinite
taps: 2
anchors.centerIn: parent
visible: false
}
InteractionHintLabel {
id: tapHintLabel
anchors.bottom: parent.bottom
text: qsTr("Double-tap on a message to choose a reaction")
visible: false
}
} }

View file

@ -143,11 +143,10 @@ Page {
Connections { Connections {
target: tdLibWrapper target: tdLibWrapper
onMessageSendersReceived: { onUsersReceived: {
Debug.log("Received poll users...")
if(extra === optionDelegate.usersResponseIdentifierString) { if(extra === optionDelegate.usersResponseIdentifierString) {
for(var i = 0; i < senders.length; i += 1) { for(var i = 0; i < userIds.length; i += 1) {
optionDelegate.users.append({id: senders[i].user_id, user:tdLibWrapper.getUserInformation(senders[i].user_id)}); optionDelegate.users.append({id: userIds[i], user:tdLibWrapper.getUserInformation(userIds[i])});
} }
loadUsersTimer.start(); loadUsersTimer.start();
} }

View file

@ -12,26 +12,6 @@
# * date Author's Name <author's email> version-release # * date Author's Name <author's email> version-release
# - Summary of changes # - Summary of changes
* Sun Dec 03 2023 Sebastian J. Wolf <sebastian@ygriega.de> 0.17
- Update to TDLib 1.8.21, expect some hiccups ;)
- Added contacts sync (OpenRepos builds only)
- Tweaks to reaction handling (opens now on double click or click + star)
- Option to jump to quoted message
- Option to highlight unread conversations
- Option to suppress notification previews
- Option to append last message content to notifications
- Added "unread mention" indicator to chat list
- Improve message when search yields no results
- New unread info for chats with high amount of unread messages
- Setting for session inactivity timeout
- UI improvements in landscape mode
- Fix: Restore video functionality on SFOS 4.5
- Fix: Chat list timestamp now updated more reliably
- Fix: Faster reconnect after network changes
- Fix: Some URLs couldn't be opened
- Updated translations for several languages
- Thanks to monich, nephros, arustg, jgibbon, carlosgonz0, okruhliak, dscheinah, pherjung and mbarashkov for your contributions
* Sun Jun 12 2022 Sebastian J. Wolf <sebastian@ygriega.de> 0.16 * Sun Jun 12 2022 Sebastian J. Wolf <sebastian@ygriega.de> 0.16
- Support message reactions - Support message reactions
- Support t.me/+... links - Support t.me/+... links

View file

@ -10,9 +10,9 @@ Name: harbour-fernschreiber
%define __requires_exclude ^lib(tdjson|ssl|crypto).*$ %define __requires_exclude ^lib(tdjson|ssl|crypto).*$
# << macros # << macros
Summary: Fernschreiber is a Telegram client for Aurora OS Summary: Fernschreiber is a Telegram client for Sailfish OS
Version: 0.17 Version: 0.17
Release: 12 Release: 3
Group: Qt/Qt Group: Qt/Qt
License: LICENSE License: LICENSE
URL: http://werkwolf.eu/ URL: http://werkwolf.eu/

View file

@ -29,19 +29,14 @@ 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_GO_TO_QUOTED_MESSAGE("goToQuotedMessage");
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");
const QString KEY_REMAINING_DOUBLE_TAP_HINTS("remainingDoubleTapHints");
const QString KEY_ONLINE_ONLY_MODE("onlineOnlyMode"); const QString KEY_ONLINE_ONLY_MODE("onlineOnlyMode");
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)
@ -160,20 +155,6 @@ 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();
@ -188,34 +169,6 @@ 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::goToQuotedMessage() const
{
return settings.value(KEY_GO_TO_QUOTED_MESSAGE, false).toBool();
}
void AppSettings::setGoToQuotedMessage(bool enable)
{
if (goToQuotedMessage() != enable) {
LOG(KEY_GO_TO_QUOTED_MESSAGE << enable);
settings.setValue(KEY_GO_TO_QUOTED_MESSAGE, enable);
emit goToQuotedMessageChanged();
}
}
bool AppSettings::storageOptimizer() const bool AppSettings::storageOptimizer() const
{ {
return settings.value(KEY_STORAGE_OPTIMIZER, true).toBool(); return settings.value(KEY_STORAGE_OPTIMIZER, true).toBool();
@ -259,20 +212,6 @@ void AppSettings::setRemainingInteractionHints(int remainingHints)
} }
} }
int AppSettings::remainingDoubleTapHints() const
{
return settings.value(KEY_REMAINING_DOUBLE_TAP_HINTS, 3).toInt();
}
void AppSettings::setRemainingDoubleTapHints(int remainingHints)
{
if (remainingDoubleTapHints() != remainingHints) {
LOG(KEY_REMAINING_DOUBLE_TAP_HINTS << remainingHints);
settings.setValue(KEY_REMAINING_DOUBLE_TAP_HINTS, remainingHints);
emit remainingDoubleTapHintsChanged();
}
}
bool AppSettings::onlineOnlyMode() const bool AppSettings::onlineOnlyMode() const
{ {
return settings.value(KEY_ONLINE_ONLY_MODE, false).toBool(); return settings.value(KEY_ONLINE_ONLY_MODE, false).toBool();
@ -301,20 +240,6 @@ 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,19 +32,14 @@ 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 goToQuotedMessage READ goToQuotedMessage WRITE setGoToQuotedMessage NOTIFY goToQuotedMessageChanged)
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)
Q_PROPERTY(int remainingDoubleTapHints READ remainingDoubleTapHints WRITE setRemainingDoubleTapHints NOTIFY remainingDoubleTapHintsChanged)
Q_PROPERTY(bool onlineOnlyMode READ onlineOnlyMode WRITE setOnlineOnlyMode NOTIFY onlineOnlyModeChanged) Q_PROPERTY(bool onlineOnlyMode READ onlineOnlyMode WRITE setOnlineOnlyMode NOTIFY onlineOnlyModeChanged)
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 {
@ -88,18 +83,9 @@ 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 goToQuotedMessage() const;
void setGoToQuotedMessage(bool enable);
bool storageOptimizer() const; bool storageOptimizer() const;
void setStorageOptimizer(bool enable); void setStorageOptimizer(bool enable);
@ -109,9 +95,6 @@ public:
int remainingInteractionHints() const; int remainingInteractionHints() const;
void setRemainingInteractionHints(int remainingHints); void setRemainingInteractionHints(int remainingHints);
int remainingDoubleTapHints() const;
void setRemainingDoubleTapHints(int remainingHints);
bool onlineOnlyMode() const; bool onlineOnlyMode() const;
void setOnlineOnlyMode(bool enable); void setOnlineOnlyMode(bool enable);
@ -124,9 +107,6 @@ 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();
@ -136,19 +116,14 @@ signals:
void animateStickersChanged(); void animateStickersChanged();
void notificationTurnsDisplayOnChanged(); void notificationTurnsDisplayOnChanged();
void notificationSoundsEnabledChanged(); void notificationSoundsEnabledChanged();
void notificationSuppressContentChanged();
void notificationFeedbackChanged(); void notificationFeedbackChanged();
void notificationAlwaysShowPreviewChanged();
void goToQuotedMessageChanged();
void storageOptimizerChanged(); void storageOptimizerChanged();
void allowInlineBotLocationAccessChanged(); void allowInlineBotLocationAccessChanged();
void remainingInteractionHintsChanged(); void remainingInteractionHintsChanged();
void remainingDoubleTapHintsChanged();
void onlineOnlyModeChanged(); void onlineOnlyModeChanged();
void delayMessageReadChanged(); void delayMessageReadChanged();
void focusTextAreaOnChatOpenChanged(); void focusTextAreaOnChatOpenChanged();
void sponsoredMessChanged(); void sponsoredMessChanged();
void highlightUnreadConversationsChanged();
private: private:
QSettings settings; QSettings settings;

View file

@ -44,7 +44,6 @@ namespace {
const QString UNREAD_COUNT("unread_count"); const QString UNREAD_COUNT("unread_count");
const QString UNREAD_MENTION_COUNT("unread_mention_count"); const QString UNREAD_MENTION_COUNT("unread_mention_count");
const QString UNREAD_REACTION_COUNT("unread_reaction_count"); const QString UNREAD_REACTION_COUNT("unread_reaction_count");
const QString AVAILABLE_REACTIONS("available_reactions");
const QString NOTIFICATION_SETTINGS("notification_settings"); const QString NOTIFICATION_SETTINGS("notification_settings");
const QString LAST_READ_INBOX_MESSAGE_ID("last_read_inbox_message_id"); const QString LAST_READ_INBOX_MESSAGE_ID("last_read_inbox_message_id");
const QString LAST_READ_OUTBOX_MESSAGE_ID("last_read_outbox_message_id"); const QString LAST_READ_OUTBOX_MESSAGE_ID("last_read_outbox_message_id");
@ -71,7 +70,6 @@ public:
int unreadCount() const; int unreadCount() const;
int unreadMentionCount() const; int unreadMentionCount() const;
int unreadReactionCount() const; int unreadReactionCount() const;
QVariant availableReactions() const;
QVariant photoSmall() const; QVariant photoSmall() const;
qlonglong lastReadInboxMessageId() const; qlonglong lastReadInboxMessageId() const;
qlonglong senderUserId() const; qlonglong senderUserId() const;
@ -170,11 +168,6 @@ int ChatListModel::ChatData::unreadMentionCount() const
return chatData.value(UNREAD_MENTION_COUNT).toInt(); return chatData.value(UNREAD_MENTION_COUNT).toInt();
} }
QVariant ChatListModel::ChatData::availableReactions() const
{
return chatData.value(AVAILABLE_REACTIONS);
}
int ChatListModel::ChatData::unreadReactionCount() const int ChatListModel::ChatData::unreadReactionCount() const
{ {
return chatData.value(UNREAD_REACTION_COUNT).toInt(); return chatData.value(UNREAD_REACTION_COUNT).toInt();
@ -407,7 +400,6 @@ ChatListModel::ChatListModel(TDLibWrapper *tdLibWrapper, AppSettings *appSetting
connect(tdLibWrapper, SIGNAL(chatDraftMessageUpdated(qlonglong, QVariantMap, QString)), this, SLOT(handleChatDraftMessageUpdated(qlonglong, QVariantMap, QString))); connect(tdLibWrapper, SIGNAL(chatDraftMessageUpdated(qlonglong, QVariantMap, QString)), this, SLOT(handleChatDraftMessageUpdated(qlonglong, QVariantMap, QString)));
connect(tdLibWrapper, SIGNAL(chatUnreadMentionCountUpdated(qlonglong, int)), this, SLOT(handleChatUnreadMentionCountUpdated(qlonglong, int))); connect(tdLibWrapper, SIGNAL(chatUnreadMentionCountUpdated(qlonglong, int)), this, SLOT(handleChatUnreadMentionCountUpdated(qlonglong, int)));
connect(tdLibWrapper, SIGNAL(chatUnreadReactionCountUpdated(qlonglong, int)), this, SLOT(handleChatUnreadReactionCountUpdated(qlonglong, int))); connect(tdLibWrapper, SIGNAL(chatUnreadReactionCountUpdated(qlonglong, int)), this, SLOT(handleChatUnreadReactionCountUpdated(qlonglong, int)));
connect(tdLibWrapper, SIGNAL(chatAvailableReactionsUpdated(qlonglong,QVariantMap)), this, SLOT(handleChatAvailableReactionsUpdated(qlonglong,QVariantMap)));
// Don't start the timer until we have at least one chat // Don't start the timer until we have at least one chat
relativeTimeRefreshTimer = new QTimer(this); relativeTimeRefreshTimer = new QTimer(this);
@ -444,7 +436,6 @@ QHash<int,QByteArray> ChatListModel::roleNames() const
roles.insert(ChatListModel::RoleUnreadCount, "unread_count"); roles.insert(ChatListModel::RoleUnreadCount, "unread_count");
roles.insert(ChatListModel::RoleUnreadMentionCount, "unread_mention_count"); roles.insert(ChatListModel::RoleUnreadMentionCount, "unread_mention_count");
roles.insert(ChatListModel::RoleUnreadReactionCount, "unread_reaction_count"); roles.insert(ChatListModel::RoleUnreadReactionCount, "unread_reaction_count");
roles.insert(ChatListModel::RoleAvailableReactions, "available_reactions");
roles.insert(ChatListModel::RoleLastReadInboxMessageId, "last_read_inbox_message_id"); roles.insert(ChatListModel::RoleLastReadInboxMessageId, "last_read_inbox_message_id");
roles.insert(ChatListModel::RoleLastMessageSenderId, "last_message_sender_id"); roles.insert(ChatListModel::RoleLastMessageSenderId, "last_message_sender_id");
roles.insert(ChatListModel::RoleLastMessageDate, "last_message_date"); roles.insert(ChatListModel::RoleLastMessageDate, "last_message_date");
@ -481,7 +472,6 @@ QVariant ChatListModel::data(const QModelIndex &index, int role) const
case ChatListModel::RolePhotoSmall: return data->photoSmall(); case ChatListModel::RolePhotoSmall: return data->photoSmall();
case ChatListModel::RoleUnreadCount: return data->unreadCount(); case ChatListModel::RoleUnreadCount: return data->unreadCount();
case ChatListModel::RoleUnreadMentionCount: return data->unreadMentionCount(); case ChatListModel::RoleUnreadMentionCount: return data->unreadMentionCount();
case ChatListModel::RoleAvailableReactions: return data->availableReactions();
case ChatListModel::RoleUnreadReactionCount: return data->unreadReactionCount(); case ChatListModel::RoleUnreadReactionCount: return data->unreadReactionCount();
case ChatListModel::RoleLastReadInboxMessageId: return data->lastReadInboxMessageId(); case ChatListModel::RoleLastReadInboxMessageId: return data->lastReadInboxMessageId();
case ChatListModel::RoleLastMessageSenderId: return data->senderUserId(); case ChatListModel::RoleLastMessageSenderId: return data->senderUserId();
@ -571,15 +561,6 @@ int ChatListModel::updateChatOrder(int chatIndex)
return newIndex; return newIndex;
} }
void ChatListModel::enableRefreshTimer()
{
// Start timestamp refresh timer if not yet active (usually when the first visible chat is discovered)
if (!relativeTimeRefreshTimer->isActive()) {
LOG("Enabling refresh timer");
relativeTimeRefreshTimer->start();
}
}
void ChatListModel::calculateUnreadState() void ChatListModel::calculateUnreadState()
{ {
if (this->appSettings->onlineOnlyMode()) { if (this->appSettings->onlineOnlyMode()) {
@ -618,7 +599,6 @@ void ChatListModel::addVisibleChat(ChatData *chat)
this->tdLibWrapper->registerJoinChat(); this->tdLibWrapper->registerJoinChat();
emit chatJoined(chat->chatId, chat->chatData.value("title").toString()); emit chatJoined(chat->chatId, chat->chatData.value("title").toString());
} }
enableRefreshTimer();
} }
void ChatListModel::updateChatVisibility(const TDLibWrapper::Group *group) void ChatListModel::updateChatVisibility(const TDLibWrapper::Group *group)
@ -707,7 +687,6 @@ void ChatListModel::setShowAllChats(bool showAll)
void ChatListModel::handleChatDiscovered(const QString &, const QVariantMap &chatToBeAdded) void ChatListModel::handleChatDiscovered(const QString &, const QVariantMap &chatToBeAdded)
{ {
LOG("New chat discovered");
ChatData *chat = new ChatData(tdLibWrapper, chatToBeAdded); ChatData *chat = new ChatData(tdLibWrapper, chatToBeAdded);
const TDLibWrapper::Group *group = tdLibWrapper->getGroup(chat->groupId); const TDLibWrapper::Group *group = tdLibWrapper->getGroup(chat->groupId);
@ -726,8 +705,12 @@ void ChatListModel::handleChatDiscovered(const QString &, const QVariantMap &cha
LOG("Hidden chat" << chat->chatId); LOG("Hidden chat" << chat->chatId);
hiddenChats.insert(chat->chatId, chat); hiddenChats.insert(chat->chatId, chat);
} else { } else {
LOG("Visible chat" << chat->chatId);
addVisibleChat(chat); addVisibleChat(chat);
// Start timestamp refresh timer when the first visible chat is discovered
if (!relativeTimeRefreshTimer->isActive()) {
relativeTimeRefreshTimer->start();
}
} }
} }
@ -1046,31 +1029,10 @@ void ChatListModel::handleChatUnreadReactionCountUpdated(qlonglong chatId, int u
} }
} }
void ChatListModel::handleChatAvailableReactionsUpdated(qlonglong chatId, const QVariantMap availableReactions)
{
if (chatIndexMap.contains(chatId)) {
LOG("Updating available reaction type for" << chatId << availableReactions);
const int chatIndex = chatIndexMap.value(chatId);
ChatData *chat = chatList.at(chatIndex);
chat->chatData.insert(AVAILABLE_REACTIONS, availableReactions);
QVector<int> changedRoles;
changedRoles.append(ChatListModel::RoleAvailableReactions);
const QModelIndex modelIndex(index(chatIndex));
emit dataChanged(modelIndex, modelIndex, changedRoles);
} else {
ChatData *chat = hiddenChats.value(chatId);
if (chat) {
LOG("Updating available reaction type for hidden chat" << chatId << availableReactions);
chat->chatData.insert(AVAILABLE_REACTIONS, availableReactions);
}
}
}
void ChatListModel::handleRelativeTimeRefreshTimer() void ChatListModel::handleRelativeTimeRefreshTimer()
{ {
LOG("Refreshing timestamps"); LOG("Refreshing timestamps");
QVector<int> roles; QVector<int> roles;
roles.append(ChatListModel::RoleLastMessageDate); roles.append(ChatListModel::RoleLastMessageDate);
roles.append(ChatListModel::RoleLastMessageStatus);
emit dataChanged(index(0), index(chatList.size() - 1), roles); emit dataChanged(index(0), index(chatList.size() - 1), roles);
} }

View file

@ -42,7 +42,6 @@ public:
RoleUnreadCount, RoleUnreadCount,
RoleUnreadMentionCount, RoleUnreadMentionCount,
RoleUnreadReactionCount, RoleUnreadReactionCount,
RoleAvailableReactions,
RoleLastReadInboxMessageId, RoleLastReadInboxMessageId,
RoleLastMessageSenderId, RoleLastMessageSenderId,
RoleLastMessageDate, RoleLastMessageDate,
@ -94,7 +93,6 @@ private slots:
void handleChatDraftMessageUpdated(qlonglong chatId, const QVariantMap &draftMessage, const QString &order); void handleChatDraftMessageUpdated(qlonglong chatId, const QVariantMap &draftMessage, const QString &order);
void handleChatUnreadMentionCountUpdated(qlonglong chatId, int unreadMentionCount); void handleChatUnreadMentionCountUpdated(qlonglong chatId, int unreadMentionCount);
void handleChatUnreadReactionCountUpdated(qlonglong chatId, int unreadReactionCount); void handleChatUnreadReactionCountUpdated(qlonglong chatId, int unreadReactionCount);
void handleChatAvailableReactionsUpdated(qlonglong chatId, const QVariantMap availableReactions);
void handleRelativeTimeRefreshTimer(); void handleRelativeTimeRefreshTimer();
signals: signals:
@ -110,7 +108,6 @@ private:
void updateChatVisibility(const TDLibWrapper::Group *group); void updateChatVisibility(const TDLibWrapper::Group *group);
void updateSecretChatVisibility(const QVariantMap secretChatDetails); void updateSecretChatVisibility(const QVariantMap secretChatDetails);
int updateChatOrder(int chatIndex); int updateChatOrder(int chatIndex);
void enableRefreshTimer();
private: private:
TDLibWrapper *tdLibWrapper; TDLibWrapper *tdLibWrapper;

View file

@ -363,15 +363,6 @@ void ChatModel::initialize(const QVariantMap &chatInformation)
tdLibWrapper->getChatHistory(chatId, this->chatInformation.value(LAST_READ_INBOX_MESSAGE_ID).toLongLong()); tdLibWrapper->getChatHistory(chatId, this->chatInformation.value(LAST_READ_INBOX_MESSAGE_ID).toLongLong());
} }
void ChatModel::triggerLoadHistoryForMessage(qlonglong messageId)
{
if (!this->inIncrementalUpdate && !messages.isEmpty()) {
LOG("Trigger loading message with id..." << messageId);
this->inIncrementalUpdate = true;
this->tdLibWrapper->getChatHistory(chatId, messageId);
}
}
void ChatModel::triggerLoadMoreHistory() void ChatModel::triggerLoadMoreHistory()
{ {
if (!this->inIncrementalUpdate && !messages.isEmpty()) { if (!this->inIncrementalUpdate && !messages.isEmpty()) {
@ -409,17 +400,6 @@ QVariantMap ChatModel::getMessage(int index)
return QVariantMap(); return QVariantMap();
} }
int ChatModel::getMessageIndex(qlonglong messageId)
{
if (messages.size() == 0) {
return -1;
}
if (messageIndexMap.contains(messageId)) {
return messageIndexMap.value(messageId);
}
return -1;
}
int ChatModel::getLastReadMessageIndex() int ChatModel::getLastReadMessageIndex()
{ {
LOG("Obtaining last read message index"); LOG("Obtaining last read message index");

View file

@ -40,14 +40,12 @@ public:
Q_INVOKABLE void clear(bool contentOnly = false); Q_INVOKABLE void clear(bool contentOnly = false);
Q_INVOKABLE void initialize(const QVariantMap &chatInformation); Q_INVOKABLE void initialize(const QVariantMap &chatInformation);
Q_INVOKABLE void triggerLoadMoreHistory(); Q_INVOKABLE void triggerLoadMoreHistory();
Q_INVOKABLE void triggerLoadHistoryForMessage(qlonglong messageId);
Q_INVOKABLE void triggerLoadMoreFuture(); Q_INVOKABLE void triggerLoadMoreFuture();
Q_INVOKABLE QVariantMap getChatInformation(); Q_INVOKABLE QVariantMap getChatInformation();
Q_INVOKABLE QVariantMap getMessage(int index); Q_INVOKABLE QVariantMap getMessage(int index);
Q_INVOKABLE int getLastReadMessageIndex(); Q_INVOKABLE int getLastReadMessageIndex();
Q_INVOKABLE void setSearchQuery(const QString newSearchQuery); Q_INVOKABLE void setSearchQuery(const QString newSearchQuery);
Q_INVOKABLE int getMessageIndex(qlonglong messageId);
QVariantMap smallPhoto() const; QVariantMap smallPhoto() const;
qlonglong getChatId() const; qlonglong getChatId() const;

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("usernames").toMap().value("editable_username").toString(); case ContactRole::RoleUsername: return requestedContact.value("username");
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

@ -56,10 +56,10 @@ QVariant KnownUsersModel::data(const QModelIndex &index, int role) const
case KnownUserRole::RoleDisplay: return requestedUser; case KnownUserRole::RoleDisplay: return requestedUser;
case KnownUserRole::RoleUserId: return requestedUser.value("id"); case KnownUserRole::RoleUserId: return requestedUser.value("id");
case KnownUserRole::RoleTitle: return QString(requestedUser.value("first_name").toString() + " " + requestedUser.value("last_name").toString()).trimmed(); case KnownUserRole::RoleTitle: return QString(requestedUser.value("first_name").toString() + " " + requestedUser.value("last_name").toString()).trimmed();
case KnownUserRole::RoleUsername: return requestedUser.value("usernames").toMap().value("editable_username").toString(); case KnownUserRole::RoleUsername: return requestedUser.value("username");
case KnownUserRole::RoleUserHandle: return QString("@" + (requestedUser.value("usernames").toMap().value("editable_username").toString().isEmpty() ? requestedUser.value("id").toString() : requestedUser.value("usernames").toMap().value("editable_username").toString())); case KnownUserRole::RoleUserHandle: return QString("@" + (requestedUser.value("username").toString().isEmpty() ? requestedUser.value("id").toString() : requestedUser.value("username").toString()));
case KnownUserRole::RolePhotoSmall: return requestedUser.value("profile_photo").toMap().value("small"); case KnownUserRole::RolePhotoSmall: return requestedUser.value("profile_photo").toMap().value("small");
case KnownUserRole::RoleFilter: return QString(requestedUser.value("first_name").toString() + " " + requestedUser.value("last_name").toString() + " " + requestedUser.value("usernames").toMap().value("editable_username").toString()).trimmed(); case KnownUserRole::RoleFilter: return QString(requestedUser.value("first_name").toString() + " " + requestedUser.value("last_name").toString() + " " + requestedUser.value("username").toString()).trimmed();
} }
} }
return QVariant(); return QVariant();

View file

@ -341,18 +341,8 @@ 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();
bool outputMessageCount = notificationGroup->totalCount > 1; if (notificationGroup->totalCount == 1 && !messageMap.isEmpty()) {
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
@ -362,9 +352,15 @@ 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());
@ -381,11 +377,7 @@ 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

@ -46,7 +46,6 @@ namespace {
const QString UNREAD_COUNT("unread_count"); const QString UNREAD_COUNT("unread_count");
const QString UNREAD_MENTION_COUNT("unread_mention_count"); const QString UNREAD_MENTION_COUNT("unread_mention_count");
const QString UNREAD_REACTION_COUNT("unread_reaction_count"); const QString UNREAD_REACTION_COUNT("unread_reaction_count");
const QString AVAILABLE_REACTIONS("available_reactions");
const QString TEXT("text"); const QString TEXT("text");
const QString LAST_READ_INBOX_MESSAGE_ID("last_read_inbox_message_id"); const QString LAST_READ_INBOX_MESSAGE_ID("last_read_inbox_message_id");
const QString LAST_READ_OUTBOX_MESSAGE_ID("last_read_outbox_message_id"); const QString LAST_READ_OUTBOX_MESSAGE_ID("last_read_outbox_message_id");
@ -61,11 +60,6 @@ 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");
@ -76,11 +70,8 @@ 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)
@ -124,14 +115,11 @@ TDLibReceiver::TDLibReceiver(void *tdLibClient, QObject *parent) : QThread(paren
handlers.insert("updateChatPosition", &TDLibReceiver::processUpdateChatPosition); handlers.insert("updateChatPosition", &TDLibReceiver::processUpdateChatPosition);
handlers.insert("updateChatReadInbox", &TDLibReceiver::processUpdateChatReadInbox); handlers.insert("updateChatReadInbox", &TDLibReceiver::processUpdateChatReadInbox);
handlers.insert("updateChatReadOutbox", &TDLibReceiver::processUpdateChatReadOutbox); handlers.insert("updateChatReadOutbox", &TDLibReceiver::processUpdateChatReadOutbox);
handlers.insert("updateChatAvailableReactions", &TDLibReceiver::processUpdateChatAvailableReactions);
handlers.insert("updateBasicGroup", &TDLibReceiver::processUpdateBasicGroup); handlers.insert("updateBasicGroup", &TDLibReceiver::processUpdateBasicGroup);
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("foundChatMessages", &TDLibReceiver::processFoundChatMessages); 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);
@ -162,7 +150,6 @@ TDLibReceiver::TDLibReceiver(void *tdLibClient, QObject *parent) : QThread(paren
handlers.insert("updateChatPinnedMessage", &TDLibReceiver::processUpdateChatPinnedMessage); handlers.insert("updateChatPinnedMessage", &TDLibReceiver::processUpdateChatPinnedMessage);
handlers.insert("updateMessageIsPinned", &TDLibReceiver::processUpdateMessageIsPinned); handlers.insert("updateMessageIsPinned", &TDLibReceiver::processUpdateMessageIsPinned);
handlers.insert("users", &TDLibReceiver::processUsers); handlers.insert("users", &TDLibReceiver::processUsers);
handlers.insert("messageSenders", &TDLibReceiver::processMessageSenders);
handlers.insert("error", &TDLibReceiver::processError); handlers.insert("error", &TDLibReceiver::processError);
handlers.insert("ok", &TDLibReceiver::ok); handlers.insert("ok", &TDLibReceiver::ok);
handlers.insert("secretChat", &TDLibReceiver::processSecretChat); handlers.insert("secretChat", &TDLibReceiver::processSecretChat);
@ -178,10 +165,8 @@ TDLibReceiver::TDLibReceiver(void *tdLibClient, QObject *parent) : QThread(paren
handlers.insert("updateMessageInteractionInfo", &TDLibReceiver::processUpdateMessageInteractionInfo); handlers.insert("updateMessageInteractionInfo", &TDLibReceiver::processUpdateMessageInteractionInfo);
handlers.insert("sessions", &TDLibReceiver::processSessions); handlers.insert("sessions", &TDLibReceiver::processSessions);
handlers.insert("availableReactions", &TDLibReceiver::processAvailableReactions); handlers.insert("availableReactions", &TDLibReceiver::processAvailableReactions);
handlers.insert("updateMessageMentionRead", &TDLibReceiver::processUpdateChatUnreadMentionCount);
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)
@ -365,14 +350,6 @@ void TDLibReceiver::processUpdateChatReadOutbox(const QVariantMap &receivedInfor
emit chatReadOutboxUpdated(chat_id, last_read_outbox_message_id); emit chatReadOutboxUpdated(chat_id, last_read_outbox_message_id);
} }
void TDLibReceiver::processUpdateChatAvailableReactions(const QVariantMap &receivedInformation)
{
const qlonglong chat_id(receivedInformation.value(CHAT_ID).toLongLong());
const QVariantMap available_reactions(receivedInformation.value(AVAILABLE_REACTIONS).toMap());
LOG("Available reactions updated for" << chat_id << "new information:" << available_reactions);
emit chatAvailableReactionsUpdated(chat_id, available_reactions);
}
void TDLibReceiver::processUpdateBasicGroup(const QVariantMap &receivedInformation) void TDLibReceiver::processUpdateBasicGroup(const QVariantMap &receivedInformation)
{ {
const QVariantMap basicGroup(receivedInformation.value(BASIC_GROUP).toMap()); const QVariantMap basicGroup(receivedInformation.value(BASIC_GROUP).toMap());
@ -403,33 +380,13 @@ void TDLibReceiver::processMessages(const QVariantMap &receivedInformation)
emit messagesReceived(cleanupList(receivedInformation.value(MESSAGES).toList()), total_count); emit messagesReceived(cleanupList(receivedInformation.value(MESSAGES).toList()), total_count);
} }
void TDLibReceiver::processFoundChatMessages(const QVariantMap &receivedInformation)
{
const int total_count = receivedInformation.value(TOTAL_COUNT).toInt();
LOG("Received found chat messages, amount: " << total_count);
emit messagesReceived(cleanupList(receivedInformation.value(MESSAGES).toList()), total_count);
}
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();
@ -443,7 +400,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, cleanupMap(receivedInformation)); emit messageInformation(chatId, messageId, receivedInformation);
} }
void TDLibReceiver::processMessageLinkInfo(const QVariantMap &receivedInformation) void TDLibReceiver::processMessageLinkInfo(const QVariantMap &receivedInformation)
@ -468,7 +425,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, cleanupMap(message)); emit messageSendSucceeded(messageId, oldMessageId, message);
} }
void TDLibReceiver::processUpdateActiveNotifications(const QVariantMap &receivedInformation) void TDLibReceiver::processUpdateActiveNotifications(const QVariantMap &receivedInformation)
@ -645,12 +602,6 @@ void TDLibReceiver::processUsers(const QVariantMap &receivedInformation)
emit usersReceived(receivedInformation.value(_EXTRA).toString(), receivedInformation.value("user_ids").toList(), receivedInformation.value(TOTAL_COUNT).toInt()); emit usersReceived(receivedInformation.value(_EXTRA).toString(), receivedInformation.value("user_ids").toList(), receivedInformation.value(TOTAL_COUNT).toInt());
} }
void TDLibReceiver::processMessageSenders(const QVariantMap &receivedInformation)
{
LOG("Received Message Senders");
emit messageSendersReceived(receivedInformation.value(_EXTRA).toString(), receivedInformation.value("senders").toList(), receivedInformation.value(TOTAL_COUNT).toInt());
}
void TDLibReceiver::processError(const QVariantMap &receivedInformation) void TDLibReceiver::processError(const QVariantMap &receivedInformation)
{ {
LOG("Received an error"); LOG("Received an error");
@ -701,7 +652,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(), cleanupMap(receivedInformation.value(DRAFT_MESSAGE).toMap()), findChatPositionOrder(receivedInformation.value(POSITIONS).toList())); emit chatDraftMessageUpdated(receivedInformation.value(CHAT_ID).toLongLong(), receivedInformation.value("draft_message").toMap(), findChatPositionOrder(receivedInformation.value(POSITIONS).toList()));
} }
void TDLibReceiver::processInlineQueryResults(const QVariantMap &receivedInformation) void TDLibReceiver::processInlineQueryResults(const QVariantMap &receivedInformation)
@ -738,9 +689,8 @@ void TDLibReceiver::processUpdateMessageInteractionInfo(const QVariantMap &recei
void TDLibReceiver::processSessions(const QVariantMap &receivedInformation) void TDLibReceiver::processSessions(const QVariantMap &receivedInformation)
{ {
int inactive_session_ttl_days = receivedInformation.value("inactive_session_ttl_days").toInt();
QVariantList sessions = receivedInformation.value("sessions").toList(); QVariantList sessions = receivedInformation.value("sessions").toList();
emit sessionsReceived(inactive_session_ttl_days, sessions); emit sessionsReceived(sessions);
} }
void TDLibReceiver::processAvailableReactions(const QVariantMap &receivedInformation) void TDLibReceiver::processAvailableReactions(const QVariantMap &receivedInformation)
@ -754,8 +704,6 @@ void TDLibReceiver::processAvailableReactions(const QVariantMap &receivedInforma
void TDLibReceiver::processUpdateChatUnreadMentionCount(const QVariantMap &receivedInformation) void TDLibReceiver::processUpdateChatUnreadMentionCount(const QVariantMap &receivedInformation)
{ {
// Handles both updateMessageMentionRead and updateChatUnreadMentionCount
// They both have chat_id and unread_mention_count which is all we need
const qlonglong chatId = receivedInformation.value(CHAT_ID).toLongLong(); const qlonglong chatId = receivedInformation.value(CHAT_ID).toLongLong();
const int unreadMentionCount = receivedInformation.value(UNREAD_MENTION_COUNT).toInt(); const int unreadMentionCount = receivedInformation.value(UNREAD_MENTION_COUNT).toInt();
LOG("Chat unread mention count updated" << chatId << unreadMentionCount); LOG("Chat unread mention count updated" << chatId << unreadMentionCount);
@ -770,13 +718,6 @@ 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
@ -806,65 +747,17 @@ 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) {
QVariantMap message(map); bool cleaned = false;
bool messageChanged = false; const QVariantMap content(cleanupMap(map.value(CONTENT).toMap(), &cleaned));
const QVariantMap content(cleanupMap(map.value(CONTENT).toMap(), &messageChanged)); if (cleaned) {
if (messageChanged) { QVariantMap message(map);
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

@ -52,7 +52,6 @@ signals:
void chatPinnedUpdated(qlonglong chatId, bool isPinned); void chatPinnedUpdated(qlonglong chatId, bool isPinned);
void chatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, int unreadCount); void chatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, int unreadCount);
void chatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId); void chatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId);
void chatAvailableReactionsUpdated(const qlonglong &chatId, const QVariantMap &availableReactions);
void basicGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation); void basicGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation);
void superGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation); void superGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation);
void chatOnlineMemberCountUpdated(const QString &chatId, int onlineMemberCount); void chatOnlineMemberCountUpdated(const QString &chatId, int onlineMemberCount);
@ -89,8 +88,7 @@ signals:
void chatTitleUpdated(const QString &chatId, const QString &title); void chatTitleUpdated(const QString &chatId, const QString &title);
void chatPinnedMessageUpdated(qlonglong chatId, qlonglong pinnedMessageId); void chatPinnedMessageUpdated(qlonglong chatId, qlonglong pinnedMessageId);
void messageIsPinnedUpdated(qlonglong chatId, qlonglong messageId, bool isPinned); void messageIsPinnedUpdated(qlonglong chatId, qlonglong messageId, bool isPinned);
void usersReceived(const QString &extra, const QVariantList &senders, int totalUsers); void usersReceived(const QString &extra, const QVariantList &userIds, int totalUsers);
void messageSendersReceived(const QString &extra, const QVariantList &userIds, int totalUsers);
void errorReceived(const int code, const QString &message, const QString &extra); void errorReceived(const int code, const QString &message, const QString &extra);
void secretChat(qlonglong secretChatId, const QVariantMap &secretChat); void secretChat(qlonglong secretChatId, const QVariantMap &secretChat);
void secretChatUpdated(qlonglong secretChatId, const QVariantMap &secretChat); void secretChatUpdated(qlonglong secretChatId, const QVariantMap &secretChat);
@ -103,11 +101,10 @@ signals:
void userPrivacySettingRulesUpdated(const QVariantMap &updatedRules); void userPrivacySettingRulesUpdated(const QVariantMap &updatedRules);
void messageInteractionInfoUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &updatedInfo); void messageInteractionInfoUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &updatedInfo);
void okReceived(const QString &request); void okReceived(const QString &request);
void sessionsReceived(int inactive_session_ttl_days, const QVariantList &sessions); void sessionsReceived(const QVariantList &sessions);
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 &);
@ -137,14 +134,11 @@ private:
void processUpdateChatPosition(const QVariantMap &receivedInformation); void processUpdateChatPosition(const QVariantMap &receivedInformation);
void processUpdateChatReadInbox(const QVariantMap &receivedInformation); void processUpdateChatReadInbox(const QVariantMap &receivedInformation);
void processUpdateChatReadOutbox(const QVariantMap &receivedInformation); void processUpdateChatReadOutbox(const QVariantMap &receivedInformation);
void processUpdateChatAvailableReactions(const QVariantMap &receivedInformation);
void processUpdateBasicGroup(const QVariantMap &receivedInformation); void processUpdateBasicGroup(const QVariantMap &receivedInformation);
void processUpdateSuperGroup(const QVariantMap &receivedInformation); void processUpdateSuperGroup(const QVariantMap &receivedInformation);
void processChatOnlineMemberCountUpdated(const QVariantMap &receivedInformation); void processChatOnlineMemberCountUpdated(const QVariantMap &receivedInformation);
void processMessages(const QVariantMap &receivedInformation); void processMessages(const QVariantMap &receivedInformation);
void processFoundChatMessages(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);
@ -176,7 +170,6 @@ private:
void processUpdateChatPinnedMessage(const QVariantMap &receivedInformation); void processUpdateChatPinnedMessage(const QVariantMap &receivedInformation);
void processUpdateMessageIsPinned(const QVariantMap &receivedInformation); void processUpdateMessageIsPinned(const QVariantMap &receivedInformation);
void processUsers(const QVariantMap &receivedInformation); void processUsers(const QVariantMap &receivedInformation);
void processMessageSenders(const QVariantMap &receivedInformation);
void processError(const QVariantMap &receivedInformation); void processError(const QVariantMap &receivedInformation);
void processSecretChat(const QVariantMap &receivedInformation); void processSecretChat(const QVariantMap &receivedInformation);
void processUpdateSecretChat(const QVariantMap &receivedInformation); void processUpdateSecretChat(const QVariantMap &receivedInformation);
@ -193,7 +186,6 @@ 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,9 +36,6 @@
#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,40 +45,26 @@ namespace {
const QString LAST_NAME("last_name"); const QString LAST_NAME("last_name");
const QString FIRST_NAME("first_name"); const QString FIRST_NAME("first_name");
const QString USERNAME("username"); const QString USERNAME("username");
const QString USERNAMES("usernames");
const QString EDITABLE_USERNAME("editable_username");
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 *settings, MceInterface *mce, QObject *parent) TDLibWrapper::TDLibWrapper(AppSettings *appSettings, MceInterface *mceInterface, 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();
@ -137,7 +120,6 @@ void TDLibWrapper::initializeTDLibReceiver() {
connect(this->tdLibReceiver, SIGNAL(chatOrderUpdated(QString, QString)), this, SIGNAL(chatOrderUpdated(QString, QString))); connect(this->tdLibReceiver, SIGNAL(chatOrderUpdated(QString, QString)), this, SIGNAL(chatOrderUpdated(QString, QString)));
connect(this->tdLibReceiver, SIGNAL(chatReadInboxUpdated(QString, QString, int)), this, SIGNAL(chatReadInboxUpdated(QString, QString, int))); connect(this->tdLibReceiver, SIGNAL(chatReadInboxUpdated(QString, QString, int)), this, SIGNAL(chatReadInboxUpdated(QString, QString, int)));
connect(this->tdLibReceiver, SIGNAL(chatReadOutboxUpdated(QString, QString)), this, SIGNAL(chatReadOutboxUpdated(QString, QString))); connect(this->tdLibReceiver, SIGNAL(chatReadOutboxUpdated(QString, QString)), this, SIGNAL(chatReadOutboxUpdated(QString, QString)));
connect(this->tdLibReceiver, SIGNAL(chatAvailableReactionsUpdated(qlonglong, QVariantMap)), this, SLOT(handleAvailableReactionsUpdated(qlonglong, QVariantMap)));
connect(this->tdLibReceiver, SIGNAL(basicGroupUpdated(qlonglong, QVariantMap)), this, SLOT(handleBasicGroupUpdated(qlonglong, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(basicGroupUpdated(qlonglong, QVariantMap)), this, SLOT(handleBasicGroupUpdated(qlonglong, QVariantMap)));
connect(this->tdLibReceiver, SIGNAL(superGroupUpdated(qlonglong, QVariantMap)), this, SLOT(handleSuperGroupUpdated(qlonglong, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(superGroupUpdated(qlonglong, QVariantMap)), this, SLOT(handleSuperGroupUpdated(qlonglong, QVariantMap)));
connect(this->tdLibReceiver, SIGNAL(chatOnlineMemberCountUpdated(QString, int)), this, SIGNAL(chatOnlineMemberCountUpdated(QString, int))); connect(this->tdLibReceiver, SIGNAL(chatOnlineMemberCountUpdated(QString, int)), this, SIGNAL(chatOnlineMemberCountUpdated(QString, int)));
@ -177,7 +159,6 @@ void TDLibWrapper::initializeTDLibReceiver() {
connect(this->tdLibReceiver, SIGNAL(chatPinnedMessageUpdated(qlonglong, qlonglong)), this, SIGNAL(chatPinnedMessageUpdated(qlonglong, qlonglong))); connect(this->tdLibReceiver, SIGNAL(chatPinnedMessageUpdated(qlonglong, qlonglong)), this, SIGNAL(chatPinnedMessageUpdated(qlonglong, qlonglong)));
connect(this->tdLibReceiver, SIGNAL(messageIsPinnedUpdated(qlonglong, qlonglong, bool)), this, SLOT(handleMessageIsPinnedUpdated(qlonglong, qlonglong, bool))); connect(this->tdLibReceiver, SIGNAL(messageIsPinnedUpdated(qlonglong, qlonglong, bool)), this, SLOT(handleMessageIsPinnedUpdated(qlonglong, qlonglong, bool)));
connect(this->tdLibReceiver, SIGNAL(usersReceived(QString, QVariantList, int)), this, SIGNAL(usersReceived(QString, QVariantList, int))); connect(this->tdLibReceiver, SIGNAL(usersReceived(QString, QVariantList, int)), this, SIGNAL(usersReceived(QString, QVariantList, int)));
connect(this->tdLibReceiver, SIGNAL(messageSendersReceived(QString, QVariantList, int)), this, SIGNAL(messageSendersReceived(QString, QVariantList, int)));
connect(this->tdLibReceiver, SIGNAL(errorReceived(int, QString, QString)), this, SLOT(handleErrorReceived(int, QString, QString))); connect(this->tdLibReceiver, SIGNAL(errorReceived(int, QString, QString)), this, SLOT(handleErrorReceived(int, QString, QString)));
connect(this->tdLibReceiver, SIGNAL(contactsImported(QVariantList, QVariantList)), this, SIGNAL(contactsImported(QVariantList, QVariantList))); connect(this->tdLibReceiver, SIGNAL(contactsImported(QVariantList, QVariantList)), this, SIGNAL(contactsImported(QVariantList, QVariantList)));
connect(this->tdLibReceiver, SIGNAL(messageEditedUpdated(qlonglong, qlonglong, QVariantMap)), this, SIGNAL(messageEditedUpdated(qlonglong, qlonglong, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(messageEditedUpdated(qlonglong, qlonglong, QVariantMap)), this, SIGNAL(messageEditedUpdated(qlonglong, qlonglong, QVariantMap)));
@ -189,11 +170,10 @@ void TDLibWrapper::initializeTDLibReceiver() {
connect(this->tdLibReceiver, SIGNAL(userPrivacySettingRulesUpdated(QVariantMap)), this, SLOT(handleUpdatedUserPrivacySettingRules(QVariantMap))); connect(this->tdLibReceiver, SIGNAL(userPrivacySettingRulesUpdated(QVariantMap)), this, SLOT(handleUpdatedUserPrivacySettingRules(QVariantMap)));
connect(this->tdLibReceiver, SIGNAL(messageInteractionInfoUpdated(qlonglong, qlonglong, QVariantMap)), this, SIGNAL(messageInteractionInfoUpdated(qlonglong, qlonglong, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(messageInteractionInfoUpdated(qlonglong, qlonglong, QVariantMap)), this, SIGNAL(messageInteractionInfoUpdated(qlonglong, qlonglong, QVariantMap)));
connect(this->tdLibReceiver, SIGNAL(okReceived(QString)), this, SIGNAL(okReceived(QString))); connect(this->tdLibReceiver, SIGNAL(okReceived(QString)), this, SIGNAL(okReceived(QString)));
connect(this->tdLibReceiver, SIGNAL(sessionsReceived(int, QVariantList)), this, SIGNAL(sessionsReceived(int, QVariantList))); connect(this->tdLibReceiver, SIGNAL(sessionsReceived(QVariantList)), this, SIGNAL(sessionsReceived(QVariantList)));
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();
} }
@ -212,7 +192,7 @@ void TDLibWrapper::sendRequest(const QVariantMap &requestObject)
QString TDLibWrapper::getVersion() QString TDLibWrapper::getVersion()
{ {
return this->versionString; return this->version;
} }
TDLibWrapper::AuthorizationState TDLibWrapper::getAuthorizationState() TDLibWrapper::AuthorizationState TDLibWrapper::getAuthorizationState()
@ -275,7 +255,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;
@ -409,24 +389,15 @@ static bool compareReplacements(const QVariant &replacement1, const QVariant &re
} }
} }
QVariantMap TDLibWrapper::newSendMessageRequest(qlonglong chatId, qlonglong replyToMessageId) void TDLibWrapper::sendTextMessage(const QString &chatId, const QString &message, const QString &replyToMessageId)
{
QVariantMap request;
request.insert(_TYPE, "sendMessage");
request.insert(CHAT_ID, chatId);
if (replyToMessageId) {
QVariantMap replyTo;
replyTo.insert(_TYPE, TYPE_INPUT_MESSAGE_REPLY_TO_MESSAGE);
replyTo.insert(MESSAGE_ID, replyToMessageId);
request.insert(REPLY_TO, replyTo);
}
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(newSendMessageRequest(chatId, replyToMessageId)); QVariantMap requestObject;
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");
@ -465,7 +436,7 @@ void TDLibWrapper::sendTextMessage(qlonglong chatId, const QString &message, qlo
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();
} }
@ -479,13 +450,17 @@ void TDLibWrapper::sendTextMessage(qlonglong chatId, const QString &message, qlo
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::sendPhotoMessage(qlonglong chatId, const QString &filePath, const QString &message, qlonglong replyToMessageId) void TDLibWrapper::sendPhotoMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId)
{ {
LOG("Sending photo message" << chatId << filePath << message << replyToMessageId); LOG("Sending photo message" << chatId << filePath << message << replyToMessageId);
QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId)); QVariantMap requestObject;
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");
@ -499,13 +474,17 @@ void TDLibWrapper::sendPhotoMessage(qlonglong chatId, const QString &filePath, c
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::sendVideoMessage(qlonglong chatId, const QString &filePath, const QString &message, qlonglong replyToMessageId) void TDLibWrapper::sendVideoMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId)
{ {
LOG("Sending video message" << chatId << filePath << message << replyToMessageId); LOG("Sending video message" << chatId << filePath << message << replyToMessageId);
QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId)); QVariantMap requestObject;
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");
@ -519,13 +498,17 @@ void TDLibWrapper::sendVideoMessage(qlonglong chatId, const QString &filePath, c
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::sendDocumentMessage(qlonglong chatId, const QString &filePath, const QString &message, qlonglong replyToMessageId) void TDLibWrapper::sendDocumentMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId)
{ {
LOG("Sending document message" << chatId << filePath << message << replyToMessageId); LOG("Sending document message" << chatId << filePath << message << replyToMessageId);
QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId)); QVariantMap requestObject;
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");
@ -539,13 +522,17 @@ void TDLibWrapper::sendDocumentMessage(qlonglong chatId, const QString &filePath
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::sendVoiceNoteMessage(qlonglong chatId, const QString &filePath, const QString &message, qlonglong replyToMessageId) void TDLibWrapper::sendVoiceNoteMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId)
{ {
LOG("Sending voice note message" << chatId << filePath << message << replyToMessageId); LOG("Sending voice note message" << chatId << filePath << message << replyToMessageId);
QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId)); QVariantMap requestObject;
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");
@ -559,19 +546,24 @@ void TDLibWrapper::sendVoiceNoteMessage(qlonglong chatId, const QString &filePat
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::sendLocationMessage(qlonglong chatId, double latitude, double longitude, double horizontalAccuracy, qlonglong replyToMessageId) void TDLibWrapper::sendLocationMessage(const QString &chatId, double latitude, double longitude, double horizontalAccuracy, const QString &replyToMessageId)
{ {
LOG("Sending location message" << chatId << latitude << longitude << horizontalAccuracy << replyToMessageId); LOG("Sending location message" << chatId << latitude << longitude << horizontalAccuracy << replyToMessageId);
QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId)); QVariantMap requestObject;
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);
@ -580,16 +572,21 @@ void TDLibWrapper::sendLocationMessage(qlonglong chatId, double latitude, double
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::sendStickerMessage(qlonglong chatId, const QString &fileId, qlonglong replyToMessageId) void TDLibWrapper::sendStickerMessage(const QString &chatId, const QString &fileId, const QString &replyToMessageId)
{ {
LOG("Sending sticker message" << chatId << fileId << replyToMessageId); LOG("Sending sticker message" << chatId << fileId << replyToMessageId);
QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId)); QVariantMap requestObject;
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);
@ -597,10 +594,15 @@ void TDLibWrapper::sendStickerMessage(qlonglong chatId, const QString &fileId, q
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::sendPollMessage(qlonglong chatId, const QString &question, const QVariantList &options, bool anonymous, int correctOption, bool multiple, const QString &explanation, qlonglong replyToMessageId) void TDLibWrapper::sendPollMessage(const QString &chatId, const QString &question, const QVariantList &options, bool anonymous, int correctOption, bool multiple, const QString &explanation, const QString &replyToMessageId)
{ {
LOG("Sending poll message" << chatId << question << replyToMessageId); LOG("Sending poll message" << chatId << question << replyToMessageId);
QVariantMap requestObject(newSendMessageRequest(chatId, replyToMessageId)); QVariantMap requestObject;
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");
@ -618,7 +620,7 @@ void TDLibWrapper::sendPollMessage(qlonglong chatId, const QString &question, co
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);
@ -707,11 +709,7 @@ void TDLibWrapper::getChatSponsoredMessage(qlonglong chatId)
{ {
LOG("Retrieving sponsored message" << chatId); LOG("Retrieving sponsored message" << chatId);
QVariantMap requestObject; QVariantMap requestObject;
// getChatSponsoredMessage has been replaced with getChatSponsoredMessages requestObject.insert(_TYPE, "getChatSponsoredMessage");
// 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);
@ -1173,18 +1171,9 @@ 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);
} }
@ -1444,8 +1433,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);
} }
@ -1468,23 +1457,11 @@ 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(CHAT_ID, chatId); requestObject.insert(_TYPE, "setMessageReaction");
requestObject.insert(MESSAGE_ID, messageId); requestObject.insert("chat_id", chatId);
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);
} }
@ -1517,19 +1494,11 @@ void TDLibWrapper::setNetworkType(NetworkType networkType)
break; break;
} }
requestObject.insert(TYPE, networkTypeObject); requestObject.insert("type", networkTypeObject);
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::setInactiveSessionTtl(int days)
{
QVariantMap requestObject;
requestObject.insert(_TYPE, "setInactiveSessionTtl");
requestObject.insert("inactive_session_ttl_days", days);
this->sendRequest(requestObject);
}
void TDLibWrapper::searchEmoji(const QString &queryString) void TDLibWrapper::searchEmoji(const QString &queryString)
{ {
LOG("Searching emoji" << queryString); LOG("Searching emoji" << queryString);
@ -1606,49 +1575,6 @@ QVariantMap TDLibWrapper::getChat(const QString &chatId)
return this->chats.value(chatId).toMap(); return this->chats.value(chatId).toMap();
} }
QStringList TDLibWrapper::getChatReactions(const QString &chatId)
{
LOG("Obtaining chat reactions for chat" << 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) {
LOG("Chat uses all available reactions, currently available number" << activeEmojiReactions.size());
return activeEmojiReactions;
} else if (reactions_type == CHAT_AVAILABLE_REACTIONS_SOME) {
LOG("Chat uses reduced set of reactions");
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);
}
}
}
LOG("Found emojis for this chat" << emojis.size());
return emojis;
} else if (reactions_type.isEmpty()) {
LOG("No chat reaction type specified, using all reactions");
return available_reactions.toStringList();
} else {
LOG("Unknown chat reaction type" << reactions_type);
return QStringList();
}
}
QVariantMap TDLibWrapper::getSecretChatFromCache(qlonglong secretChatId) QVariantMap TDLibWrapper::getSecretChatFromCache(qlonglong secretChatId)
{ {
return this->secretChats.value(secretChatId); return this->secretChats.value(secretChatId);
@ -1719,16 +1645,7 @@ DBusAdaptor *TDLibWrapper::getDBusAdaptor()
void TDLibWrapper::handleVersionDetected(const QString &version) void TDLibWrapper::handleVersionDetected(const QString &version)
{ {
this->versionString = version; this->version = 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);
} }
@ -1841,15 +1758,15 @@ 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;
emit ownUserUpdated(userInformation); emit ownUserUpdated(userInformation);
} }
LOG("User information updated:" << userInformation.value(USERNAMES).toMap().value(EDITABLE_USERNAME).toString() << userInformation.value(FIRST_NAME).toString() << userInformation.value(LAST_NAME).toString()); LOG("User information updated:" << userInformation.value(USERNAME).toString() << userInformation.value(FIRST_NAME).toString() << userInformation.value(LAST_NAME).toString());
this->allUsers.insert(updatedUserId, userInformation); this->allUsers.insert(updatedUserId, userInformation);
this->allUserNames.insert(userInformation.value(USERNAMES).toMap().value(EDITABLE_USERNAME).toString(), userInformation); this->allUserNames.insert(userInformation.value(USERNAME).toString(), userInformation);
emit userUpdated(updatedUserId, userInformation); emit userUpdated(updatedUserId, userInformation);
} }
@ -1857,24 +1774,24 @@ 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(USERNAMES).toMap().value(EDITABLE_USERNAME).toString(), userInformation); this->allUserNames.insert(userInformation.value(USERNAME).toString(), userInformation);
emit userUpdated(userId, updatedUserInformation); emit userUpdated(userId, updatedUserInformation);
} }
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);
} }
@ -1914,17 +1831,6 @@ void TDLibWrapper::handleUnreadChatCountUpdated(const QVariantMap &chatCountInfo
} }
} }
void TDLibWrapper::handleAvailableReactionsUpdated(qlonglong chatId, const QVariantMap &availableReactions)
{
LOG("Updating available reactions for chat" << chatId << availableReactions);
QString chatIdString = QString::number(chatId);
QVariantMap chatInformation = this->getChat(chatIdString);
chatInformation.insert(CHAT_AVAILABLE_REACTIONS, availableReactions);
this->chats.insert(chatIdString, chatInformation);
emit chatAvailableReactionsUpdated(chatId, availableReactions);
}
void TDLibWrapper::handleBasicGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation) void TDLibWrapper::handleBasicGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation)
{ {
emit basicGroupUpdated(updateGroup(groupId, groupInformation, &basicGroups)->groupId); emit basicGroupUpdated(updateGroup(groupId, groupInformation, &basicGroups)->groupId);
@ -1950,7 +1856,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);
} }
@ -2082,13 +1988,6 @@ 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)
{ {
@ -2178,40 +2077,28 @@ 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 QVariantMap initialParameters;
// See https://github.com/tdlib/td/commit/f6a2ecd initialParameters.insert("api_id", TDLIB_API_ID);
if (versionNumber > VERSION_NUMBER(1,8,5)) { initialParameters.insert("api_hash", TDLIB_API_HASH);
fillTdlibParameters(requestObject); initialParameters.insert("database_directory", QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tdlib");
} else { bool onlineOnlyMode = this->appSettings->onlineOnlyMode();
QVariantMap initialParameters; initialParameters.insert("use_file_database", !onlineOnlyMode);
fillTdlibParameters(initialParameters); initialParameters.insert("use_chat_info_database", !onlineOnlyMode);
requestObject.insert("parameters", initialParameters); 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);
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }

View file

@ -148,7 +148,6 @@ 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);
@ -176,14 +175,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(qlonglong chatId, const QString &message, qlonglong replyToMessageId = 0); Q_INVOKABLE void sendTextMessage(const QString &chatId, 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 sendPhotoMessage(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 sendVideoMessage(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 sendDocumentMessage(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 sendVoiceNoteMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId = "0");
Q_INVOKABLE void sendLocationMessage(qlonglong chatId, double latitude, double longitude, double horizontalAccuracy, qlonglong replyToMessageId = 0); Q_INVOKABLE void sendLocationMessage(const QString &chatId, double latitude, double longitude, double horizontalAccuracy, const QString &replyToMessageId = "0");
Q_INVOKABLE void sendStickerMessage(qlonglong chatId, const QString &fileId, qlonglong replyToMessageId = 0); Q_INVOKABLE void sendStickerMessage(const QString &chatId, const QString &fileId, 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 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 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 = "");
@ -251,7 +250,6 @@ public:
Q_INVOKABLE void getPageSource(const QString &address); Q_INVOKABLE void getPageSource(const QString &address);
Q_INVOKABLE void setMessageReaction(qlonglong chatId, qlonglong messageId, const QString &reaction); Q_INVOKABLE void setMessageReaction(qlonglong chatId, qlonglong messageId, const QString &reaction);
Q_INVOKABLE void setNetworkType(NetworkType networkType); Q_INVOKABLE void setNetworkType(NetworkType networkType);
Q_INVOKABLE void setInactiveSessionTtl(int days);
// Others (candidates for extraction ;)) // Others (candidates for extraction ;))
Q_INVOKABLE void searchEmoji(const QString &queryString); Q_INVOKABLE void searchEmoji(const QString &queryString);
@ -279,7 +277,6 @@ signals:
void chatPinnedUpdated(qlonglong chatId, bool isPinned); void chatPinnedUpdated(qlonglong chatId, bool isPinned);
void chatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, int unreadCount); void chatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, int unreadCount);
void chatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId); void chatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId);
void chatAvailableReactionsUpdated(const qlonglong &chatId, const QVariantMap &availableReactions);
void userUpdated(const QString &userId, const QVariantMap &userInformation); void userUpdated(const QString &userId, const QVariantMap &userInformation);
void ownUserUpdated(const QVariantMap &userInformation); void ownUserUpdated(const QVariantMap &userInformation);
void basicGroupUpdated(qlonglong groupId); void basicGroupUpdated(qlonglong groupId);
@ -323,7 +320,6 @@ signals:
void chatTitleUpdated(const QString &chatId, const QString &title); void chatTitleUpdated(const QString &chatId, const QString &title);
void chatPinnedMessageUpdated(qlonglong chatId, qlonglong pinnedMessageId); void chatPinnedMessageUpdated(qlonglong chatId, qlonglong pinnedMessageId);
void usersReceived(const QString &extra, const QVariantList &userIds, int totalUsers); void usersReceived(const QString &extra, const QVariantList &userIds, int totalUsers);
void messageSendersReceived(const QString &extra, const QVariantList &senders, int totalUsers);
void errorReceived(int code, const QString &message, const QString &extra); void errorReceived(int code, const QString &message, const QString &extra);
void contactsImported(const QVariantList &importerCount, const QVariantList &userIds); void contactsImported(const QVariantList &importerCount, const QVariantList &userIds);
void messageNotFound(qlonglong chatId, qlonglong messageId); void messageNotFound(qlonglong chatId, qlonglong messageId);
@ -334,7 +330,7 @@ signals:
void userPrivacySettingUpdated(UserPrivacySetting setting, UserPrivacySettingRule rule); void userPrivacySettingUpdated(UserPrivacySetting setting, UserPrivacySettingRule rule);
void messageInteractionInfoUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &updatedInfo); void messageInteractionInfoUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &updatedInfo);
void okReceived(const QString &request); void okReceived(const QString &request);
void sessionsReceived(int inactive_session_ttl_days, const QVariantList &sessions); void sessionsReceived(const QVariantList &sessions);
void openFileExternally(const QString &filePath); void openFileExternally(const QString &filePath);
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);
@ -353,7 +349,6 @@ public slots:
void handleChatReceived(const QVariantMap &chatInformation); void handleChatReceived(const QVariantMap &chatInformation);
void handleUnreadMessageCountUpdated(const QVariantMap &messageCountInformation); void handleUnreadMessageCountUpdated(const QVariantMap &messageCountInformation);
void handleUnreadChatCountUpdated(const QVariantMap &chatCountInformation); void handleUnreadChatCountUpdated(const QVariantMap &chatCountInformation);
void handleAvailableReactionsUpdated(qlonglong chatId, const QVariantMap &availableReactions);
void handleBasicGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation); void handleBasicGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation);
void handleSuperGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation); void handleSuperGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation);
void handleStickerSets(const QVariantList &stickerSets); void handleStickerSets(const QVariantList &stickerSets);
@ -369,7 +364,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:
@ -377,9 +372,7 @@ 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:
@ -390,7 +383,7 @@ private:
MceInterface *mceInterface; MceInterface *mceInterface;
TDLibReceiver *tdLibReceiver; TDLibReceiver *tdLibReceiver;
DBusInterface *dbusInterface; DBusInterface *dbusInterface;
QString versionString; QString version;
TDLibWrapper::AuthorizationState authorizationState; TDLibWrapper::AuthorizationState authorizationState;
QVariantMap authorizationStateData; QVariantMap authorizationStateData;
TDLibWrapper::ConnectionState connectionState; TDLibWrapper::ConnectionState connectionState;
@ -406,9 +399,7 @@ 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

@ -1,5 +1,5 @@
// //
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@ -23,7 +23,7 @@ namespace td {
* Requests can be sent using the method ClientManager::send from any thread. * Requests can be sent using the method ClientManager::send from any thread.
* New updates and responses to requests can be received using the method ClientManager::receive from any thread after * New updates and responses to requests can be received using the method ClientManager::receive from any thread after
* the first request has been sent to the client instance. ClientManager::receive must not be called simultaneously from * the first request has been sent to the client instance. ClientManager::receive must not be called simultaneously from
* two different threads. Also, note that all updates and responses to requests should be applied in the same order as * two different threads. Also note that all updates and responses to requests should be applied in the same order as
* they were received, to ensure consistency. * they were received, to ensure consistency.
* Some TDLib requests can be executed synchronously from any thread using the method ClientManager::execute. * Some TDLib requests can be executed synchronously from any thread using the method ClientManager::execute.
* *
@ -96,7 +96,7 @@ class ClientManager final {
ClientId client_id; ClientId client_id;
/** /**
* Request identifier to which the response corresponds, or 0 for incoming updates from TDLib. * Request identifier, to which the response corresponds, or 0 for incoming updates from TDLib.
*/ */
RequestId request_id; RequestId request_id;
@ -126,10 +126,10 @@ class ClientManager final {
/** /**
* A type of callback function that will be called when a message is added to the internal TDLib log. * A type of callback function that will be called when a message is added to the internal TDLib log.
* *
* \param verbosity_level Log verbosity level with which the message was added from -1 up to 1024. * \param verbosity_level Log verbosity level with which the message was added (-1 - 1024).
* If 0, then TDLib will crash as soon as the callback returns. * If 0, then TDLib will crash as soon as the callback returns.
* None of the TDLib methods can be called from the callback. * None of the TDLib methods can be called from the callback.
* \param message Null-terminated UTF-8-encoded string with the message added to the log. * \param message Null-terminated string with the message added to the log.
*/ */
using LogMessageCallbackPtr = void (*)(int verbosity_level, const char *message); using LogMessageCallbackPtr = void (*)(int verbosity_level, const char *message);
@ -177,7 +177,7 @@ class ClientManager final {
* The TDLib instance is created for the lifetime of the Client object. * The TDLib instance is created for the lifetime of the Client object.
* Requests to TDLib can be sent using the Client::send method from any thread. * Requests to TDLib can be sent using the Client::send method from any thread.
* New updates and responses to requests can be received using the Client::receive method from any thread, * New updates and responses to requests can be received using the Client::receive method from any thread,
* this function must not be called simultaneously from two different threads. Also, note that all updates and * this function must not be called simultaneously from two different threads. Also note that all updates and
* responses to requests should be applied in the same order as they were received, to ensure consistency. * responses to requests should be applied in the same order as they were received, to ensure consistency.
* Given this information, it's advisable to call this function from a dedicated thread. * Given this information, it's advisable to call this function from a dedicated thread.
* Some service TDLib requests can be executed synchronously from any thread using the Client::execute method. * Some service TDLib requests can be executed synchronously from any thread using the Client::execute method.
@ -199,7 +199,7 @@ class ClientManager final {
* if (response.id == 0) { * if (response.id == 0) {
* // process response.object as an incoming update of type td_api::Update * // process response.object as an incoming update of type td_api::Update
* } else { * } else {
* // process response.object as an answer to a sent request with identifier response.id * // process response.object as an answer to a sent request with id response.id
* } * }
* } * }
* \endcode * \endcode

View file

@ -1,5 +1,5 @@
// //
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
// //
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@ -28,7 +28,7 @@
* Requests can be sent using td_send and the received client identifier. * Requests can be sent using td_send and the received client identifier.
* New updates and responses to requests can be received through td_receive from any thread after the first request * New updates and responses to requests can be received through td_receive from any thread after the first request
* has been sent to the client instance. This function must not be called simultaneously from two different threads. * has been sent to the client instance. This function must not be called simultaneously from two different threads.
* Also, note that all updates and responses to requests must be applied in the order they were received for consistency. * Also note that all updates and responses to requests must be applied in the order they were received for consistency.
* Some TDLib requests can be executed synchronously from any thread using td_execute. * Some TDLib requests can be executed synchronously from any thread using td_execute.
* TDLib client instances are destroyed automatically after they are closed. * TDLib client instances are destroyed automatically after they are closed.
* All TDLib client instances must be closed before application termination to ensure data consistency. * All TDLib client instances must be closed before application termination to ensure data consistency.
@ -88,10 +88,10 @@ TDJSON_EXPORT const char *td_execute(const char *request);
/** /**
* A type of callback function that will be called when a message is added to the internal TDLib log. * A type of callback function that will be called when a message is added to the internal TDLib log.
* *
* \param verbosity_level Log verbosity level with which the message was added from -1 up to 1024. * \param verbosity_level Log verbosity level with which the message was added (-1 - 1024).
* If 0, then TDLib will crash as soon as the callback returns. * If 0, then TDLib will crash as soon as the callback returns.
* None of the TDLib methods can be called from the callback. * None of the TDLib methods can be called from the callback.
* \param message Null-terminated UTF-8-encoded string with the message added to the log. * \param message Null-terminated string with the logged message.
*/ */
typedef void (*td_log_message_callback_ptr)(int verbosity_level, const char *message); typedef void (*td_log_message_callback_ptr)(int verbosity_level, const char *message);
@ -118,7 +118,7 @@ TDJSON_EXPORT void td_set_log_message_callback(int max_verbosity_level, td_log_m
* A TDLib client instance can be created through td_json_client_create. * A TDLib client instance can be created through td_json_client_create.
* Requests then can be sent using td_json_client_send from any thread. * Requests then can be sent using td_json_client_send from any thread.
* New updates and request responses can be received through td_json_client_receive from any thread. This function * New updates and request responses can be received through td_json_client_receive from any thread. This function
* must not be called simultaneously from two different threads. Also, note that all updates and request responses * must not be called simultaneously from two different threads. Also note that all updates and request responses
* must be applied in the order they were received to ensure consistency. * must be applied in the order they were received to ensure consistency.
* Given this information, it's advisable to call this function from a dedicated thread. * Given this information, it's advisable to call this function from a dedicated thread.
* Some service TDLib requests can be executed synchronously from any thread by using td_json_client_execute. * Some service TDLib requests can be executed synchronously from any thread by using td_json_client_execute.

View file

@ -1,5 +1,5 @@
// //
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View file

@ -1,5 +1,5 @@
// //
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@ -97,8 +97,8 @@ class unique_ptr {
using element_type = T; using element_type = T;
unique_ptr() noexcept = default; unique_ptr() noexcept = default;
unique_ptr(const unique_ptr &) = delete; unique_ptr(const unique_ptr &other) = delete;
unique_ptr &operator=(const unique_ptr &) = delete; unique_ptr &operator=(const unique_ptr &other) = delete;
unique_ptr(unique_ptr &&other) noexcept : ptr_(other.release()) { unique_ptr(unique_ptr &&other) noexcept : ptr_(other.release()) {
} }
unique_ptr &operator=(unique_ptr &&other) noexcept { unique_ptr &operator=(unique_ptr &&other) noexcept {
@ -187,11 +187,11 @@ using tl_object_ptr = tl::unique_ptr<Type>;
* A function to create a dynamically allocated TL-object. Can be treated as an analogue of std::make_unique. * A function to create a dynamically allocated TL-object. Can be treated as an analogue of std::make_unique.
* Usage example: * Usage example:
* \code * \code
* auto get_me_request = td::make_tl_object<td::td_api::getMe>(); * auto get_authorization_state_request = td::make_tl_object<td::td_api::getAuthorizationState>();
* auto message_text = td::make_tl_object<td::td_api::formattedText>("Hello, world!!!", * auto message_text = td::make_tl_object<td::td_api::formattedText>("Hello, world!!!",
* td::td_api::array<td::tl_object_ptr<td::td_api::textEntity>>()); * td::td_api::array<td::tl_object_ptr<td::td_api::textEntity>>());
* auto send_message_request = td::make_tl_object<td::td_api::sendMessage>(chat_id, 0, nullptr, nullptr, nullptr, * auto send_message_request = td::make_tl_object<td::td_api::sendMessage>(chat_id, 0, 0, nullptr, nullptr,
* td::make_tl_object<td::td_api::inputMessageText>(std::move(message_text), nullptr, true)); * td::make_tl_object<td::td_api::inputMessageText>(std::move(message_text), false, true));
* \endcode * \endcode
* *
* \tparam Type Type of the TL-object to construct. * \tparam Type Type of the TL-object to construct.

View file

@ -483,10 +483,6 @@
<source>Deleted User</source> <source>Deleted User</source>
<translation>Gelöschtes Konto</translation> <translation>Gelöschtes Konto</translation>
</message> </message>
<message>
<source>Double-tap on a message to choose a reaction</source>
<translation>Drücke zweimal auf eine Nachricht, um eine Reaktion auszuwählen</translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -499,6 +495,13 @@
<translation>Sie haben noch keine Chats.</translation> <translation>Sie haben noch keine Chats.</translation>
</message> </message>
</context> </context>
<context>
<name>ContactSync</name>
<message>
<source>Could not synchronize your contacts with Telegram.</source>
<translation>Konnte Ihre Kontakte nicht mit Telegram synchronisieren.</translation>
</message>
</context>
<context> <context>
<name>CoverPage</name> <name>CoverPage</name>
<message> <message>
@ -1579,34 +1582,6 @@
<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>
<message>
<source>Go to quoted message</source>
<translation>Zu zitierter Nachricht springen</translation>
</message>
<message>
<source>When tapping a quoted message, open it in chat instead of showing it in an overlay.</source>
<translation>Beim Tippen auf eine zitierte Nachricht zu dieser springen anstatt es in einem Overlay anzuzeigen.</translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1704,6 +1679,10 @@
<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>
@ -1716,41 +1695,6 @@
<source>Sessions</source> <source>Sessions</source>
<translation>Sitzungen</translation> <translation>Sitzungen</translation>
</message> </message>
<message numerus="yes">
<source>%1 day(s)</source>
<translation>
<numerusform>%1 Tag</numerusform>
<numerusform>%1 Tage</numerusform>
</translation>
</message>
<message>
<source>1 week</source>
<translation>1 Woche</translation>
</message>
<message>
<source>1 month</source>
<translation>1 Monat</translation>
</message>
<message>
<source>3 months</source>
<translation>3 Monate</translation>
</message>
<message>
<source>6 months</source>
<translation>6 Monate</translation>
</message>
<message>
<source>1 year</source>
<translation>1 Jahr</translation>
</message>
<message>
<source>Session Timeout</source>
<translation>Timeout von Sitzungen</translation>
</message>
<message>
<source>Inactive sessions will be terminated after this timeframe</source>
<translation>Inaktive Sitzungen werden nach dieser Zeitdauer abgeschaltet</translation>
</message>
</context> </context>
<context> <context>
<name>SettingsStorage</name> <name>SettingsStorage</name>

View file

@ -483,10 +483,6 @@
<source>Deleted User</source> <source>Deleted User</source>
<translation>Deleted User</translation> <translation>Deleted User</translation>
</message> </message>
<message>
<source>Double-tap on a message to choose a reaction</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -499,6 +495,13 @@
<translation>You don&apos;t have any chats yet.</translation> <translation>You don&apos;t have any chats yet.</translation>
</message> </message>
</context> </context>
<context>
<name>ContactSync</name>
<message>
<source>Could not synchronize your contacts with Telegram.</source>
<translation type="unfinished">Could not synchronize your contacts with Telegram.</translation>
</message>
</context>
<context> <context>
<name>CoverPage</name> <name>CoverPage</name>
<message> <message>
@ -1581,34 +1584,6 @@ 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>
<message>
<source>Go to quoted message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>When tapping a quoted message, open it in chat instead of showing it in an overlay.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1714,45 +1689,14 @@ 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>
</message> </message>
<message numerus="yes">
<source>%1 day(s)</source>
<translation>
<numerusform>%1 day</numerusform>
<numerusform>%1 days</numerusform>
</translation>
</message>
<message>
<source>1 week</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 month</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>3 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>6 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 year</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Session Timeout</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Inactive sessions will be terminated after this timeframe</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsStorage</name> <name>SettingsStorage</name>

File diff suppressed because it is too large Load diff

View file

@ -483,10 +483,6 @@
<source>Deleted User</source> <source>Deleted User</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Double-tap on a message to choose a reaction</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -499,6 +495,13 @@
<translation>Sinulla ei ole vielä keskusteluja.</translation> <translation>Sinulla ei ole vielä keskusteluja.</translation>
</message> </message>
</context> </context>
<context>
<name>ContactSync</name>
<message>
<source>Could not synchronize your contacts with Telegram.</source>
<translation type="unfinished">Yhteystietojasi ei voitu synkronoida Telegramin kanssa.</translation>
</message>
</context>
<context> <context>
<name>CoverPage</name> <name>CoverPage</name>
<message> <message>
@ -1580,34 +1583,6 @@
<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>
<message>
<source>Go to quoted message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>When tapping a quoted message, open it in chat instead of showing it in an overlay.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1713,45 +1688,14 @@
<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>
</message> </message>
<message numerus="yes">
<source>%1 day(s)</source>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
<message>
<source>1 week</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 month</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>3 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>6 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 year</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Session Timeout</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Inactive sessions will be terminated after this timeframe</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsStorage</name> <name>SettingsStorage</name>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS> <!DOCTYPE TS>
<TS version="2.1" language="fr"> <TS version="2.1" language="en">
<context> <context>
<name>AboutPage</name> <name>AboutPage</name>
<message> <message>
@ -483,10 +483,6 @@
<source>Deleted User</source> <source>Deleted User</source>
<translation>Supprimer l&apos;utilisateur</translation> <translation>Supprimer l&apos;utilisateur</translation>
</message> </message>
<message>
<source>Double-tap on a message to choose a reaction</source>
<translation>Toucher deux fois sur un message pour réagir</translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -499,6 +495,13 @@
<translation>Vous n&apos;avez aucune conversation.</translation> <translation>Vous n&apos;avez aucune conversation.</translation>
</message> </message>
</context> </context>
<context>
<name>ContactSync</name>
<message>
<source>Could not synchronize your contacts with Telegram.</source>
<translation>Impossible de synchroniser vos contacts avec Telegram.</translation>
</message>
</context>
<context> <context>
<name>CoverPage</name> <name>CoverPage</name>
<message> <message>
@ -1163,7 +1166,7 @@
</message> </message>
<message> <message>
<source>No contacts found.</source> <source>No contacts found.</source>
<translation>Aucun contact trouvé</translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>
@ -1579,34 +1582,6 @@
<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>Toujours visualiser le message dans les 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>En plus d&apos;afficher le nombre de messages non-lus, le dernier message sera également ajouté aux notifications.</translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation>Mettre en valeur les messages non-lus</translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation>Mettre en valeur les conversations avec des messages non-lus</translation>
</message>
<message>
<source>Hide content in notifications</source>
<translation>Masquer le contenu dans les notifications</translation>
</message>
<message>
<source>Go to quoted message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>When tapping a quoted message, open it in chat instead of showing it in an overlay.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1712,45 +1687,14 @@
<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>
</message> </message>
<message numerus="yes">
<source>%1 day(s)</source>
<translation>
<numerusform>%1 jour(s)</numerusform>
<numerusform></numerusform>
</translation>
</message>
<message>
<source>1 week</source>
<translation>1 semaine</translation>
</message>
<message>
<source>1 month</source>
<translation>1 mois</translation>
</message>
<message>
<source>3 months</source>
<translation>3 mois</translation>
</message>
<message>
<source>6 months</source>
<translation>6 mois</translation>
</message>
<message>
<source>1 year</source>
<translation>1 année</translation>
</message>
<message>
<source>Session Timeout</source>
<translation>Délai d&apos;inactivité de session</translation>
</message>
<message>
<source>Inactive sessions will be terminated after this timeframe</source>
<translation>Sessions inactives seront terminées après ce délai</translation>
</message>
</context> </context>
<context> <context>
<name>SettingsStorage</name> <name>SettingsStorage</name>

View file

@ -473,10 +473,6 @@
<source>Deleted User</source> <source>Deleted User</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Double-tap on a message to choose a reaction</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -489,6 +485,13 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context>
<name>ContactSync</name>
<message>
<source>Could not synchronize your contacts with Telegram.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>CoverPage</name> <name>CoverPage</name>
<message> <message>
@ -1552,34 +1555,6 @@
<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>
<message>
<source>Go to quoted message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>When tapping a quoted message, open it in chat instead of showing it in an overlay.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1685,44 +1660,14 @@
<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>
</message> </message>
<message numerus="yes">
<source>%1 day(s)</source>
<translation type="unfinished">
<numerusform></numerusform>
</translation>
</message>
<message>
<source>1 week</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 month</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>3 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>6 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 year</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Session Timeout</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Inactive sessions will be terminated after this timeframe</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsStorage</name> <name>SettingsStorage</name>

View file

@ -483,10 +483,6 @@
<source>Deleted User</source> <source>Deleted User</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Double-tap on a message to choose a reaction</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -499,6 +495,13 @@
<translation>Nessuna chat presente</translation> <translation>Nessuna chat presente</translation>
</message> </message>
</context> </context>
<context>
<name>ContactSync</name>
<message>
<source>Could not synchronize your contacts with Telegram.</source>
<translation type="unfinished">Sincronizzazione contatti con Telegram non riuscita</translation>
</message>
</context>
<context> <context>
<name>CoverPage</name> <name>CoverPage</name>
<message> <message>
@ -1579,34 +1582,6 @@
<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>
<message>
<source>Go to quoted message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>When tapping a quoted message, open it in chat instead of showing it in an overlay.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1712,45 +1687,14 @@
<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>
</message> </message>
<message numerus="yes">
<source>%1 day(s)</source>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
<message>
<source>1 week</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 month</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>3 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>6 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 year</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Session Timeout</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Inactive sessions will be terminated after this timeframe</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsStorage</name> <name>SettingsStorage</name>

View file

@ -493,10 +493,6 @@
<source>Deleted User</source> <source>Deleted User</source>
<translation>Usunięty użytkownik</translation> <translation>Usunięty użytkownik</translation>
</message> </message>
<message>
<source>Double-tap on a message to choose a reaction</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -509,6 +505,13 @@
<translation>Nie masz jeszcze żadnych czatów.</translation> <translation>Nie masz jeszcze żadnych czatów.</translation>
</message> </message>
</context> </context>
<context>
<name>ContactSync</name>
<message>
<source>Could not synchronize your contacts with Telegram.</source>
<translation>Nie można zsynchonizaować kontaktów z Telegramem.</translation>
</message>
</context>
<context> <context>
<name>CoverPage</name> <name>CoverPage</name>
<message> <message>
@ -1606,34 +1609,6 @@
<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>
<message>
<source>Go to quoted message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>When tapping a quoted message, open it in chat instead of showing it in an overlay.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1739,46 +1714,14 @@
<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>
</message> </message>
<message numerus="yes">
<source>%1 day(s)</source>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
<message>
<source>1 week</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 month</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>3 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>6 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 year</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Session Timeout</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Inactive sessions will be terminated after this timeframe</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsStorage</name> <name>SettingsStorage</name>

View file

@ -348,11 +348,11 @@
</message> </message>
<message> <message>
<source>Leave Chat</source> <source>Leave Chat</source>
<translation>Выйти из чата</translation> <translation>Выйти из Чата</translation>
</message> </message>
<message> <message>
<source>Join Chat</source> <source>Join Chat</source>
<translation>Зайти в чат</translation> <translation>Зайти в Чат</translation>
</message> </message>
<message> <message>
<source>Leaving chat</source> <source>Leaving chat</source>
@ -427,7 +427,7 @@
</message> </message>
<message> <message>
<source>Search in Chat</source> <source>Search in Chat</source>
<translation>Поиск в чате</translation> <translation>Найти в Чате</translation>
</message> </message>
<message> <message>
<source>Search in chat...</source> <source>Search in chat...</source>
@ -493,10 +493,6 @@
<source>Deleted User</source> <source>Deleted User</source>
<translation>Удалённый пользователь</translation> <translation>Удалённый пользователь</translation>
</message> </message>
<message>
<source>Double-tap on a message to choose a reaction</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -509,6 +505,13 @@
<translation>Тут пока ничего нет</translation> <translation>Тут пока ничего нет</translation>
</message> </message>
</context> </context>
<context>
<name>ContactSync</name>
<message>
<source>Could not synchronize your contacts with Telegram.</source>
<translation>Невозможно синхронизировать ваши контакты с Телеграм.</translation>
</message>
</context>
<context> <context>
<name>CoverPage</name> <name>CoverPage</name>
<message> <message>
@ -1156,7 +1159,7 @@
</message> </message>
<message> <message>
<source>Secret Chat</source> <source>Secret Chat</source>
<translation>Секретный чат</translation> <translation>Секретный Чат</translation>
</message> </message>
<message> <message>
<source>End-to-end-encrypted, accessible on this device only</source> <source>End-to-end-encrypted, accessible on this device only</source>
@ -1238,7 +1241,7 @@
</message> </message>
<message> <message>
<source>New Chat</source> <source>New Chat</source>
<translation>Новый чат</translation> <translation>Новый Чат</translation>
</message> </message>
<message> <message>
<source>Filter your chats...</source> <source>Filter your chats...</source>
@ -1246,7 +1249,7 @@
</message> </message>
<message> <message>
<source>Search Chats</source> <source>Search Chats</source>
<translation>Поиск чатов</translation> <translation>Найти Чаты</translation>
</message> </message>
<message> <message>
<source>Download of %1 successful.</source> <source>Download of %1 successful.</source>
@ -1457,7 +1460,7 @@
<name>SearchChatsPage</name> <name>SearchChatsPage</name>
<message> <message>
<source>No chats found.</source> <source>No chats found.</source>
<translation>Ничего не найдено</translation> <translation>Чаты не найдены</translation>
</message> </message>
<message> <message>
<source>Searching chats...</source> <source>Searching chats...</source>
@ -1465,7 +1468,7 @@
</message> </message>
<message> <message>
<source>Private Chat</source> <source>Private Chat</source>
<translation>Приватный чат</translation> <translation>Приватный Чат</translation>
</message> </message>
<message> <message>
<source>Group</source> <source>Group</source>
@ -1493,7 +1496,7 @@
</message> </message>
<message> <message>
<source>Search Chats</source> <source>Search Chats</source>
<translation>Поиск чатов</translation> <translation>Найти Чаты</translation>
</message> </message>
<message> <message>
<source>Search a chat...</source> <source>Search a chat...</source>
@ -1609,34 +1612,6 @@
<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>Всегда показывать последнее сообщение на экране событий</translation>
</message>
<message>
<source>In addition to showing the number of unread messages, the latest message will also be appended to notifications.</source>
<translation>Включать в текст на экране событий не только количество непрочитанных сообщений, но и содержимое последнего сообщения.</translation>
</message>
<message>
<source>Highlight unread messages</source>
<translation>Выделять непрочитанные сообщения</translation>
</message>
<message>
<source>Highlight Conversations with unread messages</source>
<translation>Помечать чаты и каналы с непрочитанными сообщениями другим шрифтом и цветом.</translation>
</message>
<message>
<source>Hide content in notifications</source>
<translation>Не показывать содержимое сообщений в уведомлениях</translation>
</message>
<message>
<source>Go to quoted message</source>
<translation>Переходить к цитируемому сообщению</translation>
</message>
<message>
<source>When tapping a quoted message, open it in chat instead of showing it in an overlay.</source>
<translation>По нажатию на цитируемое сообщение, переходить к нему в чате вместо отображения во всплывающем окне.</translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1742,46 +1717,14 @@
<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>
</message> </message>
<message numerus="yes">
<source>%1 day(s)</source>
<translation>
<numerusform>%1 день</numerusform>
<numerusform>%1 дня</numerusform>
<numerusform>%1 дней</numerusform>
</translation>
</message>
<message>
<source>1 week</source>
<translation>1 неделя</translation>
</message>
<message>
<source>1 month</source>
<translation>1 месяц</translation>
</message>
<message>
<source>3 months</source>
<translation>3 месяца</translation>
</message>
<message>
<source>6 months</source>
<translation>6 месяцев</translation>
</message>
<message>
<source>1 year</source>
<translation>1 год</translation>
</message>
<message>
<source>Session Timeout</source>
<translation>Таймаут неактивности</translation>
</message>
<message>
<source>Inactive sessions will be terminated after this timeframe</source>
<translation>Неактивные сеансы будут автоматически завершены через указанное время.</translation>
</message>
</context> </context>
<context> <context>
<name>SettingsStorage</name> <name>SettingsStorage</name>

View file

@ -493,10 +493,6 @@
<source>Deleted User</source> <source>Deleted User</source>
<translation>Odstránený používateľ</translation> <translation>Odstránený používateľ</translation>
</message> </message>
<message>
<source>Double-tap on a message to choose a reaction</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -509,6 +505,13 @@
<translation>Nemáte žiadne čety.</translation> <translation>Nemáte žiadne čety.</translation>
</message> </message>
</context> </context>
<context>
<name>ContactSync</name>
<message>
<source>Could not synchronize your contacts with Telegram.</source>
<translation>Nemožno synchonizovať kontakty s Telegramom.</translation>
</message>
</context>
<context> <context>
<name>CoverPage</name> <name>CoverPage</name>
<message> <message>
@ -1606,34 +1609,6 @@
<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>
<message>
<source>Go to quoted message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>When tapping a quoted message, open it in chat instead of showing it in an overlay.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1739,46 +1714,14 @@
<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>
</message> </message>
<message numerus="yes">
<source>%1 day(s)</source>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
<message>
<source>1 week</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 month</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>3 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>6 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 year</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Session Timeout</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Inactive sessions will be terminated after this timeframe</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsStorage</name> <name>SettingsStorage</name>

View file

@ -483,10 +483,6 @@
<source>Deleted User</source> <source>Deleted User</source>
<translation>Tog bort användare</translation> <translation>Tog bort användare</translation>
</message> </message>
<message>
<source>Double-tap on a message to choose a reaction</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -499,6 +495,13 @@
<translation>Du har inga chattar än.</translation> <translation>Du har inga chattar än.</translation>
</message> </message>
</context> </context>
<context>
<name>ContactSync</name>
<message>
<source>Could not synchronize your contacts with Telegram.</source>
<translation>Kunde inte synkronisera dina kontakter med Telegram.</translation>
</message>
</context>
<context> <context>
<name>CoverPage</name> <name>CoverPage</name>
<message> <message>
@ -1579,34 +1582,6 @@
<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>
<message>
<source>Go to quoted message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>When tapping a quoted message, open it in chat instead of showing it in an overlay.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1712,45 +1687,14 @@
<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>
</message> </message>
<message numerus="yes">
<source>%1 day(s)</source>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
<message>
<source>1 week</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 month</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>3 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>6 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 year</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Session Timeout</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Inactive sessions will be terminated after this timeframe</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsStorage</name> <name>SettingsStorage</name>

View file

@ -473,10 +473,6 @@
<source>Deleted User</source> <source>Deleted User</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Double-tap on a message to choose a reaction</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -489,6 +485,13 @@
<translation></translation> <translation></translation>
</message> </message>
</context> </context>
<context>
<name>ContactSync</name>
<message>
<source>Could not synchronize your contacts with Telegram.</source>
<translation type="unfinished"> Telegram </translation>
</message>
</context>
<context> <context>
<name>CoverPage</name> <name>CoverPage</name>
<message> <message>
@ -1553,34 +1556,6 @@
<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>
<message>
<source>Go to quoted message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>When tapping a quoted message, open it in chat instead of showing it in an overlay.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1686,44 +1661,14 @@
<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>
</message> </message>
<message numerus="yes">
<source>%1 day(s)</source>
<translation type="unfinished">
<numerusform></numerusform>
</translation>
</message>
<message>
<source>1 week</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 month</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>3 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>6 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 year</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Session Timeout</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Inactive sessions will be terminated after this timeframe</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsStorage</name> <name>SettingsStorage</name>

View file

@ -483,10 +483,6 @@
<source>Deleted User</source> <source>Deleted User</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Double-tap on a message to choose a reaction</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -499,6 +495,13 @@
<translation>You don&apos;t have any chats yet.</translation> <translation>You don&apos;t have any chats yet.</translation>
</message> </message>
</context> </context>
<context>
<name>ContactSync</name>
<message>
<source>Could not synchronize your contacts with Telegram.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>CoverPage</name> <name>CoverPage</name>
<message> <message>
@ -1579,34 +1582,6 @@
<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>
<message>
<source>Go to quoted message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>When tapping a quoted message, open it in chat instead of showing it in an overlay.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsPage</name> <name>SettingsPage</name>
@ -1712,45 +1687,14 @@
<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>
</message> </message>
<message numerus="yes">
<source>%1 day(s)</source>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
<message>
<source>1 week</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 month</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>3 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>6 months</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 year</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Session Timeout</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Inactive sessions will be terminated after this timeframe</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsStorage</name> <name>SettingsStorage</name>