Replace SelectedItemSet with MessageIdsList.

Use vector<FullMsgId> everywhere instead QMap<..,HistoryItem*>.
The old way the app crashed in case some messages were deleted.
If the items are needed use HistoryItemsList=vector<HistoryItem*>.
This commit is contained in:
John Preston 2017-12-06 14:13:38 +04:00
parent 3845985a6b
commit 6764a3cc86
25 changed files with 269 additions and 248 deletions

View File

@ -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<HistoryItem*>(item);
}) | ranges::to_vector;
}
MessageIdsList AuthSessionData::itemsToIds(
const HistoryItemsList &items) const {
return ranges::view::all(
items
) | ranges::view::transform([](not_null<HistoryItem*> item) {
return item->fullId();
}) | ranges::to_vector;
}
AuthSession &Auth() {
auto result = Messenger::Instance().authSession();
Assert(result != nullptr);

View File

@ -261,6 +261,9 @@ public:
return _savedGifs;
}
HistoryItemsList idsToItems(const MessageIdsList &ids) const;
MessageIdsList itemsToIds(const HistoryItemsList &items) const;
private:
struct Variables {
Variables();

View File

@ -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<FullMsgId> DeleteMessagesBox::CollectFrom(
const SelectedItemSet &items) {
return ranges::make_iterator_range(
items.begin(),
items.end()
) | ranges::view::transform([](not_null<HistoryItem*> item) {
return item->fullId();
}) | ranges::to_vector;
}
void DeleteMessagesBox::prepare() {
auto text = QString();
if (_moderateFrom) {

View File

@ -177,7 +177,7 @@ public:
QWidget*,
not_null<HistoryItem*> 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<FullMsgId> CollectFrom(const SelectedItemSet &items);
const std::vector<FullMsgId> _ids;
const MessageIdsList _ids;
const bool _singleItem = false;
UserData *_moderateFrom = nullptr;
ChannelData *_moderateInChannel = nullptr;

View File

@ -892,7 +892,7 @@ void AddBotToGroupBoxController::prepareViewHook() {
}
ChooseRecipientBoxController::ChooseRecipientBoxController(
base::lambda<void(not_null<PeerData*>)> callback)
base::lambda_once<void(not_null<PeerData*>)> callback)
: _callback(std::move(callback)) {
}

View File

@ -243,7 +243,7 @@ private:
class ChooseRecipientBoxController : public ChatsListBoxController {
public:
ChooseRecipientBoxController(
base::lambda<void(not_null<PeerData*>)> callback);
base::lambda_once<void(not_null<PeerData*>)> callback);
void rowClicked(not_null<PeerListRow*> row) override;
@ -257,6 +257,6 @@ protected:
not_null<History*> history) override;
private:
base::lambda<void(not_null<PeerData*>)> _callback;
base::lambda_once<void(not_null<PeerData*>)> _callback;
};

View File

@ -154,6 +154,8 @@ inline bool operator<(const FullMsgId &a, const FullMsgId &b) {
return a.channel < b.channel;
}
using MessageIdsList = std::vector<FullMsgId>;
inline PeerId peerFromMessage(const MTPmessage &msg) {
auto compute = [](auto &message) {
auto from_id = message.has_from_id() ? peerFromUser(message.vfrom_id) : 0;

View File

@ -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();
}

View File

@ -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) {

View File

@ -33,7 +33,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
void HistoryInit();
class HistoryItem;
using SelectedItemSet = QMap<int, not_null<HistoryItem*>>;
using HistoryItemsList = std::vector<not_null<HistoryItem*>>;
enum NewMessageType {
NewMessageUnread,
@ -423,11 +423,11 @@ public:
return _editDraft ? editDraft() : localDraft();
}
QVector<FullMsgId> 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<Data::Draft> _localDraft, _cloudDraft;
std::unique_ptr<Data::Draft> _editDraft;
QVector<FullMsgId> _forwardDraft;
MessageIdsList _forwardDraft;
using TypingUsers = QMap<UserData*, TimeMs>;
TypingUsers _typing;

View File

@ -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;
}

View File

@ -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);

View File

