Merge pull request #255 from jgibbon/feature/draft-messages

implement message drafts
This commit is contained in:
Sebastian Wolf 2020-12-31 13:17:17 +01:00 committed by GitHub
commit d108cb109d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 149 additions and 4 deletions

View file

@ -11,15 +11,17 @@ PhotoTextsListItem {
photoData: photo_small || ({}) photoData: photo_small || ({})
} }
property int ownUserId property int ownUserId
property bool showDraft: !!draft_message_text && draft_message_date > last_message_date
property string previewText: showDraft ? draft_message_text : last_message_text
// chat title // chat title
primaryText.text: title ? Emoji.emojify(title + ( display.notification_settings.mute_for > 0 ? " 🔇" : "" ), Theme.fontSizeMedium) : qsTr("Unknown") primaryText.text: title ? Emoji.emojify(title + ( display.notification_settings.mute_for > 0 ? " 🔇" : "" ), Theme.fontSizeMedium) : qsTr("Unknown")
// last user // last user
prologSecondaryText.text: is_channel ? "" : ( last_message_sender_id ? ( last_message_sender_id !== ownUserId ? Emoji.emojify(Functions.getUserName(tdLibWrapper.getUserInformation(last_message_sender_id)), primaryText.font.pixelSize) : qsTr("You") ) : "" ) prologSecondaryText.text: showDraft ? "<i>"+qsTr("Draft")+"</i>" : (is_channel ? "" : ( last_message_sender_id ? ( last_message_sender_id !== ownUserId ? Emoji.emojify(Functions.getUserName(tdLibWrapper.getUserInformation(last_message_sender_id)), primaryText.font.pixelSize) : qsTr("You") ) : "" ))
// last message // last message
secondaryText.text: last_message_text ? Emoji.emojify(Functions.enhanceHtmlEntities(last_message_text), Theme.fontSizeExtraSmall) : "<i>" + qsTr("No message in this chat.") + "</i>" secondaryText.text: previewText ? Emoji.emojify(Functions.enhanceHtmlEntities(previewText), Theme.fontSizeExtraSmall) : "<i>" + qsTr("No message in this chat.") + "</i>"
// message date // message date
tertiaryText.text: ( last_message_date ? ( last_message_date.length === 0 ? "" : Functions.getDateTimeElapsed(last_message_date) + Emoji.emojify(last_message_status, tertiaryText.font.pixelSize) ) : "" ) tertiaryText.text: showDraft ? Functions.getDateTimeElapsed(draft_message_date) : ( last_message_date ? ( last_message_date.length === 0 ? "" : Functions.getDateTimeElapsed(last_message_date) + Emoji.emojify(last_message_status, tertiaryText.font.pixelSize) ) : "" )
unreadCount: unread_count unreadCount: unread_count
isSecret: ( chat_type === TelegramAPI.ChatTypeSecret ) isSecret: ( chat_type === TelegramAPI.ChatTypeSecret )
isMarkedAsUnread: is_marked_as_unread isMarkedAsUnread: is_marked_as_unread

View file

