From 3814b0833dc42b7511bf8ac4b9d8acbcfe16abe6 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 8 Aug 2019 15:13:26 +0100 Subject: [PATCH] Keep track of scheduled messages. --- Telegram/SourceFiles/api/api_hash.h | 37 +++ Telegram/SourceFiles/apiwrap.h | 9 - .../data/data_document_good_thumbnail.cpp | 2 +- .../data/data_scheduled_messages.cpp | 278 ++++++++++++++++++ .../data/data_scheduled_messages.h | 72 +++++ Telegram/SourceFiles/data/data_session.cpp | 7 +- Telegram/SourceFiles/data/data_session.h | 27 +- .../admin_log/history_admin_log_inner.cpp | 35 +-- .../admin_log/history_admin_log_inner.h | 2 - .../admin_log/history_admin_log_item.cpp | 27 +- .../admin_log/history_admin_log_item.h | 2 - .../admin_log/history_admin_log_section.h | 21 -- Telegram/SourceFiles/history/history.cpp | 10 +- Telegram/SourceFiles/history/history.h | 8 +- Telegram/SourceFiles/history/history_item.cpp | 7 +- Telegram/SourceFiles/history/history_item.h | 12 +- .../SourceFiles/history/history_message.cpp | 2 +- .../history/view/history_view_element.cpp | 2 +- .../history/view/history_view_message.cpp | 2 +- .../history/view/media/history_view_game.cpp | 4 +- .../view/media/history_view_web_page.cpp | 2 +- Telegram/SourceFiles/mainwidget.cpp | 10 + Telegram/gyp/telegram_sources.txt | 3 + 23 files changed, 477 insertions(+), 104 deletions(-) create mode 100644 Telegram/SourceFiles/api/api_hash.h create mode 100644 Telegram/SourceFiles/data/data_scheduled_messages.cpp create mode 100644 Telegram/SourceFiles/data/data_scheduled_messages.h diff --git a/Telegram/SourceFiles/api/api_hash.h b/Telegram/SourceFiles/api/api_hash.h new file mode 100644 index 000000000..e3ee9a570 --- /dev/null +++ b/Telegram/SourceFiles/api/api_hash.h @@ -0,0 +1,37 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +namespace Api { + +uint32 HashInit() { + return 0; +} + +template < + typename Int, + typename = std::enable_if_t< + std::is_same_v || std::is_same_v>> +void HashUpdate(uint32 &already, Int value) { + already += (already * 20261) + uint32(value); +} + +int32 HashFinalize(uint32 already) { + return int32(already & 0x7FFFFFFF); +} + +template +inline int32 CountHash(IntRange &&range) { + auto result = HashInit(); + for (const auto value : range) { + HashUpdate(result, value); + } + return HashFinalize(result); +} + +} // namespace Api diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 36ef555be..955ef5e68 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -65,15 +65,6 @@ inline QString ToString(uint64 value) { } // namespace details -template -inline int32 CountHash(IntRange &&range) { - uint32 acc = 0; - for (auto value : range) { - acc += (acc * 20261) + uint32(value); - } - return int32(acc & 0x7FFFFFFF); -} - template < typename ...Types, typename = std::enable_if_t<(sizeof...(Types) > 0)>> diff --git a/Telegram/SourceFiles/data/data_document_good_thumbnail.cpp b/Telegram/SourceFiles/data/data_document_good_thumbnail.cpp index bc3667b67..8818e6ab0 100644 --- a/Telegram/SourceFiles/data/data_document_good_thumbnail.cpp +++ b/Telegram/SourceFiles/data/data_document_good_thumbnail.cpp @@ -31,7 +31,7 @@ QImage Prepare( QByteArray data, FileType type) { if (type == FileType::Video) { - return Media::Clip::PrepareForSending(path, data).thumbnail; + return ::Media::Clip::PrepareForSending(path, data).thumbnail; } else if (type == FileType::AnimatedSticker) { return Lottie::ReadThumbnail(Lottie::ReadContent(data, path)); } diff --git a/Telegram/SourceFiles/data/data_scheduled_messages.cpp b/Telegram/SourceFiles/data/data_scheduled_messages.cpp new file mode 100644 index 000000000..8d5b2a0ec --- /dev/null +++ b/Telegram/SourceFiles/data/data_scheduled_messages.cpp @@ -0,0 +1,278 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "data/data_scheduled_messages.h" + +#include "data/data_peer.h" +#include "data/data_session.h" +#include "api/api_hash.h" +#include "main/main_session.h" +#include "history/history.h" +#include "history/history_item_components.h" +#include "apiwrap.h" + +namespace Data { +namespace { + +MTPMessage PrepareMessage(const MTPMessage &message, MsgId id) { + return message.match([&](const MTPDmessageEmpty &) { + return MTP_messageEmpty(MTP_int(id)); + }, [&](const MTPDmessageService &data) { + return MTP_messageService( + MTP_flags(data.vflags().v + | MTPDmessageService::Flag( + MTPDmessage::Flag::f_from_scheduled)), + MTP_int(id), + MTP_int(data.vfrom_id().value_or_empty()), + data.vto_id(), + MTP_int(data.vreply_to_msg_id().value_or_empty()), + data.vdate(), + data.vaction()); + }, [&](const MTPDmessage &data) { + const auto fwdFrom = data.vfwd_from(); + const auto media = data.vmedia(); + const auto markup = data.vreply_markup(); + const auto entities = data.ventities(); + return MTP_message( + MTP_flags(data.vflags().v | MTPDmessage::Flag::f_from_scheduled), + MTP_int(id), + MTP_int(data.vfrom_id().value_or_empty()), + data.vto_id(), + fwdFrom ? *fwdFrom : MTPMessageFwdHeader(), + MTP_int(data.vvia_bot_id().value_or_empty()), + MTP_int(data.vreply_to_msg_id().value_or_empty()), + data.vdate(), + data.vmessage(), + media ? *media : MTPMessageMedia(), + markup ? *markup : MTPReplyMarkup(), + entities ? *entities : MTPVector(), + MTP_int(data.vviews().value_or_empty()), + MTP_int(data.vedit_date().value_or_empty()), + MTP_bytes(data.vpost_author().value_or_empty()), + MTP_long(data.vgrouped_id().value_or_empty()), + //MTPMessageReactions(), + MTPVector()); + }); +} + +} // namespace + +ScheduledMessages::ScheduledMessages(not_null owner) +: _session(&owner->session()) { + owner->itemRemoved( + ) | rpl::filter([](not_null item) { + return item->isScheduled(); + }) | rpl::start_with_next([=](not_null item) { + remove(item); + }, _lifetime); +} + +ScheduledMessages::~ScheduledMessages() { + for (const auto &request : _requests) { + _session->api().request(request.second.requestId).cancel(); + } +} + +MsgId ScheduledMessages::scheduledId(not_null item) { + if (const auto i = _data.find(item->history()); i != end(_data)) { + const auto &list = i->second.idByItem; + if (const auto j = list.find(item); j != end(list)) { + return j->second; + } + } + return MsgId(0); +} + +HistoryItem *ScheduledMessages::scheduledMessage( + not_null history, + MsgId id) { + if (const auto i = _data.find(history); i != end(_data)) { + const auto &list = i->second.itemById; + if (const auto j = list.find(id); j != end(list)) { + return j->second; + } + } + return nullptr; +} + +void ScheduledMessages::apply(const MTPDupdateNewScheduledMessage &update) { + const auto &message = update.vmessage(); + const auto peer = PeerFromMessage(message); + if (!peer) { + return; + } + const auto history = _session->data().historyLoaded(peer); + if (!history) { + return; + } + append(history, _data[history], message); + _updates.fire_copy(history); +} + +void ScheduledMessages::apply( + const MTPDupdateDeleteScheduledMessages &update) { + const auto peer = peerFromMTP(update.vpeer()); + if (!peer) { + return; + } + const auto history = _session->data().historyLoaded(peer); + if (!history) { + return; + } + auto i = _data.find(history); + if (i == end(_data)) { + return; + } + for (const auto &id : update.vmessages().v) { + const auto &list = i->second; + const auto j = list.itemById.find(id.v); + if (j != end(list.itemById)) { + j->second->destroy(); + i = _data.find(history); + if (i == end(_data)) { + break; + } + } + } + _updates.fire_copy(history); +} + +rpl::producer<> ScheduledMessages::updates(not_null history) { + request(history); + + return _updates.events( + ) | rpl::filter([=](not_null value) { + return (value == history); + }) | rpl::map([] { + return rpl::empty_value(); + }); +} + +void ScheduledMessages::request(not_null history) { + auto &request = _requests[history]; + if (request.requestId) { + return; + } + request.requestId = _session->api().request( + MTPmessages_GetScheduledHistory( + history->peer->input, + MTP_int(request.hash)) + ).done([=](const MTPmessages_Messages &result) { + parse(history, result); + }).fail([=](const RPCError &error) { + _requests.remove(history); + }).send(); +} + +void ScheduledMessages::parse( + not_null history, + const MTPmessages_Messages &list) { + auto &request = _requests[history]; + request.requestId = 0; + + auto element = _data.find(history); + list.match([&](const MTPDmessages_messagesNotModified &data) { + }, [&](const auto &data) { + _session->data().processUsers(data.vusers()); + _session->data().processChats(data.vchats()); + const auto &messages = data.vmessages().v; + if (messages.isEmpty()) { + return; + } + element = _data.emplace(history, List()).first; + auto &list = element->second; + for (const auto &message : messages) { + append(history, list, message); + } + if (list.items.empty()) { + _data.erase(element); + element = end(_data); + } + _updates.fire_copy(history); + }); + + request.hash = (element != end(_data)) + ? countListHash(element->second) + : 0; + if (!request.requestId && !request.hash) { + _requests.remove(history); + } +} + +void ScheduledMessages::append( + not_null history, + List &list, + const MTPMessage &message) { + const auto id = message.match([&](const auto &data) { + return data.vid().v; + }); + const auto i = list.itemById.find(id); + if (i != end(list.itemById)) { + const auto j = ranges::find( + list.items, + i->second.get(), + &OwnedItem::get); + const auto e = end(list.items); + Assert(j != e); + if (j + 1 != e) { + std::rotate(j, j + 1, e); + } + return; + } + + const auto item = _session->data().addNewMessage( + PrepareMessage(message, history->nextNonHistoryEntryId()), + MTPDmessage_ClientFlags(), + NewMessageType::Existing); + if (!item || item->history() != history) { + LOG(("API Error: Bad data received in scheduled messages.")); + return; + } + list.items.emplace_back(item); + list.itemById.emplace(id, item); + list.idByItem.emplace(item, id); +} + +void ScheduledMessages::remove(not_null item) { + const auto history = item->history(); + const auto i = _data.find(history); + Assert(i != end(_data)); + auto &list = i->second; + + const auto j = list.idByItem.find(item); + Assert(j != end(list.idByItem)); + list.itemById.remove(j->second); + list.idByItem.erase(j); + + const auto k = ranges::find(list.items, item, &OwnedItem::get); + Assert(k != list.items.end()); + k->release(); + list.items.erase(k); + + if (list.items.empty()) { + _data.erase(i); + } + _updates.fire_copy(history); +} + +int32 ScheduledMessages::countListHash(const List &list) const { + using namespace Api; + + auto hash = HashInit(); + for (const auto &item : list.items) { + const auto j = list.idByItem.find(item.get()); + HashUpdate(hash, j->second); + if (const auto edited = item->Get()) { + HashUpdate(hash, std::max(item->date(), edited->date)); + } else { + HashUpdate(hash, item->date()); + } + } + return HashFinalize(hash); +} + +} // namespace Data diff --git a/Telegram/SourceFiles/data/data_scheduled_messages.h b/Telegram/SourceFiles/data/data_scheduled_messages.h new file mode 100644 index 000000000..305b78e44 --- /dev/null +++ b/Telegram/SourceFiles/data/data_scheduled_messages.h @@ -0,0 +1,72 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "history/history_item.h" + +class History; + +namespace Main { +class Session; +} // namespace Main + +namespace Data { + +class Session; + +class ScheduledMessages final { +public: + explicit ScheduledMessages(not_null owner); + ScheduledMessages(const ScheduledMessages &other) = delete; + ScheduledMessages &operator=(const ScheduledMessages &other) = delete; + ~ScheduledMessages(); + + [[nodiscard]] MsgId scheduledId(not_null item); + [[nodiscard]] HistoryItem *scheduledMessage( + not_null history, + MsgId id); + + void apply(const MTPDupdateNewScheduledMessage &update); + void apply(const MTPDupdateDeleteScheduledMessages &update); + + [[nodiscard]] rpl::producer<> updates(not_null history); + +private: + using OwnedItem = std::unique_ptr; + struct List { + std::vector items; + base::flat_map> itemById; + base::flat_map, MsgId> idByItem; + }; + struct Request { + int32 hash = 0; + mtpRequestId requestId = 0; + }; + + void request(not_null history); + void parse( + not_null history, + const MTPmessages_Messages &list); + void append( + not_null history, + List &list, + const MTPMessage &message); + void remove(not_null item); + [[nodiscard]] int32 countListHash(const List &list) const; + + const not_null _session; + + base::flat_map, List> _data; + base::flat_map, Request> _requests; + rpl::event_stream> _updates; + + rpl::lifetime _lifetime; + +}; + +} // namespace Data diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index f5dde4767..79084dd14 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -205,8 +205,9 @@ Session::Session(not_null session) , _sendActionsAnimation([=](crl::time now) { return sendActionsAnimationCallback(now); }) +, _unmuteByFinishedTimer([=] { unmuteByFinished(); }) , _groups(this) -, _unmuteByFinishedTimer([=] { unmuteByFinished(); }) { +, _scheduledMessages(this) { _cache->open(Local::cacheKey()); _bigFileCache->open(Local::cacheBigFileKey()); @@ -1814,10 +1815,10 @@ void Session::removeDependencyMessage(not_null item) { } void Session::destroyMessage(not_null item) { - Expects(!item->isLogEntry() || !item->mainView()); + Expects(item->isHistoryEntry() || !item->mainView()); const auto peerId = item->history()->peer->id; - if (!item->isLogEntry()) { + if (item->isHistoryEntry()) { // All this must be done for all items manually in History::clear()! item->eraseFromUnreadMentions(); if (IsServerMsgId(item->id)) { diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index e6bc85073..02a673be3 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "dialogs/dialogs_main_list.h" #include "data/data_groups.h" #include "data/data_notify_settings.h" +#include "data/data_scheduled_messages.h" #include "history/history_location_manager.h" #include "base/timer.h" #include "base/flags.h" @@ -63,6 +64,7 @@ namespace Data { class Folder; class LocationPoint; class WallPaper; +class ScheduledMessages; class Session final { public: @@ -80,6 +82,20 @@ public: return *_session; } + [[nodiscard]] Groups &groups() { + return _groups; + } + [[nodiscard]] const Groups &groups() const { + return _groups; + } + + [[nodiscard]] ScheduledMessages &scheduledMessages() { + return _scheduledMessages; + } + [[nodiscard]] const ScheduledMessages &scheduledMessages() const { + return _scheduledMessages; + } + void clear(); void startExport(PeerData *peer = nullptr); @@ -670,13 +686,6 @@ public: void setProxyPromoted(PeerData *promoted); PeerData *proxyPromoted() const; - Groups &groups() { - return _groups; - } - const Groups &groups() const { - return _groups; - } - bool updateWallpapers(const MTPaccount_WallPapers &data); void removeWallpaper(const WallPaper &paper); const std::vector &wallpapers() const; @@ -945,7 +954,6 @@ private: base::flat_map> _folders; //rpl::variable _defaultFeedId = FeedId(); // #feed - Groups _groups; std::unordered_map< not_null, std::vector>> _views; @@ -980,6 +988,9 @@ private: std::vector _wallpapers; int32 _wallpapersHash = 0; + Groups _groups; + ScheduledMessages _scheduledMessages; + rpl::lifetime _lifetime; }; diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp index a5fc9f776..3a2a197a6 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -219,34 +219,33 @@ InnerWidget::InnerWidget( , _controller(controller) , _channel(channel) , _history(channel->owner().history(channel)) -, _scrollDateCheck([this] { scrollDateCheck(); }) +, _scrollDateCheck([=] { scrollDateCheck(); }) , _emptyText( - st::historyAdminLogEmptyWidth - - st::historyAdminLogEmptyPadding.left() - - st::historyAdminLogEmptyPadding.left()) -, _idManager(_history->adminLogIdManager()) { + st::historyAdminLogEmptyWidth + - st::historyAdminLogEmptyPadding.left() + - st::historyAdminLogEmptyPadding.left()) { setMouseTracking(true); - _scrollDateHideTimer.setCallback([this] { scrollDateHideByTimer(); }); + _scrollDateHideTimer.setCallback([=] { scrollDateHideByTimer(); }); session().data().viewRepaintRequest( - ) | rpl::start_with_next([this](auto view) { + ) | rpl::start_with_next([=](auto view) { if (view->delegate() == this) { repaintItem(view); } }, lifetime()); session().data().viewResizeRequest( - ) | rpl::start_with_next([this](auto view) { + ) | rpl::start_with_next([=](auto view) { if (view->delegate() == this) { resizeItem(view); } }, lifetime()); session().data().itemViewRefreshRequest( - ) | rpl::start_with_next([this](auto item) { + ) | rpl::start_with_next([=](auto item) { if (const auto view = viewForItem(item)) { refreshItem(view); } }, lifetime()); session().data().viewLayoutChanged( - ) | rpl::start_with_next([this](auto view) { + ) | rpl::start_with_next([=](auto view) { if (view->delegate() == this) { if (view->isUnderCursor()) { updateSelected(); @@ -254,15 +253,18 @@ InnerWidget::InnerWidget( } }, lifetime()); session().data().animationPlayInlineRequest( - ) | rpl::start_with_next([this](auto item) { + ) | rpl::start_with_next([=](auto item) { if (const auto view = viewForItem(item)) { if (const auto media = view->media()) { media->playAnimation(); } } }, lifetime()); - subscribe(session().data().queryItemVisibility(), [this](const Data::Session::ItemVisibilityQuery &query) { - if (_history != query.item->history() || !query.item->isLogEntry() || !isVisible()) { + subscribe(session().data().queryItemVisibility(), [=]( + const Data::Session::ItemVisibilityQuery &query) { + if (_history != query.item->history() + || query.item->isHistoryEntry() + || !isVisible()) { return; } if (const auto view = viewForItem(query.item)) { @@ -562,7 +564,6 @@ void InnerWidget::saveState(not_null memento) { base::take(_eventIds), _upLoaded, _downLoaded); - memento->setIdManager(base::take(_idManager)); base::take(_itemsByData); } _upLoaded = _downLoaded = true; // Don't load or handle anything anymore. @@ -575,9 +576,6 @@ void InnerWidget::restoreState(not_null memento) { _itemsByData.emplace(item->data(), item.get()); } _eventIds = memento->takeEventIds(); - if (auto manager = memento->takeIdManager()) { - _idManager = std::move(manager); - } _admins = memento->takeAdmins(); _adminsCanEdit = memento->takeAdminsCanEdit(); _filter = memento->takeFilter(); @@ -678,7 +676,6 @@ void InnerWidget::addEvents(Direction direction, const QVector 1) { @@ -883,8 +880,6 @@ void InnerWidget::clearAfterFilterChange() { _items.clear(); _eventIds.clear(); _itemsByData.clear(); - _idManager = nullptr; - _idManager = _history->adminLogIdManager(); updateEmptyText(); updateSize(); } diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h index 3eb1524f3..709b033cf 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h @@ -276,8 +276,6 @@ private: std::vector> _adminsCanEdit; Fn _showFilterCallback; - std::shared_ptr _idManager; - }; } // namespace AdminLog diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp index e4c7c466d..d115daa2e 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp @@ -369,7 +369,6 @@ void OwnedItem::refreshView( void GenerateItems( not_null delegate, not_null history, - not_null idManager, const MTPDchannelAdminLogEvent &event, Fn callback) { Expects(history->peer->isChannel()); @@ -394,7 +393,7 @@ void GenerateItems( addPart(history->owner().makeServiceMessage( history, MTPDmessage_ClientFlags(), - idManager->next(), + history->nextNonHistoryEntryId(), date, message, MTPDmessage::Flags(0), @@ -434,7 +433,7 @@ void GenerateItems( auto newDescription = PrepareText(newValue, QString()); auto body = history->owner().makeMessage( history, - idManager->next(), + history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, bodyReplyTo, @@ -470,7 +469,7 @@ void GenerateItems( auto newLink = newValue.isEmpty() ? TextWithEntities() : PrepareText(Core::App().createInternalLinkFull(newValue), QString()); auto body = history->owner().makeMessage( history, - idManager->next(), + history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, bodyReplyTo, @@ -535,7 +534,7 @@ void GenerateItems( addPart(history->createItem( PrepareLogMessage( action.vmessage(), - idManager->next(), + history->nextNonHistoryEntryId(), date), MTPDmessage_ClientFlags(), detachExistingItem)); @@ -560,7 +559,7 @@ void GenerateItems( auto body = history->createItem( PrepareLogMessage( action.vnew_message(), - idManager->next(), + history->nextNonHistoryEntryId(), date), MTPDmessage_ClientFlags(), detachExistingItem); @@ -583,7 +582,7 @@ void GenerateItems( auto detachExistingItem = false; addPart(history->createItem( - PrepareLogMessage(action.vmessage(), idManager->next(), date), + PrepareLogMessage(action.vmessage(), history->nextNonHistoryEntryId(), date), MTPDmessage_ClientFlags(), detachExistingItem)); }; @@ -610,7 +609,7 @@ void GenerateItems( auto bodyText = GenerateParticipantChangeText(channel, action.vparticipant()); addPart(history->owner().makeMessage( history, - idManager->next(), + history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, bodyReplyTo, @@ -629,7 +628,7 @@ void GenerateItems( auto bodyText = GenerateParticipantChangeText(channel, action.vnew_participant(), &action.vprev_participant()); addPart(history->owner().makeMessage( history, - idManager->next(), + history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, bodyReplyTo, @@ -654,7 +653,7 @@ void GenerateItems( auto bodyText = GenerateParticipantChangeText(channel, action.vnew_participant(), &action.vprev_participant()); addPart(history->owner().makeMessage( history, - idManager->next(), + history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, bodyReplyTo, @@ -689,7 +688,7 @@ void GenerateItems( addPart(history->owner().makeServiceMessage( history, MTPDmessage_ClientFlags(), - idManager->next(), + history->nextNonHistoryEntryId(), date, message, MTPDmessage::Flags(0), @@ -713,7 +712,7 @@ void GenerateItems( auto bodyText = GenerateDefaultBannedRightsChangeText(channel, action.vnew_banned_rights(), action.vprev_banned_rights()); addPart(history->owner().makeMessage( history, - idManager->next(), + history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, bodyReplyTo, @@ -730,7 +729,7 @@ void GenerateItems( auto detachExistingItem = false; addPart(history->createItem( - PrepareLogMessage(action.vmessage(), idManager->next(), date), + PrepareLogMessage(action.vmessage(), history->nextNonHistoryEntryId(), date), MTPDmessage_ClientFlags(), detachExistingItem)); }; @@ -765,7 +764,7 @@ void GenerateItems( addPart(history->owner().makeServiceMessage( history, MTPDmessage_ClientFlags(), - idManager->next(), + history->nextNonHistoryEntryId(), date, message, MTPDmessage::Flags(0), diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.h b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.h index a7455ce46..cdd2fcf48 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.h +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.h @@ -15,12 +15,10 @@ class Element; namespace AdminLog { class OwnedItem; -class LocalIdManager; void GenerateItems( not_null delegate, not_null history, - not_null idManager, const MTPDchannelAdminLogEvent &event, Fn callback); diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_section.h b/Telegram/SourceFiles/history/admin_log/history_admin_log_section.h index 433e0d08b..c9106674e 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_section.h +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_section.h @@ -47,20 +47,6 @@ inline bool operator!=(const FilterValue &a, const FilterValue &b) { return !(a == b); } -class LocalIdManager { -public: - LocalIdManager() = default; - LocalIdManager(const LocalIdManager &other) = delete; - LocalIdManager &operator=(const LocalIdManager &other) = delete; - MsgId next() { - return ++_counter; - } - -private: - MsgId _counter = ServerMaxMsgId; - -}; - class Widget final : public Window::SectionWidget { public: Widget(QWidget *parent, not_null controller, not_null channel); @@ -164,18 +150,12 @@ public: void setSearchQuery(QString &&query) { _searchQuery = std::move(query); } - void setIdManager(std::shared_ptr &&manager) { - _idManager = std::move(manager); - } std::vector takeItems() { return std::move(_items); } std::set takeEventIds() { return std::move(_eventIds); } - std::shared_ptr takeIdManager() { - return std::move(_idManager); - } bool upLoaded() const { return _upLoaded; } @@ -198,7 +178,6 @@ private: std::set _eventIds; bool _upLoaded = false; bool _downLoaded = true; - std::shared_ptr _idManager; FilterValue _filter; QString _searchQuery; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 05d3c0736..f40d83fc5 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history.h" #include "history/view/history_view_element.h" -#include "history/admin_log/history_admin_log_section.h" #include "history/history_message.h" #include "history/history_service.h" #include "history/history_item_components.h" @@ -1823,13 +1822,8 @@ void History::getNextFirstUnreadMessage() { _firstUnreadView = nullptr; } -std::shared_ptr History::adminLogIdManager() { - if (const auto strong = _adminLogIdManager.lock()) { - return strong; - } - auto result = std::make_shared(); - _adminLogIdManager = result; - return result; +MsgId History::nextNonHistoryEntryId() { + return ++_nonHistoryEntryId; } bool History::folderKnown() const { diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 9011fead3..f881b0add 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -42,10 +42,6 @@ namespace HistoryView { class Element; } // namespace HistoryView -namespace AdminLog { -class LocalIdManager; -} // namespace AdminLog - enum class NewMessageType { Unread, Last, @@ -337,7 +333,7 @@ public: // of the displayed window relative to the history start coordinate void countScrollState(int top); - std::shared_ptr adminLogIdManager(); + MsgId nextNonHistoryEntryId(); bool folderKnown() const override; Data::Folder *folder() const override; @@ -538,7 +534,7 @@ private: std::deque> _notifications; - std::weak_ptr _adminLogIdManager; + MsgId _nonHistoryEntryId = ServerMaxMsgId; }; diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index f300f91e9..51456a5ab 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -352,7 +352,8 @@ void HistoryItem::addLogEntryOriginal( WebPageId localId, const QString &label, const TextWithEntities &content) { - Expects(isLogEntry()); + Expects(!isHistoryEntry()); + Expects(!isScheduled()); AddComponents(HistoryMessageLogEntryOriginal::Bit()); Get()->page = _history->owner().webpage( @@ -505,7 +506,9 @@ bool HistoryItem::canStopPoll() const { } bool HistoryItem::canDelete() const { - if (isLogEntry() || (!IsServerMsgId(id) && serviceMsg())) { + if (!IsServerMsgId(id) && serviceMsg()) { + return false; + } else if (!isHistoryEntry() && !isScheduled()) { return false; } auto channel = _history->peer->asChannel(); diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index b38623722..25f35f23a 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -85,8 +85,16 @@ public: UserData *viaBot() const; UserData *getMessageBot() const; - bool isLogEntry() const { - return (id > ServerMaxMsgId); + [[nodiscard]] bool isHistoryEntry() const { + return (id < ServerMaxMsgId); + } + [[nodiscard]] bool isFromScheduled() const { + return isHistoryEntry() + && (_flags & MTPDmessage::Flag::f_from_scheduled); + } + [[nodiscard]] bool isScheduled() const { + return !isHistoryEntry() + && (_flags & MTPDmessage::Flag::f_from_scheduled); } void addLogEntryOriginal( WebPageId localId, diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index ecca72575..6709c16e1 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -736,7 +736,7 @@ void HistoryMessage::applyGroupAdminChanges( } bool HistoryMessage::allowsForward() const { - if (id < 0 || isLogEntry()) { + if (id < 0 || !isHistoryEntry()) { return false; } return !_media || _media->allowsForward(); diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index fbcbd6476..6edb1f866 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -608,7 +608,7 @@ const HistoryBlock *Element::block() const { } void Element::attachToBlock(not_null block, int index) { - Expects(!_data->isLogEntry()); + Expects(_data->isHistoryEntry()); Expects(_block == nullptr); Expects(_indexInBlock < 0); Expects(index >= 0); diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index bc0a8e315..aa0c29c89 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -846,7 +846,7 @@ TextState Message::textState( result.symbol += item->_text.length(); } - if (keyboard && !item->isLogEntry()) { + if (keyboard && item->isHistoryEntry()) { auto keyboardTop = g.top() + g.height() + st::msgBotKbButton.margin; if (QRect(g.left(), keyboardTop, g.width(), keyboardHeight).contains(point)) { result.link = keyboard->getLink(point - QPoint(g.left(), keyboardTop)); diff --git a/Telegram/SourceFiles/history/view/media/history_view_game.cpp b/Telegram/SourceFiles/history/view/media/history_view_game.cpp index ef4453351..235467df9 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_game.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_game.cpp @@ -313,7 +313,7 @@ TextState Game::textState(QPoint point, StateRequest request) const { tshift += _descriptionLines * lineHeight; } if (inThumb) { - if (!_parent->data()->isLogEntry()) { + if (_parent->data()->isHistoryEntry()) { result.link = _openl; } } else if (_attach) { @@ -326,7 +326,7 @@ TextState Game::textState(QPoint point, StateRequest request) const { if (QRect(attachLeft, tshift, _attach->width(), height() - tshift - bshift).contains(point)) { if (_attach->isReadyForOpen()) { - if (!_parent->data()->isLogEntry()) { + if (_parent->data()->isHistoryEntry()) { result.link = _openl; } } else { diff --git a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp index d36be0352..fb4b16ae9 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp @@ -702,7 +702,7 @@ QMargins WebPage::inBubblePadding() const { } bool WebPage::isLogEntryOriginal() const { - return _parent->data()->isLogEntry() && _parent->media() != this; + return !_parent->data()->isHistoryEntry() && _parent->media() != this; } int WebPage::bottomInfoPadding() const { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 7264a3cf6..50ab79205 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4073,6 +4073,16 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } } break; + case mtpc_updateNewScheduledMessage: { + const auto &d = update.c_updateNewScheduledMessage(); + session().data().scheduledMessages().apply(d); + } break; + + case mtpc_updateDeleteScheduledMessages: { + const auto &d = update.c_updateDeleteScheduledMessages(); + session().data().scheduledMessages().apply(d); + } break; + case mtpc_updateWebPage: { auto &d = update.c_updateWebPage(); diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index 5c57e2d44..fb48628b6 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -1,3 +1,4 @@ +<(src_loc)/api/api_hash.h <(src_loc)/api/api_sending.cpp <(src_loc)/api/api_sending.h <(src_loc)/api/api_single_message_search.cpp @@ -220,6 +221,8 @@ <(src_loc)/data/data_search_controller.h <(src_loc)/data/data_session.cpp <(src_loc)/data/data_session.h +<(src_loc)/data/data_scheduled_messages.cpp +<(src_loc)/data/data_scheduled_messages.h <(src_loc)/data/data_shared_media.cpp <(src_loc)/data/data_shared_media.h <(src_loc)/data/data_sparse_ids.cpp