Support default forum topic icons.

This commit is contained in:
John Preston 2022-10-21 21:13:13 +04:00
parent 5314833c82
commit 0cba9e4a22
13 changed files with 187 additions and 18 deletions

View file

@ -473,6 +473,8 @@ PRIVATE
data/data_folder.h data/data_folder.h
data/data_forum.cpp data/data_forum.cpp
data/data_forum.h data/data_forum.h
data/data_forum_icons.cpp
data/data_forum_icons.h
data/data_forum_topic.cpp data/data_forum_topic.cpp
data/data_forum_topic.h data/data_forum_topic.h
data/data_file_click_handler.cpp data/data_file_click_handler.cpp

View file

@ -571,7 +571,7 @@ bool WhoReadExists(not_null<HistoryItem*> item) {
const auto peer = history->peer; const auto peer = history->peer;
const auto chat = peer->asChat(); const auto chat = peer->asChat();
const auto megagroup = peer->asMegagroup(); const auto megagroup = peer->asMegagroup();
if (!chat && !megagroup) { if ((!chat && !megagroup) || peer->isForum()) {
return false; return false;
} }
const auto &appConfig = peer->session().account().appConfig(); const auto &appConfig = peer->session().account().appConfig();

View file

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_document.h" #include "data/data_document.h"
#include "data/data_forum.h" #include "data/data_forum.h"
#include "data/data_forum_icons.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/stickers/data_custom_emoji.h" #include "data/stickers/data_custom_emoji.h"
@ -222,7 +223,7 @@ struct IconSelector {
auto factory = [=](DocumentId id, Fn<void()> repaint) auto factory = [=](DocumentId id, Fn<void()> repaint)
-> std::unique_ptr<Ui::Text::CustomEmoji> { -> std::unique_ptr<Ui::Text::CustomEmoji> {
const auto tag = Data::CustomEmojiManager::SizeTag::Large; const auto tag = Data::CustomEmojiManager::SizeTag::Large;
if (const auto colorId = kDefaultIconId) { if (id == kDefaultIconId) {
return std::make_unique<DefaultIconEmoji>( return std::make_unique<DefaultIconEmoji>(
rpl::duplicate(defaultIcon), rpl::duplicate(defaultIcon),
repaint); repaint);
@ -230,7 +231,14 @@ struct IconSelector {
return manager->create(id, std::move(repaint), tag); return manager->create(id, std::move(repaint), tag);
}; };
const auto icons = &controller->session().data().forumIcons();
const auto body = box->verticalLayout(); 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( const auto selector = body->add(
object_ptr<EmojiListWidget>(body, EmojiListDescriptor{ object_ptr<EmojiListWidget>(body, EmojiListDescriptor{
.session = &controller->session(), .session = &controller->session(),
@ -239,12 +247,18 @@ struct IconSelector {
.paused = Window::PausedIn( .paused = Window::PausedIn(
controller, controller,
Window::GifPauseReason::Layer), Window::GifPauseReason::Layer),
.customRecentList = { kDefaultIconId }, .customRecentList = recent(),
.customRecentFactory = std::move(factory), .customRecentFactory = std::move(factory),
.st = &st::reactPanelEmojiPan, .st = &st::reactPanelEmojiPan,
}), }),
st::reactPanelEmojiPan.padding); st::reactPanelEmojiPan.padding);
icons->requestDefaultIfUnknown();
icons->defaultUpdates(
) | rpl::start_with_next([=] {
selector->provideRecent(recent());
}, selector->lifetime());
auto ownedFooter = selector->createFooter(); auto ownedFooter = selector->createFooter();
const auto footer = ownedFooter.data(); const auto footer = ownedFooter.data();
placeFooter(std::move(ownedFooter)); placeFooter(std::move(ownedFooter));
@ -278,8 +292,12 @@ struct IconSelector {
selector->customChosen( selector->customChosen(
) | rpl::start_with_next([=](ChatHelpers::FileChosen data) { ) | rpl::start_with_next([=](ChatHelpers::FileChosen data) {
const auto owner = &controller->session().data(); const auto owner = &controller->session().data();
const auto custom = (data.document->id != kDefaultIconId); const auto document = data.document;
if (custom && !controller->session().premium()) { 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 // #TODO forum premium promo
ShowPremiumPreviewBox(controller, PremiumPreview::EmojiStatus); ShowPremiumPreviewBox(controller, PremiumPreview::EmojiStatus);
return; return;
@ -288,7 +306,7 @@ struct IconSelector {
if (state->button && custom) { if (state->button && custom) {
const auto &from = data.messageSendingFrom; const auto &from = data.messageSendingFrom;
auto args = Ui::ReactionFlyAnimationArgs{ auto args = Ui::ReactionFlyAnimationArgs{
.id = { { data.document->id } }, .id = { { id } },
.flyIcon = from.frame, .flyIcon = from.frame,
.flyFrom = body->mapFromGlobal(from.globalStartGeometry), .flyFrom = body->mapFromGlobal(from.globalStartGeometry),
}; };
@ -299,7 +317,7 @@ struct IconSelector {
[=] { state->animation->repaint(); }, [=] { state->animation->repaint(); },
Data::CustomEmojiSizeTag::Large); Data::CustomEmojiSizeTag::Large);
} }
state->iconId = data.document->id; state->iconId = id;
}, selector->lifetime()); }, selector->lifetime());
auto paintIconFrame = [=](not_null<Ui::RpWidget*> button) { auto paintIconFrame = [=](not_null<Ui::RpWidget*> button) {

View file

@ -50,6 +50,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session_settings.h" #include "main/main_session_settings.h"
#include "inline_bots/bot_attach_web_view.h" #include "inline_bots/bot_attach_web_view.h"
#include "history/history.h" #include "history/history.h"
#include "history/history_item.h"
#include "base/qt/qt_common_adapters.h" #include "base/qt/qt_common_adapters.h"
#include "apiwrap.h" #include "apiwrap.h"
@ -536,13 +537,14 @@ bool OpenMediaTimestamp(
MsgId(parts.value(2).toLongLong())); MsgId(parts.value(2).toLongLong()));
const auto session = &controller->session(); const auto session = &controller->session();
const auto document = session->data().document(documentId); const auto document = session->data().document(documentId);
const auto context = session->data().message(itemId);
const auto timeMs = time * crl::time(1000); const auto timeMs = time * crl::time(1000);
if (document->isVideoFile()) { if (document->isVideoFile()) {
controller->window().openInMediaView(Media::View::OpenRequest( controller->window().openInMediaView(Media::View::OpenRequest(
controller, controller,
document, document,
session->data().message(itemId), context,
MsgId(0), // #TODO forum shared media context ? context->topicRootId() : MsgId(0),
false, false,
timeMs)); timeMs));
} else if (document->isSong() || document->isVoiceMessage()) { } else if (document->isSong() || document->isVoiceMessage()) {

View file

@ -44,7 +44,6 @@ constexpr auto kMaxTimeout = 6 * 60 * 60 * crl::time(1000);
EmojiStatuses::EmojiStatuses(not_null<Session*> owner) EmojiStatuses::EmojiStatuses(not_null<Session*> owner)
: _owner(owner) : _owner(owner)
, _defaultRefreshTimer([=] { refreshDefault(); })
, _clearingTimer([=] { processClearing(); }) { , _clearingTimer([=] { processClearing(); }) {
refreshDefault(); refreshDefault();
refreshColored(); refreshColored();

View file

@ -9,10 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer.h" #include "base/timer.h"
namespace Ui::Text {
class CustomEmoji;
} // namespace Ui::Text
namespace Main { namespace Main {
class Session; class Session;
} // namespace Main } // namespace Main
@ -78,7 +74,6 @@ private:
bool _recentRequestScheduled = false; bool _recentRequestScheduled = false;
uint64 _recentHash = 0; uint64 _recentHash = 0;
base::Timer _defaultRefreshTimer;
mtpRequestId _defaultRequestId = 0; mtpRequestId _defaultRequestId = 0;
uint64 _defaultHash = 0; uint64 _defaultHash = 0;

View file

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_histories.h" #include "data/data_histories.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_forum_icons.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/notify/data_notify_settings.h" #include "data/notify/data_notify_settings.h"
#include "history/history.h" #include "history/history.h"
@ -45,6 +46,9 @@ Forum::Forum(not_null<History*> history)
if (_history->inChatList()) { if (_history->inChatList()) {
preloadTopics(); preloadTopics();
} }
if (channel()->canCreateTopics()) {
owner().forumIcons().requestDefaultIfUnknown();
}
} }
Forum::~Forum() { Forum::~Forum() {

View file

@ -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<Session*> 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<DocumentId> &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

View file

@ -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<Session*> owner);
~ForumIcons();
[[nodiscard]] Session &owner() const {
return *_owner;
}
[[nodiscard]] Main::Session &session() const;
void refreshDefault();
void requestDefaultIfUnknown();
[[nodiscard]] const std::vector<DocumentId> &list() const;
[[nodiscard]] rpl::producer<> defaultUpdates() const;
private:
void requestDefault();
void updateDefault(const MTPDmessages_stickerSet &data);
const not_null<Session*> _owner;
std::vector<DocumentId> _default;
rpl::event_stream<> _defaultUpdated;
mtpRequestId _defaultRequestId = 0;
rpl::lifetime _lifetime;
};
} // namespace Data

View file

@ -62,6 +62,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_sponsored_messages.h" #include "data/data_sponsored_messages.h"
#include "data/data_message_reactions.h" #include "data/data_message_reactions.h"
#include "data/data_emoji_statuses.h" #include "data/data_emoji_statuses.h"
#include "data/data_forum_icons.h"
#include "data/data_cloud_themes.h" #include "data/data_cloud_themes.h"
#include "data/data_streaming.h" #include "data/data_streaming.h"
#include "data/data_media_rotation.h" #include "data/data_media_rotation.h"
@ -257,6 +258,7 @@ Session::Session(not_null<Main::Session*> session)
, _sponsoredMessages(std::make_unique<SponsoredMessages>(this)) , _sponsoredMessages(std::make_unique<SponsoredMessages>(this))
, _reactions(std::make_unique<Reactions>(this)) , _reactions(std::make_unique<Reactions>(this))
, _emojiStatuses(std::make_unique<EmojiStatuses>(this)) , _emojiStatuses(std::make_unique<EmojiStatuses>(this))
, _forumIcons(std::make_unique<ForumIcons>(this))
, _notifySettings(std::make_unique<NotifySettings>(this)) , _notifySettings(std::make_unique<NotifySettings>(this))
, _customEmojiManager(std::make_unique<CustomEmojiManager>(this)) { , _customEmojiManager(std::make_unique<CustomEmojiManager>(this)) {
_cache->open(_session->local().cacheKey()); _cache->open(_session->local().cacheKey());

View file

@ -53,6 +53,7 @@ class SendActionManager;
class SponsoredMessages; class SponsoredMessages;
class Reactions; class Reactions;
class EmojiStatuses; class EmojiStatuses;
class ForumIcons;
class ChatFilters; class ChatFilters;
class CloudThemes; class CloudThemes;
class Streaming; class Streaming;
@ -128,6 +129,9 @@ public:
[[nodiscard]] EmojiStatuses &emojiStatuses() const { [[nodiscard]] EmojiStatuses &emojiStatuses() const {
return *_emojiStatuses; return *_emojiStatuses;
} }
[[nodiscard]] ForumIcons &forumIcons() const {
return *_forumIcons;
}
[[nodiscard]] NotifySettings &notifySettings() const { [[nodiscard]] NotifySettings &notifySettings() const {
return *_notifySettings; return *_notifySettings;
} }
@ -986,6 +990,7 @@ private:
std::unique_ptr<SponsoredMessages> _sponsoredMessages; std::unique_ptr<SponsoredMessages> _sponsoredMessages;
const std::unique_ptr<Reactions> _reactions; const std::unique_ptr<Reactions> _reactions;
const std::unique_ptr<EmojiStatuses> _emojiStatuses; const std::unique_ptr<EmojiStatuses> _emojiStatuses;
const std::unique_ptr<ForumIcons> _forumIcons;
const std::unique_ptr<NotifySettings> _notifySettings; const std::unique_ptr<NotifySettings> _notifySettings;
const std::unique_ptr<CustomEmojiManager> _customEmojiManager; const std::unique_ptr<CustomEmojiManager> _customEmojiManager;

View file

@ -502,7 +502,6 @@ void TopBarWidget::paintTopBar(Painter &p) {
|| history->peer->sharedMediaInfo() || history->peer->sharedMediaInfo()
|| (_activeChat.section == Section::Scheduled) || (_activeChat.section == Section::Scheduled)
|| (_activeChat.section == Section::Pinned)) { || (_activeChat.section == Section::Pinned)) {
// #TODO forum name emoji.
auto text = (_activeChat.section == Section::Scheduled) auto text = (_activeChat.section == Section::Scheduled)
? ((history && history->peer->isSelf()) ? ((history && history->peer->isSelf())
? tr::lng_reminder_messages(tr::now) ? tr::lng_reminder_messages(tr::now)
@ -929,7 +928,7 @@ void TopBarWidget::updateControlsGeometry() {
_leftTaken += _info->width(); _leftTaken += _info->width();
} else if (_activeChat.key.topic() } else if (_activeChat.key.topic()
|| _activeChat.section == Section::ChatsList) { || _activeChat.section == Section::ChatsList) {
_leftTaken += st::topBarArrowPadding.right(); _leftTaken += st::normalFont->spacew;
} }
_rightTaken = 0; _rightTaken = 0;

View file

@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/profile/info_profile_badge.h" #include "info/profile/info_profile_badge.h"
#include "info/profile/info_profile_emoji_status_panel.h" #include "info/profile/info_profile_emoji_status_panel.h"
#include "info/info_controller.h" #include "info/info_controller.h"
#include "boxes/peers/edit_forum_topic_box.h"
#include "history/view/media/history_view_sticker_player.h" #include "history/view/media/history_view_sticker_player.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
@ -283,8 +284,16 @@ Cover::Cover(
_peer, _peer,
_userpic->takeResultImage()); _userpic->takeResultImage());
}, _userpic->lifetime()); }, _userpic->lifetime());
} else if (topic->canEdit()) {
_iconView->setClickedCallback([=] {
_controller->show(Box(
EditForumTopicBox,
_controller,
topic->history(),
topic->rootId()));
});
} else { } else {
// #TODO forum icon change on click if possible _iconView->setAttribute(Qt::WA_TransparentForMouseEvents);
} }
} }