@ -373,6 +373,7 @@ Page {
} }
Component.onDestruction: { Component.onDestruction: {
tdLibWrapper.setChatDraftMessage(chatInformation.id, 0, newMessageColumn.replyToMessageId, newMessageTextField.text);
tdLibWrapper.closeChat(chatInformation.id); tdLibWrapper.closeChat(chatInformation.id);
} }
@ -387,6 +388,15 @@ Page {
pageStack.pushAttached(Qt.resolvedUrl("ChatInformationPage.qml"), { "chatInformation" : chatInformation, "privateChatUserInformation": chatPartnerInformation, "groupInformation": chatGroupInformation, "chatOnlineMemberCount": chatOnlineMemberCount}); pageStack.pushAttached(Qt.resolvedUrl("ChatInformationPage.qml"), { "chatInformation" : chatInformation, "privateChatUserInformation": chatPartnerInformation, "groupInformation": chatGroupInformation, "chatOnlineMemberCount": chatOnlineMemberCount});
chatPage.isInitialized = true; chatPage.isInitialized = true;
if(chatInformation.draft_message) {
if(chatInformation.draft_message && chatInformation.draft_message.input_message_text) {
newMessageTextField.text = chatInformation.draft_message.input_message_text.text.text;
if(chatInformation.draft_message.reply_to_message_id) {
tdLibWrapper.getMessage(chatInformation.id, chatInformation.draft_message.reply_to_message_id);
}
}
}
} }
break; break;
case PageStatus.Inactive: case PageStatus.Inactive:
@ -443,6 +453,9 @@ Page {
Debug.log("[ChatPage] Received pinned message"); Debug.log("[ChatPage] Received pinned message");
pinnedMessageItem.pinnedMessage = message; pinnedMessageItem.pinnedMessage = message;
} }
if (messageId === chatInformation.draft_message.reply_to_message_id) {
newMessageInReplyToRow.inReplyToMessage = message;
}
} }
onSecretChatReceived: { onSecretChatReceived: {
if (secretChatId === chatInformation.type.secret_chat_id) { if (secretChatId === chatInformation.type.secret_chat_id) {

View file

@ -35,6 +35,7 @@ namespace {
const QString CHAT_ID("chat_id"); const QString CHAT_ID("chat_id");
const QString CONTENT("content"); const QString CONTENT("content");
const QString LAST_MESSAGE("last_message"); const QString LAST_MESSAGE("last_message");
const QString DRAFT_MESSAGE("draft_message");
const QString SENDER("sender"); const QString SENDER("sender");
const QString USER_ID("user_id"); const QString USER_ID("user_id");
const QString BASIC_GROUP_ID("basic_group_id"); const QString BASIC_GROUP_ID("basic_group_id");
@ -71,6 +72,8 @@ public:
qlonglong senderMessageDate() const; qlonglong senderMessageDate() const;
QString senderMessageText() const; QString senderMessageText() const;
QString senderMessageStatus() const; QString senderMessageStatus() const;
qlonglong draftMessageDate() const;
QString draftMessageText() const;
bool isChannel() const; bool isChannel() const;
bool isHidden() const; bool isHidden() const;
bool isMarkedAsUnread() const; bool isMarkedAsUnread() const;
@ -189,6 +192,7 @@ QString ChatListModel::ChatData::senderMessageText() const
return FernschreiberUtils::getMessageShortText(tdLibWrapper, lastMessage(CONTENT).toMap(), isChannel(), this->userInformation.value(ID).toLongLong(), lastMessage(SENDER).toMap() ); return FernschreiberUtils::getMessageShortText(tdLibWrapper, lastMessage(CONTENT).toMap(), isChannel(), this->userInformation.value(ID).toLongLong(), lastMessage(SENDER).toMap() );
} }
QString ChatListModel::ChatData::senderMessageStatus() const QString ChatListModel::ChatData::senderMessageStatus() const
{ {
if (isChannel() || this->userInformation.value(ID).toLongLong() != senderUserId() || this->userInformation.value(ID).toLongLong() == chatId) { if (isChannel() || this->userInformation.value(ID).toLongLong() != senderUserId() || this->userInformation.value(ID).toLongLong() == chatId) {
@ -210,6 +214,23 @@ QString ChatListModel::ChatData::senderMessageStatus() const
} }
} }
} }
qlonglong ChatListModel::ChatData::draftMessageDate() const
{
QVariantMap draft = chatData.value(DRAFT_MESSAGE).toMap();
if(draft.isEmpty()) {
return qlonglong(0);
}
return draft.value(DATE).toLongLong();
}
QString ChatListModel::ChatData::draftMessageText() const
{
QVariantMap draft = chatData.value(DRAFT_MESSAGE).toMap();
if(draft.isEmpty()) {
return QString();
}
return draft.value("input_message_text").toMap().value(TEXT).toMap().value(TEXT).toString();
}
bool ChatListModel::ChatData::isChannel() const bool ChatListModel::ChatData::isChannel() const
{ {
@ -343,6 +364,7 @@ ChatListModel::ChatListModel(TDLibWrapper *tdLibWrapper) : showHiddenChats(false
connect(tdLibWrapper, SIGNAL(secretChatReceived(qlonglong, QVariantMap)), this, SLOT(handleSecretChatUpdated(qlonglong, QVariantMap))); connect(tdLibWrapper, SIGNAL(secretChatReceived(qlonglong, QVariantMap)), this, SLOT(handleSecretChatUpdated(qlonglong, QVariantMap)));
connect(tdLibWrapper, SIGNAL(chatTitleUpdated(QString, QString)), this, SLOT(handleChatTitleUpdated(QString, QString))); connect(tdLibWrapper, SIGNAL(chatTitleUpdated(QString, QString)), this, SLOT(handleChatTitleUpdated(QString, QString)));
connect(tdLibWrapper, SIGNAL(chatIsMarkedAsUnreadUpdated(qlonglong, bool)), this, SLOT(handleChatIsMarkedAsUnreadUpdated(qlonglong, bool))); connect(tdLibWrapper, SIGNAL(chatIsMarkedAsUnreadUpdated(qlonglong, bool)), this, SLOT(handleChatIsMarkedAsUnreadUpdated(qlonglong, bool)));
connect(tdLibWrapper, SIGNAL(chatDraftMessageUpdated(qlonglong, QVariantMap, QString)), this, SLOT(handleChatDraftMessageUpdated(qlonglong, QVariantMap, QString)));
// Don't start the timer until we have at least one chat // Don't start the timer until we have at least one chat
relativeTimeRefreshTimer = new QTimer(this); relativeTimeRefreshTimer = new QTimer(this);
@ -378,6 +400,8 @@ QHash<int,QByteArray> ChatListModel::roleNames() const
roles.insert(ChatListModel::RoleIsChannel, "is_channel"); roles.insert(ChatListModel::RoleIsChannel, "is_channel");
roles.insert(ChatListModel::RoleIsMarkedAsUnread, "is_marked_as_unread"); roles.insert(ChatListModel::RoleIsMarkedAsUnread, "is_marked_as_unread");
roles.insert(ChatListModel::RoleFilter, "filter"); roles.insert(ChatListModel::RoleFilter, "filter");
roles.insert(ChatListModel::RoleDraftMessageDate, "draft_message_date");
roles.insert(ChatListModel::RoleDraftMessageText, "draft_message_text");
return roles; return roles;
} }
@ -409,6 +433,8 @@ QVariant ChatListModel::data(const QModelIndex &index, int role) const
case ChatListModel::RoleIsChannel: return data->isChannel(); case ChatListModel::RoleIsChannel: return data->isChannel();
case ChatListModel::RoleIsMarkedAsUnread: return data->isMarkedAsUnread(); case ChatListModel::RoleIsMarkedAsUnread: return data->isMarkedAsUnread();
case ChatListModel::RoleFilter: return QString(data->title() + " " + data->senderMessageText()).trimmed(); case ChatListModel::RoleFilter: return QString(data->title() + " " + data->senderMessageText()).trimmed();
case ChatListModel::RoleDraftMessageText: return data->draftMessageText();
case ChatListModel::RoleDraftMessageDate: return data->draftMessageDate();
} }
} }
return QVariant(); return QVariant();
@ -844,6 +870,25 @@ void ChatListModel::handleChatIsMarkedAsUnreadUpdated(qlonglong chatId, bool cha
} }
} }
void ChatListModel::handleChatDraftMessageUpdated(qlonglong chatId, const QVariantMap &draftMessage, const QString &order)
{
LOG("Updating draft message for" << chatId);
if (chatIndexMap.contains(chatId)) {
const int chatIndex = chatIndexMap.value(chatId);
ChatData *chat = chatList.at(chatIndex);
chat->chatData.insert(DRAFT_MESSAGE, draftMessage);
QVector<int> changedRoles;
changedRoles.append(ChatListModel::RoleDraftMessageDate);
changedRoles.append(ChatListModel::RoleDraftMessageText);
const QModelIndex modelIndex(index(chatIndex));
emit dataChanged(modelIndex, modelIndex, changedRoles);
if (chat->setOrder(order)) {
updateChatOrder(chatIndex);
}
}
}
void ChatListModel::handleRelativeTimeRefreshTimer() void ChatListModel::handleRelativeTimeRefreshTimer()
{ {
LOG("Refreshing timestamps"); LOG("Refreshing timestamps");

View file

@ -47,7 +47,9 @@ public:
RoleIsVerified, RoleIsVerified,
RoleIsChannel, RoleIsChannel,
RoleIsMarkedAsUnread, RoleIsMarkedAsUnread,
RoleFilter RoleFilter,
RoleDraftMessageText,
RoleDraftMessageDate
}; };
ChatListModel(TDLibWrapper *tdLibWrapper); ChatListModel(TDLibWrapper *tdLibWrapper);
@ -78,6 +80,7 @@ private slots:
void handleSecretChatUpdated(qlonglong secretChatId, const QVariantMap &secretChat); void handleSecretChatUpdated(qlonglong secretChatId, const QVariantMap &secretChat);
void handleChatTitleUpdated(const QString &chatId, const QString &title); void handleChatTitleUpdated(const QString &chatId, const QString &title);
void handleChatIsMarkedAsUnreadUpdated(qlonglong chatId, bool chatIsMarkedAsUnread); void handleChatIsMarkedAsUnreadUpdated(qlonglong chatId, bool chatIsMarkedAsUnread);
void handleChatDraftMessageUpdated(qlonglong chatId, const QVariantMap &draftMessage, const QString &order);
void handleRelativeTimeRefreshTimer(); void handleRelativeTimeRefreshTimer();
signals: signals:

