diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 375f2b17a..5fd01d4fc 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -28,6 +28,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "history/history_media_types.h" #include "ui/widgets/popup_menu.h" #include "window/window_controller.h" +#include "window/window_peer_menu.h" +#include "boxes/confirm_box.h" #include "chat_helpers/message_field.h" #include "chat_helpers/stickers.h" #include "history/history_widget.h" @@ -1110,7 +1112,7 @@ void HistoryInner::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton bu && !_pressWasInactive && !_selected.empty() && (_selected.cbegin()->second == FullSelection)) { - changeDragSelection( + changeSelectionAsGroup( &_selected, _mouseActionItem, SelectAction::Invert); @@ -1220,7 +1222,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { isUponSelected = -1; if (_selected.cbegin()->second == FullSelection) { hasSelected = 2; - if (App::hoveredItem() && _selected.find(App::hoveredItem()) != _selected.cend()) { + if (_dragStateItem && _selected.find(_dragStateItem) != _selected.cend()) { isUponSelected = 2; } else { isUponSelected = -2; @@ -1307,23 +1309,35 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { })); } _menu->addAction(lang(lng_context_clear_selection), _widget, SLOT(onClearSelected())); - } else if (App::hoveredLinkItem()) { + } else if (_dragStateItem) { if (isUponSelected != -2) { - if (App::hoveredLinkItem()->canForward()) { - _menu->addAction(lang(lng_context_forward_msg), _widget, SLOT(forwardMessage()))->setEnabled(true); + if (_dragStateItem->canForward()) { + _menu->addAction(lang(lng_context_forward_msg), base::lambda_guarded(this, [this] { + if (const auto item = App::contextItem()) { + forwardItem(item); + } + }))->setEnabled(true); } - if (App::hoveredLinkItem()->canDelete()) { + if (_dragStateItem->canDelete()) { _menu->addAction(lang(lng_context_delete_msg), base::lambda_guarded(this, [this] { - _widget->confirmDeleteContextItem(); + if (const auto item = App::contextItem()) { + deleteItem(item); + } })); } } - if (App::hoveredLinkItem()->id > 0 && !App::hoveredLinkItem()->serviceMsg()) { + if (_dragStateItem && _dragStateItem->id > 0 && !_dragStateItem->serviceMsg()) { _menu->addAction(lang(lng_context_select_msg), base::lambda_guarded(this, [this] { - // TODO + if (const auto item = App::contextItem()) { + if (!item->detached()) { + changeSelection(&_selected, item, SelectAction::Select); + repaintItem(item); + _widget->updateTopBarSelection(); + } + } }))->setEnabled(true); } - App::contextItem(App::hoveredLinkItem()); + App::contextItem(_dragStateItem); } } else { // maybe cursor on some text history item? bool canDelete = item && item->canDelete() && (item->id > 0 || !item->serviceMsg()); @@ -1421,23 +1435,46 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } _menu->addAction(lang(lng_context_clear_selection), _widget, SLOT(onClearSelected())); } else if (item && ((isUponSelected != -2 && (canForward || canDelete)) || item->id > 0)) { + const auto fullId = item->fullId(); if (isUponSelected != -2) { if (canForward) { - _menu->addAction(lang(lng_context_forward_msg), _widget, SLOT(forwardMessage()))->setEnabled(true); + _menu->addAction(lang(lng_context_forward_msg), base::lambda_guarded(this, [this] { + if (const auto item = App::contextItem()) { + forwardAsGroup(item); + } + }))->setEnabled(true); } if (canDelete) { _menu->addAction(lang((msg && msg->uploading()) ? lng_context_cancel_upload : lng_context_delete_msg), base::lambda_guarded(this, [this] { - _widget->confirmDeleteContextItem(); + if (const auto item = App::contextItem()) { + deleteAsGroup(item); + } })); } } if (item->id > 0 && !item->serviceMsg()) { - _menu->addAction(lang(lng_context_select_msg), _widget, SLOT(selectMessage()))->setEnabled(true); + _menu->addAction(lang(lng_context_select_msg), base::lambda_guarded(this, [this] { + if (const auto item = App::contextItem()) { + if (!item->detached()) { + changeSelectionAsGroup(&_selected, item, SelectAction::Select); + repaintItem(item); + _widget->updateTopBarSelection(); + } + } + }))->setEnabled(true); } } else { if (App::mousedItem() && !App::mousedItem()->serviceMsg() && App::mousedItem()->id > 0) { - _menu->addAction(lang(lng_context_select_msg), _widget, SLOT(selectMessage()))->setEnabled(true); + _menu->addAction(lang(lng_context_select_msg), base::lambda_guarded(this, [this] { + if (const auto item = App::contextItem()) { + if (!item->detached()) { + changeSelectionAsGroup(&_selected, item, SelectAction::Select); + repaintItem(item); + _widget->updateTopBarSelection(); + } + } + }))->setEnabled(true); item = App::mousedItem(); } } @@ -2428,112 +2465,169 @@ void HistoryInner::applyDragSelection() { applyDragSelection(&_selected); } -bool HistoryInner::isFullSelected( +HistoryMessageGroup *HistoryInner::itemGroup( + not_null item) const { + if (const auto group = item->Get()) { + if (group->leader == item) { + return group; + } + return group->leader->Get(); + } + return nullptr; +} + +bool HistoryInner::isSelected( not_null toItems, not_null item) const { - const auto group = [&] { - if (const auto group = item->Get()) { - if (group->leader == item) { - return group; - } - return group->leader->Get(); - } - return (HistoryMessageGroup*)nullptr; - }(); - const auto singleSelected = [&](not_null item) { - const auto i = toItems->find(item); - return (i != toItems->cend()) && (i->second == FullSelection); - }; - if (group) { - if (!singleSelected(group->leader)) { + const auto i = toItems->find(item); + return (i != toItems->cend()) && (i->second == FullSelection); +} + +bool HistoryInner::isSelectedAsGroup( + not_null toItems, + not_null item) const { + if (const auto group = itemGroup(item)) { + if (!isSelected(toItems, group->leader)) { return false; } for (const auto other : group->others) { - if (!singleSelected(other)) { + if (!isSelected(toItems, other)) { return false; } } - } else if (!singleSelected(item)) { + return true; + } + return isSelected(toItems, item); +} + +bool HistoryInner::goodForSelection( + not_null toItems, + not_null item, + int &totalCount) const { + if (item->id <= 0 || item->serviceMsg()) { return false; } + if (toItems->find(item) == toItems->end()) { + ++totalCount; + } return true; } -void HistoryInner::changeDragSelection( +void HistoryInner::addToSelection( + not_null toItems, + not_null item) const { + const auto i = toItems->find(item); + if (i == toItems->cend()) { + toItems->emplace(item, FullSelection); + } else if (i->second != FullSelection) { + i->second = FullSelection; + } +} + +void HistoryInner::removeFromSelection( + not_null toItems, + not_null item) const { + const auto i = toItems->find(item); + if (i != toItems->cend()) { + toItems->erase(i); + } +} + +void HistoryInner::changeSelection( not_null toItems, not_null item, SelectAction action) const { if (action == SelectAction::Invert) { - action = isFullSelected(toItems, item) + action = isSelected(toItems, item) ? SelectAction::Deselect : SelectAction::Select; } - auto total = toItems->size(); + auto total = int(toItems->size()); const auto add = (action == SelectAction::Select); - const auto goodForAdding = [&](not_null item) { - if (item->id <= 0 || item->serviceMsg()) { + if (add + && goodForSelection(toItems, item, total) + && total <= MaxSelectedItems) { + addToSelection(toItems, item); + } else { + removeFromSelection(toItems, item); + } +} + +void HistoryInner::changeSelectionAsGroup( + not_null toItems, + not_null item, + SelectAction action) const { + const auto group = itemGroup(item); + if (!group) { + return changeSelection(toItems, item, action); + } + if (action == SelectAction::Invert) { + action = isSelectedAsGroup(toItems, item) + ? SelectAction::Deselect + : SelectAction::Select; + } + auto total = int(toItems->size()); + const auto add = (action == SelectAction::Select); + + const auto adding = [&] { + if (!add || !goodForSelection(toItems, group->leader, total)) { return false; } - if (toItems->find(item) == toItems->end()) { - ++total; - } - return true; - }; - const auto addSingle = [&](not_null item) { - const auto i = toItems->find(item); - if (i == toItems->cend()) { - toItems->emplace(item, FullSelection); - } else if (i->second != FullSelection) { - i->second = FullSelection; - } - }; - const auto removeSingle = [&](not_null item) { - const auto i = toItems->find(item); - if (i != toItems->cend()) { - toItems->erase(i); - } - }; - const auto group = [&] { - if (const auto group = item->Get()) { - if (group->leader == item) { - return group; - } - return group->leader->Get(); - } - return (HistoryMessageGroup*)nullptr; - }(); - if (group) { - const auto adding = [&] { - if (!add || !goodForAdding(group->leader)) { + for (const auto other : group->others) { + if (!goodForSelection(toItems, other, total)) { return false; } - for (const auto other : group->others) { - if (!goodForAdding(other)) { - return false; - } - } - return (total <= MaxSelectedItems); - }(); - if (adding) { - addSingle(group->leader); - for (const auto other : group->others) { - addSingle(other); - } - } else { - removeSingle(group->leader); - for (const auto other : group->others) { - removeSingle(other); - } + } + return (total <= MaxSelectedItems); + }(); + if (adding) { + addToSelection(toItems, group->leader); + for (const auto other : group->others) { + addToSelection(toItems, other); } } else { - if (add && goodForAdding(item) && total <= MaxSelectedItems) { - addSingle(item); - } else { - removeSingle(item); + removeFromSelection(toItems, group->leader); + for (const auto other : group->others) { + removeFromSelection(toItems, other); } } } +void HistoryInner::forwardItem(not_null item) { + Window::ShowForwardMessagesBox({ 1, item->fullId() }); +} + +void HistoryInner::forwardAsGroup(not_null item) { + if (const auto group = itemGroup(item)) { + auto items = Auth().data().itemsToIds(group->others); + items.push_back(group->leader->fullId()); + Window::ShowForwardMessagesBox(std::move(items)); + } else { + Window::ShowForwardMessagesBox({ 1, item->fullId() }); + } +} + +void HistoryInner::deleteItem(not_null item) { + if (auto message = item->toHistoryMessage()) { + if (message->uploading()) { + App::main()->cancelUploadLayer(); + return; + } + } + const auto suggestModerateActions = true; + Ui::show(Box(item, suggestModerateActions)); +} + +void HistoryInner::deleteAsGroup(not_null item) { + const auto group = itemGroup(item); + if (!group || group->others.empty()) { + return deleteItem(item); + } + auto items = Auth().data().itemsToIds(group->others); + items.push_back(group->leader->fullId()); + Ui::show(Box(std::move(items))); +} + void HistoryInner::addSelectionRange( not_null toItems, not_null history, @@ -2546,7 +2640,7 @@ void HistoryInner::addSelectionRange( auto block = history->blocks[fromblock]; for (int cnt = (fromblock < toblock) ? block->items.size() : (toitem + 1); fromitem < cnt; ++fromitem) { auto item = block->items[fromitem]; - changeDragSelection(toItems, item, SelectAction::Select); + changeSelectionAsGroup(toItems, item, SelectAction::Select); } if (toItems->size() >= MaxSelectedItems) break; fromitem = 0; @@ -2601,7 +2695,7 @@ void HistoryInner::applyDragSelection( } } for (const auto item : toRemove) { - changeDragSelection(toItems, item, SelectAction::Deselect); + changeSelectionAsGroup(toItems, item, SelectAction::Deselect); } } } diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 92c9e0dec..0681b0d25 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -141,6 +141,12 @@ private: Selecting, }; + enum class SelectAction { + Select, + Deselect, + Invert, + }; + void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button); void mouseActionUpdate(const QPoint &screenPos); void mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button); @@ -220,6 +226,8 @@ private: style::cursor _cursor = style::cur_default; using SelectedItems = std::map>; SelectedItems _selected; + + HistoryMessageGroup *itemGroup(not_null item) const; void applyDragSelection(); void applyDragSelection(not_null toItems) const; void addSelectionRange( @@ -229,18 +237,34 @@ private: int fromitem, int toblock, int toitem) const; - bool isFullSelected( + bool isSelected( not_null toItems, not_null item) const; - enum class SelectAction { - Select, - Deselect, - Invert, - }; - void changeDragSelection( + bool isSelectedAsGroup( + not_null toItems, + not_null item) const; + bool goodForSelection( + not_null toItems, + not_null item, + int &totalCount) const; + void addToSelection( + not_null toItems, + not_null item) const; + void removeFromSelection( + not_null toItems, + not_null item) const; + void changeSelection( not_null toItems, not_null item, SelectAction action) const; + void changeSelectionAsGroup( + not_null toItems, + not_null item, + SelectAction action) const; + void forwardItem(not_null item); + void forwardAsGroup(not_null item); + void deleteItem(not_null item); + void deleteAsGroup(not_null item); // Does any of the shown histories has this flag set. bool hasPendingResizedItems() const { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 6401fcc0a..ecf8698ff 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -3735,20 +3735,6 @@ void HistoryWidget::onCmdStart() { setFieldText({ qsl("/"), TextWithTags::Tags() }, 0, Ui::FlatTextarea::AddToUndoHistory); } -void HistoryWidget::forwardMessage() { - auto item = App::contextItem(); - if (!item || item->id < 0 || item->serviceMsg()) return; - - Window::ShowForwardMessagesBox({ 1, item->fullId() }); -} - -void HistoryWidget::selectMessage() { - auto item = App::contextItem(); - if (!item || item->id < 0 || item->serviceMsg()) return; - - if (_list) _list->selectItem(item); -} - void HistoryWidget::setMembersShowAreaActive(bool active) { if (!active) { _membersDropdownShowTimer.stop(); @@ -6198,19 +6184,6 @@ void HistoryWidget::onForwardSelected() { }); } -void HistoryWidget::confirmDeleteContextItem() { - auto item = App::contextItem(); - if (!item) return; - - if (auto message = item->toHistoryMessage()) { - if (message->uploading()) { - App::main()->cancelUploadLayer(); - return; - } - } - App::main()->deleteLayer(); -} - void HistoryWidget::confirmDeleteSelectedItems() { if (!_list) return; @@ -6220,29 +6193,6 @@ void HistoryWidget::confirmDeleteSelectedItems() { App::main()->deleteLayer(int(selected.size())); } -void HistoryWidget::deleteContextItem(bool forEveryone) { - Ui::hideLayer(); - - auto item = App::contextItem(); - if (!item) { - return; - } - - auto toDelete = QVector(1, MTP_int(item->id)); - auto history = item->history(); - auto wasOnServer = (item->id > 0); - auto wasLast = (history->lastMsg == item); - item->destroy(); - - if (!wasOnServer && wasLast && !history->lastMsg) { - App::main()->checkPeerHistory(history->peer); - } - - if (wasOnServer) { - App::main()->deleteMessages(history->peer, toDelete, forEveryone); - } -} - void HistoryWidget::deleteSelectedItems(bool forEveryone) { Ui::hideLayer(); if (!_list) return; diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 843f19d7c..bc017eb93 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -325,9 +325,7 @@ public: bool isItemVisible(HistoryItem *item); - void confirmDeleteContextItem(); void confirmDeleteSelectedItems(); - void deleteContextItem(bool forEveryone); void deleteSelectedItems(bool forEveryone); // Float player interface. @@ -414,9 +412,6 @@ public slots: void onWindowVisibleChanged(); - void forwardMessage(); - void selectMessage(); - void onFieldFocused(); void onFieldResize(); void onCheckFieldAutocomplete(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 20e08e50e..c730f4345 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -965,9 +965,18 @@ void MainWidget::cancelUploadLayer() { return; } - Auth().uploader().pause(item->fullId()); - Ui::show(Box(lang(lng_selected_cancel_sure_this), lang(lng_selected_upload_stop), lang(lng_continue), base::lambda_guarded(this, [this] { - _history->deleteContextItem(false); + const auto itemId = item->fullId(); + Auth().uploader().pause(itemId); + Ui::show(Box(lang(lng_selected_cancel_sure_this), lang(lng_selected_upload_stop), lang(lng_continue), base::lambda_guarded(this, [=] { + Ui::hideLayer(); + if (const auto item = App::histItemById(itemId)) { + const auto history = item->history(); + const auto wasLast = (history->lastMsg == item); + item->destroy(); + if (wasLast && !history->lastMsg) { + checkPeerHistory(history->peer); + } + } Auth().uploader().unpause(); }), base::lambda_guarded(this, [] { Auth().uploader().unpause();