/* 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.h" #include "apiwrap.h" #include "window/themes/window_theme.h" #include "window/window_peer_menu.h" #include "window/window_session_controller.h" #include "window/window_controller.h" #include "ui/chat/chat_theme.h" #include "ui/controls/userpic_button.h" #include "ui/effects/snowflakes.h" #include "ui/effects/toggle_arrow.h" #include "ui/widgets/popup_menu.h" #include "ui/widgets/scroll_area.h" #include "ui/widgets/shadow.h" #include "ui/widgets/tooltip.h" #include "ui/wrap/slide_wrap.h" #include "ui/text/text_utilities.h" #include "ui/text/text_options.h" #include "ui/new_badges.h" #include "ui/painter.h" #include "ui/rect.h" #include "ui/vertical_list.h" #include "ui/unread_badge_paint.h" #include "inline_bots/bot_attach_web_view.h" #include "storage/localstorage.h" #include "storage/storage_account.h" #include "support/support_templates.h" #include "settings/settings_advanced.h" #include "settings/settings_calls.h" #include "settings/settings_information.h" #include "info/profile/info_profile_badge.h" #include "info/profile/info_profile_emoji_status_panel.h" #include "info/stories/info_stories_widget.h" #include "info/info_memento.h" #include "base/platform/base_platform_info.h" #include "base/qt_signal_producer.h" #include "boxes/about_box.h" #include "ui/boxes/confirm_box.h" #include "boxes/peer_list_controllers.h" #include "boxes/premium_preview_box.h" #include "calls/calls_box_controller.h" #include "lang/lang_keys.h" #include "lottie/lottie_icon.h" #include "core/click_handler_types.h" #include "core/application.h" #include "main/main_session.h" #include "main/main_session_settings.h" #include "main/main_account.h" #include "main/main_domain.h" #include "mtproto/mtproto_config.h" #include "data/data_chat.h" #include "data/data_document_media.h" #include "data/data_folder.h" #include "data/data_session.h" #include "data/data_document.h" #include "data/data_file_origin.h" #include "data/data_user.h" #include "data/data_changes.h" #include "data/data_channel.h" #include "data/data_stories.h" #include "mainwidget.h" #include "styles/style_chat.h" // popupMenuExpandedSeparator #include "styles/style_window.h" #include "styles/style_settings.h" #include "styles/style_info.h" // infoTopBarMenu #include "styles/style_layers.h" #include "styles/style_menu_icons.h" #include #include #include #include namespace Window { namespace { constexpr auto kPlayStatusLimit = 2; 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()); } }; 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, !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) { const auto row = box->addRow( object_ptr