/* 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 "menu/menu_send.h" #include "api/api_common.h" #include "base/event_filter.h" #include "boxes/abstract_box.h" #include "core/shortcuts.h" #include "history/view/history_view_schedule_box.h" #include "lang/lang_keys.h" #include "ui/widgets/popup_menu.h" #include "data/data_peer.h" #include "data/data_session.h" #include "main/main_session.h" #include "history/history.h" #include "history/history_unread_things.h" #include "apiwrap.h" #include "styles/style_menu_icons.h" #include namespace SendMenu { Fn DefaultSilentCallback(Fn send) { return [=] { send({ .silent = true }); }; } Fn DefaultScheduleCallback( not_null parent, Type type, Fn send) { const auto weak = Ui::MakeWeak(parent); return [=] { Ui::show( HistoryView::PrepareScheduleBox( weak, type, [=](Api::SendOptions options) { send(options); }), Ui::LayerOption::KeepOther); }; } FillMenuResult FillSendMenu( not_null menu, Type type, Fn silent, Fn schedule) { if (!silent && !schedule) { return FillMenuResult::None; } const auto now = type; if (now == Type::Disabled || (!silent && now == Type::SilentOnly)) { return FillMenuResult::None; } if (silent && now != Type::Reminder) { menu->addAction( tr::lng_send_silent_message(tr::now), silent, &st::menuIconMute); } if (schedule && now != Type::SilentOnly) { menu->addAction( (now == Type::Reminder ? tr::lng_reminder_message(tr::now) : tr::lng_schedule_message(tr::now)), schedule, &st::menuIconSchedule); } return FillMenuResult::Success; } void SetupMenuAndShortcuts( not_null button, Fn type, Fn silent, Fn schedule) { if (!silent && !schedule) { return; } const auto menu = std::make_shared>(); const auto showMenu = [=] { *menu = base::make_unique_q( button, st::popupMenuWithIcons); const auto result = FillSendMenu(*menu, type(), silent, schedule); const auto success = (result == FillMenuResult::Success); if (success) { (*menu)->popup(QCursor::pos()); } return success; }; base::install_event_filter(button, [=](not_null e) { if (e->type() == QEvent::ContextMenu && showMenu()) { return base::EventFilterResult::Cancel; } return base::EventFilterResult::Continue; }); Shortcuts::Requests( ) | rpl::start_with_next([=](not_null request) { using Command = Shortcuts::Command; const auto now = type(); if (now == Type::Disabled || (!silent && now == Type::SilentOnly)) { return; } (silent && (now != Type::Reminder) && request->check(Command::SendSilentMessage) && request->handle([=] { silent(); return true; })) || (schedule && (now != Type::SilentOnly) && request->check(Command::ScheduleMessage) && request->handle([=] { schedule(); return true; })) || (request->check(Command::JustSendMessage) && request->handle([=] { const auto post = [&](QEvent::Type type) { QApplication::postEvent( button, new QMouseEvent( type, QPointF(0, 0), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)); }; post(QEvent::MouseButtonPress); post(QEvent::MouseButtonRelease); return true; })); }, button->lifetime()); } void SetupReadAllMenu( not_null button, Fn currentPeer, const QString &text, Fn, Fn)> sendReadRequest) { struct State { base::unique_qptr menu; base::flat_set> sentForPeers; }; const auto state = std::make_shared(); const auto showMenu = [=] { const auto peer = currentPeer(); if (!peer) { return; } state->menu = base::make_unique_q( button, st::popupMenuWithIcons); state->menu->addAction(text, [=] { if (!state->sentForPeers.emplace(peer).second) { return; } sendReadRequest(peer, [=] { state->sentForPeers.remove(peer); }); }, &st::menuIconMarkRead); state->menu->popup(QCursor::pos()); }; base::install_event_filter(button, [=](not_null e) { if (e->type() == QEvent::ContextMenu) { showMenu(); return base::EventFilterResult::Cancel; } return base::EventFilterResult::Continue; }); } void SetupUnreadMentionsMenu( not_null button, Fn currentPeer) { const auto text = tr::lng_context_mark_read_mentions_all(tr::now); const auto sendRequest = [=](not_null peer, Fn done) { peer->session().api().request(MTPmessages_ReadMentions( peer->input )).done([=](const MTPmessages_AffectedHistory &result) { done(); peer->session().api().applyAffectedHistory(peer, result); peer->owner().history(peer)->unreadMentions().clear(); }).fail(done).send(); }; SetupReadAllMenu(button, currentPeer, text, sendRequest); } void SetupUnreadReactionsMenu( not_null button, Fn currentPeer) { const auto text = tr::lng_context_mark_read_reactions_all(tr::now); const auto sendRequest = [=](not_null peer, Fn done) { peer->session().api().request(MTPmessages_ReadReactions( peer->input )).done([=](const MTPmessages_AffectedHistory &result) { done(); peer->session().api().applyAffectedHistory(peer, result); peer->owner().history(peer)->unreadReactions().clear(); }).fail(done).send(); }; SetupReadAllMenu(button, currentPeer, text, sendRequest); } } // namespace SendMenu