diff --git a/qml/js/functions.js b/qml/js/functions.js index 10ed884..b56556c 100644 --- a/qml/js/functions.js +++ b/qml/js/functions.js @@ -31,10 +31,19 @@ function getSimpleMessageText(message) { return qsTr("Sticker: %1").arg(message.content.sticker.emoji); } if (message.content['@type'] === 'messagePhoto') { - return (typeof message.content.caption) ? qsTr("Picture: %1").arg(message.content.caption.text) : qsTr("Picture"); + return (message.content.caption.text !== "") ? qsTr("Picture: %1").arg(message.content.caption.text) : qsTr("shared a picture"); } if (message.content['@type'] === 'messageVideo') { - return (typeof message.content.caption) ? qsTr("Video: %1").arg(message.content.caption.text) : qsTr("Video"); + return (message.content.caption.text !== "") ? qsTr("Video: %1").arg(message.content.caption.text) : qsTr("shared a video"); + } + if (message.content['@type'] === 'messageAudio') { + return (message.content.caption.text !== "") ? qsTr("Audio: %1").arg(message.content.caption.text) : qsTr("shared an audio"); + } + if (message.content['@type'] === 'messageVoiceNote') { + return (message.content.caption.text !== "") ? qsTr("Voice Note: %1").arg(message.content.caption.text) : qsTr("shared a voice note"); + } + if (message.content['@type'] === 'messageLocation') { + return qsTr("shared their location"); } if (message.content['@type'] === 'messageContactRegistered') { return qsTr("has registered with Telegram"); diff --git a/qml/pages/ChatPage.qml b/qml/pages/ChatPage.qml index 828a286..f5498d0 100644 --- a/qml/pages/ChatPage.qml +++ b/qml/pages/ChatPage.qml @@ -30,6 +30,7 @@ Page { allowedOrientations: Orientation.All property bool loading: true; + property int myUserId: tdLibWrapper.getUserInformation().id; property variant chatInformation; property bool isPrivateChat: false; property bool isBasicGroup: false; @@ -84,6 +85,7 @@ Page { function initializePage() { tdLibWrapper.openChat(chatInformation.id); + chatModel.initialize(chatInformation.id); var chatType = chatInformation.type['@type']; isPrivateChat = ( chatType === "chatTypePrivate" ); isBasicGroup = ( chatType === "chatTypeBasicGroup" ); @@ -144,6 +146,13 @@ Page { } } + Connections { + target: chatModel + onMessagesReceived: { + chatView.positionViewAtEnd(); + } + } + Timer { id: chatContactTimeUpdater interval: 60000 @@ -170,7 +179,7 @@ Page { Row { id: headerRow width: parent.width - (3 * Theme.horizontalPageMargin) - height: chatOverviewColumn.height + Theme.horizontalPageMargin + height: chatOverviewColumn.height + ( 2 * Theme.horizontalPageMargin ) anchors.horizontalCenter: parent.horizontalCenter spacing: Theme.paddingMedium @@ -180,13 +189,13 @@ Page { replacementStringHint: chatNameText.text width: chatOverviewColumn.height height: chatOverviewColumn.height - anchors.bottom: parent.bottom + anchors.verticalCenter: parent.verticalCenter } Column { id: chatOverviewColumn width: parent.width - chatPictureThumbnail.width - Theme.paddingMedium - anchors.bottom: parent.bottom + anchors.verticalCenter: parent.verticalCenter Text { id: chatNameText text: chatInformation.title !== "" ? Emoji.emojify(chatInformation.title, font.pixelSize) : qsTr("Unknown") @@ -228,16 +237,72 @@ Page { height: parent.height - ( 2 * Theme.paddingMedium ) - headerRow.height - newMessageRow.height clip: true - // visible: count > 0 + visible: count > 0 - // model: chatListModel + model: chatModel delegate: ListItem { - id: chatItem - - //contentHeight: chatListRow.height + chatListSeparator.height + 2 * Theme.paddingMedium + id: messageListItem + contentHeight: messageTextItem.height + Theme.paddingMedium contentWidth: parent.width + Column { + id: messageTextItem + + spacing: Theme.paddingSmall + + width: parent.width + height: messageText.height + messageDateText.height + Theme.paddingMedium + anchors.verticalCenter: parent.verticalCenter + + Text { + anchors { + left: parent.left + leftMargin: (chatPage.myUserId === display.sender_user_id) ? 4 * Theme.horizontalPageMargin : Theme.horizontalPageMargin + right: parent.right + rightMargin: (chatPage.myUserId === display.sender_user_id) ? Theme.horizontalPageMargin : 4 * Theme.horizontalPageMargin + } + + id: messageText + text: Emoji.emojify(Functions.getSimpleMessageText(display), font.pixelSize) + font.pixelSize: Theme.fontSizeSmall + color: chatPage.myUserId === display.sender_user_id ? Theme.highlightColor : Theme.primaryColor + wrapMode: Text.Wrap + textFormat: Text.StyledText + onLinkActivated: { + // Functions.handleLink(link); + } + horizontalAlignment: (chatPage.myUserId === display.sender_user_id) ? Text.AlignRight : Text.AlignLeft + linkColor: Theme.highlightColor + } + + Timer { + id: messageDateUpdater + interval: 60000 + running: true + repeat: true + onTriggered: { + messageDateText.text = Functions.getDateTimeElapsed(display.date); + } + } + + Text { + anchors { + left: parent.left + leftMargin: (chatPage.myUserId === display.sender_user_id) ? 4 * Theme.horizontalPageMargin : Theme.horizontalPageMargin + right: parent.right + rightMargin: (chatPage.myUserId === display.sender_user_id) ? Theme.horizontalPageMargin : 4 * Theme.horizontalPageMargin + } + + id: messageDateText + text: Functions.getDateTimeElapsed(display.date) + font.pixelSize: Theme.fontSizeTiny + color: chatPage.myUserId === display.sender_user_id ? Theme.highlightColor : Theme.primaryColor + horizontalAlignment: (chatPage.myUserId === display.sender_user_id) ? Text.AlignRight : Text.AlignLeft + } + + } + } VerticalScrollDecorator {} diff --git a/src/chatmodel.cpp b/src/chatmodel.cpp index ef9c066..f9c0d3f 100644 --- a/src/chatmodel.cpp +++ b/src/chatmodel.cpp @@ -1,8 +1,12 @@ #include "chatmodel.h" +#include + ChatModel::ChatModel(TDLibWrapper *tdLibWrapper) { this->tdLibWrapper = tdLibWrapper; + this->inReload = false; + connect(this->tdLibWrapper, SIGNAL(messagesReceived(QVariantList)), this, SLOT(handleMessagesReceived(QVariantList))); } ChatModel::~ChatModel() @@ -27,7 +31,9 @@ bool ChatModel::insertRows(int row, int count, const QModelIndex &parent) { qDebug() << "[ChatModel] Inserting at " << row << ", row count: " << count; beginInsertRows(parent, row, row + count - 1); - this->messages.insert(row, this->messagesToBeAdded); + for (int i = 0; i < count; i++) { + this->messages.insert(row + i, this->messagesToBeAdded.at(i)); + } this->messageIndexMap.clear(); for (int i = 0; i < this->messages.size(); i++) { this->messageIndexMap.insert(this->messages.at(i).toMap().value("id").toString(), i); @@ -35,3 +41,63 @@ bool ChatModel::insertRows(int row, int count, const QModelIndex &parent) endInsertRows(); return true; } + +void ChatModel::initialize(const QString &chatId) +{ + this->chatId = chatId; + this->messages.clear(); + this->messageIndexMap.clear(); + this->messagesToBeAdded.clear(); +} + +bool compareMessages(const QVariant &message1, const QVariant &message2) +{ + QVariantMap messageMap1 = message1.toMap(); + QVariantMap messageMap2 = message2.toMap(); + if (messageMap1.value("id").toLongLong() < messageMap2.value("id").toLongLong()) { + return true; + } else { + return false; + } +} + +void ChatModel::handleMessagesReceived(const QVariantList &messages) +{ + qDebug() << "[ChatModel] Receiving new messages :)"; + this->messagesMutex.lock(); + this->messagesToBeAdded.clear(); + QListIterator messagesIterator(messages); + while (messagesIterator.hasNext()) { + QVariantMap currentMessage = messagesIterator.next().toMap(); + if (currentMessage.value("chat_id").toString() == this->chatId) { + this->messagesToBeAdded.append(currentMessage); + } + } + std::sort(this->messagesToBeAdded.begin(), this->messagesToBeAdded.end(), compareMessages); + if (this->messages.isEmpty()) { + beginResetModel(); + this->messages.append(this->messagesToBeAdded); + endResetModel(); + } else { + // There is only an append or a prepend, tertium non datur! (probably ;)) + if (this->messages.last().toMap().value("id").toLongLong() < this->messagesToBeAdded.first().toMap().value("id").toLongLong()) { + // Append + this->insertRows(rowCount(QModelIndex()), this->messagesToBeAdded.size()); + } else { + // Prepend + this->insertRows(0, this->messagesToBeAdded.size()); + } + } + this->messagesMutex.unlock(); + + // First call only returns one message, we need to get a little more than that... + if (this->messagesToBeAdded.size() == 1 && !this->inReload) { + qDebug() << "[ChatModel] Only one message received in first call, loading more..."; + this->inReload = true; + this->tdLibWrapper->getChatHistory(this->chatId, this->messagesToBeAdded.first().toMap().value("id").toLongLong()); + } else { + qDebug() << "[ChatModel] Messages loaded, notifying chat UI..."; + this->inReload = false; + emit messagesReceived(); + } +} diff --git a/src/chatmodel.h b/src/chatmodel.h index ba035a6..a8ea60d 100644 --- a/src/chatmodel.h +++ b/src/chatmodel.h @@ -17,13 +17,23 @@ public: virtual QVariant data(const QModelIndex &index, int role) const override; virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; + Q_INVOKABLE void initialize(const QString &chatId); + +signals: + void messagesReceived(); + +public slots: + void handleMessagesReceived(const QVariantList &messages); + private: TDLibWrapper *tdLibWrapper; QVariantList messages; QVariantList messagesToBeAdded; QVariantMap messageIndexMap; - QMutex chatListMutex; + QMutex messagesMutex; + QString chatId; + bool inReload; }; #endif // CHATMODEL_H diff --git a/translations/harbour-fernschreiber-de.ts b/translations/harbour-fernschreiber-de.ts index e680997..4a05354 100644 --- a/translations/harbour-fernschreiber-de.ts +++ b/translations/harbour-fernschreiber-de.ts @@ -258,10 +258,6 @@ Video: %1 - - Video - - has registered with Telegram @@ -270,10 +266,6 @@ Picture: %1 - - Picture - - Sticker: %1 @@ -290,5 +282,33 @@ left this chat. + + Audio: %1 + + + + Voice Note: %1 + + + + shared a picture + + + + shared a video + + + + shared an audio + + + + shared a voice note + + + + shared their location + + diff --git a/translations/harbour-fernschreiber.ts b/translations/harbour-fernschreiber.ts index e680997..4a05354 100644 --- a/translations/harbour-fernschreiber.ts +++ b/translations/harbour-fernschreiber.ts @@ -258,10 +258,6 @@ Video: %1 - - Video - - has registered with Telegram @@ -270,10 +266,6 @@ Picture: %1 - - Picture - - Sticker: %1 @@ -290,5 +282,33 @@ left this chat. + + Audio: %1 + + + + Voice Note: %1 + + + + shared a picture + + + + shared a video + + + + shared an audio + + + + shared a voice note + + + + shared their location + +