mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 14:17:12 +02:00
Support nice leaving of shareable folder.
This commit is contained in:
parent
4444844443
commit
6be2fb9790
8 changed files with 396 additions and 79 deletions
|
@ -3558,9 +3558,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_filters_toast_add" = "{chat} added to {folder} folder";
|
||||
"lng_filters_toast_remove" = "{chat} removed from {folder} folder";
|
||||
|
||||
"lng_filters_link" = "Invite links";
|
||||
"lng_filters_delete_sure" = "Are you sure you want to delete this folder? This will also deactivate all the invite links used to share this folder.";
|
||||
"lng_filters_link" = "Share Folder";
|
||||
"lng_filters_link_has" = "Invite links";
|
||||
"lng_filters_link_badge" = "New";
|
||||
"lng_filters_link_create" = "Share Folder";
|
||||
"lng_filters_link_create" = "Create an Invite Link";
|
||||
"lng_filters_link_cant" = "No way to share folders with chat types or excluded chats.";
|
||||
"lng_filters_link_about" = "Share access to some of this folder's groups and channels with others.";
|
||||
"lng_filters_link_about_many" = "Create more links to set up different access levels for different people.";
|
||||
|
@ -3577,6 +3579,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_filters_link_noadmin_status" = "you can't invite others here";
|
||||
"lng_filters_link_noadmin_group_error" = "You don't have the admin rights to share invite links to this group chat.";
|
||||
"lng_filters_link_noadmin_channel_error" = "You don't have the admin rights to share invite links to this channel.";
|
||||
"lng_filters_link_already_group" = "you are already a member";
|
||||
"lng_filters_link_already_channel" = "you are already subscribed";
|
||||
"lng_filters_link_chats_about" = "Select groups and channels that you want everyone who adds the folder via invite link to join.";
|
||||
"lng_filters_link_no_about" = "There are no chats in this folder that you can share with others.";
|
||||
"lng_filters_link_chats_no" = "These chats cannot be shared";
|
||||
|
@ -3604,8 +3608,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_filters_by_link_quit#other" = "{count} chats to quit";
|
||||
"lng_filters_by_link_select" = "Select All";
|
||||
"lng_filters_by_link_deselect" = "Deselect All";
|
||||
"lng_filters_by_link_about_quit" = "You can deselect the chats you don't want to quit.";
|
||||
"lng_filters_by_link_remove_button" = "Remove Folder";
|
||||
"lng_filters_by_link_quit_button" = "Remove Folder and Chats";
|
||||
"lng_filters_added_title" = "Folder {folder} Added";
|
||||
"lng_filters_added_also#one" = "You also joined {count} chat.";
|
||||
"lng_filters_added_also#other" = "You also joined {count} chats.";
|
||||
"lng_filters_updated_title" = "Folder {folder} Updated";
|
||||
"lng_filters_updated_also#one" = "You have joined {count} new chat.";
|
||||
"lng_filters_updated_also#other" = "You have joined {count} new chats.";
|
||||
"lng_filters_bar_you_can#one" = "You can join {count} new chat";
|
||||
"lng_filters_bar_you_can#other" = "You can join {count} new chats";
|
||||
"lng_filters_bar_view" = "Click here to view them";
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "apiwrap.h"
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "boxes/filters/edit_filter_links.h" // FilterChatStatusText
|
||||
#include "core/application.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_peer.h"
|
||||
|
@ -21,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toasts/common_toasts.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/filter_icons.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_filter_icons.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
@ -41,10 +43,9 @@ public:
|
|||
ToggleChatsController(
|
||||
not_null<Window::SessionController*> window,
|
||||
ToggleAction action,
|
||||
const QString &slug,
|
||||
FilterId filterId,
|
||||
const QString &title,
|
||||
std::vector<not_null<PeerData*>> chats);
|
||||
std::vector<not_null<PeerData*>> chats,
|
||||
std::vector<not_null<PeerData*>> additional);
|
||||
|
||||
void prepare() override;
|
||||
void rowClicked(not_null<PeerListRow*> row) override;
|
||||
|
@ -63,10 +64,9 @@ private:
|
|||
Ui::RpWidget *_addedTopWidget = nullptr;
|
||||
|
||||
ToggleAction _action = ToggleAction::Adding;
|
||||
QString _slug;
|
||||
FilterId _filterId = 0;
|
||||
QString _filterTitle;
|
||||
std::vector<not_null<PeerData*>> _chats;
|
||||
std::vector<not_null<PeerData*>> _additional;
|
||||
rpl::variable<base::flat_set<not_null<PeerData*>>> _selected;
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||
|
@ -128,13 +128,18 @@ void InitFilterLinkHeader(
|
|||
Fn<void(int)> setAddedTopHeight,
|
||||
Ui::FilterLinkHeaderType type,
|
||||
const QString &title,
|
||||
const QString &iconEmoji,
|
||||
rpl::producer<int> count) {
|
||||
const auto icon = Ui::LookupFilterIcon(
|
||||
Ui::LookupFilterIconByEmoji(
|
||||
iconEmoji
|
||||
).value_or(Ui::FilterIcon::Custom)).active;
|
||||
auto header = Ui::MakeFilterLinkHeader(box, {
|
||||
.type = type,
|
||||
.title = TitleText(type)(tr::now),
|
||||
.about = AboutText(type, title),
|
||||
.folderTitle = title,
|
||||
.folderIcon = &st::foldersCustomActive,
|
||||
.folderIcon = icon,
|
||||
.badge = (type == Ui::FilterLinkHeaderType::AddingChats
|
||||
? std::move(count)
|
||||
: rpl::single(0)),
|
||||
|
@ -220,16 +225,14 @@ void ImportInvite(
|
|||
ToggleChatsController::ToggleChatsController(
|
||||
not_null<Window::SessionController*> window,
|
||||
ToggleAction action,
|
||||
const QString &slug,
|
||||
FilterId filterId,
|
||||
const QString &title,
|
||||
std::vector<not_null<PeerData*>> chats)
|
||||
std::vector<not_null<PeerData*>> chats,
|
||||
std::vector<not_null<PeerData*>> additional)
|
||||
: _window(window)
|
||||
, _action(action)
|
||||
, _slug(slug)
|
||||
, _filterId(filterId)
|
||||
, _filterTitle(title)
|
||||
, _chats(std::move(chats)) {
|
||||
, _chats(std::move(chats))
|
||||
, _additional(std::move(additional)) {
|
||||
setStyleOverrides(&st::filterLinkChatsList);
|
||||
}
|
||||
|
||||
|
@ -237,12 +240,34 @@ void ToggleChatsController::prepare() {
|
|||
setupAboveWidget();
|
||||
setupBelowWidget();
|
||||
auto selected = base::flat_set<not_null<PeerData*>>();
|
||||
for (const auto &peer : _chats) {
|
||||
const auto add = [&](not_null<PeerData*> peer, bool additional = false) {
|
||||
auto row = std::make_unique<PeerListRow>(peer);
|
||||
if (delegate()->peerListFindRow(peer->id.value)) {
|
||||
return;
|
||||
}
|
||||
const auto raw = row.get();
|
||||
delegate()->peerListAppendRow(std::move(row));
|
||||
delegate()->peerListSetRowChecked(raw, true);
|
||||
selected.emplace(peer);
|
||||
if (!additional || _action == ToggleAction::Removing) {
|
||||
if (const auto status = FilterChatStatusText(peer)
|
||||
; !status.isEmpty()) {
|
||||
raw->setCustomStatus(status);
|
||||
}
|
||||
}
|
||||
if (!additional) {
|
||||
delegate()->peerListSetRowChecked(raw, true);
|
||||
selected.emplace(peer);
|
||||
} else if (_action == ToggleAction::Adding) {
|
||||
raw->setDisabledState(PeerListRow::State::DisabledChecked);
|
||||
raw->setCustomStatus(peer->isBroadcast()
|
||||
? tr::lng_filters_link_already_channel(tr::now)
|
||||
: tr::lng_filters_link_already_group(tr::now));
|
||||
}
|
||||
};
|
||||
for (const auto &peer : _chats) {
|
||||
add(peer);
|
||||
}
|
||||
for (const auto &peer : _additional) {
|
||||
add(peer, true);
|
||||
}
|
||||
delegate()->peerListRefreshRows();
|
||||
_selected = std::move(selected);
|
||||
|
@ -269,23 +294,51 @@ void ToggleChatsController::setupAboveWidget() {
|
|||
|
||||
_addedTopWidget = container->add(object_ptr<Ui::RpWidget>(container));
|
||||
AddDivider(container);
|
||||
const auto totalCount = [&] {
|
||||
if (_chats.empty()) {
|
||||
return _additional.size();
|
||||
} else if (_additional.empty()) {
|
||||
return _chats.size();
|
||||
}
|
||||
auto result = _chats.size();
|
||||
for (const auto &peer : _additional) {
|
||||
if (!ranges::contains(_chats, peer)) {
|
||||
++result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
const auto count = (_action == ToggleAction::Removing)
|
||||
? totalCount()
|
||||
: _chats.empty()
|
||||
? _additional.size()
|
||||
: _chats.size();
|
||||
AddSubsectionTitle(
|
||||
container,
|
||||
tr::lng_filters_by_link_join(
|
||||
lt_count,
|
||||
rpl::single(float64(_chats.size()))),
|
||||
(_action == ToggleAction::Removing
|
||||
? tr::lng_filters_by_link_quit
|
||||
: _chats.empty()
|
||||
? tr::lng_filters_by_link_in
|
||||
: tr::lng_filters_by_link_join)(
|
||||
lt_count,
|
||||
rpl::single(float64(count))),
|
||||
st::filterLinkSubsectionTitlePadding);
|
||||
|
||||
delegate()->peerListSetAboveWidget(std::move(wrap));
|
||||
}
|
||||
|
||||
void ToggleChatsController::setupBelowWidget() {
|
||||
if (_chats.empty()) {
|
||||
return;
|
||||
}
|
||||
delegate()->peerListSetBelowWidget(
|
||||
object_ptr<Ui::DividerLabel>(
|
||||
(QWidget*)nullptr,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
(QWidget*)nullptr,
|
||||
tr::lng_filters_by_link_about(tr::now),
|
||||
(_action == ToggleAction::Removing
|
||||
? tr::lng_filters_by_link_about_quit
|
||||
: tr::lng_filters_by_link_about)(tr::now),
|
||||
st::boxDividerLabel),
|
||||
st::settingsDividerLabelPadding));
|
||||
}
|
||||
|
@ -305,12 +358,40 @@ void ToggleChatsController::setAddedTopHeight(int addedTopHeight) {
|
|||
_addedTopWidget->resize(_addedTopWidget->width(), addedTopHeight);
|
||||
}
|
||||
|
||||
void ShowImportToast(
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
const QString &title,
|
||||
Ui::FilterLinkHeaderType type,
|
||||
int added) {
|
||||
const auto strong = weak.get();
|
||||
if (!strong) {
|
||||
return;
|
||||
}
|
||||
const auto created = (type == Ui::FilterLinkHeaderType::AddingFilter);
|
||||
const auto phrase = created
|
||||
? tr::lng_filters_added_title
|
||||
: tr::lng_filters_updated_title;
|
||||
auto text = Ui::Text::Bold(phrase(tr::now, lt_folder, title));
|
||||
if (added > 0) {
|
||||
const auto phrase = created
|
||||
? tr::lng_filters_added_also
|
||||
: tr::lng_filters_updated_also;
|
||||
text.append('\n').append(phrase(tr::now, lt_count, added));
|
||||
}
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(strong).toastParent(),
|
||||
.text = { std::move(text) },
|
||||
});
|
||||
}
|
||||
|
||||
void ProcessFilterInvite(
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
const QString &slug,
|
||||
FilterId filterId,
|
||||
const QString &title,
|
||||
std::vector<not_null<PeerData*>> peers) {
|
||||
const QString &iconEmoji,
|
||||
std::vector<not_null<PeerData*>> peers,
|
||||
std::vector<not_null<PeerData*>> already) {
|
||||
const auto strong = weak.get();
|
||||
if (!strong) {
|
||||
return;
|
||||
|
@ -323,19 +404,21 @@ void ProcessFilterInvite(
|
|||
});
|
||||
return;
|
||||
}
|
||||
const auto fullyAdded = (peers.empty() && filterId);
|
||||
auto controller = std::make_unique<ToggleChatsController>(
|
||||
strong,
|
||||
ToggleAction::Adding,
|
||||
slug,
|
||||
filterId,
|
||||
title,
|
||||
std::move(peers));
|
||||
std::move(peers),
|
||||
std::move(already));
|
||||
const auto raw = controller.get();
|
||||
auto initBox = [=](not_null<PeerListBox*> box) {
|
||||
box->setStyle(st::filterInviteBox);
|
||||
|
||||
using Type = Ui::FilterLinkHeaderType;
|
||||
const auto type = !filterId
|
||||
const auto type = fullyAdded
|
||||
? Type::AllAdded
|
||||
: !filterId
|
||||
? Type::AddingFilter
|
||||
: Type::AddingChats;
|
||||
auto badge = raw->selectedValue(
|
||||
|
@ -344,7 +427,7 @@ void ProcessFilterInvite(
|
|||
});
|
||||
InitFilterLinkHeader(box, [=](int addedTopHeight) {
|
||||
raw->setAddedTopHeight(addedTopHeight);
|
||||
}, type, title, rpl::duplicate(badge));
|
||||
}, type, title, iconEmoji, rpl::duplicate(badge));
|
||||
|
||||
auto owned = Ui::FilterLinkProcessButton(
|
||||
box,
|
||||
|
@ -380,6 +463,7 @@ void ProcessFilterInvite(
|
|||
} else if (!state->importing) {
|
||||
state->importing = true;
|
||||
ImportInvite(weak, slug, peers, crl::guard(box, [=] {
|
||||
ShowImportToast(weak, title, type, peers.size());
|
||||
box->closeBox();
|
||||
}), crl::guard(box, [=] {
|
||||
state->importing = false;
|
||||
|
@ -396,7 +480,8 @@ void ProcessFilterInvite(
|
|||
base::weak_ptr<Window::SessionController> weak,
|
||||
const QString &slug,
|
||||
FilterId filterId,
|
||||
std::vector<not_null<PeerData*>> peers) {
|
||||
std::vector<not_null<PeerData*>> peers,
|
||||
std::vector<not_null<PeerData*>> already) {
|
||||
const auto strong = weak.get();
|
||||
if (!strong) {
|
||||
return;
|
||||
|
@ -411,7 +496,14 @@ void ProcessFilterInvite(
|
|||
});
|
||||
return;
|
||||
}
|
||||
ProcessFilterInvite(weak, slug, filterId, it->title(), std::move(peers));
|
||||
ProcessFilterInvite(
|
||||
weak,
|
||||
slug,
|
||||
filterId,
|
||||
it->title(),
|
||||
it->iconEmoji(),
|
||||
std::move(peers),
|
||||
std::move(already));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -441,6 +533,7 @@ void CheckFilterInvite(
|
|||
return;
|
||||
}
|
||||
auto title = QString();
|
||||
auto iconEmoji = QString();
|
||||
auto filterId = FilterId();
|
||||
auto peers = std::vector<not_null<PeerData*>>();
|
||||
auto already = std::vector<not_null<PeerData*>>();
|
||||
|
@ -459,6 +552,7 @@ void CheckFilterInvite(
|
|||
};
|
||||
result.match([&](const MTPDcommunities_communityInvite &data) {
|
||||
title = qs(data.vtitle());
|
||||
iconEmoji = data.vemoticon().value_or_empty();
|
||||
peers = parseList(data.vpeers());
|
||||
}, [&](const MTPDcommunities_communityInviteAlready &data) {
|
||||
filterId = data.vfilter_id().v;
|
||||
|
@ -477,20 +571,103 @@ void CheckFilterInvite(
|
|||
owner.chatsFilters().changed(
|
||||
) | rpl::start_with_next([=] {
|
||||
lifetime->destroy();
|
||||
ProcessFilterInvite(weak, slug, filterId, std::move(peers));
|
||||
ProcessFilterInvite(
|
||||
weak,
|
||||
slug,
|
||||
filterId,
|
||||
std::move(peers),
|
||||
std::move(already));
|
||||
}, *lifetime);
|
||||
owner.chatsFilters().reload();
|
||||
} else if (filterId) {
|
||||
ProcessFilterInvite(weak, slug, filterId, std::move(peers));
|
||||
ProcessFilterInvite(
|
||||
weak,
|
||||
slug,
|
||||
filterId,
|
||||
std::move(peers),
|
||||
std::move(already));
|
||||
} else {
|
||||
ProcessFilterInvite(weak, slug, filterId, title, std::move(peers));
|
||||
ProcessFilterInvite(
|
||||
weak,
|
||||
slug,
|
||||
filterId,
|
||||
title,
|
||||
iconEmoji,
|
||||
std::move(peers),
|
||||
std::move(already));
|
||||
}
|
||||
}, [=](const MTP::Error &error) {
|
||||
if (error.code() != 400) {
|
||||
return;
|
||||
}
|
||||
ProcessFilterInvite(weak, slug, FilterId(), QString(), {});
|
||||
ProcessFilterInvite(weak, slug, {}, {}, {}, {}, {});
|
||||
});
|
||||
}
|
||||
|
||||
void ProcessFilterRemove(
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
const QString &title,
|
||||
const QString &iconEmoji,
|
||||
std::vector<not_null<PeerData*>> all,
|
||||
std::vector<not_null<PeerData*>> suggest,
|
||||
Fn<void(std::vector<not_null<PeerData*>>)> done) {
|
||||
const auto strong = weak.get();
|
||||
if (!strong) {
|
||||
return;
|
||||
}
|
||||
Core::App().hideMediaView();
|
||||
if (all.empty() && suggest.empty()) {
|
||||
done({});
|
||||
return;
|
||||
}
|
||||
auto controller = std::make_unique<ToggleChatsController>(
|
||||
strong,
|
||||
ToggleAction::Removing,
|
||||
title,
|
||||
std::move(suggest),
|
||||
std::move(all));
|
||||
const auto raw = controller.get();
|
||||
auto initBox = [=](not_null<PeerListBox*> box) {
|
||||
box->setStyle(st::filterInviteBox);
|
||||
|
||||
const auto type = Ui::FilterLinkHeaderType::Removing;
|
||||
auto badge = raw->selectedValue(
|
||||
) | rpl::map([=](const base::flat_set<not_null<PeerData*>> &peers) {
|
||||
return int(peers.size());
|
||||
});
|
||||
InitFilterLinkHeader(box, [=](int addedTopHeight) {
|
||||
raw->setAddedTopHeight(addedTopHeight);
|
||||
}, type, title, iconEmoji, rpl::single(0));
|
||||
|
||||
auto owned = Ui::FilterLinkProcessButton(
|
||||
box,
|
||||
type,
|
||||
title,
|
||||
std::move(badge));
|
||||
|
||||
const auto button = owned.data();
|
||||
box->widthValue(
|
||||
) | rpl::start_with_next([=](int width) {
|
||||
const auto &padding = st::filterInviteBox.buttonPadding;
|
||||
button->resizeToWidth(width
|
||||
- padding.left()
|
||||
- padding.right());
|
||||
button->moveToLeft(padding.left(), padding.top());
|
||||
}, button->lifetime());
|
||||
|
||||
box->addButton(std::move(owned));
|
||||
|
||||
raw->selectedValue(
|
||||
) | rpl::start_with_next([=](
|
||||
base::flat_set<not_null<PeerData*>> &&peers) {
|
||||
button->setClickedCallback([=] {
|
||||
done(peers | ranges::to_vector);
|
||||
box->closeBox();
|
||||
});
|
||||
}, box->lifetime());
|
||||
};
|
||||
strong->show(
|
||||
Box<PeerListBox>(std::move(controller), std::move(initBox)));
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
|
|
@ -25,4 +25,12 @@ void CheckFilterInvite(
|
|||
not_null<Window::SessionController*> controller,
|
||||
const QString &slug);
|
||||
|
||||
void ProcessFilterRemove(
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
const QString &title,
|
||||
const QString &iconEmoji,
|
||||
std::vector<not_null<PeerData*>> all,
|
||||
std::vector<not_null<PeerData*>> suggest,
|
||||
Fn<void(std::vector<not_null<PeerData*>>)> done);
|
||||
|
||||
} // namespace Api
|
||||
|
|
|
@ -706,7 +706,16 @@ void EditFilterBox(
|
|||
return result;
|
||||
};
|
||||
|
||||
AddSubsectionTitle(content, tr::lng_filters_link());
|
||||
AddSubsectionTitle(
|
||||
content,
|
||||
rpl::conditional(
|
||||
state->hasLinks.value(),
|
||||
tr::lng_filters_link_has(),
|
||||
tr::lng_filters_link()));
|
||||
|
||||
state->hasLinks.changes() | rpl::start_with_next([=] {
|
||||
content->resizeToWidth(content->widthNoMargins());
|
||||
}, content->lifetime());
|
||||
|
||||
if (filter.community()) {
|
||||
window->session().data().chatsFilters().reloadCommunityLinks(
|
||||
|
|
|
@ -679,26 +679,12 @@ void LinkController::prepare() {
|
|||
|
||||
setupAboveWidget();
|
||||
setupBelowWidget();
|
||||
const auto countStatus = [&](not_null<PeerData*> peer) {
|
||||
if (const auto chat = peer->asChat()) {
|
||||
if (const auto count = chat->count; count > 0) {
|
||||
return tr::lng_chat_status_members(tr::now, lt_count, count);
|
||||
}
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
if (channel->membersCountKnown()) {
|
||||
return (channel->isBroadcast()
|
||||
? tr::lng_chat_status_subscribers
|
||||
: tr::lng_chat_status_members)(
|
||||
tr::now,
|
||||
lt_count,
|
||||
channel->membersCount());
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
};
|
||||
for (const auto &history : _data.chats) {
|
||||
const auto peer = history->peer;
|
||||
auto row = std::make_unique<ChatRow>(peer, countStatus(peer), false);
|
||||
auto row = std::make_unique<ChatRow>(
|
||||
peer,
|
||||
FilterChatStatusText(peer),
|
||||
false);
|
||||
const auto raw = row.get();
|
||||
delegate()->peerListAppendRow(std::move(row));
|
||||
delegate()->peerListSetRowChecked(raw, true);
|
||||
|
@ -712,7 +698,7 @@ void LinkController::prepare() {
|
|||
const auto error = ErrorForSharing(history);
|
||||
auto row = std::make_unique<ChatRow>(
|
||||
peer,
|
||||
error ? error->status : countStatus(peer),
|
||||
error ? error->status : FilterChatStatusText(peer),
|
||||
error.has_value());
|
||||
const auto raw = row.get();
|
||||
delegate()->peerListAppendRow(std::move(row));
|
||||
|
@ -1160,6 +1146,24 @@ object_ptr<Ui::BoxContent> ShowLinkBox(
|
|||
return Box<PeerListBox>(std::move(controller), std::move(initBox));
|
||||
}
|
||||
|
||||
QString FilterChatStatusText(not_null<PeerData*> peer) {
|
||||
if (const auto chat = peer->asChat()) {
|
||||
if (const auto count = chat->count; count > 0) {
|
||||
return tr::lng_chat_status_members(tr::now, lt_count, count);
|
||||
}
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
if (channel->membersCountKnown()) {
|
||||
return (channel->isBroadcast()
|
||||
? tr::lng_chat_status_subscribers
|
||||
: tr::lng_chat_status_members)(
|
||||
tr::now,
|
||||
lt_count,
|
||||
channel->membersCount());
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void SetupFilterLinks(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
not_null<Window::SessionController*> window,
|
||||
|
|
|
@ -36,10 +36,11 @@ void ExportFilterLink(
|
|||
Fn<void(Data::ChatFilterLink)> done,
|
||||
Fn<void(QString)> fail);
|
||||
|
||||
object_ptr<Ui::BoxContent> ShowLinkBox(
|
||||
[[nodiscard]] object_ptr<Ui::BoxContent> ShowLinkBox(
|
||||
not_null<Window::SessionController*> window,
|
||||
const Data::ChatFilter &filter,
|
||||
const Data::ChatFilterLink &link);
|
||||
[[nodiscard]] QString FilterChatStatusText(not_null<PeerData*> peer);
|
||||
|
||||
void SetupFilterLinks(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
|
|
|
@ -1354,6 +1354,9 @@ void Session::setupChannelLeavingViewer() {
|
|||
history->removeJoinedMessage();
|
||||
history->updateChatListExistence();
|
||||
history->updateChatListSortPosition();
|
||||
if (!history->inChatList()) {
|
||||
history->clearFolder();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, _lifetime);
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "settings/settings_folders.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_chat_filters.h" // ProcessFilterRemove.
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "boxes/filters/edit_filter_box.h"
|
||||
#include "core/application.h"
|
||||
|
@ -22,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lottie/lottie_icon.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/filter_icons.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/painter.h"
|
||||
|
@ -102,6 +104,10 @@ struct FilterRow {
|
|||
not_null<FilterRowButton*> button;
|
||||
Data::ChatFilter filter;
|
||||
bool removed = false;
|
||||
bool removeHasLinks = false;
|
||||
mtpRequestId removePeersRequestId = 0;
|
||||
std::vector<not_null<PeerData*>> suggestRemovePeers;
|
||||
std::vector<not_null<PeerData*>> removePeers;
|
||||
bool added = false;
|
||||
bool postponedCountUpdate = false;
|
||||
};
|
||||
|
@ -361,6 +367,81 @@ void FilterRowButton::paintEvent(QPaintEvent *e) {
|
|||
controller->show(Box(FiltersLimitBox, session));
|
||||
return true;
|
||||
};
|
||||
const auto markForRemovalSure = [=](not_null<FilterRowButton*> button) {
|
||||
const auto row = find(button);
|
||||
if (row->removed || row->removePeersRequestId > 0) {
|
||||
return;
|
||||
} else if (row->filter.community()
|
||||
&& !row->filter.always().empty()) {
|
||||
const auto chosen = crl::guard(button, [=](
|
||||
std::vector<not_null<PeerData*>> peers) {
|
||||
const auto row = find(button);
|
||||
row->removePeers = std::move(peers);
|
||||
row->removed = true;
|
||||
button->setRemoved(true);
|
||||
});
|
||||
Api::ProcessFilterRemove(
|
||||
controller,
|
||||
row->filter.title(),
|
||||
row->filter.iconEmoji(),
|
||||
row->filter.always() | ranges::views::transform(
|
||||
&History::peer
|
||||
) | ranges::to_vector,
|
||||
row->suggestRemovePeers,
|
||||
chosen);
|
||||
} else {
|
||||
row->removePeers = {};
|
||||
row->removed = true;
|
||||
button->setRemoved(true);
|
||||
}
|
||||
};
|
||||
const auto markForRemoval = [=](not_null<FilterRowButton*> button) {
|
||||
const auto row = find(button);
|
||||
if (row->removed || row->removePeersRequestId > 0) {
|
||||
return;
|
||||
} else if (row->filter.community() && row->removeHasLinks) {
|
||||
controller->show(Ui::MakeConfirmBox({
|
||||
.text = { tr::lng_filters_delete_sure(tr::now) },
|
||||
.confirmed = crl::guard(button, [=](Fn<void()> close) {
|
||||
markForRemovalSure(button);
|
||||
close();
|
||||
}),
|
||||
.confirmText = tr::lng_box_delete(),
|
||||
.confirmStyle = &st::attentionBoxButton,
|
||||
}));
|
||||
} else {
|
||||
markForRemovalSure(button);
|
||||
}
|
||||
};
|
||||
const auto remove = [=](not_null<FilterRowButton*> button) {
|
||||
const auto row = find(button);
|
||||
if (row->removed || row->removePeersRequestId > 0) {
|
||||
return;
|
||||
} else if (row->filter.community() && !row->removePeersRequestId) {
|
||||
row->removePeersRequestId = session->api().request(
|
||||
MTPcommunities_GetLeaveCommunitySuggestions(
|
||||
MTP_inputCommunityDialogFilter(
|
||||
MTP_int(row->filter.id())))
|
||||
).done(crl::guard(button, [=](const MTPVector<MTPPeer> &result) {
|
||||
const auto row = find(button);
|
||||
row->removePeersRequestId = -1;
|
||||
row->suggestRemovePeers = ranges::views::all(
|
||||
result.v
|
||||
) | ranges::views::transform([=](const MTPPeer &peer) {
|
||||
return session->data().peer(peerFromMTP(peer));
|
||||
}) | ranges::to_vector;
|
||||
row->removeHasLinks = true; // #TODO filters
|
||||
markForRemoval(button);
|
||||
})).fail(crl::guard(button, [=] {
|
||||
const auto row = find(button);
|
||||
row->removePeersRequestId = -1;
|
||||
row->removeHasLinks = false;
|
||||
markForRemoval(button);
|
||||
})).send();
|
||||
} else {
|
||||
markForRemoval(button);
|
||||
}
|
||||
};
|
||||
const auto wrap = container->add(object_ptr<Ui::VerticalLayout>(
|
||||
container));
|
||||
const auto addFilter = [=](const Data::ChatFilter &filter) {
|
||||
|
@ -368,8 +449,7 @@ void FilterRowButton::paintEvent(QPaintEvent *e) {
|
|||
object_ptr<FilterRowButton>(wrap, session, filter));
|
||||
button->removeRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
button->setRemoved(true);
|
||||
find(button)->removed = true;
|
||||
remove(button);
|
||||
}, button->lifetime());
|
||||
button->restoreRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
|
@ -562,6 +642,7 @@ void FilterRowButton::paintEvent(QPaintEvent *e) {
|
|||
auto updates = std::vector<MTPUpdate>();
|
||||
auto addRequests = std::vector<MTPmessages_UpdateDialogFilter>();
|
||||
auto removeRequests = std::vector<MTPmessages_UpdateDialogFilter>();
|
||||
auto removeCommunityRequests = std::vector<MTPcommunities_LeaveCommunity>();
|
||||
|
||||
auto &realFilters = session->data().chatsFilters();
|
||||
const auto &list = realFilters.list();
|
||||
|
@ -590,17 +671,32 @@ void FilterRowButton::paintEvent(QPaintEvent *e) {
|
|||
const auto tl = removed
|
||||
? MTPDialogFilter()
|
||||
: row.filter.tl(newId);
|
||||
const auto request = MTPmessages_UpdateDialogFilter(
|
||||
MTP_flags(removed
|
||||
? MTPmessages_UpdateDialogFilter::Flag(0)
|
||||
: MTPmessages_UpdateDialogFilter::Flag::f_filter),
|
||||
MTP_int(newId),
|
||||
tl);
|
||||
if (removed) {
|
||||
removeRequests.push_back(request);
|
||||
const auto removeCommunityWithChats = removed
|
||||
&& row.filter.community()
|
||||
&& !row.removePeers.empty();
|
||||
if (removeCommunityWithChats) {
|
||||
auto inputs = ranges::views::all(
|
||||
row.removePeers
|
||||
) | ranges::views::transform([](not_null<PeerData*> peer) {
|
||||
return MTPInputPeer(peer->input);
|
||||
}) | ranges::to<QVector>();
|
||||
removeCommunityRequests.push_back(
|
||||
MTPcommunities_LeaveCommunity(
|
||||
MTP_inputCommunityDialogFilter(MTP_int(newId)),
|
||||
MTP_vector<MTPInputPeer>(std::move(inputs))));
|
||||
} else {
|
||||
addRequests.push_back(request);
|
||||
order.push_back(newId);
|
||||
const auto request = MTPmessages_UpdateDialogFilter(
|
||||
MTP_flags(removed
|
||||
? MTPmessages_UpdateDialogFilter::Flag(0)
|
||||
: MTPmessages_UpdateDialogFilter::Flag::f_filter),
|
||||
MTP_int(newId),
|
||||
tl);
|
||||
if (removed) {
|
||||
removeRequests.push_back(request);
|
||||
} else {
|
||||
addRequests.push_back(request);
|
||||
order.push_back(newId);
|
||||
}
|
||||
}
|
||||
updates.push_back(MTP_updateDialogFilter(
|
||||
MTP_flags(removed
|
||||
|
@ -629,7 +725,8 @@ void FilterRowButton::paintEvent(QPaintEvent *e) {
|
|||
order = std::move(order),
|
||||
updates = std::move(updates),
|
||||
addRequests = std::move(addRequests),
|
||||
removeRequests = std::move(removeRequests)
|
||||
removeRequests = std::move(removeRequests),
|
||||
removeCommunityRequests = std::move(removeCommunityRequests)
|
||||
] {
|
||||
const auto api = &session->api();
|
||||
const auto filters = &session->data().chatsFilters();
|
||||
|
@ -646,18 +743,25 @@ void FilterRowButton::paintEvent(QPaintEvent *e) {
|
|||
filters->apply(update);
|
||||
}
|
||||
auto previousId = mtpRequestId(0);
|
||||
auto &&requests = ranges::views::concat(
|
||||
removeRequests,
|
||||
addRequests);
|
||||
for (auto &request : requests) {
|
||||
previousId = api->request(
|
||||
std::move(request)
|
||||
).done([=](const auto &, mtpRequestId id) {
|
||||
ids->remove(id);
|
||||
checkFinished();
|
||||
}).afterRequest(previousId).send();
|
||||
ids->emplace(previousId);
|
||||
}
|
||||
const auto sendRequests = [&](const auto &requests) {
|
||||
for (auto &request : requests) {
|
||||
previousId = api->request(
|
||||
std::move(request)
|
||||
).done([=](const auto &result, mtpRequestId id) {
|
||||
if constexpr (std::is_same_v<
|
||||
std::decay_t<decltype(result)>,
|
||||
MTPUpdates>) {
|
||||
session->api().applyUpdates(result);
|
||||
}
|
||||
ids->remove(id);
|
||||
checkFinished();
|
||||
}).afterRequest(previousId).send();
|
||||
ids->emplace(previousId);
|
||||
}
|
||||
};
|
||||
sendRequests(removeRequests);
|
||||
sendRequests(removeCommunityRequests);
|
||||
sendRequests(addRequests);
|
||||
if (!order.empty() && !addRequests.empty()) {
|
||||
filters->saveOrder(order, previousId);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue