Introduce filter capabilities for chat list

This commit is contained in:
Sebastian Wolf 2020-12-16 23:32:42 +01:00
parent f7e005da46
commit 45bcc4f33d
No known key found for this signature in database
GPG key ID: CEA9522B5F38A90A
15 changed files with 171 additions and 56 deletions

View file

@ -65,6 +65,7 @@ Page {
onTriggered: { onTriggered: {
overviewPage.chatListCreated = true; overviewPage.chatListCreated = true;
chatListModel.redrawModel(); chatListModel.redrawModel();
chatListView.model = chatListProxyModel;
} }
} }
@ -76,6 +77,16 @@ Page {
} }
} }
Timer {
id: searchChatTimer
interval: 300
running: false
repeat: false
onTriggered: {
chatListProxyModel.setFilterWildcard("*" + chatSearchField.text + "*");
}
}
function setPageStatus() { function setPageStatus() {
switch (overviewPage.connectionState) { switch (overviewPage.connectionState) {
case TelegramAPI.WaitingForNetwork: case TelegramAPI.WaitingForNetwork:
@ -138,6 +149,14 @@ Page {
} }
} }
function resetFocus() {
chatSearchField.focus = false;
overviewPage.focus = true;
chatSearchField.visible = false;
pageHeader.visible = true;
searchChatButton.visible = overviewPage.connectionState === TelegramAPI.ConnectionReady;
}
Connections { Connections {
target: tdLibWrapper target: tdLibWrapper
onAuthorizationStateChanged: { onAuthorizationStateChanged: {
@ -217,7 +236,7 @@ Page {
Row { Row {
id: headerRow id: headerRow
width: parent.width width: parent.width - Theme.horizontalPageMargin
GlassItem { GlassItem {
id: pageStatus id: pageStatus
@ -232,8 +251,50 @@ Page {
PageHeader { PageHeader {
id: pageHeader id: pageHeader
title: qsTr("Fernschreiber") title: qsTr("Fernschreiber")
width: parent.width - pageStatus.width width: visible ? ( parent.width - pageStatus.width - searchChatButton.width ) : 0
opacity: visible ? 1 : 0
Behavior on opacity { NumberAnimation {} }
} }
IconButton {
id: searchChatButton
width: visible ? height : 0
opacity: visible ? 1 : 0
Behavior on opacity { NumberAnimation {} }
anchors.verticalCenter: parent.verticalCenter
icon {
source: "image://theme/icon-m-search?" + Theme.highlightColor
asynchronous: true
}
visible: overviewPage.connectionState === TelegramAPI.ConnectionReady
onClicked: {
chatSearchField.focus = true;
chatSearchField.visible = true;
pageHeader.visible = false;
searchChatButton.visible = false;
}
}
SearchField {
id: chatSearchField
visible: false
opacity: visible ? 1 : 0
Behavior on opacity { NumberAnimation {} }
width: visible ? ( parent.width - pageStatus.width ) : 0
height: pageHeader.height
placeholderText: qsTr("Search a chat...")
active: searchHeaderItem.visible
onTextChanged: {
searchChatTimer.restart();
}
EnterKey.iconSource: "image://theme/icon-m-enter-close"
EnterKey.onClicked: {
resetFocus();
}
}
} }
Item { Item {

View file

@ -54,23 +54,6 @@ namespace {
class ChatListModel::ChatData class ChatListModel::ChatData
{ {
public: public:
enum Role {
RoleDisplay = Qt::DisplayRole,
RoleChatId,
RoleChatType,
RoleTitle,
RolePhotoSmall,
RoleUnreadCount,
RoleLastReadInboxMessageId,
RoleLastMessageSenderId,
RoleLastMessageDate,
RoleLastMessageText,
RoleLastMessageStatus,
RoleChatMemberStatus,
RoleSecretChatState,
RoleIsVerified,
RoleIsChannel
};
ChatData(const QVariantMap &data, const QVariantMap &userInformation); ChatData(const QVariantMap &data, const QVariantMap &userInformation);
@ -368,21 +351,22 @@ ChatListModel::~ChatListModel()
QHash<int,QByteArray> ChatListModel::roleNames() const QHash<int,QByteArray> ChatListModel::roleNames() const
{ {
QHash<int,QByteArray> roles; QHash<int,QByteArray> roles;
roles.insert(ChatData::RoleDisplay, "display"); roles.insert(ChatListModel::RoleDisplay, "display");
roles.insert(ChatData::RoleChatId, "chat_id"); roles.insert(ChatListModel::RoleChatId, "chat_id");
roles.insert(ChatData::RoleChatType, "chat_type"); roles.insert(ChatListModel::RoleChatType, "chat_type");
roles.insert(ChatData::RoleTitle, "title"); roles.insert(ChatListModel::RoleTitle, "title");
roles.insert(ChatData::RolePhotoSmall, "photo_small"); roles.insert(ChatListModel::RolePhotoSmall, "photo_small");
roles.insert(ChatData::RoleUnreadCount, "unread_count"); roles.insert(ChatListModel::RoleUnreadCount, "unread_count");
roles.insert(ChatData::RoleLastReadInboxMessageId, "last_read_inbox_message_id"); roles.insert(ChatListModel::RoleLastReadInboxMessageId, "last_read_inbox_message_id");
roles.insert(ChatData::RoleLastMessageSenderId, "last_message_sender_id"); roles.insert(ChatListModel::RoleLastMessageSenderId, "last_message_sender_id");
roles.insert(ChatData::RoleLastMessageDate, "last_message_date"); roles.insert(ChatListModel::RoleLastMessageDate, "last_message_date");
roles.insert(ChatData::RoleLastMessageText, "last_message_text"); roles.insert(ChatListModel::RoleLastMessageText, "last_message_text");
roles.insert(ChatData::RoleLastMessageStatus, "last_message_status"); roles.insert(ChatListModel::RoleLastMessageStatus, "last_message_status");
roles.insert(ChatData::RoleChatMemberStatus, "chat_member_status"); roles.insert(ChatListModel::RoleChatMemberStatus, "chat_member_status");
roles.insert(ChatData::RoleSecretChatState, "secret_chat_state"); roles.insert(ChatListModel::RoleSecretChatState, "secret_chat_state");
roles.insert(ChatData::RoleIsVerified, "is_verified"); roles.insert(ChatListModel::RoleIsVerified, "is_verified");
roles.insert(ChatData::RoleIsChannel, "is_channel"); roles.insert(ChatListModel::RoleIsChannel, "is_channel");
roles.insert(ChatListModel::RoleFilter, "filter");
return roles; return roles;
} }
@ -396,22 +380,23 @@ QVariant ChatListModel::data(const QModelIndex &index, int role) const
const int row = index.row(); const int row = index.row();
if (row >= 0 && row < chatList.size()) { if (row >= 0 && row < chatList.size()) {
const ChatData *data = chatList.at(row); const ChatData *data = chatList.at(row);
switch ((ChatData::Role)role) { switch ((ChatListModel::Role)role) {
case ChatData::RoleDisplay: return data->chatData; case ChatListModel::RoleDisplay: return data->chatData;
case ChatData::RoleChatId: return data->chatId; case ChatListModel::RoleChatId: return data->chatId;
case ChatData::RoleChatType: return data->chatType; case ChatListModel::RoleChatType: return data->chatType;
case ChatData::RoleTitle: return data->title(); case ChatListModel::RoleTitle: return data->title();
case ChatData::RolePhotoSmall: return data->photoSmall(); case ChatListModel::RolePhotoSmall: return data->photoSmall();
case ChatData::RoleUnreadCount: return data->unreadCount(); case ChatListModel::RoleUnreadCount: return data->unreadCount();
case ChatData::RoleLastReadInboxMessageId: return data->lastReadInboxMessageId(); case ChatListModel::RoleLastReadInboxMessageId: return data->lastReadInboxMessageId();
case ChatData::RoleLastMessageSenderId: return data->senderUserId(); case ChatListModel::RoleLastMessageSenderId: return data->senderUserId();
case ChatData::RoleLastMessageText: return data->senderMessageText(); case ChatListModel::RoleLastMessageText: return data->senderMessageText();
case ChatData::RoleLastMessageDate: return data->senderMessageDate(); case ChatListModel::RoleLastMessageDate: return data->senderMessageDate();
case ChatData::RoleLastMessageStatus: return data->senderMessageStatus(); case ChatListModel::RoleLastMessageStatus: return data->senderMessageStatus();
case ChatData::RoleChatMemberStatus: return data->memberStatus; case ChatListModel::RoleChatMemberStatus: return data->memberStatus;
case ChatData::RoleSecretChatState: return data->secretChatState; case ChatListModel::RoleSecretChatState: return data->secretChatState;
case ChatData::RoleIsVerified: return data->verified; case ChatListModel::RoleIsVerified: return data->verified;
case ChatData::RoleIsChannel: return data->isChannel(); case ChatListModel::RoleIsChannel: return data->isChannel();
case ChatListModel::RoleFilter: return QString(data->title() + " " + data->senderMessageText()).trimmed();
} }
} }
return QVariant(); return QVariant();
@ -677,12 +662,12 @@ void ChatListModel::handleChatReadInboxUpdated(const QString &id, const QString
const int chatIndex = chatIndexMap.value(chatId); const int chatIndex = chatIndexMap.value(chatId);
ChatData *chat = chatList.at(chatIndex); ChatData *chat = chatList.at(chatIndex);
QVector<int> changedRoles; QVector<int> changedRoles;
changedRoles.append(ChatData::RoleDisplay); changedRoles.append(ChatListModel::RoleDisplay);
if (chat->updateUnreadCount(unreadCount)) { if (chat->updateUnreadCount(unreadCount)) {
changedRoles.append(ChatData::RoleUnreadCount); changedRoles.append(ChatListModel::RoleUnreadCount);
} }
if (chat->updateLastReadInboxMessageId(messageId)) { if (chat->updateLastReadInboxMessageId(messageId)) {
changedRoles.append(ChatData::RoleLastReadInboxMessageId); changedRoles.append(ChatListModel::RoleLastReadInboxMessageId);
} }
const QModelIndex modelIndex(index(chatIndex)); const QModelIndex modelIndex(index(chatIndex));
emit dataChanged(modelIndex, modelIndex, changedRoles); emit dataChanged(modelIndex, modelIndex, changedRoles);
@ -726,7 +711,7 @@ void ChatListModel::handleChatPhotoUpdated(qlonglong chatId, const QVariantMap &
ChatData *chat = chatList.at(chatIndex); ChatData *chat = chatList.at(chatIndex);
chat->chatData.insert(PHOTO, photo); chat->chatData.insert(PHOTO, photo);
QVector<int> changedRoles; QVector<int> changedRoles;
changedRoles.append(ChatData::RolePhotoSmall); changedRoles.append(ChatListModel::RolePhotoSmall);
const QModelIndex modelIndex(index(chatIndex)); const QModelIndex modelIndex(index(chatIndex));
emit dataChanged(modelIndex, modelIndex, changedRoles); emit dataChanged(modelIndex, modelIndex, changedRoles);
} else { } else {
@ -815,7 +800,7 @@ void ChatListModel::handleChatTitleUpdated(const QString &chatId, const QString
ChatData *chat = chatList.at(chatIndex); ChatData *chat = chatList.at(chatIndex);
chat->chatData.insert(TITLE, title); chat->chatData.insert(TITLE, title);
QVector<int> changedRoles; QVector<int> changedRoles;
changedRoles.append(ChatData::RoleTitle); changedRoles.append(ChatListModel::RoleTitle);
const QModelIndex modelIndex(index(chatIndex)); const QModelIndex modelIndex(index(chatIndex));
emit dataChanged(modelIndex, modelIndex, changedRoles); emit dataChanged(modelIndex, modelIndex, changedRoles);
} else { } else {
@ -831,6 +816,6 @@ void ChatListModel::handleRelativeTimeRefreshTimer()
{ {
LOG("Refreshing timestamps"); LOG("Refreshing timestamps");
QVector<int> roles; QVector<int> roles;
roles.append(ChatData::RoleLastMessageDate); roles.append(ChatListModel::RoleLastMessageDate);
emit dataChanged(index(0), index(chatList.size() - 1), roles); emit dataChanged(index(0), index(chatList.size() - 1), roles);
} }

View file

@ -29,6 +29,26 @@ class ChatListModel : public QAbstractListModel
Q_PROPERTY(bool showAllChats READ showAllChats WRITE setShowAllChats NOTIFY showAllChatsChanged) Q_PROPERTY(bool showAllChats READ showAllChats WRITE setShowAllChats NOTIFY showAllChatsChanged)
public: public:
enum Role {
RoleDisplay = Qt::DisplayRole,
RoleChatId,
RoleChatType,
RoleTitle,
RolePhotoSmall,
RoleUnreadCount,
RoleLastReadInboxMessageId,
RoleLastMessageSenderId,
RoleLastMessageDate,
RoleLastMessageText,
RoleLastMessageStatus,
RoleChatMemberStatus,
RoleSecretChatState,
RoleIsVerified,
RoleIsChannel,
RoleFilter
};
ChatListModel(TDLibWrapper *tdLibWrapper); ChatListModel(TDLibWrapper *tdLibWrapper);
~ChatListModel() override; ~ChatListModel() override;

View file

@ -88,6 +88,11 @@ int main(int argc, char *argv[])
ChatListModel chatListModel(tdLibWrapper); ChatListModel chatListModel(tdLibWrapper);
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);

View file

@ -1026,6 +1026,10 @@
<source>New Chat</source> <source>New Chat</source>
<translation>Neuer Chat</translation> <translation>Neuer Chat</translation>
</message> </message>
<message>
<source>Search a chat...</source>
<translation>Einen Chat suchen...</translation>
</message>
</context> </context>
<context> <context>
<name>PinnedMessageItem</name> <name>PinnedMessageItem</name>

View file

@ -1026,6 +1026,10 @@
<source>New Chat</source> <source>New Chat</source>
<translation>New Chat</translation> <translation>New Chat</translation>
</message> </message>
<message>
<source>Search a chat...</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>PinnedMessageItem</name> <name>PinnedMessageItem</name>

View file

@ -1015,6 +1015,10 @@
<source>New Chat</source> <source>New Chat</source>
<translation>Nueva charla</translation> <translation>Nueva charla</translation>
</message> </message>
<message>
<source>Search a chat...</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>PinnedMessageItem</name> <name>PinnedMessageItem</name>

View file

@ -1027,6 +1027,10 @@
<source>New Chat</source> <source>New Chat</source>
<translation>Uusi keskustelu</translation> <translation>Uusi keskustelu</translation>
</message> </message>
<message>
<source>Search a chat...</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>PinnedMessageItem</name> <name>PinnedMessageItem</name>

View file

@ -1015,6 +1015,10 @@
<source>New Chat</source> <source>New Chat</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Search a chat...</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>PinnedMessageItem</name> <name>PinnedMessageItem</name>

View file

@ -1026,6 +1026,10 @@
<source>New Chat</source> <source>New Chat</source>
<translation>Nuova chat</translation> <translation>Nuova chat</translation>
</message> </message>
<message>
<source>Search a chat...</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>PinnedMessageItem</name> <name>PinnedMessageItem</name>

View file

@ -1037,6 +1037,10 @@
<source>New Chat</source> <source>New Chat</source>
<translation>Nowy czat</translation> <translation>Nowy czat</translation>
</message> </message>
<message>
<source>Search a chat...</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>PinnedMessageItem</name> <name>PinnedMessageItem</name>

View file

@ -1037,6 +1037,10 @@
<source>New Chat</source> <source>New Chat</source>
<translation>Новый Чат</translation> <translation>Новый Чат</translation>
</message> </message>
<message>
<source>Search a chat...</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>PinnedMessageItem</name> <name>PinnedMessageItem</name>

View file

@ -1026,6 +1026,10 @@
<source>New Chat</source> <source>New Chat</source>
<translation>Ny chatt</translation> <translation>Ny chatt</translation>
</message> </message>
<message>
<source>Search a chat...</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>PinnedMessageItem</name> <name>PinnedMessageItem</name>

View file

@ -1015,6 +1015,10 @@
<source>New Chat</source> <source>New Chat</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>Search a chat...</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>PinnedMessageItem</name> <name>PinnedMessageItem</name>

View file

@ -1026,6 +1026,10 @@
<source>New Chat</source> <source>New Chat</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Search a chat...</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>PinnedMessageItem</name> <name>PinnedMessageItem</name>