/* 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 "window/window_main_menu_helpers.h" #include "apiwrap.h" #include "base/platform/base_platform_info.h" #include "data/data_channel.h" #include "data/data_chat.h" #include "data/data_document.h" #include "data/data_document_media.h" #include "data/data_file_origin.h" #include "data/data_session.h" #include "data/data_user.h" #include "inline_bots/bot_attach_web_view.h" #include "lang/lang_keys.h" #include "lottie/lottie_icon.h" #include "main/main_session.h" #include "ui/controls/userpic_button.h" #include "ui/layers/generic_box.h" #include "ui/new_badges.h" #include "ui/painter.h" #include "ui/rect.h" #include "ui/widgets/popup_menu.h" #include "ui/widgets/tooltip.h" #include "ui/wrap/slide_wrap.h" #include "ui/ui_utility.h" #include "window/window_controller.h" #include "window/window_session_controller.h" #include "styles/style_chat.h" #include "styles/style_info.h" #include "styles/style_menu_icons.h" #include "styles/style_window.h" namespace Window { namespace { class VersionLabel final : public Ui::FlatLabel , public Ui::AbstractTooltipShower { public: using Ui::FlatLabel::FlatLabel; void clickHandlerActiveChanged( const ClickHandlerPtr &action, bool active) override { update(); if (active && action && !action->dragText().isEmpty()) { Ui::Tooltip::Show(1000, this); } else { Ui::Tooltip::Hide(); } } QString tooltipText() const override { return u"Build date: %1."_q.arg(__DATE__); } QPoint tooltipPos() const override { return QCursor::pos(); } bool tooltipWindowActive() const override { return Ui::AppInFocus() && Ui::InFocusChain(window()); } }; } // namespace [[nodiscard]] not_null AddVersionLabel( not_null parent) { return (Platform::IsMacStoreBuild() || Platform::IsWindowsStoreBuild()) ? Ui::CreateChild( parent.get(), st::mainMenuVersionLabel) : Ui::CreateChild( parent.get(), st::mainMenuVersionLabel); } not_null AddMyChannelsBox( not_null button, not_null controller, bool chats) { button->setAcceptBoth(true); const auto requestIcon = [=, session = &controller->session()]( not_null box, Fn)> done) { const auto api = box->lifetime().make_state( &session->mtp()); api->request(MTPmessages_GetStickerSet( Data::InputStickerSet({ .shortName = u"tg_placeholders_android"_q, }), MTP_int(0) )).done([=](const MTPmessages_StickerSet &result) { result.match([&](const MTPDmessages_stickerSet &data) { const auto &v = data.vdocuments().v; if (v.size() > 1) { done(session->data().processDocument(v[1])); } }, [](const MTPDmessages_stickerSetNotModified &) { }); }).send(); }; const auto addIcon = [=](not_null box) { const auto widget = box->addRow(object_ptr(box)); widget->paintRequest( ) | rpl::start_with_next([=] { auto p = QPainter(widget); p.setFont(st::boxTextFont); p.setPen(st::windowSubTextFg); p.drawText( widget->rect(), tr::lng_contacts_loading(tr::now), style::al_center); }, widget->lifetime()); widget->resize(Size(st::maxStickerSize)); widget->show(); box->verticalLayout()->resizeToWidth(box->width()); requestIcon(box, [=](not_null document) { const auto view = document->createMediaView(); const auto origin = document->stickerSetOrigin(); controller->session().downloaderTaskFinished( ) | rpl::take_while([=] { if (view->bytes().isEmpty()) { return true; } auto owned = Lottie::MakeIcon({ .json = Images::UnpackGzip(view->bytes()), .sizeOverride = Size(st::maxStickerSize), }); const auto icon = owned.get(); widget->lifetime().add([kept = std::move(owned)]{}); widget->paintRequest( ) | rpl::start_with_next([=] { auto p = QPainter(widget); icon->paint(p, (widget->width() - icon->width()) / 2, 0); }, widget->lifetime()); icon->animate( [=] { widget->update(); }, 0, icon->framesCount()); return false; }) | rpl::start(widget->lifetime()); view->automaticLoad(origin, nullptr); view->videoThumbnailWanted(origin); }); }; const auto myChannelsBox = [=](not_null box) { box->setTitle(chats ? tr::lng_notification_groups() : tr::lng_notification_channels()); box->addButton(tr::lng_close(), [=] { box->closeBox(); }); const auto st = box->lifetime().make_state( st::defaultUserpicButton); st->photoSize = st::defaultPeerListItem.photoSize; st->size = QSize(st->photoSize, st->photoSize); class Button final : public Ui::SettingsButton { public: using Ui::SettingsButton::SettingsButton; void setPeer(not_null p) { const auto c = p->asChannel(); const auto g = p->asChat(); _text.setText( st::defaultPeerListItem.nameStyle, ((c && c->isMegagroup()) ? u"[s] "_q : QString()) + p->name()); const auto count = c ? c->membersCount() : g->count; _status.setText( st::defaultTextStyle, (g && !g->amIn()) ? tr::lng_chat_status_unaccessible(tr::now) : !p->username().isEmpty() ? ('@' + p->username()) : (count > 0) ? ((c && !c->isMegagroup()) ? tr::lng_chat_status_subscribers : tr::lng_chat_status_members)( tr::now, lt_count, count) : QString()); } int resizeGetHeight(int) override { return st::defaultPeerListItem.height; } void paintEvent(QPaintEvent *e) override { Ui::SettingsButton::paintEvent(e); auto p = Painter(this); const auto &st = st::defaultPeerListItem; const auto availableWidth = width() - st::boxRowPadding.right() - st.namePosition.x(); p.setPen(st.nameFg); auto context = Ui::Text::PaintContext{ .position = st.namePosition, .outerWidth = availableWidth, .availableWidth = availableWidth, .elisionLines = 1, }; _text.draw(p, context); p.setPen(st.statusFg); context.position = st.statusPosition; _status.draw(p, context); } private: Ui::Text::String _text; Ui::Text::String _status; }; const auto add = [&]( not_null peer, not_null container) { const auto row = container->add( object_ptr