diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 207809bf0..10c5b47cd 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -89,11 +89,10 @@ namespace { using SentData = QMap>; SentData sentData; - HistoryItem *hoveredItem = nullptr, + HistoryView::Message *hoveredItem = nullptr, *pressedItem = nullptr, *hoveredLinkItem = nullptr, *pressedLinkItem = nullptr, - *contextItem = nullptr, *mousedItem = nullptr; QPixmap *emoji = nullptr, *emojiLarge = nullptr; @@ -934,7 +933,7 @@ namespace { : nullptr); existing->setViewsCount(m.has_views() ? m.vviews.v : -1); existing->indexAsNewItem(); - if (!existing->detached()) { + if (existing->mainView()) { App::checkSavedGif(existing); return true; } @@ -1836,23 +1835,20 @@ namespace { } } - void historyItemDetached(HistoryItem *item) { - if (::hoveredItem == item) { + void messageViewDestroyed(not_null view) { + if (::hoveredItem == view) { hoveredItem(nullptr); } - if (::pressedItem == item) { + if (::pressedItem == view) { pressedItem(nullptr); } - if (::hoveredLinkItem == item) { + if (::hoveredLinkItem == view) { hoveredLinkItem(nullptr); } - if (::pressedLinkItem == item) { + if (::pressedLinkItem == view) { pressedLinkItem(nullptr); } - if (::contextItem == item) { - contextItem(nullptr); - } - if (::mousedItem == item) { + if (::mousedItem == view) { mousedItem(nullptr); } } @@ -1867,7 +1863,6 @@ namespace { data->erase(i); } } - historyItemDetached(item); auto j = ::dependentItems.find(item); if (j != ::dependentItems.cend()) { DependentItemsSet items; @@ -1903,13 +1898,13 @@ namespace { QVector toDelete; for_const (auto item, msgsData) { - if (item->detached()) { + if (!item->mainView()) { toDelete.push_back(item); } } for_const (auto &chMsgsData, channelMsgsData) { for_const (auto item, chMsgsData) { - if (item->detached()) { + if (!item->mainView()) { toDelete.push_back(item); } } @@ -2187,51 +2182,43 @@ namespace { clearAllImages(); } - void hoveredItem(HistoryItem *item) { + void hoveredItem(HistoryView::Message *item) { ::hoveredItem = item; } - HistoryItem *hoveredItem() { + HistoryView::Message *hoveredItem() { return ::hoveredItem; } - void pressedItem(HistoryItem *item) { + void pressedItem(HistoryView::Message *item) { ::pressedItem = item; } - HistoryItem *pressedItem() { + HistoryView::Message *pressedItem() { return ::pressedItem; } - void hoveredLinkItem(HistoryItem *item) { + void hoveredLinkItem(HistoryView::Message *item) { ::hoveredLinkItem = item; } - HistoryItem *hoveredLinkItem() { + HistoryView::Message *hoveredLinkItem() { return ::hoveredLinkItem; } - void pressedLinkItem(HistoryItem *item) { + void pressedLinkItem(HistoryView::Message *item) { ::pressedLinkItem = item; } - HistoryItem *pressedLinkItem() { + HistoryView::Message *pressedLinkItem() { return ::pressedLinkItem; } - void contextItem(HistoryItem *item) { - ::contextItem = item; - } - - HistoryItem *contextItem() { - return ::contextItem; - } - - void mousedItem(HistoryItem *item) { + void mousedItem(HistoryView::Message *item) { ::mousedItem = item; } - HistoryItem *mousedItem() { + HistoryView::Message *mousedItem() { return ::mousedItem; } @@ -2240,7 +2227,6 @@ namespace { pressedItem(nullptr); hoveredLinkItem(nullptr); pressedLinkItem(nullptr); - contextItem(nullptr); mousedItem(nullptr); } diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 16fb2a46d..c0bd75b79 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -15,6 +15,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class Messenger; class MainWindow; class MainWidget; +class LocationCoords; +struct LocationData; + +namespace HistoryView { +class Message; +} // namespace HistoryView using HistoryItemsMap = OrderedSet; using PhotoItems = QHash; @@ -27,9 +33,6 @@ using GifItems = QHash; using PhotosData = QHash; using DocumentsData = QHash; -class LocationCoords; -struct LocationData; - namespace App { MainWindow *wnd(); MainWidget *main(); @@ -190,13 +193,13 @@ namespace App { return histItemById(msgId.channel, msgId.msg); } void historyRegItem(HistoryItem *item); - void historyItemDetached(HistoryItem *item); void historyUnregItem(HistoryItem *item); void historyUpdateDependent(HistoryItem *item); void historyClearMsgs(); void historyClearItems(); void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency); void historyUnregDependency(HistoryItem *dependent, HistoryItem *dependency); + void messageViewDestroyed(not_null view); void historyRegRandom(uint64 randomId, const FullMsgId &itemId); void historyUnregRandom(uint64 randomId); @@ -205,18 +208,16 @@ namespace App { void historyUnregSentData(uint64 randomId); void histSentDataByItem(uint64 randomId, PeerId &peerId, QString &text); - void hoveredItem(HistoryItem *item); - HistoryItem *hoveredItem(); - void pressedItem(HistoryItem *item); - HistoryItem *pressedItem(); - void hoveredLinkItem(HistoryItem *item); - HistoryItem *hoveredLinkItem(); - void pressedLinkItem(HistoryItem *item); - HistoryItem *pressedLinkItem(); - void contextItem(HistoryItem *item); - HistoryItem *contextItem(); - void mousedItem(HistoryItem *item); - HistoryItem *mousedItem(); + void hoveredItem(HistoryView::Message *item); + HistoryView::Message *hoveredItem(); + void pressedItem(HistoryView::Message *item); + HistoryView::Message *pressedItem(); + void hoveredLinkItem(HistoryView::Message *item); + HistoryView::Message *hoveredLinkItem(); + void pressedLinkItem(HistoryView::Message *item); + HistoryView::Message *pressedLinkItem(); + void mousedItem(HistoryView::Message *item); + HistoryView::Message *mousedItem(); void clearMousedItems(); const style::font &monofont(); diff --git a/Telegram/SourceFiles/core/click_handler_types.cpp b/Telegram/SourceFiles/core/click_handler_types.cpp index bcd8a03ac..8f9918c28 100644 --- a/Telegram/SourceFiles/core/click_handler_types.cpp +++ b/Telegram/SourceFiles/core/click_handler_types.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "messenger.h" #include "platform/platform_specific.h" +#include "history/view/history_view_message.h" #include "boxes/confirm_box.h" #include "base/qthelp_regex.h" #include "base/qthelp_url.h" @@ -241,10 +242,11 @@ void BotCommandClickHandler::onClick(Qt::MouseButton button) const { } if (auto peer = Ui::getPeerForMouseAction()) { // old way - UserData *bot = peer->isUser() ? peer->asUser() : nullptr; - if (auto item = App::hoveredLinkItem()) { - if (!bot) { - bot = item->fromOriginal()->asUser(); // may return nullptr + auto bot = peer->isUser() ? peer->asUser() : nullptr; + if (!bot) { + if (const auto view = App::hoveredLinkItem()) { + // may return nullptr + bot = view->data()->fromOriginal()->asUser(); } } Ui::showPeerHistory(peer, ShowAtTheEndMsgId); diff --git a/Telegram/SourceFiles/core/utils.h b/Telegram/SourceFiles/core/utils.h index c0d28c498..fdfff3be2 100644 --- a/Telegram/SourceFiles/core/utils.h +++ b/Telegram/SourceFiles/core/utils.h @@ -527,7 +527,6 @@ inline int ceilclamp(float64 value, int32 step, int32 lowest, int32 highest) { enum ForwardWhatMessages { ForwardSelectedMessages, - ForwardContextMessage, ForwardPressedMessage, ForwardPressedLinkMessage }; diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 56a3df4c2..ffe275015 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -336,7 +336,9 @@ void DocumentSaveClickHandler::doSave( bool forceSavingAs) { if (!data->date) return; - auto filepath = data->filepath(DocumentData::FilePathResolveSaveFromDataSilent, forceSavingAs); + auto filepath = data->filepath( + DocumentData::FilePathResolveSaveFromDataSilent, + forceSavingAs); if (!filepath.isEmpty() && !forceSavingAs) { File::OpenWith(filepath, QCursor::pos()); } else { @@ -345,9 +347,7 @@ void DocumentSaveClickHandler::doSave( auto filename = filepath.isEmpty() ? QString() : fileinfo.fileName(); auto newfname = documentSaveFilename(data, forceSavingAs, filename, filedir); if (!newfname.isEmpty()) { - auto action = (filename.isEmpty() || forceSavingAs) ? ActionOnLoadNone : ActionOnLoadOpenWith; - auto actionMsgId = App::hoveredLinkItem() ? App::hoveredLinkItem()->fullId() : (App::contextItem() ? App::contextItem()->fullId() : FullMsgId()); - data->save(newfname, action, actionMsgId); + data->save(newfname, ActionOnLoadNone, FullMsgId()); } } } @@ -362,8 +362,7 @@ void DocumentCancelClickHandler::onClickImpl() const { if (data->uploading()) { if (const auto item = App::histItemById(context())) { - App::contextItem(item); - App::main()->cancelUploadLayer(); + App::main()->cancelUploadLayer(item); } } else { data->cancel(); diff --git a/Telegram/SourceFiles/data/data_photo.cpp b/Telegram/SourceFiles/data/data_photo.cpp index 1c645f91b..ca109aec7 100644 --- a/Telegram/SourceFiles/data/data_photo.cpp +++ b/Telegram/SourceFiles/data/data_photo.cpp @@ -137,8 +137,7 @@ void PhotoCancelClickHandler::onClickImpl() const { if (data->uploading()) { if (const auto item = App::histItemById(context())) { - App::contextItem(item); - App::main()->cancelUploadLayer(); + App::main()->cancelUploadLayer(item); } } else { data->cancel(); diff --git a/Telegram/SourceFiles/data/data_types.cpp b/Telegram/SourceFiles/data/data_types.cpp index 70b2645cf..9438d4b9f 100644 --- a/Telegram/SourceFiles/data/data_types.cpp +++ b/Telegram/SourceFiles/data/data_types.cpp @@ -44,9 +44,5 @@ void MessageCursor::applyTo(QTextEdit *edit) { HistoryItem *FileClickHandler::getActionItem() const { return context() ? App::histItemById(context()) - : App::hoveredLinkItem() - ? App::hoveredLinkItem() - : App::contextItem() - ? App::contextItem() : nullptr; } diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp index cd0b40735..a5e9582df 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -418,13 +418,14 @@ void InnerWidget::updateEmptyText() { QString InnerWidget::tooltipText() const { if (_mouseCursorState == HistoryInDateCursorState && _mouseAction == MouseAction::None) { - if (const auto item = App::hoveredItem()) { - auto dateText = item->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat)); + if (const auto view = App::hoveredItem()) { + auto dateText = view->data()->date.toString( + QLocale::system().dateTimeFormat(QLocale::LongFormat)); return dateText; } } else if (_mouseCursorState == HistoryInForwardedCursorState && _mouseAction == MouseAction::None) { - if (const auto item = App::hoveredItem()) { - if (const auto forwarded = item->Get()) { + if (const auto view = App::hoveredItem()) { + if (const auto forwarded = view->data()->Get()) { return forwarded->text.originalText(AllTextSelection, ExpandLinksNone); } } @@ -808,10 +809,6 @@ void InnerWidget::contextMenuEvent(QContextMenuEvent *e) { } void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { - if (_menu) { - _menu->deleteLater(); - _menu = 0; - } if (e->reason() == QContextMenuEvent::Mouse) { mouseActionUpdate(e->globalPos()); } @@ -828,10 +825,10 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (App::mousedItem() && App::mousedItem() == App::hoveredItem()) { auto mousePos = mapPointToItem( mapFromGlobal(_mousePosition), - viewForItem(App::mousedItem())); + App::mousedItem()); HistoryStateRequest request; request.flags |= Text::StateRequest::Flag::LookupSymbol; - auto dragState = App::mousedItem()->getState(mousePos, request); + auto dragState = App::mousedItem()->data()->getState(mousePos, request); if (dragState.cursor == HistoryInTextCursorState && dragState.symbol >= selFrom && dragState.symbol < selTo) { isUponSelected = 1; } @@ -841,10 +838,12 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { isUponSelected = hasSelected; } - _menu = new Ui::PopupMenu(nullptr); + _menu = base::make_unique_q(nullptr); _contextMenuLink = ClickHandler::getActive(); - auto item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem(); + auto view = App::hoveredItem() + ? App::hoveredItem() + : App::hoveredLinkItem(); auto lnkPhoto = dynamic_cast(_contextMenuLink.get()); auto lnkDocument = dynamic_cast(_contextMenuLink.get()); auto lnkPeer = dynamic_cast(_contextMenuLink.get()); @@ -853,41 +852,52 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { auto lnkIsAudio = lnkDocument ? lnkDocument->document()->isAudioFile() : false; if (lnkPhoto || lnkDocument) { if (isUponSelected > 0) { - _menu->addAction(lang(lng_context_copy_selected), [this] { copySelectedText(); })->setEnabled(true); + _menu->addAction(lang(lng_context_copy_selected), [=] { + copySelectedText(); + })->setEnabled(true); } if (lnkPhoto) { - _menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, photo = lnkPhoto->photo()] { + const auto photo = lnkPhoto->photo(); + _menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [=] { savePhotoToFile(photo); }))->setEnabled(true); - _menu->addAction(lang(lng_context_copy_image), [this, photo = lnkPhoto->photo()] { + _menu->addAction(lang(lng_context_copy_image), [=] { copyContextImage(photo); })->setEnabled(true); } else { auto document = lnkDocument->document(); if (document->loading()) { - _menu->addAction(lang(lng_context_cancel_download), [this] { cancelContextDownload(); })->setEnabled(true); + _menu->addAction(lang(lng_context_cancel_download), [=] { + cancelContextDownload(document); + })->setEnabled(true); } else { if (document->loaded() && document->isGifv()) { if (!cAutoPlayGif()) { - _menu->addAction(lang(lng_context_open_gif), [this] { openContextGif(); })->setEnabled(true); + const auto itemId = view + ? view->data()->fullId() + : FullMsgId(); + _menu->addAction(lang(lng_context_open_gif), [=] { + openContextGif(itemId); + })->setEnabled(true); } } if (!document->filepath(DocumentData::FilePathResolveChecked).isEmpty()) { - _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [this] { showContextInFolder(); })->setEnabled(true); + _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [=] { + showContextInFolder(document); + })->setEnabled(true); } _menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsVoice ? lng_context_save_audio : (lnkIsAudio ? lng_context_save_audio_file : lng_context_save_file))), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] { saveDocumentToFile(document); }))->setEnabled(true); } } - if (App::hoveredLinkItem()) { - App::contextItem(App::hoveredLinkItem()); - } } else if (lnkPeer) { // suggest to block if (auto user = lnkPeer->peer()->asUser()) { suggestRestrictUser(user); } } else { // maybe cursor on some text history item? + const auto item = view ? view->data().get() : nullptr; + const auto itemId = item ? item->fullId() : FullMsgId(); bool canDelete = item && item->canDelete() && (item->id > 0 || !item->serviceMsg()); bool canForward = item && item->canForward(); @@ -903,9 +913,11 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { media = static_cast(media)->attach(); } if (media->type() == MediaTypeSticker) { - if (auto document = media->getDocument()) { + if (const auto document = media->getDocument()) { if (document->sticker() && document->sticker()->set.type() != mtpc_inputStickerSetEmpty) { - _menu->addAction(lang(document->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), [this] { showStickerPackInfo(); }); + _menu->addAction(lang(document->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), [=] { + showStickerPackInfo(document); + }); } _menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] { saveDocumentToFile(document); @@ -914,15 +926,21 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } else if (media->type() == MediaTypeGif && !_contextMenuLink) { if (auto document = media->getDocument()) { if (document->loading()) { - _menu->addAction(lang(lng_context_cancel_download), [this] { cancelContextDownload(); })->setEnabled(true); + _menu->addAction(lang(lng_context_cancel_download), [=] { + cancelContextDownload(document); + })->setEnabled(true); } else { if (document->isGifv()) { if (!cAutoPlayGif()) { - _menu->addAction(lang(lng_context_open_gif), [this] { openContextGif(); })->setEnabled(true); + _menu->addAction(lang(lng_context_open_gif), [=] { + openContextGif(itemId); + })->setEnabled(true); } } if (!document->filepath(DocumentData::FilePathResolveChecked).isEmpty()) { - _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [this] { showContextInFolder(); })->setEnabled(true); + _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [=] { + showContextInFolder(document); + })->setEnabled(true); } _menu->addAction(lang(lng_context_save_file), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] { saveDocumentToFile(document); @@ -932,7 +950,9 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } } if (msg && !_contextMenuLink && (!msg->emptyText() || mediaHasTextForCopy)) { - _menu->addAction(lang(lng_context_copy_text), [this] { copyContextText(); })->setEnabled(true); + _menu->addAction(lang(lng_context_copy_text), [=] { + copyContextText(itemId); + })->setEnabled(true); } } } @@ -941,17 +961,11 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (!linkCopyToClipboardText.isEmpty()) { _menu->addAction(linkCopyToClipboardText, [this] { copyContextUrl(); })->setEnabled(true); } - App::contextItem(item); } if (_menu->actions().isEmpty()) { - delete base::take(_menu); + _menu = nullptr; } else { - connect(_menu, &QObject::destroyed, this, [this](QObject *object) { - if (_menu == object) { - _menu = nullptr; - } - }); _menu->popup(e->globalPos()); e->accept(); } @@ -961,11 +975,15 @@ void InnerWidget::savePhotoToFile(PhotoData *photo) { if (!photo || !photo->date || !photo->loaded()) return; auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter(); - FileDialog::GetWritePath(lang(lng_save_photo), filter, filedialogDefaultName(qsl("photo"), qsl(".jpg")), base::lambda_guarded(this, [this, photo](const QString &result) { - if (!result.isEmpty()) { - photo->full->pix().toImage().save(result, "JPG"); - } - })); + FileDialog::GetWritePath( + lang(lng_save_photo), + filter, + filedialogDefaultName(qsl("photo"), qsl(".jpg")), + base::lambda_guarded(this, [=](const QString &result) { + if (!result.isEmpty()) { + photo->full->pix().toImage().save(result, "JPG"); + } + })); } void InnerWidget::saveDocumentToFile(DocumentData *document) { @@ -988,50 +1006,28 @@ void InnerWidget::copyContextUrl() { } } -void InnerWidget::showStickerPackInfo() { - if (!App::contextItem()) return; - - if (auto media = App::contextItem()->getMedia()) { - if (auto doc = media->getDocument()) { - if (auto sticker = doc->sticker()) { - if (sticker->set.type() != mtpc_inputStickerSetEmpty) { - App::main()->stickersBox(sticker->set); - } - } +void InnerWidget::showStickerPackInfo(not_null document) { + if (auto sticker = document->sticker()) { + if (sticker->set.type() != mtpc_inputStickerSetEmpty) { + App::main()->stickersBox(sticker->set); } } } -void InnerWidget::cancelContextDownload() { - if (auto lnkDocument = dynamic_cast(_contextMenuLink.get())) { - lnkDocument->document()->cancel(); - } else if (auto item = App::contextItem()) { - if (auto media = item->getMedia()) { - if (auto doc = media->getDocument()) { - doc->cancel(); - } - } - } +void InnerWidget::cancelContextDownload(not_null document) { + document->cancel(); } -void InnerWidget::showContextInFolder() { - QString filepath; - if (auto lnkDocument = dynamic_cast(_contextMenuLink.get())) { - filepath = lnkDocument->document()->filepath(DocumentData::FilePathResolveChecked); - } else if (auto item = App::contextItem()) { - if (auto media = item->getMedia()) { - if (auto doc = media->getDocument()) { - filepath = doc->filepath(DocumentData::FilePathResolveChecked); - } - } - } +void InnerWidget::showContextInFolder(not_null document) { + const auto filepath = document->filepath( + DocumentData::FilePathResolveChecked); if (!filepath.isEmpty()) { File::ShowInFolder(filepath); } } -void InnerWidget::openContextGif() { - if (auto item = App::contextItem()) { +void InnerWidget::openContextGif(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { if (auto media = item->getMedia()) { if (auto document = media->getDocument()) { Messenger::Instance().showDocument(document, item); @@ -1040,16 +1036,20 @@ void InnerWidget::openContextGif() { } } -void InnerWidget::copyContextText() { - auto item = App::contextItem(); - if (!item || (item->getMedia() && item->getMedia()->type() == MediaTypeSticker)) { - return; +void InnerWidget::copyContextText(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { + if (const auto media = item->getMedia()) { + if (media->type() == MediaTypeSticker) { + return; + } + } + setToClipboard(item->selectedText(FullSelection)); } - - setToClipboard(item->selectedText(FullSelection)); } -void InnerWidget::setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode) { +void InnerWidget::setToClipboard( + const TextWithEntities &forClipboard, + QClipboard::Mode mode) { if (auto data = MimeDataFromTextWithEntities(forClipboard)) { QApplication::clipboard()->setMimeData(data.release(), mode); } @@ -1057,6 +1057,7 @@ void InnerWidget::setToClipboard(const TextWithEntities &forClipboard, QClipboar void InnerWidget::suggestRestrictUser(not_null user) { Expects(_menu != nullptr); + if (!_channel->isMegagroup() || !_channel->canBanMembers() || _admins.empty()) { return; } @@ -1065,8 +1066,8 @@ void InnerWidget::suggestRestrictUser(not_null user) { return; } } - _menu->addAction(lang(lng_context_restrict_user), [this, user] { - auto editRestrictions = [user, this](bool hasAdminRights, const MTPChannelBannedRights ¤tRights) { + _menu->addAction(lang(lng_context_restrict_user), [=] { + auto editRestrictions = [=](bool hasAdminRights, const MTPChannelBannedRights ¤tRights) { auto weak = QPointer(this); auto weakBox = std::make_shared>(); auto box = Box(_channel, user, hasAdminRights, currentRights); @@ -1085,7 +1086,7 @@ void InnerWidget::suggestRestrictUser(not_null user) { if (base::contains(_admins, user)) { editRestrictions(true, MTP_channelBannedRights(MTP_flags(0), MTP_int(0))); } else { - request(MTPchannels_GetParticipant(_channel->inputChannel, user->inputUser)).done([this, editRestrictions](const MTPchannels_ChannelParticipant &result) { + request(MTPchannels_GetParticipant(_channel->inputChannel, user->inputUser)).done([=](const MTPchannels_ChannelParticipant &result) { Expects(result.type() == mtpc_channels_channelParticipant); auto &participant = result.c_channels_channelParticipant(); @@ -1162,8 +1163,8 @@ void InnerWidget::enterEventHook(QEvent *e) { } void InnerWidget::leaveEventHook(QEvent *e) { - if (auto item = App::hoveredItem()) { - repaintItem(viewForItem(item)); + if (const auto view = App::hoveredItem()) { + repaintItem(view); App::hoveredItem(nullptr); } ClickHandler::clearActive(); @@ -1181,13 +1182,13 @@ void InnerWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butt ClickHandler::pressed(); if (App::pressedItem() != App::hoveredItem()) { - repaintItem(viewForItem(App::pressedItem())); + repaintItem(App::pressedItem()); App::pressedItem(App::hoveredItem()); - repaintItem(viewForItem(App::pressedItem())); + repaintItem(App::pressedItem()); } _mouseAction = MouseAction::None; - _mouseActionItem = viewForItem(App::mousedItem()); + _mouseActionItem = App::mousedItem(); _dragStartPosition = mapPointToItem( mapFromGlobal(screenPos), _mouseActionItem); @@ -1270,8 +1271,8 @@ void InnerWidget::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton but if (_mouseAction == MouseAction::Dragging) { activated = nullptr; } - if (App::pressedItem()) { - repaintItem(viewForItem(App::pressedItem())); + if (const auto view = App::pressedItem()) { + repaintItem(view); App::pressedItem(nullptr); } @@ -1318,23 +1319,25 @@ void InnerWidget::updateSelected() { const auto view = (from != end) ? from->get() : nullptr; const auto item = view ? view->data().get() : nullptr; if (item) { - App::mousedItem(item); + App::mousedItem(view); itemPoint = mapPointToItem(point, view); if (item->hasPoint(itemPoint)) { - if (App::hoveredItem() != item) { - repaintItem(viewForItem(App::hoveredItem())); - App::hoveredItem(item); + if (App::hoveredItem() != view) { + repaintItem(App::hoveredItem()); + App::hoveredItem(view); repaintItem(view); } - } else if (App::hoveredItem()) { - repaintItem(viewForItem(App::hoveredItem())); + } else if (const auto view = App::hoveredItem()) { + repaintItem(view); App::hoveredItem(nullptr); } } HistoryTextState dragState; ClickHandlerHost *lnkhost = nullptr; - auto selectingText = (view == _mouseActionItem && item == App::hoveredItem() && _selectedItem); + auto selectingText = _selectedItem + && (view == _mouseActionItem) + && (view == App::hoveredItem()); if (view) { if (view != _mouseActionItem || (itemPoint - _dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) { if (_mouseAction == MouseAction::PrepareDrag) { @@ -1422,13 +1425,9 @@ void InnerWidget::updateSelected() { } // Voice message seek support. - if (auto pressedItem = App::pressedLinkItem()) { - if (!pressedItem->detached()) { - if (pressedItem->history() == _history) { - auto adjustedPoint = mapPointToItem(point, viewForItem(pressedItem)); - pressedItem->updatePressed(adjustedPoint); - } - } + if (const auto pressedView = App::pressedLinkItem()) { + const auto adjustedPoint = mapPointToItem(point, pressedView); + pressedView->data()->updatePressed(adjustedPoint); } //if (_mouseAction == MouseAction::Selecting) { diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h index 58cbe930b..39b706fbc 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h @@ -121,12 +121,12 @@ private: void savePhotoToFile(PhotoData *photo); void saveDocumentToFile(DocumentData *document); void copyContextImage(PhotoData *photo); - void showStickerPackInfo(); + void showStickerPackInfo(not_null document); void copyContextUrl(); - void cancelContextDownload(); - void showContextInFolder(); - void openContextGif(); - void copyContextText(); + void cancelContextDownload(not_null document); + void showContextInFolder(not_null document); + void openContextGif(FullMsgId itemId); + void copyContextText(FullMsgId itemId); void copySelectedText(); TextWithEntities getSelectedText() const; void setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode = QClipboard::Clipboard); @@ -228,8 +228,7 @@ private: bool _wasSelectedText = false; // was some text selected in current drag action Qt::CursorShape _cursor = style::cur_default; - // context menu - Ui::PopupMenu *_menu = nullptr; + base::unique_qptr _menu; QPoint _trippleClickPoint; base::Timer _trippleClickTimer; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 2a33b0b6a..c6568788a 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -376,9 +376,9 @@ void ChannelHistory::getRangeDifference() { for (auto blockIndex = 0, blocksCount = int(blocks.size()); blockIndex < blocksCount; ++blockIndex) { const auto &block = blocks[blockIndex]; for (auto itemIndex = 0, itemsCount = int(block->messages.size()); itemIndex < itemsCount; ++itemIndex) { - const auto &message = block->messages[itemIndex]; - if (message->id() > 0) { - fromId = message->id(); + const auto id = block->messages[itemIndex]->data()->id; + if (id > 0) { + fromId = id; break; } } @@ -389,9 +389,9 @@ void ChannelHistory::getRangeDifference() { for (auto blockIndex = blocks.size(); blockIndex > 0;) { const auto &block = blocks[--blockIndex]; for (auto itemIndex = block->messages.size(); itemIndex > 0;) { - const auto &message = block->messages[--itemIndex]; - if (message->id() > 0) { - toId = message->id(); + const auto id = block->messages[--itemIndex]->data()->id; + if (id > 0) { + toId = id; break; } } @@ -420,11 +420,16 @@ void ChannelHistory::getRangeDifferenceNext(int32 pts) { } HistoryJoined *ChannelHistory::insertJoinedMessage(bool unread) { - if (_joinedMessage || !peer->asChannel()->amIn() || (peer->isMegagroup() && peer->asChannel()->mgInfo->joinedMessageFound)) { + if (_joinedMessage + || !peer->asChannel()->amIn() + || (peer->isMegagroup() + && peer->asChannel()->mgInfo->joinedMessageFound)) { return _joinedMessage; } - auto inviter = (peer->asChannel()->inviter > 0) ? App::userLoaded(peer->asChannel()->inviter) : nullptr; + const auto inviter = (peer->asChannel()->inviter > 0) + ? App::userLoaded(peer->asChannel()->inviter) + : nullptr; if (!inviter) return nullptr; MTPDmessage::Flags flags = 0; @@ -491,7 +496,7 @@ void ChannelHistory::checkJoinedMessage(bool createUnread) { if (isEmpty()) { if (loadedAtTop() && loadedAtBottom()) { if (insertJoinedMessage(createUnread)) { - if (!_joinedMessage->detached()) { + if (_joinedMessage->mainView()) { setLastMessage(_joinedMessage); } } @@ -508,7 +513,7 @@ void ChannelHistory::checkJoinedMessage(bool createUnread) { if (!firstDate.isNull() && !lastDate.isNull() && (firstDate <= inviteDate || loadedAtTop()) && (lastDate > inviteDate || loadedAtBottom())) { bool willBeLastMsg = (inviteDate >= lastDate); if (insertJoinedMessage(createUnread && willBeLastMsg) && willBeLastMsg) { - if (!_joinedMessage->detached()) { + if (_joinedMessage->mainView()) { setLastMessage(_joinedMessage); } } @@ -545,8 +550,8 @@ void ChannelHistory::cleared(bool leaveItems) { _joinedMessage = nullptr; } -void ChannelHistory::messageDetached(HistoryItem *msg) { - if (_joinedMessage == msg) { +void ChannelHistory::messageDetached(not_null message) { + if (_joinedMessage == message) { _joinedMessage = nullptr; } } @@ -565,7 +570,9 @@ History *Histories::find(const PeerId &peerId) { not_null Histories::findOrInsert(const PeerId &peerId) { auto i = map.constFind(peerId); if (i == map.cend()) { - auto history = peerIsChannel(peerId) ? static_cast(new ChannelHistory(peerId)) : (new History(peerId)); + auto history = peerIsChannel(peerId) + ? static_cast(new ChannelHistory(peerId)) + : (new History(peerId)); i = map.insert(peerId, history); } return i.value(); @@ -574,7 +581,9 @@ not_null Histories::findOrInsert(const PeerId &peerId) { not_null Histories::findOrInsert(const PeerId &peerId, int32 unreadCount, int32 maxInboxRead, int32 maxOutboxRead) { auto i = map.constFind(peerId); if (i == map.cend()) { - auto history = peerIsChannel(peerId) ? static_cast(new ChannelHistory(peerId)) : (new History(peerId)); + auto history = peerIsChannel(peerId) + ? static_cast(new ChannelHistory(peerId)) + : (new History(peerId)); i = map.insert(peerId, history); history->setUnreadCount(unreadCount); history->inboxReadBefore = maxInboxRead + 1; @@ -634,7 +643,7 @@ void Histories::step_typings(TimeMs ms, bool timer) { } void Histories::remove(const PeerId &peer) { - Map::iterator i = map.find(peer); + const auto i = map.find(peer); if (i != map.cend()) { typing.remove(i.value()); delete i.value(); @@ -717,14 +726,17 @@ void Histories::checkSelfDestructItems() { } } -HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem) { +HistoryItem *History::createItem( + const MTPMessage &msg, + bool applyServiceAction, + bool detachExistingItem) { const auto msgId = idFromMessage(msg); if (!msgId) return nullptr; auto result = App::histItemById(channelId(), msgId); if (result) { - if (!result->detached() && detachExistingItem) { - result->detach(); + if (detachExistingItem) { + result->removeMainView(); } if (msg.type() == mtpc_message) { const auto media = msg.c_message().has_media() @@ -1053,13 +1065,18 @@ HistoryItem *History::addNewMessage(const MTPMessage &msg, NewMessageType type) return addNewToLastBlock(msg, type); } -HistoryItem *History::addNewToLastBlock(const MTPMessage &msg, NewMessageType type) { +HistoryItem *History::addNewToLastBlock( + const MTPMessage &msg, + NewMessageType type) { Expects(type != NewMessageExisting); const auto applyServiceAction = (type == NewMessageUnread); const auto detachExistingItem = (type != NewMessageLast); - const auto item = createItem(msg, applyServiceAction, detachExistingItem); - if (!item || !item->detached()) { + const auto item = createItem( + msg, + applyServiceAction, + detachExistingItem); + if (!item || item->mainView()) { return item; } const auto result = addNewItem(item, (type == NewMessageUnread)); @@ -1367,14 +1384,14 @@ HistoryBlock *History::prepareBlockForAddingItem() { }; void History::addItemToBlock(not_null item) { - Expects(item->detached()); + Expects(!item->mainView()); auto block = prepareBlockForAddingItem(); block->messages.push_back(std::make_unique( item, HistoryView::Context::History)); - item->attachToBlock(block, block->messages.size() - 1); + block->messages.back()->attachToBlock(block, block->messages.size() - 1); item->previousItemChanged(); if (isBuildingFrontBlock() && _buildingFrontBlock->expectedItemsCount > 0) { @@ -1617,7 +1634,7 @@ void History::addNewerSlice(const QVector &slice) { void History::checkLastMsg() { if (lastMsg) { - if (!newLoaded && !lastMsg->detached()) { + if (!newLoaded && lastMsg->mainView()) { newLoaded = true; checkAddAllToUnreadMentions(); } @@ -1840,7 +1857,7 @@ QDateTime History::adjustChatListDate() const { void History::countScrollState(int top) { countScrollTopItem(top); if (scrollTopItem) { - scrollTopOffset = (top - scrollTopItem->data()->block()->y() - scrollTopItem->y()); + scrollTopOffset = (top - scrollTopItem->block()->y() - scrollTopItem->y()); } } @@ -1854,8 +1871,8 @@ void History::countScrollTopItem(int top) { auto blockIndex = 0; auto itemTop = 0; if (scrollTopItem) { - itemIndex = scrollTopItem->data()->indexInBlock(); - blockIndex = scrollTopItem->data()->block()->indexInHistory(); + itemIndex = scrollTopItem->indexInBlock(); + blockIndex = scrollTopItem->block()->indexInHistory(); itemTop = blocks[blockIndex]->y() + scrollTopItem->y(); } if (itemTop > top) { @@ -1915,7 +1932,9 @@ void History::getNextScrollTopItem(HistoryBlock *block, int32 i) { } void History::addUnreadBar() { - if (unreadBar || !showFrom || showFrom->detached() || !unreadCount()) return; + if (unreadBar || !showFrom || !showFrom->mainView() || !unreadCount()) { + return; + } int32 count = unreadCount(); if (peer->migrateTo()) { @@ -1944,14 +1963,16 @@ not_null History::addNewInTheMiddle( const auto &block = blocks[blockIndex]; - block->messages.insert( + const auto it = block->messages.insert( block->messages.begin() + itemIndex, - std::make_unique(newItem, HistoryView::Context::History)); - newItem->attachToBlock(block.get(), itemIndex); + std::make_unique( + newItem, + HistoryView::Context::History)); + (*it)->attachToBlock(block.get(), itemIndex); newItem->previousItemChanged(); if (itemIndex + 1 < block->messages.size()) { for (auto i = itemIndex + 1, l = int(block->messages.size()); i != l; ++i) { - block->messages[i]->data()->setIndexInBlock(i); + block->messages[i]->setIndexInBlock(i); } block->messages[itemIndex + 1]->data()->previousItemChanged(); } else if (blockIndex + 1 < blocks.size() && !blocks[blockIndex + 1]->messages.empty()) { @@ -1969,12 +1990,12 @@ not_null History::addNewInTheMiddle( } HistoryItem *History::findNextItem(not_null item) const { - Expects(!item->detached()); + Expects(item->mainView()); - const auto nextBlockIndex = item->block()->indexInHistory() + 1; - const auto nextItemIndex = item->indexInBlock() + 1; - if (nextItemIndex < int(item->block()->messages.size())) { - return item->block()->messages[nextItemIndex]->data(); + const auto nextBlockIndex = item->mainView()->block()->indexInHistory() + 1; + const auto nextItemIndex = item->mainView()->indexInBlock() + 1; + if (nextItemIndex < int(item->mainView()->block()->messages.size())) { + return item->mainView()->block()->messages[nextItemIndex]->data(); } else if (nextBlockIndex < int(blocks.size())) { return blocks[nextBlockIndex]->messages.front()->data(); } @@ -1982,12 +2003,12 @@ HistoryItem *History::findNextItem(not_null item) const { } HistoryItem *History::findPreviousItem(not_null item) const { - Expects(!item->detached()); + Expects(item->mainView()); - const auto blockIndex = item->block()->indexInHistory(); - const auto itemIndex = item->indexInBlock(); + const auto blockIndex = item->mainView()->block()->indexInHistory(); + const auto itemIndex = item->mainView()->indexInBlock(); if (itemIndex > 0) { - return item->block()->messages[itemIndex - 1]->data(); + return item->mainView()->block()->messages[itemIndex - 1]->data(); } else if (blockIndex > 0) { return blocks[blockIndex - 1]->messages.back()->data(); } @@ -2021,7 +2042,7 @@ not_null History::findGroupLast( void History::recountGroupingAround(not_null item) { Expects(item->history() == this); - if (!item->detached() && item->groupId()) { + if (item->mainView() && item->groupId()) { const auto [groupFrom, groupTill] = recountGroupingFromTill(item); recountGrouping(groupFrom, groupTill); } @@ -2084,8 +2105,8 @@ auto History::recountGroupingFromTill(not_null item) void History::recountGrouping( not_null from, not_null till) { - Expects(!from->detached()); - Expects(!till->detached()); + Expects(from->mainView()); + Expects(till->mainView()); from->validateGroupId(); auto others = std::vector>(); @@ -2186,7 +2207,7 @@ bool History::isReadyFor(MsgId msgId) { return loadedAtBottom(); } HistoryItem *item = App::histItemById(channelId(), msgId); - return item && (item->history() == this) && !item->detached(); + return item && (item->history() == this) && item->mainView(); } void History::getReadyFor(MsgId msgId) { @@ -2539,15 +2560,16 @@ void HistoryBlock::clear(bool leaveItems) { if (leaveItems) { for (const auto &message : list) { - message->data()->detachFast(); + message->data()->clearMainView(); } } // #TODO feeds delete all items in history } -void HistoryBlock::removeItem(not_null item) { - Expects(item->block() == this); +void HistoryBlock::remove(not_null view) { + Expects(view->block() == this); + const auto item = view->data(); auto [groupFrom, groupTill] = _history->recountGroupingFromTill(item); const auto groupHistory = _history; const auto needGroupRecount = (groupFrom != groupTill); @@ -2561,7 +2583,7 @@ void HistoryBlock::removeItem(not_null item) { } auto blockIndex = indexInHistory(); - auto itemIndex = item->indexInBlock(); + auto itemIndex = view->indexInBlock(); if (_history->showFrom == item) { _history->getNextShowFrom(this, itemIndex); } @@ -2575,10 +2597,10 @@ void HistoryBlock::removeItem(not_null item) { _history->getNextScrollTopItem(this, itemIndex); } - item->detachFast(); + item->clearMainView(); messages.erase(messages.begin() + itemIndex); for (auto i = itemIndex, l = int(messages.size()); i < l; ++i) { - messages[i]->data()->setIndexInBlock(i); + messages[i]->setIndexInBlock(i); } if (messages.empty()) { // Deletes this. diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index b231a74f3..f28c5c3b6 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -550,7 +550,7 @@ class ChannelHistory : public History { public: using History::History; - void messageDetached(HistoryItem *msg); + void messageDetached(not_null message); void getRangeDifference(); void getRangeDifferenceNext(int32 pts); @@ -579,15 +579,17 @@ private: class HistoryBlock { public: + using Message = HistoryView::Message; + HistoryBlock(not_null history); HistoryBlock(const HistoryBlock &) = delete; HistoryBlock &operator=(const HistoryBlock &) = delete; ~HistoryBlock(); - std::vector> messages; + std::vector> messages; void clear(bool leaveItems = false); - void removeItem(not_null item); + void remove(not_null view); int resizeGetHeight(int newWidth, bool resizeAllItems); int y() const { diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index dfbca504c..671dd1938 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -123,8 +123,8 @@ HistoryInner::HistoryInner( : RpWidget(nullptr) , _controller(controller) , _peer(history->peer) -, _migrated(history->migrateFrom()) , _history(history) +, _migrated(history->migrateFrom()) , _widget(historyWidget) , _scroll(scroll) , _scrollDateCheck([this] { onScrollDateCheck(); }) { @@ -188,10 +188,17 @@ void HistoryInner::messagesReceivedDown(PeerData *peer, const QVectordetached() || !_history) return; - int32 msgy = itemTop(item); - if (msgy >= 0) { - update(0, msgy, width(), item->height()); + if (item) { + repaintItem(item->mainView()); + } +} + +void HistoryInner::repaintItem(const Message *view) { + if (view) { + const auto top = itemTop(view); + if (top >= 0) { + update(0, top, width(), view->data()->height()); + } } } @@ -437,7 +444,7 @@ TextSelection HistoryInner::itemRenderSelection( int selfromy, int seltoy) const { const auto item = view->data(); - const auto y = item->block()->y() + view->y(); + const auto y = view->block()->y() + view->y(); if (y >= selfromy && y < seltoy) { if (_dragSelecting && !item->serviceMsg() && item->id > 0) { return FullSelection; @@ -491,7 +498,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { if (selfromy < 0 || seltoy < 0) { selfromy = seltoy = -1; } else { - seltoy += _dragSelTo->height(); + seltoy += _dragSelTo->data()->height(); } auto mtop = migratedTop(); @@ -869,12 +876,17 @@ void HistoryInner::touchScrollUpdated(const QPoint &screenPos) { touchUpdateSpeed(); } -QPoint HistoryInner::mapPointToItem(QPoint p, HistoryItem *item) { - int32 msgy = itemTop(item); - if (msgy < 0) return QPoint(0, 0); +QPoint HistoryInner::mapPointToItem(QPoint p, const Message *view) { + if (view) { + const auto top = itemTop(view); + p.setY(p.y() - top); + return p; + } + return QPoint(); +} - p.setY(p.y() - msgy); - return p; +QPoint HistoryInner::mapPointToItem(QPoint p, const HistoryItem *item) { + return item ? mapPointToItem(p, item->mainView()) : QPoint(); } void HistoryInner::mousePressEvent(QMouseEvent *e) { @@ -897,7 +909,9 @@ void HistoryInner::mouseActionStart(const QPoint &screenPos, Qt::MouseButton but } _mouseAction = MouseAction::None; - _mouseActionItem = App::mousedItem(); + _mouseActionItem = App::mousedItem() + ? App::mousedItem()->data().get() + : nullptr; _dragStartPosition = mapPointToItem(mapFromGlobal(screenPos), _mouseActionItem); _pressWasInactive = _controller->window()->wasInactivePress(); if (_pressWasInactive) _controller->window()->setInactivePress(false); @@ -960,7 +974,7 @@ void HistoryInner::mouseActionStart(const QPoint &screenPos, Qt::MouseButton but if (uponSelected) { _mouseAction = MouseAction::PrepareDrag; // start text drag } else if (!_pressWasInactive) { - if (dynamic_cast(App::pressedItem()->getMedia()) || _mouseCursorState == HistoryInDateCursorState) { + if (dynamic_cast(App::pressedItem()->data()->getMedia()) || _mouseCursorState == HistoryInDateCursorState) { _mouseAction = MouseAction::PrepareDrag; // start sticker drag or by-date drag } else { if (dragState.afterSymbol) ++_mouseTextSymbol; @@ -1061,7 +1075,7 @@ void HistoryInner::performDrag() { auto forwardMimeType = QString(); auto pressedMedia = static_cast(nullptr); if (auto pressedItem = App::pressedItem()) { - pressedMedia = pressedItem->getMedia(); + pressedMedia = pressedItem->data()->getMedia(); if (_mouseCursorState == HistoryInDateCursorState || (pressedMedia && pressedMedia->dragItem())) { forwardMimeType = qsl("application/x-td-forward-pressed"); } @@ -1113,9 +1127,10 @@ void HistoryInner::itemRemoved(not_null item) { _dragStateItem = nullptr; } - if (_dragSelFrom == item || _dragSelTo == item) { - _dragSelFrom = 0; - _dragSelTo = 0; + if (_dragSelFrom && _dragSelFrom->data() == item + || _dragSelTo && _dragSelTo->data() == item) { + _dragSelFrom = nullptr; + _dragSelTo = nullptr; update(); } onUpdateSelected(); @@ -1183,7 +1198,7 @@ void HistoryInner::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton bu } else if (_mouseAction == MouseAction::Selecting) { if (_dragSelFrom && _dragSelTo) { applyDragSelection(); - _dragSelFrom = _dragSelTo = 0; + _dragSelFrom = _dragSelTo = nullptr; } else if (!_selected.empty() && !_pressWasInactive) { auto sel = _selected.cbegin()->second; if (sel != FullSelection && sel.from == sel.to) { @@ -1246,10 +1261,6 @@ void HistoryInner::contextMenuEvent(QContextMenuEvent *e) { } void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { - if (_menu) { - _menu->deleteLater(); - _menu = nullptr; - } if (e->reason() == QContextMenuEvent::Mouse) { mouseActionUpdate(e->globalPos()); } @@ -1276,7 +1287,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { auto mousePos = mapPointToItem(mapFromGlobal(_mousePosition), App::mousedItem()); HistoryStateRequest request; request.flags |= Text::StateRequest::Flag::LookupSymbol; - auto dragState = App::mousedItem()->getState(mousePos, request); + auto dragState = App::mousedItem()->data()->getState(mousePos, request); if (dragState.cursor == HistoryInTextCursorState && dragState.symbol >= selFrom && dragState.symbol < selTo) { isUponSelected = 1; } @@ -1287,7 +1298,37 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { isUponSelected = hasSelected; } - _menu = new Ui::PopupMenu(nullptr); + _menu = base::make_unique_q(nullptr); + + const auto addItemActions = [&](HistoryItem *item) { + if (!item + || !IsServerMsgId(item->id) + || isUponSelected == 2 + || isUponSelected == -2) { + return; + } + const auto itemId = item->fullId(); + if (canSendMessages) { + _menu->addAction(lang(lng_context_reply_msg), [=] { + _widget->replyToMessage(itemId); + }); + } + if (item->canEdit(::date(unixtime()))) { + _menu->addAction(lang(lng_context_edit_msg), [=] { + _widget->editMessage(itemId); + }); + } + if (item->canPin()) { + const auto isPinned = item->isPinned(); + _menu->addAction(lang(isPinned ? lng_context_unpin_msg : lng_context_pin_msg), [=] { + if (isPinned) { + _widget->unpinMessage(itemId); + } else { + _widget->pinMessage(itemId); + } + }); + } + }; _contextMenuLink = ClickHandler::getActive(); auto lnkPhoto = dynamic_cast(_contextMenuLink.get()); @@ -1297,134 +1338,116 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { auto lnkIsAudio = lnkDocument ? lnkDocument->document()->isAudioFile() : false; if (lnkPhoto || lnkDocument) { const auto item = _dragStateItem; + const auto itemId = item ? item->fullId() : FullMsgId(); if (isUponSelected > 0) { _menu->addAction(lang((isUponSelected > 1) ? lng_context_copy_selected_items : lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true); } - if (item && item->id > 0 && isUponSelected != 2 && isUponSelected != -2) { - if (canSendMessages) { - _menu->addAction(lang(lng_context_reply_msg), _widget, SLOT(onReplyToMessage())); - } - if (item->canEdit(::date(unixtime()))) { - _menu->addAction(lang(lng_context_edit_msg), _widget, SLOT(onEditMessage())); - } - if (item->canPin()) { - auto isPinned = item->isPinned(); - _menu->addAction(lang(isPinned ? lng_context_unpin_msg : lng_context_pin_msg), _widget, isPinned ? SLOT(onUnpinMessage()) : SLOT(onPinMessage())); - } - App::contextItem(item); - } + addItemActions(item); if (lnkPhoto) { - _menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, photo = lnkPhoto->photo()] { + const auto photo = lnkPhoto->photo(); + _menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [=] { savePhotoToFile(photo); }))->setEnabled(true); - _menu->addAction(lang(lng_context_copy_image), [this, photo = lnkPhoto->photo()] { + _menu->addAction(lang(lng_context_copy_image), [=] { copyContextImage(photo); })->setEnabled(true); } else { auto document = lnkDocument->document(); if (document->loading()) { - _menu->addAction(lang(lng_context_cancel_download), this, SLOT(cancelContextDownload()))->setEnabled(true); + _menu->addAction(lang(lng_context_cancel_download), [=] { + cancelContextDownload(document); + })->setEnabled(true); } else { if (document->loaded() && document->isGifv()) { if (!cAutoPlayGif()) { - _menu->addAction(lang(lng_context_open_gif), this, SLOT(openContextGif()))->setEnabled(true); + _menu->addAction(lang(lng_context_open_gif), [=] { + openContextGif(itemId); + })->setEnabled(true); } - _menu->addAction(lang(lng_context_save_gif), this, SLOT(saveContextGif()))->setEnabled(true); + _menu->addAction(lang(lng_context_save_gif), [=] { + saveContextGif(itemId); + })->setEnabled(true); } if (!document->filepath(DocumentData::FilePathResolveChecked).isEmpty()) { - _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true); + _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [=] { + showContextInFolder(document); + })->setEnabled(true); } - _menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsVoice ? lng_context_save_audio : (lnkIsAudio ? lng_context_save_audio_file : lng_context_save_file))), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] { + _menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsVoice ? lng_context_save_audio : (lnkIsAudio ? lng_context_save_audio_file : lng_context_save_file))), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [=] { saveDocumentToFile(document); }))->setEnabled(true); } } if (item && item->hasDirectLink() && isUponSelected != 2 && isUponSelected != -2) { - _menu->addAction(lang(item->history()->peer->isMegagroup() ? lng_context_copy_link : lng_context_copy_post_link), _widget, SLOT(onCopyPostLink())); + _menu->addAction(lang(item->history()->peer->isMegagroup() ? lng_context_copy_link : lng_context_copy_post_link), [=] { + _widget->copyPostLink(itemId); + }); } if (isUponSelected > 1) { if (selectedState.count > 0 && selectedState.canForwardCount == selectedState.count) { _menu->addAction(lang(lng_context_forward_selected), _widget, SLOT(onForwardSelected())); } if (selectedState.count > 0 && selectedState.canDeleteCount == selectedState.count) { - _menu->addAction(lang(lng_context_delete_selected), base::lambda_guarded(this, [this] { + _menu->addAction(lang(lng_context_delete_selected), [=] { _widget->confirmDeleteSelectedItems(); - })); + }); } _menu->addAction(lang(lng_context_clear_selection), _widget, SLOT(onClearSelected())); } else if (item) { + const auto itemId = item->fullId(); if (isUponSelected != -2) { if (item->canForward()) { - _menu->addAction(lang(lng_context_forward_msg), base::lambda_guarded(this, [this] { - if (const auto item = App::contextItem()) { - forwardItem(item); - } - }))->setEnabled(true); + _menu->addAction(lang(lng_context_forward_msg), [=] { + forwardItem(itemId); + })->setEnabled(true); } if (item->canDelete()) { - _menu->addAction(lang(lng_context_delete_msg), base::lambda_guarded(this, [this] { - if (const auto item = App::contextItem()) { - deleteItem(item); - } - })); + _menu->addAction(lang(lng_context_delete_msg), [=] { + deleteItem(itemId); + }); } } - if (item && item->id > 0 && !item->serviceMsg()) { - _menu->addAction(lang(lng_context_select_msg), base::lambda_guarded(this, [this] { - if (const auto item = App::contextItem()) { - if (!item->detached()) { + if (IsServerMsgId(item->id) && !item->serviceMsg()) { + _menu->addAction(lang(lng_context_select_msg), [=] { + if (const auto item = App::histItemById(itemId)) { + if (const auto view = item->mainView()) { changeSelection(&_selected, item, SelectAction::Select); repaintItem(item); _widget->updateTopBarSelection(); } } - }))->setEnabled(true); + })->setEnabled(true); } - App::contextItem(item); } } else { // maybe cursor on some text history item? - auto item = App::hoveredItem() - ? App::hoveredItem() - : App::hoveredLinkItem(); - if (const auto group = item ? item->getFullGroup() : nullptr) { - item = group->others.empty() - ? group->leader - : group->others.front().get(); - } + const auto item = [&]() -> HistoryItem* { + if (const auto result = App::hoveredItem() + ? App::hoveredItem()->data().get() + : App::hoveredLinkItem() + ? App::hoveredLinkItem()->data().get() + : nullptr) { + if (const auto group = result->getFullGroup()) { + return group->others.empty() + ? group->leader + : group->others.front().get(); + } + return result; + } + return nullptr; + }(); + const auto itemId = item ? item->fullId() : FullMsgId(); const auto canDelete = item && item->canDelete() && (item->id > 0 || !item->serviceMsg()); const auto canForward = item && item->canForward(); - auto msg = dynamic_cast(item); + const auto msg = dynamic_cast(item); if (isUponSelected > 0) { _menu->addAction(lang((isUponSelected > 1) ? lng_context_copy_selected_items : lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true); - if (item && item->id > 0 && isUponSelected != 2) { - if (canSendMessages) { - _menu->addAction(lang(lng_context_reply_msg), _widget, SLOT(onReplyToMessage())); - } - if (item->canEdit(::date(unixtime()))) { - _menu->addAction(lang(lng_context_edit_msg), _widget, SLOT(onEditMessage())); - } - if (item->canPin()) { - auto isPinned = item->isPinned(); - _menu->addAction(lang(isPinned ? lng_context_unpin_msg : lng_context_pin_msg), _widget, isPinned ? SLOT(onUnpinMessage()) : SLOT(onPinMessage())); - } - } + addItemActions(item); } else { - if (item && item->id > 0 && isUponSelected != -2) { - if (canSendMessages) { - _menu->addAction(lang(lng_context_reply_msg), _widget, SLOT(onReplyToMessage())); - } - if (item->canEdit(::date(unixtime()))) { - _menu->addAction(lang(lng_context_edit_msg), _widget, SLOT(onEditMessage())); - } - if (item->canPin()) { - auto isPinned = item->isPinned(); - _menu->addAction(lang(isPinned ? lng_context_unpin_msg : lng_context_pin_msg), _widget, isPinned ? SLOT(onUnpinMessage()) : SLOT(onPinMessage())); - } - } + addItemActions(item); if (item && !isUponSelected) { auto mediaHasTextForCopy = false; if (auto media = (msg ? msg->getMedia() : nullptr)) { @@ -1435,8 +1458,12 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (media->type() == MediaTypeSticker) { if (auto document = media->getDocument()) { if (document->sticker() && document->sticker()->set.type() != mtpc_inputStickerSetEmpty) { - _menu->addAction(lang(document->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), [this, document] { showStickerPackInfo(document); }); - _menu->addAction(lang(Stickers::IsFaved(document) ? lng_faved_stickers_remove : lng_faved_stickers_add), [this, document] { toggleFavedSticker(document); }); + _menu->addAction(lang(document->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), [=] { + showStickerPackInfo(document); + }); + _menu->addAction(lang(Stickers::IsFaved(document) ? lng_faved_stickers_remove : lng_faved_stickers_add), [=] { + toggleFavedSticker(document); + }); } _menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] { saveDocumentToFile(document); @@ -1445,16 +1472,24 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } else if (media->type() == MediaTypeGif && !_contextMenuLink) { if (auto document = media->getDocument()) { if (document->loading()) { - _menu->addAction(lang(lng_context_cancel_download), this, SLOT(cancelContextDownload()))->setEnabled(true); + _menu->addAction(lang(lng_context_cancel_download), [=] { + cancelContextDownload(document); + })->setEnabled(true); } else { if (document->isGifv()) { if (!cAutoPlayGif()) { - _menu->addAction(lang(lng_context_open_gif), this, SLOT(openContextGif()))->setEnabled(true); + _menu->addAction(lang(lng_context_open_gif), [=] { + openContextGif(itemId); + })->setEnabled(true); } - _menu->addAction(lang(lng_context_save_gif), this, SLOT(saveContextGif()))->setEnabled(true); + _menu->addAction(lang(lng_context_save_gif), [=] { + saveContextGif(itemId); + })->setEnabled(true); } if (!document->filepath(DocumentData::FilePathResolveChecked).isEmpty()) { - _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true); + _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [=] { + showContextInFolder(document); + })->setEnabled(true); } _menu->addAction(lang(lng_context_save_file), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] { saveDocumentToFile(document); @@ -1464,7 +1499,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } } if (msg && !_contextMenuLink && (!msg->emptyText() || mediaHasTextForCopy)) { - _menu->addAction(lang(lng_context_copy_text), this, SLOT(copyContextText()))->setEnabled(true); + _menu->addAction(lang(lng_context_copy_text), [=] { + copyContextText(itemId); + })->setEnabled(true); } } } @@ -1475,7 +1512,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } if (linkCopyToClipboardText.isEmpty()) { if (item && item->hasDirectLink() && isUponSelected != 2 && isUponSelected != -2) { - _menu->addAction(lang(item->history()->peer->isMegagroup() ? lng_context_copy_link : lng_context_copy_post_link), _widget, SLOT(onCopyPostLink())); + _menu->addAction(lang(item->history()->peer->isMegagroup() ? lng_context_copy_link : lng_context_copy_post_link), [=] { + _widget->copyPostLink(itemId); + }); } } if (isUponSelected > 1) { @@ -1483,73 +1522,62 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { _menu->addAction(lang(lng_context_forward_selected), _widget, SLOT(onForwardSelected())); } if (selectedState.count > 0 && selectedState.count == selectedState.canDeleteCount) { - _menu->addAction(lang(lng_context_delete_selected), base::lambda_guarded(this, [this] { + _menu->addAction(lang(lng_context_delete_selected), [=] { _widget->confirmDeleteSelectedItems(); - })); + }); } _menu->addAction(lang(lng_context_clear_selection), _widget, SLOT(onClearSelected())); } else if (item && ((isUponSelected != -2 && (canForward || canDelete)) || item->id > 0)) { if (isUponSelected != -2) { if (canForward) { - _menu->addAction(lang(lng_context_forward_msg), base::lambda_guarded(this, [this] { - if (const auto item = App::contextItem()) { - forwardAsGroup(item); - } - }))->setEnabled(true); + _menu->addAction(lang(lng_context_forward_msg), [=] { + forwardAsGroup(itemId); + })->setEnabled(true); } if (canDelete) { - _menu->addAction(lang((msg && msg->uploading()) ? lng_context_cancel_upload : lng_context_delete_msg), base::lambda_guarded(this, [this] { - if (const auto item = App::contextItem()) { - deleteAsGroup(item); - } - })); + _menu->addAction(lang((msg && msg->uploading()) ? lng_context_cancel_upload : lng_context_delete_msg), [=] { + deleteAsGroup(itemId); + }); } } if (item->id > 0 && !item->serviceMsg()) { - _menu->addAction(lang(lng_context_select_msg), base::lambda_guarded(this, [this] { - if (const auto item = App::contextItem()) { - if (!item->detached()) { + _menu->addAction(lang(lng_context_select_msg), [=] { + if (const auto item = App::histItemById(itemId)) { + if (const auto view = item->mainView()) { changeSelectionAsGroup(&_selected, item, SelectAction::Select); - repaintItem(item); + repaintItem(view); _widget->updateTopBarSelection(); } } - }))->setEnabled(true); + })->setEnabled(true); } } else { - if (App::mousedItem() && !App::mousedItem()->serviceMsg() && App::mousedItem()->id > 0) { - _menu->addAction(lang(lng_context_select_msg), base::lambda_guarded(this, [this] { - if (const auto item = App::contextItem()) { - if (!item->detached()) { + if (App::mousedItem() + && IsServerMsgId(App::mousedItem()->data()->id) + && !App::mousedItem()->data()->serviceMsg()) { + const auto itemId = App::mousedItem()->data()->fullId(); + _menu->addAction(lang(lng_context_select_msg), [=] { + if (const auto item = App::histItemById(itemId)) { + if (const auto view = item->mainView()) { changeSelectionAsGroup(&_selected, item, SelectAction::Select); repaintItem(item); _widget->updateTopBarSelection(); } } - }))->setEnabled(true); - item = App::mousedItem(); + })->setEnabled(true); } } - App::contextItem(item); } if (_menu->actions().isEmpty()) { - delete _menu; - _menu = 0; + _menu = nullptr; } else { - connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*))); _menu->popup(e->globalPos()); e->accept(); } } -void HistoryInner::onMenuDestroy(QObject *obj) { - if (_menu == obj) { - _menu = nullptr; - } -} - void HistoryInner::copySelectedText() { setToClipboard(getSelectedText()); } @@ -1560,8 +1588,8 @@ void HistoryInner::copyContextUrl() { } } -void HistoryInner::savePhotoToFile(PhotoData *photo) { - if (!photo || !photo->date || !photo->loaded()) return; +void HistoryInner::savePhotoToFile(not_null photo) { + if (!photo->date || !photo->loaded()) return; auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter(); FileDialog::GetWritePath(lang(lng_save_photo), filter, filedialogDefaultName(qsl("photo"), qsl(".jpg")), base::lambda_guarded(this, [this, photo](const QString &result) { @@ -1571,13 +1599,13 @@ void HistoryInner::savePhotoToFile(PhotoData *photo) { })); } -void HistoryInner::copyContextImage(PhotoData *photo) { - if (!photo || !photo->date || !photo->loaded()) return; +void HistoryInner::copyContextImage(not_null photo) { + if (!photo->date || !photo->loaded()) return; QApplication::clipboard()->setPixmap(photo->full->pix()); } -void HistoryInner::showStickerPackInfo(DocumentData *document) { +void HistoryInner::showStickerPackInfo(not_null document) { if (auto sticker = document->sticker()) { if (sticker->set.type() != mtpc_inputStickerSetEmpty) { App::main()->stickersBox(sticker->set); @@ -1585,73 +1613,60 @@ void HistoryInner::showStickerPackInfo(DocumentData *document) { } } -void HistoryInner::toggleFavedSticker(DocumentData *document) { +void HistoryInner::toggleFavedSticker(not_null document) { auto unfave = Stickers::IsFaved(document); MTP::send(MTPmessages_FaveSticker(document->mtpInput(), MTP_bool(unfave)), rpcDone([document, unfave](const MTPBool &result) { Stickers::SetFaved(document, !unfave); })); } -void HistoryInner::cancelContextDownload() { - if (auto lnkDocument = dynamic_cast(_contextMenuLink.get())) { - lnkDocument->document()->cancel(); - } else if (auto item = App::contextItem()) { - if (auto media = item->getMedia()) { - if (auto doc = media->getDocument()) { - doc->cancel(); - } - } - } +void HistoryInner::cancelContextDownload(not_null document) { + document->cancel(); } -void HistoryInner::showContextInFolder() { - QString filepath; - if (auto lnkDocument = dynamic_cast(_contextMenuLink.get())) { - filepath = lnkDocument->document()->filepath(DocumentData::FilePathResolveChecked); - } else if (auto item = App::contextItem()) { - if (auto media = item->getMedia()) { - if (auto doc = media->getDocument()) { - filepath = doc->filepath(DocumentData::FilePathResolveChecked); - } - } - } +void HistoryInner::showContextInFolder(not_null document) { + const auto filepath = document->filepath( + DocumentData::FilePathResolveChecked); if (!filepath.isEmpty()) { File::ShowInFolder(filepath); } } -void HistoryInner::saveDocumentToFile(DocumentData *document) { +void HistoryInner::saveDocumentToFile(not_null document) { DocumentSaveClickHandler::doSave(document, true); } -void HistoryInner::openContextGif() { - if (auto item = App::contextItem()) { - if (auto media = item->getMedia()) { - if (auto document = media->getDocument()) { +void HistoryInner::openContextGif(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { + if (const auto media = item->getMedia()) { + if (const auto document = media->getDocument()) { Messenger::Instance().showDocument(document, item); } } } } -void HistoryInner::saveContextGif() { - if (auto item = App::contextItem()) { - if (auto media = item->getMedia()) { - if (auto document = media->getDocument()) { +void HistoryInner::saveContextGif(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { + if (const auto media = item->getMedia()) { + if (const auto document = media->getDocument()) { _widget->saveGif(document); } } } } -void HistoryInner::copyContextText() { - const auto item = App::contextItem(); - if (!item || (item->getMedia() && item->getMedia()->type() == MediaTypeSticker)) { - return; +void HistoryInner::copyContextText(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { + if (const auto media = item->getMedia()) { + if (media->type() == MediaTypeSticker) { + return; + } + } + const auto group = item->getFullGroup(); + const auto leader = group ? group->leader : item; + setToClipboard(leader->selectedText(FullSelection)); } - const auto group = item->getFullGroup(); - const auto leader = group ? group->leader : item; - setToClipboard(leader->selectedText(FullSelection)); } void HistoryInner::setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode) { @@ -1705,7 +1720,7 @@ TextWithEntities HistoryInner::getSelectedText() const { }; for (const auto [item, selection] : selected) { - if (item->detached()) { + if (!item->mainView()) { continue; } @@ -2084,38 +2099,32 @@ void HistoryInner::adjustCurrent(int32 y, History *history) const { } } -HistoryItem *HistoryInner::prevItem(HistoryItem *item) { - if (!item || item->detached()) { +HistoryView::Message *HistoryInner::prevItem(Message *view) { + if (!view) { return nullptr; - } - - const auto block = item->block(); - int blockIndex = block->indexInHistory(), itemIndex = item->indexInBlock(); - if (itemIndex > 0) { - return block->messages[itemIndex - 1]->data(); - } - if (blockIndex > 0) { - return item->history()->blocks[blockIndex - 1]->messages.back()->data(); - } - if (item->history() == _history && _migrated && _history->loadedAtTop() && !_migrated->isEmpty() && _migrated->loadedAtBottom()) { - return _migrated->blocks.back()->messages.back()->data(); + } else if (const auto result = view->previousInBlocks()) { + return result; + } else if (view->data()->history() == _history + && _migrated + && _history->loadedAtTop() + && !_migrated->isEmpty() + && _migrated->loadedAtBottom()) { + return _migrated->blocks.back()->messages.back().get(); } return nullptr; } -HistoryItem *HistoryInner::nextItem(HistoryItem *item) { - if (!item || item->detached()) return nullptr; - - const auto block = item->block(); - int blockIndex = block->indexInHistory(), itemIndex = item->indexInBlock(); - if (itemIndex + 1 < block->messages.size()) { - return block->messages[itemIndex + 1]->data(); - } - if (blockIndex + 1 < item->history()->blocks.size()) { - return item->history()->blocks[blockIndex + 1]->messages.front()->data(); - } - if (item->history() == _migrated && _history && _migrated->loadedAtBottom() && _history->loadedAtTop() && !_history->isEmpty()) { - return _history->blocks.front()->messages.front()->data(); +HistoryView::Message *HistoryInner::nextItem(Message *view) { + if (!view) { + return nullptr; + } else if (const auto result = view->nextInBlocks()) { + return result; + } else if (view->data()->history() == _migrated + && _history + && _migrated->loadedAtBottom() + && _history->loadedAtTop() + && !_history->isEmpty()) { + return _history->blocks.front()->messages.front().get(); } return nullptr; } @@ -2204,36 +2213,38 @@ void HistoryInner::onUpdateSelected() { auto mousePos = mapFromGlobal(_mousePosition); auto point = _widget->clampMousePosition(mousePos); - HistoryBlock *block = 0; - HistoryItem *item = 0; + auto block = (HistoryBlock*)nullptr; + auto item = (HistoryItem*)nullptr; + auto view = (Message*)nullptr; QPoint m; adjustCurrent(point.y()); if (_curHistory && !_curHistory->isEmpty()) { block = _curHistory->blocks[_curBlock].get(); - item = block->messages[_curItem]->data(); + view = block->messages[_curItem].get(); + item = view->data(); - App::mousedItem(item); - m = mapPointToItem(point, item); + App::mousedItem(view); + m = mapPointToItem(point, view); if (item->hasPoint(m)) { - if (App::hoveredItem() != item) { + if (App::hoveredItem() != view) { repaintItem(App::hoveredItem()); - App::hoveredItem(item); + App::hoveredItem(view); repaintItem(App::hoveredItem()); } } else if (App::hoveredItem()) { repaintItem(App::hoveredItem()); - App::hoveredItem(0); + App::hoveredItem(nullptr); } } - if (_mouseActionItem && _mouseActionItem->detached()) { + if (_mouseActionItem && !_mouseActionItem->mainView()) { mouseActionCancel(); } HistoryTextState dragState; ClickHandlerHost *lnkhost = nullptr; auto selectingText = (item == _mouseActionItem) - && (item == App::hoveredItem()) + && (view == App::hoveredItem()) && !_selected.empty() && (_selected.cbegin()->second != FullSelection); if (point.y() < _historyPaddingTop) { @@ -2382,36 +2393,49 @@ void HistoryInner::onUpdateSelected() { updateDragSelection(0, 0, false); } else if (canSelectMany) { auto selectingDown = (itemTop(_mouseActionItem) < itemTop(item)) || (_mouseActionItem == item && _dragStartPosition.y() < m.y()); - auto dragSelFrom = _mouseActionItem, dragSelTo = item; - if (!dragSelFrom->hasPoint(_dragStartPosition)) { // maybe exclude dragSelFrom + auto dragSelFrom = _mouseActionItem->mainView(); + auto dragSelTo = view; + if (!dragSelFrom->data()->hasPoint(_dragStartPosition)) { // maybe exclude dragSelFrom if (selectingDown) { - if (_dragStartPosition.y() >= dragSelFrom->height() - dragSelFrom->marginBottom() || ((item == dragSelFrom) && (m.y() < _dragStartPosition.y() + QApplication::startDragDistance() || m.y() < dragSelFrom->marginTop()))) { - dragSelFrom = (dragSelFrom == dragSelTo) ? 0 : nextItem(dragSelFrom); + if (_dragStartPosition.y() >= dragSelFrom->data()->height() - dragSelFrom->data()->marginBottom() || ((view == dragSelFrom) && (m.y() < _dragStartPosition.y() + QApplication::startDragDistance() || m.y() < dragSelFrom->data()->marginTop()))) { + dragSelFrom = (dragSelFrom != dragSelTo) + ? nextItem(dragSelFrom) + : nullptr; } } else { - if (_dragStartPosition.y() < dragSelFrom->marginTop() || ((item == dragSelFrom) && (m.y() >= _dragStartPosition.y() - QApplication::startDragDistance() || m.y() >= dragSelFrom->height() - dragSelFrom->marginBottom()))) { - dragSelFrom = (dragSelFrom == dragSelTo) ? 0 : prevItem(dragSelFrom); + if (_dragStartPosition.y() < dragSelFrom->data()->marginTop() || ((view == dragSelFrom) && (m.y() >= _dragStartPosition.y() - QApplication::startDragDistance() || m.y() >= dragSelFrom->data()->height() - dragSelFrom->data()->marginBottom()))) { + dragSelFrom = (dragSelFrom != dragSelTo) + ? prevItem(dragSelFrom) + : nullptr; } } } if (_mouseActionItem != item) { // maybe exclude dragSelTo if (selectingDown) { - if (m.y() < dragSelTo->marginTop()) { - dragSelTo = (dragSelFrom == dragSelTo) ? 0 : prevItem(dragSelTo); + if (m.y() < dragSelTo->data()->marginTop()) { + dragSelTo = (dragSelFrom != dragSelTo) + ? prevItem(dragSelFrom) + : nullptr; } } else { - if (m.y() >= dragSelTo->height() - dragSelTo->marginBottom()) { - dragSelTo = (dragSelFrom == dragSelTo) ? 0 : nextItem(dragSelTo); + if (m.y() >= dragSelTo->data()->height() - dragSelTo->data()->marginBottom()) { + dragSelTo = (dragSelFrom != dragSelTo) + ? nextItem(dragSelFrom) + : nullptr; } } } auto dragSelecting = false; auto dragFirstAffected = dragSelFrom; - while (dragFirstAffected && (dragFirstAffected->id < 0 || dragFirstAffected->serviceMsg())) { - dragFirstAffected = (dragFirstAffected == dragSelTo) ? 0 : (selectingDown ? nextItem(dragFirstAffected) : prevItem(dragFirstAffected)); + while (dragFirstAffected && (dragFirstAffected->data()->id < 0 || dragFirstAffected->data()->serviceMsg())) { + dragFirstAffected = (dragFirstAffected != dragSelTo) + ? (selectingDown + ? nextItem(dragFirstAffected) + : prevItem(dragFirstAffected)) + : nullptr; } if (dragFirstAffected) { - auto i = _selected.find(dragFirstAffected); + auto i = _selected.find(dragFirstAffected->data()); dragSelecting = (i == _selected.cend() || i->second != FullSelection); } updateDragSelection(dragSelFrom, dragSelTo, dragSelecting); @@ -2432,7 +2456,7 @@ void HistoryInner::onUpdateSelected() { // Voice message seek support. if (const auto pressedItem = _dragStateItem) { - if (!pressedItem->detached()) { + if (pressedItem->mainView()) { if (pressedItem->history() == _history || pressedItem->history() == _migrated) { auto adjustedPoint = mapPointToItem(point, pressedItem); pressedItem->updatePressed(adjustedPoint); @@ -2452,7 +2476,7 @@ void HistoryInner::onUpdateSelected() { } } -void HistoryInner::updateDragSelection(HistoryItem *dragSelFrom, HistoryItem *dragSelTo, bool dragSelecting) { +void HistoryInner::updateDragSelection(Message *dragSelFrom, Message *dragSelTo, bool dragSelecting) { if (_dragSelFrom == dragSelFrom && _dragSelTo == dragSelTo && _dragSelecting == dragSelecting) { return; } @@ -2460,7 +2484,7 @@ void HistoryInner::updateDragSelection(HistoryItem *dragSelFrom, HistoryItem *dr _dragSelTo = dragSelTo; int32 fromy = itemTop(_dragSelFrom), toy = itemTop(_dragSelTo); if (fromy >= 0 && toy >= 0 && fromy > toy) { - qSwap(_dragSelFrom, _dragSelTo); + std::swap(_dragSelFrom, _dragSelTo); } _dragSelecting = dragSelecting; if (!_wasSelectedText && _dragSelFrom && _dragSelTo && _dragSelecting) { @@ -2484,10 +2508,10 @@ int HistoryInner::historyScrollTop() const { auto htop = historyTop(); auto mtop = migratedTop(); if (htop >= 0 && _history->scrollTopItem) { - return htop + _history->scrollTopItem->data()->block()->y() + _history->scrollTopItem->y() + _history->scrollTopOffset; + return htop + _history->scrollTopItem->block()->y() + _history->scrollTopItem->y() + _history->scrollTopOffset; } if (mtop >= 0 && _migrated->scrollTopItem) { - return mtop + _migrated->scrollTopItem->data()->block()->y() + _migrated->scrollTopItem->y() + _migrated->scrollTopOffset; + return mtop + _migrated->scrollTopItem->block()->y() + _migrated->scrollTopItem->y() + _migrated->scrollTopOffset; } return ScrollMax; } @@ -2506,12 +2530,25 @@ int HistoryInner::historyDrawTop() const { return (top >= 0) ? (top + _historySkipHeight) : -1; } -int HistoryInner::itemTop(const HistoryItem *item) const { // -1 if should not be visible, -2 if bad history() - if (!item) return -2; - if (item->detached()) return -1; +// -1 if should not be visible, -2 if bad history() +int HistoryInner::itemTop(const HistoryItem *item) const { + if (!item) { + return -2; + } + return itemTop(item->mainView()); +} - auto top = (item->history() == _history) ? historyTop() : (item->history() == _migrated ? migratedTop() : -2); - return (top < 0) ? top : (top + item->mainView()->y() + item->block()->y()); +int HistoryInner::itemTop(const Message *view) const { + if (!view) { + return -1; + } + + auto top = (view->data()->history() == _history) + ? historyTop() + : (view->data()->history() == _migrated + ? migratedTop() + : -2); + return (top < 0) ? top : (top + view->y() + view->block()->y()); } void HistoryInner::notifyIsBotChanged() { @@ -2541,8 +2578,8 @@ int HistoryInner::moveScrollFollowingInlineKeyboard( const HistoryItem *item, int oldKeyboardTop, int newKeyboardTop) { - if (item == App::mousedItem()) { - int top = itemTop(item); + if (item->isUnderCursor()) { + const auto top = itemTop(item); if (top >= oldKeyboardTop) { return newKeyboardTop - oldKeyboardTop; } @@ -2671,24 +2708,32 @@ void HistoryInner::changeSelectionAsGroup( } } -void HistoryInner::forwardItem(not_null item) { - Window::ShowForwardMessagesBox({ 1, item->fullId() }); +void HistoryInner::forwardItem(FullMsgId itemId) { + Window::ShowForwardMessagesBox({ 1, itemId }); } -void HistoryInner::forwardAsGroup(not_null item) { - if (const auto group = item->getFullGroup()) { - 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::forwardAsGroup(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { + if (const auto group = item->getFullGroup()) { + auto items = Auth().data().itemsToIds(group->others); + items.push_back(group->leader->fullId()); + Window::ShowForwardMessagesBox(std::move(items)); + } else { + Window::ShowForwardMessagesBox({ 1, itemId }); + } + } +} + +void HistoryInner::deleteItem(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { + deleteItem(item); } } void HistoryInner::deleteItem(not_null item) { if (auto message = item->toHistoryMessage()) { if (message->uploading()) { - App::main()->cancelUploadLayer(); + App::main()->cancelUploadLayer(item); return; } } @@ -2696,14 +2741,16 @@ void HistoryInner::deleteItem(not_null item) { Ui::show(Box(item, suggestModerateActions)); } -void HistoryInner::deleteAsGroup(not_null item) { - const auto group = item->getFullGroup(); - if (!group || group->others.empty()) { - return deleteItem(item); +void HistoryInner::deleteAsGroup(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { + const auto group = item->getFullGroup(); + if (!group || group->others.empty()) { + return deleteItem(item); + } + auto items = Auth().data().itemsToIds(group->others); + items.push_back(group->leader->fullId()); + Ui::show(Box(Auth().data().groupToIds(group))); } - auto items = Auth().data().itemsToIds(group->others); - items.push_back(group->leader->fullId()); - Ui::show(Box(Auth().data().groupToIds(group))); } void HistoryInner::addSelectionRange( @@ -2731,7 +2778,7 @@ void HistoryInner::applyDragSelection( const auto selfromy = itemTop(_dragSelFrom); const auto seltoy = [&] { auto result = itemTop(_dragSelTo); - return (result < 0) ? result : (result + _dragSelTo->height()); + return (result < 0) ? result : (result + _dragSelTo->data()->height()); }(); if (selfromy < 0 || seltoy < 0) { return; @@ -2746,8 +2793,8 @@ void HistoryInner::applyDragSelection( auto toblock = _dragSelTo->block()->indexInHistory(); auto toitem = _dragSelTo->indexInBlock(); if (_migrated) { - if (_dragSelFrom->history() == _migrated) { - if (_dragSelTo->history() == _migrated) { + if (_dragSelFrom->data()->history() == _migrated) { + if (_dragSelTo->data()->history() == _migrated) { addSelectionRange(toItems, _migrated, fromblock, fromitem, toblock, toitem); toblock = -1; toitem = -1; @@ -2756,7 +2803,7 @@ void HistoryInner::applyDragSelection( } fromblock = 0; fromitem = 0; - } else if (_dragSelTo->history() == _migrated) { // wtf + } else if (_dragSelTo->data()->history() == _migrated) { // wtf toblock = -1; toitem = -1; } @@ -2780,21 +2827,21 @@ void HistoryInner::applyDragSelection( QString HistoryInner::tooltipText() const { if (_mouseCursorState == HistoryInDateCursorState && _mouseAction == MouseAction::None) { - if (const auto item = App::hoveredItem()) { - auto dateText = item->date.toString( + if (const auto view = App::hoveredItem()) { + auto dateText = view->data()->date.toString( QLocale::system().dateTimeFormat(QLocale::LongFormat)); - auto editedDate = item->displayedEditDate(); + auto editedDate = view->data()->displayedEditDate(); if (!editedDate.isNull()) { dateText += '\n' + lng_edited_date(lt_date, editedDate.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat))); } - if (const auto forwarded = item->Get()) { + if (const auto forwarded = view->data()->Get()) { dateText += '\n' + lng_forwarded_date(lt_date, forwarded->originalDate.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat))); } return dateText; } } else if (_mouseCursorState == HistoryInForwardedCursorState && _mouseAction == MouseAction::None) { - if (const auto item = App::hoveredItem()) { - if (const auto forwarded = item->Get()) { + if (const auto view = App::hoveredItem()) { + if (const auto forwarded = view->data()->Get()) { return forwarded->text.originalText(AllTextSelection, ExpandLinksNone); } } diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index d45b90e73..dce0d73e7 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -28,6 +28,8 @@ class HistoryInner Q_OBJECT public: + using Message = HistoryView::Message; + HistoryInner( not_null historyWidget, not_null controller, @@ -40,12 +42,12 @@ public: TextWithEntities getSelectedText() const; void touchScrollUpdated(const QPoint &screenPos); - QPoint mapPointToItem(QPoint p, HistoryItem *item); void recountHistoryGeometry(); void updateSize(); void repaintItem(const HistoryItem *item); + void repaintItem(const Message *view); bool canCopySelected() const; bool canDeleteSelected() const; @@ -68,7 +70,10 @@ public: int migratedTop() const; int historyTop() const; int historyDrawTop() const; - int itemTop(const HistoryItem *item) const; // -1 if should not be visible, -2 if bad history() + + // -1 if should not be visible, -2 if bad history() + int itemTop(const HistoryItem *item) const; + int itemTop(const Message *view) const; void notifyIsBotChanged(); void notifyMigrateUpdated(); @@ -104,14 +109,8 @@ public slots: void onParentGeometryChanged(); void copyContextUrl(); - void cancelContextDownload(); - void showContextInFolder(); - void saveContextGif(); - void openContextGif(); - void copyContextText(); void copySelectedText(); - void onMenuDestroy(QObject *obj); void onTouchSelect(); void onTouchScrollTimer(); @@ -122,7 +121,6 @@ private slots: private: class BotAbout; using SelectedItems = std::map>; - using Message = HistoryView::Message; enum class MouseAction { None, PrepareDrag, @@ -135,166 +133,6 @@ private: Deselect, Invert, }; - - void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button); - void mouseActionUpdate(const QPoint &screenPos); - void mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button); - void mouseActionCancel(); - void performDrag(); - - void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false); - - void itemRemoved(not_null item); - void savePhotoToFile(PhotoData *photo); - void saveDocumentToFile(DocumentData *document); - void copyContextImage(PhotoData *photo); - void showStickerPackInfo(DocumentData *document); - void toggleFavedSticker(DocumentData *document); - - void touchResetSpeed(); - void touchUpdateSpeed(); - void touchDeaccelerate(int32 elapsed); - - void adjustCurrent(int32 y) const; - void adjustCurrent(int32 y, History *history) const; - HistoryItem *prevItem(HistoryItem *item); - HistoryItem *nextItem(HistoryItem *item); - void updateDragSelection(HistoryItem *dragSelFrom, HistoryItem *dragSelTo, bool dragSelecting); - TextSelection itemRenderSelection( - not_null view, - int selfromy, - int seltoy) const; - TextSelection computeRenderSelection( - not_null selected, - not_null item) const; - - void setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode = QClipboard::Clipboard); - - void toggleScrollDateShown(); - void repaintScrollDateCallback(); - bool displayScrollDate() const; - void scrollDateHide(); - void keepScrollDateForNow(); - - not_null _controller; - - PeerData *_peer = nullptr; - History *_migrated = nullptr; - History *_history = nullptr; - int _historyPaddingTop = 0; - - // with migrated history we perhaps do not need to display first _history message - // (if last _migrated message and first _history message are both isGroupMigrate) - // or at least we don't need to display first _history date (just skip it by height) - int _historySkipHeight = 0; - - std::unique_ptr _botAbout; - - HistoryWidget *_widget = nullptr; - Ui::ScrollArea *_scroll = nullptr; - mutable History *_curHistory = nullptr; - mutable int _curBlock = 0; - mutable int _curItem = 0; - - bool _firstLoading = false; - - style::cursor _cursor = style::cur_default; - SelectedItems _selected; - - void applyDragSelection(); - void applyDragSelection(not_null toItems) const; - void addSelectionRange( - not_null toItems, - not_null history, - int fromblock, - int fromitem, - int toblock, - int toitem) const; - bool isSelected( - not_null toItems, - not_null item) const; - 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 { - return (_history && _history->hasPendingResizedItems()) || (_migrated && _migrated->hasPendingResizedItems()); - } - - MouseAction _mouseAction = MouseAction::None; - TextSelectType _mouseSelectType = TextSelectType::Letters; - QPoint _dragStartPosition; - QPoint _mousePosition; - HistoryItem *_mouseActionItem = nullptr; - HistoryItem *_dragStateItem = nullptr; - HistoryCursorState _mouseCursorState = HistoryDefaultCursorState; - uint16 _mouseTextSymbol = 0; - bool _pressWasInactive = false; - - QPoint _trippleClickPoint; - QTimer _trippleClickTimer; - - ClickHandlerPtr _contextMenuLink; - - HistoryItem *_dragSelFrom = nullptr; - HistoryItem *_dragSelTo = nullptr; - bool _dragSelecting = false; - bool _wasSelectedText = false; // was some text selected in current drag action - - // scroll by touch support (at least Windows Surface tablets) - bool _touchScroll = false; - bool _touchSelect = false; - bool _touchInProgress = false; - QPoint _touchStart, _touchPrevPos, _touchPos; - QTimer _touchSelectTimer; - - Ui::TouchScrollState _touchScrollState = Ui::TouchScrollState::Manual; - bool _touchPrevPosValid = false; - bool _touchWaitingAcceleration = false; - QPoint _touchSpeed; - TimeMs _touchSpeedTime = 0; - TimeMs _touchAccelerationTime = 0; - TimeMs _touchTime = 0; - QTimer _touchScrollTimer; - - // context menu - Ui::PopupMenu *_menu = nullptr; - - // save visible area coords for painting / pressing userpics - int _visibleAreaTop = 0; - int _visibleAreaBottom = 0; - - bool _scrollDateShown = false; - Animation _scrollDateOpacity; - SingleQueuedInvokation _scrollDateCheck; - SingleTimer _scrollDateHideTimer; - Message *_scrollDateLastItem = nullptr; - int _scrollDateLastItemTop = 0; - ClickHandlerPtr _scrollDateLink; - enum class EnumItemsDirection { TopToBottom, BottomToTop, @@ -335,4 +173,171 @@ private: template void enumerateDates(Method method); + void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button); + void mouseActionUpdate(const QPoint &screenPos); + void mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button); + void mouseActionCancel(); + void performDrag(); + + QPoint mapPointToItem(QPoint p, const Message *view); + QPoint mapPointToItem(QPoint p, const HistoryItem *item); + + void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false); + void cancelContextDownload(not_null document); + void openContextGif(FullMsgId itemId); + void saveContextGif(FullMsgId itemId); + void copyContextText(FullMsgId itemId); + void showContextInFolder(not_null document); + void savePhotoToFile(not_null photo); + void saveDocumentToFile(not_null document); + void copyContextImage(not_null photo); + void showStickerPackInfo(not_null document); + void toggleFavedSticker(not_null document); + + void itemRemoved(not_null item); + + void touchResetSpeed(); + void touchUpdateSpeed(); + void touchDeaccelerate(int32 elapsed); + + void adjustCurrent(int32 y) const; + void adjustCurrent(int32 y, History *history) const; + Message *prevItem(Message *item); + Message *nextItem(Message *item); + void updateDragSelection(Message *dragSelFrom, Message *dragSelTo, bool dragSelecting); + TextSelection itemRenderSelection( + not_null view, + int selfromy, + int seltoy) const; + TextSelection computeRenderSelection( + not_null selected, + not_null item) const; + + void setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode = QClipboard::Clipboard); + + void toggleScrollDateShown(); + void repaintScrollDateCallback(); + bool displayScrollDate() const; + void scrollDateHide(); + void keepScrollDateForNow(); + + void applyDragSelection(); + void applyDragSelection(not_null toItems) const; + void addSelectionRange( + not_null toItems, + not_null history, + int fromblock, + int fromitem, + int toblock, + int toitem) const; + bool isSelected( + not_null toItems, + not_null item) const; + 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(FullMsgId itemId); + void forwardAsGroup(FullMsgId itemId); + void deleteItem(not_null item); + void deleteItem(FullMsgId itemId); + void deleteAsGroup(FullMsgId itemId); + + // Does any of the shown histories has this flag set. + bool hasPendingResizedItems() const { + return (_history && _history->hasPendingResizedItems()) || (_migrated && _migrated->hasPendingResizedItems()); + } + + not_null _controller; + + not_null _peer; + not_null _history; + History *_migrated = nullptr; + int _historyPaddingTop = 0; + + // with migrated history we perhaps do not need to display first _history message + // (if last _migrated message and first _history message are both isGroupMigrate) + // or at least we don't need to display first _history date (just skip it by height) + int _historySkipHeight = 0; + + std::unique_ptr _botAbout; + + HistoryWidget *_widget = nullptr; + Ui::ScrollArea *_scroll = nullptr; + mutable History *_curHistory = nullptr; + mutable int _curBlock = 0; + mutable int _curItem = 0; + + bool _firstLoading = false; + + style::cursor _cursor = style::cur_default; + SelectedItems _selected; + + MouseAction _mouseAction = MouseAction::None; + TextSelectType _mouseSelectType = TextSelectType::Letters; + QPoint _dragStartPosition; + QPoint _mousePosition; + HistoryItem *_mouseActionItem = nullptr; + HistoryItem *_dragStateItem = nullptr; + HistoryCursorState _mouseCursorState = HistoryDefaultCursorState; + uint16 _mouseTextSymbol = 0; + bool _pressWasInactive = false; + + QPoint _trippleClickPoint; + QTimer _trippleClickTimer; + + ClickHandlerPtr _contextMenuLink; + + Message *_dragSelFrom = nullptr; + Message *_dragSelTo = nullptr; + bool _dragSelecting = false; + bool _wasSelectedText = false; // was some text selected in current drag action + + // scroll by touch support (at least Windows Surface tablets) + bool _touchScroll = false; + bool _touchSelect = false; + bool _touchInProgress = false; + QPoint _touchStart, _touchPrevPos, _touchPos; + QTimer _touchSelectTimer; + + Ui::TouchScrollState _touchScrollState = Ui::TouchScrollState::Manual; + bool _touchPrevPosValid = false; + bool _touchWaitingAcceleration = false; + QPoint _touchSpeed; + TimeMs _touchSpeedTime = 0; + TimeMs _touchAccelerationTime = 0; + TimeMs _touchTime = 0; + QTimer _touchScrollTimer; + + base::unique_qptr _menu; + + // save visible area coords for painting / pressing userpics + int _visibleAreaTop = 0; + int _visibleAreaBottom = 0; + + bool _scrollDateShown = false; + Animation _scrollDateOpacity; + SingleQueuedInvokation _scrollDateCheck; + SingleTimer _scrollDateHideTimer; + Message *_scrollDateLastItem = nullptr; + int _scrollDateLastItemTop = 0; + ClickHandlerPtr _scrollDateLink; + }; diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index a4a5cd71b..aa75fdde4 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -259,7 +259,8 @@ void HistoryItem::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool activ markup->inlineKeyboard->clickHandlerActiveChanged(p, active); } } - App::hoveredLinkItem(active ? this : nullptr); + // #TODO hoveredLinkItem + // App::hoveredLinkItem(active ? this : nullptr); Auth().data().requestItemRepaint(this); } @@ -269,7 +270,8 @@ void HistoryItem::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pres markup->inlineKeyboard->clickHandlerPressedChanged(p, pressed); } } - App::pressedLinkItem(pressed ? this : nullptr); + // #TODO hoveredLinkItem + // App::pressedLinkItem(pressed ? this : nullptr); Auth().data().requestItemRepaint(this); } @@ -291,7 +293,7 @@ UserData *HistoryItem::viaBot() const { void HistoryItem::destroy() { const auto history = this->history(); if (isLogEntry()) { - Assert(detached()); + Assert(!mainView()); } else { // All this must be done for all items manually in History::clear(false)! eraseFromUnreadMentions(); @@ -309,7 +311,7 @@ void HistoryItem::destroy() { const auto wasAtBottom = history->loadedAtBottom(); history->removeNotification(this); - detach(); + removeMainView(); if (history->lastMsg == this) { history->fixLastMessage(wasAtBottom); @@ -336,33 +338,18 @@ void HistoryItem::destroy() { delete this; } -void HistoryItem::detach() { - if (detached()) return; - - if (_history->isChannel()) { - _history->asChannelHistory()->messageDetached(this); +void HistoryItem::removeMainView() { + if (const auto view = mainView()) { + if (const auto channelHistory = _history->asChannelHistory()) { + channelHistory->messageDetached(this); + } + _history->setPendingResize(); + view->removeFromBlock(); + _mainView = nullptr; } - _block->removeItem(this); - App::historyItemDetached(this); - - _history->setPendingResize(); } -void HistoryItem::attachToBlock(not_null block, int index) { - Expects(!isLogEntry()); - Expects(_block == nullptr); - Expects(_indexInBlock < 0); - Expects(index >= 0); - - _block = block; - _indexInBlock = index; - _mainView = block->messages[index].get(); - setPendingResize(); -} - -void HistoryItem::detachFast() { - _block = nullptr; - _indexInBlock = -1; +void HistoryItem::clearMainView() { _mainView = nullptr; validateGroupId(); @@ -391,6 +378,7 @@ void HistoryItem::indexAsNewItem() { void HistoryItem::previousItemChanged() { Expects(!isLogEntry()); + recountDisplayDate(); recountAttachToPrevious(); } @@ -398,6 +386,7 @@ void HistoryItem::previousItemChanged() { // Called only if there is no more next item! Not always when it changes! void HistoryItem::nextItemChanged() { Expects(!isLogEntry()); + setAttachToNext(false); } @@ -421,6 +410,7 @@ bool HistoryItem::computeIsAttachToPrevious(not_null previous) { void HistoryItem::recountAttachToPrevious() { Expects(!isLogEntry()); + auto attachToPrevious = false; if (auto previous = previousItem()) { attachToPrevious = computeIsAttachToPrevious(previous); @@ -940,11 +930,6 @@ void HistoryItem::clipCallback(Media::Clip::Notification notification) { } if (!stopped) { setPendingInitDimensions(); - if (detached()) { - // We still want to handle our pending initDimensions and - // resize state even if we're detached in history. - _history->setHasPendingResizedItems(); - } Auth().data().markItemLayoutChanged(this); Global::RefPendingRepaintItems().insert(this); } @@ -984,27 +969,26 @@ void HistoryItem::audioTrackUpdated() { } } +bool HistoryItem::isUnderCursor() const { + if (const auto view = App::hoveredItem()) { + return view->data() == this; + } + return false; +} + HistoryItem *HistoryItem::previousItem() const { - if (_block && _indexInBlock >= 0) { - if (_indexInBlock > 0) { - return _block->messages[_indexInBlock - 1]->data(); - } - if (auto previous = _block->previousBlock()) { - Assert(!previous->messages.empty()); - return previous->messages.back()->data(); + if (const auto view = mainView()) { + if (const auto previous = view->previousInBlocks()) { + return previous->data(); } } return nullptr; } HistoryItem *HistoryItem::nextItem() const { - if (_block && _indexInBlock >= 0) { - if (_indexInBlock + 1 < _block->messages.size()) { - return _block->messages[_indexInBlock + 1]->data(); - } - if (auto next = _block->nextBlock()) { - Assert(!next->messages.empty()); - return next->messages.front()->data(); + if (const auto view = mainView()) { + if (const auto next = view->nextInBlocks()) { + return next->data(); } } return nullptr; @@ -1107,9 +1091,9 @@ HistoryItem::~HistoryItem() { ClickHandlerPtr goToMessageClickHandler(PeerData *peer, MsgId msgId) { return std::make_shared([peer, msgId] { if (App::main()) { - auto current = App::mousedItem(); - if (current && current->history()->peer == peer) { - App::main()->pushReplyReturn(current); + auto view = App::mousedItem(); + if (view && view->data()->history()->peer == peer) { + App::main()->pushReplyReturn(view->data()); } App::wnd()->controller()->showPeerHistory( peer, diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 1f82b4850..cf75bdee6 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -53,6 +53,9 @@ public: int minHeight() const { return _minh; } + int width() const { + return _width; + } int height() const { return _height; } @@ -62,6 +65,7 @@ public: protected: mutable int _maxw = 0; mutable int _minh = 0; + mutable int _width = 0; mutable int _height = 0; }; @@ -226,34 +230,16 @@ public: PeerData *from() const { return _from; } - HistoryBlock *block() { - return _block; - } - const HistoryBlock *block() const { - return _block; - } HistoryView::Message *mainView() const { return _mainView; } + void setMainView(HistoryView::Message *view) { + _mainView = view; + } + void clearMainView(); + void removeMainView(); + void destroy(); - void detach(); - void detachFast(); - bool detached() const { - return !_block; - } - void attachToBlock(not_null block, int index); - void setIndexInBlock(int index) { - Expects(_block != nullptr); - Expects(index >= 0); - - _indexInBlock = index; - } - int indexInBlock() const { - Expects((_indexInBlock >= 0) == (_block != nullptr)); - //Expects((_block == nullptr) || (_block->messages[_indexInBlock]->data() == this)); - - return _indexInBlock; - } bool out() const { return _flags & MTPDmessage::Flag::f_out; } @@ -493,9 +479,7 @@ public: } void setPendingResize() { _flags |= MTPDmessage_ClientFlag::f_pending_resize; - if (!detached() || isLogEntry()) { - _history->setHasPendingResizedItems(); - } + _history->setHasPendingResizedItems(); } bool pendingInitDimensions() const { return _flags & MTPDmessage_ClientFlag::f_pending_init_dimensions; @@ -535,10 +519,6 @@ public: void makeGroupLeader(std::vector> &&others); HistoryMessageGroup *getFullGroup(); - int width() const { - return _width; - } - void clipCallback(Media::Clip::Notification notification); void audioTrackUpdated(); @@ -556,6 +536,8 @@ public: setAttachToNext(attachToNext); } + bool isUnderCursor() const; + HistoryItem *previousItem() const; HistoryItem *nextItem() const; @@ -586,8 +568,6 @@ protected: const not_null _history; not_null _from; - HistoryBlock *_block = nullptr; - int _indexInBlock = -1; MTPDmessage::Flags _flags = 0; // This should be called only from previousItemChanged() @@ -642,7 +622,6 @@ private: void resetGroupMedia(const std::vector> &others); HistoryView::Message *_mainView = nullptr; - int _width = 0; }; diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index 38170f366..5fc316db3 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -398,8 +398,9 @@ struct HistoryMessageLogEntryOriginal : public RuntimeComponent { - ClickHandlerPtr _linksavel, _linkcancell; + std::shared_ptr _linksavel, _linkcancell; int _thumbw = 0; mutable int _linkw = 0; diff --git a/Telegram/SourceFiles/history/history_media.h b/Telegram/SourceFiles/history/history_media.h index 498748290..1ed783e4e 100644 --- a/Telegram/SourceFiles/history/history_media.h +++ b/Telegram/SourceFiles/history/history_media.h @@ -230,10 +230,6 @@ public: return QString(); } - int currentWidth() const { - return _width; - } - void setInBubbleState(MediaInBubbleState state) { _inBubbleState = state; } @@ -265,7 +261,6 @@ public: protected: not_null _parent; - int _width = 0; MediaInBubbleState _inBubbleState = MediaInBubbleState::None; diff --git a/Telegram/SourceFiles/history/history_media_grouped.cpp b/Telegram/SourceFiles/history/history_media_grouped.cpp index 5b9e056da..709495c8c 100644 --- a/Telegram/SourceFiles/history/history_media_grouped.cpp +++ b/Telegram/SourceFiles/history/history_media_grouped.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item_components.h" #include "history/history_media_types.h" #include "history/history_message.h" +#include "history/view/history_view_message.h" #include "storage/storage_shared_media.h" #include "lang/lang_keys.h" #include "ui/grouped_layout.h" @@ -176,7 +177,7 @@ void HistoryGroupedMedia::draw( } else if (_parent->getMedia() == this) { auto fullRight = _width; auto fullBottom = _height; - if (_parent->id < 0 || App::hoveredItem() == _parent) { + if (needInfoDisplay()) { _parent->drawInfo(p, fullRight, fullBottom, _width, selected, InfoDisplayOverImage); } if (!_parent->hasBubble() && _parent->displayRightAction()) { @@ -295,7 +296,8 @@ void HistoryGroupedMedia::clickHandlerPressedChanged( for (const auto &element : _elements) { element.content->clickHandlerPressedChanged(p, pressed); if (pressed && element.content->dragItemByHandler(p)) { - App::pressedLinkItem(element.item); + // #TODO pressedLinkItem + //App::pressedLinkItem(element.item); } } } @@ -455,3 +457,7 @@ bool HistoryGroupedMedia::computeNeedBubble() const { } return false; } + +bool HistoryGroupedMedia::needInfoDisplay() const { + return (_parent->id < 0 || _parent->isUnderCursor()); +} diff --git a/Telegram/SourceFiles/history/history_media_grouped.h b/Telegram/SourceFiles/history/history_media_grouped.h index daa85a903..d5d8db1af 100644 --- a/Telegram/SourceFiles/history/history_media_grouped.h +++ b/Telegram/SourceFiles/history/history_media_grouped.h @@ -115,6 +115,7 @@ private: }; + bool needInfoDisplay() const; bool computeNeedBubble() const; not_null main() const; bool validateGroupElements( diff --git a/Telegram/SourceFiles/history/history_media_types.cpp b/Telegram/SourceFiles/history/history_media_types.cpp index f1700d5bc..34900a913 100644 --- a/Telegram/SourceFiles/history/history_media_types.cpp +++ b/Telegram/SourceFiles/history/history_media_types.cpp @@ -446,7 +446,7 @@ void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, Tim } else if (notChild) { auto fullRight = skipx + width; auto fullBottom = skipy + height; - if (_data->uploading() || App::hoveredItem() == _parent) { + if (needInfoDisplay()) { _parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, InfoDisplayOverImage); } if (!bubble && _parent->displayRightAction()) { @@ -646,6 +646,10 @@ bool HistoryPhoto::dataLoaded() const { return _data->loaded(); } +bool HistoryPhoto::needInfoDisplay() const { + return (_data->uploading() || _parent->isUnderCursor()); +} + void HistoryPhoto::validateGroupedCache( const QRect &geometry, RectParts corners, @@ -1402,11 +1406,17 @@ void HistoryDocument::createComponents(bool caption) { } UpdateComponents(mask); if (auto thumbed = Get()) { - thumbed->_linksavel = std::make_shared(_data); - thumbed->_linkcancell = std::make_shared(_data); + thumbed->_linksavel = std::make_shared( + _data, + _parent->fullId()); + thumbed->_linkcancell = std::make_shared( + _data, + _parent->fullId()); } if (auto voice = Get()) { - voice->_seekl = std::make_shared(_data); + voice->_seekl = std::make_shared( + _data, + _parent->fullId()); } } @@ -2066,6 +2076,23 @@ void HistoryDocument::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool HistoryFileMedia::clickHandlerPressedChanged(p, pressed); } +void HistoryDocument::refreshParentId(not_null realParent) { + HistoryFileMedia::refreshParentId(realParent); + + const auto contextId = realParent->fullId(); + if (auto thumbed = Get()) { + if (thumbed->_linksavel) { + thumbed->_linksavel->setMessageId(contextId); + thumbed->_linkcancell->setMessageId(contextId); + } + } + if (auto voice = Get()) { + if (voice->_seekl) { + voice->_seekl->setMessageId(contextId); + } + } +} + bool HistoryDocument::playInline(bool autoplay) { if (_data->isVoiceMessage()) { DocumentOpenClickHandler::doOpen(_data, _parent, ActionOnLoadPlayInline); @@ -2157,7 +2184,9 @@ void HistoryGif::initDimensions() { _caption.setSkipBlock(_parent->skipBlockWidth(), _parent->skipBlockHeight()); } if (!_openInMediaviewLink) { - _openInMediaviewLink = std::make_shared(_data); + _openInMediaviewLink = std::make_shared( + _data, + _parent->fullId()); } int32 tw = 0, th = 0; @@ -2548,7 +2577,7 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM fullRight = maxRight; } } - if (isRound || _data->uploading() || App::hoveredItem() == _parent) { + if (isRound || needInfoDisplay()) { _parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, isRound ? InfoDisplayOverBackground : InfoDisplayOverImage); } if (!bubble && _parent->displayRightAction()) { @@ -2955,6 +2984,10 @@ bool HistoryGif::dataLoaded() const { return (_parent->id > 0) ? _data->loaded() : false; } +bool HistoryGif::needInfoDisplay() const { + return (_data->uploading() || _parent->isUnderCursor()); +} + HistorySticker::HistorySticker( not_null parent, not_null document) @@ -3835,7 +3868,7 @@ int HistoryWebPage::resizeGetHeight(int width) { _height += _attach->height() - bubble.top() - bubble.bottom(); if (!_attach->additionalInfoString().isEmpty()) { _height += bottomInfoPadding(); - } else if (isBubbleBottom() && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { + } else if (isBubbleBottom() && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { _height += bottomInfoPadding(); } } @@ -3873,7 +3906,7 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, T bshift += bottomInfoPadding(); } else if (!attachAdditionalInfoText.isEmpty()) { bshift += bottomInfoPadding(); - } else if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { + } else if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { bshift += bottomInfoPadding(); } @@ -3939,13 +3972,13 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, T auto attachLeft = padding.left() - bubble.left(); auto attachTop = tshift - bubble.top(); - if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth(); + if (rtl()) attachLeft = _width - attachLeft - _attach->width(); p.translate(attachLeft, attachTop); auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 }; _attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms); - int32 pixwidth = _attach->currentWidth(), pixheight = _attach->height(); + int32 pixwidth = _attach->width(), pixheight = _attach->height(); if (_data->type == WebPageVideo && _attach->type() == MediaTypePhoto) { if (_attach->isReadyForOpen()) { @@ -3991,7 +4024,7 @@ HistoryTextState HistoryWebPage::getState(QPoint point, HistoryStateRequest requ auto padding = inBubblePadding(); auto tshift = padding.top(); auto bshift = padding.bottom(); - if (_asArticle || (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right())) { + if (_asArticle || (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right())) { bshift += bottomInfoPadding(); } width -= padding.left() + padding.right(); @@ -4055,7 +4088,7 @@ HistoryTextState HistoryWebPage::getState(QPoint point, HistoryStateRequest requ if (QRect(padding.left(), tshift, width, _height - tshift - bshift).contains(point)) { auto attachLeft = padding.left() - bubble.left(); auto attachTop = tshift - bubble.top(); - if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth(); + if (rtl()) attachLeft = _width - attachLeft - _attach->width(); result = _attach->getState(point - QPoint(attachLeft, attachTop), request); if (result.link && !_data->document && _data->photo && _attach->isReadyForOpen()) { @@ -4325,7 +4358,7 @@ int HistoryGame::resizeGetHeight(int width) { _attach->resizeGetHeight(width + bubble.left() + bubble.right()); _height += _attach->height() - bubble.top() - bubble.bottom(); - if (isBubbleBottom() && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { + if (isBubbleBottom() && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { _height += bottomInfoPadding(); } } @@ -4351,7 +4384,7 @@ void HistoryGame::draw(Painter &p, const QRect &r, TextSelection selection, Time auto tshift = padding.top(); auto bshift = padding.bottom(); width -= padding.left() + padding.right(); - if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { + if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { bshift += bottomInfoPadding(); } @@ -4383,13 +4416,13 @@ void HistoryGame::draw(Painter &p, const QRect &r, TextSelection selection, Time auto attachLeft = padding.left() - bubble.left(); auto attachTop = tshift - bubble.top(); - if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth(); + if (rtl()) attachLeft = _width - attachLeft - _attach->width(); auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 }; p.translate(attachLeft, attachTop); _attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms); - auto pixwidth = _attach->currentWidth(); + auto pixwidth = _attach->width(); auto pixheight = _attach->height(); auto gameW = _gameTagWidth + 2 * st::msgDateImgPadding.x(); @@ -4419,7 +4452,7 @@ HistoryTextState HistoryGame::getState(QPoint point, HistoryStateRequest request auto padding = inBubblePadding(); auto tshift = padding.top(); auto bshift = padding.bottom(); - if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { + if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { bshift += bottomInfoPadding(); } width -= padding.left() + padding.right(); @@ -4465,9 +4498,9 @@ HistoryTextState HistoryGame::getState(QPoint point, HistoryStateRequest request auto attachLeft = padding.left() - bubble.left(); auto attachTop = tshift - bubble.top(); - if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth(); + if (rtl()) attachLeft = _width - attachLeft - _attach->width(); - if (QRect(attachLeft, tshift, _attach->currentWidth(), _height - tshift - bshift).contains(point)) { + if (QRect(attachLeft, tshift, _attach->width(), _height - tshift - bshift).contains(point)) { if (_attach->isReadyForOpen()) { if (!_parent->isLogEntry()) { result.link = _openl; @@ -4782,7 +4815,7 @@ int HistoryInvoice::resizeGetHeight(int width) { _attach->resizeGetHeight(width + bubble.left() + bubble.right()); _height += _attach->height() - bubble.top() - bubble.bottom(); - if (isBubbleBottom() && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { + if (isBubbleBottom() && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { _height += bottomInfoPadding(); } } else { @@ -4816,7 +4849,7 @@ void HistoryInvoice::draw(Painter &p, const QRect &r, TextSelection selection, T auto tshift = padding.top(); auto bshift = padding.bottom(); width -= padding.left() + padding.right(); - if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { + if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { bshift += bottomInfoPadding(); } @@ -4845,13 +4878,13 @@ void HistoryInvoice::draw(Painter &p, const QRect &r, TextSelection selection, T auto attachLeft = padding.left() - bubble.left(); auto attachTop = tshift - bubble.top(); - if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth(); + if (rtl()) attachLeft = _width - attachLeft - _attach->width(); auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 }; p.translate(attachLeft, attachTop); _attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms); - auto pixwidth = _attach->currentWidth(); + auto pixwidth = _attach->width(); auto pixheight = _attach->height(); auto available = _status.maxWidth(); @@ -4885,7 +4918,7 @@ HistoryTextState HistoryInvoice::getState(QPoint point, HistoryStateRequest requ auto padding = inBubblePadding(); auto tshift = padding.top(); auto bshift = padding.bottom(); - if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { + if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { bshift += bottomInfoPadding(); } width -= padding.left() + padding.right(); @@ -4924,9 +4957,9 @@ HistoryTextState HistoryInvoice::getState(QPoint point, HistoryStateRequest requ auto attachLeft = padding.left() - bubble.left(); auto attachTop = tshift - bubble.top(); - if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth(); + if (rtl()) attachLeft = _width - attachLeft - _attach->width(); - if (QRect(attachLeft, tshift, _attach->currentWidth(), _height - tshift - bshift).contains(point)) { + if (QRect(attachLeft, tshift, _attach->width(), _height - tshift - bshift).contains(point)) { result = _attach->getState(point - QPoint(attachLeft, attachTop), request); } } diff --git a/Telegram/SourceFiles/history/history_media_types.h b/Telegram/SourceFiles/history/history_media_types.h index 3cee96094..dca037b15 100644 --- a/Telegram/SourceFiles/history/history_media_types.h +++ b/Telegram/SourceFiles/history/history_media_types.h @@ -254,6 +254,7 @@ protected: bool dataLoaded() const override; private: + bool needInfoDisplay() const; void validateGroupedCache( const QRect &geometry, RectParts corners, @@ -466,6 +467,8 @@ public: void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override; + void refreshParentId(not_null realParent) override; + protected: float64 dataProgress() const override; bool dataFinished() const override; @@ -588,6 +591,7 @@ protected: } private: + bool needInfoDisplay() const; int additionalWidth( const HistoryMessageVia *via, const HistoryMessageReply *reply, diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index 803edfbaa..89665071c 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -1227,8 +1227,8 @@ bool HistoryMessage::displayFastReply() const { QRect HistoryMessage::countGeometry() const { auto maxwidth = qMin(st::msgMaxWidth, _maxw); - if (_media && _media->currentWidth() < maxwidth) { - maxwidth = qMax(_media->currentWidth(), qMin(maxwidth, plainMaxWidth())); + if (_media && _media->width() < maxwidth) { + maxwidth = qMax(_media->width(), qMin(maxwidth, plainMaxWidth())); } const auto outLayout = hasOutLayout(); @@ -1904,7 +1904,7 @@ void HistoryMessage::paintFromName( return 0; }(); const auto replyWidth = [&] { - if (App::hoveredItem() == this && displayFastReply()) { + if (isUnderCursor() && displayFastReply()) { return st::msgFont->width(FastReplyText()); } return 0; @@ -2364,7 +2364,7 @@ bool HistoryMessage::getStateFromName( not_null outResult) const { if (displayFromName()) { const auto replyWidth = [&] { - if (App::hoveredItem() == this && displayFastReply()) { + if (isUnderCursor() && displayFastReply()) { return st::msgFont->width(FastReplyText()); } return 0; diff --git a/Telegram/SourceFiles/history/history_service.cpp b/Telegram/SourceFiles/history/history_service.cpp index da0abc5b5..3ffc7f5a7 100644 --- a/Telegram/SourceFiles/history/history_service.cpp +++ b/Telegram/SourceFiles/history/history_service.cpp @@ -550,7 +550,7 @@ int HistoryService::resizeContentGetHeight() { } _height += st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom(); if (_media) { - _height += st::msgServiceMargin.top() + _media->resizeGetHeight(_media->currentWidth()); + _height += st::msgServiceMargin.top() + _media->resizeGetHeight(_media->width()); } } diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index a48440102..c03676083 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -628,7 +628,7 @@ HistoryWidget::HistoryWidget(QWidget *parent, not_null cont })); subscribe(Auth().data().pendingHistoryResize(), [this] { handlePendingHistoryUpdate(); }); subscribe(Auth().data().queryItemVisibility(), [this](const Data::Session::ItemVisibilityQuery &query) { - if (_a_show.animating() || _history != query.item->history() || query.item->detached() || !isVisible()) { + if (_a_show.animating() || _history != query.item->history() || !query.item->mainView() || !isVisible()) { return; } auto top = _list->itemTop(query.item); @@ -642,9 +642,7 @@ HistoryWidget::HistoryWidget(QWidget *parent, not_null cont Auth().data().itemLayoutChanged( ) | rpl::start_with_next([this](auto item) { if (_peer && _list) { - if ((item == App::mousedItem()) - || (item == App::hoveredItem()) - || (item == App::hoveredLinkItem())) { + if (item->isUnderCursor()) { _list->onUpdateSelected(); } } @@ -804,7 +802,7 @@ void HistoryWidget::adjustHighlightedMessageToMigrated() { _history->channelId(), _highlightedMessageId); if (highlighted && highlighted->isGroupMigrate()) { - _highlightedMessageId = -_migrated->blocks.back()->messages.back()->id(); + _highlightedMessageId = -_migrated->blocks.back()->messages.back()->data()->id; } } } @@ -818,7 +816,7 @@ void HistoryWidget::checkNextHighlight() { auto msgId = _highlightQueue.front(); _highlightQueue.pop_front(); auto item = getItemFromHistoryOrMigrated(msgId); - if (item && !item->detached()) { + if (item && item->mainView()) { return msgId; } } @@ -832,7 +830,7 @@ void HistoryWidget::checkNextHighlight() { void HistoryWidget::updateHighlightedMessage() { auto item = getItemFromHistoryOrMigrated(_highlightedMessageId); - if (!item || item->detached()) { + if (!item || !item->mainView()) { return stopMessageHighlight(); } auto duration = st::activeFadeInDuration + st::activeFadeOutDuration; @@ -1440,8 +1438,7 @@ void HistoryWidget::clearReplyReturns() { _replyReturn = 0; } -void HistoryWidget::pushReplyReturn(HistoryItem *item) { - if (!item) return; +void HistoryWidget::pushReplyReturn(not_null item) { if (item->history() == _history) { _replyReturns.push_back(item->id); } else if (item->history() == _migrated) { @@ -1707,13 +1704,6 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re _nonEmptySelection = false; _topBar->showSelected(HistoryView::TopBarWidget::SelectedState {}); - App::hoveredItem(nullptr); - App::pressedItem(nullptr); - App::hoveredLinkItem(nullptr); - App::pressedLinkItem(nullptr); - App::contextItem(nullptr); - App::mousedItem(nullptr); - if (_peer) { App::forgetMedia(); _serviceImageCacheSize = imageCacheSize(); @@ -2424,7 +2414,7 @@ bool HistoryWidget::doWeReadServerHistory() const { if (scrollTop + 1 > _scroll->scrollTopMax()) return true; auto showFrom = (_migrated && _migrated->showFrom) ? _migrated->showFrom : (_history ? _history->showFrom : nullptr); - if (showFrom && !showFrom->detached()) { + if (showFrom && showFrom->mainView()) { int scrollBottom = scrollTop + _scroll->height(); if (scrollBottom > _list->itemTop(showFrom)) return true; } @@ -2445,7 +2435,7 @@ bool HistoryWidget::doWeReadMentions() const { } bool HistoryWidget::historyHasNotFreezedUnreadBar(History *history) const { - if (history && history->showFrom && !history->showFrom->detached() && history->unreadBar) { + if (history && history->showFrom && history->showFrom->mainView() && history->unreadBar) { if (auto unreadBar = history->unreadBar->Get()) { return !unreadBar->_freezed; } @@ -2675,7 +2665,7 @@ void HistoryWidget::visibleAreaUpdated() { _list->visibleAreaUpdated(scrollTop, scrollBottom); if (_history->loadedAtBottom() && (_history->unreadCount() > 0 || (_migrated && _migrated->unreadCount() > 0))) { auto showFrom = (_migrated && _migrated->showFrom) ? _migrated->showFrom : (_history ? _history->showFrom : nullptr); - auto showFromVisible = (showFrom && !showFrom->detached() && scrollBottom > _list->itemTop(showFrom)); + auto showFromVisible = (showFrom && showFrom->mainView() && scrollBottom > _list->itemTop(showFrom)); auto atBottom = (scrollTop >= _scroll->scrollTopMax()); if ((showFromVisible || atBottom) && App::wnd()->doWeReadServerHistory()) { Auth().api().readServerHistory(_history); @@ -2727,14 +2717,14 @@ void HistoryWidget::checkReplyReturns() { auto scrollTopMax = _scroll->scrollTopMax(); auto scrollHeight = _scroll->height(); while (_replyReturn) { - auto below = (_replyReturn->detached() && _replyReturn->history() == _history && !_history->isEmpty() && _replyReturn->id < _history->blocks.back()->messages.back()->id()); + auto below = (!_replyReturn->mainView() && _replyReturn->history() == _history && !_history->isEmpty() && _replyReturn->id < _history->blocks.back()->messages.back()->data()->id); if (!below) { - below = (_replyReturn->detached() && _replyReturn->history() == _migrated && !_history->isEmpty()); + below = (!_replyReturn->mainView() && _replyReturn->history() == _migrated && !_history->isEmpty()); } if (!below) { - below = (_replyReturn->detached() && _migrated && _replyReturn->history() == _migrated && !_migrated->isEmpty() && _replyReturn->id < _migrated->blocks.back()->messages.back()->id()); + below = (!_replyReturn->mainView() && _migrated && _replyReturn->history() == _migrated && !_migrated->isEmpty() && _replyReturn->id < _migrated->blocks.back()->messages.back()->data()->id); } - if (!below && !_replyReturn->detached()) { + if (!below && _replyReturn->mainView()) { below = (scrollTop >= scrollTopMax) || (_list->itemTop(_replyReturn) < scrollTop + scrollHeight / 2); } if (below) { @@ -3424,7 +3414,7 @@ bool HistoryWidget::insertBotCommand(const QString &cmd) { auto insertingInlineBot = !cmd.isEmpty() && (cmd.at(0) == '@'); auto toInsert = cmd; if (!toInsert.isEmpty() && !insertingInlineBot) { - auto bot = _peer->isUser() ? _peer : (App::hoveredLinkItem() ? App::hoveredLinkItem()->fromOriginal() : nullptr); + auto bot = _peer->isUser() ? _peer : (App::hoveredLinkItem() ? App::hoveredLinkItem()->data()->fromOriginal() : nullptr); if (bot && (!bot->isUser() || !bot->asUser()->botInfo)) { bot = nullptr; } @@ -4951,7 +4941,7 @@ void HistoryWidget::updateHistoryDownVisibility() { if (!_list || !history || history->unreadCount() <= 0) { return false; } - if (!history->showFrom || history->showFrom->detached()) { + if (!history->showFrom || !history->showFrom->mainView()) { return false; } return (_list->itemTop(history->showFrom) >= _scroll->scrollTop() + _scroll->height()); @@ -5052,41 +5042,34 @@ void HistoryWidget::keyPressEvent(QKeyEvent *e) { _scroll->keyPressEvent(e); } else if ((e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier)) == Qt::ControlModifier) { if (_history && _history->lastMsg && !_editMsgId) { - if (_replyToId) { - HistoryItem *item = App::histItemById(_history->channelId(), _replyToId)->nextItem(); - if (item) App::contextItem(item); - else { cancelReply(); return; } - } else { - return; + if (const auto item = App::histItemById(_history->channelId(), _replyToId)) { + if (const auto next = item->nextItem()) { + Ui::showPeerHistory(_peer, next->id); + replyToMessage(next); + } } - Ui::showPeerHistory(_peer, App::contextItem()->id); - onReplyToMessage(); - return; } } } else if (e->key() == Qt::Key_Up) { if (!(e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier))) { if (_history && _history->lastSentMsg && _history->lastSentMsg->canEdit(::date(unixtime()))) { - if (_field->isEmpty() && !_editMsgId && !_replyToId) { - App::contextItem(_history->lastSentMsg); - onEditMessage(); + if (_field->isEmpty() && !_editMsgId && !_replyToId && _history->lastSentMsg) { + editMessage(_history->lastSentMsg); return; } } _scroll->keyPressEvent(e); } else if ((e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier)) == Qt::ControlModifier) { if (_history && _history->lastMsg && !_editMsgId) { - if (_replyToId) { - HistoryItem *item = App::histItemById(_history->channelId(), _replyToId); - App::contextItem(item->previousItem()); - } else { - App::contextItem(_history->lastMsg); + if (const auto item = App::histItemById(_history->channelId(), _replyToId)) { + if (const auto previous = item->previousItem()) { + Ui::showPeerHistory(_peer, previous->id); + replyToMessage(previous); + } + } else if (const auto previous = _history->lastMsg) { + Ui::showPeerHistory(_peer, previous->id); + replyToMessage(previous); } - if (App::contextItem()) { - Ui::showPeerHistory(_peer, App::contextItem()->id); - onReplyToMessage(); - } - return; } } } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { @@ -5517,26 +5500,31 @@ void HistoryWidget::setFieldText(const TextWithTags &textWithTags, TextUpdateEve _previewLinks.clear(); } -void HistoryWidget::onReplyToMessage() { - auto to = App::contextItem(); - if (!to || to->id <= 0 || !_canSendMessages) return; +void HistoryWidget::replyToMessage(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { + replyToMessage(item); + } +} - if (to->history() == _migrated) { - if (to->isGroupMigrate() && !_history->isEmpty() && _history->blocks.front()->messages.front()->data()->isGroupMigrate() && _history != _migrated) { - App::contextItem(_history->blocks.front()->messages.front()->data()); - onReplyToMessage(); - App::contextItem(to); +void HistoryWidget::replyToMessage(not_null item) { + if (!IsServerMsgId(item->id) || !_canSendMessages) { + return; + } + if (item->history() == _migrated) { + if (item->isGroupMigrate() + && !_history->isEmpty() + && _history->blocks.front()->messages.front()->data()->isGroupMigrate() + && _history != _migrated) { + replyToMessage(_history->blocks.front()->messages.front()->data()); } else { - if (to->id < 0 || to->serviceMsg()) { + if (item->serviceMsg()) { Ui::show(Box(lang(lng_reply_cant))); } else { - Ui::show(Box(lang(lng_reply_cant_forward), lang(lng_selected_forward), base::lambda_guarded(this, [this] { - auto item = App::contextItem(); - if (!item || item->id < 0 || item->serviceMsg()) return; - + const auto itemId = item->fullId(); + Ui::show(Box(lang(lng_reply_cant_forward), lang(lng_selected_forward), base::lambda_guarded(this, [=] { App::main()->setForwardDraft( _peer->id, - { 1, item->fullId() }); + { 1, itemId }); }))); } } @@ -5547,13 +5535,17 @@ void HistoryWidget::onReplyToMessage() { if (_editMsgId) { if (auto localDraft = _history->localDraft()) { - localDraft->msgId = to->id; + localDraft->msgId = item->id; } else { - _history->setLocalDraft(std::make_unique(TextWithTags(), to->id, MessageCursor(), false)); + _history->setLocalDraft(std::make_unique( + TextWithTags(), + item->id, + MessageCursor(), + false)); } } else { - _replyEditMsg = to; - _replyToId = to->id; + _replyEditMsg = item; + _replyToId = item->id; _replyEditMsgText.setText( st::messageTextStyle, TextUtilities::Clean(_replyEditMsg->inReplyText()), @@ -5575,13 +5567,16 @@ void HistoryWidget::onReplyToMessage() { _field->setFocus(); } -void HistoryWidget::onEditMessage() { - auto to = App::contextItem(); - if (!to) return; +void HistoryWidget::editMessage(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { + editMessage(item); + } +} - if (auto media = to->getMedia()) { +void HistoryWidget::editMessage(not_null item) { + if (const auto media = item->getMedia()) { if (media->canEditCaption()) { - Ui::show(Box(media, to->fullId())); + Ui::show(Box(media, item->fullId())); return; } } @@ -5598,14 +5593,25 @@ void HistoryWidget::onEditMessage() { } } - auto original = to->originalText(); - auto editData = TextWithTags { TextUtilities::ApplyEntities(original), ConvertEntitiesToTextTags(original.entities) }; - auto cursor = MessageCursor { editData.text.size(), editData.text.size(), QFIXED_MAX }; - _history->setEditDraft(std::make_unique(editData, to->id, cursor, false)); + const auto original = item->originalText(); + const auto editData = TextWithTags { + TextUtilities::ApplyEntities(original), + ConvertEntitiesToTextTags(original.entities) + }; + const auto cursor = MessageCursor { + editData.text.size(), + editData.text.size(), + QFIXED_MAX + }; + _history->setEditDraft(std::make_unique( + editData, + item->id, + cursor, + false)); applyDraft(false); _previewData = nullptr; - if (auto media = to->getMedia()) { + if (const auto media = item->getMedia()) { if (media->type() == MediaTypeWebPage) { _previewData = static_cast(media)->webpage(); updatePreview(); @@ -5631,22 +5637,23 @@ void HistoryWidget::onEditMessage() { _field->setFocus(); } -void HistoryWidget::onPinMessage() { - auto to = App::contextItem(); - if (!to || !to->canPin()) return; - - Ui::show(Box( - to->history()->peer->asChannel(), - to->id)); +void HistoryWidget::pinMessage(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { + if (item->canPin()) { + const auto channel = item->history()->peer->asChannel(); + Assert(channel != nullptr); + Ui::show(Box(channel, item->id)); + } + } } -void HistoryWidget::onUnpinMessage() { - if (!_peer || !_peer->isChannel()) return; - - Ui::show(Box(lang(lng_pinned_unpin_sure), lang(lng_pinned_unpin), base::lambda_guarded(this, [this] { - auto channel = _peer ? _peer->asChannel() : nullptr; - if (!channel) return; +void HistoryWidget::unpinMessage(FullMsgId itemId) { + const auto channel = _peer ? _peer->asChannel() : nullptr; + if (!channel) { + return; + } + Ui::show(Box(lang(lng_pinned_unpin_sure), lang(lng_pinned_unpin), base::lambda_guarded(this, [=] { channel->clearPinnedMessage(); Ui::hideLayer(); @@ -5666,8 +5673,8 @@ void HistoryWidget::unpinDone(const MTPUpdates &updates) { } void HistoryWidget::onPinnedHide() { - auto channel = _peer ? _peer->asChannel() : nullptr; - auto pinnedId = channel->pinnedMessageId(); + const auto channel = _peer ? _peer->asChannel() : nullptr; + const auto pinnedId = channel ? channel->pinnedMessageId() : MsgId(0); if (!pinnedId) { if (pinnedMsgVisibilityUpdated()) { updateControlsGeometry(); @@ -5677,9 +5684,9 @@ void HistoryWidget::onPinnedHide() { } if (channel->canPinMessages()) { - onUnpinMessage(); + unpinMessage(FullMsgId(peerToChannel(channel->id), pinnedId)); } else { - Global::RefHiddenPinnedMessages().insert(_peer->id, pinnedId); + Global::RefHiddenPinnedMessages().insert(channel->id, pinnedId); Local::writeUserSettings(); if (pinnedMsgVisibilityUpdated()) { updateControlsGeometry(); @@ -5688,11 +5695,12 @@ void HistoryWidget::onPinnedHide() { } } -void HistoryWidget::onCopyPostLink() { - auto item = App::contextItem(); - if (!item || !item->hasDirectLink()) return; - - QApplication::clipboard()->setText(item->directLink()); +void HistoryWidget::copyPostLink(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { + if (item->hasDirectLink()) { + QApplication::clipboard()->setText(item->directLink()); + } + } } bool HistoryWidget::lastForceReplyReplied(const FullMsgId &replyTo) const { @@ -6076,10 +6084,7 @@ void HistoryWidget::onForwardSelected() { void HistoryWidget::confirmDeleteSelectedItems() { if (!_list) return; - auto selected = _list->getSelectedItems(); - if (selected.empty()) return; - - App::main()->deleteLayer(int(selected.size())); + App::main()->deleteLayer(_list->getSelectedItems()); } void HistoryWidget::deleteSelectedItems(bool forEveryone) { diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 77e9ea5cd..eb74e7862 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -250,6 +250,14 @@ public: void updateScrollColors(); + void replyToMessage(FullMsgId itemId); + void replyToMessage(not_null item); + void editMessage(FullMsgId itemId); + void editMessage(not_null item); + void pinMessage(FullMsgId itemId); + void unpinMessage(FullMsgId itemId); + void copyPostLink(FullMsgId itemId); + MsgId replyToId() const; void messageDataReceived(ChannelData *channel, MsgId msgId); bool lastForceReplyReplied(const FullMsgId &replyTo) const; @@ -260,7 +268,7 @@ public: void updateForwardingTexts(); void clearReplyReturns(); - void pushReplyReturn(HistoryItem *item); + void pushReplyReturn(not_null item); QList replyReturns(); void setReplyReturns(PeerId peer, const QList &replyReturns); void calcNextReplyReturn(); @@ -361,12 +369,7 @@ signals: public slots: void onCancel(); - void onReplyToMessage(); - void onEditMessage(); - void onPinMessage(); - void onUnpinMessage(); void onPinnedHide(); - void onCopyPostLink(); void onFieldBarCancel(); void onPreviewParse(); diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 54121662d..dadb47e67 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -466,13 +466,13 @@ void ListWidget::checkMoveToOtherViewer() { QString ListWidget::tooltipText() const { if (_mouseCursorState == HistoryInDateCursorState && _mouseAction == MouseAction::None) { - if (const auto item = App::hoveredItem()) { - auto dateText = item->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat)); + if (const auto view = App::hoveredItem()) { + auto dateText = view->data()->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat)); return dateText; } } else if (_mouseCursorState == HistoryInForwardedCursorState && _mouseAction == MouseAction::None) { - if (const auto item = App::hoveredItem()) { - if (const auto forwarded = item->Get()) { + if (const auto view = App::hoveredItem()) { + if (const auto forwarded = view->data()->Get()) { return forwarded->text.originalText(AllTextSelection, ExpandLinksNone); } } @@ -724,10 +724,6 @@ void ListWidget::contextMenuEvent(QContextMenuEvent *e) { } void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { - if (_menu) { - _menu->deleteLater(); - _menu = 0; - } if (e->reason() == QContextMenuEvent::Mouse) { mouseActionUpdate(e->globalPos()); } @@ -742,10 +738,12 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { auto selTo = _selectedText.to; hasSelected = (selTo > selFrom) ? 1 : 0; if (App::mousedItem() && App::mousedItem() == App::hoveredItem()) { - auto mousePos = mapPointToItem(mapFromGlobal(_mousePosition), viewForItem(App::mousedItem())); + auto mousePos = mapPointToItem( + mapFromGlobal(_mousePosition), + App::mousedItem()); HistoryStateRequest request; request.flags |= Text::StateRequest::Flag::LookupSymbol; - auto dragState = App::mousedItem()->getState(mousePos, request); + auto dragState = App::mousedItem()->data()->getState(mousePos, request); if (dragState.cursor == HistoryInTextCursorState && dragState.symbol >= selFrom && dragState.symbol < selTo) { isUponSelected = 1; } @@ -755,10 +753,12 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { isUponSelected = hasSelected; } - _menu = new Ui::PopupMenu(nullptr); + _menu = base::make_unique_q(nullptr); _contextMenuLink = ClickHandler::getActive(); - auto item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem(); + auto view = App::hoveredItem() + ? App::hoveredItem() + : App::hoveredLinkItem(); auto lnkPhoto = dynamic_cast(_contextMenuLink.get()); auto lnkDocument = dynamic_cast(_contextMenuLink.get()); auto lnkPeer = dynamic_cast(_contextMenuLink.get()); @@ -767,39 +767,50 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { auto lnkIsAudio = lnkDocument ? lnkDocument->document()->isAudioFile() : false; if (lnkPhoto || lnkDocument) { if (isUponSelected > 0) { - _menu->addAction(lang(lng_context_copy_selected), [this] { copySelectedText(); })->setEnabled(true); + _menu->addAction(lang(lng_context_copy_selected), [=] { + copySelectedText(); + })->setEnabled(true); } if (lnkPhoto) { - _menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, photo = lnkPhoto->photo()] { + const auto photo = lnkPhoto->photo(); + _menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [=] { savePhotoToFile(photo); }))->setEnabled(true); - _menu->addAction(lang(lng_context_copy_image), [this, photo = lnkPhoto->photo()] { + _menu->addAction(lang(lng_context_copy_image), [=] { copyContextImage(photo); })->setEnabled(true); } else { auto document = lnkDocument->document(); if (document->loading()) { - _menu->addAction(lang(lng_context_cancel_download), [this] { cancelContextDownload(); })->setEnabled(true); + _menu->addAction(lang(lng_context_cancel_download), [=] { + cancelContextDownload(document); + })->setEnabled(true); } else { if (document->loaded() && document->isGifv()) { if (!cAutoPlayGif()) { - _menu->addAction(lang(lng_context_open_gif), [this] { openContextGif(); })->setEnabled(true); + const auto itemId = view + ? view->data()->fullId() + : FullMsgId(); + _menu->addAction(lang(lng_context_open_gif), [=] { + openContextGif(itemId); + })->setEnabled(true); } } if (!document->filepath(DocumentData::FilePathResolveChecked).isEmpty()) { - _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [this] { showContextInFolder(); })->setEnabled(true); + _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [=] { + showContextInFolder(document); + })->setEnabled(true); } _menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsVoice ? lng_context_save_audio : (lnkIsAudio ? lng_context_save_audio_file : lng_context_save_file))), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] { saveDocumentToFile(document); }))->setEnabled(true); } } - if (App::hoveredLinkItem()) { - App::contextItem(App::hoveredLinkItem()); - } } else if (lnkPeer) { // suggest to block // #TODO suggest restrict peer } else { // maybe cursor on some text history item? + const auto item = view ? view->data().get() : nullptr; + const auto itemId = item ? item->fullId() : FullMsgId(); bool canDelete = item && item->canDelete() && (item->id > 0 || !item->serviceMsg()); bool canForward = item && item->canForward(); @@ -817,7 +828,9 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (media->type() == MediaTypeSticker) { if (auto document = media->getDocument()) { if (document->sticker() && document->sticker()->set.type() != mtpc_inputStickerSetEmpty) { - _menu->addAction(lang(document->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), [this] { showStickerPackInfo(); }); + _menu->addAction(lang(document->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), [=] { + showStickerPackInfo(document); + }); } _menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] { saveDocumentToFile(document); @@ -826,15 +839,21 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } else if (media->type() == MediaTypeGif && !_contextMenuLink) { if (auto document = media->getDocument()) { if (document->loading()) { - _menu->addAction(lang(lng_context_cancel_download), [this] { cancelContextDownload(); })->setEnabled(true); + _menu->addAction(lang(lng_context_cancel_download), [=] { + cancelContextDownload(document); + })->setEnabled(true); } else { if (document->isGifv()) { if (!cAutoPlayGif()) { - _menu->addAction(lang(lng_context_open_gif), [this] { openContextGif(); })->setEnabled(true); + _menu->addAction(lang(lng_context_open_gif), [=] { + openContextGif(itemId); + })->setEnabled(true); } } if (!document->filepath(DocumentData::FilePathResolveChecked).isEmpty()) { - _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [this] { showContextInFolder(); })->setEnabled(true); + _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [=] { + showContextInFolder(document); + })->setEnabled(true); } _menu->addAction(lang(lng_context_save_file), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] { saveDocumentToFile(document); @@ -844,7 +863,9 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } } if (msg && !_contextMenuLink && (!msg->emptyText() || mediaHasTextForCopy)) { - _menu->addAction(lang(lng_context_copy_text), [this] { copyContextText(); })->setEnabled(true); + _menu->addAction(lang(lng_context_copy_text), [=] { + copyContextText(itemId); + })->setEnabled(true); } } } @@ -853,17 +874,11 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (!linkCopyToClipboardText.isEmpty()) { _menu->addAction(linkCopyToClipboardText, [this] { copyContextUrl(); })->setEnabled(true); } - App::contextItem(item); } if (_menu->actions().isEmpty()) { - delete base::take(_menu); + _menu = nullptr; } else { - connect(_menu, &QObject::destroyed, this, [this](QObject *object) { - if (_menu == object) { - _menu = nullptr; - } - }); _menu->popup(e->globalPos()); e->accept(); } @@ -873,11 +888,15 @@ void ListWidget::savePhotoToFile(PhotoData *photo) { if (!photo || !photo->date || !photo->loaded()) return; auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter(); - FileDialog::GetWritePath(lang(lng_save_photo), filter, filedialogDefaultName(qsl("photo"), qsl(".jpg")), base::lambda_guarded(this, [this, photo](const QString &result) { - if (!result.isEmpty()) { - photo->full->pix().toImage().save(result, "JPG"); - } - })); + FileDialog::GetWritePath( + lang(lng_save_photo), + filter, + filedialogDefaultName(qsl("photo"), qsl(".jpg")), + base::lambda_guarded(this, [this, photo](const QString &result) { + if (!result.isEmpty()) { + photo->full->pix().toImage().save(result, "JPG"); + } + })); } void ListWidget::saveDocumentToFile(DocumentData *document) { @@ -900,50 +919,28 @@ void ListWidget::copyContextUrl() { } } -void ListWidget::showStickerPackInfo() { - if (!App::contextItem()) return; - - if (auto media = App::contextItem()->getMedia()) { - if (auto doc = media->getDocument()) { - if (auto sticker = doc->sticker()) { - if (sticker->set.type() != mtpc_inputStickerSetEmpty) { - App::main()->stickersBox(sticker->set); - } - } +void ListWidget::showStickerPackInfo(not_null document) { + if (auto sticker = document->sticker()) { + if (sticker->set.type() != mtpc_inputStickerSetEmpty) { + App::main()->stickersBox(sticker->set); } } } -void ListWidget::cancelContextDownload() { - if (auto lnkDocument = dynamic_cast(_contextMenuLink.get())) { - lnkDocument->document()->cancel(); - } else if (auto item = App::contextItem()) { - if (auto media = item->getMedia()) { - if (auto doc = media->getDocument()) { - doc->cancel(); - } - } - } +void ListWidget::cancelContextDownload(not_null document) { + document->cancel(); } -void ListWidget::showContextInFolder() { - QString filepath; - if (auto lnkDocument = dynamic_cast(_contextMenuLink.get())) { - filepath = lnkDocument->document()->filepath(DocumentData::FilePathResolveChecked); - } else if (auto item = App::contextItem()) { - if (auto media = item->getMedia()) { - if (auto doc = media->getDocument()) { - filepath = doc->filepath(DocumentData::FilePathResolveChecked); - } - } - } +void ListWidget::showContextInFolder(not_null document) { + const auto filepath = document->filepath( + DocumentData::FilePathResolveChecked); if (!filepath.isEmpty()) { File::ShowInFolder(filepath); } } -void ListWidget::openContextGif() { - if (auto item = App::contextItem()) { +void ListWidget::openContextGif(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { if (auto media = item->getMedia()) { if (auto document = media->getDocument()) { Messenger::Instance().showDocument(document, item); @@ -952,16 +949,20 @@ void ListWidget::openContextGif() { } } -void ListWidget::copyContextText() { - auto item = App::contextItem(); - if (!item || (item->getMedia() && item->getMedia()->type() == MediaTypeSticker)) { - return; +void ListWidget::copyContextText(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { + if (const auto media = item->getMedia()) { + if (media->type() == MediaTypeSticker) { + return; + } + } + setToClipboard(item->selectedText(FullSelection)); } - - setToClipboard(item->selectedText(FullSelection)); } -void ListWidget::setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode) { +void ListWidget::setToClipboard( + const TextWithEntities &forClipboard, + QClipboard::Mode mode) { if (auto data = MimeDataFromTextWithEntities(forClipboard)) { QApplication::clipboard()->setMimeData(data.release(), mode); } @@ -996,8 +997,8 @@ void ListWidget::enterEventHook(QEvent *e) { } void ListWidget::leaveEventHook(QEvent *e) { - if (auto item = App::hoveredItem()) { - repaintItem(viewForItem(item)); + if (const auto view = App::hoveredItem()) { + repaintItem(view); App::hoveredItem(nullptr); } ClickHandler::clearActive(); @@ -1015,13 +1016,13 @@ void ListWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butto ClickHandler::pressed(); if (App::pressedItem() != App::hoveredItem()) { - repaintItem(viewForItem(App::pressedItem())); + repaintItem(App::pressedItem()); App::pressedItem(App::hoveredItem()); - repaintItem(viewForItem(App::pressedItem())); + repaintItem(App::pressedItem()); } _mouseAction = MouseAction::None; - _mouseActionItem = viewForItem(App::mousedItem()); + _mouseActionItem = App::mousedItem(); _dragStartPosition = mapPointToItem(mapFromGlobal(screenPos), _mouseActionItem); _pressWasInactive = _controller->window()->wasInactivePress(); if (_pressWasInactive) _controller->window()->setInactivePress(false); @@ -1102,8 +1103,8 @@ void ListWidget::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton butt if (_mouseAction == MouseAction::Dragging) { activated = nullptr; } - if (App::pressedItem()) { - repaintItem(viewForItem(App::pressedItem())); + if (const auto view = App::pressedItem()) { + repaintItem(view); App::pressedItem(nullptr); } @@ -1144,23 +1145,25 @@ void ListWidget::updateSelected() { const auto view = strictFindItemByY(point.y()); const auto item = view ? view->data().get() : nullptr; if (view) { - App::mousedItem(item); + App::mousedItem(view); itemPoint = mapPointToItem(point, view); if (item->hasPoint(itemPoint)) { - if (App::hoveredItem() != item) { - repaintItem(viewForItem(App::hoveredItem())); - App::hoveredItem(item); + if (App::hoveredItem() != view) { + repaintItem(App::hoveredItem()); + App::hoveredItem(view); repaintItem(view); } - } else if (App::hoveredItem()) { - repaintItem(viewForItem(App::hoveredItem())); + } else if (const auto view = App::hoveredItem()) { + repaintItem(view); App::hoveredItem(nullptr); } } HistoryTextState dragState; ClickHandlerHost *lnkhost = nullptr; - auto selectingText = (view == _mouseActionItem && item == App::hoveredItem() && _selectedItem); + auto selectingText = _selectedItem + && (view == _mouseActionItem) + && (view == App::hoveredItem()); if (view) { if (view != _mouseActionItem || (itemPoint - _dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) { if (_mouseAction == MouseAction::PrepareDrag) { @@ -1246,14 +1249,9 @@ void ListWidget::updateSelected() { } // Voice message seek support. - if (auto pressedItem = App::pressedLinkItem()) { - if (!pressedItem->detached()) { - // #TODO seek support - //if (pressedItem->history() == _history) { - // auto adjustedPoint = mapPointToItem(point, pressedItem); - // pressedItem->updatePressed(adjustedPoint); - //} - } + if (const auto pressedView = App::pressedLinkItem()) { + auto adjustedPoint = mapPointToItem(point, pressedView); + pressedView->data()->updatePressed(adjustedPoint); } //if (_mouseAction == MouseAction::Selecting) { diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index 5f72a004d..cab38c6be 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -160,12 +160,12 @@ private: void savePhotoToFile(PhotoData *photo); void saveDocumentToFile(DocumentData *document); void copyContextImage(PhotoData *photo); - void showStickerPackInfo(); + void showStickerPackInfo(not_null document); void copyContextUrl(); - void cancelContextDownload(); - void showContextInFolder(); - void openContextGif(); - void copyContextText(); + void cancelContextDownload(not_null document); + void showContextInFolder(not_null document); + void openContextGif(FullMsgId itemId); + void copyContextText(FullMsgId itemId); void copySelectedText(); TextWithEntities getSelectedText() const; void setToClipboard( @@ -254,8 +254,7 @@ private: bool _wasSelectedText = false; // was some text selected in current drag action Qt::CursorShape _cursor = style::cur_default; - // context menu - Ui::PopupMenu *_menu = nullptr; + base::unique_qptr _menu; QPoint _trippleClickPoint; base::Timer _trippleClickTimer; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 64f8fd534..d56d4694b 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -14,12 +14,56 @@ Message::Message(not_null data, Context context) , _context(context) { } -MsgId Message::id() const { - return _data->id; -} - not_null Message::data() const { return _data; } +void Message::attachToBlock(not_null block, int index) { + Expects(!_data->isLogEntry()); + Expects(_block == nullptr); + Expects(_indexInBlock < 0); + Expects(index >= 0); + + _block = block; + _indexInBlock = index; + _data->setMainView(this); + _data->setPendingResize(); +} + +void Message::removeFromBlock() { + Expects(_block != nullptr); + + _block->remove(this); +} + +Message *Message::previousInBlocks() const { + if (_block && _indexInBlock >= 0) { + if (_indexInBlock > 0) { + return _block->messages[_indexInBlock - 1].get(); + } + if (auto previous = _block->previousBlock()) { + Assert(!previous->messages.empty()); + return previous->messages.back().get(); + } + } + return nullptr; +} + +Message *Message::nextInBlocks() const { + if (_block && _indexInBlock >= 0) { + if (_indexInBlock + 1 < _block->messages.size()) { + return _block->messages[_indexInBlock + 1].get(); + } + if (auto next = _block->nextBlock()) { + Assert(!next->messages.empty()); + return next->messages.front().get(); + } + } + return nullptr; +} + +Message::~Message() { + App::messageViewDestroyed(this); +} + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_message.h b/Telegram/SourceFiles/history/view/history_view_message.h index fe9cd4a91..357414fb9 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.h +++ b/Telegram/SourceFiles/history/view/history_view_message.h @@ -23,7 +23,6 @@ class Message public: Message(not_null data, Context context); - MsgId id() const; not_null data() const; int y() const { @@ -33,11 +32,39 @@ public: _y = y; } + HistoryBlock *block() { + return _block; + } + const HistoryBlock *block() const { + return _block; + } + void attachToBlock(not_null block, int index); + void removeFromBlock(); + void setIndexInBlock(int index) { + Expects(_block != nullptr); + Expects(index >= 0); + + _indexInBlock = index; + } + int indexInBlock() const { + Expects((_indexInBlock >= 0) == (_block != nullptr)); + Expects((_block == nullptr) || (_block->messages[_indexInBlock].get() == this)); + + return _indexInBlock; + } + Message *previousInBlocks() const; + Message *nextInBlocks() const; + + ~Message(); + private: const not_null _data; int _y = 0; Context _context; + HistoryBlock *_block = nullptr; + int _indexInBlock = -1; + }; } // namespace HistoryView diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 264fa8c98..07dcbde77 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -596,17 +596,19 @@ bool MainWidget::setForwardDraft(PeerId peerId, ForwardWhatMessages what) { return _history->getSelectedItems(); } auto item = (HistoryItem*)nullptr; - if (what == ForwardContextMessage) { - item = App::contextItem(); - } else if (what == ForwardPressedMessage) { - item = App::pressedItem(); + if (what == ForwardPressedMessage) { + item = App::pressedItem() + ? App::pressedItem()->data().get() + : nullptr; if (const auto group = item ? item->getFullGroup() : nullptr) { if (item->id > 0) { return Auth().data().groupToIds(group); } } } else if (what == ForwardPressedLinkMessage) { - item = App::pressedLinkItem(); + item = App::pressedLinkItem() + ? App::pressedLinkItem()->data().get() + : nullptr; } if (item && item->toHistoryMessage() && item->id > 0) { return { 1, item->fullId() }; @@ -677,8 +679,7 @@ bool MainWidget::shareUrl( void MainWidget::replyToItem(not_null item) { if (_history->peer() == item->history()->peer || _history->peer() == item->history()->peer->migrateTo()) { - App::contextItem(item); - _history->onReplyToMessage(); + _history->replyToMessage(item); } } @@ -932,24 +933,20 @@ void MainWidget::showSendPathsLayer() { hiderLayer(object_ptr(this)); } -void MainWidget::deleteLayer(int selectedCount) { - if (selectedCount) { - auto selected = _history->getSelectedItems(); - if (!selected.empty()) { - Ui::show(Box(std::move(selected))); - } - } else if (const auto item = App::contextItem()) { +void MainWidget::deleteLayer(MessageIdsList &&items) { + if (!items.empty()) { + Ui::show(Box(std::move(items))); + } +} + +void MainWidget::deleteLayer(FullMsgId itemId) { + if (const auto item = App::histItemById(itemId)) { const auto suggestModerateActions = true; Ui::show(Box(item, suggestModerateActions)); } } -void MainWidget::cancelUploadLayer() { - auto item = App::contextItem(); - if (!item) { - return; - } - +void MainWidget::cancelUploadLayer(not_null item) { 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, [=] { @@ -2111,7 +2108,7 @@ void MainWidget::updateBotKeyboard(History *h) { _history->updateBotKeyboard(h); } -void MainWidget::pushReplyReturn(HistoryItem *item) { +void MainWidget::pushReplyReturn(not_null item) { _history->pushReplyReturn(item); } @@ -4931,7 +4928,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { const auto newId = d.vid.v; if (const auto local = App::histItemById(fullId)) { const auto existing = App::histItemById(channel, newId); - if (existing && local->detached()) { + if (existing && !local->mainView()) { const auto history = local->history(); const auto wasLast = (history->lastMsg == local); local->destroy(); diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index ac74c0981..004e29630 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -168,8 +168,9 @@ public: void showForwardLayer(MessageIdsList &&items); void showSendPathsLayer(); - void deleteLayer(int selectedCount = 0); // 0 - context item - void cancelUploadLayer(); + void deleteLayer(MessageIdsList &&items); + void deleteLayer(FullMsgId itemId); + void cancelUploadLayer(not_null item); void shareUrlLayer(const QString &url, const QString &text); void inlineSwitchLayer(const QString &botAndQuery); void hiderLayer(object_ptr h); @@ -272,7 +273,7 @@ public: void messageDataReceived(ChannelData *channel, MsgId msgId); void updateBotKeyboard(History *h); - void pushReplyReturn(HistoryItem *item); + void pushReplyReturn(not_null item); void cancelForwarding(not_null history); void finishForwarding(not_null history); diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 4a974ab0d..c38ffc8a7 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -1003,8 +1003,10 @@ void MediaView::onForward() { void MediaView::onDelete() { close(); - auto deletingPeerPhoto = [this]() { - if (!_msgid) return true; + const auto deletingPeerPhoto = [this] { + if (!_msgid) { + return true; + } if (_photo && _history) { if (_history->peer->userpicPhotoId() == _photo->id) { return _firstOpenedPeerPhoto; @@ -1015,9 +1017,8 @@ void MediaView::onDelete() { if (deletingPeerPhoto()) { App::main()->deletePhotoLayer(_photo); - } else if (auto item = App::histItemById(_msgid)) { - App::contextItem(item); - App::main()->deleteLayer(); + } else { + App::main()->deleteLayer(_msgid); } } diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index 4602b488b..52bf2a597 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -120,7 +120,8 @@ ItemBase::ItemBase(not_null parent) : _parent(parent) { void ItemBase::clickHandlerActiveChanged( const ClickHandlerPtr &action, bool active) { - App::hoveredLinkItem(active ? _parent.get() : nullptr); + // #TODO hoveredLinkItem +// App::hoveredLinkItem(active ? _parent.get() : nullptr); Auth().data().requestItemRepaint(_parent); if (_check) { _check->setActive(active); @@ -130,7 +131,8 @@ void ItemBase::clickHandlerActiveChanged( void ItemBase::clickHandlerPressedChanged( const ClickHandlerPtr &action, bool pressed) { - App::pressedLinkItem(pressed ? _parent.get() : nullptr); + // #TODO pressedLinkItem +// App::pressedLinkItem(pressed ? _parent.get() : nullptr); Auth().data().requestItemRepaint(_parent); if (_check) { _check->setPressed(pressed); @@ -172,18 +174,25 @@ ItemBase::~ItemBase() = default; void RadialProgressItem::setDocumentLinks( not_null document) { - auto createSaveHandler = []( - not_null document - ) -> ClickHandlerPtr { + const auto context = parent()->fullId(); + const auto createSaveHandler = [&]() -> ClickHandlerPtr { if (document->isVoiceMessage()) { - return std::make_shared(document); + return std::make_shared( + document, + context); } - return std::make_shared(document); + return std::make_shared( + document, + context); }; setLinks( - std::make_shared(document), - createSaveHandler(document), - std::make_shared(document)); + std::make_shared( + document, + context), + createSaveHandler(), + std::make_shared( + document, + context)); } void RadialProgressItem::clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) { @@ -539,7 +548,7 @@ Voice::Voice( const style::OverviewFileLayout &st) : RadialProgressItem(parent) , _data(voice) -, _namel(std::make_shared(_data)) +, _namel(std::make_shared(_data, parent->fullId())) , _st(st) { AddComponents(Info::Bit()); @@ -784,7 +793,7 @@ Document::Document( : RadialProgressItem(parent) , _data(document) , _msgl(goToMessageClickHandler(parent)) -, _namel(std::make_shared(_data)) +, _namel(std::make_shared(_data, parent->fullId())) , _st(st) , _date(langDateTime(date(_data->date))) , _datew(st::normalFont->width(_date)) @@ -1205,7 +1214,9 @@ Link::Link( if (_page) { mainUrl = _page->url; if (_page->document) { - _photol = std::make_shared(_page->document); + _photol = std::make_shared( + _page->document, + parent->fullId()); } else if (_page->photo) { if (_page->type == WebPageProfile || _page->type == WebPageVideo) { _photol = std::make_shared(_page->url);