mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/telegramdesktop/tdesktop
synced 2026-09-20 16:13:46 +08:00
[chat] Migrate theme choose support.
This commit is contained in:
@@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history_item_reply_markup.h"
|
||||
#include "iv/iv_rich_message_serializer.h"
|
||||
#include "iv/iv_rich_page.h"
|
||||
#include "ui/chat/choose_theme_controller.h"
|
||||
#include "ui/chat/pinned_bar.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/controls/swipe_handler.h"
|
||||
@@ -138,6 +139,27 @@ enum class SendPermission {
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<MsgId> ShowAtMsgIdFromPosition(
|
||||
not_null<History*> history,
|
||||
Data::MessagePosition position) {
|
||||
const auto migrated = history->migrateFrom();
|
||||
if (position == Data::UnreadMessagePosition) {
|
||||
return ShowAtUnreadMsgId;
|
||||
} else if (position == Data::MaxMessagePosition) {
|
||||
return ShowAtTheEndMsgId;
|
||||
}
|
||||
const auto fullId = position.fullId;
|
||||
if ((fullId.peer == history->peer->id)
|
||||
&& (IsServerMsgId(fullId.msg) || IsClientMsgId(fullId.msg))) {
|
||||
return fullId.msg;
|
||||
} else if (migrated
|
||||
&& (fullId.peer == migrated->peer->id)
|
||||
&& IsServerMsgId(fullId.msg)) {
|
||||
return -fullId.msg;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ChatMemento::ChatMemento(
|
||||
@@ -156,6 +178,9 @@ ChatMemento::ChatMemento(
|
||||
.date = TimeId(0),
|
||||
});
|
||||
}
|
||||
if (!_highlightId && !_id.repliesRootId && !_id.sublist) {
|
||||
setFromHistory(_id.history);
|
||||
}
|
||||
}
|
||||
|
||||
ChatMemento::ChatMemento(
|
||||
@@ -175,6 +200,37 @@ void ChatMemento::setFromTopic(not_null<Data::ForumTopic*> topic) {
|
||||
}
|
||||
}
|
||||
|
||||
void ChatMemento::setFromHistory(not_null<History*> history) {
|
||||
const auto migrated = history->migrateFrom();
|
||||
const auto showAtMsgId = history->showAtMsgId;
|
||||
if (showAtMsgId == ShowAtUnreadMsgId) {
|
||||
_list.setAroundPosition(Data::UnreadMessagePosition);
|
||||
} else if (showAtMsgId == ShowAtTheEndMsgId) {
|
||||
_list.setAroundPosition(Data::MaxMessagePosition);
|
||||
} else if (IsServerMsgId(showAtMsgId) || IsClientMsgId(showAtMsgId)) {
|
||||
_list.setAroundPosition({
|
||||
.fullId = FullMsgId(history->peer->id, showAtMsgId),
|
||||
.date = TimeId(0),
|
||||
});
|
||||
} else if (migrated && IsServerMsgId(-showAtMsgId)) {
|
||||
_list.setAroundPosition({
|
||||
.fullId = FullMsgId(migrated->peer->id, -showAtMsgId),
|
||||
.date = TimeId(0),
|
||||
});
|
||||
}
|
||||
if (const auto scrollTopItem = history->scrollTopItem) {
|
||||
_list.setScrollTopState(ListMemento::ScrollTopState{
|
||||
.item = scrollTopItem->data()->position(),
|
||||
.shift = history->scrollTopOffset,
|
||||
});
|
||||
} else if (migrated && migrated->scrollTopItem) {
|
||||
_list.setScrollTopState(ListMemento::ScrollTopState{
|
||||
.item = migrated->scrollTopItem->data()->position(),
|
||||
.shift = migrated->scrollTopOffset,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Data::ForumTopic *ChatMemento::topicForRemoveRequests() const {
|
||||
return _id.repliesRootId
|
||||
@@ -669,8 +725,23 @@ ChatWidget::ChatWidget(
|
||||
session().changes().historyUpdates(
|
||||
_history,
|
||||
HistoryUpdateFlag::BotKeyboard
|
||||
) | rpl::on_next([=] {
|
||||
updateBotKeyboard();
|
||||
| HistoryUpdateFlag::UnreadMentions
|
||||
| HistoryUpdateFlag::UnreadReactions
|
||||
| HistoryUpdateFlag::UnreadPollVotes
|
||||
| HistoryUpdateFlag::UnreadView
|
||||
) | rpl::on_next([=](const Data::HistoryUpdate &update) {
|
||||
const auto flags = update.flags;
|
||||
if (flags & HistoryUpdateFlag::BotKeyboard) {
|
||||
updateBotKeyboard();
|
||||
}
|
||||
if ((flags & HistoryUpdateFlag::UnreadMentions)
|
||||
|| (flags & HistoryUpdateFlag::UnreadReactions)
|
||||
|| (flags & HistoryUpdateFlag::UnreadPollVotes)) {
|
||||
_cornerButtons.updateUnreadThingsVisibility();
|
||||
}
|
||||
if (flags & HistoryUpdateFlag::UnreadView) {
|
||||
unreadCountUpdated();
|
||||
}
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
@@ -731,6 +802,7 @@ ChatWidget::~ChatWidget() {
|
||||
}
|
||||
_aboutView = nullptr;
|
||||
_suggestOptions = nullptr;
|
||||
_chooseTheme = nullptr;
|
||||
base::take(_sendAction);
|
||||
if (_repliesRootId) {
|
||||
controller()->sendingAnimation().clear();
|
||||
@@ -739,6 +811,11 @@ ChatWidget::~ChatWidget() {
|
||||
_subsectionTabsLifetime.destroy();
|
||||
controller()->saveSubsectionTabs(base::take(_subsectionTabs));
|
||||
}
|
||||
if (mode() == Mode::History) {
|
||||
auto state = ListMemento();
|
||||
_inner->saveState(&state);
|
||||
saveHistoryScrollState(state);
|
||||
}
|
||||
if (_topic) {
|
||||
if (_topic->creating()) {
|
||||
if (controller()->activeChatCurrent().topic() == _topic) {
|
||||
@@ -772,6 +849,9 @@ void ChatWidget::orderWidgets() {
|
||||
}
|
||||
_bottom->raise();
|
||||
_composeControls->raisePanels();
|
||||
if (_chooseTheme) {
|
||||
_chooseTheme->raise();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatWidget::setupRoot() {
|
||||
@@ -2274,6 +2354,49 @@ bool ChatWidget::clearChooseReportMessages() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatWidget::toggleChooseChatTheme(
|
||||
not_null<PeerData*> peer,
|
||||
std::optional<bool> show) {
|
||||
const auto update = [=] {
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
};
|
||||
if (peer != _peer) {
|
||||
return false;
|
||||
} else if (_chooseTheme) {
|
||||
if (isChoosingTheme() && !show.value_or(false)) {
|
||||
const auto was = base::take(_chooseTheme);
|
||||
if (Ui::InFocusChain(this)) {
|
||||
setInnerFocus();
|
||||
}
|
||||
update();
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
}
|
||||
return true;
|
||||
} else if (!show.value_or(true)) {
|
||||
return true;
|
||||
} else if (_composeControls->isRecording()) {
|
||||
controller()->showToast(tr::lng_chat_theme_cant_voice(tr::now));
|
||||
return true;
|
||||
}
|
||||
_chooseTheme = std::make_unique<Ui::ChooseThemeController>(
|
||||
this,
|
||||
controller(),
|
||||
peer);
|
||||
_chooseTheme->shouldBeShownValue(
|
||||
) | rpl::on_next(update, _chooseTheme->lifetime());
|
||||
orderWidgets();
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
update();
|
||||
return true;
|
||||
}
|
||||
|
||||
Ui::ChatTheme *ChatWidget::customChatTheme() const {
|
||||
return _theme.get();
|
||||
}
|
||||
|
||||
void ChatWidget::updateTopBarChooseForReport() {
|
||||
if (_chooseForReport && _chooseForReport->active) {
|
||||
_topBar->showChooseMessagesForReport(
|
||||
@@ -2306,9 +2429,22 @@ void ChatWidget::reportSelectedMessages() {
|
||||
void ChatWidget::updateControlsVisibility() {
|
||||
_bottom->updateControlsVisibility();
|
||||
const auto active = _bottom->isButtonActive();
|
||||
const auto choosingTheme = isChoosingTheme();
|
||||
const auto hasSublistReplacement = _bottom->hasOpenChatButton()
|
||||
|| _bottom->hasAboutHiddenAuthor();
|
||||
if (active) {
|
||||
if (choosingTheme) {
|
||||
_chooseTheme->show();
|
||||
setInnerFocus();
|
||||
} else if (_chooseTheme) {
|
||||
_chooseTheme->hide();
|
||||
}
|
||||
if (choosingTheme && _kbScroll) {
|
||||
_kbScroll->hide();
|
||||
_kbShown = false;
|
||||
setKeyboardReplyTo(nullptr);
|
||||
hideKeyboardReplyToExternal();
|
||||
}
|
||||
if (active || choosingTheme) {
|
||||
if (!hasSublistReplacement) {
|
||||
_composeControls->hide();
|
||||
}
|
||||
@@ -3030,6 +3166,8 @@ void ChatWidget::doSetInnerFocus() {
|
||||
&& _inner->getSelectedText().rich.text.isEmpty()
|
||||
&& _inner->getSelectedItems().empty()) {
|
||||
_composeSearch->setInnerFocus();
|
||||
} else if (isChoosingTheme()) {
|
||||
_chooseTheme->setFocus();
|
||||
} else if (!_inner->getSelectedText().rich.text.isEmpty()
|
||||
|| !_inner->getSelectedItems().empty()
|
||||
|| !_composeControls->focus()) {
|
||||
@@ -3048,9 +3186,6 @@ bool ChatWidget::showInternal(
|
||||
refreshSuggestFromDraft();
|
||||
} else {
|
||||
restoreState(logMemento);
|
||||
if (!logMemento->highlightId()) {
|
||||
showAtPosition(Data::UnreadMessagePosition);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -3191,10 +3326,62 @@ void ChatWidget::replyToMessage(FullReplyTo id) {
|
||||
refreshTopBarActiveChat();
|
||||
}
|
||||
|
||||
void ChatWidget::saveHistoryScrollState(const ListMemento &state) {
|
||||
if (mode() != Mode::History || !_inner) {
|
||||
return;
|
||||
}
|
||||
const auto migrated = _history->migrateFrom();
|
||||
const auto aroundPosition = state.aroundPosition();
|
||||
const auto scrollTopState = state.scrollTopState();
|
||||
const auto useAroundPosition = scrollTopState.item
|
||||
|| (aroundPosition == Data::UnreadMessagePosition)
|
||||
|| (aroundPosition == Data::MaxMessagePosition);
|
||||
_history->showAtMsgId = (useAroundPosition
|
||||
? ShowAtMsgIdFromPosition(_history, aroundPosition)
|
||||
: std::nullopt).value_or((_lastShownAt
|
||||
&& migrated
|
||||
&& (_lastShownAt.peer == migrated->peer->id)
|
||||
&& IsServerMsgId(_lastShownAt.msg))
|
||||
? -_lastShownAt.msg
|
||||
: _lastShownAt
|
||||
? _lastShownAt.msg
|
||||
: ShowAtUnreadMsgId);
|
||||
const auto atBottom = (_scroll->scrollTop() >= _scroll->scrollTopMax())
|
||||
&& _inner->loadedAtBottomKnown()
|
||||
&& _inner->loadedAtBottom();
|
||||
if (atBottom) {
|
||||
_history->forgetScrollState();
|
||||
if (migrated) {
|
||||
migrated->forgetScrollState();
|
||||
}
|
||||
} else {
|
||||
const auto useMigrated = migrated
|
||||
&& (scrollTopState.item.fullId.peer == migrated->peer->id);
|
||||
if (useMigrated) {
|
||||
_history->forgetScrollState();
|
||||
if (const auto item = session().data().message(scrollTopState.item.fullId)) {
|
||||
migrated->scrollTopItem = item->mainView();
|
||||
migrated->scrollTopOffset = scrollTopState.shift;
|
||||
if (!migrated->scrollTopItem) {
|
||||
migrated->forgetScrollState();
|
||||
}
|
||||
} else {
|
||||
migrated->forgetScrollState();
|
||||
}
|
||||
} else {
|
||||
_history->countScrollState(_scroll->scrollTop());
|
||||
if (migrated) {
|
||||
migrated->forgetScrollState();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChatWidget::saveState(not_null<ChatMemento*> memento) {
|
||||
memento->setReplies(_replies);
|
||||
memento->setReplyReturns(_cornerButtons.replyReturns());
|
||||
_inner->saveState(memento->list());
|
||||
saveHistoryScrollState(*memento->list());
|
||||
}
|
||||
|
||||
void ChatWidget::refreshReplies() {
|
||||
@@ -3299,7 +3486,15 @@ void ChatWidget::subscribeToSublist() {
|
||||
}
|
||||
|
||||
void ChatWidget::unreadCountUpdated() {
|
||||
if (_sublist && _sublist->unreadMark()) {
|
||||
if (mode() == Mode::History) {
|
||||
const auto hideCounter = _history->isForum()
|
||||
|| !_history->trackUnreadMessages();
|
||||
refreshUnreadCountBadge(hideCounter
|
||||
? 0
|
||||
: _history->amMonoforumAdmin()
|
||||
? _history->chatListUnreadState().messages
|
||||
: _history->chatListBadgesState().unreadCounter);
|
||||
} else if (_sublist && _sublist->unreadMark()) {
|
||||
crl::on_main(this, [=] {
|
||||
const auto guard = base::make_weak(this);
|
||||
controller()->showPeerHistory(_sublist->owningHistory());
|
||||
@@ -3362,6 +3557,9 @@ void ChatWidget::restoreState(not_null<ChatMemento*> memento) {
|
||||
activateChooseForReport();
|
||||
}
|
||||
updateBotKeyboard();
|
||||
if (mode() == Mode::History) {
|
||||
unreadCountUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatWidget::resizeEvent(QResizeEvent *e) {
|
||||
@@ -3413,36 +3611,40 @@ void ChatWidget::updateControlsGeometry() {
|
||||
bottom -= bottomHeight;
|
||||
}
|
||||
bottom -= tabsBottomSkip;
|
||||
if (_suggestOptions) {
|
||||
bottom -= st::historyReplyHeight;
|
||||
}
|
||||
const auto maxFieldHeight = computeMaxFieldHeightForKeyboard(
|
||||
top,
|
||||
bottom);
|
||||
if (_kbScroll && keyboardRowsVisible() && _keyboard) {
|
||||
_keyboard->resizeToWidth(innerWidth, maxFieldHeight);
|
||||
const auto keyboardReserve = std::min(
|
||||
_keyboard->height(),
|
||||
maxFieldHeight - (maxFieldHeight / 2));
|
||||
_composeControls->setFieldMaxHeight(
|
||||
maxFieldHeight - keyboardReserve);
|
||||
const auto maxKbHeight = keyboardReserve;
|
||||
_keyboard->resizeToWidth(innerWidth, maxKbHeight);
|
||||
const auto kbHeight = std::min(
|
||||
_keyboard->height(),
|
||||
maxKbHeight);
|
||||
_kbScroll->setGeometry(
|
||||
tabsLeftSkip,
|
||||
bottom - kbHeight,
|
||||
innerWidth,
|
||||
kbHeight);
|
||||
bottom -= kbHeight;
|
||||
if (isChoosingTheme()) {
|
||||
bottom -= _chooseTheme->height();
|
||||
} else {
|
||||
_composeControls->setFieldMaxHeight(
|
||||
st::historyComposeFieldMaxHeight);
|
||||
}
|
||||
if (!bottomHeight) {
|
||||
bottom -= _composeControls->heightCurrent();
|
||||
if (_suggestOptions) {
|
||||
bottom -= st::historyReplyHeight;
|
||||
}
|
||||
const auto maxFieldHeight = computeMaxFieldHeightForKeyboard(
|
||||
top,
|
||||
bottom);
|
||||
if (_kbScroll && keyboardRowsVisible() && _keyboard) {
|
||||
_keyboard->resizeToWidth(innerWidth, maxFieldHeight);
|
||||
const auto keyboardReserve = std::min(
|
||||
_keyboard->height(),
|
||||
maxFieldHeight - (maxFieldHeight / 2));
|
||||
_composeControls->setFieldMaxHeight(
|
||||
maxFieldHeight - keyboardReserve);
|
||||
const auto maxKbHeight = keyboardReserve;
|
||||
_keyboard->resizeToWidth(innerWidth, maxKbHeight);
|
||||
const auto kbHeight = std::min(
|
||||
_keyboard->height(),
|
||||
maxKbHeight);
|
||||
_kbScroll->setGeometry(
|
||||
tabsLeftSkip,
|
||||
bottom - kbHeight,
|
||||
innerWidth,
|
||||
kbHeight);
|
||||
bottom -= kbHeight;
|
||||
} else {
|
||||
_composeControls->setFieldMaxHeight(
|
||||
st::historyComposeFieldMaxHeight);
|
||||
}
|
||||
if (!bottomHeight) {
|
||||
bottom -= _composeControls->heightCurrent();
|
||||
}
|
||||
}
|
||||
const auto composeTop = bottom;
|
||||
|
||||
@@ -3525,6 +3727,10 @@ bool ChatWidget::emptyShown() const {
|
||||
|| (_topic->lastKnownServerMessageId() == _repliesRootId));
|
||||
}
|
||||
|
||||
bool ChatWidget::isChoosingTheme() const {
|
||||
return _chooseTheme && _chooseTheme->shouldBeShown();
|
||||
}
|
||||
|
||||
void ChatWidget::onScroll() {
|
||||
if (_skipScrollEvent) {
|
||||
return;
|
||||
@@ -3542,6 +3748,11 @@ void ChatWidget::updateInnerVisibleArea() {
|
||||
_topControls->updatePinnedViewer();
|
||||
_cornerButtons.updateJumpDownVisibility();
|
||||
_cornerButtons.updateUnreadThingsVisibility();
|
||||
if (mode() == Mode::History) {
|
||||
auto state = ListMemento();
|
||||
_inner->saveState(&state);
|
||||
saveHistoryScrollState(state);
|
||||
}
|
||||
if (_lastScrollTop != scrollTop) {
|
||||
if (!_synteticScrollEvent) {
|
||||
_topControls->checkLastPinnedClickedIdReset(
|
||||
@@ -3682,6 +3893,10 @@ void ChatWidget::listCancelRequest() {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (isChoosingTheme()) {
|
||||
toggleChooseChatTheme(_peer, false);
|
||||
return;
|
||||
}
|
||||
if (_inner && !_inner->getSelectedItems().empty()) {
|
||||
clearSelected();
|
||||
return;
|
||||
@@ -4216,6 +4431,16 @@ void ChatWidget::updateBotKeyboard(History *h, bool force) {
|
||||
const auto forceReply = _keyboard->forceReply() && !realReplySource;
|
||||
const auto canShow = _canSendMessages
|
||||
&& !_bottom->isButtonActive();
|
||||
if (isChoosingTheme()) {
|
||||
_kbScroll->hide();
|
||||
_kbShown = false;
|
||||
setKeyboardReplyTo(nullptr);
|
||||
hideKeyboardReplyToExternal();
|
||||
updateKeyboardUiState(hasMarkup, true);
|
||||
updateControlsGeometry();
|
||||
update();
|
||||
return;
|
||||
}
|
||||
const auto rowsFromRealReply = realReplySource && hasMarkup;
|
||||
const auto suppressKeyboardUi = editing || (reply && !rowsFromRealReply);
|
||||
const auto shouldShowRows = canShow
|
||||
|
||||
@@ -43,6 +43,7 @@ class ScrollArea;
|
||||
struct PreparedList;
|
||||
struct PreparedBundle;
|
||||
class SendFilesWay;
|
||||
class ChooseThemeController;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Profile {
|
||||
@@ -149,6 +150,10 @@ public:
|
||||
Data::ReportInput &&reportInput,
|
||||
Fn<void(std::vector<MsgId>)> &&done) override;
|
||||
bool clearChooseReportMessages() override;
|
||||
bool toggleChooseChatTheme(
|
||||
not_null<PeerData*> peer,
|
||||
std::optional<bool> show = std::nullopt) override;
|
||||
[[nodiscard]] Ui::ChatTheme *customChatTheme() const override;
|
||||
|
||||
void setInternalState(
|
||||
const QRect &geometry,
|
||||
@@ -291,6 +296,7 @@ private:
|
||||
void updateInnerVisibleArea();
|
||||
void updateControlsGeometry();
|
||||
void updateAdaptiveLayout();
|
||||
void saveHistoryScrollState(const ListMemento &state);
|
||||
void saveState(not_null<ChatMemento*> memento);
|
||||
void restoreState(not_null<ChatMemento*> memento);
|
||||
void setReplies(std::shared_ptr<Data::RepliesList> replies);
|
||||
@@ -474,6 +480,7 @@ private:
|
||||
void toggleMuteUnmute();
|
||||
void reportSelectedMessages();
|
||||
void updateTopBarChooseForReport();
|
||||
[[nodiscard]] bool isChoosingTheme() const;
|
||||
[[nodiscard]] bool emptyShown() const;
|
||||
[[nodiscard]] bool showSlowmodeError();
|
||||
|
||||
@@ -500,6 +507,7 @@ private:
|
||||
bool active = false;
|
||||
};
|
||||
std::unique_ptr<ChooseMessagesForReport> _chooseForReport;
|
||||
std::unique_ptr<Ui::ChooseThemeController> _chooseTheme;
|
||||
|
||||
Data::SavedSublist *_sublist = nullptr;
|
||||
PeerId _monoforumPeerId;
|
||||
@@ -602,6 +610,7 @@ public:
|
||||
}
|
||||
|
||||
void setFromTopic(not_null<Data::ForumTopic*> topic);
|
||||
void setFromHistory(not_null<History*> history);
|
||||
|
||||
void setReplyReturns(const QVector<FullMsgId> &list) {
|
||||
_replyReturns = list;
|
||||
|
||||
@@ -1363,7 +1363,9 @@ void MainWidget::clearChooseReportMessages() {
|
||||
void MainWidget::toggleChooseChatTheme(
|
||||
not_null<PeerData*> peer,
|
||||
std::optional<bool> show) {
|
||||
_history->toggleChooseChatTheme(peer, show);
|
||||
if (!_mainSection || !_mainSection->toggleChooseChatTheme(peer, show)) {
|
||||
_history->toggleChooseChatTheme(peer, show);
|
||||
}
|
||||
}
|
||||
|
||||
bool MainWidget::showHistoryInDifferentWindow(
|
||||
@@ -1713,6 +1715,11 @@ PeerData *MainWidget::peer() const {
|
||||
}
|
||||
|
||||
Ui::ChatTheme *MainWidget::customChatTheme() const {
|
||||
if (_mainSection) {
|
||||
if (const auto custom = _mainSection->customChatTheme()) {
|
||||
return custom;
|
||||
}
|
||||
}
|
||||
return _history->customChatTheme();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/object_ptr.h"
|
||||
#include "window/window_section_common.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
class PeerData;
|
||||
|
||||
namespace ChatHelpers {
|
||||
@@ -176,6 +178,14 @@ public:
|
||||
virtual bool clearChooseReportMessages() {
|
||||
return false;
|
||||
}
|
||||
virtual bool toggleChooseChatTheme(
|
||||
not_null<PeerData*> peer,
|
||||
std::optional<bool> show = std::nullopt) {
|
||||
return false;
|
||||
}
|
||||
[[nodiscard]] virtual Ui::ChatTheme *customChatTheme() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual bool preventsClose(
|
||||
Fn<void()> &&continueCallback) const {
|
||||
|
||||
Reference in New Issue
Block a user