/* 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 "info/profile/info_profile_cover.h" #include "data/data_peer_values.h" #include "data/data_channel.h" #include "data/data_chat.h" #include "data/data_peer.h" #include "data/data_changes.h" #include "info/profile/info_profile_values.h" #include "info/profile/info_profile_badge.h" #include "info/profile/info_profile_emoji_status_panel.h" #include "info/info_controller.h" #include "lang/lang_keys.h" #include "ui/widgets/labels.h" #include "ui/text/text_utilities.h" #include "ui/special_buttons.h" #include "base/unixtime.h" #include "window/window_session_controller.h" #include "main/main_session.h" #include "settings/settings_premium.h" #include "apiwrap.h" #include "api/api_peer_photo.h" #include "styles/style_boxes.h" #include "styles/style_info.h" namespace Info::Profile { namespace { auto MembersStatusText(int count) { return tr::lng_chat_status_members(tr::now, lt_count_decimal, count); }; auto OnlineStatusText(int count) { return tr::lng_chat_status_online(tr::now, lt_count_decimal, count); }; auto ChatStatusText(int fullCount, int onlineCount, bool isGroup) { if (onlineCount > 1 && onlineCount <= fullCount) { return tr::lng_chat_status_members_online( tr::now, lt_members_count, MembersStatusText(fullCount), lt_online_count, OnlineStatusText(onlineCount)); } else if (fullCount > 0) { return isGroup ? tr::lng_chat_status_members( tr::now, lt_count_decimal, fullCount) : tr::lng_chat_status_subscribers( tr::now, lt_count_decimal, fullCount); } return isGroup ? tr::lng_group_status(tr::now) : tr::lng_channel_status(tr::now); }; } // namespace Cover::Cover( QWidget *parent, not_null peer, not_null controller) : Cover(parent, peer, controller, NameValue( peer ) | rpl::map([=](const TextWithEntities &name) { return name.text; })) { } Cover::Cover( QWidget *parent, not_null peer, not_null controller, rpl::producer title) : FixedHeightWidget( parent, st::infoProfilePhotoTop + st::infoProfilePhoto.size.height() + st::infoProfilePhotoBottom) , _controller(controller) , _peer(peer) , _emojiStatusPanel(peer->isSelf() ? std::make_unique() : nullptr) , _badge( std::make_unique( this, st::infoPeerBadge, peer, _emojiStatusPanel.get(), [=] { return controller->isGifPausedAtLeastFor( Window::GifPauseReason::Layer); })) , _userpic( this, controller, _peer, Ui::UserpicButton::Role::OpenPhoto, st::infoProfilePhoto) , _name(this, st::infoProfileNameLabel) , _status( this, _peer->isMegagroup() ? st::infoProfileMegagroupStatusLabel : st::infoProfileStatusLabel) , _refreshStatusTimer([this] { refreshStatusText(); }) { _peer->updateFull(); _name->setSelectable(true); _name->setContextCopyText(tr::lng_profile_copy_fullname(tr::now)); if (!_peer->isMegagroup()) { _status->setAttribute(Qt::WA_TransparentForMouseEvents); } _badge->setPremiumClickCallback([=] { if (const auto panel = _emojiStatusPanel.get()) { panel->show(_controller, _badge->widget(), _badge->sizeTag()); } else { ::Settings::ShowEmojiStatusPremium(_controller, _peer); } }); _badge->updated() | rpl::start_with_next([=] { refreshNameGeometry(width()); }, _name->lifetime()); initViewers(std::move(title)); setupChildGeometry(); _userpic->uploadPhotoRequests( ) | rpl::start_with_next([=] { _peer->session().api().peerPhoto().upload( _peer, _userpic->takeResultImage()); }, _userpic->lifetime()); } void Cover::setupChildGeometry() { widthValue( ) | rpl::start_with_next([this](int newWidth) { _userpic->moveToLeft( st::infoProfilePhotoLeft, st::infoProfilePhotoTop, newWidth); refreshNameGeometry(newWidth); refreshStatusGeometry(newWidth); }, lifetime()); } Cover *Cover::setOnlineCount(rpl::producer &&count) { std::move( count ) | rpl::start_with_next([this](int count) { _onlineCount = count; refreshStatusText(); }, lifetime()); return this; } void Cover::initViewers(rpl::producer title) { using Flag = Data::PeerUpdate::Flag; std::move( title ) | rpl::start_with_next([=](const QString &title) { _name->setText(title); refreshNameGeometry(width()); }, lifetime()); _peer->session().changes().peerFlagsValue( _peer, Flag::OnlineStatus | Flag::Members ) | rpl::start_with_next( [=] { refreshStatusText(); }, lifetime()); if (!_peer->isUser()) { _peer->session().changes().peerFlagsValue( _peer, Flag::Rights ) | rpl::start_with_next( [=] { refreshUploadPhotoOverlay(); }, lifetime()); } else if (_peer->isSelf()) { refreshUploadPhotoOverlay(); } } void Cover::refreshUploadPhotoOverlay() { _userpic->switchChangePhotoOverlay([&] { if (const auto chat = _peer->asChat()) { return chat->canEditInformation(); } else if (const auto channel = _peer->asChannel()) { return channel->canEditInformation(); } return _peer->isSelf(); }()); } void Cover::refreshStatusText() { auto hasMembersLink = [&] { if (auto megagroup = _peer->asMegagroup()) { return megagroup->canViewMembers(); } return false; }(); auto statusText = [&]() -> TextWithEntities { using namespace Ui::Text; auto currentTime = base::unixtime::now(); if (auto user = _peer->asUser()) { const auto result = Data::OnlineTextFull(user, currentTime); const auto showOnline = Data::OnlineTextActive(user, currentTime); const auto updateIn = Data::OnlineChangeTimeout(user, currentTime); if (showOnline) { _refreshStatusTimer.callOnce(updateIn); } return showOnline ? PlainLink(result) : TextWithEntities{ .text = result }; } else if (auto chat = _peer->asChat()) { if (!chat->amIn()) { return tr::lng_chat_status_unaccessible({}, WithEntities); } auto fullCount = std::max( chat->count, int(chat->participants.size())); return { .text = ChatStatusText(fullCount, _onlineCount, true) }; } else if (auto channel = _peer->asChannel()) { auto fullCount = qMax(channel->membersCount(), 1); auto result = ChatStatusText( fullCount, _onlineCount, channel->isMegagroup()); return hasMembersLink ? PlainLink(result) : TextWithEntities{ .text = result }; } return tr::lng_chat_status_unaccessible(tr::now, WithEntities); }(); _status->setMarkedText(statusText); if (hasMembersLink) { _status->setLink(1, std::make_shared([=] { _showSection.fire(Section::Type::Members); })); } refreshStatusGeometry(width()); } Cover::~Cover() { } void Cover::refreshNameGeometry(int newWidth) { auto nameLeft = st::infoProfileNameLeft; auto nameTop = st::infoProfileNameTop; auto nameWidth = newWidth - nameLeft - st::infoProfileNameRight; if (const auto widget = _badge->widget()) { nameWidth -= st::infoVerifiedCheckPosition.x() + widget->width(); } _name->resizeToNaturalWidth(nameWidth); _name->moveToLeft(nameLeft, nameTop, newWidth); const auto badgeLeft = nameLeft + _name->width(); const auto badgeTop = nameTop; const auto badgeBottom = nameTop + _name->height(); _badge->move(badgeLeft, badgeTop, badgeBottom); } void Cover::refreshStatusGeometry(int newWidth) { auto statusWidth = newWidth - st::infoProfileStatusLeft - st::infoProfileStatusRight; _status->resizeToWidth(statusWidth); _status->moveToLeft( st::infoProfileStatusLeft, st::infoProfileStatusTop, newWidth); } } // namespace Info::Profile