Add group/ungroup action in channel peer menu.

This commit is contained in:
John Preston 2018-01-23 19:51:12 +03:00
parent ced0c4d8f0
commit 65df137610
24 changed files with 347 additions and 118 deletions

View file

@ -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

View file

@ -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>(

View file

@ -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*>,

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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();
}

View file

@ -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 {

View file

@ -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);
}

View file

@ -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();
}

View file

@ -37,6 +37,10 @@ public:
explicit Session(not_null<AuthSession*> session);
~Session();
AuthSession &session() const {
return *_session;
}
base::Variable<bool> &contactsLoaded() {
return _contactsLoaded;
}

View file

@ -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;
}
}

View file

@ -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];

View file

@ -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);

View file

@ -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;

View file

@ -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(

View file

@ -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();

View file

@ -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);
}

View file

@ -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

View file

@ -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();

View file

@ -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

View file

@ -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;

View file

@ -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>>();

View file

@ -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);