diff --git a/Telegram/SourceFiles/auth_session.cpp b/Telegram/SourceFiles/auth_session.cpp index 2c130b283e..6b44166654 100644 --- a/Telegram/SourceFiles/auth_session.cpp +++ b/Telegram/SourceFiles/auth_session.cpp @@ -356,6 +356,28 @@ rpl::producer<> AuthSessionData::savedGifsUpdated() const { return _savedGifsUpdated.events(); } +HistoryItemsList AuthSessionData::idsToItems( + const MessageIdsList &ids) const { + return ranges::view::all( + ids + ) | ranges::view::transform([](const FullMsgId &fullId) { + return App::histItemById(fullId); + }) | ranges::view::filter([](HistoryItem *item) { + return item != nullptr; + }) | ranges::view::transform([](HistoryItem *item) { + return not_null(item); + }) | ranges::to_vector; +} + +MessageIdsList AuthSessionData::itemsToIds( + const HistoryItemsList &items) const { + return ranges::view::all( + items + ) | ranges::view::transform([](not_null item) { + return item->fullId(); + }) | ranges::to_vector; +} + AuthSession &Auth() { auto result = Messenger::Instance().authSession(); Assert(result != nullptr); diff --git a/Telegram/SourceFiles/auth_session.h b/Telegram/SourceFiles/auth_session.h index 4f826b3a65..aa63710822 100644 --- a/Telegram/SourceFiles/auth_session.h +++ b/Telegram/SourceFiles/auth_session.h @@ -261,6 +261,9 @@ public: return _savedGifs; } + HistoryItemsList idsToItems(const MessageIdsList &ids) const; + MessageIdsList itemsToIds(const HistoryItemsList &items) const; + private: struct Variables { Variables(); diff --git a/Telegram/SourceFiles/boxes/confirm_box.cpp b/Telegram/SourceFiles/boxes/confirm_box.cpp index dc7a05efe2..0630180699 100644 --- a/Telegram/SourceFiles/boxes/confirm_box.cpp +++ b/Telegram/SourceFiles/boxes/confirm_box.cpp @@ -450,21 +450,11 @@ DeleteMessagesBox::DeleteMessagesBox( DeleteMessagesBox::DeleteMessagesBox( QWidget*, - const SelectedItemSet &selected) -: _ids(CollectFrom(selected)) { + MessageIdsList &&selected) +: _ids(std::move(selected)) { Expects(!_ids.empty()); } -std::vector DeleteMessagesBox::CollectFrom( - const SelectedItemSet &items) { - return ranges::make_iterator_range( - items.begin(), - items.end() - ) | ranges::view::transform([](not_null item) { - return item->fullId(); - }) | ranges::to_vector; -} - void DeleteMessagesBox::prepare() { auto text = QString(); if (_moderateFrom) { diff --git a/Telegram/SourceFiles/boxes/confirm_box.h b/Telegram/SourceFiles/boxes/confirm_box.h index 4d155da7a9..7034143636 100644 --- a/Telegram/SourceFiles/boxes/confirm_box.h +++ b/Telegram/SourceFiles/boxes/confirm_box.h @@ -177,7 +177,7 @@ public: QWidget*, not_null item, bool suggestModerateActions); - DeleteMessagesBox(QWidget*, const SelectedItemSet &selected); + DeleteMessagesBox(QWidget*, MessageIdsList &&selected); protected: void prepare() override; @@ -188,9 +188,7 @@ protected: private: void deleteAndClear(); - static std::vector CollectFrom(const SelectedItemSet &items); - - const std::vector _ids; + const MessageIdsList _ids; const bool _singleItem = false; UserData *_moderateFrom = nullptr; ChannelData *_moderateInChannel = nullptr; diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index 8283fcb60c..296c4a081b 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -892,7 +892,7 @@ void AddBotToGroupBoxController::prepareViewHook() { } ChooseRecipientBoxController::ChooseRecipientBoxController( - base::lambda)> callback) + base::lambda_once)> callback) : _callback(std::move(callback)) { } diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.h b/Telegram/SourceFiles/boxes/peer_list_controllers.h index 5c92cdc680..4e6c9191d7 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.h +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.h @@ -243,7 +243,7 @@ private: class ChooseRecipientBoxController : public ChatsListBoxController { public: ChooseRecipientBoxController( - base::lambda)> callback); + base::lambda_once)> callback); void rowClicked(not_null row) override; @@ -257,6 +257,6 @@ protected: not_null history) override; private: - base::lambda)> _callback; + base::lambda_once)> _callback; }; diff --git a/Telegram/SourceFiles/data/data_types.h b/Telegram/SourceFiles/data/data_types.h index b2338cd101..1c0abb90de 100644 --- a/Telegram/SourceFiles/data/data_types.h +++ b/Telegram/SourceFiles/data/data_types.h @@ -154,6 +154,8 @@ inline bool operator<(const FullMsgId &a, const FullMsgId &b) { return a.channel < b.channel; } +using MessageIdsList = std::vector; + inline PeerId peerFromMessage(const MTPmessage &msg) { auto compute = [](auto &message) { auto from_id = message.has_from_id() ? peerFromUser(message.vfrom_id) : 0; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 73953541cc..bfebcbca60 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -798,7 +798,7 @@ void DialogsWidget::updateDragInScroll(bool inScroll) { if (_dragInScroll != inScroll) { _dragInScroll = inScroll; if (_dragInScroll) { - App::main()->showForwardLayer(SelectedItemSet()); + App::main()->showForwardLayer({}); } else { App::main()->dialogsCancelled(); } diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 530a34c2c0..e9d420042e 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -214,26 +214,16 @@ void History::draftSavedToCloud() { if (App::main()) App::main()->writeDrafts(this); } -SelectedItemSet History::validateForwardDraft() { - auto result = SelectedItemSet(); - auto count = 0; - for_const (auto &fullMsgId, _forwardDraft) { - if (auto item = App::histItemById(fullMsgId)) { - result.insert(++count, item); - } - } +HistoryItemsList History::validateForwardDraft() { + auto result = Auth().data().idsToItems(_forwardDraft); if (result.size() != _forwardDraft.size()) { - setForwardDraft(result); + setForwardDraft(Auth().data().itemsToIds(result)); } return result; } -void History::setForwardDraft(const SelectedItemSet &items) { - _forwardDraft.clear(); - _forwardDraft.reserve(items.size()); - for_const (auto item, items) { - _forwardDraft.push_back(item->fullId()); - } +void History::setForwardDraft(MessageIdsList &&items) { + _forwardDraft = std::move(items); } bool History::updateSendActionNeedsAnimating(UserData *user, const MTPSendMessageAction &action) { diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index dc87a8890d..bc2eb3caad 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -33,7 +33,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org void HistoryInit(); class HistoryItem; -using SelectedItemSet = QMap>; +using HistoryItemsList = std::vector>; enum NewMessageType { NewMessageUnread, @@ -423,11 +423,11 @@ public: return _editDraft ? editDraft() : localDraft(); } - QVector forwardDraft() const { + const MessageIdsList &forwardDraft() const { return _forwardDraft; } - SelectedItemSet validateForwardDraft(); - void setForwardDraft(const SelectedItemSet &items); + HistoryItemsList validateForwardDraft(); + void setForwardDraft(MessageIdsList &&items); // some fields below are a property of a currently displayed instance of this // conversation history not a property of the conversation history itself @@ -603,7 +603,7 @@ private: std::unique_ptr _localDraft, _cloudDraft; std::unique_ptr _editDraft; - QVector _forwardDraft; + MessageIdsList _forwardDraft; using TypingUsers = QMap; TypingUsers _typing; diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index a447cac569..6ec8085ceb 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -1984,22 +1984,26 @@ void HistoryInner::clearSelectedItems(bool onlyTextSelection) { } } -SelectedItemSet HistoryInner::getSelectedItems() const { - auto result = SelectedItemSet(); +MessageIdsList HistoryInner::getSelectedItems() const { + using namespace ranges; + if (_selected.empty() || _selected.cbegin()->second != FullSelection) { - return result; + return {}; } - for (auto &selected : _selected) { - auto item = selected.first; - if (item && item->toHistoryMessage() && item->id > 0) { - if (item->history() == _migrated) { - result.insert(item->id - ServerMaxMsgId, item); - } else { - result.insert(item->id, item); - } - } - } + auto result = make_iterator_range( + _selected.begin(), + _selected.end() + ) | view::filter([](const auto &selected) { + const auto item = selected.first; + return item && item->toHistoryMessage() && (item->id > 0); + }) | view::transform([](const auto &selected) { + return selected.first->fullId(); + }) | to_vector; + + result |= action::sort(ordered_less{}, [](const FullMsgId &msgId) { + return msgId.channel ? msgId.msg : (msgId.msg - ServerMaxMsgId); + }); return result; } diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 202e4f4dbe..a1d2b2bd04 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -65,7 +65,7 @@ public: HistoryTopBarWidget::SelectedState getSelectionState() const; void clearSelectedItems(bool onlyTextSelection = false); - SelectedItemSet getSelectedItems() const; + MessageIdsList getSelectedItems() const; void selectItem(HistoryItem *item); void updateBotInfo(bool recount = true); diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index ba38afdf43..741bee6edd 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -119,9 +119,9 @@ MTPDmessage::Flags NewForwardedFlags( return result; } -bool HasMediaItems(const SelectedItemSet &items) { - for_const (auto item, items) { - if (auto media = item->getMedia()) { +bool HasMediaItems(const HistoryItemsList &items) { + for (const auto item : items) { + if (const auto media = item->getMedia()) { switch (media->type()) { case MediaTypePhoto: case MediaTypeVideo: @@ -135,9 +135,9 @@ bool HasMediaItems(const SelectedItemSet &items) { return false; } -bool HasStickerItems(const SelectedItemSet &items) { - for_const (auto item, items) { - if (auto media = item->getMedia()) { +bool HasStickerItems(const HistoryItemsList &items) { + for (const auto item : items) { + if (const auto media = item->getMedia()) { switch (media->type()) { case MediaTypeSticker: return true; } @@ -146,9 +146,9 @@ bool HasStickerItems(const SelectedItemSet &items) { return false; } -bool HasGifItems(const SelectedItemSet &items) { - for_const (auto item, items) { - if (auto media = item->getMedia()) { +bool HasGifItems(const HistoryItemsList &items) { + for (const auto item : items) { + if (const auto media = item->getMedia()) { switch (media->type()) { case MediaTypeGif: return !media->getDocument()->isRoundVideo(); } @@ -157,9 +157,9 @@ bool HasGifItems(const SelectedItemSet &items) { return false; } -bool HasGameItems(const SelectedItemSet &items) { - for_const (auto item, items) { - if (auto media = item->getMedia()) { +bool HasGameItems(const HistoryItemsList &items) { + for (const auto item : items) { + if (const auto media = item->getMedia()) { switch (media->type()) { case MediaTypeGame: return true; } @@ -168,8 +168,8 @@ bool HasGameItems(const SelectedItemSet &items) { return false; } -bool HasInlineItems(const SelectedItemSet &items) { - for_const (auto item, items) { +bool HasInlineItems(const HistoryItemsList &items) { + for (const auto item : items) { if (item->viaBot()) { return true; } @@ -229,13 +229,12 @@ void FastShareMessage(not_null item) { return; } - auto items = SelectedItemSet(); + auto items = HistoryItemsList(1, item); auto restrictedSomewhere = false; auto restrictedEverywhere = true; auto firstError = QString(); - items.insert(item->id, item); - for_const (auto peer, result) { - auto error = GetErrorTextForForward(peer, items); + for (const auto peer : result) { + const auto error = GetErrorTextForForward(peer, items); if (!error.isEmpty()) { if (firstError.isEmpty()) { firstError = error; @@ -266,7 +265,7 @@ void FastShareMessage(not_null item) { auto sendFlags = MTPmessages_ForwardMessages::Flag::f_with_my_score; MTPVector msgIds = MTP_vector(1, MTP_int(data->msgId.msg)); if (auto main = App::main()) { - for_const (auto peer, result) { + for (const auto peer : result) { if (!GetErrorTextForForward(peer, items).isEmpty()) { continue; } @@ -320,7 +319,9 @@ MTPDmessage::Flags NewMessageFlags(not_null peer) { return result; } -QString GetErrorTextForForward(not_null peer, const SelectedItemSet &items) { +QString GetErrorTextForForward( + not_null peer, + const HistoryItemsList &items) { if (!peer->canWrite()) { return lang(lng_forward_cant); } diff --git a/Telegram/SourceFiles/history/history_message.h b/Telegram/SourceFiles/history/history_message.h index e94cf3cb19..a22137129d 100644 --- a/Telegram/SourceFiles/history/history_message.h +++ b/Telegram/SourceFiles/history/history_message.h @@ -23,7 +23,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org void HistoryInitMessages(); base::lambda HistoryDependentItemCallback(const FullMsgId &msgId); MTPDmessage::Flags NewMessageFlags(not_null peer); -QString GetErrorTextForForward(not_null peer, const SelectedItemSet &items); +QString GetErrorTextForForward( + not_null peer, + const HistoryItemsList &items); void FastShareMessage(not_null item); class HistoryMessage : public HistoryItem, private HistoryItemInstantiated { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 774d1da4b6..9289990716 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -66,15 +66,16 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "storage/localstorage.h" #include "apiwrap.h" #include "history/history_top_bar_widget.h" -#include "window/themes/window_theme.h" #include "observer_peer.h" #include "base/qthelp_regex.h" #include "ui/widgets/popup_menu.h" #include "platform/platform_file_utilities.h" #include "auth_session.h" +#include "window/themes/window_theme.h" #include "window/notifications_manager.h" #include "window/window_controller.h" #include "window/window_slide_animation.h" +#include "window/window_peer_menu.h" #include "inline_bots/inline_results_widget.h" #include "chat_helpers/emoji_suggestions_widget.h" @@ -174,8 +175,11 @@ void ReportSpamPanel::setReported(bool reported, PeerData *onPeer) { update(); } -HistoryHider::HistoryHider(MainWidget *parent, const SelectedItemSet &items) : RpWidget(parent) -, _forwardItems(items) +HistoryHider::HistoryHider( + MainWidget *parent, + MessageIdsList &&items) +: RpWidget(parent) +, _forwardItems(std::move(items)) , _send(this, langFactory(lng_forward_send), st::defaultBoxButton) , _cancel(this, langFactory(lng_cancel), st::defaultBoxButton) { init(); @@ -212,20 +216,6 @@ HistoryHider::HistoryHider(MainWidget *parent, const QString &url, const QString void HistoryHider::init() { subscribe(Lang::Current().updated(), [this] { refreshLang(); }); - if (!_forwardItems.empty()) { - Auth().data().itemRemoved() - | rpl::start_with_next([this](auto item) { - for (auto i = _forwardItems.begin(); i != _forwardItems.end(); ++i) { - if (i->get() == item) { - i = _forwardItems.erase(i); - break; - } - } - if (_forwardItems.empty()) { - startHide(); - } - }, lifetime()); - } connect(_send, SIGNAL(clicked()), this, SLOT(forward())); connect(_cancel, SIGNAL(clicked()), this, SLOT(startHide())); subscribe(Global::RefPeerChooseCancel(), [this] { startHide(); }); @@ -336,7 +326,7 @@ void HistoryHider::forward() { } else if (!_botAndQuery.isEmpty()) { parent()->onInlineSwitchChosen(_offered->id, _botAndQuery); } else { - parent()->setForwardDraft(_offered->id, _forwardItems); + parent()->setForwardDraft(_offered->id, std::move(_forwardItems)); } } emit forwarded(); @@ -418,7 +408,7 @@ bool HistoryHider::offerPeer(PeerId peer) { } else { auto toId = _offered->id; _offered = nullptr; - if (parent()->setForwardDraft(toId, _forwardItems)) { + if (parent()->setForwardDraft(toId, std::move(_forwardItems))) { startHide(); } return false; @@ -3673,7 +3663,7 @@ bool HistoryWidget::canSendMessages(PeerData *peer) const { } bool HistoryWidget::readyToForward() const { - return _canSendMessages && !_toForward.isEmpty(); + return _canSendMessages && !_toForward.empty(); } bool HistoryWidget::hasSilentToggle() const { @@ -3880,9 +3870,7 @@ void HistoryWidget::forwardMessage() { auto item = App::contextItem(); if (!item || item->id < 0 || item->serviceMsg()) return; - auto items = SelectedItemSet(); - items.insert(item->id, item); - App::main()->showForwardBox(std::move(items)); + Window::ShowForwardMessagesBox({ 1, item->fullId() }); } void HistoryWidget::selectMessage() { @@ -4878,15 +4866,13 @@ void HistoryWidget::itemRemoved(not_null item) { onKbToggle(); _kbReplyTo = 0; } - for (auto i = _toForward.begin(); i != _toForward.end(); ++i) { - if (i->get() == item) { - i = _toForward.erase(i); - updateForwardingTexts(); - if (_toForward.empty()) { - updateControlsVisibility(); - updateControlsGeometry(); - } - break; + auto found = ranges::find(_toForward, item); + if (found != _toForward.end()) { + _toForward.erase(found); + updateForwardingTexts(); + if (_toForward.empty()) { + updateControlsVisibility(); + updateControlsGeometry(); } } } @@ -5278,9 +5264,13 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) { updateField(); } else if (_inReplyEditForward) { if (readyToForward()) { - auto items = _toForward; + const auto items = std::move(_toForward); App::main()->cancelForwarding(_history); - App::main()->showForwardBox(std::move(items)); + Window::ShowForwardMessagesBox(ranges::view::all( + items + ) | ranges::view::transform([](not_null item) { + return item->fullId(); + }) | ranges::to_vector); } else { Ui::showPeerHistory(_peer, _editMsgId ? _editMsgId : replyToId()); } @@ -5680,9 +5670,9 @@ void HistoryWidget::onReplyToMessage() { auto item = App::contextItem(); if (!item || item->id < 0 || item->serviceMsg()) return; - auto items = SelectedItemSet(); - items.insert(item->id, item); - App::main()->setForwardDraft(_peer->id, items); + App::main()->setForwardDraft( + _peer->id, + { 1, item->fullId() }); }))); } } @@ -6178,7 +6168,7 @@ void HistoryWidget::handlePeerUpdate() { void HistoryWidget::onForwardSelected() { if (!_list) return; - App::main()->showForwardBox(getSelectedItems()); + Window::ShowForwardMessagesBox(getSelectedItems()); } void HistoryWidget::confirmDeleteContextItem() { @@ -6198,9 +6188,9 @@ void HistoryWidget::confirmDeleteSelectedItems() { if (!_list) return; auto selected = _list->getSelectedItems(); - if (selected.isEmpty()) return; + if (selected.empty()) return; - App::main()->deleteLayer(selected.size()); + App::main()->deleteLayer(int(selected.size())); } void HistoryWidget::deleteContextItem(bool forEveryone) { @@ -6230,18 +6220,24 @@ void HistoryWidget::deleteSelectedItems(bool forEveryone) { Ui::hideLayer(); if (!_list) return; - auto selected = _list->getSelectedItems(); - if (selected.isEmpty()) return; + const auto items = _list->getSelectedItems(); + const auto selected = ranges::view::all( + items + ) | ranges::view::transform([](const FullMsgId &fullId) { + return App::histItemById(fullId); + }) | ranges::view::filter([](HistoryItem *item) { + return item != nullptr; + }) | ranges::to_vector; + + if (selected.empty()) return; QMap> idsByPeer; - for_const (auto item, selected) { - if (item->id > 0) { - idsByPeer[item->history()->peer].push_back(MTP_int(item->id)); - } + for (const auto item : selected) { + idsByPeer[item->history()->peer].push_back(MTP_int(item->id)); } onClearSelected(); - for_const (auto item, selected) { + for (const auto item : selected) { item->destroy(); } @@ -6275,8 +6271,8 @@ HistoryItem *HistoryWidget::getItemFromHistoryOrMigrated(MsgId genericMsgId) con return App::histItemById(_channel, genericMsgId); } -SelectedItemSet HistoryWidget::getSelectedItems() const { - return _list ? _list->getSelectedItems() : SelectedItemSet(); +MessageIdsList HistoryWidget::getSelectedItems() const { + return _list ? _list->getSelectedItems() : MessageIdsList(); } void HistoryWidget::updateTopBarSelection() { @@ -6354,12 +6350,12 @@ void HistoryWidget::updateForwarding() { void HistoryWidget::updateForwardingTexts() { int32 version = 0; QString from, text; - if (!_toForward.isEmpty()) { + if (const auto count = int(_toForward.size())) { QMap fromUsersMap; QVector fromUsers; fromUsers.reserve(_toForward.size()); - for (auto i = _toForward.cbegin(), e = _toForward.cend(); i != e; ++i) { - auto from = i.value()->senderOriginal(); + for (const auto item : _toForward) { + const auto from = item->senderOriginal(); if (!fromUsersMap.contains(from)) { fromUsersMap.insert(from, true); fromUsers.push_back(from); @@ -6374,10 +6370,10 @@ void HistoryWidget::updateForwardingTexts() { from = lng_forwarding_from_two(lt_user, fromUsers.at(0)->shortName(), lt_second_user, fromUsers.at(1)->shortName()); } - if (_toForward.size() < 2) { - text = _toForward.cbegin().value()->inReplyText(); + if (count < 2) { + text = _toForward.front()->inReplyText(); } else { - text = lng_forward_messages(lt_count, _toForward.size()); + text = lng_forward_messages(lt_count, count); } } _toForwardFrom.setText(st::msgNameStyle, from, _textNameOptions); @@ -6386,9 +6382,9 @@ void HistoryWidget::updateForwardingTexts() { } void HistoryWidget::checkForwardingInfo() { - if (!_toForward.isEmpty()) { + if (!_toForward.empty()) { auto version = 0; - for_const (auto item, _toForward) { + for (const auto item : _toForward) { version += item->senderOriginal()->nameVersion; } if (version != _toForwardNameVersion) { @@ -6461,10 +6457,14 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) { auto forwardLeft = st::historyReplySkip; st::historyForwardIcon.paint(p, st::historyReplyIconPosition + QPoint(0, backy), width()); if (!drawWebPagePreview) { - auto firstItem = _toForward.cbegin().value(); - auto firstMedia = firstItem->getMedia(); - auto serviceColor = (_toForward.size() > 1) || (firstMedia != nullptr) || firstItem->serviceMsg(); - auto preview = (_toForward.size() < 2 && firstMedia && firstMedia->hasReplyPreview()) ? firstMedia->replyPreview() : ImagePtr(); + const auto firstItem = _toForward.front(); + const auto firstMedia = firstItem->getMedia(); + const auto serviceColor = (_toForward.size() > 1) + || (firstMedia != nullptr) + || firstItem->serviceMsg(); + const auto preview = (_toForward.size() < 2 && firstMedia && firstMedia->hasReplyPreview()) + ? firstMedia->replyPreview() + : ImagePtr(); if (!preview->isNull()) { auto to = QRect(forwardLeft, backy + st::msgReplyPadding.top(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height()); if (preview->width() == preview->height()) { diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 09f4432c7e..de7143ae9d 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -102,7 +102,7 @@ class HistoryHider : public Ui::RpWidget, private base::Subscriber { Q_OBJECT public: - HistoryHider(MainWidget *parent, const SelectedItemSet &items); // forward messages + HistoryHider(MainWidget *parent, MessageIdsList &&items); // forward messages HistoryHider(MainWidget *parent, UserData *sharedContact); // share contact HistoryHider(MainWidget *parent); // send path from command line argument HistoryHider(MainWidget *parent, const QString &url, const QString &text); // share url @@ -143,7 +143,7 @@ private: MainWidget *parent(); UserData *_sharedContact = nullptr; - SelectedItemSet _forwardItems; + MessageIdsList _forwardItems; bool _sendPath = false; QString _shareUrl, _shareText; @@ -261,7 +261,7 @@ public: void enqueueMessageHighlight(not_null item); TimeMs highlightStartTime(not_null item) const; - SelectedItemSet getSelectedItems() const; + MessageIdsList getSelectedItems() const; void itemEdited(HistoryItem *item); void updateScrollColors(); @@ -485,7 +485,7 @@ private: void showNextUnreadMention(); void handlePeerUpdate(); void setMembersShowAreaActive(bool active); - void forwardItems(SelectedItemSet &&items); + void forwardItems(MessageIdsList &&items); void highlightMessage(MsgId universalMessageId); void adjustHighlightedMessageToMigrated(); @@ -553,7 +553,7 @@ private: Text _replyToName; int _replyToNameVersion = 0; - SelectedItemSet _toForward; + HistoryItemsList _toForward; Text _toForwardFrom, _toForwardText; int _toForwardNameVersion = 0; diff --git a/Telegram/SourceFiles/info/info_top_bar.cpp b/Telegram/SourceFiles/info/info_top_bar.cpp index 5f9a521761..869ba0cd33 100644 --- a/Telegram/SourceFiles/info/info_top_bar.cpp +++ b/Telegram/SourceFiles/info/info_top_bar.cpp @@ -38,6 +38,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "ui/wrap/fade_wrap.h" #include "ui/wrap/padding_wrap.h" #include "ui/search_field_controller.h" +#include "window/window_peer_menu.h" namespace Info { @@ -489,14 +490,14 @@ bool TopBar::searchMode() const { return _searchModeAvailable && _searchModeEnabled; } -SelectedItemSet TopBar::collectItems() const { - auto result = SelectedItemSet(); - for (auto value : _selectedItems.list) { - if (auto item = App::histItemById(value.msgId)) { - result.insert(result.size(), item); - } - } - return result; +MessageIdsList TopBar::collectItems() const { + return ranges::view::all( + _selectedItems.list + ) | ranges::view::transform([](auto &&item) { + return item.msgId; + }) | ranges::view::filter([](const FullMsgId &msgId) { + return App::histItemById(msgId) != nullptr; + }) | ranges::to_vector; } void TopBar::performForward() { @@ -505,20 +506,11 @@ void TopBar::performForward() { _cancelSelectionClicks.fire({}); return; } - auto callback = [items = std::move(items), weak = make_weak(this)]( - not_null peer) { - App::main()->setForwardDraft(peer->id, items); + Window::ShowForwardMessagesBox(std::move(items), [weak = make_weak(this)]{ if (weak) { weak->_cancelSelectionClicks.fire({}); } - }; - Ui::show(Box( - std::make_unique(std::move(callback)), - [](not_null box) { - box->addButton(langFactory(lng_cancel), [box] { - box->closeBox(); - }); - })); + }); } void TopBar::performDelete() { @@ -526,7 +518,7 @@ void TopBar::performDelete() { if (items.empty()) { _cancelSelectionClicks.fire({}); } else { - Ui::show(Box(items)); + Ui::show(Box(std::move(items))); } } diff --git a/Telegram/SourceFiles/info/info_top_bar.h b/Telegram/SourceFiles/info/info_top_bar.h index 1156128f0e..252af10c12 100644 --- a/Telegram/SourceFiles/info/info_top_bar.h +++ b/Telegram/SourceFiles/info/info_top_bar.h @@ -97,12 +97,11 @@ private: bool searchMode() const; Ui::StringWithNumbers generateSelectedText() const; [[nodiscard]] bool computeCanDelete() const; - [[nodiscard]] SelectedItemSet collectSelectedItems() const; void updateSelectionState(); void createSelectionControls(); void clearSelectionControls(); - SelectedItemSet collectItems() const; + MessageIdsList collectItems() const; void performForward(); void performDelete(); diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 7cd605f7e1..f5858ebfb0 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -673,17 +673,13 @@ auto ListWidget::collectSelectedItems() const -> SelectedItems { return items; } -SelectedItemSet ListWidget::collectSelectedSet() const { - auto items = SelectedItemSet(); - if (hasSelectedItems()) { - for (auto &data : _selected) { - auto fullId = computeFullId(data.first); - if (auto item = App::histItemById(fullId)) { - items.insert(items.size(), item); - } - } - } - return items; +MessageIdsList ListWidget::collectSelectedIds() const { + const auto selected = collectSelectedItems(); + return ranges::view::all( + selected.list + ) | ranges::view::transform([](const SelectedItem &item) { + return item.msgId; + }) | ranges::to_vector; } void ListWidget::pushSelectedItems() { @@ -1364,29 +1360,29 @@ void ListWidget::contextMenuEvent(QContextMenuEvent *e) { } void ListWidget::forwardSelected() { - forwardItems(collectSelectedSet()); + forwardItems(collectSelectedIds()); } void ListWidget::forwardItem(UniversalMsgId universalId) { - if (auto item = App::histItemById(computeFullId(universalId))) { - auto items = SelectedItemSet(); - items.insert(0, item); - forwardItems(std::move(items)); + if (const auto item = App::histItemById(computeFullId(universalId))) { + forwardItems({ 1, item->fullId() }); } } -void ListWidget::forwardItems(SelectedItemSet items) { +void ListWidget::forwardItems(MessageIdsList &&items) { if (items.empty()) { return; } auto weak = make_weak(this); + auto callback = [weak, items = std::move(items)]( + not_null peer) mutable { + App::main()->setForwardDraft(peer->id, std::move(items)); + if (weak) { + weak->clearSelected(); + } + }; auto controller = std::make_unique( - [weak, items = std::move(items)](not_null peer) { - App::main()->setForwardDraft(peer->id, items); - if (weak) { - weak->clearSelected(); - } - }); + std::move(callback)); Ui::show(Box( std::move(controller), [](not_null box) { @@ -1397,20 +1393,18 @@ void ListWidget::forwardItems(SelectedItemSet items) { } void ListWidget::deleteSelected() { - deleteItems(collectSelectedSet()); + deleteItems(collectSelectedIds()); } void ListWidget::deleteItem(UniversalMsgId universalId) { - if (auto item = App::histItemById(computeFullId(universalId))) { - auto items = SelectedItemSet(); - items.insert(0, item); - deleteItems(std::move(items)); + if (const auto item = App::histItemById(computeFullId(universalId))) { + deleteItems({ 1, item->fullId() }); } } -void ListWidget::deleteItems(SelectedItemSet items) { +void ListWidget::deleteItems(MessageIdsList &&items) { if (!items.empty()) { - Ui::show(Box(items)); + Ui::show(Box(std::move(items))); } } diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.h b/Telegram/SourceFiles/info/media/info_media_list_widget.h index 9ac20bba72..eff50591f3 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.h @@ -174,7 +174,7 @@ private: Type type); SelectedItems collectSelectedItems() const; - SelectedItemSet collectSelectedSet() const; + MessageIdsList collectSelectedIds() const; void pushSelectedItems(); FullMsgId computeFullId(UniversalMsgId universalId) const; bool hasSelected() const; @@ -187,10 +187,10 @@ private: void clearSelected(); void forwardSelected(); void forwardItem(UniversalMsgId universalId); - void forwardItems(SelectedItemSet items); + void forwardItems(MessageIdsList &&items); void deleteSelected(); void deleteItem(UniversalMsgId universalId); - void deleteItems(SelectedItemSet items); + void deleteItems(MessageIdsList &&items); void applyItemSelection( UniversalMsgId universalId, TextSelection selection); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 338f072bbc..51c410a63d 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -39,6 +39,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "ui/widgets/dropdown_menu.h" #include "ui/focus_persister.h" #include "ui/resize_area.h" +#include "ui/toast/toast.h" #include "chat_helpers/message_field.h" #include "chat_helpers/stickers.h" #include "info/info_memento.h" @@ -616,10 +617,10 @@ void MainWidget::finishFloatPlayerDrag(not_null instance, bool closed) { } bool MainWidget::setForwardDraft(PeerId peerId, ForwardWhatMessages what) { - auto toForward = SelectedItemSet(); - if (what == ForwardSelectedMessages) { - toForward = _history->getSelectedItems(); - } else { + const auto collect = [&]() -> MessageIdsList { + if (what == ForwardSelectedMessages) { + return _history->getSelectedItems(); + } auto item = (HistoryItem*)nullptr; if (what == ForwardContextMessage) { item = App::contextItem(); @@ -629,10 +630,11 @@ bool MainWidget::setForwardDraft(PeerId peerId, ForwardWhatMessages what) { item = App::pressedLinkItem(); } if (item && item->toHistoryMessage() && item->id > 0) { - toForward.insert(item->id, item); + return { 1, item->fullId() }; } - } - auto result = setForwardDraft(peerId, toForward); + return {}; + }; + const auto result = setForwardDraft(peerId, collect()); if (!result) { if (what == ForwardPressedMessage || what == ForwardPressedLinkMessage) { // We've already released the mouse button, so the forwarding is cancelled. @@ -645,16 +647,18 @@ bool MainWidget::setForwardDraft(PeerId peerId, ForwardWhatMessages what) { return result; } -bool MainWidget::setForwardDraft(PeerId peerId, const SelectedItemSet &items) { +bool MainWidget::setForwardDraft(PeerId peerId, MessageIdsList &&items) { Expects(peerId != 0); - auto peer = App::peer(peerId); - auto error = GetErrorTextForForward(peer, items); + const auto peer = App::peer(peerId); + const auto error = GetErrorTextForForward( + peer, + Auth().data().idsToItems(items)); if (!error.isEmpty()) { Ui::show(Box(error), LayerOption::KeepOther); return false; } - App::history(peer)->setForwardDraft(items); + App::history(peer)->setForwardDraft(std::move(items)); if (_history->peer() == peer) { _history->cancelReply(); } @@ -713,16 +717,16 @@ bool MainWidget::onInlineSwitchChosen(const PeerId &peer, const QString &botAndQ } void MainWidget::cancelForwarding(History *history) { - history->setForwardDraft(SelectedItemSet()); + history->setForwardDraft({}); _history->updateForwarding(); } void MainWidget::finishForwarding(History *history, bool silent) { if (!history) return; - auto toForward = history->validateForwardDraft(); - if (!toForward.isEmpty()) { - auto genClientSideMessage = (toForward.size() < 2); + const auto toForward = history->validateForwardDraft(); + if (const auto count = int(toForward.size())) { + auto genClientSideMessage = (count < 2); PeerData *forwardFrom = 0; App::main()->readServerHistory(history); @@ -745,12 +749,12 @@ void MainWidget::finishForwarding(History *history, bool silent) { QVector ids; QVector randomIds; - ids.reserve(toForward.size()); - randomIds.reserve(toForward.size()); - for (auto i = toForward.cbegin(), e = toForward.cend(); i != e; ++i) { + ids.reserve(count); + randomIds.reserve(count); + for (const auto item : toForward) { auto randomId = rand_value(); if (genClientSideMessage) { - if (auto message = i.value()->toHistoryMessage()) { + if (auto message = item->toHistoryMessage()) { auto newId = FullMsgId(peerToChannel(history->peer->id), clientMsgId()); auto messageFromId = channelPost ? 0 : Auth().userId(); auto messagePostAuthor = channelPost ? (Auth().user()->firstName + ' ' + Auth().user()->lastName) : QString(); @@ -758,15 +762,15 @@ void MainWidget::finishForwarding(History *history, bool silent) { App::historyRegRandom(randomId, newId); } } - if (forwardFrom != i.value()->history()->peer) { + if (forwardFrom != item->history()->peer) { if (forwardFrom) { history->sendRequestId = MTP::send(MTPmessages_ForwardMessages(MTP_flags(sendFlags), forwardFrom->input, MTP_vector(ids), MTP_vector(randomIds), history->peer->input), rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, history->sendRequestId); ids.resize(0); randomIds.resize(0); } - forwardFrom = i.value()->history()->peer; + forwardFrom = item->history()->peer; } - ids.push_back(MTP_int(i.value()->id)); + ids.push_back(MTP_int(item->id)); randomIds.push_back(MTP_long(randomId)); } history->sendRequestId = MTP::send(MTPmessages_ForwardMessages(MTP_flags(sendFlags), forwardFrom->input, MTP_vector(ids), MTP_vector(randomIds), history->peer->input), rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, history->sendRequestId); @@ -1005,37 +1009,22 @@ void MainWidget::hiderLayer(object_ptr h) { checkFloatPlayerVisibility(); } -void MainWidget::showForwardLayer(const SelectedItemSet &items) { - hiderLayer(object_ptr(this, items)); +void MainWidget::showForwardLayer(MessageIdsList &&items) { + hiderLayer(object_ptr(this, std::move(items))); } void MainWidget::showSendPathsLayer() { hiderLayer(object_ptr(this)); } -void MainWidget::showForwardBox(SelectedItemSet &&items) { - auto controller = std::make_unique( - [items = std::move(items)](not_null peer) { - App::main()->setForwardDraft(peer->id, items); - }); - Ui::show(Box( - std::move(controller), - [](not_null box) { - box->addButton(langFactory(lng_cancel), [box] { - box->closeBox(); - }); - })); -} - void MainWidget::deleteLayer(int selectedCount) { if (selectedCount) { - auto forDelete = true; auto selected = _history->getSelectedItems(); - if (!selected.isEmpty()) { - Ui::show(Box(selected)); + if (!selected.empty()) { + Ui::show(Box(std::move(selected))); } - } else if (auto item = App::contextItem()) { - auto suggestModerateActions = true; + } else if (const auto item = App::contextItem()) { + const auto suggestModerateActions = true; Ui::show(Box(item, suggestModerateActions)); } } @@ -1335,7 +1324,10 @@ bool MainWidget::addParticipantsFail( } void MainWidget::kickParticipant(ChatData *chat, UserData *user) { - MTP::send(MTPmessages_DeleteChatUser(chat->inputChat, user->inputUser), rpcDone(&MainWidget::sentUpdatesReceived), rpcFail(&MainWidget::kickParticipantFail, chat)); + MTP::send( + MTPmessages_DeleteChatUser(chat->inputChat, user->inputUser), + rpcDone(&MainWidget::sentUpdatesReceived), + rpcFail(&MainWidget::kickParticipantFail, chat)); Ui::showPeerHistory(chat->id, ShowAtTheEndMsgId); } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index e508fbd8d3..c3e2296c5c 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -178,9 +178,8 @@ public: int32 dlgsWidth() const; - void showForwardLayer(const SelectedItemSet &items); + void showForwardLayer(MessageIdsList &&items); void showSendPathsLayer(); - void showForwardBox(SelectedItemSet &&items); void deleteLayer(int selectedCount = 0); // 0 - context item void cancelUploadLayer(); void shareContactLayer(UserData *contact); @@ -189,7 +188,7 @@ public: void hiderLayer(object_ptr h); void noHider(HistoryHider *destroyed); bool setForwardDraft(PeerId peer, ForwardWhatMessages what); - bool setForwardDraft(PeerId peer, const SelectedItemSet &items); + bool setForwardDraft(PeerId peer, MessageIdsList &&items); bool shareUrl( not_null peer, const QString &url, diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index ecd76f6312..1c578c95db 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -35,6 +35,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "history/history_message.h" #include "history/history_media_types.h" #include "window/themes/window_theme_preview.h" +#include "window/window_peer_menu.h" #include "base/task_queue.h" #include "observer_peer.h" #include "auth_session.h" @@ -936,11 +937,7 @@ void MediaView::onForward() { } close(); - if (auto main = App::main()) { - auto items = SelectedItemSet(); - items.insert(item->id, item); - main->showForwardBox(std::move(items)); - } + Window::ShowForwardMessagesBox({ 1, item->fullId() }); } void MediaView::onDelete() { diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index d62eb61bb0..f20deaaac6 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -28,6 +28,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #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" @@ -492,6 +493,37 @@ void PeerMenuShareContactBox(not_null user) { })); } +void ShowForwardMessagesBox( + MessageIdsList &&items, + base::lambda_once &&successCallback) { + auto weak = std::make_shared>(); + auto callback = [ + ids = std::move(items), + callback = std::move(successCallback), + weak + ](not_null peer) mutable { + if (peer->isSelf()) { + 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 box) { + box->addButton(langFactory(lng_cancel), [box] { + box->closeBox(); + }); + }; + *weak = Ui::show(Box( + std::make_unique(std::move(callback)), + std::move(initBox)), LayerOption::KeepOther); +} + void PeerMenuAddChannelMembers(not_null channel) { if (channel->isMegagroup()) { auto &participants = channel->mgInfo->lastParticipants; diff --git a/Telegram/SourceFiles/window/window_peer_menu.h b/Telegram/SourceFiles/window/window_peer_menu.h index 2e666a2bfa..c4bb25a401 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.h +++ b/Telegram/SourceFiles/window/window_peer_menu.h @@ -45,4 +45,8 @@ void PeerMenuShareContactBox(not_null user); void PeerMenuAddContact(not_null user); void PeerMenuAddChannelMembers(not_null channel); +void ShowForwardMessagesBox( + MessageIdsList &&items, + base::lambda_once &&successCallback = nullptr); + } // namespace Window