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