View file

@ -43,6 +43,7 @@ namespace {
const QString LAST_MESSAGE("last_message"); const QString LAST_MESSAGE("last_message");
const QString TOTAL_COUNT("total_count"); const QString TOTAL_COUNT("total_count");
const QString UNREAD_COUNT("unread_count"); const QString UNREAD_COUNT("unread_count");
const QString TEXT("text");
const QString LAST_READ_INBOX_MESSAGE_ID("last_read_inbox_message_id"); const QString LAST_READ_INBOX_MESSAGE_ID("last_read_inbox_message_id");
const QString LAST_READ_OUTBOX_MESSAGE_ID("last_read_outbox_message_id"); const QString LAST_READ_OUTBOX_MESSAGE_ID("last_read_outbox_message_id");
const QString SECRET_CHAT("secret_chat"); const QString SECRET_CHAT("secret_chat");
@ -134,6 +135,7 @@ TDLibReceiver::TDLibReceiver(void *tdLibClient, QObject *parent) : QThread(paren
handlers.insert("importedContacts", &TDLibReceiver::processImportedContacts); handlers.insert("importedContacts", &TDLibReceiver::processImportedContacts);
handlers.insert("updateMessageEdited", &TDLibReceiver::processUpdateMessageEdited); handlers.insert("updateMessageEdited", &TDLibReceiver::processUpdateMessageEdited);
handlers.insert("updateChatIsMarkedAsUnread", &TDLibReceiver::processUpdateChatIsMarkedAsUnread); handlers.insert("updateChatIsMarkedAsUnread", &TDLibReceiver::processUpdateChatIsMarkedAsUnread);
handlers.insert("updateChatDraftMessage", &TDLibReceiver::processUpdateChatDraftMessage);
} }
void TDLibReceiver::setActive(bool active) void TDLibReceiver::setActive(bool active)
@ -576,3 +578,9 @@ void TDLibReceiver::processUpdateChatIsMarkedAsUnread(const QVariantMap &receive
LOG("The unread state of a chat was updated"); LOG("The unread state of a chat was updated");
emit chatIsMarkedAsUnreadUpdated(receivedInformation.value(CHAT_ID).toLongLong(), receivedInformation.value("is_marked_as_unread").toBool()); emit chatIsMarkedAsUnreadUpdated(receivedInformation.value(CHAT_ID).toLongLong(), receivedInformation.value("is_marked_as_unread").toBool());
} }
void TDLibReceiver::processUpdateChatDraftMessage(const QVariantMap &receivedInformation)
{
LOG("Draft message was updated");
emit chatDraftMessageUpdated(receivedInformation.value(CHAT_ID).toLongLong(), receivedInformation.value("draft_message").toMap(), findChatPositionOrder(receivedInformation.value(POSITIONS).toList()));
}