@ -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<HistoryItem*> 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<HistoryItem*> item) {
auto sendFlags = MTPmessages_ForwardMessages::Flag::f_with_my_score;
MTPVector<MTPint> msgIds = MTP_vector<MTPint>(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<PeerData*> peer) {
return result;
}
QString GetErrorTextForForward(not_null<PeerData*> peer, const SelectedItemSet &items) {
QString GetErrorTextForForward(
not_null<PeerData*> peer,
const HistoryItemsList &items) {
if (!peer->canWrite()) {
return lang(lng_forward_cant);
}

View File

@ -23,7 +23,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
void HistoryInitMessages();
base::lambda<void(ChannelData*, MsgId)> HistoryDependentItemCallback(const FullMsgId &msgId);
MTPDmessage::Flags NewMessageFlags(not_null<PeerData*> peer);
QString GetErrorTextForForward(not_null<PeerData*> peer, const SelectedItemSet &items);
QString GetErrorTextForForward(
not_null<PeerData*> peer,
const HistoryItemsList &items);
void FastShareMessage(not_null<HistoryItem*> item);
class HistoryMessage : public HistoryItem, private HistoryItemInstantiated<HistoryMessage> {

View File

@ -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<const HistoryItem*> 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<HistoryItem*> 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<PeerData*, QVector<MTPint>> 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<PeerData*, bool> fromUsersMap;
QVector<PeerData*> 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()) {

View File

@ -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<HistoryItem*> item);
TimeMs highlightStartTime(not_null<const HistoryItem*> 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;

View File

@ -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<PeerData*> peer) {
App::main()->setForwardDraft(peer->id, items);
Window::ShowForwardMessagesBox(std::move(items), [weak = make_weak(this)]{
if (weak) {
weak->_cancelSelectionClicks.fire({});
}
};
Ui::show(Box<PeerListBox>(
std::make_unique<ChooseRecipientBoxController>(std::move(callback)),
[](not_null<PeerListBox*> 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<DeleteMessagesBox>(items));
Ui::show(Box<DeleteMessagesBox>(std::move(items)));
}
}

View File

@ -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();

View File

@ -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<PeerData*> peer) mutable {
App::main()->setForwardDraft(peer->id, std::move(items));
if (weak) {
weak->clearSelected();
}
};
auto controller = std::make_unique<ChooseRecipientBoxController>(
[weak, items = std::move(items)](not_null<PeerData*> peer) {
App::main()->setForwardDraft(peer->id, items);
if (weak) {
weak->clearSelected();
}
});
std::move(callback));
Ui::show(Box<PeerListBox>(
std::move(controller),
[](not_null<PeerListBox*> 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<DeleteMessagesBox>(items));
Ui::show(Box<DeleteMessagesBox>(std::move(items)));
}
}

View File

@ -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);

View File

@ -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<Float*> 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<InformBox>(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<MTPint> ids;
QVector<MTPlong> 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<uint64>();
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<MTPint>(ids), MTP_vector<MTPlong>(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<MTPint>(ids), MTP_vector<MTPlong>(randomIds), history->peer->input), rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, history->sendRequestId);
@ -1005,37 +1009,22 @@ void MainWidget::hiderLayer(object_ptr<HistoryHider> h) {
checkFloatPlayerVisibility();
}
void MainWidget::showForwardLayer(const SelectedItemSet &items) {
hiderLayer(object_ptr<HistoryHider>(this, items));
void MainWidget::showForwardLayer(MessageIdsList &&items) {
hiderLayer(object_ptr<HistoryHider>(this, std::move(items)));
}
void MainWidget::showSendPathsLayer() {
hiderLayer(object_ptr<HistoryHider>(this));
}
void MainWidget::showForwardBox(SelectedItemSet &&items) {
auto controller = std::make_unique<ChooseRecipientBoxController>(
[items = std::move(items)](not_null<PeerData*> peer) {
App::main()->setForwardDraft(peer->id, items);
});
Ui::show(Box<PeerListBox>(
std::move(controller),
[](not_null<PeerListBox*> 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<DeleteMessagesBox>(selected));
if (!selected.empty()) {
Ui::show(Box<DeleteMessagesBox>(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<DeleteMessagesBox>(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);
}

View File

@ -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<HistoryHider> 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<PeerData*> peer,
const QString &url,

View File

@ -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() {

View File

@ -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<UserData*> user) {
}));
}
void ShowForwardMessagesBox(
MessageIdsList &&items,
base::lambda_once<void()> &&successCallback) {
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()) {
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);
}
void PeerMenuAddChannelMembers(not_null<ChannelData*> channel) {
if (channel->isMegagroup()) {
auto &participants = channel->mgInfo->lastParticipants;

View File

@ -45,4 +45,8 @@ void PeerMenuShareContactBox(not_null<UserData*> user);
void PeerMenuAddContact(not_null<UserData*> user);
void PeerMenuAddChannelMembers(not_null<ChannelData*> channel);
void ShowForwardMessagesBox(
MessageIdsList &&items,
base::lambda_once<void()> &&successCallback = nullptr);
} // namespace Window