mirror of
https://github.com/vale981/tdesktop
synced 2025-03-05 17:51:41 -05:00
Keep track of scheduled messages.
This commit is contained in:
parent
549789bfb7
commit
3814b0833d
23 changed files with 477 additions and 104 deletions
37
Telegram/SourceFiles/api/api_hash.h
Normal file
37
Telegram/SourceFiles/api/api_hash.h
Normal file
|
@ -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<Int, int32> || std::is_same_v<Int, uint32>>>
|
||||
void HashUpdate(uint32 &already, Int value) {
|
||||
already += (already * 20261) + uint32(value);
|
||||
}
|
||||
|
||||
int32 HashFinalize(uint32 already) {
|
||||
return int32(already & 0x7FFFFFFF);
|
||||
}
|
||||
|
||||
template <typename IntRange>
|
||||
inline int32 CountHash(IntRange &&range) {
|
||||
auto result = HashInit();
|
||||
for (const auto value : range) {
|
||||
HashUpdate(result, value);
|
||||
}
|
||||
return HashFinalize(result);
|
||||
}
|
||||
|
||||
} // namespace Api
|
|
@ -65,15 +65,6 @@ inline QString ToString(uint64 value) {
|
|||
|
||||
} // namespace details
|
||||
|
||||
template <typename IntRange>
|
||||
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)>>
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
278
Telegram/SourceFiles/data/data_scheduled_messages.cpp
Normal file
278
Telegram/SourceFiles/data/data_scheduled_messages.cpp
Normal file
|
@ -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<MTPMessageEntity>(),
|
||||
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<MTPRestrictionReason>());
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ScheduledMessages::ScheduledMessages(not_null<Session*> owner)
|
||||
: _session(&owner->session()) {
|
||||
owner->itemRemoved(
|
||||
) | rpl::filter([](not_null<const HistoryItem*> item) {
|
||||
return item->isScheduled();
|
||||
}) | rpl::start_with_next([=](not_null<const HistoryItem*> item) {
|
||||
remove(item);
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
ScheduledMessages::~ScheduledMessages() {
|
||||
for (const auto &request : _requests) {
|
||||
_session->api().request(request.second.requestId).cancel();
|
||||
}
|
||||
}
|
||||
|
||||
MsgId ScheduledMessages::scheduledId(not_null<HistoryItem*> 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*> 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*> history) {
|
||||
request(history);
|
||||
|
||||
return _updates.events(
|
||||
) | rpl::filter([=](not_null<History*> value) {
|
||||
return (value == history);
|
||||
}) | rpl::map([] {
|
||||
return rpl::empty_value();
|
||||
});
|
||||
}
|
||||
|
||||
void ScheduledMessages::request(not_null<History*> 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*> 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*> 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<const HistoryItem*> 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<HistoryMessageEdited>()) {
|
||||
HashUpdate(hash, std::max(item->date(), edited->date));
|
||||
} else {
|
||||
HashUpdate(hash, item->date());
|
||||
}
|
||||
}
|
||||
return HashFinalize(hash);
|
||||
}
|
||||
|
||||
} // namespace Data
|
72
Telegram/SourceFiles/data/data_scheduled_messages.h
Normal file
72
Telegram/SourceFiles/data/data_scheduled_messages.h
Normal file
|
@ -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<Session*> owner);
|
||||
ScheduledMessages(const ScheduledMessages &other) = delete;
|
||||
ScheduledMessages &operator=(const ScheduledMessages &other) = delete;
|
||||
~ScheduledMessages();
|
||||
|
||||
[[nodiscard]] MsgId scheduledId(not_null<HistoryItem*> item);
|
||||
[[nodiscard]] HistoryItem *scheduledMessage(
|
||||
not_null<History*> history,
|
||||
MsgId id);
|
||||
|
||||
void apply(const MTPDupdateNewScheduledMessage &update);
|
||||
void apply(const MTPDupdateDeleteScheduledMessages &update);
|
||||
|
||||
[[nodiscard]] rpl::producer<> updates(not_null<History*> history);
|
||||
|
||||
private:
|
||||
using OwnedItem = std::unique_ptr<HistoryItem, HistoryItem::Destroyer>;
|
||||
struct List {
|
||||
std::vector<OwnedItem> items;
|
||||
base::flat_map<MsgId, not_null<HistoryItem*>> itemById;
|
||||
base::flat_map<not_null<HistoryItem*>, MsgId> idByItem;
|
||||
};
|
||||
struct Request {
|
||||
int32 hash = 0;
|
||||
mtpRequestId requestId = 0;
|
||||
};
|
||||
|
||||
void request(not_null<History*> history);
|
||||
void parse(
|
||||
not_null<History*> history,
|
||||
const MTPmessages_Messages &list);
|
||||
void append(
|
||||
not_null<History*> history,
|
||||
List &list,
|
||||
const MTPMessage &message);
|
||||
void remove(not_null<const HistoryItem*> item);
|
||||
[[nodiscard]] int32 countListHash(const List &list) const;
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
base::flat_map<not_null<History*>, List> _data;
|
||||
base::flat_map<not_null<History*>, Request> _requests;
|
||||
rpl::event_stream<not_null<History*>> _updates;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Data
|
|
@ -205,8 +205,9 @@ Session::Session(not_null<Main::Session*> 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<HistoryItem*> item) {
|
|||
}
|
||||
|
||||
void Session::destroyMessage(not_null<HistoryItem*> 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)) {
|
||||
|
|
|
@ -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<WallPaper> &wallpapers() const;
|
||||
|
@ -945,7 +954,6 @@ private:
|
|||
base::flat_map<FolderId, std::unique_ptr<Folder>> _folders;
|
||||
//rpl::variable<FeedId> _defaultFeedId = FeedId(); // #feed
|
||||
|
||||
Groups _groups;
|
||||
std::unordered_map<
|
||||
not_null<const HistoryItem*>,
|
||||
std::vector<not_null<ViewElement*>>> _views;
|
||||
|
@ -980,6 +988,9 @@ private:
|
|||
std::vector<WallPaper> _wallpapers;
|
||||
int32 _wallpapersHash = 0;
|
||||
|
||||
Groups _groups;
|
||||
ScheduledMessages _scheduledMessages;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
|
|
@ -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<SectionMemento*> 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<SectionMemento*> 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<MTPChannelAdminLo
|
|||
GenerateItems(
|
||||
this,
|
||||
_history,
|
||||
_idManager.get(),
|
||||
data,
|
||||
addOne);
|
||||
if (count > 1) {
|
||||
|
@ -883,8 +880,6 @@ void InnerWidget::clearAfterFilterChange() {
|
|||
_items.clear();
|
||||
_eventIds.clear();
|
||||
_itemsByData.clear();
|
||||
_idManager = nullptr;
|
||||
_idManager = _history->adminLogIdManager();
|
||||
updateEmptyText();
|
||||
updateSize();
|
||||
}
|
||||
|
|
|
@ -276,8 +276,6 @@ private:
|
|||
std::vector<not_null<UserData*>> _adminsCanEdit;
|
||||
Fn<void(FilterValue &&filter)> _showFilterCallback;
|
||||
|
||||
std::shared_ptr<LocalIdManager> _idManager;
|
||||
|
||||
};
|
||||
|
||||
} // namespace AdminLog
|
||||
|
|
|
@ -369,7 +369,6 @@ void OwnedItem::refreshView(
|
|||
void GenerateItems(
|
||||
not_null<HistoryView::ElementDelegate*> delegate,
|
||||
not_null<History*> history,
|
||||
not_null<LocalIdManager*> idManager,
|
||||
const MTPDchannelAdminLogEvent &event,
|
||||
Fn<void(OwnedItem item)> 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),
|
||||
|
|
|
@ -15,12 +15,10 @@ class Element;
|
|||
namespace AdminLog {
|
||||
|
||||
class OwnedItem;
|
||||
class LocalIdManager;
|
||||
|
||||
void GenerateItems(
|
||||
not_null<HistoryView::ElementDelegate*> delegate,
|
||||
not_null<History*> history,
|
||||
not_null<LocalIdManager*> idManager,
|
||||
const MTPDchannelAdminLogEvent &event,
|
||||
Fn<void(OwnedItem item)> callback);
|
||||
|
||||
|
|
|
@ -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<Window::SessionController*> controller, not_null<ChannelData*> channel);
|
||||
|
@ -164,18 +150,12 @@ public:
|
|||
void setSearchQuery(QString &&query) {
|
||||
_searchQuery = std::move(query);
|
||||
}
|
||||
void setIdManager(std::shared_ptr<LocalIdManager> &&manager) {
|
||||
_idManager = std::move(manager);
|
||||
}
|
||||
std::vector<OwnedItem> takeItems() {
|
||||
return std::move(_items);
|
||||
}
|
||||
std::set<uint64> takeEventIds() {
|
||||
return std::move(_eventIds);
|
||||
}
|
||||
std::shared_ptr<LocalIdManager> takeIdManager() {
|
||||
return std::move(_idManager);
|
||||
}
|
||||
bool upLoaded() const {
|
||||
return _upLoaded;
|
||||
}
|
||||
|
@ -198,7 +178,6 @@ private:
|
|||
std::set<uint64> _eventIds;
|
||||
bool _upLoaded = false;
|
||||
bool _downLoaded = true;
|
||||
std::shared_ptr<LocalIdManager> _idManager;
|
||||
FilterValue _filter;
|
||||
QString _searchQuery;
|
||||
|
||||
|
|
|
@ -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<AdminLog::LocalIdManager> History::adminLogIdManager() {
|
||||
if (const auto strong = _adminLogIdManager.lock()) {
|
||||
return strong;
|
||||
}
|
||||
auto result = std::make_shared<AdminLog::LocalIdManager>();
|
||||
_adminLogIdManager = result;
|
||||
return result;
|
||||
MsgId History::nextNonHistoryEntryId() {
|
||||
return ++_nonHistoryEntryId;
|
||||
}
|
||||
|
||||
bool History::folderKnown() const {
|
||||
|
|
|
@ -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<AdminLog::LocalIdManager> adminLogIdManager();
|
||||
MsgId nextNonHistoryEntryId();
|
||||
|
||||
bool folderKnown() const override;
|
||||
Data::Folder *folder() const override;
|
||||
|
@ -538,7 +534,7 @@ private:
|
|||
|
||||
std::deque<not_null<HistoryItem*>> _notifications;
|
||||
|
||||
std::weak_ptr<AdminLog::LocalIdManager> _adminLogIdManager;
|
||||
MsgId _nonHistoryEntryId = ServerMaxMsgId;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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<HistoryMessageLogEntryOriginal>()->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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -608,7 +608,7 @@ const HistoryBlock *Element::block() const {
|
|||
}
|
||||
|
||||
void Element::attachToBlock(not_null<HistoryBlock*> block, int index) {
|
||||
Expects(!_data->isLogEntry());
|
||||
Expects(_data->isHistoryEntry());
|
||||
Expects(_block == nullptr);
|
||||
Expects(_indexInBlock < 0);
|
||||
Expects(index >= 0);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue