diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 8d81aeadb..b1b8bf217 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -400,11 +400,6 @@ ChannelData *Session::channelLoaded(ChannelId id) const { return nullptr; } -AssertIsDebug(); -base::flat_map< - not_null, - base::flat_set>> Emojis; - not_null Session::processUser(const MTPUser &data) { const auto result = user(data.match([](const auto &data) { return data.vid().v; @@ -564,20 +559,10 @@ not_null Session::processUser(const MTPUser &data) { const MTPDemojiStatus &data) { return DocumentId(data.vdocument_id().v); }, [&](const MTPDemojiStatusEmpty &) { - //return DocumentId(); - auto &emojis = Emojis[this]; - return emojis.empty() - ? DocumentId() - : (*(emojis.begin() - + base::RandomIndex(emojis.size())))->id; + return DocumentId(); })); } else { - //result->setEmojiStatus(0); - auto &emojis = Emojis[this]; - result->setEmojiStatus(emojis.empty() - ? DocumentId() - : (*(emojis.begin() - + base::RandomIndex(emojis.size())))->id); + result->setEmojiStatus(0); } if (!minimal) { if (const auto botInfoVersion = data.vbot_info_version()) { @@ -2968,23 +2953,6 @@ void Session::documentApplyFields( if (dc != 0 && access != 0) { document->setRemoteLocation(dc, access, fileReference); } - - AssertIsDebug(); - if (document->isPremiumEmoji()) { - auto &emojis = Emojis[this]; - if (emojis.emplace(document).second) { - const auto size = int(emojis.size()); - crl::on_main(_session, [=] { - for (auto &[id, peer] : _peers) { - if (const auto user = peer->asUser()) { - if (user->isPremium() && !base::RandomIndex(size)) { - user->setEmojiStatus(document->id); - } - } - } - }); - } - } } not_null Session::webpage(WebPageId id) { diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 73991db15..21a6709dd 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -232,11 +232,13 @@ InnerWidget::InnerWidget( | UpdateFlag::Photo | UpdateFlag::IsContact | UpdateFlag::FullInfo + | UpdateFlag::EmojiStatus ) | rpl::start_with_next([=](const Data::PeerUpdate &update) { if (update.flags & (UpdateFlag::Name | UpdateFlag::Photo - | UpdateFlag::FullInfo)) { + | UpdateFlag::FullInfo + | UpdateFlag::EmojiStatus)) { const auto peer = update.peer; const auto history = peer->owner().historyLoaded(peer); if (_state == WidgetState::Default) { @@ -2066,7 +2068,6 @@ void InnerWidget::visibleTopBottomUpdated( _loadMoreCallback(); } } - } void InnerWidget::itemRemoved(not_null item) { 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 0639937f7..1007c62c7 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -165,6 +165,7 @@ TopBarWidget::TopBarWidget( | UpdateFlag::Members | UpdateFlag::SupportInfo | UpdateFlag::Rights + | UpdateFlag::EmojiStatus ) | rpl::start_with_next([=](const Data::PeerUpdate &update) { if (update.flags & UpdateFlag::HasCalls) { if (update.peer->isUser() @@ -182,6 +183,10 @@ TopBarWidget::TopBarWidget( | UpdateFlag::SupportInfo)) { updateOnlineDisplay(); } + if ((update.flags & UpdateFlag::EmojiStatus) + && (_activeChat.key.peer() == update.peer)) { + this->update(); + } }, lifetime()); rpl::combine( diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp index 7935cbf09..38ed694b6 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp @@ -11,7 +11,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_peer_values.h" #include "data/data_channel.h" #include "data/data_chat.h" +#include "data/data_user.h" #include "data/data_changes.h" +#include "data/data_session.h" +#include "data/data_document.h" +#include "data/stickers/data_custom_emoji.h" #include "editor/photo_editor_layer_widget.h" #include "info/profile/info_profile_values.h" #include "info/info_controller.h" @@ -25,13 +29,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/unread_badge.h" #include "base/unixtime.h" #include "window/window_session_controller.h" +#include "window/window_controller.h" #include "core/application.h" #include "main/main_session.h" #include "settings/settings_premium.h" #include "apiwrap.h" +#include "mainwindow.h" #include "api/api_peer_photo.h" +#include "chat_helpers/tabbed_panel.h" +#include "chat_helpers/tabbed_selector.h" #include "styles/style_boxes.h" #include "styles/style_info.h" +#include "styles/style_chat_helpers.h" namespace Info { namespace Profile { @@ -174,14 +183,11 @@ void Cover::initViewers(rpl::producer title) { } else if (_peer->isSelf()) { refreshUploadPhotoOverlay(); } - BadgeValue( - _peer - ) | rpl::start_with_next([=](Badge badge) { - if (badge == Badge::Premium - && !_peer->session().premiumBadgesShown()) { - badge = Badge::None; - } - setBadge(badge); + rpl::combine( + BadgeValue(_peer), + EmojiStatusIdValue(_peer) + ) | rpl::start_with_next([=](Badge badge, DocumentId emojiStatusId) { + setBadge(badge, emojiStatusId); }, lifetime()); } @@ -196,11 +202,19 @@ void Cover::refreshUploadPhotoOverlay() { }()); } -void Cover::setBadge(Badge badge) { - if (_badge == badge) { +void Cover::setBadge(Badge badge, DocumentId emojiStatusId) { + if (!_peer->session().premiumBadgesShown() && badge == Badge::Premium) { + badge = Badge::None; + } + if (badge != Badge::Premium) { + emojiStatusId = 0; + } + if (_badge == badge && _emojiStatusId == emojiStatusId) { return; } _badge = badge; + _emojiStatusId = emojiStatusId; + _emojiStatus = nullptr; _verifiedCheck.destroy(); _scamFakeBadge.destroy(); switch (_badge) { @@ -212,17 +226,41 @@ void Cover::setBadge(Badge badge) { _verifiedCheck.create(this); _verifiedCheck->show(); _verifiedCheck->resize(icon->size()); + if (_emojiStatusId) { + auto &owner = _controller->session().data(); + _emojiStatus = owner.customEmojiManager().create( + _emojiStatusId, + [raw = _verifiedCheck.data()]{ raw->update(); }, + Data::CustomEmojiManager::SizeTag::Normal); + } + _verifiedCheck->paintRequest( - ) | rpl::start_with_next([icon, check = _verifiedCheck.data()] { + ) | rpl::start_with_next([=, check = _verifiedCheck.data()] { Painter p(check); - icon->paint(p, 0, 0, check->width()); + if (_emojiStatus) { + _emojiStatus->paint( + p, + 0, + 0, + crl::now(), + st::windowBgOver->c, + _controller->isGifPausedAtLeastFor( + Window::GifPauseReason::Layer)); + } else { + icon->paint(p, 0, 0, check->width()); + } }, _verifiedCheck->lifetime()); + if (_badge == Badge::Premium) { const auto userId = peerToUser(_peer->id).bare; _verifiedCheck->setClickedCallback([=] { - ::Settings::ShowPremium( - _controller, - u"profile__%1"_q.arg(userId)); + if (_peer->isSelf()) { + showEmojiStatusSelector(); + } else { + ::Settings::ShowPremium( + _controller, + u"profile__%1"_q.arg(userId)); + } }); } else { _verifiedCheck->setAttribute(Qt::WA_TransparentForMouseEvents); @@ -253,6 +291,49 @@ void Cover::setBadge(Badge badge) { refreshNameGeometry(width()); } +void Cover::showEmojiStatusSelector() { + Expects(_verifiedCheck != nullptr); + + if (!_emojiStatusPanel) { + createEmojiStatusSelector(); + } + const auto parent = _emojiStatusPanel->parentWidget(); + const auto global = _verifiedCheck->mapToGlobal({ 0, 0 }); + const auto local = parent->mapFromGlobal(global); + _emojiStatusPanel->moveBottomRight( + local.y(), + local.x() + _verifiedCheck->width() * 3); + _emojiStatusPanel->toggleAnimated(); +} + +void Cover::createEmojiStatusSelector() { + const auto container = _controller->window().widget()->bodyWidget(); + using Selector = ChatHelpers::TabbedSelector; + _emojiStatusPanel = base::make_unique_q( + container, + _controller, + object_ptr( + nullptr, + _controller, + Window::GifPauseReason::Layer, + ChatHelpers::TabbedSelector::Mode::EmojiOnly)); + _emojiStatusPanel->setDesiredHeightValues( + 1., + st::emojiPanMinHeight / 2, + st::emojiPanMinHeight); + _emojiStatusPanel->hide(); + _emojiStatusPanel->selector()->setAllowEmojiWithoutPremium(false); + _emojiStatusPanel->selector()->customEmojiChosen( + ) | rpl::start_with_next([=](Selector::FileChosen data) { + _controller->session().user()->setEmojiStatus(data.document->id); + _controller->session().api().request(MTPaccount_UpdateEmojiStatus( + MTP_emojiStatus(MTP_long(data.document->id)) + )).send(); + _emojiStatusPanel->hideAnimated(); + }, _emojiStatusPanel->lifetime()); + _emojiStatusPanel->selector()->showPromoForPremiumEmoji(); +} + void Cover::refreshStatusText() { auto hasMembersLink = [&] { if (auto megagroup = _peer->asMegagroup()) { diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.h b/Telegram/SourceFiles/info/profile/info_profile_cover.h index 38b2b037a..eaa00d934 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.h +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.h @@ -19,6 +19,10 @@ namespace style { struct InfoToggle; } // namespace style +namespace ChatHelpers { +class TabbedPanel; +} // namespace ChatHelpers + namespace Ui { class AbstractButton; class UserpicButton; @@ -64,10 +68,15 @@ private: void refreshNameGeometry(int newWidth); void refreshStatusGeometry(int newWidth); void refreshUploadPhotoOverlay(); - void setBadge(Badge badge); + void setBadge(Badge badge, DocumentId emojiStatusId); + void createEmojiStatusSelector(); + void showEmojiStatusSelector(); const not_null _controller; const not_null _peer; + DocumentId _emojiStatusId = 0; + std::unique_ptr _emojiStatus; + base::unique_qptr _emojiStatusPanel; int _onlineCount = 0; Badge _badge = Badge(); diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.cpp b/Telegram/SourceFiles/info/profile/info_profile_values.cpp index db3f0e8fb..939e07fe5 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_values.cpp @@ -500,5 +500,16 @@ rpl::producer BadgeValue(not_null peer) { return rpl::single(Badge::None); } +rpl::producer EmojiStatusIdValue(not_null peer) { + if (const auto user = peer->asUser()) { + return user->session().changes().peerFlagsValue( + peer, + Data::PeerUpdate::Flag::EmojiStatus + ) | rpl::map([=] { return user->emojiStatusId(); }); + } + return rpl::single(DocumentId(0)); +} + + } // namespace Profile } // namespace Info diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.h b/Telegram/SourceFiles/info/profile/info_profile_values.h index c245d8b70..805d534f6 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.h +++ b/Telegram/SourceFiles/info/profile/info_profile_values.h @@ -98,6 +98,8 @@ enum class Badge { Fake, }; [[nodiscard]] rpl::producer BadgeValue(not_null peer); +[[nodiscard]] rpl::producer EmojiStatusIdValue( + not_null peer); } // namespace Profile } // namespace Info diff --git a/Telegram/SourceFiles/window/window_main_menu.cpp b/Telegram/SourceFiles/window/window_main_menu.cpp index 688cc80cc..e3c372c64 100644 --- a/Telegram/SourceFiles/window/window_main_menu.cpp +++ b/Telegram/SourceFiles/window/window_main_menu.cpp @@ -764,8 +764,6 @@ void MainMenu::paintEvent(QPaintEvent *e) { - st::mainMenuCoverNameLeft - _toggleAccounts->rightSkip(); - p.setFont(st::semiboldFont); - p.setPen(st::windowBoldFg); const auto user = _controller->session().user(); if (_nameVersion < user->nameVersion()) { _nameVersion = user->nameVersion(); @@ -774,11 +772,37 @@ void MainMenu::paintEvent(QPaintEvent *e) { user->name(), Ui::NameTextOptions()); } + const auto paused = _controller->isGifPausedAtLeastFor( + GifPauseReason::Layer); + const auto badgeWidth = user->emojiStatusId() + ? _badge.drawGetWidth( + p, + QRect( + st::mainMenuCoverNameLeft, + st::mainMenuCoverNameTop, + widthText, + st::msgNameStyle.font->height), + _name.maxWidth(), + width(), + { + .peer = user, + .verified = nullptr, + .premium = &st::dialogsPremiumIcon, + .scam = nullptr, + .preview = st::windowBgOver->c, + .customEmojiRepaint = [=] { update(); }, + .now = crl::now(), + .paused = paused, + }) + : 0; + + p.setFont(st::semiboldFont); + p.setPen(st::windowBoldFg); _name.drawLeftElided( p, st::mainMenuCoverNameLeft, st::mainMenuCoverNameTop, - widthText, + widthText - badgeWidth, width()); p.setFont(st::mainMenuPhoneFont); p.setPen(st::windowSubTextFg); diff --git a/Telegram/SourceFiles/window/window_main_menu.h b/Telegram/SourceFiles/window/window_main_menu.h index df08e222e..16528923e 100644 --- a/Telegram/SourceFiles/window/window_main_menu.h +++ b/Telegram/SourceFiles/window/window_main_menu.h @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/object_ptr.h" #include "base/binary_guard.h" #include "ui/rp_widget.h" +#include "ui/unread_badge.h" #include "ui/layers/layer_widget.h" namespace Ui { @@ -66,6 +67,7 @@ private: const not_null _controller; object_ptr _userpicButton; + Ui::PeerBadge _badge; Ui::Text::String _name; int _nameVersion = 0; object_ptr _toggleAccounts;