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/tdlibreceiver.cpp \
|
||||
src/tdlibwrapper.cpp \
|
||||
src/textfiltermodel.cpp \
|
||||
src/tgsplugin.cpp
|
||||
|
||||
DISTFILES += qml/harbour-fernschreiber.qml \
|
||||
|
@ -228,6 +229,7 @@ HEADERS += \
|
|||
src/tdlibreceiver.h \
|
||||
src/tdlibsecrets.h \
|
||||
src/tdlibwrapper.h \
|
||||
src/textfiltermodel.h \
|
||||
src/tgsplugin.h
|
||||
|
||||
# https://github.com/Samsung/rlottie.git
|
||||
|
|
|
@ -103,19 +103,11 @@ Page {
|
|||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: searchChatTimer
|
||||
interval: 300
|
||||
running: false
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
if (chatSearchField.text === "") {
|
||||
chatListView.model = chatListModel;
|
||||
} else {
|
||||
chatListView.model = chatListProxyModel;
|
||||
}
|
||||
chatListProxyModel.setFilterWildcard("*" + chatSearchField.text + "*");
|
||||
}
|
||||
TextFilterModel {
|
||||
id: chatListProxyModel
|
||||
sourceModel: (chatSearchField.opacity > 0) ? chatListModel : null
|
||||
filterRoleName: "filter"
|
||||
filterText: chatSearchField.text
|
||||
}
|
||||
|
||||
function openMessage(chatId, messageId) {
|
||||
|
@ -355,10 +347,6 @@ Page {
|
|||
placeholderText: qsTr("Filter your chats...")
|
||||
canHide: text === ""
|
||||
|
||||
onTextChanged: {
|
||||
searchChatTimer.restart();
|
||||
}
|
||||
|
||||
onHideClicked: {
|
||||
resetFocus();
|
||||
}
|
||||
|
@ -380,7 +368,7 @@ Page {
|
|||
clip: true
|
||||
opacity: (overviewPage.chatListCreated && !overviewPage.logoutLoading) ? 1 : 0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
model: chatListModel
|
||||
model: chatListProxyModel.sourceModel ? chatListProxyModel : chatListModel
|
||||
delegate: ChatListViewItem {
|
||||
ownUserId: overviewPage.ownUserId
|
||||
isVerified: is_verified
|
||||
|
@ -394,7 +382,7 @@ Page {
|
|||
|
||||
ViewPlaceholder {
|
||||
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.")
|
||||
}
|
||||
|
||||
|
|
|
@ -320,6 +320,7 @@ QVector<int> ChatListModel::ChatData::updateLastMessage(const QVariantMap &messa
|
|||
changedRoles.append(RoleLastMessageDate);
|
||||
}
|
||||
if (prevSenderMessageText != senderMessageText()) {
|
||||
changedRoles.append(RoleFilter);
|
||||
changedRoles.append(RoleLastMessageText);
|
||||
}
|
||||
if (prevSenderMessageStatus != senderMessageStatus()) {
|
||||
|
@ -388,6 +389,9 @@ ChatListModel::ChatListModel(TDLibWrapper *tdLibWrapper, AppSettings *appSetting
|
|||
relativeTimeRefreshTimer->setSingleShot(false);
|
||||
relativeTimeRefreshTimer->setInterval(30000);
|
||||
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()
|
||||
|
@ -457,7 +461,7 @@ QVariant ChatListModel::data(const QModelIndex &index, int role) const
|
|||
case ChatListModel::RoleIsChannel: return data->isChannel();
|
||||
case ChatListModel::RoleIsMarkedAsUnread: return data->isMarkedAsUnread();
|
||||
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::RoleDraftMessageDate: return data->draftMessageDate();
|
||||
}
|
||||
|
@ -891,6 +895,7 @@ void ChatListModel::handleChatTitleUpdated(const QString &chatId, const QString
|
|||
chat->chatData.insert(TITLE, title);
|
||||
QVector<int> changedRoles;
|
||||
changedRoles.append(ChatListModel::RoleTitle);
|
||||
changedRoles.append(ChatListModel::RoleFilter);
|
||||
const QModelIndex modelIndex(index(chatIndex));
|
||||
emit dataChanged(modelIndex, modelIndex, changedRoles);
|
||||
} else {
|
||||
|
|
|
@ -28,6 +28,7 @@ class ChatListModel : public QAbstractListModel
|
|||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool showAllChats READ showAllChats WRITE setShowAllChats NOTIFY showAllChatsChanged)
|
||||
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
||||
|
||||
public:
|
||||
|
||||
|
@ -57,9 +58,9 @@ public:
|
|||
ChatListModel(TDLibWrapper *tdLibWrapper, AppSettings *appSettings);
|
||||
~ChatListModel() override;
|
||||
|
||||
virtual QHash<int,QByteArray> roleNames() const override;
|
||||
virtual int rowCount(const QModelIndex&) const override;
|
||||
virtual QVariant data(const QModelIndex &index, int role) const override;
|
||||
QHash<int,QByteArray> roleNames() const Q_DECL_OVERRIDE;
|
||||
int rowCount(const QModelIndex &index = QModelIndex()) const Q_DECL_OVERRIDE;
|
||||
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
|
||||
|
||||
Q_INVOKABLE void redrawModel();
|
||||
Q_INVOKABLE QVariantMap get(int row);
|
||||
|
@ -90,6 +91,7 @@ private slots:
|
|||
void handleRelativeTimeRefreshTimer();
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
void showAllChatsChanged();
|
||||
void chatChanged(const qlonglong &changedChatId);
|
||||
void chatJoined(const qlonglong &chatId, const QString &chatTitle);
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "dbusadaptor.h"
|
||||
#include "processlauncher.h"
|
||||
#include "stickermanager.h"
|
||||
#include "textfiltermodel.h"
|
||||
#include "tgsplugin.h"
|
||||
#include "fernschreiberutils.h"
|
||||
#include "knownusersmodel.h"
|
||||
|
@ -69,6 +70,7 @@ int main(int argc, char *argv[])
|
|||
const char *uri = "WerkWolf.Fernschreiber";
|
||||
qmlRegisterType<TDLibFile>(uri, 1, 0, "TDLibFile");
|
||||
qmlRegisterType<NamedAction>(uri, 1, 0, "NamedAction");
|
||||
qmlRegisterType<TextFilterModel>(uri, 1, 0, "TextFilterModel");
|
||||
qmlRegisterSingletonType<DebugLogJS>(uri, 1, 0, "DebugLog", DebugLogJS::createSingleton);
|
||||
|
||||
AppSettings *appSettings = new AppSettings(view.data());
|
||||
|
@ -89,11 +91,6 @@ int main(int argc, char *argv[])
|
|||
|
||||
ChatListModel chatListModel(tdLibWrapper, appSettings);
|
||||
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);
|
||||
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