Show monoforums as forums in chats list.

This commit is contained in:
John Preston 2025-05-16 16:29:40 +04:00
parent 5dc50b6d96
commit 358e64f2cc
22 changed files with 303 additions and 75 deletions

View file

@ -247,7 +247,7 @@ void ChannelData::setFlags(ChannelDataFlags which) {
if (const auto forum = this->forum()) {
forum->preloadTopics();
} else if (const auto monoforum = this->monoforum()) {
monoforum->loadMore();
monoforum->preloadSublists();
}
}
}

View file

@ -202,7 +202,7 @@ void Forum::applyTopicDeleted(MsgId rootId) {
}
void Forum::reorderLastTopics() {
// We want first kShowChatNamesCount histories, by last message date.
// We want first kShowTopicNamesCount histories, by last message date.
const auto pred = [](not_null<ForumTopic*> a, not_null<ForumTopic*> b) {
const auto aItem = a->chatListMessage();
const auto bItem = b->chatListMessage();

View file

@ -60,14 +60,14 @@ MTPInputReplyTo ReplyToForMTP(
&& (to->history() != history || to->id != replyingToTopicId))
? to->topicRootId()
: replyingToTopicId;
const auto possibleMonoforumPeer = (to && to->savedSublistPeer())
? to->savedSublistPeer()
const auto possibleMonoforumPeerId = (to && to->sublistPeerId())
? to->sublistPeerId()
: replyTo.monoforumPeerId
? history->owner().peer(replyTo.monoforumPeerId).get()
: history->session().user().get();
const auto replyToMonoforumPeer = history->peer->amMonoforumAdmin()
? possibleMonoforumPeer
: nullptr;
? replyTo.monoforumPeerId
: history->session().user()->id;
const auto replyToMonoforumPeerId = history->peer->amMonoforumAdmin()
? possibleMonoforumPeerId
: PeerId();
const auto external = replyTo.messageId
&& (replyTo.messageId.peer != history->peer->id
|| replyingToTopicId != replyToTopicId);
@ -82,7 +82,9 @@ MTPInputReplyTo ReplyToForMTP(
| (replyTo.quote.text.isEmpty()
? Flag()
: (Flag::f_quote_text | Flag::f_quote_offset))
| (replyToMonoforumPeer ? Flag::f_monoforum_peer_id : Flag())
| (replyToMonoforumPeerId
? Flag::f_monoforum_peer_id
: Flag())
| (quoteEntities.v.isEmpty()
? Flag()
: Flag::f_quote_entities)),
@ -94,8 +96,8 @@ MTPInputReplyTo ReplyToForMTP(
MTP_string(replyTo.quote.text),
quoteEntities,
MTP_int(replyTo.quoteOffset),
(replyToMonoforumPeer
? replyToMonoforumPeer->input
(replyToMonoforumPeerId
? history->owner().peer(replyToMonoforumPeerId)->input
: MTPInputPeer()));
} else if (history->peer->amMonoforumAdmin()
&& replyTo.monoforumPeerId) {

View file

@ -25,6 +25,7 @@ constexpr auto kFirstPerPage = 10;
constexpr auto kListPerPage = 100;
constexpr auto kListFirstPerPage = 20;
constexpr auto kLoadedSublistsMinCount = 20;
constexpr auto kShowSublistNamesCount = 5;
} // namespace
@ -33,13 +34,13 @@ SavedMessages::SavedMessages(
ChannelData *parentChat)
: _owner(owner)
, _parentChat(parentChat)
, _parentHistory(parentChat ? owner->history(parentChat).get() : nullptr)
, _chatsList(
&_owner->session(),
FilterId(),
_owner->maxPinnedChatsLimitValue(this))
, _loadMore([=] { sendLoadMoreRequests(); }) {
if (_parentChat
&& _parentChat->owner().history(_parentChat)->inChatList()) {
if (_parentHistory && _parentHistory->inChatList()) {
preloadSublists();
}
}
@ -128,6 +129,7 @@ void SavedMessages::sendLoadMore() {
if (_chatsList.loaded()) {
_chatsListLoadedEvents.fire({});
}
reorderLastSublists();
}).fail([=](const MTP::Error &error) {
if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) {
_unsupported = true;
@ -366,6 +368,75 @@ void SavedMessages::apply(const MTPDupdateSavedDialogPinned &update) {
});
}
void SavedMessages::reorderLastSublists() {
if (!_parentHistory) {
return;
}
// We want first kShowChatNamesCount histories, by last message date.
const auto pred = [](
not_null<SavedSublist*> a,
not_null<SavedSublist*> b) {
const auto aItem = a->chatListMessage();
const auto bItem = b->chatListMessage();
const auto aDate = aItem ? aItem->date() : TimeId(0);
const auto bDate = bItem ? bItem->date() : TimeId(0);
return aDate > bDate;
};
_lastSublists.clear();
_lastSublists.reserve(kShowSublistNamesCount + 1);
auto &&sublists = ranges::views::all(
*_chatsList.indexed()
) | ranges::views::transform([](not_null<Dialogs::Row*> row) {
return row->sublist();
});
auto nonPinnedChecked = 0;
for (const auto sublist : sublists) {
const auto i = ranges::upper_bound(
_lastSublists,
not_null(sublist),
pred);
if (size(_lastSublists) < kShowSublistNamesCount
|| i != end(_lastSublists)) {
_lastSublists.insert(i, sublist);
}
if (size(_lastSublists) > kShowSublistNamesCount) {
_lastSublists.pop_back();
}
if (!sublist->isPinnedDialog(FilterId())
&& ++nonPinnedChecked >= kShowSublistNamesCount) {
break;
}
}
++_lastSublistsVersion;
_parentHistory->updateChatListEntry();
}
void SavedMessages::listMessageChanged(HistoryItem *from, HistoryItem *to) {
if (from || to) {
reorderLastSublists();
}
}
int SavedMessages::recentSublistsListVersion() const {
return _lastSublistsVersion;
}
void SavedMessages::recentSublistsInvalidate(
not_null<SavedSublist*> sublist) {
Expects(_parentHistory != nullptr);
if (ranges::contains(_lastSublists, sublist)) {
++_lastSublistsVersion;
_parentHistory->updateChatListEntry();
}
}
auto SavedMessages::recentSublists() const
-> const std::vector<not_null<SavedSublist*>> & {
return _lastSublists;
}
rpl::producer<> SavedMessages::destroyed() const {
if (!_parentChat) {
return rpl::never<>();

View file

@ -49,18 +49,27 @@ public:
void apply(const MTPDupdatePinnedSavedDialogs &update);
void apply(const MTPDupdateSavedDialogPinned &update);
void listMessageChanged(HistoryItem *from, HistoryItem *to);
[[nodiscard]] int recentSublistsListVersion() const;
void recentSublistsInvalidate(not_null<SavedSublist*> sublist);
[[nodiscard]] auto recentSublists() const
-> const std::vector<not_null<SavedSublist*>> &;
[[nodiscard]] rpl::lifetime &lifetime();
private:
void loadPinned();
void apply(const MTPmessages_SavedDialogs &result, bool pinned);
void reorderLastSublists();
void sendLoadMore();
void sendLoadMore(not_null<SavedSublist*> sublist);
void sendLoadMoreRequests();
const not_null<Session*> _owner;
ChannelData *_parentChat = nullptr;
History *_parentHistory = nullptr;
rpl::event_stream<not_null<SavedSublist*>> _sublistDestroyed;
@ -81,6 +90,9 @@ private:
base::flat_set<not_null<SavedSublist*>> _loadMoreSublistsScheduled;
bool _loadMoreScheduled = false;
std::vector<not_null<SavedSublist*>> _lastSublists;
int _lastSublistsVersion = 0;
rpl::event_stream<> _chatsListChanges;
rpl::event_stream<> _chatsListLoadedEvents;

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_saved_sublist.h"
#include "data/data_histories.h"
#include "data/data_channel.h"
#include "data/data_peer.h"
#include "data/data_user.h"
#include "data/data_saved_messages.h"
@ -80,6 +81,7 @@ void SavedSublist::applyMaybeLast(not_null<HistoryItem*> item, bool added) {
: (IsServerMsgId(b->id) ? false : (a->id < b->id));
};
const auto was = _items.empty() ? nullptr : _items.front().get();
if (_items.empty()) {
_items.push_back(item);
} else if (_items.front() == item) {
@ -104,6 +106,8 @@ void SavedSublist::applyMaybeLast(not_null<HistoryItem*> item, bool added) {
if (_items.front() == item) {
setChatListTimeId(item->date());
resolveChatListMessageGroup();
_parent->listMessageChanged(was, item.get());
}
_changed.fire({});
}
@ -132,6 +136,8 @@ void SavedSublist::removeOne(not_null<HistoryItem*> item) {
} else {
setChatListTimeId(_items.front()->date());
}
_parent->listMessageChanged(item.get(), chatListMessage());
}
if (removed || _fullCount) {
_changed.fire({});
@ -195,6 +201,11 @@ int SavedSublist::fixedOnTopIndex() const {
}
bool SavedSublist::shouldBeInChatList() const {
if (const auto monoforum = _parent->parentChat()) {
if (monoforum == sublistPeer()) {
return false;
}
}
return isPinnedDialog(FilterId()) || !_items.empty();
}

View file

@ -229,6 +229,13 @@ uint64 Entry::computeSortPosition(FilterId filterId) const {
}
void Entry::updateChatListExistence() {
if (const auto history = asHistory()) {
if (const auto channel = history->peer->asMonoforum()) {
if (!folderKnown()) {
history->clearFolder();
}
}
}
setChatListExistence(shouldBeInChatList());
}

View file

@ -892,10 +892,11 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
const auto active = mayBeActive && isRowActive(row, activeEntry);
const auto history = key.history();
const auto forum = history && history->isForum();
if (forum && !_topicJumpCache) {
const auto monoforum = history && history->amMonoforumAdmin();
if ((forum || monoforum) && !_topicJumpCache) {
_topicJumpCache = std::make_unique<Ui::TopicJumpCache>();
}
const auto expanding = forum
const auto expanding = (forum || monoforum)
&& (history->peer->id == childListShown.peerId);
context.rightButton = maybeCacheRightButton(row);
if (history) {
@ -921,14 +922,14 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
}
}
context.st = (forum ? &st::forumDialogRow : _st.get());
context.st = (forum || monoforum) ? &st::forumDialogRow : _st.get();
auto chatsFilterTags = std::vector<QImage*>();
if (context.narrow) {
context.chatsFilterTags = nullptr;
} else if (row->entry()->hasChatsFilterTags(context.filter)) {
const auto a = active;
context.st = forum
context.st = (forum || monoforum)
? &st::taggedForumDialogRow
: &st::taggedDialogRow;
auto availableWidth = context.width

View file

@ -320,7 +320,7 @@ Row::~Row() {
void Row::recountHeight(float64 narrowRatio, FilterId filterId) {
if (const auto history = _id.history()) {
const auto hasTags = _id.entry()->hasChatsFilterTags(filterId);
_height = history->isForum()
_height = (history->isForum() || history->amMonoforumAdmin())
? anim::interpolate(
hasTags
? st::taggedForumDialogRow.height
@ -466,7 +466,7 @@ void Row::PaintCornerBadgeFrame(
for (auto i = 0; i != storiesUnreadCount; ++i) {
segments.push_back({ storiesUnreadBrush, storiesUnread });
}
if (peer && peer->forum()) {
if (peer && (peer->forum() || peer->monoforum())) {
const auto radius = context.st->photoSize
* Ui::ForumUserpicRadiusMultiplier();
Ui::PaintOutlineSegments(q, outline, radius, segments);

View file

@ -67,7 +67,7 @@ const auto kPsaBadgePrefix = "cloud_lng_badge_psa_";
} else if (const auto user = history->peer->asUser()) {
return !user->lastseen().isHidden();
}
return !history->isForum();
return !history->isForum() && !history->amMonoforumAdmin();
}
void PaintRowTopRight(
@ -1046,21 +1046,23 @@ void RowPainter::Paint(
? nullptr
: thread
? &thread->lastItemDialogsView()
: sublist
? &sublist->lastItemDialogsView()
: nullptr;
if (view) {
const auto forum = context.st->topicsHeight
? row->history()->peer->forum()
const auto forum = (peer && context.st->topicsHeight)
? peer->forum()
: nullptr;
if (!view->prepared(item, forum)) {
const auto monoforum = (peer && context.st->topicsHeight)
? peer->monoforum()
: nullptr;
if (!view->prepared(item, forum, monoforum)) {
view->prepare(
item,
forum,
monoforum,
[=] { entry->updateChatListEntry(); },
{});
}
if (forum) {
if (forum || monoforum) {
rect.setHeight(context.st->topicsHeight + rect.height());
}
view->paint(p, rect, context);
@ -1154,8 +1156,13 @@ void RowPainter::Paint(
availableWidth,
st::dialogsTextFont->height);
auto &view = row->itemView();
if (!view.prepared(item, nullptr)) {
view.prepare(item, nullptr, row->repaint(), previewOptions);
if (!view.prepared(item, nullptr, nullptr)) {
view.prepare(
item,
nullptr,
nullptr,
row->repaint(),
previewOptions);
}
view.paint(p, itemRect, context);
};

View file

@ -138,26 +138,39 @@ bool MessageView::dependsOn(not_null<const HistoryItem*> item) const {
bool MessageView::prepared(
not_null<const HistoryItem*> item,
Data::Forum *forum) const {
Data::Forum *forum,
Data::SavedMessages *monoforum) const {
return (_textCachedFor == item.get())
&& (!forum
&& ((!forum && !monoforum)
|| (_topics
&& _topics->forum() == forum
&& _topics->monoforum() == monoforum
&& _topics->prepared()));
}
void MessageView::prepare(
not_null<const HistoryItem*> item,
Data::Forum *forum,
Data::SavedMessages *monoforum,
Fn<void()> customEmojiRepaint,
ToPreviewOptions options) {
if (!forum) {
if (!forum && !monoforum) {
_topics = nullptr;
} else if (!_topics || _topics->forum() != forum) {
_topics = std::make_unique<TopicsView>(forum);
_topics->prepare(item->topicRootId(), customEmojiRepaint);
} else if (!_topics
|| _topics->forum() != forum
|| _topics->monoforum() != monoforum) {
_topics = std::make_unique<TopicsView>(forum, monoforum);
if (forum) {
_topics->prepare(item->topicRootId(), customEmojiRepaint);
} else {
_topics->prepare(item->sublistPeerId(), customEmojiRepaint);
}
} else if (!_topics->prepared()) {
_topics->prepare(item->topicRootId(), customEmojiRepaint);
if (forum) {
_topics->prepare(item->topicRootId(), customEmojiRepaint);
} else {
_topics->prepare(item->sublistPeerId(), customEmojiRepaint);
}
}
if (_textCachedFor == item.get()) {
return;

View file

@ -24,6 +24,7 @@ class SpoilerAnimation;
namespace Data {
class Forum;
class SavedMessages;
} // namespace Data
namespace HistoryView {
@ -56,10 +57,12 @@ public:
[[nodiscard]] bool prepared(
not_null<const HistoryItem*> item,
Data::Forum *forum) const;
Data::Forum *forum,
Data::SavedMessages *monoforum) const;
void prepare(
not_null<const HistoryItem*> item,
Data::Forum *forum,
Data::SavedMessages *monoforum,
Fn<void()> customEmojiRepaint,
ToPreviewOptions options);

View file

@ -8,10 +8,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "dialogs/ui/dialogs_topics_view.h"
#include "dialogs/ui/dialogs_layout.h"
#include "data/stickers/data_custom_emoji.h"
#include "data/data_forum.h"
#include "data/data_forum_topic.h"
#include "data/data_peer.h"
#include "data/data_saved_messages.h"
#include "data/data_saved_sublist.h"
#include "data/data_session.h"
#include "core/ui_integration.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/painter.h"
#include "ui/power_saving.h"
#include "ui/text/text_options.h"
@ -26,29 +32,35 @@ constexpr auto kIconLoopCount = 1;
} // namespace
TopicsView::TopicsView(not_null<Data::Forum*> forum)
: _forum(forum) {
TopicsView::TopicsView(Data::Forum *forum, Data::SavedMessages *monoforum)
: _forum(forum)
, _monoforum(monoforum) {
}
TopicsView::~TopicsView() = default;
bool TopicsView::prepared() const {
return (_version == _forum->recentTopicsListVersion());
const auto version = _forum
? _forum->recentTopicsListVersion()
: _monoforum->recentSublistsListVersion();
return (_version == version);
}
void TopicsView::prepare(MsgId frontRootId, Fn<void()> customEmojiRepaint) {
Expects(_forum != nullptr);
const auto &list = _forum->recentTopics();
_version = _forum->recentTopicsListVersion();
_titles.reserve(list.size());
auto index = 0;
for (const auto &topic : list) {
const auto from = begin(_titles) + index;
const auto rootId = topic->rootId();
const auto key = topic->rootId().bare;
const auto i = ranges::find(
from,
end(_titles),
rootId,
&Title::topicRootId);
key,
&Title::key);
if (i != end(_titles)) {
if (i != from) {
ranges::rotate(from, i, i + 1);
@ -58,7 +70,7 @@ void TopicsView::prepare(MsgId frontRootId, Fn<void()> customEmojiRepaint) {
}
auto &title = _titles[index++];
const auto unread = topic->chatListBadgesState().unread;
if (title.topicRootId == rootId
if (title.key == key
&& title.unread == unread
&& title.version == topic->titleVersion()) {
continue;
@ -69,7 +81,7 @@ void TopicsView::prepare(MsgId frontRootId, Fn<void()> customEmojiRepaint) {
.customEmojiLoopLimit = kIconLoopCount,
});
auto topicTitle = topic->titleWithIcon();
title.topicRootId = rootId;
title.key = key;
title.version = topic->titleVersion();
title.unread = unread;
title.title.setMarkedText(
@ -87,7 +99,79 @@ void TopicsView::prepare(MsgId frontRootId, Fn<void()> customEmojiRepaint) {
_titles.pop_back();
}
const auto i = frontRootId
? ranges::find(_titles, frontRootId, &Title::topicRootId)
? ranges::find(_titles, frontRootId.bare, &Title::key)
: end(_titles);
_jumpToTopic = (i != end(_titles));
if (_jumpToTopic) {
if (i != begin(_titles)) {
ranges::rotate(begin(_titles), i, i + 1);
}
if (!_titles.front().unread) {
_jumpToTopic = false;
}
}
}
void TopicsView::prepare(PeerId frontPeerId, Fn<void()> customEmojiRepaint) {
Expects(_monoforum != nullptr);
const auto &list = _monoforum->recentSublists();
const auto manager = &_monoforum->session().data().customEmojiManager();
_version = _monoforum->recentSublistsListVersion();
_titles.reserve(list.size());
auto index = 0;
for (const auto &sublist : list) {
const auto from = begin(_titles) + index;
const auto peer = sublist->sublistPeer();
const auto key = peer->id.value;
const auto i = ranges::find(
from,
end(_titles),
key,
&Title::key);
if (i != end(_titles)) {
if (i != from) {
ranges::rotate(from, i, i + 1);
}
} else if (index >= _titles.size()) {
_titles.emplace_back();
}
auto &title = _titles[index++];
const auto unread = sublist->chatListBadgesState().unread;
if (title.key == key
&& title.unread == unread
&& title.version == peer->nameVersion()) {
continue;
}
const auto context = Core::TextContext({
.session = &sublist->session(),
.repaint = customEmojiRepaint,
.customEmojiLoopLimit = kIconLoopCount,
});
auto topicTitle = TextWithEntities().append(
Ui::Text::SingleCustomEmoji(
manager->peerUserpicEmojiData(peer),
u"@"_q)
).append(peer->shortName());
title.key = key;
title.version = peer->nameVersion();
title.unread = unread;
title.title.setMarkedText(
st::dialogsTextStyle,
(unread
? Ui::Text::Colorized(
Ui::Text::Wrapped(
std::move(topicTitle),
EntityType::Bold))
: std::move(topicTitle)),
DialogTextOptions(),
context);
}
while (_titles.size() > index) {
_titles.pop_back();
}
const auto i = frontPeerId
? ranges::find(_titles, frontPeerId.value, &Title::key)
: end(_titles);
_jumpToTopic = (i != end(_titles));
if (_jumpToTopic) {

View file

@ -16,6 +16,8 @@ struct DialogRow;
namespace Data {
class Forum;
class ForumTopic;
class SavedMessages;
class SavedSublist;
} // namespace Data
namespace Ui {
@ -59,15 +61,19 @@ void FillJumpToLastPrepared(QPainter &p, JumpToLastPrepared context);
class TopicsView final {
public:
explicit TopicsView(not_null<Data::Forum*> forum);
TopicsView(Data::Forum *forum, Data::SavedMessages *monoforum);
~TopicsView();
[[nodiscard]] not_null<Data::Forum*> forum() const {
[[nodiscard]] Data::Forum *forum() const {
return _forum;
}
[[nodiscard]] Data::SavedMessages *monoforum() const {
return _monoforum;
}
[[nodiscard]] bool prepared() const;
void prepare(MsgId frontRootId, Fn<void()> customEmojiRepaint);
void prepare(PeerId frontPeerId, Fn<void()> customEmojiRepaint);
[[nodiscard]] int jumpToTopicWidth() const;
@ -99,7 +105,7 @@ public:
private:
struct Title {
Text::String title;
MsgId topicRootId = 0;
uint64 key = 0;
int version = -1;
bool unread = false;
};
@ -107,7 +113,8 @@ private:
[[nodiscard]] QImage topicJumpRippleMask(
not_null<TopicJumpCache*> topicJumpCache) const;
const not_null<Data::Forum*> _forum;
Data::Forum * const _forum = nullptr;
Data::SavedMessages * const _monoforum = nullptr;
mutable std::vector<Title> _titles;
mutable std::unique_ptr<RippleAnimation> _ripple;

View file

@ -3149,11 +3149,11 @@ void History::monoforumChanged(Data::SavedMessages *old) {
}
if (const auto monoforum = peer->monoforum()) {
_flags |= Flag::IsMonoforum;
_flags |= Flag::IsMonoforumAdmin;
monoforum->chatsList()->unreadStateChanges(
) | rpl::filter([=] {
return (_flags & Flag::IsMonoforum) && inChatList();
return (_flags & Flag::IsMonoforumAdmin) && inChatList();
}) | rpl::map(
AdjustedForumUnreadState
) | rpl::start_with_next([=](const Dialogs::UnreadState &old) {
@ -3165,7 +3165,7 @@ void History::monoforumChanged(Data::SavedMessages *old) {
updateChatListEntry();
}, monoforum->lifetime());
} else {
_flags &= ~Flag::IsMonoforum;
_flags &= ~Flag::IsMonoforumAdmin;
}
if (cloudDraft(MsgId(0))) {
updateChatListSortPosition();
@ -3173,8 +3173,8 @@ void History::monoforumChanged(Data::SavedMessages *old) {
_flags |= Flag::PendingAllItemsResize;
}
bool History::isMonoforum() const {
return (_flags & Flag::IsMonoforum);
bool History::amMonoforumAdmin() const {
return (_flags & Flag::IsMonoforumAdmin);
}
not_null<History*> History::migrateToOrMe() const {

View file

@ -74,7 +74,7 @@ public:
[[nodiscard]] bool isForum() const;
void monoforumChanged(Data::SavedMessages *old);
[[nodiscard]] bool isMonoforum() const;
[[nodiscard]] bool amMonoforumAdmin() const;
[[nodiscard]] not_null<History*> migrateToOrMe() const;
[[nodiscard]] History *migrateFrom() const;
@ -435,7 +435,7 @@ private:
PendingAllItemsResize = (1 << 1),
IsTopPromoted = (1 << 2),
IsForum = (1 << 3),
IsMonoforum = (1 << 4),
IsMonoforumAdmin = (1 << 4),
FakeUnreadWhileOpened = (1 << 5),
HasPinnedMessages = (1 << 6),
ResolveChatListMessage = (1 << 7),

View file

@ -3443,12 +3443,12 @@ FullStoryId HistoryItem::replyToStory() const {
}
FullReplyTo HistoryItem::replyTo() const {
const auto monoforumPeer = _history->peer->amMonoforumAdmin()
? savedSublistPeer()
: nullptr;
const auto monoforumPeerId = _history->peer->amMonoforumAdmin()
? sublistPeerId()
: PeerId();
auto result = FullReplyTo{
.topicRootId = topicRootId(),
.monoforumPeerId = monoforumPeer ? monoforumPeer->id : PeerId(),
.monoforumPeerId = monoforumPeerId,
};
if (const auto reply = Get<HistoryMessageReply>()) {
const auto &fields = reply->fields();
@ -3592,11 +3592,15 @@ Data::SavedSublist *HistoryItem::savedSublist() const {
return nullptr;
}
PeerData *HistoryItem::savedSublistPeer() const {
if (const auto sublist = savedSublist()) {
return sublist->sublistPeer();
PeerId HistoryItem::sublistPeerId() const {
if (const auto saved = Get<HistoryMessageSaved>()) {
return saved->sublistPeerId;
} else if (_history->peer->isSelf()) {
return _history->peer->id;
} else if (_history->peer->monoforum()) {
return _from->id;
}
return nullptr;
return PeerId();
}
PeerData *HistoryItem::savedFromSender() const {
@ -4046,8 +4050,8 @@ void HistoryItem::createComponentsHelper(HistoryItemCommonFields &&fields) {
? replyTo.messageId.peer
: PeerId();
const auto to = LookupReplyTo(_history, replyTo.messageId);
config.reply.monoforumPeerId = (to && to->savedSublistPeer())
? to->savedSublistPeer()->id
config.reply.monoforumPeerId = (to && to->sublistPeerId())
? to->sublistPeerId()
: replyTo.monoforumPeerId
? replyTo.monoforumPeerId
: PeerId();

View file

@ -491,7 +491,7 @@ public:
[[nodiscard]] MsgId originalId() const;
[[nodiscard]] Data::SavedSublist *savedSublist() const;
[[nodiscard]] PeerData *savedSublistPeer() const;
[[nodiscard]] PeerId sublistPeerId() const;
[[nodiscard]] PeerData *savedFromSender() const;
[[nodiscard]] const HiddenSenderInfo *savedFromHiddenSenderInfo() const;

View file

@ -1699,10 +1699,10 @@ FullReplyTo ChatWidget::replyTo() const {
const auto item = custom.messageId
? session().data().message(custom.messageId)
: nullptr;
const auto sublistPeer = item ? item->savedSublistPeer() : nullptr;
const auto sublistPeerId = item ? item->sublistPeerId() : PeerId();
if (!item
|| !monoforumPeerId
|| (sublistPeer && sublistPeer->id == monoforumPeerId)) {
|| (sublistPeerId == monoforumPeerId)) {
// Never answer to a message in a wrong monoforum peer id.
custom.topicRootId = _repliesRootId;
custom.monoforumPeerId = monoforumPeerId;

View file

@ -1487,7 +1487,7 @@ void Element::recountMonoforumSenderBarInBlocks() {
}
}
}
return sublistPeer;
return (sublistPeer == parentChat) ? nullptr : sublistPeer.get();
}();
if (barPeer && !Has<MonoforumSenderBar>()) {
AddComponents(MonoforumSenderBar::Bit());

View file

@ -773,7 +773,7 @@ void TopBarWidget::backClicked() {
_controller->closeForum();
} else if (_activeChat.section == Section::ChatsList
&& _activeChat.key.history()
&& _activeChat.key.history()->isMonoforum()) {
&& _activeChat.key.history()->amMonoforumAdmin()) {
_controller->closeMonoforum();
} else {
_controller->showBackFromStack();
@ -1236,7 +1236,8 @@ void TopBarWidget::updateMembersShowArea() {
} else if (const auto chat = peer->asChat()) {
return chat->amIn();
} else if (const auto megagroup = peer->asMegagroup()) {
return megagroup->canViewMembers()
return !megagroup->isMonoforum()
&& megagroup->canViewMembers()
&& (megagroup->membersCount()
< megagroup->session().serverConfig().chatSizeMax);
}

View file

@ -1777,9 +1777,14 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupPersonalChannel(
style::al_left);
return;
}
if (!state->view.prepared(item, nullptr)) {
if (!state->view.prepared(item, nullptr, nullptr)) {
const auto repaint = [=] { preview->update(); };
state->view.prepare(item, nullptr, repaint, {});
state->view.prepare(
item,
nullptr,
nullptr,
repaint,
{});
}
state->view.paint(p, preview->rect(), {
.st = &st::defaultDialogRow,