Show viewers count in RTMP streams.
This commit is contained in:
		
							parent
							
								
									1aa8029a8a
								
							
						
					
					
						commit
						3644dfd6fc
					
				
					 4 changed files with 132 additions and 37 deletions
				
			
		| 
						 | 
				
			
			@ -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.";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -209,6 +209,8 @@ void Panel::migrate(not_null<ChannelData*> 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<Data::GroupCall*> 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<Data::GroupCall*> 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,23 +2435,35 @@ void Panel::refreshTitleGeometry() {
 | 
			
		|||
				_wideControlsShown ? 1. : 0.)
 | 
			
		||||
			: 1.));
 | 
			
		||||
	const auto left = titleRect.x();
 | 
			
		||||
	if (from >= left && from + best <= left + titleRect.width()) {
 | 
			
		||||
		_title->resizeToWidth(best);
 | 
			
		||||
		_title->moveToLeft(from, top);
 | 
			
		||||
	} else if (titleRect.width() < best) {
 | 
			
		||||
		_title->resizeToWidth(titleRect.width());
 | 
			
		||||
		_title->moveToLeft(left, top);
 | 
			
		||||
	} else if (from < left) {
 | 
			
		||||
		_title->resizeToWidth(best);
 | 
			
		||||
		_title->moveToLeft(left, top);
 | 
			
		||||
	} else {
 | 
			
		||||
		_title->resizeToWidth(best);
 | 
			
		||||
		_title->moveToLeft(left + titleRect.width() - best, top);
 | 
			
		||||
 | 
			
		||||
	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(
 | 
			
		||||
			_title->x() + _title->width(),
 | 
			
		||||
				position,
 | 
			
		||||
				markTop - st::groupCallRecordingMarkSkip);
 | 
			
		||||
		}
 | 
			
		||||
		if (_titleBackground) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2413,13 +2474,40 @@ void Panel::refreshTitleGeometry() {
 | 
			
		|||
			_titleBackground->setGeometry(
 | 
			
		||||
				_title->x() - st::boxRadius,
 | 
			
		||||
				bottom - height,
 | 
			
		||||
			(_title->width()
 | 
			
		||||
				(position - _title->x()
 | 
			
		||||
					+ st::boxRadius
 | 
			
		||||
					+ (_recordingMark
 | 
			
		||||
						? (_recordingMark->width() + st::boxRadius / 2)
 | 
			
		||||
						: st::boxRadius)),
 | 
			
		||||
				height);
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	if (from >= left && from + best <= left + titleRect.width()) {
 | 
			
		||||
		layout(from);
 | 
			
		||||
	} else if (titleRect.width() < best) {
 | 
			
		||||
		layout(left);
 | 
			
		||||
	} else if (from < left) {
 | 
			
		||||
		layout(left);
 | 
			
		||||
	} else {
 | 
			
		||||
		layout(left + titleRect.width() - best);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Panel::refreshTitleColors() {
 | 
			
		||||
	if (!_title) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	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);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Panel::paint(QRect clip) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -178,6 +178,7 @@ private:
 | 
			
		|||
	[[nodiscard]] QRect computeTitleRect() const;
 | 
			
		||||
	void refreshTitle();
 | 
			
		||||
	void refreshTitleGeometry();
 | 
			
		||||
	void refreshTitleColors();
 | 
			
		||||
	void setupRealCallViewers();
 | 
			
		||||
	void subscribeToChanges(not_null<Data::GroupCall*> real);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -212,6 +213,8 @@ private:
 | 
			
		|||
 | 
			
		||||
	object_ptr<Ui::RpWidget> _titleBackground = { nullptr };
 | 
			
		||||
	object_ptr<Ui::FlatLabel> _title = { nullptr };
 | 
			
		||||
	object_ptr<Ui::FlatLabel> _titleSeparator = { nullptr };
 | 
			
		||||
	object_ptr<Ui::FlatLabel> _viewers = { nullptr };
 | 
			
		||||
	object_ptr<Ui::FlatLabel> _subtitle = { nullptr };
 | 
			
		||||
	object_ptr<Ui::AbstractButton> _recordingMark = { nullptr };
 | 
			
		||||
	object_ptr<Ui::IconButton> _menuToggle = { nullptr };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue