Save item views in App::*Item() variables.

Also remove App::contextItem.
Also use owning pointers for history context menus.
This commit is contained in:
John Preston 2018-01-11 16:07:29 +03:00
parent 8060cb7426
commit 062b0b2165
33 changed files with 1201 additions and 1056 deletions

View File

@ -89,11 +89,10 @@ namespace {
using SentData = QMap<uint64, QPair<PeerId, QString>>; using SentData = QMap<uint64, QPair<PeerId, QString>>;
SentData sentData; SentData sentData;
HistoryItem *hoveredItem = nullptr, HistoryView::Message *hoveredItem = nullptr,
*pressedItem = nullptr, *pressedItem = nullptr,
*hoveredLinkItem = nullptr, *hoveredLinkItem = nullptr,
*pressedLinkItem = nullptr, *pressedLinkItem = nullptr,
*contextItem = nullptr,
*mousedItem = nullptr; *mousedItem = nullptr;
QPixmap *emoji = nullptr, *emojiLarge = nullptr; QPixmap *emoji = nullptr, *emojiLarge = nullptr;
@ -934,7 +933,7 @@ namespace {
: nullptr); : nullptr);
existing->setViewsCount(m.has_views() ? m.vviews.v : -1); existing->setViewsCount(m.has_views() ? m.vviews.v : -1);
existing->indexAsNewItem(); existing->indexAsNewItem();
if (!existing->detached()) { if (existing->mainView()) {
App::checkSavedGif(existing); App::checkSavedGif(existing);
return true; return true;
} }
@ -1836,23 +1835,20 @@ namespace {
} }
} }
void historyItemDetached(HistoryItem *item) { void messageViewDestroyed(not_null<HistoryView::Message*> view) {
if (::hoveredItem == item) { if (::hoveredItem == view) {
hoveredItem(nullptr); hoveredItem(nullptr);
} }
if (::pressedItem == item) { if (::pressedItem == view) {
pressedItem(nullptr); pressedItem(nullptr);
} }
if (::hoveredLinkItem == item) { if (::hoveredLinkItem == view) {
hoveredLinkItem(nullptr); hoveredLinkItem(nullptr);
} }
if (::pressedLinkItem == item) { if (::pressedLinkItem == view) {
pressedLinkItem(nullptr); pressedLinkItem(nullptr);
} }
if (::contextItem == item) { if (::mousedItem == view) {
contextItem(nullptr);
}
if (::mousedItem == item) {
mousedItem(nullptr); mousedItem(nullptr);
} }
} }
@ -1867,7 +1863,6 @@ namespace {
data->erase(i); data->erase(i);
} }
} }
historyItemDetached(item);
auto j = ::dependentItems.find(item); auto j = ::dependentItems.find(item);
if (j != ::dependentItems.cend()) { if (j != ::dependentItems.cend()) {
DependentItemsSet items; DependentItemsSet items;
@ -1903,13 +1898,13 @@ namespace {
QVector<HistoryItem*> toDelete; QVector<HistoryItem*> toDelete;
for_const (auto item, msgsData) { for_const (auto item, msgsData) {
if (item->detached()) { if (!item->mainView()) {
toDelete.push_back(item); toDelete.push_back(item);
} }
} }
for_const (auto &chMsgsData, channelMsgsData) { for_const (auto &chMsgsData, channelMsgsData) {
for_const (auto item, chMsgsData) { for_const (auto item, chMsgsData) {
if (item->detached()) { if (!item->mainView()) {
toDelete.push_back(item); toDelete.push_back(item);
} }
} }
@ -2187,51 +2182,43 @@ namespace {
clearAllImages(); clearAllImages();
} }
void hoveredItem(HistoryItem *item) { void hoveredItem(HistoryView::Message *item) {
::hoveredItem = item; ::hoveredItem = item;
} }
HistoryItem *hoveredItem() { HistoryView::Message *hoveredItem() {
return ::hoveredItem; return ::hoveredItem;
} }
void pressedItem(HistoryItem *item) { void pressedItem(HistoryView::Message *item) {
::pressedItem = item; ::pressedItem = item;
} }
HistoryItem *pressedItem() { HistoryView::Message *pressedItem() {
return ::pressedItem; return ::pressedItem;
} }
void hoveredLinkItem(HistoryItem *item) { void hoveredLinkItem(HistoryView::Message *item) {
::hoveredLinkItem = item; ::hoveredLinkItem = item;
} }
HistoryItem *hoveredLinkItem() { HistoryView::Message *hoveredLinkItem() {
return ::hoveredLinkItem; return ::hoveredLinkItem;
} }
void pressedLinkItem(HistoryItem *item) { void pressedLinkItem(HistoryView::Message *item) {
::pressedLinkItem = item; ::pressedLinkItem = item;
} }
HistoryItem *pressedLinkItem() { HistoryView::Message *pressedLinkItem() {
return ::pressedLinkItem; return ::pressedLinkItem;
} }
void contextItem(HistoryItem *item) { void mousedItem(HistoryView::Message *item) {
::contextItem = item;
}
HistoryItem *contextItem() {
return ::contextItem;
}
void mousedItem(HistoryItem *item) {
::mousedItem = item; ::mousedItem = item;
} }
HistoryItem *mousedItem() { HistoryView::Message *mousedItem() {
return ::mousedItem; return ::mousedItem;
} }
@ -2240,7 +2227,6 @@ namespace {
pressedItem(nullptr); pressedItem(nullptr);
hoveredLinkItem(nullptr); hoveredLinkItem(nullptr);
pressedLinkItem(nullptr); pressedLinkItem(nullptr);
contextItem(nullptr);
mousedItem(nullptr); mousedItem(nullptr);
} }

View File

@ -15,6 +15,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class Messenger; class Messenger;
class MainWindow; class MainWindow;
class MainWidget; class MainWidget;
class LocationCoords;
struct LocationData;
namespace HistoryView {
class Message;
} // namespace HistoryView
using HistoryItemsMap = OrderedSet<HistoryItem*>; using HistoryItemsMap = OrderedSet<HistoryItem*>;
using PhotoItems = QHash<PhotoData*, HistoryItemsMap>; using PhotoItems = QHash<PhotoData*, HistoryItemsMap>;
@ -27,9 +33,6 @@ using GifItems = QHash<Media::Clip::Reader*, HistoryItem*>;
using PhotosData = QHash<PhotoId, PhotoData*>; using PhotosData = QHash<PhotoId, PhotoData*>;
using DocumentsData = QHash<DocumentId, DocumentData*>; using DocumentsData = QHash<DocumentId, DocumentData*>;
class LocationCoords;
struct LocationData;
namespace App { namespace App {
MainWindow *wnd(); MainWindow *wnd();
MainWidget *main(); MainWidget *main();
@ -190,13 +193,13 @@ namespace App {
return histItemById(msgId.channel, msgId.msg); return histItemById(msgId.channel, msgId.msg);
} }
void historyRegItem(HistoryItem *item); void historyRegItem(HistoryItem *item);
void historyItemDetached(HistoryItem *item);
void historyUnregItem(HistoryItem *item); void historyUnregItem(HistoryItem *item);
void historyUpdateDependent(HistoryItem *item); void historyUpdateDependent(HistoryItem *item);
void historyClearMsgs(); void historyClearMsgs();
void historyClearItems(); void historyClearItems();
void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency); void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency);
void historyUnregDependency(HistoryItem *dependent, HistoryItem *dependency); void historyUnregDependency(HistoryItem *dependent, HistoryItem *dependency);
void messageViewDestroyed(not_null<HistoryView::Message*> view);
void historyRegRandom(uint64 randomId, const FullMsgId &itemId); void historyRegRandom(uint64 randomId, const FullMsgId &itemId);
void historyUnregRandom(uint64 randomId); void historyUnregRandom(uint64 randomId);
@ -205,18 +208,16 @@ namespace App {
void historyUnregSentData(uint64 randomId); void historyUnregSentData(uint64 randomId);
void histSentDataByItem(uint64 randomId, PeerId &peerId, QString &text); void histSentDataByItem(uint64 randomId, PeerId &peerId, QString &text);
void hoveredItem(HistoryItem *item); void hoveredItem(HistoryView::Message *item);
HistoryItem *hoveredItem(); HistoryView::Message *hoveredItem();
void pressedItem(HistoryItem *item); void pressedItem(HistoryView::Message *item);
HistoryItem *pressedItem(); HistoryView::Message *pressedItem();
void hoveredLinkItem(HistoryItem *item); void hoveredLinkItem(HistoryView::Message *item);
HistoryItem *hoveredLinkItem(); HistoryView::Message *hoveredLinkItem();
void pressedLinkItem(HistoryItem *item); void pressedLinkItem(HistoryView::Message *item);
HistoryItem *pressedLinkItem(); HistoryView::Message *pressedLinkItem();
void contextItem(HistoryItem *item); void mousedItem(HistoryView::Message *item);
HistoryItem *contextItem(); HistoryView::Message *mousedItem();
void mousedItem(HistoryItem *item);
HistoryItem *mousedItem();
void clearMousedItems(); void clearMousedItems();
const style::font &monofont(); const style::font &monofont();

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "messenger.h" #include "messenger.h"
#include "platform/platform_specific.h" #include "platform/platform_specific.h"
#include "history/view/history_view_message.h"
#include "boxes/confirm_box.h" #include "boxes/confirm_box.h"
#include "base/qthelp_regex.h" #include "base/qthelp_regex.h"
#include "base/qthelp_url.h" #include "base/qthelp_url.h"
@ -241,10 +242,11 @@ void BotCommandClickHandler::onClick(Qt::MouseButton button) const {
} }
if (auto peer = Ui::getPeerForMouseAction()) { // old way if (auto peer = Ui::getPeerForMouseAction()) { // old way
UserData *bot = peer->isUser() ? peer->asUser() : nullptr; auto bot = peer->isUser() ? peer->asUser() : nullptr;
if (auto item = App::hoveredLinkItem()) { if (!bot) {
if (!bot) { if (const auto view = App::hoveredLinkItem()) {
bot = item->fromOriginal()->asUser(); // may return nullptr // may return nullptr
bot = view->data()->fromOriginal()->asUser();
} }
} }
Ui::showPeerHistory(peer, ShowAtTheEndMsgId); Ui::showPeerHistory(peer, ShowAtTheEndMsgId);

View File

@ -527,7 +527,6 @@ inline int ceilclamp(float64 value, int32 step, int32 lowest, int32 highest) {
enum ForwardWhatMessages { enum ForwardWhatMessages {
ForwardSelectedMessages, ForwardSelectedMessages,
ForwardContextMessage,
ForwardPressedMessage, ForwardPressedMessage,
ForwardPressedLinkMessage ForwardPressedLinkMessage
}; };

View File

@ -336,7 +336,9 @@ void DocumentSaveClickHandler::doSave(
bool forceSavingAs) { bool forceSavingAs) {
if (!data->date) return; if (!data->date) return;
auto filepath = data->filepath(DocumentData::FilePathResolveSaveFromDataSilent, forceSavingAs); auto filepath = data->filepath(
DocumentData::FilePathResolveSaveFromDataSilent,
forceSavingAs);
if (!filepath.isEmpty() && !forceSavingAs) { if (!filepath.isEmpty() && !forceSavingAs) {
File::OpenWith(filepath, QCursor::pos()); File::OpenWith(filepath, QCursor::pos());
} else { } else {
@ -345,9 +347,7 @@ void DocumentSaveClickHandler::doSave(
auto filename = filepath.isEmpty() ? QString() : fileinfo.fileName(); auto filename = filepath.isEmpty() ? QString() : fileinfo.fileName();
auto newfname = documentSaveFilename(data, forceSavingAs, filename, filedir); auto newfname = documentSaveFilename(data, forceSavingAs, filename, filedir);
if (!newfname.isEmpty()) { if (!newfname.isEmpty()) {
auto action = (filename.isEmpty() || forceSavingAs) ? ActionOnLoadNone : ActionOnLoadOpenWith; data->save(newfname, ActionOnLoadNone, FullMsgId());
auto actionMsgId = App::hoveredLinkItem() ? App::hoveredLinkItem()->fullId() : (App::contextItem() ? App::contextItem()->fullId() : FullMsgId());
data->save(newfname, action, actionMsgId);
} }
} }
} }
@ -362,8 +362,7 @@ void DocumentCancelClickHandler::onClickImpl() const {
if (data->uploading()) { if (data->uploading()) {
if (const auto item = App::histItemById(context())) { if (const auto item = App::histItemById(context())) {
App::contextItem(item); App::main()->cancelUploadLayer(item);
App::main()->cancelUploadLayer();
} }
} else { } else {
data->cancel(); data->cancel();

View File

@ -137,8 +137,7 @@ void PhotoCancelClickHandler::onClickImpl() const {
if (data->uploading()) { if (data->uploading()) {
if (const auto item = App::histItemById(context())) { if (const auto item = App::histItemById(context())) {
App::contextItem(item); App::main()->cancelUploadLayer(item);
App::main()->cancelUploadLayer();
} }
} else { } else {
data->cancel(); data->cancel();

View File

@ -44,9 +44,5 @@ void MessageCursor::applyTo(QTextEdit *edit) {
HistoryItem *FileClickHandler::getActionItem() const { HistoryItem *FileClickHandler::getActionItem() const {
return context() return context()
? App::histItemById(context()) ? App::histItemById(context())
: App::hoveredLinkItem()
? App::hoveredLinkItem()
: App::contextItem()
? App::contextItem()
: nullptr; : nullptr;
} }

View File

@ -418,13 +418,14 @@ void InnerWidget::updateEmptyText() {
QString InnerWidget::tooltipText() const { QString InnerWidget::tooltipText() const {
if (_mouseCursorState == HistoryInDateCursorState && _mouseAction == MouseAction::None) { if (_mouseCursorState == HistoryInDateCursorState && _mouseAction == MouseAction::None) {
if (const auto item = App::hoveredItem()) { if (const auto view = App::hoveredItem()) {
auto dateText = item->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat)); auto dateText = view->data()->date.toString(
QLocale::system().dateTimeFormat(QLocale::LongFormat));
return dateText; return dateText;
} }
} else if (_mouseCursorState == HistoryInForwardedCursorState && _mouseAction == MouseAction::None) { } else if (_mouseCursorState == HistoryInForwardedCursorState && _mouseAction == MouseAction::None) {
if (const auto item = App::hoveredItem()) { if (const auto view = App::hoveredItem()) {
if (const auto forwarded = item->Get<HistoryMessageForwarded>()) { if (const auto forwarded = view->data()->Get<HistoryMessageForwarded>()) {
return forwarded->text.originalText(AllTextSelection, ExpandLinksNone); return forwarded->text.originalText(AllTextSelection, ExpandLinksNone);
} }
} }
@ -808,10 +809,6 @@ void InnerWidget::contextMenuEvent(QContextMenuEvent *e) {
} }
void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (_menu) {
_menu->deleteLater();
_menu = 0;
}
if (e->reason() == QContextMenuEvent::Mouse) { if (e->reason() == QContextMenuEvent::Mouse) {
mouseActionUpdate(e->globalPos()); mouseActionUpdate(e->globalPos());
} }
@ -828,10 +825,10 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (App::mousedItem() && App::mousedItem() == App::hoveredItem()) { if (App::mousedItem() && App::mousedItem() == App::hoveredItem()) {
auto mousePos = mapPointToItem( auto mousePos = mapPointToItem(
mapFromGlobal(_mousePosition), mapFromGlobal(_mousePosition),
viewForItem(App::mousedItem())); App::mousedItem());
HistoryStateRequest request; HistoryStateRequest request;
request.flags |= Text::StateRequest::Flag::LookupSymbol; 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) { if (dragState.cursor == HistoryInTextCursorState && dragState.symbol >= selFrom && dragState.symbol < selTo) {
isUponSelected = 1; isUponSelected = 1;
} }
@ -841,10 +838,12 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
isUponSelected = hasSelected; isUponSelected = hasSelected;
} }
_menu = new Ui::PopupMenu(nullptr); _menu = base::make_unique_q<Ui::PopupMenu>(nullptr);
_contextMenuLink = ClickHandler::getActive(); _contextMenuLink = ClickHandler::getActive();
auto item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem(); auto view = App::hoveredItem()
? App::hoveredItem()
: App::hoveredLinkItem();
auto lnkPhoto = dynamic_cast<PhotoClickHandler*>(_contextMenuLink.get()); auto lnkPhoto = dynamic_cast<PhotoClickHandler*>(_contextMenuLink.get());
auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLink.get()); auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLink.get());
auto lnkPeer = dynamic_cast<PeerClickHandler*>(_contextMenuLink.get()); auto lnkPeer = dynamic_cast<PeerClickHandler*>(_contextMenuLink.get());
@ -853,41 +852,52 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
auto lnkIsAudio = lnkDocument ? lnkDocument->document()->isAudioFile() : false; auto lnkIsAudio = lnkDocument ? lnkDocument->document()->isAudioFile() : false;
if (lnkPhoto || lnkDocument) { if (lnkPhoto || lnkDocument) {
if (isUponSelected > 0) { 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) { 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); savePhotoToFile(photo);
}))->setEnabled(true); }))->setEnabled(true);
_menu->addAction(lang(lng_context_copy_image), [this, photo = lnkPhoto->photo()] { _menu->addAction(lang(lng_context_copy_image), [=] {
copyContextImage(photo); copyContextImage(photo);
})->setEnabled(true); })->setEnabled(true);
} else { } else {
auto document = lnkDocument->document(); auto document = lnkDocument->document();
if (document->loading()) { 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 { } else {
if (document->loaded() && document->isGifv()) { if (document->loaded() && document->isGifv()) {
if (!cAutoPlayGif()) { 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()) { 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] { _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); saveDocumentToFile(document);
}))->setEnabled(true); }))->setEnabled(true);
} }
} }
if (App::hoveredLinkItem()) {
App::contextItem(App::hoveredLinkItem());
}
} else if (lnkPeer) { // suggest to block } else if (lnkPeer) { // suggest to block
if (auto user = lnkPeer->peer()->asUser()) { if (auto user = lnkPeer->peer()->asUser()) {
suggestRestrictUser(user); suggestRestrictUser(user);
} }
} else { // maybe cursor on some text history item? } 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 canDelete = item && item->canDelete() && (item->id > 0 || !item->serviceMsg());
bool canForward = item && item->canForward(); bool canForward = item && item->canForward();
@ -903,9 +913,11 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
media = static_cast<HistoryWebPage*>(media)->attach(); media = static_cast<HistoryWebPage*>(media)->attach();
} }
if (media->type() == MediaTypeSticker) { if (media->type() == MediaTypeSticker) {
if (auto document = media->getDocument()) { if (const auto document = media->getDocument()) {
if (document->sticker() && document->sticker()->set.type() != mtpc_inputStickerSetEmpty) { 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] { _menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] {
saveDocumentToFile(document); saveDocumentToFile(document);
@ -914,15 +926,21 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
} else if (media->type() == MediaTypeGif && !_contextMenuLink) { } else if (media->type() == MediaTypeGif && !_contextMenuLink) {
if (auto document = media->getDocument()) { if (auto document = media->getDocument()) {
if (document->loading()) { 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 { } else {
if (document->isGifv()) { if (document->isGifv()) {
if (!cAutoPlayGif()) { 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()) { 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] { _menu->addAction(lang(lng_context_save_file), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] {
saveDocumentToFile(document); saveDocumentToFile(document);
@ -932,7 +950,9 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
} }
} }
if (msg && !_contextMenuLink && (!msg->emptyText() || mediaHasTextForCopy)) { 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()) { if (!linkCopyToClipboardText.isEmpty()) {
_menu->addAction(linkCopyToClipboardText, [this] { copyContextUrl(); })->setEnabled(true); _menu->addAction(linkCopyToClipboardText, [this] { copyContextUrl(); })->setEnabled(true);
} }
App::contextItem(item);
} }
if (_menu->actions().isEmpty()) { if (_menu->actions().isEmpty()) {
delete base::take(_menu); _menu = nullptr;
} else { } else {
connect(_menu, &QObject::destroyed, this, [this](QObject *object) {
if (_menu == object) {
_menu = nullptr;
}
});
_menu->popup(e->globalPos()); _menu->popup(e->globalPos());
e->accept(); e->accept();
} }
@ -961,11 +975,15 @@ void InnerWidget::savePhotoToFile(PhotoData *photo) {
if (!photo || !photo->date || !photo->loaded()) return; if (!photo || !photo->date || !photo->loaded()) return;
auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter(); 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) { FileDialog::GetWritePath(
if (!result.isEmpty()) { lang(lng_save_photo),
photo->full->pix().toImage().save(result, "JPG"); 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) { void InnerWidget::saveDocumentToFile(DocumentData *document) {
@ -988,50 +1006,28 @@ void InnerWidget::copyContextUrl() {
} }
} }
void InnerWidget::showStickerPackInfo() { void InnerWidget::showStickerPackInfo(not_null<DocumentData*> document) {
if (!App::contextItem()) return; if (auto sticker = document->sticker()) {
if (sticker->set.type() != mtpc_inputStickerSetEmpty) {
if (auto media = App::contextItem()->getMedia()) { App::main()->stickersBox(sticker->set);
if (auto doc = media->getDocument()) {
if (auto sticker = doc->sticker()) {
if (sticker->set.type() != mtpc_inputStickerSetEmpty) {
App::main()->stickersBox(sticker->set);
}
}
} }
} }
} }
void InnerWidget::cancelContextDownload() { void InnerWidget::cancelContextDownload(not_null<DocumentData*> document) {
if (auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLink.get())) { document->cancel();
lnkDocument->document()->cancel();
} else if (auto item = App::contextItem()) {
if (auto media = item->getMedia()) {
if (auto doc = media->getDocument()) {
doc->cancel();
}
}
}
} }
void InnerWidget::showContextInFolder() { void InnerWidget::showContextInFolder(not_null<DocumentData*> document) {
QString filepath; const auto filepath = document->filepath(
if (auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLink.get())) { DocumentData::FilePathResolveChecked);
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);
}
}
}
if (!filepath.isEmpty()) { if (!filepath.isEmpty()) {
File::ShowInFolder(filepath); File::ShowInFolder(filepath);
} }
} }
void InnerWidget::openContextGif() { void InnerWidget::openContextGif(FullMsgId itemId) {
if (auto item = App::contextItem()) { if (const auto item = App::histItemById(itemId)) {
if (auto media = item->getMedia()) { if (auto media = item->getMedia()) {
if (auto document = media->getDocument()) { if (auto document = media->getDocument()) {
Messenger::Instance().showDocument(document, item); Messenger::Instance().showDocument(document, item);
@ -1040,16 +1036,20 @@ void InnerWidget::openContextGif() {
} }
} }
void InnerWidget::copyContextText() { void InnerWidget::copyContextText(FullMsgId itemId) {
auto item = App::contextItem(); if (const auto item = App::histItemById(itemId)) {
if (!item || (item->getMedia() && item->getMedia()->type() == MediaTypeSticker)) { if (const auto media = item->getMedia()) {
return; 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)) { if (auto data = MimeDataFromTextWithEntities(forClipboard)) {
QApplication::clipboard()->setMimeData(data.release(), mode); QApplication::clipboard()->setMimeData(data.release(), mode);
} }
@ -1057,6 +1057,7 @@ void InnerWidget::setToClipboard(const TextWithEntities &forClipboard, QClipboar
void InnerWidget::suggestRestrictUser(not_null<UserData*> user) { void InnerWidget::suggestRestrictUser(not_null<UserData*> user) {
Expects(_menu != nullptr); Expects(_menu != nullptr);
if (!_channel->isMegagroup() || !_channel->canBanMembers() || _admins.empty()) { if (!_channel->isMegagroup() || !_channel->canBanMembers() || _admins.empty()) {
return; return;
} }
@ -1065,8 +1066,8 @@ void InnerWidget::suggestRestrictUser(not_null<UserData*> user) {
return; return;
} }
} }
_menu->addAction(lang(lng_context_restrict_user), [this, user] { _menu->addAction(lang(lng_context_restrict_user), [=] {
auto editRestrictions = [user, this](bool hasAdminRights, const MTPChannelBannedRights &currentRights) { auto editRestrictions = [=](bool hasAdminRights, const MTPChannelBannedRights &currentRights) {
auto weak = QPointer<InnerWidget>(this); auto weak = QPointer<InnerWidget>(this);
auto weakBox = std::make_shared<QPointer<EditRestrictedBox>>(); auto weakBox = std::make_shared<QPointer<EditRestrictedBox>>();
auto box = Box<EditRestrictedBox>(_channel, user, hasAdminRights, currentRights); auto box = Box<EditRestrictedBox>(_channel, user, hasAdminRights, currentRights);
@ -1085,7 +1086,7 @@ void InnerWidget::suggestRestrictUser(not_null<UserData*> user) {
if (base::contains(_admins, user)) { if (base::contains(_admins, user)) {
editRestrictions(true, MTP_channelBannedRights(MTP_flags(0), MTP_int(0))); editRestrictions(true, MTP_channelBannedRights(MTP_flags(0), MTP_int(0)));
} else { } 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); Expects(result.type() == mtpc_channels_channelParticipant);
auto &participant = result.c_channels_channelParticipant(); auto &participant = result.c_channels_channelParticipant();
@ -1162,8 +1163,8 @@ void InnerWidget::enterEventHook(QEvent *e) {
} }
void InnerWidget::leaveEventHook(QEvent *e) { void InnerWidget::leaveEventHook(QEvent *e) {
if (auto item = App::hoveredItem()) { if (const auto view = App::hoveredItem()) {
repaintItem(viewForItem(item)); repaintItem(view);
App::hoveredItem(nullptr); App::hoveredItem(nullptr);
} }
ClickHandler::clearActive(); ClickHandler::clearActive();
@ -1181,13 +1182,13 @@ void InnerWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butt
ClickHandler::pressed(); ClickHandler::pressed();
if (App::pressedItem() != App::hoveredItem()) { if (App::pressedItem() != App::hoveredItem()) {
repaintItem(viewForItem(App::pressedItem())); repaintItem(App::pressedItem());
App::pressedItem(App::hoveredItem()); App::pressedItem(App::hoveredItem());
repaintItem(viewForItem(App::pressedItem())); repaintItem(App::pressedItem());
} }
_mouseAction = MouseAction::None; _mouseAction = MouseAction::None;
_mouseActionItem = viewForItem(App::mousedItem()); _mouseActionItem = App::mousedItem();
_dragStartPosition = mapPointToItem( _dragStartPosition = mapPointToItem(
mapFromGlobal(screenPos), mapFromGlobal(screenPos),
_mouseActionItem); _mouseActionItem);
@ -1270,8 +1271,8 @@ void InnerWidget::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton but
if (_mouseAction == MouseAction::Dragging) { if (_mouseAction == MouseAction::Dragging) {
activated = nullptr; activated = nullptr;
} }
if (App::pressedItem()) { if (const auto view = App::pressedItem()) {
repaintItem(viewForItem(App::pressedItem())); repaintItem(view);
App::pressedItem(nullptr); App::pressedItem(nullptr);
} }
@ -1318,23 +1319,25 @@ void InnerWidget::updateSelected() {
const auto view = (from != end) ? from->get() : nullptr; const auto view = (from != end) ? from->get() : nullptr;
const auto item = view ? view->data().get() : nullptr; const auto item = view ? view->data().get() : nullptr;
if (item) { if (item) {
App::mousedItem(item); App::mousedItem(view);
itemPoint = mapPointToItem(point, view); itemPoint = mapPointToItem(point, view);
if (item->hasPoint(itemPoint)) { if (item->hasPoint(itemPoint)) {
if (App::hoveredItem() != item) { if (App::hoveredItem() != view) {
repaintItem(viewForItem(App::hoveredItem())); repaintItem(App::hoveredItem());
App::hoveredItem(item); App::hoveredItem(view);
repaintItem(view); repaintItem(view);
} }
} else if (App::hoveredItem()) { } else if (const auto view = App::hoveredItem()) {
repaintItem(viewForItem(App::hoveredItem())); repaintItem(view);
App::hoveredItem(nullptr); App::hoveredItem(nullptr);
} }
} }
HistoryTextState dragState; HistoryTextState dragState;
ClickHandlerHost *lnkhost = nullptr; ClickHandlerHost *lnkhost = nullptr;
auto selectingText = (view == _mouseActionItem && item == App::hoveredItem() && _selectedItem); auto selectingText = _selectedItem
&& (view == _mouseActionItem)
&& (view == App::hoveredItem());
if (view) { if (view) {
if (view != _mouseActionItem || (itemPoint - _dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) { if (view != _mouseActionItem || (itemPoint - _dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) {
if (_mouseAction == MouseAction::PrepareDrag) { if (_mouseAction == MouseAction::PrepareDrag) {
@ -1422,13 +1425,9 @@ void InnerWidget::updateSelected() {
} }
// Voice message seek support. // Voice message seek support.
if (auto pressedItem = App::pressedLinkItem()) { if (const auto pressedView = App::pressedLinkItem()) {
if (!pressedItem->detached()) { const auto adjustedPoint = mapPointToItem(point, pressedView);
if (pressedItem->history() == _history) { pressedView->data()->updatePressed(adjustedPoint);
auto adjustedPoint = mapPointToItem(point, viewForItem(pressedItem));
pressedItem->updatePressed(adjustedPoint);
}
}
} }
//if (_mouseAction == MouseAction::Selecting) { //if (_mouseAction == MouseAction::Selecting) {

View File

@ -121,12 +121,12 @@ private:
void savePhotoToFile(PhotoData *photo); void savePhotoToFile(PhotoData *photo);
void saveDocumentToFile(DocumentData *document); void saveDocumentToFile(DocumentData *document);
void copyContextImage(PhotoData *photo); void copyContextImage(PhotoData *photo);
void showStickerPackInfo(); void showStickerPackInfo(not_null<DocumentData*> document);
void copyContextUrl(); void copyContextUrl();
void cancelContextDownload(); void cancelContextDownload(not_null<DocumentData*> document);
void showContextInFolder(); void showContextInFolder(not_null<DocumentData*> document);
void openContextGif(); void openContextGif(FullMsgId itemId);
void copyContextText(); void copyContextText(FullMsgId itemId);
void copySelectedText(); void copySelectedText();
TextWithEntities getSelectedText() const; TextWithEntities getSelectedText() const;
void setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode = QClipboard::Clipboard); 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 bool _wasSelectedText = false; // was some text selected in current drag action
Qt::CursorShape _cursor = style::cur_default; Qt::CursorShape _cursor = style::cur_default;
// context menu base::unique_qptr<Ui::PopupMenu> _menu;
Ui::PopupMenu *_menu = nullptr;
QPoint _trippleClickPoint; QPoint _trippleClickPoint;
base::Timer _trippleClickTimer; base::Timer _trippleClickTimer;

View File

@ -376,9 +376,9 @@ void ChannelHistory::getRangeDifference() {
for (auto blockIndex = 0, blocksCount = int(blocks.size()); blockIndex < blocksCount; ++blockIndex) { for (auto blockIndex = 0, blocksCount = int(blocks.size()); blockIndex < blocksCount; ++blockIndex) {
const auto &block = blocks[blockIndex]; const auto &block = blocks[blockIndex];
for (auto itemIndex = 0, itemsCount = int(block->messages.size()); itemIndex < itemsCount; ++itemIndex) { for (auto itemIndex = 0, itemsCount = int(block->messages.size()); itemIndex < itemsCount; ++itemIndex) {
const auto &message = block->messages[itemIndex]; const auto id = block->messages[itemIndex]->data()->id;
if (message->id() > 0) { if (id > 0) {
fromId = message->id(); fromId = id;
break; break;
} }
} }
@ -389,9 +389,9 @@ void ChannelHistory::getRangeDifference() {
for (auto blockIndex = blocks.size(); blockIndex > 0;) { for (auto blockIndex = blocks.size(); blockIndex > 0;) {
const auto &block = blocks[--blockIndex]; const auto &block = blocks[--blockIndex];
for (auto itemIndex = block->messages.size(); itemIndex > 0;) { for (auto itemIndex = block->messages.size(); itemIndex > 0;) {
const auto &message = block->messages[--itemIndex]; const auto id = block->messages[--itemIndex]->data()->id;
if (message->id() > 0) { if (id > 0) {
toId = message->id(); toId = id;
break; break;
} }
} }
@ -420,11 +420,16 @@ void ChannelHistory::getRangeDifferenceNext(int32 pts) {
} }
HistoryJoined *ChannelHistory::insertJoinedMessage(bool unread) { 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; 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; if (!inviter) return nullptr;
MTPDmessage::Flags flags = 0; MTPDmessage::Flags flags = 0;
@ -491,7 +496,7 @@ void ChannelHistory::checkJoinedMessage(bool createUnread) {
if (isEmpty()) { if (isEmpty()) {
if (loadedAtTop() && loadedAtBottom()) { if (loadedAtTop() && loadedAtBottom()) {
if (insertJoinedMessage(createUnread)) { if (insertJoinedMessage(createUnread)) {
if (!_joinedMessage->detached()) { if (_joinedMessage->mainView()) {
setLastMessage(_joinedMessage); setLastMessage(_joinedMessage);
} }
} }
@ -508,7 +513,7 @@ void ChannelHistory::checkJoinedMessage(bool createUnread) {
if (!firstDate.isNull() && !lastDate.isNull() && (firstDate <= inviteDate || loadedAtTop()) && (lastDate > inviteDate || loadedAtBottom())) { if (!firstDate.isNull() && !lastDate.isNull() && (firstDate <= inviteDate || loadedAtTop()) && (lastDate > inviteDate || loadedAtBottom())) {
bool willBeLastMsg = (inviteDate >= lastDate); bool willBeLastMsg = (inviteDate >= lastDate);
if (insertJoinedMessage(createUnread && willBeLastMsg) && willBeLastMsg) { if (insertJoinedMessage(createUnread && willBeLastMsg) && willBeLastMsg) {
if (!_joinedMessage->detached()) { if (_joinedMessage->mainView()) {
setLastMessage(_joinedMessage); setLastMessage(_joinedMessage);
} }
} }
@ -545,8 +550,8 @@ void ChannelHistory::cleared(bool leaveItems) {
_joinedMessage = nullptr; _joinedMessage = nullptr;
} }
void ChannelHistory::messageDetached(HistoryItem *msg) { void ChannelHistory::messageDetached(not_null<HistoryItem*> message) {
if (_joinedMessage == msg) { if (_joinedMessage == message) {
_joinedMessage = nullptr; _joinedMessage = nullptr;
} }
} }
@ -565,7 +570,9 @@ History *Histories::find(const PeerId &peerId) {
not_null<History*> Histories::findOrInsert(const PeerId &peerId) { not_null<History*> Histories::findOrInsert(const PeerId &peerId) {
auto i = map.constFind(peerId); auto i = map.constFind(peerId);
if (i == map.cend()) { if (i == map.cend()) {
auto history = peerIsChannel(peerId) ? static_cast<History*>(new ChannelHistory(peerId)) : (new History(peerId)); auto history = peerIsChannel(peerId)
? static_cast<History*>(new ChannelHistory(peerId))
: (new History(peerId));
i = map.insert(peerId, history); i = map.insert(peerId, history);
} }
return i.value(); return i.value();
@ -574,7 +581,9 @@ not_null<History*> Histories::findOrInsert(const PeerId &peerId) {
not_null<History*> Histories::findOrInsert(const PeerId &peerId, int32 unreadCount, int32 maxInboxRead, int32 maxOutboxRead) { not_null<History*> Histories::findOrInsert(const PeerId &peerId, int32 unreadCount, int32 maxInboxRead, int32 maxOutboxRead) {
auto i = map.constFind(peerId); auto i = map.constFind(peerId);
if (i == map.cend()) { if (i == map.cend()) {
auto history = peerIsChannel(peerId) ? static_cast<History*>(new ChannelHistory(peerId)) : (new History(peerId)); auto history = peerIsChannel(peerId)
? static_cast<History*>(new ChannelHistory(peerId))
: (new History(peerId));
i = map.insert(peerId, history); i = map.insert(peerId, history);
history->setUnreadCount(unreadCount); history->setUnreadCount(unreadCount);
history->inboxReadBefore = maxInboxRead + 1; history->inboxReadBefore = maxInboxRead + 1;
@ -634,7 +643,7 @@ void Histories::step_typings(TimeMs ms, bool timer) {
} }
void Histories::remove(const PeerId &peer) { void Histories::remove(const PeerId &peer) {
Map::iterator i = map.find(peer); const auto i = map.find(peer);
if (i != map.cend()) { if (i != map.cend()) {
typing.remove(i.value()); typing.remove(i.value());
delete 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); const auto msgId = idFromMessage(msg);
if (!msgId) return nullptr; if (!msgId) return nullptr;
auto result = App::histItemById(channelId(), msgId); auto result = App::histItemById(channelId(), msgId);
if (result) { if (result) {
if (!result->detached() && detachExistingItem) { if (detachExistingItem) {
result->detach(); result->removeMainView();
} }
if (msg.type() == mtpc_message) { if (msg.type() == mtpc_message) {
const auto media = msg.c_message().has_media() const auto media = msg.c_message().has_media()
@ -1053,13 +1065,18 @@ HistoryItem *History::addNewMessage(const MTPMessage &msg, NewMessageType type)
return addNewToLastBlock(msg, type); return addNewToLastBlock(msg, type);
} }
HistoryItem *History::addNewToLastBlock(const MTPMessage &msg, NewMessageType type) { HistoryItem *History::addNewToLastBlock(
const MTPMessage &msg,
NewMessageType type) {
Expects(type != NewMessageExisting); Expects(type != NewMessageExisting);
const auto applyServiceAction = (type == NewMessageUnread); const auto applyServiceAction = (type == NewMessageUnread);
const auto detachExistingItem = (type != NewMessageLast); const auto detachExistingItem = (type != NewMessageLast);
const auto item = createItem(msg, applyServiceAction, detachExistingItem); const auto item = createItem(
if (!item || !item->detached()) { msg,
applyServiceAction,
detachExistingItem);
if (!item || item->mainView()) {
return item; return item;
} }
const auto result = addNewItem(item, (type == NewMessageUnread)); const auto result = addNewItem(item, (type == NewMessageUnread));
@ -1367,14 +1384,14 @@ HistoryBlock *History::prepareBlockForAddingItem() {
}; };
void History::addItemToBlock(not_null<HistoryItem*> item) { void History::addItemToBlock(not_null<HistoryItem*> item) {
Expects(item->detached()); Expects(!item->mainView());
auto block = prepareBlockForAddingItem(); auto block = prepareBlockForAddingItem();
block->messages.push_back(std::make_unique<HistoryView::Message>( block->messages.push_back(std::make_unique<HistoryView::Message>(
item, item,
HistoryView::Context::History)); HistoryView::Context::History));
item->attachToBlock(block, block->messages.size() - 1); block->messages.back()->attachToBlock(block, block->messages.size() - 1);
item->previousItemChanged(); item->previousItemChanged();
if (isBuildingFrontBlock() && _buildingFrontBlock->expectedItemsCount > 0) { if (isBuildingFrontBlock() && _buildingFrontBlock->expectedItemsCount > 0) {
@ -1617,7 +1634,7 @@ void History::addNewerSlice(const QVector<MTPMessage> &slice) {
void History::checkLastMsg() { void History::checkLastMsg() {
if (lastMsg) { if (lastMsg) {
if (!newLoaded && !lastMsg->detached()) { if (!newLoaded && lastMsg->mainView()) {
newLoaded = true; newLoaded = true;
checkAddAllToUnreadMentions(); checkAddAllToUnreadMentions();
} }
@ -1840,7 +1857,7 @@ QDateTime History::adjustChatListDate() const {
void History::countScrollState(int top) { void History::countScrollState(int top) {
countScrollTopItem(top); countScrollTopItem(top);
if (scrollTopItem) { 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 blockIndex = 0;
auto itemTop = 0; auto itemTop = 0;
if (scrollTopItem) { if (scrollTopItem) {
itemIndex = scrollTopItem->data()->indexInBlock(); itemIndex = scrollTopItem->indexInBlock();
blockIndex = scrollTopItem->data()->block()->indexInHistory(); blockIndex = scrollTopItem->block()->indexInHistory();
itemTop = blocks[blockIndex]->y() + scrollTopItem->y(); itemTop = blocks[blockIndex]->y() + scrollTopItem->y();
} }
if (itemTop > top) { if (itemTop > top) {
@ -1915,7 +1932,9 @@ void History::getNextScrollTopItem(HistoryBlock *block, int32 i) {
} }
void History::addUnreadBar() { void History::addUnreadBar() {
if (unreadBar || !showFrom || showFrom->detached() || !unreadCount()) return; if (unreadBar || !showFrom || !showFrom->mainView() || !unreadCount()) {
return;
}
int32 count = unreadCount(); int32 count = unreadCount();
if (peer->migrateTo()) { if (peer->migrateTo()) {
@ -1944,14 +1963,16 @@ not_null<HistoryItem*> History::addNewInTheMiddle(
const auto &block = blocks[blockIndex]; const auto &block = blocks[blockIndex];
block->messages.insert( const auto it = block->messages.insert(
block->messages.begin() + itemIndex, block->messages.begin() + itemIndex,
std::make_unique<HistoryView::Message>(newItem, HistoryView::Context::History)); std::make_unique<HistoryView::Message>(
newItem->attachToBlock(block.get(), itemIndex); newItem,
HistoryView::Context::History));
(*it)->attachToBlock(block.get(), itemIndex);
newItem->previousItemChanged(); newItem->previousItemChanged();
if (itemIndex + 1 < block->messages.size()) { if (itemIndex + 1 < block->messages.size()) {
for (auto i = itemIndex + 1, l = int(block->messages.size()); i != l; ++i) { 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(); block->messages[itemIndex + 1]->data()->previousItemChanged();
} else if (blockIndex + 1 < blocks.size() && !blocks[blockIndex + 1]->messages.empty()) { } else if (blockIndex + 1 < blocks.size() && !blocks[blockIndex + 1]->messages.empty()) {
@ -1969,12 +1990,12 @@ not_null<HistoryItem*> History::addNewInTheMiddle(
} }
HistoryItem *History::findNextItem(not_null<HistoryItem*> item) const { HistoryItem *History::findNextItem(not_null<HistoryItem*> item) const {
Expects(!item->detached()); Expects(item->mainView());
const auto nextBlockIndex = item->block()->indexInHistory() + 1; const auto nextBlockIndex = item->mainView()->block()->indexInHistory() + 1;
const auto nextItemIndex = item->indexInBlock() + 1; const auto nextItemIndex = item->mainView()->indexInBlock() + 1;
if (nextItemIndex < int(item->block()->messages.size())) { if (nextItemIndex < int(item->mainView()->block()->messages.size())) {
return item->block()->messages[nextItemIndex]->data(); return item->mainView()->block()->messages[nextItemIndex]->data();
} else if (nextBlockIndex < int(blocks.size())) { } else if (nextBlockIndex < int(blocks.size())) {
return blocks[nextBlockIndex]->messages.front()->data(); return blocks[nextBlockIndex]->messages.front()->data();
} }
@ -1982,12 +2003,12 @@ HistoryItem *History::findNextItem(not_null<HistoryItem*> item) const {
} }
HistoryItem *History::findPreviousItem(not_null<HistoryItem*> item) const { HistoryItem *History::findPreviousItem(not_null<HistoryItem*> item) const {
Expects(!item->detached()); Expects(item->mainView());
const auto blockIndex = item->block()->indexInHistory(); const auto blockIndex = item->mainView()->block()->indexInHistory();
const auto itemIndex = item->indexInBlock(); const auto itemIndex = item->mainView()->indexInBlock();
if (itemIndex > 0) { if (itemIndex > 0) {
return item->block()->messages[itemIndex - 1]->data(); return item->mainView()->block()->messages[itemIndex - 1]->data();
} else if (blockIndex > 0) { } else if (blockIndex > 0) {
return blocks[blockIndex - 1]->messages.back()->data(); return blocks[blockIndex - 1]->messages.back()->data();
} }
@ -2021,7 +2042,7 @@ not_null<HistoryItem*> History::findGroupLast(
void History::recountGroupingAround(not_null<HistoryItem*> item) { void History::recountGroupingAround(not_null<HistoryItem*> item) {
Expects(item->history() == this); Expects(item->history() == this);
if (!item->detached() && item->groupId()) { if (item->mainView() && item->groupId()) {
const auto [groupFrom, groupTill] = recountGroupingFromTill(item); const auto [groupFrom, groupTill] = recountGroupingFromTill(item);
recountGrouping(groupFrom, groupTill); recountGrouping(groupFrom, groupTill);
} }
@ -2084,8 +2105,8 @@ auto History::recountGroupingFromTill(not_null<HistoryItem*> item)
void History::recountGrouping( void History::recountGrouping(
not_null<HistoryItem*> from, not_null<HistoryItem*> from,
not_null<HistoryItem*> till) { not_null<HistoryItem*> till) {
Expects(!from->detached()); Expects(from->mainView());
Expects(!till->detached()); Expects(till->mainView());
from->validateGroupId(); from->validateGroupId();
auto others = std::vector<not_null<HistoryItem*>>(); auto others = std::vector<not_null<HistoryItem*>>();
@ -2186,7 +2207,7 @@ bool History::isReadyFor(MsgId msgId) {
return loadedAtBottom(); return loadedAtBottom();
} }
HistoryItem *item = App::histItemById(channelId(), msgId); 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) { void History::getReadyFor(MsgId msgId) {
@ -2539,15 +2560,16 @@ void HistoryBlock::clear(bool leaveItems) {
if (leaveItems) { if (leaveItems) {
for (const auto &message : list) { for (const auto &message : list) {
message->data()->detachFast(); message->data()->clearMainView();
} }
} }
// #TODO feeds delete all items in history // #TODO feeds delete all items in history
} }
void HistoryBlock::removeItem(not_null<HistoryItem*> item) { void HistoryBlock::remove(not_null<Message*> view) {
Expects(item->block() == this); Expects(view->block() == this);
const auto item = view->data();
auto [groupFrom, groupTill] = _history->recountGroupingFromTill(item); auto [groupFrom, groupTill] = _history->recountGroupingFromTill(item);
const auto groupHistory = _history; const auto groupHistory = _history;
const auto needGroupRecount = (groupFrom != groupTill); const auto needGroupRecount = (groupFrom != groupTill);
@ -2561,7 +2583,7 @@ void HistoryBlock::removeItem(not_null<HistoryItem*> item) {
} }
auto blockIndex = indexInHistory(); auto blockIndex = indexInHistory();
auto itemIndex = item->indexInBlock(); auto itemIndex = view->indexInBlock();
if (_history->showFrom == item) { if (_history->showFrom == item) {
_history->getNextShowFrom(this, itemIndex); _history->getNextShowFrom(this, itemIndex);
} }
@ -2575,10 +2597,10 @@ void HistoryBlock::removeItem(not_null<HistoryItem*> item) {
_history->getNextScrollTopItem(this, itemIndex); _history->getNextScrollTopItem(this, itemIndex);
} }
item->detachFast(); item->clearMainView();
messages.erase(messages.begin() + itemIndex); messages.erase(messages.begin() + itemIndex);
for (auto i = itemIndex, l = int(messages.size()); i < l; ++i) { for (auto i = itemIndex, l = int(messages.size()); i < l; ++i) {
messages[i]->data()->setIndexInBlock(i); messages[i]->setIndexInBlock(i);
} }
if (messages.empty()) { if (messages.empty()) {
// Deletes this. // Deletes this.

View File

@ -550,7 +550,7 @@ class ChannelHistory : public History {
public: public:
using History::History; using History::History;
void messageDetached(HistoryItem *msg); void messageDetached(not_null<HistoryItem*> message);
void getRangeDifference(); void getRangeDifference();
void getRangeDifferenceNext(int32 pts); void getRangeDifferenceNext(int32 pts);
@ -579,15 +579,17 @@ private:
class HistoryBlock { class HistoryBlock {
public: public:
using Message = HistoryView::Message;
HistoryBlock(not_null<History*> history); HistoryBlock(not_null<History*> history);
HistoryBlock(const HistoryBlock &) = delete; HistoryBlock(const HistoryBlock &) = delete;
HistoryBlock &operator=(const HistoryBlock &) = delete; HistoryBlock &operator=(const HistoryBlock &) = delete;
~HistoryBlock(); ~HistoryBlock();
std::vector<std::unique_ptr<HistoryView::Message>> messages; std::vector<std::unique_ptr<Message>> messages;
void clear(bool leaveItems = false); void clear(bool leaveItems = false);
void removeItem(not_null<HistoryItem*> item); void remove(not_null<Message*> view);
int resizeGetHeight(int newWidth, bool resizeAllItems); int resizeGetHeight(int newWidth, bool resizeAllItems);
int y() const { int y() const {

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,8 @@ class HistoryInner
Q_OBJECT Q_OBJECT
public: public:
using Message = HistoryView::Message;
HistoryInner( HistoryInner(
not_null<HistoryWidget*> historyWidget, not_null<HistoryWidget*> historyWidget,
not_null<Window::Controller*> controller, not_null<Window::Controller*> controller,
@ -40,12 +42,12 @@ public:
TextWithEntities getSelectedText() const; TextWithEntities getSelectedText() const;
void touchScrollUpdated(const QPoint &screenPos); void touchScrollUpdated(const QPoint &screenPos);
QPoint mapPointToItem(QPoint p, HistoryItem *item);
void recountHistoryGeometry(); void recountHistoryGeometry();
void updateSize(); void updateSize();
void repaintItem(const HistoryItem *item); void repaintItem(const HistoryItem *item);
void repaintItem(const Message *view);
bool canCopySelected() const; bool canCopySelected() const;
bool canDeleteSelected() const; bool canDeleteSelected() const;
@ -68,7 +70,10 @@ public:
int migratedTop() const; int migratedTop() const;
int historyTop() const; int historyTop() const;
int historyDrawTop() 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 notifyIsBotChanged();
void notifyMigrateUpdated(); void notifyMigrateUpdated();
@ -104,14 +109,8 @@ public slots:
void onParentGeometryChanged(); void onParentGeometryChanged();
void copyContextUrl(); void copyContextUrl();
void cancelContextDownload();
void showContextInFolder();
void saveContextGif();
void openContextGif();
void copyContextText();
void copySelectedText(); void copySelectedText();
void onMenuDestroy(QObject *obj);
void onTouchSelect(); void onTouchSelect();
void onTouchScrollTimer(); void onTouchScrollTimer();
@ -122,7 +121,6 @@ private slots:
private: private:
class BotAbout; class BotAbout;
using SelectedItems = std::map<HistoryItem*, TextSelection, std::less<>>; using SelectedItems = std::map<HistoryItem*, TextSelection, std::less<>>;
using Message = HistoryView::Message;
enum class MouseAction { enum class MouseAction {
None, None,
PrepareDrag, PrepareDrag,
@ -135,166 +133,6 @@ private:
Deselect, Deselect,
Invert, 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<const HistoryItem*> 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<Message*> view,
int selfromy,
int seltoy) const;
TextSelection computeRenderSelection(
not_null<const SelectedItems*> selected,
not_null<HistoryItem*> 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<Window::Controller*> _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> _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<SelectedItems*> toItems) const;
void addSelectionRange(
not_null<SelectedItems*> toItems,
not_null<History*> history,
int fromblock,
int fromitem,
int toblock,
int toitem) const;
bool isSelected(
not_null<SelectedItems*> toItems,
not_null<HistoryItem*> item) const;
bool isSelectedAsGroup(
not_null<SelectedItems*> toItems,
not_null<HistoryItem*> item) const;
bool goodForSelection(
not_null<SelectedItems*> toItems,
not_null<HistoryItem*> item,
int &totalCount) const;
void addToSelection(
not_null<SelectedItems*> toItems,
not_null<HistoryItem*> item) const;
void removeFromSelection(
not_null<SelectedItems*> toItems,
not_null<HistoryItem*> item) const;
void changeSelection(
not_null<SelectedItems*> toItems,
not_null<HistoryItem*> item,
SelectAction action) const;
void changeSelectionAsGroup(
not_null<SelectedItems*> toItems,
not_null<HistoryItem*> item,
SelectAction action) const;
void forwardItem(not_null<HistoryItem*> item);
void forwardAsGroup(not_null<HistoryItem*> item);
void deleteItem(not_null<HistoryItem*> item);
void deleteAsGroup(not_null<HistoryItem*> 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 { enum class EnumItemsDirection {
TopToBottom, TopToBottom,
BottomToTop, BottomToTop,
@ -335,4 +173,171 @@ private:
template <typename Method> template <typename Method>
void enumerateDates(Method method); 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<DocumentData*> document);
void openContextGif(FullMsgId itemId);
void saveContextGif(FullMsgId itemId);
void copyContextText(FullMsgId itemId);
void showContextInFolder(not_null<DocumentData*> document);
void savePhotoToFile(not_null<PhotoData*> photo);
void saveDocumentToFile(not_null<DocumentData*> document);
void copyContextImage(not_null<PhotoData*> photo);
void showStickerPackInfo(not_null<DocumentData*> document);
void toggleFavedSticker(not_null<DocumentData*> document);
void itemRemoved(not_null<const HistoryItem*> 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<Message*> view,
int selfromy,
int seltoy) const;
TextSelection computeRenderSelection(
not_null<const SelectedItems*> selected,
not_null<HistoryItem*> 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<SelectedItems*> toItems) const;
void addSelectionRange(
not_null<SelectedItems*> toItems,
not_null<History*> history,
int fromblock,
int fromitem,
int toblock,
int toitem) const;
bool isSelected(
not_null<SelectedItems*> toItems,
not_null<HistoryItem*> item) const;
bool isSelectedAsGroup(
not_null<SelectedItems*> toItems,
not_null<HistoryItem*> item) const;
bool goodForSelection(
not_null<SelectedItems*> toItems,
not_null<HistoryItem*> item,
int &totalCount) const;
void addToSelection(
not_null<SelectedItems*> toItems,
not_null<HistoryItem*> item) const;
void removeFromSelection(
not_null<SelectedItems*> toItems,
not_null<HistoryItem*> item) const;
void changeSelection(
not_null<SelectedItems*> toItems,
not_null<HistoryItem*> item,
SelectAction action) const;
void changeSelectionAsGroup(
not_null<SelectedItems*> toItems,
not_null<HistoryItem*> item,
SelectAction action) const;
void forwardItem(FullMsgId itemId);
void forwardAsGroup(FullMsgId itemId);
void deleteItem(not_null<HistoryItem*> 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<Window::Controller*> _controller;
not_null<PeerData*> _peer;
not_null<History*> _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> _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<Ui::PopupMenu> _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;
}; };

View File

@ -259,7 +259,8 @@ void HistoryItem::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool activ
markup->inlineKeyboard->clickHandlerActiveChanged(p, active); markup->inlineKeyboard->clickHandlerActiveChanged(p, active);
} }
} }
App::hoveredLinkItem(active ? this : nullptr); // #TODO hoveredLinkItem
// App::hoveredLinkItem(active ? this : nullptr);
Auth().data().requestItemRepaint(this); Auth().data().requestItemRepaint(this);
} }
@ -269,7 +270,8 @@ void HistoryItem::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pres
markup->inlineKeyboard->clickHandlerPressedChanged(p, pressed); markup->inlineKeyboard->clickHandlerPressedChanged(p, pressed);
} }
} }
App::pressedLinkItem(pressed ? this : nullptr); // #TODO hoveredLinkItem
// App::pressedLinkItem(pressed ? this : nullptr);
Auth().data().requestItemRepaint(this); Auth().data().requestItemRepaint(this);
} }
@ -291,7 +293,7 @@ UserData *HistoryItem::viaBot() const {
void HistoryItem::destroy() { void HistoryItem::destroy() {
const auto history = this->history(); const auto history = this->history();
if (isLogEntry()) { if (isLogEntry()) {
Assert(detached()); Assert(!mainView());
} else { } else {
// All this must be done for all items manually in History::clear(false)! // All this must be done for all items manually in History::clear(false)!
eraseFromUnreadMentions(); eraseFromUnreadMentions();
@ -309,7 +311,7 @@ void HistoryItem::destroy() {
const auto wasAtBottom = history->loadedAtBottom(); const auto wasAtBottom = history->loadedAtBottom();
history->removeNotification(this); history->removeNotification(this);
detach(); removeMainView();
if (history->lastMsg == this) { if (history->lastMsg == this) {
history->fixLastMessage(wasAtBottom); history->fixLastMessage(wasAtBottom);
@ -336,33 +338,18 @@ void HistoryItem::destroy() {
delete this; delete this;
} }
void HistoryItem::detach() { void HistoryItem::removeMainView() {
if (detached()) return; if (const auto view = mainView()) {
if (const auto channelHistory = _history->asChannelHistory()) {
if (_history->isChannel()) { channelHistory->messageDetached(this);
_history->asChannelHistory()->messageDetached(this); }
_history->setPendingResize();
view->removeFromBlock();
_mainView = nullptr;
} }
_block->removeItem(this);
App::historyItemDetached(this);
_history->setPendingResize();
} }
void HistoryItem::attachToBlock(not_null<HistoryBlock*> block, int index) { void HistoryItem::clearMainView() {
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;
_mainView = nullptr; _mainView = nullptr;
validateGroupId(); validateGroupId();
@ -391,6 +378,7 @@ void HistoryItem::indexAsNewItem() {
void HistoryItem::previousItemChanged() { void HistoryItem::previousItemChanged() {
Expects(!isLogEntry()); Expects(!isLogEntry());
recountDisplayDate(); recountDisplayDate();
recountAttachToPrevious(); recountAttachToPrevious();
} }
@ -398,6 +386,7 @@ void HistoryItem::previousItemChanged() {
// Called only if there is no more next item! Not always when it changes! // Called only if there is no more next item! Not always when it changes!
void HistoryItem::nextItemChanged() { void HistoryItem::nextItemChanged() {
Expects(!isLogEntry()); Expects(!isLogEntry());
setAttachToNext(false); setAttachToNext(false);
} }
@ -421,6 +410,7 @@ bool HistoryItem::computeIsAttachToPrevious(not_null<HistoryItem*> previous) {
void HistoryItem::recountAttachToPrevious() { void HistoryItem::recountAttachToPrevious() {
Expects(!isLogEntry()); Expects(!isLogEntry());
auto attachToPrevious = false; auto attachToPrevious = false;
if (auto previous = previousItem()) { if (auto previous = previousItem()) {
attachToPrevious = computeIsAttachToPrevious(previous); attachToPrevious = computeIsAttachToPrevious(previous);
@ -940,11 +930,6 @@ void HistoryItem::clipCallback(Media::Clip::Notification notification) {
} }
if (!stopped) { if (!stopped) {
setPendingInitDimensions(); 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); Auth().data().markItemLayoutChanged(this);
Global::RefPendingRepaintItems().insert(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 { HistoryItem *HistoryItem::previousItem() const {
if (_block && _indexInBlock >= 0) { if (const auto view = mainView()) {
if (_indexInBlock > 0) { if (const auto previous = view->previousInBlocks()) {
return _block->messages[_indexInBlock - 1]->data(); return previous->data();
}
if (auto previous = _block->previousBlock()) {
Assert(!previous->messages.empty());
return previous->messages.back()->data();
} }
} }
return nullptr; return nullptr;
} }
HistoryItem *HistoryItem::nextItem() const { HistoryItem *HistoryItem::nextItem() const {
if (_block && _indexInBlock >= 0) { if (const auto view = mainView()) {
if (_indexInBlock + 1 < _block->messages.size()) { if (const auto next = view->nextInBlocks()) {
return _block->messages[_indexInBlock + 1]->data(); return next->data();
}
if (auto next = _block->nextBlock()) {
Assert(!next->messages.empty());
return next->messages.front()->data();
} }
} }
return nullptr; return nullptr;
@ -1107,9 +1091,9 @@ HistoryItem::~HistoryItem() {
ClickHandlerPtr goToMessageClickHandler(PeerData *peer, MsgId msgId) { ClickHandlerPtr goToMessageClickHandler(PeerData *peer, MsgId msgId) {
return std::make_shared<LambdaClickHandler>([peer, msgId] { return std::make_shared<LambdaClickHandler>([peer, msgId] {
if (App::main()) { if (App::main()) {
auto current = App::mousedItem(); auto view = App::mousedItem();
if (current && current->history()->peer == peer) { if (view && view->data()->history()->peer == peer) {
App::main()->pushReplyReturn(current); App::main()->pushReplyReturn(view->data());
} }
App::wnd()->controller()->showPeerHistory( App::wnd()->controller()->showPeerHistory(
peer, peer,

View File

@ -53,6 +53,9 @@ public:
int minHeight() const { int minHeight() const {
return _minh; return _minh;
} }
int width() const {
return _width;
}
int height() const { int height() const {
return _height; return _height;
} }
@ -62,6 +65,7 @@ public:
protected: protected:
mutable int _maxw = 0; mutable int _maxw = 0;
mutable int _minh = 0; mutable int _minh = 0;
mutable int _width = 0;
mutable int _height = 0; mutable int _height = 0;
}; };
@ -226,34 +230,16 @@ public:
PeerData *from() const { PeerData *from() const {
return _from; return _from;
} }
HistoryBlock *block() {
return _block;
}
const HistoryBlock *block() const {
return _block;
}
HistoryView::Message *mainView() const { HistoryView::Message *mainView() const {
return _mainView; return _mainView;
} }
void setMainView(HistoryView::Message *view) {
_mainView = view;
}
void clearMainView();
void removeMainView();
void destroy(); void destroy();
void detach();
void detachFast();
bool detached() const {
return !_block;
}
void attachToBlock(not_null<HistoryBlock*> 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 { bool out() const {
return _flags & MTPDmessage::Flag::f_out; return _flags & MTPDmessage::Flag::f_out;
} }
@ -493,9 +479,7 @@ public:
} }
void setPendingResize() { void setPendingResize() {
_flags |= MTPDmessage_ClientFlag::f_pending_resize; _flags |= MTPDmessage_ClientFlag::f_pending_resize;
if (!detached() || isLogEntry()) { _history->setHasPendingResizedItems();
_history->setHasPendingResizedItems();
}
} }
bool pendingInitDimensions() const { bool pendingInitDimensions() const {
return _flags & MTPDmessage_ClientFlag::f_pending_init_dimensions; return _flags & MTPDmessage_ClientFlag::f_pending_init_dimensions;
@ -535,10 +519,6 @@ public:
void makeGroupLeader(std::vector<not_null<HistoryItem*>> &&others); void makeGroupLeader(std::vector<not_null<HistoryItem*>> &&others);
HistoryMessageGroup *getFullGroup(); HistoryMessageGroup *getFullGroup();
int width() const {
return _width;
}
void clipCallback(Media::Clip::Notification notification); void clipCallback(Media::Clip::Notification notification);
void audioTrackUpdated(); void audioTrackUpdated();
@ -556,6 +536,8 @@ public:
setAttachToNext(attachToNext); setAttachToNext(attachToNext);
} }
bool isUnderCursor() const;
HistoryItem *previousItem() const; HistoryItem *previousItem() const;
HistoryItem *nextItem() const; HistoryItem *nextItem() const;
@ -586,8 +568,6 @@ protected:
const not_null<History*> _history; const not_null<History*> _history;
not_null<PeerData*> _from; not_null<PeerData*> _from;
HistoryBlock *_block = nullptr;
int _indexInBlock = -1;
MTPDmessage::Flags _flags = 0; MTPDmessage::Flags _flags = 0;
// This should be called only from previousItemChanged() // This should be called only from previousItemChanged()
@ -642,7 +622,6 @@ private:
void resetGroupMedia(const std::vector<not_null<HistoryItem*>> &others); void resetGroupMedia(const std::vector<not_null<HistoryItem*>> &others);
HistoryView::Message *_mainView = nullptr; HistoryView::Message *_mainView = nullptr;
int _width = 0;
}; };

View File

@ -398,8 +398,9 @@ struct HistoryMessageLogEntryOriginal : public RuntimeComponent<HistoryMessageLo
}; };
class FileClickHandler;
struct HistoryDocumentThumbed : public RuntimeComponent<HistoryDocumentThumbed> { struct HistoryDocumentThumbed : public RuntimeComponent<HistoryDocumentThumbed> {
ClickHandlerPtr _linksavel, _linkcancell; std::shared_ptr<FileClickHandler> _linksavel, _linkcancell;
int _thumbw = 0; int _thumbw = 0;
mutable int _linkw = 0; mutable int _linkw = 0;

View File

@ -230,10 +230,6 @@ public:
return QString(); return QString();
} }
int currentWidth() const {
return _width;
}
void setInBubbleState(MediaInBubbleState state) { void setInBubbleState(MediaInBubbleState state) {
_inBubbleState = state; _inBubbleState = state;
} }
@ -265,7 +261,6 @@ public:
protected: protected:
not_null<HistoryItem*> _parent; not_null<HistoryItem*> _parent;
int _width = 0;
MediaInBubbleState _inBubbleState = MediaInBubbleState::None; MediaInBubbleState _inBubbleState = MediaInBubbleState::None;

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item_components.h" #include "history/history_item_components.h"
#include "history/history_media_types.h" #include "history/history_media_types.h"
#include "history/history_message.h" #include "history/history_message.h"
#include "history/view/history_view_message.h"
#include "storage/storage_shared_media.h" #include "storage/storage_shared_media.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "ui/grouped_layout.h" #include "ui/grouped_layout.h"
@ -176,7 +177,7 @@ void HistoryGroupedMedia::draw(
} else if (_parent->getMedia() == this) { } else if (_parent->getMedia() == this) {
auto fullRight = _width; auto fullRight = _width;
auto fullBottom = _height; auto fullBottom = _height;
if (_parent->id < 0 || App::hoveredItem() == _parent) { if (needInfoDisplay()) {
_parent->drawInfo(p, fullRight, fullBottom, _width, selected, InfoDisplayOverImage); _parent->drawInfo(p, fullRight, fullBottom, _width, selected, InfoDisplayOverImage);
} }
if (!_parent->hasBubble() && _parent->displayRightAction()) { if (!_parent->hasBubble() && _parent->displayRightAction()) {
@ -295,7 +296,8 @@ void HistoryGroupedMedia::clickHandlerPressedChanged(
for (const auto &element : _elements) { for (const auto &element : _elements) {
element.content->clickHandlerPressedChanged(p, pressed); element.content->clickHandlerPressedChanged(p, pressed);
if (pressed && element.content->dragItemByHandler(p)) { 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; return false;
} }
bool HistoryGroupedMedia::needInfoDisplay() const {
return (_parent->id < 0 || _parent->isUnderCursor());
}

View File

@ -115,6 +115,7 @@ private:
}; };
bool needInfoDisplay() const;
bool computeNeedBubble() const; bool computeNeedBubble() const;
not_null<HistoryMedia*> main() const; not_null<HistoryMedia*> main() const;
bool validateGroupElements( bool validateGroupElements(

View File

@ -446,7 +446,7 @@ void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, Tim
} else if (notChild) { } else if (notChild) {
auto fullRight = skipx + width; auto fullRight = skipx + width;
auto fullBottom = skipy + height; auto fullBottom = skipy + height;
if (_data->uploading() || App::hoveredItem() == _parent) { if (needInfoDisplay()) {
_parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, InfoDisplayOverImage); _parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, InfoDisplayOverImage);
} }
if (!bubble && _parent->displayRightAction()) { if (!bubble && _parent->displayRightAction()) {
@ -646,6 +646,10 @@ bool HistoryPhoto::dataLoaded() const {
return _data->loaded(); return _data->loaded();
} }
bool HistoryPhoto::needInfoDisplay() const {
return (_data->uploading() || _parent->isUnderCursor());
}
void HistoryPhoto::validateGroupedCache( void HistoryPhoto::validateGroupedCache(
const QRect &geometry, const QRect &geometry,
RectParts corners, RectParts corners,
@ -1402,11 +1406,17 @@ void HistoryDocument::createComponents(bool caption) {
} }
UpdateComponents(mask); UpdateComponents(mask);
if (auto thumbed = Get<HistoryDocumentThumbed>()) { if (auto thumbed = Get<HistoryDocumentThumbed>()) {
thumbed->_linksavel = std::make_shared<DocumentSaveClickHandler>(_data); thumbed->_linksavel = std::make_shared<DocumentSaveClickHandler>(
thumbed->_linkcancell = std::make_shared<DocumentCancelClickHandler>(_data); _data,
_parent->fullId());
thumbed->_linkcancell = std::make_shared<DocumentCancelClickHandler>(
_data,
_parent->fullId());
} }
if (auto voice = Get<HistoryDocumentVoice>()) { if (auto voice = Get<HistoryDocumentVoice>()) {
voice->_seekl = std::make_shared<VoiceSeekClickHandler>(_data); voice->_seekl = std::make_shared<VoiceSeekClickHandler>(
_data,
_parent->fullId());
} }
} }
@ -2066,6 +2076,23 @@ void HistoryDocument::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool
HistoryFileMedia::clickHandlerPressedChanged(p, pressed); HistoryFileMedia::clickHandlerPressedChanged(p, pressed);
} }
void HistoryDocument::refreshParentId(not_null<HistoryItem*> realParent) {
HistoryFileMedia::refreshParentId(realParent);
const auto contextId = realParent->fullId();
if (auto thumbed = Get<HistoryDocumentThumbed>()) {
if (thumbed->_linksavel) {
thumbed->_linksavel->setMessageId(contextId);
thumbed->_linkcancell->setMessageId(contextId);
}
}
if (auto voice = Get<HistoryDocumentVoice>()) {
if (voice->_seekl) {
voice->_seekl->setMessageId(contextId);
}
}
}
bool HistoryDocument::playInline(bool autoplay) { bool HistoryDocument::playInline(bool autoplay) {
if (_data->isVoiceMessage()) { if (_data->isVoiceMessage()) {
DocumentOpenClickHandler::doOpen(_data, _parent, ActionOnLoadPlayInline); DocumentOpenClickHandler::doOpen(_data, _parent, ActionOnLoadPlayInline);
@ -2157,7 +2184,9 @@ void HistoryGif::initDimensions() {
_caption.setSkipBlock(_parent->skipBlockWidth(), _parent->skipBlockHeight()); _caption.setSkipBlock(_parent->skipBlockWidth(), _parent->skipBlockHeight());
} }
if (!_openInMediaviewLink) { if (!_openInMediaviewLink) {
_openInMediaviewLink = std::make_shared<DocumentOpenClickHandler>(_data); _openInMediaviewLink = std::make_shared<DocumentOpenClickHandler>(
_data,
_parent->fullId());
} }
int32 tw = 0, th = 0; int32 tw = 0, th = 0;
@ -2548,7 +2577,7 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM
fullRight = maxRight; fullRight = maxRight;
} }
} }
if (isRound || _data->uploading() || App::hoveredItem() == _parent) { if (isRound || needInfoDisplay()) {
_parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, isRound ? InfoDisplayOverBackground : InfoDisplayOverImage); _parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, isRound ? InfoDisplayOverBackground : InfoDisplayOverImage);
} }
if (!bubble && _parent->displayRightAction()) { if (!bubble && _parent->displayRightAction()) {
@ -2955,6 +2984,10 @@ bool HistoryGif::dataLoaded() const {
return (_parent->id > 0) ? _data->loaded() : false; return (_parent->id > 0) ? _data->loaded() : false;
} }
bool HistoryGif::needInfoDisplay() const {
return (_data->uploading() || _parent->isUnderCursor());
}
HistorySticker::HistorySticker( HistorySticker::HistorySticker(
not_null<HistoryItem*> parent, not_null<HistoryItem*> parent,
not_null<DocumentData*> document) not_null<DocumentData*> document)
@ -3835,7 +3868,7 @@ int HistoryWebPage::resizeGetHeight(int width) {
_height += _attach->height() - bubble.top() - bubble.bottom(); _height += _attach->height() - bubble.top() - bubble.bottom();
if (!_attach->additionalInfoString().isEmpty()) { if (!_attach->additionalInfoString().isEmpty()) {
_height += bottomInfoPadding(); _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(); _height += bottomInfoPadding();
} }
} }
@ -3873,7 +3906,7 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, T
bshift += bottomInfoPadding(); bshift += bottomInfoPadding();
} else if (!attachAdditionalInfoText.isEmpty()) { } else if (!attachAdditionalInfoText.isEmpty()) {
bshift += bottomInfoPadding(); 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(); bshift += bottomInfoPadding();
} }
@ -3939,13 +3972,13 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, T
auto attachLeft = padding.left() - bubble.left(); auto attachLeft = padding.left() - bubble.left();
auto attachTop = tshift - bubble.top(); auto attachTop = tshift - bubble.top();
if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth(); if (rtl()) attachLeft = _width - attachLeft - _attach->width();
p.translate(attachLeft, attachTop); p.translate(attachLeft, attachTop);
auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 }; auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 };
_attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms); _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 (_data->type == WebPageVideo && _attach->type() == MediaTypePhoto) {
if (_attach->isReadyForOpen()) { if (_attach->isReadyForOpen()) {
@ -3991,7 +4024,7 @@ HistoryTextState HistoryWebPage::getState(QPoint point, HistoryStateRequest requ
auto padding = inBubblePadding(); auto padding = inBubblePadding();
auto tshift = padding.top(); auto tshift = padding.top();
auto bshift = padding.bottom(); 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(); bshift += bottomInfoPadding();
} }
width -= padding.left() + padding.right(); 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)) { if (QRect(padding.left(), tshift, width, _height - tshift - bshift).contains(point)) {
auto attachLeft = padding.left() - bubble.left(); auto attachLeft = padding.left() - bubble.left();
auto attachTop = tshift - bubble.top(); 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); result = _attach->getState(point - QPoint(attachLeft, attachTop), request);
if (result.link && !_data->document && _data->photo && _attach->isReadyForOpen()) { 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()); _attach->resizeGetHeight(width + bubble.left() + bubble.right());
_height += _attach->height() - bubble.top() - bubble.bottom(); _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(); _height += bottomInfoPadding();
} }
} }
@ -4351,7 +4384,7 @@ void HistoryGame::draw(Painter &p, const QRect &r, TextSelection selection, Time
auto tshift = padding.top(); auto tshift = padding.top();
auto bshift = padding.bottom(); auto bshift = padding.bottom();
width -= padding.left() + padding.right(); 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(); bshift += bottomInfoPadding();
} }
@ -4383,13 +4416,13 @@ void HistoryGame::draw(Painter &p, const QRect &r, TextSelection selection, Time
auto attachLeft = padding.left() - bubble.left(); auto attachLeft = padding.left() - bubble.left();
auto attachTop = tshift - bubble.top(); 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 }; auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 };
p.translate(attachLeft, attachTop); p.translate(attachLeft, attachTop);
_attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms); _attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms);
auto pixwidth = _attach->currentWidth(); auto pixwidth = _attach->width();
auto pixheight = _attach->height(); auto pixheight = _attach->height();
auto gameW = _gameTagWidth + 2 * st::msgDateImgPadding.x(); auto gameW = _gameTagWidth + 2 * st::msgDateImgPadding.x();
@ -4419,7 +4452,7 @@ HistoryTextState HistoryGame::getState(QPoint point, HistoryStateRequest request
auto padding = inBubblePadding(); auto padding = inBubblePadding();
auto tshift = padding.top(); auto tshift = padding.top();
auto bshift = padding.bottom(); 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(); bshift += bottomInfoPadding();
} }
width -= padding.left() + padding.right(); width -= padding.left() + padding.right();
@ -4465,9 +4498,9 @@ HistoryTextState HistoryGame::getState(QPoint point, HistoryStateRequest request
auto attachLeft = padding.left() - bubble.left(); auto attachLeft = padding.left() - bubble.left();
auto attachTop = tshift - bubble.top(); 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 (_attach->isReadyForOpen()) {
if (!_parent->isLogEntry()) { if (!_parent->isLogEntry()) {
result.link = _openl; result.link = _openl;
@ -4782,7 +4815,7 @@ int HistoryInvoice::resizeGetHeight(int width) {
_attach->resizeGetHeight(width + bubble.left() + bubble.right()); _attach->resizeGetHeight(width + bubble.left() + bubble.right());
_height += _attach->height() - bubble.top() - bubble.bottom(); _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(); _height += bottomInfoPadding();
} }
} else { } else {
@ -4816,7 +4849,7 @@ void HistoryInvoice::draw(Painter &p, const QRect &r, TextSelection selection, T
auto tshift = padding.top(); auto tshift = padding.top();
auto bshift = padding.bottom(); auto bshift = padding.bottom();
width -= padding.left() + padding.right(); 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(); bshift += bottomInfoPadding();
} }
@ -4845,13 +4878,13 @@ void HistoryInvoice::draw(Painter &p, const QRect &r, TextSelection selection, T
auto attachLeft = padding.left() - bubble.left(); auto attachLeft = padding.left() - bubble.left();
auto attachTop = tshift - bubble.top(); 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 }; auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 };
p.translate(attachLeft, attachTop); p.translate(attachLeft, attachTop);
_attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms); _attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms);
auto pixwidth = _attach->currentWidth(); auto pixwidth = _attach->width();
auto pixheight = _attach->height(); auto pixheight = _attach->height();
auto available = _status.maxWidth(); auto available = _status.maxWidth();
@ -4885,7 +4918,7 @@ HistoryTextState HistoryInvoice::getState(QPoint point, HistoryStateRequest requ
auto padding = inBubblePadding(); auto padding = inBubblePadding();
auto tshift = padding.top(); auto tshift = padding.top();
auto bshift = padding.bottom(); 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(); bshift += bottomInfoPadding();
} }
width -= padding.left() + padding.right(); width -= padding.left() + padding.right();
@ -4924,9 +4957,9 @@ HistoryTextState HistoryInvoice::getState(QPoint point, HistoryStateRequest requ
auto attachLeft = padding.left() - bubble.left(); auto attachLeft = padding.left() - bubble.left();
auto attachTop = tshift - bubble.top(); 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); result = _attach->getState(point - QPoint(attachLeft, attachTop), request);
} }
} }

View File

@ -254,6 +254,7 @@ protected:
bool dataLoaded() const override; bool dataLoaded() const override;
private: private:
bool needInfoDisplay() const;
void validateGroupedCache( void validateGroupedCache(
const QRect &geometry, const QRect &geometry,
RectParts corners, RectParts corners,
@ -466,6 +467,8 @@ public:
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override; void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
void refreshParentId(not_null<HistoryItem*> realParent) override;
protected: protected:
float64 dataProgress() const override; float64 dataProgress() const override;
bool dataFinished() const override; bool dataFinished() const override;
@ -588,6 +591,7 @@ protected:
} }
private: private:
bool needInfoDisplay() const;
int additionalWidth( int additionalWidth(
const HistoryMessageVia *via, const HistoryMessageVia *via,
const HistoryMessageReply *reply, const HistoryMessageReply *reply,

View File

@ -1227,8 +1227,8 @@ bool HistoryMessage::displayFastReply() const {
QRect HistoryMessage::countGeometry() const { QRect HistoryMessage::countGeometry() const {
auto maxwidth = qMin(st::msgMaxWidth, _maxw); auto maxwidth = qMin(st::msgMaxWidth, _maxw);
if (_media && _media->currentWidth() < maxwidth) { if (_media && _media->width() < maxwidth) {
maxwidth = qMax(_media->currentWidth(), qMin(maxwidth, plainMaxWidth())); maxwidth = qMax(_media->width(), qMin(maxwidth, plainMaxWidth()));
} }
const auto outLayout = hasOutLayout(); const auto outLayout = hasOutLayout();
@ -1904,7 +1904,7 @@ void HistoryMessage::paintFromName(
return 0; return 0;
}(); }();
const auto replyWidth = [&] { const auto replyWidth = [&] {
if (App::hoveredItem() == this && displayFastReply()) { if (isUnderCursor() && displayFastReply()) {
return st::msgFont->width(FastReplyText()); return st::msgFont->width(FastReplyText());
} }
return 0; return 0;
@ -2364,7 +2364,7 @@ bool HistoryMessage::getStateFromName(
not_null<HistoryTextState*> outResult) const { not_null<HistoryTextState*> outResult) const {
if (displayFromName()) { if (displayFromName()) {
const auto replyWidth = [&] { const auto replyWidth = [&] {
if (App::hoveredItem() == this && displayFastReply()) { if (isUnderCursor() && displayFastReply()) {
return st::msgFont->width(FastReplyText()); return st::msgFont->width(FastReplyText());
} }
return 0; return 0;

View File

@ -550,7 +550,7 @@ int HistoryService::resizeContentGetHeight() {
} }
_height += st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom(); _height += st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom();
if (_media) { if (_media) {
_height += st::msgServiceMargin.top() + _media->resizeGetHeight(_media->currentWidth()); _height += st::msgServiceMargin.top() + _media->resizeGetHeight(_media->width());
} }
} }

View File

@ -628,7 +628,7 @@ HistoryWidget::HistoryWidget(QWidget *parent, not_null<Window::Controller*> cont
})); }));
subscribe(Auth().data().pendingHistoryResize(), [this] { handlePendingHistoryUpdate(); }); subscribe(Auth().data().pendingHistoryResize(), [this] { handlePendingHistoryUpdate(); });
subscribe(Auth().data().queryItemVisibility(), [this](const Data::Session::ItemVisibilityQuery &query) { 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; return;
} }
auto top = _list->itemTop(query.item); auto top = _list->itemTop(query.item);
@ -642,9 +642,7 @@ HistoryWidget::HistoryWidget(QWidget *parent, not_null<Window::Controller*> cont
Auth().data().itemLayoutChanged( Auth().data().itemLayoutChanged(
) | rpl::start_with_next([this](auto item) { ) | rpl::start_with_next([this](auto item) {
if (_peer && _list) { if (_peer && _list) {
if ((item == App::mousedItem()) if (item->isUnderCursor()) {
|| (item == App::hoveredItem())
|| (item == App::hoveredLinkItem())) {
_list->onUpdateSelected(); _list->onUpdateSelected();
} }
} }
@ -804,7 +802,7 @@ void HistoryWidget::adjustHighlightedMessageToMigrated() {
_history->channelId(), _history->channelId(),
_highlightedMessageId); _highlightedMessageId);
if (highlighted && highlighted->isGroupMigrate()) { 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(); auto msgId = _highlightQueue.front();
_highlightQueue.pop_front(); _highlightQueue.pop_front();
auto item = getItemFromHistoryOrMigrated(msgId); auto item = getItemFromHistoryOrMigrated(msgId);
if (item && !item->detached()) { if (item && item->mainView()) {
return msgId; return msgId;
} }
} }
@ -832,7 +830,7 @@ void HistoryWidget::checkNextHighlight() {
void HistoryWidget::updateHighlightedMessage() { void HistoryWidget::updateHighlightedMessage() {
auto item = getItemFromHistoryOrMigrated(_highlightedMessageId); auto item = getItemFromHistoryOrMigrated(_highlightedMessageId);
if (!item || item->detached()) { if (!item || !item->mainView()) {
return stopMessageHighlight(); return stopMessageHighlight();
} }
auto duration = st::activeFadeInDuration + st::activeFadeOutDuration; auto duration = st::activeFadeInDuration + st::activeFadeOutDuration;
@ -1440,8 +1438,7 @@ void HistoryWidget::clearReplyReturns() {
_replyReturn = 0; _replyReturn = 0;
} }
void HistoryWidget::pushReplyReturn(HistoryItem *item) { void HistoryWidget::pushReplyReturn(not_null<HistoryItem*> item) {
if (!item) return;
if (item->history() == _history) { if (item->history() == _history) {
_replyReturns.push_back(item->id); _replyReturns.push_back(item->id);
} else if (item->history() == _migrated) { } else if (item->history() == _migrated) {
@ -1707,13 +1704,6 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
_nonEmptySelection = false; _nonEmptySelection = false;
_topBar->showSelected(HistoryView::TopBarWidget::SelectedState {}); _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) { if (_peer) {
App::forgetMedia(); App::forgetMedia();
_serviceImageCacheSize = imageCacheSize(); _serviceImageCacheSize = imageCacheSize();
@ -2424,7 +2414,7 @@ bool HistoryWidget::doWeReadServerHistory() const {
if (scrollTop + 1 > _scroll->scrollTopMax()) return true; if (scrollTop + 1 > _scroll->scrollTopMax()) return true;
auto showFrom = (_migrated && _migrated->showFrom) ? _migrated->showFrom : (_history ? _history->showFrom : nullptr); auto showFrom = (_migrated && _migrated->showFrom) ? _migrated->showFrom : (_history ? _history->showFrom : nullptr);
if (showFrom && !showFrom->detached()) { if (showFrom && showFrom->mainView()) {
int scrollBottom = scrollTop + _scroll->height(); int scrollBottom = scrollTop + _scroll->height();
if (scrollBottom > _list->itemTop(showFrom)) return true; if (scrollBottom > _list->itemTop(showFrom)) return true;
} }
@ -2445,7 +2435,7 @@ bool HistoryWidget::doWeReadMentions() const {
} }
bool HistoryWidget::historyHasNotFreezedUnreadBar(History *history) 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<HistoryMessageUnreadBar>()) { if (auto unreadBar = history->unreadBar->Get<HistoryMessageUnreadBar>()) {
return !unreadBar->_freezed; return !unreadBar->_freezed;
} }
@ -2675,7 +2665,7 @@ void HistoryWidget::visibleAreaUpdated() {
_list->visibleAreaUpdated(scrollTop, scrollBottom); _list->visibleAreaUpdated(scrollTop, scrollBottom);
if (_history->loadedAtBottom() && (_history->unreadCount() > 0 || (_migrated && _migrated->unreadCount() > 0))) { if (_history->loadedAtBottom() && (_history->unreadCount() > 0 || (_migrated && _migrated->unreadCount() > 0))) {
auto showFrom = (_migrated && _migrated->showFrom) ? _migrated->showFrom : (_history ? _history->showFrom : nullptr); 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()); auto atBottom = (scrollTop >= _scroll->scrollTopMax());
if ((showFromVisible || atBottom) && App::wnd()->doWeReadServerHistory()) { if ((showFromVisible || atBottom) && App::wnd()->doWeReadServerHistory()) {
Auth().api().readServerHistory(_history); Auth().api().readServerHistory(_history);
@ -2727,14 +2717,14 @@ void HistoryWidget::checkReplyReturns() {
auto scrollTopMax = _scroll->scrollTopMax(); auto scrollTopMax = _scroll->scrollTopMax();
auto scrollHeight = _scroll->height(); auto scrollHeight = _scroll->height();
while (_replyReturn) { 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) { if (!below) {
below = (_replyReturn->detached() && _replyReturn->history() == _migrated && !_history->isEmpty()); below = (!_replyReturn->mainView() && _replyReturn->history() == _migrated && !_history->isEmpty());
} }
if (!below) { 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); below = (scrollTop >= scrollTopMax) || (_list->itemTop(_replyReturn) < scrollTop + scrollHeight / 2);
} }
if (below) { if (below) {
@ -3424,7 +3414,7 @@ bool HistoryWidget::insertBotCommand(const QString &cmd) {
auto insertingInlineBot = !cmd.isEmpty() && (cmd.at(0) == '@'); auto insertingInlineBot = !cmd.isEmpty() && (cmd.at(0) == '@');
auto toInsert = cmd; auto toInsert = cmd;
if (!toInsert.isEmpty() && !insertingInlineBot) { 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)) { if (bot && (!bot->isUser() || !bot->asUser()->botInfo)) {
bot = nullptr; bot = nullptr;
} }
@ -4951,7 +4941,7 @@ void HistoryWidget::updateHistoryDownVisibility() {
if (!_list || !history || history->unreadCount() <= 0) { if (!_list || !history || history->unreadCount() <= 0) {
return false; return false;
} }
if (!history->showFrom || history->showFrom->detached()) { if (!history->showFrom || !history->showFrom->mainView()) {
return false; return false;
} }
return (_list->itemTop(history->showFrom) >= _scroll->scrollTop() + _scroll->height()); return (_list->itemTop(history->showFrom) >= _scroll->scrollTop() + _scroll->height());
@ -5052,41 +5042,34 @@ void HistoryWidget::keyPressEvent(QKeyEvent *e) {
_scroll->keyPressEvent(e); _scroll->keyPressEvent(e);
} else if ((e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier)) == Qt::ControlModifier) { } else if ((e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier)) == Qt::ControlModifier) {
if (_history && _history->lastMsg && !_editMsgId) { if (_history && _history->lastMsg && !_editMsgId) {
if (_replyToId) { if (const auto item = App::histItemById(_history->channelId(), _replyToId)) {
HistoryItem *item = App::histItemById(_history->channelId(), _replyToId)->nextItem(); if (const auto next = item->nextItem()) {
if (item) App::contextItem(item); Ui::showPeerHistory(_peer, next->id);
else { cancelReply(); return; } replyToMessage(next);
} else { }
return;
} }
Ui::showPeerHistory(_peer, App::contextItem()->id);
onReplyToMessage();
return;
} }
} }
} else if (e->key() == Qt::Key_Up) { } else if (e->key() == Qt::Key_Up) {
if (!(e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier))) { if (!(e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier))) {
if (_history && _history->lastSentMsg && _history->lastSentMsg->canEdit(::date(unixtime()))) { if (_history && _history->lastSentMsg && _history->lastSentMsg->canEdit(::date(unixtime()))) {
if (_field->isEmpty() && !_editMsgId && !_replyToId) { if (_field->isEmpty() && !_editMsgId && !_replyToId && _history->lastSentMsg) {
App::contextItem(_history->lastSentMsg); editMessage(_history->lastSentMsg);
onEditMessage();
return; return;
} }
} }
_scroll->keyPressEvent(e); _scroll->keyPressEvent(e);
} else if ((e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier)) == Qt::ControlModifier) { } else if ((e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier)) == Qt::ControlModifier) {
if (_history && _history->lastMsg && !_editMsgId) { if (_history && _history->lastMsg && !_editMsgId) {
if (_replyToId) { if (const auto item = App::histItemById(_history->channelId(), _replyToId)) {
HistoryItem *item = App::histItemById(_history->channelId(), _replyToId); if (const auto previous = item->previousItem()) {
App::contextItem(item->previousItem()); Ui::showPeerHistory(_peer, previous->id);
} else { replyToMessage(previous);
App::contextItem(_history->lastMsg); }
} 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) { } 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(); _previewLinks.clear();
} }
void HistoryWidget::onReplyToMessage() { void HistoryWidget::replyToMessage(FullMsgId itemId) {
auto to = App::contextItem(); if (const auto item = App::histItemById(itemId)) {
if (!to || to->id <= 0 || !_canSendMessages) return; replyToMessage(item);
}
}
if (to->history() == _migrated) { void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) {
if (to->isGroupMigrate() && !_history->isEmpty() && _history->blocks.front()->messages.front()->data()->isGroupMigrate() && _history != _migrated) { if (!IsServerMsgId(item->id) || !_canSendMessages) {
App::contextItem(_history->blocks.front()->messages.front()->data()); return;
onReplyToMessage(); }
App::contextItem(to); 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 { } else {
if (to->id < 0 || to->serviceMsg()) { if (item->serviceMsg()) {
Ui::show(Box<InformBox>(lang(lng_reply_cant))); Ui::show(Box<InformBox>(lang(lng_reply_cant)));
} else { } else {
Ui::show(Box<ConfirmBox>(lang(lng_reply_cant_forward), lang(lng_selected_forward), base::lambda_guarded(this, [this] { const auto itemId = item->fullId();
auto item = App::contextItem(); Ui::show(Box<ConfirmBox>(lang(lng_reply_cant_forward), lang(lng_selected_forward), base::lambda_guarded(this, [=] {
if (!item || item->id < 0 || item->serviceMsg()) return;
App::main()->setForwardDraft( App::main()->setForwardDraft(
_peer->id, _peer->id,
{ 1, item->fullId() }); { 1, itemId });
}))); })));
} }
} }
@ -5547,13 +5535,17 @@ void HistoryWidget::onReplyToMessage() {
if (_editMsgId) { if (_editMsgId) {
if (auto localDraft = _history->localDraft()) { if (auto localDraft = _history->localDraft()) {
localDraft->msgId = to->id; localDraft->msgId = item->id;
} else { } else {
_history->setLocalDraft(std::make_unique<Data::Draft>(TextWithTags(), to->id, MessageCursor(), false)); _history->setLocalDraft(std::make_unique<Data::Draft>(
TextWithTags(),
item->id,
MessageCursor(),
false));
} }
} else { } else {
_replyEditMsg = to; _replyEditMsg = item;
_replyToId = to->id; _replyToId = item->id;
_replyEditMsgText.setText( _replyEditMsgText.setText(
st::messageTextStyle, st::messageTextStyle,
TextUtilities::Clean(_replyEditMsg->inReplyText()), TextUtilities::Clean(_replyEditMsg->inReplyText()),
@ -5575,13 +5567,16 @@ void HistoryWidget::onReplyToMessage() {
_field->setFocus(); _field->setFocus();
} }
void HistoryWidget::onEditMessage() { void HistoryWidget::editMessage(FullMsgId itemId) {
auto to = App::contextItem(); if (const auto item = App::histItemById(itemId)) {
if (!to) return; editMessage(item);
}
}
if (auto media = to->getMedia()) { void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
if (const auto media = item->getMedia()) {
if (media->canEditCaption()) { if (media->canEditCaption()) {
Ui::show(Box<EditCaptionBox>(media, to->fullId())); Ui::show(Box<EditCaptionBox>(media, item->fullId()));
return; return;
} }
} }
@ -5598,14 +5593,25 @@ void HistoryWidget::onEditMessage() {
} }
} }
auto original = to->originalText(); const auto original = item->originalText();
auto editData = TextWithTags { TextUtilities::ApplyEntities(original), ConvertEntitiesToTextTags(original.entities) }; const auto editData = TextWithTags {
auto cursor = MessageCursor { editData.text.size(), editData.text.size(), QFIXED_MAX }; TextUtilities::ApplyEntities(original),
_history->setEditDraft(std::make_unique<Data::Draft>(editData, to->id, cursor, false)); ConvertEntitiesToTextTags(original.entities)
};
const auto cursor = MessageCursor {
editData.text.size(),
editData.text.size(),
QFIXED_MAX
};
_history->setEditDraft(std::make_unique<Data::Draft>(
editData,
item->id,
cursor,
false));
applyDraft(false); applyDraft(false);
_previewData = nullptr; _previewData = nullptr;
if (auto media = to->getMedia()) { if (const auto media = item->getMedia()) {
if (media->type() == MediaTypeWebPage) { if (media->type() == MediaTypeWebPage) {
_previewData = static_cast<HistoryWebPage*>(media)->webpage(); _previewData = static_cast<HistoryWebPage*>(media)->webpage();
updatePreview(); updatePreview();
@ -5631,22 +5637,23 @@ void HistoryWidget::onEditMessage() {
_field->setFocus(); _field->setFocus();
} }
void HistoryWidget::onPinMessage() { void HistoryWidget::pinMessage(FullMsgId itemId) {
auto to = App::contextItem(); if (const auto item = App::histItemById(itemId)) {
if (!to || !to->canPin()) return; if (item->canPin()) {
const auto channel = item->history()->peer->asChannel();
Ui::show(Box<PinMessageBox>( Assert(channel != nullptr);
to->history()->peer->asChannel(), Ui::show(Box<PinMessageBox>(channel, item->id));
to->id)); }
}
} }
void HistoryWidget::onUnpinMessage() { void HistoryWidget::unpinMessage(FullMsgId itemId) {
if (!_peer || !_peer->isChannel()) return; const auto channel = _peer ? _peer->asChannel() : nullptr;
if (!channel) {
Ui::show(Box<ConfirmBox>(lang(lng_pinned_unpin_sure), lang(lng_pinned_unpin), base::lambda_guarded(this, [this] { return;
auto channel = _peer ? _peer->asChannel() : nullptr; }
if (!channel) return;
Ui::show(Box<ConfirmBox>(lang(lng_pinned_unpin_sure), lang(lng_pinned_unpin), base::lambda_guarded(this, [=] {
channel->clearPinnedMessage(); channel->clearPinnedMessage();
Ui::hideLayer(); Ui::hideLayer();
@ -5666,8 +5673,8 @@ void HistoryWidget::unpinDone(const MTPUpdates &updates) {
} }
void HistoryWidget::onPinnedHide() { void HistoryWidget::onPinnedHide() {
auto channel = _peer ? _peer->asChannel() : nullptr; const auto channel = _peer ? _peer->asChannel() : nullptr;
auto pinnedId = channel->pinnedMessageId(); const auto pinnedId = channel ? channel->pinnedMessageId() : MsgId(0);
if (!pinnedId) { if (!pinnedId) {
if (pinnedMsgVisibilityUpdated()) { if (pinnedMsgVisibilityUpdated()) {
updateControlsGeometry(); updateControlsGeometry();
@ -5677,9 +5684,9 @@ void HistoryWidget::onPinnedHide() {
} }
if (channel->canPinMessages()) { if (channel->canPinMessages()) {
onUnpinMessage(); unpinMessage(FullMsgId(peerToChannel(channel->id), pinnedId));
} else { } else {
Global::RefHiddenPinnedMessages().insert(_peer->id, pinnedId); Global::RefHiddenPinnedMessages().insert(channel->id, pinnedId);
Local::writeUserSettings(); Local::writeUserSettings();
if (pinnedMsgVisibilityUpdated()) { if (pinnedMsgVisibilityUpdated()) {
updateControlsGeometry(); updateControlsGeometry();
@ -5688,11 +5695,12 @@ void HistoryWidget::onPinnedHide() {
} }
} }
void HistoryWidget::onCopyPostLink() { void HistoryWidget::copyPostLink(FullMsgId itemId) {
auto item = App::contextItem(); if (const auto item = App::histItemById(itemId)) {
if (!item || !item->hasDirectLink()) return; if (item->hasDirectLink()) {
QApplication::clipboard()->setText(item->directLink());
QApplication::clipboard()->setText(item->directLink()); }
}
} }
bool HistoryWidget::lastForceReplyReplied(const FullMsgId &replyTo) const { bool HistoryWidget::lastForceReplyReplied(const FullMsgId &replyTo) const {
@ -6076,10 +6084,7 @@ void HistoryWidget::onForwardSelected() {
void HistoryWidget::confirmDeleteSelectedItems() { void HistoryWidget::confirmDeleteSelectedItems() {
if (!_list) return; if (!_list) return;
auto selected = _list->getSelectedItems(); App::main()->deleteLayer(_list->getSelectedItems());
if (selected.empty()) return;
App::main()->deleteLayer(int(selected.size()));
} }
void HistoryWidget::deleteSelectedItems(bool forEveryone) { void HistoryWidget::deleteSelectedItems(bool forEveryone) {

View File

@ -250,6 +250,14 @@ public:
void updateScrollColors(); void updateScrollColors();
void replyToMessage(FullMsgId itemId);
void replyToMessage(not_null<HistoryItem*> item);
void editMessage(FullMsgId itemId);
void editMessage(not_null<HistoryItem*> item);
void pinMessage(FullMsgId itemId);
void unpinMessage(FullMsgId itemId);
void copyPostLink(FullMsgId itemId);
MsgId replyToId() const; MsgId replyToId() const;
void messageDataReceived(ChannelData *channel, MsgId msgId); void messageDataReceived(ChannelData *channel, MsgId msgId);
bool lastForceReplyReplied(const FullMsgId &replyTo) const; bool lastForceReplyReplied(const FullMsgId &replyTo) const;
@ -260,7 +268,7 @@ public:
void updateForwardingTexts(); void updateForwardingTexts();
void clearReplyReturns(); void clearReplyReturns();
void pushReplyReturn(HistoryItem *item); void pushReplyReturn(not_null<HistoryItem*> item);
QList<MsgId> replyReturns(); QList<MsgId> replyReturns();
void setReplyReturns(PeerId peer, const QList<MsgId> &replyReturns); void setReplyReturns(PeerId peer, const QList<MsgId> &replyReturns);
void calcNextReplyReturn(); void calcNextReplyReturn();
@ -361,12 +369,7 @@ signals:
public slots: public slots:
void onCancel(); void onCancel();
void onReplyToMessage();
void onEditMessage();
void onPinMessage();
void onUnpinMessage();
void onPinnedHide(); void onPinnedHide();
void onCopyPostLink();
void onFieldBarCancel(); void onFieldBarCancel();
void onPreviewParse(); void onPreviewParse();

View File

@ -466,13 +466,13 @@ void ListWidget::checkMoveToOtherViewer() {
QString ListWidget::tooltipText() const { QString ListWidget::tooltipText() const {
if (_mouseCursorState == HistoryInDateCursorState && _mouseAction == MouseAction::None) { if (_mouseCursorState == HistoryInDateCursorState && _mouseAction == MouseAction::None) {
if (const auto item = App::hoveredItem()) { if (const auto view = App::hoveredItem()) {
auto dateText = item->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat)); auto dateText = view->data()->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat));
return dateText; return dateText;
} }
} else if (_mouseCursorState == HistoryInForwardedCursorState && _mouseAction == MouseAction::None) { } else if (_mouseCursorState == HistoryInForwardedCursorState && _mouseAction == MouseAction::None) {
if (const auto item = App::hoveredItem()) { if (const auto view = App::hoveredItem()) {
if (const auto forwarded = item->Get<HistoryMessageForwarded>()) { if (const auto forwarded = view->data()->Get<HistoryMessageForwarded>()) {
return forwarded->text.originalText(AllTextSelection, ExpandLinksNone); return forwarded->text.originalText(AllTextSelection, ExpandLinksNone);
} }
} }
@ -724,10 +724,6 @@ void ListWidget::contextMenuEvent(QContextMenuEvent *e) {
} }
void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (_menu) {
_menu->deleteLater();
_menu = 0;
}
if (e->reason() == QContextMenuEvent::Mouse) { if (e->reason() == QContextMenuEvent::Mouse) {
mouseActionUpdate(e->globalPos()); mouseActionUpdate(e->globalPos());
} }
@ -742,10 +738,12 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
auto selTo = _selectedText.to; auto selTo = _selectedText.to;
hasSelected = (selTo > selFrom) ? 1 : 0; hasSelected = (selTo > selFrom) ? 1 : 0;
if (App::mousedItem() && App::mousedItem() == App::hoveredItem()) { if (App::mousedItem() && App::mousedItem() == App::hoveredItem()) {
auto mousePos = mapPointToItem(mapFromGlobal(_mousePosition), viewForItem(App::mousedItem())); auto mousePos = mapPointToItem(
mapFromGlobal(_mousePosition),
App::mousedItem());
HistoryStateRequest request; HistoryStateRequest request;
request.flags |= Text::StateRequest::Flag::LookupSymbol; 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) { if (dragState.cursor == HistoryInTextCursorState && dragState.symbol >= selFrom && dragState.symbol < selTo) {
isUponSelected = 1; isUponSelected = 1;
} }
@ -755,10 +753,12 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
isUponSelected = hasSelected; isUponSelected = hasSelected;
} }
_menu = new Ui::PopupMenu(nullptr); _menu = base::make_unique_q<Ui::PopupMenu>(nullptr);
_contextMenuLink = ClickHandler::getActive(); _contextMenuLink = ClickHandler::getActive();
auto item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem(); auto view = App::hoveredItem()
? App::hoveredItem()
: App::hoveredLinkItem();
auto lnkPhoto = dynamic_cast<PhotoClickHandler*>(_contextMenuLink.get()); auto lnkPhoto = dynamic_cast<PhotoClickHandler*>(_contextMenuLink.get());
auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLink.get()); auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLink.get());
auto lnkPeer = dynamic_cast<PeerClickHandler*>(_contextMenuLink.get()); auto lnkPeer = dynamic_cast<PeerClickHandler*>(_contextMenuLink.get());
@ -767,39 +767,50 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
auto lnkIsAudio = lnkDocument ? lnkDocument->document()->isAudioFile() : false; auto lnkIsAudio = lnkDocument ? lnkDocument->document()->isAudioFile() : false;
if (lnkPhoto || lnkDocument) { if (lnkPhoto || lnkDocument) {
if (isUponSelected > 0) { 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) { 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); savePhotoToFile(photo);
}))->setEnabled(true); }))->setEnabled(true);
_menu->addAction(lang(lng_context_copy_image), [this, photo = lnkPhoto->photo()] { _menu->addAction(lang(lng_context_copy_image), [=] {
copyContextImage(photo); copyContextImage(photo);
})->setEnabled(true); })->setEnabled(true);
} else { } else {
auto document = lnkDocument->document(); auto document = lnkDocument->document();
if (document->loading()) { 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 { } else {
if (document->loaded() && document->isGifv()) { if (document->loaded() && document->isGifv()) {
if (!cAutoPlayGif()) { 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()) { 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] { _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); saveDocumentToFile(document);
}))->setEnabled(true); }))->setEnabled(true);
} }
} }
if (App::hoveredLinkItem()) {
App::contextItem(App::hoveredLinkItem());
}
} else if (lnkPeer) { // suggest to block } else if (lnkPeer) { // suggest to block
// #TODO suggest restrict peer // #TODO suggest restrict peer
} else { // maybe cursor on some text history item? } 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 canDelete = item && item->canDelete() && (item->id > 0 || !item->serviceMsg());
bool canForward = item && item->canForward(); bool canForward = item && item->canForward();
@ -817,7 +828,9 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (media->type() == MediaTypeSticker) { if (media->type() == MediaTypeSticker) {
if (auto document = media->getDocument()) { if (auto document = media->getDocument()) {
if (document->sticker() && document->sticker()->set.type() != mtpc_inputStickerSetEmpty) { 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] { _menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] {
saveDocumentToFile(document); saveDocumentToFile(document);
@ -826,15 +839,21 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
} else if (media->type() == MediaTypeGif && !_contextMenuLink) { } else if (media->type() == MediaTypeGif && !_contextMenuLink) {
if (auto document = media->getDocument()) { if (auto document = media->getDocument()) {
if (document->loading()) { 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 { } else {
if (document->isGifv()) { if (document->isGifv()) {
if (!cAutoPlayGif()) { 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()) { 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] { _menu->addAction(lang(lng_context_save_file), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] {
saveDocumentToFile(document); saveDocumentToFile(document);
@ -844,7 +863,9 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
} }
} }
if (msg && !_contextMenuLink && (!msg->emptyText() || mediaHasTextForCopy)) { 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()) { if (!linkCopyToClipboardText.isEmpty()) {
_menu->addAction(linkCopyToClipboardText, [this] { copyContextUrl(); })->setEnabled(true); _menu->addAction(linkCopyToClipboardText, [this] { copyContextUrl(); })->setEnabled(true);
} }
App::contextItem(item);
} }
if (_menu->actions().isEmpty()) { if (_menu->actions().isEmpty()) {
delete base::take(_menu); _menu = nullptr;
} else { } else {
connect(_menu, &QObject::destroyed, this, [this](QObject *object) {
if (_menu == object) {
_menu = nullptr;
}
});
_menu->popup(e->globalPos()); _menu->popup(e->globalPos());
e->accept(); e->accept();
} }
@ -873,11 +888,15 @@ void ListWidget::savePhotoToFile(PhotoData *photo) {
if (!photo || !photo->date || !photo->loaded()) return; if (!photo || !photo->date || !photo->loaded()) return;
auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter(); 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) { FileDialog::GetWritePath(
if (!result.isEmpty()) { lang(lng_save_photo),
photo->full->pix().toImage().save(result, "JPG"); 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) { void ListWidget::saveDocumentToFile(DocumentData *document) {
@ -900,50 +919,28 @@ void ListWidget::copyContextUrl() {
} }
} }
void ListWidget::showStickerPackInfo() { void ListWidget::showStickerPackInfo(not_null<DocumentData*> document) {
if (!App::contextItem()) return; if (auto sticker = document->sticker()) {
if (sticker->set.type() != mtpc_inputStickerSetEmpty) {
if (auto media = App::contextItem()->getMedia()) { App::main()->stickersBox(sticker->set);
if (auto doc = media->getDocument()) {
if (auto sticker = doc->sticker()) {
if (sticker->set.type() != mtpc_inputStickerSetEmpty) {
App::main()->stickersBox(sticker->set);
}
}
} }
} }
} }
void ListWidget::cancelContextDownload() { void ListWidget::cancelContextDownload(not_null<DocumentData*> document) {
if (auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLink.get())) { document->cancel();
lnkDocument->document()->cancel();
} else if (auto item = App::contextItem()) {
if (auto media = item->getMedia()) {
if (auto doc = media->getDocument()) {
doc->cancel();
}
}
}
} }
void ListWidget::showContextInFolder() { void ListWidget::showContextInFolder(not_null<DocumentData*> document) {
QString filepath; const auto filepath = document->filepath(
if (auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLink.get())) { DocumentData::FilePathResolveChecked);
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);
}
}
}
if (!filepath.isEmpty()) { if (!filepath.isEmpty()) {
File::ShowInFolder(filepath); File::ShowInFolder(filepath);
} }
} }
void ListWidget::openContextGif() { void ListWidget::openContextGif(FullMsgId itemId) {
if (auto item = App::contextItem()) { if (const auto item = App::histItemById(itemId)) {
if (auto media = item->getMedia()) { if (auto media = item->getMedia()) {
if (auto document = media->getDocument()) { if (auto document = media->getDocument()) {
Messenger::Instance().showDocument(document, item); Messenger::Instance().showDocument(document, item);
@ -952,16 +949,20 @@ void ListWidget::openContextGif() {
} }
} }
void ListWidget::copyContextText() { void ListWidget::copyContextText(FullMsgId itemId) {
auto item = App::contextItem(); if (const auto item = App::histItemById(itemId)) {
if (!item || (item->getMedia() && item->getMedia()->type() == MediaTypeSticker)) { if (const auto media = item->getMedia()) {
return; 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)) { if (auto data = MimeDataFromTextWithEntities(forClipboard)) {
QApplication::clipboard()->setMimeData(data.release(), mode); QApplication::clipboard()->setMimeData(data.release(), mode);
} }
@ -996,8 +997,8 @@ void ListWidget::enterEventHook(QEvent *e) {
} }
void ListWidget::leaveEventHook(QEvent *e) { void ListWidget::leaveEventHook(QEvent *e) {
if (auto item = App::hoveredItem()) { if (const auto view = App::hoveredItem()) {
repaintItem(viewForItem(item)); repaintItem(view);
App::hoveredItem(nullptr); App::hoveredItem(nullptr);
} }
ClickHandler::clearActive(); ClickHandler::clearActive();
@ -1015,13 +1016,13 @@ void ListWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butto
ClickHandler::pressed(); ClickHandler::pressed();
if (App::pressedItem() != App::hoveredItem()) { if (App::pressedItem() != App::hoveredItem()) {
repaintItem(viewForItem(App::pressedItem())); repaintItem(App::pressedItem());
App::pressedItem(App::hoveredItem()); App::pressedItem(App::hoveredItem());
repaintItem(viewForItem(App::pressedItem())); repaintItem(App::pressedItem());
} }
_mouseAction = MouseAction::None; _mouseAction = MouseAction::None;
_mouseActionItem = viewForItem(App::mousedItem()); _mouseActionItem = App::mousedItem();
_dragStartPosition = mapPointToItem(mapFromGlobal(screenPos), _mouseActionItem); _dragStartPosition = mapPointToItem(mapFromGlobal(screenPos), _mouseActionItem);
_pressWasInactive = _controller->window()->wasInactivePress(); _pressWasInactive = _controller->window()->wasInactivePress();
if (_pressWasInactive) _controller->window()->setInactivePress(false); if (_pressWasInactive) _controller->window()->setInactivePress(false);
@ -1102,8 +1103,8 @@ void ListWidget::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton butt
if (_mouseAction == MouseAction::Dragging) { if (_mouseAction == MouseAction::Dragging) {
activated = nullptr; activated = nullptr;
} }
if (App::pressedItem()) { if (const auto view = App::pressedItem()) {
repaintItem(viewForItem(App::pressedItem())); repaintItem(view);
App::pressedItem(nullptr); App::pressedItem(nullptr);
} }
@ -1144,23 +1145,25 @@ void ListWidget::updateSelected() {
const auto view = strictFindItemByY(point.y()); const auto view = strictFindItemByY(point.y());
const auto item = view ? view->data().get() : nullptr; const auto item = view ? view->data().get() : nullptr;
if (view) { if (view) {
App::mousedItem(item); App::mousedItem(view);
itemPoint = mapPointToItem(point, view); itemPoint = mapPointToItem(point, view);
if (item->hasPoint(itemPoint)) { if (item->hasPoint(itemPoint)) {
if (App::hoveredItem() != item) { if (App::hoveredItem() != view) {
repaintItem(viewForItem(App::hoveredItem())); repaintItem(App::hoveredItem());
App::hoveredItem(item); App::hoveredItem(view);
repaintItem(view); repaintItem(view);
} }
} else if (App::hoveredItem()) { } else if (const auto view = App::hoveredItem()) {
repaintItem(viewForItem(App::hoveredItem())); repaintItem(view);
App::hoveredItem(nullptr); App::hoveredItem(nullptr);
} }
} }
HistoryTextState dragState; HistoryTextState dragState;
ClickHandlerHost *lnkhost = nullptr; ClickHandlerHost *lnkhost = nullptr;
auto selectingText = (view == _mouseActionItem && item == App::hoveredItem() && _selectedItem); auto selectingText = _selectedItem
&& (view == _mouseActionItem)
&& (view == App::hoveredItem());
if (view) { if (view) {
if (view != _mouseActionItem || (itemPoint - _dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) { if (view != _mouseActionItem || (itemPoint - _dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) {
if (_mouseAction == MouseAction::PrepareDrag) { if (_mouseAction == MouseAction::PrepareDrag) {
@ -1246,14 +1249,9 @@ void ListWidget::updateSelected() {
} }
// Voice message seek support. // Voice message seek support.
if (auto pressedItem = App::pressedLinkItem()) { if (const auto pressedView = App::pressedLinkItem()) {
if (!pressedItem->detached()) { auto adjustedPoint = mapPointToItem(point, pressedView);
// #TODO seek support pressedView->data()->updatePressed(adjustedPoint);
//if (pressedItem->history() == _history) {
// auto adjustedPoint = mapPointToItem(point, pressedItem);
// pressedItem->updatePressed(adjustedPoint);
//}
}
} }
//if (_mouseAction == MouseAction::Selecting) { //if (_mouseAction == MouseAction::Selecting) {

View File

@ -160,12 +160,12 @@ private:
void savePhotoToFile(PhotoData *photo); void savePhotoToFile(PhotoData *photo);
void saveDocumentToFile(DocumentData *document); void saveDocumentToFile(DocumentData *document);
void copyContextImage(PhotoData *photo); void copyContextImage(PhotoData *photo);
void showStickerPackInfo(); void showStickerPackInfo(not_null<DocumentData*> document);
void copyContextUrl(); void copyContextUrl();
void cancelContextDownload(); void cancelContextDownload(not_null<DocumentData*> document);
void showContextInFolder(); void showContextInFolder(not_null<DocumentData*> document);
void openContextGif(); void openContextGif(FullMsgId itemId);
void copyContextText(); void copyContextText(FullMsgId itemId);
void copySelectedText(); void copySelectedText();
TextWithEntities getSelectedText() const; TextWithEntities getSelectedText() const;
void setToClipboard( void setToClipboard(
@ -254,8 +254,7 @@ private:
bool _wasSelectedText = false; // was some text selected in current drag action bool _wasSelectedText = false; // was some text selected in current drag action
Qt::CursorShape _cursor = style::cur_default; Qt::CursorShape _cursor = style::cur_default;
// context menu base::unique_qptr<Ui::PopupMenu> _menu;
Ui::PopupMenu *_menu = nullptr;
QPoint _trippleClickPoint; QPoint _trippleClickPoint;
base::Timer _trippleClickTimer; base::Timer _trippleClickTimer;

View File

@ -14,12 +14,56 @@ Message::Message(not_null<HistoryItem*> data, Context context)
, _context(context) { , _context(context) {
} }
MsgId Message::id() const {
return _data->id;
}
not_null<HistoryItem*> Message::data() const { not_null<HistoryItem*> Message::data() const {
return _data; return _data;
} }
void Message::attachToBlock(not_null<HistoryBlock*> 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 } // namespace HistoryView

View File

@ -23,7 +23,6 @@ class Message
public: public:
Message(not_null<HistoryItem*> data, Context context); Message(not_null<HistoryItem*> data, Context context);
MsgId id() const;
not_null<HistoryItem*> data() const; not_null<HistoryItem*> data() const;
int y() const { int y() const {
@ -33,11 +32,39 @@ public:
_y = y; _y = y;
} }
HistoryBlock *block() {
return _block;
}
const HistoryBlock *block() const {
return _block;
}
void attachToBlock(not_null<HistoryBlock*> 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: private:
const not_null<HistoryItem*> _data; const not_null<HistoryItem*> _data;
int _y = 0; int _y = 0;
Context _context; Context _context;
HistoryBlock *_block = nullptr;
int _indexInBlock = -1;
}; };
} // namespace HistoryView } // namespace HistoryView

View File

@ -596,17 +596,19 @@ bool MainWidget::setForwardDraft(PeerId peerId, ForwardWhatMessages what) {
return _history->getSelectedItems(); return _history->getSelectedItems();
} }
auto item = (HistoryItem*)nullptr; auto item = (HistoryItem*)nullptr;
if (what == ForwardContextMessage) { if (what == ForwardPressedMessage) {
item = App::contextItem(); item = App::pressedItem()
} else if (what == ForwardPressedMessage) { ? App::pressedItem()->data().get()
item = App::pressedItem(); : nullptr;
if (const auto group = item ? item->getFullGroup() : nullptr) { if (const auto group = item ? item->getFullGroup() : nullptr) {
if (item->id > 0) { if (item->id > 0) {
return Auth().data().groupToIds(group); return Auth().data().groupToIds(group);
} }
} }
} else if (what == ForwardPressedLinkMessage) { } else if (what == ForwardPressedLinkMessage) {
item = App::pressedLinkItem(); item = App::pressedLinkItem()
? App::pressedLinkItem()->data().get()
: nullptr;
} }
if (item && item->toHistoryMessage() && item->id > 0) { if (item && item->toHistoryMessage() && item->id > 0) {
return { 1, item->fullId() }; return { 1, item->fullId() };
@ -677,8 +679,7 @@ bool MainWidget::shareUrl(
void MainWidget::replyToItem(not_null<HistoryItem*> item) { void MainWidget::replyToItem(not_null<HistoryItem*> item) {
if (_history->peer() == item->history()->peer if (_history->peer() == item->history()->peer
|| _history->peer() == item->history()->peer->migrateTo()) { || _history->peer() == item->history()->peer->migrateTo()) {
App::contextItem(item); _history->replyToMessage(item);
_history->onReplyToMessage();
} }
} }
@ -932,24 +933,20 @@ void MainWidget::showSendPathsLayer() {
hiderLayer(object_ptr<HistoryHider>(this)); hiderLayer(object_ptr<HistoryHider>(this));
} }
void MainWidget::deleteLayer(int selectedCount) { void MainWidget::deleteLayer(MessageIdsList &&items) {
if (selectedCount) { if (!items.empty()) {
auto selected = _history->getSelectedItems(); Ui::show(Box<DeleteMessagesBox>(std::move(items)));
if (!selected.empty()) { }
Ui::show(Box<DeleteMessagesBox>(std::move(selected))); }
}
} else if (const auto item = App::contextItem()) { void MainWidget::deleteLayer(FullMsgId itemId) {
if (const auto item = App::histItemById(itemId)) {
const auto suggestModerateActions = true; const auto suggestModerateActions = true;
Ui::show(Box<DeleteMessagesBox>(item, suggestModerateActions)); Ui::show(Box<DeleteMessagesBox>(item, suggestModerateActions));
} }
} }
void MainWidget::cancelUploadLayer() { void MainWidget::cancelUploadLayer(not_null<HistoryItem*> item) {
auto item = App::contextItem();
if (!item) {
return;
}
const auto itemId = item->fullId(); const auto itemId = item->fullId();
Auth().uploader().pause(itemId); Auth().uploader().pause(itemId);
Ui::show(Box<ConfirmBox>(lang(lng_selected_cancel_sure_this), lang(lng_selected_upload_stop), lang(lng_continue), base::lambda_guarded(this, [=] { Ui::show(Box<ConfirmBox>(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); _history->updateBotKeyboard(h);
} }
void MainWidget::pushReplyReturn(HistoryItem *item) { void MainWidget::pushReplyReturn(not_null<HistoryItem*> item) {
_history->pushReplyReturn(item); _history->pushReplyReturn(item);
} }
@ -4931,7 +4928,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
const auto newId = d.vid.v; const auto newId = d.vid.v;
if (const auto local = App::histItemById(fullId)) { if (const auto local = App::histItemById(fullId)) {
const auto existing = App::histItemById(channel, newId); const auto existing = App::histItemById(channel, newId);
if (existing && local->detached()) { if (existing && !local->mainView()) {
const auto history = local->history(); const auto history = local->history();
const auto wasLast = (history->lastMsg == local); const auto wasLast = (history->lastMsg == local);
local->destroy(); local->destroy();

View File

@ -168,8 +168,9 @@ public:
void showForwardLayer(MessageIdsList &&items); void showForwardLayer(MessageIdsList &&items);
void showSendPathsLayer(); void showSendPathsLayer();
void deleteLayer(int selectedCount = 0); // 0 - context item void deleteLayer(MessageIdsList &&items);
void cancelUploadLayer(); void deleteLayer(FullMsgId itemId);
void cancelUploadLayer(not_null<HistoryItem*> item);
void shareUrlLayer(const QString &url, const QString &text); void shareUrlLayer(const QString &url, const QString &text);
void inlineSwitchLayer(const QString &botAndQuery); void inlineSwitchLayer(const QString &botAndQuery);
void hiderLayer(object_ptr<HistoryHider> h); void hiderLayer(object_ptr<HistoryHider> h);
@ -272,7 +273,7 @@ public:
void messageDataReceived(ChannelData *channel, MsgId msgId); void messageDataReceived(ChannelData *channel, MsgId msgId);
void updateBotKeyboard(History *h); void updateBotKeyboard(History *h);
void pushReplyReturn(HistoryItem *item); void pushReplyReturn(not_null<HistoryItem*> item);
void cancelForwarding(not_null<History*> history); void cancelForwarding(not_null<History*> history);
void finishForwarding(not_null<History*> history); void finishForwarding(not_null<History*> history);

View File

@ -1003,8 +1003,10 @@ void MediaView::onForward() {
void MediaView::onDelete() { void MediaView::onDelete() {
close(); close();
auto deletingPeerPhoto = [this]() { const auto deletingPeerPhoto = [this] {
if (!_msgid) return true; if (!_msgid) {
return true;
}
if (_photo && _history) { if (_photo && _history) {
if (_history->peer->userpicPhotoId() == _photo->id) { if (_history->peer->userpicPhotoId() == _photo->id) {
return _firstOpenedPeerPhoto; return _firstOpenedPeerPhoto;
@ -1015,9 +1017,8 @@ void MediaView::onDelete() {
if (deletingPeerPhoto()) { if (deletingPeerPhoto()) {
App::main()->deletePhotoLayer(_photo); App::main()->deletePhotoLayer(_photo);
} else if (auto item = App::histItemById(_msgid)) { } else {
App::contextItem(item); App::main()->deleteLayer(_msgid);
App::main()->deleteLayer();
} }
} }

View File

@ -120,7 +120,8 @@ ItemBase::ItemBase(not_null<HistoryItem*> parent) : _parent(parent) {
void ItemBase::clickHandlerActiveChanged( void ItemBase::clickHandlerActiveChanged(
const ClickHandlerPtr &action, const ClickHandlerPtr &action,
bool active) { bool active) {
App::hoveredLinkItem(active ? _parent.get() : nullptr); // #TODO hoveredLinkItem
// App::hoveredLinkItem(active ? _parent.get() : nullptr);
Auth().data().requestItemRepaint(_parent); Auth().data().requestItemRepaint(_parent);
if (_check) { if (_check) {
_check->setActive(active); _check->setActive(active);
@ -130,7 +131,8 @@ void ItemBase::clickHandlerActiveChanged(
void ItemBase::clickHandlerPressedChanged( void ItemBase::clickHandlerPressedChanged(
const ClickHandlerPtr &action, const ClickHandlerPtr &action,
bool pressed) { bool pressed) {
App::pressedLinkItem(pressed ? _parent.get() : nullptr); // #TODO pressedLinkItem
// App::pressedLinkItem(pressed ? _parent.get() : nullptr);
Auth().data().requestItemRepaint(_parent); Auth().data().requestItemRepaint(_parent);
if (_check) { if (_check) {
_check->setPressed(pressed); _check->setPressed(pressed);
@ -172,18 +174,25 @@ ItemBase::~ItemBase() = default;
void RadialProgressItem::setDocumentLinks( void RadialProgressItem::setDocumentLinks(
not_null<DocumentData*> document) { not_null<DocumentData*> document) {
auto createSaveHandler = []( const auto context = parent()->fullId();
not_null<DocumentData*> document const auto createSaveHandler = [&]() -> ClickHandlerPtr {
) -> ClickHandlerPtr {
if (document->isVoiceMessage()) { if (document->isVoiceMessage()) {
return std::make_shared<DocumentOpenClickHandler>(document); return std::make_shared<DocumentOpenClickHandler>(
document,
context);
} }
return std::make_shared<DocumentSaveClickHandler>(document); return std::make_shared<DocumentSaveClickHandler>(
document,
context);
}; };
setLinks( setLinks(
std::make_shared<DocumentOpenClickHandler>(document), std::make_shared<DocumentOpenClickHandler>(
createSaveHandler(document), document,
std::make_shared<DocumentCancelClickHandler>(document)); context),
createSaveHandler(),
std::make_shared<DocumentCancelClickHandler>(
document,
context));
} }
void RadialProgressItem::clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) { void RadialProgressItem::clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) {
@ -539,7 +548,7 @@ Voice::Voice(
const style::OverviewFileLayout &st) const style::OverviewFileLayout &st)
: RadialProgressItem(parent) : RadialProgressItem(parent)
, _data(voice) , _data(voice)
, _namel(std::make_shared<DocumentOpenClickHandler>(_data)) , _namel(std::make_shared<DocumentOpenClickHandler>(_data, parent->fullId()))
, _st(st) { , _st(st) {
AddComponents(Info::Bit()); AddComponents(Info::Bit());
@ -784,7 +793,7 @@ Document::Document(
: RadialProgressItem(parent) : RadialProgressItem(parent)
, _data(document) , _data(document)
, _msgl(goToMessageClickHandler(parent)) , _msgl(goToMessageClickHandler(parent))
, _namel(std::make_shared<DocumentOpenClickHandler>(_data)) , _namel(std::make_shared<DocumentOpenClickHandler>(_data, parent->fullId()))
, _st(st) , _st(st)
, _date(langDateTime(date(_data->date))) , _date(langDateTime(date(_data->date)))
, _datew(st::normalFont->width(_date)) , _datew(st::normalFont->width(_date))
@ -1205,7 +1214,9 @@ Link::Link(
if (_page) { if (_page) {
mainUrl = _page->url; mainUrl = _page->url;
if (_page->document) { if (_page->document) {
_photol = std::make_shared<DocumentOpenClickHandler>(_page->document); _photol = std::make_shared<DocumentOpenClickHandler>(
_page->document,
parent->fullId());
} else if (_page->photo) { } else if (_page->photo) {
if (_page->type == WebPageProfile || _page->type == WebPageVideo) { if (_page->type == WebPageProfile || _page->type == WebPageVideo) {
_photol = std::make_shared<UrlClickHandler>(_page->url); _photol = std::make_shared<UrlClickHandler>(_page->url);