Merge remote-tracking branch 'origin/master' into searching

This commit is contained in:
Sebastian Wolf 2020-12-25 22:40:37 +01:00
commit c83fcda617
No known key found for this signature in database
GPG key ID: CEA9522B5F38A90A
26 changed files with 321 additions and 88 deletions

View file

@ -51,6 +51,7 @@ DISTFILES += qml/harbour-fernschreiber.qml \
qml/components/MessageListViewItem.qml \ qml/components/MessageListViewItem.qml \
qml/components/MessageListViewItemSimple.qml \ qml/components/MessageListViewItemSimple.qml \
qml/components/MessageOverlayFlickable.qml \ qml/components/MessageOverlayFlickable.qml \
qml/components/MultilineEmojiLabel.qml \
qml/components/PinnedMessageItem.qml \ qml/components/PinnedMessageItem.qml \
qml/components/PollPreview.qml \ qml/components/PollPreview.qml \
qml/components/PressEffect.qml \ qml/components/PressEffect.qml \

View file

@ -36,7 +36,7 @@ Row {
onInReplyToMessageChanged: { onInReplyToMessageChanged: {
if (inReplyToMessage) { if (inReplyToMessage) {
inReplyToUserText.text = (inReplyToRow.inReplyToMessage.sender.user_id !== inReplyToRow.myUserId) ? Emoji.emojify(Functions.getUserName(tdLibWrapper.getUserInformation(inReplyToRow.inReplyToMessage.sender.user_id)), inReplyToUserText.font.pixelSize) : qsTr("You"); inReplyToUserText.text = (inReplyToMessage.sender["@type"] === "messageSenderChat" ? page.chatInformation.title : (inReplyToRow.inReplyToMessage.sender.user_id !== inReplyToRow.myUserId) ? Emoji.emojify(Functions.getUserName(tdLibWrapper.getUserInformation(inReplyToRow.inReplyToMessage.sender.user_id)), inReplyToUserText.font.pixelSize) : qsTr("You"));
inReplyToMessageText.text = Emoji.emojify(Functions.getMessageText(inReplyToRow.inReplyToMessage, true, inReplyToRow.inReplyToMessage.sender.user_id === inReplyToRow.myUserId, false), inReplyToMessageText.font.pixelSize); inReplyToMessageText.text = Emoji.emojify(Functions.getMessageText(inReplyToRow.inReplyToMessage, true, inReplyToRow.inReplyToMessage.sender.user_id === inReplyToRow.myUserId, false), inReplyToMessageText.font.pixelSize);
} }
} }

View file

@ -29,6 +29,7 @@ ListItem {
property var messageId property var messageId
property var myMessage property var myMessage
property bool canReplyToMessage property bool canReplyToMessage
readonly property bool isAnonymous: myMessage.sender["@type"] === "messageSenderChat"
readonly property var userInformation: tdLibWrapper.getUserInformation(myMessage.sender.user_id) readonly property var userInformation: tdLibWrapper.getUserInformation(myMessage.sender.user_id)
property QtObject precalculatedValues: ListView.view.precalculatedValues property QtObject precalculatedValues: ListView.view.precalculatedValues
readonly property color textColor: isOwnMessage ? Theme.highlightColor : Theme.primaryColor readonly property color textColor: isOwnMessage ? Theme.highlightColor : Theme.primaryColor
@ -57,6 +58,8 @@ ListItem {
mouseX < (extraContentLoader.x + extraContentLoader.width) && mouseX < (extraContentLoader.x + extraContentLoader.width) &&
mouseY < (extraContentLoader.y + extraContentLoader.height)) { mouseY < (extraContentLoader.y + extraContentLoader.height)) {
extraContent.clicked() extraContent.clicked()
} else if (webPagePreviewLoader.item) {
webPagePreviewLoader.item.clicked()
} }
} }
} }
@ -115,9 +118,14 @@ ListItem {
} }
MenuItem { MenuItem {
onClicked: { onClicked: {
tdLibWrapper.pinMessage(page.chatInformation.id, messageId) if (myMessage.is_pinned) {
Remorse.popupAction(page, qsTr("Message unpinned"), function() { tdLibWrapper.unpinMessage(page.chatInformation.id, messageId);
pinnedMessageItem.requestCloseMessage(); } );
} else {
tdLibWrapper.pinMessage(page.chatInformation.id, messageId);
} }
text: qsTr("Pin Message") }
text: myMessage.is_pinned ? qsTr("Unpin Message") : qsTr("Pin Message")
visible: canPinMessages() visible: canPinMessages()
} }
MenuItem { MenuItem {
@ -167,6 +175,11 @@ ListItem {
messageInReplyToLoader.inReplyToMessage = message; messageInReplyToLoader.inReplyToMessage = message;
} }
} }
onMessageNotFound: {
if (messageId === myMessage.reply_to_message_id) {
messageInReplyToLoader.active = false;
}
}
} }
Component.onCompleted: { Component.onCompleted: {
@ -216,14 +229,14 @@ ListItem {
sourceComponent: Component { sourceComponent: Component {
ProfileThumbnail { ProfileThumbnail {
id: messagePictureThumbnail id: messagePictureThumbnail
photoData: (typeof messageListItem.userInformation.profile_photo !== "undefined") ? messageListItem.userInformation.profile_photo.small : ({}) photoData: messageListItem.isAnonymous ? ((typeof page.chatInformation.photo !== "undefined") ? page.chatInformation.photo.small : {}) : ((typeof messageListItem.userInformation.profile_photo !== "undefined") ? messageListItem.userInformation.profile_photo.small : ({}))
replacementStringHint: userText.text replacementStringHint: userText.text
width: Theme.itemSizeSmall width: Theme.itemSizeSmall
height: Theme.itemSizeSmall height: Theme.itemSizeSmall
visible: precalculatedValues.showUserInfo visible: precalculatedValues.showUserInfo
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
enabled: !messageListItem.precalculatedValues.pageIsSelecting enabled: !(messageListItem.precalculatedValues.pageIsSelecting || messageListItem.isAnonymous)
onClicked: { onClicked: {
tdLibWrapper.createPrivateChat(messageListItem.userInformation.id); tdLibWrapper.createPrivateChat(messageListItem.userInformation.id);
} }
@ -270,7 +283,7 @@ ListItem {
id: userText id: userText
width: parent.width width: parent.width
text: messageListItem.isOwnMessage ? qsTr("You") : Emoji.emojify(Functions.getUserName(messageListItem.userInformation), font.pixelSize) text: messageListItem.isOwnMessage ? qsTr("You") : Emoji.emojify(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
@ -281,7 +294,7 @@ ListItem {
visible: precalculatedValues.showUserInfo visible: precalculatedValues.showUserInfo
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
enabled: !messageListItem.precalculatedValues.pageIsSelecting enabled: !(messageListItem.precalculatedValues.pageIsSelecting || messageListItem.isAnonymous)
onClicked: { onClicked: {
tdLibWrapper.createPrivateChat(messageListItem.userInformation.id); tdLibWrapper.createPrivateChat(messageListItem.userInformation.id);
} }
@ -397,17 +410,10 @@ ListItem {
active: false active: false
asynchronous: true asynchronous: true
width: parent.width width: parent.width
height: typeof myMessage.content.web_page !== "undefined" ? precalculatedValues.webPagePreviewHeight : 0 height: (status === Loader.Ready) ? item.implicitHeight : myMessage.content.web_page ? precalculatedValues.webPagePreviewHeight : 0
sourceComponent: Component { sourceComponent: Component {
id: webPagePreviewComponent
WebPagePreview { WebPagePreview {
id: webPagePreview
onImplicitHeightChanged: {
webPagePreviewLoader.height = webPagePreview.implicitHeight;
}
webPageData: myMessage.content.web_page webPageData: myMessage.content.web_page
width: parent.width width: parent.width
highlighted: messageListItem.highlighted highlighted: messageListItem.highlighted

View file

@ -33,6 +33,7 @@ Flickable {
property bool showHeader: true property bool showHeader: true
readonly property var userInformation: tdLibWrapper.getUserInformation(overlayMessage.sender.user_id); readonly property var userInformation: tdLibWrapper.getUserInformation(overlayMessage.sender.user_id);
readonly property bool isOwnMessage: tdLibWrapper.getUserInformation().id === overlayMessage.sender.user_id; readonly property bool isOwnMessage: tdLibWrapper.getUserInformation().id === overlayMessage.sender.user_id;
readonly property bool isAnonymous: overlayMessage.sender["@type"] === "messageSenderChat"
readonly property string extraContentComponentName: (typeof overlayMessage.content !== "undefined" && typeof chatView.contentComponentNames[overlayMessage.content['@type']] !== "undefined" ) readonly property string extraContentComponentName: (typeof overlayMessage.content !== "undefined" && typeof chatView.contentComponentNames[overlayMessage.content['@type']] !== "undefined" )
? chatView.contentComponentNames[overlayMessage.content['@type']] : "" ? chatView.contentComponentNames[overlayMessage.content['@type']] : ""
signal requestClose; signal requestClose;
@ -104,7 +105,7 @@ Flickable {
spacing: Theme.paddingMedium spacing: Theme.paddingMedium
ProfileThumbnail { ProfileThumbnail {
id: overlayMessagePictureThumbnail id: overlayMessagePictureThumbnail
photoData: (typeof messageOverlayFlickable.userInformation.profile_photo !== "undefined") ? messageOverlayFlickable.userInformation.profile_photo.small : ({}) photoData: messageOverlayFlickable.isAnonymous ? ((typeof chatPage.chatInformation.photo !== "undefined") ? chatPage.chatInformation.photo.small : {}) : ((typeof messageOverlayFlickable.userInformation.profile_photo !== "undefined") ? messageOverlayFlickable.userInformation.profile_photo.small : ({}))
replacementStringHint: overlayMessageUserText.text replacementStringHint: overlayMessageUserText.text
width: Theme.itemSizeLarge width: Theme.itemSizeLarge
height: Theme.itemSizeLarge height: Theme.itemSizeLarge
@ -114,7 +115,7 @@ Flickable {
width: parent.width - overlayMessagePictureThumbnail.width width: parent.width - overlayMessagePictureThumbnail.width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: messageOverlayFlickable.isOwnMessage ? qsTr("You") : Emoji.emojify(Functions.getUserName(messageOverlayFlickable.userInformation), font.pixelSize) text: messageOverlayFlickable.isOwnMessage ? qsTr("You") : Emoji.emojify(messageOverlayFlickable.isAnonymous ? chatPage.chatInformation.title : Functions.getUserName(messageOverlayFlickable.userInformation), font.pixelSize)
font.pixelSize: Theme.fontSizeExtraLarge font.pixelSize: Theme.fontSizeExtraLarge
font.weight: Font.ExtraBold font.weight: Font.ExtraBold
maximumLineCount: 1 maximumLineCount: 1

View file

@ -0,0 +1,78 @@
/*
Copyright (C) 2020 Slava Monich 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.0
import Sailfish.Silica 1.0
import "../js/twemoji.js" as Emoji
// Combination of maximumLineCount and TruncationMode.Elide (or Fade) breaks
// Emoji image alignment, pushing the image down. This one aligns the image
// correctly on its line.
Label {
property string rawText
property int maxLineCount
wrapMode: Text.Wrap
textFormat: Text.StyledText
truncationMode: TruncationMode.Elide
// lineCount is unreliable for StyledText with images and line breaks
readonly property int fontSize: font.pixelSize
readonly property int actualLineHeight: (text === rawText) ? fontSize : (fontSize * 6 / 5)
readonly property int actualLineCount: Math.floor(implicitHeight/actualLineHeight)
Component.onCompleted: refitText()
onFontSizeChanged: refitText()
onWidthChanged: refitText()
onRawTextChanged: refitText()
onMaxLineCountChanged: refitText()
function emojify(str) {
return Emoji.emojify(str, fontSize)
}
function refitText() {
text = emojify(rawText)
if (maxLineCount > 0) {
var divisor = 1
var max = rawText.length
var min = max
while (actualLineCount > maxLineCount && divisor < rawText.length) {
max = min
divisor++
min = rawText.length/divisor
text = emojify(rawText.substr(0, min) + "…")
}
while (min < max) {
var mid = Math.floor((min + max)/2)
if (mid === min) {
text = emojify(rawText.substr(0, min) + "…")
break
} else {
text = emojify(rawText.substr(0, mid) + "…")
if (actualLineCount > maxLineCount) {
max = mid
} else {
min = mid
}
}
}
}
}
}

View file

@ -123,7 +123,7 @@ Item {
id: unpinMessageIconButton id: unpinMessageIconButton
icon.source: "image://theme/icon-m-remove" icon.source: "image://theme/icon-m-remove"
onClicked: { onClicked: {
Remorse.itemAction(pinnedMessageRow, qsTr("Message unpinned"), function() { tdLibWrapper.unpinMessage(chatPage.chatInformation.id); Remorse.itemAction(pinnedMessageRow, qsTr("Message unpinned"), function() { tdLibWrapper.unpinMessage(chatPage.chatInformation.id, pinnedMessage.id);
pinnedMessageItem.requestCloseMessage(); }); pinnedMessageItem.requestCloseMessage(); });
} }

View file

@ -19,101 +19,87 @@
import QtQuick 2.6 import QtQuick 2.6
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import "../components" import WerkWolf.Fernschreiber 1.0
import "../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions import "../js/functions.js" as Functions
Column { Column {
id: webPagePreviewColumn id: webPagePreviewColumn
property var webPageData; property var webPageData;
property var pictureFileInformation;
property bool hasImage: false;
property bool largerFontSize: false; property bool largerFontSize: false;
property bool highlighted property bool highlighted
readonly property bool hasImage: picture.fileId !== 0
readonly property int fontSize: largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall
spacing: Theme.paddingSmall spacing: Theme.paddingSmall
Component.onCompleted: { Component.onCompleted: {
updateWebPage();
}
function updateWebPage() {
if (webPageData) { if (webPageData) {
if (typeof webPageData.photo !== "undefined") { if (webPageData.photo) {
hasImage = true;
// Check first which size fits best... // Check first which size fits best...
var photo
for (var i = 0; i < webPageData.photo.sizes.length; i++) { for (var i = 0; i < webPageData.photo.sizes.length; i++) {
pictureFileInformation = webPageData.photo.sizes[i].photo; photo = webPageData.photo.sizes[i].photo;
if (webPageData.photo.sizes[i].width >= webPagePreviewColumn.width) { if (webPageData.photo.sizes[i].width >= webPagePreviewColumn.width) {
break; break;
} }
} }
if (pictureFileInformation.local.is_downloading_completed) { if (photo) {
singleImage.source = pictureFileInformation.local.path; picture.fileInformation = photo
} else {
tdLibWrapper.downloadFile(pictureFileInformation.id);
} }
} }
} }
} }
Connections { function clicked() {
target: tdLibWrapper descriptionText.toggleMaxLineCount()
onFileUpdated: {
if (typeof pictureFileInformation !== "undefined" && fileId === pictureFileInformation.id) {
if (fileInformation.local.is_downloading_completed) {
pictureFileInformation = fileInformation;
singleImage.source = fileInformation.local.path;
}
}
}
} }
Label { TDLibFile {
id: picture
tdlib: tdLibWrapper
autoLoad: true
}
MultilineEmojiLabel {
id: siteNameText id: siteNameText
width: parent.width width: parent.width
text: webPageData.site_name ? Emoji.emojify(webPageData.site_name, font.pixelSize) : "" rawText: webPageData.site_name ? webPageData.site_name : ""
font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall font.pixelSize: webPagePreviewColumn.fontSize
font.bold: true font.bold: true
color: Theme.secondaryHighlightColor color: Theme.secondaryHighlightColor
truncationMode: TruncationMode.Fade visible: (rawText !== "")
maximumLineCount: 1 maxLineCount: 1
textFormat: Text.StyledText
visible: (text !== "")
} }
Label { MultilineEmojiLabel {
id: titleText id: titleText
width: parent.width width: parent.width
text: webPageData.title ? Emoji.emojify(webPageData.title, font.pixelSize) : "" rawText: webPageData.title ? webPageData.title : ""
font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall font.pixelSize: webPagePreviewColumn.fontSize
font.bold: true font.bold: true
truncationMode: TruncationMode.Fade visible: (rawText !== "")
wrapMode: Text.Wrap maxLineCount: 2
maximumLineCount: 2
textFormat: Text.StyledText
visible: (text !== "")
} }
Label { MultilineEmojiLabel {
id: descriptionText id: descriptionText
width: parent.width width: parent.width
text: webPageData.description ? Emoji.emojify(Functions.enhanceMessageText(webPageData.description), font.pixelSize) : "" rawText: webPageData.description ? Functions.enhanceMessageText(webPageData.description) : ""
font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall font.pixelSize: webPagePreviewColumn.fontSize
truncationMode: TruncationMode.Fade visible: (rawText !== "")
wrapMode: Text.Wrap readonly property int defaultMaxLineCount: 3
maximumLineCount: 3 maxLineCount: defaultMaxLineCount
textFormat: Text.StyledText
visible: (text !== "")
linkColor: Theme.highlightColor linkColor: Theme.highlightColor
onLinkActivated: { onLinkActivated: {
Functions.handleLink(link); Functions.handleLink(link);
} }
function toggleMaxLineCount() {
maxLineCount = maxLineCount > 0 ? 0 : defaultMaxLineCount
}
} }
Item { Item {
@ -133,15 +119,16 @@ Column {
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
autoTransform: true autoTransform: true
asynchronous: true asynchronous: true
visible: hasImage && status === Image.Ready source: picture.isDownloadingCompleted ? picture.path : ""
visible: opacity > 0
opacity: hasImage && status === Image.Ready ? 1 : 0 opacity: hasImage && status === Image.Ready ? 1 : 0
layer.enabled: webPagePreviewColumn.highlighted layer.enabled: webPagePreviewColumn.highlighted
layer.effect: PressEffect { source: singleImage } layer.effect: PressEffect { source: singleImage }
Behavior on opacity { NumberAnimation {} } Behavior on opacity { FadeAnimation {} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
pageStack.push(Qt.resolvedUrl("../pages/ImagePage.qml"), { "photoData" : webPageData.photo, "pictureFileInformation" : pictureFileInformation }); pageStack.push(Qt.resolvedUrl("../pages/ImagePage.qml"), { "photoData" : webPageData.photo, "pictureFileInformation" : picture.fileInformation });
} }
} }
} }
@ -154,17 +141,12 @@ Column {
} }
Label { Label {
id: noPreviewAvailableText
width: parent.width width: parent.width
text: qsTr("Preview not supported for this link...") text: qsTr("Preview not supported for this link...")
font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeExtraSmall : Theme.fontSizeTiny font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeExtraSmall : Theme.fontSizeTiny
font.italic: true font.italic: true
color: Theme.secondaryColor color: Theme.secondaryColor
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
wrapMode: Text.Wrap
maximumLineCount: 1
textFormat: Text.StyledText
visible: !siteNameText.visible && !titleText.visible && !descriptionText.visible && !webPagePreviewImageItem.visible visible: !siteNameText.visible && !titleText.visible && !descriptionText.visible && !webPagePreviewImageItem.visible
} }

View file

@ -170,10 +170,7 @@ Page {
tdLibWrapper.getInstalledStickerSets(); tdLibWrapper.getInstalledStickerSets();
stickerManager.setNeedsReload(false); stickerManager.setNeedsReload(false);
} }
if (chatInformation.pinned_message_id.toString() !== "0") { tdLibWrapper.getChatPinnedMessage(chatInformation.id);
Debug.log("[ChatPage] Loading pinned message ", chatInformation.pinned_message_id);
tdLibWrapper.getMessage(chatInformation.id, chatInformation.pinned_message_id);
}
} }
function getMessageStatusText(message, listItemIndex, lastReadSentIndex, useElapsed) { function getMessageStatusText(message, listItemIndex, lastReadSentIndex, useElapsed) {
@ -422,7 +419,7 @@ Page {
Functions.handleErrorMessage(code, message); Functions.handleErrorMessage(code, message);
} }
onReceivedMessage: { onReceivedMessage: {
if (messageId === chatInformation.pinned_message_id.toString()) { if (message.is_pinned) {
Debug.log("[ChatPage] Received pinned message"); Debug.log("[ChatPage] Received pinned message");
pinnedMessageItem.pinnedMessage = message; pinnedMessageItem.pinnedMessage = message;
} }

View file

@ -65,6 +65,7 @@ Page {
onTriggered: { onTriggered: {
overviewPage.chatListCreated = true; overviewPage.chatListCreated = true;
chatListModel.redrawModel(); chatListModel.redrawModel();
chatListView.scrollToTop();
} }
} }

View file

@ -104,6 +104,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(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(QString, QVariantMap)), this, SLOT(handleMessageReceived(QString, 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)));
connect(this->tdLibWrapper, SIGNAL(chatReadOutboxUpdated(QString, QString)), this, SLOT(handleChatReadOutboxUpdated(QString, QString))); connect(this->tdLibWrapper, SIGNAL(chatReadOutboxUpdated(QString, QString)), this, SLOT(handleChatReadOutboxUpdated(QString, QString)));
connect(this->tdLibWrapper, SIGNAL(messageSendSucceeded(qlonglong, qlonglong, QVariantMap)), this, SLOT(handleMessageSendSucceeded(qlonglong, qlonglong, QVariantMap))); connect(this->tdLibWrapper, SIGNAL(messageSendSucceeded(qlonglong, qlonglong, QVariantMap)), this, SLOT(handleMessageSendSucceeded(qlonglong, qlonglong, QVariantMap)));
@ -326,6 +327,20 @@ void ChatModel::handleNewMessageReceived(qlonglong chatId, const QVariantMap &me
} }
} }
void ChatModel::handleMessageReceived(const QString &messageId, const QVariantMap &message)
{
const qlonglong messageIdLL = messageId.toLongLong();
if (messageIndexMap.contains(messageIdLL)) {
LOG("Received a message that we already know, let's update it!");
const int position = messageIndexMap.value(messageIdLL);
MessageData *messageData = messages.at(position);
messageData->messageData = message;
LOG("Message was updated at index" << position);
const QModelIndex messageIndex(index(position));
emit dataChanged(messageIndex, messageIndex);
}
}
void ChatModel::handleChatReadInboxUpdated(const QString &id, const QString &lastReadInboxMessageId, int unreadCount) void ChatModel::handleChatReadInboxUpdated(const QString &id, const QString &lastReadInboxMessageId, int unreadCount)
{ {
if (id.toLongLong() == chatId) { if (id.toLongLong() == chatId) {

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 handleNewMessageReceived(qlonglong chatId, const QVariantMap &message); void handleNewMessageReceived(qlonglong chatId, const QVariantMap &message);
void handleMessageReceived(const QString &messageId, const QVariantMap &message);
void handleChatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, int unreadCount); void handleChatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, int unreadCount);
void handleChatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId); void handleChatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId);
void handleMessageSendSucceeded(qlonglong messageId, qlonglong oldMessageId, const QVariantMap &message); void handleMessageSendSucceeded(qlonglong messageId, qlonglong oldMessageId, const QVariantMap &message);

View file

@ -125,6 +125,7 @@ TDLibReceiver::TDLibReceiver(void *tdLibClient, QObject *parent) : QThread(paren
handlers.insert("updateChatPhoto", &TDLibReceiver::processUpdateChatPhoto); handlers.insert("updateChatPhoto", &TDLibReceiver::processUpdateChatPhoto);
handlers.insert("updateChatTitle", &TDLibReceiver::processUpdateChatTitle); handlers.insert("updateChatTitle", &TDLibReceiver::processUpdateChatTitle);
handlers.insert("updateChatPinnedMessage", &TDLibReceiver::processUpdateChatPinnedMessage); handlers.insert("updateChatPinnedMessage", &TDLibReceiver::processUpdateChatPinnedMessage);
handlers.insert("updateMessageIsPinned", &TDLibReceiver::processUpdateMessageIsPinned);
handlers.insert("users", &TDLibReceiver::processUsers); handlers.insert("users", &TDLibReceiver::processUsers);
handlers.insert("error", &TDLibReceiver::processError); handlers.insert("error", &TDLibReceiver::processError);
handlers.insert("ok", &TDLibReceiver::nop); handlers.insert("ok", &TDLibReceiver::nop);
@ -519,6 +520,12 @@ void TDLibReceiver::processUpdateChatPinnedMessage(const QVariantMap &receivedIn
emit chatPinnedMessageUpdated(receivedInformation.value(CHAT_ID).toLongLong(), receivedInformation.value("pinned_message_id").toLongLong()); emit chatPinnedMessageUpdated(receivedInformation.value(CHAT_ID).toLongLong(), receivedInformation.value("pinned_message_id").toLongLong());
} }
void TDLibReceiver::processUpdateMessageIsPinned(const QVariantMap &receivedInformation)
{
LOG("Received UpdateMessageIsPinned");
emit messageIsPinnedUpdated(receivedInformation.value(CHAT_ID).toLongLong(), receivedInformation.value(MESSAGE_ID).toLongLong(), receivedInformation.value("is_pinned").toBool());
}
void TDLibReceiver::processUsers(const QVariantMap &receivedInformation) void TDLibReceiver::processUsers(const QVariantMap &receivedInformation)
{ {
LOG("Received Users"); LOG("Received Users");
@ -528,7 +535,7 @@ void TDLibReceiver::processUsers(const QVariantMap &receivedInformation)
void TDLibReceiver::processError(const QVariantMap &receivedInformation) void TDLibReceiver::processError(const QVariantMap &receivedInformation)
{ {
LOG("Received an error"); LOG("Received an error");
emit errorReceived(receivedInformation.value("code").toInt(), receivedInformation.value(MESSAGE).toString()); emit errorReceived(receivedInformation.value("code").toInt(), receivedInformation.value(MESSAGE).toString(), receivedInformation.value(EXTRA).toString());
} }
void TDLibReceiver::nop(const QVariantMap &) void TDLibReceiver::nop(const QVariantMap &)

View file

@ -83,8 +83,9 @@ signals:
void chatPhotoUpdated(qlonglong chatId, const QVariantMap &photo); void chatPhotoUpdated(qlonglong chatId, const QVariantMap &photo);
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 usersReceived(const QString &extra, const QVariantList &userIds, int totalUsers); void usersReceived(const QString &extra, const QVariantList &userIds, int totalUsers);
void errorReceived(const int code, const QString &message); 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);
void contactsImported(const QVariantList &importerCount, const QVariantList &userIds); void contactsImported(const QVariantList &importerCount, const QVariantList &userIds);
@ -145,6 +146,7 @@ private:
void processUpdateChatPhoto(const QVariantMap &receivedInformation); void processUpdateChatPhoto(const QVariantMap &receivedInformation);
void processUpdateChatTitle(const QVariantMap &receivedInformation); void processUpdateChatTitle(const QVariantMap &receivedInformation);
void processUpdateChatPinnedMessage(const QVariantMap &receivedInformation); void processUpdateChatPinnedMessage(const QVariantMap &receivedInformation);
void processUpdateMessageIsPinned(const QVariantMap &receivedInformation);
void processUsers(const QVariantMap &receivedInformation); void processUsers(const QVariantMap &receivedInformation);
void processError(const QVariantMap &receivedInformation); void processError(const QVariantMap &receivedInformation);
void nop(const QVariantMap &receivedInformation); void nop(const QVariantMap &receivedInformation);

View file

@ -39,6 +39,7 @@
namespace { namespace {
const QString STATUS("status"); const QString STATUS("status");
const QString ID("id"); const QString ID("id");
const QString CHAT_ID("chat_id");
const QString TYPE("type"); const QString TYPE("type");
const QString LAST_NAME("last_name"); const QString LAST_NAME("last_name");
const QString FIRST_NAME("first_name"); const QString FIRST_NAME("first_name");
@ -89,7 +90,7 @@ TDLibWrapper::TDLibWrapper(AppSettings *appSettings, MceInterface *mceInterface,
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(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(QString, QVariantMap)), this, SIGNAL(receivedMessage(QString, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(messageInformation(QString, QVariantMap)), this, SLOT(handleMessageInformation(QString, 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)));
connect(this->tdLibReceiver, SIGNAL(activeNotificationsUpdated(QVariantList)), this, SIGNAL(activeNotificationsUpdated(QVariantList))); connect(this->tdLibReceiver, SIGNAL(activeNotificationsUpdated(QVariantList)), this, SIGNAL(activeNotificationsUpdated(QVariantList)));
connect(this->tdLibReceiver, SIGNAL(notificationGroupUpdated(QVariantMap)), this, SIGNAL(notificationGroupUpdated(QVariantMap))); connect(this->tdLibReceiver, SIGNAL(notificationGroupUpdated(QVariantMap)), this, SIGNAL(notificationGroupUpdated(QVariantMap)));
@ -118,8 +119,9 @@ TDLibWrapper::TDLibWrapper(AppSettings *appSettings, MceInterface *mceInterface,
connect(this->tdLibReceiver, SIGNAL(chatPhotoUpdated(qlonglong, QVariantMap)), this, SIGNAL(chatPhotoUpdated(qlonglong, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(chatPhotoUpdated(qlonglong, QVariantMap)), this, SIGNAL(chatPhotoUpdated(qlonglong, QVariantMap)));
connect(this->tdLibReceiver, SIGNAL(chatTitleUpdated(QString, QString)), this, SIGNAL(chatTitleUpdated(QString, QString))); connect(this->tdLibReceiver, SIGNAL(chatTitleUpdated(QString, QString)), this, SIGNAL(chatTitleUpdated(QString, QString)));
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(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(errorReceived(int, QString)), this, SIGNAL(errorReceived(int, 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(&emojiSearchWorker, SIGNAL(searchCompleted(QString, QVariantList)), this, SLOT(handleEmojiSearchCompleted(QString, QVariantList))); connect(&emojiSearchWorker, SIGNAL(searchCompleted(QString, QVariantList)), this, SLOT(handleEmojiSearchCompleted(QString, QVariantList)));
@ -310,12 +312,14 @@ void TDLibWrapper::pinMessage(const QString &chatId, const QString &messageId, b
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::unpinMessage(const QString &chatId) void TDLibWrapper::unpinMessage(const QString &chatId, const QString &messageId)
{ {
LOG("Unpin message from chat" << chatId); LOG("Unpin message from chat" << chatId);
QVariantMap requestObject; QVariantMap requestObject;
requestObject.insert(_TYPE, "unpinChatMessage"); requestObject.insert(_TYPE, "unpinChatMessage");
requestObject.insert("chat_id", chatId); requestObject.insert("chat_id", chatId);
requestObject.insert("message_id", messageId);
requestObject.insert(_EXTRA, "unpinChatMessage:" + chatId);
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
@ -537,6 +541,17 @@ void TDLibWrapper::getMessage(const QString &chatId, const QString &messageId)
requestObject.insert(_TYPE, "getMessage"); requestObject.insert(_TYPE, "getMessage");
requestObject.insert("chat_id", chatId); requestObject.insert("chat_id", chatId);
requestObject.insert("message_id", messageId); requestObject.insert("message_id", messageId);
requestObject.insert(_EXTRA, "getMessage:" + messageId);
this->sendRequest(requestObject);
}
void TDLibWrapper::getChatPinnedMessage(const qlonglong &chatId)
{
LOG("Retrieving pinned message" << chatId);
QVariantMap requestObject;
requestObject.insert(_TYPE, "getChatPinnedMessage");
requestObject.insert("chat_id", chatId);
requestObject.insert(_EXTRA, "getChatPinnedMessage:" + QString::number(chatId));
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
@ -1272,6 +1287,40 @@ void TDLibWrapper::handleStorageOptimizerChanged()
setOptionBoolean("use_storage_optimizer", appSettings->storageOptimizer()); setOptionBoolean("use_storage_optimizer", appSettings->storageOptimizer());
} }
void TDLibWrapper::handleErrorReceived(const int code, const QString &message, const QString &extra)
{
if (code == 404 && extra.startsWith("getMessage:")) {
emit messageNotFound(extra.mid(11).toLongLong());
}
emit errorReceived(code, message, extra);
}
void TDLibWrapper::handleMessageInformation(const QString &messageId, const QVariantMap &receivedInformation)
{
QString extraInformation = receivedInformation.value(_EXTRA).toString();
if (extraInformation.startsWith("getChatPinnedMessage")) {
emit chatPinnedMessageUpdated(receivedInformation.value(CHAT_ID).toLongLong(), messageId.toLongLong());
// Sometimes it seems that pinned messages aren't returned as pinned ones, weird!
// This is a workaround for now, let's see what comes out of https://github.com/tdlib/td/issues/1343
QVariantMap updatedInformation(receivedInformation);
updatedInformation.insert("is_pinned", true);
emit receivedMessage(messageId, updatedInformation);
} else {
emit receivedMessage(messageId, receivedInformation);
}
}
void TDLibWrapper::handleMessageIsPinnedUpdated(qlonglong chatId, qlonglong messageId, bool isPinned)
{
if (isPinned) {
emit chatPinnedMessageUpdated(chatId, messageId);
} else {
emit chatPinnedMessageUpdated(chatId, 0);
this->getChatPinnedMessage(chatId);
}
}
void TDLibWrapper::setInitialParameters() void TDLibWrapper::setInitialParameters()
{ {
LOG("Sending initial parameters to TD Lib"); LOG("Sending initial parameters to TD Lib");

View file

@ -134,7 +134,7 @@ public:
Q_INVOKABLE void getChatHistory(qlonglong chatId, const qlonglong &fromMessageId = 0, int offset = -1, int limit = 50, bool onlyLocal = false); Q_INVOKABLE void getChatHistory(qlonglong chatId, const 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 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); 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");
Q_INVOKABLE void sendPhotoMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendPhotoMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId = "0");
Q_INVOKABLE void sendVideoMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendVideoMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId = "0");
@ -143,6 +143,7 @@ public:
Q_INVOKABLE void sendPollMessage(const QString &chatId, const QString &question, const QVariantList &options, const bool &anonymous, const int &correctOption, const bool &multiple, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendPollMessage(const QString &chatId, const QString &question, const QVariantList &options, const bool &anonymous, const int &correctOption, const bool &multiple, const QString &replyToMessageId = "0");
Q_INVOKABLE void forwardMessages(const QString &chatId, const QString &fromChatId, const QVariantList &messageIds, const bool sendCopy, const bool removeCaption); Q_INVOKABLE void forwardMessages(const QString &chatId, const QString &fromChatId, const QVariantList &messageIds, const bool sendCopy, const bool removeCaption);
Q_INVOKABLE void getMessage(const QString &chatId, const QString &messageId); Q_INVOKABLE void getMessage(const QString &chatId, const QString &messageId);
Q_INVOKABLE void getChatPinnedMessage(const 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);
@ -242,8 +243,9 @@ 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 errorReceived(const int code, const QString &message); void errorReceived(const 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(const qlonglong messageId);
public slots: public slots:
void handleVersionDetected(const QString &version); void handleVersionDetected(const QString &version);
@ -265,6 +267,9 @@ public slots:
void handleSecretChatReceived(qlonglong secretChatId, const QVariantMap &secretChat); void handleSecretChatReceived(qlonglong secretChatId, const QVariantMap &secretChat);
void handleSecretChatUpdated(qlonglong secretChatId, const QVariantMap &secretChat); void handleSecretChatUpdated(qlonglong secretChatId, const QVariantMap &secretChat);
void handleStorageOptimizerChanged(); void handleStorageOptimizerChanged();
void handleErrorReceived(const int code, const QString &message, const QString &extra);
void handleMessageInformation(const QString &messageId, const QVariantMap &receivedInformation);
void handleMessageIsPinnedUpdated(qlonglong chatId, qlonglong messageId, bool isPinned);
private: private:
void setOption(const QString &name, const QString &type, const QVariant &value); void setOption(const QString &name, const QString &type, const QVariant &value);

View file

@ -904,6 +904,14 @@
<source>Pin Message</source> <source>Pin Message</source>
<translation>Nachricht anheften</translation> <translation>Nachricht anheften</translation>
</message> </message>
<message>
<source>Message unpinned</source>
<translation>Nachricht losgeheftet</translation>
</message>
<message>
<source>Unpin Message</source>
<translation>Nachricht losheften</translation>
</message>
</context> </context>
<context> <context>
<name>MessageListViewItemSimple</name> <name>MessageListViewItemSimple</name>

View file

@ -904,6 +904,14 @@
<source>Pin Message</source> <source>Pin Message</source>
<translation>Pin Message</translation> <translation>Pin Message</translation>
</message> </message>
<message>
<source>Message unpinned</source>
<translation>Message unpinned</translation>
</message>
<message>
<source>Unpin Message</source>
<translation>Unpin Message</translation>
</message>
</context> </context>
<context> <context>
<name>MessageListViewItemSimple</name> <name>MessageListViewItemSimple</name>

View file

@ -894,6 +894,14 @@
<source>Pin Message</source> <source>Pin Message</source>
<translation>Anclar mensaje </translation> <translation>Anclar mensaje </translation>
</message> </message>
<message>
<source>Message unpinned</source>
<translation type="unfinished">Desanclar mensaje</translation>
</message>
<message>
<source>Unpin Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>MessageListViewItemSimple</name> <name>MessageListViewItemSimple</name>

View file

@ -905,6 +905,14 @@
<source>Pin Message</source> <source>Pin Message</source>
<translation>Kiinnitä viesti</translation> <translation>Kiinnitä viesti</translation>
</message> </message>
<message>
<source>Message unpinned</source>
<translation type="unfinished">Viestin kiinnitys poistettu</translation>
</message>
<message>
<source>Unpin Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>MessageListViewItemSimple</name> <name>MessageListViewItemSimple</name>

View file

@ -894,6 +894,14 @@
<source>Pin Message</source> <source>Pin Message</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Message unpinned</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unpin Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>MessageListViewItemSimple</name> <name>MessageListViewItemSimple</name>

View file

@ -904,6 +904,14 @@
<source>Pin Message</source> <source>Pin Message</source>
<translation>Metti messaggio in evidenza</translation> <translation>Metti messaggio in evidenza</translation>
</message> </message>
<message>
<source>Message unpinned</source>
<translation type="unfinished">Messaggio non più in evidenza</translation>
</message>
<message>
<source>Unpin Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>MessageListViewItemSimple</name> <name>MessageListViewItemSimple</name>

View file

@ -914,6 +914,14 @@
<source>Pin Message</source> <source>Pin Message</source>
<translation>Przypnij wiadomość</translation> <translation>Przypnij wiadomość</translation>
</message> </message>
<message>
<source>Message unpinned</source>
<translation type="unfinished">Wiadomość opięta</translation>
</message>
<message>
<source>Unpin Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>MessageListViewItemSimple</name> <name>MessageListViewItemSimple</name>

View file

@ -914,6 +914,14 @@
<source>Pin Message</source> <source>Pin Message</source>
<translation>Закрепить сообщение</translation> <translation>Закрепить сообщение</translation>
</message> </message>
<message>
<source>Message unpinned</source>
<translation type="unfinished">Сообщение откреплено</translation>
</message>
<message>
<source>Unpin Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>MessageListViewItemSimple</name> <name>MessageListViewItemSimple</name>

View file

@ -904,6 +904,14 @@
<source>Pin Message</source> <source>Pin Message</source>
<translation>Fäst meddelandet</translation> <translation>Fäst meddelandet</translation>
</message> </message>
<message>
<source>Message unpinned</source>
<translation type="unfinished">Meddelandet lösgjort</translation>
</message>
<message>
<source>Unpin Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>MessageListViewItemSimple</name> <name>MessageListViewItemSimple</name>

View file

@ -894,6 +894,14 @@
<source>Pin Message</source> <source>Pin Message</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>Message unpinned</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unpin Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>MessageListViewItemSimple</name> <name>MessageListViewItemSimple</name>

View file

@ -904,6 +904,14 @@
<source>Pin Message</source> <source>Pin Message</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Message unpinned</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unpin Message</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>MessageListViewItemSimple</name> <name>MessageListViewItemSimple</name>