From 68a2adc38d50860c52828742fd5ef879fc050078 Mon Sep 17 00:00:00 2001 From: Slava Monich Date: Fri, 10 Dec 2021 03:15:32 +0200 Subject: [PATCH] Optimized forwarding It was a very strange experience. Now it's more like what an average user would expect :) --- harbour-fernschreiber.pro | 2 + qml/pages/ChatSelectionPage.qml | 72 +++------------- src/chatlistmodel.cpp | 2 + src/chatlistmodel.h | 1 + src/chatpermissionfiltermodel.cpp | 131 ++++++++++++++++++++++++++++++ src/chatpermissionfiltermodel.h | 57 +++++++++++++ src/harbour-fernschreiber.cpp | 2 + 7 files changed, 206 insertions(+), 61 deletions(-) create mode 100644 src/chatpermissionfiltermodel.cpp create mode 100644 src/chatpermissionfiltermodel.h diff --git a/harbour-fernschreiber.pro b/harbour-fernschreiber.pro index d19ecd1..211dd90 100644 --- a/harbour-fernschreiber.pro +++ b/harbour-fernschreiber.pro @@ -22,6 +22,7 @@ DEFINES += QT_STATICPLUGIN SOURCES += src/harbour-fernschreiber.cpp \ src/appsettings.cpp \ + src/chatpermissionfiltermodel.cpp \ src/chatlistmodel.cpp \ src/chatmodel.cpp \ src/contactsmodel.cpp \ @@ -210,6 +211,7 @@ INSTALLS += telegram 86.png 108.png 128.png 172.png 256.png \ HEADERS += \ src/appsettings.h \ + src/chatpermissionfiltermodel.h \ src/chatlistmodel.h \ src/chatmodel.h \ src/contactsmodel.h \ diff --git a/qml/pages/ChatSelectionPage.qml b/qml/pages/ChatSelectionPage.qml index c3027dd..0c77d1f 100644 --- a/qml/pages/ChatSelectionPage.qml +++ b/qml/pages/ChatSelectionPage.qml @@ -18,6 +18,7 @@ */ import QtQuick 2.6 import Sailfish.Silica 1.0 +import WerkWolf.Fernschreiber 1.0 import "../components" import "../js/twemoji.js" as Emoji @@ -59,10 +60,10 @@ Dialog { } PageHeader { - id: pageHeader - title: qsTr("Select Chat") - width: parent.width - } + id: pageHeader + title: qsTr("Select Chat") + width: parent.width + } SilicaListView { id: chatListView @@ -76,63 +77,14 @@ Dialog { clip: true - model: chatListModel + model: ChatPermissionFilterModel { + tdlib: tdLibWrapper + sourceModel: chatListModel + requirePermissions: chatSelectionPage.payload.neededPermissions + } + delegate: ChatListViewItem { ownUserId: chatSelectionPage.myUserId - Loader { // checking permissions takes a while, so we defer those calculations - id: visibleLoader - asynchronous: true - sourceComponent: Component { - QtObject { - property bool visible: false - Component.onCompleted: { - if(chatSelectionPage.state === "forwardMessages" || chatSelectionPage.state === "fillTextArea" ) { - var chatType = display.type['@type'] - var chatGroupInformation - if(chatType === "chatTypePrivate" || chatType === "chatTypeSecret") { - visible = true - return; - } - else if (chatType === "chatTypeBasicGroup" ) { - chatGroupInformation = tdLibWrapper.getBasicGroup(display.type.basic_group_id) - } - else if (chatType === "chatTypeSupergroup" ) { - chatGroupInformation = tdLibWrapper.getSuperGroup(display.type.supergroup_id) - } - var groupStatus = chatGroupInformation.status - var groupStatusType = groupStatus["@type"] - var groupStatusPermissions = groupStatus.permissions - var groupPermissions = display.permissions - visible = (groupStatusType === "chatMemberStatusCreator" - || groupStatusType === "chatMemberStatusAdministrator" - || (groupStatusType === "chatMemberStatusMember" - && chatSelectionPage.payload.neededPermissions.every(function(neededPermission){ - return groupPermissions[neededPermission] - }) - ) - || (groupStatusType === "chatMemberStatusRestricted" - && chatSelectionPage.payload.neededPermissions.every(function(neededPermission){ - return groupStatusPermissions[neededPermission] - }) - ) - ) - } else { // future uses of chat selection can be processed here - visible = true - } - } - } - } - } - - property bool valid: visibleLoader && visibleLoader.item && visibleLoader.item.visible - opacity: valid ? 1.0 : 0 - - Behavior on opacity { FadeAnimation {}} - Behavior on height { NumberAnimation {}} - - // normal height while calculating, otherwise all elements get displayed at once - height: !visibleLoader.item || valid ? contentHeight : 0 - enabled: valid onClicked: { var chat = tdLibWrapper.getChat(display.id); switch(chatSelectionPage.state) { @@ -154,6 +106,4 @@ Dialog { VerticalScrollDecorator {} } - - } diff --git a/src/chatlistmodel.cpp b/src/chatlistmodel.cpp index 9cc589e..b4e9397 100644 --- a/src/chatlistmodel.cpp +++ b/src/chatlistmodel.cpp @@ -413,6 +413,7 @@ QHash ChatListModel::roleNames() const roles.insert(ChatListModel::RoleDisplay, "display"); roles.insert(ChatListModel::RoleChatId, "chat_id"); roles.insert(ChatListModel::RoleChatType, "chat_type"); + roles.insert(ChatListModel::RoleGroupId, "group_id"); roles.insert(ChatListModel::RoleTitle, "title"); roles.insert(ChatListModel::RolePhotoSmall, "photo_small"); roles.insert(ChatListModel::RoleUnreadCount, "unread_count"); @@ -447,6 +448,7 @@ QVariant ChatListModel::data(const QModelIndex &index, int role) const case ChatListModel::RoleDisplay: return data->chatData; case ChatListModel::RoleChatId: return data->chatId; case ChatListModel::RoleChatType: return data->chatType; + case ChatListModel::RoleGroupId: return data->groupId; case ChatListModel::RoleTitle: return data->title(); case ChatListModel::RolePhotoSmall: return data->photoSmall(); case ChatListModel::RoleUnreadCount: return data->unreadCount(); diff --git a/src/chatlistmodel.h b/src/chatlistmodel.h index f3659b7..0d8cdaf 100644 --- a/src/chatlistmodel.h +++ b/src/chatlistmodel.h @@ -36,6 +36,7 @@ public: RoleDisplay = Qt::DisplayRole, RoleChatId, RoleChatType, + RoleGroupId, RoleTitle, RolePhotoSmall, RoleUnreadCount, diff --git a/src/chatpermissionfiltermodel.cpp b/src/chatpermissionfiltermodel.cpp new file mode 100644 index 0000000..11e3073 --- /dev/null +++ b/src/chatpermissionfiltermodel.cpp @@ -0,0 +1,131 @@ +/* + 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 . +*/ + +#include "chatpermissionfiltermodel.h" +#include "chatlistmodel.h" + +#define DEBUG_MODULE ChatPermissionFilterModel +#include "debuglog.h" + +namespace { + const QString PERMISSIONS("permissions"); + const QString STATUS("status"); +} + +ChatPermissionFilterModel::ChatPermissionFilterModel(QObject *parent) : QSortFilterProxyModel(parent) +{ + setDynamicSortFilter(true); +} + +void ChatPermissionFilterModel::setSource(QObject *model) +{ + setSourceModel(qobject_cast(model)); +} + +void ChatPermissionFilterModel::setSourceModel(QAbstractItemModel *model) +{ + if (sourceModel() != model) { + LOG(model); + QSortFilterProxyModel::setSourceModel(model); + emit sourceChanged(); + } +} + +TDLibWrapper *ChatPermissionFilterModel::getTDLibWrapper() const +{ + return tdLibWrapper; +} + +void ChatPermissionFilterModel::setTDLibWrapper(QObject *obj) +{ + TDLibWrapper *wrapper = qobject_cast(obj); + if (tdLibWrapper != wrapper) { + tdLibWrapper = wrapper; + LOG(wrapper); + invalidateFilter(); + } +} + +QStringList ChatPermissionFilterModel::getRequirePermissions() const +{ + return requirePermissions; +} + +void ChatPermissionFilterModel::setRequirePermissions(QStringList permissions) +{ + if (requirePermissions != permissions) { + requirePermissions = permissions; + LOG(requirePermissions); + invalidateFilter(); + emit requirePermissionsChanged(); + } +} + +bool ChatPermissionFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const +{ + QAbstractItemModel* model = sourceModel(); + if (model && tdLibWrapper && !requirePermissions.isEmpty()) { + const TDLibWrapper::Group* group = Q_NULLPTR; + const QModelIndex index(model->index(sourceRow, 0, sourceParent)); + TDLibWrapper::ChatType chatType = (TDLibWrapper::ChatType) + model->data(index, ChatListModel::RoleChatType).toInt(); + + switch (chatType) { + case TDLibWrapper::ChatTypeUnknown: + return false; + case TDLibWrapper::TDLibWrapper::ChatTypePrivate: + case TDLibWrapper::TDLibWrapper::ChatTypeSecret: + return true; + case TDLibWrapper::TDLibWrapper::ChatTypeBasicGroup: + case TDLibWrapper::TDLibWrapper::ChatTypeSupergroup: + group = tdLibWrapper->getGroup(model->data(index, + ChatListModel::RoleGroupId).toLongLong()); + break; + } + + if (group) { + TDLibWrapper::ChatMemberStatus memberStatus = (TDLibWrapper::ChatMemberStatus) + model->data(index, ChatListModel::RoleChatMemberStatus).toInt(); + QVariantMap permissions; + + switch (memberStatus) { + case TDLibWrapper::ChatMemberStatusCreator: + case TDLibWrapper::ChatMemberStatusAdministrator: + case TDLibWrapper::ChatMemberStatusMember: + permissions = model->data(index, ChatListModel::RoleDisplay).toMap().value(PERMISSIONS).toMap(); + break; + case TDLibWrapper::ChatMemberStatusRestricted: + permissions = group->groupInfo.value(STATUS).toMap().value(PERMISSIONS).toMap(); + break; + case TDLibWrapper::ChatMemberStatusLeft: + case TDLibWrapper::ChatMemberStatusUnknown: + case TDLibWrapper::ChatMemberStatusBanned: + return false; + } + + if (!permissions.isEmpty()) { + const int n = requirePermissions.count(); + for (int i = 0; i < n; i++) { + if (permissions.value(requirePermissions.at(i)).toBool()) { + return true; + } + } + } + } + } + return false; +} diff --git a/src/chatpermissionfiltermodel.h b/src/chatpermissionfiltermodel.h new file mode 100644 index 0000000..d77b3f6 --- /dev/null +++ b/src/chatpermissionfiltermodel.h @@ -0,0 +1,57 @@ +/* + 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 . +*/ + +#ifndef CHATPERMISSIONFILTERMODEL_H +#define CHATPERMISSIONFILTERMODEL_H + +#include "tdlibwrapper.h" + +#include + +class ChatPermissionFilterModel : public QSortFilterProxyModel +{ + Q_OBJECT + Q_PROPERTY(QObject* tdlib READ getTDLibWrapper WRITE setTDLibWrapper NOTIFY tdlibChanged) + Q_PROPERTY(QObject* sourceModel READ sourceModel WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(QStringList requirePermissions READ getRequirePermissions WRITE setRequirePermissions NOTIFY requirePermissionsChanged) + +public: + ChatPermissionFilterModel(QObject *parent = Q_NULLPTR); + + TDLibWrapper *getTDLibWrapper() const; + void setTDLibWrapper(QObject* obj); + + void setSource(QObject* model); + void setSourceModel(QAbstractItemModel *model) Q_DECL_OVERRIDE; + + void setRequirePermissions(QStringList permissions); + QStringList getRequirePermissions() const; + +signals: + void tdlibChanged(); + void sourceChanged(); + void requirePermissionsChanged(); + +protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_OVERRIDE; + +private: + TDLibWrapper *tdLibWrapper; + QStringList requirePermissions; +}; + +#endif // CHATPERMISSIONFILTERMODEL_H diff --git a/src/harbour-fernschreiber.cpp b/src/harbour-fernschreiber.cpp index 1754fcf..319c67f 100644 --- a/src/harbour-fernschreiber.cpp +++ b/src/harbour-fernschreiber.cpp @@ -34,6 +34,7 @@ #include "debuglogjs.h" #include "tdlibfile.h" #include "tdlibwrapper.h" +#include "chatpermissionfiltermodel.h" #include "chatlistmodel.h" #include "chatmodel.h" #include "namedaction.h" @@ -71,6 +72,7 @@ int main(int argc, char *argv[]) qmlRegisterType(uri, 1, 0, "TDLibFile"); qmlRegisterType(uri, 1, 0, "NamedAction"); qmlRegisterType(uri, 1, 0, "TextFilterModel"); + qmlRegisterType(uri, 1, 0, "ChatPermissionFilterModel"); qmlRegisterSingletonType(uri, 1, 0, "DebugLog", DebugLogJS::createSingleton); AppSettings *appSettings = new AppSettings(view.data());