mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Support default General topic in forums.
This commit is contained in:
parent
2201159da5
commit
73e56b0340
23 changed files with 385 additions and 183 deletions
|
@ -248,6 +248,7 @@ public:
|
|||
not_null<Window::SessionNavigation*> navigation,
|
||||
not_null<Ui::BoxContent*> box,
|
||||
not_null<PeerData*> peer);
|
||||
~Controller();
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::VerticalLayout> createContent();
|
||||
void setFocus();
|
||||
|
@ -388,6 +389,8 @@ Controller::Controller(
|
|||
_peer->updateFull();
|
||||
}
|
||||
|
||||
Controller::~Controller() = default;
|
||||
|
||||
void Controller::subscribeToMigration() {
|
||||
SubscribeToMigration(
|
||||
_peer,
|
||||
|
@ -815,7 +818,7 @@ void Controller::fillForumButton() {
|
|||
|
||||
AddButtonWithText(
|
||||
_controls.buttonsLayout,
|
||||
rpl::single(u"Forum"_q), // #TODO forum
|
||||
rpl::single(u"Forum"_q), // #TODO forum lang
|
||||
rpl::single(QString()),
|
||||
[] {},
|
||||
{ &st::settingsIconGroup, Settings::kIconPurple }
|
||||
|
|
|
@ -60,13 +60,9 @@ Data::ChatBotCommands::Changed MegagroupInfo::setBotCommands(
|
|||
return _botCommands.update(list);
|
||||
}
|
||||
|
||||
void MegagroupInfo::setIsForum(not_null<ChannelData*> that, bool is) {
|
||||
if (is == (_forum != nullptr)) {
|
||||
return;
|
||||
} else if (is) {
|
||||
void MegagroupInfo::ensureForum(not_null<ChannelData*> that) {
|
||||
if (!_forum) {
|
||||
_forum = std::make_unique<Data::Forum>(that->owner().history(that));
|
||||
} else {
|
||||
_forum = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,35 +70,15 @@ Data::Forum *MegagroupInfo::forum() const {
|
|||
return _forum.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<Data::Forum> MegagroupInfo::takeForumData() {
|
||||
return std::move(_forum);
|
||||
}
|
||||
|
||||
ChannelData::ChannelData(not_null<Data::Session*> owner, PeerId id)
|
||||
: PeerData(owner, id)
|
||||
, inputChannel(
|
||||
MTP_inputChannel(MTP_long(peerToChannel(id).bare), MTP_long(0)))
|
||||
, _ptsWaiter(&owner->session().updates()) {
|
||||
_flags.changes(
|
||||
) | rpl::start_with_next([=](const Flags::Change &change) {
|
||||
if (change.diff
|
||||
& (Flag::Left | Flag::Forbidden)) {
|
||||
if (const auto chat = getMigrateFromChat()) {
|
||||
session().changes().peerUpdated(chat, UpdateFlag::Migration);
|
||||
session().changes().peerUpdated(this, UpdateFlag::Migration);
|
||||
}
|
||||
}
|
||||
if (change.diff & Flag::Megagroup) {
|
||||
if (change.value & Flag::Megagroup) {
|
||||
if (!mgInfo) {
|
||||
mgInfo = std::make_unique<MegagroupInfo>();
|
||||
}
|
||||
} else if (mgInfo) {
|
||||
mgInfo = nullptr;
|
||||
}
|
||||
}
|
||||
if (change.diff & Flag::CallNotEmpty) {
|
||||
if (const auto history = this->owner().historyLoaded(this)) {
|
||||
history->updateChatListEntry();
|
||||
}
|
||||
}
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
void ChannelData::setPhoto(const MTPChatPhoto &photo) {
|
||||
|
@ -132,6 +108,44 @@ void ChannelData::setAccessHash(uint64 accessHash) {
|
|||
MTP_long(accessHash));
|
||||
}
|
||||
|
||||
void ChannelData::setFlags(ChannelDataFlags which) {
|
||||
const auto diff = flags() ^ which;
|
||||
if ((which & Flag::Megagroup) && !mgInfo) {
|
||||
mgInfo = std::make_unique<MegagroupInfo>();
|
||||
}
|
||||
|
||||
// Let Data::Forum live till the end of _flags.set.
|
||||
// That way the data can be used in changes handler.
|
||||
// Example: render frame for forum auto-closing animation.
|
||||
const auto taken = ((diff & Flag::Forum) && !(which & Flag::Forum))
|
||||
? mgInfo->takeForumData()
|
||||
: nullptr;
|
||||
|
||||
if ((diff & Flag::Forum) && (which & Flag::Forum)) {
|
||||
mgInfo->ensureForum(this);
|
||||
}
|
||||
_flags.set(which);
|
||||
if (diff & (Flag::Left | Flag::Forbidden)) {
|
||||
if (const auto chat = getMigrateFromChat()) {
|
||||
session().changes().peerUpdated(chat, UpdateFlag::Migration);
|
||||
session().changes().peerUpdated(this, UpdateFlag::Migration);
|
||||
}
|
||||
}
|
||||
if (diff & Flag::CallNotEmpty) {
|
||||
if (const auto history = this->owner().historyLoaded(this)) {
|
||||
history->updateChatListEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelData::addFlags(ChannelDataFlags which) {
|
||||
setFlags(flags() | which);
|
||||
}
|
||||
|
||||
void ChannelData::removeFlags(ChannelDataFlags which) {
|
||||
setFlags(flags() & ~which);
|
||||
}
|
||||
|
||||
void ChannelData::setInviteLink(const QString &newInviteLink) {
|
||||
_inviteLink = newInviteLink;
|
||||
}
|
||||
|
|
|
@ -96,8 +96,9 @@ public:
|
|||
return _botCommands;
|
||||
}
|
||||
|
||||
void setIsForum(not_null<ChannelData*> that, bool is);
|
||||
void ensureForum(not_null<ChannelData*> that);
|
||||
[[nodiscard]] Data::Forum *forum() const;
|
||||
[[nodiscard]] std::unique_ptr<Data::Forum> takeForumData();
|
||||
|
||||
std::deque<not_null<UserData*>> lastParticipants;
|
||||
base::flat_map<not_null<UserData*>, Admin> lastAdmins;
|
||||
|
@ -148,15 +149,9 @@ public:
|
|||
void setPhoto(const MTPChatPhoto &photo);
|
||||
void setAccessHash(uint64 accessHash);
|
||||
|
||||
void setFlags(ChannelDataFlags which) {
|
||||
_flags.set(which);
|
||||
}
|
||||
void addFlags(ChannelDataFlags which) {
|
||||
_flags.add(which);
|
||||
}
|
||||
void removeFlags(ChannelDataFlags which) {
|
||||
_flags.remove(which);
|
||||
}
|
||||
void setFlags(ChannelDataFlags which);
|
||||
void addFlags(ChannelDataFlags which);
|
||||
void removeFlags(ChannelDataFlags which);
|
||||
[[nodiscard]] auto flags() const {
|
||||
return _flags.current();
|
||||
}
|
||||
|
@ -490,8 +485,6 @@ private:
|
|||
int _slowmodeSeconds = 0;
|
||||
TimeId _slowmodeLastMessage = 0;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
||||
namespace Data {
|
||||
|
|
|
@ -29,12 +29,25 @@ constexpr auto kTopicsPerPage = 500;
|
|||
|
||||
} // namespace
|
||||
|
||||
Forum::Forum(not_null<History*> forum)
|
||||
: _forum(forum)
|
||||
, _topicsList(&forum->session(), FilterId(0), rpl::single(1)) {
|
||||
Forum::Forum(not_null<History*> history)
|
||||
: _history(history)
|
||||
, _topicsList(&_history->session(), FilterId(0), rpl::single(1)) {
|
||||
Expects(_history->peer->isChannel());
|
||||
}
|
||||
|
||||
Forum::~Forum() = default;
|
||||
Forum::~Forum() {
|
||||
if (_requestId) {
|
||||
_history->session().api().request(_requestId).cancel();
|
||||
}
|
||||
}
|
||||
|
||||
not_null<History*> Forum::history() const {
|
||||
return _history;
|
||||
}
|
||||
|
||||
not_null<ChannelData*> Forum::channel() const {
|
||||
return _history->peer->asChannel();
|
||||
}
|
||||
|
||||
not_null<Dialogs::MainList*> Forum::topicsList() {
|
||||
return &_topicsList;
|
||||
|
@ -44,28 +57,24 @@ void Forum::requestTopics() {
|
|||
if (_allLoaded || _requestId) {
|
||||
return;
|
||||
}
|
||||
const auto forum = _forum;
|
||||
const auto firstLoad = !_offsetDate;
|
||||
const auto loadCount = firstLoad ? kTopicsFirstLoad : kTopicsPerPage;
|
||||
const auto api = &forum->session().api();
|
||||
const auto api = &_history->session().api();
|
||||
_requestId = api->request(MTPchannels_GetForumTopics(
|
||||
MTP_flags(0),
|
||||
forum->peer->asChannel()->inputChannel,
|
||||
channel()->inputChannel,
|
||||
MTPstring(), // q
|
||||
MTP_int(_offsetDate),
|
||||
MTP_int(_offsetId),
|
||||
MTP_int(_offsetTopicId),
|
||||
MTP_int(loadCount)
|
||||
)).done([=](const MTPmessages_ForumTopics &result) {
|
||||
if (!forum->peer->isForum()) {
|
||||
return;
|
||||
}
|
||||
const auto &data = result.data();
|
||||
const auto owner = &forum->owner();
|
||||
const auto owner = &channel()->owner();
|
||||
owner->processUsers(data.vusers());
|
||||
owner->processChats(data.vchats());
|
||||
owner->processMessages(data.vmessages(), NewMessageType::Existing);
|
||||
forum->peer->asChannel()->ptsReceived(data.vpts().v);
|
||||
channel()->ptsReceived(data.vpts().v);
|
||||
const auto &list = data.vtopics().v;
|
||||
for (const auto &topic : list) {
|
||||
const auto rootId = MsgId(topic.data().vid().v);
|
||||
|
@ -74,7 +83,7 @@ void Forum::requestTopics() {
|
|||
const auto raw = creating
|
||||
? _topics.emplace(
|
||||
rootId,
|
||||
std::make_unique<ForumTopic>(forum, rootId)
|
||||
std::make_unique<ForumTopic>(_history, rootId)
|
||||
).first->second.get()
|
||||
: i->second.get();
|
||||
raw->applyTopic(topic);
|
||||
|
@ -107,7 +116,7 @@ void Forum::applyTopicAdded(MsgId rootId, const QString &title) {
|
|||
} else {
|
||||
const auto raw = _topics.emplace(
|
||||
rootId,
|
||||
std::make_unique<ForumTopic>(_forum, rootId)
|
||||
std::make_unique<ForumTopic>(_history, rootId)
|
||||
).first->second.get();
|
||||
raw->applyTitle(title);
|
||||
raw->addToChatList(FilterId(), topicsList());
|
||||
|
@ -122,10 +131,18 @@ void Forum::applyTopicRemoved(MsgId rootId) {
|
|||
}
|
||||
|
||||
ForumTopic *Forum::topicFor(not_null<HistoryItem*> item) {
|
||||
if (const auto rootId = item->replyToTop()) {
|
||||
return topicFor(item->topicRootId());
|
||||
}
|
||||
|
||||
ForumTopic *Forum::topicFor(MsgId rootId) {
|
||||
if (rootId != ForumTopic::kGeneralId) {
|
||||
if (const auto i = _topics.find(rootId); i != end(_topics)) {
|
||||
return i->second.get();
|
||||
}
|
||||
} else {
|
||||
// #TODO forum lang
|
||||
applyTopicAdded(rootId, "General! Created.");
|
||||
return _topics.find(rootId)->second.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -148,13 +165,13 @@ void ShowAddForumTopic(
|
|||
object_ptr<Ui::InputField>(
|
||||
box,
|
||||
st::defaultInputField,
|
||||
rpl::single(u"Topic Title"_q))); // #TODO forum
|
||||
rpl::single(u"Topic Title"_q))); // #TODO forum lang
|
||||
const auto message = box->addRow(
|
||||
object_ptr<Ui::InputField>(
|
||||
box,
|
||||
st::newGroupDescription,
|
||||
Ui::InputField::Mode::MultiLine,
|
||||
rpl::single(u"Message"_q))); // #TODO forum
|
||||
rpl::single(u"Message"_q))); // #TODO forum lang
|
||||
box->setFocusCallback([=] {
|
||||
title->setFocusFast();
|
||||
});
|
||||
|
|
|
@ -20,9 +20,11 @@ namespace Data {
|
|||
|
||||
class Forum final {
|
||||
public:
|
||||
explicit Forum(not_null<History*> forum);
|
||||
explicit Forum(not_null<History*> history);
|
||||
~Forum();
|
||||
|
||||
[[nodiscard]] not_null<History*> history() const;
|
||||
[[nodiscard]] not_null<ChannelData*> channel() const;
|
||||
[[nodiscard]] not_null<Dialogs::MainList*> topicsList();
|
||||
|
||||
void requestTopics();
|
||||
|
@ -32,9 +34,10 @@ public:
|
|||
void applyTopicAdded(MsgId rootId, const QString &title);
|
||||
void applyTopicRemoved(MsgId rootId);
|
||||
[[nodiscard]] ForumTopic *topicFor(not_null<HistoryItem*> item);
|
||||
[[nodiscard]] ForumTopic *topicFor(MsgId rootId);
|
||||
|
||||
private:
|
||||
const not_null<History*> _forum;
|
||||
const not_null<History*> _history;
|
||||
|
||||
base::flat_map<MsgId, std::unique_ptr<ForumTopic>> _topics;
|
||||
Dialogs::MainList _topicsList;
|
||||
|
|
|
@ -198,6 +198,9 @@ void ForumTopic::requestChatListMessage() {
|
|||
}
|
||||
|
||||
TimeId ForumTopic::adjustedChatListTimeId() const {
|
||||
if (isGeneral()) {
|
||||
return TimeId(1);
|
||||
}
|
||||
const auto result = chatListTimeId();
|
||||
#if 0 // #TODO forum
|
||||
if (const auto draft = cloudDraft()) {
|
||||
|
@ -236,10 +239,10 @@ bool ForumTopic::lastServerMessageKnown() const {
|
|||
}
|
||||
|
||||
void ForumTopic::applyTitle(const QString &title) {
|
||||
if (_title == title) {
|
||||
if (_title == title || (isGeneral() && !_title.isEmpty())) {
|
||||
return;
|
||||
}
|
||||
_title = title;
|
||||
_title = isGeneral() ? "General! Topic." : title; // #TODO forum lang
|
||||
++_titleVersion;
|
||||
indexTitleParts();
|
||||
updateChatListEntry();
|
||||
|
|
|
@ -26,6 +26,8 @@ class Session;
|
|||
|
||||
class ForumTopic final : public Dialogs::Entry {
|
||||
public:
|
||||
static constexpr auto kGeneralId = 1;
|
||||
|
||||
ForumTopic(not_null<History*> forum, MsgId rootId);
|
||||
|
||||
ForumTopic(const ForumTopic &) = delete;
|
||||
|
@ -33,6 +35,9 @@ public:
|
|||
|
||||
[[nodiscard]] not_null<History*> forum() const;
|
||||
[[nodiscard]] MsgId rootId() const;
|
||||
[[nodiscard]] bool isGeneral() const {
|
||||
return (_rootId == kGeneralId);
|
||||
}
|
||||
|
||||
void applyTopic(const MTPForumTopic &topic);
|
||||
|
||||
|
@ -88,7 +93,6 @@ private:
|
|||
int unreadCount,
|
||||
MsgId maxInboxRead,
|
||||
MsgId maxOutboxRead);
|
||||
void applyChatListMessage(HistoryItem *item);
|
||||
|
||||
void setLastMessage(HistoryItem *item);
|
||||
void setLastServerMessage(HistoryItem *item);
|
||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_changes.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_messages.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
|
@ -125,7 +126,10 @@ void RepliesList::appendClientSideMessages(MessagesSlice &slice) {
|
|||
}
|
||||
slice.ids.reserve(messages.size());
|
||||
for (const auto &item : messages) {
|
||||
if (item->replyToTop() != _rootId) {
|
||||
const auto checkId = (_rootId == ForumTopic::kGeneralId)
|
||||
? item->topicRootId()
|
||||
: item->replyToTop();
|
||||
if (!item->inThread(_rootId)) {
|
||||
continue;
|
||||
}
|
||||
slice.ids.push_back(item->fullId());
|
||||
|
@ -143,7 +147,7 @@ void RepliesList::appendClientSideMessages(MessagesSlice &slice) {
|
|||
dates.push_back(message->date());
|
||||
}
|
||||
for (const auto &item : messages) {
|
||||
if (item->replyToTop() != _rootId) {
|
||||
if (!item->inThread(_rootId)) {
|
||||
continue;
|
||||
}
|
||||
const auto date = item->date();
|
||||
|
@ -341,12 +345,15 @@ bool RepliesList::buildFromData(not_null<Viewer*> viewer) {
|
|||
auto nearestToAround = std::optional<MsgId>();
|
||||
slice->ids.reserve(useAfter + useBefore);
|
||||
for (auto j = i - useAfter, e = i + useBefore; j != e; ++j) {
|
||||
if (!nearestToAround && *j < around) {
|
||||
const auto id = *j;
|
||||
if (id == _rootId) {
|
||||
continue;
|
||||
} else if (!nearestToAround && id < around) {
|
||||
nearestToAround = (j == i - useAfter)
|
||||
? *j
|
||||
? id
|
||||
: *(j - 1);
|
||||
}
|
||||
slice->ids.emplace_back(peerId, *j);
|
||||
slice->ids.emplace_back(peerId, id);
|
||||
}
|
||||
slice->nearestToAround = FullMsgId(
|
||||
peerId,
|
||||
|
@ -380,7 +387,7 @@ bool RepliesList::applyUpdate(
|
|||
}
|
||||
}
|
||||
}
|
||||
if (update.item->replyToTop() != _rootId) {
|
||||
if (!update.item->inThread(_rootId)) {
|
||||
return false;
|
||||
}
|
||||
const auto id = update.item->id;
|
||||
|
@ -613,7 +620,7 @@ bool RepliesList::processMessagesIsEmpty(const MTPmessages_Messages &result) {
|
|||
auto skipped = 0;
|
||||
for (const auto &message : list) {
|
||||
if (const auto item = owner.addNewMessage(message, localFlags, type)) {
|
||||
if (item->replyToTop() == _rootId) {
|
||||
if (item->inThread(_rootId)) {
|
||||
if (toFront && item->id > _list.front()) {
|
||||
refreshed.push_back(item->id);
|
||||
} else if (_list.empty() || item->id < _list.back()) {
|
||||
|
|
|
@ -807,12 +807,7 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
|||
| ((data.is_forum() && data.is_megagroup())
|
||||
? Flag::Forum
|
||||
: Flag());
|
||||
const auto wasForum = channel->isForum();
|
||||
channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
|
||||
if (const auto nowForum = channel->isForum(); nowForum != wasForum) {
|
||||
Assert(channel->mgInfo != nullptr);
|
||||
channel->mgInfo->setIsForum(channel, nowForum);
|
||||
}
|
||||
|
||||
channel->setName(
|
||||
qs(data.vtitle()),
|
||||
|
|
|
@ -404,12 +404,13 @@ void InnerWidget::changeOpenedFolder(Data::Folder *folder) {
|
|||
}
|
||||
|
||||
void InnerWidget::changeOpenedForum(ChannelData *forum) {
|
||||
if (_openedForum == forum) {
|
||||
const auto now = _openedForum ? _openedForum->channel().get() : nullptr;
|
||||
if (now == forum) {
|
||||
return;
|
||||
}
|
||||
stopReorderPinned();
|
||||
clearSelection();
|
||||
_openedForum = forum;
|
||||
_openedForum = forum ? forum->forum() : nullptr;
|
||||
|
||||
_openedForumLifetime.destroy();
|
||||
if (forum) {
|
||||
|
@ -1791,7 +1792,7 @@ not_null<IndexedList*> InnerWidget::shownDialogs() const {
|
|||
return _filterId
|
||||
? session().data().chatsFilters().chatsList(_filterId)->indexed()
|
||||
: _openedForum
|
||||
? _openedForum->forum()->topicsList()->indexed()
|
||||
? _openedForum->topicsList()->indexed()
|
||||
: session().data().chatsList(_openedFolder)->indexed();
|
||||
}
|
||||
|
||||
|
@ -2296,7 +2297,7 @@ Data::Folder *InnerWidget::shownFolder() const {
|
|||
return _openedFolder;
|
||||
}
|
||||
|
||||
ChannelData *InnerWidget::shownForum() const {
|
||||
Data::Forum *InnerWidget::shownForum() const {
|
||||
return _openedForum;
|
||||
}
|
||||
|
||||
|
@ -2410,7 +2411,7 @@ void InnerWidget::refreshEmptyLabel() {
|
|||
} else if (_emptyState == EmptyState::EmptyFolder) {
|
||||
editOpenedFilter();
|
||||
} else if (_emptyState == EmptyState::EmptyForum) {
|
||||
Data::ShowAddForumTopic(_controller, _openedForum);
|
||||
Data::ShowAddForumTopic(_controller, _openedForum->channel());
|
||||
}
|
||||
});
|
||||
_empty->setVisible(_state == WidgetState::Default);
|
||||
|
@ -3286,7 +3287,9 @@ void InnerWidget::setupShortcuts() {
|
|||
});
|
||||
request->check(Command::ChatSelf) && request->handle([=] {
|
||||
if (_openedForum) {
|
||||
Data::ShowAddForumTopic(_controller, _openedForum);
|
||||
Data::ShowAddForumTopic(
|
||||
_controller,
|
||||
_openedForum->channel());
|
||||
} else {
|
||||
_controller->content()->choosePeer(
|
||||
session().userPeerId(),
|
||||
|
|
|
@ -36,6 +36,8 @@ class SessionController;
|
|||
|
||||
namespace Data {
|
||||
class CloudImageView;
|
||||
class Folder;
|
||||
class Forum;
|
||||
} // namespace Data
|
||||
|
||||
namespace Dialogs::Ui {
|
||||
|
@ -110,7 +112,7 @@ public:
|
|||
void scrollToEntry(const RowDescriptor &entry);
|
||||
|
||||
Data::Folder *shownFolder() const;
|
||||
ChannelData *shownForum() const;
|
||||
Data::Forum *shownForum() const;
|
||||
int32 lastSearchDate() const;
|
||||
PeerData *lastSearchPeer() const;
|
||||
MsgId lastSearchId() const;
|
||||
|
@ -351,7 +353,7 @@ private:
|
|||
Qt::MouseButton _pressButton = Qt::LeftButton;
|
||||
|
||||
Data::Folder *_openedFolder = nullptr;
|
||||
ChannelData *_openedForum = nullptr;
|
||||
Data::Forum *_openedForum = nullptr;
|
||||
rpl::lifetime _openedForumLifetime;
|
||||
|
||||
std::vector<std::unique_ptr<CollapsedRow>> _collapsedRows;
|
||||
|
|
|
@ -260,50 +260,7 @@ Widget::Widget(
|
|||
}, lifetime());
|
||||
_inner->chosenRow(
|
||||
) | rpl::start_with_next([=](const ChosenRow &row) {
|
||||
const auto openSearchResult = !controller->selectingPeer()
|
||||
&& row.filteredRow;
|
||||
const auto history = row.key.history();
|
||||
if (const auto topic = row.key.topic()) {
|
||||
controller->showRepliesForMessage(
|
||||
topic->forum(),
|
||||
topic->rootId());
|
||||
} else if (history && history->peer->isForum()) {
|
||||
controller->openForum(history->peer->asChannel());
|
||||
} else if (history) {
|
||||
const auto peer = history->peer;
|
||||
const auto showAtMsgId = controller->uniqueChatsInSearchResults()
|
||||
? ShowAtUnreadMsgId
|
||||
: row.message.fullId.msg;
|
||||
if (row.newWindow && controller->canShowSeparateWindow(peer)) {
|
||||
const auto active = controller->activeChatCurrent();
|
||||
const auto fromActive = active.history()
|
||||
? (active.history()->peer == peer)
|
||||
: false;
|
||||
const auto toSeparate = [=] {
|
||||
Core::App().ensureSeparateWindowForPeer(
|
||||
peer,
|
||||
showAtMsgId);
|
||||
};
|
||||
if (fromActive) {
|
||||
controller->window().preventOrInvoke([=] {
|
||||
controller->content()->ui_showPeerHistory(
|
||||
0,
|
||||
Window::SectionShow::Way::ClearStack,
|
||||
0);
|
||||
toSeparate();
|
||||
});
|
||||
} else {
|
||||
toSeparate();
|
||||
}
|
||||
} else {
|
||||
controller->content()->choosePeer(peer->id, showAtMsgId);
|
||||
}
|
||||
} else if (const auto folder = row.key.folder()) {
|
||||
controller->openFolder(folder);
|
||||
}
|
||||
if (openSearchResult && !session().supportMode()) {
|
||||
escape();
|
||||
}
|
||||
chosenRow(row);
|
||||
}, lifetime());
|
||||
|
||||
_scroll->geometryChanged(
|
||||
|
@ -422,6 +379,53 @@ Widget::Widget(
|
|||
setupDownloadBar();
|
||||
}
|
||||
|
||||
void Widget::chosenRow(const ChosenRow &row) {
|
||||
const auto openSearchResult = !controller()->selectingPeer()
|
||||
&& row.filteredRow;
|
||||
const auto history = row.key.history();
|
||||
if (const auto topic = row.key.topic()) {
|
||||
controller()->showRepliesForMessage(
|
||||
topic->forum(),
|
||||
topic->rootId());
|
||||
} else if (history && history->peer->isForum()) {
|
||||
controller()->openForum(history->peer->asChannel());
|
||||
} else if (history) {
|
||||
const auto peer = history->peer;
|
||||
const auto showAtMsgId = controller()->uniqueChatsInSearchResults()
|
||||
? ShowAtUnreadMsgId
|
||||
: row.message.fullId.msg;
|
||||
if (row.newWindow && controller()->canShowSeparateWindow(peer)) {
|
||||
const auto active = controller()->activeChatCurrent();
|
||||
const auto fromActive = active.history()
|
||||
? (active.history()->peer == peer)
|
||||
: false;
|
||||
const auto toSeparate = [=] {
|
||||
Core::App().ensureSeparateWindowForPeer(
|
||||
peer,
|
||||
showAtMsgId);
|
||||
};
|
||||
if (fromActive) {
|
||||
controller()->window().preventOrInvoke([=] {
|
||||
controller()->content()->ui_showPeerHistory(
|
||||
0,
|
||||
Window::SectionShow::Way::ClearStack,
|
||||
0);
|
||||
toSeparate();
|
||||
});
|
||||
} else {
|
||||
toSeparate();
|
||||
}
|
||||
} else {
|
||||
controller()->content()->choosePeer(peer->id, showAtMsgId);
|
||||
}
|
||||
} else if (const auto folder = row.key.folder()) {
|
||||
controller()->openFolder(folder);
|
||||
}
|
||||
if (openSearchResult && !session().supportMode()) {
|
||||
escape();
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setGeometryWithTopMoved(
|
||||
const QRect &newGeometry,
|
||||
int topDelta) {
|
||||
|
|
|
@ -116,6 +116,7 @@ private:
|
|||
Internal,
|
||||
};
|
||||
|
||||
void chosenRow(const ChosenRow &row);
|
||||
void listScrollUpdated();
|
||||
void cancelSearchInChat();
|
||||
void filterCursorMoved(int from = -1, int to = -1);
|
||||
|
|
|
@ -47,6 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_messages.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_user.h"
|
||||
|
@ -1058,6 +1059,21 @@ MsgId HistoryItem::replyToTop() const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
MsgId HistoryItem::topicRootId() const {
|
||||
if (const auto reply = Get<HistoryMessageReply>()
|
||||
; reply && reply->topicPost) {
|
||||
return reply->replyToTop();
|
||||
}
|
||||
return Data::ForumTopic::kGeneralId;
|
||||
}
|
||||
|
||||
MsgId HistoryItem::inThread(MsgId rootId) const {
|
||||
const auto checkId = (rootId == Data::ForumTopic::kGeneralId)
|
||||
? topicRootId()
|
||||
: replyToTop();
|
||||
return (checkId == rootId);
|
||||
}
|
||||
|
||||
not_null<PeerData*> HistoryItem::author() const {
|
||||
return (isPost() && !isSponsored()) ? history()->peer : from();
|
||||
}
|
||||
|
|
|
@ -410,6 +410,8 @@ public:
|
|||
|
||||
[[nodiscard]] MsgId replyToId() const;
|
||||
[[nodiscard]] MsgId replyToTop() const;
|
||||
[[nodiscard]] MsgId topicRootId() const;
|
||||
[[nodiscard]] MsgId inThread(MsgId rootId) const;
|
||||
|
||||
[[nodiscard]] not_null<PeerData*> author() const;
|
||||
|
||||
|
|
|
@ -259,7 +259,7 @@ bool HistoryMessageReply::updateData(
|
|||
} else {
|
||||
holder->history()->owner().registerDependentMessage(
|
||||
holder,
|
||||
replyToMsg);
|
||||
replyToMsg.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -298,7 +298,7 @@ bool HistoryMessageReply::updateData(
|
|||
void HistoryMessageReply::setReplyToLinkFrom(
|
||||
not_null<HistoryMessage*> holder) {
|
||||
replyToLnk = replyToMsg
|
||||
? goToMessageClickHandler(replyToMsg, holder->fullId())
|
||||
? goToMessageClickHandler(replyToMsg.get(), holder->fullId())
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ void HistoryMessageReply::clearData(not_null<HistoryMessage*> holder) {
|
|||
if (replyToMsg) {
|
||||
holder->history()->owner().unregisterDependentMessage(
|
||||
holder,
|
||||
replyToMsg);
|
||||
replyToMsg.get());
|
||||
replyToMsg = nullptr;
|
||||
}
|
||||
replyToMsgId = 0;
|
||||
|
@ -399,7 +399,7 @@ void HistoryMessageReply::resize(int width) const {
|
|||
void HistoryMessageReply::itemRemoved(
|
||||
HistoryMessage *holder,
|
||||
HistoryItem *removed) {
|
||||
if (replyToMsg == removed) {
|
||||
if (replyToMsg.get() == removed) {
|
||||
clearData(holder);
|
||||
holder->history()->owner().requestItemResize(holder);
|
||||
}
|
||||
|
|
|
@ -132,29 +132,55 @@ struct HistoryMessageSponsored : public RuntimeComponent<HistoryMessageSponsored
|
|||
bool recommended = false;
|
||||
};
|
||||
|
||||
struct HistoryMessageReply : public RuntimeComponent<HistoryMessageReply, HistoryItem> {
|
||||
class ReplyToMessagePointer final {
|
||||
public:
|
||||
ReplyToMessagePointer(HistoryItem *item = nullptr) : _data(item) {
|
||||
}
|
||||
ReplyToMessagePointer(ReplyToMessagePointer &&other)
|
||||
: _data(base::take(other._data)) {
|
||||
}
|
||||
ReplyToMessagePointer &operator=(ReplyToMessagePointer &&other) {
|
||||
_data = base::take(other._data);
|
||||
return *this;
|
||||
}
|
||||
ReplyToMessagePointer &operator=(HistoryItem *item) {
|
||||
_data = item;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool empty() const {
|
||||
return !_data;
|
||||
}
|
||||
[[nodiscard]] HistoryItem *get() const {
|
||||
return _data;
|
||||
}
|
||||
explicit operator bool() const {
|
||||
return !empty();
|
||||
}
|
||||
|
||||
[[nodiscard]] HistoryItem *operator->() const {
|
||||
return _data;
|
||||
}
|
||||
[[nodiscard]] HistoryItem &operator*() const {
|
||||
return *_data;
|
||||
}
|
||||
|
||||
private:
|
||||
HistoryItem *_data = nullptr;
|
||||
|
||||
};
|
||||
|
||||
struct HistoryMessageReply
|
||||
: public RuntimeComponent<HistoryMessageReply, HistoryItem> {
|
||||
HistoryMessageReply() = default;
|
||||
HistoryMessageReply(const HistoryMessageReply &other) = delete;
|
||||
HistoryMessageReply(HistoryMessageReply &&other) = delete;
|
||||
HistoryMessageReply &operator=(const HistoryMessageReply &other) = delete;
|
||||
HistoryMessageReply &operator=(HistoryMessageReply &&other) {
|
||||
replyToPeerId = other.replyToPeerId;
|
||||
replyToMsgId = other.replyToMsgId;
|
||||
replyToMsgTop = other.replyToMsgTop;
|
||||
replyToDocumentId = other.replyToDocumentId;
|
||||
replyToWebPageId = other.replyToWebPageId;
|
||||
std::swap(replyToMsg, other.replyToMsg);
|
||||
replyToLnk = std::move(other.replyToLnk);
|
||||
replyToName = std::move(other.replyToName);
|
||||
replyToText = std::move(other.replyToText);
|
||||
replyToVersion = other.replyToVersion;
|
||||
maxReplyWidth = other.maxReplyWidth;
|
||||
replyToVia = std::move(other.replyToVia);
|
||||
return *this;
|
||||
}
|
||||
HistoryMessageReply &operator=(
|
||||
const HistoryMessageReply &other) = delete;
|
||||
HistoryMessageReply &operator=(HistoryMessageReply &&other) = default;
|
||||
~HistoryMessageReply() {
|
||||
// clearData() should be called by holder.
|
||||
Expects(replyToMsg == nullptr);
|
||||
Expects(replyToMsg.empty());
|
||||
Expects(replyToVia == nullptr);
|
||||
}
|
||||
|
||||
|
@ -205,15 +231,16 @@ struct HistoryMessageReply : public RuntimeComponent<HistoryMessageReply, Histor
|
|||
PeerId replyToPeerId = 0;
|
||||
MsgId replyToMsgId = 0;
|
||||
MsgId replyToMsgTop = 0;
|
||||
HistoryItem *replyToMsg = nullptr;
|
||||
DocumentId replyToDocumentId = 0;
|
||||
WebPageId replyToWebPageId = 0;
|
||||
ReplyToMessagePointer replyToMsg;
|
||||
std::unique_ptr<HistoryMessageVia> replyToVia;
|
||||
ClickHandlerPtr replyToLnk;
|
||||
mutable Ui::Text::String replyToName, replyToText;
|
||||
mutable int replyToVersion = 0;
|
||||
mutable int maxReplyWidth = 0;
|
||||
std::unique_ptr<HistoryMessageVia> replyToVia;
|
||||
int toWidth = 0;
|
||||
bool topicPost = false;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ TextForMimeData WrapAsItem(
|
|||
not_null<HistoryItem*> item,
|
||||
TextForMimeData &&result) {
|
||||
if (const auto reply = item->Get<HistoryMessageReply>()) {
|
||||
if (const auto message = reply->replyToMsg) {
|
||||
if (const auto message = reply->replyToMsg.get()) {
|
||||
result = WrapAsReply(std::move(result), message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -247,6 +247,7 @@ struct HistoryMessage::CreateConfig {
|
|||
PeerId replyToPeer = 0;
|
||||
MsgId replyTo = 0;
|
||||
MsgId replyToTop = 0;
|
||||
bool replyIsTopicPost = false;
|
||||
UserId viaBotId = 0;
|
||||
int viewsCount = -1;
|
||||
QString author;
|
||||
|
@ -963,6 +964,7 @@ void HistoryMessage::createComponents(CreateConfig &&config) {
|
|||
reply->replyToPeerId = config.replyToPeer;
|
||||
reply->replyToMsgId = config.replyTo;
|
||||
reply->replyToMsgTop = isScheduled() ? 0 : config.replyToTop;
|
||||
reply->topicPost = config.replyIsTopicPost;
|
||||
if (!reply->updateData(this)) {
|
||||
RequestDependentMessageData(
|
||||
this,
|
||||
|
|
|
@ -57,6 +57,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_user.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_forum.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_replies_list.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "data/data_changes.h"
|
||||
|
@ -160,6 +162,7 @@ RepliesWidget::RepliesWidget(
|
|||
, _history(history)
|
||||
, _rootId(rootId)
|
||||
, _root(lookupRoot())
|
||||
, _topic(lookupTopic())
|
||||
, _areComments(computeAreComments())
|
||||
, _sendAction(history->owner().sendActionManager().repliesPainter(
|
||||
history,
|
||||
|
@ -332,6 +335,7 @@ RepliesWidget::~RepliesWidget() {
|
|||
if (_readRequestTimer.isActive()) {
|
||||
sendReadTillRequest();
|
||||
}
|
||||
_history->session().api().request(_resolveTopicRequestId).cancel();
|
||||
base::take(_sendAction);
|
||||
_history->owner().sendActionManager().repliesPainterRemoved(
|
||||
_history,
|
||||
|
@ -437,6 +441,58 @@ HistoryItem *RepliesWidget::lookupRoot() const {
|
|||
return _history->owner().message(_history->peer, _rootId);
|
||||
}
|
||||
|
||||
Data::ForumTopic *RepliesWidget::lookupTopic() {
|
||||
if (const auto forum = _history->peer->forum()) {
|
||||
const auto result = forum->topicFor(_rootId);
|
||||
if (!result && !_resolveTopicRequestId) {
|
||||
const auto api = &_history->session().api();
|
||||
_resolveTopicRequestId = api->request(
|
||||
MTPchannels_GetForumTopicsByID(
|
||||
forum->channel()->inputChannel,
|
||||
MTP_vector<MTPint>(1, MTP_int(_rootId.bare)))
|
||||
).done([=](const MTPmessages_ForumTopics &result) {
|
||||
const auto &data = result.data();
|
||||
const auto owner = &_history->owner();
|
||||
owner->processUsers(data.vusers());
|
||||
owner->processChats(data.vchats());
|
||||
owner->processMessages(data.vmessages(), NewMessageType::Existing);
|
||||
channel()->ptsReceived(data.vpts().v);
|
||||
const auto &list = data.vtopics().v;
|
||||
for (const auto &topic : list) {
|
||||
const auto rootId = MsgId(topic.data().vid().v);
|
||||
const auto i = _topics.find(rootId);
|
||||
const auto creating = (i == end(_topics));
|
||||
const auto raw = creating
|
||||
? _topics.emplace(
|
||||
rootId,
|
||||
std::make_unique<ForumTopic>(_history, rootId)
|
||||
).first->second.get()
|
||||
: i->second.get();
|
||||
raw->applyTopic(topic);
|
||||
if (creating) {
|
||||
raw->addToChatList(FilterId(), topicsList());
|
||||
}
|
||||
if (const auto last = raw->lastServerMessage()) {
|
||||
_offsetDate = last->date();
|
||||
_offsetId = last->id;
|
||||
}
|
||||
_offsetTopicId = rootId;
|
||||
}
|
||||
if (list.isEmpty() || list.size() == data.vcount().v) {
|
||||
_allLoaded = true;
|
||||
}
|
||||
_requestId = 0;
|
||||
_chatsListChanges.fire({});
|
||||
if (_allLoaded) {
|
||||
_chatsListLoadedEvents.fire({});
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool RepliesWidget::computeAreComments() const {
|
||||
return _root && _root->isDiscussionPost();
|
||||
}
|
||||
|
@ -1294,7 +1350,11 @@ void RepliesWidget::refreshTopBarActiveChat() {
|
|||
|
||||
MsgId RepliesWidget::replyToId() const {
|
||||
const auto custom = _composeControls->replyingToMessage().msg;
|
||||
return custom ? custom : _rootId;
|
||||
return custom
|
||||
? custom
|
||||
: (_rootId == Data::ForumTopic::kGeneralId)
|
||||
? MsgId(0)
|
||||
: _rootId;
|
||||
}
|
||||
|
||||
void RepliesWidget::setupScrollDownButton() {
|
||||
|
@ -1578,23 +1638,34 @@ bool RepliesWidget::showMessage(
|
|||
}
|
||||
const auto id = FullMsgId(_history->peer->id, messageId);
|
||||
const auto message = _history->owner().message(id);
|
||||
if (!message || message->replyToTop() != _rootId) {
|
||||
if (!message) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto originItem = [&]() -> HistoryItem* {
|
||||
auto originFound = false;
|
||||
const auto general = (_rootId == Data::ForumTopic::kGeneralId);
|
||||
const auto originMessage = [&]() -> HistoryItem* {
|
||||
using OriginMessage = Window::SectionShow::OriginMessage;
|
||||
if (const auto origin = std::get_if<OriginMessage>(¶ms.origin)) {
|
||||
if (const auto returnTo = session().data().message(origin->id)) {
|
||||
if (returnTo->history() == _history
|
||||
&& returnTo->replyToTop() == _rootId
|
||||
&& _replyReturn != returnTo) {
|
||||
if (returnTo->history() != _history) {
|
||||
return nullptr;
|
||||
} else if (general
|
||||
&& _inner->viewByPosition(returnTo->position())
|
||||
&& returnTo->replyToId() == messageId) {
|
||||
return returnTo;
|
||||
} else if (!general && (returnTo->replyToTop() == _rootId)) {
|
||||
return returnTo;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}();
|
||||
if (!originMessage) {
|
||||
return false;
|
||||
}
|
||||
const auto originItem = (!originMessage || _replyReturn == originMessage)
|
||||
? nullptr
|
||||
: originMessage;
|
||||
showAtPosition(message->position(), originItem);
|
||||
return true;
|
||||
}
|
||||
|
@ -1756,8 +1827,8 @@ void RepliesWidget::updateInnerVisibleArea() {
|
|||
void RepliesWidget::updatePinnedVisibility() {
|
||||
if (!_loaded) {
|
||||
return;
|
||||
} else if (!_root) {
|
||||
setPinnedVisibility(true);
|
||||
} else if (!_root || _root->isEmpty()) {
|
||||
setPinnedVisibility(!_root);
|
||||
return;
|
||||
}
|
||||
const auto item = [&] {
|
||||
|
|
|
@ -49,6 +49,7 @@ class Result;
|
|||
|
||||
namespace Data {
|
||||
class RepliesList;
|
||||
class ForumTopic;
|
||||
} // namespace Data
|
||||
|
||||
namespace HistoryView {
|
||||
|
@ -208,6 +209,7 @@ private:
|
|||
[[nodiscard]] SendMenu::Type sendMenuType() const;
|
||||
[[nodiscard]] MsgId replyToId() const;
|
||||
[[nodiscard]] HistoryItem *lookupRoot() const;
|
||||
[[nodiscard]] Data::ForumTopic *lookupTopic();
|
||||
[[nodiscard]] bool computeAreComments() const;
|
||||
[[nodiscard]] std::optional<int> computeUnreadCount() const;
|
||||
void orderWidgets();
|
||||
|
@ -270,6 +272,8 @@ private:
|
|||
const MsgId _rootId = 0;
|
||||
std::shared_ptr<Ui::ChatTheme> _theme;
|
||||
HistoryItem *_root = nullptr;
|
||||
Data::ForumTopic *_topic = nullptr;
|
||||
|
||||
std::shared_ptr<Data::RepliesList> _replies;
|
||||
rpl::variable<bool> _areComments = false;
|
||||
std::shared_ptr<SendActionPainter> _sendAction;
|
||||
|
@ -301,6 +305,8 @@ private:
|
|||
bool _readRequestPending = false;
|
||||
mtpRequestId _readRequestId = 0;
|
||||
|
||||
mtpRequestId _resolveTopicRequestId = 0;
|
||||
|
||||
mtpRequestId _reloadUnreadCountRequestId = 0;
|
||||
bool _loaded = false;
|
||||
|
||||
|
|
|
@ -676,19 +676,6 @@ SessionController::SessionController(
|
|||
closeFolder();
|
||||
}, lifetime());
|
||||
|
||||
_openedForum.changes(
|
||||
) | rpl::filter([](ChannelData *forum) {
|
||||
return (forum != nullptr);
|
||||
}) | rpl::map([](ChannelData *forum) {
|
||||
return forum->flagsValue(
|
||||
) | rpl::filter([](ChannelData::Flags::Change change) {
|
||||
return (change.diff & ChannelData::Flag::Forum)
|
||||
&& !(change.value & ChannelData::Flag::Forum);
|
||||
});
|
||||
}) | rpl::flatten_latest() | rpl::start_with_next([=] {
|
||||
closeForum();
|
||||
}, lifetime());
|
||||
|
||||
session->data().chatsFilters().changed(
|
||||
) | rpl::start_with_next([=] {
|
||||
checkOpenedFilter();
|
||||
|
@ -842,7 +829,9 @@ void SessionController::checkOpenedFilter() {
|
|||
const auto &list = session().data().chatsFilters().list();
|
||||
const auto i = ranges::find(list, filterId, &Data::ChatFilter::id);
|
||||
if (i == end(list)) {
|
||||
setActiveChatsFilter(0);
|
||||
setActiveChatsFilter(
|
||||
0,
|
||||
{ anim::type::normal, anim::activation::background });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -874,18 +863,35 @@ void SessionController::closeFolder() {
|
|||
_openedFolder = nullptr;
|
||||
}
|
||||
|
||||
void SessionController::openForum(not_null<ChannelData*> forum) {
|
||||
void SessionController::openForum(
|
||||
not_null<ChannelData*> forum,
|
||||
const SectionShow ¶ms) {
|
||||
Expects(forum->isForum());
|
||||
|
||||
_openedForumLifetime.destroy();
|
||||
if (_openedForum.current() != forum) {
|
||||
resetFakeUnreadWhileOpened();
|
||||
}
|
||||
setActiveChatsFilter(0);
|
||||
setActiveChatsFilter(0, params);
|
||||
closeFolder();
|
||||
_openedForum = forum.get();
|
||||
if (_openedForum.current() == forum) {
|
||||
forum->flagsValue(
|
||||
) | rpl::filter([=](const ChannelData::Flags::Change &update) {
|
||||
using Flag = ChannelData::Flag;
|
||||
return (update.diff & Flag::Forum)
|
||||
&& !(update.value & Flag::Forum);
|
||||
}) | rpl::start_with_next([=] {
|
||||
closeForum();
|
||||
showPeerHistory(
|
||||
forum,
|
||||
{ anim::type::normal, anim::activation::background });
|
||||
}, _openedForumLifetime);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionController::closeForum() {
|
||||
_openedForumLifetime.destroy();
|
||||
_openedForum = nullptr;
|
||||
}
|
||||
|
||||
|
@ -926,12 +932,27 @@ void SessionController::setActiveChatEntry(Dialogs::RowDescriptor row) {
|
|||
const auto was = _activeChatEntry.current().key.history();
|
||||
const auto now = row.key.history();
|
||||
if (was && was != now) {
|
||||
_activeHistoryLifetime.destroy();
|
||||
was->setFakeUnreadWhileOpened(false);
|
||||
_invitePeekTimer.cancel();
|
||||
}
|
||||
_activeChatEntry = row;
|
||||
if (now) {
|
||||
now->setFakeUnreadWhileOpened(true);
|
||||
if (const auto channel = now->peer->asChannel()
|
||||
; channel && !channel->isForum()) {
|
||||
channel->flagsValue(
|
||||
) | rpl::filter([=](const ChannelData::Flags::Change &update) {
|
||||
using Flag = ChannelData::Flag;
|
||||
return (update.diff & Flag::Forum)
|
||||
&& (update.value & Flag::Forum);
|
||||
}) | rpl::start_with_next([=] {
|
||||
clearSectionStack(
|
||||
{ anim::type::normal, anim::activation::background });
|
||||
openForum(channel,
|
||||
{ anim::type::normal, anim::activation::background });
|
||||
}, _openedForumLifetime);
|
||||
}
|
||||
}
|
||||
if (session().supportMode()) {
|
||||
pushToChatEntryHistory(row);
|
||||
|
@ -1601,7 +1622,9 @@ FilterId SessionController::activeChatsFilterCurrent() const {
|
|||
return _activeChatsFilter.current();
|
||||
}
|
||||
|
||||
void SessionController::setActiveChatsFilter(FilterId id) {
|
||||
void SessionController::setActiveChatsFilter(
|
||||
FilterId id,
|
||||
const SectionShow ¶ms) {
|
||||
if (activeChatsFilterCurrent() != id) {
|
||||
resetFakeUnreadWhileOpened();
|
||||
}
|
||||
|
@ -1610,7 +1633,7 @@ void SessionController::setActiveChatsFilter(FilterId id) {
|
|||
closeFolder();
|
||||
}
|
||||
if (adaptive().isOneColumn()) {
|
||||
Ui::showChatsList(&session());
|
||||
clearSectionStack(params);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -345,7 +345,9 @@ public:
|
|||
void closeFolder();
|
||||
const rpl::variable<Data::Folder*> &openedFolder() const;
|
||||
|
||||
void openForum(not_null<ChannelData*> forum);
|
||||
void openForum(
|
||||
not_null<ChannelData*> forum,
|
||||
const SectionShow ¶ms = SectionShow::Way::ClearStack);
|
||||
void closeForum();
|
||||
const rpl::variable<ChannelData*> &openedForum() const;
|
||||
|
||||
|
@ -474,7 +476,9 @@ public:
|
|||
[[nodiscard]] int filtersWidth() const;
|
||||
[[nodiscard]] rpl::producer<FilterId> activeChatsFilter() const;
|
||||
[[nodiscard]] FilterId activeChatsFilterCurrent() const;
|
||||
void setActiveChatsFilter(FilterId id);
|
||||
void setActiveChatsFilter(
|
||||
FilterId id,
|
||||
const SectionShow ¶ms = SectionShow::Way::ClearStack);
|
||||
|
||||
void toggleFiltersMenu(bool enabled);
|
||||
[[nodiscard]] rpl::producer<> filtersMenuChanged() const;
|
||||
|
@ -582,6 +586,7 @@ private:
|
|||
const std::unique_ptr<ChatHelpers::TabbedSelector> _tabbedSelector;
|
||||
|
||||
rpl::variable<Dialogs::RowDescriptor> _activeChatEntry;
|
||||
rpl::lifetime _activeHistoryLifetime;
|
||||
base::Variable<bool> _dialogsListFocused = { false };
|
||||
base::Variable<bool> _dialogsListDisplayForced = { false };
|
||||
std::deque<Dialogs::RowDescriptor> _chatEntryHistory;
|
||||
|
@ -600,6 +605,7 @@ private:
|
|||
PeerData *_showEditPeer = nullptr;
|
||||
rpl::variable<Data::Folder*> _openedFolder;
|
||||
rpl::variable<ChannelData*> _openedForum;
|
||||
rpl::lifetime _openedForumLifetime;
|
||||
|
||||
rpl::event_stream<> _filtersMenuChanged;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue