diff --git a/Telegram/Resources/animations/edit_peers/topics.tgs b/Telegram/Resources/animations/edit_peers/topics.tgs
new file mode 100644
index 0000000000..a5552a4acb
Binary files /dev/null and b/Telegram/Resources/animations/edit_peers/topics.tgs differ
diff --git a/Telegram/Resources/animations/edit_peers/topics_list.tgs b/Telegram/Resources/animations/edit_peers/topics_list.tgs
new file mode 100644
index 0000000000..d85bf7ff85
Binary files /dev/null and b/Telegram/Resources/animations/edit_peers/topics_list.tgs differ
diff --git a/Telegram/Resources/animations/edit_peers/topics_tabs.tgs b/Telegram/Resources/animations/edit_peers/topics_tabs.tgs
new file mode 100644
index 0000000000..3a240b4c62
Binary files /dev/null and b/Telegram/Resources/animations/edit_peers/topics_tabs.tgs differ
diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index 39db6ae517..2cb115b74b 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -3216,6 +3216,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_feature_transcribe" = "Voice-to-Text Conversion";
"lng_feature_autotranslate" = "Autotranslation of Messages";
+"lng_edit_topics_enable" = "Enable Topics";
+"lng_edit_topics_about" = "The group chat will be divided into topics created by admins or users.";
+"lng_edit_topics_layout" = "Topics layout";
+"lng_edit_topics_layout_about" = "Choose how topics appear for all members.";
+"lng_edit_topics_tabs" = "Tabs";
+"lng_edit_topics_list" = "List";
+
"lng_giveaway_new_title" = "Boosts via Gifts";
"lng_giveaway_new_about" = "Get more boosts for your channel by gifting Premium to your subscribers.";
"lng_giveaway_new_about_group" = "Get more boosts for your group by gifting Premium to your members.";
diff --git a/Telegram/Resources/qrc/telegram/animations.qrc b/Telegram/Resources/qrc/telegram/animations.qrc
index ae94041686..09702ee5d0 100644
--- a/Telegram/Resources/qrc/telegram/animations.qrc
+++ b/Telegram/Resources/qrc/telegram/animations.qrc
@@ -33,6 +33,9 @@
../../animations/hello_status.tgs
../../animations/starref_link.tgs
../../animations/media_forbidden.tgs
+ ../../animations/edit_peers/topics.tgs
+ ../../animations/edit_peers/topics_tabs.tgs
+ ../../animations/edit_peers/topics_list.tgs
../../animations/dice/dice_idle.tgs
../../animations/dice/dart_idle.tgs
diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
index 7cfffe5c15..c53412162a 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
@@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peers/edit_peer_requests_box.h"
#include "boxes/peers/edit_peer_reactions.h"
#include "boxes/peers/replace_boost_box.h"
+#include "boxes/peers/toggle_topics_box.h"
#include "boxes/peers/verify_peers_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/edit_privacy_box.h" // EditDirectMessagesPriceBox
@@ -377,6 +378,7 @@ private:
std::optional description;
std::optional hiddenPreHistory;
std::optional forum;
+ std::optional forumTabs;
std::optional autotranslate;
std::optional signatures;
std::optional signatureProfiles;
@@ -481,6 +483,7 @@ private:
std::optional _historyVisibilitySavedValue;
std::optional _typeDataSavedValue;
std::optional _forumSavedValue;
+ std::optional _forumTabsSavedValue;
std::optional _autotranslateSavedValue;
std::optional _signaturesSavedValue;
std::optional _signatureProfilesSavedValue;
@@ -1104,21 +1107,30 @@ void Controller::fillDirectMessagesButton() {
void Controller::fillForumButton() {
Expects(_controls.buttonsLayout != nullptr);
+ _forumSavedValue = _peer->isForum();
+ _forumTabsSavedValue = !_peer->isChannel()
+ || !_peer->isForum()
+ || _peer->asChannel()->useSubsectionTabs();
+
+ const auto changes = std::make_shared>();
+ const auto label = [=] {
+ return !*_forumSavedValue
+ ? tr::lng_manage_monoforum_off(tr::now)
+ : *_forumTabsSavedValue
+ ? tr::lng_edit_topics_tabs(tr::now)
+ : tr::lng_edit_topics_list(tr::now);
+ };
const auto button = _controls.forumToggle = _controls.buttonsLayout->add(
EditPeerInfoBox::CreateButton(
_controls.buttonsLayout,
tr::lng_forum_topics_switch(),
- rpl::single(QString()),
+ changes->events_starting_with({}) | rpl::map(label),
[] {},
st::manageGroupTopicsButton,
{ &st::menuIconTopics }));
- const auto unlocks = std::make_shared>();
- button->toggleOn(
- rpl::single(_peer->isForum()) | rpl::then(unlocks->events())
- )->toggledValue(
- ) | rpl::start_with_next([=](bool toggled) {
- if (_controls.forumToggleLocked && toggled) {
- unlocks->fire(false);
+
+ button->setClickedCallback(crl::guard(this, [=] {
+ if (!*_forumSavedValue && _controls.forumToggleLocked) {
if (_discussionLinkSavedValue && *_discussionLinkSavedValue) {
ShowForumForDiscussionError(_navigation);
} else {
@@ -1130,13 +1142,21 @@ void Controller::fillForumButton() {
Ui::Text::RichLangValue));
}
} else {
- _forumSavedValue = toggled;
- if (toggled) {
- _savingData.hiddenPreHistory = false;
- }
- refreshHistoryVisibility();
+ _navigation->uiShow()->show(Box(
+ Ui::ToggleTopicsBox,
+ *_forumSavedValue,
+ *_forumTabsSavedValue,
+ crl::guard(this, [=](bool topics, bool topicsTabs) {
+ _forumSavedValue = topics;
+ _forumTabsSavedValue = !topics || topicsTabs;
+ if (topics) {
+ _savingData.hiddenPreHistory = false;
+ }
+ changes->fire({});
+ refreshHistoryVisibility();
+ })));
}
- }, _controls.buttonsLayout->lifetime());
+ }));
refreshForumToggleLocked();
}
@@ -2143,6 +2163,7 @@ bool Controller::validateForum(Saving &to) const {
return true;
}
to.forum = _forumSavedValue;
+ to.forumTabs = _forumTabsSavedValue;
return true;
}
@@ -2589,8 +2610,13 @@ void Controller::togglePreHistoryHidden(
void Controller::saveForum() {
const auto channel = _peer->asChannel();
+ const auto nowForum = _peer->isForum();
+ const auto nowForumTabs = !channel
+ || !nowForum
+ || channel->useSubsectionTabs();
if (!_savingData.forum
- || *_savingData.forum == _peer->isForum()) {
+ || (*_savingData.forum == nowForum
+ && *_savingData.forumTabs == nowForumTabs)) {
return continueSave();
} else if (!channel) {
const auto saveForChannel = [=](not_null channel) {
@@ -2608,7 +2634,7 @@ void Controller::saveForum() {
_api.request(MTPchannels_ToggleForum(
channel->inputChannel,
MTP_bool(*_savingData.forum),
- MTP_bool(channel->flags() & ChannelDataFlag::ForumTabs)
+ MTP_bool(*_savingData.forum && *_savingData.forumTabs)
)).done([=](const MTPUpdates &result) {
const auto weak = base::make_weak(this);
channel->session().api().applyUpdates(result);
diff --git a/Telegram/SourceFiles/boxes/peers/toggle_topics_box.cpp b/Telegram/SourceFiles/boxes/peers/toggle_topics_box.cpp
new file mode 100644
index 0000000000..b2fed66b25
--- /dev/null
+++ b/Telegram/SourceFiles/boxes/peers/toggle_topics_box.cpp
@@ -0,0 +1,226 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#include "boxes/peers/toggle_topics_box.h"
+
+#include "lang/lang_keys.h"
+#include "lottie/lottie_icon.h"
+#include "settings/settings_common.h"
+#include "ui/effects/ripple_animation.h"
+#include "ui/layers/generic_box.h"
+#include "ui/text/text_utilities.h"
+#include "ui/widgets/checkbox.h"
+#include "ui/widgets/labels.h"
+#include "ui/wrap/slide_wrap.h"
+#include "ui/wrap/vertical_layout.h"
+#include "ui/painter.h"
+#include "ui/vertical_list.h"
+#include "styles/style_info.h"
+#include "styles/style_layers.h"
+#include "styles/style_settings.h"
+
+namespace Ui {
+namespace {
+
+enum class LayoutType {
+ Tabs,
+ List
+};
+
+class LayoutButton final : public Ui::RippleButton {
+public:
+ LayoutButton(
+ QWidget *parent,
+ LayoutType type,
+ std::shared_ptr> group);
+
+private:
+ void paintEvent(QPaintEvent *e) override;
+
+ QImage prepareRippleMask() const override;
+
+ Ui::FlatLabel _text;
+ Ui::Animations::Simple _activeAnimation;
+ bool _active = false;
+
+};
+
+LayoutButton::LayoutButton(
+ QWidget *parent,
+ LayoutType type,
+ std::shared_ptr> group)
+: RippleButton(parent, st::defaultRippleAnimationBgOver)
+, _text(this, st::topicsLayoutButtonLabel)
+, _active(group->current() == type) {
+ _text.setText(type == LayoutType::Tabs
+ ? tr::lng_edit_topics_tabs(tr::now)
+ : tr::lng_edit_topics_list(tr::now));
+ const auto iconColorOverride = [=] {
+ return anim::color(
+ st::windowSubTextFg,
+ st::windowActiveTextFg,
+ _activeAnimation.value(_active ? 1. : 0.));
+ };
+ const auto iconSize = st::topicsLayoutButtonIconSize;
+ auto [iconWidget, iconAnimate] = Settings::CreateLottieIcon(
+ this,
+ {
+ .name = (type == LayoutType::Tabs
+ ? u"topics_tabs"_q
+ : u"topics_list"_q),
+ .color = &st::windowSubTextFg,
+ .sizeOverride = { iconSize, iconSize },
+ .colorizeUsingAlpha = true,
+ },
+ st::topicsLayoutButtonIconPadding,
+ iconColorOverride);
+ const auto icon = iconWidget.release();
+ setClickedCallback([=] {
+ group->setValue(type);
+ });
+ group->value() | rpl::start_with_next([=](LayoutType value) {
+ const auto active = (value == type);
+ _text.setTextColorOverride(active
+ ? st::windowFgActive->c
+ : std::optional());
+
+ if (_active == active) {
+ return;
+ }
+ _active = active;
+ _text.update();
+ if (_active) {
+ iconAnimate(anim::repeat::once);
+ }
+ _activeAnimation.start([=] {
+ icon->update();
+ }, _active ? 0. : 1., _active ? 0. : 1., st::fadeWrapDuration);
+ }, lifetime());
+
+ _text.paintRequest() | rpl::start_with_next([=](QRect clip) {
+ if (_active) {
+ auto p = QPainter(&_text);
+ auto hq = PainterHighQualityEnabler(p);
+ const auto radius = _text.height() / 2.;
+ p.setPen(Qt::NoPen);
+ p.setBrush(st::windowBgActive);
+ p.drawRoundedRect(_text.rect(), radius, radius);
+ }
+ }, _text.lifetime());
+
+ const auto padding = st::topicsLayoutButtonPadding;
+ const auto skip = st::topicsLayoutButtonSkip;
+ const auto text = _text.height();
+
+ resize(
+ padding.left() + icon->width() + padding.right(),
+ padding.top() + icon->height() + skip + text + padding.bottom());
+ icon->move(padding.left(), padding.top());
+ _text.move(
+ (width() - _text.width()) / 2,
+ padding.top() + icon->height() + skip);
+}
+
+void LayoutButton::paintEvent(QPaintEvent *e) {
+ auto p = QPainter(this);
+ const auto rippleBg = anim::color(
+ st::windowBgOver,
+ st::lightButtonBgOver,
+ _activeAnimation.value(_active ? 1. : 0.));
+ paintRipple(p, QPoint(), &rippleBg);
+}
+
+QImage LayoutButton::prepareRippleMask() const {
+ return Ui::RippleAnimation::RoundRectMask(size(), st::boxRadius);
+}
+
+} // namespace
+
+void ToggleTopicsBox(
+ not_null box,
+ bool enabled,
+ bool tabs,
+ Fn callback) {
+ box->setTitle(tr::lng_forum_topics_switch());
+ box->setWidth(st::boxWideWidth);
+
+ const auto container = box->verticalLayout();
+
+ Settings::AddDividerTextWithLottie(container, {
+ .lottie = u"topics"_q,
+ .lottieSize = st::settingsFilterIconSize,
+ .lottieMargins = st::settingsFilterIconPadding,
+ .showFinished = box->showFinishes(),
+ .about = tr::lng_edit_topics_about(
+ Ui::Text::RichLangValue
+ ),
+ .aboutMargins = st::settingsFilterDividerLabelPadding,
+ });
+
+ Ui::AddSkip(container);
+
+ const auto toggle = container->add(
+ object_ptr(
+ container,
+ tr::lng_edit_topics_enable(),
+ st::settingsButtonNoIcon));
+ toggle->toggleOn(rpl::single(enabled));
+
+ const auto group = std::make_shared>(tabs
+ ? LayoutType::Tabs
+ : LayoutType::List);
+
+ const auto layoutWrap = container->add(
+ object_ptr>(
+ container,
+ object_ptr(container)));
+ const auto layout = layoutWrap->entity();
+
+ Ui::AddSubsectionTitle(layout, tr::lng_edit_topics_layout());
+ const auto buttons = layout->add(
+ object_ptr(layout),
+ QMargins(0, 0, 0, st::defaultVerticalListSkip * 2));
+
+ const auto tabsButton = Ui::CreateChild(
+ buttons,
+ LayoutType::Tabs,
+ group);
+ const auto listButton = Ui::CreateChild(
+ buttons,
+ LayoutType::List,
+ group);
+
+ buttons->resize(container->width(), tabsButton->height());
+ buttons->widthValue() | rpl::start_with_next([=](int outer) {
+ const auto skip = st::boxRowPadding.left() - st::boxRadius;
+ tabsButton->moveToLeft(skip, 0, outer);
+ listButton->moveToRight(skip, 0, outer);
+ }, buttons->lifetime());
+
+ Ui::AddDividerText(
+ layout,
+ tr::lng_edit_topics_layout_about(Ui::Text::RichLangValue));
+
+ layoutWrap->toggle(enabled, anim::type::instant);
+ toggle->toggledChanges(
+ ) | rpl::start_with_next([=](bool checked) {
+ layoutWrap->toggle(checked, anim::type::normal);
+ }, layoutWrap->lifetime());
+
+ box->addButton(tr::lng_settings_save(), [=] {
+ const auto enabledValue = toggle->toggled();
+ const auto tabsValue = (group->current() == LayoutType::Tabs);
+ callback(enabledValue, tabsValue);
+ box->closeBox();
+ });
+
+ box->addButton(tr::lng_cancel(), [=] {
+ box->closeBox();
+ });
+}
+
+} // namespace Ui
diff --git a/Telegram/SourceFiles/boxes/peers/toggle_topics_box.h b/Telegram/SourceFiles/boxes/peers/toggle_topics_box.h
new file mode 100644
index 0000000000..0bd4ad3685
--- /dev/null
+++ b/Telegram/SourceFiles/boxes/peers/toggle_topics_box.h
@@ -0,0 +1,20 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#pragma once
+
+#include "ui/layers/generic_box.h"
+
+namespace Ui {
+
+void ToggleTopicsBox(
+ not_null box,
+ bool enabled,
+ bool tabs,
+ Fn callback);
+
+} // namespace Ui
diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp
index 6684631180..43182a6ad6 100644
--- a/Telegram/SourceFiles/data/data_channel.cpp
+++ b/Telegram/SourceFiles/data/data_channel.cpp
@@ -410,7 +410,7 @@ void ChannelData::setPendingRequestsCount(
bool ChannelData::useSubsectionTabs() const {
return isForum()
- && ((flags() & ChannelDataFlag::ForumTabs) || true); AssertIsDebug();
+ && (flags() & ChannelDataFlag::ForumTabs);
}
ChatRestrictionsInfo ChannelData::KickedRestrictedRights(
diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp
index ec41e8ee17..f9a3127f56 100644
--- a/Telegram/SourceFiles/data/data_session.cpp
+++ b/Telegram/SourceFiles/data/data_session.cpp
@@ -979,12 +979,13 @@ not_null Session::processChat(const MTPChat &data) {
| Flag::CallNotEmpty
| Flag::Forbidden
| (!minimal
- ? (Flag::Left | Flag::Creator | Flag::ForumTabs)
+ ? (Flag::Left | Flag::Creator)
: Flag())
| Flag::NoForwards
| Flag::JoinToWrite
| Flag::RequestToJoin
| Flag::Forum
+ | Flag::ForumTabs
| ((!minimal && !data.is_stories_hidden_min())
? Flag::StoriesHidden
: Flag())
@@ -1016,8 +1017,7 @@ not_null Session::processChat(const MTPChat &data) {
: Flag())
| (!minimal
? ((data.is_left() ? Flag::Left : Flag())
- | (data.is_creator() ? Flag::Creator : Flag())
- | (data.is_forum_tabs() ? Flag::ForumTabs : Flag()))
+ | (data.is_creator() ? Flag::Creator : Flag()))
: Flag())
| (data.is_noforwards() ? Flag::NoForwards : Flag())
| (data.is_join_to_send() ? Flag::JoinToWrite : Flag())
@@ -1025,6 +1025,7 @@ not_null Session::processChat(const MTPChat &data) {
| ((data.is_forum() && data.is_megagroup())
? Flag::Forum
: Flag())
+ | (data.is_forum_tabs() ? Flag::ForumTabs : Flag())
| ((!minimal
&& !data.is_stories_hidden_min()
&& data.is_stories_hidden())
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index 8a88024743..0630c14547 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -2623,6 +2623,7 @@ void HistoryWidget::showHistory(
channel->flagsValue(
) | rpl::start_with_next([=] {
refreshJoinChannelText();
+ validateSubsectionTabs();
}, _list->lifetime());
} else {
refreshJoinChannelText();
@@ -8245,8 +8246,18 @@ void HistoryWidget::showPremiumToast(not_null document) {
void HistoryWidget::validateSubsectionTabs() {
if (!_history || !HistoryView::SubsectionTabs::UsedFor(_history)) {
- _subsectionTabsLifetime.destroy();
- _subsectionTabs = nullptr;
+ if (_subsectionTabs) {
+ _subsectionTabsLifetime.destroy();
+ _subsectionTabs = nullptr;
+ updateControlsGeometry();
+ if (const auto forum = _history->asForum()) {
+ controller()->showForum(forum, {
+ Window::SectionShow::Way::Backward,
+ anim::type::normal,
+ anim::activation::background,
+ });
+ }
+ }
return;
} else if (_subsectionTabs) {
return;
@@ -8259,6 +8270,7 @@ void HistoryWidget::validateSubsectionTabs() {
_history);
}
_subsectionTabs->removeRequests() | rpl::start_with_next([=] {
+ _subsectionTabsLifetime.destroy();
_subsectionTabs = nullptr;
updateControlsGeometry();
}, _subsectionTabsLifetime);
diff --git a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp
index 6829d8a432..70e7d71042 100644
--- a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp
@@ -928,6 +928,7 @@ void ChatWidget::setupComposeControls() {
channel->flagsValue()
) | rpl::start_with_next([=] {
refreshJoinGroupButton();
+ validateSubsectionTabs();
}, lifetime());
} else {
refreshJoinGroupButton();
@@ -1522,8 +1523,18 @@ void ChatWidget::edit(
void ChatWidget::validateSubsectionTabs() {
if (!HistoryView::SubsectionTabs::UsedFor(_history)) {
- _subsectionTabsLifetime.destroy();
- _subsectionTabs = nullptr;
+ if (_subsectionTabs) {
+ _subsectionTabsLifetime.destroy();
+ _subsectionTabs = nullptr;
+ updateControlsGeometry();
+ if (const auto forum = _history->asForum()) {
+ controller()->showForum(forum, {
+ Window::SectionShow::Way::Backward,
+ anim::type::normal,
+ anim::activation::background,
+ });
+ }
+ }
return;
} else if (_subsectionTabs) {
return;
@@ -1537,6 +1548,7 @@ void ChatWidget::validateSubsectionTabs() {
thread);
}
_subsectionTabs->removeRequests() | rpl::start_with_next([=] {
+ _subsectionTabsLifetime.destroy();
_subsectionTabs = nullptr;
updateControlsGeometry();
}, _subsectionTabsLifetime);
diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style
index 3097de7a26..a9446d9c08 100644
--- a/Telegram/SourceFiles/info/info.style
+++ b/Telegram/SourceFiles/info/info.style
@@ -1177,3 +1177,13 @@ infoGiftTooltip: ImportantTooltip(defaultImportantTooltip) {
padding: margins(8px, 2px, 8px, 3px);
}
infoGiftTooltipFont: font(11px semibold);
+
+topicsLayoutButtonLabel: FlatLabel(defaultFlatLabel) {
+ style: semiboldTextStyle;
+ margin: margins(10px, 4px, 10px, 4px);
+ textFg: windowSubTextFg;
+}
+topicsLayoutButtonIconPadding: margins(4px, 0px, 4px, 0px);
+topicsLayoutButtonIconSize: 140px;
+topicsLayoutButtonPadding: margins(4px, 0px, 4px, 12px);
+topicsLayoutButtonSkip: 0px;
diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp
index 5412b5886b..f02f2f07c6 100644
--- a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp
+++ b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp
@@ -957,4 +957,3 @@ void InnerWidget::showFinished() {
}
} // namespace Info::Statistics
-
diff --git a/Telegram/SourceFiles/mtproto/scheme/api.tl b/Telegram/SourceFiles/mtproto/scheme/api.tl
index 1955440642..fc937d352b 100644
--- a/Telegram/SourceFiles/mtproto/scheme/api.tl
+++ b/Telegram/SourceFiles/mtproto/scheme/api.tl
@@ -2506,6 +2506,7 @@ channels.restrictSponsoredMessages#9ae91519 channel:InputChannel restricted:Bool
channels.searchPosts#d19f987b hashtag:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates;
channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates;
+channels.getMessageAuthor#ece2a0e6 channel:InputChannel id:int = User;
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
diff --git a/Telegram/SourceFiles/settings/settings_common.cpp b/Telegram/SourceFiles/settings/settings_common.cpp
index 465a70735c..68bceccf38 100644
--- a/Telegram/SourceFiles/settings/settings_common.cpp
+++ b/Telegram/SourceFiles/settings/settings_common.cpp
@@ -242,7 +242,8 @@ void AddDividerTextWithLottie(
LottieIcon CreateLottieIcon(
not_null parent,
Lottie::IconDescriptor &&descriptor,
- style::margins padding) {
+ style::margins padding,
+ Fn colorOverride) {
Expects(!descriptor.frame); // I'm not sure it considers limitFps.
descriptor.limitFps = true;
@@ -262,7 +263,9 @@ LottieIcon CreateLottieIcon(
const auto looped = raw->lifetime().make_state(true);
const auto start = [=] {
- icon->animate([=] { raw->update(); }, 0, icon->framesCount() - 1);
+ icon->animate([=] {
+ raw->update();
+ }, 0, icon->framesCount() - 1);
};
const auto animate = [=](anim::repeat repeat) {
*looped = (repeat == anim::repeat::loop);
@@ -272,7 +275,9 @@ LottieIcon CreateLottieIcon(
) | rpl::start_with_next([=] {
auto p = QPainter(raw);
const auto left = (raw->width() - width) / 2;
- icon->paint(p, left, padding.top());
+ icon->paint(p, left, padding.top(), colorOverride
+ ? colorOverride()
+ : std::optional());
if (!icon->animating() && icon->frameIndex() > 0 && *looped) {
start();
}
diff --git a/Telegram/SourceFiles/settings/settings_common.h b/Telegram/SourceFiles/settings/settings_common.h
index 2c2c31b64b..6a9e214951 100644
--- a/Telegram/SourceFiles/settings/settings_common.h
+++ b/Telegram/SourceFiles/settings/settings_common.h
@@ -204,7 +204,8 @@ struct LottieIcon {
[[nodiscard]] LottieIcon CreateLottieIcon(
not_null parent,
Lottie::IconDescriptor &&descriptor,
- style::margins padding = {});
+ style::margins padding = {},
+ Fn colorOverride = nullptr);
struct SliderWithLabel {
object_ptr widget;
diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp
index d0ba08a2c7..5e123fd458 100644
--- a/Telegram/SourceFiles/window/window_session_controller.cpp
+++ b/Telegram/SourceFiles/window/window_session_controller.cpp
@@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_saved_sublist.h"
#include "data/data_session.h"
#include "data/data_file_origin.h"
+#include "data/data_flags.h"
#include "data/data_folder.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
@@ -1896,10 +1897,11 @@ void SessionController::showForum(
if (_shownForum.current() != forum) {
return;
}
- forum->destroyed(
- ) | rpl::start_with_next([=, history = forum->history()] {
+ const auto history = forum->history();
+ const auto closeAndShowHistory = [=](bool showOnlyIfEmpty) {
const auto now = activeChatCurrent().owningHistory();
- const auto showHistory = !now || (now == history);
+ const auto showHistory = !now
+ || (!showOnlyIfEmpty && (now == history));
const auto weak = base::make_weak(this);
closeForum();
if (weak && showHistory) {
@@ -1909,6 +1911,19 @@ void SessionController::showForum(
anim::activation::background,
});
}
+ };
+ forum->destroyed(
+ ) | rpl::start_with_next([=] {
+ closeAndShowHistory(false);
+ }, _shownForumLifetime);
+ using FlagChange = Data::Flags::Change;
+ forum->channel()->flagsValue(
+ ) | rpl::start_with_next([=](FlagChange change) {
+ if (change.diff & ChannelDataFlag::ForumTabs) {
+ if (HistoryView::SubsectionTabs::UsedFor(history)) {
+ closeAndShowHistory(true);
+ }
+ }
}, _shownForumLifetime);
content()->showForum(forum, params);
closeMonoforum();
diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake
index f39e17f834..7bdd372fd6 100644
--- a/Telegram/cmake/td_ui.cmake
+++ b/Telegram/cmake/td_ui.cmake
@@ -58,6 +58,8 @@ PRIVATE
boxes/peers/edit_peer_history_visibility_box.cpp
boxes/peers/edit_peer_history_visibility_box.h
+ boxes/peers/toggle_topics_box.cpp
+ boxes/peers/toggle_topics_box.h
calls/group/ui/calls_group_recording_box.cpp
calls/group/ui/calls_group_recording_box.h
diff --git a/Telegram/lib_lottie b/Telegram/lib_lottie
index 4038a11f63..4fc3ac0ea5 160000
--- a/Telegram/lib_lottie
+++ b/Telegram/lib_lottie
@@ -1 +1 @@
-Subproject commit 4038a11f635311073f6d55786490920b043cb319
+Subproject commit 4fc3ac0ea52f271cc9b108481f83d56fd76ab0ed