864 lines
22 KiB
C++
864 lines
22 KiB
C++
/*
|
|
This file is part of Telegram Desktop,
|
|
the official desktop application for the Telegram messaging service.
|
|
|
|
For license and copyright information please follow this link:
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
*/
|
|
#include "window/window_peer_menu.h"
|
|
|
|
#include "lang/lang_keys.h"
|
|
#include "boxes/confirm_box.h"
|
|
#include "boxes/mute_settings_box.h"
|
|
#include "boxes/add_contact_box.h"
|
|
#include "boxes/report_box.h"
|
|
#include "boxes/create_poll_box.h"
|
|
#include "boxes/peer_list_controllers.h"
|
|
#include "boxes/peers/manage_peer_box.h"
|
|
#include "boxes/peers/edit_peer_info_box.h"
|
|
#include "ui/toast/toast.h"
|
|
#include "core/tl_help.h"
|
|
#include "auth_session.h"
|
|
#include "apiwrap.h"
|
|
#include "mainwidget.h"
|
|
#include "mainwindow.h"
|
|
#include "observer_peer.h"
|
|
#include "styles/style_boxes.h"
|
|
#include "history/history.h"
|
|
#include "window/window_controller.h"
|
|
#include "support/support_helper.h"
|
|
#include "info/info_memento.h"
|
|
#include "info/info_controller.h"
|
|
#include "info/feed/info_feed_channels_controllers.h"
|
|
#include "info/profile/info_profile_values.h"
|
|
#include "data/data_session.h"
|
|
#include "data/data_feed.h"
|
|
#include "data/data_poll.h"
|
|
#include "data/data_channel.h"
|
|
#include "data/data_chat.h"
|
|
#include "data/data_user.h"
|
|
#include "dialogs/dialogs_key.h"
|
|
|
|
namespace Window {
|
|
namespace {
|
|
|
|
class Filler {
|
|
public:
|
|
Filler(
|
|
not_null<Controller*> controller,
|
|
not_null<PeerData*> peer,
|
|
const PeerMenuCallback &addAction,
|
|
PeerMenuSource source);
|
|
void fill();
|
|
|
|
private:
|
|
bool showInfo();
|
|
void addPinToggle();
|
|
void addInfo();
|
|
void addSearch();
|
|
void addToggleUnreadMark();
|
|
void addUserActions(not_null<UserData*> user);
|
|
void addBlockUser(not_null<UserData*> user);
|
|
void addChatActions(not_null<ChatData*> chat);
|
|
void addChannelActions(not_null<ChannelData*> channel);
|
|
|
|
not_null<Controller*> _controller;
|
|
not_null<PeerData*> _peer;
|
|
const PeerMenuCallback &_addAction;
|
|
PeerMenuSource _source;
|
|
|
|
};
|
|
|
|
class FeedFiller {
|
|
public:
|
|
FeedFiller(
|
|
not_null<Controller*> controller,
|
|
not_null<Data::Feed*> feed,
|
|
const PeerMenuCallback &addAction,
|
|
PeerMenuSource source);
|
|
void fill();
|
|
|
|
private:
|
|
bool showInfo();
|
|
void addPinToggle();
|
|
void addInfo();
|
|
void addSearch();
|
|
void addNotifications();
|
|
void addUngroup();
|
|
|
|
not_null<Controller*> _controller;
|
|
not_null<Data::Feed*> _feed;
|
|
const PeerMenuCallback &_addAction;
|
|
PeerMenuSource _source;
|
|
|
|
};
|
|
|
|
History *FindWastedPin() {
|
|
const auto &order = Auth().data().pinnedDialogsOrder();
|
|
for (const auto pinned : order) {
|
|
if (const auto history = pinned.history()) {
|
|
if (history->peer->isChat()
|
|
&& history->peer->asChat()->isDeactivated()
|
|
&& !history->inChatList(Dialogs::Mode::All)) {
|
|
return history;
|
|
}
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void AddChatMembers(not_null<ChatData*> chat) {
|
|
if (chat->count >= Global::ChatSizeMax() && chat->amCreator()) {
|
|
Ui::show(Box<ConvertToSupergroupBox>(chat));
|
|
} else {
|
|
AddParticipantsBoxController::Start(chat);
|
|
}
|
|
}
|
|
|
|
bool PinnedLimitReached(Dialogs::Key key) {
|
|
const auto pinnedCount = Auth().data().pinnedDialogsCount();
|
|
const auto pinnedMax = Global::PinnedDialogsCountMax();
|
|
if (pinnedCount < pinnedMax) {
|
|
return false;
|
|
}
|
|
// Some old chat, that was converted, maybe is still pinned.
|
|
if (auto wasted = FindWastedPin()) {
|
|
Auth().data().setPinnedDialog(wasted, false);
|
|
Auth().data().setPinnedDialog(key, true);
|
|
Auth().api().savePinnedOrder();
|
|
} else {
|
|
auto errorText = lng_error_pinned_max(
|
|
lt_count,
|
|
pinnedMax);
|
|
Ui::show(Box<InformBox>(errorText));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void TogglePinnedDialog(Dialogs::Key key) {
|
|
const auto isPinned = !key.entry()->isPinnedDialog();
|
|
if (isPinned && PinnedLimitReached(key)) {
|
|
return;
|
|
}
|
|
|
|
Auth().data().setPinnedDialog(key, isPinned);
|
|
auto flags = MTPmessages_ToggleDialogPin::Flags(0);
|
|
if (isPinned) {
|
|
flags |= MTPmessages_ToggleDialogPin::Flag::f_pinned;
|
|
}
|
|
//MTP::send(MTPmessages_ToggleDialogPin( // #feed
|
|
// MTP_flags(flags),
|
|
// key.history()
|
|
// ? MTP_inputDialogPeer(key.history()->peer->input)
|
|
// : MTP_inputDialogPeerFeed(MTP_int(key.feed()->id()))));
|
|
if (key.history()) {
|
|
MTP::send(MTPmessages_ToggleDialogPin(
|
|
MTP_flags(flags),
|
|
MTP_inputDialogPeer(key.history()->peer->input)));
|
|
}
|
|
if (isPinned) {
|
|
if (const auto main = App::main()) {
|
|
main->dialogsToUp();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
Filler::Filler(
|
|
not_null<Controller*> controller,
|
|
not_null<PeerData*> peer,
|
|
const PeerMenuCallback &addAction,
|
|
PeerMenuSource source)
|
|
: _controller(controller)
|
|
, _peer(peer)
|
|
, _addAction(addAction)
|
|
, _source(source) {
|
|
}
|
|
|
|
bool Filler::showInfo() {
|
|
if (_source == PeerMenuSource::Profile || _peer->isSelf()) {
|
|
return false;
|
|
} else if (_controller->activeChatCurrent().peer() != _peer) {
|
|
return true;
|
|
} else if (!Adaptive::ThreeColumn()) {
|
|
return true;
|
|
} else if (
|
|
!Auth().settings().thirdSectionInfoEnabled() &&
|
|
!Auth().settings().tabbedReplacedWithInfo()) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Filler::addPinToggle() {
|
|
auto peer = _peer;
|
|
auto isPinned = false;
|
|
if (auto history = App::historyLoaded(peer)) {
|
|
isPinned = history->isPinnedDialog();
|
|
}
|
|
auto pinText = [](bool isPinned) {
|
|
return lang(isPinned
|
|
? lng_context_unpin_from_top
|
|
: lng_context_pin_to_top);
|
|
};
|
|
auto pinToggle = [=] {
|
|
TogglePinnedDialog(App::history(peer));
|
|
};
|
|
auto pinAction = _addAction(pinText(isPinned), pinToggle);
|
|
|
|
const auto lifetime = Ui::CreateChild<rpl::lifetime>(pinAction);
|
|
Notify::PeerUpdateViewer(
|
|
peer,
|
|
Notify::PeerUpdate::Flag::ChatPinnedChanged
|
|
) | rpl::start_with_next([peer, pinAction, pinText] {
|
|
auto isPinned = App::history(peer)->isPinnedDialog();
|
|
pinAction->setText(pinText(isPinned));
|
|
}, *lifetime);
|
|
}
|
|
|
|
void Filler::addInfo() {
|
|
auto controller = _controller;
|
|
auto peer = _peer;
|
|
auto infoKey = (peer->isChat() || peer->isMegagroup())
|
|
? lng_context_view_group
|
|
: (peer->isUser()
|
|
? lng_context_view_profile
|
|
: lng_context_view_channel);
|
|
_addAction(lang(infoKey), [=] {
|
|
controller->showPeerInfo(peer);
|
|
});
|
|
}
|
|
|
|
void Filler::addSearch() {
|
|
_addAction(lang(lng_profile_search_messages), [peer = _peer] {
|
|
App::main()->searchInChat(App::history(peer));
|
|
});
|
|
}
|
|
|
|
void Filler::addToggleUnreadMark() {
|
|
const auto peer = _peer;
|
|
const auto isUnread = [](not_null<PeerData*> peer) {
|
|
if (const auto history = App::historyLoaded(peer)) {
|
|
return (history->chatListUnreadCount() > 0)
|
|
|| (history->chatListUnreadMark());
|
|
}
|
|
return false;
|
|
};
|
|
const auto label = [=](not_null<PeerData*> peer) {
|
|
return lang(isUnread(peer)
|
|
? lng_context_mark_read
|
|
: lng_context_mark_unread);
|
|
};
|
|
auto action = _addAction(label(peer), [=] {
|
|
const auto markAsRead = isUnread(peer);
|
|
const auto handle = [&](not_null<History*> history) {
|
|
if (markAsRead) {
|
|
Auth().api().readServerHistory(history);
|
|
} else {
|
|
Auth().api().changeDialogUnreadMark(history, !markAsRead);
|
|
}
|
|
};
|
|
const auto history = App::history(peer);
|
|
handle(history);
|
|
if (markAsRead) {
|
|
if (const auto migrated = history->migrateSibling()) {
|
|
handle(migrated);
|
|
}
|
|
}
|
|
});
|
|
|
|
const auto lifetime = Ui::CreateChild<rpl::lifetime>(action);
|
|
Notify::PeerUpdateViewer(
|
|
_peer,
|
|
Notify::PeerUpdate::Flag::UnreadViewChanged
|
|
) | rpl::start_with_next([=] {
|
|
action->setText(label(peer));
|
|
}, *lifetime);
|
|
}
|
|
|
|
void Filler::addBlockUser(not_null<UserData*> user) {
|
|
auto blockText = [](not_null<UserData*> user) {
|
|
return lang(user->isBlocked()
|
|
? (user->botInfo
|
|
? lng_profile_restart_bot
|
|
: lng_profile_unblock_user)
|
|
: (user->botInfo
|
|
? lng_profile_block_bot
|
|
: lng_profile_block_user));
|
|
};
|
|
auto blockAction = _addAction(blockText(user), [=] {
|
|
if (user->isBlocked()) {
|
|
Auth().api().unblockUser(user);
|
|
} else {
|
|
Auth().api().blockUser(user);
|
|
}
|
|
});
|
|
|
|
const auto lifetime = Ui::CreateChild<rpl::lifetime>(blockAction);
|
|
Notify::PeerUpdateViewer(
|
|
_peer,
|
|
Notify::PeerUpdate::Flag::UserIsBlocked
|
|
) | rpl::start_with_next([=] {
|
|
blockAction->setText(blockText(user));
|
|
}, *lifetime);
|
|
|
|
if (user->blockStatus() == UserData::BlockStatus::Unknown) {
|
|
Auth().api().requestFullPeer(user);
|
|
}
|
|
}
|
|
|
|
void Filler::addUserActions(not_null<UserData*> user) {
|
|
if (_source != PeerMenuSource::ChatsList) {
|
|
if (Auth().supportMode()) {
|
|
_addAction("Edit support info", [=] {
|
|
Auth().supportHelper().editInfo(user);
|
|
});
|
|
}
|
|
if (user->isContact()) {
|
|
if (!user->isSelf()) {
|
|
_addAction(
|
|
lang(lng_info_share_contact),
|
|
[user] { PeerMenuShareContactBox(user); });
|
|
_addAction(
|
|
lang(lng_info_edit_contact),
|
|
[user] { Ui::show(Box<AddContactBox>(user)); });
|
|
_addAction(
|
|
lang(lng_info_delete_contact),
|
|
[user] { PeerMenuDeleteContact(user); });
|
|
}
|
|
} else if (user->canShareThisContact()) {
|
|
if (!user->isSelf()) {
|
|
_addAction(
|
|
lang(lng_info_add_as_contact),
|
|
[user] { PeerMenuAddContact(user); });
|
|
}
|
|
_addAction(
|
|
lang(lng_info_share_contact),
|
|
[user] { PeerMenuShareContactBox(user); });
|
|
} else if (user->botInfo && !user->botInfo->cantJoinGroups) {
|
|
_addAction(
|
|
lang(lng_profile_invite_to_group),
|
|
[user] { AddBotToGroupBoxController::Start(user); });
|
|
}
|
|
_addAction(
|
|
lang(lng_profile_export_chat),
|
|
[=] { PeerMenuExportChat(user); });
|
|
}
|
|
_addAction(
|
|
lang(lng_profile_delete_conversation),
|
|
DeleteAndLeaveHandler(user));
|
|
_addAction(
|
|
lang(lng_profile_clear_history),
|
|
ClearHistoryHandler(user));
|
|
if (!user->isInaccessible() && user != Auth().user()) {
|
|
addBlockUser(user);
|
|
}
|
|
}
|
|
|
|
void Filler::addChatActions(not_null<ChatData*> chat) {
|
|
if (_source != PeerMenuSource::ChatsList) {
|
|
if (ManagePeerBox::Available(chat)) {
|
|
const auto text = lang(lng_manage_group_title);
|
|
_addAction(text, [=] {
|
|
Ui::show(Box<ManagePeerBox>(chat));
|
|
});
|
|
}
|
|
if (chat->canAddMembers()) {
|
|
_addAction(
|
|
lang(lng_profile_add_participant),
|
|
[chat] { AddChatMembers(chat); });
|
|
}
|
|
if (chat->canWrite()) {
|
|
_addAction(
|
|
lang(lng_polls_create),
|
|
[=] { PeerMenuCreatePoll(chat); });
|
|
}
|
|
_addAction(
|
|
lang(lng_profile_export_chat),
|
|
[=] { PeerMenuExportChat(chat); });
|
|
}
|
|
_addAction(
|
|
lang(lng_profile_clear_and_exit),
|
|
DeleteAndLeaveHandler(_peer));
|
|
_addAction(
|
|
lang(lng_profile_clear_history),
|
|
ClearHistoryHandler(_peer));
|
|
}
|
|
|
|
void Filler::addChannelActions(not_null<ChannelData*> channel) {
|
|
auto isGroup = channel->isMegagroup();
|
|
if (!isGroup) {
|
|
const auto feed = channel->feed();
|
|
const auto grouped = (feed != nullptr);
|
|
if (!grouped || feed->channels().size() > 1) {
|
|
//_addAction( // #feed
|
|
// lang(grouped ? lng_feed_ungroup : lng_feed_group),
|
|
// [=] { ToggleChannelGrouping(channel, !grouped); });
|
|
}
|
|
}
|
|
if (_source != PeerMenuSource::ChatsList) {
|
|
if (ManagePeerBox::Available(channel)) {
|
|
const auto text = lang(isGroup
|
|
? lng_manage_group_title
|
|
: lng_manage_channel_title);
|
|
_addAction(text, [channel] {
|
|
Ui::show(Box<ManagePeerBox>(channel));
|
|
});
|
|
}
|
|
if (channel->canAddMembers()) {
|
|
_addAction(
|
|
lang(lng_channel_add_members),
|
|
[channel] { PeerMenuAddChannelMembers(channel); });
|
|
}
|
|
if (channel->canWrite()) {
|
|
_addAction(
|
|
lang(lng_polls_create),
|
|
[=] { PeerMenuCreatePoll(channel); });
|
|
}
|
|
_addAction(
|
|
lang(isGroup
|
|
? lng_profile_export_chat
|
|
: lng_profile_export_channel),
|
|
[=] { PeerMenuExportChat(channel); });
|
|
}
|
|
if (channel->amIn()) {
|
|
if (isGroup && !channel->isPublic()) {
|
|
_addAction(
|
|
lang(lng_profile_clear_history),
|
|
ClearHistoryHandler(channel));
|
|
}
|
|
auto text = lang(isGroup
|
|
? lng_profile_leave_group
|
|
: lng_profile_leave_channel);
|
|
_addAction(text, DeleteAndLeaveHandler(channel));
|
|
} else {
|
|
auto text = lang(isGroup
|
|
? lng_profile_join_group
|
|
: lng_profile_join_channel);
|
|
_addAction(
|
|
text,
|
|
[channel] { Auth().api().joinChannel(channel); });
|
|
}
|
|
if (_source != PeerMenuSource::ChatsList) {
|
|
auto needReport = !channel->amCreator()
|
|
&& (!isGroup || channel->isPublic());
|
|
if (needReport) {
|
|
_addAction(lang(lng_profile_report), [channel] {
|
|
Ui::show(Box<ReportBox>(channel));
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
void Filler::fill() {
|
|
if (_source == PeerMenuSource::ChatsList) {
|
|
if (const auto history = App::historyLoaded(_peer)) {
|
|
if (!history->useProxyPromotion()) {
|
|
addPinToggle();
|
|
}
|
|
}
|
|
}
|
|
if (showInfo()) {
|
|
addInfo();
|
|
}
|
|
if (_source != PeerMenuSource::Profile && !_peer->isSelf()) {
|
|
PeerMenuAddMuteAction(_peer, _addAction);
|
|
}
|
|
if (_source == PeerMenuSource::ChatsList) {
|
|
addSearch();
|
|
addToggleUnreadMark();
|
|
}
|
|
|
|
if (const auto user = _peer->asUser()) {
|
|
addUserActions(user);
|
|
} else if (const auto chat = _peer->asChat()) {
|
|
addChatActions(chat);
|
|
} else if (const auto channel = _peer->asChannel()) {
|
|
addChannelActions(channel);
|
|
}
|
|
}
|
|
|
|
FeedFiller::FeedFiller(
|
|
not_null<Controller*> controller,
|
|
not_null<Data::Feed*> feed,
|
|
const PeerMenuCallback &addAction,
|
|
PeerMenuSource source)
|
|
: _controller(controller)
|
|
, _feed(feed)
|
|
, _addAction(addAction)
|
|
, _source(source) {
|
|
}
|
|
|
|
void FeedFiller::fill() {
|
|
if (_source == PeerMenuSource::ChatsList) {
|
|
addPinToggle();
|
|
}
|
|
if (showInfo()) {
|
|
addInfo();
|
|
}
|
|
addNotifications();
|
|
if (_source == PeerMenuSource::ChatsList) {
|
|
addSearch();
|
|
}
|
|
addUngroup();
|
|
}
|
|
|
|
bool FeedFiller::showInfo() {
|
|
if (_source == PeerMenuSource::Profile) {
|
|
return false;
|
|
} else if (_controller->activeChatCurrent().feed() != _feed) {
|
|
return true;
|
|
} else if (!Adaptive::ThreeColumn()) {
|
|
return true;
|
|
} else if (
|
|
!Auth().settings().thirdSectionInfoEnabled() &&
|
|
!Auth().settings().tabbedReplacedWithInfo()) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void FeedFiller::addPinToggle() {
|
|
const auto feed = _feed;
|
|
const auto isPinned = feed->isPinnedDialog();
|
|
const auto pinText = [](bool isPinned) {
|
|
return lang(isPinned
|
|
? lng_context_unpin_from_top
|
|
: lng_context_pin_to_top);
|
|
};
|
|
_addAction(pinText(isPinned), [=] {
|
|
TogglePinnedDialog(feed);
|
|
});
|
|
}
|
|
|
|
void FeedFiller::addInfo() {
|
|
auto controller = _controller;
|
|
auto feed = _feed;
|
|
_addAction(lang(lng_context_view_feed_info), [=] {
|
|
controller->showSection(Info::Memento(
|
|
feed,
|
|
Info::Section(Info::Section::Type::Profile)));
|
|
});
|
|
}
|
|
|
|
void FeedFiller::addNotifications() {
|
|
const auto feed = _feed;
|
|
_addAction(lang(lng_feed_notifications), [=] {
|
|
Info::FeedProfile::NotificationsController::Start(feed);
|
|
});
|
|
}
|
|
|
|
void FeedFiller::addSearch() {
|
|
const auto feed = _feed;
|
|
_addAction(lang(lng_profile_search_messages), [=] {
|
|
App::main()->searchInChat(feed);
|
|
});
|
|
}
|
|
|
|
void FeedFiller::addUngroup() {
|
|
const auto feed = _feed;
|
|
//_addAction(lang(lng_feed_ungroup_all), [=] { // #feed
|
|
// PeerMenuUngroupFeed(feed);
|
|
//});
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void PeerMenuExportChat(not_null<PeerData*> peer) {
|
|
Auth().data().startExport(peer);
|
|
}
|
|
|
|
void PeerMenuDeleteContact(not_null<UserData*> user) {
|
|
auto text = lng_sure_delete_contact(
|
|
lt_contact,
|
|
App::peerName(user));
|
|
auto deleteSure = [=] {
|
|
Ui::hideLayer();
|
|
MTP::send(
|
|
MTPcontacts_DeleteContact(user->inputUser),
|
|
App::main()->rpcDone(
|
|
&MainWidget::deletedContact,
|
|
user.get()));
|
|
};
|
|
auto box = Box<ConfirmBox>(
|
|
text,
|
|
lang(lng_box_delete),
|
|
std::move(deleteSure));
|
|
Ui::show(std::move(box));
|
|
}
|
|
|
|
void PeerMenuAddContact(not_null<UserData*> user) {
|
|
Ui::show(Box<AddContactBox>(
|
|
user->firstName,
|
|
user->lastName,
|
|
Auth().data().findContactPhone(user)));
|
|
}
|
|
|
|
void PeerMenuShareContactBox(not_null<UserData*> user) {
|
|
const auto weak = std::make_shared<QPointer<PeerListBox>>();
|
|
auto callback = [=](not_null<PeerData*> peer) {
|
|
if (!peer->canWrite()) {
|
|
Ui::show(Box<InformBox>(
|
|
lang(lng_forward_share_cant)),
|
|
LayerOption::KeepOther);
|
|
return;
|
|
} else if (peer->isSelf()) {
|
|
auto options = ApiWrap::SendOptions(App::history(peer));
|
|
Auth().api().shareContact(user, options);
|
|
Ui::Toast::Show(lang(lng_share_done));
|
|
if (auto strong = *weak) {
|
|
strong->closeBox();
|
|
}
|
|
return;
|
|
}
|
|
auto recipient = peer->isUser()
|
|
? peer->name
|
|
: '\xAB' + peer->name + '\xBB';
|
|
Ui::show(Box<ConfirmBox>(
|
|
lng_forward_share_contact(lt_recipient, recipient),
|
|
lang(lng_forward_send),
|
|
[peer, user] {
|
|
const auto history = App::history(peer);
|
|
Ui::showPeerHistory(history, ShowAtTheEndMsgId);
|
|
auto options = ApiWrap::SendOptions(history);
|
|
Auth().api().shareContact(user, options);
|
|
}), LayerOption::KeepOther);
|
|
};
|
|
*weak = Ui::show(Box<PeerListBox>(
|
|
std::make_unique<ChooseRecipientBoxController>(std::move(callback)),
|
|
[](not_null<PeerListBox*> box) {
|
|
box->addButton(langFactory(lng_cancel), [box] {
|
|
box->closeBox();
|
|
});
|
|
}));
|
|
}
|
|
|
|
void PeerMenuCreatePoll(not_null<PeerData*> peer) {
|
|
const auto box = Ui::show(Box<CreatePollBox>());
|
|
const auto lock = box->lifetime().make_state<bool>(false);
|
|
box->submitRequests(
|
|
) | rpl::start_with_next([=](const PollData &result) {
|
|
if (std::exchange(*lock, true)) {
|
|
return;
|
|
}
|
|
const auto options = ApiWrap::SendOptions(App::history(peer));
|
|
Auth().api().createPoll(result, options, crl::guard(box, [=] {
|
|
box->closeBox();
|
|
}), crl::guard(box, [=](const RPCError &error) {
|
|
*lock = false;
|
|
box->submitFailed(lang(lng_attach_failed));
|
|
}));
|
|
}, box->lifetime());
|
|
}
|
|
|
|
QPointer<Ui::RpWidget> ShowForwardMessagesBox(
|
|
MessageIdsList &&items,
|
|
FnMut<void()> &&successCallback) {
|
|
const auto weak = std::make_shared<QPointer<PeerListBox>>();
|
|
auto callback = [
|
|
ids = std::move(items),
|
|
callback = std::move(successCallback),
|
|
weak
|
|
](not_null<PeerData*> peer) mutable {
|
|
if (peer->isSelf()) {
|
|
auto items = Auth().data().idsToItems(ids);
|
|
if (!items.empty()) {
|
|
auto options = ApiWrap::SendOptions(App::history(peer));
|
|
options.generateLocal = false;
|
|
Auth().api().forwardMessages(std::move(items), options, [] {
|
|
Ui::Toast::Show(lang(lng_share_done));
|
|
});
|
|
}
|
|
} else {
|
|
App::main()->setForwardDraft(peer->id, std::move(ids));
|
|
}
|
|
if (const auto strong = *weak) {
|
|
strong->closeBox();
|
|
}
|
|
if (callback) {
|
|
callback();
|
|
}
|
|
};
|
|
auto initBox = [](not_null<PeerListBox*> box) {
|
|
box->addButton(langFactory(lng_cancel), [box] {
|
|
box->closeBox();
|
|
});
|
|
};
|
|
*weak = Ui::show(Box<PeerListBox>(
|
|
std::make_unique<ChooseRecipientBoxController>(std::move(callback)),
|
|
std::move(initBox)), LayerOption::KeepOther);
|
|
return weak->data();
|
|
}
|
|
|
|
void PeerMenuAddChannelMembers(not_null<ChannelData*> channel) {
|
|
if (!channel->isMegagroup()
|
|
&& channel->membersCount() >= Global::ChatSizeMax()) {
|
|
Ui::show(
|
|
Box<MaxInviteBox>(channel),
|
|
LayerOption::KeepOther);
|
|
return;
|
|
}
|
|
auto callback = [channel](const MTPchannels_ChannelParticipants &result) {
|
|
Auth().api().parseChannelParticipants(channel, result, [&](
|
|
int availableCount,
|
|
const QVector<MTPChannelParticipant> &list) {
|
|
auto already = (
|
|
list
|
|
) | ranges::view::transform([&](auto &&p) {
|
|
return TLHelp::ReadChannelParticipantUserId(p);
|
|
}) | ranges::view::transform([](UserId userId) {
|
|
return App::userLoaded(userId);
|
|
}) | ranges::view::filter([](UserData *user) {
|
|
return (user != nullptr);
|
|
}) | ranges::to_vector;
|
|
|
|
AddParticipantsBoxController::Start(
|
|
channel,
|
|
{ already.begin(), already.end() });
|
|
});
|
|
};
|
|
Auth().api().requestChannelMembersForAdd(channel, callback);
|
|
}
|
|
|
|
void PeerMenuAddMuteAction(
|
|
not_null<PeerData*> peer,
|
|
const PeerMenuCallback &addAction) {
|
|
Auth().data().requestNotifySettings(peer);
|
|
const auto muteText = [](bool isMuted) {
|
|
return lang(isMuted
|
|
? lng_enable_notifications_from_tray
|
|
: lng_disable_notifications_from_tray);
|
|
};
|
|
const auto muteAction = addAction(QString("-"), [=] {
|
|
if (!Auth().data().notifyIsMuted(peer)) {
|
|
Ui::show(Box<MuteSettingsBox>(peer));
|
|
} else {
|
|
Auth().data().updateNotifySettings(peer, 0);
|
|
}
|
|
});
|
|
|
|
const auto lifetime = Ui::CreateChild<rpl::lifetime>(muteAction);
|
|
Info::Profile::NotificationsEnabledValue(
|
|
peer
|
|
) | rpl::start_with_next([=](bool enabled) {
|
|
muteAction->setText(muteText(!enabled));
|
|
}, *lifetime);
|
|
}
|
|
// #feed
|
|
//void PeerMenuUngroupFeed(not_null<Data::Feed*> feed) {
|
|
// Ui::show(Box<ConfirmBox>(
|
|
// lang(lng_feed_sure_ungroup_all),
|
|
// lang(lng_feed_ungroup_sure),
|
|
// [=] { Ui::hideLayer(); Auth().api().ungroupAllFromFeed(feed); }));
|
|
//}
|
|
//
|
|
//void ToggleChannelGrouping(not_null<ChannelData*> channel, bool group) {
|
|
// const auto callback = [=] {
|
|
// Ui::Toast::Show(lang(group
|
|
// ? lng_feed_channel_added
|
|
// : lng_feed_channel_removed));
|
|
// };
|
|
// if (group) {
|
|
// const auto feed = Auth().data().feed(Data::Feed::kId);
|
|
// if (feed->channels().size() < 2) {
|
|
// Info::FeedProfile::EditController::Start(feed, channel);
|
|
// return;
|
|
// }
|
|
// }
|
|
// Auth().api().toggleChannelGrouping(
|
|
// channel,
|
|
// group,
|
|
// callback);
|
|
//}
|
|
|
|
Fn<void()> ClearHistoryHandler(not_null<PeerData*> peer) {
|
|
return [peer] {
|
|
const auto weak = std::make_shared<QPointer<ConfirmBox>>();
|
|
const auto text = peer->isSelf()
|
|
? lang(lng_sure_delete_saved_messages)
|
|
: peer->isUser()
|
|
? lng_sure_delete_history(lt_contact, peer->name)
|
|
: lng_sure_delete_group_history(lt_group, peer->name);
|
|
auto callback = [=] {
|
|
if (auto strong = *weak) {
|
|
strong->closeBox();
|
|
}
|
|
Auth().api().clearHistory(peer);
|
|
};
|
|
*weak = Ui::show(
|
|
Box<ConfirmBox>(
|
|
text,
|
|
lang(lng_box_delete),
|
|
st::attentionBoxButton,
|
|
std::move(callback)),
|
|
LayerOption::KeepOther);
|
|
};
|
|
}
|
|
|
|
Fn<void()> DeleteAndLeaveHandler(not_null<PeerData*> peer) {
|
|
return [peer] {
|
|
const auto warningText = peer->isSelf()
|
|
? lang(lng_sure_delete_saved_messages)
|
|
: peer->isUser()
|
|
? lng_sure_delete_history(lt_contact, peer->name)
|
|
: peer->isChat()
|
|
? lng_sure_delete_and_exit(lt_group, peer->name)
|
|
: lang(peer->isMegagroup()
|
|
? lng_sure_leave_group
|
|
: lng_sure_leave_channel);
|
|
const auto confirmText = lang(peer->isUser()
|
|
? lng_box_delete
|
|
: lng_box_leave);
|
|
const auto &confirmStyle = peer->isChannel()
|
|
? st::defaultBoxButton
|
|
: st::attentionBoxButton;
|
|
auto callback = [peer] {
|
|
Ui::hideLayer();
|
|
const auto controller = App::wnd()->controller();
|
|
if (controller->activeChatCurrent().peer() == peer) {
|
|
Ui::showChatsList();
|
|
}
|
|
if (peer->isUser()) {
|
|
App::main()->deleteConversation(peer);
|
|
} else if (const auto chat = peer->asChat()) {
|
|
App::main()->deleteAndExit(chat);
|
|
} else if (const auto channel = peer->asChannel()) {
|
|
// Don't delete old history by default,
|
|
// because Android app doesn't.
|
|
//
|
|
//if (auto migrateFrom = channel->migrateFrom()) {
|
|
// App::main()->deleteConversation(migrateFrom);
|
|
//}
|
|
Auth().api().leaveChannel(channel);
|
|
}
|
|
};
|
|
Ui::show(
|
|
Box<ConfirmBox>(
|
|
warningText,
|
|
confirmText,
|
|
confirmStyle,
|
|
std::move(callback)),
|
|
LayerOption::KeepOther);
|
|
};
|
|
}
|
|
|
|
void FillPeerMenu(
|
|
not_null<Controller*> controller,
|
|
not_null<PeerData*> peer,
|
|
const PeerMenuCallback &callback,
|
|
PeerMenuSource source) {
|
|
Filler filler(controller, peer, callback, source);
|
|
filler.fill();
|
|
}
|
|
|
|
void FillFeedMenu(
|
|
not_null<Controller*> controller,
|
|
not_null<Data::Feed*> feed,
|
|
const PeerMenuCallback &callback,
|
|
PeerMenuSource source) {
|
|
FeedFiller filler(controller, feed, callback, source);
|
|
filler.fill();
|
|
}
|
|
|
|
} // namespace Window
|