Added initial ability to send and receive scheduled messages in forums.

This commit is contained in:
23rd 2024-03-12 15:36:36 +03:00
parent cd59f1d576
commit 672ad64e53
9 changed files with 246 additions and 37 deletions

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_scheduled_messages.h" #include "data/data_scheduled_messages.h"
#include "base/unixtime.h" #include "base/unixtime.h"
#include "data/data_forum_topic.h"
#include "data/data_peer.h" #include "data/data_peer.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "api/api_hash.h" #include "api/api_hash.h"
@ -173,6 +174,16 @@ int ScheduledMessages::count(not_null<History*> history) const {
return (i != end(_data)) ? i->second.items.size() : 0; return (i != end(_data)) ? i->second.items.size() : 0;
} }
bool ScheduledMessages::hasFor(not_null<Data::ForumTopic*> topic) const {
const auto i = _data.find(topic->owningHistory());
if (i == end(_data)) {
return false;
}
return ranges::any_of(i->second.items, [&](const OwnedItem &item) {
return item->topic() == topic;
});
}
void ScheduledMessages::sendNowSimpleMessage( void ScheduledMessages::sendNowSimpleMessage(
const MTPDupdateShortSentMessage &update, const MTPDupdateShortSentMessage &update,
not_null<HistoryItem*> local) { not_null<HistoryItem*> local) {
@ -374,7 +385,8 @@ rpl::producer<> ScheduledMessages::updates(not_null<History*> history) {
}) | rpl::to_empty; }) | rpl::to_empty;
} }
Data::MessagesSlice ScheduledMessages::list(not_null<History*> history) { Data::MessagesSlice ScheduledMessages::list(
not_null<History*> history) const {
auto result = Data::MessagesSlice(); auto result = Data::MessagesSlice();
const auto i = _data.find(history); const auto i = _data.find(history);
if (i == end(_data)) { if (i == end(_data)) {
@ -396,6 +408,31 @@ Data::MessagesSlice ScheduledMessages::list(not_null<History*> history) {
return result; return result;
} }
Data::MessagesSlice ScheduledMessages::list(
not_null<const Data::ForumTopic*> topic) const {
auto result = Data::MessagesSlice();
const auto i = _data.find(topic->Data::Thread::owningHistory());
if (i == end(_data)) {
const auto i = _requests.find(topic->Data::Thread::owningHistory());
if (i == end(_requests)) {
return result;
}
result.fullCount = result.skippedAfter = result.skippedBefore = 0;
return result;
}
const auto &list = i->second.items;
result.skippedAfter = result.skippedBefore = 0;
result.fullCount = int(list.size());
result.ids = ranges::views::all(
list
) | ranges::views::filter([&](const OwnedItem &item) {
return item->topic() == topic;
}) | ranges::views::transform(
&HistoryItem::fullId
) | ranges::to_vector;
return result;
}
void ScheduledMessages::request(not_null<History*> history) { void ScheduledMessages::request(not_null<History*> history) {
const auto peer = history->peer; const auto peer = history->peer;
if (peer->isBroadcast() && !Data::CanSendAnything(peer)) { if (peer->isBroadcast() && !Data::CanSendAnything(peer)) {

View File

@ -34,6 +34,7 @@ public:
[[nodiscard]] HistoryItem *lookupItem(PeerId peer, MsgId msg) const; [[nodiscard]] HistoryItem *lookupItem(PeerId peer, MsgId msg) const;
[[nodiscard]] HistoryItem *lookupItem(FullMsgId itemId) const; [[nodiscard]] HistoryItem *lookupItem(FullMsgId itemId) const;
[[nodiscard]] int count(not_null<History*> history) const; [[nodiscard]] int count(not_null<History*> history) const;
[[nodiscard]] bool hasFor(not_null<Data::ForumTopic*> topic) const;
[[nodiscard]] MsgId localMessageId(MsgId remoteId) const; [[nodiscard]] MsgId localMessageId(MsgId remoteId) const;
void checkEntitiesAndUpdate(const MTPDmessage &data); void checkEntitiesAndUpdate(const MTPDmessage &data);
@ -51,7 +52,9 @@ public:
not_null<HistoryItem*> local); not_null<HistoryItem*> local);
[[nodiscard]] rpl::producer<> updates(not_null<History*> history); [[nodiscard]] rpl::producer<> updates(not_null<History*> history);
[[nodiscard]] Data::MessagesSlice list(not_null<History*> history); [[nodiscard]] Data::MessagesSlice list(not_null<History*> history) const;
[[nodiscard]] Data::MessagesSlice list(
not_null<const Data::ForumTopic*> topic) const;
private: private:
using OwnedItem = std::unique_ptr<HistoryItem, HistoryItem::Destroyer>; using OwnedItem = std::unique_ptr<HistoryItem, HistoryItem::Destroyer>;

View File

@ -2723,6 +2723,9 @@ void HistoryWidget::setupScheduledToggle() {
) | rpl::map([=](Dialogs::Key key) -> rpl::producer<> { ) | rpl::map([=](Dialogs::Key key) -> rpl::producer<> {
if (const auto history = key.history()) { if (const auto history = key.history()) {
return session().data().scheduledMessages().updates(history); return session().data().scheduledMessages().updates(history);
} else if (const auto topic = key.topic()) {
return session().data().scheduledMessages().updates(
topic->owningHistory());
} }
return rpl::never<rpl::empty_value>(); return rpl::never<rpl::empty_value>();
}) | rpl::flatten_latest( }) | rpl::flatten_latest(

View File

@ -850,9 +850,36 @@ ComposeControls::ComposeControls(
descriptor.stickerOrEmojiChosen descriptor.stickerOrEmojiChosen
) | rpl::start_to_stream(_stickerOrEmojiChosen, _wrap->lifetime()); ) | rpl::start_to_stream(_stickerOrEmojiChosen, _wrap->lifetime());
} }
if (descriptor.scheduledToggleValue) {
std::move(
descriptor.scheduledToggleValue
) | rpl::start_with_next([=](bool hasScheduled) {
if (!_scheduled && hasScheduled) {
_scheduled = base::make_unique_q<Ui::IconButton>(
_wrap.get(),
st::historyScheduledToggle);
_scheduled->show();
_scheduled->clicks(
) | rpl::filter(
rpl::mappers::_1 == Qt::LeftButton
) | rpl::to_empty | rpl::start_to_stream(
_showScheduledRequests,
_scheduled->lifetime());
orderControls(); // Raise drag areas to the top.
updateControlsVisibility();
updateControlsGeometry(_wrap->size());
} else if (_scheduled && !hasScheduled) {
_scheduled = nullptr;
}
}, _wrap->lifetime());
}
init(); init();
} }
rpl::producer<> ComposeControls::showScheduledRequests() const {
return _showScheduledRequests.events();
}
ComposeControls::~ComposeControls() { ComposeControls::~ComposeControls() {
saveFieldToHistoryLocalDraft(); saveFieldToHistoryLocalDraft();
unregisterDraftSources(); unregisterDraftSources();
@ -2497,7 +2524,7 @@ void ComposeControls::finishAnimating() {
void ComposeControls::updateControlsGeometry(QSize size) { void ComposeControls::updateControlsGeometry(QSize size) {
// (_attachToggle|_replaceMedia) (_sendAs) -- _inlineResults ------ _tabbedPanel -- _fieldBarCancel // (_attachToggle|_replaceMedia) (_sendAs) -- _inlineResults ------ _tabbedPanel -- _fieldBarCancel
// (_attachDocument|_attachPhoto) _field (_ttlInfo) (_silent|_botCommandStart) _tabbedSelectorToggle _send // (_attachDocument|_attachPhoto) _field (_ttlInfo) (_scheduled) (_silent|_botCommandStart) _tabbedSelectorToggle _send
const auto fieldWidth = size.width() const auto fieldWidth = size.width()
- _attachToggle->width() - _attachToggle->width()
@ -2508,6 +2535,7 @@ void ComposeControls::updateControlsGeometry(QSize size) {
- (_likeShown ? _like->width() : 0) - (_likeShown ? _like->width() : 0)
- (_botCommandShown ? _botCommandStart->width() : 0) - (_botCommandShown ? _botCommandStart->width() : 0)
- (_silent ? _silent->width() : 0) - (_silent ? _silent->width() : 0)
- (_scheduled ? _scheduled->width() : 0)
- (_ttlInfo ? _ttlInfo->width() : 0); - (_ttlInfo ? _ttlInfo->width() : 0);
{ {
const auto oldFieldHeight = _field->height(); const auto oldFieldHeight = _field->height();
@ -2566,6 +2594,10 @@ void ComposeControls::updateControlsGeometry(QSize size) {
_silent->moveToRight(right, buttonsTop); _silent->moveToRight(right, buttonsTop);
right += _silent->width(); right += _silent->width();
} }
if (_scheduled) {
_scheduled->moveToRight(right, buttonsTop);
right += _scheduled->width();
}
if (_ttlInfo) { if (_ttlInfo) {
_ttlInfo->move(size.width() - right - _ttlInfo->width(), buttonsTop); _ttlInfo->move(size.width() - right - _ttlInfo->width(), buttonsTop);
} }
@ -2595,6 +2627,9 @@ void ComposeControls::updateControlsVisibility() {
} else { } else {
_attachToggle->show(); _attachToggle->show();
} }
if (_scheduled) {
_scheduled->setVisible(!isEditingMessage());
}
} }
bool ComposeControls::updateLikeShown() { bool ComposeControls::updateLikeShown() {

View File

@ -112,6 +112,7 @@ struct ComposeControlsDescriptor {
QString voiceCustomCancelText; QString voiceCustomCancelText;
bool voiceLockFromBottom = false; bool voiceLockFromBottom = false;
ChatHelpers::ComposeFeatures features; ChatHelpers::ComposeFeatures features;
rpl::producer<bool> scheduledToggleValue;
}; };
class ComposeControls final { class ComposeControls final {
@ -172,6 +173,7 @@ public:
[[nodiscard]] auto replyNextRequests() const [[nodiscard]] auto replyNextRequests() const
-> rpl::producer<ReplyNextRequest>; -> rpl::producer<ReplyNextRequest>;
[[nodiscard]] rpl::producer<> focusRequests() const; [[nodiscard]] rpl::producer<> focusRequests() const;
[[nodiscard]] rpl::producer<> showScheduledRequests() const;
using MimeDataHook = Fn<bool( using MimeDataHook = Fn<bool(
not_null<const QMimeData*> data, not_null<const QMimeData*> data,
@ -382,6 +384,7 @@ private:
std::unique_ptr<Ui::SilentToggle> _silent; std::unique_ptr<Ui::SilentToggle> _silent;
std::unique_ptr<Controls::TTLButton> _ttlInfo; std::unique_ptr<Controls::TTLButton> _ttlInfo;
base::unique_qptr<Controls::CharactersLimitLabel> _charsLimitation; base::unique_qptr<Controls::CharactersLimitLabel> _charsLimitation;
base::unique_qptr<Ui::IconButton> _scheduled;
std::unique_ptr<InlineBots::Layout::Widget> _inlineResults; std::unique_ptr<InlineBots::Layout::Widget> _inlineResults;
std::unique_ptr<ChatHelpers::TabbedPanel> _tabbedPanel; std::unique_ptr<ChatHelpers::TabbedPanel> _tabbedPanel;
@ -408,6 +411,7 @@ private:
rpl::event_stream<> _likeToggled; rpl::event_stream<> _likeToggled;
rpl::event_stream<ReplyNextRequest> _replyNextRequests; rpl::event_stream<ReplyNextRequest> _replyNextRequests;
rpl::event_stream<> _focusRequests; rpl::event_stream<> _focusRequests;
rpl::event_stream<> _showScheduledRequests;
rpl::variable<bool> _recording; rpl::variable<bool> _recording;
rpl::variable<bool> _hasSendText; rpl::variable<bool> _hasSendText;

View File

@ -861,7 +861,9 @@ QSize Message::performCountOptimalSize() {
void Message::refreshTopicButton() { void Message::refreshTopicButton() {
const auto item = data(); const auto item = data();
if (isAttachedToPrevious() || context() != Context::History) { if (isAttachedToPrevious()
|| (context() != Context::History)
|| item->isScheduled()) {
_topicButton = nullptr; _topicButton = nullptr;
} else if (const auto topic = item->topic()) { } else if (const auto topic = item->topic()) {
if (!_topicButton) { if (!_topicButton) {

View File

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_sticker_toast.h" #include "history/view/history_view_sticker_toast.h"
#include "history/view/history_view_cursor_state.h" #include "history/view/history_view_cursor_state.h"
#include "history/view/history_view_contact_status.h" #include "history/view/history_view_contact_status.h"
#include "history/view/history_view_scheduled_section.h"
#include "history/view/history_view_service_message.h" #include "history/view/history_view_service_message.h"
#include "history/view/history_view_pinned_tracker.h" #include "history/view/history_view_pinned_tracker.h"
#include "history/view/history_view_pinned_section.h" #include "history/view/history_view_pinned_section.h"
@ -62,6 +63,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_changes.h" #include "data/data_changes.h"
#include "data/data_shared_media.h" #include "data/data_shared_media.h"
#include "data/data_send_action.h" #include "data/data_send_action.h"
#include "data/data_scheduled_messages.h"
#include "data/data_premium_limits.h" #include "data/data_premium_limits.h"
#include "storage/storage_media_prepare.h" #include "storage/storage_media_prepare.h"
#include "storage/storage_account.h" #include "storage/storage_account.h"
@ -221,9 +223,19 @@ RepliesWidget::RepliesWidget(
listShowPremiumToast(emoji); listShowPremiumToast(emoji);
}, },
.mode = ComposeControls::Mode::Normal, .mode = ComposeControls::Mode::Normal,
.sendMenuType = SendMenu::Type::SilentOnly, .sendMenuType = _topic
? SendMenu::Type::Scheduled
: SendMenu::Type::SilentOnly,
.regularWindow = controller, .regularWindow = controller,
.stickerOrEmojiChosen = controller->stickerOrEmojiChosen(), .stickerOrEmojiChosen = controller->stickerOrEmojiChosen(),
.scheduledToggleValue = _topic
? rpl::single(rpl::empty_value()) | rpl::then(
session().data().scheduledMessages().updates(
_topic->owningHistory())
) | rpl::map([=] {
return session().data().scheduledMessages().hasFor(_topic);
})
: rpl::single(false),
})) }))
, _translateBar(std::make_unique<TranslateBar>(this, controller, history)) , _translateBar(std::make_unique<TranslateBar>(this, controller, history))
, _scroll(std::make_unique<Ui::ScrollArea>( , _scroll(std::make_unique<Ui::ScrollArea>(
@ -364,6 +376,20 @@ RepliesWidget::RepliesWidget(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
_inner->update(); _inner->update();
}, lifetime()); }, lifetime());
} else {
session().api().sendActions(
) | rpl::filter([=](const Api::SendAction &action) {
return (action.history == _history)
&& (action.replyTo.topicRootId == _topic->topicRootId());
}) | rpl::start_with_next([=](const Api::SendAction &action) {
if (action.options.scheduled) {
_composeControls->cancelReplyMessage();
crl::on_main(this, [=, t = _topic] {
controller->showSection(
std::make_shared<HistoryView::ScheduledMemento>(t));
});
}
}, lifetime());
} }
setupTopicViewer(); setupTopicViewer();
@ -778,6 +804,14 @@ void RepliesWidget::setupComposeControls() {
data.direction == Direction::Next); data.direction == Direction::Next);
}, lifetime()); }, lifetime());
_composeControls->showScheduledRequests(
) | rpl::start_with_next([=] {
controller()->showSection(
_topic
? std::make_shared<HistoryView::ScheduledMemento>(_topic)
: std::make_shared<HistoryView::ScheduledMemento>(_history));
}, lifetime());
_composeControls->setMimeDataHook([=]( _composeControls->setMimeDataHook([=](
not_null<const QMimeData*> data, not_null<const QMimeData*> data,
Ui::InputField::MimeAction action) { Ui::InputField::MimeAction action) {

View File

@ -33,6 +33,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/mime_type.h" #include "core/mime_type.h"
#include "chat_helpers/tabbed_selector.h" #include "chat_helpers/tabbed_selector.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "data/data_forum.h"
#include "data/data_forum_topic.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_changes.h" #include "data/data_changes.h"
#include "data/data_scheduled_messages.h" #include "data/data_scheduled_messages.h"
@ -53,6 +55,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace HistoryView { namespace HistoryView {
ScheduledMemento::ScheduledMemento(not_null<History*> history)
: _history(history)
, _forumTopic(nullptr) {
}
ScheduledMemento::ScheduledMemento(not_null<Data::ForumTopic*> forumTopic)
: _history(forumTopic->owningHistory())
, _forumTopic(forumTopic) {
}
object_ptr<Window::SectionWidget> ScheduledMemento::createWidget( object_ptr<Window::SectionWidget> ScheduledMemento::createWidget(
QWidget *parent, QWidget *parent,
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
@ -61,7 +73,11 @@ object_ptr<Window::SectionWidget> ScheduledMemento::createWidget(
if (column == Window::Column::Third) { if (column == Window::Column::Third) {
return nullptr; return nullptr;
} }
auto result = object_ptr<ScheduledWidget>(parent, controller, _history); auto result = object_ptr<ScheduledWidget>(
parent,
controller,
_history,
_forumTopic);
result->setInternalState(geometry, this); result->setInternalState(geometry, this);
return result; return result;
} }
@ -69,9 +85,11 @@ object_ptr<Window::SectionWidget> ScheduledMemento::createWidget(
ScheduledWidget::ScheduledWidget( ScheduledWidget::ScheduledWidget(
QWidget *parent, QWidget *parent,
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<History*> history) not_null<History*> history,
const Data::ForumTopic *forumTopic)
: Window::SectionWidget(parent, controller, history->peer) : Window::SectionWidget(parent, controller, history->peer)
, _history(history) , _history(history)
, _forumTopic(forumTopic)
, _scroll( , _scroll(
this, this,
controller->chatStyle()->value(lifetime(), st::historyScroll), controller->chatStyle()->value(lifetime(), st::historyScroll),
@ -175,30 +193,80 @@ ScheduledWidget::ScheduledWidget(
ScheduledWidget::~ScheduledWidget() = default; ScheduledWidget::~ScheduledWidget() = default;
void ScheduledWidget::setupComposeControls() { void ScheduledWidget::setupComposeControls() {
auto writeRestriction = rpl::combine( auto writeRestriction = _forumTopic
session().changes().peerFlagsValue( ? [&] {
_history->peer, auto topicWriteRestrictions = rpl::single(
Data::PeerUpdate::Flag::Rights), ) | rpl::then(session().changes().topicUpdates(
Data::CanSendAnythingValue(_history->peer) Data::TopicUpdate::Flag::Closed
) | rpl::map([=] { ) | rpl::filter([=](const Data::TopicUpdate &update) {
const auto allWithoutPolls = Data::AllSendRestrictions() return (update.topic->history() == _history)
& ~ChatRestriction::SendPolls; && (update.topic->rootId() == _forumTopic->rootId());
const auto canSendAnything = Data::CanSendAnyOf( }) | rpl::to_empty) | rpl::map([=] {
_history->peer, return (!_forumTopic
allWithoutPolls); || _forumTopic->canToggleClosed()
const auto restriction = Data::RestrictionError( || !_forumTopic->closed())
_history->peer, ? std::optional<QString>()
ChatRestriction::SendOther); : tr::lng_forum_topic_closed(tr::now);
auto text = !canSendAnything });
? (restriction return rpl::combine(
? restriction session().changes().peerFlagsValue(
: tr::lng_group_not_accessible(tr::now)) _history->peer,
: std::optional<QString>(); Data::PeerUpdate::Flag::Rights),
return text ? Controls::WriteRestriction{ Data::CanSendAnythingValue(_history->peer),
.text = std::move(*text), std::move(topicWriteRestrictions)
.type = Controls::WriteRestrictionType::Rights, ) | rpl::map([=](
} : Controls::WriteRestriction(); auto,
}); auto,
std::optional<QString> topicRestriction) {
const auto allWithoutPolls = Data::AllSendRestrictions()
& ~ChatRestriction::SendPolls;
const auto canSendAnything = Data::CanSendAnyOf(
_forumTopic,
allWithoutPolls);
const auto restriction = Data::RestrictionError(
_history->peer,
ChatRestriction::SendOther);
auto text = !canSendAnything
? (restriction
? restriction
: topicRestriction
? std::move(topicRestriction)
: tr::lng_group_not_accessible(tr::now))
: topicRestriction
? std::move(topicRestriction)
: std::optional<QString>();
return text ? Controls::WriteRestriction{
.text = std::move(*text),
.type = Controls::WriteRestrictionType::Rights,
} : Controls::WriteRestriction();
});
}()
: [&] {
return rpl::combine(
session().changes().peerFlagsValue(
_history->peer,
Data::PeerUpdate::Flag::Rights),
Data::CanSendAnythingValue(_history->peer)
) | rpl::map([=] {
const auto allWithoutPolls = Data::AllSendRestrictions()
& ~ChatRestriction::SendPolls;
const auto canSendAnything = Data::CanSendAnyOf(
_history->peer,
allWithoutPolls);
const auto restriction = Data::RestrictionError(
_history->peer,
ChatRestriction::SendOther);
auto text = !canSendAnything
? (restriction
? restriction
: tr::lng_group_not_accessible(tr::now))
: std::optional<QString>();
return text ? Controls::WriteRestriction{
.text = std::move(*text),
.type = Controls::WriteRestrictionType::Rights,
} : Controls::WriteRestriction();
});
}();
_composeControls->setHistory({ _composeControls->setHistory({
.history = _history.get(), .history = _history.get(),
.writeRestriction = std::move(writeRestriction), .writeRestriction = std::move(writeRestriction),
@ -564,6 +632,12 @@ Api::SendAction ScheduledWidget::prepareSendAction(
Api::SendOptions options) const { Api::SendOptions options) const {
auto result = Api::SendAction(_history, options); auto result = Api::SendAction(_history, options);
result.options.sendAs = _composeControls->sendAsPeer(); result.options.sendAs = _composeControls->sendAsPeer();
if (_forumTopic) {
result.replyTo.topicRootId = _forumTopic->topicRootId();
result.replyTo.messageId = FullMsgId(
history()->peer->id,
_forumTopic->topicRootId());
}
return result; return result;
} }
@ -576,7 +650,7 @@ void ScheduledWidget::send() {
const auto error = GetErrorTextForSending( const auto error = GetErrorTextForSending(
_history->peer, _history->peer,
{ {
.topicRootId = MsgId(), .topicRootId = _forumTopic ? _forumTopic->topicRootId() : MsgId(),
.forward = nullptr, .forward = nullptr,
.text = &textWithTags, .text = &textWithTags,
.ignoreSlowmodeCountdown = true, .ignoreSlowmodeCountdown = true,
@ -943,6 +1017,16 @@ bool ScheduledWidget::returnTabbedSelector() {
} }
std::shared_ptr<Window::SectionMemento> ScheduledWidget::createMemento() { std::shared_ptr<Window::SectionMemento> ScheduledWidget::createMemento() {
if (_forumTopic) {
if (const auto forum = history()->asForum()) {
const auto rootId = _forumTopic->topicRootId();
if (const auto topic = forum->topicFor(rootId)) {
auto result = std::make_shared<ScheduledMemento>(topic);
saveState(result.get());
return result;
}
}
}
auto result = std::make_shared<ScheduledMemento>(history()); auto result = std::make_shared<ScheduledMemento>(history());
saveState(result.get()); saveState(result.get());
return result; return result;
@ -1098,7 +1182,9 @@ rpl::producer<Data::MessagesSlice> ScheduledWidget::listSource(
return rpl::single(rpl::empty) | rpl::then( return rpl::single(rpl::empty) | rpl::then(
data->scheduledMessages().updates(_history) data->scheduledMessages().updates(_history)
) | rpl::map([=] { ) | rpl::map([=] {
return data->scheduledMessages().list(_history); return _forumTopic
? data->scheduledMessages().list(_forumTopic)
: data->scheduledMessages().list(_history);
}) | rpl::after_next([=](const Data::MessagesSlice &slice) { }) | rpl::after_next([=](const Data::MessagesSlice &slice) {
highlightSingleNewMessage(slice); highlightSingleNewMessage(slice);
}); });
@ -1187,6 +1273,9 @@ void ScheduledWidget::listUpdateDateLink(
} }
bool ScheduledWidget::listElementHideReply(not_null<const Element*> view) { bool ScheduledWidget::listElementHideReply(not_null<const Element*> view) {
if (const auto root = view->data()->topicRootId()) {
return root == view->data()->replyTo().messageId.msg;
}
return false; return false;
} }

View File

@ -58,7 +58,8 @@ public:
ScheduledWidget( ScheduledWidget(
QWidget *parent, QWidget *parent,
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<History*> history); not_null<History*> history,
const Data::ForumTopic *forumTopic);
~ScheduledWidget(); ~ScheduledWidget();
not_null<History*> history() const; not_null<History*> history() const;
@ -261,6 +262,7 @@ private:
Api::SendOptions options); Api::SendOptions options);
const not_null<History*> _history; const not_null<History*> _history;
const Data::ForumTopic *_forumTopic;
std::shared_ptr<Ui::ChatTheme> _theme; std::shared_ptr<Ui::ChatTheme> _theme;
object_ptr<Ui::ScrollArea> _scroll; object_ptr<Ui::ScrollArea> _scroll;
QPointer<ListWidget> _inner; QPointer<ListWidget> _inner;
@ -280,9 +282,8 @@ private:
class ScheduledMemento : public Window::SectionMemento { class ScheduledMemento : public Window::SectionMemento {
public: public:
ScheduledMemento(not_null<History*> history) ScheduledMemento(not_null<History*> history);
: _history(history) { ScheduledMemento(not_null<Data::ForumTopic*> forumTopic);
}
object_ptr<Window::SectionWidget> createWidget( object_ptr<Window::SectionWidget> createWidget(
QWidget *parent, QWidget *parent,
@ -300,6 +301,7 @@ public:
private: private:
const not_null<History*> _history; const not_null<History*> _history;
const Data::ForumTopic *_forumTopic;
ListMemento _list; ListMemento _list;
}; };