View file

@ -91,6 +91,7 @@ signals:
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);
void chatIsMarkedAsUnreadUpdated(qlonglong chatId, bool chatIsMarkedAsUnread); void chatIsMarkedAsUnreadUpdated(qlonglong chatId, bool chatIsMarkedAsUnread);
void chatDraftMessageUpdated(qlonglong chatId, const QVariantMap &draftMessage, const QString &order);
private: private:
typedef void (TDLibReceiver::*Handler)(const QVariantMap &); typedef void (TDLibReceiver::*Handler)(const QVariantMap &);
@ -157,6 +158,7 @@ private:
void processUpdateMessageEdited(const QVariantMap &receivedInformation); void processUpdateMessageEdited(const QVariantMap &receivedInformation);
void processImportedContacts(const QVariantMap &receivedInformation); void processImportedContacts(const QVariantMap &receivedInformation);
void processUpdateChatIsMarkedAsUnread(const QVariantMap &receivedInformation); void processUpdateChatIsMarkedAsUnread(const QVariantMap &receivedInformation);
void processUpdateChatDraftMessage(const QVariantMap &receivedInformation);
}; };
#endif // TDLIBRECEIVER_H #endif // TDLIBRECEIVER_H

View file

@ -45,6 +45,7 @@ namespace {
const QString LAST_NAME("last_name"); const QString LAST_NAME("last_name");
const QString FIRST_NAME("first_name"); const QString FIRST_NAME("first_name");
const QString USERNAME("username"); const QString USERNAME("username");
const QString THREAD_ID("thread_id");
const QString VALUE("value"); const QString VALUE("value");
const QString _TYPE("@type"); const QString _TYPE("@type");
const QString _EXTRA("@extra"); const QString _EXTRA("@extra");
@ -126,6 +127,7 @@ TDLibWrapper::TDLibWrapper(AppSettings *appSettings, MceInterface *mceInterface,
connect(this->tdLibReceiver, SIGNAL(contactsImported(QVariantList, QVariantList)), this, SIGNAL(contactsImported(QVariantList, QVariantList))); connect(this->tdLibReceiver, SIGNAL(contactsImported(QVariantList, QVariantList)), this, SIGNAL(contactsImported(QVariantList, QVariantList)));
connect(this->tdLibReceiver, SIGNAL(messageEditedUpdated(qlonglong, qlonglong, QVariantMap)), this, SIGNAL(messageEditedUpdated(qlonglong, qlonglong, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(messageEditedUpdated(qlonglong, qlonglong, QVariantMap)), this, SIGNAL(messageEditedUpdated(qlonglong, qlonglong, QVariantMap)));
connect(this->tdLibReceiver, SIGNAL(chatIsMarkedAsUnreadUpdated(qlonglong, bool)), this, SIGNAL(chatIsMarkedAsUnreadUpdated(qlonglong, bool))); connect(this->tdLibReceiver, SIGNAL(chatIsMarkedAsUnreadUpdated(qlonglong, bool)), this, SIGNAL(chatIsMarkedAsUnreadUpdated(qlonglong, bool)));
connect(this->tdLibReceiver, SIGNAL(chatDraftMessageUpdated(qlonglong, QVariantMap, QString)), this, SIGNAL(chatDraftMessageUpdated(qlonglong, QVariantMap, QString)));
connect(&emojiSearchWorker, SIGNAL(searchCompleted(QString, QVariantList)), this, SLOT(handleEmojiSearchCompleted(QString, QVariantList))); connect(&emojiSearchWorker, SIGNAL(searchCompleted(QString, QVariantList)), this, SLOT(handleEmojiSearchCompleted(QString, QVariantList)));
@ -982,6 +984,30 @@ void TDLibWrapper::toggleChatIsMarkedAsUnread(qlonglong chatId, bool isMarkedAsU
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::setChatDraftMessage(qlonglong chatId, qlonglong threadId, qlonglong replyToMessageId, const QString &draft)
{
LOG("Set Draft Message" << chatId);
QVariantMap requestObject;
requestObject.insert(_TYPE, "setChatDraftMessage");
requestObject.insert(CHAT_ID, chatId);
requestObject.insert(THREAD_ID, threadId);
QVariantMap draftMessage;
QVariantMap inputMessageContent;
QVariantMap formattedText;
formattedText.insert("text", draft);
formattedText.insert("clear_draft", draft.isEmpty());
formattedText.insert(_TYPE, "formattedText");
inputMessageContent.insert(_TYPE, "inputMessageText");
inputMessageContent.insert("text", formattedText);
draftMessage.insert(_TYPE, "draftMessage");
draftMessage.insert("reply_to_message_id", replyToMessageId);
draftMessage.insert("input_message_text", inputMessageContent);
requestObject.insert("draft_message", draftMessage);
this->sendRequest(requestObject);
}
void TDLibWrapper::searchEmoji(const QString &queryString) void TDLibWrapper::searchEmoji(const QString &queryString)
{ {
LOG("Searching emoji" << queryString); LOG("Searching emoji" << queryString);

View file

@ -183,6 +183,7 @@ public:
Q_INVOKABLE void searchPublicChats(const QString &query); Q_INVOKABLE void searchPublicChats(const QString &query);
Q_INVOKABLE void readAllChatMentions(qlonglong chatId); Q_INVOKABLE void readAllChatMentions(qlonglong chatId);
Q_INVOKABLE void toggleChatIsMarkedAsUnread(qlonglong chatId, bool isMarkedAsUnread); Q_INVOKABLE void toggleChatIsMarkedAsUnread(qlonglong chatId, bool isMarkedAsUnread);
Q_INVOKABLE void setChatDraftMessage(qlonglong chatId, qlonglong threadId, qlonglong replyToMessageId, const QString &draft);
// Others (candidates for extraction ;)) // Others (candidates for extraction ;))
Q_INVOKABLE void searchEmoji(const QString &queryString); Q_INVOKABLE void searchEmoji(const QString &queryString);
@ -253,6 +254,7 @@ signals:
void contactsImported(const QVariantList &importerCount, const QVariantList &userIds); void contactsImported(const QVariantList &importerCount, const QVariantList &userIds);
void messageNotFound(qlonglong chatId, qlonglong messageId); void messageNotFound(qlonglong chatId, qlonglong messageId);
void chatIsMarkedAsUnreadUpdated(qlonglong chatId, bool chatIsMarkedAsUnread); void chatIsMarkedAsUnreadUpdated(qlonglong chatId, bool chatIsMarkedAsUnread);
void chatDraftMessageUpdated(qlonglong chatId, const QVariantMap &draftMessage, const QString &order);
public slots: public slots:
void handleVersionDetected(const QString &version); void handleVersionDetected(const QString &version);

View file

@ -272,6 +272,10 @@
<source>Mark chat as read</source> <source>Mark chat as read</source>
<translation>Chat als gelesen markieren</translation> <translation>Chat als gelesen markieren</translation>
</message> </message>
<message>
<source>Draft</source>
<translation>Entwurf</translation>
</message>
</context> </context>
<context> <context>
<name>ChatPage</name> <name>ChatPage</name>

View file

@ -272,6 +272,10 @@
<source>Mark chat as read</source> <source>Mark chat as read</source>
<translation>Mark chat as read</translation> <translation>Mark chat as read</translation>
</message> </message>
<message>
<source>Draft</source>
<translation>Draft</translation>
</message>
</context> </context>
<context> <context>
<name>ChatPage</name> <name>ChatPage</name>

View file

@ -265,6 +265,10 @@
<source>Mark chat as unread</source> <source>Mark chat as unread</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Draft</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Mark chat as read</source> <source>Mark chat as read</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>

View file

@ -268,6 +268,10 @@
<source>Mark chat as unread</source> <source>Mark chat as unread</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Draft</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Mark chat as read</source> <source>Mark chat as read</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>

View file

@ -265,6 +265,10 @@
<source>Mark chat as unread</source> <source>Mark chat as unread</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Draft</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Mark chat as read</source> <source>Mark chat as read</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>

View file

@ -268,6 +268,10 @@
<source>Mark chat as unread</source> <source>Mark chat as unread</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Draft</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Mark chat as read</source> <source>Mark chat as read</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>

View file

@ -271,6 +271,10 @@
<source>Mark chat as unread</source> <source>Mark chat as unread</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Draft</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Mark chat as read</source> <source>Mark chat as read</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>

View file

@ -271,6 +271,10 @@
<source>Mark chat as unread</source> <source>Mark chat as unread</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Draft</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Mark chat as read</source> <source>Mark chat as read</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>

View file

@ -268,6 +268,10 @@
<source>Mark chat as unread</source> <source>Mark chat as unread</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Draft</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Mark chat as read</source> <source>Mark chat as read</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>

View file

@ -265,6 +265,10 @@
<source>Mark chat as unread</source> <source>Mark chat as unread</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Draft</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Mark chat as read</source> <source>Mark chat as read</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>

View file

@ -272,6 +272,10 @@
<source>Mark chat as read</source> <source>Mark chat as read</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Draft</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ChatPage</name> <name>ChatPage</name>