Update to TDLib 1.7.9, preliminary support for sponsored messages

This commit is contained in:
Sebastian Wolf 2021-12-05 22:06:05 +01:00
parent 0400d12e52
commit a59d32b29d
No known key found for this signature in database
GPG key ID: CEA9522B5F38A90A
31 changed files with 5228 additions and 535 deletions

View file

@ -108,6 +108,7 @@ DISTFILES += qml/harbour-fernschreiber.qml \
qml/components/messageContent/MessageVideoNote.qml \ qml/components/messageContent/MessageVideoNote.qml \
qml/components/messageContent/MessageVideo.qml \ qml/components/messageContent/MessageVideo.qml \
qml/components/messageContent/MessageVoiceNote.qml \ qml/components/messageContent/MessageVoiceNote.qml \
qml/components/messageContent/SponsoredMessage.qml \
qml/components/messageContent/WebPagePreview.qml \ qml/components/messageContent/WebPagePreview.qml \
qml/components/settingsPage/Accordion.qml \ qml/components/settingsPage/Accordion.qml \
qml/components/settingsPage/AccordionItem.qml \ qml/components/settingsPage/AccordionItem.qml \

View file

@ -110,7 +110,7 @@ ListItem {
text: qsTr("Reply to Message") text: qsTr("Reply to Message")
} }
MenuItem { MenuItem {
visible: myMessage.can_be_edited visible: typeof myMessage.can_be_edited !== "undefined" && myMessage.can_be_edited
onClicked: messageListItem.editMessage() onClicked: messageListItem.editMessage()
text: qsTr("Edit Message") text: qsTr("Edit Message")
} }
@ -138,16 +138,16 @@ ListItem {
Connections { Connections {
target: chatModel target: chatModel
onMessagesReceived: { onMessagesReceived: {
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex(); messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
} }
onMessagesIncrementalUpdate: { onMessagesIncrementalUpdate: {
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex(); messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
} }
onNewMessageReceived: { onNewMessageReceived: {
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex(); messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
} }
onUnreadCountUpdated: { onUnreadCountUpdated: {
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex(); messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
} }
onLastReadSentMessageUpdated: { onLastReadSentMessageUpdated: {
Debug.log("[ChatModel] Messages in this chat were read, new last read: ", lastReadSentIndex, ", updating description for index ", index, ", status: ", (index <= lastReadSentIndex)); Debug.log("[ChatModel] Messages in this chat were read, new last read: ", lastReadSentIndex, ", updating description for index ", index, ", status: ", (index <= lastReadSentIndex));
@ -256,7 +256,7 @@ ListItem {
} }
height: messageTextColumn.height + precalculatedValues.paddingMediumDouble height: messageTextColumn.height + precalculatedValues.paddingMediumDouble
width: precalculatedValues.backgroundWidth width: precalculatedValues.backgroundWidth
property bool isUnread: index > chatModel.getLastReadMessageIndex() property bool isUnread: index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage"
color: Theme.colorScheme === Theme.LightOnDark ? (isUnread ? Theme.secondaryHighlightColor : Theme.secondaryColor) : (isUnread ? Theme.backgroundGlowColor : Theme.overlayBackgroundColor) color: Theme.colorScheme === Theme.LightOnDark ? (isUnread ? Theme.secondaryHighlightColor : Theme.secondaryColor) : (isUnread ? Theme.backgroundGlowColor : Theme.overlayBackgroundColor)
radius: parent.width / 50 radius: parent.width / 50
opacity: isUnread ? 0.5 : 0.2 opacity: isUnread ? 0.5 : 0.2
@ -278,7 +278,7 @@ ListItem {
id: userText id: userText
width: parent.width width: parent.width
text: messageListItem.isOwnMessage ? qsTr("You") : Emoji.emojify(messageListItem.isAnonymous ? page.chatInformation.title : Functions.getUserName(messageListItem.userInformation), font.pixelSize) text: messageListItem.isOwnMessage ? qsTr("You") : Emoji.emojify( myMessage['@type'] === "sponsoredMessage" ? tdLibWrapper.getChat(myMessage.sponsor_chat_id).title : ( messageListItem.isAnonymous ? page.chatInformation.title : Functions.getUserName(messageListItem.userInformation) ), font.pixelSize)
font.pixelSize: Theme.fontSizeExtraSmall font.pixelSize: Theme.fontSizeExtraSmall
font.weight: Font.ExtraBold font.weight: Font.ExtraBold
color: messageListItem.textColor color: messageListItem.textColor
@ -286,7 +286,7 @@ ListItem {
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
textFormat: Text.StyledText textFormat: Text.StyledText
horizontalAlignment: messageListItem.textAlign horizontalAlignment: messageListItem.textAlign
visible: precalculatedValues.showUserInfo visible: precalculatedValues.showUserInfo || myMessage['@type'] === "sponsoredMessage"
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
enabled: !(messageListItem.precalculatedValues.pageIsSelecting || messageListItem.isAnonymous) enabled: !(messageListItem.precalculatedValues.pageIsSelecting || messageListItem.isAnonymous)
@ -302,7 +302,7 @@ ListItem {
Loader { Loader {
id: messageInReplyToLoader id: messageInReplyToLoader
active: myMessage.reply_to_message_id !== 0 active: typeof myMessage.reply_to_message_id !== "undefined" && myMessage.reply_to_message_id !== 0
width: parent.width width: parent.width
// text height ~= 1,28*font.pixelSize // text height ~= 1,28*font.pixelSize
height: active ? precalculatedValues.messageInReplyToHeight : 0 height: active ? precalculatedValues.messageInReplyToHeight : 0
@ -409,6 +409,21 @@ ListItem {
visible: (text !== "") visible: (text !== "")
} }
Loader {
id: sponsoredMessageButtonLoader
active: myMessage['@type'] === "sponsoredMessage"
asynchronous: true
width: parent.width
height: (status === Loader.Ready) ? item.implicitHeight : myMessage['@type'] === "sponsoredMessage" ? Theme.itemSizeMedium : 0
sourceComponent: Component {
SponsoredMessage {
sponsoredMessageData: myMessage
width: parent.width
}
}
}
Loader { Loader {
id: webPagePreviewLoader id: webPagePreviewLoader
active: false active: false

View file

@ -0,0 +1,59 @@
/*
Copyright (C) 2021 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import QtGraphicalEffects 1.0
import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../"
import "../../js/functions.js" as Functions
Column {
id: sponsoredMessageColumn
property var sponsoredMessageData;
Component.onCompleted: {
if (sponsoredMessageData) {
if (typeof sponsoredMessageData.link === "undefined") {
sponsoredMessageButton.text = qsTr("Go to Channel");
sponsoredMessageButton.advertisesChannel = true;
} else if (sponsoredMessageData.link['@type'] === "internalLinkTypeMessage") {
sponsoredMessageButton.text = qsTr("Go to Message");
sponsoredMessageButton.enabled = false;
} else {
sponsoredMessageButton.text = qsTr("Start Bot");
sponsoredMessageButton.enabled = false;
}
}
}
Button {
id: sponsoredMessageButton
property bool advertisesChannel: false;
anchors {
horizontalCenter: parent.horizontalCenter
}
onClicked: {
if (advertisesChannel) {
tdLibWrapper.createSupergroupChat(sponsoredMessageData.sponsor_chat_id, "openDirectly");
}
}
}
}

View file

@ -34,7 +34,10 @@ function getUserName(userInformation) {
function getMessageText(message, simple, currentUserId, ignoreEntities) { function getMessageText(message, simple, currentUserId, ignoreEntities) {
var myself = ( message.sender['@type'] === "messageSenderUser" && message.sender.user_id.toString() === currentUserId.toString() ); var myself = false;
if ( message['@type'] !== "sponsoredMessage" ) {
myself = ( message.sender['@type'] === "messageSenderUser" && message.sender.user_id.toString() === currentUserId.toString() );
}
switch(message.content['@type']) { switch(message.content['@type']) {
case 'messageText': case 'messageText':

View file

@ -44,6 +44,7 @@ Page {
property bool isBasicGroup: false; property bool isBasicGroup: false;
property bool isSuperGroup: false; property bool isSuperGroup: false;
property bool isChannel: false; property bool isChannel: false;
property bool containsSponsoredMessages: false;
property var chatPartnerInformation; property var chatPartnerInformation;
property var botInformation; property var botInformation;
property var chatGroupInformation; property var chatGroupInformation;
@ -188,6 +189,10 @@ Page {
return ""; return "";
} }
if (message['@type'] === "sponsoredMessage") {
return qsTr("Sponsored Message");
}
if (message.edit_date > 0) { if (message.edit_date > 0) {
messageStatusSuffix += " - " + qsTr("edited"); messageStatusSuffix += " - " + qsTr("edited");
} }
@ -552,11 +557,13 @@ Page {
} }
} }
onUserFullInfoUpdated: { onUserFullInfoUpdated: {
if(userId === chatPartnerInformation.id) { if(userId === chatPartnerInformation.id) {
chatPage.botInformation = userFullInfo; chatPage.botInformation = userFullInfo;
} }
} }
onSponsoredMessagesReceived: {
chatPage.containsSponsoredMessages = true;
}
} }
Connections { Connections {
@ -684,8 +691,10 @@ Page {
} }
onTriggered: { onTriggered: {
if(chatInformation.unread_count > 0 && lastQueuedIndex > -1) { var messageToRead = chatModel.getMessage(lastQueuedIndex);
var messageToRead = chatModel.getMessage(lastQueuedIndex); if (messageToRead['@type'] === "sponsoredMessage") {
tdLibWrapper.viewSponsoredMessage(chatInformation.id, messageToRead.id);
} else if (chatInformation.unread_count > 0 && lastQueuedIndex > -1) {
if (messageToRead && messageToRead.id) { if (messageToRead && messageToRead.id) {
tdLibWrapper.viewMessage(chatInformation.id, messageToRead.id, false); tdLibWrapper.viewMessage(chatInformation.id, messageToRead.id, false);
} }
@ -1086,6 +1095,9 @@ Page {
Debug.log("Page is initialized!"); Debug.log("Page is initialized!");
chatPage.isInitialized = true; chatPage.isInitialized = true;
chatView.handleScrollPositionChanged(); chatView.handleScrollPositionChanged();
if (chatPage.isChannel) {
tdLibWrapper.getChatSponsoredMessages(chatInformation.id);
}
} }
} }
} }
@ -1136,7 +1148,8 @@ Page {
function handleScrollPositionChanged() { function handleScrollPositionChanged() {
Debug.log("Current position: ", chatView.contentY); Debug.log("Current position: ", chatView.contentY);
if (chatOverviewItem.visible && chatInformation.unread_count > 0) { Debug.log("Contains sponsored messages?", chatPage.containsSponsoredMessages);
if (chatOverviewItem.visible && ( chatInformation.unread_count > 0 || chatPage.containsSponsoredMessages ) ) {
var bottomIndex = chatView.indexAt(chatView.contentX, ( chatView.contentY + chatView.height - Theme.horizontalPageMargin )); var bottomIndex = chatView.indexAt(chatView.contentX, ( chatView.contentY + chatView.height - Theme.horizontalPageMargin ));
if (bottomIndex > -1) { if (bottomIndex > -1) {
viewMessageTimer.queueViewMessage(bottomIndex) viewMessageTimer.queueViewMessage(bottomIndex)

View file

@ -221,6 +221,17 @@ QVector<int> ChatModel::MessageData::setInteractionInfo(const QVariantMap &info)
bool ChatModel::MessageData::lessThan(const MessageData *message1, const MessageData *message2) bool ChatModel::MessageData::lessThan(const MessageData *message1, const MessageData *message2)
{ {
bool message1Sponsored = message1->messageData.value("@type") == "sponsoredMessage";
bool message2Sponsored = message2->messageData.value("@type") == "sponsoredMessage";
if (message1Sponsored && message2Sponsored) {
return message1->messageId < message2->messageId;
}
if (message1Sponsored && !message2Sponsored) {
return false;
}
if (!message1Sponsored && message2Sponsored) {
return true;
}
return message1->messageId < message2->messageId; return message1->messageId < message2->messageId;
} }
@ -232,6 +243,7 @@ ChatModel::ChatModel(TDLibWrapper *tdLibWrapper) :
{ {
this->tdLibWrapper = tdLibWrapper; this->tdLibWrapper = tdLibWrapper;
connect(this->tdLibWrapper, SIGNAL(messagesReceived(QVariantList, int)), this, SLOT(handleMessagesReceived(QVariantList, int))); connect(this->tdLibWrapper, SIGNAL(messagesReceived(QVariantList, int)), this, SLOT(handleMessagesReceived(QVariantList, int)));
connect(this->tdLibWrapper, SIGNAL(sponsoredMessagesReceived(QVariantList)), this, SLOT(handleSponsoredMessagesReceived(QVariantList)));
connect(this->tdLibWrapper, SIGNAL(newMessageReceived(qlonglong, QVariantMap)), this, SLOT(handleNewMessageReceived(qlonglong, QVariantMap))); connect(this->tdLibWrapper, SIGNAL(newMessageReceived(qlonglong, QVariantMap)), this, SLOT(handleNewMessageReceived(qlonglong, QVariantMap)));
connect(this->tdLibWrapper, SIGNAL(receivedMessage(qlonglong, qlonglong, QVariantMap)), this, SLOT(handleMessageReceived(qlonglong, qlonglong, QVariantMap))); connect(this->tdLibWrapper, SIGNAL(receivedMessage(qlonglong, qlonglong, QVariantMap)), this, SLOT(handleMessageReceived(qlonglong, qlonglong, QVariantMap)));
connect(this->tdLibWrapper, SIGNAL(chatReadInboxUpdated(QString, QString, int)), this, SLOT(handleChatReadInboxUpdated(QString, QString, int))); connect(this->tdLibWrapper, SIGNAL(chatReadInboxUpdated(QString, QString, int)), this, SLOT(handleChatReadInboxUpdated(QString, QString, int)));
@ -462,6 +474,23 @@ void ChatModel::handleMessagesReceived(const QVariantList &messages, int totalCo
} }
void ChatModel::handleSponsoredMessagesReceived(const QVariantList &sponsoredMessages)
{
LOG("Handling sponsored messages:" <<sponsoredMessages.size());
if (sponsoredMessages.size() > 0) {
QList<MessageData*> messagesToBeAdded;
for (QVariant sponsoredMessage: sponsoredMessages) {
QVariantMap sponsoredMessageData = sponsoredMessage.toMap();
const qlonglong messageId = sponsoredMessageData.value(ID).toLongLong();
if (messageId && !messageIndexMap.contains(messageId)) {
LOG("New sponsored message will be added:" << messageId);
messagesToBeAdded.append(new MessageData(sponsoredMessageData, messageId));
}
}
appendMessages(messagesToBeAdded);
}
}
void ChatModel::handleNewMessageReceived(qlonglong chatId, const QVariantMap &message) void ChatModel::handleNewMessageReceived(qlonglong chatId, const QVariantMap &message)
{ {
const qlonglong messageId = message.value(ID).toLongLong(); const qlonglong messageId = message.value(ID).toLongLong();
@ -662,7 +691,14 @@ void ChatModel::insertMessages(const QList<MessageData*> newMessages)
appendMessages(newMessages); appendMessages(newMessages);
} else if (!newMessages.isEmpty()) { } else if (!newMessages.isEmpty()) {
// There is only an append or a prepend, tertium non datur! (probably ;)) // There is only an append or a prepend, tertium non datur! (probably ;))
const qlonglong lastKnownId = messages.last()->messageId; qlonglong lastKnownId = -1;
for (int i = (messages.size() - 1); i >=0; i-- ) {
if (messages.at(i)->messageData.value("@type").toString() == "sponsoredMessage") {
continue;
} else {
lastKnownId = messages.at(i)->messageId;
}
}
const qlonglong firstNewId = newMessages.first()->messageId; const qlonglong firstNewId = newMessages.first()->messageId;
LOG("Inserting messages, last known ID:" << lastKnownId << ", first new ID:" << firstNewId); LOG("Inserting messages, last known ID:" << lastKnownId << ", first new ID:" << firstNewId);
if (lastKnownId < firstNewId) { if (lastKnownId < firstNewId) {

View file

@ -63,6 +63,7 @@ signals:
private slots: private slots:
void handleMessagesReceived(const QVariantList &messages, int totalCount); void handleMessagesReceived(const QVariantList &messages, int totalCount);
void handleSponsoredMessagesReceived(const QVariantList &sponsoredMessages);
void handleNewMessageReceived(qlonglong chatId, const QVariantMap &message); void handleNewMessageReceived(qlonglong chatId, const QVariantMap &message);
void handleMessageReceived(qlonglong chatId, qlonglong messageId, const QVariantMap &message); void handleMessageReceived(qlonglong chatId, qlonglong messageId, const QVariantMap &message);
void handleChatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, int unreadCount); void handleChatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, int unreadCount);

View file

@ -101,6 +101,7 @@ TDLibReceiver::TDLibReceiver(void *tdLibClient, QObject *parent) : QThread(paren
handlers.insert("updateSupergroup", &TDLibReceiver::processUpdateSuperGroup); handlers.insert("updateSupergroup", &TDLibReceiver::processUpdateSuperGroup);
handlers.insert("updateChatOnlineMemberCount", &TDLibReceiver::processChatOnlineMemberCountUpdated); handlers.insert("updateChatOnlineMemberCount", &TDLibReceiver::processChatOnlineMemberCountUpdated);
handlers.insert("messages", &TDLibReceiver::processMessages); handlers.insert("messages", &TDLibReceiver::processMessages);
handlers.insert("sponsoredMessages", &TDLibReceiver::processSponsoredMessages);
handlers.insert("updateNewMessage", &TDLibReceiver::processUpdateNewMessage); handlers.insert("updateNewMessage", &TDLibReceiver::processUpdateNewMessage);
handlers.insert("message", &TDLibReceiver::processMessage); handlers.insert("message", &TDLibReceiver::processMessage);
handlers.insert("updateMessageSendSucceeded", &TDLibReceiver::processMessageSendSucceeded); handlers.insert("updateMessageSendSucceeded", &TDLibReceiver::processMessageSendSucceeded);
@ -356,6 +357,12 @@ void TDLibReceiver::processMessages(const QVariantMap &receivedInformation)
emit messagesReceived(receivedInformation.value(MESSAGES).toList(), receivedInformation.value(TOTAL_COUNT).toInt()); emit messagesReceived(receivedInformation.value(MESSAGES).toList(), receivedInformation.value(TOTAL_COUNT).toInt());
} }
void TDLibReceiver::processSponsoredMessages(const QVariantMap &receivedInformation)
{
LOG("Received sponsored messages");
emit sponsoredMessagesReceived(receivedInformation.value("messages").toList());
}
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();

View file

@ -56,6 +56,7 @@ signals:
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);
void messagesReceived(const QVariantList &messages, int totalCount); void messagesReceived(const QVariantList &messages, int totalCount);
void sponsoredMessagesReceived(const QVariantList &sponsoredMessages);
void newMessageReceived(qlonglong chatId, const QVariantMap &message); void newMessageReceived(qlonglong chatId, const QVariantMap &message);
void messageInformation(qlonglong chatId, qlonglong messageId, const QVariantMap &message); void messageInformation(qlonglong chatId, qlonglong messageId, const QVariantMap &message);
void messageSendSucceeded(qlonglong messageId, qlonglong oldMessageId, const QVariantMap &message); void messageSendSucceeded(qlonglong messageId, qlonglong oldMessageId, const QVariantMap &message);
@ -130,6 +131,7 @@ private:
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 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 processMessageSendSucceeded(const QVariantMap &receivedInformation); void processMessageSendSucceeded(const QVariantMap &receivedInformation);

View file

@ -118,6 +118,7 @@ void TDLibWrapper::initializeTDLibReciever() {
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)));
connect(this->tdLibReceiver, SIGNAL(messagesReceived(QVariantList, int)), this, SIGNAL(messagesReceived(QVariantList, int))); connect(this->tdLibReceiver, SIGNAL(messagesReceived(QVariantList, int)), this, SIGNAL(messagesReceived(QVariantList, int)));
connect(this->tdLibReceiver, SIGNAL(sponsoredMessagesReceived(QVariantList)), this, SIGNAL(sponsoredMessagesReceived(QVariantList)));
connect(this->tdLibReceiver, SIGNAL(newMessageReceived(qlonglong, QVariantMap)), this, SIGNAL(newMessageReceived(qlonglong, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(newMessageReceived(qlonglong, QVariantMap)), this, SIGNAL(newMessageReceived(qlonglong, QVariantMap)));
connect(this->tdLibReceiver, SIGNAL(messageInformation(qlonglong, qlonglong, QVariantMap)), this, SLOT(handleMessageInformation(qlonglong, qlonglong, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(messageInformation(qlonglong, qlonglong, QVariantMap)), this, SLOT(handleMessageInformation(qlonglong, qlonglong, QVariantMap)));
connect(this->tdLibReceiver, SIGNAL(messageSendSucceeded(qlonglong, qlonglong, QVariantMap)), this, SIGNAL(messageSendSucceeded(qlonglong, qlonglong, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(messageSendSucceeded(qlonglong, qlonglong, QVariantMap)), this, SIGNAL(messageSendSucceeded(qlonglong, qlonglong, QVariantMap)));
@ -335,6 +336,17 @@ void TDLibWrapper::viewMessage(const QString &chatId, const QString &messageId,
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::viewSponsoredMessage(qlonglong chatId, qlonglong messageId)
{
LOG("Mark sponsored message as viewed" << chatId << messageId);
QVariantMap requestObject;
requestObject.insert(_TYPE, "viewSponsoredMessage");
requestObject.insert(CHAT_ID, chatId);
requestObject.insert("sponsored_message_id", messageId);
requestObject.insert(_EXTRA, "viewSponsoredMessage");
this->sendRequest(requestObject);
}
void TDLibWrapper::pinMessage(const QString &chatId, const QString &messageId, bool disableNotification) void TDLibWrapper::pinMessage(const QString &chatId, const QString &messageId, bool disableNotification)
{ {
LOG("Pin message to chat" << chatId << messageId << disableNotification); LOG("Pin message to chat" << chatId << messageId << disableNotification);
@ -655,6 +667,16 @@ void TDLibWrapper::getChatPinnedMessage(qlonglong chatId)
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::getChatSponsoredMessages(qlonglong chatId)
{
LOG("Retrieving sponsored messages" << chatId);
QVariantMap requestObject;
requestObject.insert(_TYPE, "getChatSponsoredMessages");
requestObject.insert(CHAT_ID, chatId);
requestObject.insert(_EXTRA, "getChatSponsoredMessages:" + QString::number(chatId));
this->sendRequest(requestObject);
}
void TDLibWrapper::setOptionInteger(const QString &optionName, int optionValue) void TDLibWrapper::setOptionInteger(const QString &optionName, int optionValue)
{ {
LOG("Setting integer option" << optionName << optionValue); LOG("Setting integer option" << optionName << optionValue);

View file

@ -158,6 +158,7 @@ public:
Q_INVOKABLE void leaveChat(const QString &chatId); Q_INVOKABLE void leaveChat(const QString &chatId);
Q_INVOKABLE void getChatHistory(qlonglong chatId, qlonglong fromMessageId = 0, int offset = -1, int limit = 50, bool onlyLocal = false); Q_INVOKABLE void getChatHistory(qlonglong chatId, qlonglong fromMessageId = 0, int offset = -1, int limit = 50, bool onlyLocal = false);
Q_INVOKABLE void viewMessage(const QString &chatId, const QString &messageId, bool force); Q_INVOKABLE void viewMessage(const QString &chatId, const QString &messageId, bool force);
Q_INVOKABLE void viewSponsoredMessage(qlonglong chatId, qlonglong messageId);
Q_INVOKABLE void pinMessage(const QString &chatId, const QString &messageId, bool disableNotification = false); Q_INVOKABLE void pinMessage(const QString &chatId, const QString &messageId, bool disableNotification = false);
Q_INVOKABLE void unpinMessage(const QString &chatId, const QString &messageId); Q_INVOKABLE void unpinMessage(const QString &chatId, const QString &messageId);
Q_INVOKABLE void sendTextMessage(const QString &chatId, const QString &message, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendTextMessage(const QString &chatId, const QString &message, const QString &replyToMessageId = "0");
@ -172,6 +173,7 @@ public:
Q_INVOKABLE void getMessage(qlonglong chatId, qlonglong messageId); Q_INVOKABLE void getMessage(qlonglong chatId, qlonglong messageId);
Q_INVOKABLE void getCallbackQueryAnswer(const QString &chatId, const QString &messageId, const QVariantMap &payload); Q_INVOKABLE void getCallbackQueryAnswer(const QString &chatId, const QString &messageId, const QVariantMap &payload);
Q_INVOKABLE void getChatPinnedMessage(qlonglong chatId); Q_INVOKABLE void getChatPinnedMessage(qlonglong chatId);
Q_INVOKABLE void getChatSponsoredMessages(qlonglong chatId);
Q_INVOKABLE void setOptionInteger(const QString &optionName, int optionValue); Q_INVOKABLE void setOptionInteger(const QString &optionName, int optionValue);
Q_INVOKABLE void setOptionBoolean(const QString &optionName, bool optionValue); Q_INVOKABLE void setOptionBoolean(const QString &optionName, bool optionValue);
Q_INVOKABLE void setChatNotificationSettings(const QString &chatId, const QVariantMap &notificationSettings); Q_INVOKABLE void setChatNotificationSettings(const QString &chatId, const QVariantMap &notificationSettings);
@ -260,6 +262,7 @@ signals:
void superGroupUpdated(qlonglong groupId); void superGroupUpdated(qlonglong groupId);
void chatOnlineMemberCountUpdated(const QString &chatId, int onlineMemberCount); void chatOnlineMemberCountUpdated(const QString &chatId, int onlineMemberCount);
void messagesReceived(const QVariantList &messages, int totalCount); void messagesReceived(const QVariantList &messages, int totalCount);
void sponsoredMessagesReceived(const QVariantList &sponsoredMessages);
void newMessageReceived(qlonglong chatId, const QVariantMap &message); void newMessageReceived(qlonglong chatId, const QVariantMap &message);
void copyToDownloadsSuccessful(const QString &fileName, const QString &filePath); void copyToDownloadsSuccessful(const QString &fileName, const QString &filePath);
void copyToDownloadsError(const QString &fileName, const QString &filePath); void copyToDownloadsError(const QString &fileName, const QString &filePath);

View file

@ -1,5 +1,5 @@
// //
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 // 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)
@ -119,12 +119,12 @@ class Client final {
/** /**
* Move constructor. * Move constructor.
*/ */
Client(Client &&other); Client(Client &&other) noexcept;
/** /**
* Move assignment operator. * Move assignment operator.
*/ */
Client &operator=(Client &&other); Client &operator=(Client &&other) noexcept;
private: private:
class Impl; class Impl;
@ -238,6 +238,27 @@ class ClientManager final {
*/ */
static td_api::object_ptr<td_api::Object> execute(td_api::object_ptr<td_api::Function> &&request); static td_api::object_ptr<td_api::Object> execute(td_api::object_ptr<td_api::Function> &&request);
/**
* 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 (-1 - 1024).
* If 0, then TDLib will crash as soon as the callback returns.
* None of the TDLib methods can be called from the callback.
* \param message Null-terminated string with the message added to the log.
*/
using LogMessageCallbackPtr = void (*)(int verbosity_level, const char *message);
/**
* Sets the callback that will be called when a message is added to the internal TDLib log.
* None of the TDLib methods can be called from the callback.
* By default the callback is not set.
*
* \param[in] max_verbosity_level The maximum verbosity level of messages for which the callback will be called.
* \param[in] callback Callback that will be called when a message is added to the internal TDLib log.
* Pass nullptr to remove the callback.
*/
static void set_log_message_callback(int max_verbosity_level, LogMessageCallbackPtr callback);
/** /**
* Destroys the client manager and all TDLib client instances managed by it. * Destroys the client manager and all TDLib client instances managed by it.
*/ */
@ -246,12 +267,12 @@ class ClientManager final {
/** /**
* Move constructor. * Move constructor.
*/ */
ClientManager(ClientManager &&other); ClientManager(ClientManager &&other) noexcept;
/** /**
* Move assignment operator. * Move assignment operator.
*/ */
ClientManager &operator=(ClientManager &&other); ClientManager &operator=(ClientManager &&other) noexcept;
/** /**
* Returns a pointer to a singleton ClientManager instance. * Returns a pointer to a singleton ClientManager instance.

View file

@ -1,5 +1,5 @@
// //
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 // 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)
@ -21,7 +21,7 @@ namespace td {
* Interface for managing the internal logging of TDLib. * Interface for managing the internal logging of TDLib.
* By default TDLib writes logs to stderr or an OS specific log and uses a verbosity level of 5. * By default TDLib writes logs to stderr or an OS specific log and uses a verbosity level of 5.
* These functions are deprecated since TDLib 1.4.0 in favor of the td::td_api::setLogVerbosityLevel, * These functions are deprecated since TDLib 1.4.0 in favor of the td::td_api::setLogVerbosityLevel,
* td::td_api::setLogStream and other synchronous requests for managing the intrenal TDLib logging. * td::td_api::setLogStream and other synchronous requests for managing the internal TDLib logging.
*/ */
class Log { class Log {
public: public:
@ -76,6 +76,7 @@ class Log {
* The TDLib will crash as soon as callback returns. * The TDLib will crash as soon as callback returns.
* By default the callback is not set. * By default the callback is not set.
* *
* \deprecated Use ClientManager::set_log_message_callback instead.
* \param[in] callback Callback that will be called when a fatal error happens. * \param[in] callback Callback that will be called when a fatal error happens.
* Pass nullptr to remove the callback. * Pass nullptr to remove the callback.
*/ */

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-2020 // 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)
@ -94,8 +94,11 @@ TDJSON_EXPORT const char *td_json_client_execute(void *client, const char *reque
*/ */
TDJSON_EXPORT void td_json_client_destroy(void *client); TDJSON_EXPORT void td_json_client_destroy(void *client);
/* /**
* New TDLib JSON interface. * \file
* Alternatively, you can use new TDLib JSON interface, which will replace the current JSON interface in TDLib 2.0.0.
*
* Objects and functions serialization to JSON is the same for both JSON interfaces.
* *
* The main TDLib interface is asynchronous. To match requests with a corresponding response, the field "@extra" can * The main TDLib interface is asynchronous. To match requests with a corresponding response, the field "@extra" can
* be added to the request object. The corresponding response will have an "@extra" field with exactly the same value. * be added to the request object. The corresponding response will have an "@extra" field with exactly the same value.
@ -109,6 +112,7 @@ TDJSON_EXPORT void td_json_client_destroy(void *client);
* 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.
* *
* General pattern of usage: * General pattern of usage:
* \code * \code
@ -156,6 +160,27 @@ TDJSON_EXPORT const char *td_receive(double timeout);
*/ */
TDJSON_EXPORT const char *td_execute(const char *request); 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.
*
* \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.
* None of the TDLib methods can be called from the callback.
* \param message Null-terminated string with the logged message.
*/
typedef void (*td_log_message_callback_ptr)(int verbosity_level, const char *message);
/**
* Sets the callback that will be called when a message is added to the internal TDLib log.
* None of the TDLib methods can be called from the callback.
* By default the callback is not set.
*
* \param[in] max_verbosity_level The maximum verbosity level of messages for which the callback will be called.
* \param[in] callback Callback that will be called when a message is added to the internal TDLib log.
* Pass nullptr to remove the callback.
*/
TDJSON_EXPORT void td_set_log_message_callback(int max_verbosity_level, td_log_message_callback_ptr callback);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View file

@ -1,5 +1,5 @@
// //
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 // 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)
@ -11,7 +11,7 @@
* C interface for managing the internal logging of TDLib. * C interface for managing the internal logging of TDLib.
* By default TDLib writes logs to stderr or an OS specific log and uses a verbosity level of 5. * By default TDLib writes logs to stderr or an OS specific log and uses a verbosity level of 5.
* These functions are deprecated since TDLib 1.4.0 in favor of the setLogVerbosityLevel, setLogStream and * These functions are deprecated since TDLib 1.4.0 in favor of the setLogVerbosityLevel, setLogStream and
* other synchronous requests for managing the intrenal TDLib logging. * other synchronous requests for managing the internal TDLib logging.
*/ */
#include "td/telegram/tdjson_export.h" #include "td/telegram/tdjson_export.h"
@ -71,10 +71,11 @@ typedef void (*td_log_fatal_error_callback_ptr)(const char *error_message);
* The TDLib will crash as soon as callback returns. * The TDLib will crash as soon as callback returns.
* By default the callback is not set. * By default the callback is not set.
* *
* \deprecated Use td_set_log_message_callback instead.
* \param[in] callback Callback that will be called when a fatal error happens. * \param[in] callback Callback that will be called when a fatal error happens.
* Pass NULL to remove the callback. * Pass NULL to remove the callback.
*/ */
TDJSON_EXPORT void td_set_log_fatal_error_callback(td_log_fatal_error_callback_ptr callback); TDJSON_DEPRECATED_EXPORT void td_set_log_fatal_error_callback(td_log_fatal_error_callback_ptr callback);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"

View file

@ -1,5 +1,5 @@
// //
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 // 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

@ -522,6 +522,10 @@
<source>Accuracy: %1m</source> <source>Accuracy: %1m</source>
<translation>Genauigkeit: %1m</translation> <translation>Genauigkeit: %1m</translation>
</message> </message>
<message>
<source>Sponsored Message</source>
<translation>Gesponsorte Nachricht</translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -1761,6 +1765,21 @@
<translation>Lade hoch...</translation> <translation>Lade hoch...</translation>
</message> </message>
</context> </context>
<context>
<name>SponsoredMessage</name>
<message>
<source>Go to Channel</source>
<translation>Zum Kanal gehen</translation>
</message>
<message>
<source>Go to Message</source>
<translation>Zur Nachricht gehen</translation>
</message>
<message>
<source>Start Bot</source>
<translation>Bot starten</translation>
</message>
</context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>
<message> <message>

View file

@ -522,6 +522,10 @@
<source>Accuracy: %1m</source> <source>Accuracy: %1m</source>
<translation>Accuracy: %1m</translation> <translation>Accuracy: %1m</translation>
</message> </message>
<message>
<source>Sponsored Message</source>
<translation>Sponsored Message</translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -1763,6 +1767,21 @@ messages</numerusform>
<translation>Uploading...</translation> <translation>Uploading...</translation>
</message> </message>
</context> </context>
<context>
<name>SponsoredMessage</name>
<message>
<source>Go to Channel</source>
<translation>Go to Channel</translation>
</message>
<message>
<source>Go to Message</source>
<translation>Go to Message</translation>
</message>
<message>
<source>Start Bot</source>
<translation>Start Bot</translation>
</message>
</context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>
<message> <message>

View file

@ -522,6 +522,10 @@
<source>Accuracy: %1m</source> <source>Accuracy: %1m</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Sponsored Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -1761,6 +1765,21 @@
<translation>Subiendo...</translation> <translation>Subiendo...</translation>
</message> </message>
</context> </context>
<context>
<name>SponsoredMessage</name>
<message>
<source>Go to Channel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Go to Message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start Bot</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>
<message> <message>

View file

@ -522,6 +522,10 @@
<source>Accuracy: %1m</source> <source>Accuracy: %1m</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Sponsored Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -1762,6 +1766,21 @@
<translation>Lähetetään...</translation> <translation>Lähetetään...</translation>
</message> </message>
</context> </context>
<context>
<name>SponsoredMessage</name>
<message>
<source>Go to Channel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Go to Message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start Bot</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>
<message> <message>

View file

@ -522,6 +522,10 @@
<source>Accuracy: %1m</source> <source>Accuracy: %1m</source>
<translation>Précision : %1 m</translation> <translation>Précision : %1 m</translation>
</message> </message>
<message>
<source>Sponsored Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -1761,6 +1765,21 @@
<translation>Téléverse</translation> <translation>Téléverse</translation>
</message> </message>
</context> </context>
<context>
<name>SponsoredMessage</name>
<message>
<source>Go to Channel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Go to Message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start Bot</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>
<message> <message>

View file

@ -512,6 +512,10 @@
<source>Accuracy: %1m</source> <source>Accuracy: %1m</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Sponsored Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -1734,6 +1738,21 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context>
<name>SponsoredMessage</name>
<message>
<source>Go to Channel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Go to Message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start Bot</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>
<message> <message>

View file

@ -522,6 +522,10 @@
<source>Accuracy: %1m</source> <source>Accuracy: %1m</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Sponsored Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -1761,6 +1765,21 @@
<translation>Carica...</translation> <translation>Carica...</translation>
</message> </message>
</context> </context>
<context>
<name>SponsoredMessage</name>
<message>
<source>Go to Channel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Go to Message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start Bot</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>
<message> <message>

View file

@ -532,6 +532,10 @@
<source>Accuracy: %1m</source> <source>Accuracy: %1m</source>
<translation>Dokładność: %1m</translation> <translation>Dokładność: %1m</translation>
</message> </message>
<message>
<source>Sponsored Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -1788,6 +1792,21 @@
<translation>Przesyłanie...</translation> <translation>Przesyłanie...</translation>
</message> </message>
</context> </context>
<context>
<name>SponsoredMessage</name>
<message>
<source>Go to Channel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Go to Message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start Bot</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>
<message> <message>

View file

@ -532,6 +532,10 @@
<source>Accuracy: %1m</source> <source>Accuracy: %1m</source>
<translation>Точность: %1м</translation> <translation>Точность: %1м</translation>
</message> </message>
<message>
<source>Sponsored Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -1791,6 +1795,21 @@
<translation>Отправка...</translation> <translation>Отправка...</translation>
</message> </message>
</context> </context>
<context>
<name>SponsoredMessage</name>
<message>
<source>Go to Channel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Go to Message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start Bot</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>
<message> <message>

View file

@ -532,6 +532,10 @@
<source>Accuracy: %1m</source> <source>Accuracy: %1m</source>
<translation>Presnosť: %1 m</translation> <translation>Presnosť: %1 m</translation>
</message> </message>
<message>
<source>Sponsored Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -1788,6 +1792,21 @@
<translation>Zapisovanie...</translation> <translation>Zapisovanie...</translation>
</message> </message>
</context> </context>
<context>
<name>SponsoredMessage</name>
<message>
<source>Go to Channel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Go to Message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start Bot</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>
<message> <message>

View file

@ -522,6 +522,10 @@
<source>Accuracy: %1m</source> <source>Accuracy: %1m</source>
<translation>Noggrannhet: %1m</translation> <translation>Noggrannhet: %1m</translation>
</message> </message>
<message>
<source>Sponsored Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -1761,6 +1765,21 @@
<translation>Ladda upp...</translation> <translation>Ladda upp...</translation>
</message> </message>
</context> </context>
<context>
<name>SponsoredMessage</name>
<message>
<source>Go to Channel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Go to Message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start Bot</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>
<message> <message>

View file

@ -512,6 +512,10 @@
<source>Accuracy: %1m</source> <source>Accuracy: %1m</source>
<translation>: %1m</translation> <translation>: %1m</translation>
</message> </message>
<message>
<source>Sponsored Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -1735,6 +1739,21 @@
<translation></translation> <translation></translation>
</message> </message>
</context> </context>
<context>
<name>SponsoredMessage</name>
<message>
<source>Go to Channel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Go to Message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start Bot</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>
<message> <message>

View file

@ -522,6 +522,10 @@
<source>Accuracy: %1m</source> <source>Accuracy: %1m</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Sponsored Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatSelectionPage</name> <name>ChatSelectionPage</name>
@ -1761,6 +1765,21 @@
<translation type="unfinished">Uploading...</translation> <translation type="unfinished">Uploading...</translation>
</message> </message>
</context> </context>
<context>
<name>SponsoredMessage</name>
<message>
<source>Go to Channel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Go to Message</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start Bot</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>
<message> <message>