Merge pull request #464 from monich/filter
Improve chat search performance
This commit is contained in:
commit
37518d06a6
7 changed files with 178 additions and 28 deletions
|
@ -38,6 +38,7 @@ SOURCES += src/harbour-fernschreiber.cpp \
|
||||||
src/tdlibfile.cpp \
|
src/tdlibfile.cpp \
|
||||||
src/tdlibreceiver.cpp \
|
src/tdlibreceiver.cpp \
|
||||||
src/tdlibwrapper.cpp \
|
src/tdlibwrapper.cpp \
|
||||||
|
src/textfiltermodel.cpp \
|
||||||
src/tgsplugin.cpp
|
src/tgsplugin.cpp
|
||||||
|
|
||||||
DISTFILES += qml/harbour-fernschreiber.qml \
|
DISTFILES += qml/harbour-fernschreiber.qml \
|
||||||
|
@ -228,6 +229,7 @@ HEADERS += \
|
||||||
src/tdlibreceiver.h \
|
src/tdlibreceiver.h \
|
||||||
src/tdlibsecrets.h \
|
src/tdlibsecrets.h \
|
||||||
src/tdlibwrapper.h \
|
src/tdlibwrapper.h \
|
||||||
|
src/textfiltermodel.h \
|
||||||
src/tgsplugin.h
|
src/tgsplugin.h
|
||||||
|
|
||||||
# https://github.com/Samsung/rlottie.git
|
# https://github.com/Samsung/rlottie.git
|
||||||
|
|
|
@ -103,19 +103,11 @@ Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
TextFilterModel {
|
||||||
id: searchChatTimer
|
id: chatListProxyModel
|
||||||
interval: 300
|
sourceModel: (chatSearchField.opacity > 0) ? chatListModel : null
|
||||||
running: false
|
filterRoleName: "filter"
|
||||||
repeat: false
|
filterText: chatSearchField.text
|
||||||
onTriggered: {
|
|
||||||
if (chatSearchField.text === "") {
|
|
||||||
chatListView.model = chatListModel;
|
|
||||||
} else {
|
|
||||||
chatListView.model = chatListProxyModel;
|
|
||||||
}
|
|
||||||
chatListProxyModel.setFilterWildcard("*" + chatSearchField.text + "*");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function openMessage(chatId, messageId) {
|
function openMessage(chatId, messageId) {
|
||||||
|
@ -355,10 +347,6 @@ Page {
|
||||||
placeholderText: qsTr("Filter your chats...")
|
placeholderText: qsTr("Filter your chats...")
|
||||||
canHide: text === ""
|
canHide: text === ""
|
||||||
|
|
||||||
onTextChanged: {
|
|
||||||
searchChatTimer.restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
onHideClicked: {
|
onHideClicked: {
|
||||||
resetFocus();
|
resetFocus();
|
||||||
}
|
}
|
||||||
|
@ -380,7 +368,7 @@ Page {
|
||||||
clip: true
|
clip: true
|
||||||
opacity: (overviewPage.chatListCreated && !overviewPage.logoutLoading) ? 1 : 0
|
opacity: (overviewPage.chatListCreated && !overviewPage.logoutLoading) ? 1 : 0
|
||||||
Behavior on opacity { FadeAnimation {} }
|
Behavior on opacity { FadeAnimation {} }
|
||||||
model: chatListModel
|
model: chatListProxyModel.sourceModel ? chatListProxyModel : chatListModel
|
||||||
delegate: ChatListViewItem {
|
delegate: ChatListViewItem {
|
||||||
ownUserId: overviewPage.ownUserId
|
ownUserId: overviewPage.ownUserId
|
||||||
isVerified: is_verified
|
isVerified: is_verified
|
||||||
|
@ -394,7 +382,7 @@ Page {
|
||||||
|
|
||||||
ViewPlaceholder {
|
ViewPlaceholder {
|
||||||
enabled: chatListView.count === 0
|
enabled: chatListView.count === 0
|
||||||
text: chatSearchField.text === "" ? qsTr("You don't have any chats yet.") : qsTr("No matching chats found.")
|
text: chatListModel.count === 0 ? qsTr("You don't have any chats yet.") : qsTr("No matching chats found.")
|
||||||
hintText: qsTr("You can search public chats or create a new chat via the pull-down menu.")
|
hintText: qsTr("You can search public chats or create a new chat via the pull-down menu.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -320,6 +320,7 @@ QVector<int> ChatListModel::ChatData::updateLastMessage(const QVariantMap &messa
|
||||||
changedRoles.append(RoleLastMessageDate);
|
changedRoles.append(RoleLastMessageDate);
|
||||||
}
|
}
|
||||||
if (prevSenderMessageText != senderMessageText()) {
|
if (prevSenderMessageText != senderMessageText()) {
|
||||||
|
changedRoles.append(RoleFilter);
|
||||||
changedRoles.append(RoleLastMessageText);
|
changedRoles.append(RoleLastMessageText);
|
||||||
}
|
}
|
||||||
if (prevSenderMessageStatus != senderMessageStatus()) {
|
if (prevSenderMessageStatus != senderMessageStatus()) {
|
||||||
|
@ -388,6 +389,9 @@ ChatListModel::ChatListModel(TDLibWrapper *tdLibWrapper, AppSettings *appSetting
|
||||||
relativeTimeRefreshTimer->setSingleShot(false);
|
relativeTimeRefreshTimer->setSingleShot(false);
|
||||||
relativeTimeRefreshTimer->setInterval(30000);
|
relativeTimeRefreshTimer->setInterval(30000);
|
||||||
connect(relativeTimeRefreshTimer, SIGNAL(timeout()), SLOT(handleRelativeTimeRefreshTimer()));
|
connect(relativeTimeRefreshTimer, SIGNAL(timeout()), SLOT(handleRelativeTimeRefreshTimer()));
|
||||||
|
connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(countChanged()));
|
||||||
|
connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(countChanged()));
|
||||||
|
connect(this, SIGNAL(modelReset()), SIGNAL(countChanged()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatListModel::~ChatListModel()
|
ChatListModel::~ChatListModel()
|
||||||
|
@ -457,7 +461,7 @@ 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::RoleIsPinned: return data->isPinned();
|
case ChatListModel::RoleIsPinned: return data->isPinned();
|
||||||
case ChatListModel::RoleFilter: return QString(data->title() + " " + data->senderMessageText()).trimmed();
|
case ChatListModel::RoleFilter: return data->title() + " " + data->senderMessageText();
|
||||||
case ChatListModel::RoleDraftMessageText: return data->draftMessageText();
|
case ChatListModel::RoleDraftMessageText: return data->draftMessageText();
|
||||||
case ChatListModel::RoleDraftMessageDate: return data->draftMessageDate();
|
case ChatListModel::RoleDraftMessageDate: return data->draftMessageDate();
|
||||||
}
|
}
|
||||||
|
@ -891,6 +895,7 @@ void ChatListModel::handleChatTitleUpdated(const QString &chatId, const QString
|
||||||
chat->chatData.insert(TITLE, title);
|
chat->chatData.insert(TITLE, title);
|
||||||
QVector<int> changedRoles;
|
QVector<int> changedRoles;
|
||||||
changedRoles.append(ChatListModel::RoleTitle);
|
changedRoles.append(ChatListModel::RoleTitle);
|
||||||
|
changedRoles.append(ChatListModel::RoleFilter);
|
||||||
const QModelIndex modelIndex(index(chatIndex));
|
const QModelIndex modelIndex(index(chatIndex));
|
||||||
emit dataChanged(modelIndex, modelIndex, changedRoles);
|
emit dataChanged(modelIndex, modelIndex, changedRoles);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -28,6 +28,7 @@ class ChatListModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool showAllChats READ showAllChats WRITE setShowAllChats NOTIFY showAllChatsChanged)
|
Q_PROPERTY(bool showAllChats READ showAllChats WRITE setShowAllChats NOTIFY showAllChatsChanged)
|
||||||
|
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -57,9 +58,9 @@ public:
|
||||||
ChatListModel(TDLibWrapper *tdLibWrapper, AppSettings *appSettings);
|
ChatListModel(TDLibWrapper *tdLibWrapper, AppSettings *appSettings);
|
||||||
~ChatListModel() override;
|
~ChatListModel() override;
|
||||||
|
|
||||||
virtual QHash<int,QByteArray> roleNames() const override;
|
QHash<int,QByteArray> roleNames() const Q_DECL_OVERRIDE;
|
||||||
virtual int rowCount(const QModelIndex&) const override;
|
int rowCount(const QModelIndex &index = QModelIndex()) const Q_DECL_OVERRIDE;
|
||||||
virtual QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
Q_INVOKABLE void redrawModel();
|
Q_INVOKABLE void redrawModel();
|
||||||
Q_INVOKABLE QVariantMap get(int row);
|
Q_INVOKABLE QVariantMap get(int row);
|
||||||
|
@ -90,6 +91,7 @@ private slots:
|
||||||
void handleRelativeTimeRefreshTimer();
|
void handleRelativeTimeRefreshTimer();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void countChanged();
|
||||||
void showAllChatsChanged();
|
void showAllChatsChanged();
|
||||||
void chatChanged(const qlonglong &changedChatId);
|
void chatChanged(const qlonglong &changedChatId);
|
||||||
void chatJoined(const qlonglong &chatId, const QString &chatTitle);
|
void chatJoined(const qlonglong &chatId, const QString &chatTitle);
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "dbusadaptor.h"
|
#include "dbusadaptor.h"
|
||||||
#include "processlauncher.h"
|
#include "processlauncher.h"
|
||||||
#include "stickermanager.h"
|
#include "stickermanager.h"
|
||||||
|
#include "textfiltermodel.h"
|
||||||
#include "tgsplugin.h"
|
#include "tgsplugin.h"
|
||||||
#include "fernschreiberutils.h"
|
#include "fernschreiberutils.h"
|
||||||
#include "knownusersmodel.h"
|
#include "knownusersmodel.h"
|
||||||
|
@ -69,6 +70,7 @@ int main(int argc, char *argv[])
|
||||||
const char *uri = "WerkWolf.Fernschreiber";
|
const char *uri = "WerkWolf.Fernschreiber";
|
||||||
qmlRegisterType<TDLibFile>(uri, 1, 0, "TDLibFile");
|
qmlRegisterType<TDLibFile>(uri, 1, 0, "TDLibFile");
|
||||||
qmlRegisterType<NamedAction>(uri, 1, 0, "NamedAction");
|
qmlRegisterType<NamedAction>(uri, 1, 0, "NamedAction");
|
||||||
|
qmlRegisterType<TextFilterModel>(uri, 1, 0, "TextFilterModel");
|
||||||
qmlRegisterSingletonType<DebugLogJS>(uri, 1, 0, "DebugLog", DebugLogJS::createSingleton);
|
qmlRegisterSingletonType<DebugLogJS>(uri, 1, 0, "DebugLog", DebugLogJS::createSingleton);
|
||||||
|
|
||||||
AppSettings *appSettings = new AppSettings(view.data());
|
AppSettings *appSettings = new AppSettings(view.data());
|
||||||
|
@ -89,11 +91,6 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
ChatListModel chatListModel(tdLibWrapper, appSettings);
|
ChatListModel chatListModel(tdLibWrapper, appSettings);
|
||||||
context->setContextProperty("chatListModel", &chatListModel);
|
context->setContextProperty("chatListModel", &chatListModel);
|
||||||
QSortFilterProxyModel chatListProxyModel(view.data());
|
|
||||||
chatListProxyModel.setSourceModel(&chatListModel);
|
|
||||||
chatListProxyModel.setFilterRole(ChatListModel::RoleFilter);
|
|
||||||
chatListProxyModel.setFilterCaseSensitivity(Qt::CaseInsensitive);
|
|
||||||
context->setContextProperty("chatListProxyModel", &chatListProxyModel);
|
|
||||||
|
|
||||||
ChatModel chatModel(tdLibWrapper);
|
ChatModel chatModel(tdLibWrapper);
|
||||||
context->setContextProperty("chatModel", &chatModel);
|
context->setContextProperty("chatModel", &chatModel);
|
||||||
|
|
98
src/textfiltermodel.cpp
Normal file
98
src/textfiltermodel.cpp
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "textfiltermodel.h"
|
||||||
|
|
||||||
|
#define DEBUG_MODULE TextFilterModel
|
||||||
|
#include "debuglog.h"
|
||||||
|
|
||||||
|
TextFilterModel::TextFilterModel(QObject *parent) : QSortFilterProxyModel(parent)
|
||||||
|
{
|
||||||
|
setDynamicSortFilter(true);
|
||||||
|
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
setFilterFixedString(QString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextFilterModel::setSource(QObject *model)
|
||||||
|
{
|
||||||
|
setSourceModel(qobject_cast<QAbstractItemModel*>(model));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextFilterModel::setSourceModel(QAbstractItemModel *model)
|
||||||
|
{
|
||||||
|
if (sourceModel() != model) {
|
||||||
|
LOG(model);
|
||||||
|
QSortFilterProxyModel::setSourceModel(model);
|
||||||
|
updateFilterRole();
|
||||||
|
emit sourceChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TextFilterModel::getFilterRoleName() const
|
||||||
|
{
|
||||||
|
return filterRoleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextFilterModel::setFilterRoleName(QString role)
|
||||||
|
{
|
||||||
|
if (filterRoleName != role) {
|
||||||
|
filterRoleName = role;
|
||||||
|
LOG(role);
|
||||||
|
updateFilterRole();
|
||||||
|
emit filterRoleNameChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TextFilterModel::getFilterText() const
|
||||||
|
{
|
||||||
|
return filterText;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextFilterModel::setFilterText(QString text)
|
||||||
|
{
|
||||||
|
if (filterText.compare(text, Qt::CaseInsensitive) != 0) {
|
||||||
|
filterText = text;
|
||||||
|
LOG(text);
|
||||||
|
setFilterFixedString(text);
|
||||||
|
emit filterTextChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextFilterModel::findRole(QAbstractItemModel *model, QString role)
|
||||||
|
{
|
||||||
|
if (model && !role.isEmpty()) {
|
||||||
|
const QByteArray roleName(role.toUtf8());
|
||||||
|
const QHash<int,QByteArray> roleMap(model->roleNames());
|
||||||
|
const QList<int> roles(roleMap.keys());
|
||||||
|
const int n = roles.count();
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
const QByteArray name(roleMap.value(roles.at(i)));
|
||||||
|
if (name == roleName) {
|
||||||
|
LOG(role << roles.at(i));
|
||||||
|
return roles.at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG("Unknown role" << role);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextFilterModel::updateFilterRole()
|
||||||
|
{
|
||||||
|
const int role = findRole(sourceModel(), filterRoleName);
|
||||||
|
setFilterRole((role >= 0) ? role : Qt::DisplayRole);
|
||||||
|
}
|
58
src/textfiltermodel.h
Normal file
58
src/textfiltermodel.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TEXTFILTERMODEL_H
|
||||||
|
#define TEXTFILTERMODEL_H
|
||||||
|
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
|
class TextFilterModel : public QSortFilterProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QString filterRoleName READ getFilterRoleName WRITE setFilterRoleName NOTIFY filterRoleNameChanged)
|
||||||
|
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
|
||||||
|
Q_PROPERTY(QObject* sourceModel READ sourceModel WRITE setSource NOTIFY sourceChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
TextFilterModel(QObject *parent = Q_NULLPTR);
|
||||||
|
|
||||||
|
void setSource(QObject* model);
|
||||||
|
void setSourceModel(QAbstractItemModel *model) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
QString getFilterRoleName() const;
|
||||||
|
void setFilterRoleName(QString role);
|
||||||
|
|
||||||
|
QString getFilterText() const;
|
||||||
|
void setFilterText(QString text);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sourceChanged();
|
||||||
|
void filterRoleNameChanged();
|
||||||
|
void filterTextChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void updateFilterRole();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int findRole(QAbstractItemModel *model, QString role);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString filterRoleName;
|
||||||
|
QString filterText;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TEXTFILTERMODEL_H
|
Loading…
Reference in a new issue