diff --git a/src/app/messagesadapter.h b/src/app/messagesadapter.h index 1deb16089e9fdeedc24ed7063c2917a884af41e4..e612a4cdfe5a6bd0638876b51a52f32c0435b140 100644 --- a/src/app/messagesadapter.h +++ b/src/app/messagesadapter.h @@ -36,11 +36,18 @@ class FilteredMsgListModel final : public QSortFilterProxyModel { Q_OBJECT + Q_PROPERTY(int count READ count NOTIFY countChanged) public: explicit FilteredMsgListModel(QObject* parent = nullptr) : QSortFilterProxyModel(parent) { sort(0, Qt::AscendingOrder); + + connect(this, &QAbstractItemModel::rowsInserted, this, &FilteredMsgListModel::countChanged); + connect(this, &QAbstractItemModel::rowsRemoved, this, &FilteredMsgListModel::countChanged); + connect(this, &QAbstractItemModel::modelReset, this, &FilteredMsgListModel::countChanged); + connect(this, &QAbstractItemModel::layoutChanged, this, &FilteredMsgListModel::countChanged); + } bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override { @@ -60,6 +67,22 @@ public: auto index = mapFromSource(sourceModel()->index(sourceRow, 0)); return index.row(); }; + Q_INVOKABLE QVariantMap get(int row) const + { + QVariantMap map; + QModelIndex modelIndex = index(row, 0); + QHash<int, QByteArray> roles = roleNames(); + for (QHash<int, QByteArray>::const_iterator it = roles.begin(); it != roles.end(); ++it) + map.insert(it.value(), data(modelIndex, it.key())); + return map; + } + + int count() const + { + return rowCount(); + } +Q_SIGNALS: + void countChanged(); }; class MessagesAdapter final : public QmlAdapterBase diff --git a/src/app/selectablelistproxymodel.cpp b/src/app/selectablelistproxymodel.cpp index 83bd1ee5e7bc299a8591ff972e1aecd6a28e8676..b6751c4596eceae7da6defa26192c6ec78a7de69 100644 --- a/src/app/selectablelistproxymodel.cpp +++ b/src/app/selectablelistproxymodel.cpp @@ -136,6 +136,7 @@ SelectableListProxyModel::updateSelection(bool rowsRemoved) } Q_EMIT validSelectionChanged(); + Q_EMIT countChanged(); } void diff --git a/src/app/selectablelistproxymodel.h b/src/app/selectablelistproxymodel.h index 68f218c27b8257324e67f103daf0e6f9f66d4ee2..c130813788dcdd08e5abba86da6489d04e79cfe6 100644 --- a/src/app/selectablelistproxymodel.h +++ b/src/app/selectablelistproxymodel.h @@ -29,6 +29,7 @@ class SelectableListProxyModel : public QSortFilterProxyModel { Q_OBJECT QML_PROPERTY(int, currentFilteredRow) + Q_PROPERTY(int count READ count NOTIFY countChanged) public: explicit SelectableListProxyModel(QAbstractListModel* model, QObject* parent = nullptr); @@ -42,11 +43,27 @@ public: Q_INVOKABLE QVariant dataForRow(int row, int role) const; void selectSourceRow(int row); + Q_INVOKABLE QVariantMap get(int row) const + { + QVariantMap map; + QModelIndex modelIndex = index(row, 0); + QHash<int, QByteArray> roles = roleNames(); + for (QHash<int, QByteArray>::const_iterator it = roles.begin(); it != roles.end(); ++it) + map.insert(it.value(), data(modelIndex, it.key())); + return map; + } + + int count() const + { + return rowCount(); + } + public Q_SLOTS: void updateSelection(bool rowsRemoved = false); Q_SIGNALS: void validSelectionChanged(); + void countChanged(); private Q_SLOTS: void onModelUpdated(); diff --git a/tests/qml/src/tst_ConversationListView.qml b/tests/qml/src/tst_ConversationListView.qml new file mode 100644 index 0000000000000000000000000000000000000000..c070996ecdf68e86b26c1dff2f8b4ea42586e6a1 --- /dev/null +++ b/tests/qml/src/tst_ConversationListView.qml @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2024 Savoir-faire Linux Inc. + * + * This program 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. + * + * This program 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +import QtQuick +import QtQuick.Layouts +import QtTest + +import net.jami.Adapters 1.1 +import net.jami.Models 1.1 +import net.jami.Constants 1.1 +import net.jami.Enums 1.1 + +import "../../../src/app/" +import "../../../src/app/mainview" +import "../../../src/app/mainview/components" +import "../../../src/app/commoncomponents" + +ColumnLayout { + id: root + + spacing: 0 + + width: 300 + height: 300 + ConversationListView { + id: uut + headerVisible: false + headerLabel: "" + + TestCase { + name: "Check fake conversation list" + function test_checkFakeConversationList() { + uut.model = [{"ActiveCallsCount":0,"CallStackViewShouldShow":false,"Draft":"","InCall":false, + "IsAudioOnly":false,"IsBanned":false,"IsCoreDialog":false,"IsRequest":false,"IsSwarm":true, + "LastInteraction":"Outgoing call - 00:32","LastInteractionTimeStamp":1702479346,"Mode":2," + Monikers":[],"Presence":2,"Title":"Test2 (you)","UID":"48f500d116c0ec9ee16991ee55e9740defbf3601","UnreadMessagesCount":0, + "Uris":["5ede716f701ef17fc103a22e6aaea0d91f1b08b0"]}, + {"ActiveCallsCount":0,"Alias":"Alice","BestId":"581accfc568aeb20c49ed5f1fe7e78806f9c6186", + "CallStackViewShouldShow":false,"ContactType":1,"Draft":"","InCall":false,"IsAudioOnly":false, + "IsBanned":false,"IsCoreDialog":true,"IsRequest":false,"IsSwarm":true,"LastInteraction":"Incoming call - 26:17", + "LastInteractionTimeStamp":1689259642,"Mode":0,"Monikers":["Alice",""],"Presence":0, + "RegisteredName":"","Title":"Alice","UID":"68fda54c89c56dc9e92073f0e6a3f36f438eb639","URI":"581accfc568aeb20c49ed5f1fe7e78806f9c6186", + "UnreadMessagesCount":4,"Uris":["581accfc568aeb20c49ed5f1fe7e78806f9c6186"]}, + {"ActiveCallsCount":0,"Alias":"","BestId":"test","CallStackViewShouldShow":false,"ContactType":1,"Draft":"","InCall":false, + "IsAudioOnly":false,"IsBanned":false,"IsCoreDialog":true,"IsRequest":false,"IsSwarm":true,"LastInteraction":"3", + "LastInteractionTimeStamp":1688407560,"Mode":0,"Monikers":["","test"],"Presence":0,"RegisteredName":"test", + "Title":"test","UID":"f25910613c7d9029188231f3b09d6cdb1c90bdf0","URI":"8de0bbe6be0fd5d49dc5648f7a680ada1af68bd7", + "UnreadMessagesCount":0,"Uris":["8de0bbe6be0fd5d49dc5648f7a680ada1af68bd7"]}] + compare(uut.model.length, 3) + } + } + } +} diff --git a/tests/qml/src/tst_MessageListView.qml b/tests/qml/src/tst_MessageListView.qml new file mode 100644 index 0000000000000000000000000000000000000000..e7327fe413602d00aa7e15648064f8c77e91b916 --- /dev/null +++ b/tests/qml/src/tst_MessageListView.qml @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2024 Savoir-faire Linux Inc. + * + * This program 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. + * + * This program 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +import QtQuick +import QtQuick.Layouts +import QtTest + +import net.jami.Adapters 1.1 +import net.jami.Models 1.1 +import net.jami.Constants 1.1 +import net.jami.Enums 1.1 + +import "../../../src/app/" +import "../../../src/app/mainview" +import "../../../src/app/mainview/components" +import "../../../src/app/commoncomponents" + +ColumnLayout { + id: root + + spacing: 0 + + width: 300 + height: 300 + MessageListView { + id: uut + + TestCase { + name: "Check fake conversation" + function test_checkFakeConversation() { + uut.model = [{"ActionUri":"","Author":"9cdbe0ec5f1399834f597dbfef6bf7f382000000", + "Body":"Missed incoming call","ConfId":"","ContactAction":"", + "DeviceId":"","Duration":0,"FileExtension":"", + "Id":"280713b932f0b4f0ce67f31a9708c48f2cbdec31" + ,"Index":2,"IsEmojiOnly":false,"IsRead":false,"LinkPreviewInfo":{}, + "ParsedBody":"","PreviousBodies":[],"Reactions":{}, + "Readers":["9cdbe0ec5f1399834f597dbfef6bf7f382000000"], + "ReplyTo":"","ReplyToAuthor":"","ReplyToBody":"","Status":4, + "Timestamp":1708025453,"TotalSize":0,"TransferName":"","Type":3}, + {"ActionUri":"5387a0669154964f649b4069c2fce55e76c30a97","Author":"", + "Body":" joined","ConfId":"","ContactAction":"join","DeviceId":"", + "Duration":0,"FileExtension":"","Id":"79d091d8bd9fc2dbdb3053e61939c488db06e2bd", + "Index":1,"IsEmojiOnly":false,"IsRead":false,"LinkPreviewInfo":{}, + "ParsedBody":"","PreviousBodies":[],"Reactions":{},"Readers":[] + ,"ReplyTo":"","ReplyToAuthor":"","ReplyToBody":"","Status":4,"Timestamp":1708025440, + "TotalSize":0,"TransferName":"","Type":4}, + {"ActionUri":"","Author":"9cdbe0ec5f1399834f597dbfef6bf7f382000000","Body":"Private conversation created", + "ConfId":"","ContactAction":"","DeviceId":"","Duration":0,"FileExtension":"", + "Id":"fe2b91a35cbd1cc11ac868eadf2ed8a9b3dd227b","Index":0,"IsEmojiOnly":false, + "IsRead":false,"LinkPreviewInfo":{},"ParsedBody":"","PreviousBodies":[], + "Reactions":{},"Readers":[],"ReplyTo":"","ReplyToAuthor":"", + "ReplyToBody":"","Status":4,"Timestamp":1708025382,"TotalSize":0,"TransferName":"","Type":1}] + compare(uut.model.length, 3) + } + } + } +}