From 0cba9e4a22b5b5bd5a9fc3d63b5867d70921b2b8 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Oct 2022 21:13:13 +0400 Subject: [PATCH] Support default forum topic icons. --- Telegram/CMakeLists.txt | 2 + Telegram/SourceFiles/api/api_who_reacted.cpp | 2 +- .../boxes/peers/edit_forum_topic_box.cpp | 30 +++++-- .../SourceFiles/core/local_url_handlers.cpp | 6 +- .../SourceFiles/data/data_emoji_statuses.cpp | 1 - .../SourceFiles/data/data_emoji_statuses.h | 5 -- Telegram/SourceFiles/data/data_forum.cpp | 4 + .../SourceFiles/data/data_forum_icons.cpp | 82 +++++++++++++++++++ Telegram/SourceFiles/data/data_forum_icons.h | 52 ++++++++++++ Telegram/SourceFiles/data/data_session.cpp | 2 + Telegram/SourceFiles/data/data_session.h | 5 ++ .../view/history_view_top_bar_widget.cpp | 3 +- .../info/profile/info_profile_cover.cpp | 11 ++- 13 files changed, 187 insertions(+), 18 deletions(-) create mode 100644 Telegram/SourceFiles/data/data_forum_icons.cpp create mode 100644 Telegram/SourceFiles/data/data_forum_icons.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 0c8b2d5fcd..0fb828dc24 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -473,6 +473,8 @@ PRIVATE data/data_folder.h data/data_forum.cpp data/data_forum.h + data/data_forum_icons.cpp + data/data_forum_icons.h data/data_forum_topic.cpp data/data_forum_topic.h data/data_file_click_handler.cpp diff --git a/Telegram/SourceFiles/api/api_who_reacted.cpp b/Telegram/SourceFiles/api/api_who_reacted.cpp index 26a99ce1ff..596a41cbe8 100644 --- a/Telegram/SourceFiles/api/api_who_reacted.cpp +++ b/Telegram/SourceFiles/api/api_who_reacted.cpp @@ -571,7 +571,7 @@ bool WhoReadExists(not_null item) { const auto peer = history->peer; const auto chat = peer->asChat(); const auto megagroup = peer->asMegagroup(); - if (!chat && !megagroup) { + if ((!chat && !megagroup) || peer->isForum()) { return false; } const auto &appConfig = peer->session().account().appConfig(); diff --git a/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp index 852c00c3ad..05741f9ab5 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_channel.h" #include "data/data_document.h" #include "data/data_forum.h" +#include "data/data_forum_icons.h" #include "data/data_forum_topic.h" #include "data/data_session.h" #include "data/stickers/data_custom_emoji.h" @@ -222,7 +223,7 @@ struct IconSelector { auto factory = [=](DocumentId id, Fn repaint) -> std::unique_ptr { const auto tag = Data::CustomEmojiManager::SizeTag::Large; - if (const auto colorId = kDefaultIconId) { + if (id == kDefaultIconId) { return std::make_unique( rpl::duplicate(defaultIcon), repaint); @@ -230,7 +231,14 @@ struct IconSelector { return manager->create(id, std::move(repaint), tag); }; + const auto icons = &controller->session().data().forumIcons(); const auto body = box->verticalLayout(); + Settings::AddSkip(body); + const auto recent = [=] { + auto list = icons->list(); + list.insert(begin(list), kDefaultIconId); + return list; + }; const auto selector = body->add( object_ptr(body, EmojiListDescriptor{ .session = &controller->session(), @@ -239,12 +247,18 @@ struct IconSelector { .paused = Window::PausedIn( controller, Window::GifPauseReason::Layer), - .customRecentList = { kDefaultIconId }, + .customRecentList = recent(), .customRecentFactory = std::move(factory), .st = &st::reactPanelEmojiPan, }), st::reactPanelEmojiPan.padding); + icons->requestDefaultIfUnknown(); + icons->defaultUpdates( + ) | rpl::start_with_next([=] { + selector->provideRecent(recent()); + }, selector->lifetime()); + auto ownedFooter = selector->createFooter(); const auto footer = ownedFooter.data(); placeFooter(std::move(ownedFooter)); @@ -278,8 +292,12 @@ struct IconSelector { selector->customChosen( ) | rpl::start_with_next([=](ChatHelpers::FileChosen data) { const auto owner = &controller->session().data(); - const auto custom = (data.document->id != kDefaultIconId); - if (custom && !controller->session().premium()) { + const auto document = data.document; + const auto id = document->id; + const auto custom = (id != kDefaultIconId); + const auto premium = custom + && !ranges::contains(document->owner().forumIcons().list(), id); + if (premium && !controller->session().premium()) { // #TODO forum premium promo ShowPremiumPreviewBox(controller, PremiumPreview::EmojiStatus); return; @@ -288,7 +306,7 @@ struct IconSelector { if (state->button && custom) { const auto &from = data.messageSendingFrom; auto args = Ui::ReactionFlyAnimationArgs{ - .id = { { data.document->id } }, + .id = { { id } }, .flyIcon = from.frame, .flyFrom = body->mapFromGlobal(from.globalStartGeometry), }; @@ -299,7 +317,7 @@ struct IconSelector { [=] { state->animation->repaint(); }, Data::CustomEmojiSizeTag::Large); } - state->iconId = data.document->id; + state->iconId = id; }, selector->lifetime()); auto paintIconFrame = [=](not_null button) { diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp index aceafa7c80..ecaeba34cf 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.cpp +++ b/Telegram/SourceFiles/core/local_url_handlers.cpp @@ -50,6 +50,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session_settings.h" #include "inline_bots/bot_attach_web_view.h" #include "history/history.h" +#include "history/history_item.h" #include "base/qt/qt_common_adapters.h" #include "apiwrap.h" @@ -536,13 +537,14 @@ bool OpenMediaTimestamp( MsgId(parts.value(2).toLongLong())); const auto session = &controller->session(); const auto document = session->data().document(documentId); + const auto context = session->data().message(itemId); const auto timeMs = time * crl::time(1000); if (document->isVideoFile()) { controller->window().openInMediaView(Media::View::OpenRequest( controller, document, - session->data().message(itemId), - MsgId(0), // #TODO forum shared media + context, + context ? context->topicRootId() : MsgId(0), false, timeMs)); } else if (document->isSong() || document->isVoiceMessage()) { diff --git a/Telegram/SourceFiles/data/data_emoji_statuses.cpp b/Telegram/SourceFiles/data/data_emoji_statuses.cpp index 7c89d516e1..6000145d06 100644 --- a/Telegram/SourceFiles/data/data_emoji_statuses.cpp +++ b/Telegram/SourceFiles/data/data_emoji_statuses.cpp @@ -44,7 +44,6 @@ constexpr auto kMaxTimeout = 6 * 60 * 60 * crl::time(1000); EmojiStatuses::EmojiStatuses(not_null owner) : _owner(owner) -, _defaultRefreshTimer([=] { refreshDefault(); }) , _clearingTimer([=] { processClearing(); }) { refreshDefault(); refreshColored(); diff --git a/Telegram/SourceFiles/data/data_emoji_statuses.h b/Telegram/SourceFiles/data/data_emoji_statuses.h index d3e9490753..26f9f716d1 100644 --- a/Telegram/SourceFiles/data/data_emoji_statuses.h +++ b/Telegram/SourceFiles/data/data_emoji_statuses.h @@ -9,10 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/timer.h" -namespace Ui::Text { -class CustomEmoji; -} // namespace Ui::Text - namespace Main { class Session; } // namespace Main @@ -78,7 +74,6 @@ private: bool _recentRequestScheduled = false; uint64 _recentHash = 0; - base::Timer _defaultRefreshTimer; mtpRequestId _defaultRequestId = 0; uint64 _defaultHash = 0; diff --git a/Telegram/SourceFiles/data/data_forum.cpp b/Telegram/SourceFiles/data/data_forum.cpp index 642249c141..9237393576 100644 --- a/Telegram/SourceFiles/data/data_forum.cpp +++ b/Telegram/SourceFiles/data/data_forum.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_channel.h" #include "data/data_histories.h" #include "data/data_session.h" +#include "data/data_forum_icons.h" #include "data/data_forum_topic.h" #include "data/notify/data_notify_settings.h" #include "history/history.h" @@ -45,6 +46,9 @@ Forum::Forum(not_null history) if (_history->inChatList()) { preloadTopics(); } + if (channel()->canCreateTopics()) { + owner().forumIcons().requestDefaultIfUnknown(); + } } Forum::~Forum() { diff --git a/Telegram/SourceFiles/data/data_forum_icons.cpp b/Telegram/SourceFiles/data/data_forum_icons.cpp new file mode 100644 index 0000000000..e2ced07cf0 --- /dev/null +++ b/Telegram/SourceFiles/data/data_forum_icons.cpp @@ -0,0 +1,82 @@ +/* +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 "data/data_forum_icons.h" + +#include "main/main_session.h" +#include "data/data_session.h" +#include "data/data_document.h" +#include "apiwrap.h" + +namespace Data { +namespace { + +constexpr auto kRefreshDefaultListEach = 60 * 60 * crl::time(1000); +constexpr auto kRecentRequestTimeout = 10 * crl::time(1000); +constexpr auto kMaxTimeout = 6 * 60 * 60 * crl::time(1000); + +} // namespace + +ForumIcons::ForumIcons(not_null owner) +: _owner(owner) { +} + +ForumIcons::~ForumIcons() = default; + +Main::Session &ForumIcons::session() const { + return _owner->session(); +} + +void ForumIcons::requestDefaultIfUnknown() { + if (_default.empty()) { + requestDefault(); + } +} + +void ForumIcons::refreshDefault() { + requestDefault(); +} + +const std::vector &ForumIcons::list() const { + return _default; +} + +rpl::producer<> ForumIcons::defaultUpdates() const { + return _defaultUpdated.events(); +} + +void ForumIcons::requestDefault() { + if (_defaultRequestId) { + return; + } + auto &api = _owner->session().api(); + _defaultRequestId = api.request(MTPmessages_GetStickerSet( + MTP_inputStickerSetEmojiDefaultTopicIcons(), + MTP_int(0) // hash + )).done([=](const MTPmessages_StickerSet &result) { + _defaultRequestId = 0; + result.match([&](const MTPDmessages_stickerSet &data) { + updateDefault(data); + }, [](const MTPDmessages_stickerSetNotModified &) { + LOG(("API Error: Unexpected messages.stickerSetNotModified.")); + }); + }).fail([=] { + _defaultRequestId = 0; + }).send(); +} + +void ForumIcons::updateDefault(const MTPDmessages_stickerSet &data) { + const auto &list = data.vdocuments().v; + _default.clear(); + _default.reserve(list.size()); + for (const auto &sticker : data.vdocuments().v) { + _default.push_back(_owner->processDocument(sticker)->id); + } + _defaultUpdated.fire({}); +} + +} // namespace Data diff --git a/Telegram/SourceFiles/data/data_forum_icons.h b/Telegram/SourceFiles/data/data_forum_icons.h new file mode 100644 index 0000000000..cc0bdd9a67 --- /dev/null +++ b/Telegram/SourceFiles/data/data_forum_icons.h @@ -0,0 +1,52 @@ +/* +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 + +namespace Main { +class Session; +} // namespace Main + +namespace Data { + +class DocumentMedia; +class Session; + +class ForumIcons final { +public: + explicit ForumIcons(not_null owner); + ~ForumIcons(); + + [[nodiscard]] Session &owner() const { + return *_owner; + } + [[nodiscard]] Main::Session &session() const; + + void refreshDefault(); + void requestDefaultIfUnknown(); + + [[nodiscard]] const std::vector &list() const; + + [[nodiscard]] rpl::producer<> defaultUpdates() const; + +private: + void requestDefault(); + + void updateDefault(const MTPDmessages_stickerSet &data); + + const not_null _owner; + + std::vector _default; + rpl::event_stream<> _defaultUpdated; + + mtpRequestId _defaultRequestId = 0; + + rpl::lifetime _lifetime; + +}; + +} // namespace Data diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 19f8b9daaf..7b7ffe9f5a 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -62,6 +62,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_sponsored_messages.h" #include "data/data_message_reactions.h" #include "data/data_emoji_statuses.h" +#include "data/data_forum_icons.h" #include "data/data_cloud_themes.h" #include "data/data_streaming.h" #include "data/data_media_rotation.h" @@ -257,6 +258,7 @@ Session::Session(not_null session) , _sponsoredMessages(std::make_unique(this)) , _reactions(std::make_unique(this)) , _emojiStatuses(std::make_unique(this)) +, _forumIcons(std::make_unique(this)) , _notifySettings(std::make_unique(this)) , _customEmojiManager(std::make_unique(this)) { _cache->open(_session->local().cacheKey()); diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 34d7f493de..d491e897b3 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -53,6 +53,7 @@ class SendActionManager; class SponsoredMessages; class Reactions; class EmojiStatuses; +class ForumIcons; class ChatFilters; class CloudThemes; class Streaming; @@ -128,6 +129,9 @@ public: [[nodiscard]] EmojiStatuses &emojiStatuses() const { return *_emojiStatuses; } + [[nodiscard]] ForumIcons &forumIcons() const { + return *_forumIcons; + } [[nodiscard]] NotifySettings ¬ifySettings() const { return *_notifySettings; } @@ -986,6 +990,7 @@ private: std::unique_ptr _sponsoredMessages; const std::unique_ptr _reactions; const std::unique_ptr _emojiStatuses; + const std::unique_ptr _forumIcons; const std::unique_ptr _notifySettings; const std::unique_ptr _customEmojiManager; diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index 7cb026791f..2b29389b89 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -502,7 +502,6 @@ void TopBarWidget::paintTopBar(Painter &p) { || history->peer->sharedMediaInfo() || (_activeChat.section == Section::Scheduled) || (_activeChat.section == Section::Pinned)) { - // #TODO forum name emoji. auto text = (_activeChat.section == Section::Scheduled) ? ((history && history->peer->isSelf()) ? tr::lng_reminder_messages(tr::now) @@ -929,7 +928,7 @@ void TopBarWidget::updateControlsGeometry() { _leftTaken += _info->width(); } else if (_activeChat.key.topic() || _activeChat.section == Section::ChatsList) { - _leftTaken += st::topBarArrowPadding.right(); + _leftTaken += st::normalFont->spacew; } _rightTaken = 0; diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp index 13fd5c9ce9..4509e2d30d 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/profile/info_profile_badge.h" #include "info/profile/info_profile_emoji_status_panel.h" #include "info/info_controller.h" +#include "boxes/peers/edit_forum_topic_box.h" #include "history/view/media/history_view_sticker_player.h" #include "lang/lang_keys.h" #include "ui/widgets/labels.h" @@ -283,8 +284,16 @@ Cover::Cover( _peer, _userpic->takeResultImage()); }, _userpic->lifetime()); + } else if (topic->canEdit()) { + _iconView->setClickedCallback([=] { + _controller->show(Box( + EditForumTopicBox, + _controller, + topic->history(), + topic->rootId())); + }); } else { - // #TODO forum icon change on click if possible + _iconView->setAttribute(Qt::WA_TransparentForMouseEvents); } }