From 599ede9a0b01f7b43e516f70dbd48cce684e614e Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 25 Mar 2016 14:29:45 +0300 Subject: [PATCH] Beta 9034004 version: Some lang grammar fixes, all "audio" changed to "voice message" PeerData can have three loaded states (not loaded, minimal, full) Interface/Interfaces renamed to Component/Composer HistoryReply moved to a Component named HistoryMessageReply --- Telegram/Resources/lang.strings | 35 +- Telegram/SourceFiles/app.cpp | 86 +- Telegram/SourceFiles/app.h | 54 +- Telegram/SourceFiles/boxes/addcontactbox.cpp | 11 +- Telegram/SourceFiles/config.h | 2 +- Telegram/SourceFiles/gui/text.cpp | 53 +- Telegram/SourceFiles/gui/text.h | 10 +- Telegram/SourceFiles/history.cpp | 1017 ++++++++---------- Telegram/SourceFiles/history.h | 327 +++--- Telegram/SourceFiles/historywidget.cpp | 13 +- Telegram/SourceFiles/layout.cpp | 21 +- Telegram/SourceFiles/layout.h | 27 +- Telegram/SourceFiles/localstorage.cpp | 14 +- Telegram/SourceFiles/mainwidget.cpp | 16 +- Telegram/SourceFiles/overviewwidget.cpp | 5 +- Telegram/SourceFiles/structs.cpp | 18 +- Telegram/SourceFiles/structs.h | 129 ++- Telegram/SourceFiles/types.cpp | 49 +- Telegram/SourceFiles/types.h | 171 +-- Telegram/SourceFiles/window.cpp | 6 +- Telegram/Telegram.rc | 8 +- Telegram/Version | 2 +- 22 files changed, 1036 insertions(+), 1038 deletions(-) diff --git a/Telegram/Resources/lang.strings b/Telegram/Resources/lang.strings index 942d92582..c5b317fdd 100644 --- a/Telegram/Resources/lang.strings +++ b/Telegram/Resources/lang.strings @@ -663,9 +663,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_stickers_count" = "{count:Loading...|# sticker|# stickers}"; "lng_in_dlg_photo" = "Photo"; -"lng_in_dlg_video" = "Video"; +"lng_in_dlg_video" = "Video file"; +"lng_in_dlg_audio_file" = "Audio file"; "lng_in_dlg_contact" = "Contact"; -"lng_in_dlg_audio" = "Audio"; +"lng_in_dlg_audio" = "Voice message"; "lng_in_dlg_file" = "File"; "lng_in_dlg_sticker" = "Sticker"; "lng_in_dlg_sticker_emoji" = "{emoji} (sticker)"; @@ -720,28 +721,29 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_user_typing" = "{user} is typing"; "lng_users_typing" = "{user} and {second_user} are typing"; "lng_many_typing" = "{count:_not_used_|# is|# are} typing"; -"lng_send_action_record_video" = "recording video"; +"lng_send_action_record_video" = "recording a video"; "lng_user_action_record_video" = "{user} is recording a video"; -"lng_send_action_upload_video" = "sending video"; +"lng_send_action_upload_video" = "sending a video"; "lng_user_action_upload_video" = "{user} is sending a video"; -"lng_send_action_record_audio" = "recording audio"; -"lng_user_action_record_audio" = "{user} is recording an audio"; -"lng_send_action_upload_audio" = "sending audio"; -"lng_user_action_upload_audio" = "{user} is sending an audio"; -"lng_send_action_upload_photo" = "sending photo"; +"lng_send_action_record_audio" = "recording a voice message"; +"lng_user_action_record_audio" = "{user} is recording a voice message"; +"lng_send_action_upload_audio" = "sending a voice message"; +"lng_user_action_upload_audio" = "{user} is sending a voice message"; +"lng_send_action_upload_photo" = "sending a photo"; "lng_user_action_upload_photo" = "{user} is sending a photo"; -"lng_send_action_upload_file" = "sending file"; +"lng_send_action_upload_file" = "sending a file"; "lng_user_action_upload_file" = "{user} is sending a file"; -"lng_send_action_geo_location" = "picking location"; +"lng_send_action_geo_location" = "picking a location"; "lng_user_action_geo_location" = "{user} is picking a location"; -"lng_send_action_choose_contact" = "choosing contact"; +"lng_send_action_choose_contact" = "choosing a contact"; "lng_user_action_choose_contact" = "{user} is choosing a contact"; "lng_unread_bar" = "{count:_not_used_|# unread message|# unread messages}"; "lng_maps_point" = "Location"; "lng_save_photo" = "Save image"; -"lng_save_video" = "Save video"; -"lng_save_audio" = "Save audio"; +"lng_save_video" = "Save video file"; +"lng_save_audio_file" = "Save audio file"; +"lng_save_audio" = "Save voice message"; "lng_save_file" = "Save file"; "lng_save_downloaded" = "{ready} / {total} {mb}"; "lng_duration_and_size" = "{duration}, {size}"; @@ -766,8 +768,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_context_cancel_download" = "Cancel Download"; "lng_context_show_in_folder" = "Show in Folder"; "lng_context_show_in_finder" = "Show in Finder"; -"lng_context_save_video" = "Save Video As..."; -"lng_context_save_audio" = "Save Audio As..."; +"lng_context_save_video" = "Save Video File As..."; +"lng_context_save_audio_file" = "Save Audio File As..."; +"lng_context_save_audio" = "Save Voice Message As..."; "lng_context_pack_info" = "Pack Info"; "lng_context_pack_add" = "Add Stickers"; "lng_context_save_file" = "Save File As..."; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index e9d2bbe5c..407ea84e9 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -478,7 +478,13 @@ namespace App { if (!data) continue; - data->loaded = true; + if (minimal) { + if (data->loadedStatus == PeerData::NotLoaded) { + data->loadedStatus = PeerData::MinimalLoaded; + } + } else if (data->loadedStatus != PeerData::FullLoaded) { + data->loadedStatus = PeerData::FullLoaded; + } if (status && !minimal) switch (status->type()) { case mtpc_userStatusEmpty: data->onlineTill = 0; break; case mtpc_userStatusRecently: @@ -655,7 +661,13 @@ namespace App { } if (!data) continue; - data->loaded = true; + if (minimal) { + if (data->loadedStatus == PeerData::NotLoaded) { + data->loadedStatus = PeerData::MinimalLoaded; + } + } else if (data->loadedStatus != PeerData::FullLoaded) { + data->loadedStatus = PeerData::FullLoaded; + } if (App::main()) { if (emitPeerUpdated) { App::main()->peerUpdated(data); @@ -1000,7 +1012,7 @@ namespace App { } void checkSavedGif(HistoryItem *item) { - if (!item->Is() && (item->out() || item->history()->peer == App::self())) { + if (!item->Has() && (item->out() || item->history()->peer == App::self())) { if (HistoryMedia *media = item->getMedia()) { if (DocumentData *doc = media->getDocument()) { if (doc->isGifv()) { @@ -1394,41 +1406,16 @@ namespace App { return 0; } - PeerData *peerLoaded(const PeerId &peer) { - PeersData::const_iterator i = peersData.constFind(peer); - return (i != peersData.cend()) ? i.value() : 0; - } - - UserData *userLoaded(const PeerId &id) { - PeerData *peer = peerLoaded(id); - return (peer && peer->loaded) ? peer->asUser() : 0; - } - ChatData *chatLoaded(const PeerId &id) { - PeerData *peer = peerLoaded(id); - return (peer && peer->loaded) ? peer->asChat() : 0; - } - ChannelData *channelLoaded(const PeerId &id) { - PeerData *peer = peerLoaded(id); - return (peer && peer->loaded) ? peer->asChannel() : 0; - } - UserData *userLoaded(int32 user_id) { - return userLoaded(peerFromUser(user_id)); - } - ChatData *chatLoaded(int32 chat_id) { - return chatLoaded(peerFromChat(chat_id)); - } - ChannelData *channelLoaded(int32 channel_id) { - return channelLoaded(peerFromChannel(channel_id)); - } - UserData *curUser() { return user(MTP::authedId()); } - PeerData *peer(const PeerId &id) { - PeersData::const_iterator i = peersData.constFind(id); + PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction) { + if (!id) return nullptr; + + auto i = peersData.constFind(id); if (i == peersData.cend()) { - PeerData *newData = 0; + PeerData *newData = nullptr; if (peerIsUser(id)) { newData = new UserData(id); } else if (peerIsChat(id)) { @@ -1436,33 +1423,26 @@ namespace App { } else if (peerIsChannel(id)) { newData = new ChannelData(id); } - if (!newData) return 0; + t_assert(newData != nullptr); newData->input = MTPinputPeer(MTP_inputPeerEmpty()); i = peersData.insert(id, newData); } + switch (restriction) { + case PeerData::MinimalLoaded: { + if (i.value()->loadedStatus == PeerData::NotLoaded) { + return nullptr; + } + } break; + case PeerData::FullLoaded: { + if (i.value()->loadedStatus != PeerData::FullLoaded) { + return nullptr; + } + } break; + } return i.value(); } - UserData *user(const PeerId &id) { - return peer(id)->asUser(); - } - ChatData *chat(const PeerId &id) { - return peer(id)->asChat(); - } - ChannelData *channel(const PeerId &id) { - return peer(id)->asChannel(); - } - UserData *user(int32 user_id) { - return user(peerFromUser(user_id)); - } - ChatData *chat(int32 chat_id) { - return chat(peerFromChat(chat_id)); - } - ChannelData *channel(int32 channel_id) { - return channel(peerFromChannel(channel_id)); - } - UserData *self() { return ::self; } diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 77bd4e5b6..ebe1711e5 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -110,21 +110,47 @@ namespace App { WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert = 0); WebPageData *feedWebPage(const MTPWebPage &webpage); - PeerData *peerLoaded(const PeerId &id); - UserData *userLoaded(const PeerId &id); - ChatData *chatLoaded(const PeerId &id); - ChannelData *channelLoaded(const PeerId &id); - UserData *userLoaded(int32 user); - ChatData *chatLoaded(int32 chat); - ChannelData *channelLoaded(int32 channel); + PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded); + inline UserData *user(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { + return asUser(peer(id, restriction)); + } + inline ChatData *chat(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { + return asChat(peer(id, restriction)); + } + inline ChannelData *channel(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { + return asChannel(peer(id, restriction)); + } + inline UserData *user(UserId userId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { + return asUser(peer(peerFromUser(userId), restriction)); + } + inline ChatData *chat(ChatId chatId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { + return asChat(peer(peerFromChat(chatId), restriction)); + } + inline ChannelData *channel(ChannelId channelId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { + return asChannel(peer(peerFromChannel(channelId), restriction)); + } + inline PeerData *peerLoaded(const PeerId &id) { + return peer(id, PeerData::FullLoaded); + } + inline UserData *userLoaded(const PeerId &id) { + return user(id, PeerData::FullLoaded); + } + inline ChatData *chatLoaded(const PeerId &id) { + return chat(id, PeerData::FullLoaded); + } + inline ChannelData *channelLoaded(const PeerId &id) { + return channel(id, PeerData::FullLoaded); + } + inline UserData *userLoaded(UserId userId) { + return user(userId, PeerData::FullLoaded); + } + inline ChatData *chatLoaded(ChatId chatId) { + return chat(chatId, PeerData::FullLoaded); + } + inline ChannelData *channelLoaded(ChannelId channelId) { + return channel(channelId, PeerData::FullLoaded); + } - PeerData *peer(const PeerId &id); - UserData *user(const PeerId &id); - ChatData *chat(const PeerId &id); - ChannelData *channel(const PeerId &id); - UserData *user(int32 user_id); - ChatData *chat(int32 chat_id); - ChannelData *channel(int32 channel_id); UserData *self(); PeerData *peerByName(const QString &username); QString peerName(const PeerData *peer, bool forDialogs = false); diff --git a/Telegram/SourceFiles/boxes/addcontactbox.cpp b/Telegram/SourceFiles/boxes/addcontactbox.cpp index b3e1c85c7..53d9e5d80 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.cpp +++ b/Telegram/SourceFiles/boxes/addcontactbox.cpp @@ -224,18 +224,15 @@ void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) { App::feedUsers(d.vusers); const QVector &v(d.vimported.c_vector().v); - int32 uid = 0; + UserData *user = nullptr; if (!v.isEmpty()) { const MTPDimportedContact &c(v.front().c_importedContact()); if (c.vclient_id.v != _contactId) return; - uid = c.vuser_id.v; - if (uid && !App::userLoaded(uid)) { - uid = 0; - } + user = App::userLoaded(c.vuser_id.v); } - if (uid) { - Notify::userIsContactChanged(App::userLoaded(peerFromUser(uid)), true); + if (user) { + Notify::userIsContactChanged(user, true); Ui::hideLayer(); } else { _save.hide(); diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 758dee907..6aad20f74 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org static const int32 AppVersion = 9034; static const wchar_t *AppVersionStr = L"0.9.34"; static const bool DevVersion = false; -#define BETA_VERSION (9034003ULL) // just comment this line to build public version +#define BETA_VERSION (9034004ULL) // just comment this line to build public version static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)"; static const wchar_t *AppName = L"Telegram Desktop"; diff --git a/Telegram/SourceFiles/gui/text.cpp b/Telegram/SourceFiles/gui/text.cpp index 30eab680e..f350a1f3e 100644 --- a/Telegram/SourceFiles/gui/text.cpp +++ b/Telegram/SourceFiles/gui/text.cpp @@ -2534,20 +2534,32 @@ Text::Text(style::font font, const QString &text, const TextParseOptions &option } } -Text::Text(const Text &other) : -_minResizeWidth(other._minResizeWidth), _maxWidth(other._maxWidth), -_minHeight(other._minHeight), -_text(other._text), -_font(other._font), -_blocks(other._blocks.size()), -_links(other._links), -_startDir(other._startDir) -{ +Text::Text(const Text &other) +: _minResizeWidth(other._minResizeWidth) +, _maxWidth(other._maxWidth) +, _minHeight(other._minHeight) +, _text(other._text) +, _font(other._font) +, _blocks(other._blocks.size()) +, _links(other._links) +, _startDir(other._startDir) { for (int32 i = 0, l = _blocks.size(); i < l; ++i) { _blocks[i] = other._blocks.at(i)->clone(); } } +Text::Text(Text &&other) +: _minResizeWidth(other._minResizeWidth) +, _maxWidth(other._maxWidth) +, _minHeight(other._minHeight) +, _text(other._text) +, _font(other._font) +, _blocks(other._blocks) +, _links(other._links) +, _startDir(other._startDir) { + other.clearFields(); +} + Text &Text::operator=(const Text &other) { _minResizeWidth = other._minResizeWidth; _maxWidth = other._maxWidth; @@ -2563,10 +2575,23 @@ Text &Text::operator=(const Text &other) { return *this; } +Text &Text::operator=(Text &&other) { + _minResizeWidth = other._minResizeWidth; + _maxWidth = other._maxWidth; + _minHeight = other._minHeight; + _text = other._text; + _font = other._font; + _blocks = other._blocks; + _links = other._links; + _startDir = other._startDir; + other.clearFields(); + return *this; +} + void Text::setText(style::font font, const QString &text, const TextParseOptions &options) { if (!_textStyle) _initDefault(); _font = font; - clean(); + clear(); { TextParser parser(this, text, options); } @@ -2644,7 +2669,7 @@ void Text::recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir) { void Text::setMarkedText(style::font font, const QString &text, const EntitiesInText &entities, const TextParseOptions &options) { if (!_textStyle) _initDefault(); _font = font; - clean(); + clear(); { // QString newText; // utf16 of the text for emoji // newText.reserve(8 * text.size()); @@ -3216,10 +3241,14 @@ EntitiesInText Text::originalEntities() const { return result; } -void Text::clean() { +void Text::clear() { for (TextBlocks::iterator i = _blocks.begin(), e = _blocks.end(); i != e; ++i) { delete *i; } + clearFields(); +} + +void Text::clearFields() { _blocks.clear(); _links.clear(); _maxWidth = _minHeight = 0; diff --git a/Telegram/SourceFiles/gui/text.h b/Telegram/SourceFiles/gui/text.h index d78f20cf5..7cb1e23a0 100644 --- a/Telegram/SourceFiles/gui/text.h +++ b/Telegram/SourceFiles/gui/text.h @@ -598,7 +598,9 @@ public: Text(int32 minResizeWidth = QFIXED_MAX); Text(style::font font, const QString &text, const TextParseOptions &options = _defaultOptions, int32 minResizeWidth = QFIXED_MAX, bool richText = false); Text(const Text &other); + Text(Text &&other); Text &operator=(const Text &other); + Text &operator=(Text &&other); int32 countWidth(int32 width) const; int32 countHeight(int32 width) const; @@ -686,15 +688,19 @@ public: return true; } - void clean(); + void clear(); ~Text() { - clean(); + clear(); } private: void recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir = Qt::LayoutDirectionAuto); + // clear() deletes all blocks and calls this method + // it is also called from move constructor / assignment operator + void clearFields(); + QFixed _minResizeWidth, _maxWidth; int32 _minHeight; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index fd5a698d1..b04fb0b06 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -75,12 +75,6 @@ namespace { _webpageDescriptionOptions.maxh = st::webPageDescriptionFont->height * 3; } - inline HistoryReply *toHistoryReply(HistoryItem *item) { - return item ? item->toHistoryReply() : 0; - } - inline const HistoryReply *toHistoryReply(const HistoryItem *item) { - return item ? item->toHistoryReply() : 0; - } inline const TextParseOptions &itemTextOptions(HistoryItem *item) { return itemTextOptions(item->history(), item->author()); } @@ -1235,7 +1229,7 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, switch (msg.type()) { case mtpc_messageEmpty: - result = HistoryServiceMessage::create(this, msg.c_messageEmpty().vid.v, date(), lang(lng_message_empty)); + result = HistoryService::create(this, msg.c_messageEmpty().vid.v, date(), lang(lng_message_empty)); break; case mtpc_message: { @@ -1287,15 +1281,11 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, QString text(lng_message_unsupported(lt_link, qsl("https://desktop.telegram.org"))); EntitiesInText entities = textParseEntities(text, _historyTextNoMonoOptions.flags); entities.push_front(EntityInText(EntityInTextItalic, 0, text.size())); - result = HistoryMessage::create(this, m.vid.v, m.vflags.v, m.vvia_bot_id.v, date(m.vdate), m.vfrom_id.v, text, entities); + result = HistoryMessage::create(this, m.vid.v, m.vflags.v, m.vreply_to_msg_id.v, m.vvia_bot_id.v, date(m.vdate), m.vfrom_id.v, text, entities); } else if (badMedia) { - result = HistoryServiceMessage::create(this, m.vid.v, date(m.vdate), lang(lng_message_empty), m.vflags.v, nullptr, m.has_from_id() ? m.vfrom_id.v : 0); + result = HistoryService::create(this, m.vid.v, date(m.vdate), lang(lng_message_empty), m.vflags.v, nullptr, m.has_from_id() ? m.vfrom_id.v : 0); } else { - if (m.has_reply_to_msg_id() && m.vreply_to_msg_id.v > 0) { - result = HistoryReply::create(this, m); - } else { - result = HistoryMessage::create(this, m); - } + result = HistoryMessage::create(this, m); if (m.has_reply_markup()) { App::feedReplyMarkup(channelId(), msgId, m.vreply_markup); } @@ -1304,7 +1294,7 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, case mtpc_messageService: { const MTPDmessageService &d(msg.c_messageService()); - result = HistoryServiceMessage::create(this, d); + result = HistoryService::create(this, d); if (applyServiceAction) { const MTPmessageAction &action(d.vaction); @@ -1424,12 +1414,12 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, peer->asChat()->flags |= MTPDchat::Flag::f_deactivated; //const MTPDmessageActionChatMigrateTo &d(action.c_messageActionChatMigrateTo()); - //PeerData *channel = App::peerLoaded(peerFromChannel(d.vchannel_id)); + //PeerData *channel = App::channelLoaded(d.vchannel_id.v); } break; case mtpc_messageActionChannelMigrateFrom: { //const MTPDmessageActionChannelMigrateFrom &d(action.c_messageActionChannelMigrateFrom()); - //PeerData *chat = App::peerLoaded(peerFromChat(d.vchat_id)); + //PeerData *chat = App::chatLoaded(d.vchat_id.v); } break; case mtpc_messageActionPinMessage: { @@ -1455,21 +1445,15 @@ HistoryItem *History::createItemForwarded(MsgId id, MTPDmessage::Flags flags, QD } HistoryItem *History::createItemDocument(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption) { - if ((flags & MTPDmessage::Flag::f_reply_to_msg_id) && replyTo > 0) { - return HistoryReply::create(this, id, flags, viaBotId, replyTo, date, from, doc, caption); - } - return HistoryMessage::create(this, id, flags, viaBotId, date, from, doc, caption); + return HistoryMessage::create(this, id, flags, replyTo, viaBotId, date, from, doc, caption); } HistoryItem *History::createItemPhoto(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption) { - if ((flags & MTPDmessage::Flag::f_reply_to_msg_id) && replyTo > 0) { - return HistoryReply::create(this, id, flags, viaBotId, replyTo, date, from, photo, caption); - } - return HistoryMessage::create(this, id, flags, viaBotId, date, from, photo, caption); + return HistoryMessage::create(this, id, flags, replyTo, viaBotId, date, from, photo, caption); } HistoryItem *History::addNewService(MsgId msgId, QDateTime date, const QString &text, MTPDmessage::Flags flags, HistoryMedia *media, bool newMsg) { - return addNewItem(HistoryServiceMessage::create(this, msgId, date, text, flags, media), newMsg); + return addNewItem(HistoryService::create(this, msgId, date, text, flags, media), newMsg); } HistoryItem *History::addNewMessage(const MTPMessage &msg, NewMessageType type) { @@ -2723,9 +2707,6 @@ void HistoryDependentItemCallback::call(ChannelData *channel, MsgId msgId) const } } -HistoryMessageUnreadBar::HistoryMessageUnreadBar(Interfaces*) : _width(0), _freezed(false) { -} - void HistoryMessageUnreadBar::init(int count) { if (_freezed) return; _text = lng_unread_bar(lt_count, count); @@ -2752,9 +2733,6 @@ void HistoryMessageUnreadBar::paint(Painter &p, int y, int w) const { p.drawText((w - _width) / 2, y + (st::unreadBarHeight - st::lineWidth - st::unreadBarFont->height) / 2 + st::unreadBarFont->ascent, _text); } -HistoryMessageDate::HistoryMessageDate(Interfaces*) : _width(0) { -} - void HistoryMessageDate::init(const QDateTime &date) { _text = langDayOfMonthFull(date.date()); _width = st::msgServiceFont->width(_text); @@ -2835,13 +2813,13 @@ void HistoryItem::detachFast() { void HistoryItem::previousItemChanged() { if (displayDate()) { - if (!Is()) { - AddInterfaces(HistoryMessageDate::Bit()); + if (!Has()) { + AddComponents(HistoryMessageDate::Bit()); Get()->init(date); setPendingInitDimensions(); } - } else if (Is()) { - RemoveInterfaces(HistoryMessageDate::Bit()); + } else if (Has()) { + RemoveComponents(HistoryMessageDate::Bit()); setPendingInitDimensions(); } @@ -2850,7 +2828,7 @@ void HistoryItem::previousItemChanged() { void HistoryItem::recountAttachToPrevious() { bool attach = false; - if (!isPost() && !Is() && !Is()) { + if (!isPost() && !Has() && !Has()) { if (HistoryItem *prev = previous()) { attach = !prev->isPost() && !prev->serviceMsg() && prev->from() == from() && qAbs(prev->date.secsTo(date)) < AttachMessageToPreviousSecondsDelta; } @@ -2875,7 +2853,7 @@ bool HistoryItem::canEdit(const QDateTime &cur) const { if (!channel || id < 0 || date.secsTo(cur) >= Global::EditTimeLimit()) return false; if (const HistoryMessage *msg = toHistoryMessage()) { - if (msg->Is() || msg->Is()) return false; + if (msg->Has() || msg->Has()) return false; if (HistoryMedia *media = msg->getMedia()) { HistoryMediaType t = media->type(); @@ -2898,8 +2876,8 @@ bool HistoryItem::canEdit(const QDateTime &cur) const { } void HistoryItem::destroyUnreadBar() { - if (Is()) { - RemoveInterfaces(HistoryMessageUnreadBar::Bit()); + if (Has()) { + RemoveComponents(HistoryMessageUnreadBar::Bit()); setPendingInitDimensions(); if (_history->unreadBar == this) { _history->unreadBar = nullptr; @@ -2912,8 +2890,8 @@ void HistoryItem::destroyUnreadBar() { void HistoryItem::setUnreadBarCount(int count) { if (count > 0) { HistoryMessageUnreadBar *bar; - if (!Is()) { - AddInterfaces(HistoryMessageUnreadBar::Bit()); + if (!Has()) { + AddComponents(HistoryMessageUnreadBar::Bit()); setPendingInitDimensions(); recountAttachToPrevious(); @@ -3795,15 +3773,15 @@ void HistoryDocumentVoice::ensurePlayback(const HistoryDocument *that) const { void HistoryDocumentVoice::checkPlaybackFinished() const { if (_playback && !_playback->_a_progress.animating()) { delete _playback; - _playback = 0; + _playback = nullptr; } } HistoryDocument::HistoryDocument(DocumentData *document, const QString &caption, const HistoryItem *parent) : HistoryFileMedia() -, _parent(0) +, _parent(nullptr) , _data(document) { createInterfaces(!caption.isEmpty()); - if (HistoryDocumentNamed *named = Get()) { + if (auto *named = Get()) { named->_name = documentName(_data); named->_namew = st::semiboldFont->width(named->_name); } @@ -3812,21 +3790,21 @@ HistoryDocument::HistoryDocument(DocumentData *document, const QString &caption, setStatusSize(FileStatusSizeReady); - if (HistoryDocumentCaptioned *captioned = Get()) { + if (auto *captioned = Get()) { captioned->_caption.setText(st::msgFont, caption + parent->skipBlock(), itemTextNoMonoOptions(parent)); } } HistoryDocument::HistoryDocument(const HistoryDocument &other) : HistoryFileMedia() -, Interfaces() -, _parent(0) +, Composer() +, _parent(nullptr) , _data(other._data) { - const HistoryDocumentCaptioned *captioned = other.Get(); + auto *captioned = other.Get(); createInterfaces(captioned != 0); - if (HistoryDocumentNamed *named = Get()) { - if (const HistoryDocumentNamed *oin = other.Get()) { - named->_name = oin->_name; - named->_namew = oin->_namew; + if (auto *named = Get()) { + if (auto *othernamed = other.Get()) { + named->_name = othernamed->_name; + named->_namew = othernamed->_namew; } else { named->_name = documentName(_data); named->_namew = st::semiboldFont->width(named->_name); @@ -3855,8 +3833,8 @@ void HistoryDocument::createInterfaces(bool caption) { if (caption) { mask |= HistoryDocumentCaptioned::Bit(); } - UpdateInterfaces(mask); - if (HistoryDocumentThumbed *thumbed = Get()) { + UpdateComponents(mask); + if (auto *thumbed = Get()) { thumbed->_linksavel.reset(new DocumentSaveLink(_data)); thumbed->_linkcancell.reset(new DocumentCancelLink(_data)); } @@ -3865,12 +3843,12 @@ void HistoryDocument::createInterfaces(bool caption) { void HistoryDocument::initDimensions(const HistoryItem *parent) { _parent = parent; - HistoryDocumentCaptioned *captioned = Get(); + auto *captioned = Get(); if (captioned && captioned->_caption.hasSkipBlock()) { captioned->_caption.setSkipBlock(parent->skipBlockWidth(), parent->skipBlockHeight()); } - HistoryDocumentThumbed *thumbed = Get(); + auto *thumbed = Get(); if (thumbed) { _data->thumb->load(); int32 tw = convertScale(_data->thumb->width()), th = convertScale(_data->thumb->height()); @@ -3895,14 +3873,14 @@ void HistoryDocument::initDimensions(const HistoryItem *parent) { _maxw = qMax(_maxw, tleft + documentMaxStatusWidth(_data) + unread + parent->skipBlockWidth() + st::msgPadding.right()); } - if (HistoryDocumentNamed *named = Get()) { + if (auto *named = Get()) { _maxw = qMax(tleft + named->_namew + tright, _maxw); _maxw = qMin(_maxw, int(st::msgMaxWidth)); } if (thumbed) { _minh = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); - if (!captioned && parent->Is()) { + if (!captioned && parent->Has()) { _minh += st::msgDateFont->height - st::msgDateDelta.y(); } } else { @@ -3917,7 +3895,7 @@ void HistoryDocument::initDimensions(const HistoryItem *parent) { } int32 HistoryDocument::resize(int32 width, const HistoryItem *parent) { - HistoryDocumentCaptioned *captioned = Get(); + auto *captioned = Get(); if (!captioned) { return HistoryFileMedia::resize(width, parent); } @@ -3953,7 +3931,7 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r bool radial = isRadialAnimation(ms); int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0, bottom = 0; - if (const HistoryDocumentThumbed *thumbed = Get()) { + if (auto *thumbed = Get()) { nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right(); nametop = st::msgFileThumbNameTop; nameright = st::msgFileThumbPadding.left(); @@ -4061,7 +4039,7 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r } int32 namewidth = _width - nameleft - nameright; - if (const HistoryDocumentVoice *voice = Get()) { + if (auto *voice = Get()) { const VoiceWaveform *wf = 0; uchar norm_value = 0; if (_data->voice()) { @@ -4120,7 +4098,7 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r sum_i += bar_count; } } - } else if (const HistoryDocumentNamed *named = Get()) { + } else if (auto *named = Get()) { p.setFont(st::semiboldFont); p.setPen(st::black); if (namewidth < named->_namew) { @@ -4147,7 +4125,7 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r } } - if (const HistoryDocumentCaptioned *captioned = Get()) { + if (auto *captioned = Get()) { p.setPen(st::black); captioned->_caption.draw(p, st::msgPadding.left(), bottom, captionw); } @@ -4162,7 +4140,7 @@ void HistoryDocument::getState(TextLinkPtr &lnk, HistoryCursorState &state, int3 bool showPause = updateStatusText(parent); int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0, bottom = 0; - if (const HistoryDocumentThumbed *thumbed = Get()) { + if (auto *thumbed = Get()) { nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right(); linktop = st::msgFileThumbLinkTop; bottom = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); @@ -4191,7 +4169,7 @@ void HistoryDocument::getState(TextLinkPtr &lnk, HistoryCursorState &state, int3 } int32 height = _height; - if (const HistoryDocumentCaptioned *captioned = Get()) { + if (auto *captioned = Get()) { if (y >= bottom) { bool inText = false; captioned->_caption.getState(lnk, inText, x - st::msgPadding.left(), y - bottom, _width - st::msgPadding.left() - st::msgPadding.right()); @@ -4208,13 +4186,15 @@ void HistoryDocument::getState(TextLinkPtr &lnk, HistoryCursorState &state, int3 const QString HistoryDocument::inDialogsText() const { QString result; - if (Get()) { + if (Has()) { result = lang(lng_in_dlg_audio); + } else if (_data->song()) { + result = lang(lng_in_dlg_audio_file); } else { - const HistoryDocumentNamed *named = Get(); + auto *named = Get(); result = (!named || named->_name.isEmpty()) ? lang(lng_in_dlg_file) : named->_name; } - if (const HistoryDocumentCaptioned *captioned = Get()) { + if (auto *captioned = Get()) { if (!captioned->_caption.isEmpty()) { result.append(' ').append(captioned->_caption.original(0, 0xFFFF, Text::ExpandLinksNone)); } @@ -4223,24 +4203,31 @@ const QString HistoryDocument::inDialogsText() const { } const QString HistoryDocument::inHistoryText() const { - QString result = qsl("[ ") + lang(Get() ? lng_in_dlg_audio : lng_in_dlg_file); - if (const HistoryDocumentNamed *named = Get()) { + QString result; + if (Has()) { + result = lang(lng_in_dlg_audio); + } else if (_data->song()) { + result = lang(lng_in_dlg_audio_file); + } else { + result = lang(lng_in_dlg_file); + } + if (auto *named = Get()) { if (!named->_name.isEmpty()) { result.append(qsl(" : ")).append(named->_name); } } - if (const HistoryDocumentCaptioned *captioned = Get()) { + if (auto *captioned = Get()) { if (!captioned->_caption.isEmpty()) { result.append(qsl(", ")).append(captioned->_caption.original(0, 0xFFFF, Text::ExpandLinksAll)); } } - return result.append(qsl(" ]")); + return qsl("[ ") + result.append(qsl(" ]")); } void HistoryDocument::setStatusSize(int32 newSize, qint64 realDuration) const { int32 duration = _data->song() ? _data->song()->duration : (_data->voice() ? _data->voice()->duration : -1); HistoryFileMedia::setStatusSize(newSize, _data->size, duration, realDuration); - if (const HistoryDocumentThumbed *thumbed = Get()) { + if (auto *thumbed = Get()) { if (_statusSize == FileStatusSizeReady) { thumbed->_link = lang(lng_media_download).toUpper(); } else if (_statusSize == FileStatusSizeLoaded) { @@ -4276,7 +4263,7 @@ bool HistoryDocument::updateStatusText(const HistoryItem *parent) const { } if (playing.msgId == parent->fullId() && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { - if (const HistoryDocumentVoice *voice = Get()) { + if (auto *voice = Get()) { bool was = voice->_playback; voice->ensurePlayback(this); if (!was || playingPosition != voice->_playback->_position) { @@ -4296,7 +4283,7 @@ bool HistoryDocument::updateStatusText(const HistoryItem *parent) const { showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting); } else { statusSize = FileStatusSizeLoaded; - if (const HistoryDocumentVoice *voice = Get()) { + if (auto *voice = Get()) { voice->checkPlaybackFinished(); } } @@ -4332,7 +4319,7 @@ bool HistoryDocument::updateStatusText(const HistoryItem *parent) const { } void HistoryDocument::step_voiceProgress(float64 ms, bool timer) { - if (HistoryDocumentVoice *voice = Get()) { + if (auto *voice = Get()) { if (voice->_playback) { float64 dt = ms / (2 * AudioVoiceMsgUpdateView); if (dt >= 1) { @@ -4372,12 +4359,12 @@ ImagePtr HistoryDocument::replyPreview() { } HistoryGif::HistoryGif(DocumentData *document, const QString &caption, const HistoryItem *parent) : HistoryFileMedia() -, _parent(0) +, _parent(nullptr) , _data(document) , _thumbw(1) , _thumbh(1) , _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) -, _gif(0) { +, _gif(nullptr) { setLinks(new GifOpenLink(_data), new GifOpenLink(_data), new DocumentCancelLink(_data)); setStatusSize(FileStatusSizeReady); @@ -4390,12 +4377,12 @@ HistoryGif::HistoryGif(DocumentData *document, const QString &caption, const His } HistoryGif::HistoryGif(const HistoryGif &other) : HistoryFileMedia() -, _parent(0) +, _parent(nullptr) , _data(other._data) , _thumbw(other._thumbw) , _thumbh(other._thumbh) , _caption(other._caption) -, _gif(0) { +, _gif(nullptr) { setLinks(new GifOpenLink(_data), new GifOpenLink(_data), new DocumentCancelLink(_data)); setStatusSize(other._statusSize); @@ -4783,7 +4770,7 @@ void HistorySticker::initDimensions(const HistoryItem *parent) { if (_pixh < 1) _pixh = 1; _maxw = qMax(_pixw, int16(st::minPhotoSize)); _minh = qMax(_pixh, int16(st::minPhotoSize)); - if (const HistoryReply *reply = toHistoryReply(parent)) { + if (auto *reply = parent->Get()) { _maxw += st::msgReplyPadding.left() + reply->replyToWidth(); } _height = _minh; @@ -4791,10 +4778,10 @@ void HistorySticker::initDimensions(const HistoryItem *parent) { int32 HistorySticker::resize(int32 width, const HistoryItem *parent) { // return new height _width = qMin(width, _maxw); - if (const HistoryReply *reply = toHistoryReply(parent)) { + if (auto *reply = parent->Get()) { int32 usew = _maxw - st::msgReplyPadding.left() - reply->replyToWidth(); int32 rw = _width - usew - st::msgReplyPadding.left() - st::msgReplyPadding.left() - st::msgReplyPadding.right(); - reply->resizeVia(rw); + reply->resize(rw); } return _height; } @@ -4808,7 +4795,7 @@ void HistorySticker::draw(Painter &p, const HistoryItem *parent, const QRect &r, bool out = parent->out(), isPost = parent->isPost(), outbg = out && !isPost; int32 usew = _maxw, usex = 0; - const HistoryReply *reply = toHistoryReply(parent); + auto *reply = parent->Get(); if (reply) { usew -= st::msgReplyPadding.left() + reply->replyToWidth(); if (isPost) { @@ -4842,7 +4829,11 @@ void HistorySticker::draw(Painter &p, const HistoryItem *parent, const QRect &r, App::roundRect(p, rx, ry, rw, rh, selected ? App::msgServiceSelectBg() : App::msgServiceBg(), selected ? ServiceSelectedCorners : ServiceCorners); - reply->drawReplyTo(p, rx + st::msgReplyPadding.left(), ry, rw - st::msgReplyPadding.left() - st::msgReplyPadding.right(), selected, true); + HistoryMessageReply::PaintFlags flags = 0; + if (selected) { + flags |= HistoryMessageReply::PaintSelected; + } + reply->paint(p, parent, rx + st::msgReplyPadding.left(), ry, rw - st::msgReplyPadding.left() - st::msgReplyPadding.right(), flags); } } } @@ -4853,7 +4844,7 @@ void HistorySticker::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 bool out = parent->out(), isPost = parent->isPost(), outbg = out && !isPost; int32 usew = _maxw, usex = 0; - const HistoryReply *reply = toHistoryReply(parent); + auto *reply = parent->Get(); if (reply) { usew -= reply->replyToWidth(); if (isPost) { @@ -5782,7 +5773,7 @@ void HistoryLocation::initDimensions(const HistoryItem *parent) { _minh += st::mediaPadding.top() + st::mediaPadding.bottom(); if (!_title.isEmpty() || !_description.isEmpty()) { _minh += st::webPagePhotoSkip; - if (!parent->Is() && !parent->toHistoryReply()) { + if (!parent->Has() && !parent->Has()) { _minh += st::msgPadding.top(); } } @@ -5822,7 +5813,7 @@ int32 HistoryLocation::resize(int32 width, const HistoryItem *parent) { } if (!_title.isEmpty() || !_description.isEmpty()) { _height += st::webPagePhotoSkip; - if (!parent->Is() && !parent->toHistoryReply()) { + if (!parent->Has() && !parent->Has()) { _height += st::msgPadding.top(); } } @@ -5841,7 +5832,7 @@ void HistoryLocation::draw(Painter &p, const HistoryItem *parent, const QRect &r skipy = st::mediaPadding.top(); if (!_title.isEmpty() || !_description.isEmpty()) { - if (!parent->Is() && !parent->toHistoryReply()) { + if (!parent->Has() && !parent->Has()) { skipy += st::msgPadding.top(); } } @@ -5904,7 +5895,7 @@ void HistoryLocation::getState(TextLinkPtr &lnk, HistoryCursorState &state, int3 skipy = st::mediaPadding.top(); if (!_title.isEmpty() || !_description.isEmpty()) { - if (!parent->Is() && !parent->toHistoryReply()) { + if (!parent->Has() && !parent->Has()) { skipy += st::msgPadding.top(); } } @@ -5956,12 +5947,6 @@ void ViaInlineBotLink::onClick(Qt::MouseButton button) const { App::insertBotCommand('@' + _bot->username); } -HistoryMessageVia::HistoryMessageVia(Interfaces *) -: _bot(0) -, _width(0) -, _maxWidth(0) { -} - void HistoryMessageVia::create(int32 userId) { _bot = App::user(peerFromUser(userId)); _maxWidth = st::msgServiceNameFont->width(lng_inline_bot_via(lt_inline_bot, '@' + _bot->username)); @@ -5983,14 +5968,6 @@ void HistoryMessageVia::resize(int32 availw) const { } } -HistoryMessageViews::HistoryMessageViews(Interfaces *) -: _views(0) -, _viewsWidth(0) { -} - -HistoryMessageSigned::HistoryMessageSigned(Interfaces *) { -} - void HistoryMessageSigned::create(UserData *from, const QDateTime &date) { QString time = qsl(", ") + date.toString(cTimeFormat()), name = App::peerName(from); int32 timew = st::msgDateFont->width(time), namew = st::msgDateFont->width(name); @@ -6000,17 +5977,10 @@ void HistoryMessageSigned::create(UserData *from, const QDateTime &date) { _signature.setText(st::msgDateFont, name + time, _textNameOptions); } -int32 HistoryMessageSigned::maxWidth() const { +int HistoryMessageSigned::maxWidth() const { return _signature.maxWidth(); } -HistoryMessageForwarded::HistoryMessageForwarded(Interfaces *) -: _authorOriginal(0) -, _fromOriginal(0) -, _originalId(0) -, _text(1) { -} - void HistoryMessageForwarded::create(const HistoryMessageVia *via) const { QString text; if (_authorOriginal != _fromOriginal) { @@ -6041,8 +6011,150 @@ void HistoryMessageForwarded::create(const HistoryMessageVia *via) const { } } -HistoryMessage::HistoryMessage(History *history, const MTPDmessage &msg) : - HistoryItem(history, msg.vid.v, msg.vflags.v, ::date(msg.vdate), msg.has_from_id() ? msg.vfrom_id.v : 0) { +bool HistoryMessageReply::updateData(HistoryMessage *holder, bool force) { + if (!force) { + if (replyToMsg || !replyToMsgId) { + return true; + } + } + if (!replyToMsg) { + replyToMsg = App::histItemById(holder->channelId(), replyToMsgId); + if (replyToMsg) { + App::historyRegDependency(holder, replyToMsg); + } + } + + if (replyToMsg) { + replyToText.setText(st::msgFont, replyToMsg->inReplyText(), _textDlgOptions); + + updateName(); + + replyToLnk = TextLinkPtr(new MessageLink(replyToMsg->history()->peer->id, replyToMsg->id)); + if (!replyToMsg->Has()) { + if (UserData *bot = replyToMsg->viaBot()) { + _replyToVia = new HistoryMessageVia(0); + _replyToVia->create(peerToUser(bot->id)); + } + } + } else if (force) { + replyToMsgId = 0; + } + if (force) { + holder->setPendingInitDimensions(); + } + return (replyToMsg || !replyToMsgId); +} + +void HistoryMessageReply::clearData(HistoryMessage *holder) { + delete _replyToVia; + _replyToVia = nullptr; + if (replyToMsg) { + App::historyUnregDependency(holder, replyToMsg); + replyToMsg = nullptr; + } + replyToMsgId = 0; +} + +void HistoryMessageReply::checkNameUpdate() const { + if (replyToMsg && replyToMsg->author()->nameVersion > replyToVersion) { + updateName(); + } +} + +void HistoryMessageReply::updateName() const { + if (replyToMsg) { + QString name = (_replyToVia && replyToMsg->author()->isUser()) ? replyToMsg->author()->asUser()->firstName : App::peerName(replyToMsg->author()); + replyToName.setText(st::msgServiceNameFont, name, _textNameOptions); + replyToVersion = replyToMsg->author()->nameVersion; + bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false; + int32 previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0; + int32 w = replyToName.maxWidth(); + if (_replyToVia) { + w += st::msgServiceFont->spacew + _replyToVia->_maxWidth; + } + + _maxReplyWidth = previewSkip + qMax(w, qMin(replyToText.maxWidth(), int32(st::maxSignatureSize))); + } else { + _maxReplyWidth = st::msgDateFont->width(lang(replyToMsgId ? lng_profile_loading : lng_deleted_message)); + } + _maxReplyWidth = st::msgReplyPadding.left() + st::msgReplyBarSkip + _maxReplyWidth + st::msgReplyPadding.right(); +} + +void HistoryMessageReply::resize(int width) const { + if (_replyToVia) { + bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false; + int previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0; + _replyToVia->resize(width - st::msgReplyBarSkip - previewSkip - replyToName.maxWidth() - st::msgServiceFont->spacew); + } +} + +void HistoryMessageReply::itemRemoved(HistoryMessage *holder, HistoryItem *removed) { + if (replyToMsg == removed) { + clearData(holder); + holder->setPendingInitDimensions(); + } +} + +void HistoryMessageReply::paint(Painter &p, const HistoryItem *holder, int x, int y, int w, PaintFlags flags) const { + bool selected = (flags & PaintSelected), outbg = holder->hasOutLayout(); + + style::color bar; + if (flags & PaintInBubble) { + bar = ((flags & PaintSelected) ? (outbg ? st::msgOutReplyBarSelColor : st::msgInReplyBarSelColor) : (outbg ? st::msgOutReplyBarColor : st::msgInReplyBarColor)); + } else { + bar = st::white; + } + QRect rbar(rtlrect(x + st::msgReplyBarPos.x(), y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), st::msgReplyBarSize.width(), st::msgReplyBarSize.height(), w + 2 * x)); + p.fillRect(rbar, bar); + + if (w > st::msgReplyBarSkip) { + if (replyToMsg) { + bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false; + int previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0; + + if (hasPreview) { + ImagePtr replyPreview = replyToMsg->getMedia()->replyPreview(); + if (!replyPreview->isNull()) { + QRect to(rtlrect(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height(), w + 2 * x)); + p.drawPixmap(to.x(), to.y(), replyPreview->pixSingle(replyPreview->width() / cIntRetinaFactor(), replyPreview->height() / cIntRetinaFactor(), to.width(), to.height())); + if (selected) { + App::roundRect(p, to, textstyleCurrent()->selectOverlay, SelectedOverlayCorners); + } + } + } + if (w > st::msgReplyBarSkip + previewSkip) { + if (flags & PaintInBubble) { + p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg)); + } else { + p.setPen(st::white); + } + replyToName.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top(), w - st::msgReplyBarSkip - previewSkip, w + 2 * x); + if (_replyToVia && w > st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew) { + p.setFont(st::msgServiceFont); + p.drawText(x + st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew, y + st::msgReplyPadding.top() + st::msgServiceFont->ascent, _replyToVia->_text); + } + + HistoryMessage *replyToAsMsg = replyToMsg->toHistoryMessage(); + if (!(flags & PaintInBubble)) { + } else if ((replyToAsMsg && replyToAsMsg->emptyText()) || replyToMsg->serviceMsg()) { + style::color date(outbg ? (selected ? st::msgOutDateFgSelected : st::msgOutDateFg) : (selected ? st::msgInDateFgSelected : st::msgInDateFg)); + p.setPen(date); + } else { + p.setPen(st::msgColor); + } + replyToText.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top() + st::msgServiceNameFont->height, w - st::msgReplyBarSkip - previewSkip, w + 2 * x); + } + } else { + p.setFont(st::msgDateFont); + style::color date(outbg ? (selected ? st::msgOutDateFgSelected : st::msgOutDateFg) : (selected ? st::msgInDateFgSelected : st::msgInDateFg)); + p.setPen((flags & PaintInBubble) ? date : st::white); + p.drawTextLeft(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2, w + 2 * x, st::msgDateFont->elided(lang(replyToMsgId ? lng_profile_loading : lng_deleted_message), w - st::msgReplyBarSkip)); + } + } +} + +HistoryMessage::HistoryMessage(History *history, const MTPDmessage &msg) +: HistoryItem(history, msg.vid.v, msg.vflags.v, ::date(msg.vdate), msg.has_from_id() ? msg.vfrom_id.v : 0) { PeerId authorOriginalId = 0, fromOriginalId = 0; MsgId originalId = 0; if (msg.has_fwd_from() && msg.vfwd_from.type() == mtpc_messageFwdHeader) { @@ -6053,7 +6165,10 @@ HistoryMessage::HistoryMessage(History *history, const MTPDmessage &msg) : if (f.has_channel_post()) originalId = f.vchannel_post.v; } } - createInterfaces(msg.has_via_bot_id() ? msg.vvia_bot_id.v : 0, msg.has_views() ? msg.vviews.v : -1, authorOriginalId, fromOriginalId, originalId); + MsgId replyTo = msg.has_reply_to_msg_id() ? msg.vreply_to_msg_id.v : 0; + int32 viaBotId = msg.has_via_bot_id() ? msg.vvia_bot_id.v : 0; + int views = msg.has_views() ? msg.vviews.v : -1; + createInterfaces(replyTo, viaBotId, views, authorOriginalId, fromOriginalId, originalId); QString text(textClean(qs(msg.vmessage))); initMedia(msg.has_media() ? (&msg.vmedia) : 0, text); @@ -6064,8 +6179,9 @@ HistoryMessage::HistoryMessage(History *history, MsgId id, MTPDmessage::Flags fl : HistoryItem(history, id, newForwardedFlags(history->peer, from, fwd) | flags, date, from) { UserData *fwdViaBot = fwd->viaBot(); int32 viaBotId = fwdViaBot ? peerToUser(fwdViaBot->id) : 0; - int32 fwdViewsCount = fwd->viewsCount(), views = (fwdViewsCount > 0) ? fwdViewsCount : (isPost() ? 1 : -1); - createInterfaces(viaBotId, views, fwd->authorOriginal()->id, fwd->fromOriginal()->id, fwd->authorOriginal()->isChannel() ? fwd->id : 0); + int fwdViewsCount = fwd->viewsCount(), views = (fwdViewsCount > 0) ? fwdViewsCount : (isPost() ? 1 : -1); + MsgId replyTo = 0; + createInterfaces(replyTo, viaBotId, views, fwd->authorOriginal()->id, fwd->fromOriginal()->id, fwd->authorOriginal()->isChannel() ? fwd->id : 0); if (HistoryMedia *mediaOriginal = fwd->getMedia()) { _media = mediaOriginal->clone(); @@ -6074,32 +6190,41 @@ HistoryMessage::HistoryMessage(History *history, MsgId id, MTPDmessage::Flags fl setText(fwd->originalText(), fwd->originalEntities()); } -HistoryMessage::HistoryMessage(History *history, MsgId id, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities) - : HistoryItem(history, id, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { - createInterfaces((flags & MTPDmessage::Flag::f_via_bot_id) ? viaBotId : 0, isPost() ? 1 : -1); +HistoryMessage::HistoryMessage(History *history, MsgId id, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities) +: HistoryItem(history, id, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { + createInterfacesHelper(flags, replyTo, viaBotId); setText(msg, entities); } -HistoryMessage::HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption) : -HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { - createInterfaces((flags & MTPDmessage::Flag::f_via_bot_id) ? viaBotId : 0, isPost() ? 1 : -1); +HistoryMessage::HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption) +: HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { + createInterfacesHelper(flags, replyTo, viaBotId); initMediaFromDocument(doc, caption); setText(QString(), EntitiesInText()); } -HistoryMessage::HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption) : -HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { - createInterfaces((flags & MTPDmessage::Flag::f_via_bot_id) ? viaBotId : 0, isPost() ? 1 : -1); +HistoryMessage::HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption) +: HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { + createInterfacesHelper(flags, replyTo, viaBotId); _media = new HistoryPhoto(photo, caption, this); _media->attachToItem(this); setText(QString(), EntitiesInText()); } -void HistoryMessage::createInterfaces(int32 viaBotId, int32 viewsCount, const PeerId &authorIdOriginal, const PeerId &fromIdOriginal, MsgId originalId) { +void HistoryMessage::createInterfacesHelper(MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId) { + if (!(flags & MTPDmessage::Flag::f_via_bot_id)) viaBotId = 0; + if (!(flags & MTPDmessage::Flag::f_reply_to_msg_id)) replyTo = 0; + createInterfaces(replyTo, viaBotId, isPost() ? 1 : -1); +} + +void HistoryMessage::createInterfaces(MsgId replyTo, int32 viaBotId, int32 viewsCount, const PeerId &authorIdOriginal, const PeerId &fromIdOriginal, MsgId originalId) { uint64 mask = 0; + if (replyTo) { + mask |= HistoryMessageReply::Bit(); + } if (viaBotId) { mask |= HistoryMessageVia::Bit(); } @@ -6112,17 +6237,23 @@ void HistoryMessage::createInterfaces(int32 viaBotId, int32 viewsCount, const Pe if (authorIdOriginal && fromIdOriginal) { mask |= HistoryMessageForwarded::Bit(); } - UpdateInterfaces(mask); - if (HistoryMessageVia *via = Get()) { + UpdateComponents(mask); + if (auto *reply = Get()) { + reply->replyToMsgId = replyTo; + if (!reply->updateData(this) && App::api()) { + App::api()->requestMessageData(history()->peer->asChannel(), replyTo, new HistoryDependentItemCallback(fullId())); + } + } + if (auto *via = Get()) { via->create(viaBotId); } - if (HistoryMessageViews *views = Get()) { + if (auto *views = Get()) { views->_views = viewsCount; } - if (HistoryMessageSigned *msgsigned = Get()) { + if (auto *msgsigned = Get()) { msgsigned->create(_from->asUser(), date); } - if (HistoryMessageForwarded *fwd = Get()) { + if (auto *fwd = Get()) { fwd->_authorOriginal = App::peer(authorIdOriginal); fwd->_fromOriginal = App::peer(fromIdOriginal); fwd->_originalId = originalId; @@ -6150,13 +6281,13 @@ QString formatViewsCount(int32 views) { } void HistoryMessage::initTime() { - if (HistoryMessageSigned *msgsigned = Get()) { + if (auto *msgsigned = Get()) { _timeWidth = msgsigned->maxWidth(); } else { _timeText = date.toString(cTimeFormat()); _timeWidth = st::msgDateFont->width(_timeText); } - if (HistoryMessageViews *views = Get()) { + if (auto *views = Get()) { views->_viewsText = (views->_views >= 0) ? formatViewsCount(views->_views) : QString(); views->_viewsWidth = views->_viewsText.isEmpty() ? 0 : st::msgDateFont->width(views->_viewsText); } @@ -6228,9 +6359,10 @@ int32 HistoryMessage::plainMaxWidth() const { } void HistoryMessage::initDimensions() { + auto *reply = Get(); if (drawBubble()) { - HistoryMessageForwarded *fwd = Get(); - HistoryMessageVia *via = Get(); + auto fwd = Get(); + auto via = Get(); if (fwd) { fwd->create(via); } @@ -6286,6 +6418,16 @@ void HistoryMessage::initDimensions() { _maxw = _media->maxWidth(); _minh = _media->minHeight(); } + if (reply) { + reply->updateName(); + if (!_media) { + int replyw = st::msgPadding.left() + reply->_maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right(); + if (reply->_replyToVia) { + replyw += st::msgServiceFont->spacew + reply->_replyToVia->_maxWidth; + } + if (replyw > _maxw) _maxw = replyw; + } + } } void HistoryMessage::countPositionAndSize(int32 &left, int32 &width) const { @@ -6312,8 +6454,8 @@ void HistoryMessage::countPositionAndSize(int32 &left, int32 &width) const { void HistoryMessage::fromNameUpdated(int32 width) const { _authorNameVersion = author()->nameVersion; - if (!Is()) { - if (const HistoryMessageVia *via = Get()) { + if (!Has()) { + if (auto *via = Get()) { via->resize(width - st::msgPadding.left() - st::msgPadding.right() - author()->nameText.maxWidth() - st::msgServiceFont->spacew); } } @@ -6361,7 +6503,7 @@ QString HistoryMessage::selectedText(uint32 selection) const { uint16 selectedTo = (selection == FullSelection) ? 0xFFFF : (selection & 0xFFFF); result = _text.original(selectedFrom, selectedTo, Text::ExpandLinksAll); } - if (const HistoryMessageForwarded *fwd = Get()) { + if (auto *fwd = Get()) { if (selection == FullSelection) { QString fwdinfo = fwd->_text.original(0, 0xFFFF, Text::ExpandLinksAll), wrapped; wrapped.reserve(fwdinfo.size() + 4 + result.size()); @@ -6369,6 +6511,14 @@ QString HistoryMessage::selectedText(uint32 selection) const { result = wrapped; } } + if (auto *reply = Get()) { + if (selection == FullSelection && reply->replyToMsg) { + QString wrapped; + wrapped.reserve(lang(lng_in_reply_to).size() + reply->replyToMsg->author()->name.size() + 4 + result.size()); + wrapped.append('[').append(lang(lng_in_reply_to)).append(' ').append(reply->replyToMsg->author()->name).append(qsl("]\n")).append(result); + result = wrapped; + } + } return result; } @@ -6464,7 +6614,7 @@ void HistoryMessage::drawInfo(Painter &p, int32 right, int32 bottom, int32 width } dateX += HistoryMessage::timeLeft(); - if (const HistoryMessageSigned *msgsigned = Get()) { + if (auto *msgsigned = Get()) { msgsigned->_signature.drawElided(p, dateX, dateY, _timeWidth); } else { p.drawText(dateX, dateY + st::msgDateFont->ascent, _timeText); @@ -6472,7 +6622,7 @@ void HistoryMessage::drawInfo(Painter &p, int32 right, int32 bottom, int32 width QPoint iconPos; const QRect *iconRect = 0; - if (const HistoryMessageViews *views = Get()) { + if (auto *views = Get()) { iconPos = QPoint(infoRight - infoW + st::msgViewsPos.x(), infoBottom - st::msgViewsImg.pxHeight() + st::msgViewsPos.y()); if (id > 0) { if (outbg) { @@ -6511,7 +6661,7 @@ void HistoryMessage::drawInfo(Painter &p, int32 right, int32 bottom, int32 width } void HistoryMessage::setViewsCount(int32 count) { - HistoryMessageViews *views = Get(); + auto *views = Get(); if (!views || views->_views == count || (count >= 0 && views->_views > count)) return; int32 was = views->_viewsWidth; @@ -6588,9 +6738,14 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m // author()->paintUserpic(p, st::msgPhotoSize, photoleft, phototop); //} + auto *reply = Get(); + if (reply) { + reply->checkNameUpdate(); + } + if (bubble) { - const HistoryMessageForwarded *fwd = Get(); - const HistoryMessageVia *via = Get(); + auto *fwd = Get(); + auto *via = Get(); if (displayFromName() && author()->nameVersion > _authorNameVersion) { fromNameUpdated(width); } @@ -6619,7 +6774,16 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m } QRect trect(r.marginsAdded(-st::msgPadding)); - drawMessageText(p, trect, selection); + + paintForwardedInfo(p, trect, selected); + paintReplyInfo(p, trect, selected); + paintViaBotIdInfo(p, trect, selected); + + p.setPen(st::msgColor); + p.setFont(st::msgFont); + uint16 selectedFrom = selected ? 0 : ((selection >> 16) & 0xFFFF); + uint16 selectedTo = selected ? 0 : (selection & 0xFFFF); + _text.draw(p, trect.x(), trect.y(), trect.width(), style::al_left, 0, -1, selectedFrom, selectedTo); if (_media && _media->isDisplayed()) { int32 top = height - marginBottom() - _media->height(); @@ -6642,38 +6806,52 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m textstyleRestore(); } -void HistoryMessage::drawMessageText(Painter &p, QRect trect, uint32 selection) const { +void HistoryMessage::paintForwardedInfo(Painter &p, QRect &trect, bool selected) const { if (displayForwardedFrom()) { style::font serviceFont(st::msgServiceFont), serviceName(st::msgServiceNameFont); - bool outbg = out() && !isPost(); - p.setPen((selection == FullSelection) ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg)); + p.setPen(selected ? (hasOutLayout() ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (hasOutLayout() ? st::msgOutServiceFg : st::msgInServiceFg)); p.setFont(serviceFont); - const HistoryMessageForwarded *fwd = Get(); + auto *fwd = Get(); bool breakEverywhere = (fwd->_text.countHeight(trect.width()) > 2 * serviceFont->height); - textstyleSet(&((selection == FullSelection) ? (outbg ? st::outFwdTextStyleSelected : st::inFwdTextStyleSelected) : (outbg ? st::outFwdTextStyle : st::inFwdTextStyle))); + textstyleSet(&(selected ? (hasOutLayout() ? st::outFwdTextStyleSelected : st::inFwdTextStyleSelected) : (hasOutLayout() ? st::outFwdTextStyle : st::inFwdTextStyle))); fwd->_text.drawElided(p, trect.x(), trect.y(), trect.width(), 2, style::al_left, 0, -1, 0, breakEverywhere); - textstyleSet(&(outbg ? st::outTextStyle : st::inTextStyle)); + textstyleSet(&(hasOutLayout() ? st::outTextStyle : st::inTextStyle)); trect.setY(trect.y() + (((fwd->_text.maxWidth() > trect.width()) ? 2 : 1) * serviceFont->height)); } +} - bool outbg = out() && !isPost(), selected = (selection == FullSelection); - if (!displayFromName() && !Is()) { - if (const HistoryMessageVia *via = Get()) { +void HistoryMessage::paintReplyInfo(Painter &p, QRect &trect, bool selected) const { + if (auto *reply = Get()) { + int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); + + HistoryMessageReply::PaintFlags flags = HistoryMessageReply::PaintInBubble; + if (selected) { + flags |= HistoryMessageReply::PaintSelected; + } + reply->paint(p, this, trect.x(), trect.y(), trect.width(), flags); + + trect.setY(trect.y() + h); + } +} + +void HistoryMessage::paintViaBotIdInfo(Painter &p, QRect &trect, bool selected) const { + if (!displayFromName() && !Has()) { + if (auto *via = Get()) { p.setFont(st::msgServiceNameFont); - p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg)); + p.setPen(selected ? (hasOutLayout() ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (hasOutLayout() ? st::msgOutServiceFg : st::msgInServiceFg)); p.drawTextLeft(trect.left(), trect.top(), _history->width, via->_text); trect.setY(trect.y() + st::msgServiceNameFont->height); } } +} - p.setPen(st::msgColor); - p.setFont(st::msgFont); - uint16 selectedFrom = (selection == FullSelection) ? 0 : (selection >> 16) & 0xFFFF; - uint16 selectedTo = (selection == FullSelection) ? 0 : selection & 0xFFFF; - _text.draw(p, trect.x(), trect.y(), trect.width(), style::al_left, 0, -1, selectedFrom, selectedTo); +void HistoryMessage::dependencyItemRemoved(HistoryItem *dependency) { + if (auto *reply = Get()) { + reply->itemRemoved(this, dependency); + } } void HistoryMessage::destroy() { @@ -6691,8 +6869,9 @@ int HistoryMessage::resizeGetHeight_(int width) { width = st::msgMaxWidth; } if (drawBubble()) { - HistoryMessageForwarded *fwd = Get(); - HistoryMessageVia *via = Get(); + auto *fwd = Get(); + auto *reply = Get(); + auto *via = Get(); bool media = (_media && _media->isDisplayed()); if (width >= _maxw) { @@ -6745,6 +6924,15 @@ int HistoryMessage::resizeGetHeight_(int width) { _height += fwdheight; } } + + if (reply) { + if (emptyText() && !displayFromName() && !Has()) { + _height += st::msgPadding.top() + st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom() + st::mediaHeaderSkip; + } else { + _height += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); + } + reply->resize(width - st::msgPadding.left() - st::msgPadding.right()); + } } else { _height = _media->resize(width, this); } @@ -6800,26 +6988,27 @@ void HistoryMessage::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 if (width < 1) return; if (drawBubble()) { - const HistoryMessageForwarded *fwd = Get(); - const HistoryMessageVia *via = Get(); + auto *fwd = Get(); + auto *via = Get(); + auto *reply = Get(); int top = marginTop(); QRect r(left, top, width, height - top - marginBottom()); - if (displayFromName()) { // from user left name - if (y >= r.top() + st::msgPadding.top() && y < r.top() + st::msgPadding.top() + st::msgNameFont->height) { - if (x >= r.left() + st::msgPadding.left() && x < r.left() + r.width() - st::msgPadding.right() && x < r.left() + st::msgPadding.left() + author()->nameText.maxWidth()) { + QRect trect(r.marginsAdded(-st::msgPadding)); + if (displayFromName()) { + if (y >= trect.top() && y < trect.top() + st::msgNameFont->height) { + if (x >= trect.left() && x < trect.left() + trect.width() && x < trect.left() + author()->nameText.maxWidth()) { lnk = author()->lnk; return; } - if (via && !fwd && x >= r.left() + st::msgPadding.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew && x < r.left() + st::msgPadding.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew + via->_width) { + if (via && !fwd && x >= trect.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew && x < trect.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew + via->_width) { lnk = via->_lnk; return; } } - r.setTop(r.top() + st::msgNameFont->height); + trect.setTop(trect.top() + st::msgNameFont->height); } if (displayForwardedFrom()) { - QRect trect(r.marginsAdded(-st::msgPadding)); int32 fwdheight = ((fwd->_text.maxWidth() > trect.width()) ? 2 : 1) * st::semiboldFont->height; if (y >= trect.top() && y < trect.top() + fwdheight) { bool inText = false; @@ -6832,57 +7021,57 @@ void HistoryMessage::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 } return; } - y -= fwdheight; - r.setHeight(r.height() - fwdheight); + trect.setTop(trect.top() + fwdheight); } - getStateFromMessageText(lnk, state, x, y, r); - } else { - _media->getState(lnk, state, x - left, y - marginTop(), this); - } -} - -void HistoryMessage::getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const QRect &r) const { - bool inDate = false; - - QRect trect(r.marginsAdded(-st::msgPadding)); - - const HistoryMessageForwarded *fwd = Get(); - if (!displayFromName() && !fwd) { - if (const HistoryMessageVia *via = Get()) { + if (via && !displayFromName() && !displayForwardedFrom()) { if (x >= trect.left() && y >= trect.top() && y < trect.top() + st::msgNameFont->height && x < trect.left() + via->_width) { lnk = via->_lnk; return; } trect.setTop(trect.top() + st::msgNameFont->height); } - } + if (reply) { + int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); + if (y >= trect.top() && y < trect.top() + h) { + if (reply->replyToMsg && y >= trect.top() + st::msgReplyPadding.top() && y < trect.top() + st::msgReplyPadding.top() + st::msgReplyBarSize.height() && x >= trect.left() && x < trect.left() + trect.width()) { + lnk = reply->replyToLink(); + } + return; + } + trect.setTop(trect.top() + h); + } - TextLinkPtr medialnk; - if (_media && _media->isDisplayed()) { - if (!_media->customInfoLayout()) { + bool inDate = false; + + TextLinkPtr medialnk; + if (_media && _media->isDisplayed()) { + if (!_media->customInfoLayout()) { + inDate = HistoryMessage::pointInTime(r.x() + r.width(), r.y() + r.height(), x, y, InfoDisplayDefault); + } + if (y >= r.bottom() - _media->height() && y < r.bottom()) { + _media->getState(lnk, state, x - r.left(), y - (r.bottom() - _media->height()), this); + if (inDate) state = HistoryInDateCursorState; + return; + } + trect.setBottom(trect.bottom() - _media->height()); + } else { inDate = HistoryMessage::pointInTime(r.x() + r.width(), r.y() + r.height(), x, y, InfoDisplayDefault); } - if (y >= r.bottom() - _media->height() && y < r.bottom()) { - _media->getState(lnk, state, x - r.left(), y - (r.bottom() - _media->height()), this); - if (inDate) state = HistoryInDateCursorState; - return; + + textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle)); + bool inText = false; + _text.getState(lnk, inText, x - trect.x(), y - trect.y(), trect.width()); + textstyleRestore(); + + if (inDate) { + state = HistoryInDateCursorState; + } else if (inText) { + state = HistoryInTextCursorState; + } else { + state = HistoryDefaultCursorState; } - trect.setBottom(trect.bottom() - _media->height()); } else { - inDate = HistoryMessage::pointInTime(r.x() + r.width(), r.y() + r.height(), x, y, InfoDisplayDefault); - } - - textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle)); - bool inText = false; - _text.getState(lnk, inText, x - trect.x(), y - trect.y(), trect.width()); - textstyleRestore(); - - if (inDate) { - state = HistoryInDateCursorState; - } else if (inText) { - state = HistoryInTextCursorState; - } else { - state = HistoryDefaultCursorState; + _media->getState(lnk, state, x - left, y - marginTop(), this); } } @@ -6890,26 +7079,31 @@ void HistoryMessage::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, symbol = 0; after = false; upon = false; + if (drawBubble()) { int left = 0, width = 0, height = _height; countPositionAndSize(left, width); if (width < 1) return; - const HistoryMessageForwarded *fwd = Get(); - const HistoryMessageVia *via = Get(); + auto *fwd = Get(); + auto *via = Get(); + auto *reply = Get(); int top = marginTop(); QRect r(left, top, width, height - top - marginBottom()); - if (displayFromName()) { // from user left name - r.setTop(r.top() + st::msgNameFont->height); - } else if (via && !fwd) { - r.setTop(r.top() + st::msgNameFont->height); - } QRect trect(r.marginsAdded(-st::msgPadding)); + if (displayFromName()) { + trect.setTop(trect.top() + st::msgNameFont->height); + } else if (via && !fwd) { + trect.setTop(trect.top() + st::msgNameFont->height); + } if (displayForwardedFrom()) { int32 fwdheight = ((fwd->_text.maxWidth() > trect.width()) ? 2 : 1) * st::semiboldFont->height; - y -= fwdheight; - r.setHeight(r.height() - fwdheight); + trect.setTop(trect.top() + fwdheight); + } + if (reply) { + int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); + trect.setTop(trect.top() + h); } if (_media && _media->isDisplayed()) { trect.setBottom(trect.bottom() - _media->height()); @@ -6966,332 +7160,15 @@ HistoryMessage::~HistoryMessage() { _media->detachFromItem(this); deleteAndMark(_media); } + if (auto *reply = Get()) { + reply->clearData(this); + } if (_flags & MTPDmessage::Flag::f_reply_markup) { App::clearReplyMarkup(channelId(), id); } } -HistoryReply::HistoryReply(History *history, const MTPDmessage &msg) : HistoryMessage(history, msg) -, replyToMsgId(msg.vreply_to_msg_id.v) -, replyToMsg(0) -, replyToVersion(0) -, _maxReplyWidth(0) -, _replyToVia(0) { - if (!updateReplyTo() && App::api()) { - App::api()->requestMessageData(history->peer->asChannel(), replyToMsgId, new HistoryDependentItemCallback(fullId())); - } -} - -HistoryReply::HistoryReply(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption) -: HistoryMessage(history, msgId, flags, viaBotId, date, from, doc, caption) -, replyToMsgId(replyTo) -, replyToMsg(0) -, replyToVersion(0) -, _maxReplyWidth(0) -, _replyToVia(0) { - if (!updateReplyTo() && App::api()) { - App::api()->requestMessageData(history->peer->asChannel(), replyToMsgId, new HistoryDependentItemCallback(fullId())); - } -} - -HistoryReply::HistoryReply(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption) -: HistoryMessage(history, msgId, flags, viaBotId, date, from, photo, caption) -, replyToMsgId(replyTo) -, replyToMsg(0) -, replyToVersion(0) -, _maxReplyWidth(0) -, _replyToVia(0) { - if (!updateReplyTo() && App::api()) { - App::api()->requestMessageData(history->peer->asChannel(), replyToMsgId, new HistoryDependentItemCallback(fullId())); - } - replyToNameUpdated(); -} - -QString HistoryReply::selectedText(uint32 selection) const { - if (selection != FullSelection || !replyToMsg) return HistoryMessage::selectedText(selection); - QString result, original = HistoryMessage::selectedText(selection); - result.reserve(lang(lng_in_reply_to).size() + replyToMsg->author()->name.size() + 4 + original.size()); - result.append('[').append(lang(lng_in_reply_to)).append(' ').append(replyToMsg->author()->name).append(qsl("]\n")).append(original); - return result; -} - -void HistoryReply::initDimensions() { - replyToNameUpdated(); - HistoryMessage::initDimensions(); - if (!_media) { - int32 replyw = st::msgPadding.left() + _maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right(); - if (_replyToVia) { - replyw += st::msgServiceFont->spacew + _replyToVia->_maxWidth; - } - if (replyw > _maxw) _maxw = replyw; - } -} - -bool HistoryReply::updateReplyTo(bool force) { - if (!force) { - if (replyToMsg || !replyToMsgId) { - return true; - } - } - if (!replyToMsg) { - replyToMsg = App::histItemById(channelId(), replyToMsgId); - if (replyToMsg) { - App::historyRegDependency(this, replyToMsg); - } - } - - if (replyToMsg) { - replyToText.setText(st::msgFont, replyToMsg->inReplyText(), _textDlgOptions); - - replyToNameUpdated(); - - replyToLnk = TextLinkPtr(new MessageLink(replyToMsg->history()->peer->id, replyToMsg->id)); - if (!replyToMsg->Is()) { - if (UserData *bot = replyToMsg->viaBot()) { - _replyToVia = new HistoryMessageVia(0); - _replyToVia->create(peerToUser(bot->id)); - } - } - } else if (force) { - replyToMsgId = 0; - } - if (force) { - setPendingInitDimensions(); - } - return (replyToMsg || !replyToMsgId); -} - -void HistoryReply::replyToNameUpdated() const { - if (replyToMsg) { - QString name = (_replyToVia && replyToMsg->author()->isUser()) ? replyToMsg->author()->asUser()->firstName : App::peerName(replyToMsg->author()); - replyToName.setText(st::msgServiceNameFont, name, _textNameOptions); - replyToVersion = replyToMsg->author()->nameVersion; - bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false; - int32 previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0; - int32 w = replyToName.maxWidth(); - if (_replyToVia) { - w += st::msgServiceFont->spacew + _replyToVia->_maxWidth; - } - - _maxReplyWidth = previewSkip + qMax(w, qMin(replyToText.maxWidth(), int32(st::maxSignatureSize))); - } else { - _maxReplyWidth = st::msgDateFont->width(lang(replyToMsgId ? lng_profile_loading : lng_deleted_message)); - } - _maxReplyWidth = st::msgReplyPadding.left() + st::msgReplyBarSkip + _maxReplyWidth + st::msgReplyPadding.right(); -} - -int32 HistoryReply::replyToWidth() const { - return _maxReplyWidth; -} - -TextLinkPtr HistoryReply::replyToLink() const { - return replyToLnk; -} - -MsgId HistoryReply::replyToId() const { - return replyToMsgId; -} - -HistoryItem *HistoryReply::replyToMessage() const { - return replyToMsg; -} - -void HistoryReply::dependencyItemRemoved(HistoryItem *dependency) { - if (replyToMsg == dependency) { - delete _replyToVia; - _replyToVia = 0; - - replyToMsg = nullptr; - replyToMsgId = 0; - initDimensions(); - } -} - -void HistoryReply::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const { - if (replyToMsg && replyToMsg->author()->nameVersion > replyToVersion) { - replyToNameUpdated(); - } - HistoryMessage::draw(p, r, selection, ms); -} - -void HistoryReply::drawReplyTo(Painter &p, int32 x, int32 y, int32 w, bool selected, bool likeService) const { - style::color bar; - bool outbg = out() && !isPost(); - if (likeService) { - bar = st::white; - } else { - bar = (selected ? (outbg ? st::msgOutReplyBarSelColor : st::msgInReplyBarSelColor) : (outbg ? st::msgOutReplyBarColor : st::msgInReplyBarColor)); - } - QRect rbar(rtlrect(x + st::msgReplyBarPos.x(), y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), st::msgReplyBarSize.width(), st::msgReplyBarSize.height(), w + 2 * x)); - p.fillRect(rbar, bar); - - if (w > st::msgReplyBarSkip) { - if (replyToMsg) { - bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false; - int previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0; - - if (hasPreview) { - ImagePtr replyPreview = replyToMsg->getMedia()->replyPreview(); - if (!replyPreview->isNull()) { - QRect to(rtlrect(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height(), w + 2 * x)); - p.drawPixmap(to.x(), to.y(), replyPreview->pixSingle(replyPreview->width() / cIntRetinaFactor(), replyPreview->height() / cIntRetinaFactor(), to.width(), to.height())); - if (selected) { - App::roundRect(p, to, textstyleCurrent()->selectOverlay, SelectedOverlayCorners); - } - } - } - if (w > st::msgReplyBarSkip + previewSkip) { - if (likeService) { - p.setPen(st::white); - } else { - p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg)); - } - replyToName.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top(), w - st::msgReplyBarSkip - previewSkip, w + 2 * x); - if (_replyToVia && w > st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew) { - p.setFont(st::msgServiceFont); - p.drawText(x + st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew, y + st::msgReplyPadding.top() + st::msgServiceFont->ascent, _replyToVia->_text); - } - - HistoryMessage *replyToAsMsg = replyToMsg->toHistoryMessage(); - if (likeService) { - } else if ((replyToAsMsg && replyToAsMsg->emptyText()) || replyToMsg->serviceMsg()) { - style::color date(outbg ? (selected ? st::msgOutDateFgSelected : st::msgOutDateFg) : (selected ? st::msgInDateFgSelected : st::msgInDateFg)); - p.setPen(date); - } else { - p.setPen(st::msgColor); - } - replyToText.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top() + st::msgServiceNameFont->height, w - st::msgReplyBarSkip - previewSkip, w + 2 * x); - } - } else { - p.setFont(st::msgDateFont); - style::color date(outbg ? (selected ? st::msgOutDateFgSelected : st::msgOutDateFg) : (selected ? st::msgInDateFgSelected : st::msgInDateFg)); - p.setPen(likeService ? st::white : date); - p.drawTextLeft(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2, w + 2 * x, st::msgDateFont->elided(lang(replyToMsgId ? lng_profile_loading : lng_deleted_message), w - st::msgReplyBarSkip)); - } - } -} - -void HistoryReply::drawMessageText(Painter &p, QRect trect, uint32 selection) const { - int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); - - drawReplyTo(p, trect.x(), trect.y(), trect.width(), (selection == FullSelection)); - - trect.setY(trect.y() + h); - HistoryMessage::drawMessageText(p, trect, selection); -} - -int32 HistoryReply::resizeGetHeight_(int32 width) { - HistoryMessage::resizeGetHeight_(width); - - if (drawBubble()) { - if (emptyText() && !displayFromName() && !Is()) { - _height += st::msgPadding.top() + st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom() + st::mediaHeaderSkip; - } else { - _height += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); - } - if (_replyToVia) { - bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false; - int previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0; - _replyToVia->resize(width - st::msgPadding.left() - st::msgPadding.right() - st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew); - } - } - return _height; -} - -void HistoryReply::resizeVia(int32 w) const { - if (!_replyToVia) return; - - bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false; - int previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0; - _replyToVia->resize(w - st::msgReplyBarSkip - previewSkip - replyToName.maxWidth() - st::msgServiceFont->spacew); -} - -void HistoryReply::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const { - lnk = TextLinkPtr(); - state = HistoryDefaultCursorState; - - if (drawBubble()) { - int32 left = 0, width = 0; - countPositionAndSize(left, width); - //if (displayFromPhoto()) { - // int32 photoleft = left + ((!isPost() && out()) ? (width + (st::msgPhotoSkip - st::msgPhotoSize)) : (-st::msgPhotoSkip)); - // if (x >= photoleft && x < photoleft + st::msgPhotoSize) { - // return HistoryMessage::getState(lnk, state, x, y); - // } - //} - if (width < 1) return; - - int top = marginTop(); - QRect r(left, top, width, _height - top - marginBottom()); - if (displayFromName()) { - style::font nameFont(st::msgNameFont); - if (y >= r.top() + st::msgPadding.top() && y < r.top() + st::msgPadding.top() + nameFont->height) { - return HistoryMessage::getState(lnk, state, x, y); - } - r.setTop(r.top() + nameFont->height); - } - QRect trect(r.marginsAdded(-st::msgPadding)); - - int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); - if (y >= trect.top() && y < trect.top() + h) { - if (replyToMsg && y >= trect.top() + st::msgReplyPadding.top() && y < trect.top() + st::msgReplyPadding.top() + st::msgReplyBarSize.height() && x >= trect.left() && x < trect.left() + trect.width()) { - lnk = replyToLnk; - } - return; - } - y -= h; - } - return HistoryMessage::getState(lnk, state, x, y); -} - -void HistoryReply::getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const QRect &r) const { - int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); - - QRect realr(r); - realr.setHeight(r.height() - h); - HistoryMessage::getStateFromMessageText(lnk, state, x, y, realr); -} - -void HistoryReply::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const { - symbol = 0; - after = false; - upon = false; - - if (drawBubble()) { - int32 left = 0, width = 0; - countPositionAndSize(left, width); - if (width < 1) return; - - int top = marginTop(); - QRect r(left, top, width, _height - top - marginBottom()); - if (displayFromName()) { - style::font nameFont(st::msgNameFont); - if (y >= r.top() + st::msgPadding.top() && y < r.top() + st::msgPadding.top() + nameFont->height) { - return HistoryMessage::getSymbol(symbol, after, upon, x, y); - } - r.setTop(r.top() + nameFont->height); - } - QRect trect(r.marginsAdded(-st::msgPadding)); - - int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); - y -= h; - } - return HistoryMessage::getSymbol(symbol, after, upon, x, y); -} - -HistoryReply::~HistoryReply() { - if (replyToMsg) { - App::historyUnregDependency(this, replyToMsg); - } - deleteAndMark(_replyToVia); -} - -HistoryServicePinned::HistoryServicePinned(Interfaces *) -: msgId(0) -, msg(0) { -} - -void HistoryServiceMessage::setMessageByAction(const MTPmessageAction &action) { +void HistoryService::setMessageByAction(const MTPmessageAction &action) { QList links; LangString text = lang(lng_message_empty); QString from = textcmdLink(1, _from->name); @@ -7399,7 +7276,7 @@ void HistoryServiceMessage::setMessageByAction(const MTPmessageAction &action) { case mtpc_messageActionChatMigrateTo: { _flags |= MTPDmessage_ClientFlag::f_is_group_migrate; const MTPDmessageActionChatMigrateTo &d(action.c_messageActionChatMigrateTo()); - if (true/*PeerData *channel = App::peerLoaded(peerFromChannel(d.vchannel_id))*/) { + if (true/*PeerData *channel = App::channelLoaded(d.vchannel_id.v)*/) { text = lang(lng_action_group_migrate); } else { text = lang(lng_contacts_loading); @@ -7409,7 +7286,7 @@ void HistoryServiceMessage::setMessageByAction(const MTPmessageAction &action) { case mtpc_messageActionChannelMigrateFrom: { _flags |= MTPDmessage_ClientFlag::f_is_group_migrate; const MTPDmessageActionChannelMigrateFrom &d(action.c_messageActionChannelMigrateFrom()); - if (true/*PeerData *chat = App::peerLoaded(peerFromChannel(d.vchat_id))*/) { + if (true/*PeerData *chat = App::chatLoaded(d.vchat_id.v)*/) { text = lang(lng_action_group_migrate); } else { text = lang(lng_contacts_loading); @@ -7418,7 +7295,7 @@ void HistoryServiceMessage::setMessageByAction(const MTPmessageAction &action) { case mtpc_messageActionPinMessage: { if (updatePinnedText(&from, &text)) { - HistoryServicePinned *pinned = Get(); + auto *pinned = Get(); t_assert(pinned != nullptr); links.push_back(pinned->lnk); @@ -7439,8 +7316,8 @@ void HistoryServiceMessage::setMessageByAction(const MTPmessageAction &action) { } } -bool HistoryServiceMessage::updatePinned(bool force) { - HistoryServicePinned *pinned = Get(); +bool HistoryService::updatePinned(bool force) { + auto *pinned = Get(); t_assert(pinned != nullptr); if (!force) { @@ -7478,7 +7355,7 @@ bool HistoryServiceMessage::updatePinned(bool force) { return (pinned->msg || !pinned->msgId); } -bool HistoryServiceMessage::updatePinnedText(const QString *pfrom, QString *ptext) { +bool HistoryService::updatePinnedText(const QString *pfrom, QString *ptext) { bool result = false; QString from, text; if (pfrom) { @@ -7488,7 +7365,7 @@ bool HistoryServiceMessage::updatePinnedText(const QString *pfrom, QString *ptex } TextLinkPtr second; - HistoryServicePinned *pinned = Get(); + auto *pinned = Get(); if (pinned && pinned->msg) { HistoryMedia *media = pinned->msg->getMedia(); QString mediaText; @@ -7550,10 +7427,10 @@ bool HistoryServiceMessage::updatePinnedText(const QString *pfrom, QString *ptex return result; } -HistoryServiceMessage::HistoryServiceMessage(History *history, const MTPDmessageService &msg) : +HistoryService::HistoryService(History *history, const MTPDmessageService &msg) : HistoryItem(history, msg.vid.v, mtpCastFlags(msg.vflags.v), ::date(msg.vdate), msg.has_from_id() ? msg.vfrom_id.v : 0) { if (msg.has_reply_to_msg_id()) { - UpdateInterfaces(HistoryServicePinned::Bit()); + UpdateComponents(HistoryServicePinned::Bit()); MsgId pinnedMsgId = Get()->msgId = msg.vreply_to_msg_id.v; if (!updatePinned() && App::api()) { App::api()->requestMessageData(history->peer->asChannel(), pinnedMsgId, new HistoryDependentItemCallback(fullId())); @@ -7562,19 +7439,19 @@ HistoryServiceMessage::HistoryServiceMessage(History *history, const MTPDmessage setMessageByAction(msg.vaction); } -HistoryServiceMessage::HistoryServiceMessage(History *history, MsgId msgId, QDateTime date, const QString &msg, MTPDmessage::Flags flags, HistoryMedia *media, int32 from) : +HistoryService::HistoryService(History *history, MsgId msgId, QDateTime date, const QString &msg, MTPDmessage::Flags flags, HistoryMedia *media, int32 from) : HistoryItem(history, msgId, flags, date, from) , _text(st::msgServiceFont, msg, _historySrvOptions, st::dlgMinWidth) , _media(media) { } -void HistoryServiceMessage::initDimensions() { +void HistoryService::initDimensions() { _maxw = _text.maxWidth() + st::msgServicePadding.left() + st::msgServicePadding.right(); _minh = _text.minHeight(); if (_media) _media->initDimensions(this); } -void HistoryServiceMessage::countPositionAndSize(int32 &left, int32 &width) const { +void HistoryService::countPositionAndSize(int32 &left, int32 &width) const { left = st::msgServiceMargin.left(); int32 maxwidth = _history->width; if (Adaptive::Wide()) { @@ -7583,29 +7460,29 @@ void HistoryServiceMessage::countPositionAndSize(int32 &left, int32 &width) cons width = maxwidth - st::msgServiceMargin.left() - st::msgServiceMargin.left(); } -QString HistoryServiceMessage::selectedText(uint32 selection) const { +QString HistoryService::selectedText(uint32 selection) const { uint16 selectedFrom = (selection == FullSelection) ? 0 : (selection >> 16) & 0xFFFF; uint16 selectedTo = (selection == FullSelection) ? 0xFFFF : (selection & 0xFFFF); return _text.original(selectedFrom, selectedTo); } -QString HistoryServiceMessage::inDialogsText() const { +QString HistoryService::inDialogsText() const { return _text.original(0, 0xFFFF, Text::ExpandLinksNone); } -QString HistoryServiceMessage::inReplyText() const { - QString result = HistoryServiceMessage::inDialogsText(); +QString HistoryService::inReplyText() const { + QString result = HistoryService::inDialogsText(); return result.trimmed().startsWith(author()->name) ? result.trimmed().mid(author()->name.size()).trimmed() : result; } -void HistoryServiceMessage::setServiceText(const QString &text) { +void HistoryService::setServiceText(const QString &text) { textstyleSet(&st::serviceTextStyle); _text.setText(st::msgServiceFont, text, _historySrvOptions); textstyleRestore(); initDimensions(); } -void HistoryServiceMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const { +void HistoryService::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const { int left = 0, width = 0, height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins countPositionAndSize(left, width); if (width < 1) return; @@ -7673,7 +7550,7 @@ void HistoryServiceMessage::draw(Painter &p, const QRect &r, uint32 selection, u } } -int32 HistoryServiceMessage::resizeGetHeight_(int32 width) { +int32 HistoryService::resizeGetHeight_(int32 width) { int32 maxwidth = _history->width; if (Adaptive::Wide()) { maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left())); @@ -7705,7 +7582,7 @@ int32 HistoryServiceMessage::resizeGetHeight_(int32 width) { return _height; } -bool HistoryServiceMessage::hasPoint(int32 x, int32 y) const { +bool HistoryService::hasPoint(int32 x, int32 y) const { int left = 0, width = 0, height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins countPositionAndSize(left, width); if (width < 1) return false; @@ -7726,7 +7603,7 @@ bool HistoryServiceMessage::hasPoint(int32 x, int32 y) const { return QRect(left, st::msgServiceMargin.top(), width, height).contains(x, y); } -void HistoryServiceMessage::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const { +void HistoryService::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const { lnk = TextLinkPtr(); state = HistoryDefaultCursorState; @@ -7759,7 +7636,7 @@ void HistoryServiceMessage::getState(TextLinkPtr &lnk, HistoryCursorState &state } } -void HistoryServiceMessage::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const { +void HistoryService::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const { symbol = 0; after = false; upon = false; @@ -7787,7 +7664,7 @@ void HistoryServiceMessage::getSymbol(uint16 &symbol, bool &after, bool &upon, i textstyleRestore(); } -void HistoryServiceMessage::drawInDialog(Painter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const { +void HistoryService::drawInDialog(Painter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const { if (cacheFor != this) { cacheFor = this; cache.setText(st::dlgHistFont, inDialogsText(), _textDlgOptions); @@ -7797,17 +7674,17 @@ void HistoryServiceMessage::drawInDialog(Painter &p, const QRect &r, bool act, c cache.drawElided(p, tr.left(), tr.top(), tr.width(), tr.height() / st::dlgHistFont->height); } -QString HistoryServiceMessage::notificationText() const { +QString HistoryService::notificationText() const { QString msg = _text.original(); if (msg.size() > 0xFF) msg = msg.mid(0, 0xFF) + qsl("..."); return msg; } -HistoryMedia *HistoryServiceMessage::getMedia(bool inOverview) const { +HistoryMedia *HistoryService::getMedia(bool inOverview) const { return inOverview ? 0 : _media; } -HistoryServiceMessage::~HistoryServiceMessage() { +HistoryService::~HistoryService() { if (auto pinned = Get()) { if (pinned->msg) { App::historyUnregDependency(this, pinned->msg); @@ -7820,7 +7697,7 @@ HistoryServiceMessage::~HistoryServiceMessage() { } HistoryGroup::HistoryGroup(History *history, const MTPDmessageGroup &group, const QDateTime &date) - : HistoryServiceMessage(history, clientMsgId(), date, lng_channel_comments_count(lt_count, group.vcount.v)/* + qsl(" (%1 ... %2)").arg(group.vmin_id.v).arg(group.vmax_id.v)*/) + : HistoryService(history, clientMsgId(), date, lng_channel_comments_count(lt_count, group.vcount.v)/* + qsl(" (%1 ... %2)").arg(group.vmin_id.v).arg(group.vmax_id.v)*/) , _minId(group.vmin_id.v) , _maxId(group.vmax_id.v) , _count(group.vcount.v) @@ -7828,7 +7705,7 @@ HistoryGroup::HistoryGroup(History *history, const MTPDmessageGroup &group, cons } HistoryGroup::HistoryGroup(History *history, HistoryItem *newItem, const QDateTime &date) - : HistoryServiceMessage(history, clientMsgId(), date, lng_channel_comments_count(lt_count, 1)/* + qsl(" (%1 ... %2)").arg(newItem->id - 1).arg(newItem->id + 1)*/) + : HistoryService(history, clientMsgId(), date, lng_channel_comments_count(lt_count, 1)/* + qsl(" (%1 ... %2)").arg(newItem->id - 1).arg(newItem->id + 1)*/) , _minId(newItem->id - 1) , _maxId(newItem->id + 1) , _count(1) @@ -7898,7 +7775,7 @@ void HistoryGroup::updateText() { } HistoryCollapse::HistoryCollapse(History *history, MsgId wasMinId, const QDateTime &date) - : HistoryServiceMessage(history, clientMsgId(), date, qsl("-")) + : HistoryService(history, clientMsgId(), date, qsl("-")) , _wasMinId(wasMinId) { } @@ -7911,7 +7788,7 @@ void HistoryCollapse::getState(TextLinkPtr &lnk, HistoryCursorState &state, int3 } HistoryJoined::HistoryJoined(History *history, const QDateTime &inviteDate, UserData *inviter, MTPDmessage::Flags flags) - : HistoryServiceMessage(history, clientMsgId(), inviteDate, QString(), flags) { + : HistoryService(history, clientMsgId(), inviteDate, QString(), flags) { textstyleSet(&st::serviceTextStyle); if (peerToUser(inviter->id) == MTP::authedId()) { _text.setText(st::msgServiceFont, lang(history->isMegagroup() ? lng_action_you_joined_group : lng_action_you_joined), _historySrvOptions); diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 1a8c9626d..07bce6754 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -936,7 +936,6 @@ protected: }; -class HistoryReply; // dynamic_cast optimize class HistoryMessage; // dynamic_cast optimize enum HistoryCursorState { @@ -962,43 +961,104 @@ enum HistoryItemType { HistoryItemJoined }; -struct HistoryMessageVia : public BasicInterface { - HistoryMessageVia(Interfaces *); +struct HistoryMessageVia : public BaseComponent { + HistoryMessageVia(Composer*) { + } void create(int32 userId); void resize(int32 availw) const; - UserData *_bot; + UserData *_bot = nullptr; mutable QString _text; - mutable int32 _width, _maxWidth; + mutable int _width = 0; + mutable int _maxWidth = 0; TextLinkPtr _lnk; }; -struct HistoryMessageViews : public BasicInterface { - HistoryMessageViews(Interfaces *); +struct HistoryMessageViews : public BaseComponent { + HistoryMessageViews(Composer*) { + } QString _viewsText; - int32 _views, _viewsWidth; + int _views = 0; + int _viewsWidth = 0; }; -struct HistoryMessageSigned : public BasicInterface { - HistoryMessageSigned(Interfaces *); +struct HistoryMessageSigned : public BaseComponent { + HistoryMessageSigned(Composer*) { + } void create(UserData *from, const QDateTime &date); - int32 maxWidth() const; + int maxWidth() const; Text _signature; }; -struct HistoryMessageForwarded : public BasicInterface { - HistoryMessageForwarded(Interfaces *); +struct HistoryMessageForwarded : public BaseComponent { + HistoryMessageForwarded(Composer*) { + } void create(const HistoryMessageVia *via) const; - bool display(bool hasVia) const; - PeerData *_authorOriginal, *_fromOriginal; - MsgId _originalId; - mutable Text _text; + PeerData *_authorOriginal = nullptr; + PeerData *_fromOriginal = nullptr; + MsgId _originalId = 0; + mutable Text _text = { 1 }; }; +struct HistoryMessageReply : public BaseComponent { + HistoryMessageReply(Composer*) { + } + HistoryMessageReply &operator=(HistoryMessageReply &&other) { + replyToMsgId = other.replyToMsgId; + std::swap(replyToMsg, other.replyToMsg); + replyToLnk = std11::move(other.replyToLnk); + replyToName = std11::move(other.replyToName); + replyToText = std11::move(other.replyToText); + replyToVersion = other.replyToVersion; + _maxReplyWidth = other._maxReplyWidth; + std::swap(_replyToVia, other._replyToVia); + return *this; + } + ~HistoryMessageReply() { + // clearData() should be called by holder + t_assert(replyToMsg == nullptr); + t_assert(_replyToVia == nullptr); + } + bool updateData(HistoryMessage *holder, bool force = false); + void clearData(HistoryMessage *holder); // must be called before destructor + + void checkNameUpdate() const; + void updateName() const; + void resize(int width) const; + void itemRemoved(HistoryMessage *holder, HistoryItem *removed); + + enum PaintFlag { + PaintInBubble = 0x01, + PaintSelected = 0x02, + }; + Q_DECLARE_FLAGS(PaintFlags, PaintFlag); + void paint(Painter &p, const HistoryItem *holder, int x, int y, int w, PaintFlags flags) const; + + MsgId replyToId() const { + return replyToMsgId; + } + int replyToWidth() const { + return _maxReplyWidth; + } + TextLinkPtr replyToLink() const { + return replyToLnk; + } + + MsgId replyToMsgId = 0; + HistoryItem *replyToMsg = nullptr; + TextLinkPtr replyToLnk; + mutable Text replyToName, replyToText; + mutable int replyToVersion = 0; + mutable int _maxReplyWidth = 0; + HistoryMessageVia *_replyToVia = nullptr; + int toWidth = 0; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(HistoryMessageReply::PaintFlags); + class HistoryDependentItemCallback : public SharedCallback2 { public: HistoryDependentItemCallback(FullMsgId dependent) : _dependent(dependent) { @@ -1012,28 +1072,30 @@ private: // any HistoryItem can have this Interface for // displaying the day mark above the message -struct HistoryMessageDate : public BasicInterface { - HistoryMessageDate(Interfaces *); +struct HistoryMessageDate : public BaseComponent { + HistoryMessageDate(Composer*) { + } void init(const QDateTime &date); int height() const; void paint(Painter &p, int y, int w) const; QString _text; - int _width; + int _width = 0; }; // any HistoryItem can have this Interface for // displaying the unread messages bar above the message -struct HistoryMessageUnreadBar : public BasicInterface { - HistoryMessageUnreadBar(Interfaces *); +struct HistoryMessageUnreadBar : public BaseComponent { + HistoryMessageUnreadBar(Composer*) { + } void init(int count); int height() const; void paint(Painter &p, int y, int w) const; QString _text; - int _width; + int _width = 0; // if unread bar is freezed the new messages do not // increment the counter displayed by this bar @@ -1041,11 +1103,11 @@ struct HistoryMessageUnreadBar : public BasicInterface // it happens when we've opened the conversation and // we've seen the bar and new messages are marked as read // as soon as they are added to the chat history - bool _freezed; + bool _freezed = false; }; class HistoryMedia; -class HistoryItem : public HistoryElem, public Interfaces { +class HistoryItem : public HistoryElem, public Composer { public: HistoryItem(const HistoryItem &) = delete; @@ -1075,8 +1137,11 @@ public: return true; } - virtual UserData *viaBot() const { - return 0; + UserData *viaBot() const { + if (const HistoryMessageVia *via = Get()) { + return via->_bot; + } + return nullptr; } History *history() const { @@ -1165,6 +1230,9 @@ public: bool isSilent() const { return _flags & MTPDmessage::Flag::f_silent; } + bool hasOutLayout() const { + return out() && !isPost(); + } virtual int32 viewsCount() const { return hasViews() ? 1 : -1; } @@ -1315,10 +1383,10 @@ public: virtual const HistoryMessage *toHistoryMessage() const { // dynamic_cast optimize return 0; } - virtual HistoryReply *toHistoryReply() { // dynamic_cast optimize - return 0; - } - virtual const HistoryReply *toHistoryReply() const { // dynamic_cast optimize + MsgId replyToId() const { + if (auto *reply = Get()) { + return reply->replyToId(); + } return 0; } @@ -1433,7 +1501,7 @@ protected: // this should be used only in previousItemChanged() // to add required bits to the Interfaces mask - // after that always use Is() + // after that always use Has() bool displayDate() const { if (HistoryItem *prev = previous()) { return prev->date.date().day() != date.date().day(); @@ -1750,7 +1818,7 @@ public: return _caption.original(); } bool needsBubble(const HistoryItem *parent) const override { - return !_caption.isEmpty() || parent->Is() || parent->toHistoryReply() || parent->viaBot(); + return !_caption.isEmpty() || parent->Has() || parent->Has() || parent->viaBot(); } bool customInfoLayout() const override { return _caption.isEmpty(); @@ -1819,7 +1887,7 @@ public: return _caption.original(); } bool needsBubble(const HistoryItem *parent) const override { - return !_caption.isEmpty() || parent->Is() || parent->toHistoryReply() || parent->viaBot(); + return !_caption.isEmpty() || parent->Has() || parent->Has() || parent->viaBot(); } bool customInfoLayout() const override { return _caption.isEmpty(); @@ -1850,25 +1918,25 @@ private: }; -struct HistoryDocumentThumbed : public BasicInterface { - HistoryDocumentThumbed(Interfaces *interfaces) : _thumbw(0), _linkw(0) { +struct HistoryDocumentThumbed : public BaseComponent { + HistoryDocumentThumbed(Composer*) { } TextLinkPtr _linksavel, _linkcancell; - int32 _thumbw; + int _thumbw = 0; - mutable int32 _linkw; + mutable int _linkw = 0; mutable QString _link; }; -struct HistoryDocumentCaptioned : public BasicInterface { - HistoryDocumentCaptioned(Interfaces *interfaces) : _caption(st::msgFileMinWidth - st::msgPadding.left() - st::msgPadding.right()) { +struct HistoryDocumentCaptioned : public BaseComponent { + HistoryDocumentCaptioned(Composer*) : _caption(st::msgFileMinWidth - st::msgPadding.left() - st::msgPadding.right()) { } Text _caption; }; -struct HistoryDocumentNamed : public BasicInterface { - HistoryDocumentNamed(Interfaces *interfaces) : _namew(0) { +struct HistoryDocumentNamed : public BaseComponent { + HistoryDocumentNamed(Composer*) { } QString _name; - int32 _namew; + int _namew = 0; }; class HistoryDocument; struct HistoryDocumentVoicePlayback { @@ -1878,18 +1946,22 @@ struct HistoryDocumentVoicePlayback { anim::fvalue a_progress; Animation _a_progress; }; -struct HistoryDocumentVoice : public BasicInterface { - HistoryDocumentVoice(Interfaces *that) : _playback(0) { +struct HistoryDocumentVoice : public BaseComponent { + HistoryDocumentVoice(Composer*) { + } + HistoryDocumentVoice &operator=(HistoryDocumentVoice &&other) { + std::swap(_playback, other._playback); + return *this; } ~HistoryDocumentVoice() { deleteAndMark(_playback); } void ensurePlayback(const HistoryDocument *interfaces) const; void checkPlaybackFinished() const; - mutable HistoryDocumentVoicePlayback *_playback; + mutable HistoryDocumentVoicePlayback *_playback = nullptr; }; -class HistoryDocument : public HistoryFileMedia, public Interfaces { +class HistoryDocument : public HistoryFileMedia, public Composer { public: HistoryDocument(DocumentData *document, const QString &caption, const HistoryItem *parent); @@ -2021,7 +2093,7 @@ public: return _caption.original(); } bool needsBubble(const HistoryItem *parent) const override { - return !_caption.isEmpty() || parent->Is() || parent->toHistoryReply() || parent->viaBot(); + return !_caption.isEmpty() || parent->Has() || parent->Has() || parent->viaBot(); } bool customInfoLayout() const override { return _caption.isEmpty(); @@ -2327,7 +2399,7 @@ public: } bool needsBubble(const HistoryItem *parent) const { - return !_title.isEmpty() || !_description.isEmpty() || parent->Is() || parent->toHistoryReply() || parent->viaBot(); + return !_title.isEmpty() || !_description.isEmpty() || parent->Has() || parent->Has() || parent->viaBot(); } bool customInfoLayout() const { return true; @@ -2365,14 +2437,14 @@ public: static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *fwd) { return _create(history, msgId, flags, date, from, fwd); } - static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities) { - return _create(history, msgId, flags, viaBotId, date, from, msg, entities); + static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities) { + return _create(history, msgId, flags, replyTo, viaBotId, date, from, msg, entities); } - static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption) { - return _create(history, msgId, flags, viaBotId, date, from, doc, caption); + static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption) { + return _create(history, msgId, flags, replyTo, viaBotId, date, from, doc, caption); } - static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption) { - return _create(history, msgId, flags, viaBotId, date, from, photo, caption); + static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption) { + return _create(history, msgId, flags, replyTo, viaBotId, date, from, photo, caption); } void initTime(); @@ -2380,13 +2452,6 @@ public: void initMediaFromDocument(DocumentData *doc, const QString &caption); void fromNameUpdated(int32 width) const; - virtual UserData *viaBot() const override { - if (const HistoryMessageVia *via = Get()) { - return via->_bot; - } - return 0; - } - int32 plainMaxWidth() const; void countPositionAndSize(int32 &left, int32 &width) const; @@ -2403,7 +2468,7 @@ public: if (!hasFromName()) return false; if (isAttachedToPrevious()) return false; - return (!emptyText() || !_media || !_media->isDisplayed() || toHistoryReply() || Is() || viaBot() || !_media->hideFromName()); + return (!emptyText() || !_media || !_media->isDisplayed() || Has() || Has() || viaBot() || !_media->hideFromName()); } bool uploading() const { return _media && _media->uploading(); @@ -2414,7 +2479,7 @@ public: void setId(MsgId newId) override; void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const override; - virtual void drawMessageText(Painter &p, QRect trect, uint32 selection) const; + void dependencyItemRemoved(HistoryItem *dependency) override; void destroy() override; @@ -2422,7 +2487,6 @@ public: bool pointInTime(int32 right, int32 bottom, int32 x, int32 y, InfoDisplayType type) const override; void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const override; - virtual void getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const QRect &r) const; void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const override; uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const override { @@ -2491,6 +2555,16 @@ public: return HistoryItem::viewsCount(); } + bool updateDependencyItem() override { + if (auto *reply = Get()) { + return reply->updateData(this, true); + } + return true; + } + MsgId dependencyMsgId() const override { + return replyToId(); + } + HistoryMessage *toHistoryMessage() override { // dynamic_cast optimize return this; } @@ -2509,23 +2583,26 @@ protected: HistoryMessage(History *history, const MTPDmessage &msg); HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *fwd); // local forwarded - HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities); // local message - HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption); // local document - HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption); // local photo + HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities); // local message + HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption); // local document + HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption); // local photo friend class HistoryItemInstantiated; void initDimensions() override; int resizeGetHeight_(int width) override; - void createInterfaces(int32 viaBotId, int32 viewsCount, const PeerId &authorIdOriginal = 0, const PeerId &fromIdOriginal = 0, MsgId originalId = 0); - bool displayForwardedFrom() const { if (const HistoryMessageForwarded *fwd = Get()) { - return Is() || !_media || !_media->isDisplayed() || fwd->_authorOriginal->isChannel() || !_media->hideForwardedFrom(); + return Has() || !_media || !_media->isDisplayed() || fwd->_authorOriginal->isChannel() || !_media->hideForwardedFrom(); } return false; } - void paintForwardedInfo(Painter &p, int32 x, int32 y, int32 w, bool selected) const; + + void paintForwardedInfo(Painter &p, QRect &trect, bool selected) const; + void paintReplyInfo(Painter &p, QRect &trect, bool selected) const; + + // this method draws "via @bot" if it is not painted in forwarded info or in from name + void paintViaBotIdInfo(Painter &p, QRect &trect, bool selected) const; Text _text = { int(st::msgMinWidth) }; @@ -2536,79 +2613,8 @@ protected: QString _timeText; int _timeWidth = 0; -}; - -class HistoryReply : public HistoryMessage, private HistoryItemInstantiated { -public: - - static HistoryReply *create(History *history, const MTPDmessage &msg) { - return _create(history, msg); - } - static HistoryReply *create(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption) { - return _create(history, msgId, flags, viaBotId, replyTo, date, from, doc, caption); - } - static HistoryReply *create(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption) { - return _create(history, msgId, flags, viaBotId, replyTo, date, from, photo, caption); - } - - bool updateDependencyItem() override { - return updateReplyTo(true); - } - MsgId dependencyMsgId() const override { - return replyToId(); - } - int32 replyToWidth() const; - - TextLinkPtr replyToLink() const; - - MsgId replyToId() const; - HistoryItem *replyToMessage() const; - void dependencyItemRemoved(HistoryItem *dependency) override; - - void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const override; - void drawReplyTo(Painter &p, int32 x, int32 y, int32 w, bool selected, bool likeService = false) const; - void drawMessageText(Painter &p, QRect trect, uint32 selection) const override; - void resizeVia(int32 w) const; - void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const override; - void getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const QRect &r) const override; - void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const override; - - PeerData *replyTo() const { - return replyToMsg ? replyToMsg->author() : 0; - } - QString selectedText(uint32 selection) const override; - - HistoryReply *toHistoryReply() override { // dynamic_cast optimize - return this; - } - const HistoryReply *toHistoryReply() const override { // dynamic_cast optimize - return this; - } - - ~HistoryReply(); - -protected: - - HistoryReply(History *history, const MTPDmessage &msg); - HistoryReply(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption); - HistoryReply(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption); - using HistoryItemInstantiated::_create; - friend class HistoryItemInstantiated; - - void initDimensions() override; - int resizeGetHeight_(int width) override; - - bool updateReplyTo(bool force = false); - void replyToNameUpdated() const; - - MsgId replyToMsgId; - HistoryItem *replyToMsg; - TextLinkPtr replyToLnk; - mutable Text replyToName, replyToText; - mutable int32 replyToVersion; - mutable int32 _maxReplyWidth; - HistoryMessageVia *_replyToVia; - int32 toWidth; + void createInterfacesHelper(MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId); + void createInterfaces(MsgId replyTo, int32 viaBotId, int32 viewsCount, const PeerId &authorIdOriginal = 0, const PeerId &fromIdOriginal = 0, MsgId originalId = 0); }; @@ -2627,7 +2633,7 @@ inline MTPDmessage::Flags newForwardedFlags(PeerData *p, int32 from, HistoryMess if (from) { result |= MTPDmessage::Flag::f_from_id; } - if (fwd->Is()) { + if (fwd->Has()) { result |= MTPDmessage::Flag::f_via_bot_id; } if (!p->isChannel()) { @@ -2642,21 +2648,22 @@ inline MTPDmessage::Flags newForwardedFlags(PeerData *p, int32 from, HistoryMess return result; } -struct HistoryServicePinned : public BasicInterface { - HistoryServicePinned(Interfaces *); +struct HistoryServicePinned : public BaseComponent { + HistoryServicePinned(Composer*) { + } - MsgId msgId; - HistoryItem *msg; + MsgId msgId = 0; + HistoryItem *msg = nullptr; TextLinkPtr lnk; }; -class HistoryServiceMessage : public HistoryItem, private HistoryItemInstantiated { +class HistoryService : public HistoryItem, private HistoryItemInstantiated { public: - static HistoryServiceMessage *create(History *history, const MTPDmessageService &msg) { + static HistoryService *create(History *history, const MTPDmessageService &msg) { return _create(history, msg); } - static HistoryServiceMessage *create(History *history, MsgId msgId, QDateTime date, const QString &msg, MTPDmessage::Flags flags = 0, HistoryMedia *media = 0, int32 from = 0) { + static HistoryService *create(History *history, MsgId msgId, QDateTime date, const QString &msg, MTPDmessage::Flags flags = 0, HistoryMedia *media = 0, int32 from = 0) { return _create(history, msgId, date, msg, flags, media, from); } @@ -2710,13 +2717,13 @@ public: void setServiceText(const QString &text); - ~HistoryServiceMessage(); + ~HistoryService(); protected: - HistoryServiceMessage(History *history, const MTPDmessageService &msg); - HistoryServiceMessage(History *history, MsgId msgId, QDateTime date, const QString &msg, MTPDmessage::Flags flags = 0, HistoryMedia *media = 0, int32 from = 0); - friend class HistoryItemInstantiated; + HistoryService(History *history, const MTPDmessageService &msg); + HistoryService(History *history, MsgId msgId, QDateTime date, const QString &msg, MTPDmessage::Flags flags = 0, HistoryMedia *media = 0, int32 from = 0); + friend class HistoryItemInstantiated; void initDimensions() override; int resizeGetHeight_(int width) override; @@ -2731,7 +2738,7 @@ protected: int32 _textWidth, _textHeight; }; -class HistoryGroup : public HistoryServiceMessage, private HistoryItemInstantiated { +class HistoryGroup : public HistoryService, private HistoryItemInstantiated { public: static HistoryGroup *create(History *history, const MTPDmessageGroup &group, const QDateTime &date) { @@ -2787,7 +2794,7 @@ private: }; -class HistoryCollapse : public HistoryServiceMessage, private HistoryItemInstantiated { +class HistoryCollapse : public HistoryService, private HistoryItemInstantiated { public: static HistoryCollapse *create(History *history, MsgId wasMinId, const QDateTime &date) { @@ -2822,7 +2829,7 @@ private: }; -class HistoryJoined : public HistoryServiceMessage, private HistoryItemInstantiated { +class HistoryJoined : public HistoryService, private HistoryItemInstantiated { public: static HistoryJoined *create(History *history, const QDateTime &date, UserData *from, MTPDmessage::Flags flags) { diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index ab66e4639..902fe59c5 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -948,7 +948,8 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { PhotoLink *lnkPhoto = dynamic_cast(_contextMenuLnk.data()); DocumentLink *lnkDocument = dynamic_cast(_contextMenuLnk.data()); bool lnkIsVideo = lnkDocument ? lnkDocument->document()->isVideo() : false; - bool lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != 0) : false; + bool lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != nullptr) : false; + bool lnkIsSong = lnkDocument ? (lnkDocument->document()->song() != nullptr) : false; if (lnkPhoto || lnkDocument) { if (isUponSelected > 0) { _menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true); @@ -978,7 +979,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (lnkDocument && !lnkDocument->document()->filepath(DocumentData::FilePathResolveChecked).isEmpty()) { _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true); } - _menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsAudio ? lng_context_save_audio : lng_context_save_file)), this, SLOT(saveContextFile()))->setEnabled(true); + _menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsAudio ? lng_context_save_audio : (lnkIsSong ? lng_context_save_audio_file : lng_context_save_file))), this, SLOT(saveContextFile()))->setEnabled(true); } } if (item && item->hasDirectLink() && isUponSelected != 2 && isUponSelected != -2) { @@ -5996,7 +5997,7 @@ void HistoryWidget::onPhotoUploaded(const FullMsgId &newId, bool silent, const M uint64 randomId = rand_value(); App::historyRegRandom(randomId, newId); History *hist = item->history(); - MsgId replyTo = item->toHistoryReply() ? item->toHistoryReply()->replyToId() : 0; + MsgId replyTo = item->replyToId(); MTPmessages_SendMedia::Flags sendFlags = 0; if (replyTo) { sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id; @@ -6048,7 +6049,7 @@ void HistoryWidget::onDocumentUploaded(const FullMsgId &newId, bool silent, cons uint64 randomId = rand_value(); App::historyRegRandom(randomId, newId); History *hist = item->history(); - MsgId replyTo = item->toHistoryReply() ? item->toHistoryReply()->replyToId() : 0; + MsgId replyTo = item->replyToId(); MTPmessages_SendMedia::Flags sendFlags = 0; if (replyTo) { sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id; @@ -6077,7 +6078,7 @@ void HistoryWidget::onThumbDocumentUploaded(const FullMsgId &newId, bool silent, uint64 randomId = rand_value(); App::historyRegRandom(randomId, newId); History *hist = item->history(); - MsgId replyTo = item->toHistoryReply() ? item->toHistoryReply()->replyToId() : 0; + MsgId replyTo = item->replyToId(); MTPmessages_SendMedia::Flags sendFlags = 0; if (replyTo) { sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id; @@ -6986,7 +6987,7 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() { } else if (_pinnedBar->msgId != pinnedMsgId) { _pinnedBar->msgId = pinnedMsgId; _pinnedBar->msg = 0; - _pinnedBar->text.clean(); + _pinnedBar->text.clear(); updatePinnedBar(); update(); } diff --git a/Telegram/SourceFiles/layout.cpp b/Telegram/SourceFiles/layout.cpp index 87998c2fc..794d81de5 100644 --- a/Telegram/SourceFiles/layout.cpp +++ b/Telegram/SourceFiles/layout.cpp @@ -293,9 +293,10 @@ void LayoutAbstractFileItem::setStatusSize(int32 newSize, int32 fullSize, int32 } } -LayoutOverviewDate::LayoutOverviewDate(const QDate &date, bool month) : LayoutItem(OverviewItemInfo::Bit()) +LayoutOverviewDate::LayoutOverviewDate(const QDate &date, bool month) : LayoutItem() , _date(date) , _text(month ? langMonthFull(date) : langDayOfMonthFull(date)) { + AddComponents(OverviewItemInfo::Bit()); } void LayoutOverviewDate::initDimensions() { @@ -311,7 +312,7 @@ void LayoutOverviewDate::paint(Painter &p, const QRect &clip, uint32 selection, } } -LayoutOverviewPhoto::LayoutOverviewPhoto(PhotoData *photo, HistoryItem *parent) : LayoutMediaItem(0, parent) +LayoutOverviewPhoto::LayoutOverviewPhoto(PhotoData *photo, HistoryItem *parent) : LayoutMediaItem(parent) , _data(photo) , _link(new PhotoLink(photo)) , _goodLoaded(false) { @@ -385,7 +386,7 @@ void LayoutOverviewPhoto::getState(TextLinkPtr &link, HistoryCursorState &cursor } } -LayoutOverviewVideo::LayoutOverviewVideo(DocumentData *video, HistoryItem *parent) : LayoutAbstractFileItem(0, parent) +LayoutOverviewVideo::LayoutOverviewVideo(DocumentData *video, HistoryItem *parent) : LayoutAbstractFileItem(parent) , _data(video) , _duration(formatDurationText(_data->duration())) , _thumbLoaded(false) { @@ -549,9 +550,11 @@ void LayoutOverviewVideo::updateStatusText() const { } } -LayoutOverviewVoice::LayoutOverviewVoice(DocumentData *voice, HistoryItem *parent) : LayoutAbstractFileItem(OverviewItemInfo::Bit(), parent) +LayoutOverviewVoice::LayoutOverviewVoice(DocumentData *voice, HistoryItem *parent) : LayoutAbstractFileItem(parent) , _data(voice) , _namel(new DocumentOpenLink(_data)) { + AddComponents(OverviewItemInfo::Bit()); + t_assert(_data->voice() != 0); setLinks(new DocumentOpenLink(_data), new DocumentOpenLink(_data), new DocumentCancelLink(_data)); @@ -741,7 +744,7 @@ bool LayoutOverviewVoice::updateStatusText() const { return showPause; } -LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryItem *parent) : LayoutAbstractFileItem(OverviewItemInfo::Bit(), parent) +LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryItem *parent) : LayoutAbstractFileItem(parent) , _data(document) , _msgl(new MessageLink(parent)) , _namel(new DocumentOpenLink(_data)) @@ -751,6 +754,8 @@ LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryIt , _namew(st::semiboldFont->width(_name)) , _datew(st::normalFont->width(_date)) , _colorIndex(documentColorIndex(_data, _ext)) { + AddComponents(OverviewItemInfo::Bit()); + setLinks(new DocumentOpenLink(_data), new DocumentSaveLink(_data), new DocumentCancelLink(_data)); setStatusSize(FileStatusSizeReady, _data->size, _data->song() ? _data->song()->duration : -1, 0); @@ -1066,7 +1071,9 @@ namespace { } } -LayoutOverviewLink::LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent) : LayoutMediaItem(OverviewItemInfo::Bit(), parent) { +LayoutOverviewLink::LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent) : LayoutMediaItem(parent) { + AddComponents(OverviewItemInfo::Bit()); + QString text = _parent->originalText(); EntitiesInText entities = _parent->originalEntities(); @@ -1319,7 +1326,7 @@ LayoutOverviewLink::Link::Link(const QString &url, const QString &text) , lnk(linkFromUrl(url)) { } -LayoutInlineItem::LayoutInlineItem(InlineResult *result, DocumentData *doc, PhotoData *photo) : LayoutItem(0) +LayoutInlineItem::LayoutInlineItem(InlineResult *result, DocumentData *doc, PhotoData *photo) : LayoutItem() , _result(result) , _doc(doc) , _photo(photo) diff --git a/Telegram/SourceFiles/layout.h b/Telegram/SourceFiles/layout.h index d52d1e3eb..a91d83bb2 100644 --- a/Telegram/SourceFiles/layout.h +++ b/Telegram/SourceFiles/layout.h @@ -101,10 +101,11 @@ public: }; class LayoutMediaItem; -class LayoutItem : public Interfaces { +class LayoutItem : public Composer { public: - LayoutItem(uint64 i_mask) : Interfaces(i_mask), _maxw(0), _minh(0) { + LayoutItem() { } + LayoutItem &operator=(const LayoutItem &) = delete; int32 maxWidth() const { return _maxw; @@ -167,14 +168,16 @@ public: } protected: - int32 _width, _height, _maxw, _minh; - LayoutItem &operator=(const LayoutItem &); + int _width = 0; + int _height = 0; + int _maxw = 0; + int _minh = 0; }; class LayoutMediaItem : public LayoutItem { public: - LayoutMediaItem(uint64 i_mask, HistoryItem *parent) : LayoutItem(i_mask), _parent(parent) { + LayoutMediaItem(HistoryItem *parent) : _parent(parent) { } virtual LayoutMediaItem *toLayoutMediaItem() { @@ -194,7 +197,7 @@ protected: class LayoutRadialProgressItem : public LayoutMediaItem { public: - LayoutRadialProgressItem(uint64 i_mask, HistoryItem *parent) : LayoutMediaItem(i_mask, parent) + LayoutRadialProgressItem(HistoryItem *parent) : LayoutMediaItem(parent) , _radial(0) , a_iconOver(0, 0) , _a_iconOver(animation(this, &LayoutRadialProgressItem::step_iconOver)) { @@ -240,7 +243,7 @@ private: class LayoutAbstractFileItem : public LayoutRadialProgressItem { public: - LayoutAbstractFileItem(uint64 i_mask, HistoryItem *parent) : LayoutRadialProgressItem(i_mask, parent) { + LayoutAbstractFileItem(HistoryItem *parent) : LayoutRadialProgressItem(parent) { } protected: @@ -268,19 +271,19 @@ public: }; -class OverviewItemInfo : public BasicInterface { +class OverviewItemInfo : public BaseComponent { public: - OverviewItemInfo(Interfaces *) : _top(0) { + OverviewItemInfo(Composer*) { } - int32 top() const { + int top() const { return _top; } - void setTop(int32 top) { + void setTop(int top) { _top = top; } private: - int32 _top; + int _top = 0; }; diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 16fed59d5..035b1b5a3 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -3550,7 +3550,7 @@ namespace Local { return result; } - void _writePeer(QDataStream &stream, PeerData *peer, int32 fileVersion = AppVersion) { + void _writePeer(QDataStream &stream, PeerData *peer) { stream << quint64(peer->id) << quint64(peer->photoId); _writeStorageImageLocation(stream, peer->photoLoc); if (peer->isUser()) { @@ -3560,7 +3560,7 @@ namespace Local { if (AppVersion >= 9012) { stream << qint32(user->flags); } - if (AppVersion >= 9016 || fileVersion >= 9016) { + if (AppVersion >= 9016) { stream << (user->botInfo ? user->botInfo->inlinePlaceholder : QString()); } stream << qint32(user->onlineTill) << qint32(user->contact) << qint32(user->botInfo ? user->botInfo->version : -1); @@ -3580,18 +3580,16 @@ namespace Local { } PeerData *_readPeer(FileReadDescriptor &from, int32 fileVersion = 0) { - PeerData *result = 0; quint64 peerId = 0, photoId = 0; from.stream >> peerId >> photoId; StorageImageLocation photoLoc(_readStorageImageLocation(from)); - result = App::peerLoaded(peerId); - bool wasLoaded = (result && result->loaded); - + PeerData *result = App::peerLoaded(peerId); + bool wasLoaded = (result != nullptr); if (!wasLoaded) { result = App::peer(peerId); - result->loaded = true; + result->loadedStatus = PeerData::FullLoaded; } if (result->isUser()) { UserData *user = result->asUser(); @@ -3737,7 +3735,7 @@ namespace Local { } data.stream << quint32(botsCnt); for (RecentInlineBots::const_iterator i = bots.cbegin(), e = bots.cend(); i != e; ++i) { - _writePeer(data.stream, *i, 9016); + _writePeer(data.stream, *i); } FileWriteDescriptor file(_recentHashtagsAndBotsKey); file.writeEncrypted(data); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 1833b4296..2f2805d1e 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4099,17 +4099,17 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { case mtpc_updateShortMessage: { const MTPDupdateShortMessage &d(updates.c_updateShortMessage()); - if (!App::userLoaded(d.vuser_id.v) || (d.has_via_bot_id() && !App::peerLoaded(peerFromUser(d.vvia_bot_id)))) { + if (!App::userLoaded(d.vuser_id.v) || (d.has_via_bot_id() && !App::userLoaded(d.vvia_bot_id.v))) { MTP_LOG(0, ("getDifference { good - getting user for updateShortMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); return getDifference(); } if (d.has_fwd_from() && d.vfwd_from.type() == mtpc_messageFwdHeader) { const MTPDmessageFwdHeader &f(d.vfwd_from.c_messageFwdHeader()); - if (f.has_from_id() && !App::peerLoaded(peerFromUser(f.vfrom_id))) { + if (f.has_from_id() && !App::userLoaded(f.vfrom_id.v)) { MTP_LOG(0, ("getDifference { good - getting user for updateShortMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); return getDifference(); } - if (f.has_channel_id() && !App::peerLoaded(peerFromChannel(f.vchannel_id))) { + if (f.has_channel_id() && !App::channelLoaded(f.vchannel_id.v)) { MTP_LOG(0, ("getDifference { good - getting user for updateShortMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); return getDifference(); } @@ -4133,18 +4133,18 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { case mtpc_updateShortChatMessage: { const MTPDupdateShortChatMessage &d(updates.c_updateShortChatMessage()); bool noFrom = !App::userLoaded(d.vfrom_id.v); - if (!App::chatLoaded(d.vchat_id.v) || noFrom || (d.has_via_bot_id() && !App::peerLoaded(peerFromUser(d.vvia_bot_id)))) { + if (!App::chatLoaded(d.vchat_id.v) || noFrom || (d.has_via_bot_id() && !App::userLoaded(d.vvia_bot_id.v))) { MTP_LOG(0, ("getDifference { good - getting user for updateShortChatMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); if (noFrom && App::api()) App::api()->requestFullPeer(App::chatLoaded(d.vchat_id.v)); return getDifference(); } if (d.has_fwd_from() && d.vfwd_from.type() == mtpc_messageFwdHeader) { const MTPDmessageFwdHeader &f(d.vfwd_from.c_messageFwdHeader()); - if (f.has_from_id() && !App::peerLoaded(peerFromUser(f.vfrom_id))) { + if (f.has_from_id() && !App::userLoaded(f.vfrom_id.v)) { MTP_LOG(0, ("getDifference { good - getting user for updateShortChatMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); return getDifference(); } - if (f.has_channel_id() && !App::peerLoaded(peerFromChannel(f.vchannel_id))) { + if (f.has_channel_id() && !App::channelLoaded(f.vchannel_id.v)) { MTP_LOG(0, ("getDifference { good - getting user for updateShortChatMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); return getDifference(); } @@ -4357,9 +4357,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updateChatUserTyping: { const MTPDupdateChatUserTyping &d(update.c_updateChatUserTyping()); History *history = 0; - if (PeerData *chat = App::peerLoaded(peerFromChat(d.vchat_id.v))) { + if (PeerData *chat = App::chatLoaded(d.vchat_id.v)) { history = App::historyLoaded(chat->id); - } else if (PeerData *channel = App::peerLoaded(peerFromChannel(d.vchat_id.v))) { + } else if (PeerData *channel = App::channelLoaded(d.vchat_id.v)) { history = App::historyLoaded(channel->id); } UserData *user = (d.vuser_id.v == MTP::authedId()) ? 0 : App::userLoaded(d.vuser_id.v); diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index c75c84698..f0c06c53d 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -1267,8 +1267,9 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { _contextMenuLnk = textlnkOver(); PhotoLink *lnkPhoto = dynamic_cast(_contextMenuLnk.data()); DocumentLink *lnkDocument = dynamic_cast(_contextMenuLnk.data()); - bool lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != 0) : false; bool lnkIsVideo = lnkDocument ? lnkDocument->document()->isVideo() : false; + bool lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != nullptr) : false; + bool lnkIsSong = lnkDocument ? (lnkDocument->document()->song() != nullptr) : false; if (lnkPhoto || lnkDocument) { _menu = new PopupMenu(); if (App::hoveredLinkItem()) { @@ -1282,7 +1283,7 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (lnkDocument && !lnkDocument->document()->filepath(DocumentData::FilePathResolveChecked).isEmpty()) { _menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true); } - _menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsAudio ? lng_context_save_audio : lng_context_save_file)), this, SLOT(saveContextFile()))->setEnabled(true); + _menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsAudio ? lng_context_save_audio : (lnkIsSong ? lng_context_save_audio_file : lng_context_save_file))), this, SLOT(saveContextFile()))->setEnabled(true); } } if (isUponSelected > 1) { diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 0426f8620..85932fb31 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -35,8 +35,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "localstorage.h" namespace { - int32 peerColorIndex(const PeerId &peer) { - int32 myId(MTP::authedId()), peerId(peerToBareInt(peer)); + int peerColorIndex(const PeerId &peer) { + UserId myId(MTP::authedId()), peerId(peerToBareInt(peer)); QByteArray both(qsl("%1%2").arg(peerId).arg(myId).toUtf8()); if (both.size() > 15) { both = both.mid(0, 15); @@ -47,7 +47,7 @@ namespace { } } -style::color peerColor(int32 index) { +style::color peerColor(int index) { static const style::color peerColors[8] = { style::color(st::color1), style::color(st::color2), @@ -61,7 +61,7 @@ style::color peerColor(int32 index) { return peerColors[index]; } -ImagePtr userDefPhoto(int32 index) { +ImagePtr userDefPhoto(int index) { static const ImagePtr userDefPhotos[UserColorsCount] = { ImagePtr(qsl(":/ava/art/usercolor1.png"), "PNG"), ImagePtr(qsl(":/ava/art/usercolor2.png"), "PNG"), @@ -75,7 +75,7 @@ ImagePtr userDefPhoto(int32 index) { return userDefPhotos[index]; } -ImagePtr chatDefPhoto(int32 index) { +ImagePtr chatDefPhoto(int index) { static const ImagePtr chatDefPhotos[4] = { ImagePtr(qsl(":/ava/art/chatcolor1.png"), "PNG"), ImagePtr(qsl(":/ava/art/chatcolor2.png"), "PNG"), @@ -85,7 +85,7 @@ ImagePtr chatDefPhoto(int32 index) { return chatDefPhotos[index]; } -ImagePtr channelDefPhoto(int32 index) { +ImagePtr channelDefPhoto(int index) { static const ImagePtr channelDefPhotos[4] = { ImagePtr(qsl(":/ava/art/channelcolor1.png"), "PNG"), ImagePtr(qsl(":/ava/art/channelcolor2.png"), "PNG"), @@ -100,7 +100,7 @@ NotifySettingsPtr globalNotifyAllPtr = UnknownNotifySettings, globalNotifyUsersP PeerData::PeerData(const PeerId &id) : id(id) , lnk(new PeerLink(this)) -, loaded(false) +, loadedStatus(NotLoaded) , colorIndex(peerColorIndex(id)) , color(peerColor(colorIndex)) , photoId(UnknownPeerPhotoId) @@ -279,7 +279,7 @@ void UserData::setPhone(const QString &newPhone) { phone = newPhone; } -void UserData::setBotInfoVersion(int32 version) { +void UserData::setBotInfoVersion(int version) { if (version < 0) { if (botInfo) { if (!botInfo->commands.isEmpty()) { @@ -850,7 +850,7 @@ QString documentSaveFilename(const DocumentData *data, bool forceSavingAs = fals } else { filter = mimeType.filterString() + qsl(";;All files (*.*)"); } - caption = lang(lng_save_file); + caption = lang(data->song() ? lng_save_audio_file : lng_save_file); prefix = qsl("doc"); } diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index 4896a0cea..6546a8c03 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -20,9 +20,21 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once +typedef int32 UserId; +typedef int32 ChatId; typedef int32 ChannelId; static const ChannelId NoChannel = 0; +typedef int32 MsgId; +struct FullMsgId { + FullMsgId() : channel(NoChannel), msg(0) { + } + FullMsgId(ChannelId channel, MsgId msg) : channel(channel), msg(msg) { + } + ChannelId channel; + MsgId msg; +}; + typedef uint64 PeerId; static const uint64 PeerIdMask = 0xFFFFFFFFULL; static const uint64 PeerIdTypeMask = 0x300000000ULL; @@ -38,10 +50,10 @@ inline bool peerIsChat(const PeerId &id) { inline bool peerIsChannel(const PeerId &id) { return (id & PeerIdTypeMask) == PeerIdChannelShift; } -inline PeerId peerFromUser(int32 user_id) { +inline PeerId peerFromUser(UserId user_id) { return PeerIdUserShift | uint64(uint32(user_id)); } -inline PeerId peerFromChat(int32 chat_id) { +inline PeerId peerFromChat(ChatId chat_id) { return PeerIdChatShift | uint64(uint32(chat_id)); } inline PeerId peerFromChannel(ChannelId channel_id) { @@ -59,10 +71,10 @@ inline PeerId peerFromChannel(const MTPint &channel_id) { inline int32 peerToBareInt(const PeerId &id) { return int32(uint32(id & PeerIdMask)); } -inline int32 peerToUser(const PeerId &id) { +inline UserId peerToUser(const PeerId &id) { return peerIsUser(id) ? peerToBareInt(id) : 0; } -inline int32 peerToChat(const PeerId &id) { +inline ChatId peerToChat(const PeerId &id) { return peerIsChat(id) ? peerToBareInt(id) : 0; } inline ChannelId peerToChannel(const PeerId &id) { @@ -112,7 +124,7 @@ inline MTPDmessage::Flags flagsFromMessage(const MTPmessage &msg) { } return 0; } -inline int32 idFromMessage(const MTPmessage &msg) { +inline MsgId idFromMessage(const MTPmessage &msg) { switch (msg.type()) { case mtpc_messageEmpty: return msg.c_messageEmpty().vid.v; case mtpc_message: return msg.c_message().vid.v; @@ -120,7 +132,7 @@ inline int32 idFromMessage(const MTPmessage &msg) { } return 0; } -inline int32 dateFromMessage(const MTPmessage &msg) { +inline TimeId dateFromMessage(const MTPmessage &msg) { switch (msg.type()) { case mtpc_message: return msg.c_message().vdate.v; case mtpc_messageService: return msg.c_messageService().vdate.v; @@ -135,15 +147,6 @@ typedef uint64 DocumentId; typedef uint64 WebPageId; static const WebPageId CancelledWebPageId = 0xFFFFFFFFFFFFFFFFULL; -typedef int32 MsgId; -struct FullMsgId { - FullMsgId() : channel(NoChannel), msg(0) { - } - FullMsgId(ChannelId channel, MsgId msg) : channel(channel), msg(msg) { - } - ChannelId channel; - MsgId msg; -}; inline bool operator==(const FullMsgId &a, const FullMsgId &b) { return (a.channel == b.channel) && (a.msg == b.msg); } @@ -168,7 +171,7 @@ struct NotifySettings { NotifySettings() : flags(MTPDpeerNotifySettings::Flag::f_show_previews), mute(0), sound("default") { } MTPDpeerNotifySettings::Flags flags; - int32 mute; + TimeId mute; string sound; bool previews() const { return flags & MTPDpeerNotifySettings::Flag::f_show_previews; @@ -184,9 +187,9 @@ static const NotifySettingsPtr EmptyNotifySettings = NotifySettingsPtr(1); extern NotifySettings globalNotifyAll, globalNotifyUsers, globalNotifyChats; extern NotifySettingsPtr globalNotifyAllPtr, globalNotifyUsersPtr, globalNotifyChatsPtr; -inline bool isNotifyMuted(NotifySettingsPtr settings, int32 *changeIn = 0) { +inline bool isNotifyMuted(NotifySettingsPtr settings, TimeId *changeIn = 0) { if (settings != UnknownNotifySettings && settings != EmptyNotifySettings) { - int32 t = unixtime(); + TimeId t = unixtime(); if (settings->mute > t) { if (changeIn) *changeIn = settings->mute - t + 1; return true; @@ -196,12 +199,12 @@ inline bool isNotifyMuted(NotifySettingsPtr settings, int32 *changeIn = 0) { return false; } -static const int32 UserColorsCount = 8; +static const int UserColorsCount = 8; -style::color peerColor(int32 index); -ImagePtr userDefPhoto(int32 index); -ImagePtr chatDefPhoto(int32 index); -ImagePtr channelDefPhoto(int32 index); +style::color peerColor(int index); +ImagePtr userDefPhoto(int index); +ImagePtr chatDefPhoto(int index); +ImagePtr channelDefPhoto(int index); static const PhotoId UnknownPeerPhotoId = 0xFFFFFFFFFFFFFFFFULL; @@ -276,10 +279,15 @@ public: typedef QSet NameFirstChars; NameFirstChars chars; - bool loaded; + enum LoadedStatus { + NotLoaded = 0x00, + MinimalLoaded = 0x01, + FullLoaded = 0x02, + }; + LoadedStatus loadedStatus; MTPinputPeer input; - int32 colorIndex; + int colorIndex; style::color color; void setUserpic(ImagePtr userpic); @@ -297,7 +305,7 @@ public: PhotoId photoId; StorageImageLocation photoLoc; - int32 nameVersion; + int nameVersion; NotifySettingsPtr notify; @@ -358,7 +366,7 @@ struct BotInfo { } bool inited; bool readsAllHistory, cantJoinGroups; - int32 version; + int version; QString description, inlinePlaceholder; QList commands; Text text; // description @@ -382,7 +390,7 @@ public: void setPhoto(const MTPUserProfilePhoto &photo); void setName(const QString &first, const QString &last, const QString &phoneName, const QString &username); void setPhone(const QString &newPhone); - void setBotInfoVersion(int32 version); + void setBotInfoVersion(int version); void setBotInfo(const MTPBotInfo &info); void setNameOrPhone(const QString &newNameOrPhone); @@ -407,13 +415,13 @@ public: QString phone; QString nameOrPhone; Text phoneText; - int32 onlineTill = 0; + TimeId onlineTill = 0; int32 contact = -1; // -1 - not contact, cant add (self, empty, deleted, foreign), 0 - not contact, can add (request), 1 - contact UserBlockedStatus blocked = UserBlockUnknown; typedef QList Photos; Photos photos; - int32 photosCount = -1; // -1 not loaded, 0 all loaded + int photosCount = -1; // -1 not loaded, 0 all loaded QString about; @@ -462,10 +470,10 @@ public: ChannelData *migrateToPtr; - int32 count; - int32 date; - int32 version; - int32 creator; + int count; + TimeId date; + int version; + UserId creator; MTPDchat::Flags flags; bool isForbidden; @@ -499,7 +507,7 @@ public: bool isMigrated() const { return flags & MTPDchat::Flag::f_migrated_to; } - typedef QMap Participants; + typedef QMap Participants; Participants participants; typedef OrderedSet InvitedByMe; InvitedByMe invitedByMe; @@ -753,29 +761,59 @@ private: }; +inline bool isUser(const PeerData *peer) { + return peer ? peer->isUser() : false; +} inline UserData *PeerData::asUser() { - return isUser() ? static_cast(this) : 0; + return isUser() ? static_cast(this) : nullptr; +} +inline UserData *asUser(PeerData *peer) { + return peer ? peer->asUser() : nullptr; } inline const UserData *PeerData::asUser() const { - return isUser() ? static_cast(this) : 0; + return isUser() ? static_cast(this) : nullptr; +} +inline const UserData *asUser(const PeerData *peer) { + return peer ? peer->asUser() : nullptr; +} +inline bool isChat(const PeerData *peer) { + return peer ? peer->isChat() : false; } inline ChatData *PeerData::asChat() { - return isChat() ? static_cast(this) : 0; + return isChat() ? static_cast(this) : nullptr; +} +inline ChatData *asChat(PeerData *peer) { + return peer ? peer->asChat() : nullptr; } inline const ChatData *PeerData::asChat() const { - return isChat() ? static_cast(this) : 0; + return isChat() ? static_cast(this) : nullptr; +} +inline const ChatData *asChat(const PeerData *peer) { + return peer ? peer->asChat() : nullptr; +} +inline bool isChannel(const PeerData *peer) { + return peer ? peer->isChannel() : false; } inline ChannelData *PeerData::asChannel() { - return isChannel() ? static_cast(this) : 0; + return isChannel() ? static_cast(this) : nullptr; +} +inline ChannelData *asChannel(PeerData *peer) { + return peer ? peer->asChannel() : nullptr; } inline const ChannelData *PeerData::asChannel() const { - return isChannel() ? static_cast(this) : 0; + return isChannel() ? static_cast(this) : nullptr; +} +inline const ChannelData *asChannel(const PeerData *peer) { + return peer ? peer->asChannel() : nullptr; +} +inline bool isMegagroup(const PeerData *peer) { + return peer ? peer->isMegagroup() : false; } inline ChatData *PeerData::migrateFrom() const { - return (isMegagroup() && asChannel()->amIn()) ? asChannel()->mgInfo->migrateFromPtr : 0; + return (isMegagroup() && asChannel()->amIn()) ? asChannel()->mgInfo->migrateFromPtr : nullptr; } inline ChannelData *PeerData::migrateTo() const { - return (isChat() && asChat()->migrateToPtr && asChat()->migrateToPtr->amIn()) ? asChat()->migrateToPtr : 0; + return (isChat() && asChat()->migrateToPtr && asChat()->migrateToPtr->amIn()) ? asChat()->migrateToPtr : nullptr; } inline const Text &PeerData::dialogName() const { return migrateTo() ? migrateTo()->dialogName() : ((isUser() && !asUser()->phoneText.isEmpty()) ? asUser()->phoneText : nameText); @@ -998,11 +1036,14 @@ public: SongData *song() { return (type == SongDocument) ? static_cast(_additional) : 0; } + const SongData *song() const { + return (type == SongDocument) ? static_cast(_additional) : 0; + } VoiceData *voice() { return (type == VoiceDocument) ? static_cast(_additional) : 0; } const VoiceData *voice() const { - return (type == VoiceDocument) ? static_cast(_additional) : 0; + return (type == VoiceDocument) ? static_cast(_additional) : 0; } bool isAnimation() const { return (type == AnimatedDocument) || !mime.compare(qstr("image/gif"), Qt::CaseInsensitive); diff --git a/Telegram/SourceFiles/types.cpp b/Telegram/SourceFiles/types.cpp index 6f0b408d9..e4541be90 100644 --- a/Telegram/SourceFiles/types.cpp +++ b/Telegram/SourceFiles/types.cpp @@ -120,8 +120,8 @@ namespace { } } -int32 myunixtime() { - return (int32)time(NULL); +TimeId myunixtime() { + return (TimeId)time(NULL); } void unixtimeInit() { @@ -149,19 +149,19 @@ void unixtimeSet(int32 serverTime, bool force) { _initMsgIdConstants(); } -int32 unixtime() { - int32 result = myunixtime(); +TimeId unixtime() { + TimeId result = myunixtime(); QReadLocker locker(&unixtimeLock); return result + unixtimeDelta; } -int32 fromServerTime(const MTPint &serverTime) { +TimeId fromServerTime(const MTPint &serverTime) { QReadLocker locker(&unixtimeLock); return serverTime.v - unixtimeDelta; } -MTPint toServerTime(const int32 &clientTime) { +MTPint toServerTime(const TimeId &clientTime) { QReadLocker locker(&unixtimeLock); return MTP_int(clientTime + unixtimeDelta); } @@ -1034,35 +1034,32 @@ MimeType mimeTypeForData(const QByteArray &data) { return MimeType(QMimeDatabase().mimeTypeForData(data)); } -class InterfacesMetadatasMap : public QMap { -public: - ~InterfacesMetadatasMap() { - for (const_iterator i = cbegin(), e = cend(); i != e; ++i) { - delete i.value(); +struct ComposerMetadatasMap { + QMap data; + ~ComposerMetadatasMap() { + for_const (const ComposerMetadata *p, data) { + delete p; } } }; -const InterfacesMetadata *GetInterfacesMetadata(uint64 mask) { - typedef QMap InterfacesMetadatasMap; - static InterfacesMetadatasMap InterfacesMetadatas; - static QMutex InterfacesMetadatasMutex; +const ComposerMetadata *GetComposerMetadata(uint64 mask) { + static ComposerMetadatasMap ComposerMetadatas; + static QMutex ComposerMetadatasMutex; - QMutexLocker lock(&InterfacesMetadatasMutex); - InterfacesMetadatasMap::const_iterator i = InterfacesMetadatas.constFind(mask); - if (i == InterfacesMetadatas.cend()) { - InterfacesMetadata *meta = new InterfacesMetadata(mask); - if (!meta) { // terminate if we can't allocate memory - throw "Can't allocate memory!"; - } + QMutexLocker lock(&ComposerMetadatasMutex); + auto i = ComposerMetadatas.data.constFind(mask); + if (i == ComposerMetadatas.data.cend()) { + ComposerMetadata *meta = new ComposerMetadata(mask); + t_assert(meta != nullptr); - i = InterfacesMetadatas.insert(mask, meta); + i = ComposerMetadatas.data.insert(mask, meta); } return i.value(); } -const InterfacesMetadata *Interfaces::ZeroInterfacesMetadata = GetInterfacesMetadata(0); +const ComposerMetadata *Composer::ZeroComposerMetadata = GetComposerMetadata(0); -InterfaceWrapStruct InterfaceWraps[64]; +ComponentWrapStruct ComponentWraps[64]; -QAtomicInt InterfaceIndexLast(0); +QAtomicInt ComponentIndexLast; diff --git a/Telegram/SourceFiles/types.h b/Telegram/SourceFiles/types.h index fd6ea2438..4d3263332 100644 --- a/Telegram/SourceFiles/types.h +++ b/Telegram/SourceFiles/types.h @@ -104,6 +104,30 @@ using std::string; using std::exception; using std::swap; +// we copy some parts of C++11 std:: library, because on OS X 10.6+ +// version we can use C++11, but we can't use its library :( +namespace std11 { + +template +struct remove_reference { + typedef T type; +}; +template +struct remove_reference { + typedef T type; +}; +template +struct remove_reference { + typedef T type; +}; + +template +inline typename remove_reference::type &&move(T &&value) { + return static_cast::type&&>(value); +} + +} // namespace std11 + #include "logs.h" static volatile int *t_assert_nullptr = 0; @@ -140,12 +164,12 @@ private: }; class MTPint; - -int32 myunixtime(); +typedef int32 TimeId; +TimeId myunixtime(); void unixtimeInit(); -void unixtimeSet(int32 servertime, bool force = false); -int32 unixtime(); -int32 fromServerTime(const MTPint &serverTime); +void unixtimeSet(TimeId servertime, bool force = false); +TimeId unixtime(); +TimeId fromServerTime(const MTPint &serverTime); uint64 msgid(); int32 reqid(); @@ -541,24 +565,26 @@ inline void destroyImplementation(I *&ptr) { deleteAndMark(ptr); } -class Interfaces; -typedef void(*InterfaceConstruct)(void *location, Interfaces *interfaces); -typedef void(*InterfaceDestruct)(void *location); -typedef void(*InterfaceMove)(void *location, void *waslocation); +class Composer; +typedef void(*ComponentConstruct)(void *location, Composer *composer); +typedef void(*ComponentDestruct)(void *location); +typedef void(*ComponentMove)(void *location, void *waslocation); -struct InterfaceWrapStruct { - InterfaceWrapStruct() : Size(0), Construct(0), Destruct(0) { +struct ComponentWrapStruct { + // don't init any fields, because it is only created in + // global scope, so it will be filled by zeros from the start + ComponentWrapStruct() { } - InterfaceWrapStruct(int size, InterfaceConstruct construct, InterfaceDestruct destruct, InterfaceMove move) + ComponentWrapStruct(int size, ComponentConstruct construct, ComponentDestruct destruct, ComponentMove move) : Size(size) , Construct(construct) , Destruct(destruct) , Move(move) { } int Size; - InterfaceConstruct Construct; - InterfaceDestruct Destruct; - InterfaceMove Move; + ComponentConstruct Construct; + ComponentDestruct Destruct; + ComponentMove Move; }; template @@ -567,36 +593,43 @@ struct CeilDivideMinimumOne { }; template -struct InterfaceWrapTemplate { +struct ComponentWrapTemplate { static const int Size = CeilDivideMinimumOne::Result * sizeof(uint64); - static void Construct(void *location, Interfaces *interfaces) { - new (location) Type(interfaces); + static void Construct(void *location, Composer *composer) { + new (location) Type(composer); } static void Destruct(void *location) { ((Type*)location)->~Type(); } static void Move(void *location, void *waslocation) { - *(Type*)location = *(Type*)waslocation; + *(Type*)location = std11::move(*(Type*)waslocation); } }; -extern InterfaceWrapStruct InterfaceWraps[64]; -extern QAtomicInt InterfaceIndexLast; +extern ComponentWrapStruct ComponentWraps[64]; +extern QAtomicInt ComponentIndexLast; template -class BasicInterface { +class BaseComponent { public: + BaseComponent() { + } + BaseComponent(const BaseComponent &other) = delete; + BaseComponent &operator=(const BaseComponent &other) = delete; + BaseComponent(BaseComponent &&other) = delete; + BaseComponent &operator=(BaseComponent &&other) = default; + static int Index() { static QAtomicInt _index(0); if (int index = _index.loadAcquire()) { return index - 1; } while (true) { - int last = InterfaceIndexLast.loadAcquire(); - if (InterfaceIndexLast.testAndSetOrdered(last, last + 1)) { + int last = ComponentIndexLast.loadAcquire(); + if (ComponentIndexLast.testAndSetOrdered(last, last + 1)) { t_assert(last < 64); if (_index.testAndSetOrdered(0, last + 1)) { - InterfaceWraps[last] = InterfaceWrapStruct(InterfaceWrapTemplate::Size, InterfaceWrapTemplate::Construct, InterfaceWrapTemplate::Destruct, InterfaceWrapTemplate::Move); + ComponentWraps[last] = ComponentWrapStruct(ComponentWrapTemplate::Size, ComponentWrapTemplate::Construct, ComponentWrapTemplate::Destruct, ComponentWrapTemplate::Move); } break; } @@ -609,22 +642,14 @@ public: }; -template -class BasicInterfaceWithPointer : public BasicInterface { -public: - BasicInterfaceWithPointer(Interfaces *interfaces) : interfaces(interfaces) { - } - Interfaces *interfaces = 0; -}; - -class InterfacesMetadata { +class ComposerMetadata { public: - InterfacesMetadata(uint64 mask) : size(0), last(64), _mask(mask) { + ComposerMetadata(uint64 mask) : size(0), last(64), _mask(mask) { for (int i = 0; i < 64; ++i) { uint64 m = (1 << i); if (_mask & m) { - int s = InterfaceWraps[i].Size; + int s = ComponentWraps[i].Size; if (s) { offsets[i] = size; size += s; @@ -660,15 +685,15 @@ private: }; -const InterfacesMetadata *GetInterfacesMetadata(uint64 mask); +const ComposerMetadata *GetComposerMetadata(uint64 mask); -class Interfaces { +class Composer { public: - Interfaces(uint64 mask = 0) : _data(zerodata()) { + Composer(uint64 mask = 0) : _data(zerodata()) { if (mask) { - const InterfacesMetadata *meta = GetInterfacesMetadata(mask); - int32 size = sizeof(const InterfacesMetadata *) + meta->size; + const ComposerMetadata *meta = GetComposerMetadata(mask); + int size = sizeof(meta) + meta->size; void *data = operator new(size); if (!data) { // terminate if we can't allocate memory throw "Can't allocate memory!"; @@ -680,13 +705,13 @@ public: int offset = meta->offsets[i]; if (offset >= 0) { try { - InterfaceWraps[i].Construct(_dataptrunsafe(offset), this); + ComponentWraps[i].Construct(_dataptrunsafe(offset), this); } catch (...) { while (i > 0) { --i; offset = meta->offsets[--i]; if (offset >= 0) { - InterfaceWraps[i].Destruct(_dataptrunsafe(offset)); + ComponentWraps[i].Destruct(_dataptrunsafe(offset)); } } throw; @@ -695,38 +720,41 @@ public: } } } - void UpdateInterfaces(uint64 mask = 0) { + Composer(const Composer &other) = delete; + Composer &operator=(const Composer &other) = delete; + ~Composer() { + if (_data != zerodata()) { + const ComposerMetadata *meta = _meta(); + for (int i = 0; i < meta->last; ++i) { + int offset = meta->offsets[i]; + if (offset >= 0) { + ComponentWraps[i].Destruct(_dataptrunsafe(offset)); + } + } + operator delete(_data); + } + } + + void UpdateComponents(uint64 mask = 0) { if (!_meta()->equals(mask)) { - Interfaces tmp(mask); + Composer tmp(mask); tmp.swap(*this); if (_data != zerodata() && tmp._data != zerodata()) { - const InterfacesMetadata *meta = _meta(), *wasmeta = tmp._meta(); + const ComposerMetadata *meta = _meta(), *wasmeta = tmp._meta(); for (int i = 0; i < meta->last; ++i) { int offset = meta->offsets[i], wasoffset = wasmeta->offsets[i]; if (offset >= 0 && wasoffset >= 0) { - InterfaceWraps[i].Move(_dataptrunsafe(offset), tmp._dataptrunsafe(wasoffset)); + ComponentWraps[i].Move(_dataptrunsafe(offset), tmp._dataptrunsafe(wasoffset)); } } } } } - void AddInterfaces(uint64 mask = 0) { - UpdateInterfaces(_meta()->maskadd(mask)); + void AddComponents(uint64 mask = 0) { + UpdateComponents(_meta()->maskadd(mask)); } - void RemoveInterfaces(uint64 mask = 0) { - UpdateInterfaces(_meta()->maskremove(mask)); - } - ~Interfaces() { - if (_data != zerodata()) { - const InterfacesMetadata *meta = _meta(); - for (int i = 0; i < meta->last; ++i) { - int offset = meta->offsets[i]; - if (offset >= 0) { - InterfaceWraps[i].Destruct(_dataptrunsafe(offset)); - } - } - operator delete(_data); - } + void RemoveComponents(uint64 mask = 0) { + UpdateComponents(_meta()->maskremove(mask)); } template @@ -738,31 +766,28 @@ public: return static_cast(_dataptr(_meta()->offsets[Type::Index()])); } template - bool Is() const { + bool Has() const { return (_meta()->offsets[Type::Index()] >= 0); } private: - static const InterfacesMetadata *ZeroInterfacesMetadata; + static const ComposerMetadata *ZeroComposerMetadata; static void *zerodata() { - return &ZeroInterfacesMetadata; + return &ZeroComposerMetadata; } void *_dataptrunsafe(int skip) const { - return (char*)_data + sizeof(const InterfacesMetadata*) + skip; + return (char*)_data + sizeof(_meta()) + skip; } void *_dataptr(int skip) const { return (skip >= 0) ? _dataptrunsafe(skip) : 0; } - const InterfacesMetadata *&_meta() const { - return *static_cast(_data); + const ComposerMetadata *&_meta() const { + return *static_cast(_data); } void *_data; - Interfaces(const Interfaces &other); - Interfaces &operator=(const Interfaces &other); - - void swap(Interfaces &other) { + void swap(Composer &other) { std::swap(_data, other._data); } diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp index 4c155538d..d2ce17a4f 100644 --- a/Telegram/SourceFiles/window.cpp +++ b/Telegram/SourceFiles/window.cpp @@ -1410,7 +1410,7 @@ void Window::notifySchedule(History *history, HistoryItem *item) { haveSetting = false; } - int delay = item->Is() ? 500 : 100, t = unixtime(); + int delay = item->Has() ? 500 : 100, t = unixtime(); uint64 ms = getms(true); bool isOnline = main->lastWasOnline(), otherNotOld = ((cOtherOnline() * uint64(1000)) + Global::OnlineCloudTimeout() > t * uint64(1000)); bool otherLaterThanMe = (cOtherOnline() * uint64(1000) + (ms - main->lastSetOnline()) > t * uint64(1000)); @@ -1629,7 +1629,7 @@ void Window::notifyShowNext(NotifyWindow *remove) { notifyWaitTimer.start(next - ms); break; } else { - HistoryItem *fwd = notifyItem->Is() ? notifyItem : 0; // forwarded notify grouping + HistoryItem *fwd = notifyItem->Has() ? notifyItem : nullptr; // forwarded notify grouping int32 fwdCount = 1; uint64 ms = getms(true); @@ -1657,7 +1657,7 @@ void Window::notifyShowNext(NotifyWindow *remove) { } while (history->hasNotification()); if (nextNotify) { if (fwd) { - HistoryItem *nextFwd = nextNotify->Is() ? nextNotify : 0; + HistoryItem *nextFwd = nextNotify->Has() ? nextNotify : nullptr; if (nextFwd && fwd->author() == nextFwd->author() && qAbs(int64(nextFwd->date.toTime_t()) - int64(fwd->date.toTime_t())) < 2) { fwd = nextFwd; ++fwdCount; diff --git a/Telegram/Telegram.rc b/Telegram/Telegram.rc index cd7485bd7..863775349 100644 --- a/Telegram/Telegram.rc +++ b/Telegram/Telegram.rc @@ -34,8 +34,8 @@ IDI_ICON1 ICON "SourceFiles\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,9,34,3 - PRODUCTVERSION 0,9,34,3 + FILEVERSION 0,9,34,4 + PRODUCTVERSION 0,9,34,4 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Telegram Messenger LLP" - VALUE "FileVersion", "0.9.34.3" + VALUE "FileVersion", "0.9.34.4" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.9.34.3" + VALUE "ProductVersion", "0.9.34.4" END END BLOCK "VarFileInfo" diff --git a/Telegram/Version b/Telegram/Version index 9c0370804..7d9e063d1 100644 --- a/Telegram/Version +++ b/Telegram/Version @@ -3,4 +3,4 @@ AppVersionStrMajor 0.9 AppVersionStrSmall 0.9.34 AppVersionStr 0.9.34 DevChannel 0 -BetaVersion 9034003 +BetaVersion 9034004