From 3644dfd6fc64dd28fb350eb764192cd6c89bfd48 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 8 Mar 2022 18:16:59 +0400 Subject: [PATCH] Show viewers count in RTMP streams. --- Telegram/Resources/langs/lang.strings | 2 + Telegram/SourceFiles/calls/calls.style | 4 +- .../calls/group/calls_group_panel.cpp | 160 ++++++++++++++---- .../calls/group/calls_group_panel.h | 3 + 4 files changed, 132 insertions(+), 37 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 177419c16..4f21582e7 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2411,6 +2411,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_group_call_rtmp_start" = "Start Streaming"; "lng_group_call_rtmp_revoke" = "Revoke Stream Key"; "lng_group_call_rtmp_revoke_sure" = "Are you sure you want to revoke your Server URL and Stream Key?"; +"lng_group_call_rtmp_viewers#one" = "{count} viewer"; +"lng_group_call_rtmp_viewers#other" = "{count} viewers"; "lng_no_mic_permission" = "Telegram needs access to your microphone so that you can make calls and record voice messages."; diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index d0e1fd5e6..eb5f05c5a 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -494,8 +494,9 @@ callErrorToast: Toast(defaultToast) { groupCallWidth: 380px; groupCallHeight: 580px; groupCallWidthRtmp: 720px; +groupCallWidthRtmpMin: 240px; groupCallHeightRtmp: 580px; -groupCallHeightRtmpMin: 280px; +groupCallHeightRtmpMin: 160px; groupCallRipple: RippleAnimation(defaultRippleAnimation) { color: groupCallMembersBgRipple; @@ -773,6 +774,7 @@ groupCallTitleLabel: FlatLabel(groupCallSubtitleLabel) { linkFontOver: font(semibold 14px); } } +groupCallTitleSeparator: 4px; groupCallVideoLimitLabel: FlatLabel(defaultFlatLabel) { align: align(top); textFg: groupCallMemberNotJoinedStatus; diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp index 02a91665b..efc0f0aa4 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp @@ -209,6 +209,8 @@ void Panel::migrate(not_null channel) { _peerLifetime.destroy(); subscribeToPeerChanges(); _title.destroy(); + _titleSeparator.destroy(); + _viewers.destroy(); refreshTitle(); } @@ -925,6 +927,10 @@ void Panel::raiseControls() { if (_title) { _title->raise(); } + if (_viewers) { + _titleSeparator->raise(); + _viewers->raise(); + } if (_recordingMark) { _recordingMark->raise(); } @@ -1029,6 +1035,7 @@ void Panel::updateWideControlsVisibility() { void Panel::subscribeToChanges(not_null real) { const auto livestream = real->peer()->isBroadcast(); const auto validateRecordingMark = [=](bool recording) { + recording = true; AssertIsDebug(); if (!recording && _recordingMark) { _recordingMark.destroy(); } else if (recording && !_recordingMark) { @@ -1439,6 +1446,12 @@ void Panel::showBox( Ui::LayerOptions options, anim::type animated) { hideStickedTooltip(StickedTooltipHide::Unavailable); + if (window()->width() < st::groupCallWidth + || window()->height() < st::groupCallWidth) { + window()->resize( + std::max(window()->width(), st::groupCallWidth), + std::max(window()->height(), st::groupCallWidth)); + } _layerBg->showBox(std::move(box), options, animated); } @@ -1502,17 +1515,20 @@ void Panel::initGeometry() { const auto height = _call->rtmp() ? st::groupCallHeightRtmp : st::groupCallHeight; - const auto minHeight = (_call->rtmp() && !_call->canManage()) + const auto minWidth = _call->rtmp() + ? st::groupCallWidthRtmpMin + : st::groupCallWidth; + const auto minHeight = _call->rtmp() ? st::groupCallHeightRtmpMin : st::groupCallHeight; const auto rect = QRect(0, 0, width, height); window()->setGeometry(rect.translated(center - rect.center())); - window()->setMinimumSize({ st::groupCallWidth, minHeight }); + window()->setMinimumSize({ minWidth, minHeight }); window()->show(); } QRect Panel::computeTitleRect() const { - const auto skip = st::groupCallTitleTop; + const auto skip = st::groupCallTitleSeparator; const auto remove = skip + (_menuToggle ? (_menuToggle->width() + st::groupCallMenuTogglePosition.x()) @@ -1555,11 +1571,7 @@ bool Panel::updateMode() { _niceTooltip.destroy(); } _mode = mode; - if (_title) { - _title->setTextColorOverride(wide - ? std::make_optional(st::groupCallMemberNotJoinedStatus->c) - : std::nullopt); - } + refreshTitleColors(); if (wide && _subtitle) { _subtitle.destroy(); } else if (!wide && !_subtitle) { @@ -1664,6 +1676,8 @@ void Panel::setupEmptyRtmp() { (size.width() - _emptyRtmp->width()) / 2, (size.height() - _emptyRtmp->height()) / 3); }, _emptyRtmp->lifetime()); + + raiseControls(); }, lifetime()); } @@ -2322,6 +2336,38 @@ void Panel::refreshTitle() { st::groupCallTitleLabel); _title->show(); _title->setAttribute(Qt::WA_TransparentForMouseEvents); + if (_call->rtmp()) { + _titleSeparator.create( + widget(), + rpl::single(QString::fromUtf8("\xE2\x80\xA2")), + st::groupCallTitleLabel); + _titleSeparator->show(); + _titleSeparator->setAttribute(Qt::WA_TransparentForMouseEvents); + auto countText = _call->real( + ) | rpl::map([=](not_null real) { + return tr::lng_group_call_rtmp_viewers( + lt_count, + real->fullCountValue( + ) | rpl::map([=](int count) { + return std::max(float64(count), 1.); + })); + }) | rpl::flatten_latest( + ) | rpl::after_next([=] { + refreshTitleGeometry(); + }); + _viewers.create( + widget(), + std::move(countText), + st::groupCallTitleLabel); + _viewers->show(); + _viewers->setAttribute(Qt::WA_TransparentForMouseEvents); + } + + refreshTitleColors(); + style::PaletteChanged( + ) | rpl::start_with_next([=] { + refreshTitleColors(); + }, _title->lifetime()); } refreshTitleGeometry(); if (!_subtitle && mode() == PanelMode::Default) { @@ -2372,7 +2418,10 @@ void Panel::refreshTitleGeometry() { fullRect.width() - _recordingMark->width(), fullRect.height()) : fullRect; - const auto best = _title->naturalWidth(); + const auto sep = st::groupCallTitleSeparator; + const auto best = _title->naturalWidth() + (_viewers + ? (_titleSeparator->width() + sep * 2 + _viewers->naturalWidth()) + : 0); const auto from = (widget()->width() - best) / 2; const auto shownTop = (mode() == PanelMode::Default) ? st::groupCallTitleTop @@ -2386,39 +2435,78 @@ void Panel::refreshTitleGeometry() { _wideControlsShown ? 1. : 0.) : 1.)); const auto left = titleRect.x(); + + const auto notEnough = std::max(0, best - titleRect.width()); + const auto titleMaxWidth = _title->naturalWidth(); + const auto viewersMaxWidth = _viewers ? _viewers->naturalWidth() : 0; + const auto viewersNotEnough = std::clamp( + viewersMaxWidth - titleMaxWidth, + 0, + notEnough + ) + std::max( + (notEnough - std::abs(viewersMaxWidth - titleMaxWidth)) / 2, + 0); + _title->resizeToWidth( + _title->naturalWidth() - (notEnough - viewersNotEnough)); + if (_viewers) { + _viewers->resizeToWidth(_viewers->naturalWidth() - viewersNotEnough); + } + const auto layout = [&](int position) { + _title->moveToLeft(position, top); + position += _title->width(); + if (_viewers) { + _titleSeparator->moveToLeft(position + sep, top); + position += sep + _titleSeparator->width() + sep; + _viewers->moveToLeft(position, top); + position += _viewers->width(); + } + if (_recordingMark) { + const auto markTop = top + st::groupCallRecordingMarkTop; + _recordingMark->move( + position, + markTop - st::groupCallRecordingMarkSkip); + } + if (_titleBackground) { + const auto bottom = _title->y() + + _title->height() + + (st::boxRadius / 2); + const auto height = std::max(bottom, st::boxRadius * 2); + _titleBackground->setGeometry( + _title->x() - st::boxRadius, + bottom - height, + (position - _title->x() + + st::boxRadius + + (_recordingMark + ? (_recordingMark->width() + st::boxRadius / 2) + : st::boxRadius)), + height); + } + }; + if (from >= left && from + best <= left + titleRect.width()) { - _title->resizeToWidth(best); - _title->moveToLeft(from, top); + layout(from); } else if (titleRect.width() < best) { - _title->resizeToWidth(titleRect.width()); - _title->moveToLeft(left, top); + layout(left); } else if (from < left) { - _title->resizeToWidth(best); - _title->moveToLeft(left, top); + layout(left); } else { - _title->resizeToWidth(best); - _title->moveToLeft(left + titleRect.width() - best, top); + layout(left + titleRect.width() - best); } - if (_recordingMark) { - const auto markTop = top + st::groupCallRecordingMarkTop; - _recordingMark->move( - _title->x() + _title->width(), - markTop - st::groupCallRecordingMarkSkip); +} + +void Panel::refreshTitleColors() { + if (!_title) { + return; } - if (_titleBackground) { - const auto bottom = _title->y() - + _title->height() - + (st::boxRadius / 2); - const auto height = std::max(bottom, st::boxRadius * 2); - _titleBackground->setGeometry( - _title->x() - st::boxRadius, - bottom - height, - (_title->width() - + st::boxRadius - + (_recordingMark - ? (_recordingMark->width() + st::boxRadius / 2) - : st::boxRadius)), - height); + auto gray = st::groupCallMemberNotJoinedStatus->c; + const auto wide = (_mode.current() == PanelMode::Wide); + _title->setTextColorOverride(wide + ? std::make_optional(gray) + : std::nullopt); + if (_viewers) { + _viewers->setTextColorOverride(gray); + gray.setAlphaF(gray.alphaF() * 0.5); + _titleSeparator->setTextColorOverride(gray); } } diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.h b/Telegram/SourceFiles/calls/group/calls_group_panel.h index f5de44893..a2246a32d 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.h +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.h @@ -178,6 +178,7 @@ private: [[nodiscard]] QRect computeTitleRect() const; void refreshTitle(); void refreshTitleGeometry(); + void refreshTitleColors(); void setupRealCallViewers(); void subscribeToChanges(not_null real); @@ -212,6 +213,8 @@ private: object_ptr _titleBackground = { nullptr }; object_ptr _title = { nullptr }; + object_ptr _titleSeparator = { nullptr }; + object_ptr _viewers = { nullptr }; object_ptr _subtitle = { nullptr }; object_ptr _recordingMark = { nullptr }; object_ptr _menuToggle = { nullptr };