Optimized forwarding

It was a very strange experience. Now it's more like what an average
user would expect :)
This commit is contained in:
Slava Monich 2021-12-10 03:15:32 +02:00
parent fb4ce26dd3
commit 68a2adc38d
7 changed files with 206 additions and 61 deletions

View file

@ -22,6 +22,7 @@ DEFINES += QT_STATICPLUGIN
SOURCES += src/harbour-fernschreiber.cpp \ SOURCES += src/harbour-fernschreiber.cpp \
src/appsettings.cpp \ src/appsettings.cpp \
src/chatpermissionfiltermodel.cpp \
src/chatlistmodel.cpp \ src/chatlistmodel.cpp \
src/chatmodel.cpp \ src/chatmodel.cpp \
src/contactsmodel.cpp \ src/contactsmodel.cpp \
@ -210,6 +211,7 @@ INSTALLS += telegram 86.png 108.png 128.png 172.png 256.png \
HEADERS += \ HEADERS += \
src/appsettings.h \ src/appsettings.h \
src/chatpermissionfiltermodel.h \
src/chatlistmodel.h \ src/chatlistmodel.h \
src/chatmodel.h \ src/chatmodel.h \
src/contactsmodel.h \ src/contactsmodel.h \

View file

@ -18,6 +18,7 @@
*/ */
import QtQuick 2.6 import QtQuick 2.6
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../components" import "../components"
import "../js/twemoji.js" as Emoji import "../js/twemoji.js" as Emoji
@ -59,10 +60,10 @@ Dialog {
} }
PageHeader { PageHeader {
id: pageHeader id: pageHeader
title: qsTr("Select Chat") title: qsTr("Select Chat")
width: parent.width width: parent.width
} }
SilicaListView { SilicaListView {
id: chatListView id: chatListView
@ -76,63 +77,14 @@ Dialog {
clip: true clip: true
model: chatListModel model: ChatPermissionFilterModel {
tdlib: tdLibWrapper
sourceModel: chatListModel
requirePermissions: chatSelectionPage.payload.neededPermissions
}
delegate: ChatListViewItem { delegate: ChatListViewItem {
ownUserId: chatSelectionPage.myUserId 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: { onClicked: {
var chat = tdLibWrapper.getChat(display.id); var chat = tdLibWrapper.getChat(display.id);
switch(chatSelectionPage.state) { switch(chatSelectionPage.state) {
@ -154,6 +106,4 @@ Dialog {
VerticalScrollDecorator {} VerticalScrollDecorator {}
} }
} }

View file

@ -413,6 +413,7 @@ QHash<int,QByteArray> ChatListModel::roleNames() const
roles.insert(ChatListModel::RoleDisplay, "display"); roles.insert(ChatListModel::RoleDisplay, "display");
roles.insert(ChatListModel::RoleChatId, "chat_id"); roles.insert(ChatListModel::RoleChatId, "chat_id");
roles.insert(ChatListModel::RoleChatType, "chat_type"); roles.insert(ChatListModel::RoleChatType, "chat_type");
roles.insert(ChatListModel::RoleGroupId, "group_id");
roles.insert(ChatListModel::RoleTitle, "title"); roles.insert(ChatListModel::RoleTitle, "title");
roles.insert(ChatListModel::RolePhotoSmall, "photo_small"); roles.insert(ChatListModel::RolePhotoSmall, "photo_small");
roles.insert(ChatListModel::RoleUnreadCount, "unread_count"); 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::RoleDisplay: return data->chatData;
case ChatListModel::RoleChatId: return data->chatId; case ChatListModel::RoleChatId: return data->chatId;
case ChatListModel::RoleChatType: return data->chatType; case ChatListModel::RoleChatType: return data->chatType;
case ChatListModel::RoleGroupId: return data->groupId;
case ChatListModel::RoleTitle: return data->title(); case ChatListModel::RoleTitle: return data->title();
case ChatListModel::RolePhotoSmall: return data->photoSmall(); case ChatListModel::RolePhotoSmall: return data->photoSmall();
case ChatListModel::RoleUnreadCount: return data->unreadCount(); case ChatListModel::RoleUnreadCount: return data->unreadCount();

View file

@ -36,6 +36,7 @@ public:
RoleDisplay = Qt::DisplayRole, RoleDisplay = Qt::DisplayRole,
RoleChatId, RoleChatId,
RoleChatType, RoleChatType,
RoleGroupId,
RoleTitle, RoleTitle,
RolePhotoSmall, RolePhotoSmall,
RoleUnreadCount, RoleUnreadCount,

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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<ChatListModel*>(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<TDLibWrapper*>(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;
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef CHATPERMISSIONFILTERMODEL_H
#define CHATPERMISSIONFILTERMODEL_H
#include "tdlibwrapper.h"
#include <QSortFilterProxyModel>
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

View file

@ -34,6 +34,7 @@
#include "debuglogjs.h" #include "debuglogjs.h"
#include "tdlibfile.h" #include "tdlibfile.h"
#include "tdlibwrapper.h" #include "tdlibwrapper.h"
#include "chatpermissionfiltermodel.h"
#include "chatlistmodel.h" #include "chatlistmodel.h"
#include "chatmodel.h" #include "chatmodel.h"
#include "namedaction.h" #include "namedaction.h"
@ -71,6 +72,7 @@ int main(int argc, char *argv[])
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"); qmlRegisterType<TextFilterModel>(uri, 1, 0, "TextFilterModel");
qmlRegisterType<ChatPermissionFilterModel>(uri, 1, 0, "ChatPermissionFilterModel");
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());