mirror of https://github.com/procxx/kepka.git
				
				
				
			Add group/ungroup action in channel peer menu.
This commit is contained in:
		
							parent
							
								
									ced0c4d8f0
								
							
						
					
					
						commit
						65df137610
					
				| 
						 | 
					@ -1418,6 +1418,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | 
				
			||||||
"lng_feed_name" = "Feed";
 | 
					"lng_feed_name" = "Feed";
 | 
				
			||||||
"lng_feed_show_next" = "Show Next";
 | 
					"lng_feed_show_next" = "Show Next";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"lng_feed_group" = "Group in feed";
 | 
				
			||||||
 | 
					"lng_feed_ungroup" = "Ungroup from feed";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"lng_info_feed_title" = "Feed Info";
 | 
					"lng_info_feed_title" = "Feed Info";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Wnd specific
 | 
					// Wnd specific
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -170,6 +170,32 @@ void ApiWrap::savePinnedOrder() {
 | 
				
			||||||
	)).send();
 | 
						)).send();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ApiWrap::toggleChannelGrouping(
 | 
				
			||||||
 | 
							not_null<ChannelData*> channel,
 | 
				
			||||||
 | 
							bool group) {
 | 
				
			||||||
 | 
						if (const auto already = _channelGroupingRequests.take(channel)) {
 | 
				
			||||||
 | 
							request(*already).cancel();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						const auto feedId = Data::Feed::kId;
 | 
				
			||||||
 | 
						const auto flags = group
 | 
				
			||||||
 | 
							? MTPchannels_ChangeFeedBroadcast::Flag::f_feed_id
 | 
				
			||||||
 | 
							: MTPchannels_ChangeFeedBroadcast::Flag(0);
 | 
				
			||||||
 | 
						const auto requestId = request(MTPchannels_ChangeFeedBroadcast(
 | 
				
			||||||
 | 
							MTP_flags(flags),
 | 
				
			||||||
 | 
							channel->inputChannel,
 | 
				
			||||||
 | 
							MTP_int(feedId)
 | 
				
			||||||
 | 
						)).done([=](const MTPBool &result) {
 | 
				
			||||||
 | 
							_channelGroupingRequests.remove(channel);
 | 
				
			||||||
 | 
							if (group) {
 | 
				
			||||||
 | 
								channel->setFeed(Auth().data().feed(feedId));
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								channel->clearFeed();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}).fail([=](const RPCError &error) {
 | 
				
			||||||
 | 
							_channelGroupingRequests.remove(channel);
 | 
				
			||||||
 | 
						}).send();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ApiWrap::sendMessageFail(const RPCError &error) {
 | 
					void ApiWrap::sendMessageFail(const RPCError &error) {
 | 
				
			||||||
	if (error.type() == qstr("PEER_FLOOD")) {
 | 
						if (error.type() == qstr("PEER_FLOOD")) {
 | 
				
			||||||
		Ui::show(Box<InformBox>(
 | 
							Ui::show(Box<InformBox>(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,6 +46,7 @@ public:
 | 
				
			||||||
	void applyUpdates(const MTPUpdates &updates, uint64 sentMessageRandomId = 0);
 | 
						void applyUpdates(const MTPUpdates &updates, uint64 sentMessageRandomId = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void savePinnedOrder();
 | 
						void savePinnedOrder();
 | 
				
			||||||
 | 
						void toggleChannelGrouping(not_null<ChannelData*> channel, bool group);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	using RequestMessageDataCallback = base::lambda<void(ChannelData*, MsgId)>;
 | 
						using RequestMessageDataCallback = base::lambda<void(ChannelData*, MsgId)>;
 | 
				
			||||||
	void requestMessageData(
 | 
						void requestMessageData(
 | 
				
			||||||
| 
						 | 
					@ -92,9 +93,13 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void scheduleStickerSetRequest(uint64 setId, uint64 access);
 | 
						void scheduleStickerSetRequest(uint64 setId, uint64 access);
 | 
				
			||||||
	void requestStickerSets();
 | 
						void requestStickerSets();
 | 
				
			||||||
	void saveStickerSets(const Stickers::Order &localOrder, const Stickers::Order &localRemoved);
 | 
						void saveStickerSets(
 | 
				
			||||||
 | 
							const Stickers::Order &localOrder,
 | 
				
			||||||
 | 
							const Stickers::Order &localRemoved);
 | 
				
			||||||
	void updateStickers();
 | 
						void updateStickers();
 | 
				
			||||||
	void setGroupStickerSet(not_null<ChannelData*> megagroup, const MTPInputStickerSet &set);
 | 
						void setGroupStickerSet(
 | 
				
			||||||
 | 
							not_null<ChannelData*> megagroup,
 | 
				
			||||||
 | 
							const MTPInputStickerSet &set);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void joinChannel(ChannelData *channel);
 | 
						void joinChannel(ChannelData *channel);
 | 
				
			||||||
	void leaveChannel(ChannelData *channel);
 | 
						void leaveChannel(ChannelData *channel);
 | 
				
			||||||
| 
						 | 
					@ -369,7 +374,11 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ChannelData *_channelMembersForAdd = nullptr;
 | 
						ChannelData *_channelMembersForAdd = nullptr;
 | 
				
			||||||
	mtpRequestId _channelMembersForAddRequestId = 0;
 | 
						mtpRequestId _channelMembersForAddRequestId = 0;
 | 
				
			||||||
	base::lambda<void(const MTPchannels_ChannelParticipants&)> _channelMembersForAddCallback;
 | 
						base::lambda<void(
 | 
				
			||||||
 | 
							const MTPchannels_ChannelParticipants&)> _channelMembersForAddCallback;
 | 
				
			||||||
 | 
						base::flat_map<
 | 
				
			||||||
 | 
							not_null<ChannelData*>,
 | 
				
			||||||
 | 
							mtpRequestId> _channelGroupingRequests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	using KickRequest = std::pair<
 | 
						using KickRequest = std::pair<
 | 
				
			||||||
		not_null<ChannelData*>,
 | 
							not_null<ChannelData*>,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,10 +7,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
#include "data/data_feed.h"
 | 
					#include "data/data_feed.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "data/data_session.h"
 | 
				
			||||||
#include "dialogs/dialogs_key.h"
 | 
					#include "dialogs/dialogs_key.h"
 | 
				
			||||||
#include "history/history.h"
 | 
					#include "history/history.h"
 | 
				
			||||||
#include "history/history_item.h"
 | 
					#include "history/history_item.h"
 | 
				
			||||||
#include "lang/lang_keys.h"
 | 
					#include "lang/lang_keys.h"
 | 
				
			||||||
 | 
					#include "storage/storage_facade.h"
 | 
				
			||||||
 | 
					#include "storage/storage_feed_messages.h"
 | 
				
			||||||
 | 
					#include "auth_session.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Data {
 | 
					namespace Data {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,13 +27,18 @@ MessagePosition FeedPositionFromMTP(const MTPFeedPosition &position) {
 | 
				
			||||||
		data.vid.v));
 | 
							data.vid.v));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Feed::Feed(FeedId id)
 | 
					Feed::Feed(FeedId id, not_null<Data::Session*> parent)
 | 
				
			||||||
: Entry(this)
 | 
					: Entry(this)
 | 
				
			||||||
, _id(id)
 | 
					, _id(id)
 | 
				
			||||||
 | 
					, _parent(parent)
 | 
				
			||||||
, _name(lang(lng_feed_name)) {
 | 
					, _name(lang(lng_feed_name)) {
 | 
				
			||||||
	indexNameParts();
 | 
						indexNameParts();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FeedId Feed::id() const {
 | 
				
			||||||
 | 
						return _id;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Feed::indexNameParts() {
 | 
					void Feed::indexNameParts() {
 | 
				
			||||||
	_nameWords.clear();
 | 
						_nameWords.clear();
 | 
				
			||||||
	_nameFirstLetters.clear();
 | 
						_nameFirstLetters.clear();
 | 
				
			||||||
| 
						 | 
					@ -59,18 +68,37 @@ void Feed::indexNameParts() {
 | 
				
			||||||
void Feed::registerOne(not_null<ChannelData*> channel) {
 | 
					void Feed::registerOne(not_null<ChannelData*> channel) {
 | 
				
			||||||
	const auto history = App::history(channel);
 | 
						const auto history = App::history(channel);
 | 
				
			||||||
	if (!base::contains(_channels, history)) {
 | 
						if (!base::contains(_channels, history)) {
 | 
				
			||||||
 | 
							const auto invisible = (_channels.size() < 2);
 | 
				
			||||||
		_channels.push_back(history);
 | 
							_channels.push_back(history);
 | 
				
			||||||
		if (history->lastMsg) {
 | 
							if (history->lastMsg) {
 | 
				
			||||||
			updateLastMessage(history->lastMsg);
 | 
								updateLastMessage(history->lastMsg);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							_parent->session().storage().remove(
 | 
				
			||||||
 | 
								Storage::FeedMessagesInvalidate(_id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							history->updateChatListExistence();
 | 
				
			||||||
 | 
							if (invisible && _channels.size() > 1) {
 | 
				
			||||||
 | 
								updateChatListExistence();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Feed::unregisterOne(not_null<ChannelData*> channel) {
 | 
					void Feed::unregisterOne(not_null<ChannelData*> channel) {
 | 
				
			||||||
	const auto history = App::history(channel);
 | 
						const auto history = App::history(channel);
 | 
				
			||||||
	_channels.erase(ranges::remove(_channels, history), end(_channels));
 | 
						const auto i = ranges::remove(_channels, history);
 | 
				
			||||||
	if (_lastMessage->history() == history) {
 | 
						if (i != end(_channels)) {
 | 
				
			||||||
		messageRemoved(_lastMessage);
 | 
							const auto visible = (_channels.size() > 1);
 | 
				
			||||||
 | 
							_channels.erase(i, end(_channels));
 | 
				
			||||||
 | 
							if (_lastMessage && _lastMessage->history() == history) {
 | 
				
			||||||
 | 
								messageRemoved(_lastMessage);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							_parent->session().storage().remove(
 | 
				
			||||||
 | 
								Storage::FeedMessagesRemoveAll(_id, channel->bareId()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							history->updateChatListExistence();
 | 
				
			||||||
 | 
							if (visible && _channels.size() < 2) {
 | 
				
			||||||
 | 
								updateChatListExistence();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,6 +133,7 @@ void Feed::paintUserpic(
 | 
				
			||||||
		case 1:
 | 
							case 1:
 | 
				
			||||||
		case 3: x += delta; break;
 | 
							case 3: x += delta; break;
 | 
				
			||||||
		case 2: x -= delta; y += delta; break;
 | 
							case 2: x -= delta; y += delta; break;
 | 
				
			||||||
 | 
							case 4: return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -146,4 +175,48 @@ void Feed::setUnreadCounts(int unreadCount, int unreadMutedCount) {
 | 
				
			||||||
	_unreadMutedCount = unreadMutedCount;
 | 
						_unreadMutedCount = unreadMutedCount;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Feed::setUnreadPosition(const MessagePosition &position) {
 | 
				
			||||||
 | 
						_unreadPosition = position;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MessagePosition Feed::unreadPosition() const {
 | 
				
			||||||
 | 
						return _unreadPosition.current();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rpl::producer<MessagePosition> Feed::unreadPositionChanges() const {
 | 
				
			||||||
 | 
						return _unreadPosition.changes();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Feed::toImportant() const {
 | 
				
			||||||
 | 
						return false; // TODO feeds workmode
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Feed::shouldBeInChatList() const {
 | 
				
			||||||
 | 
						return _channels.size() > 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int Feed::chatListUnreadCount() const {
 | 
				
			||||||
 | 
						return _unreadCount;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Feed::chatListMutedBadge() const {
 | 
				
			||||||
 | 
						return _unreadCount <= _unreadMutedCount;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HistoryItem *Feed::chatsListItem() const {
 | 
				
			||||||
 | 
						return _lastMessage;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const QString &Feed::chatsListName() const {
 | 
				
			||||||
 | 
						return _name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const base::flat_set<QString> &Feed::chatsListNameWords() const {
 | 
				
			||||||
 | 
						return _nameWords;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const base::flat_set<QChar> &Feed::chatsListFirstLetters() const {
 | 
				
			||||||
 | 
						return _nameFirstLetters;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Data
 | 
					} // namespace Data
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,15 +14,17 @@ class ChannelData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Data {
 | 
					namespace Data {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Session;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MessagePosition FeedPositionFromMTP(const MTPFeedPosition &position);
 | 
					MessagePosition FeedPositionFromMTP(const MTPFeedPosition &position);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Feed : public Dialogs::Entry {
 | 
					class Feed : public Dialogs::Entry {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Feed(FeedId id);
 | 
						static constexpr auto kId = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	FeedId id() const {
 | 
						Feed(FeedId id, not_null<Data::Session*> parent);
 | 
				
			||||||
		return _id;
 | 
					
 | 
				
			||||||
	}
 | 
						FeedId id() const;
 | 
				
			||||||
	void registerOne(not_null<ChannelData*> channel);
 | 
						void registerOne(not_null<ChannelData*> channel);
 | 
				
			||||||
	void unregisterOne(not_null<ChannelData*> channel);
 | 
						void unregisterOne(not_null<ChannelData*> channel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,37 +33,18 @@ public:
 | 
				
			||||||
	void historyCleared(not_null<History*> history);
 | 
						void historyCleared(not_null<History*> history);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void setUnreadCounts(int unreadCount, int unreadMutedCount);
 | 
						void setUnreadCounts(int unreadCount, int unreadMutedCount);
 | 
				
			||||||
	void setUnreadPosition(const MessagePosition &position) {
 | 
						void setUnreadPosition(const MessagePosition &position);
 | 
				
			||||||
		_unreadPosition = position;
 | 
						MessagePosition unreadPosition() const;
 | 
				
			||||||
	}
 | 
						rpl::producer<MessagePosition> unreadPositionChanges() const;
 | 
				
			||||||
	MessagePosition unreadPosition() const {
 | 
					 | 
				
			||||||
		return _unreadPosition.current();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	rpl::producer<MessagePosition> unreadPositionChanges() const {
 | 
					 | 
				
			||||||
		return _unreadPosition.changes();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool toImportant() const override {
 | 
						bool toImportant() const override;
 | 
				
			||||||
		return false; // TODO feeds workmode
 | 
						bool shouldBeInChatList() const override;
 | 
				
			||||||
	}
 | 
						int chatListUnreadCount() const override;
 | 
				
			||||||
	int chatListUnreadCount() const override {
 | 
						bool chatListMutedBadge() const override;
 | 
				
			||||||
		return _unreadCount;
 | 
						HistoryItem *chatsListItem() const override;
 | 
				
			||||||
	}
 | 
						const QString &chatsListName() const override;
 | 
				
			||||||
	bool chatListMutedBadge() const override {
 | 
						const base::flat_set<QString> &chatsListNameWords() const override;
 | 
				
			||||||
		return _unreadCount <= _unreadMutedCount;
 | 
						const base::flat_set<QChar> &chatsListFirstLetters() const override;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	HistoryItem *chatsListItem() const override {
 | 
					 | 
				
			||||||
		return _lastMessage;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	const QString &chatsListName() const override {
 | 
					 | 
				
			||||||
		return _name;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	const base::flat_set<QString> &chatsListNameWords() const override {
 | 
					 | 
				
			||||||
		return _nameWords;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	const base::flat_set<QChar> &chatsListFirstLetters() const override {
 | 
					 | 
				
			||||||
		return _nameFirstLetters;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void loadUserpic() override;
 | 
						void loadUserpic() override;
 | 
				
			||||||
	void paintUserpic(
 | 
						void paintUserpic(
 | 
				
			||||||
| 
						 | 
					@ -76,6 +59,7 @@ private:
 | 
				
			||||||
	bool justSetLastMessage(not_null<HistoryItem*> item);
 | 
						bool justSetLastMessage(not_null<HistoryItem*> item);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	FeedId _id = 0;
 | 
						FeedId _id = 0;
 | 
				
			||||||
 | 
						not_null<Data::Session*> _parent;
 | 
				
			||||||
	std::vector<not_null<History*>> _channels;
 | 
						std::vector<not_null<History*>> _channels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QString _name;
 | 
						QString _name;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,8 +64,16 @@ rpl::producer<MessagesSlice> FeedMessagesViewer(
 | 
				
			||||||
		Auth().storage().feedMessagesAllRemoved(
 | 
							Auth().storage().feedMessagesAllRemoved(
 | 
				
			||||||
		) | rpl::filter([=](const AllRemoved &update) {
 | 
							) | rpl::filter([=](const AllRemoved &update) {
 | 
				
			||||||
			return (update.feedId == key.feedId);
 | 
								return (update.feedId == key.feedId);
 | 
				
			||||||
 | 
							}) | rpl::filter([=](const AllRemoved &update) {
 | 
				
			||||||
 | 
								return builder->removeFromChannel(update.channelId);
 | 
				
			||||||
 | 
							}) | rpl::start_with_next(pushNextSnapshot, lifetime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							using Invalidate = Storage::FeedMessagesInvalidate;
 | 
				
			||||||
 | 
							Auth().storage().feedMessagesInvalidated(
 | 
				
			||||||
 | 
							) | rpl::filter([=](const Invalidate &update) {
 | 
				
			||||||
 | 
								return (update.feedId == key.feedId);
 | 
				
			||||||
		}) | rpl::filter([=] {
 | 
							}) | rpl::filter([=] {
 | 
				
			||||||
			return builder->removeAll();
 | 
								return builder->invalidated();
 | 
				
			||||||
		}) | rpl::start_with_next(pushNextSnapshot, lifetime);
 | 
							}) | rpl::start_with_next(pushNextSnapshot, lifetime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		using Result = Storage::FeedMessagesResult;
 | 
							using Result = Storage::FeedMessagesResult;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -136,7 +136,7 @@ void MessagesList::removeOne(MessagePosition messageId) {
 | 
				
			||||||
		std::less<>(),
 | 
							std::less<>(),
 | 
				
			||||||
		[](const Slice &slice) { return slice.range.till; });
 | 
							[](const Slice &slice) { return slice.range.till; });
 | 
				
			||||||
	if (slice != _slices.end() && slice->range.from <= messageId) {
 | 
						if (slice != _slices.end() && slice->range.from <= messageId) {
 | 
				
			||||||
		_slices.modify(slice, [messageId](Slice &slice) {
 | 
							_slices.modify(slice, [&](Slice &slice) {
 | 
				
			||||||
			return slice.messages.remove(messageId);
 | 
								return slice.messages.remove(messageId);
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -146,9 +146,28 @@ void MessagesList::removeOne(MessagePosition messageId) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MessagesList::removeAll(ChannelId channelId) {
 | 
					void MessagesList::removeAll(ChannelId channelId) {
 | 
				
			||||||
	// #TODO feeds show
 | 
						auto removed = 0;
 | 
				
			||||||
	//_slices.clear();
 | 
						for (auto i = begin(_slices); i != end(_slices); ++i) {
 | 
				
			||||||
	//_slices.emplace(base::flat_set<MessagePosition>{}, FullMessagesRange);
 | 
							_slices.modify(i, [&](Slice &slice) {
 | 
				
			||||||
 | 
								auto &messages = slice.messages;
 | 
				
			||||||
 | 
								for (auto j = begin(messages); j != end(messages);) {
 | 
				
			||||||
 | 
									if (j->fullId.channel == channelId) {
 | 
				
			||||||
 | 
										j = messages.erase(j);
 | 
				
			||||||
 | 
										++removed;
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										++j;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (removed && _count) {
 | 
				
			||||||
 | 
							*_count -= removed;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MessagesList::invalidated() {
 | 
				
			||||||
 | 
						_slices.clear();
 | 
				
			||||||
 | 
						_count = base::none;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rpl::producer<MessagesResult> MessagesList::query(
 | 
					rpl::producer<MessagesResult> MessagesList::query(
 | 
				
			||||||
| 
						 | 
					@ -302,6 +321,13 @@ bool MessagesSliceBuilder::removeFromChannel(ChannelId channelId) {
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool MessagesSliceBuilder::invalidated() {
 | 
				
			||||||
 | 
						_fullCount = _skippedBefore = _skippedAfter = base::none;
 | 
				
			||||||
 | 
						_ids.clear();
 | 
				
			||||||
 | 
						checkInsufficient();
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MessagesSliceBuilder::checkInsufficient() {
 | 
					void MessagesSliceBuilder::checkInsufficient() {
 | 
				
			||||||
	sliceToLimits();
 | 
						sliceToLimits();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -130,6 +130,7 @@ public:
 | 
				
			||||||
		base::optional<int> count);
 | 
							base::optional<int> count);
 | 
				
			||||||
	void removeOne(MessagePosition messageId);
 | 
						void removeOne(MessagePosition messageId);
 | 
				
			||||||
	void removeAll(ChannelId channelId);
 | 
						void removeAll(ChannelId channelId);
 | 
				
			||||||
 | 
						void invalidated();
 | 
				
			||||||
	rpl::producer<MessagesResult> query(MessagesQuery &&query) const;
 | 
						rpl::producer<MessagesResult> query(MessagesQuery &&query) const;
 | 
				
			||||||
	rpl::producer<MessagesSliceUpdate> sliceUpdated() const;
 | 
						rpl::producer<MessagesSliceUpdate> sliceUpdated() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -194,6 +195,7 @@ public:
 | 
				
			||||||
	bool removeOne(MessagePosition messageId);
 | 
						bool removeOne(MessagePosition messageId);
 | 
				
			||||||
	bool removeFromChannel(ChannelId channelId);
 | 
						bool removeFromChannel(ChannelId channelId);
 | 
				
			||||||
	bool removeAll();
 | 
						bool removeAll();
 | 
				
			||||||
 | 
						bool invalidated();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void checkInsufficient();
 | 
						void checkInsufficient();
 | 
				
			||||||
	struct AroundData {
 | 
						struct AroundData {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -862,10 +862,11 @@ void ChannelData::clearFeed() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ChannelData::setFeedPointer(Data::Feed *feed) {
 | 
					void ChannelData::setFeedPointer(Data::Feed *feed) {
 | 
				
			||||||
	if (_feed != feed) {
 | 
						if (_feed != feed) {
 | 
				
			||||||
		if (_feed) {
 | 
							const auto was = _feed;
 | 
				
			||||||
			_feed->unregisterOne(this);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		_feed = feed;
 | 
							_feed = feed;
 | 
				
			||||||
 | 
							if (was) {
 | 
				
			||||||
 | 
								was->unregisterOne(this);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (_feed) {
 | 
							if (_feed) {
 | 
				
			||||||
			_feed->registerOne(this);
 | 
								_feed->registerOne(this);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1426,7 +1426,7 @@ not_null<Data::Feed*> Session::feed(FeedId id) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	const auto [it, ok] = _feeds.emplace(
 | 
						const auto [it, ok] = _feeds.emplace(
 | 
				
			||||||
		id,
 | 
							id,
 | 
				
			||||||
		std::make_unique<Data::Feed>(id));
 | 
							std::make_unique<Data::Feed>(id, this));
 | 
				
			||||||
	return it->second.get();
 | 
						return it->second.get();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,6 +37,10 @@ public:
 | 
				
			||||||
	explicit Session(not_null<AuthSession*> session);
 | 
						explicit Session(not_null<AuthSession*> session);
 | 
				
			||||||
	~Session();
 | 
						~Session();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						AuthSession &session() const {
 | 
				
			||||||
 | 
							return *_session;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	base::Variable<bool> &contactsLoaded() {
 | 
						base::Variable<bool> &contactsLoaded() {
 | 
				
			||||||
		return _contactsLoaded;
 | 
							return _contactsLoaded;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,26 +65,56 @@ void Entry::cachePinnedIndex(int index) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Entry::needUpdateInChatList() const {
 | 
				
			||||||
 | 
						return inChatList(Dialogs::Mode::All) || shouldBeInChatList();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Entry::updateChatListSortPosition() {
 | 
					void Entry::updateChatListSortPosition() {
 | 
				
			||||||
	_sortKeyInChatList = isPinnedDialog()
 | 
						_sortKeyInChatList = isPinnedDialog()
 | 
				
			||||||
		? PinnedDialogPos(_pinnedIndex)
 | 
							? PinnedDialogPos(_pinnedIndex)
 | 
				
			||||||
		: DialogPosFromDate(adjustChatListDate());
 | 
							: DialogPosFromDate(adjustChatListDate());
 | 
				
			||||||
	if (auto m = App::main()) {
 | 
						if (needUpdateInChatList()) {
 | 
				
			||||||
		if (needUpdateInChatList()) {
 | 
							setChatListExistence(true);
 | 
				
			||||||
			if (_sortKeyInChatList) {
 | 
						}
 | 
				
			||||||
				m->createDialog(_key);
 | 
					}
 | 
				
			||||||
				updateChatListEntry();
 | 
					
 | 
				
			||||||
			} else {
 | 
					void Entry::updateChatListExistence() {
 | 
				
			||||||
				removeDialog();
 | 
						setChatListExistence(shouldBeInChatList());
 | 
				
			||||||
			}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Entry::setChatListExistence(bool exists) {
 | 
				
			||||||
 | 
						if (const auto main = App::main()) {
 | 
				
			||||||
 | 
							if (exists && _sortKeyInChatList) {
 | 
				
			||||||
 | 
								main->createDialog(_key);
 | 
				
			||||||
 | 
								updateChatListEntry();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								main->removeDialog(_key);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Entry::removeDialog() {
 | 
					QDateTime Entry::adjustChatListDate() const {
 | 
				
			||||||
	if (const auto main = App::main()) {
 | 
						return chatsListDate();
 | 
				
			||||||
		main->removeDialog(_key);
 | 
					}
 | 
				
			||||||
	}
 | 
					
 | 
				
			||||||
 | 
					void Entry::changedInChatListHook(Dialogs::Mode list, bool added) {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Entry::changedChatListPinHook() {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RowsByLetter &Entry::chatListLinks(Mode list) {
 | 
				
			||||||
 | 
						return _chatListLinks[static_cast<int>(list)];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const RowsByLetter &Entry::chatListLinks(Mode list) const {
 | 
				
			||||||
 | 
						return _chatListLinks[static_cast<int>(list)];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Row *Entry::mainChatListLink(Mode list) const {
 | 
				
			||||||
 | 
						auto it = chatListLinks(list).find(0);
 | 
				
			||||||
 | 
						Assert(it != chatListLinks(list).cend());
 | 
				
			||||||
 | 
						return it->second;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PositionChange Entry::adjustByPosInChatList(
 | 
					PositionChange Entry::adjustByPosInChatList(
 | 
				
			||||||
| 
						 | 
					@ -99,7 +129,7 @@ PositionChange Entry::adjustByPosInChatList(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Entry::setChatsListDate(const QDateTime &date) {
 | 
					void Entry::setChatsListDate(const QDateTime &date) {
 | 
				
			||||||
	if (!_lastMessageDate.isNull() && _lastMessageDate >= date) {
 | 
						if (!_lastMessageDate.isNull() && _lastMessageDate >= date) {
 | 
				
			||||||
		if (!needUpdateInChatList() || !inChatList(Dialogs::Mode::All)) {
 | 
							if (!inChatList(Dialogs::Mode::All)) {
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,13 +63,11 @@ public:
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	void updateChatListSortPosition();
 | 
						void updateChatListSortPosition();
 | 
				
			||||||
	void setChatsListDate(const QDateTime &date);
 | 
						void setChatsListDate(const QDateTime &date);
 | 
				
			||||||
 | 
						void updateChatListExistence();
 | 
				
			||||||
 | 
						bool needUpdateInChatList() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual bool toImportant() const = 0;
 | 
						virtual bool toImportant() const = 0;
 | 
				
			||||||
 | 
						virtual bool shouldBeInChatList() const = 0;
 | 
				
			||||||
	virtual bool needUpdateInChatList() const {
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	virtual int chatListUnreadCount() const = 0;
 | 
						virtual int chatListUnreadCount() const = 0;
 | 
				
			||||||
	virtual bool chatListMutedBadge() const = 0;
 | 
						virtual bool chatListMutedBadge() const = 0;
 | 
				
			||||||
	virtual HistoryItem *chatsListItem() const = 0;
 | 
						virtual HistoryItem *chatsListItem() const = 0;
 | 
				
			||||||
| 
						 | 
					@ -102,26 +100,14 @@ public:
 | 
				
			||||||
	mutable Text lastItemTextCache;
 | 
						mutable Text lastItemTextCache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	virtual QDateTime adjustChatListDate() const {
 | 
						virtual QDateTime adjustChatListDate() const;
 | 
				
			||||||
		return chatsListDate();
 | 
						virtual void changedInChatListHook(Dialogs::Mode list, bool added);
 | 
				
			||||||
	}
 | 
						virtual void changedChatListPinHook();
 | 
				
			||||||
	virtual void removeDialog();
 | 
					 | 
				
			||||||
	virtual void changedInChatListHook(Dialogs::Mode list, bool added) {
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	virtual void changedChatListPinHook() {
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RowsByLetter &chatListLinks(Mode list) {
 | 
						void setChatListExistence(bool exists);
 | 
				
			||||||
		return _chatListLinks[static_cast<int>(list)];
 | 
						RowsByLetter &chatListLinks(Mode list);
 | 
				
			||||||
	}
 | 
						const RowsByLetter &chatListLinks(Mode list) const;
 | 
				
			||||||
	const RowsByLetter &chatListLinks(Mode list) const {
 | 
						Row *mainChatListLink(Mode list) const;
 | 
				
			||||||
		return _chatListLinks[static_cast<int>(list)];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	Row *mainChatListLink(Mode list) const {
 | 
					 | 
				
			||||||
		auto it = chatListLinks(list).find(0);
 | 
					 | 
				
			||||||
		Assert(it != chatListLinks(list).cend());
 | 
					 | 
				
			||||||
		return it->second;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Dialogs::Key _key;
 | 
						Dialogs::Key _key;
 | 
				
			||||||
	RowsByLetter _chatListLinks[2];
 | 
						RowsByLetter _chatListLinks[2];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | 
				
			||||||
#include "calls/calls_instance.h"
 | 
					#include "calls/calls_instance.h"
 | 
				
			||||||
#include "storage/storage_facade.h"
 | 
					#include "storage/storage_facade.h"
 | 
				
			||||||
#include "storage/storage_shared_media.h"
 | 
					#include "storage/storage_shared_media.h"
 | 
				
			||||||
 | 
					#include "storage/storage_feed_messages.h"
 | 
				
			||||||
#include "data/data_channel_admins.h"
 | 
					#include "data/data_channel_admins.h"
 | 
				
			||||||
#include "data/data_feed.h"
 | 
					#include "data/data_feed.h"
 | 
				
			||||||
#include "ui/text_options.h"
 | 
					#include "ui/text_options.h"
 | 
				
			||||||
| 
						 | 
					@ -1478,7 +1479,13 @@ HistoryBlock *History::prepareBlockForAddingItem() {
 | 
				
			||||||
		blocks.back()->messages.reserve(kNewBlockEachMessage);
 | 
							blocks.back()->messages.reserve(kNewBlockEachMessage);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return blocks.back().get();
 | 
						return blocks.back().get();
 | 
				
			||||||
};
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void History::viewReplaced(not_null<const Element*> was, Element *now) {
 | 
				
			||||||
 | 
						if (scrollTopItem == was) scrollTopItem= now;
 | 
				
			||||||
 | 
						if (_firstUnreadView == was) _firstUnreadView= now;
 | 
				
			||||||
 | 
						if (_unreadBarView == was) _unreadBarView = now;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void History::addItemToBlock(not_null<HistoryItem*> item) {
 | 
					void History::addItemToBlock(not_null<HistoryItem*> item) {
 | 
				
			||||||
	Expects(!item->mainView());
 | 
						Expects(!item->mainView());
 | 
				
			||||||
| 
						 | 
					@ -1908,7 +1915,7 @@ void History::getNextFirstUnreadMessage() {
 | 
				
			||||||
		const auto count = int(block->messages.size());
 | 
							const auto count = int(block->messages.size());
 | 
				
			||||||
		for (auto i = index + 1; i != count; ++i) {
 | 
							for (auto i = index + 1; i != count; ++i) {
 | 
				
			||||||
			const auto &message = block->messages[i];
 | 
								const auto &message = block->messages[i];
 | 
				
			||||||
			if (setFromMessage(block->messages[i])) {
 | 
								if (setFromMessage(message)) {
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -2264,15 +2271,17 @@ void History::setLastMessage(HistoryItem *msg) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool History::needUpdateInChatList() const {
 | 
					bool History::shouldBeInChatList() const {
 | 
				
			||||||
	if (inChatList(Dialogs::Mode::All)) {
 | 
						if (peer->migrateTo()) {
 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	} else if (peer->migrateTo()) {
 | 
					 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	} else if (isPinnedDialog()) {
 | 
						} else if (isPinnedDialog()) {
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	} else if (const auto channel = peer->asChannel()) {
 | 
						} else if (const auto channel = peer->asChannel()) {
 | 
				
			||||||
		return !channel->feed() && channel->amIn();
 | 
							if (!channel->amIn()) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							} else if (const auto feed = channel->feed()) {
 | 
				
			||||||
 | 
								return !feed->needUpdateInChatList();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2396,6 +2405,13 @@ void History::clear(bool leaveItems) {
 | 
				
			||||||
		setLastMessage(nullptr);
 | 
							setLastMessage(nullptr);
 | 
				
			||||||
		notifies.clear();
 | 
							notifies.clear();
 | 
				
			||||||
		Auth().storage().remove(Storage::SharedMediaRemoveAll(peer->id));
 | 
							Auth().storage().remove(Storage::SharedMediaRemoveAll(peer->id));
 | 
				
			||||||
 | 
							if (const auto channel = peer->asChannel()) {
 | 
				
			||||||
 | 
								if (const auto feed = channel->feed()) {
 | 
				
			||||||
 | 
									Auth().storage().remove(Storage::FeedMessagesRemoveAll(
 | 
				
			||||||
 | 
										feed->id(),
 | 
				
			||||||
 | 
										channel->bareId()));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		Auth().data().notifyHistoryCleared(this);
 | 
							Auth().data().notifyHistoryCleared(this);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	clearBlocks(leaveItems);
 | 
						clearBlocks(leaveItems);
 | 
				
			||||||
| 
						 | 
					@ -2483,12 +2499,6 @@ void History::clearOnDestroy() {
 | 
				
			||||||
	clearBlocks(false);
 | 
						clearBlocks(false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void History::removeDialog() {
 | 
					 | 
				
			||||||
	if (const auto main = App::main()) {
 | 
					 | 
				
			||||||
		main->deleteConversation(peer, false);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void History::changedInChatListHook(Dialogs::Mode list, bool added) {
 | 
					void History::changedInChatListHook(Dialogs::Mode list, bool added) {
 | 
				
			||||||
	if (list == Dialogs::Mode::All && unreadCount()) {
 | 
						if (list == Dialogs::Mode::All && unreadCount()) {
 | 
				
			||||||
		const auto delta = added ? unreadCount() : -unreadCount();
 | 
							const auto delta = added ? unreadCount() : -unreadCount();
 | 
				
			||||||
| 
						 | 
					@ -2588,9 +2598,7 @@ void HistoryBlock::refreshView(not_null<Element*> view) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto blockIndex = indexInHistory();
 | 
						auto blockIndex = indexInHistory();
 | 
				
			||||||
	auto itemIndex = view->indexInBlock();
 | 
						auto itemIndex = view->indexInBlock();
 | 
				
			||||||
	if (_history->scrollTopItem == view) {
 | 
						_history->viewReplaced(view, refreshed.get());
 | 
				
			||||||
		_history->scrollTopItem = refreshed.get();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	messages[itemIndex] = std::move(refreshed);
 | 
						messages[itemIndex] = std::move(refreshed);
 | 
				
			||||||
	messages[itemIndex]->attachToBlock(this, itemIndex);
 | 
						messages[itemIndex]->attachToBlock(this, itemIndex);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -130,6 +130,8 @@ class IndexedList;
 | 
				
			||||||
class ChannelHistory;
 | 
					class ChannelHistory;
 | 
				
			||||||
class History : public Dialogs::Entry {
 | 
					class History : public Dialogs::Entry {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
						using Element = HistoryView::Element;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	History(const PeerId &peerId);
 | 
						History(const PeerId &peerId);
 | 
				
			||||||
	History(const History &) = delete;
 | 
						History(const History &) = delete;
 | 
				
			||||||
	History &operator=(const History &) = delete;
 | 
						History &operator=(const History &) = delete;
 | 
				
			||||||
| 
						 | 
					@ -198,10 +200,10 @@ public:
 | 
				
			||||||
	void addUnreadBar();
 | 
						void addUnreadBar();
 | 
				
			||||||
	void destroyUnreadBar();
 | 
						void destroyUnreadBar();
 | 
				
			||||||
	bool hasNotFreezedUnreadBar() const;
 | 
						bool hasNotFreezedUnreadBar() const;
 | 
				
			||||||
	HistoryView::Element *unreadBar() const;
 | 
						Element *unreadBar() const;
 | 
				
			||||||
	void calculateFirstUnreadMessage();
 | 
						void calculateFirstUnreadMessage();
 | 
				
			||||||
	void unsetFirstUnreadMessage();
 | 
						void unsetFirstUnreadMessage();
 | 
				
			||||||
	HistoryView::Element *firstUnreadMessage() const;
 | 
						Element *firstUnreadMessage() const;
 | 
				
			||||||
	void clearNotifications();
 | 
						void clearNotifications();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool loadedAtBottom() const; // last message is in the list
 | 
						bool loadedAtBottom() const; // last message is in the list
 | 
				
			||||||
| 
						 | 
					@ -310,7 +312,7 @@ public:
 | 
				
			||||||
	HistoryItemsList validateForwardDraft();
 | 
						HistoryItemsList validateForwardDraft();
 | 
				
			||||||
	void setForwardDraft(MessageIdsList &&items);
 | 
						void setForwardDraft(MessageIdsList &&items);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool needUpdateInChatList() const override;
 | 
						bool shouldBeInChatList() const override;
 | 
				
			||||||
	bool toImportant() const override {
 | 
						bool toImportant() const override {
 | 
				
			||||||
		return !mute();
 | 
							return !mute();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -363,7 +365,7 @@ public:
 | 
				
			||||||
	// we save a pointer of the history item at the top of the displayed window
 | 
						// we save a pointer of the history item at the top of the displayed window
 | 
				
			||||||
	// together with an offset from the window top to the top of this message
 | 
						// together with an offset from the window top to the top of this message
 | 
				
			||||||
	// resulting scrollTop = top(scrollTopItem) + scrollTopOffset
 | 
						// resulting scrollTop = top(scrollTopItem) + scrollTopOffset
 | 
				
			||||||
	HistoryView::Element *scrollTopItem = nullptr;
 | 
						Element *scrollTopItem = nullptr;
 | 
				
			||||||
	int scrollTopOffset = 0;
 | 
						int scrollTopOffset = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool lastKeyboardInited = false;
 | 
						bool lastKeyboardInited = false;
 | 
				
			||||||
| 
						 | 
					@ -439,10 +441,9 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void mainViewRemoved(
 | 
						void mainViewRemoved(
 | 
				
			||||||
		not_null<HistoryBlock*> block,
 | 
							not_null<HistoryBlock*> block,
 | 
				
			||||||
		not_null<HistoryView::Element*> view);
 | 
							not_null<Element*> view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QDateTime adjustChatListDate() const override;
 | 
						QDateTime adjustChatListDate() const override;
 | 
				
			||||||
	void removeDialog() override;
 | 
					 | 
				
			||||||
	void changedInChatListHook(Dialogs::Mode list, bool added) override;
 | 
						void changedInChatListHook(Dialogs::Mode list, bool added) override;
 | 
				
			||||||
	void changedChatListPinHook() override;
 | 
						void changedChatListPinHook() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -474,13 +475,15 @@ private:
 | 
				
			||||||
	// Depending on isBuildingFrontBlock() gets front or back block.
 | 
						// Depending on isBuildingFrontBlock() gets front or back block.
 | 
				
			||||||
	HistoryBlock *prepareBlockForAddingItem();
 | 
						HistoryBlock *prepareBlockForAddingItem();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void viewReplaced(not_null<const Element*> was, Element *now);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Flags _flags = 0;
 | 
						Flags _flags = 0;
 | 
				
			||||||
	bool _mute = false;
 | 
						bool _mute = false;
 | 
				
			||||||
	int _unreadCount = 0;
 | 
						int _unreadCount = 0;
 | 
				
			||||||
	int _width = 0;
 | 
						int _width = 0;
 | 
				
			||||||
	int _height = 0;
 | 
						int _height = 0;
 | 
				
			||||||
	HistoryView::Element *_unreadBarView = nullptr;
 | 
						Element *_unreadBarView = nullptr;
 | 
				
			||||||
	HistoryView::Element *_firstUnreadView = nullptr;
 | 
						Element *_firstUnreadView = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	base::optional<int> _unreadMentionsCount;
 | 
						base::optional<int> _unreadMentionsCount;
 | 
				
			||||||
	base::flat_set<MsgId> _unreadMentions;
 | 
						base::flat_set<MsgId> _unreadMentions;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4349,11 +4349,11 @@ void HistoryWidget::sendFileConfirmed(
 | 
				
			||||||
			NewMessageUnread);
 | 
								NewMessageUnread);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Auth().data().sendHistoryChangeNotifications();
 | 
				
			||||||
	if (_peer && file->to.peer == _peer->id) {
 | 
						if (_peer && file->to.peer == _peer->id) {
 | 
				
			||||||
		App::main()->historyToDown(_history);
 | 
							App::main()->historyToDown(_history);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	App::main()->dialogsToUp();
 | 
						App::main()->dialogsToUp();
 | 
				
			||||||
	Auth().data().sendHistoryChangeNotifications();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void HistoryWidget::onPhotoUploaded(
 | 
					void HistoryWidget::onPhotoUploaded(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | 
				
			||||||
#include "apiwrap.h"
 | 
					#include "apiwrap.h"
 | 
				
			||||||
#include "layout.h"
 | 
					#include "layout.h"
 | 
				
			||||||
#include "window/window_controller.h"
 | 
					#include "window/window_controller.h"
 | 
				
			||||||
 | 
					#include "window/window_peer_menu.h"
 | 
				
			||||||
#include "auth_session.h"
 | 
					#include "auth_session.h"
 | 
				
			||||||
#include "ui/widgets/popup_menu.h"
 | 
					#include "ui/widgets/popup_menu.h"
 | 
				
			||||||
#include "core/file_utilities.h"
 | 
					#include "core/file_utilities.h"
 | 
				
			||||||
| 
						 | 
					@ -879,6 +880,12 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (lnkPeer) { // suggest to block
 | 
						} else if (lnkPeer) { // suggest to block
 | 
				
			||||||
		// #TODO suggest restrict peer
 | 
							// #TODO suggest restrict peer
 | 
				
			||||||
 | 
							if (const auto channel = lnkPeer->peer()->asChannel()) {
 | 
				
			||||||
 | 
								const auto grouped = (channel->feed() != nullptr);
 | 
				
			||||||
 | 
								_menu->addAction(
 | 
				
			||||||
 | 
									lang(grouped ? lng_feed_ungroup : lng_feed_group),
 | 
				
			||||||
 | 
									[=] { Window::ToggleChannelGrouping(channel, !grouped); });
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} else { // maybe cursor on some text history item?
 | 
						} else { // maybe cursor on some text history item?
 | 
				
			||||||
		const auto item = view ? view->data().get() : nullptr;
 | 
							const auto item = view ? view->data().get() : nullptr;
 | 
				
			||||||
		const auto itemId = item ? item->fullId() : FullMsgId();
 | 
							const auto itemId = item ? item->fullId() : FullMsgId();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -699,6 +699,7 @@ void MainWidget::finishForwarding(not_null<History*> history) {
 | 
				
			||||||
		cancelForwarding(history);
 | 
							cancelForwarding(history);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Auth().data().sendHistoryChangeNotifications();
 | 
				
			||||||
	historyToDown(history);
 | 
						historyToDown(history);
 | 
				
			||||||
	dialogsToUp();
 | 
						dialogsToUp();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1059,8 +1060,8 @@ void MainWidget::deleteConversation(
 | 
				
			||||||
		history->newLoaded = true;
 | 
							history->newLoaded = true;
 | 
				
			||||||
		history->oldLoaded = deleteHistory;
 | 
							history->oldLoaded = deleteHistory;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (peer->isChannel()) {
 | 
						if (const auto channel = peer->asChannel()) {
 | 
				
			||||||
		peer->asChannel()->ptsWaitingForShortPoll(-1);
 | 
							channel->ptsWaitingForShortPoll(-1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (deleteHistory) {
 | 
						if (deleteHistory) {
 | 
				
			||||||
		DeleteHistoryRequest request = { peer, false };
 | 
							DeleteHistoryRequest request = { peer, false };
 | 
				
			||||||
| 
						 | 
					@ -1268,8 +1269,8 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu
 | 
				
			||||||
					history->asChannelHistory()->insertJoinedMessage(true);
 | 
										history->asChannelHistory()->insertJoinedMessage(true);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else if (const auto history = App::historyLoaded(peer->id)) {
 | 
				
			||||||
			deleteConversation(peer, false);
 | 
								deleteConversation(history->peer, false);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		const auto history = App::history(peer->id);
 | 
							const auto history = App::history(peer->id);
 | 
				
			||||||
| 
						 | 
					@ -5221,8 +5222,10 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 | 
				
			||||||
		if (auto channel = App::channelLoaded(d.vchannel_id.v)) {
 | 
							if (auto channel = App::channelLoaded(d.vchannel_id.v)) {
 | 
				
			||||||
			channel->inviter = 0;
 | 
								channel->inviter = 0;
 | 
				
			||||||
			if (!channel->amIn()) {
 | 
								if (!channel->amIn()) {
 | 
				
			||||||
				deleteConversation(channel, false);
 | 
									if (const auto history = App::historyLoaded(channel->id)) {
 | 
				
			||||||
			} else if (!channel->amCreator() && App::history(channel->id)) { // create history
 | 
										history->updateChatListExistence();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else if (!channel->amCreator() && App::history(channel->id)) {
 | 
				
			||||||
				_updatedChannels.insert(channel, true);
 | 
									_updatedChannels.insert(channel, true);
 | 
				
			||||||
				Auth().api().requestSelfParticipant(channel);
 | 
									Auth().api().requestSelfParticipant(channel);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,11 +36,13 @@ public:
 | 
				
			||||||
	void add(FeedMessagesAddSlice &&query);
 | 
						void add(FeedMessagesAddSlice &&query);
 | 
				
			||||||
	void remove(FeedMessagesRemoveOne &&query);
 | 
						void remove(FeedMessagesRemoveOne &&query);
 | 
				
			||||||
	void remove(FeedMessagesRemoveAll &&query);
 | 
						void remove(FeedMessagesRemoveAll &&query);
 | 
				
			||||||
 | 
						void remove(FeedMessagesInvalidate &&query);
 | 
				
			||||||
	rpl::producer<FeedMessagesResult> query(
 | 
						rpl::producer<FeedMessagesResult> query(
 | 
				
			||||||
		FeedMessagesQuery &&query) const;
 | 
							FeedMessagesQuery &&query) const;
 | 
				
			||||||
	rpl::producer<FeedMessagesSliceUpdate> feedMessagesSliceUpdated() const;
 | 
						rpl::producer<FeedMessagesSliceUpdate> feedMessagesSliceUpdated() const;
 | 
				
			||||||
	rpl::producer<FeedMessagesRemoveOne> feedMessagesOneRemoved() const;
 | 
						rpl::producer<FeedMessagesRemoveOne> feedMessagesOneRemoved() const;
 | 
				
			||||||
	rpl::producer<FeedMessagesRemoveAll> feedMessagesAllRemoved() const;
 | 
						rpl::producer<FeedMessagesRemoveAll> feedMessagesAllRemoved() const;
 | 
				
			||||||
 | 
						rpl::producer<FeedMessagesInvalidate> feedMessagesInvalidated() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	SharedMedia _sharedMedia;
 | 
						SharedMedia _sharedMedia;
 | 
				
			||||||
| 
						 | 
					@ -125,6 +127,10 @@ void Facade::Impl::remove(FeedMessagesRemoveAll &&query) {
 | 
				
			||||||
	return _feedMessages.remove(std::move(query));
 | 
						return _feedMessages.remove(std::move(query));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Facade::Impl::remove(FeedMessagesInvalidate &&query) {
 | 
				
			||||||
 | 
						return _feedMessages.remove(std::move(query));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rpl::producer<FeedMessagesResult> Facade::Impl::query(
 | 
					rpl::producer<FeedMessagesResult> Facade::Impl::query(
 | 
				
			||||||
		FeedMessagesQuery &&query) const {
 | 
							FeedMessagesQuery &&query) const {
 | 
				
			||||||
	return _feedMessages.query(std::move(query));
 | 
						return _feedMessages.query(std::move(query));
 | 
				
			||||||
| 
						 | 
					@ -142,6 +148,10 @@ rpl::producer<FeedMessagesRemoveAll> Facade::Impl::feedMessagesAllRemoved() cons
 | 
				
			||||||
	return _feedMessages.allRemoved();
 | 
						return _feedMessages.allRemoved();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rpl::producer<FeedMessagesInvalidate> Facade::Impl::feedMessagesInvalidated() const {
 | 
				
			||||||
 | 
						return _feedMessages.invalidated();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Facade::Facade() : _impl(std::make_unique<Impl>()) {
 | 
					Facade::Facade() : _impl(std::make_unique<Impl>()) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -221,6 +231,10 @@ void Facade::remove(FeedMessagesRemoveAll &&query) {
 | 
				
			||||||
	return _impl->remove(std::move(query));
 | 
						return _impl->remove(std::move(query));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Facade::remove(FeedMessagesInvalidate &&query) {
 | 
				
			||||||
 | 
						return _impl->remove(std::move(query));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rpl::producer<FeedMessagesResult> Facade::query(
 | 
					rpl::producer<FeedMessagesResult> Facade::query(
 | 
				
			||||||
		FeedMessagesQuery &&query) const {
 | 
							FeedMessagesQuery &&query) const {
 | 
				
			||||||
	return _impl->query(std::move(query));
 | 
						return _impl->query(std::move(query));
 | 
				
			||||||
| 
						 | 
					@ -238,6 +252,10 @@ rpl::producer<FeedMessagesRemoveAll> Facade::feedMessagesAllRemoved() const {
 | 
				
			||||||
	return _impl->feedMessagesAllRemoved();
 | 
						return _impl->feedMessagesAllRemoved();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rpl::producer<FeedMessagesInvalidate> Facade::feedMessagesInvalidated() const {
 | 
				
			||||||
 | 
						return _impl->feedMessagesInvalidated();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Facade::~Facade() = default;
 | 
					Facade::~Facade() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Storage
 | 
					} // namespace Storage
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,6 +39,7 @@ struct FeedMessagesAddNew;
 | 
				
			||||||
struct FeedMessagesAddSlice;
 | 
					struct FeedMessagesAddSlice;
 | 
				
			||||||
struct FeedMessagesRemoveOne;
 | 
					struct FeedMessagesRemoveOne;
 | 
				
			||||||
struct FeedMessagesRemoveAll;
 | 
					struct FeedMessagesRemoveAll;
 | 
				
			||||||
 | 
					struct FeedMessagesInvalidate;
 | 
				
			||||||
struct FeedMessagesQuery;
 | 
					struct FeedMessagesQuery;
 | 
				
			||||||
using FeedMessagesResult = Data::MessagesResult;
 | 
					using FeedMessagesResult = Data::MessagesResult;
 | 
				
			||||||
struct FeedMessagesSliceUpdate;
 | 
					struct FeedMessagesSliceUpdate;
 | 
				
			||||||
| 
						 | 
					@ -70,12 +71,14 @@ public:
 | 
				
			||||||
	void add(FeedMessagesAddSlice &&query);
 | 
						void add(FeedMessagesAddSlice &&query);
 | 
				
			||||||
	void remove(FeedMessagesRemoveOne &&query);
 | 
						void remove(FeedMessagesRemoveOne &&query);
 | 
				
			||||||
	void remove(FeedMessagesRemoveAll &&query);
 | 
						void remove(FeedMessagesRemoveAll &&query);
 | 
				
			||||||
 | 
						void remove(FeedMessagesInvalidate &&query);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rpl::producer<FeedMessagesResult> query(
 | 
						rpl::producer<FeedMessagesResult> query(
 | 
				
			||||||
		FeedMessagesQuery &&query) const;
 | 
							FeedMessagesQuery &&query) const;
 | 
				
			||||||
	rpl::producer<FeedMessagesSliceUpdate> feedMessagesSliceUpdated() const;
 | 
						rpl::producer<FeedMessagesSliceUpdate> feedMessagesSliceUpdated() const;
 | 
				
			||||||
	rpl::producer<FeedMessagesRemoveOne> feedMessagesOneRemoved() const;
 | 
						rpl::producer<FeedMessagesRemoveOne> feedMessagesOneRemoved() const;
 | 
				
			||||||
	rpl::producer<FeedMessagesRemoveAll> feedMessagesAllRemoved() const;
 | 
						rpl::producer<FeedMessagesRemoveAll> feedMessagesAllRemoved() const;
 | 
				
			||||||
 | 
						rpl::producer<FeedMessagesInvalidate> feedMessagesInvalidated() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	~Facade();
 | 
						~Facade();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,6 +55,14 @@ void FeedMessages::remove(FeedMessagesRemoveAll &&query) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FeedMessages::remove(FeedMessagesInvalidate &&query) {
 | 
				
			||||||
 | 
						auto feedIt = _lists.find(query.feedId);
 | 
				
			||||||
 | 
						if (feedIt != _lists.end()) {
 | 
				
			||||||
 | 
							feedIt->second.invalidated();
 | 
				
			||||||
 | 
							_invalidated.fire(std::move(query));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rpl::producer<FeedMessagesResult> FeedMessages::query(
 | 
					rpl::producer<FeedMessagesResult> FeedMessages::query(
 | 
				
			||||||
		FeedMessagesQuery &&query) const {
 | 
							FeedMessagesQuery &&query) const {
 | 
				
			||||||
	auto feedIt = _lists.find(query.key.feedId);
 | 
						auto feedIt = _lists.find(query.key.feedId);
 | 
				
			||||||
| 
						 | 
					@ -82,4 +90,8 @@ rpl::producer<FeedMessagesRemoveAll> FeedMessages::allRemoved() const {
 | 
				
			||||||
	return _allRemoved.events();
 | 
						return _allRemoved.events();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rpl::producer<FeedMessagesInvalidate> FeedMessages::invalidated() const {
 | 
				
			||||||
 | 
						return _invalidated.events();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Storage
 | 
					} // namespace Storage
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,6 +64,15 @@ struct FeedMessagesRemoveAll {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct FeedMessagesInvalidate {
 | 
				
			||||||
 | 
						explicit FeedMessagesInvalidate(FeedId feedId)
 | 
				
			||||||
 | 
						: feedId(feedId) {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FeedId feedId = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct FeedMessagesKey {
 | 
					struct FeedMessagesKey {
 | 
				
			||||||
	FeedMessagesKey(
 | 
						FeedMessagesKey(
 | 
				
			||||||
		FeedId feedId,
 | 
							FeedId feedId,
 | 
				
			||||||
| 
						 | 
					@ -122,12 +131,14 @@ public:
 | 
				
			||||||
	void add(FeedMessagesAddSlice &&query);
 | 
						void add(FeedMessagesAddSlice &&query);
 | 
				
			||||||
	void remove(FeedMessagesRemoveOne &&query);
 | 
						void remove(FeedMessagesRemoveOne &&query);
 | 
				
			||||||
	void remove(FeedMessagesRemoveAll &&query);
 | 
						void remove(FeedMessagesRemoveAll &&query);
 | 
				
			||||||
 | 
						void remove(FeedMessagesInvalidate &&query);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rpl::producer<FeedMessagesResult> query(
 | 
						rpl::producer<FeedMessagesResult> query(
 | 
				
			||||||
		FeedMessagesQuery &&query) const;
 | 
							FeedMessagesQuery &&query) const;
 | 
				
			||||||
	rpl::producer<FeedMessagesSliceUpdate> sliceUpdated() const;
 | 
						rpl::producer<FeedMessagesSliceUpdate> sliceUpdated() const;
 | 
				
			||||||
	rpl::producer<FeedMessagesRemoveOne> oneRemoved() const;
 | 
						rpl::producer<FeedMessagesRemoveOne> oneRemoved() const;
 | 
				
			||||||
	rpl::producer<FeedMessagesRemoveAll> allRemoved() const;
 | 
						rpl::producer<FeedMessagesRemoveAll> allRemoved() const;
 | 
				
			||||||
 | 
						rpl::producer<FeedMessagesInvalidate> invalidated() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	using List = Data::MessagesList;
 | 
						using List = Data::MessagesList;
 | 
				
			||||||
| 
						 | 
					@ -139,6 +150,7 @@ private:
 | 
				
			||||||
	rpl::event_stream<FeedMessagesSliceUpdate> _sliceUpdated;
 | 
						rpl::event_stream<FeedMessagesSliceUpdate> _sliceUpdated;
 | 
				
			||||||
	rpl::event_stream<FeedMessagesRemoveOne> _oneRemoved;
 | 
						rpl::event_stream<FeedMessagesRemoveOne> _oneRemoved;
 | 
				
			||||||
	rpl::event_stream<FeedMessagesRemoveAll> _allRemoved;
 | 
						rpl::event_stream<FeedMessagesRemoveAll> _allRemoved;
 | 
				
			||||||
 | 
						rpl::event_stream<FeedMessagesInvalidate> _invalidated;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rpl::lifetime _lifetime;
 | 
						rpl::lifetime _lifetime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -349,6 +349,12 @@ void Filler::addChatActions(not_null<ChatData*> chat) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Filler::addChannelActions(not_null<ChannelData*> channel) {
 | 
					void Filler::addChannelActions(not_null<ChannelData*> channel) {
 | 
				
			||||||
	auto isGroup = channel->isMegagroup();
 | 
						auto isGroup = channel->isMegagroup();
 | 
				
			||||||
 | 
						if (!isGroup) {
 | 
				
			||||||
 | 
							const auto grouped = (channel->feed() != nullptr);
 | 
				
			||||||
 | 
							_addAction(
 | 
				
			||||||
 | 
								lang(grouped ? lng_feed_ungroup : lng_feed_group),
 | 
				
			||||||
 | 
								[=] { ToggleChannelGrouping(channel, !grouped); });
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (_source != PeerMenuSource::ChatsList) {
 | 
						if (_source != PeerMenuSource::ChatsList) {
 | 
				
			||||||
		if (ManagePeerBox::Available(channel)) {
 | 
							if (ManagePeerBox::Available(channel)) {
 | 
				
			||||||
			auto text = lang(isGroup
 | 
								auto text = lang(isGroup
 | 
				
			||||||
| 
						 | 
					@ -583,6 +589,10 @@ void PeerMenuAddChannelMembers(not_null<ChannelData*> channel) {
 | 
				
			||||||
	Auth().api().requestChannelMembersForAdd(channel, callback);
 | 
						Auth().api().requestChannelMembersForAdd(channel, callback);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToggleChannelGrouping(not_null<ChannelData*> channel, bool group) {
 | 
				
			||||||
 | 
						Auth().api().toggleChannelGrouping(channel, group);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
base::lambda<void()> ClearHistoryHandler(not_null<PeerData*> peer) {
 | 
					base::lambda<void()> ClearHistoryHandler(not_null<PeerData*> peer) {
 | 
				
			||||||
	return [peer] {
 | 
						return [peer] {
 | 
				
			||||||
		const auto weak = std::make_shared<QPointer<ConfirmBox>>();
 | 
							const auto weak = std::make_shared<QPointer<ConfirmBox>>();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,6 +45,7 @@ void PeerMenuShareContactBox(not_null<UserData*> user);
 | 
				
			||||||
void PeerMenuAddContact(not_null<UserData*> user);
 | 
					void PeerMenuAddContact(not_null<UserData*> user);
 | 
				
			||||||
void PeerMenuAddChannelMembers(not_null<ChannelData*> channel);
 | 
					void PeerMenuAddChannelMembers(not_null<ChannelData*> channel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToggleChannelGrouping(not_null<ChannelData*> channel, bool group);
 | 
				
			||||||
base::lambda<void()> ClearHistoryHandler(not_null<PeerData*> peer);
 | 
					base::lambda<void()> ClearHistoryHandler(not_null<PeerData*> peer);
 | 
				
			||||||
base::lambda<void()> DeleteAndLeaveHandler(not_null<PeerData*> peer);
 | 
					base::lambda<void()> DeleteAndLeaveHandler(not_null<PeerData*> peer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue